@braid-cloud/cli 0.1.10 → 0.1.13
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 +31 -0
- package/dist/index.js +1860 -854
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
package/dist/index.js
CHANGED
|
@@ -55,28 +55,28 @@ __export(config_exports, {
|
|
|
55
55
|
setApiKeyAsync: () => setApiKeyAsync
|
|
56
56
|
});
|
|
57
57
|
import { existsSync } from "fs";
|
|
58
|
-
import { mkdir, readFile, writeFile } from "fs/promises";
|
|
59
|
-
import { homedir } from "os";
|
|
60
|
-
import { dirname, join, parse } from "path";
|
|
61
|
-
import
|
|
62
|
-
import { Data, Effect, pipe } from "effect";
|
|
58
|
+
import { mkdir as mkdir2, readFile, writeFile as writeFile2 } from "fs/promises";
|
|
59
|
+
import { homedir as homedir2 } from "os";
|
|
60
|
+
import { dirname as dirname2, join as join2, parse } from "path";
|
|
61
|
+
import process3 from "process";
|
|
62
|
+
import { Data as Data2, Effect as Effect3, pipe as pipe3 } from "effect";
|
|
63
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";
|
|
67
67
|
init_esm_shims();
|
|
68
|
-
CONFIG_DIR =
|
|
69
|
-
CONFIG_FILE =
|
|
68
|
+
CONFIG_DIR = join2(homedir2(), ".config", "braid");
|
|
69
|
+
CONFIG_FILE = join2(CONFIG_DIR, "config.json");
|
|
70
70
|
PROJECT_CONFIG_FILENAME = "braid.json";
|
|
71
71
|
USER_CONFIG_FILENAME = "braid.user.json";
|
|
72
|
-
ConfigReadError = class extends
|
|
72
|
+
ConfigReadError = class extends Data2.TaggedError("ConfigReadError") {
|
|
73
73
|
};
|
|
74
|
-
ConfigWriteError = class extends
|
|
74
|
+
ConfigWriteError = class extends Data2.TaggedError("ConfigWriteError") {
|
|
75
75
|
};
|
|
76
|
-
findConfigFile = (filename, startDir =
|
|
76
|
+
findConfigFile = (filename, startDir = process3.cwd()) => {
|
|
77
77
|
let currentDir = startDir;
|
|
78
78
|
while (true) {
|
|
79
|
-
const configPath =
|
|
79
|
+
const configPath = join2(currentDir, filename);
|
|
80
80
|
if (existsSync(configPath)) {
|
|
81
81
|
return configPath;
|
|
82
82
|
}
|
|
@@ -87,9 +87,9 @@ var init_config = __esm({
|
|
|
87
87
|
currentDir = parsed.dir;
|
|
88
88
|
}
|
|
89
89
|
};
|
|
90
|
-
findProjectConfigFile = (startDir =
|
|
91
|
-
findUserConfigFile = (startDir =
|
|
92
|
-
loadProjectConfig = () =>
|
|
90
|
+
findProjectConfigFile = (startDir = process3.cwd()) => findConfigFile(PROJECT_CONFIG_FILENAME, startDir);
|
|
91
|
+
findUserConfigFile = (startDir = process3.cwd()) => findConfigFile(USER_CONFIG_FILENAME, startDir);
|
|
92
|
+
loadProjectConfig = () => Effect3.tryPromise({
|
|
93
93
|
try: async () => {
|
|
94
94
|
const configPath = await findProjectConfigFile();
|
|
95
95
|
if (!configPath) {
|
|
@@ -99,8 +99,8 @@ var init_config = __esm({
|
|
|
99
99
|
return JSON.parse(content);
|
|
100
100
|
},
|
|
101
101
|
catch: () => void 0
|
|
102
|
-
}).pipe(
|
|
103
|
-
loadUserConfig = () =>
|
|
102
|
+
}).pipe(Effect3.orElseSucceed(() => void 0));
|
|
103
|
+
loadUserConfig = () => Effect3.tryPromise({
|
|
104
104
|
try: async () => {
|
|
105
105
|
const configPath = await findUserConfigFile();
|
|
106
106
|
if (!configPath) {
|
|
@@ -110,16 +110,16 @@ var init_config = __esm({
|
|
|
110
110
|
return JSON.parse(content);
|
|
111
111
|
},
|
|
112
112
|
catch: () => void 0
|
|
113
|
-
}).pipe(
|
|
114
|
-
resolveUserConfigWritePath = (startDir =
|
|
115
|
-
resolveProjectConfigWritePath = (startDir =
|
|
116
|
-
saveUserConfig = (config, startDir =
|
|
113
|
+
}).pipe(Effect3.orElseSucceed(() => void 0));
|
|
114
|
+
resolveUserConfigWritePath = (startDir = process3.cwd()) => findUserConfigFile(startDir) ?? join2(startDir, USER_CONFIG_FILENAME);
|
|
115
|
+
resolveProjectConfigWritePath = (startDir = process3.cwd()) => findProjectConfigFile(startDir) ?? join2(startDir, PROJECT_CONFIG_FILENAME);
|
|
116
|
+
saveUserConfig = (config, startDir = process3.cwd()) => {
|
|
117
117
|
const targetPath = resolveUserConfigWritePath(startDir);
|
|
118
|
-
return
|
|
119
|
-
|
|
118
|
+
return pipe3(
|
|
119
|
+
Effect3.tryPromise({
|
|
120
120
|
try: async () => {
|
|
121
|
-
await
|
|
122
|
-
await
|
|
121
|
+
await mkdir2(dirname2(targetPath), { recursive: true, mode: 448 });
|
|
122
|
+
await writeFile2(targetPath, JSON.stringify(config, null, 2), {
|
|
123
123
|
encoding: "utf-8",
|
|
124
124
|
mode: 384
|
|
125
125
|
});
|
|
@@ -129,13 +129,13 @@ var init_config = __esm({
|
|
|
129
129
|
})
|
|
130
130
|
);
|
|
131
131
|
};
|
|
132
|
-
saveProjectConfig = (config, startDir =
|
|
132
|
+
saveProjectConfig = (config, startDir = process3.cwd()) => {
|
|
133
133
|
const targetPath = resolveProjectConfigWritePath(startDir);
|
|
134
|
-
return
|
|
135
|
-
|
|
134
|
+
return pipe3(
|
|
135
|
+
Effect3.tryPromise({
|
|
136
136
|
try: async () => {
|
|
137
|
-
await
|
|
138
|
-
await
|
|
137
|
+
await mkdir2(dirname2(targetPath), { recursive: true, mode: 448 });
|
|
138
|
+
await writeFile2(targetPath, JSON.stringify(config, null, 2), {
|
|
139
139
|
encoding: "utf-8",
|
|
140
140
|
mode: 384
|
|
141
141
|
});
|
|
@@ -206,10 +206,10 @@ var init_config = __esm({
|
|
|
206
206
|
}
|
|
207
207
|
};
|
|
208
208
|
applyEnvOverrides = (merged) => {
|
|
209
|
-
if (
|
|
210
|
-
merged.token =
|
|
209
|
+
if (process3.env.BRAID_API_KEY) {
|
|
210
|
+
merged.token = process3.env.BRAID_API_KEY;
|
|
211
211
|
}
|
|
212
|
-
const envServerUrl =
|
|
212
|
+
const envServerUrl = process3.env.BRAID_SKILLS_SERVER_URL ?? process3.env.BRAID_SERVER_URL;
|
|
213
213
|
if (envServerUrl && isValidServerUrl(envServerUrl)) {
|
|
214
214
|
merged.serverUrl = envServerUrl;
|
|
215
215
|
}
|
|
@@ -219,15 +219,15 @@ var init_config = __esm({
|
|
|
219
219
|
includeUserGlobal: true,
|
|
220
220
|
includeOrgGlobal: true
|
|
221
221
|
});
|
|
222
|
-
loadMergedConfig = () =>
|
|
223
|
-
|
|
222
|
+
loadMergedConfig = () => pipe3(
|
|
223
|
+
Effect3.all({
|
|
224
224
|
projectConfig: loadProjectConfig(),
|
|
225
225
|
userConfig: loadUserConfig(),
|
|
226
226
|
globalConfig: loadConfig().pipe(
|
|
227
|
-
|
|
227
|
+
Effect3.orElseSucceed(() => ({}))
|
|
228
228
|
)
|
|
229
229
|
}),
|
|
230
|
-
|
|
230
|
+
Effect3.map(({ projectConfig, userConfig, globalConfig }) => {
|
|
231
231
|
const merged = createDefaultMergedConfig();
|
|
232
232
|
applyConfigSource(merged, projectConfig);
|
|
233
233
|
applyConfigSource(merged, userConfig);
|
|
@@ -238,24 +238,24 @@ var init_config = __esm({
|
|
|
238
238
|
return merged;
|
|
239
239
|
})
|
|
240
240
|
);
|
|
241
|
-
loadConfig = () =>
|
|
242
|
-
|
|
241
|
+
loadConfig = () => pipe3(
|
|
242
|
+
Effect3.tryPromise({
|
|
243
243
|
try: () => readFile(CONFIG_FILE, "utf-8"),
|
|
244
244
|
catch: (e) => new ConfigReadError({ path: CONFIG_FILE, cause: e })
|
|
245
245
|
}),
|
|
246
|
-
|
|
247
|
-
(content) =>
|
|
246
|
+
Effect3.flatMap(
|
|
247
|
+
(content) => Effect3.try({
|
|
248
248
|
try: () => JSON.parse(content),
|
|
249
249
|
catch: () => ({})
|
|
250
250
|
})
|
|
251
251
|
),
|
|
252
|
-
|
|
252
|
+
Effect3.orElseSucceed(() => ({}))
|
|
253
253
|
);
|
|
254
|
-
saveConfig = (config) =>
|
|
255
|
-
|
|
254
|
+
saveConfig = (config) => pipe3(
|
|
255
|
+
Effect3.tryPromise({
|
|
256
256
|
try: async () => {
|
|
257
|
-
await
|
|
258
|
-
await
|
|
257
|
+
await mkdir2(dirname2(CONFIG_FILE), { recursive: true, mode: 448 });
|
|
258
|
+
await writeFile2(CONFIG_FILE, JSON.stringify(config, null, 2), {
|
|
259
259
|
encoding: "utf-8",
|
|
260
260
|
mode: 384
|
|
261
261
|
});
|
|
@@ -263,33 +263,33 @@ var init_config = __esm({
|
|
|
263
263
|
catch: (e) => new ConfigWriteError({ path: CONFIG_FILE, cause: e })
|
|
264
264
|
})
|
|
265
265
|
);
|
|
266
|
-
getApiKey = () =>
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
(envKey) => envKey ?
|
|
266
|
+
getApiKey = () => pipe3(
|
|
267
|
+
Effect3.succeed(process3.env.BRAID_API_KEY),
|
|
268
|
+
Effect3.flatMap(
|
|
269
|
+
(envKey) => envKey ? Effect3.succeed(envKey) : pipe3(
|
|
270
270
|
loadUserConfig(),
|
|
271
|
-
|
|
272
|
-
(userConfig) => userConfig?.token ?
|
|
271
|
+
Effect3.flatMap(
|
|
272
|
+
(userConfig) => userConfig?.token ? Effect3.succeed(userConfig.token) : pipe3(
|
|
273
273
|
loadConfig(),
|
|
274
|
-
|
|
274
|
+
Effect3.map((config) => config.apiKey)
|
|
275
275
|
)
|
|
276
276
|
)
|
|
277
277
|
)
|
|
278
278
|
)
|
|
279
279
|
);
|
|
280
|
-
setApiKey = (apiKey) =>
|
|
280
|
+
setApiKey = (apiKey) => pipe3(
|
|
281
281
|
loadConfig(),
|
|
282
|
-
|
|
282
|
+
Effect3.flatMap((config) => saveConfig({ ...config, apiKey }))
|
|
283
283
|
);
|
|
284
|
-
getServerUrl = () =>
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
(envUrl) => envUrl ?
|
|
284
|
+
getServerUrl = () => pipe3(
|
|
285
|
+
Effect3.succeed(process3.env.BRAID_SERVER_URL),
|
|
286
|
+
Effect3.flatMap(
|
|
287
|
+
(envUrl) => envUrl ? Effect3.succeed(envUrl) : pipe3(
|
|
288
288
|
loadUserConfig(),
|
|
289
|
-
|
|
290
|
-
(userConfig) => userConfig?.serverUrl ?
|
|
289
|
+
Effect3.flatMap(
|
|
290
|
+
(userConfig) => userConfig?.serverUrl ? Effect3.succeed(userConfig.serverUrl) : pipe3(
|
|
291
291
|
loadConfig(),
|
|
292
|
-
|
|
292
|
+
Effect3.map(
|
|
293
293
|
(config) => config.serverUrl ?? "https://braid.cloud"
|
|
294
294
|
)
|
|
295
295
|
)
|
|
@@ -297,55 +297,74 @@ var init_config = __esm({
|
|
|
297
297
|
)
|
|
298
298
|
)
|
|
299
299
|
);
|
|
300
|
-
clearApiKey = () =>
|
|
300
|
+
clearApiKey = () => pipe3(
|
|
301
301
|
loadConfig(),
|
|
302
|
-
|
|
302
|
+
Effect3.flatMap((config) => {
|
|
303
303
|
const { apiKey: _, ...rest } = config;
|
|
304
304
|
return saveConfig(rest);
|
|
305
305
|
})
|
|
306
306
|
);
|
|
307
|
-
loadConfigAsync = () =>
|
|
308
|
-
loadProjectConfigAsync = () =>
|
|
309
|
-
loadUserConfigAsync = () =>
|
|
310
|
-
loadMergedConfigAsync = () =>
|
|
307
|
+
loadConfigAsync = () => Effect3.runPromise(loadConfig());
|
|
308
|
+
loadProjectConfigAsync = () => Effect3.runPromise(loadProjectConfig());
|
|
309
|
+
loadUserConfigAsync = () => Effect3.runPromise(loadUserConfig());
|
|
310
|
+
loadMergedConfigAsync = () => Effect3.runPromise(loadMergedConfig());
|
|
311
311
|
findProjectConfigFileAsync = (startDir) => findProjectConfigFile(startDir);
|
|
312
312
|
findUserConfigFileAsync = (startDir) => findUserConfigFile(startDir);
|
|
313
|
-
saveConfigAsync = (config) =>
|
|
314
|
-
saveUserConfigAsync = (config, startDir) =>
|
|
315
|
-
saveProjectConfigAsync = (config, startDir) =>
|
|
316
|
-
getApiKeyAsync = () =>
|
|
317
|
-
setApiKeyAsync = (apiKey) =>
|
|
318
|
-
getServerUrlAsync = () =>
|
|
319
|
-
clearApiKeyAsync = () =>
|
|
313
|
+
saveConfigAsync = (config) => Effect3.runPromise(saveConfig(config));
|
|
314
|
+
saveUserConfigAsync = (config, startDir) => Effect3.runPromise(saveUserConfig(config, startDir));
|
|
315
|
+
saveProjectConfigAsync = (config, startDir) => Effect3.runPromise(saveProjectConfig(config, startDir));
|
|
316
|
+
getApiKeyAsync = () => Effect3.runPromise(getApiKey());
|
|
317
|
+
setApiKeyAsync = (apiKey) => Effect3.runPromise(setApiKey(apiKey));
|
|
318
|
+
getServerUrlAsync = () => Effect3.runPromise(getServerUrl());
|
|
319
|
+
clearApiKeyAsync = () => Effect3.runPromise(clearApiKey());
|
|
320
320
|
}
|
|
321
321
|
});
|
|
322
322
|
|
|
323
323
|
// src/lib/api.ts
|
|
324
|
-
import { Data as
|
|
325
|
-
var TRAILING_SLASH_REGEX, ApiError, AuthenticationError, NetworkError, resolveApiKey, resolveServerUrl, parseResponse, buildApiUrl, buildExportUrl, executeApiRequest, parseScopeOptionsResponse, fetchScopeOptions, buildRuleOptionsUrl, fetchRuleOptions, fetchSkills, runLifecycleCommand, DEFAULT_PUBLIC_SERVER_URL, NotFoundError, RateLimitedError, handlePublicApiResponse, fetchPublicMetadata, fetchPublicExport, fetchPublicMetadataAsync, fetchPublicExportAsync, validateApiKey, fetchSkillsAsync, validateApiKeyAsync, fetchScopeOptionsAsync, fetchRuleOptionsAsync, runLifecycleCommandAsync;
|
|
324
|
+
import { Data as Data3, Effect as Effect4, pipe as pipe4 } from "effect";
|
|
325
|
+
var TRAILING_SLASH_REGEX, ALLOW_UNTRUSTED_SERVER_ENV, isTruthy, isLocalHost, isTrustedApiServerUrl, ApiError, AuthenticationError, NetworkError, resolveApiKey, resolveServerUrl, parseResponse, buildApiUrl, buildExportUrl, executeApiRequest, parseScopeOptionsResponse, fetchScopeOptions, buildRuleOptionsUrl, fetchRuleOptions, fetchSkills, runLifecycleCommand, DEFAULT_PUBLIC_SERVER_URL, NotFoundError, RateLimitedError, handlePublicApiResponse, fetchPublicMetadata, fetchPublicExport, fetchPublicMetadataAsync, fetchPublicExportAsync, validateApiKey, fetchSkillsAsync, validateApiKeyAsync, fetchScopeOptionsAsync, fetchRuleOptionsAsync, runLifecycleCommandAsync;
|
|
326
326
|
var init_api = __esm({
|
|
327
327
|
"src/lib/api.ts"() {
|
|
328
328
|
"use strict";
|
|
329
329
|
init_esm_shims();
|
|
330
330
|
init_config();
|
|
331
331
|
TRAILING_SLASH_REGEX = /\/$/;
|
|
332
|
-
|
|
332
|
+
ALLOW_UNTRUSTED_SERVER_ENV = "BRAID_ALLOW_UNTRUSTED_SERVER_URL";
|
|
333
|
+
isTruthy = (value) => value === "1" || value === "true" || value === "yes";
|
|
334
|
+
isLocalHost = (hostname2) => hostname2 === "localhost" || hostname2 === "127.0.0.1" || hostname2 === "::1";
|
|
335
|
+
isTrustedApiServerUrl = (serverUrl) => {
|
|
336
|
+
try {
|
|
337
|
+
const parsed = new URL(serverUrl);
|
|
338
|
+
const hostname2 = parsed.hostname;
|
|
339
|
+
const isBraidHost = hostname2 === "braid.cloud" || hostname2.endsWith(".braid.cloud");
|
|
340
|
+
if (parsed.protocol === "https:" && isBraidHost) {
|
|
341
|
+
return true;
|
|
342
|
+
}
|
|
343
|
+
if (parsed.protocol === "http:" && isLocalHost(hostname2)) {
|
|
344
|
+
return true;
|
|
345
|
+
}
|
|
346
|
+
return false;
|
|
347
|
+
} catch {
|
|
348
|
+
return false;
|
|
349
|
+
}
|
|
350
|
+
};
|
|
351
|
+
ApiError = class extends Data3.TaggedError("ApiError") {
|
|
333
352
|
};
|
|
334
|
-
AuthenticationError = class extends
|
|
353
|
+
AuthenticationError = class extends Data3.TaggedError("AuthenticationError") {
|
|
335
354
|
};
|
|
336
|
-
NetworkError = class extends
|
|
355
|
+
NetworkError = class extends Data3.TaggedError("NetworkError") {
|
|
337
356
|
};
|
|
338
357
|
resolveApiKey = (optionsApiKey) => {
|
|
339
358
|
if (optionsApiKey) {
|
|
340
|
-
return
|
|
359
|
+
return Effect4.succeed(optionsApiKey);
|
|
341
360
|
}
|
|
342
|
-
return
|
|
343
|
-
|
|
361
|
+
return pipe4(
|
|
362
|
+
Effect4.tryPromise({
|
|
344
363
|
try: () => getApiKeyAsync(),
|
|
345
364
|
catch: () => new NetworkError({ message: "Failed to read config" })
|
|
346
365
|
}),
|
|
347
|
-
|
|
348
|
-
(key) => key ?
|
|
366
|
+
Effect4.flatMap(
|
|
367
|
+
(key) => key ? Effect4.succeed(key) : Effect4.fail(
|
|
349
368
|
new AuthenticationError({
|
|
350
369
|
message: 'No API key configured. Run "braid auth" to authenticate.'
|
|
351
370
|
})
|
|
@@ -355,24 +374,43 @@ var init_api = __esm({
|
|
|
355
374
|
};
|
|
356
375
|
resolveServerUrl = (optionsServerUrl) => {
|
|
357
376
|
if (optionsServerUrl) {
|
|
358
|
-
|
|
377
|
+
if (!(isTruthy(process.env[ALLOW_UNTRUSTED_SERVER_ENV]) || isTrustedApiServerUrl(optionsServerUrl))) {
|
|
378
|
+
return Effect4.fail(
|
|
379
|
+
new NetworkError({
|
|
380
|
+
message: `Untrusted server URL '${optionsServerUrl}'. Set ${ALLOW_UNTRUSTED_SERVER_ENV}=true to override.`
|
|
381
|
+
})
|
|
382
|
+
);
|
|
383
|
+
}
|
|
384
|
+
return Effect4.succeed(optionsServerUrl);
|
|
359
385
|
}
|
|
360
|
-
return
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
386
|
+
return pipe4(
|
|
387
|
+
Effect4.tryPromise({
|
|
388
|
+
try: () => getServerUrlAsync(),
|
|
389
|
+
catch: () => new NetworkError({ message: "Failed to read config" })
|
|
390
|
+
}),
|
|
391
|
+
Effect4.flatMap((serverUrl) => {
|
|
392
|
+
if (isTruthy(process.env[ALLOW_UNTRUSTED_SERVER_ENV]) || isTrustedApiServerUrl(serverUrl)) {
|
|
393
|
+
return Effect4.succeed(serverUrl);
|
|
394
|
+
}
|
|
395
|
+
return Effect4.fail(
|
|
396
|
+
new NetworkError({
|
|
397
|
+
message: `Untrusted server URL '${serverUrl}'. Set ${ALLOW_UNTRUSTED_SERVER_ENV}=true to override.`
|
|
398
|
+
})
|
|
399
|
+
);
|
|
400
|
+
})
|
|
401
|
+
);
|
|
364
402
|
};
|
|
365
403
|
parseResponse = (response, json) => {
|
|
366
404
|
if (!response.ok) {
|
|
367
405
|
const errorResponse = json;
|
|
368
406
|
if (response.status === 401) {
|
|
369
|
-
return
|
|
407
|
+
return Effect4.fail(
|
|
370
408
|
new AuthenticationError({
|
|
371
409
|
message: errorResponse.error || "Invalid or expired API key. Run 'braid auth' to re-authenticate."
|
|
372
410
|
})
|
|
373
411
|
);
|
|
374
412
|
}
|
|
375
|
-
return
|
|
413
|
+
return Effect4.fail(
|
|
376
414
|
new ApiError({
|
|
377
415
|
message: errorResponse.error || "API request failed",
|
|
378
416
|
code: errorResponse.code || "UNKNOWN_ERROR",
|
|
@@ -380,7 +418,7 @@ var init_api = __esm({
|
|
|
380
418
|
})
|
|
381
419
|
);
|
|
382
420
|
}
|
|
383
|
-
return
|
|
421
|
+
return Effect4.succeed(json);
|
|
384
422
|
};
|
|
385
423
|
buildApiUrl = (serverUrl, path2) => {
|
|
386
424
|
const baseUrl = serverUrl.replace(TRAILING_SLASH_REGEX, "");
|
|
@@ -420,8 +458,8 @@ var init_api = __esm({
|
|
|
420
458
|
}
|
|
421
459
|
return url;
|
|
422
460
|
};
|
|
423
|
-
executeApiRequest = (url, apiKey, serverUrl) =>
|
|
424
|
-
|
|
461
|
+
executeApiRequest = (url, apiKey, serverUrl) => pipe4(
|
|
462
|
+
Effect4.tryPromise({
|
|
425
463
|
try: () => fetch(url.toString(), {
|
|
426
464
|
method: "GET",
|
|
427
465
|
headers: {
|
|
@@ -434,13 +472,13 @@ var init_api = __esm({
|
|
|
434
472
|
cause: e
|
|
435
473
|
})
|
|
436
474
|
}),
|
|
437
|
-
|
|
438
|
-
(response) =>
|
|
439
|
-
|
|
475
|
+
Effect4.flatMap(
|
|
476
|
+
(response) => pipe4(
|
|
477
|
+
Effect4.tryPromise({
|
|
440
478
|
try: () => response.json(),
|
|
441
479
|
catch: () => new NetworkError({ message: "Failed to parse API response" })
|
|
442
480
|
}),
|
|
443
|
-
|
|
481
|
+
Effect4.flatMap((json) => parseResponse(response, json))
|
|
444
482
|
)
|
|
445
483
|
)
|
|
446
484
|
);
|
|
@@ -448,13 +486,13 @@ var init_api = __esm({
|
|
|
448
486
|
if (!response.ok) {
|
|
449
487
|
const errorResponse = json;
|
|
450
488
|
if (response.status === 401) {
|
|
451
|
-
return
|
|
489
|
+
return Effect4.fail(
|
|
452
490
|
new AuthenticationError({
|
|
453
491
|
message: errorResponse.error || "Invalid or expired API key. Run 'braid auth' to re-authenticate."
|
|
454
492
|
})
|
|
455
493
|
);
|
|
456
494
|
}
|
|
457
|
-
return
|
|
495
|
+
return Effect4.fail(
|
|
458
496
|
new ApiError({
|
|
459
497
|
message: errorResponse.error || "API request failed",
|
|
460
498
|
code: errorResponse.code || "UNKNOWN_ERROR",
|
|
@@ -462,17 +500,17 @@ var init_api = __esm({
|
|
|
462
500
|
})
|
|
463
501
|
);
|
|
464
502
|
}
|
|
465
|
-
return
|
|
503
|
+
return Effect4.succeed(json);
|
|
466
504
|
};
|
|
467
|
-
fetchScopeOptions = (options = {}) =>
|
|
468
|
-
|
|
505
|
+
fetchScopeOptions = (options = {}) => pipe4(
|
|
506
|
+
Effect4.all({
|
|
469
507
|
apiKey: resolveApiKey(options.apiKey),
|
|
470
508
|
serverUrl: resolveServerUrl(options.serverUrl)
|
|
471
509
|
}),
|
|
472
|
-
|
|
510
|
+
Effect4.flatMap(({ apiKey, serverUrl }) => {
|
|
473
511
|
const url = buildApiUrl(serverUrl, "/api/skills/scope-options");
|
|
474
|
-
return
|
|
475
|
-
|
|
512
|
+
return pipe4(
|
|
513
|
+
Effect4.tryPromise({
|
|
476
514
|
try: () => fetch(url.toString(), {
|
|
477
515
|
method: "GET",
|
|
478
516
|
headers: {
|
|
@@ -485,13 +523,13 @@ var init_api = __esm({
|
|
|
485
523
|
cause: e
|
|
486
524
|
})
|
|
487
525
|
}),
|
|
488
|
-
|
|
489
|
-
(response) =>
|
|
490
|
-
|
|
526
|
+
Effect4.flatMap(
|
|
527
|
+
(response) => pipe4(
|
|
528
|
+
Effect4.tryPromise({
|
|
491
529
|
try: () => response.json(),
|
|
492
530
|
catch: () => new NetworkError({ message: "Failed to parse API response" })
|
|
493
531
|
}),
|
|
494
|
-
|
|
532
|
+
Effect4.flatMap((json) => parseScopeOptionsResponse(response, json))
|
|
495
533
|
)
|
|
496
534
|
)
|
|
497
535
|
);
|
|
@@ -522,14 +560,14 @@ var init_api = __esm({
|
|
|
522
560
|
}
|
|
523
561
|
return url;
|
|
524
562
|
};
|
|
525
|
-
fetchRuleOptions = (options = {}) =>
|
|
526
|
-
|
|
563
|
+
fetchRuleOptions = (options = {}) => pipe4(
|
|
564
|
+
Effect4.all({
|
|
527
565
|
apiKey: resolveApiKey(options.apiKey),
|
|
528
566
|
serverUrl: resolveServerUrl(options.serverUrl)
|
|
529
567
|
}),
|
|
530
|
-
|
|
531
|
-
({ apiKey, serverUrl }) =>
|
|
532
|
-
|
|
568
|
+
Effect4.flatMap(
|
|
569
|
+
({ apiKey, serverUrl }) => pipe4(
|
|
570
|
+
Effect4.tryPromise({
|
|
533
571
|
try: () => fetch(buildRuleOptionsUrl(serverUrl, options).toString(), {
|
|
534
572
|
method: "GET",
|
|
535
573
|
headers: {
|
|
@@ -542,17 +580,17 @@ var init_api = __esm({
|
|
|
542
580
|
cause: e
|
|
543
581
|
})
|
|
544
582
|
}),
|
|
545
|
-
|
|
546
|
-
(response) =>
|
|
547
|
-
|
|
583
|
+
Effect4.flatMap(
|
|
584
|
+
(response) => pipe4(
|
|
585
|
+
Effect4.tryPromise({
|
|
548
586
|
try: () => response.json(),
|
|
549
587
|
catch: () => new NetworkError({ message: "Failed to parse API response" })
|
|
550
588
|
}),
|
|
551
|
-
|
|
589
|
+
Effect4.flatMap((json) => {
|
|
552
590
|
if (!response.ok) {
|
|
553
591
|
return parseResponse(response, json).pipe(
|
|
554
|
-
|
|
555
|
-
() =>
|
|
592
|
+
Effect4.flatMap(
|
|
593
|
+
() => Effect4.fail(
|
|
556
594
|
new ApiError({
|
|
557
595
|
message: "API request failed",
|
|
558
596
|
code: "UNKNOWN_ERROR",
|
|
@@ -562,30 +600,30 @@ var init_api = __esm({
|
|
|
562
600
|
)
|
|
563
601
|
);
|
|
564
602
|
}
|
|
565
|
-
return
|
|
603
|
+
return Effect4.succeed(json);
|
|
566
604
|
})
|
|
567
605
|
)
|
|
568
606
|
)
|
|
569
607
|
)
|
|
570
608
|
)
|
|
571
609
|
);
|
|
572
|
-
fetchSkills = (options) =>
|
|
573
|
-
|
|
610
|
+
fetchSkills = (options) => pipe4(
|
|
611
|
+
Effect4.all({
|
|
574
612
|
apiKey: resolveApiKey(options.apiKey),
|
|
575
613
|
serverUrl: resolveServerUrl(options.serverUrl)
|
|
576
614
|
}),
|
|
577
|
-
|
|
615
|
+
Effect4.flatMap(({ apiKey, serverUrl }) => {
|
|
578
616
|
const url = buildExportUrl(serverUrl, options);
|
|
579
617
|
return executeApiRequest(url, apiKey, serverUrl);
|
|
580
618
|
})
|
|
581
619
|
);
|
|
582
|
-
runLifecycleCommand = (request, options = {}) =>
|
|
583
|
-
|
|
620
|
+
runLifecycleCommand = (request, options = {}) => pipe4(
|
|
621
|
+
Effect4.all({
|
|
584
622
|
apiKey: resolveApiKey(options.apiKey),
|
|
585
623
|
serverUrl: resolveServerUrl(options.serverUrl)
|
|
586
624
|
}),
|
|
587
|
-
|
|
588
|
-
({ apiKey, serverUrl }) =>
|
|
625
|
+
Effect4.flatMap(
|
|
626
|
+
({ apiKey, serverUrl }) => Effect4.tryPromise({
|
|
589
627
|
try: async () => {
|
|
590
628
|
const response = await fetch(
|
|
591
629
|
buildApiUrl(serverUrl, "/api/lifecycle").toString(),
|
|
@@ -627,23 +665,23 @@ var init_api = __esm({
|
|
|
627
665
|
)
|
|
628
666
|
);
|
|
629
667
|
DEFAULT_PUBLIC_SERVER_URL = "https://braid.cloud";
|
|
630
|
-
NotFoundError = class extends
|
|
668
|
+
NotFoundError = class extends Data3.TaggedError("NotFoundError") {
|
|
631
669
|
};
|
|
632
|
-
RateLimitedError = class extends
|
|
670
|
+
RateLimitedError = class extends Data3.TaggedError("RateLimitedError") {
|
|
633
671
|
};
|
|
634
672
|
handlePublicApiResponse = (response, json) => {
|
|
635
673
|
if (response.ok) {
|
|
636
|
-
return
|
|
674
|
+
return Effect4.succeed(json);
|
|
637
675
|
}
|
|
638
676
|
if (response.status === 404) {
|
|
639
|
-
return
|
|
677
|
+
return Effect4.fail(
|
|
640
678
|
new NotFoundError({ message: "Public content not found" })
|
|
641
679
|
);
|
|
642
680
|
}
|
|
643
681
|
if (response.status === 429) {
|
|
644
682
|
const retryAfter = response.headers.get("Retry-After");
|
|
645
683
|
const retryMs = retryAfter ? Number(retryAfter) * 1e3 : null;
|
|
646
|
-
return
|
|
684
|
+
return Effect4.fail(
|
|
647
685
|
new RateLimitedError({
|
|
648
686
|
message: "Rate limited. Please try again later.",
|
|
649
687
|
...retryMs !== null ? { retryAfterMs: retryMs } : {}
|
|
@@ -651,7 +689,7 @@ var init_api = __esm({
|
|
|
651
689
|
);
|
|
652
690
|
}
|
|
653
691
|
const errorResponse = json;
|
|
654
|
-
return
|
|
692
|
+
return Effect4.fail(
|
|
655
693
|
new ApiError({
|
|
656
694
|
message: errorResponse.error || "API request failed",
|
|
657
695
|
code: errorResponse.code || "UNKNOWN_ERROR",
|
|
@@ -665,21 +703,21 @@ var init_api = __esm({
|
|
|
665
703
|
""
|
|
666
704
|
);
|
|
667
705
|
const url = `${baseUrl}/api/public/@${handle}/${slug}`;
|
|
668
|
-
return
|
|
669
|
-
|
|
706
|
+
return pipe4(
|
|
707
|
+
Effect4.tryPromise({
|
|
670
708
|
try: () => fetch(url, { method: "GET" }),
|
|
671
709
|
catch: (e) => new NetworkError({
|
|
672
710
|
message: `Failed to connect to ${baseUrl}`,
|
|
673
711
|
cause: e
|
|
674
712
|
})
|
|
675
713
|
}),
|
|
676
|
-
|
|
677
|
-
(response) =>
|
|
678
|
-
|
|
714
|
+
Effect4.flatMap(
|
|
715
|
+
(response) => pipe4(
|
|
716
|
+
Effect4.tryPromise({
|
|
679
717
|
try: () => response.json(),
|
|
680
718
|
catch: () => new NetworkError({ message: "Failed to parse API response" })
|
|
681
719
|
}),
|
|
682
|
-
|
|
720
|
+
Effect4.flatMap(
|
|
683
721
|
(json) => handlePublicApiResponse(response, json)
|
|
684
722
|
)
|
|
685
723
|
)
|
|
@@ -695,60 +733,73 @@ var init_api = __esm({
|
|
|
695
733
|
if (ruleIds && ruleIds.length > 0) {
|
|
696
734
|
url.searchParams.set("ruleIds", ruleIds.join(","));
|
|
697
735
|
}
|
|
698
|
-
return
|
|
699
|
-
|
|
736
|
+
return pipe4(
|
|
737
|
+
Effect4.tryPromise({
|
|
700
738
|
try: () => fetch(url.toString(), { method: "GET" }),
|
|
701
739
|
catch: (e) => new NetworkError({
|
|
702
740
|
message: `Failed to connect to ${baseUrl}`,
|
|
703
741
|
cause: e
|
|
704
742
|
})
|
|
705
743
|
}),
|
|
706
|
-
|
|
707
|
-
(response) =>
|
|
708
|
-
|
|
744
|
+
Effect4.flatMap(
|
|
745
|
+
(response) => pipe4(
|
|
746
|
+
Effect4.tryPromise({
|
|
709
747
|
try: () => response.json(),
|
|
710
748
|
catch: () => new NetworkError({ message: "Failed to parse API response" })
|
|
711
749
|
}),
|
|
712
|
-
|
|
750
|
+
Effect4.flatMap(
|
|
713
751
|
(json) => handlePublicApiResponse(response, json)
|
|
714
752
|
)
|
|
715
753
|
)
|
|
716
754
|
)
|
|
717
755
|
);
|
|
718
756
|
};
|
|
719
|
-
fetchPublicMetadataAsync = (handle, slug, serverUrl) =>
|
|
720
|
-
fetchPublicExportAsync = (handle, slug, ruleIds, serverUrl) =>
|
|
721
|
-
validateApiKey = (apiKey, serverUrl) =>
|
|
722
|
-
|
|
723
|
-
try:
|
|
757
|
+
fetchPublicMetadataAsync = (handle, slug, serverUrl) => Effect4.runPromise(fetchPublicMetadata(handle, slug, serverUrl));
|
|
758
|
+
fetchPublicExportAsync = (handle, slug, ruleIds, serverUrl) => Effect4.runPromise(fetchPublicExport(handle, slug, ruleIds, serverUrl));
|
|
759
|
+
validateApiKey = (apiKey, serverUrl) => pipe4(
|
|
760
|
+
Effect4.try({
|
|
761
|
+
try: () => {
|
|
724
762
|
const baseUrl = serverUrl ?? "https://braid.cloud";
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
"Content-Type": "application/json"
|
|
732
|
-
}
|
|
733
|
-
});
|
|
734
|
-
return response.status !== 401;
|
|
763
|
+
if (!(isTruthy(process.env[ALLOW_UNTRUSTED_SERVER_ENV]) || isTrustedApiServerUrl(baseUrl))) {
|
|
764
|
+
throw new NetworkError({
|
|
765
|
+
message: `Untrusted server URL '${baseUrl}'. Set ${ALLOW_UNTRUSTED_SERVER_ENV}=true to override.`
|
|
766
|
+
});
|
|
767
|
+
}
|
|
768
|
+
return baseUrl;
|
|
735
769
|
},
|
|
736
|
-
catch: (e) => new NetworkError({
|
|
737
|
-
|
|
738
|
-
|
|
770
|
+
catch: (e) => e instanceof NetworkError ? e : new NetworkError({ message: "Invalid server URL" })
|
|
771
|
+
}),
|
|
772
|
+
Effect4.flatMap(
|
|
773
|
+
(baseUrl) => Effect4.tryPromise({
|
|
774
|
+
try: async () => {
|
|
775
|
+
const url = buildApiUrl(baseUrl, "/api/skills/export");
|
|
776
|
+
url.searchParams.set("profile", "default");
|
|
777
|
+
const response = await fetch(url.toString(), {
|
|
778
|
+
method: "GET",
|
|
779
|
+
headers: {
|
|
780
|
+
Authorization: `Bearer ${apiKey}`,
|
|
781
|
+
"Content-Type": "application/json"
|
|
782
|
+
}
|
|
783
|
+
});
|
|
784
|
+
return response.status !== 401;
|
|
785
|
+
},
|
|
786
|
+
catch: (e) => new NetworkError({
|
|
787
|
+
message: `Failed to connect to ${baseUrl}`,
|
|
788
|
+
cause: e
|
|
789
|
+
})
|
|
739
790
|
})
|
|
740
|
-
|
|
791
|
+
)
|
|
741
792
|
);
|
|
742
|
-
fetchSkillsAsync = (options) =>
|
|
743
|
-
validateApiKeyAsync = (apiKey, serverUrl) =>
|
|
744
|
-
fetchScopeOptionsAsync = (options = {}) =>
|
|
745
|
-
fetchRuleOptionsAsync = (options = {}) =>
|
|
746
|
-
runLifecycleCommandAsync = (request, options = {}) =>
|
|
793
|
+
fetchSkillsAsync = (options) => Effect4.runPromise(fetchSkills(options));
|
|
794
|
+
validateApiKeyAsync = (apiKey, serverUrl) => Effect4.runPromise(validateApiKey(apiKey, serverUrl));
|
|
795
|
+
fetchScopeOptionsAsync = (options = {}) => Effect4.runPromise(fetchScopeOptions(options));
|
|
796
|
+
fetchRuleOptionsAsync = (options = {}) => Effect4.runPromise(fetchRuleOptions(options));
|
|
797
|
+
runLifecycleCommandAsync = (request, options = {}) => Effect4.runPromise(runLifecycleCommand(request, options));
|
|
747
798
|
}
|
|
748
799
|
});
|
|
749
800
|
|
|
750
801
|
// src/lib/tui.ts
|
|
751
|
-
import
|
|
802
|
+
import process4 from "process";
|
|
752
803
|
import {
|
|
753
804
|
cancel as clackCancel,
|
|
754
805
|
confirm as clackConfirm,
|
|
@@ -773,19 +824,19 @@ function spinner() {
|
|
|
773
824
|
return {
|
|
774
825
|
start: (message) => {
|
|
775
826
|
if (message) {
|
|
776
|
-
|
|
827
|
+
process4.stdout.write(`${message}
|
|
777
828
|
`);
|
|
778
829
|
}
|
|
779
830
|
},
|
|
780
831
|
stop: (message) => {
|
|
781
832
|
if (message) {
|
|
782
|
-
|
|
833
|
+
process4.stdout.write(`${message}
|
|
783
834
|
`);
|
|
784
835
|
}
|
|
785
836
|
},
|
|
786
837
|
message: (message) => {
|
|
787
838
|
if (message) {
|
|
788
|
-
|
|
839
|
+
process4.stdout.write(`${message}
|
|
789
840
|
`);
|
|
790
841
|
}
|
|
791
842
|
}
|
|
@@ -795,7 +846,7 @@ function intro(message) {
|
|
|
795
846
|
if (isTTY) {
|
|
796
847
|
clackIntro(message);
|
|
797
848
|
} else {
|
|
798
|
-
|
|
849
|
+
process4.stdout.write(`
|
|
799
850
|
${message}
|
|
800
851
|
`);
|
|
801
852
|
}
|
|
@@ -804,7 +855,7 @@ function outro(message) {
|
|
|
804
855
|
if (isTTY) {
|
|
805
856
|
clackOutro(message);
|
|
806
857
|
} else {
|
|
807
|
-
|
|
858
|
+
process4.stdout.write(`${message}
|
|
808
859
|
|
|
809
860
|
`);
|
|
810
861
|
}
|
|
@@ -814,7 +865,7 @@ var init_tui = __esm({
|
|
|
814
865
|
"src/lib/tui.ts"() {
|
|
815
866
|
"use strict";
|
|
816
867
|
init_esm_shims();
|
|
817
|
-
isTTY = Boolean(
|
|
868
|
+
isTTY = Boolean(process4.stdout.isTTY);
|
|
818
869
|
cancel = clackCancel;
|
|
819
870
|
confirm = clackConfirm;
|
|
820
871
|
isCancel = clackIsCancel;
|
|
@@ -925,10 +976,10 @@ var scope_exports = {};
|
|
|
925
976
|
__export(scope_exports, {
|
|
926
977
|
scopeCommand: () => scopeCommand
|
|
927
978
|
});
|
|
928
|
-
import
|
|
979
|
+
import process5 from "process";
|
|
929
980
|
function exitCancelled(message) {
|
|
930
981
|
cancel(message);
|
|
931
|
-
|
|
982
|
+
process5.exit(0);
|
|
932
983
|
}
|
|
933
984
|
async function selectTargetFile(options) {
|
|
934
985
|
if (options.file) {
|
|
@@ -1276,7 +1327,7 @@ async function scopeCommand(options) {
|
|
|
1276
1327
|
} catch (error) {
|
|
1277
1328
|
loadSpinner.stop("Failed to load scope options");
|
|
1278
1329
|
log.error(error instanceof Error ? error.message : String(error));
|
|
1279
|
-
|
|
1330
|
+
process5.exit(1);
|
|
1280
1331
|
}
|
|
1281
1332
|
}
|
|
1282
1333
|
var init_scope = __esm({
|
|
@@ -1296,303 +1347,256 @@ init_esm_shims();
|
|
|
1296
1347
|
import { createRequire } from "module";
|
|
1297
1348
|
import { Command } from "commander";
|
|
1298
1349
|
|
|
1299
|
-
// src/commands/
|
|
1350
|
+
// src/commands/agents.ts
|
|
1300
1351
|
init_esm_shims();
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
import
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
message: "An API key is already configured. Replace it?",
|
|
1327
|
-
initialValue: false
|
|
1328
|
-
});
|
|
1329
|
-
if (isCancel(shouldReplace) || !shouldReplace) {
|
|
1330
|
-
outro("Auth cancelled.");
|
|
1331
|
-
return;
|
|
1332
|
-
}
|
|
1352
|
+
|
|
1353
|
+
// src/lib/agent-writer.ts
|
|
1354
|
+
init_esm_shims();
|
|
1355
|
+
import { mkdir, writeFile } from "fs/promises";
|
|
1356
|
+
import { dirname, resolve, sep } from "path";
|
|
1357
|
+
import { Data, Effect, pipe } from "effect";
|
|
1358
|
+
|
|
1359
|
+
// src/lib/agent-adapters.ts
|
|
1360
|
+
init_esm_shims();
|
|
1361
|
+
var NATIVE_AGENT_IDS = /* @__PURE__ */ new Set(["claude-code", "opencode"]);
|
|
1362
|
+
var MAPPED_AGENT_IDS = /* @__PURE__ */ new Set([
|
|
1363
|
+
"cursor",
|
|
1364
|
+
"windsurf",
|
|
1365
|
+
"cline",
|
|
1366
|
+
"roo",
|
|
1367
|
+
"codex"
|
|
1368
|
+
]);
|
|
1369
|
+
var resolveProfile = (agent) => {
|
|
1370
|
+
if (NATIVE_AGENT_IDS.has(agent.id)) {
|
|
1371
|
+
return {
|
|
1372
|
+
tier: "native",
|
|
1373
|
+
supportsGlobalInstall: Boolean(agent.agentsGlobalPath),
|
|
1374
|
+
supportsProjectInstall: Boolean(agent.agentsProjectPath),
|
|
1375
|
+
notes: "Native subagent/frontmatter format supported."
|
|
1376
|
+
};
|
|
1333
1377
|
}
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
return "API key should start with 'br_'";
|
|
1342
|
-
}
|
|
1343
|
-
return void 0;
|
|
1344
|
-
}
|
|
1345
|
-
});
|
|
1346
|
-
if (isCancel(apiKey)) {
|
|
1347
|
-
cancel("Auth cancelled.");
|
|
1348
|
-
process5.exit(0);
|
|
1378
|
+
if (MAPPED_AGENT_IDS.has(agent.id)) {
|
|
1379
|
+
return {
|
|
1380
|
+
tier: "mapped",
|
|
1381
|
+
supportsGlobalInstall: Boolean(agent.globalPath),
|
|
1382
|
+
supportsProjectInstall: Boolean(agent.projectPath),
|
|
1383
|
+
notes: "No native agent file format confirmed; install as compatibility artifacts."
|
|
1384
|
+
};
|
|
1349
1385
|
}
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
}
|
|
1356
|
-
authSpinner.stop(message);
|
|
1357
|
-
authSpinnerActive = false;
|
|
1386
|
+
return {
|
|
1387
|
+
tier: "compat",
|
|
1388
|
+
supportsGlobalInstall: Boolean(agent.globalPath),
|
|
1389
|
+
supportsProjectInstall: Boolean(agent.projectPath),
|
|
1390
|
+
notes: "Install compatibility output only, with capability warning surfaced to user."
|
|
1358
1391
|
};
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1392
|
+
};
|
|
1393
|
+
|
|
1394
|
+
// src/lib/agent-writer.ts
|
|
1395
|
+
var AgentWriteError = class extends Data.TaggedError("AgentWriteError") {
|
|
1396
|
+
};
|
|
1397
|
+
var isObjectRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1398
|
+
var slugify = (value) => value.toLowerCase().replace(/[^a-z0-9\s-]/g, "").replace(/\s+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
|
|
1399
|
+
var escapeYaml = (value) => value.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
1400
|
+
var toYamlLines = (key, value, indent = 0) => {
|
|
1401
|
+
const prefix = " ".repeat(indent);
|
|
1402
|
+
const nestedPrefix = " ".repeat(indent + 2);
|
|
1403
|
+
if (typeof value === "string") {
|
|
1404
|
+
return [`${prefix}${key}: "${escapeYaml(value)}"`];
|
|
1405
|
+
}
|
|
1406
|
+
if (typeof value === "number" || typeof value === "boolean") {
|
|
1407
|
+
return [`${prefix}${key}: ${value}`];
|
|
1408
|
+
}
|
|
1409
|
+
if (Array.isArray(value)) {
|
|
1410
|
+
if (value.length === 0) {
|
|
1411
|
+
return [`${prefix}${key}: []`];
|
|
1374
1412
|
}
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1413
|
+
return [
|
|
1414
|
+
`${prefix}${key}:`,
|
|
1415
|
+
...value.map((item) => {
|
|
1416
|
+
if (typeof item === "string" || typeof item === "number" || typeof item === "boolean") {
|
|
1417
|
+
return `${nestedPrefix}- ${typeof item === "string" ? `"${escapeYaml(item)}"` : item}`;
|
|
1418
|
+
}
|
|
1419
|
+
if (isObjectRecord(item)) {
|
|
1420
|
+
const nested = Object.entries(item).flatMap(
|
|
1421
|
+
([nestedKey, nestedValue]) => toYamlLines(nestedKey, nestedValue, indent + 4)
|
|
1422
|
+
);
|
|
1423
|
+
return `${nestedPrefix}-
|
|
1424
|
+
${nested.join("\n")}`;
|
|
1425
|
+
}
|
|
1426
|
+
return `${nestedPrefix}- null`;
|
|
1427
|
+
})
|
|
1428
|
+
];
|
|
1429
|
+
}
|
|
1430
|
+
if (isObjectRecord(value)) {
|
|
1431
|
+
const entries = Object.entries(value);
|
|
1432
|
+
if (entries.length === 0) {
|
|
1433
|
+
return [`${prefix}${key}: {}`];
|
|
1378
1434
|
}
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
1386
|
-
log.error(`Failed to validate API key: ${message}`);
|
|
1387
|
-
process5.exit(1);
|
|
1435
|
+
return [
|
|
1436
|
+
`${prefix}${key}:`,
|
|
1437
|
+
...entries.flatMap(
|
|
1438
|
+
([nestedKey, nestedValue]) => toYamlLines(nestedKey, nestedValue, indent + 2)
|
|
1439
|
+
)
|
|
1440
|
+
];
|
|
1388
1441
|
}
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1442
|
+
return [];
|
|
1443
|
+
};
|
|
1444
|
+
var buildClaudeMarkdown = (spec) => {
|
|
1445
|
+
const lines = ["---"];
|
|
1446
|
+
lines.push(...toYamlLines("name", spec.name));
|
|
1447
|
+
lines.push(...toYamlLines("description", spec.description));
|
|
1448
|
+
if (spec.model) {
|
|
1449
|
+
lines.push(...toYamlLines("model", spec.model));
|
|
1395
1450
|
}
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
log.info(`Source: ${userConfigPath ?? CONFIG_FILE}`);
|
|
1399
|
-
}
|
|
1400
|
-
async function displayProjectConfig() {
|
|
1401
|
-
const projectConfigPath = await findProjectConfigFileAsync();
|
|
1402
|
-
if (projectConfigPath) {
|
|
1403
|
-
log.info(`Project config: ${projectConfigPath}`);
|
|
1451
|
+
if (spec.tools !== void 0) {
|
|
1452
|
+
lines.push(...toYamlLines("tools", spec.tools));
|
|
1404
1453
|
}
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
const hasOrgProjects = config.orgProjects && config.orgProjects.length > 0;
|
|
1408
|
-
const hasPersonalProjects = config.personalProjects && config.personalProjects.length > 0;
|
|
1409
|
-
if (!(config.profile || hasOrgProjects || hasPersonalProjects)) {
|
|
1410
|
-
return;
|
|
1454
|
+
if (spec.permission !== void 0) {
|
|
1455
|
+
lines.push(...toYamlLines("permissionMode", spec.permission));
|
|
1411
1456
|
}
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
log.info(`Default profile: ${config.profile}`);
|
|
1457
|
+
if (spec.steps !== void 0) {
|
|
1458
|
+
lines.push(...toYamlLines("maxTurns", spec.steps));
|
|
1415
1459
|
}
|
|
1416
|
-
if (
|
|
1417
|
-
|
|
1460
|
+
if (spec.temperature !== void 0) {
|
|
1461
|
+
lines.push(...toYamlLines("temperature", spec.temperature));
|
|
1418
1462
|
}
|
|
1419
|
-
if (
|
|
1420
|
-
|
|
1463
|
+
if (spec.linkedSkillNames && spec.linkedSkillNames.length > 0) {
|
|
1464
|
+
lines.push(...toYamlLines("skills", spec.linkedSkillNames));
|
|
1421
1465
|
}
|
|
1422
|
-
if (
|
|
1423
|
-
|
|
1466
|
+
if (spec.additional) {
|
|
1467
|
+
for (const [key, value] of Object.entries(spec.additional)) {
|
|
1468
|
+
lines.push(...toYamlLines(key, value));
|
|
1469
|
+
}
|
|
1424
1470
|
}
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
);
|
|
1433
|
-
return;
|
|
1471
|
+
lines.push("---", "", spec.prompt.trim(), "");
|
|
1472
|
+
return lines.join("\n");
|
|
1473
|
+
};
|
|
1474
|
+
var buildOpenCodeMarkdown = (spec) => {
|
|
1475
|
+
const lines = ["---"];
|
|
1476
|
+
lines.push(...toYamlLines("description", spec.description));
|
|
1477
|
+
if (spec.mode) {
|
|
1478
|
+
lines.push(...toYamlLines("mode", spec.mode));
|
|
1434
1479
|
}
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
await displayProjectConfig();
|
|
1438
|
-
displayResolvedSettings(config);
|
|
1439
|
-
}
|
|
1440
|
-
async function authLogoutCommand() {
|
|
1441
|
-
const { clearApiKeyAsync: clearApiKeyAsync2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
1442
|
-
await clearApiKeyAsync2();
|
|
1443
|
-
log.success("Logged out. API key removed from config.");
|
|
1444
|
-
}
|
|
1445
|
-
|
|
1446
|
-
// src/commands/discover.ts
|
|
1447
|
-
init_esm_shims();
|
|
1448
|
-
init_api();
|
|
1449
|
-
init_config();
|
|
1450
|
-
init_tui();
|
|
1451
|
-
import process6 from "process";
|
|
1452
|
-
var parseCsv = (input) => {
|
|
1453
|
-
if (!input) {
|
|
1454
|
-
return void 0;
|
|
1480
|
+
if (spec.model) {
|
|
1481
|
+
lines.push(...toYamlLines("model", spec.model));
|
|
1455
1482
|
}
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
};
|
|
1459
|
-
var writeJson = (value) => {
|
|
1460
|
-
process6.stdout.write(`${JSON.stringify(value, null, 2)}
|
|
1461
|
-
`);
|
|
1462
|
-
};
|
|
1463
|
-
var exitWithError = (error) => {
|
|
1464
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
1465
|
-
log.error(message);
|
|
1466
|
-
process6.exit(1);
|
|
1467
|
-
};
|
|
1468
|
-
var applyCommonOptions = (base, options) => ({
|
|
1469
|
-
...base,
|
|
1470
|
-
...options.server ? { serverUrl: options.server } : {},
|
|
1471
|
-
...options.apiKey ? { apiKey: options.apiKey } : {}
|
|
1472
|
-
});
|
|
1473
|
-
var applyOptionalString = (target, key, value) => {
|
|
1474
|
-
if (value) {
|
|
1475
|
-
target[key] = value;
|
|
1483
|
+
if (spec.tools !== void 0) {
|
|
1484
|
+
lines.push(...toYamlLines("tools", spec.tools));
|
|
1476
1485
|
}
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1486
|
+
if (spec.permission !== void 0) {
|
|
1487
|
+
lines.push(...toYamlLines("permission", spec.permission));
|
|
1488
|
+
}
|
|
1489
|
+
if (spec.steps !== void 0) {
|
|
1490
|
+
lines.push(...toYamlLines("steps", spec.steps));
|
|
1481
1491
|
}
|
|
1492
|
+
if (spec.temperature !== void 0) {
|
|
1493
|
+
lines.push(...toYamlLines("temperature", spec.temperature));
|
|
1494
|
+
}
|
|
1495
|
+
if (spec.topP !== void 0) {
|
|
1496
|
+
lines.push(...toYamlLines("top_p", spec.topP));
|
|
1497
|
+
}
|
|
1498
|
+
if (spec.hidden !== void 0) {
|
|
1499
|
+
lines.push(...toYamlLines("hidden", spec.hidden));
|
|
1500
|
+
}
|
|
1501
|
+
if (spec.color) {
|
|
1502
|
+
lines.push(...toYamlLines("color", spec.color));
|
|
1503
|
+
}
|
|
1504
|
+
if (spec.additional) {
|
|
1505
|
+
for (const [key, value] of Object.entries(spec.additional)) {
|
|
1506
|
+
lines.push(...toYamlLines(key, value));
|
|
1507
|
+
}
|
|
1508
|
+
}
|
|
1509
|
+
lines.push("---", "", spec.prompt.trim(), "");
|
|
1510
|
+
return lines.join("\n");
|
|
1482
1511
|
};
|
|
1483
|
-
var
|
|
1484
|
-
|
|
1485
|
-
|
|
1512
|
+
var buildCompatMarkdown = (spec, source) => [
|
|
1513
|
+
"# Compatibility Agent",
|
|
1514
|
+
"",
|
|
1515
|
+
`Source: ${source}`,
|
|
1516
|
+
`Name: ${spec.name}`,
|
|
1517
|
+
"",
|
|
1518
|
+
spec.prompt.trim(),
|
|
1519
|
+
""
|
|
1520
|
+
].join("\n");
|
|
1521
|
+
var assertWithinBase = (basePath, filename) => {
|
|
1522
|
+
const resolvedBase = resolve(basePath);
|
|
1523
|
+
const resolvedPath = resolve(basePath, filename);
|
|
1524
|
+
if (resolvedPath !== resolvedBase && !resolvedPath.startsWith(`${resolvedBase}${sep}`)) {
|
|
1525
|
+
throw new Error(`Path traversal detected: ${filename}`);
|
|
1486
1526
|
}
|
|
1527
|
+
return resolvedPath;
|
|
1487
1528
|
};
|
|
1488
|
-
|
|
1489
|
-
try {
|
|
1490
|
-
const
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1529
|
+
var writeSingleAgent = (installPath, platform2, spec) => Effect.tryPromise({
|
|
1530
|
+
try: async () => {
|
|
1531
|
+
const profile = resolveProfile(platform2);
|
|
1532
|
+
const fileStem = slugify(spec.name) || "agent";
|
|
1533
|
+
const filename = `${fileStem}.md`;
|
|
1534
|
+
const fullPath = assertWithinBase(installPath, filename);
|
|
1535
|
+
await mkdir(dirname(fullPath), { recursive: true });
|
|
1536
|
+
const warnings = [];
|
|
1537
|
+
let content;
|
|
1538
|
+
if (platform2.id === "claude-code") {
|
|
1539
|
+
if (spec.mode === "primary") {
|
|
1540
|
+
warnings.push(
|
|
1541
|
+
"Claude adapter does not support primary mode; using subagent semantics."
|
|
1542
|
+
);
|
|
1543
|
+
}
|
|
1544
|
+
content = buildClaudeMarkdown(spec);
|
|
1545
|
+
} else if (platform2.id === "opencode") {
|
|
1546
|
+
content = buildOpenCodeMarkdown(spec);
|
|
1547
|
+
} else {
|
|
1548
|
+
warnings.push(
|
|
1549
|
+
`Platform ${platform2.id} uses ${profile.tier} adapter with compatibility output.`
|
|
1550
|
+
);
|
|
1551
|
+
content = buildCompatMarkdown(spec, platform2.name);
|
|
1496
1552
|
}
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
try {
|
|
1533
|
-
const result = await fetchRuleOptionsAsync(
|
|
1534
|
-
await buildRulesRequest(options)
|
|
1535
|
-
);
|
|
1536
|
-
if (options.json) {
|
|
1537
|
-
writeJson(result);
|
|
1538
|
-
return;
|
|
1539
|
-
}
|
|
1540
|
-
if (result.rules.length === 0) {
|
|
1541
|
-
log.info("No rules found.");
|
|
1542
|
-
return;
|
|
1543
|
-
}
|
|
1544
|
-
for (const rule of result.rules) {
|
|
1545
|
-
log.info(`${rule.id} ${rule.title}`);
|
|
1546
|
-
}
|
|
1547
|
-
} catch (error) {
|
|
1548
|
-
exitWithError(error);
|
|
1549
|
-
}
|
|
1550
|
-
}
|
|
1551
|
-
var buildSkillsRequest = async (options) => {
|
|
1552
|
-
const config = await loadMergedConfigAsync();
|
|
1553
|
-
const orgProjects = parseCsv(options.orgProjects) ?? config.orgProjects;
|
|
1554
|
-
const personalProjects = parseCsv(options.personalProjects) ?? config.personalProjects;
|
|
1555
|
-
const request = applyCommonOptions({}, options);
|
|
1556
|
-
applyOptionalString(request, "profile", options.profile ?? config.profile);
|
|
1557
|
-
applyOptionalArray(request, "orgProjects", orgProjects);
|
|
1558
|
-
applyOptionalArray(request, "personalProjects", personalProjects);
|
|
1559
|
-
applyOptionalBoolean(request, "includeUserGlobal", options.includeUserGlobal);
|
|
1560
|
-
applyOptionalBoolean(request, "includeOrgGlobal", options.includeOrgGlobal);
|
|
1561
|
-
return request;
|
|
1562
|
-
};
|
|
1563
|
-
async function skillsListCommand(options) {
|
|
1564
|
-
try {
|
|
1565
|
-
const result = await fetchSkillsAsync(await buildSkillsRequest(options));
|
|
1566
|
-
if (options.json) {
|
|
1567
|
-
writeJson(result);
|
|
1568
|
-
return;
|
|
1569
|
-
}
|
|
1570
|
-
if (result.skills.length === 0) {
|
|
1571
|
-
log.info("No skills found.");
|
|
1572
|
-
return;
|
|
1573
|
-
}
|
|
1574
|
-
for (const skill of result.skills) {
|
|
1575
|
-
log.info(`${skill.name}`);
|
|
1576
|
-
}
|
|
1577
|
-
} catch (error) {
|
|
1578
|
-
exitWithError(error);
|
|
1579
|
-
}
|
|
1580
|
-
}
|
|
1581
|
-
|
|
1582
|
-
// src/commands/install.ts
|
|
1583
|
-
init_esm_shims();
|
|
1553
|
+
await writeFile(fullPath, content, "utf-8");
|
|
1554
|
+
return { written: fullPath, warnings };
|
|
1555
|
+
},
|
|
1556
|
+
catch: (cause) => new AgentWriteError({ path: installPath, operation: "write", cause })
|
|
1557
|
+
});
|
|
1558
|
+
var writeAgentsForPlatform = (platform2, specs, installPath) => pipe(
|
|
1559
|
+
Effect.forEach(
|
|
1560
|
+
specs,
|
|
1561
|
+
(spec) => pipe(
|
|
1562
|
+
writeSingleAgent(installPath, platform2, spec),
|
|
1563
|
+
Effect.map((result) => ({
|
|
1564
|
+
success: true,
|
|
1565
|
+
written: result.written,
|
|
1566
|
+
warnings: result.warnings
|
|
1567
|
+
})),
|
|
1568
|
+
Effect.catchAll(
|
|
1569
|
+
(error) => Effect.succeed({
|
|
1570
|
+
success: false,
|
|
1571
|
+
error: error.cause instanceof Error ? error.cause.message : String(error.cause),
|
|
1572
|
+
specName: spec.name
|
|
1573
|
+
})
|
|
1574
|
+
)
|
|
1575
|
+
),
|
|
1576
|
+
{ concurrency: "unbounded" }
|
|
1577
|
+
),
|
|
1578
|
+
Effect.map((results) => {
|
|
1579
|
+
const written = results.filter((r) => r.success).map((r) => r.written).sort();
|
|
1580
|
+
const warnings = results.filter((r) => r.success).flatMap((r) => r.warnings);
|
|
1581
|
+
const errors = results.filter(
|
|
1582
|
+
(r) => !r.success
|
|
1583
|
+
).map((r) => ({ agent: r.specName, error: r.error }));
|
|
1584
|
+
return { written, warnings, errors };
|
|
1585
|
+
})
|
|
1586
|
+
);
|
|
1587
|
+
var writeAgentsForPlatformAsync = (platform2, specs, installPath) => Effect.runPromise(writeAgentsForPlatform(platform2, specs, installPath));
|
|
1584
1588
|
|
|
1585
1589
|
// src/lib/agents.ts
|
|
1586
1590
|
init_esm_shims();
|
|
1587
1591
|
import { access, constants } from "fs/promises";
|
|
1588
|
-
import { homedir
|
|
1589
|
-
import { join
|
|
1590
|
-
import
|
|
1591
|
-
import { Effect as
|
|
1592
|
-
var home =
|
|
1592
|
+
import { homedir } from "os";
|
|
1593
|
+
import { join } from "path";
|
|
1594
|
+
import process2 from "process";
|
|
1595
|
+
import { Effect as Effect2, pipe as pipe2 } from "effect";
|
|
1596
|
+
var home = homedir();
|
|
1593
1597
|
var vscodeExtSettingsPath = (extensionId, filename) => {
|
|
1594
|
-
if (
|
|
1595
|
-
return
|
|
1598
|
+
if (process2.platform === "darwin") {
|
|
1599
|
+
return join(
|
|
1596
1600
|
home,
|
|
1597
1601
|
"Library",
|
|
1598
1602
|
"Application Support",
|
|
@@ -1604,9 +1608,9 @@ var vscodeExtSettingsPath = (extensionId, filename) => {
|
|
|
1604
1608
|
filename
|
|
1605
1609
|
);
|
|
1606
1610
|
}
|
|
1607
|
-
if (
|
|
1608
|
-
const appData =
|
|
1609
|
-
return
|
|
1611
|
+
if (process2.platform === "win32") {
|
|
1612
|
+
const appData = process2.env.APPDATA ?? join(home, "AppData", "Roaming");
|
|
1613
|
+
return join(
|
|
1610
1614
|
appData,
|
|
1611
1615
|
"Code",
|
|
1612
1616
|
"User",
|
|
@@ -1616,7 +1620,7 @@ var vscodeExtSettingsPath = (extensionId, filename) => {
|
|
|
1616
1620
|
filename
|
|
1617
1621
|
);
|
|
1618
1622
|
}
|
|
1619
|
-
return
|
|
1623
|
+
return join(
|
|
1620
1624
|
home,
|
|
1621
1625
|
".config",
|
|
1622
1626
|
"Code",
|
|
@@ -1628,8 +1632,8 @@ var vscodeExtSettingsPath = (extensionId, filename) => {
|
|
|
1628
1632
|
);
|
|
1629
1633
|
};
|
|
1630
1634
|
var claudeDesktopConfigPath = () => {
|
|
1631
|
-
if (
|
|
1632
|
-
return
|
|
1635
|
+
if (process2.platform === "darwin") {
|
|
1636
|
+
return join(
|
|
1633
1637
|
home,
|
|
1634
1638
|
"Library",
|
|
1635
1639
|
"Application Support",
|
|
@@ -1637,46 +1641,48 @@ var claudeDesktopConfigPath = () => {
|
|
|
1637
1641
|
"claude_desktop_config.json"
|
|
1638
1642
|
);
|
|
1639
1643
|
}
|
|
1640
|
-
if (
|
|
1641
|
-
const appData =
|
|
1642
|
-
return
|
|
1644
|
+
if (process2.platform === "win32") {
|
|
1645
|
+
const appData = process2.env.APPDATA ?? join(home, "AppData", "Roaming");
|
|
1646
|
+
return join(appData, "Claude", "claude_desktop_config.json");
|
|
1643
1647
|
}
|
|
1644
|
-
return
|
|
1648
|
+
return join(home, ".config", "Claude", "claude_desktop_config.json");
|
|
1645
1649
|
};
|
|
1646
1650
|
var AGENTS = [
|
|
1647
1651
|
{
|
|
1648
1652
|
id: "amp",
|
|
1649
1653
|
name: "Amp",
|
|
1650
1654
|
projectPath: ".agents/skills",
|
|
1651
|
-
globalPath:
|
|
1655
|
+
globalPath: join(home, ".config", "agents", "skills"),
|
|
1652
1656
|
mcpProjectConfigPath: ".amp/mcp.json",
|
|
1653
|
-
mcpGlobalConfigPath:
|
|
1657
|
+
mcpGlobalConfigPath: join(home, ".amp", "mcp.json")
|
|
1654
1658
|
},
|
|
1655
1659
|
{
|
|
1656
1660
|
id: "kimi-cli",
|
|
1657
1661
|
name: "Kimi Code CLI",
|
|
1658
1662
|
projectPath: ".agents/skills",
|
|
1659
|
-
globalPath:
|
|
1663
|
+
globalPath: join(home, ".config", "agents", "skills"),
|
|
1660
1664
|
mcpProjectConfigPath: ".agents/mcp.json",
|
|
1661
|
-
mcpGlobalConfigPath:
|
|
1665
|
+
mcpGlobalConfigPath: join(home, ".config", "agents", "mcp.json")
|
|
1662
1666
|
},
|
|
1663
1667
|
{
|
|
1664
1668
|
id: "antigravity",
|
|
1665
1669
|
name: "Antigravity",
|
|
1666
1670
|
projectPath: ".agent/skills",
|
|
1667
|
-
globalPath:
|
|
1671
|
+
globalPath: join(home, ".gemini", "antigravity", "global_skills"),
|
|
1668
1672
|
mcpProjectConfigPath: ".agent/mcp.json",
|
|
1669
|
-
mcpGlobalConfigPath:
|
|
1673
|
+
mcpGlobalConfigPath: join(home, ".gemini", "antigravity", "mcp.json")
|
|
1670
1674
|
},
|
|
1671
1675
|
{
|
|
1672
1676
|
id: "claude-code",
|
|
1673
1677
|
name: "Claude Code",
|
|
1674
1678
|
projectPath: ".claude/skills",
|
|
1675
|
-
globalPath:
|
|
1679
|
+
globalPath: join(home, ".claude", "skills"),
|
|
1680
|
+
agentsProjectPath: ".claude/agents",
|
|
1681
|
+
agentsGlobalPath: join(home, ".claude", "agents"),
|
|
1676
1682
|
projectMarkerPath: ".claude",
|
|
1677
|
-
globalMarkerPath:
|
|
1683
|
+
globalMarkerPath: join(home, ".claude"),
|
|
1678
1684
|
rulesProjectPath: ".claude/rules",
|
|
1679
|
-
rulesGlobalPath:
|
|
1685
|
+
rulesGlobalPath: join(home, ".claude", "rules"),
|
|
1680
1686
|
ruleFormat: "markdown-dir",
|
|
1681
1687
|
mcpProjectConfigPath: ".mcp.json",
|
|
1682
1688
|
mcpEntryStyle: "typed-stdio"
|
|
@@ -1692,15 +1698,15 @@ var AGENTS = [
|
|
|
1692
1698
|
id: "moltbot",
|
|
1693
1699
|
name: "Moltbot",
|
|
1694
1700
|
projectPath: "skills",
|
|
1695
|
-
globalPath:
|
|
1701
|
+
globalPath: join(home, ".moltbot", "skills"),
|
|
1696
1702
|
mcpProjectConfigPath: "mcp.json",
|
|
1697
|
-
mcpGlobalConfigPath:
|
|
1703
|
+
mcpGlobalConfigPath: join(home, ".moltbot", "mcp.json")
|
|
1698
1704
|
},
|
|
1699
1705
|
{
|
|
1700
1706
|
id: "cline",
|
|
1701
1707
|
name: "Cline",
|
|
1702
1708
|
projectPath: ".cline/skills",
|
|
1703
|
-
globalPath:
|
|
1709
|
+
globalPath: join(home, ".cline", "skills"),
|
|
1704
1710
|
rulesProjectPath: ".clinerules",
|
|
1705
1711
|
ruleFormat: "append-single",
|
|
1706
1712
|
mcpGlobalConfigPath: vscodeExtSettingsPath(
|
|
@@ -1713,73 +1719,73 @@ var AGENTS = [
|
|
|
1713
1719
|
id: "codebuddy",
|
|
1714
1720
|
name: "CodeBuddy",
|
|
1715
1721
|
projectPath: ".codebuddy/skills",
|
|
1716
|
-
globalPath:
|
|
1722
|
+
globalPath: join(home, ".codebuddy", "skills"),
|
|
1717
1723
|
mcpProjectConfigPath: ".codebuddy/mcp.json",
|
|
1718
|
-
mcpGlobalConfigPath:
|
|
1724
|
+
mcpGlobalConfigPath: join(home, ".codebuddy", "mcp.json")
|
|
1719
1725
|
},
|
|
1720
1726
|
{
|
|
1721
1727
|
id: "codex",
|
|
1722
1728
|
name: "Codex",
|
|
1723
1729
|
projectPath: ".codex/skills",
|
|
1724
|
-
globalPath:
|
|
1730
|
+
globalPath: join(home, ".codex", "skills"),
|
|
1725
1731
|
mcpProjectConfigPath: ".codex/mcp.json",
|
|
1726
|
-
mcpGlobalConfigPath:
|
|
1732
|
+
mcpGlobalConfigPath: join(home, ".codex", "mcp.json")
|
|
1727
1733
|
},
|
|
1728
1734
|
{
|
|
1729
1735
|
id: "command-code",
|
|
1730
1736
|
name: "Command Code",
|
|
1731
1737
|
projectPath: ".commandcode/skills",
|
|
1732
|
-
globalPath:
|
|
1738
|
+
globalPath: join(home, ".commandcode", "skills"),
|
|
1733
1739
|
mcpProjectConfigPath: ".commandcode/mcp.json",
|
|
1734
|
-
mcpGlobalConfigPath:
|
|
1740
|
+
mcpGlobalConfigPath: join(home, ".commandcode", "mcp.json")
|
|
1735
1741
|
},
|
|
1736
1742
|
{
|
|
1737
1743
|
id: "continue",
|
|
1738
1744
|
name: "Continue",
|
|
1739
1745
|
projectPath: ".continue/skills",
|
|
1740
|
-
globalPath:
|
|
1746
|
+
globalPath: join(home, ".continue", "skills"),
|
|
1741
1747
|
mcpProjectConfigPath: ".continue/mcp.json",
|
|
1742
|
-
mcpGlobalConfigPath:
|
|
1748
|
+
mcpGlobalConfigPath: join(home, ".continue", "mcp.json")
|
|
1743
1749
|
},
|
|
1744
1750
|
{
|
|
1745
1751
|
id: "crush",
|
|
1746
1752
|
name: "Crush",
|
|
1747
1753
|
projectPath: ".crush/skills",
|
|
1748
|
-
globalPath:
|
|
1754
|
+
globalPath: join(home, ".config", "crush", "skills"),
|
|
1749
1755
|
mcpProjectConfigPath: ".crush/mcp.json",
|
|
1750
|
-
mcpGlobalConfigPath:
|
|
1756
|
+
mcpGlobalConfigPath: join(home, ".config", "crush", "mcp.json")
|
|
1751
1757
|
},
|
|
1752
1758
|
{
|
|
1753
1759
|
id: "cursor",
|
|
1754
1760
|
name: "Cursor",
|
|
1755
1761
|
projectPath: ".cursor/skills",
|
|
1756
|
-
globalPath:
|
|
1762
|
+
globalPath: join(home, ".cursor", "skills"),
|
|
1757
1763
|
rulesProjectPath: ".cursor/rules",
|
|
1758
1764
|
ruleFormat: "mdc",
|
|
1759
1765
|
mcpProjectConfigPath: ".cursor/mcp.json",
|
|
1760
|
-
mcpGlobalConfigPath:
|
|
1766
|
+
mcpGlobalConfigPath: join(home, ".cursor", "mcp.json")
|
|
1761
1767
|
},
|
|
1762
1768
|
{
|
|
1763
1769
|
id: "droid",
|
|
1764
1770
|
name: "Droid",
|
|
1765
1771
|
projectPath: ".factory/skills",
|
|
1766
|
-
globalPath:
|
|
1772
|
+
globalPath: join(home, ".factory", "skills"),
|
|
1767
1773
|
mcpProjectConfigPath: ".factory/mcp.json",
|
|
1768
|
-
mcpGlobalConfigPath:
|
|
1774
|
+
mcpGlobalConfigPath: join(home, ".factory", "mcp.json")
|
|
1769
1775
|
},
|
|
1770
1776
|
{
|
|
1771
1777
|
id: "gemini-cli",
|
|
1772
1778
|
name: "Gemini CLI",
|
|
1773
1779
|
projectPath: ".gemini/skills",
|
|
1774
|
-
globalPath:
|
|
1780
|
+
globalPath: join(home, ".gemini", "skills"),
|
|
1775
1781
|
mcpProjectConfigPath: ".gemini/mcp.json",
|
|
1776
|
-
mcpGlobalConfigPath:
|
|
1782
|
+
mcpGlobalConfigPath: join(home, ".gemini", "mcp.json")
|
|
1777
1783
|
},
|
|
1778
1784
|
{
|
|
1779
1785
|
id: "github-copilot",
|
|
1780
1786
|
name: "GitHub Copilot",
|
|
1781
1787
|
projectPath: ".github/skills",
|
|
1782
|
-
globalPath:
|
|
1788
|
+
globalPath: join(home, ".copilot", "skills"),
|
|
1783
1789
|
rulesProjectPath: ".github/copilot-instructions.md",
|
|
1784
1790
|
ruleFormat: "append-single",
|
|
1785
1791
|
mcpProjectConfigPath: ".vscode/mcp.json",
|
|
@@ -1790,22 +1796,22 @@ var AGENTS = [
|
|
|
1790
1796
|
id: "goose",
|
|
1791
1797
|
name: "Goose",
|
|
1792
1798
|
projectPath: ".goose/skills",
|
|
1793
|
-
globalPath:
|
|
1794
|
-
mcpGlobalConfigPath:
|
|
1799
|
+
globalPath: join(home, ".config", "goose", "skills"),
|
|
1800
|
+
mcpGlobalConfigPath: join(home, ".config", "goose", "mcp.json")
|
|
1795
1801
|
},
|
|
1796
1802
|
{
|
|
1797
1803
|
id: "junie",
|
|
1798
1804
|
name: "Junie",
|
|
1799
1805
|
projectPath: ".junie/skills",
|
|
1800
|
-
globalPath:
|
|
1806
|
+
globalPath: join(home, ".junie", "skills"),
|
|
1801
1807
|
mcpProjectConfigPath: ".junie/mcp.json",
|
|
1802
|
-
mcpGlobalConfigPath:
|
|
1808
|
+
mcpGlobalConfigPath: join(home, ".junie", "mcp.json")
|
|
1803
1809
|
},
|
|
1804
1810
|
{
|
|
1805
1811
|
id: "kilo",
|
|
1806
1812
|
name: "Kilo Code",
|
|
1807
1813
|
projectPath: ".kilocode/skills",
|
|
1808
|
-
globalPath:
|
|
1814
|
+
globalPath: join(home, ".kilocode", "skills"),
|
|
1809
1815
|
mcpGlobalConfigPath: vscodeExtSettingsPath(
|
|
1810
1816
|
"kilocode.kilo-code",
|
|
1811
1817
|
"mcp_settings.json"
|
|
@@ -1816,81 +1822,83 @@ var AGENTS = [
|
|
|
1816
1822
|
id: "kiro-cli",
|
|
1817
1823
|
name: "Kiro CLI",
|
|
1818
1824
|
projectPath: ".kiro/skills",
|
|
1819
|
-
globalPath:
|
|
1825
|
+
globalPath: join(home, ".kiro", "skills"),
|
|
1820
1826
|
mcpProjectConfigPath: ".kiro/mcp.json",
|
|
1821
|
-
mcpGlobalConfigPath:
|
|
1827
|
+
mcpGlobalConfigPath: join(home, ".kiro", "mcp.json")
|
|
1822
1828
|
},
|
|
1823
1829
|
{
|
|
1824
1830
|
id: "kode",
|
|
1825
1831
|
name: "Kode",
|
|
1826
1832
|
projectPath: ".kode/skills",
|
|
1827
|
-
globalPath:
|
|
1833
|
+
globalPath: join(home, ".kode", "skills"),
|
|
1828
1834
|
mcpProjectConfigPath: ".kode/mcp.json",
|
|
1829
|
-
mcpGlobalConfigPath:
|
|
1835
|
+
mcpGlobalConfigPath: join(home, ".kode", "mcp.json")
|
|
1830
1836
|
},
|
|
1831
1837
|
{
|
|
1832
1838
|
id: "mcpjam",
|
|
1833
1839
|
name: "MCPJam",
|
|
1834
1840
|
projectPath: ".mcpjam/skills",
|
|
1835
|
-
globalPath:
|
|
1841
|
+
globalPath: join(home, ".mcpjam", "skills"),
|
|
1836
1842
|
mcpProjectConfigPath: ".mcpjam/mcp.json",
|
|
1837
|
-
mcpGlobalConfigPath:
|
|
1843
|
+
mcpGlobalConfigPath: join(home, ".mcpjam", "mcp.json")
|
|
1838
1844
|
},
|
|
1839
1845
|
{
|
|
1840
1846
|
id: "mux",
|
|
1841
1847
|
name: "Mux",
|
|
1842
1848
|
projectPath: ".mux/skills",
|
|
1843
|
-
globalPath:
|
|
1849
|
+
globalPath: join(home, ".mux", "skills"),
|
|
1844
1850
|
mcpProjectConfigPath: ".mux/mcp.json",
|
|
1845
|
-
mcpGlobalConfigPath:
|
|
1851
|
+
mcpGlobalConfigPath: join(home, ".mux", "mcp.json")
|
|
1846
1852
|
},
|
|
1847
1853
|
{
|
|
1848
1854
|
id: "opencode",
|
|
1849
1855
|
name: "OpenCode",
|
|
1850
1856
|
projectPath: ".opencode/skills",
|
|
1851
|
-
globalPath:
|
|
1857
|
+
globalPath: join(home, ".config", "opencode", "skills"),
|
|
1858
|
+
agentsProjectPath: ".opencode/agents",
|
|
1859
|
+
agentsGlobalPath: join(home, ".config", "opencode", "agents"),
|
|
1852
1860
|
mcpProjectConfigPath: ".opencode/mcp.json",
|
|
1853
|
-
mcpGlobalConfigPath:
|
|
1861
|
+
mcpGlobalConfigPath: join(home, ".config", "opencode", "mcp.json")
|
|
1854
1862
|
},
|
|
1855
1863
|
{
|
|
1856
1864
|
id: "openhands",
|
|
1857
1865
|
name: "OpenHands",
|
|
1858
1866
|
projectPath: ".openhands/skills",
|
|
1859
|
-
globalPath:
|
|
1867
|
+
globalPath: join(home, ".openhands", "skills"),
|
|
1860
1868
|
mcpProjectConfigPath: ".openhands/mcp.json",
|
|
1861
|
-
mcpGlobalConfigPath:
|
|
1869
|
+
mcpGlobalConfigPath: join(home, ".openhands", "mcp.json")
|
|
1862
1870
|
},
|
|
1863
1871
|
{
|
|
1864
1872
|
id: "pi",
|
|
1865
1873
|
name: "Pi",
|
|
1866
1874
|
projectPath: ".pi/skills",
|
|
1867
|
-
globalPath:
|
|
1875
|
+
globalPath: join(home, ".pi", "agent", "skills"),
|
|
1868
1876
|
mcpProjectConfigPath: ".pi/mcp.json",
|
|
1869
|
-
mcpGlobalConfigPath:
|
|
1877
|
+
mcpGlobalConfigPath: join(home, ".pi", "agent", "mcp.json")
|
|
1870
1878
|
},
|
|
1871
1879
|
{
|
|
1872
1880
|
id: "qoder",
|
|
1873
1881
|
name: "Qoder",
|
|
1874
1882
|
projectPath: ".qoder/skills",
|
|
1875
|
-
globalPath:
|
|
1883
|
+
globalPath: join(home, ".qoder", "skills"),
|
|
1876
1884
|
mcpProjectConfigPath: ".qoder/mcp.json",
|
|
1877
|
-
mcpGlobalConfigPath:
|
|
1885
|
+
mcpGlobalConfigPath: join(home, ".qoder", "mcp.json")
|
|
1878
1886
|
},
|
|
1879
1887
|
{
|
|
1880
1888
|
id: "qwen-code",
|
|
1881
1889
|
name: "Qwen Code",
|
|
1882
1890
|
projectPath: ".qwen/skills",
|
|
1883
|
-
globalPath:
|
|
1891
|
+
globalPath: join(home, ".qwen", "skills"),
|
|
1884
1892
|
mcpProjectConfigPath: ".qwen/mcp.json",
|
|
1885
|
-
mcpGlobalConfigPath:
|
|
1893
|
+
mcpGlobalConfigPath: join(home, ".qwen", "mcp.json")
|
|
1886
1894
|
},
|
|
1887
1895
|
{
|
|
1888
1896
|
id: "roo",
|
|
1889
1897
|
name: "Roo Code",
|
|
1890
1898
|
projectPath: ".roo/skills",
|
|
1891
|
-
globalPath:
|
|
1899
|
+
globalPath: join(home, ".roo", "skills"),
|
|
1892
1900
|
rulesProjectPath: ".roo/rules",
|
|
1893
|
-
rulesGlobalPath:
|
|
1901
|
+
rulesGlobalPath: join(home, ".roo", "rules"),
|
|
1894
1902
|
ruleFormat: "markdown-dir",
|
|
1895
1903
|
mcpGlobalConfigPath: vscodeExtSettingsPath(
|
|
1896
1904
|
"rooveterinaryinc.roo-cline",
|
|
@@ -1902,42 +1910,42 @@ var AGENTS = [
|
|
|
1902
1910
|
id: "trae",
|
|
1903
1911
|
name: "Trae",
|
|
1904
1912
|
projectPath: ".trae/skills",
|
|
1905
|
-
globalPath:
|
|
1913
|
+
globalPath: join(home, ".trae", "skills"),
|
|
1906
1914
|
mcpProjectConfigPath: ".trae/mcp.json",
|
|
1907
|
-
mcpGlobalConfigPath:
|
|
1915
|
+
mcpGlobalConfigPath: join(home, ".trae", "mcp.json")
|
|
1908
1916
|
},
|
|
1909
1917
|
{
|
|
1910
1918
|
id: "windsurf",
|
|
1911
1919
|
name: "Windsurf",
|
|
1912
1920
|
projectPath: ".windsurf/skills",
|
|
1913
|
-
globalPath:
|
|
1921
|
+
globalPath: join(home, ".codeium", "windsurf", "skills"),
|
|
1914
1922
|
rulesProjectPath: ".windsurfrules",
|
|
1915
1923
|
ruleFormat: "append-single",
|
|
1916
|
-
mcpGlobalConfigPath:
|
|
1924
|
+
mcpGlobalConfigPath: join(home, ".codeium", "windsurf", "mcp_config.json")
|
|
1917
1925
|
},
|
|
1918
1926
|
{
|
|
1919
1927
|
id: "zencoder",
|
|
1920
1928
|
name: "Zencoder",
|
|
1921
1929
|
projectPath: ".zencoder/skills",
|
|
1922
|
-
globalPath:
|
|
1930
|
+
globalPath: join(home, ".zencoder", "skills"),
|
|
1923
1931
|
mcpProjectConfigPath: ".zencoder/mcp.json",
|
|
1924
|
-
mcpGlobalConfigPath:
|
|
1932
|
+
mcpGlobalConfigPath: join(home, ".zencoder", "mcp.json")
|
|
1925
1933
|
},
|
|
1926
1934
|
{
|
|
1927
1935
|
id: "neovate",
|
|
1928
1936
|
name: "Neovate",
|
|
1929
1937
|
projectPath: ".neovate/skills",
|
|
1930
|
-
globalPath:
|
|
1938
|
+
globalPath: join(home, ".neovate", "skills"),
|
|
1931
1939
|
mcpProjectConfigPath: ".neovate/mcp.json",
|
|
1932
|
-
mcpGlobalConfigPath:
|
|
1940
|
+
mcpGlobalConfigPath: join(home, ".neovate", "mcp.json")
|
|
1933
1941
|
},
|
|
1934
1942
|
{
|
|
1935
1943
|
id: "pochi",
|
|
1936
1944
|
name: "Pochi",
|
|
1937
1945
|
projectPath: ".pochi/skills",
|
|
1938
|
-
globalPath:
|
|
1946
|
+
globalPath: join(home, ".pochi", "skills"),
|
|
1939
1947
|
mcpProjectConfigPath: ".pochi/mcp.json",
|
|
1940
|
-
mcpGlobalConfigPath:
|
|
1948
|
+
mcpGlobalConfigPath: join(home, ".pochi", "mcp.json")
|
|
1941
1949
|
},
|
|
1942
1950
|
{
|
|
1943
1951
|
id: "zed",
|
|
@@ -1945,38 +1953,38 @@ var AGENTS = [
|
|
|
1945
1953
|
projectPath: "",
|
|
1946
1954
|
globalPath: "",
|
|
1947
1955
|
projectMarkerPath: ".zed",
|
|
1948
|
-
globalMarkerPath:
|
|
1956
|
+
globalMarkerPath: join(home, ".config", "zed"),
|
|
1949
1957
|
rulesProjectPath: ".zed/rules",
|
|
1950
|
-
rulesGlobalPath:
|
|
1958
|
+
rulesGlobalPath: join(home, ".config", "zed", "rules"),
|
|
1951
1959
|
ruleFormat: "markdown-dir",
|
|
1952
|
-
mcpGlobalConfigPath:
|
|
1960
|
+
mcpGlobalConfigPath: join(home, ".config", "zed", "settings.json"),
|
|
1953
1961
|
mcpRootKey: "context_servers",
|
|
1954
1962
|
mcpEntryStyle: "zed"
|
|
1955
1963
|
}
|
|
1956
1964
|
];
|
|
1957
|
-
var directoryExists = (path2) =>
|
|
1958
|
-
|
|
1965
|
+
var directoryExists = (path2) => pipe2(
|
|
1966
|
+
Effect2.tryPromise({
|
|
1959
1967
|
try: () => access(path2, constants.F_OK),
|
|
1960
1968
|
catch: () => false
|
|
1961
1969
|
}),
|
|
1962
|
-
|
|
1963
|
-
|
|
1970
|
+
Effect2.map(() => true),
|
|
1971
|
+
Effect2.orElseSucceed(() => false)
|
|
1964
1972
|
);
|
|
1965
1973
|
var detectAgents = (projectRoot) => {
|
|
1966
|
-
const cwd = projectRoot ??
|
|
1967
|
-
return
|
|
1968
|
-
|
|
1974
|
+
const cwd = projectRoot ?? process2.cwd();
|
|
1975
|
+
return pipe2(
|
|
1976
|
+
Effect2.forEach(
|
|
1969
1977
|
AGENTS,
|
|
1970
|
-
(agent) =>
|
|
1971
|
-
|
|
1972
|
-
hasProjectConfig: agent.projectPath ? directoryExists(
|
|
1973
|
-
hasGlobalConfig: agent.globalPath ? directoryExists(agent.globalPath) :
|
|
1974
|
-
hasProjectMarker: agent.projectMarkerPath ? directoryExists(
|
|
1975
|
-
hasGlobalMarker: agent.globalMarkerPath ? directoryExists(agent.globalMarkerPath) :
|
|
1976
|
-
hasRulesProjectConfig: agent.rulesProjectPath ? directoryExists(
|
|
1977
|
-
hasRulesGlobalConfig: agent.rulesGlobalPath ? directoryExists(agent.rulesGlobalPath) :
|
|
1978
|
+
(agent) => pipe2(
|
|
1979
|
+
Effect2.all({
|
|
1980
|
+
hasProjectConfig: agent.projectPath ? directoryExists(join(cwd, agent.projectPath)) : Effect2.succeed(false),
|
|
1981
|
+
hasGlobalConfig: agent.globalPath ? directoryExists(agent.globalPath) : Effect2.succeed(false),
|
|
1982
|
+
hasProjectMarker: agent.projectMarkerPath ? directoryExists(join(cwd, agent.projectMarkerPath)) : Effect2.succeed(false),
|
|
1983
|
+
hasGlobalMarker: agent.globalMarkerPath ? directoryExists(agent.globalMarkerPath) : Effect2.succeed(false),
|
|
1984
|
+
hasRulesProjectConfig: agent.rulesProjectPath ? directoryExists(join(cwd, agent.rulesProjectPath)) : Effect2.succeed(false),
|
|
1985
|
+
hasRulesGlobalConfig: agent.rulesGlobalPath ? directoryExists(agent.rulesGlobalPath) : Effect2.succeed(false)
|
|
1978
1986
|
}),
|
|
1979
|
-
|
|
1987
|
+
Effect2.map(
|
|
1980
1988
|
({
|
|
1981
1989
|
hasProjectConfig,
|
|
1982
1990
|
hasGlobalConfig,
|
|
@@ -1993,14 +2001,14 @@ var detectAgents = (projectRoot) => {
|
|
|
1993
2001
|
),
|
|
1994
2002
|
{ concurrency: "unbounded" }
|
|
1995
2003
|
),
|
|
1996
|
-
|
|
1997
|
-
(
|
|
2004
|
+
Effect2.map(
|
|
2005
|
+
(agents2) => agents2.filter((a) => a.hasProjectConfig || a.hasGlobalConfig)
|
|
1998
2006
|
)
|
|
1999
2007
|
);
|
|
2000
2008
|
};
|
|
2001
2009
|
var getAgentById = (id) => AGENTS.find((a) => a.id === id);
|
|
2002
|
-
var detectAgentsAsync = (projectRoot) =>
|
|
2003
|
-
var directoryExistsAsync = (path2) =>
|
|
2010
|
+
var detectAgentsAsync = (projectRoot) => Effect2.runPromise(detectAgents(projectRoot));
|
|
2011
|
+
var directoryExistsAsync = (path2) => Effect2.runPromise(directoryExists(path2));
|
|
2004
2012
|
var resolveInstallPath = (agent, options) => {
|
|
2005
2013
|
if (options.global) {
|
|
2006
2014
|
return agent.globalPath || void 0;
|
|
@@ -2008,8 +2016,18 @@ var resolveInstallPath = (agent, options) => {
|
|
|
2008
2016
|
if (!agent.projectPath) {
|
|
2009
2017
|
return void 0;
|
|
2010
2018
|
}
|
|
2011
|
-
const cwd = options.projectRoot ??
|
|
2012
|
-
return
|
|
2019
|
+
const cwd = options.projectRoot ?? process2.cwd();
|
|
2020
|
+
return join(cwd, agent.projectPath);
|
|
2021
|
+
};
|
|
2022
|
+
var resolveAgentsInstallPath = (agent, options) => {
|
|
2023
|
+
if (options.global) {
|
|
2024
|
+
return agent.agentsGlobalPath;
|
|
2025
|
+
}
|
|
2026
|
+
if (!agent.agentsProjectPath) {
|
|
2027
|
+
return void 0;
|
|
2028
|
+
}
|
|
2029
|
+
const cwd = options.projectRoot ?? process2.cwd();
|
|
2030
|
+
return join(cwd, agent.agentsProjectPath);
|
|
2013
2031
|
};
|
|
2014
2032
|
var resolveRulesInstallPath = (agent, options) => {
|
|
2015
2033
|
if (options.global) {
|
|
@@ -2018,85 +2036,920 @@ var resolveRulesInstallPath = (agent, options) => {
|
|
|
2018
2036
|
if (!agent.rulesProjectPath) {
|
|
2019
2037
|
return void 0;
|
|
2020
2038
|
}
|
|
2021
|
-
const cwd = options.projectRoot ??
|
|
2022
|
-
return
|
|
2039
|
+
const cwd = options.projectRoot ?? process2.cwd();
|
|
2040
|
+
return join(cwd, agent.rulesProjectPath);
|
|
2023
2041
|
};
|
|
2024
2042
|
var hasMcpConfig = (agent) => Boolean(agent.mcpProjectConfigPath) || Boolean(agent.mcpGlobalConfigPath);
|
|
2043
|
+
var MCP_PACKAGE_SPEC = "@braid-cloud/mcp@0.1.12";
|
|
2025
2044
|
var resolveMcpConfigPath = (agent, options) => {
|
|
2026
2045
|
if (options.global) {
|
|
2027
2046
|
return agent.mcpGlobalConfigPath;
|
|
2028
2047
|
}
|
|
2029
2048
|
if (agent.mcpProjectConfigPath) {
|
|
2030
|
-
const cwd = options.projectRoot ??
|
|
2031
|
-
return
|
|
2049
|
+
const cwd = options.projectRoot ?? process2.cwd();
|
|
2050
|
+
return join(cwd, agent.mcpProjectConfigPath);
|
|
2051
|
+
}
|
|
2052
|
+
return agent.mcpGlobalConfigPath;
|
|
2053
|
+
};
|
|
2054
|
+
var buildMcpEntry = (style, env) => {
|
|
2055
|
+
const command = "npx";
|
|
2056
|
+
const args = ["-y", MCP_PACKAGE_SPEC];
|
|
2057
|
+
const envObj = Object.keys(env).length > 0 ? env : void 0;
|
|
2058
|
+
switch (style) {
|
|
2059
|
+
case "standard":
|
|
2060
|
+
return envObj ? { command, args, env: envObj } : { command, args };
|
|
2061
|
+
case "typed-stdio":
|
|
2062
|
+
return envObj ? { type: "stdio", command, args, env: envObj } : { type: "stdio", command, args };
|
|
2063
|
+
case "zed":
|
|
2064
|
+
return envObj ? { command: { path: command, args, env: envObj } } : { command: { path: command, args } };
|
|
2065
|
+
case "cline":
|
|
2066
|
+
return envObj ? { command, args, env: envObj, disabled: false } : { command, args, disabled: false };
|
|
2067
|
+
default:
|
|
2068
|
+
return envObj ? { command, args, env: envObj } : { command, args };
|
|
2069
|
+
}
|
|
2070
|
+
};
|
|
2071
|
+
var detectMcpAgents = (projectRoot) => Effect2.runPromise(
|
|
2072
|
+
pipe2(
|
|
2073
|
+
detectAgents(projectRoot),
|
|
2074
|
+
Effect2.map((detected) => detected.filter(hasMcpConfig))
|
|
2075
|
+
)
|
|
2076
|
+
);
|
|
2077
|
+
|
|
2078
|
+
// src/commands/agents.ts
|
|
2079
|
+
init_api();
|
|
2080
|
+
init_tui();
|
|
2081
|
+
var parseCsv = (input) => {
|
|
2082
|
+
if (!input) {
|
|
2083
|
+
return void 0;
|
|
2084
|
+
}
|
|
2085
|
+
const values = input.split(",").map((value) => value.trim()).filter((value) => value.length > 0);
|
|
2086
|
+
return values.length > 0 ? values : void 0;
|
|
2087
|
+
};
|
|
2088
|
+
var writeJson = (value) => {
|
|
2089
|
+
process.stdout.write(`${JSON.stringify(value, null, 2)}
|
|
2090
|
+
`);
|
|
2091
|
+
};
|
|
2092
|
+
var fail = (message) => {
|
|
2093
|
+
throw new Error(message);
|
|
2094
|
+
};
|
|
2095
|
+
var exitWithError = (error) => {
|
|
2096
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2097
|
+
log.error(message);
|
|
2098
|
+
process.exit(1);
|
|
2099
|
+
};
|
|
2100
|
+
var run = (command, args, options) => {
|
|
2101
|
+
const apiOptions = {
|
|
2102
|
+
...options.server ? { serverUrl: options.server } : {},
|
|
2103
|
+
...options.apiKey ? { apiKey: options.apiKey } : {}
|
|
2104
|
+
};
|
|
2105
|
+
return runLifecycleCommandAsync(
|
|
2106
|
+
{
|
|
2107
|
+
domain: "agents",
|
|
2108
|
+
command,
|
|
2109
|
+
args
|
|
2110
|
+
},
|
|
2111
|
+
apiOptions
|
|
2112
|
+
);
|
|
2113
|
+
};
|
|
2114
|
+
var getAgentCandidate = (value) => {
|
|
2115
|
+
if (typeof value === "object" && value !== null && "agent" in value) {
|
|
2116
|
+
return value.agent;
|
|
2117
|
+
}
|
|
2118
|
+
return value;
|
|
2119
|
+
};
|
|
2120
|
+
var getMode = (mode) => {
|
|
2121
|
+
if (mode === "primary" || mode === "subagent" || mode === "all") {
|
|
2122
|
+
return mode;
|
|
2123
|
+
}
|
|
2124
|
+
return void 0;
|
|
2125
|
+
};
|
|
2126
|
+
var getRawSkills = (agent) => {
|
|
2127
|
+
if (Array.isArray(agent.skillNames)) {
|
|
2128
|
+
return agent.skillNames;
|
|
2129
|
+
}
|
|
2130
|
+
if (Array.isArray(agent.skills)) {
|
|
2131
|
+
return agent.skills;
|
|
2132
|
+
}
|
|
2133
|
+
return void 0;
|
|
2134
|
+
};
|
|
2135
|
+
var normalizeSpec = (value) => {
|
|
2136
|
+
const candidate = getAgentCandidate(value);
|
|
2137
|
+
if (typeof candidate !== "object" || candidate === null) {
|
|
2138
|
+
throw new Error("Invalid agent payload from API");
|
|
2139
|
+
}
|
|
2140
|
+
const agent = candidate;
|
|
2141
|
+
const name = typeof agent.name === "string" ? agent.name : void 0;
|
|
2142
|
+
const description = typeof agent.description === "string" ? agent.description : void 0;
|
|
2143
|
+
const promptFromPrompt = typeof agent.prompt === "string" ? agent.prompt : void 0;
|
|
2144
|
+
const promptFromContent = typeof agent.content === "string" ? agent.content : void 0;
|
|
2145
|
+
const prompt = promptFromPrompt ?? promptFromContent;
|
|
2146
|
+
if (!(name && description && prompt)) {
|
|
2147
|
+
throw new Error(
|
|
2148
|
+
"Agent payload missing required fields: name, description, prompt"
|
|
2149
|
+
);
|
|
2150
|
+
}
|
|
2151
|
+
const result = {
|
|
2152
|
+
name,
|
|
2153
|
+
description,
|
|
2154
|
+
prompt
|
|
2155
|
+
};
|
|
2156
|
+
const mode = getMode(agent.mode);
|
|
2157
|
+
if (mode) {
|
|
2158
|
+
result.mode = mode;
|
|
2159
|
+
}
|
|
2160
|
+
if (typeof agent.model === "string") {
|
|
2161
|
+
result.model = agent.model;
|
|
2162
|
+
}
|
|
2163
|
+
const rawSkills = getRawSkills(agent);
|
|
2164
|
+
if (rawSkills) {
|
|
2165
|
+
result.linkedSkillNames = rawSkills.filter(
|
|
2166
|
+
(item) => typeof item === "string"
|
|
2167
|
+
);
|
|
2168
|
+
}
|
|
2169
|
+
return result;
|
|
2170
|
+
};
|
|
2171
|
+
var resolveInstallTargets = async (options) => {
|
|
2172
|
+
if (options.agents) {
|
|
2173
|
+
const ids = parseCsv(options.agents) ?? [];
|
|
2174
|
+
const selected = ids.map((id) => getAgentById(id)).filter(
|
|
2175
|
+
(agent) => agent !== void 0
|
|
2176
|
+
);
|
|
2177
|
+
if (selected.length === 0) {
|
|
2178
|
+
fail("No valid target agents selected");
|
|
2179
|
+
}
|
|
2180
|
+
return selected;
|
|
2181
|
+
}
|
|
2182
|
+
const detected = await detectAgentsAsync();
|
|
2183
|
+
const filtered = detected.filter(
|
|
2184
|
+
(agent) => options.global ? agent.hasGlobalConfig : agent.hasProjectConfig
|
|
2185
|
+
);
|
|
2186
|
+
if (filtered.length === 0) {
|
|
2187
|
+
fail(
|
|
2188
|
+
"No supported local agent installations detected. Use --agents to select targets."
|
|
2189
|
+
);
|
|
2190
|
+
}
|
|
2191
|
+
return filtered;
|
|
2192
|
+
};
|
|
2193
|
+
async function agentsListCommand(options) {
|
|
2194
|
+
try {
|
|
2195
|
+
const result = await run("list", {}, options);
|
|
2196
|
+
if (options.json) {
|
|
2197
|
+
writeJson(result);
|
|
2198
|
+
return;
|
|
2199
|
+
}
|
|
2200
|
+
log.success("agents list completed");
|
|
2201
|
+
writeJson(result);
|
|
2202
|
+
} catch (error) {
|
|
2203
|
+
exitWithError(error);
|
|
2204
|
+
}
|
|
2205
|
+
}
|
|
2206
|
+
async function agentsGetCommand(options) {
|
|
2207
|
+
try {
|
|
2208
|
+
const id = options.id ?? fail("agents get requires --id");
|
|
2209
|
+
const result = await run("get", { id }, options);
|
|
2210
|
+
if (options.json) {
|
|
2211
|
+
writeJson(result);
|
|
2212
|
+
return;
|
|
2213
|
+
}
|
|
2214
|
+
log.success("agents get completed");
|
|
2215
|
+
writeJson(result);
|
|
2216
|
+
} catch (error) {
|
|
2217
|
+
exitWithError(error);
|
|
2218
|
+
}
|
|
2219
|
+
}
|
|
2220
|
+
async function agentsCreateCommand(options) {
|
|
2221
|
+
try {
|
|
2222
|
+
const name = options.name ?? fail("agents create requires --name");
|
|
2223
|
+
const description = options.description ?? fail("agents create requires --description");
|
|
2224
|
+
const prompt = options.prompt ?? fail("agents create requires --prompt");
|
|
2225
|
+
const result = await run(
|
|
2226
|
+
"create",
|
|
2227
|
+
{
|
|
2228
|
+
name,
|
|
2229
|
+
description,
|
|
2230
|
+
prompt,
|
|
2231
|
+
scope: options.scope,
|
|
2232
|
+
projectId: options.projectId,
|
|
2233
|
+
model: options.model,
|
|
2234
|
+
mode: options.mode,
|
|
2235
|
+
skills: parseCsv(options.skills)
|
|
2236
|
+
},
|
|
2237
|
+
options
|
|
2238
|
+
);
|
|
2239
|
+
if (options.json) {
|
|
2240
|
+
writeJson(result);
|
|
2241
|
+
return;
|
|
2242
|
+
}
|
|
2243
|
+
log.success("agents create completed");
|
|
2244
|
+
} catch (error) {
|
|
2245
|
+
exitWithError(error);
|
|
2246
|
+
}
|
|
2247
|
+
}
|
|
2248
|
+
async function agentsUpdateCommand(options) {
|
|
2249
|
+
try {
|
|
2250
|
+
const id = options.id ?? fail("agents update requires --id");
|
|
2251
|
+
const result = await run(
|
|
2252
|
+
"update",
|
|
2253
|
+
{
|
|
2254
|
+
id,
|
|
2255
|
+
name: options.name,
|
|
2256
|
+
description: options.description,
|
|
2257
|
+
prompt: options.prompt,
|
|
2258
|
+
model: options.model,
|
|
2259
|
+
mode: options.mode,
|
|
2260
|
+
skills: parseCsv(options.skills)
|
|
2261
|
+
},
|
|
2262
|
+
options
|
|
2263
|
+
);
|
|
2264
|
+
if (options.json) {
|
|
2265
|
+
writeJson(result);
|
|
2266
|
+
return;
|
|
2267
|
+
}
|
|
2268
|
+
log.success("agents update completed");
|
|
2269
|
+
} catch (error) {
|
|
2270
|
+
exitWithError(error);
|
|
2271
|
+
}
|
|
2272
|
+
}
|
|
2273
|
+
async function agentsRemoveCommand(options) {
|
|
2274
|
+
try {
|
|
2275
|
+
const id = options.id ?? fail("agents remove requires --id");
|
|
2276
|
+
if (!options.yes) {
|
|
2277
|
+
fail("agents remove requires --yes");
|
|
2278
|
+
}
|
|
2279
|
+
const result = await run("remove", { id, yes: true }, options);
|
|
2280
|
+
if (options.json) {
|
|
2281
|
+
writeJson(result);
|
|
2282
|
+
return;
|
|
2283
|
+
}
|
|
2284
|
+
log.success("agents remove completed");
|
|
2285
|
+
} catch (error) {
|
|
2286
|
+
exitWithError(error);
|
|
2287
|
+
}
|
|
2288
|
+
}
|
|
2289
|
+
async function agentsInstallCommand(options) {
|
|
2290
|
+
try {
|
|
2291
|
+
const id = options.id ?? fail("agents install requires --id");
|
|
2292
|
+
const payload = await run("get", { id }, options);
|
|
2293
|
+
const spec = normalizeSpec(payload);
|
|
2294
|
+
const targets = await resolveInstallTargets(options);
|
|
2295
|
+
const summary = [];
|
|
2296
|
+
for (const target of targets) {
|
|
2297
|
+
const installPath = resolveAgentsInstallPath(target, { global: options.global === true }) ?? resolveInstallPath(target, { global: options.global === true });
|
|
2298
|
+
if (!installPath) {
|
|
2299
|
+
summary.push({
|
|
2300
|
+
platform: target.id,
|
|
2301
|
+
written: 0,
|
|
2302
|
+
warnings: ["No install path available for this platform"],
|
|
2303
|
+
errors: []
|
|
2304
|
+
});
|
|
2305
|
+
continue;
|
|
2306
|
+
}
|
|
2307
|
+
const result = await writeAgentsForPlatformAsync(
|
|
2308
|
+
target,
|
|
2309
|
+
[spec],
|
|
2310
|
+
installPath
|
|
2311
|
+
);
|
|
2312
|
+
summary.push({
|
|
2313
|
+
platform: target.id,
|
|
2314
|
+
installPath,
|
|
2315
|
+
written: result.written.length,
|
|
2316
|
+
warnings: result.warnings,
|
|
2317
|
+
errors: result.errors
|
|
2318
|
+
});
|
|
2319
|
+
}
|
|
2320
|
+
if (options.json) {
|
|
2321
|
+
writeJson(summary);
|
|
2322
|
+
return;
|
|
2323
|
+
}
|
|
2324
|
+
for (const item of summary) {
|
|
2325
|
+
log.info(
|
|
2326
|
+
`${item.platform}: ${item.written} file(s) written${item.installPath ? ` to ${item.installPath}` : ""}`
|
|
2327
|
+
);
|
|
2328
|
+
for (const warning of item.warnings) {
|
|
2329
|
+
log.warn(` warning: ${warning}`);
|
|
2330
|
+
}
|
|
2331
|
+
for (const error of item.errors) {
|
|
2332
|
+
log.error(` error (${error.agent}): ${error.error}`);
|
|
2333
|
+
}
|
|
2334
|
+
}
|
|
2335
|
+
log.success("agents install completed");
|
|
2336
|
+
} catch (error) {
|
|
2337
|
+
exitWithError(error);
|
|
2338
|
+
}
|
|
2339
|
+
}
|
|
2340
|
+
|
|
2341
|
+
// src/commands/auth.ts
|
|
2342
|
+
init_esm_shims();
|
|
2343
|
+
init_api();
|
|
2344
|
+
init_config();
|
|
2345
|
+
import process6 from "process";
|
|
2346
|
+
|
|
2347
|
+
// src/lib/device-auth.ts
|
|
2348
|
+
init_esm_shims();
|
|
2349
|
+
import { execFile } from "child_process";
|
|
2350
|
+
import { hostname, platform } from "os";
|
|
2351
|
+
var TRAILING_SLASHES = /\/+$/;
|
|
2352
|
+
var DeviceAuthTimeoutError = class extends Error {
|
|
2353
|
+
constructor() {
|
|
2354
|
+
super("Device authorization timed out");
|
|
2355
|
+
this.name = "DeviceAuthTimeoutError";
|
|
2356
|
+
}
|
|
2357
|
+
};
|
|
2358
|
+
var DeviceAuthDeniedError = class extends Error {
|
|
2359
|
+
constructor() {
|
|
2360
|
+
super("Device authorization was denied");
|
|
2361
|
+
this.name = "DeviceAuthDeniedError";
|
|
2362
|
+
}
|
|
2363
|
+
};
|
|
2364
|
+
var DeviceAuthExpiredError = class extends Error {
|
|
2365
|
+
constructor() {
|
|
2366
|
+
super("Device authorization code has expired");
|
|
2367
|
+
this.name = "DeviceAuthExpiredError";
|
|
2368
|
+
}
|
|
2369
|
+
};
|
|
2370
|
+
var sleep = (ms) => new Promise((resolve5) => setTimeout(resolve5, ms));
|
|
2371
|
+
async function fetchAuthConfig(serverUrl) {
|
|
2372
|
+
const url = `${serverUrl.replace(TRAILING_SLASHES, "")}/api/cli/auth-config`;
|
|
2373
|
+
const response = await fetch(url);
|
|
2374
|
+
if (!response.ok) {
|
|
2375
|
+
const body = await response.text();
|
|
2376
|
+
throw new Error(
|
|
2377
|
+
`Failed to fetch auth config (${response.status}): ${body}`
|
|
2378
|
+
);
|
|
2379
|
+
}
|
|
2380
|
+
return response.json();
|
|
2381
|
+
}
|
|
2382
|
+
async function initiateDeviceAuth(convexSiteUrl, deviceInfo) {
|
|
2383
|
+
const url = `${convexSiteUrl.replace(TRAILING_SLASHES, "")}/api/cli/device/authorize`;
|
|
2384
|
+
const response = await fetch(url, {
|
|
2385
|
+
method: "POST",
|
|
2386
|
+
headers: { "Content-Type": "application/json" },
|
|
2387
|
+
body: JSON.stringify(deviceInfo)
|
|
2388
|
+
});
|
|
2389
|
+
if (!response.ok) {
|
|
2390
|
+
const body = await response.text();
|
|
2391
|
+
throw new Error(
|
|
2392
|
+
`Failed to initiate device authorization (${response.status}): ${body}`
|
|
2393
|
+
);
|
|
2394
|
+
}
|
|
2395
|
+
return response.json();
|
|
2396
|
+
}
|
|
2397
|
+
async function pollForSession(convexSiteUrl, deviceCode, interval, expiresIn, timeoutSeconds) {
|
|
2398
|
+
const tokenUrl = `${convexSiteUrl.replace(TRAILING_SLASHES, "")}/api/cli/device/token`;
|
|
2399
|
+
const deadline = Date.now() + Math.min(expiresIn, timeoutSeconds) * 1e3;
|
|
2400
|
+
let currentInterval = interval;
|
|
2401
|
+
while (Date.now() < deadline) {
|
|
2402
|
+
await sleep(currentInterval * 1e3);
|
|
2403
|
+
const response = await fetch(tokenUrl, {
|
|
2404
|
+
method: "POST",
|
|
2405
|
+
headers: { "Content-Type": "application/json" },
|
|
2406
|
+
body: JSON.stringify({ device_code: deviceCode })
|
|
2407
|
+
});
|
|
2408
|
+
if (response.ok) {
|
|
2409
|
+
const result = await response.json();
|
|
2410
|
+
return {
|
|
2411
|
+
sessionToken: result.session_token,
|
|
2412
|
+
expiresAt: result.expires_at,
|
|
2413
|
+
user: result.user
|
|
2414
|
+
};
|
|
2415
|
+
}
|
|
2416
|
+
let errorCode;
|
|
2417
|
+
try {
|
|
2418
|
+
const errorBody = await response.json();
|
|
2419
|
+
errorCode = errorBody.error;
|
|
2420
|
+
} catch {
|
|
2421
|
+
throw new Error(`Device auth polling error: HTTP ${response.status}`);
|
|
2422
|
+
}
|
|
2423
|
+
if (errorCode === "authorization_pending") {
|
|
2424
|
+
continue;
|
|
2425
|
+
}
|
|
2426
|
+
if (errorCode === "slow_down") {
|
|
2427
|
+
currentInterval += 5;
|
|
2428
|
+
continue;
|
|
2429
|
+
}
|
|
2430
|
+
if (errorCode === "expired_token") {
|
|
2431
|
+
throw new DeviceAuthExpiredError();
|
|
2432
|
+
}
|
|
2433
|
+
if (errorCode === "access_denied") {
|
|
2434
|
+
throw new DeviceAuthDeniedError();
|
|
2435
|
+
}
|
|
2436
|
+
throw new Error(
|
|
2437
|
+
`Device auth polling error: ${errorCode ?? `HTTP ${response.status}`}`
|
|
2438
|
+
);
|
|
2439
|
+
}
|
|
2440
|
+
throw new DeviceAuthTimeoutError();
|
|
2441
|
+
}
|
|
2442
|
+
async function fetchSessionInfo(convexSiteUrl, sessionToken) {
|
|
2443
|
+
const url = `${convexSiteUrl.replace(TRAILING_SLASHES, "")}/api/cli/sessions/me`;
|
|
2444
|
+
const response = await fetch(url, {
|
|
2445
|
+
method: "GET",
|
|
2446
|
+
headers: {
|
|
2447
|
+
Authorization: `Bearer ${sessionToken}`
|
|
2448
|
+
}
|
|
2449
|
+
});
|
|
2450
|
+
if (response.status === 404) {
|
|
2451
|
+
return null;
|
|
2452
|
+
}
|
|
2453
|
+
if (!response.ok) {
|
|
2454
|
+
const body = await response.text();
|
|
2455
|
+
throw new Error(
|
|
2456
|
+
`Failed to fetch session info (${response.status}): ${body}`
|
|
2457
|
+
);
|
|
2458
|
+
}
|
|
2459
|
+
return response.json();
|
|
2460
|
+
}
|
|
2461
|
+
async function revokeSession(convexSiteUrl, sessionToken) {
|
|
2462
|
+
const url = `${convexSiteUrl.replace(TRAILING_SLASHES, "")}/api/cli/sessions/me`;
|
|
2463
|
+
const response = await fetch(url, {
|
|
2464
|
+
method: "DELETE",
|
|
2465
|
+
headers: {
|
|
2466
|
+
Authorization: `Bearer ${sessionToken}`
|
|
2467
|
+
}
|
|
2468
|
+
});
|
|
2469
|
+
if (response.status === 404) {
|
|
2470
|
+
return false;
|
|
2471
|
+
}
|
|
2472
|
+
if (!response.ok) {
|
|
2473
|
+
const body = await response.text();
|
|
2474
|
+
throw new Error(`Failed to revoke session (${response.status}): ${body}`);
|
|
2475
|
+
}
|
|
2476
|
+
return true;
|
|
2477
|
+
}
|
|
2478
|
+
var noop = () => {
|
|
2479
|
+
};
|
|
2480
|
+
function openBrowser(url) {
|
|
2481
|
+
const currentPlatform = platform();
|
|
2482
|
+
if (currentPlatform === "darwin") {
|
|
2483
|
+
execFile("open", [url], noop);
|
|
2484
|
+
} else if (currentPlatform === "win32") {
|
|
2485
|
+
execFile("cmd", ["/c", "start", "", url], noop);
|
|
2486
|
+
} else {
|
|
2487
|
+
execFile("xdg-open", [url], noop);
|
|
2488
|
+
}
|
|
2489
|
+
}
|
|
2490
|
+
function getDeviceInfo() {
|
|
2491
|
+
return {
|
|
2492
|
+
deviceName: hostname(),
|
|
2493
|
+
deviceOs: platform(),
|
|
2494
|
+
deviceHostname: hostname()
|
|
2495
|
+
};
|
|
2496
|
+
}
|
|
2497
|
+
|
|
2498
|
+
// src/commands/auth.ts
|
|
2499
|
+
init_tui();
|
|
2500
|
+
var SESSION_TOKEN_PREFIX = "brs_";
|
|
2501
|
+
var TRAILING_SLASHES2 = /\/+$/;
|
|
2502
|
+
var DEFAULT_TIMEOUT_SECONDS = 300;
|
|
2503
|
+
async function configureDefaultScopeAsync(serverUrl) {
|
|
2504
|
+
const shouldConfigureScope = await confirm({
|
|
2505
|
+
message: "Configure organization and scope defaults now?",
|
|
2506
|
+
initialValue: true
|
|
2507
|
+
});
|
|
2508
|
+
if (isCancel(shouldConfigureScope) || !shouldConfigureScope) {
|
|
2509
|
+
return;
|
|
2510
|
+
}
|
|
2511
|
+
const { scopeCommand: scopeCommand2 } = await Promise.resolve().then(() => (init_scope(), scope_exports));
|
|
2512
|
+
const config = await loadMergedConfigAsync();
|
|
2513
|
+
await scopeCommand2({
|
|
2514
|
+
file: "user",
|
|
2515
|
+
server: serverUrl,
|
|
2516
|
+
...config.token ? { apiKey: config.token } : {}
|
|
2517
|
+
});
|
|
2518
|
+
}
|
|
2519
|
+
async function manualTokenFlow(apiKey, serverUrl, options) {
|
|
2520
|
+
const authSpinner = spinner();
|
|
2521
|
+
let authSpinnerActive = true;
|
|
2522
|
+
const stopAuthSpinner = (message) => {
|
|
2523
|
+
if (!authSpinnerActive) {
|
|
2524
|
+
return;
|
|
2525
|
+
}
|
|
2526
|
+
authSpinner.stop(message);
|
|
2527
|
+
authSpinnerActive = false;
|
|
2528
|
+
};
|
|
2529
|
+
authSpinner.start("Validating API key...");
|
|
2530
|
+
try {
|
|
2531
|
+
const isValid = await validateApiKeyAsync(apiKey, serverUrl);
|
|
2532
|
+
if (!isValid) {
|
|
2533
|
+
stopAuthSpinner("Invalid API key");
|
|
2534
|
+
log.error(
|
|
2535
|
+
"The API key could not be validated. Please check your key and try again."
|
|
2536
|
+
);
|
|
2537
|
+
process6.exit(1);
|
|
2538
|
+
}
|
|
2539
|
+
await setApiKeyAsync(apiKey);
|
|
2540
|
+
const existingUserConfig = await loadUserConfigAsync();
|
|
2541
|
+
if (existingUserConfig?.token) {
|
|
2542
|
+
await saveUserConfigAsync({ ...existingUserConfig, token: apiKey });
|
|
2543
|
+
}
|
|
2544
|
+
stopAuthSpinner("API key validated and saved");
|
|
2545
|
+
if (options.scope !== false) {
|
|
2546
|
+
await configureDefaultScopeAsync(serverUrl);
|
|
2547
|
+
}
|
|
2548
|
+
log.success(`Config saved to ${CONFIG_FILE}`);
|
|
2549
|
+
outro(
|
|
2550
|
+
"You're authenticated! Run 'braid install' to use your saved scope (or pass '--profile <name>' to override)."
|
|
2551
|
+
);
|
|
2552
|
+
} catch (error) {
|
|
2553
|
+
stopAuthSpinner("Validation failed");
|
|
2554
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2555
|
+
log.error(`Failed to validate API key: ${message}`);
|
|
2556
|
+
process6.exit(1);
|
|
2557
|
+
}
|
|
2558
|
+
}
|
|
2559
|
+
function handlePollingError(error) {
|
|
2560
|
+
if (error instanceof DeviceAuthTimeoutError) {
|
|
2561
|
+
log.error("The device authorization timed out. Please try again.");
|
|
2562
|
+
} else if (error instanceof DeviceAuthExpiredError) {
|
|
2563
|
+
log.error("The device code has expired. Please try again.");
|
|
2564
|
+
} else if (error instanceof DeviceAuthDeniedError) {
|
|
2565
|
+
log.error("The authorization request was denied.");
|
|
2566
|
+
} else {
|
|
2567
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2568
|
+
log.error(`Authentication failed: ${message}`);
|
|
2569
|
+
}
|
|
2570
|
+
process6.exit(1);
|
|
2571
|
+
}
|
|
2572
|
+
async function deviceFlow(serverUrl, timeoutSeconds, options) {
|
|
2573
|
+
const configSpinner = spinner();
|
|
2574
|
+
configSpinner.start("Fetching auth configuration...");
|
|
2575
|
+
let authConfig;
|
|
2576
|
+
try {
|
|
2577
|
+
authConfig = await fetchAuthConfig(serverUrl);
|
|
2578
|
+
configSpinner.stop("Auth configuration loaded");
|
|
2579
|
+
} catch (error) {
|
|
2580
|
+
configSpinner.stop("Failed to fetch auth configuration");
|
|
2581
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2582
|
+
log.error(`Could not connect to server: ${message}`);
|
|
2583
|
+
process6.exit(1);
|
|
2584
|
+
}
|
|
2585
|
+
const deviceSpinner = spinner();
|
|
2586
|
+
deviceSpinner.start("Initiating device authorization...");
|
|
2587
|
+
let deviceAuth;
|
|
2588
|
+
try {
|
|
2589
|
+
deviceAuth = await initiateDeviceAuth(
|
|
2590
|
+
authConfig.convexSiteUrl,
|
|
2591
|
+
getDeviceInfo()
|
|
2592
|
+
);
|
|
2593
|
+
deviceSpinner.stop("Device authorization initiated");
|
|
2594
|
+
} catch (error) {
|
|
2595
|
+
deviceSpinner.stop("Failed to initiate device authorization");
|
|
2596
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2597
|
+
log.error(`Device authorization failed: ${message}`);
|
|
2598
|
+
process6.exit(1);
|
|
2599
|
+
}
|
|
2600
|
+
const verificationUrl = `${serverUrl.replace(TRAILING_SLASHES2, "")}/cli/authorize?user_code=${deviceAuth.user_code}`;
|
|
2601
|
+
log.info("");
|
|
2602
|
+
log.info(" To authenticate, visit:");
|
|
2603
|
+
log.info(` ${verificationUrl}`);
|
|
2604
|
+
log.info("");
|
|
2605
|
+
log.info(` Your code: ${deviceAuth.user_code}`);
|
|
2606
|
+
log.info("");
|
|
2607
|
+
openBrowser(verificationUrl);
|
|
2608
|
+
const expiresMinutes = Math.ceil(
|
|
2609
|
+
Math.min(deviceAuth.expires_in, timeoutSeconds) / 60
|
|
2610
|
+
);
|
|
2611
|
+
const pollSpinner = spinner();
|
|
2612
|
+
pollSpinner.start(
|
|
2613
|
+
`Waiting for authentication... (expires in ${expiresMinutes} minutes)`
|
|
2614
|
+
);
|
|
2615
|
+
let session;
|
|
2616
|
+
try {
|
|
2617
|
+
session = await pollForSession(
|
|
2618
|
+
authConfig.convexSiteUrl,
|
|
2619
|
+
deviceAuth.device_code,
|
|
2620
|
+
deviceAuth.interval,
|
|
2621
|
+
deviceAuth.expires_in,
|
|
2622
|
+
timeoutSeconds
|
|
2623
|
+
);
|
|
2624
|
+
pollSpinner.stop(`Authenticated as ${session.user.email}`);
|
|
2625
|
+
} catch (error) {
|
|
2626
|
+
pollSpinner.stop("Authentication failed");
|
|
2627
|
+
handlePollingError(error);
|
|
2628
|
+
}
|
|
2629
|
+
await setApiKeyAsync(session.sessionToken);
|
|
2630
|
+
if (options.scope !== false) {
|
|
2631
|
+
await configureDefaultScopeAsync(authConfig.convexSiteUrl);
|
|
2632
|
+
}
|
|
2633
|
+
log.success(`Session saved to ${CONFIG_FILE}`);
|
|
2634
|
+
outro(
|
|
2635
|
+
"You're authenticated! Run 'braid install' to use your saved scope (or pass '--profile <name>' to override)."
|
|
2636
|
+
);
|
|
2637
|
+
}
|
|
2638
|
+
async function authCommand(options) {
|
|
2639
|
+
intro("braid auth");
|
|
2640
|
+
const serverUrl = options.server ?? "https://braid.cloud";
|
|
2641
|
+
const config = await loadMergedConfigAsync();
|
|
2642
|
+
if (config.token) {
|
|
2643
|
+
const shouldReplace = await confirm({
|
|
2644
|
+
message: "An API key is already configured. Replace it?",
|
|
2645
|
+
initialValue: false
|
|
2646
|
+
});
|
|
2647
|
+
if (isCancel(shouldReplace) || !shouldReplace) {
|
|
2648
|
+
outro("Auth cancelled.");
|
|
2649
|
+
return;
|
|
2650
|
+
}
|
|
2651
|
+
}
|
|
2652
|
+
if (options.token) {
|
|
2653
|
+
await manualTokenFlow(options.token, serverUrl, options);
|
|
2654
|
+
return;
|
|
2655
|
+
}
|
|
2656
|
+
const timeoutSeconds = options.timeout ? Number.parseInt(options.timeout, 10) : DEFAULT_TIMEOUT_SECONDS;
|
|
2657
|
+
if (Number.isNaN(timeoutSeconds) || timeoutSeconds <= 0) {
|
|
2658
|
+
log.error("Invalid timeout value. Must be a positive number of seconds.");
|
|
2659
|
+
process6.exit(1);
|
|
2660
|
+
}
|
|
2661
|
+
await deviceFlow(serverUrl, timeoutSeconds, options);
|
|
2662
|
+
}
|
|
2663
|
+
async function displayTokenSource(masked) {
|
|
2664
|
+
if (process6.env.BRAID_API_KEY) {
|
|
2665
|
+
log.info(`Authenticated with key: ${masked}`);
|
|
2666
|
+
log.info("Source: BRAID_API_KEY environment variable");
|
|
2667
|
+
return;
|
|
2668
|
+
}
|
|
2669
|
+
const userConfigPath = await findUserConfigFileAsync();
|
|
2670
|
+
log.info(`Authenticated with key: ${masked}`);
|
|
2671
|
+
log.info(`Source: ${userConfigPath ?? CONFIG_FILE}`);
|
|
2672
|
+
}
|
|
2673
|
+
async function displayProjectConfig() {
|
|
2674
|
+
const projectConfigPath = await findProjectConfigFileAsync();
|
|
2675
|
+
if (projectConfigPath) {
|
|
2676
|
+
log.info(`Project config: ${projectConfigPath}`);
|
|
2677
|
+
}
|
|
2678
|
+
}
|
|
2679
|
+
function displayResolvedSettings(config) {
|
|
2680
|
+
const hasOrgProjects = config.orgProjects && config.orgProjects.length > 0;
|
|
2681
|
+
const hasPersonalProjects = config.personalProjects && config.personalProjects.length > 0;
|
|
2682
|
+
if (!(config.profile || hasOrgProjects || hasPersonalProjects)) {
|
|
2683
|
+
return;
|
|
2684
|
+
}
|
|
2685
|
+
log.info("");
|
|
2686
|
+
if (config.profile) {
|
|
2687
|
+
log.info(`Default profile: ${config.profile}`);
|
|
2688
|
+
}
|
|
2689
|
+
if (hasOrgProjects) {
|
|
2690
|
+
log.info(`Org projects: ${config.orgProjects?.join(", ")}`);
|
|
2691
|
+
}
|
|
2692
|
+
if (hasPersonalProjects) {
|
|
2693
|
+
log.info(`Personal projects: ${config.personalProjects?.join(", ")}`);
|
|
2694
|
+
}
|
|
2695
|
+
if (config.serverUrl !== "https://braid.cloud") {
|
|
2696
|
+
log.info(`Server: ${config.serverUrl}`);
|
|
2697
|
+
}
|
|
2698
|
+
}
|
|
2699
|
+
async function displaySessionInfo(token) {
|
|
2700
|
+
const serverUrl = await getServerUrlAsync();
|
|
2701
|
+
try {
|
|
2702
|
+
const authConfig = await fetchAuthConfig(serverUrl);
|
|
2703
|
+
const info = await fetchSessionInfo(authConfig.convexSiteUrl, token);
|
|
2704
|
+
if (!info) {
|
|
2705
|
+
log.warn(
|
|
2706
|
+
"Session is expired or revoked. Run 'braid auth' to re-authenticate."
|
|
2707
|
+
);
|
|
2708
|
+
return;
|
|
2709
|
+
}
|
|
2710
|
+
log.info(
|
|
2711
|
+
`Authenticated as: ${info.email}${info.name ? ` (${info.name})` : ""}`
|
|
2712
|
+
);
|
|
2713
|
+
log.info("Session type: CLI session");
|
|
2714
|
+
if (info.deviceName || info.deviceHostname) {
|
|
2715
|
+
log.info(
|
|
2716
|
+
`Device: ${info.deviceName ?? info.deviceHostname ?? "unknown"}`
|
|
2717
|
+
);
|
|
2718
|
+
}
|
|
2719
|
+
const expiresDate = new Date(info.expiresAt);
|
|
2720
|
+
const daysRemaining = Math.ceil(
|
|
2721
|
+
(info.expiresAt - Date.now()) / (24 * 60 * 60 * 1e3)
|
|
2722
|
+
);
|
|
2723
|
+
log.info(
|
|
2724
|
+
`Expires: ${expiresDate.toLocaleDateString()} (${daysRemaining} days)`
|
|
2725
|
+
);
|
|
2726
|
+
if (info.lastActiveAt) {
|
|
2727
|
+
log.info(`Last active: ${new Date(info.lastActiveAt).toLocaleString()}`);
|
|
2728
|
+
}
|
|
2729
|
+
} catch (error) {
|
|
2730
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2731
|
+
log.warn(`Could not fetch session details: ${message}`);
|
|
2732
|
+
const masked = `${token.slice(0, 7)}...${token.slice(-4)}`;
|
|
2733
|
+
log.info(`Session token: ${masked}`);
|
|
2734
|
+
}
|
|
2735
|
+
}
|
|
2736
|
+
async function authStatusCommand() {
|
|
2737
|
+
const config = await loadMergedConfigAsync();
|
|
2738
|
+
if (!config.token) {
|
|
2739
|
+
log.warn("Not authenticated. Run 'braid auth' to configure your API key.");
|
|
2740
|
+
log.info(
|
|
2741
|
+
`Or create a ${USER_CONFIG_FILENAME} file with: { "token": "br_xxx" }`
|
|
2742
|
+
);
|
|
2743
|
+
return;
|
|
2744
|
+
}
|
|
2745
|
+
if (config.token.startsWith(SESSION_TOKEN_PREFIX)) {
|
|
2746
|
+
await displaySessionInfo(config.token);
|
|
2747
|
+
await displayProjectConfig();
|
|
2748
|
+
displayResolvedSettings(config);
|
|
2749
|
+
return;
|
|
2750
|
+
}
|
|
2751
|
+
const masked = `${config.token.slice(0, 7)}...${config.token.slice(-4)}`;
|
|
2752
|
+
await displayTokenSource(masked);
|
|
2753
|
+
await displayProjectConfig();
|
|
2754
|
+
displayResolvedSettings(config);
|
|
2755
|
+
}
|
|
2756
|
+
async function revokeSessionIfActive(token) {
|
|
2757
|
+
const serverUrl = await getServerUrlAsync();
|
|
2758
|
+
try {
|
|
2759
|
+
const authConfig = await fetchAuthConfig(serverUrl);
|
|
2760
|
+
await revokeSession(authConfig.convexSiteUrl, token);
|
|
2761
|
+
} catch {
|
|
2762
|
+
return;
|
|
2763
|
+
}
|
|
2764
|
+
}
|
|
2765
|
+
async function authLogoutCommand() {
|
|
2766
|
+
const config = await loadMergedConfigAsync();
|
|
2767
|
+
const { clearApiKeyAsync: clearApiKeyAsync2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
2768
|
+
if (config.token?.startsWith(SESSION_TOKEN_PREFIX)) {
|
|
2769
|
+
await revokeSessionIfActive(config.token);
|
|
2770
|
+
}
|
|
2771
|
+
await clearApiKeyAsync2();
|
|
2772
|
+
log.success("Logged out. API key removed from config.");
|
|
2773
|
+
}
|
|
2774
|
+
|
|
2775
|
+
// src/commands/discover.ts
|
|
2776
|
+
init_esm_shims();
|
|
2777
|
+
init_api();
|
|
2778
|
+
init_config();
|
|
2779
|
+
init_tui();
|
|
2780
|
+
import process7 from "process";
|
|
2781
|
+
var parseCsv2 = (input) => {
|
|
2782
|
+
if (!input) {
|
|
2783
|
+
return void 0;
|
|
2784
|
+
}
|
|
2785
|
+
const values = input.split(",").map((value) => value.trim()).filter((value) => value.length > 0);
|
|
2786
|
+
return values.length > 0 ? values : void 0;
|
|
2787
|
+
};
|
|
2788
|
+
var writeJson2 = (value) => {
|
|
2789
|
+
process7.stdout.write(`${JSON.stringify(value, null, 2)}
|
|
2790
|
+
`);
|
|
2791
|
+
};
|
|
2792
|
+
var exitWithError2 = (error) => {
|
|
2793
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2794
|
+
log.error(message);
|
|
2795
|
+
process7.exit(1);
|
|
2796
|
+
};
|
|
2797
|
+
var applyCommonOptions = (base, options) => ({
|
|
2798
|
+
...base,
|
|
2799
|
+
...options.server ? { serverUrl: options.server } : {},
|
|
2800
|
+
...options.apiKey ? { apiKey: options.apiKey } : {}
|
|
2801
|
+
});
|
|
2802
|
+
var applyOptionalString = (target, key, value) => {
|
|
2803
|
+
if (value) {
|
|
2804
|
+
target[key] = value;
|
|
2805
|
+
}
|
|
2806
|
+
};
|
|
2807
|
+
var applyOptionalArray = (target, key, value) => {
|
|
2808
|
+
if (value && value.length > 0) {
|
|
2809
|
+
target[key] = value;
|
|
2810
|
+
}
|
|
2811
|
+
};
|
|
2812
|
+
var applyOptionalBoolean = (target, key, value) => {
|
|
2813
|
+
if (value !== void 0) {
|
|
2814
|
+
target[key] = value;
|
|
2815
|
+
}
|
|
2816
|
+
};
|
|
2817
|
+
async function projectsListCommand(options) {
|
|
2818
|
+
try {
|
|
2819
|
+
const result = await fetchScopeOptionsAsync(
|
|
2820
|
+
applyCommonOptions({}, options)
|
|
2821
|
+
);
|
|
2822
|
+
if (options.json) {
|
|
2823
|
+
writeJson2(result);
|
|
2824
|
+
return;
|
|
2825
|
+
}
|
|
2826
|
+
log.info("Personal projects:");
|
|
2827
|
+
if (result.personalProjects.length === 0) {
|
|
2828
|
+
log.info(" (none)");
|
|
2829
|
+
}
|
|
2830
|
+
for (const project of result.personalProjects) {
|
|
2831
|
+
log.info(` ${project.id} ${project.name}`);
|
|
2832
|
+
}
|
|
2833
|
+
for (const orgProjects of result.orgProjects) {
|
|
2834
|
+
log.info(`
|
|
2835
|
+
Organization: ${orgProjects.orgName} (${orgProjects.orgId})`);
|
|
2836
|
+
if (orgProjects.projects.length === 0) {
|
|
2837
|
+
log.info(" (none)");
|
|
2838
|
+
continue;
|
|
2839
|
+
}
|
|
2840
|
+
for (const project of orgProjects.projects) {
|
|
2841
|
+
log.info(` ${project.id} ${project.name}`);
|
|
2842
|
+
}
|
|
2843
|
+
}
|
|
2844
|
+
} catch (error) {
|
|
2845
|
+
exitWithError2(error);
|
|
2846
|
+
}
|
|
2847
|
+
}
|
|
2848
|
+
var buildRulesRequest = async (options) => {
|
|
2849
|
+
const config = await loadMergedConfigAsync();
|
|
2850
|
+
const orgProjects = parseCsv2(options.orgProjects) ?? config.orgProjects;
|
|
2851
|
+
const personalProjects = parseCsv2(options.personalProjects) ?? config.personalProjects;
|
|
2852
|
+
const request = applyCommonOptions({}, options);
|
|
2853
|
+
applyOptionalString(request, "orgId", options.orgId ?? config.org);
|
|
2854
|
+
applyOptionalArray(request, "orgProjects", orgProjects);
|
|
2855
|
+
applyOptionalArray(request, "personalProjects", personalProjects);
|
|
2856
|
+
applyOptionalBoolean(request, "includeUserGlobal", options.includeUserGlobal);
|
|
2857
|
+
applyOptionalBoolean(request, "includeOrgGlobal", options.includeOrgGlobal);
|
|
2858
|
+
return request;
|
|
2859
|
+
};
|
|
2860
|
+
async function rulesListCommand(options) {
|
|
2861
|
+
try {
|
|
2862
|
+
const result = await fetchRuleOptionsAsync(
|
|
2863
|
+
await buildRulesRequest(options)
|
|
2864
|
+
);
|
|
2865
|
+
if (options.json) {
|
|
2866
|
+
writeJson2(result);
|
|
2867
|
+
return;
|
|
2868
|
+
}
|
|
2869
|
+
if (result.rules.length === 0) {
|
|
2870
|
+
log.info("No rules found.");
|
|
2871
|
+
return;
|
|
2872
|
+
}
|
|
2873
|
+
for (const rule of result.rules) {
|
|
2874
|
+
log.info(`${rule.id} ${rule.title}`);
|
|
2875
|
+
}
|
|
2876
|
+
} catch (error) {
|
|
2877
|
+
exitWithError2(error);
|
|
2032
2878
|
}
|
|
2033
|
-
|
|
2879
|
+
}
|
|
2880
|
+
var buildSkillsRequest = async (options) => {
|
|
2881
|
+
const config = await loadMergedConfigAsync();
|
|
2882
|
+
const orgProjects = parseCsv2(options.orgProjects) ?? config.orgProjects;
|
|
2883
|
+
const personalProjects = parseCsv2(options.personalProjects) ?? config.personalProjects;
|
|
2884
|
+
const request = applyCommonOptions({}, options);
|
|
2885
|
+
applyOptionalString(request, "profile", options.profile ?? config.profile);
|
|
2886
|
+
applyOptionalArray(request, "orgProjects", orgProjects);
|
|
2887
|
+
applyOptionalArray(request, "personalProjects", personalProjects);
|
|
2888
|
+
applyOptionalBoolean(request, "includeUserGlobal", options.includeUserGlobal);
|
|
2889
|
+
applyOptionalBoolean(request, "includeOrgGlobal", options.includeOrgGlobal);
|
|
2890
|
+
return request;
|
|
2034
2891
|
};
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2892
|
+
async function skillsListCommand(options) {
|
|
2893
|
+
try {
|
|
2894
|
+
const result = await fetchSkillsAsync(await buildSkillsRequest(options));
|
|
2895
|
+
if (options.json) {
|
|
2896
|
+
writeJson2(result);
|
|
2897
|
+
return;
|
|
2898
|
+
}
|
|
2899
|
+
if (result.skills.length === 0) {
|
|
2900
|
+
log.info("No skills found.");
|
|
2901
|
+
return;
|
|
2902
|
+
}
|
|
2903
|
+
for (const skill of result.skills) {
|
|
2904
|
+
log.info(`${skill.name}`);
|
|
2905
|
+
}
|
|
2906
|
+
} catch (error) {
|
|
2907
|
+
exitWithError2(error);
|
|
2050
2908
|
}
|
|
2051
|
-
}
|
|
2052
|
-
var detectMcpAgents = (projectRoot) => Effect3.runPromise(
|
|
2053
|
-
pipe3(
|
|
2054
|
-
detectAgents(projectRoot),
|
|
2055
|
-
Effect3.map((detected) => detected.filter(hasMcpConfig))
|
|
2056
|
-
)
|
|
2057
|
-
);
|
|
2909
|
+
}
|
|
2058
2910
|
|
|
2059
2911
|
// src/commands/install.ts
|
|
2912
|
+
init_esm_shims();
|
|
2060
2913
|
init_api();
|
|
2061
2914
|
init_config();
|
|
2062
2915
|
|
|
2063
2916
|
// src/lib/metadata.ts
|
|
2064
2917
|
init_esm_shims();
|
|
2065
|
-
import { readFile as readFile2, writeFile as
|
|
2918
|
+
import { readFile as readFile2, writeFile as writeFile3 } from "fs/promises";
|
|
2066
2919
|
import { join as join3 } from "path";
|
|
2067
|
-
import { Data as
|
|
2920
|
+
import { Data as Data4, Effect as Effect5, pipe as pipe5 } from "effect";
|
|
2068
2921
|
var METADATA_FILENAME = ".braidskills-metadata.json";
|
|
2069
|
-
var MetadataReadError = class extends
|
|
2922
|
+
var MetadataReadError = class extends Data4.TaggedError("MetadataReadError") {
|
|
2070
2923
|
};
|
|
2071
|
-
var MetadataWriteError = class extends
|
|
2924
|
+
var MetadataWriteError = class extends Data4.TaggedError("MetadataWriteError") {
|
|
2072
2925
|
};
|
|
2073
2926
|
var getMetadataPath = (skillsDir) => join3(skillsDir, METADATA_FILENAME);
|
|
2074
2927
|
var readMetadata = (skillsDir) => {
|
|
2075
2928
|
const metadataPath = getMetadataPath(skillsDir);
|
|
2076
|
-
return
|
|
2077
|
-
|
|
2929
|
+
return pipe5(
|
|
2930
|
+
Effect5.tryPromise({
|
|
2078
2931
|
try: () => readFile2(metadataPath, "utf-8"),
|
|
2079
2932
|
catch: (e) => new MetadataReadError({ path: metadataPath, cause: e })
|
|
2080
2933
|
}),
|
|
2081
|
-
|
|
2082
|
-
(content) =>
|
|
2934
|
+
Effect5.flatMap(
|
|
2935
|
+
(content) => Effect5.try({
|
|
2083
2936
|
try: () => JSON.parse(content),
|
|
2084
2937
|
catch: () => ({ skills: [] })
|
|
2085
2938
|
})
|
|
2086
2939
|
),
|
|
2087
|
-
|
|
2940
|
+
Effect5.orElseSucceed(() => ({ skills: [] }))
|
|
2088
2941
|
);
|
|
2089
2942
|
};
|
|
2090
2943
|
var writeMetadata = (skillsDir, metadata) => {
|
|
2091
2944
|
const metadataPath = getMetadataPath(skillsDir);
|
|
2092
|
-
return
|
|
2093
|
-
try: () =>
|
|
2945
|
+
return Effect5.tryPromise({
|
|
2946
|
+
try: () => writeFile3(metadataPath, JSON.stringify(metadata, null, 2), "utf-8"),
|
|
2094
2947
|
catch: (e) => new MetadataWriteError({ path: metadataPath, cause: e })
|
|
2095
2948
|
});
|
|
2096
2949
|
};
|
|
2097
|
-
var updateMetadata = (skillsDir, newSkills) =>
|
|
2950
|
+
var updateMetadata = (skillsDir, newSkills) => pipe5(
|
|
2098
2951
|
readMetadata(skillsDir),
|
|
2099
|
-
|
|
2952
|
+
Effect5.map((existing) => {
|
|
2100
2953
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
2101
2954
|
const updatedSkills = [...existing.skills];
|
|
2102
2955
|
for (const skill of newSkills) {
|
|
@@ -2118,43 +2971,43 @@ var updateMetadata = (skillsDir, newSkills) => pipe4(
|
|
|
2118
2971
|
}
|
|
2119
2972
|
return { skills: updatedSkills };
|
|
2120
2973
|
}),
|
|
2121
|
-
|
|
2974
|
+
Effect5.flatMap((metadata) => writeMetadata(skillsDir, metadata))
|
|
2122
2975
|
);
|
|
2123
|
-
var removeFromMetadata = (skillsDir, skillName) =>
|
|
2976
|
+
var removeFromMetadata = (skillsDir, skillName) => pipe5(
|
|
2124
2977
|
readMetadata(skillsDir),
|
|
2125
|
-
|
|
2978
|
+
Effect5.map((metadata) => ({
|
|
2126
2979
|
skills: metadata.skills.filter((s) => s.name !== skillName)
|
|
2127
2980
|
})),
|
|
2128
|
-
|
|
2981
|
+
Effect5.flatMap((metadata) => writeMetadata(skillsDir, metadata))
|
|
2129
2982
|
);
|
|
2130
|
-
var readMetadataAsync = (skillsDir) =>
|
|
2131
|
-
var updateMetadataAsync = (skillsDir, newSkills) =>
|
|
2132
|
-
var removeFromMetadataAsync = (skillsDir, skillName) =>
|
|
2983
|
+
var readMetadataAsync = (skillsDir) => Effect5.runPromise(readMetadata(skillsDir));
|
|
2984
|
+
var updateMetadataAsync = (skillsDir, newSkills) => Effect5.runPromise(updateMetadata(skillsDir, newSkills));
|
|
2985
|
+
var removeFromMetadataAsync = (skillsDir, skillName) => Effect5.runPromise(removeFromMetadata(skillsDir, skillName));
|
|
2133
2986
|
|
|
2134
2987
|
// src/lib/rule-writer.ts
|
|
2135
2988
|
init_esm_shims();
|
|
2136
|
-
import { mkdir as
|
|
2137
|
-
import { dirname as
|
|
2138
|
-
import { Data as
|
|
2139
|
-
var RuleWriteError = class extends
|
|
2989
|
+
import { mkdir as mkdir3, readFile as readFile3, writeFile as writeFile4 } from "fs/promises";
|
|
2990
|
+
import { dirname as dirname3, resolve as resolve2, sep as sep2 } from "path";
|
|
2991
|
+
import { Data as Data5, Effect as Effect6, pipe as pipe6 } from "effect";
|
|
2992
|
+
var RuleWriteError = class extends Data5.TaggedError("RuleWriteError") {
|
|
2140
2993
|
};
|
|
2141
|
-
var createDirectory = (dir) =>
|
|
2142
|
-
try: () =>
|
|
2994
|
+
var createDirectory = (dir) => Effect6.tryPromise({
|
|
2995
|
+
try: () => mkdir3(dir, { recursive: true }),
|
|
2143
2996
|
catch: (e) => new RuleWriteError({ path: dir, operation: "mkdir", cause: e })
|
|
2144
2997
|
});
|
|
2145
|
-
var writeTextFile = (fullPath, content) =>
|
|
2146
|
-
try: () =>
|
|
2998
|
+
var writeTextFile = (fullPath, content) => Effect6.tryPromise({
|
|
2999
|
+
try: () => writeFile4(fullPath, content, "utf-8"),
|
|
2147
3000
|
catch: (e) => new RuleWriteError({ path: fullPath, operation: "write", cause: e })
|
|
2148
3001
|
});
|
|
2149
|
-
var readTextFile = (fullPath) =>
|
|
3002
|
+
var readTextFile = (fullPath) => Effect6.tryPromise({
|
|
2150
3003
|
try: () => readFile3(fullPath, "utf-8"),
|
|
2151
3004
|
catch: (e) => new RuleWriteError({ path: fullPath, operation: "read", cause: e })
|
|
2152
3005
|
});
|
|
2153
3006
|
var assertRulePathWithinBase = (basePath, ruleName) => {
|
|
2154
|
-
const resolvedBase =
|
|
2155
|
-
const resolvedFull =
|
|
2156
|
-
if (resolvedFull !== resolvedBase && !resolvedFull.startsWith(resolvedBase +
|
|
2157
|
-
return
|
|
3007
|
+
const resolvedBase = resolve2(basePath);
|
|
3008
|
+
const resolvedFull = resolve2(basePath, ruleName);
|
|
3009
|
+
if (resolvedFull !== resolvedBase && !resolvedFull.startsWith(resolvedBase + sep2)) {
|
|
3010
|
+
return Effect6.fail(
|
|
2158
3011
|
new RuleWriteError({
|
|
2159
3012
|
path: ruleName,
|
|
2160
3013
|
operation: "write",
|
|
@@ -2164,7 +3017,7 @@ var assertRulePathWithinBase = (basePath, ruleName) => {
|
|
|
2164
3017
|
})
|
|
2165
3018
|
);
|
|
2166
3019
|
}
|
|
2167
|
-
return
|
|
3020
|
+
return Effect6.succeed(resolvedFull);
|
|
2168
3021
|
};
|
|
2169
3022
|
var BRAID_SECTION_START = "<!-- braid:rules:start -->";
|
|
2170
3023
|
var BRAID_SECTION_END = "<!-- braid:rules:end -->";
|
|
@@ -2197,30 +3050,30 @@ function buildAppendContent(rules2) {
|
|
|
2197
3050
|
lines.push(BRAID_SECTION_END);
|
|
2198
3051
|
return lines.join("\n");
|
|
2199
3052
|
}
|
|
2200
|
-
var writeMdcRules = (basePath, rules2) =>
|
|
3053
|
+
var writeMdcRules = (basePath, rules2) => pipe6(
|
|
2201
3054
|
createDirectory(basePath),
|
|
2202
|
-
|
|
2203
|
-
() =>
|
|
3055
|
+
Effect6.flatMap(
|
|
3056
|
+
() => Effect6.forEach(
|
|
2204
3057
|
rules2,
|
|
2205
|
-
(rule) =>
|
|
3058
|
+
(rule) => pipe6(
|
|
2206
3059
|
assertRulePathWithinBase(basePath, `${rule.name}.mdc`),
|
|
2207
|
-
|
|
3060
|
+
Effect6.flatMap(
|
|
2208
3061
|
(filePath) => writeTextFile(filePath, buildMdcContent(rule))
|
|
2209
3062
|
)
|
|
2210
3063
|
),
|
|
2211
3064
|
{ concurrency: "unbounded" }
|
|
2212
3065
|
)
|
|
2213
3066
|
),
|
|
2214
|
-
|
|
3067
|
+
Effect6.asVoid
|
|
2215
3068
|
);
|
|
2216
|
-
var writeMarkdownDirRules = (basePath, rules2) =>
|
|
3069
|
+
var writeMarkdownDirRules = (basePath, rules2) => pipe6(
|
|
2217
3070
|
createDirectory(basePath),
|
|
2218
|
-
|
|
2219
|
-
() =>
|
|
3071
|
+
Effect6.flatMap(
|
|
3072
|
+
() => Effect6.forEach(
|
|
2220
3073
|
rules2,
|
|
2221
|
-
(rule) =>
|
|
3074
|
+
(rule) => pipe6(
|
|
2222
3075
|
assertRulePathWithinBase(basePath, `${rule.name}.md`),
|
|
2223
|
-
|
|
3076
|
+
Effect6.flatMap(
|
|
2224
3077
|
(filePath) => writeTextFile(filePath, `# ${rule.title}
|
|
2225
3078
|
|
|
2226
3079
|
${rule.content}`)
|
|
@@ -2229,17 +3082,17 @@ ${rule.content}`)
|
|
|
2229
3082
|
{ concurrency: "unbounded" }
|
|
2230
3083
|
)
|
|
2231
3084
|
),
|
|
2232
|
-
|
|
3085
|
+
Effect6.asVoid
|
|
2233
3086
|
);
|
|
2234
|
-
var writeAppendSingleRules = (filePath, rules2) =>
|
|
2235
|
-
createDirectory(
|
|
2236
|
-
|
|
2237
|
-
() =>
|
|
3087
|
+
var writeAppendSingleRules = (filePath, rules2) => pipe6(
|
|
3088
|
+
createDirectory(dirname3(filePath)),
|
|
3089
|
+
Effect6.flatMap(
|
|
3090
|
+
() => pipe6(
|
|
2238
3091
|
readTextFile(filePath),
|
|
2239
|
-
|
|
3092
|
+
Effect6.orElseSucceed(() => "")
|
|
2240
3093
|
)
|
|
2241
3094
|
),
|
|
2242
|
-
|
|
3095
|
+
Effect6.flatMap((existing) => {
|
|
2243
3096
|
const braidContent = buildAppendContent(rules2);
|
|
2244
3097
|
const startIdx = existing.indexOf(BRAID_SECTION_START);
|
|
2245
3098
|
const endIdx = existing.indexOf(BRAID_SECTION_END);
|
|
@@ -2263,21 +3116,21 @@ var writeRulesForFormat = (basePath, rules2, format) => {
|
|
|
2263
3116
|
case "append-single":
|
|
2264
3117
|
return writeAppendSingleRules(basePath, rules2);
|
|
2265
3118
|
default:
|
|
2266
|
-
return
|
|
3119
|
+
return Effect6.void;
|
|
2267
3120
|
}
|
|
2268
3121
|
};
|
|
2269
3122
|
var writeRulesForAgent = (agent, rules2, rulesPath) => {
|
|
2270
3123
|
if (!agent.ruleFormat || rules2.length === 0) {
|
|
2271
|
-
return
|
|
3124
|
+
return Effect6.succeed({ written: 0, errors: [] });
|
|
2272
3125
|
}
|
|
2273
|
-
return
|
|
3126
|
+
return pipe6(
|
|
2274
3127
|
writeRulesForFormat(rulesPath, rules2, agent.ruleFormat),
|
|
2275
|
-
|
|
3128
|
+
Effect6.map(() => ({
|
|
2276
3129
|
written: rules2.length,
|
|
2277
3130
|
errors: []
|
|
2278
3131
|
})),
|
|
2279
|
-
|
|
2280
|
-
(error) =>
|
|
3132
|
+
Effect6.catchAll(
|
|
3133
|
+
(error) => Effect6.succeed({
|
|
2281
3134
|
written: 0,
|
|
2282
3135
|
errors: [
|
|
2283
3136
|
{
|
|
@@ -2289,36 +3142,36 @@ var writeRulesForAgent = (agent, rules2, rulesPath) => {
|
|
|
2289
3142
|
)
|
|
2290
3143
|
);
|
|
2291
3144
|
};
|
|
2292
|
-
var writeRulesForAgentAsync = (agent, rules2, rulesPath) =>
|
|
3145
|
+
var writeRulesForAgentAsync = (agent, rules2, rulesPath) => Effect6.runPromise(writeRulesForAgent(agent, rules2, rulesPath));
|
|
2293
3146
|
|
|
2294
3147
|
// src/lib/skill-writer.ts
|
|
2295
3148
|
init_esm_shims();
|
|
2296
|
-
import { chmod, mkdir as
|
|
2297
|
-
import { dirname as
|
|
2298
|
-
import { Data as
|
|
2299
|
-
var WriteError = class extends
|
|
3149
|
+
import { chmod, mkdir as mkdir4, writeFile as writeFile5 } from "fs/promises";
|
|
3150
|
+
import { dirname as dirname4, resolve as resolve3, sep as sep3 } from "path";
|
|
3151
|
+
import { Data as Data6, Effect as Effect7, pipe as pipe7 } from "effect";
|
|
3152
|
+
var WriteError = class extends Data6.TaggedError("WriteError") {
|
|
2300
3153
|
};
|
|
2301
|
-
var createDirectory2 = (dir, fullPath) =>
|
|
2302
|
-
try: () =>
|
|
3154
|
+
var createDirectory2 = (dir, fullPath) => Effect7.tryPromise({
|
|
3155
|
+
try: () => mkdir4(dir, { recursive: true }),
|
|
2303
3156
|
catch: (e) => new WriteError({ path: fullPath, operation: "mkdir", cause: e })
|
|
2304
3157
|
});
|
|
2305
|
-
var writeTextFile2 = (fullPath, content) =>
|
|
2306
|
-
try: () =>
|
|
3158
|
+
var writeTextFile2 = (fullPath, content) => Effect7.tryPromise({
|
|
3159
|
+
try: () => writeFile5(fullPath, content, "utf-8"),
|
|
2307
3160
|
catch: (e) => new WriteError({ path: fullPath, operation: "write", cause: e })
|
|
2308
3161
|
});
|
|
2309
|
-
var writeBinaryFile = (fullPath, content) =>
|
|
2310
|
-
try: () =>
|
|
3162
|
+
var writeBinaryFile = (fullPath, content) => Effect7.tryPromise({
|
|
3163
|
+
try: () => writeFile5(fullPath, content),
|
|
2311
3164
|
catch: (e) => new WriteError({ path: fullPath, operation: "write", cause: e })
|
|
2312
3165
|
});
|
|
2313
|
-
var makeExecutable = (fullPath) =>
|
|
3166
|
+
var makeExecutable = (fullPath) => Effect7.tryPromise({
|
|
2314
3167
|
try: () => chmod(fullPath, 493),
|
|
2315
3168
|
catch: (e) => new WriteError({ path: fullPath, operation: "chmod", cause: e })
|
|
2316
3169
|
});
|
|
2317
|
-
var
|
|
2318
|
-
const resolvedBase =
|
|
2319
|
-
const resolvedFull =
|
|
2320
|
-
if (resolvedFull !== resolvedBase && !resolvedFull.startsWith(resolvedBase +
|
|
2321
|
-
return
|
|
3170
|
+
var assertWithinBase2 = (basePath, untrustedPath) => {
|
|
3171
|
+
const resolvedBase = resolve3(basePath);
|
|
3172
|
+
const resolvedFull = resolve3(basePath, untrustedPath);
|
|
3173
|
+
if (resolvedFull !== resolvedBase && !resolvedFull.startsWith(resolvedBase + sep3)) {
|
|
3174
|
+
return Effect7.fail(
|
|
2322
3175
|
new WriteError({
|
|
2323
3176
|
path: untrustedPath,
|
|
2324
3177
|
operation: "write",
|
|
@@ -2328,7 +3181,7 @@ var assertWithinBase = (basePath, untrustedPath) => {
|
|
|
2328
3181
|
})
|
|
2329
3182
|
);
|
|
2330
3183
|
}
|
|
2331
|
-
return
|
|
3184
|
+
return Effect7.succeed(resolvedFull);
|
|
2332
3185
|
};
|
|
2333
3186
|
var COMPATIBILITY_REGEX = /^compatibility:\s*.+$/m;
|
|
2334
3187
|
var rewriteCompatibility = (content, agentId) => {
|
|
@@ -2371,41 +3224,41 @@ var isScriptFile = (path2) => {
|
|
|
2371
3224
|
return inScriptsDir && scriptExtensions.some((ext) => lowerPath.endsWith(ext));
|
|
2372
3225
|
};
|
|
2373
3226
|
var writeFileContent = (fullPath, file, agentId) => isBinaryFile(file.path) ? writeBinaryFile(fullPath, decodeFileContentBinary(file)) : writeTextFile2(fullPath, decodeFileContent(file, agentId));
|
|
2374
|
-
var setExecutableIfScript = (fullPath,
|
|
2375
|
-
var writeSkillFile = (basePath, file, agentId) =>
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
const dir =
|
|
2379
|
-
return
|
|
3227
|
+
var setExecutableIfScript = (fullPath, file, agentId) => isScriptFile(file.path) && decodeFileContent(file, agentId).startsWith("#!") ? makeExecutable(fullPath) : Effect7.void;
|
|
3228
|
+
var writeSkillFile = (basePath, file, agentId) => pipe7(
|
|
3229
|
+
assertWithinBase2(basePath, file.path),
|
|
3230
|
+
Effect7.flatMap((fullPath) => {
|
|
3231
|
+
const dir = dirname4(fullPath);
|
|
3232
|
+
return pipe7(
|
|
2380
3233
|
createDirectory2(dir, fullPath),
|
|
2381
|
-
|
|
2382
|
-
|
|
3234
|
+
Effect7.flatMap(() => writeFileContent(fullPath, file, agentId)),
|
|
3235
|
+
Effect7.flatMap(() => setExecutableIfScript(fullPath, file, agentId))
|
|
2383
3236
|
);
|
|
2384
3237
|
})
|
|
2385
3238
|
);
|
|
2386
|
-
var writeSkill = (basePath, skill, agentId) =>
|
|
2387
|
-
|
|
2388
|
-
|
|
2389
|
-
(skillDir) =>
|
|
2390
|
-
|
|
3239
|
+
var writeSkill = (basePath, skill, agentId) => pipe7(
|
|
3240
|
+
assertWithinBase2(basePath, skill.name),
|
|
3241
|
+
Effect7.flatMap(
|
|
3242
|
+
(skillDir) => pipe7(
|
|
3243
|
+
Effect7.forEach(
|
|
2391
3244
|
skill.files,
|
|
2392
3245
|
(file) => writeSkillFile(skillDir, file, agentId),
|
|
2393
3246
|
{
|
|
2394
3247
|
concurrency: "unbounded"
|
|
2395
3248
|
}
|
|
2396
3249
|
),
|
|
2397
|
-
|
|
3250
|
+
Effect7.map(() => void 0)
|
|
2398
3251
|
)
|
|
2399
3252
|
)
|
|
2400
3253
|
);
|
|
2401
|
-
var writeSkills = (basePath, skills2, agentId) =>
|
|
2402
|
-
|
|
3254
|
+
var writeSkills = (basePath, skills2, agentId) => pipe7(
|
|
3255
|
+
Effect7.forEach(
|
|
2403
3256
|
skills2,
|
|
2404
|
-
(skill) =>
|
|
3257
|
+
(skill) => pipe7(
|
|
2405
3258
|
writeSkill(basePath, skill, agentId),
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
(error) =>
|
|
3259
|
+
Effect7.map(() => ({ success: true, skill: skill.name })),
|
|
3260
|
+
Effect7.catchAll(
|
|
3261
|
+
(error) => Effect7.succeed({
|
|
2409
3262
|
success: false,
|
|
2410
3263
|
skill: skill.name,
|
|
2411
3264
|
error: error.cause instanceof Error ? error.cause.message : String(error.cause)
|
|
@@ -2414,14 +3267,14 @@ var writeSkills = (basePath, skills2, agentId) => pipe6(
|
|
|
2414
3267
|
),
|
|
2415
3268
|
{ concurrency: "unbounded" }
|
|
2416
3269
|
),
|
|
2417
|
-
|
|
3270
|
+
Effect7.map((results) => ({
|
|
2418
3271
|
written: results.filter((r) => r.success).map((r) => r.skill),
|
|
2419
3272
|
errors: results.filter(
|
|
2420
3273
|
(r) => !r.success
|
|
2421
3274
|
).map((r) => ({ skill: r.skill, error: r.error }))
|
|
2422
3275
|
}))
|
|
2423
3276
|
);
|
|
2424
|
-
var writeSkillsAsync = (basePath, skills2, agentId) =>
|
|
3277
|
+
var writeSkillsAsync = (basePath, skills2, agentId) => Effect7.runPromise(writeSkills(basePath, skills2, agentId));
|
|
2425
3278
|
|
|
2426
3279
|
// src/commands/install.ts
|
|
2427
3280
|
init_tui();
|
|
@@ -2982,31 +3835,34 @@ init_config();
|
|
|
2982
3835
|
|
|
2983
3836
|
// src/lib/mcp-config.ts
|
|
2984
3837
|
init_esm_shims();
|
|
2985
|
-
import { mkdir as
|
|
2986
|
-
import { dirname as
|
|
2987
|
-
import { Data as
|
|
2988
|
-
var McpConfigReadError = class extends
|
|
3838
|
+
import { mkdir as mkdir5, readFile as readFile4, writeFile as writeFile6 } from "fs/promises";
|
|
3839
|
+
import { dirname as dirname5 } from "path";
|
|
3840
|
+
import { Data as Data7, Effect as Effect8, pipe as pipe8 } from "effect";
|
|
3841
|
+
var McpConfigReadError = class extends Data7.TaggedError("McpConfigReadError") {
|
|
2989
3842
|
};
|
|
2990
|
-
var McpConfigWriteError = class extends
|
|
3843
|
+
var McpConfigWriteError = class extends Data7.TaggedError("McpConfigWriteError") {
|
|
2991
3844
|
};
|
|
2992
|
-
var readMcpConfig = (path2) =>
|
|
2993
|
-
|
|
3845
|
+
var readMcpConfig = (path2) => pipe8(
|
|
3846
|
+
Effect8.tryPromise({
|
|
2994
3847
|
try: () => readFile4(path2, "utf-8"),
|
|
2995
3848
|
catch: (e) => new McpConfigReadError({ path: path2, cause: e })
|
|
2996
3849
|
}),
|
|
2997
|
-
|
|
2998
|
-
(content) =>
|
|
3850
|
+
Effect8.flatMap(
|
|
3851
|
+
(content) => Effect8.try({
|
|
2999
3852
|
try: () => JSON.parse(content),
|
|
3000
3853
|
catch: () => ({})
|
|
3001
3854
|
})
|
|
3002
3855
|
),
|
|
3003
|
-
|
|
3856
|
+
Effect8.orElseSucceed(() => ({}))
|
|
3004
3857
|
);
|
|
3005
|
-
var writeMcpConfig = (path2, config) =>
|
|
3858
|
+
var writeMcpConfig = (path2, config) => Effect8.tryPromise({
|
|
3006
3859
|
try: async () => {
|
|
3007
|
-
await
|
|
3008
|
-
await
|
|
3009
|
-
`,
|
|
3860
|
+
await mkdir5(dirname5(path2), { recursive: true, mode: 448 });
|
|
3861
|
+
await writeFile6(path2, `${JSON.stringify(config, null, 2)}
|
|
3862
|
+
`, {
|
|
3863
|
+
encoding: "utf-8",
|
|
3864
|
+
mode: 384
|
|
3865
|
+
});
|
|
3010
3866
|
},
|
|
3011
3867
|
catch: (e) => new McpConfigWriteError({ path: path2, cause: e })
|
|
3012
3868
|
});
|
|
@@ -3032,8 +3888,8 @@ var hasbraidEntry = (config, rootKey, entryName) => {
|
|
|
3032
3888
|
const servers = config[rootKey];
|
|
3033
3889
|
return servers !== void 0 && entryName in servers;
|
|
3034
3890
|
};
|
|
3035
|
-
var readMcpConfigAsync = (path2) =>
|
|
3036
|
-
var writeMcpConfigAsync = (path2, config) =>
|
|
3891
|
+
var readMcpConfigAsync = (path2) => Effect8.runPromise(readMcpConfig(path2));
|
|
3892
|
+
var writeMcpConfigAsync = (path2, config) => Effect8.runPromise(writeMcpConfig(path2, config));
|
|
3037
3893
|
|
|
3038
3894
|
// src/commands/mcp.ts
|
|
3039
3895
|
init_tui();
|
|
@@ -3346,16 +4202,16 @@ init_esm_shims();
|
|
|
3346
4202
|
init_api();
|
|
3347
4203
|
init_tui();
|
|
3348
4204
|
import process9 from "process";
|
|
3349
|
-
var
|
|
4205
|
+
var writeJson3 = (value) => {
|
|
3350
4206
|
process9.stdout.write(`${JSON.stringify(value, null, 2)}
|
|
3351
4207
|
`);
|
|
3352
4208
|
};
|
|
3353
|
-
var
|
|
4209
|
+
var exitWithError3 = (error) => {
|
|
3354
4210
|
const message = error instanceof Error ? error.message : String(error);
|
|
3355
4211
|
log.error(message);
|
|
3356
4212
|
process9.exit(1);
|
|
3357
4213
|
};
|
|
3358
|
-
var
|
|
4214
|
+
var fail2 = (message) => {
|
|
3359
4215
|
throw new Error(message);
|
|
3360
4216
|
};
|
|
3361
4217
|
var parseContext = (contextJson) => {
|
|
@@ -3364,7 +4220,7 @@ var parseContext = (contextJson) => {
|
|
|
3364
4220
|
}
|
|
3365
4221
|
return JSON.parse(contextJson);
|
|
3366
4222
|
};
|
|
3367
|
-
var
|
|
4223
|
+
var run2 = async (command, args, options) => {
|
|
3368
4224
|
const apiOptions = {
|
|
3369
4225
|
...options.server ? { serverUrl: options.server } : {},
|
|
3370
4226
|
...options.apiKey ? { apiKey: options.apiKey } : {}
|
|
@@ -3378,44 +4234,44 @@ var run = async (command, args, options) => {
|
|
|
3378
4234
|
apiOptions
|
|
3379
4235
|
);
|
|
3380
4236
|
if (options.json) {
|
|
3381
|
-
|
|
4237
|
+
writeJson3(result);
|
|
3382
4238
|
return;
|
|
3383
4239
|
}
|
|
3384
4240
|
log.success(`profiles ${command} completed`);
|
|
3385
4241
|
};
|
|
3386
4242
|
async function profilesListCommand(options) {
|
|
3387
4243
|
try {
|
|
3388
|
-
await
|
|
4244
|
+
await run2("list", {}, options);
|
|
3389
4245
|
} catch (error) {
|
|
3390
|
-
|
|
4246
|
+
exitWithError3(error);
|
|
3391
4247
|
}
|
|
3392
4248
|
}
|
|
3393
4249
|
async function profilesGetCommand(options) {
|
|
3394
4250
|
try {
|
|
3395
4251
|
if (!(options.id || options.name)) {
|
|
3396
|
-
|
|
4252
|
+
fail2("profiles get requires --id or --name");
|
|
3397
4253
|
}
|
|
3398
|
-
await
|
|
4254
|
+
await run2("get", { id: options.id, name: options.name }, options);
|
|
3399
4255
|
} catch (error) {
|
|
3400
|
-
|
|
4256
|
+
exitWithError3(error);
|
|
3401
4257
|
}
|
|
3402
4258
|
}
|
|
3403
4259
|
async function profilesCreateCommand(options) {
|
|
3404
4260
|
try {
|
|
3405
|
-
const name = options.name ??
|
|
3406
|
-
await
|
|
4261
|
+
const name = options.name ?? fail2("profiles create requires --name");
|
|
4262
|
+
await run2(
|
|
3407
4263
|
"create",
|
|
3408
4264
|
{ name, context: parseContext(options.contextJson) },
|
|
3409
4265
|
options
|
|
3410
4266
|
);
|
|
3411
4267
|
} catch (error) {
|
|
3412
|
-
|
|
4268
|
+
exitWithError3(error);
|
|
3413
4269
|
}
|
|
3414
4270
|
}
|
|
3415
4271
|
async function profilesUpdateCommand(options) {
|
|
3416
4272
|
try {
|
|
3417
|
-
const id = options.id ??
|
|
3418
|
-
await
|
|
4273
|
+
const id = options.id ?? fail2("profiles update requires --id");
|
|
4274
|
+
await run2(
|
|
3419
4275
|
"update",
|
|
3420
4276
|
{
|
|
3421
4277
|
id,
|
|
@@ -3425,26 +4281,26 @@ async function profilesUpdateCommand(options) {
|
|
|
3425
4281
|
options
|
|
3426
4282
|
);
|
|
3427
4283
|
} catch (error) {
|
|
3428
|
-
|
|
4284
|
+
exitWithError3(error);
|
|
3429
4285
|
}
|
|
3430
4286
|
}
|
|
3431
4287
|
async function profilesRemoveCommand(options) {
|
|
3432
4288
|
try {
|
|
3433
|
-
const id = options.id ??
|
|
4289
|
+
const id = options.id ?? fail2("profiles remove requires --id");
|
|
3434
4290
|
if (!options.yes) {
|
|
3435
|
-
|
|
4291
|
+
fail2("profiles remove requires --yes");
|
|
3436
4292
|
}
|
|
3437
|
-
await
|
|
4293
|
+
await run2("remove", { id, yes: true }, options);
|
|
3438
4294
|
} catch (error) {
|
|
3439
|
-
|
|
4295
|
+
exitWithError3(error);
|
|
3440
4296
|
}
|
|
3441
4297
|
}
|
|
3442
4298
|
async function profilesSetDefaultCommand(options) {
|
|
3443
4299
|
try {
|
|
3444
|
-
const id = options.id ??
|
|
3445
|
-
await
|
|
4300
|
+
const id = options.id ?? fail2("profiles set-default requires --id");
|
|
4301
|
+
await run2("set-default", { id }, options);
|
|
3446
4302
|
} catch (error) {
|
|
3447
|
-
|
|
4303
|
+
exitWithError3(error);
|
|
3448
4304
|
}
|
|
3449
4305
|
}
|
|
3450
4306
|
|
|
@@ -3453,14 +4309,14 @@ init_esm_shims();
|
|
|
3453
4309
|
init_api();
|
|
3454
4310
|
init_tui();
|
|
3455
4311
|
import process10 from "process";
|
|
3456
|
-
var
|
|
4312
|
+
var writeJson4 = (value) => {
|
|
3457
4313
|
process10.stdout.write(`${JSON.stringify(value, null, 2)}
|
|
3458
4314
|
`);
|
|
3459
4315
|
};
|
|
3460
|
-
var
|
|
4316
|
+
var fail3 = (message) => {
|
|
3461
4317
|
throw new Error(message);
|
|
3462
4318
|
};
|
|
3463
|
-
var
|
|
4319
|
+
var run3 = async (command, args, options) => {
|
|
3464
4320
|
const apiOptions = {
|
|
3465
4321
|
...options.server ? { serverUrl: options.server } : {},
|
|
3466
4322
|
...options.apiKey ? { apiKey: options.apiKey } : {}
|
|
@@ -3474,40 +4330,40 @@ var run2 = async (command, args, options) => {
|
|
|
3474
4330
|
apiOptions
|
|
3475
4331
|
);
|
|
3476
4332
|
if (options.json) {
|
|
3477
|
-
|
|
4333
|
+
writeJson4(result);
|
|
3478
4334
|
return;
|
|
3479
4335
|
}
|
|
3480
4336
|
log.success(`projects ${command} completed`);
|
|
3481
4337
|
};
|
|
3482
|
-
var
|
|
4338
|
+
var exitWithError4 = (error) => {
|
|
3483
4339
|
const message = error instanceof Error ? error.message : String(error);
|
|
3484
4340
|
log.error(message);
|
|
3485
4341
|
process10.exit(1);
|
|
3486
4342
|
};
|
|
3487
4343
|
async function projectsGetCommand(options) {
|
|
3488
4344
|
try {
|
|
3489
|
-
const id = options.id ??
|
|
3490
|
-
await
|
|
4345
|
+
const id = options.id ?? fail3("projects get requires --id");
|
|
4346
|
+
await run3("get", { id }, options);
|
|
3491
4347
|
} catch (error) {
|
|
3492
|
-
|
|
4348
|
+
exitWithError4(error);
|
|
3493
4349
|
}
|
|
3494
4350
|
}
|
|
3495
4351
|
async function projectsCreateCommand(options) {
|
|
3496
4352
|
try {
|
|
3497
|
-
const name = options.name ??
|
|
3498
|
-
await
|
|
4353
|
+
const name = options.name ?? fail3("projects create requires --name");
|
|
4354
|
+
await run3(
|
|
3499
4355
|
"create",
|
|
3500
4356
|
{ name, description: options.description, orgId: options.orgId },
|
|
3501
4357
|
options
|
|
3502
4358
|
);
|
|
3503
4359
|
} catch (error) {
|
|
3504
|
-
|
|
4360
|
+
exitWithError4(error);
|
|
3505
4361
|
}
|
|
3506
4362
|
}
|
|
3507
4363
|
async function projectsUpdateCommand(options) {
|
|
3508
4364
|
try {
|
|
3509
|
-
const id = options.id ??
|
|
3510
|
-
await
|
|
4365
|
+
const id = options.id ?? fail3("projects update requires --id");
|
|
4366
|
+
await run3(
|
|
3511
4367
|
"update",
|
|
3512
4368
|
{
|
|
3513
4369
|
id,
|
|
@@ -3517,18 +4373,18 @@ async function projectsUpdateCommand(options) {
|
|
|
3517
4373
|
options
|
|
3518
4374
|
);
|
|
3519
4375
|
} catch (error) {
|
|
3520
|
-
|
|
4376
|
+
exitWithError4(error);
|
|
3521
4377
|
}
|
|
3522
4378
|
}
|
|
3523
4379
|
async function projectsRemoveCommand(options) {
|
|
3524
4380
|
try {
|
|
3525
|
-
const id = options.id ??
|
|
4381
|
+
const id = options.id ?? fail3("projects remove requires --id");
|
|
3526
4382
|
if (!options.yes) {
|
|
3527
|
-
|
|
4383
|
+
fail3("projects remove requires --yes");
|
|
3528
4384
|
}
|
|
3529
|
-
await
|
|
4385
|
+
await run3("remove", { id, yes: true }, options);
|
|
3530
4386
|
} catch (error) {
|
|
3531
|
-
|
|
4387
|
+
exitWithError4(error);
|
|
3532
4388
|
}
|
|
3533
4389
|
}
|
|
3534
4390
|
|
|
@@ -3537,26 +4393,26 @@ init_esm_shims();
|
|
|
3537
4393
|
init_api();
|
|
3538
4394
|
init_tui();
|
|
3539
4395
|
import process11 from "process";
|
|
3540
|
-
var
|
|
4396
|
+
var writeJson5 = (value) => {
|
|
3541
4397
|
process11.stdout.write(`${JSON.stringify(value, null, 2)}
|
|
3542
4398
|
`);
|
|
3543
4399
|
};
|
|
3544
|
-
var
|
|
4400
|
+
var parseCsv3 = (input) => {
|
|
3545
4401
|
if (!input) {
|
|
3546
4402
|
return void 0;
|
|
3547
4403
|
}
|
|
3548
4404
|
const values = input.split(",").map((value) => value.trim()).filter((value) => value.length > 0);
|
|
3549
4405
|
return values.length > 0 ? values : void 0;
|
|
3550
4406
|
};
|
|
3551
|
-
var
|
|
4407
|
+
var exitWithError5 = (error) => {
|
|
3552
4408
|
const message = error instanceof Error ? error.message : String(error);
|
|
3553
4409
|
log.error(message);
|
|
3554
4410
|
process11.exit(1);
|
|
3555
4411
|
};
|
|
3556
|
-
var
|
|
4412
|
+
var fail4 = (message) => {
|
|
3557
4413
|
throw new Error(message);
|
|
3558
4414
|
};
|
|
3559
|
-
var
|
|
4415
|
+
var run4 = async (command, args, options) => {
|
|
3560
4416
|
const apiOptions = {
|
|
3561
4417
|
...options.server ? { serverUrl: options.server } : {},
|
|
3562
4418
|
...options.apiKey ? { apiKey: options.apiKey } : {}
|
|
@@ -3570,76 +4426,76 @@ var run3 = async (command, args, options) => {
|
|
|
3570
4426
|
apiOptions
|
|
3571
4427
|
);
|
|
3572
4428
|
if (options.json) {
|
|
3573
|
-
|
|
4429
|
+
writeJson5(result);
|
|
3574
4430
|
return;
|
|
3575
4431
|
}
|
|
3576
4432
|
log.success(`references ${command} completed`);
|
|
3577
4433
|
};
|
|
3578
4434
|
async function referencesListCommand(options) {
|
|
3579
4435
|
try {
|
|
3580
|
-
const ruleId = options.ruleId ??
|
|
3581
|
-
await
|
|
4436
|
+
const ruleId = options.ruleId ?? fail4("references list requires --rule-id");
|
|
4437
|
+
await run4("list", { ruleId }, options);
|
|
3582
4438
|
} catch (error) {
|
|
3583
|
-
|
|
4439
|
+
exitWithError5(error);
|
|
3584
4440
|
}
|
|
3585
4441
|
}
|
|
3586
4442
|
async function referencesGetCommand(options) {
|
|
3587
4443
|
try {
|
|
3588
|
-
const id = options.id ??
|
|
3589
|
-
await
|
|
4444
|
+
const id = options.id ?? fail4("references get requires --id");
|
|
4445
|
+
await run4("get", { id }, options);
|
|
3590
4446
|
} catch (error) {
|
|
3591
|
-
|
|
4447
|
+
exitWithError5(error);
|
|
3592
4448
|
}
|
|
3593
4449
|
}
|
|
3594
4450
|
async function referencesCreateCommand(options) {
|
|
3595
4451
|
try {
|
|
3596
|
-
const ruleId = options.ruleId ??
|
|
3597
|
-
const file = options.file ??
|
|
3598
|
-
await
|
|
4452
|
+
const ruleId = options.ruleId ?? fail4("references create requires --rule-id");
|
|
4453
|
+
const file = options.file ?? fail4("references create requires --file");
|
|
4454
|
+
await run4("create", { ruleId, file }, options);
|
|
3599
4455
|
} catch (error) {
|
|
3600
|
-
|
|
4456
|
+
exitWithError5(error);
|
|
3601
4457
|
}
|
|
3602
4458
|
}
|
|
3603
4459
|
async function referencesUpdateCommand(options) {
|
|
3604
4460
|
try {
|
|
3605
|
-
const id = options.id ??
|
|
3606
|
-
await
|
|
4461
|
+
const id = options.id ?? fail4("references update requires --id");
|
|
4462
|
+
await run4(
|
|
3607
4463
|
"update",
|
|
3608
4464
|
{ id, label: options.label, replaceFile: options.replaceFile },
|
|
3609
4465
|
options
|
|
3610
4466
|
);
|
|
3611
4467
|
} catch (error) {
|
|
3612
|
-
|
|
4468
|
+
exitWithError5(error);
|
|
3613
4469
|
}
|
|
3614
4470
|
}
|
|
3615
4471
|
async function referencesRemoveCommand(options) {
|
|
3616
4472
|
try {
|
|
3617
|
-
const id = options.id ??
|
|
4473
|
+
const id = options.id ?? fail4("references remove requires --id");
|
|
3618
4474
|
if (!options.yes) {
|
|
3619
|
-
|
|
4475
|
+
fail4("references remove requires --yes");
|
|
3620
4476
|
}
|
|
3621
|
-
await
|
|
4477
|
+
await run4("remove", { id, yes: true }, options);
|
|
3622
4478
|
} catch (error) {
|
|
3623
|
-
|
|
4479
|
+
exitWithError5(error);
|
|
3624
4480
|
}
|
|
3625
4481
|
}
|
|
3626
4482
|
async function referencesReorderCommand(options) {
|
|
3627
4483
|
try {
|
|
3628
|
-
const ruleId = options.ruleId ??
|
|
3629
|
-
const orderedIds =
|
|
4484
|
+
const ruleId = options.ruleId ?? fail4("references reorder requires --rule-id");
|
|
4485
|
+
const orderedIds = parseCsv3(options.orderedIds);
|
|
3630
4486
|
if (!orderedIds || orderedIds.length === 0) {
|
|
3631
|
-
|
|
4487
|
+
fail4("references reorder requires --ordered-ids");
|
|
3632
4488
|
}
|
|
3633
|
-
await
|
|
4489
|
+
await run4("reorder", { ruleId, orderedIds }, options);
|
|
3634
4490
|
} catch (error) {
|
|
3635
|
-
|
|
4491
|
+
exitWithError5(error);
|
|
3636
4492
|
}
|
|
3637
4493
|
}
|
|
3638
4494
|
|
|
3639
4495
|
// src/commands/remove.ts
|
|
3640
4496
|
init_esm_shims();
|
|
3641
4497
|
import { rm } from "fs/promises";
|
|
3642
|
-
import { join as join4, resolve as
|
|
4498
|
+
import { join as join4, resolve as resolve4 } from "path";
|
|
3643
4499
|
import process12 from "process";
|
|
3644
4500
|
init_tui();
|
|
3645
4501
|
async function collectInstalledSkills(detectedAgents, options) {
|
|
@@ -3712,8 +4568,8 @@ async function confirmRemoval(selectedCount, options) {
|
|
|
3712
4568
|
async function removeSkill(skill, removeSpinner) {
|
|
3713
4569
|
removeSpinner.start(`Removing ${skill.name} from ${skill.agentName}...`);
|
|
3714
4570
|
try {
|
|
3715
|
-
const resolvedSkillPath =
|
|
3716
|
-
const resolvedInstallPath =
|
|
4571
|
+
const resolvedSkillPath = resolve4(skill.skillPath);
|
|
4572
|
+
const resolvedInstallPath = resolve4(skill.installPath);
|
|
3717
4573
|
if (!resolvedSkillPath.startsWith(`${resolvedInstallPath}/`)) {
|
|
3718
4574
|
removeSpinner.stop(`Unsafe path for ${skill.name}`);
|
|
3719
4575
|
log.warn(" Skill path escapes install directory, skipping.");
|
|
@@ -3779,26 +4635,26 @@ init_esm_shims();
|
|
|
3779
4635
|
init_api();
|
|
3780
4636
|
init_tui();
|
|
3781
4637
|
import process13 from "process";
|
|
3782
|
-
var
|
|
4638
|
+
var parseCsv4 = (input) => {
|
|
3783
4639
|
if (!input) {
|
|
3784
4640
|
return void 0;
|
|
3785
4641
|
}
|
|
3786
4642
|
const values = input.split(",").map((value) => value.trim()).filter((value) => value.length > 0);
|
|
3787
4643
|
return values.length > 0 ? values : void 0;
|
|
3788
4644
|
};
|
|
3789
|
-
var
|
|
4645
|
+
var writeJson6 = (value) => {
|
|
3790
4646
|
process13.stdout.write(`${JSON.stringify(value, null, 2)}
|
|
3791
4647
|
`);
|
|
3792
4648
|
};
|
|
3793
|
-
var
|
|
4649
|
+
var exitWithError6 = (error) => {
|
|
3794
4650
|
const message = error instanceof Error ? error.message : String(error);
|
|
3795
4651
|
log.error(message);
|
|
3796
4652
|
process13.exit(1);
|
|
3797
4653
|
};
|
|
3798
|
-
var
|
|
4654
|
+
var fail5 = (message) => {
|
|
3799
4655
|
throw new Error(message);
|
|
3800
4656
|
};
|
|
3801
|
-
var
|
|
4657
|
+
var run5 = async (command, args, options) => {
|
|
3802
4658
|
const apiOptions = {
|
|
3803
4659
|
...options.server ? { serverUrl: options.server } : {},
|
|
3804
4660
|
...options.apiKey ? { apiKey: options.apiKey } : {}
|
|
@@ -3812,161 +4668,161 @@ var run4 = async (command, args, options) => {
|
|
|
3812
4668
|
apiOptions
|
|
3813
4669
|
);
|
|
3814
4670
|
if (options.json) {
|
|
3815
|
-
|
|
4671
|
+
writeJson6(result);
|
|
3816
4672
|
return;
|
|
3817
4673
|
}
|
|
3818
4674
|
log.success(`rules ${command} completed`);
|
|
3819
4675
|
};
|
|
3820
4676
|
async function rulesGetCommand(options) {
|
|
3821
4677
|
try {
|
|
3822
|
-
const id = options.id ??
|
|
3823
|
-
await
|
|
4678
|
+
const id = options.id ?? fail5("rules get requires --id");
|
|
4679
|
+
await run5("get", { id }, options);
|
|
3824
4680
|
} catch (error) {
|
|
3825
|
-
|
|
4681
|
+
exitWithError6(error);
|
|
3826
4682
|
}
|
|
3827
4683
|
}
|
|
3828
4684
|
async function rulesCreateCommand(options) {
|
|
3829
4685
|
try {
|
|
3830
|
-
const title = options.title ??
|
|
3831
|
-
const content = options.content ??
|
|
3832
|
-
await
|
|
4686
|
+
const title = options.title ?? fail5("rules create requires --title");
|
|
4687
|
+
const content = options.content ?? fail5("rules create requires --content");
|
|
4688
|
+
await run5(
|
|
3833
4689
|
"create",
|
|
3834
4690
|
{
|
|
3835
4691
|
title,
|
|
3836
4692
|
content,
|
|
3837
4693
|
projectId: options.projectId,
|
|
3838
|
-
tags:
|
|
4694
|
+
tags: parseCsv4(options.tags),
|
|
3839
4695
|
priority: options.priority
|
|
3840
4696
|
},
|
|
3841
4697
|
options
|
|
3842
4698
|
);
|
|
3843
4699
|
} catch (error) {
|
|
3844
|
-
|
|
4700
|
+
exitWithError6(error);
|
|
3845
4701
|
}
|
|
3846
4702
|
}
|
|
3847
4703
|
async function rulesUpdateCommand(options) {
|
|
3848
4704
|
try {
|
|
3849
|
-
const id = options.id ??
|
|
3850
|
-
await
|
|
4705
|
+
const id = options.id ?? fail5("rules update requires --id");
|
|
4706
|
+
await run5(
|
|
3851
4707
|
"update",
|
|
3852
4708
|
{
|
|
3853
4709
|
id,
|
|
3854
4710
|
title: options.title,
|
|
3855
4711
|
content: options.content,
|
|
3856
|
-
tags:
|
|
4712
|
+
tags: parseCsv4(options.tags),
|
|
3857
4713
|
priority: options.priority
|
|
3858
4714
|
},
|
|
3859
4715
|
options
|
|
3860
4716
|
);
|
|
3861
4717
|
} catch (error) {
|
|
3862
|
-
|
|
4718
|
+
exitWithError6(error);
|
|
3863
4719
|
}
|
|
3864
4720
|
}
|
|
3865
4721
|
async function rulesRemoveCommand(options) {
|
|
3866
4722
|
try {
|
|
3867
|
-
const id = options.id ??
|
|
4723
|
+
const id = options.id ?? fail5("rules remove requires --id");
|
|
3868
4724
|
if (!options.yes) {
|
|
3869
|
-
|
|
4725
|
+
fail5("rules remove requires --yes");
|
|
3870
4726
|
}
|
|
3871
|
-
await
|
|
4727
|
+
await run5("remove", { id, yes: true }, options);
|
|
3872
4728
|
} catch (error) {
|
|
3873
|
-
|
|
4729
|
+
exitWithError6(error);
|
|
3874
4730
|
}
|
|
3875
4731
|
}
|
|
3876
4732
|
async function rulesEnableCommand(options) {
|
|
3877
4733
|
try {
|
|
3878
|
-
const id = options.id ??
|
|
3879
|
-
await
|
|
4734
|
+
const id = options.id ?? fail5("rules enable requires --id");
|
|
4735
|
+
await run5("enable", { id }, options);
|
|
3880
4736
|
} catch (error) {
|
|
3881
|
-
|
|
4737
|
+
exitWithError6(error);
|
|
3882
4738
|
}
|
|
3883
4739
|
}
|
|
3884
4740
|
async function rulesDisableCommand(options) {
|
|
3885
4741
|
try {
|
|
3886
|
-
const id = options.id ??
|
|
3887
|
-
await
|
|
4742
|
+
const id = options.id ?? fail5("rules disable requires --id");
|
|
4743
|
+
await run5("disable", { id }, options);
|
|
3888
4744
|
} catch (error) {
|
|
3889
|
-
|
|
4745
|
+
exitWithError6(error);
|
|
3890
4746
|
}
|
|
3891
4747
|
}
|
|
3892
4748
|
async function rulesMoveCommand(options) {
|
|
3893
4749
|
try {
|
|
3894
|
-
const id = options.id ??
|
|
3895
|
-
const projectId = options.projectId ??
|
|
3896
|
-
await
|
|
4750
|
+
const id = options.id ?? fail5("rules move requires --id");
|
|
4751
|
+
const projectId = options.projectId ?? fail5("rules move requires --project-id");
|
|
4752
|
+
await run5("move", { id, projectId }, options);
|
|
3897
4753
|
} catch (error) {
|
|
3898
|
-
|
|
4754
|
+
exitWithError6(error);
|
|
3899
4755
|
}
|
|
3900
4756
|
}
|
|
3901
4757
|
async function rulesDuplicateCommand(options) {
|
|
3902
4758
|
try {
|
|
3903
|
-
const id = options.id ??
|
|
3904
|
-
await
|
|
4759
|
+
const id = options.id ?? fail5("rules duplicate requires --id");
|
|
4760
|
+
await run5(
|
|
3905
4761
|
"duplicate",
|
|
3906
4762
|
{ id, targetProjectId: options.targetProjectId },
|
|
3907
4763
|
options
|
|
3908
4764
|
);
|
|
3909
4765
|
} catch (error) {
|
|
3910
|
-
|
|
4766
|
+
exitWithError6(error);
|
|
3911
4767
|
}
|
|
3912
4768
|
}
|
|
3913
4769
|
async function rulesForkCommand(options) {
|
|
3914
4770
|
try {
|
|
3915
|
-
const id = options.id ??
|
|
3916
|
-
await
|
|
4771
|
+
const id = options.id ?? fail5("rules fork requires --id");
|
|
4772
|
+
await run5(
|
|
3917
4773
|
"fork",
|
|
3918
4774
|
{ id, targetProjectId: options.targetProjectId },
|
|
3919
4775
|
options
|
|
3920
4776
|
);
|
|
3921
4777
|
} catch (error) {
|
|
3922
|
-
|
|
4778
|
+
exitWithError6(error);
|
|
3923
4779
|
}
|
|
3924
4780
|
}
|
|
3925
4781
|
async function rulesSyncStatusCommand(options) {
|
|
3926
4782
|
try {
|
|
3927
|
-
await
|
|
4783
|
+
await run5("sync-status", { id: options.id }, options);
|
|
3928
4784
|
} catch (error) {
|
|
3929
|
-
|
|
4785
|
+
exitWithError6(error);
|
|
3930
4786
|
}
|
|
3931
4787
|
}
|
|
3932
4788
|
async function rulesSyncHistoryCommand(options) {
|
|
3933
4789
|
try {
|
|
3934
|
-
const id = options.id ??
|
|
3935
|
-
await
|
|
4790
|
+
const id = options.id ?? fail5("rules sync-history requires --id");
|
|
4791
|
+
await run5("sync-history", { id }, options);
|
|
3936
4792
|
} catch (error) {
|
|
3937
|
-
|
|
4793
|
+
exitWithError6(error);
|
|
3938
4794
|
}
|
|
3939
4795
|
}
|
|
3940
4796
|
async function rulesSyncEnableCommand(options) {
|
|
3941
4797
|
try {
|
|
3942
|
-
const id = options.id ??
|
|
3943
|
-
await
|
|
4798
|
+
const id = options.id ?? fail5("rules sync-enable requires --id");
|
|
4799
|
+
await run5("sync-enable", { id }, options);
|
|
3944
4800
|
} catch (error) {
|
|
3945
|
-
|
|
4801
|
+
exitWithError6(error);
|
|
3946
4802
|
}
|
|
3947
4803
|
}
|
|
3948
4804
|
async function rulesSyncDisableCommand(options) {
|
|
3949
4805
|
try {
|
|
3950
|
-
const id = options.id ??
|
|
3951
|
-
await
|
|
4806
|
+
const id = options.id ?? fail5("rules sync-disable requires --id");
|
|
4807
|
+
await run5("sync-disable", { id }, options);
|
|
3952
4808
|
} catch (error) {
|
|
3953
|
-
|
|
4809
|
+
exitWithError6(error);
|
|
3954
4810
|
}
|
|
3955
4811
|
}
|
|
3956
4812
|
async function rulesSyncCheckCommand(options) {
|
|
3957
4813
|
try {
|
|
3958
|
-
const id = options.id ??
|
|
3959
|
-
await
|
|
4814
|
+
const id = options.id ?? fail5("rules sync-check requires --id");
|
|
4815
|
+
await run5("sync-check", { id }, options);
|
|
3960
4816
|
} catch (error) {
|
|
3961
|
-
|
|
4817
|
+
exitWithError6(error);
|
|
3962
4818
|
}
|
|
3963
4819
|
}
|
|
3964
4820
|
async function rulesSyncNowCommand(options) {
|
|
3965
4821
|
try {
|
|
3966
|
-
const id = options.id ??
|
|
3967
|
-
await
|
|
4822
|
+
const id = options.id ?? fail5("rules sync-now requires --id");
|
|
4823
|
+
await run5("sync-now", { id }, options);
|
|
3968
4824
|
} catch (error) {
|
|
3969
|
-
|
|
4825
|
+
exitWithError6(error);
|
|
3970
4826
|
}
|
|
3971
4827
|
}
|
|
3972
4828
|
|
|
@@ -3983,11 +4839,11 @@ import {
|
|
|
3983
4839
|
outro as outro2,
|
|
3984
4840
|
spinner as spinner3
|
|
3985
4841
|
} from "@clack/prompts";
|
|
3986
|
-
import { Data as
|
|
4842
|
+
import { Data as Data8, Effect as Effect9, pipe as pipe9 } from "effect";
|
|
3987
4843
|
init_api();
|
|
3988
|
-
var UpdateError = class extends
|
|
4844
|
+
var UpdateError = class extends Data8.TaggedError("UpdateError") {
|
|
3989
4845
|
};
|
|
3990
|
-
var UserCancelledError = class extends
|
|
4846
|
+
var UserCancelledError = class extends Data8.TaggedError("UserCancelledError") {
|
|
3991
4847
|
};
|
|
3992
4848
|
async function resolveValidInstallPath(agent, options) {
|
|
3993
4849
|
const installPath = resolveInstallPath(agent, {
|
|
@@ -3999,7 +4855,7 @@ async function resolveValidInstallPath(agent, options) {
|
|
|
3999
4855
|
const exists = await directoryExistsAsync(installPath);
|
|
4000
4856
|
return exists ? installPath : null;
|
|
4001
4857
|
}
|
|
4002
|
-
var collectSourcesFromAgent = (agent, options, sourcesToUpdate) =>
|
|
4858
|
+
var collectSourcesFromAgent = (agent, options, sourcesToUpdate) => Effect9.tryPromise({
|
|
4003
4859
|
try: async () => {
|
|
4004
4860
|
const installPath = await resolveValidInstallPath(agent, options);
|
|
4005
4861
|
if (!installPath) {
|
|
@@ -4030,10 +4886,10 @@ var collectSourcesFromAgent = (agent, options, sourcesToUpdate) => Effect8.tryPr
|
|
|
4030
4886
|
},
|
|
4031
4887
|
catch: () => new UpdateError({ message: "Failed to collect sources" })
|
|
4032
4888
|
});
|
|
4033
|
-
var collectSources = (detectedAgents, options) =>
|
|
4034
|
-
|
|
4035
|
-
|
|
4036
|
-
(sourcesToUpdate) =>
|
|
4889
|
+
var collectSources = (detectedAgents, options) => pipe9(
|
|
4890
|
+
Effect9.succeed(/* @__PURE__ */ new Map()),
|
|
4891
|
+
Effect9.tap(
|
|
4892
|
+
(sourcesToUpdate) => Effect9.forEach(
|
|
4037
4893
|
detectedAgents,
|
|
4038
4894
|
(agent) => collectSourcesFromAgent(agent, options, sourcesToUpdate),
|
|
4039
4895
|
{ concurrency: 1 }
|
|
@@ -4042,9 +4898,9 @@ var collectSources = (detectedAgents, options) => pipe8(
|
|
|
4042
4898
|
);
|
|
4043
4899
|
var selectSources = (sourcesToUpdate, options) => {
|
|
4044
4900
|
if (options.yes) {
|
|
4045
|
-
return
|
|
4901
|
+
return Effect9.succeed(sourcesToUpdate);
|
|
4046
4902
|
}
|
|
4047
|
-
return
|
|
4903
|
+
return Effect9.tryPromise({
|
|
4048
4904
|
try: async () => {
|
|
4049
4905
|
const sources = Array.from(sourcesToUpdate.entries()).map(
|
|
4050
4906
|
([key, source]) => ({
|
|
@@ -4095,7 +4951,7 @@ var buildFetchOptionsForSource = (source, options) => {
|
|
|
4095
4951
|
}
|
|
4096
4952
|
return fetchOptions;
|
|
4097
4953
|
};
|
|
4098
|
-
var updateAgentSkills = (agentId, agentName, installPath, response, serverUrl, updateSpinner) =>
|
|
4954
|
+
var updateAgentSkills = (agentId, agentName, installPath, response, serverUrl, updateSpinner) => Effect9.tryPromise({
|
|
4099
4955
|
try: async () => {
|
|
4100
4956
|
updateSpinner.start(`Updating ${agentName}...`);
|
|
4101
4957
|
const result = await writeSkillsAsync(
|
|
@@ -4133,15 +4989,15 @@ var updateSource = (source, options, updateSpinner) => {
|
|
|
4133
4989
|
const serverUrl = options.server ?? source.serverUrl;
|
|
4134
4990
|
const fetchOptions = buildFetchOptionsForSource(source, options);
|
|
4135
4991
|
if (fetchOptions === null) {
|
|
4136
|
-
return
|
|
4992
|
+
return Effect9.fail(
|
|
4137
4993
|
new UpdateError({
|
|
4138
4994
|
message: "Skills installed with legacy metadata format. Please reinstall using 'braid install --profile <name>' or 'braid install --projects <names>'.",
|
|
4139
4995
|
source: sourceDesc
|
|
4140
4996
|
})
|
|
4141
4997
|
);
|
|
4142
4998
|
}
|
|
4143
|
-
return
|
|
4144
|
-
|
|
4999
|
+
return pipe9(
|
|
5000
|
+
Effect9.tryPromise({
|
|
4145
5001
|
try: async () => {
|
|
4146
5002
|
updateSpinner.start(`Fetching latest skills from ${sourceDesc}...`);
|
|
4147
5003
|
const response = await fetchSkillsAsync(fetchOptions);
|
|
@@ -4155,9 +5011,9 @@ var updateSource = (source, options, updateSpinner) => {
|
|
|
4155
5011
|
source: sourceDesc
|
|
4156
5012
|
})
|
|
4157
5013
|
}),
|
|
4158
|
-
|
|
4159
|
-
(response) =>
|
|
4160
|
-
|
|
5014
|
+
Effect9.flatMap(
|
|
5015
|
+
(response) => pipe9(
|
|
5016
|
+
Effect9.forEach(
|
|
4161
5017
|
source.agents,
|
|
4162
5018
|
({ agentId, agentName, installPath }) => updateAgentSkills(
|
|
4163
5019
|
agentId,
|
|
@@ -4169,7 +5025,7 @@ var updateSource = (source, options, updateSpinner) => {
|
|
|
4169
5025
|
),
|
|
4170
5026
|
{ concurrency: 1 }
|
|
4171
5027
|
),
|
|
4172
|
-
|
|
5028
|
+
Effect9.map((results) => ({
|
|
4173
5029
|
updated: results.reduce((sum, r) => sum + r.updated, 0),
|
|
4174
5030
|
errors: results.reduce((sum, r) => sum + r.errors, 0)
|
|
4175
5031
|
}))
|
|
@@ -4177,22 +5033,22 @@ var updateSource = (source, options, updateSpinner) => {
|
|
|
4177
5033
|
)
|
|
4178
5034
|
);
|
|
4179
5035
|
};
|
|
4180
|
-
var updateAllSources = (sources, options, updateSpinner) =>
|
|
4181
|
-
|
|
5036
|
+
var updateAllSources = (sources, options, updateSpinner) => pipe9(
|
|
5037
|
+
Effect9.forEach(
|
|
4182
5038
|
Array.from(sources.values()),
|
|
4183
|
-
(source) =>
|
|
5039
|
+
(source) => pipe9(
|
|
4184
5040
|
updateSource(source, options, updateSpinner),
|
|
4185
|
-
|
|
5041
|
+
Effect9.catchAll((error) => {
|
|
4186
5042
|
updateSpinner.stop(
|
|
4187
5043
|
`Failed to update from ${getSourceDesc(source)}`
|
|
4188
5044
|
);
|
|
4189
5045
|
log3.error(` ${error.message}`);
|
|
4190
|
-
return
|
|
5046
|
+
return Effect9.succeed({ updated: 0, errors: 1 });
|
|
4191
5047
|
})
|
|
4192
5048
|
),
|
|
4193
5049
|
{ concurrency: 1 }
|
|
4194
5050
|
),
|
|
4195
|
-
|
|
5051
|
+
Effect9.map((results) => ({
|
|
4196
5052
|
totalUpdated: results.reduce((sum, r) => sum + r.updated, 0),
|
|
4197
5053
|
totalErrors: results.reduce((sum, r) => sum + r.errors, 0)
|
|
4198
5054
|
}))
|
|
@@ -4231,28 +5087,28 @@ var handleProgramExit = (result, updateSpinner) => {
|
|
|
4231
5087
|
async function updateCommand(options) {
|
|
4232
5088
|
const updateSpinner = spinner3();
|
|
4233
5089
|
updateSpinner.start("Scanning for installed skills...");
|
|
4234
|
-
const program2 =
|
|
4235
|
-
|
|
5090
|
+
const program2 = pipe9(
|
|
5091
|
+
Effect9.tryPromise({
|
|
4236
5092
|
try: () => detectAgentsAsync(),
|
|
4237
5093
|
catch: () => new UpdateError({ message: "Failed to detect agents" })
|
|
4238
5094
|
}),
|
|
4239
|
-
|
|
4240
|
-
(
|
|
5095
|
+
Effect9.filterOrFail(
|
|
5096
|
+
(agents2) => agents2.length > 0,
|
|
4241
5097
|
() => new UpdateError({ message: "No AI coding agents detected." })
|
|
4242
5098
|
),
|
|
4243
|
-
|
|
4244
|
-
|
|
5099
|
+
Effect9.flatMap((detectedAgents) => collectSources(detectedAgents, options)),
|
|
5100
|
+
Effect9.tap((sources) => {
|
|
4245
5101
|
updateSpinner.stop(`Found ${sources.size} source(s) to update`);
|
|
4246
5102
|
}),
|
|
4247
|
-
|
|
5103
|
+
Effect9.filterOrFail(
|
|
4248
5104
|
(sources) => sources.size > 0,
|
|
4249
5105
|
() => new UpdateError({ message: "No skills installed via braid." })
|
|
4250
5106
|
),
|
|
4251
|
-
|
|
4252
|
-
|
|
5107
|
+
Effect9.flatMap((sources) => selectSources(sources, options)),
|
|
5108
|
+
Effect9.flatMap(
|
|
4253
5109
|
(selectedSources) => updateAllSources(selectedSources, options, updateSpinner)
|
|
4254
5110
|
),
|
|
4255
|
-
|
|
5111
|
+
Effect9.tap(({ totalUpdated, totalErrors }) => {
|
|
4256
5112
|
if (totalErrors > 0) {
|
|
4257
5113
|
outro2(`Updated ${totalUpdated} skills with ${totalErrors} errors.`);
|
|
4258
5114
|
} else {
|
|
@@ -4260,10 +5116,136 @@ async function updateCommand(options) {
|
|
|
4260
5116
|
}
|
|
4261
5117
|
})
|
|
4262
5118
|
);
|
|
4263
|
-
const result = await
|
|
5119
|
+
const result = await Effect9.runPromiseExit(program2);
|
|
4264
5120
|
handleProgramExit(result, updateSpinner);
|
|
4265
5121
|
}
|
|
4266
5122
|
|
|
5123
|
+
// src/commands/workflows.ts
|
|
5124
|
+
init_esm_shims();
|
|
5125
|
+
init_api();
|
|
5126
|
+
init_tui();
|
|
5127
|
+
import process14 from "process";
|
|
5128
|
+
var writeJson7 = (value) => {
|
|
5129
|
+
process14.stdout.write(`${JSON.stringify(value, null, 2)}
|
|
5130
|
+
`);
|
|
5131
|
+
};
|
|
5132
|
+
var fail6 = (message) => {
|
|
5133
|
+
throw new Error(message);
|
|
5134
|
+
};
|
|
5135
|
+
var parseMetadata = (metadata) => {
|
|
5136
|
+
if (!metadata) {
|
|
5137
|
+
return void 0;
|
|
5138
|
+
}
|
|
5139
|
+
try {
|
|
5140
|
+
return JSON.parse(metadata);
|
|
5141
|
+
} catch {
|
|
5142
|
+
throw new Error("metadata must be valid JSON");
|
|
5143
|
+
}
|
|
5144
|
+
};
|
|
5145
|
+
var run6 = async (command, args, options) => {
|
|
5146
|
+
const apiOptions = {
|
|
5147
|
+
...options.server ? { serverUrl: options.server } : {},
|
|
5148
|
+
...options.apiKey ? { apiKey: options.apiKey } : {}
|
|
5149
|
+
};
|
|
5150
|
+
const result = await runLifecycleCommandAsync(
|
|
5151
|
+
{
|
|
5152
|
+
domain: "workflows",
|
|
5153
|
+
command,
|
|
5154
|
+
args
|
|
5155
|
+
},
|
|
5156
|
+
apiOptions
|
|
5157
|
+
);
|
|
5158
|
+
if (options.json) {
|
|
5159
|
+
writeJson7(result);
|
|
5160
|
+
return;
|
|
5161
|
+
}
|
|
5162
|
+
log.success(`workflows ${command} completed`);
|
|
5163
|
+
};
|
|
5164
|
+
var exitWithError7 = (error) => {
|
|
5165
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
5166
|
+
log.error(message);
|
|
5167
|
+
process14.exit(1);
|
|
5168
|
+
};
|
|
5169
|
+
async function workflowsListCommand(options) {
|
|
5170
|
+
try {
|
|
5171
|
+
await run6("list", { projectId: options.projectId }, options);
|
|
5172
|
+
} catch (error) {
|
|
5173
|
+
exitWithError7(error);
|
|
5174
|
+
}
|
|
5175
|
+
}
|
|
5176
|
+
async function workflowsStartCommand(options) {
|
|
5177
|
+
try {
|
|
5178
|
+
const sessionId = options.sessionId ?? fail6("workflows start requires --session-id");
|
|
5179
|
+
const flowId = options.flowId ?? fail6("workflows start requires --flow-id");
|
|
5180
|
+
await run6(
|
|
5181
|
+
"start",
|
|
5182
|
+
{
|
|
5183
|
+
sessionId,
|
|
5184
|
+
flowId,
|
|
5185
|
+
currentNodeId: options.currentNodeId,
|
|
5186
|
+
currentStepLabel: options.currentStepLabel,
|
|
5187
|
+
metadata: parseMetadata(options.metadata)
|
|
5188
|
+
},
|
|
5189
|
+
options
|
|
5190
|
+
);
|
|
5191
|
+
} catch (error) {
|
|
5192
|
+
exitWithError7(error);
|
|
5193
|
+
}
|
|
5194
|
+
}
|
|
5195
|
+
async function workflowsProgressCommand(options) {
|
|
5196
|
+
try {
|
|
5197
|
+
const executionId = options.executionId ?? fail6("workflows progress requires --execution-id");
|
|
5198
|
+
await run6(
|
|
5199
|
+
"progress",
|
|
5200
|
+
{
|
|
5201
|
+
executionId,
|
|
5202
|
+
currentNodeId: options.currentNodeId,
|
|
5203
|
+
currentStepLabel: options.currentStepLabel,
|
|
5204
|
+
metadata: parseMetadata(options.metadata)
|
|
5205
|
+
},
|
|
5206
|
+
options
|
|
5207
|
+
);
|
|
5208
|
+
} catch (error) {
|
|
5209
|
+
exitWithError7(error);
|
|
5210
|
+
}
|
|
5211
|
+
}
|
|
5212
|
+
async function workflowsActiveCommand(options) {
|
|
5213
|
+
try {
|
|
5214
|
+
const sessionId = options.sessionId ?? fail6("workflows active requires --session-id");
|
|
5215
|
+
await run6("active", { sessionId }, options);
|
|
5216
|
+
} catch (error) {
|
|
5217
|
+
exitWithError7(error);
|
|
5218
|
+
}
|
|
5219
|
+
}
|
|
5220
|
+
async function workflowsCompleteCommand(options) {
|
|
5221
|
+
try {
|
|
5222
|
+
const executionId = options.executionId ?? fail6("workflows complete requires --execution-id");
|
|
5223
|
+
await run6("complete", { executionId }, options);
|
|
5224
|
+
} catch (error) {
|
|
5225
|
+
exitWithError7(error);
|
|
5226
|
+
}
|
|
5227
|
+
}
|
|
5228
|
+
async function workflowsFailCommand(options) {
|
|
5229
|
+
try {
|
|
5230
|
+
const executionId = options.executionId ?? fail6("workflows fail requires --execution-id");
|
|
5231
|
+
await run6(
|
|
5232
|
+
"fail",
|
|
5233
|
+
{ executionId, errorMessage: options.errorMessage },
|
|
5234
|
+
options
|
|
5235
|
+
);
|
|
5236
|
+
} catch (error) {
|
|
5237
|
+
exitWithError7(error);
|
|
5238
|
+
}
|
|
5239
|
+
}
|
|
5240
|
+
async function workflowsCancelCommand(options) {
|
|
5241
|
+
try {
|
|
5242
|
+
const executionId = options.executionId ?? fail6("workflows cancel requires --execution-id");
|
|
5243
|
+
await run6("cancel", { executionId }, options);
|
|
5244
|
+
} catch (error) {
|
|
5245
|
+
exitWithError7(error);
|
|
5246
|
+
}
|
|
5247
|
+
}
|
|
5248
|
+
|
|
4267
5249
|
// src/index.ts
|
|
4268
5250
|
var require2 = createRequire(import.meta.url);
|
|
4269
5251
|
var { version: PACKAGE_VERSION } = require2("../package.json");
|
|
@@ -4272,7 +5254,13 @@ program.name("braid").description(
|
|
|
4272
5254
|
"Install braid prompts as agent skills to your local development environment"
|
|
4273
5255
|
).version(PACKAGE_VERSION);
|
|
4274
5256
|
var auth = program.command("auth").description("Configure API key for braid authentication");
|
|
4275
|
-
auth.command("login", { isDefault: true }).description("
|
|
5257
|
+
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(
|
|
5258
|
+
"--token <token>",
|
|
5259
|
+
"API key for non-interactive login (skips device flow)"
|
|
5260
|
+
).option(
|
|
5261
|
+
"--timeout <seconds>",
|
|
5262
|
+
"Device flow timeout in seconds (default: 300)"
|
|
5263
|
+
).option("--no-scope", "Skip scope setup after login").action(authCommand);
|
|
4276
5264
|
auth.command("status").description("Show current authentication status").action(authStatusCommand);
|
|
4277
5265
|
auth.command("logout").description("Remove stored API key").action(authLogoutCommand);
|
|
4278
5266
|
program.command("install").alias("add").description(
|
|
@@ -4353,6 +5341,24 @@ profiles.command("create").description("Create profile").requiredOption("--name
|
|
|
4353
5341
|
profiles.command("update").description("Update profile").requiredOption("--id <id>", "Profile ID").option("--name <name>", "Profile name").option("--context-json <json>", "Context JSON").option("-s, --server <url>", "braid server URL (for review apps, local dev)").option("--api-key <token>", "API key override").option("--json", "Output JSON").action(profilesUpdateCommand);
|
|
4354
5342
|
profiles.command("remove").description("Remove profile").requiredOption("--id <id>", "Profile ID").option("-y, --yes", "Confirm destructive action").option("-s, --server <url>", "braid server URL (for review apps, local dev)").option("--api-key <token>", "API key override").option("--json", "Output JSON").action(profilesRemoveCommand);
|
|
4355
5343
|
profiles.command("set-default").description("Set default profile").requiredOption("--id <id>", "Profile ID").option("-s, --server <url>", "braid server URL (for review apps, local dev)").option("--api-key <token>", "API key override").option("--json", "Output JSON").action(profilesSetDefaultCommand);
|
|
5344
|
+
var agents = program.command("agents").description("Manage agent artifacts");
|
|
5345
|
+
var workflows = program.command("workflows").description("Manage local workflow execution lifecycle");
|
|
5346
|
+
workflows.command("list").description("List control flows available for execution").option("--project-id <id>", "Project ID filter").option("-s, --server <url>", "braid server URL (for review apps, local dev)").option("--api-key <token>", "API key override").option("--json", "Output JSON").action(workflowsListCommand);
|
|
5347
|
+
workflows.command("start").description("Start a workflow execution for a CLI session").requiredOption("--session-id <id>", "CLI session ID").requiredOption("--flow-id <id>", "Control flow ID").option("--current-node-id <id>", "Current node ID").option("--current-step-label <label>", "Current step label").option("--metadata <json>", "JSON metadata payload").option("-s, --server <url>", "braid server URL (for review apps, local dev)").option("--api-key <token>", "API key override").option("--json", "Output JSON").action(workflowsStartCommand);
|
|
5348
|
+
workflows.command("progress").description("Update workflow execution progress").requiredOption("--execution-id <id>", "Workflow execution ID").option("--current-node-id <id>", "Current node ID").option("--current-step-label <label>", "Current step label").option("--metadata <json>", "JSON metadata payload").option("-s, --server <url>", "braid server URL (for review apps, local dev)").option("--api-key <token>", "API key override").option("--json", "Output JSON").action(workflowsProgressCommand);
|
|
5349
|
+
workflows.command("active").description("Get active workflow execution for a CLI session").requiredOption("--session-id <id>", "CLI session 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(workflowsActiveCommand);
|
|
5350
|
+
workflows.command("complete").description("Mark a workflow execution complete").requiredOption("--execution-id <id>", "Workflow execution 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(workflowsCompleteCommand);
|
|
5351
|
+
workflows.command("fail").description("Mark a workflow execution failed").requiredOption("--execution-id <id>", "Workflow execution ID").option("--error-message <message>", "Failure message").option("-s, --server <url>", "braid server URL (for review apps, local dev)").option("--api-key <token>", "API key override").option("--json", "Output JSON").action(workflowsFailCommand);
|
|
5352
|
+
workflows.command("cancel").description("Cancel a workflow execution").requiredOption("--execution-id <id>", "Workflow execution 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(workflowsCancelCommand);
|
|
5353
|
+
agents.command("list").description("List saved agents").option("-s, --server <url>", "braid server URL (for review apps, local dev)").option("--api-key <token>", "API key override").option("--json", "Output JSON").action(agentsListCommand);
|
|
5354
|
+
agents.command("get").description("Get an agent by id").requiredOption("--id <id>", "Agent 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(agentsGetCommand);
|
|
5355
|
+
agents.command("create").description("Create an agent").requiredOption("--name <name>", "Agent name").requiredOption("--description <description>", "Agent description").requiredOption("--prompt <prompt>", "Agent system prompt").option("--scope <scope>", "Scope: global or project").option("--project-id <id>", "Project ID for project-scoped agent").option("--mode <mode>", "Mode: primary, subagent, all").option("--model <model>", "Model override").option("--skills <list>", "Comma-separated skill names").option("-s, --server <url>", "braid server URL (for review apps, local dev)").option("--api-key <token>", "API key override").option("--json", "Output JSON").action(agentsCreateCommand);
|
|
5356
|
+
agents.command("update").description("Update an agent").requiredOption("--id <id>", "Agent ID").option("--name <name>", "Agent name").option("--description <description>", "Agent description").option("--prompt <prompt>", "Agent system prompt").option("--mode <mode>", "Mode: primary, subagent, all").option("--model <model>", "Model override").option("--skills <list>", "Comma-separated skill names").option("-s, --server <url>", "braid server URL (for review apps, local dev)").option("--api-key <token>", "API key override").option("--json", "Output JSON").action(agentsUpdateCommand);
|
|
5357
|
+
agents.command("remove").description("Remove an agent").requiredOption("--id <id>", "Agent ID").option("-y, --yes", "Confirm destructive action").option("-s, --server <url>", "braid server URL (for review apps, local dev)").option("--api-key <token>", "API key override").option("--json", "Output JSON").action(agentsRemoveCommand);
|
|
5358
|
+
agents.command("install").description("Install a saved agent to local coding tools").requiredOption("--id <id>", "Agent ID").option(
|
|
5359
|
+
"-a, --agents <list>",
|
|
5360
|
+
"Comma-separated list of target coding tools (eg. claude-code,opencode)"
|
|
5361
|
+
).option("-g, --global", "Install to global agent directories").option("-s, --server <url>", "braid server URL (for review apps, local dev)").option("--api-key <token>", "API key override").option("--json", "Output JSON").action(agentsInstallCommand);
|
|
4356
5362
|
var references = program.command("references").description("Manage rule references");
|
|
4357
5363
|
references.command("list").description("List references for a rule").requiredOption("--rule-id <id>", "Rule ID").option("-s, --server <url>", "braid server URL (for review apps, local dev)").option("--api-key <token>", "API key override").option("--json", "Output JSON").action(referencesListCommand);
|
|
4358
5364
|
references.command("get").description("Get a reference by id").requiredOption("--id <id>", "Reference ID").option("-s, --server <url>", "braid server URL (for review apps, local dev)").option("--api-key <token>", "API key override").option("--json", "Output JSON").action(referencesGetCommand);
|