@baton-dx/cli 0.3.2 → 0.4.1
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/dist/ai-tool-detection-BFep6YS9.mjs +4 -0
- package/dist/{agent-detection-DTiVeO5W.mjs → ai-tool-detection-CMsBNa9e.mjs} +26 -82
- package/dist/ai-tool-detection-CMsBNa9e.mjs.map +1 -0
- package/dist/{create-BkpEXaht.mjs → create-DYQJmn8s.mjs} +3 -3
- package/dist/{create-BkpEXaht.mjs.map → create-DYQJmn8s.mjs.map} +1 -1
- package/dist/index.mjs +117 -176
- package/dist/index.mjs.map +1 -1
- package/dist/{list-DSLwzhBG.mjs → list-o1wqD5W_.mjs} +3 -3
- package/dist/{list-DSLwzhBG.mjs.map → list-o1wqD5W_.mjs.map} +1 -1
- package/dist/{src-BCGnnv5D.mjs → src-CHISlTPa.mjs} +140 -70
- package/dist/src-CHISlTPa.mjs.map +1 -0
- package/package.json +2 -2
- package/dist/agent-detection-DTiVeO5W.mjs.map +0 -1
- package/dist/agent-detection-l61K-AbU.mjs +0 -4
- package/dist/src-BCGnnv5D.mjs.map +0 -1
package/dist/index.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { r as __toESM } from "./chunk-BbwQpWto.mjs";
|
|
3
3
|
import { a as Ne, c as Ve, d as bt, f as je, g as runMain, h as defineCommand, i as Le, l as We, m as require_dist, o as R, p as Ct, r as Je, s as Re, t as findSourceRoot, u as Ze } from "./context-detection-DqOTnD6_.mjs";
|
|
4
|
-
import { $ as
|
|
5
|
-
import { n as
|
|
4
|
+
import { $ as loadProjectManifest, A as placeFile, B as ensureBatonDirGitignored, C as getProfileWeight, D as resolveProfileSupport, E as mergeContentParts, F as readLock, G as idePlatformRegistry, H as updateGitignore, I as writeLock, J as getAllAIToolAdapters, K as isKnownIdePlatform, L as resolveVersion, M as findSourceManifest, N as removePlacedFiles, O as resolveProfileChain, P as generateLock, Q as loadProfileManifest, R as cloneGitSource, S as mergeSkillsWithWarnings, T as sortProfilesByWeight, U as getIdePlatformTargetDir, V as removeGitignoreManagedSection, W as getRegisteredIdePlatforms, X as parseSource, Y as parseFrontmatter, Z as loadLockfile, _ as mergeMemoryWithWarnings, a as clearIdeCache, at as getAllAIToolKeys, b as mergeRulesWithWarnings, c as getDefaultGlobalSource, d as getGlobalSources, et as KEBAB_CASE_REGEX, f as removeGlobalSource, g as mergeMemory, h as require_lib, i as computeIntersection, it as getAIToolPath, j as discoverProfilesInSourceRepo, k as detectLegacyPaths, l as getGlobalAiTools, m as setGlobalIdePlatforms, n as readProjectPreferences, nt as SourceParseError, o as detectInstalledIdes, p as setGlobalAiTools, q as getAIToolAdaptersForKeys, r as writeProjectPreferences, rt as getAIToolConfig, s as addGlobalSource, t as resolvePreferences, tt as FileNotFoundError, u as getGlobalIdePlatforms, v as mergeAgentsWithWarnings, w as isLockedProfile, x as mergeSkills, y as mergeRules, z as collectComprehensivePatterns } from "./src-CHISlTPa.mjs";
|
|
5
|
+
import { n as detectInstalledAITools, t as clearAIToolCache } from "./ai-tool-detection-CMsBNa9e.mjs";
|
|
6
6
|
import { d as esm_default } from "./esm-BagM-kVd.mjs";
|
|
7
7
|
import { access, mkdir, readFile, readdir, rm, stat, writeFile } from "node:fs/promises";
|
|
8
8
|
import { dirname, isAbsolute, join, relative, resolve } from "node:path";
|
|
@@ -39,7 +39,7 @@ async function runGlobalMode$1(nonInteractive) {
|
|
|
39
39
|
Le("No changes made.");
|
|
40
40
|
return;
|
|
41
41
|
}
|
|
42
|
-
const options =
|
|
42
|
+
const options = getAllAIToolAdapters().map((adapter) => {
|
|
43
43
|
const isSaved = currentTools.includes(adapter.key);
|
|
44
44
|
return {
|
|
45
45
|
value: adapter.key,
|
|
@@ -125,7 +125,7 @@ async function runProjectMode$1(nonInteractive) {
|
|
|
125
125
|
Le("Configuration complete.");
|
|
126
126
|
return;
|
|
127
127
|
}
|
|
128
|
-
const allAdapters =
|
|
128
|
+
const allAdapters = getAllAIToolAdapters();
|
|
129
129
|
const currentProjectTools = existing?.ai.useGlobal === false ? existing.ai.tools : globalTools;
|
|
130
130
|
const options = allAdapters.map((adapter) => {
|
|
131
131
|
const isGlobal = globalTools.includes(adapter.key);
|
|
@@ -181,37 +181,37 @@ const aiToolsListCommand = defineCommand({
|
|
|
181
181
|
async run({ args }) {
|
|
182
182
|
if (!args.json) We("Baton - AI Tools");
|
|
183
183
|
const savedTools = await getGlobalAiTools();
|
|
184
|
-
const
|
|
185
|
-
const keysToShow = args.all ?
|
|
186
|
-
const
|
|
187
|
-
const isSaved = savedTools.includes(
|
|
184
|
+
const allAIToolKeys = getAllAIToolKeys();
|
|
185
|
+
const keysToShow = args.all ? allAIToolKeys : savedTools.length > 0 ? savedTools : allAIToolKeys;
|
|
186
|
+
const toolStatuses = await Promise.all(keysToShow.map(async (toolKey) => {
|
|
187
|
+
const isSaved = savedTools.includes(toolKey);
|
|
188
188
|
let skillCount = 0;
|
|
189
189
|
let ruleCount = 0;
|
|
190
|
-
let
|
|
190
|
+
let aiToolConfigCount = 0;
|
|
191
191
|
let memoryCount = 0;
|
|
192
192
|
let commandCount = 0;
|
|
193
193
|
if (isSaved) {
|
|
194
|
-
skillCount = await countConfigs(
|
|
195
|
-
ruleCount = await countConfigs(
|
|
196
|
-
|
|
197
|
-
memoryCount = await countConfigs(
|
|
198
|
-
commandCount = await countConfigs(
|
|
194
|
+
skillCount = await countConfigs(toolKey, "skills", "project");
|
|
195
|
+
ruleCount = await countConfigs(toolKey, "rules", "project");
|
|
196
|
+
aiToolConfigCount = await countConfigs(toolKey, "agents", "project");
|
|
197
|
+
memoryCount = await countConfigs(toolKey, "memory", "project");
|
|
198
|
+
commandCount = await countConfigs(toolKey, "commands", "project");
|
|
199
199
|
}
|
|
200
200
|
const paths = {
|
|
201
|
-
skills:
|
|
202
|
-
rules:
|
|
203
|
-
agents:
|
|
204
|
-
memory:
|
|
205
|
-
commands:
|
|
201
|
+
skills: getAIToolPath(toolKey, "skills", "project", ""),
|
|
202
|
+
rules: getAIToolPath(toolKey, "rules", "project", ""),
|
|
203
|
+
agents: getAIToolPath(toolKey, "agents", "project", ""),
|
|
204
|
+
memory: getAIToolPath(toolKey, "memory", "project", ""),
|
|
205
|
+
commands: getAIToolPath(toolKey, "commands", "project", "")
|
|
206
206
|
};
|
|
207
207
|
return {
|
|
208
|
-
key:
|
|
209
|
-
name:
|
|
208
|
+
key: toolKey,
|
|
209
|
+
name: getAIToolConfig(toolKey).name,
|
|
210
210
|
saved: isSaved,
|
|
211
211
|
counts: {
|
|
212
212
|
skills: skillCount,
|
|
213
213
|
rules: ruleCount,
|
|
214
|
-
agents:
|
|
214
|
+
agents: aiToolConfigCount,
|
|
215
215
|
memory: memoryCount,
|
|
216
216
|
commands: commandCount
|
|
217
217
|
},
|
|
@@ -219,23 +219,23 @@ const aiToolsListCommand = defineCommand({
|
|
|
219
219
|
};
|
|
220
220
|
}));
|
|
221
221
|
if (args.json) {
|
|
222
|
-
console.log(JSON.stringify(
|
|
222
|
+
console.log(JSON.stringify(toolStatuses, null, 2));
|
|
223
223
|
return;
|
|
224
224
|
}
|
|
225
225
|
if (savedTools.length === 0) {
|
|
226
226
|
R.warn("No AI tools saved in global config.");
|
|
227
227
|
R.info("Run 'baton ai-tools scan' to detect and save your AI tools.");
|
|
228
228
|
console.log("");
|
|
229
|
-
R.info(`All ${
|
|
230
|
-
for (const key of
|
|
231
|
-
const config =
|
|
229
|
+
R.info(`All ${allAIToolKeys.length} supported tools:`);
|
|
230
|
+
for (const key of allAIToolKeys) {
|
|
231
|
+
const config = getAIToolConfig(key);
|
|
232
232
|
console.log(` \x1b[90m- ${config.name}\x1b[0m`);
|
|
233
233
|
}
|
|
234
234
|
Le("Run 'baton ai-tools scan' to get started.");
|
|
235
235
|
return;
|
|
236
236
|
}
|
|
237
237
|
console.log(`\nSaved AI tools (${savedTools.length}):\n`);
|
|
238
|
-
for (const agent of
|
|
238
|
+
for (const agent of toolStatuses) {
|
|
239
239
|
const statusColor = agent.saved ? "\x1B[32m" : "\x1B[90m";
|
|
240
240
|
const status = agent.saved ? "✓" : "✗";
|
|
241
241
|
console.log(`${statusColor}${status}[0m ${agent.name.padEnd(20)}`);
|
|
@@ -252,15 +252,15 @@ const aiToolsListCommand = defineCommand({
|
|
|
252
252
|
}
|
|
253
253
|
console.log("");
|
|
254
254
|
}
|
|
255
|
-
Le("Manage tools: 'baton ai-tools scan' (detect) | 'baton
|
|
255
|
+
Le("Manage tools: 'baton ai-tools scan' (detect) | 'baton ai-tools configure' (select)");
|
|
256
256
|
}
|
|
257
257
|
});
|
|
258
258
|
/**
|
|
259
|
-
* Count config files of a given type for
|
|
259
|
+
* Count config files of a given type for a tool
|
|
260
260
|
*/
|
|
261
|
-
async function countConfigs(
|
|
261
|
+
async function countConfigs(toolKey, configType, scope) {
|
|
262
262
|
try {
|
|
263
|
-
const dirPath =
|
|
263
|
+
const dirPath = getAIToolPath(toolKey, configType, scope, "").replace(/{name}.*$/, "").replace(/\/$/, "");
|
|
264
264
|
if (!(await stat(dirPath)).isDirectory()) return 0;
|
|
265
265
|
return (await readdir(dirPath)).length;
|
|
266
266
|
} catch (_error) {
|
|
@@ -284,15 +284,15 @@ const aiToolsScanCommand = defineCommand({
|
|
|
284
284
|
We("Baton - AI Tool Scanner");
|
|
285
285
|
const spinner = bt();
|
|
286
286
|
spinner.start("Scanning for AI tools...");
|
|
287
|
-
|
|
288
|
-
const
|
|
289
|
-
const allAdapters =
|
|
287
|
+
clearAIToolCache();
|
|
288
|
+
const detectedAITools = await detectInstalledAITools();
|
|
289
|
+
const allAdapters = getAllAIToolAdapters();
|
|
290
290
|
const currentTools = await getGlobalAiTools();
|
|
291
291
|
spinner.stop("Scan complete.");
|
|
292
|
-
if (
|
|
292
|
+
if (detectedAITools.length > 0) R.success(`Found ${detectedAITools.length} AI tool${detectedAITools.length !== 1 ? "s" : ""} on your system.`);
|
|
293
293
|
else R.warn("No AI tools detected on your system.");
|
|
294
294
|
if (args.yes) {
|
|
295
|
-
const detectedKeys =
|
|
295
|
+
const detectedKeys = detectedAITools;
|
|
296
296
|
if (detectedKeys.length !== currentTools.length || detectedKeys.some((key) => !currentTools.includes(key))) {
|
|
297
297
|
await setGlobalAiTools(detectedKeys);
|
|
298
298
|
R.success(`Saved ${detectedKeys.length} detected tool(s) to global config.`);
|
|
@@ -301,7 +301,7 @@ const aiToolsScanCommand = defineCommand({
|
|
|
301
301
|
return;
|
|
302
302
|
}
|
|
303
303
|
const options = allAdapters.map((adapter) => {
|
|
304
|
-
const isDetected =
|
|
304
|
+
const isDetected = detectedAITools.includes(adapter.key);
|
|
305
305
|
return {
|
|
306
306
|
value: adapter.key,
|
|
307
307
|
label: isDetected ? `${adapter.name} (detected)` : adapter.name
|
|
@@ -310,7 +310,7 @@ const aiToolsScanCommand = defineCommand({
|
|
|
310
310
|
const selected = await je({
|
|
311
311
|
message: "Select which AI tools to save:",
|
|
312
312
|
options,
|
|
313
|
-
initialValues:
|
|
313
|
+
initialValues: detectedAITools
|
|
314
314
|
});
|
|
315
315
|
if (Ct(selected)) {
|
|
316
316
|
Le("Scan finished (not saved).");
|
|
@@ -341,7 +341,6 @@ const aiToolsCommand = defineCommand({
|
|
|
341
341
|
|
|
342
342
|
//#endregion
|
|
343
343
|
//#region src/utils/build-intersection.ts
|
|
344
|
-
var import_dist = require_dist();
|
|
345
344
|
/**
|
|
346
345
|
* Compute the intersection for a single profile source string.
|
|
347
346
|
* Shared utility used by sync, config, and manage commands.
|
|
@@ -420,26 +419,6 @@ function formatIntersectionSummary(intersection) {
|
|
|
420
419
|
|
|
421
420
|
//#endregion
|
|
422
421
|
//#region src/commands/config.ts
|
|
423
|
-
const VALID_KEYS = [
|
|
424
|
-
"cache-dir",
|
|
425
|
-
"default-scope",
|
|
426
|
-
"symlink-mode",
|
|
427
|
-
"default-tools"
|
|
428
|
-
];
|
|
429
|
-
async function loadConfig() {
|
|
430
|
-
const configFile = getGlobalConfigPath();
|
|
431
|
-
try {
|
|
432
|
-
await access(configFile);
|
|
433
|
-
} catch {
|
|
434
|
-
return {};
|
|
435
|
-
}
|
|
436
|
-
return (0, import_dist.parse)(await readFile(configFile, "utf-8"));
|
|
437
|
-
}
|
|
438
|
-
async function saveConfig(config) {
|
|
439
|
-
const configFile = getGlobalConfigPath();
|
|
440
|
-
await mkdir(getBatonHome(), { recursive: true });
|
|
441
|
-
await writeFile(configFile, (0, import_dist.stringify)(config), "utf-8");
|
|
442
|
-
}
|
|
443
422
|
async function showDashboard() {
|
|
444
423
|
We("Baton Dashboard");
|
|
445
424
|
const [sources, aiTools, idePlatforms, projectManifest] = await Promise.all([
|
|
@@ -467,7 +446,7 @@ async function showDashboard() {
|
|
|
467
446
|
if (resolvedAiTools.length > 0) {
|
|
468
447
|
const toolNames = resolvedAiTools.map((key) => {
|
|
469
448
|
try {
|
|
470
|
-
return
|
|
449
|
+
return getAIToolConfig(key).name;
|
|
471
450
|
} catch {
|
|
472
451
|
return key;
|
|
473
452
|
}
|
|
@@ -485,7 +464,7 @@ async function showDashboard() {
|
|
|
485
464
|
if (aiTools.length > 0) {
|
|
486
465
|
const toolNames = aiTools.map((key) => {
|
|
487
466
|
try {
|
|
488
|
-
return
|
|
467
|
+
return getAIToolConfig(key).name;
|
|
489
468
|
} catch {
|
|
490
469
|
return key;
|
|
491
470
|
}
|
|
@@ -520,7 +499,7 @@ async function showDashboard() {
|
|
|
520
499
|
}
|
|
521
500
|
}
|
|
522
501
|
console.log("");
|
|
523
|
-
Le("
|
|
502
|
+
Le("Manage tools: 'baton ai-tools configure' | 'baton ides configure'");
|
|
524
503
|
}
|
|
525
504
|
async function loadProjectManifestSafe$1() {
|
|
526
505
|
try {
|
|
@@ -532,101 +511,10 @@ async function loadProjectManifestSafe$1() {
|
|
|
532
511
|
const configCommand = defineCommand({
|
|
533
512
|
meta: {
|
|
534
513
|
name: "config",
|
|
535
|
-
description: "Show Baton dashboard overview
|
|
536
|
-
},
|
|
537
|
-
args: {
|
|
538
|
-
action: {
|
|
539
|
-
type: "positional",
|
|
540
|
-
description: "Action: set, get, or list",
|
|
541
|
-
required: false
|
|
542
|
-
},
|
|
543
|
-
key: {
|
|
544
|
-
type: "positional",
|
|
545
|
-
description: "Configuration key",
|
|
546
|
-
required: false
|
|
547
|
-
},
|
|
548
|
-
value: {
|
|
549
|
-
type: "positional",
|
|
550
|
-
description: "Configuration value (for set)",
|
|
551
|
-
required: false
|
|
552
|
-
}
|
|
514
|
+
description: "Show Baton dashboard overview"
|
|
553
515
|
},
|
|
554
|
-
async run(
|
|
555
|
-
|
|
556
|
-
const key = args.key;
|
|
557
|
-
const value = args.value;
|
|
558
|
-
if (!action) {
|
|
559
|
-
await showDashboard();
|
|
560
|
-
return;
|
|
561
|
-
}
|
|
562
|
-
const selectedAction = action;
|
|
563
|
-
if (selectedAction === "list") {
|
|
564
|
-
We("⚙️ Baton Configuration");
|
|
565
|
-
const config = await loadConfig();
|
|
566
|
-
if (Object.keys(config).length === 0) {
|
|
567
|
-
Le("No configuration set. Using defaults.");
|
|
568
|
-
return;
|
|
569
|
-
}
|
|
570
|
-
console.log("");
|
|
571
|
-
for (const [configKey, configValue] of Object.entries(config)) console.log(`${configKey}: ${Array.isArray(configValue) ? configValue.join(", ") : configValue}`);
|
|
572
|
-
console.log("");
|
|
573
|
-
Le("Configuration loaded");
|
|
574
|
-
return;
|
|
575
|
-
}
|
|
576
|
-
if (selectedAction === "get") {
|
|
577
|
-
if (!key) {
|
|
578
|
-
We("⚙️ Baton Configuration");
|
|
579
|
-
Le("Error: Missing key argument. Usage: baton config get <key>");
|
|
580
|
-
process.exit(1);
|
|
581
|
-
}
|
|
582
|
-
if (!VALID_KEYS.includes(key)) {
|
|
583
|
-
We("⚙️ Baton Configuration");
|
|
584
|
-
Le(`Error: Invalid key "${key}". Valid keys: ${VALID_KEYS.join(", ")}`);
|
|
585
|
-
process.exit(1);
|
|
586
|
-
}
|
|
587
|
-
const configValue = (await loadConfig())[key];
|
|
588
|
-
if (configValue === void 0) {
|
|
589
|
-
We("⚙️ Baton Configuration");
|
|
590
|
-
Le(`"${key}" is not set (using default)`);
|
|
591
|
-
return;
|
|
592
|
-
}
|
|
593
|
-
console.log(Array.isArray(configValue) ? configValue.join(", ") : configValue);
|
|
594
|
-
return;
|
|
595
|
-
}
|
|
596
|
-
if (selectedAction === "set") {
|
|
597
|
-
if (!key || !value) {
|
|
598
|
-
We("⚙️ Baton Configuration");
|
|
599
|
-
Le("Error: Missing arguments. Usage: baton config set <key> <value>");
|
|
600
|
-
process.exit(1);
|
|
601
|
-
}
|
|
602
|
-
if (!VALID_KEYS.includes(key)) {
|
|
603
|
-
We("⚙️ Baton Configuration");
|
|
604
|
-
Le(`Error: Invalid key "${key}". Valid keys: ${VALID_KEYS.join(", ")}`);
|
|
605
|
-
process.exit(1);
|
|
606
|
-
}
|
|
607
|
-
We("⚙️ Baton Configuration");
|
|
608
|
-
const config = await loadConfig();
|
|
609
|
-
if (key === "default-scope") {
|
|
610
|
-
if (value !== "project" && value !== "global") {
|
|
611
|
-
Le("Error: default-scope must be either \"project\" or \"global\"");
|
|
612
|
-
process.exit(1);
|
|
613
|
-
}
|
|
614
|
-
config["default-scope"] = value;
|
|
615
|
-
} else if (key === "symlink-mode") {
|
|
616
|
-
if (value !== "true" && value !== "false") {
|
|
617
|
-
Le("Error: symlink-mode must be either \"true\" or \"false\"");
|
|
618
|
-
process.exit(1);
|
|
619
|
-
}
|
|
620
|
-
config["symlink-mode"] = value === "true";
|
|
621
|
-
} else if (key === "default-tools") config["default-tools"] = value.split(",").map((s) => s.trim());
|
|
622
|
-
else if (key === "cache-dir") config["cache-dir"] = value;
|
|
623
|
-
await saveConfig(config);
|
|
624
|
-
Le(`✓ Set ${key} = ${Array.isArray(config[key]) ? config[key].join(", ") : config[key]}`);
|
|
625
|
-
return;
|
|
626
|
-
}
|
|
627
|
-
We("⚙️ Baton Configuration");
|
|
628
|
-
Le(`Error: Unknown action "${selectedAction}". Use: set, get, or list`);
|
|
629
|
-
process.exit(1);
|
|
516
|
+
async run() {
|
|
517
|
+
await showDashboard();
|
|
630
518
|
}
|
|
631
519
|
});
|
|
632
520
|
|
|
@@ -727,7 +615,7 @@ const diffCommand = defineCommand({
|
|
|
727
615
|
spinner.stop("Configurations merged");
|
|
728
616
|
spinner.start("Computing tool intersection...");
|
|
729
617
|
const globalAiTools = await getGlobalAiTools();
|
|
730
|
-
const
|
|
618
|
+
const detectedAITools = await detectInstalledAITools();
|
|
731
619
|
let syncedAiTools;
|
|
732
620
|
if (globalAiTools.length > 0) {
|
|
733
621
|
const developerTools = {
|
|
@@ -740,13 +628,13 @@ const diffCommand = defineCommand({
|
|
|
740
628
|
if (intersection) for (const tool of intersection.aiTools.synced) aggregatedSyncedAi.add(tool);
|
|
741
629
|
} catch {}
|
|
742
630
|
syncedAiTools = aggregatedSyncedAi.size > 0 ? [...aggregatedSyncedAi] : [];
|
|
743
|
-
} else syncedAiTools =
|
|
631
|
+
} else syncedAiTools = detectedAITools;
|
|
744
632
|
if (syncedAiTools.length === 0) {
|
|
745
633
|
spinner.stop("No AI tools in intersection");
|
|
746
634
|
Ne("No AI tools match. Run `baton ai-tools scan`.");
|
|
747
635
|
process.exit(1);
|
|
748
636
|
}
|
|
749
|
-
const adapters =
|
|
637
|
+
const adapters = getAIToolAdaptersForKeys(syncedAiTools);
|
|
750
638
|
spinner.stop(`Comparing for: ${syncedAiTools.join(", ")}`);
|
|
751
639
|
spinner.start("Comparing remote sources with placed files...");
|
|
752
640
|
const diffs = [];
|
|
@@ -1283,6 +1171,7 @@ const idesCommand = defineCommand({
|
|
|
1283
1171
|
|
|
1284
1172
|
//#endregion
|
|
1285
1173
|
//#region src/utils/first-run-preferences.ts
|
|
1174
|
+
var import_dist = require_dist();
|
|
1286
1175
|
/**
|
|
1287
1176
|
* Format an IDE platform key into a display name.
|
|
1288
1177
|
* Duplicated here to avoid circular dependency with ides/utils.
|
|
@@ -1339,7 +1228,7 @@ async function promptFirstRunPreferences(projectRoot, nonInteractive) {
|
|
|
1339
1228
|
let aiTools = [];
|
|
1340
1229
|
if (aiMode === "customize") {
|
|
1341
1230
|
const globalTools = await getGlobalAiTools();
|
|
1342
|
-
const allAdapters =
|
|
1231
|
+
const allAdapters = getAllAIToolAdapters();
|
|
1343
1232
|
const selected = await je({
|
|
1344
1233
|
message: "Select AI tools for this project:",
|
|
1345
1234
|
options: allAdapters.map((adapter) => ({
|
|
@@ -1711,8 +1600,8 @@ async function autoScanAiTools(spinner, isInteractive) {
|
|
|
1711
1600
|
return;
|
|
1712
1601
|
}
|
|
1713
1602
|
spinner.start("Scanning for installed AI tools...");
|
|
1714
|
-
|
|
1715
|
-
const detectedTools = await
|
|
1603
|
+
clearAIToolCache();
|
|
1604
|
+
const detectedTools = await detectInstalledAITools();
|
|
1716
1605
|
spinner.stop(detectedTools.length > 0 ? `Found ${detectedTools.length} AI tool${detectedTools.length !== 1 ? "s" : ""}: ${detectedTools.join(", ")}` : "No AI tools detected.");
|
|
1717
1606
|
if (detectedTools.length === 0) {
|
|
1718
1607
|
R.warn("No AI tools detected. You can run 'baton ai-tools scan' later.");
|
|
@@ -2054,7 +1943,7 @@ async function handleConfigureAiTools(cwd) {
|
|
|
2054
1943
|
R.success("Project configured to use global AI tools.");
|
|
2055
1944
|
return;
|
|
2056
1945
|
}
|
|
2057
|
-
const allAdapters =
|
|
1946
|
+
const allAdapters = getAllAIToolAdapters();
|
|
2058
1947
|
const currentProjectTools = existing?.ai.useGlobal === false ? existing.ai.tools : globalTools;
|
|
2059
1948
|
const options = allAdapters.map((adapter) => ({
|
|
2060
1949
|
value: adapter.key,
|
|
@@ -2279,8 +2168,8 @@ const profileCommand = defineCommand({
|
|
|
2279
2168
|
description: "Manage profiles (create, list, remove)"
|
|
2280
2169
|
},
|
|
2281
2170
|
subCommands: {
|
|
2282
|
-
create: () => import("./create-
|
|
2283
|
-
list: () => import("./list-
|
|
2171
|
+
create: () => import("./create-DYQJmn8s.mjs").then((m) => m.createCommand),
|
|
2172
|
+
list: () => import("./list-o1wqD5W_.mjs").then((m) => m.profileListCommand),
|
|
2284
2173
|
remove: () => import("./remove-BBs6Mv8t.mjs").then((m) => m.profileRemoveCommand)
|
|
2285
2174
|
}
|
|
2286
2175
|
});
|
|
@@ -2933,6 +2822,9 @@ const syncCommand = defineCommand({
|
|
|
2933
2822
|
const rulesResult = mergeRulesWithWarnings(weightSortedProfiles);
|
|
2934
2823
|
const mergedRules = rulesResult.rules;
|
|
2935
2824
|
allWeightWarnings.push(...rulesResult.warnings);
|
|
2825
|
+
const agentsResult = mergeAgentsWithWarnings(weightSortedProfiles);
|
|
2826
|
+
const mergedAgents = agentsResult.agents;
|
|
2827
|
+
allWeightWarnings.push(...agentsResult.warnings);
|
|
2936
2828
|
const memoryResult = mergeMemoryWithWarnings(weightSortedProfiles);
|
|
2937
2829
|
const mergedMemory = memoryResult.entries;
|
|
2938
2830
|
allWeightWarnings.push(...memoryResult.warnings);
|
|
@@ -3031,11 +2923,11 @@ const syncCommand = defineCommand({
|
|
|
3031
2923
|
}
|
|
3032
2924
|
}
|
|
3033
2925
|
const mergedIdeCount = ideMap.size;
|
|
3034
|
-
spinner.stop(`Merged: ${mergedSkills.length} skills, ${mergedRules.length} rules, ${mergedMemory.length} memory files, ${mergedCommandCount} commands, ${mergedFileCount} files, ${mergedIdeCount} IDE configs`);
|
|
2926
|
+
spinner.stop(`Merged: ${mergedSkills.length} skills, ${mergedRules.length} rules, ${mergedAgents.length} agents, ${mergedMemory.length} memory files, ${mergedCommandCount} commands, ${mergedFileCount} files, ${mergedIdeCount} IDE configs`);
|
|
3035
2927
|
if (allWeightWarnings.length > 0) for (const w of allWeightWarnings) R.warn(`Weight conflict: "${w.profileA}" and "${w.profileB}" both define ${w.category} "${w.key}" with weight ${w.weight}. Last declared wins.`);
|
|
3036
2928
|
spinner.start("Computing tool intersection...");
|
|
3037
2929
|
const prefs = await resolvePreferences(projectRoot);
|
|
3038
|
-
const
|
|
2930
|
+
const detectedAITools = await detectInstalledAITools();
|
|
3039
2931
|
if (verbose) {
|
|
3040
2932
|
R.info(`AI tools: ${prefs.ai.tools.join(", ") || "(none)"} (from ${prefs.ai.source} preferences)`);
|
|
3041
2933
|
R.info(`IDE platforms: ${prefs.ide.platforms.join(", ") || "(none)"} (from ${prefs.ide.source} preferences)`);
|
|
@@ -3062,14 +2954,14 @@ const syncCommand = defineCommand({
|
|
|
3062
2954
|
syncedAiTools = aggregatedSyncedAi.size > 0 ? [...aggregatedSyncedAi] : [];
|
|
3063
2955
|
syncedIdePlatforms = [...aggregatedSyncedIde];
|
|
3064
2956
|
} else {
|
|
3065
|
-
syncedAiTools =
|
|
2957
|
+
syncedAiTools = detectedAITools;
|
|
3066
2958
|
syncedIdePlatforms = null;
|
|
3067
|
-
if (
|
|
2959
|
+
if (detectedAITools.length > 0) {
|
|
3068
2960
|
R.warn("No AI tools configured. Run `baton ai-tools scan` to configure your tools.");
|
|
3069
|
-
R.info(`Falling back to detected tools: ${
|
|
2961
|
+
R.info(`Falling back to detected tools: ${detectedAITools.join(", ")}`);
|
|
3070
2962
|
}
|
|
3071
2963
|
}
|
|
3072
|
-
if (syncedAiTools.length === 0 &&
|
|
2964
|
+
if (syncedAiTools.length === 0 && detectedAITools.length === 0) {
|
|
3073
2965
|
spinner.stop("No AI tools available");
|
|
3074
2966
|
Ne("No AI tools found. Install an AI coding tool first.");
|
|
3075
2967
|
process.exit(1);
|
|
@@ -3098,7 +2990,7 @@ const syncCommand = defineCommand({
|
|
|
3098
2990
|
}
|
|
3099
2991
|
} else spinner.stop("No legacy files found");
|
|
3100
2992
|
spinner.start("Processing configurations...");
|
|
3101
|
-
const adapters =
|
|
2993
|
+
const adapters = getAIToolAdaptersForKeys(syncedAiTools);
|
|
3102
2994
|
const placementConfig = {
|
|
3103
2995
|
mode: "copy",
|
|
3104
2996
|
projectRoot
|
|
@@ -3213,6 +3105,7 @@ const syncCommand = defineCommand({
|
|
|
3213
3105
|
if (!dryRun && syncAi) for (const adapter of adapters) {
|
|
3214
3106
|
if (verbose) R.step(`[${adapter.key}] Placing rules...`);
|
|
3215
3107
|
for (const ruleEntry of mergedRules) try {
|
|
3108
|
+
const ruleName = ruleEntry.name.replace(/\.md$/, "");
|
|
3216
3109
|
const isUniversal = ruleEntry.agents.length === 0;
|
|
3217
3110
|
const isForThisAdapter = ruleEntry.agents.includes(adapter.key);
|
|
3218
3111
|
if (!isUniversal && !isForThisAdapter) continue;
|
|
@@ -3221,7 +3114,7 @@ const syncCommand = defineCommand({
|
|
|
3221
3114
|
spinner.message(`Warning: Could not resolve local path for profile ${ruleEntry.profileName}`);
|
|
3222
3115
|
continue;
|
|
3223
3116
|
}
|
|
3224
|
-
const ruleSourcePath = resolve(profileDir, "ai", "rules", isUniversal ? "universal" : ruleEntry.agents[0], `${
|
|
3117
|
+
const ruleSourcePath = resolve(profileDir, "ai", "rules", isUniversal ? "universal" : ruleEntry.agents[0], `${ruleName}.md`);
|
|
3225
3118
|
let rawContent;
|
|
3226
3119
|
try {
|
|
3227
3120
|
rawContent = await readFile(ruleSourcePath, "utf-8");
|
|
@@ -3231,12 +3124,12 @@ const syncCommand = defineCommand({
|
|
|
3231
3124
|
}
|
|
3232
3125
|
const parsed = parseFrontmatter(rawContent);
|
|
3233
3126
|
const ruleFile = {
|
|
3234
|
-
name:
|
|
3127
|
+
name: ruleName,
|
|
3235
3128
|
content: rawContent,
|
|
3236
3129
|
frontmatter: Object.keys(parsed.data).length > 0 ? parsed.data : void 0
|
|
3237
3130
|
};
|
|
3238
3131
|
const transformed = adapter.transformRule(ruleFile);
|
|
3239
|
-
const targetPath = adapter.getPath("rules", "project",
|
|
3132
|
+
const targetPath = adapter.getPath("rules", "project", ruleName);
|
|
3240
3133
|
const absolutePath = targetPath.startsWith("/") ? targetPath : resolve(projectRoot, targetPath);
|
|
3241
3134
|
const existing = contentAccumulator.get(absolutePath);
|
|
3242
3135
|
if (existing) {
|
|
@@ -3246,7 +3139,7 @@ const syncCommand = defineCommand({
|
|
|
3246
3139
|
parts: [transformed.content],
|
|
3247
3140
|
adapter,
|
|
3248
3141
|
type: "rules",
|
|
3249
|
-
name:
|
|
3142
|
+
name: ruleName,
|
|
3250
3143
|
profiles: new Set([ruleEntry.profileName])
|
|
3251
3144
|
});
|
|
3252
3145
|
} catch (error) {
|
|
@@ -3254,6 +3147,53 @@ const syncCommand = defineCommand({
|
|
|
3254
3147
|
stats.errors++;
|
|
3255
3148
|
}
|
|
3256
3149
|
}
|
|
3150
|
+
if (!dryRun && syncAi) for (const adapter of adapters) {
|
|
3151
|
+
if (verbose) R.step(`[${adapter.key}] Placing agents...`);
|
|
3152
|
+
for (const agentEntry of mergedAgents) try {
|
|
3153
|
+
const agentName = agentEntry.name.replace(/\.md$/, "");
|
|
3154
|
+
const isUniversal = agentEntry.agents.length === 0;
|
|
3155
|
+
const isForThisAdapter = agentEntry.agents.includes(adapter.key);
|
|
3156
|
+
if (!isUniversal && !isForThisAdapter) continue;
|
|
3157
|
+
const profileDir = profileLocalPaths.get(agentEntry.profileName);
|
|
3158
|
+
if (!profileDir) {
|
|
3159
|
+
spinner.message(`Warning: Could not resolve local path for profile ${agentEntry.profileName}`);
|
|
3160
|
+
continue;
|
|
3161
|
+
}
|
|
3162
|
+
const agentSourcePath = resolve(profileDir, "ai", "agents", isUniversal ? "universal" : agentEntry.agents[0], `${agentName}.md`);
|
|
3163
|
+
let rawContent;
|
|
3164
|
+
try {
|
|
3165
|
+
rawContent = await readFile(agentSourcePath, "utf-8");
|
|
3166
|
+
} catch {
|
|
3167
|
+
spinner.message(`Warning: Could not read agent file: ${agentSourcePath}`);
|
|
3168
|
+
continue;
|
|
3169
|
+
}
|
|
3170
|
+
const parsed = parseFrontmatter(rawContent);
|
|
3171
|
+
const frontmatter = Object.keys(parsed.data).length > 0 ? parsed.data : { name: agentName };
|
|
3172
|
+
const agentFile = {
|
|
3173
|
+
name: agentName,
|
|
3174
|
+
content: rawContent,
|
|
3175
|
+
description: frontmatter.description,
|
|
3176
|
+
frontmatter
|
|
3177
|
+
};
|
|
3178
|
+
const transformed = adapter.transformAgent(agentFile);
|
|
3179
|
+
const targetPath = adapter.getPath("agents", "project", agentName);
|
|
3180
|
+
const absolutePath = targetPath.startsWith("/") ? targetPath : resolve(projectRoot, targetPath);
|
|
3181
|
+
const existing = contentAccumulator.get(absolutePath);
|
|
3182
|
+
if (existing) {
|
|
3183
|
+
existing.parts.push(transformed.content);
|
|
3184
|
+
existing.profiles.add(agentEntry.profileName);
|
|
3185
|
+
} else contentAccumulator.set(absolutePath, {
|
|
3186
|
+
parts: [transformed.content],
|
|
3187
|
+
adapter,
|
|
3188
|
+
type: "agents",
|
|
3189
|
+
name: agentName,
|
|
3190
|
+
profiles: new Set([agentEntry.profileName])
|
|
3191
|
+
});
|
|
3192
|
+
} catch (error) {
|
|
3193
|
+
spinner.message(`Error placing agent ${agentEntry.name} for ${adapter.name}: ${error}`);
|
|
3194
|
+
stats.errors++;
|
|
3195
|
+
}
|
|
3196
|
+
}
|
|
3257
3197
|
if (!dryRun && syncAi) for (const [absolutePath, entry] of contentAccumulator) try {
|
|
3258
3198
|
const combinedContent = entry.parts.join("\n\n");
|
|
3259
3199
|
const result = await placeFile(combinedContent, entry.adapter, entry.type, "project", entry.name, placementConfig);
|
|
@@ -3393,6 +3333,7 @@ const syncCommand = defineCommand({
|
|
|
3393
3333
|
if (syncAi) {
|
|
3394
3334
|
parts.push(` • ${mergedSkills.length} skills`);
|
|
3395
3335
|
parts.push(` • ${mergedRules.length} rules`);
|
|
3336
|
+
parts.push(` • ${mergedAgents.length} agents`);
|
|
3396
3337
|
parts.push(` • ${mergedMemory.length} memory files`);
|
|
3397
3338
|
parts.push(` • ${mergedCommandCount} commands`);
|
|
3398
3339
|
}
|