@baton-dx/cli 0.3.2 → 0.4.0

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/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 loadProfileManifest, A as detectLegacyPaths, B as collectComprehensivePatterns, C as mergeSkillsWithWarnings, D as mergeContentParts, E as sortProfilesByWeight, F as generateLock, G as getRegisteredIdePlatforms, H as removeGitignoreManagedSection, I as readLock, J as getAdaptersForKeys, K as idePlatformRegistry, L as writeLock, M as discoverProfilesInSourceRepo, N as findSourceManifest, O as resolveProfileSupport, P as removePlacedFiles, Q as loadLockfile, R as resolveVersion, S as mergeSkills, T as isLockedProfile, U as updateGitignore, V as ensureBatonDirGitignored, W as getIdePlatformTargetDir, X as parseFrontmatter, Y as getAllAdapters, Z as parseSource, _ as require_lib, a as clearIdeCache, at as getAgentPath, b as mergeRules, c as getBatonHome, d as getGlobalConfigPath, et as loadProjectManifest, f as getGlobalIdePlatforms, g as setGlobalIdePlatforms, h as setGlobalAiTools, i as computeIntersection, it as getAgentConfig, j as placeFile, k as resolveProfileChain, l as getDefaultGlobalSource, m as removeGlobalSource, n as readProjectPreferences, nt as FileNotFoundError, o as detectInstalledIdes, ot as getAllAgentKeys, p as getGlobalSources, q as isKnownIdePlatform, r as writeProjectPreferences, rt as SourceParseError, s as addGlobalSource, t as resolvePreferences, tt as KEBAB_CASE_REGEX, u as getGlobalAiTools, v as mergeMemory, w as getProfileWeight, x as mergeRulesWithWarnings, y as mergeMemoryWithWarnings, z as cloneGitSource } from "./src-BCGnnv5D.mjs";
5
- import { n as detectInstalledAgents, t as clearAgentCache } from "./agent-detection-DTiVeO5W.mjs";
4
+ import { $ as loadLockfile, A as resolveProfileChain, B as cloneGitSource, C as mergeSkills, D as sortProfilesByWeight, E as isLockedProfile, F as removePlacedFiles, G as getIdePlatformTargetDir, H as ensureBatonDirGitignored, I as generateLock, J as isKnownIdePlatform, K as getRegisteredIdePlatforms, L as readLock, M as placeFile, N as discoverProfilesInSourceRepo, O as mergeContentParts, P as findSourceManifest, Q as parseSource, R as writeLock, S as mergeRulesWithWarnings, T as getProfileWeight, U as removeGitignoreManagedSection, V as collectComprehensivePatterns, W as updateGitignore, X as getAllAIToolAdapters, Y as getAIToolAdaptersForKeys, Z as parseFrontmatter, _ as require_lib, a as clearIdeCache, at as getAIToolConfig, b as mergeAgentsWithWarnings, c as getBatonHome, d as getGlobalConfigPath, et as loadProfileManifest, f as getGlobalIdePlatforms, g as setGlobalIdePlatforms, h as setGlobalAiTools, i as computeIntersection, it as SourceParseError, j as detectLegacyPaths, k as resolveProfileSupport, l as getDefaultGlobalSource, m as removeGlobalSource, n as readProjectPreferences, nt as KEBAB_CASE_REGEX, o as detectInstalledIdes, ot as getAIToolPath, p as getGlobalSources, q as idePlatformRegistry, r as writeProjectPreferences, rt as FileNotFoundError, s as addGlobalSource, st as getAllAIToolKeys, t as resolvePreferences, tt as loadProjectManifest, u as getGlobalAiTools, v as mergeMemory, w as mergeSkillsWithWarnings, x as mergeRules, y as mergeMemoryWithWarnings, z as resolveVersion } from "./src-D41VR6ro.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 = getAllAdapters().map((adapter) => {
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 = getAllAdapters();
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 allAgentKeys = getAllAgentKeys();
185
- const keysToShow = args.all ? allAgentKeys : savedTools.length > 0 ? savedTools : allAgentKeys;
186
- const agentStatuses = await Promise.all(keysToShow.map(async (agentKey) => {
187
- const isSaved = savedTools.includes(agentKey);
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 agentCount = 0;
190
+ let aiToolConfigCount = 0;
191
191
  let memoryCount = 0;
192
192
  let commandCount = 0;
193
193
  if (isSaved) {
194
- skillCount = await countConfigs(agentKey, "skills", "project");
195
- ruleCount = await countConfigs(agentKey, "rules", "project");
196
- agentCount = await countConfigs(agentKey, "agents", "project");
197
- memoryCount = await countConfigs(agentKey, "memory", "project");
198
- commandCount = await countConfigs(agentKey, "commands", "project");
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: getAgentPath(agentKey, "skills", "project", ""),
202
- rules: getAgentPath(agentKey, "rules", "project", ""),
203
- agents: getAgentPath(agentKey, "agents", "project", ""),
204
- memory: getAgentPath(agentKey, "memory", "project", ""),
205
- commands: getAgentPath(agentKey, "commands", "project", "")
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: agentKey,
209
- name: getAgentConfig(agentKey).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: agentCount,
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(agentStatuses, null, 2));
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 ${allAgentKeys.length} supported tools:`);
230
- for (const key of allAgentKeys) {
231
- const config = getAgentConfig(key);
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 agentStatuses) {
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} ${agent.name.padEnd(20)}`);
@@ -256,11 +256,11 @@ const aiToolsListCommand = defineCommand({
256
256
  }
257
257
  });
258
258
  /**
259
- * Count config files of a given type for an agent
259
+ * Count config files of a given type for a tool
260
260
  */
261
- async function countConfigs(agentKey, configType, scope) {
261
+ async function countConfigs(toolKey, configType, scope) {
262
262
  try {
263
- const dirPath = getAgentPath(agentKey, configType, scope, "").replace(/{name}.*$/, "").replace(/\/$/, "");
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
- clearAgentCache();
288
- const detectedAgents = await detectInstalledAgents();
289
- const allAdapters = getAllAdapters();
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 (detectedAgents.length > 0) R.success(`Found ${detectedAgents.length} AI tool${detectedAgents.length !== 1 ? "s" : ""} on your system.`);
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 = detectedAgents;
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 = detectedAgents.includes(adapter.key);
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: detectedAgents
313
+ initialValues: detectedAITools
314
314
  });
315
315
  if (Ct(selected)) {
316
316
  Le("Scan finished (not saved).");
@@ -467,7 +467,7 @@ async function showDashboard() {
467
467
  if (resolvedAiTools.length > 0) {
468
468
  const toolNames = resolvedAiTools.map((key) => {
469
469
  try {
470
- return getAgentConfig(key).name;
470
+ return getAIToolConfig(key).name;
471
471
  } catch {
472
472
  return key;
473
473
  }
@@ -485,7 +485,7 @@ async function showDashboard() {
485
485
  if (aiTools.length > 0) {
486
486
  const toolNames = aiTools.map((key) => {
487
487
  try {
488
- return getAgentConfig(key).name;
488
+ return getAIToolConfig(key).name;
489
489
  } catch {
490
490
  return key;
491
491
  }
@@ -727,7 +727,7 @@ const diffCommand = defineCommand({
727
727
  spinner.stop("Configurations merged");
728
728
  spinner.start("Computing tool intersection...");
729
729
  const globalAiTools = await getGlobalAiTools();
730
- const detectedAgents = await detectInstalledAgents();
730
+ const detectedAITools = await detectInstalledAITools();
731
731
  let syncedAiTools;
732
732
  if (globalAiTools.length > 0) {
733
733
  const developerTools = {
@@ -740,13 +740,13 @@ const diffCommand = defineCommand({
740
740
  if (intersection) for (const tool of intersection.aiTools.synced) aggregatedSyncedAi.add(tool);
741
741
  } catch {}
742
742
  syncedAiTools = aggregatedSyncedAi.size > 0 ? [...aggregatedSyncedAi] : [];
743
- } else syncedAiTools = detectedAgents;
743
+ } else syncedAiTools = detectedAITools;
744
744
  if (syncedAiTools.length === 0) {
745
745
  spinner.stop("No AI tools in intersection");
746
746
  Ne("No AI tools match. Run `baton ai-tools scan`.");
747
747
  process.exit(1);
748
748
  }
749
- const adapters = getAdaptersForKeys(syncedAiTools);
749
+ const adapters = getAIToolAdaptersForKeys(syncedAiTools);
750
750
  spinner.stop(`Comparing for: ${syncedAiTools.join(", ")}`);
751
751
  spinner.start("Comparing remote sources with placed files...");
752
752
  const diffs = [];
@@ -1339,7 +1339,7 @@ async function promptFirstRunPreferences(projectRoot, nonInteractive) {
1339
1339
  let aiTools = [];
1340
1340
  if (aiMode === "customize") {
1341
1341
  const globalTools = await getGlobalAiTools();
1342
- const allAdapters = getAllAdapters();
1342
+ const allAdapters = getAllAIToolAdapters();
1343
1343
  const selected = await je({
1344
1344
  message: "Select AI tools for this project:",
1345
1345
  options: allAdapters.map((adapter) => ({
@@ -1711,8 +1711,8 @@ async function autoScanAiTools(spinner, isInteractive) {
1711
1711
  return;
1712
1712
  }
1713
1713
  spinner.start("Scanning for installed AI tools...");
1714
- clearAgentCache();
1715
- const detectedTools = await detectInstalledAgents();
1714
+ clearAIToolCache();
1715
+ const detectedTools = await detectInstalledAITools();
1716
1716
  spinner.stop(detectedTools.length > 0 ? `Found ${detectedTools.length} AI tool${detectedTools.length !== 1 ? "s" : ""}: ${detectedTools.join(", ")}` : "No AI tools detected.");
1717
1717
  if (detectedTools.length === 0) {
1718
1718
  R.warn("No AI tools detected. You can run 'baton ai-tools scan' later.");
@@ -2054,7 +2054,7 @@ async function handleConfigureAiTools(cwd) {
2054
2054
  R.success("Project configured to use global AI tools.");
2055
2055
  return;
2056
2056
  }
2057
- const allAdapters = getAllAdapters();
2057
+ const allAdapters = getAllAIToolAdapters();
2058
2058
  const currentProjectTools = existing?.ai.useGlobal === false ? existing.ai.tools : globalTools;
2059
2059
  const options = allAdapters.map((adapter) => ({
2060
2060
  value: adapter.key,
@@ -2279,8 +2279,8 @@ const profileCommand = defineCommand({
2279
2279
  description: "Manage profiles (create, list, remove)"
2280
2280
  },
2281
2281
  subCommands: {
2282
- create: () => import("./create-BkpEXaht.mjs").then((m) => m.createCommand),
2283
- list: () => import("./list-DSLwzhBG.mjs").then((m) => m.profileListCommand),
2282
+ create: () => import("./create-SYKl8g0B.mjs").then((m) => m.createCommand),
2283
+ list: () => import("./list-UzuMEqbc.mjs").then((m) => m.profileListCommand),
2284
2284
  remove: () => import("./remove-BBs6Mv8t.mjs").then((m) => m.profileRemoveCommand)
2285
2285
  }
2286
2286
  });
@@ -2933,6 +2933,9 @@ const syncCommand = defineCommand({
2933
2933
  const rulesResult = mergeRulesWithWarnings(weightSortedProfiles);
2934
2934
  const mergedRules = rulesResult.rules;
2935
2935
  allWeightWarnings.push(...rulesResult.warnings);
2936
+ const agentsResult = mergeAgentsWithWarnings(weightSortedProfiles);
2937
+ const mergedAgents = agentsResult.agents;
2938
+ allWeightWarnings.push(...agentsResult.warnings);
2936
2939
  const memoryResult = mergeMemoryWithWarnings(weightSortedProfiles);
2937
2940
  const mergedMemory = memoryResult.entries;
2938
2941
  allWeightWarnings.push(...memoryResult.warnings);
@@ -3031,11 +3034,11 @@ const syncCommand = defineCommand({
3031
3034
  }
3032
3035
  }
3033
3036
  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`);
3037
+ spinner.stop(`Merged: ${mergedSkills.length} skills, ${mergedRules.length} rules, ${mergedAgents.length} agents, ${mergedMemory.length} memory files, ${mergedCommandCount} commands, ${mergedFileCount} files, ${mergedIdeCount} IDE configs`);
3035
3038
  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
3039
  spinner.start("Computing tool intersection...");
3037
3040
  const prefs = await resolvePreferences(projectRoot);
3038
- const detectedAgents = await detectInstalledAgents();
3041
+ const detectedAITools = await detectInstalledAITools();
3039
3042
  if (verbose) {
3040
3043
  R.info(`AI tools: ${prefs.ai.tools.join(", ") || "(none)"} (from ${prefs.ai.source} preferences)`);
3041
3044
  R.info(`IDE platforms: ${prefs.ide.platforms.join(", ") || "(none)"} (from ${prefs.ide.source} preferences)`);
@@ -3062,14 +3065,14 @@ const syncCommand = defineCommand({
3062
3065
  syncedAiTools = aggregatedSyncedAi.size > 0 ? [...aggregatedSyncedAi] : [];
3063
3066
  syncedIdePlatforms = [...aggregatedSyncedIde];
3064
3067
  } else {
3065
- syncedAiTools = detectedAgents;
3068
+ syncedAiTools = detectedAITools;
3066
3069
  syncedIdePlatforms = null;
3067
- if (detectedAgents.length > 0) {
3070
+ if (detectedAITools.length > 0) {
3068
3071
  R.warn("No AI tools configured. Run `baton ai-tools scan` to configure your tools.");
3069
- R.info(`Falling back to detected tools: ${detectedAgents.join(", ")}`);
3072
+ R.info(`Falling back to detected tools: ${detectedAITools.join(", ")}`);
3070
3073
  }
3071
3074
  }
3072
- if (syncedAiTools.length === 0 && detectedAgents.length === 0) {
3075
+ if (syncedAiTools.length === 0 && detectedAITools.length === 0) {
3073
3076
  spinner.stop("No AI tools available");
3074
3077
  Ne("No AI tools found. Install an AI coding tool first.");
3075
3078
  process.exit(1);
@@ -3098,7 +3101,7 @@ const syncCommand = defineCommand({
3098
3101
  }
3099
3102
  } else spinner.stop("No legacy files found");
3100
3103
  spinner.start("Processing configurations...");
3101
- const adapters = getAdaptersForKeys(syncedAiTools);
3104
+ const adapters = getAIToolAdaptersForKeys(syncedAiTools);
3102
3105
  const placementConfig = {
3103
3106
  mode: "copy",
3104
3107
  projectRoot
@@ -3213,6 +3216,7 @@ const syncCommand = defineCommand({
3213
3216
  if (!dryRun && syncAi) for (const adapter of adapters) {
3214
3217
  if (verbose) R.step(`[${adapter.key}] Placing rules...`);
3215
3218
  for (const ruleEntry of mergedRules) try {
3219
+ const ruleName = ruleEntry.name.replace(/\.md$/, "");
3216
3220
  const isUniversal = ruleEntry.agents.length === 0;
3217
3221
  const isForThisAdapter = ruleEntry.agents.includes(adapter.key);
3218
3222
  if (!isUniversal && !isForThisAdapter) continue;
@@ -3221,7 +3225,7 @@ const syncCommand = defineCommand({
3221
3225
  spinner.message(`Warning: Could not resolve local path for profile ${ruleEntry.profileName}`);
3222
3226
  continue;
3223
3227
  }
3224
- const ruleSourcePath = resolve(profileDir, "ai", "rules", isUniversal ? "universal" : ruleEntry.agents[0], `${ruleEntry.name}.md`);
3228
+ const ruleSourcePath = resolve(profileDir, "ai", "rules", isUniversal ? "universal" : ruleEntry.agents[0], `${ruleName}.md`);
3225
3229
  let rawContent;
3226
3230
  try {
3227
3231
  rawContent = await readFile(ruleSourcePath, "utf-8");
@@ -3231,12 +3235,12 @@ const syncCommand = defineCommand({
3231
3235
  }
3232
3236
  const parsed = parseFrontmatter(rawContent);
3233
3237
  const ruleFile = {
3234
- name: ruleEntry.name,
3238
+ name: ruleName,
3235
3239
  content: rawContent,
3236
3240
  frontmatter: Object.keys(parsed.data).length > 0 ? parsed.data : void 0
3237
3241
  };
3238
3242
  const transformed = adapter.transformRule(ruleFile);
3239
- const targetPath = adapter.getPath("rules", "project", ruleEntry.name);
3243
+ const targetPath = adapter.getPath("rules", "project", ruleName);
3240
3244
  const absolutePath = targetPath.startsWith("/") ? targetPath : resolve(projectRoot, targetPath);
3241
3245
  const existing = contentAccumulator.get(absolutePath);
3242
3246
  if (existing) {
@@ -3246,7 +3250,7 @@ const syncCommand = defineCommand({
3246
3250
  parts: [transformed.content],
3247
3251
  adapter,
3248
3252
  type: "rules",
3249
- name: ruleEntry.name,
3253
+ name: ruleName,
3250
3254
  profiles: new Set([ruleEntry.profileName])
3251
3255
  });
3252
3256
  } catch (error) {
@@ -3254,6 +3258,53 @@ const syncCommand = defineCommand({
3254
3258
  stats.errors++;
3255
3259
  }
3256
3260
  }
3261
+ if (!dryRun && syncAi) for (const adapter of adapters) {
3262
+ if (verbose) R.step(`[${adapter.key}] Placing agents...`);
3263
+ for (const agentEntry of mergedAgents) try {
3264
+ const agentName = agentEntry.name.replace(/\.md$/, "");
3265
+ const isUniversal = agentEntry.agents.length === 0;
3266
+ const isForThisAdapter = agentEntry.agents.includes(adapter.key);
3267
+ if (!isUniversal && !isForThisAdapter) continue;
3268
+ const profileDir = profileLocalPaths.get(agentEntry.profileName);
3269
+ if (!profileDir) {
3270
+ spinner.message(`Warning: Could not resolve local path for profile ${agentEntry.profileName}`);
3271
+ continue;
3272
+ }
3273
+ const agentSourcePath = resolve(profileDir, "ai", "agents", isUniversal ? "universal" : agentEntry.agents[0], `${agentName}.md`);
3274
+ let rawContent;
3275
+ try {
3276
+ rawContent = await readFile(agentSourcePath, "utf-8");
3277
+ } catch {
3278
+ spinner.message(`Warning: Could not read agent file: ${agentSourcePath}`);
3279
+ continue;
3280
+ }
3281
+ const parsed = parseFrontmatter(rawContent);
3282
+ const frontmatter = Object.keys(parsed.data).length > 0 ? parsed.data : { name: agentName };
3283
+ const agentFile = {
3284
+ name: agentName,
3285
+ content: rawContent,
3286
+ description: frontmatter.description,
3287
+ frontmatter
3288
+ };
3289
+ const transformed = adapter.transformAgent(agentFile);
3290
+ const targetPath = adapter.getPath("agents", "project", agentName);
3291
+ const absolutePath = targetPath.startsWith("/") ? targetPath : resolve(projectRoot, targetPath);
3292
+ const existing = contentAccumulator.get(absolutePath);
3293
+ if (existing) {
3294
+ existing.parts.push(transformed.content);
3295
+ existing.profiles.add(agentEntry.profileName);
3296
+ } else contentAccumulator.set(absolutePath, {
3297
+ parts: [transformed.content],
3298
+ adapter,
3299
+ type: "agents",
3300
+ name: agentName,
3301
+ profiles: new Set([agentEntry.profileName])
3302
+ });
3303
+ } catch (error) {
3304
+ spinner.message(`Error placing agent ${agentEntry.name} for ${adapter.name}: ${error}`);
3305
+ stats.errors++;
3306
+ }
3307
+ }
3257
3308
  if (!dryRun && syncAi) for (const [absolutePath, entry] of contentAccumulator) try {
3258
3309
  const combinedContent = entry.parts.join("\n\n");
3259
3310
  const result = await placeFile(combinedContent, entry.adapter, entry.type, "project", entry.name, placementConfig);
@@ -3393,6 +3444,7 @@ const syncCommand = defineCommand({
3393
3444
  if (syncAi) {
3394
3445
  parts.push(` • ${mergedSkills.length} skills`);
3395
3446
  parts.push(` • ${mergedRules.length} rules`);
3447
+ parts.push(` • ${mergedAgents.length} agents`);
3396
3448
  parts.push(` • ${mergedMemory.length} memory files`);
3397
3449
  parts.push(` • ${mergedCommandCount} commands`);
3398
3450
  }