@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/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-SYKl8g0B.mjs} +3 -3
- package/dist/{create-BkpEXaht.mjs.map → create-SYKl8g0B.mjs.map} +1 -1
- package/dist/index.mjs +111 -59
- package/dist/index.mjs.map +1 -1
- package/dist/{list-DSLwzhBG.mjs → list-UzuMEqbc.mjs} +3 -3
- package/dist/{list-DSLwzhBG.mjs.map → list-UzuMEqbc.mjs.map} +1 -1
- package/dist/{src-BCGnnv5D.mjs → src-D41VR6ro.mjs} +140 -70
- package/dist/src-D41VR6ro.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 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 =
|
|
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)}`);
|
|
@@ -256,11 +256,11 @@ const aiToolsListCommand = defineCommand({
|
|
|
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).");
|
|
@@ -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
|
|
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
|
|
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
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
1715
|
-
const detectedTools = await
|
|
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 =
|
|
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-
|
|
2283
|
-
list: () => import("./list-
|
|
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
|
|
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 =
|
|
3068
|
+
syncedAiTools = detectedAITools;
|
|
3066
3069
|
syncedIdePlatforms = null;
|
|
3067
|
-
if (
|
|
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: ${
|
|
3072
|
+
R.info(`Falling back to detected tools: ${detectedAITools.join(", ")}`);
|
|
3070
3073
|
}
|
|
3071
3074
|
}
|
|
3072
|
-
if (syncedAiTools.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 =
|
|
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], `${
|
|
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:
|
|
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",
|
|
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:
|
|
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
|
}
|