@baton-dx/cli 0.6.0 → 0.7.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-Bw4qveB8.mjs → ai-tool-detection-46GECWyV.mjs} +1 -1
- package/dist/{ai-tool-detection-DMnwwNBI.mjs → ai-tool-detection-CMsBNa9e.mjs} +1 -1
- package/dist/{ai-tool-detection-DMnwwNBI.mjs.map → ai-tool-detection-CMsBNa9e.mjs.map} +1 -1
- package/dist/context-detection-DO0ZeRyQ.mjs +3191 -0
- package/dist/context-detection-DO0ZeRyQ.mjs.map +1 -0
- package/dist/{create-Y2IeW_fK.mjs → create-y-ut18-j.mjs} +5 -4
- package/dist/{create-Y2IeW_fK.mjs.map → create-y-ut18-j.mjs.map} +1 -1
- package/dist/{context-detection-D9yccWot.mjs → dist-BoZnMvNi.mjs} +2 -3188
- package/dist/dist-BoZnMvNi.mjs.map +1 -0
- package/dist/index.mjs +112 -57
- package/dist/index.mjs.map +1 -1
- package/dist/{list-D3woEF2B.mjs → list-BHPDZfmU.mjs} +5 -4
- package/dist/{list-D3woEF2B.mjs.map → list-BHPDZfmU.mjs.map} +1 -1
- package/dist/{prompt-CLnET8eQ.mjs → prompt-DXfUeR3X.mjs} +8 -8
- package/dist/prompt-DXfUeR3X.mjs.map +1 -0
- package/dist/{remove-CsxkkNiu.mjs → remove-Cx8jC2vY.mjs} +3 -2
- package/dist/{remove-CsxkkNiu.mjs.map → remove-Cx8jC2vY.mjs.map} +1 -1
- package/dist/src-B8_hp8ig.mjs +6 -0
- package/dist/{src-BVo3M5-4.mjs → src-BI6xWv0H.mjs} +70 -12
- package/dist/src-BI6xWv0H.mjs.map +1 -0
- package/package.json +1 -1
- package/dist/context-detection-D9yccWot.mjs.map +0 -1
- package/dist/prompt-CLnET8eQ.mjs.map +0 -1
- package/dist/src-BVo3M5-4.mjs.map +0 -1
package/dist/index.mjs
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { n as
|
|
2
|
+
import { i as __toESM, t as require_dist } from "./dist-BoZnMvNi.mjs";
|
|
3
|
+
import { a as Ne, c as Ve, d as bt, f as je, h as runMain, i as Le, l as We, m as defineCommand, o as R, p as Ct, r as Je, s as Re, t as findSourceRoot, u as Ze } from "./context-detection-DO0ZeRyQ.mjs";
|
|
4
|
+
import { $ as cloneGitSource, A as mergeRulesWithWarnings, At as loadProfileManifest, B as detectLegacyPaths, C as setGlobalAiTools, D as mergeMemoryWithWarnings, E as mergeMemory, F as isLockedProfile, H as discoverProfilesInSourceRepo, I as sortProfilesByWeight, J as removePlacedFiles, Jt as getAllAIToolKeys, K as readState, Kt as getAIToolConfig, L as mergeContentParts, Lt as KEBAB_CASE_REGEX, M as mergeSkillsWithWarnings, O as mergeAgentsWithWarnings, Ot as parseFrontmatter, P as getProfileWeight, Q as resolveVersion, R as resolveProfileSupport, S as saveGlobalConfig, T as require_lib, U as findSourceManifest, V as placeFile, Vt as FileNotFoundError, Wt as SourceParseError, X as readLock, Y as generateLock, Z as writeLock, a as resolvePreferences, at as updateGitignore, b as loadGlobalConfig, c as writeProjectPreferences, ct as idePlatformRegistry, d as clearIdeCache, dt as getAIToolAdaptersForKeys, f as detectInstalledIdes, ft as getAllAIToolAdapters, g as getGlobalAiTools, h as getDefaultGlobalSource, i as formatInstallCommand, it as removeGitignoreManagedSection, j as mergeSkills, jt as loadProjectManifest, k as mergeRules, kt as parseSource, lt as isKnownIdePlatform, n as isUpdateAvailable, nt as collectComprehensivePatterns, ot as getIdePlatformTargetDir, p as addGlobalSource, q as writeState, qt as getAIToolPath, r as detectInstallMethod, rt as ensureBatonDirGitignored, s as readProjectPreferences, st as getRegisteredIdePlatforms, t as checkLatestVersion, tt as esm_default, u as computeIntersection, v as getGlobalIdePlatforms, w as setGlobalIdePlatforms, x as removeGlobalSource, y as getGlobalSources, z as resolveProfileChain } from "./src-BI6xWv0H.mjs";
|
|
5
|
+
import { n as detectInstalledAITools, t as clearAIToolCache } from "./ai-tool-detection-CMsBNa9e.mjs";
|
|
5
6
|
import { access, mkdir, readFile, readdir, rm, stat, writeFile } from "node:fs/promises";
|
|
6
7
|
import { dirname, isAbsolute, join, relative, resolve } from "node:path";
|
|
7
8
|
import { fileURLToPath } from "node:url";
|
|
@@ -608,14 +609,46 @@ async function writeLockData(params) {
|
|
|
608
609
|
spinner.stop("Lockfile updated");
|
|
609
610
|
}
|
|
610
611
|
/**
|
|
611
|
-
*
|
|
612
|
-
*
|
|
612
|
+
* Write local placement state to `.baton/state.yaml`.
|
|
613
|
+
* Tracks tool-specific file paths placed on disk for orphan detection.
|
|
614
|
+
*/
|
|
615
|
+
async function writeStateData(params) {
|
|
616
|
+
const { actualPlacedPaths, syncedAiTools, projectRoot, spinner } = params;
|
|
617
|
+
spinner.start("Writing local state...");
|
|
618
|
+
await writeState(projectRoot, {
|
|
619
|
+
synced_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
620
|
+
tools: syncedAiTools,
|
|
621
|
+
placed_files: [...actualPlacedPaths].sort()
|
|
622
|
+
});
|
|
623
|
+
spinner.stop("Local state updated");
|
|
624
|
+
}
|
|
625
|
+
/**
|
|
626
|
+
* Load previous tool-specific paths for orphan detection.
|
|
627
|
+
*
|
|
628
|
+
* Reads from `.baton/state.yaml` (preferred). Falls back to extracting paths
|
|
629
|
+
* from an old-format `baton.lock` (legacy tool-specific keys) for migration.
|
|
630
|
+
*/
|
|
631
|
+
async function loadPreviousPlacedPaths(projectRoot) {
|
|
632
|
+
const state = await readState(projectRoot);
|
|
633
|
+
if (state) return new Set(state.placed_files);
|
|
634
|
+
try {
|
|
635
|
+
const { readLock } = await import("./src-B8_hp8ig.mjs");
|
|
636
|
+
const previousLock = await readLock(resolve(projectRoot, "baton.lock"));
|
|
637
|
+
const paths = /* @__PURE__ */ new Set();
|
|
638
|
+
for (const pkg of Object.values(previousLock.packages)) for (const filePath of Object.keys(pkg.integrity)) if (filePath.startsWith(".") || filePath.includes("/")) paths.add(filePath);
|
|
639
|
+
return paths;
|
|
640
|
+
} catch {
|
|
641
|
+
return /* @__PURE__ */ new Set();
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
/**
|
|
645
|
+
* Detect and remove files that were previously placed but are no longer
|
|
646
|
+
* part of the current sync. Compares tool-specific paths from state.yaml
|
|
647
|
+
* against currently placed paths. Cleans up empty parent directories.
|
|
613
648
|
*/
|
|
614
649
|
async function cleanupOrphanedFiles(params) {
|
|
615
|
-
const { previousPaths,
|
|
650
|
+
const { previousPaths, currentPaths, projectRoot, dryRun, autoYes, spinner } = params;
|
|
616
651
|
if (previousPaths.size === 0) return;
|
|
617
|
-
const currentPaths = /* @__PURE__ */ new Set();
|
|
618
|
-
for (const files of placedFiles.values()) for (const filePath of Object.keys(files)) currentPaths.add(filePath);
|
|
619
652
|
const orphanedPaths = [...previousPaths].filter((prev) => !currentPaths.has(prev));
|
|
620
653
|
if (orphanedPaths.length === 0) return;
|
|
621
654
|
if (dryRun) {
|
|
@@ -729,8 +762,7 @@ const applyCommand = defineCommand({
|
|
|
729
762
|
if (verbose) R.warn("No lockfile found. Falling back to manifest versions.");
|
|
730
763
|
}
|
|
731
764
|
const maxCacheAgeMs = fresh ? 0 : void 0;
|
|
732
|
-
const previousPaths =
|
|
733
|
-
if (lockfile) for (const pkg of Object.values(lockfile.packages)) for (const filePath of Object.keys(pkg.integrity)) previousPaths.add(filePath);
|
|
765
|
+
const previousPaths = await loadPreviousPlacedPaths(projectRoot);
|
|
734
766
|
const spinner = bt();
|
|
735
767
|
spinner.start("Resolving profile chain...");
|
|
736
768
|
const allProfiles = [];
|
|
@@ -974,6 +1006,7 @@ const applyCommand = defineCommand({
|
|
|
974
1006
|
projectRoot
|
|
975
1007
|
};
|
|
976
1008
|
const placedFiles = /* @__PURE__ */ new Map();
|
|
1009
|
+
const actualPlacedPaths = /* @__PURE__ */ new Set();
|
|
977
1010
|
const profileLocalPaths = /* @__PURE__ */ new Map();
|
|
978
1011
|
for (const profileSource of projectManifest.profiles || []) {
|
|
979
1012
|
const parsed = parseSource(profileSource.source);
|
|
@@ -1065,18 +1098,18 @@ const applyCommand = defineCommand({
|
|
|
1065
1098
|
const absoluteTargetDir = targetSkillPath.startsWith("/") ? targetSkillPath : resolve(projectRoot, targetSkillPath);
|
|
1066
1099
|
const placed = await copyDirectoryRecursive(skillSourceDir, absoluteTargetDir);
|
|
1067
1100
|
stats.created += placed;
|
|
1101
|
+
actualPlacedPaths.add(targetSkillPath);
|
|
1102
|
+
const canonicalKey = `skills/${skillItem.name}`;
|
|
1068
1103
|
const profileFiles = getOrCreatePlacedFiles(placedFiles, skillItem.profileName);
|
|
1069
|
-
try {
|
|
1070
|
-
profileFiles[
|
|
1104
|
+
if (!profileFiles[canonicalKey]) try {
|
|
1105
|
+
profileFiles[canonicalKey] = {
|
|
1071
1106
|
content: await readFile(resolve(skillSourceDir, "index.md"), "utf-8"),
|
|
1072
|
-
|
|
1073
|
-
category: "ai"
|
|
1107
|
+
type: "skills"
|
|
1074
1108
|
};
|
|
1075
1109
|
} catch {
|
|
1076
|
-
profileFiles[
|
|
1110
|
+
profileFiles[canonicalKey] = {
|
|
1077
1111
|
content: skillItem.name,
|
|
1078
|
-
|
|
1079
|
-
category: "ai"
|
|
1112
|
+
type: "skills"
|
|
1080
1113
|
};
|
|
1081
1114
|
}
|
|
1082
1115
|
if (verbose) {
|
|
@@ -1185,12 +1218,13 @@ const applyCommand = defineCommand({
|
|
|
1185
1218
|
const result = await placeFile(combinedContent, entry.adapter, entry.type, "project", entry.name, placementConfig);
|
|
1186
1219
|
if (result.action !== "skipped") stats.created++;
|
|
1187
1220
|
const relPath = isAbsolute(result.path) ? relative(projectRoot, result.path) : result.path;
|
|
1221
|
+
actualPlacedPaths.add(relPath);
|
|
1222
|
+
const canonicalKey = `${entry.type}/${entry.name}`;
|
|
1188
1223
|
for (const profileName of entry.profiles) {
|
|
1189
1224
|
const pf = getOrCreatePlacedFiles(placedFiles, profileName);
|
|
1190
|
-
pf[
|
|
1225
|
+
if (!pf[canonicalKey]) pf[canonicalKey] = {
|
|
1191
1226
|
content: combinedContent,
|
|
1192
|
-
|
|
1193
|
-
category: "ai"
|
|
1227
|
+
type: entry.type
|
|
1194
1228
|
};
|
|
1195
1229
|
}
|
|
1196
1230
|
if (verbose) {
|
|
@@ -1218,11 +1252,12 @@ const applyCommand = defineCommand({
|
|
|
1218
1252
|
const result = await placeFile(content, adapter, "commands", "project", commandName, placementConfig);
|
|
1219
1253
|
if (result.action !== "skipped") stats.created++;
|
|
1220
1254
|
const cmdRelPath = isAbsolute(result.path) ? relative(projectRoot, result.path) : result.path;
|
|
1255
|
+
actualPlacedPaths.add(cmdRelPath);
|
|
1256
|
+
const canonicalKey = `commands/${commandName}`;
|
|
1221
1257
|
const pf = getOrCreatePlacedFiles(placedFiles, profile.name);
|
|
1222
|
-
pf[
|
|
1258
|
+
if (!pf[canonicalKey]) pf[canonicalKey] = {
|
|
1223
1259
|
content,
|
|
1224
|
-
|
|
1225
|
-
category: "ai"
|
|
1260
|
+
type: "commands"
|
|
1226
1261
|
};
|
|
1227
1262
|
if (verbose) {
|
|
1228
1263
|
const label = result.action === "skipped" ? "unchanged, skipped" : result.action;
|
|
@@ -1251,10 +1286,12 @@ const applyCommand = defineCommand({
|
|
|
1251
1286
|
stats.created++;
|
|
1252
1287
|
if (verbose) R.info(` -> ${fileEntry.target} (created)`);
|
|
1253
1288
|
} else if (verbose) R.info(` -> ${fileEntry.target} (unchanged, skipped)`);
|
|
1289
|
+
actualPlacedPaths.add(fileEntry.target);
|
|
1290
|
+
const canonicalKey = `files/${fileEntry.target}`;
|
|
1254
1291
|
const fpf = getOrCreatePlacedFiles(placedFiles, fileEntry.profileName);
|
|
1255
|
-
fpf[
|
|
1292
|
+
if (!fpf[canonicalKey]) fpf[canonicalKey] = {
|
|
1256
1293
|
content,
|
|
1257
|
-
|
|
1294
|
+
type: "files"
|
|
1258
1295
|
};
|
|
1259
1296
|
} catch (error) {
|
|
1260
1297
|
spinner.message(`Error placing file ${fileEntry.source}: ${error}`);
|
|
@@ -1282,11 +1319,12 @@ const applyCommand = defineCommand({
|
|
|
1282
1319
|
if (verbose) R.info(` -> ${ideEntry.targetDir}/${ideEntry.fileName} (created)`);
|
|
1283
1320
|
} else if (verbose) R.info(` -> ${ideEntry.targetDir}/${ideEntry.fileName} (unchanged, skipped)`);
|
|
1284
1321
|
const ideRelPath = `${ideEntry.targetDir}/${ideEntry.fileName}`;
|
|
1322
|
+
actualPlacedPaths.add(ideRelPath);
|
|
1323
|
+
const canonicalKey = `ide/${ideEntry.ideKey}/${ideEntry.fileName}`;
|
|
1285
1324
|
const ipf = getOrCreatePlacedFiles(placedFiles, ideEntry.profileName);
|
|
1286
|
-
ipf[
|
|
1325
|
+
if (!ipf[canonicalKey]) ipf[canonicalKey] = {
|
|
1287
1326
|
content,
|
|
1288
|
-
|
|
1289
|
-
category: "ide"
|
|
1327
|
+
type: "ide"
|
|
1290
1328
|
};
|
|
1291
1329
|
} catch (error) {
|
|
1292
1330
|
spinner.message(`Error placing IDE config ${ideEntry.fileName}: ${error}`);
|
|
@@ -1306,9 +1344,15 @@ const applyCommand = defineCommand({
|
|
|
1306
1344
|
projectRoot,
|
|
1307
1345
|
spinner
|
|
1308
1346
|
});
|
|
1347
|
+
if (!dryRun) await writeStateData({
|
|
1348
|
+
actualPlacedPaths,
|
|
1349
|
+
syncedAiTools,
|
|
1350
|
+
projectRoot,
|
|
1351
|
+
spinner
|
|
1352
|
+
});
|
|
1309
1353
|
await cleanupOrphanedFiles({
|
|
1310
1354
|
previousPaths,
|
|
1311
|
-
|
|
1355
|
+
currentPaths: actualPlacedPaths,
|
|
1312
1356
|
projectRoot,
|
|
1313
1357
|
dryRun,
|
|
1314
1358
|
autoYes,
|
|
@@ -3043,9 +3087,9 @@ const profileCommand = defineCommand({
|
|
|
3043
3087
|
description: "Manage profiles (create, list, remove)"
|
|
3044
3088
|
},
|
|
3045
3089
|
subCommands: {
|
|
3046
|
-
create: () => import("./create-
|
|
3047
|
-
list: () => import("./list-
|
|
3048
|
-
remove: () => import("./remove-
|
|
3090
|
+
create: () => import("./create-y-ut18-j.mjs").then((m) => m.createCommand),
|
|
3091
|
+
list: () => import("./list-BHPDZfmU.mjs").then((m) => m.profileListCommand),
|
|
3092
|
+
remove: () => import("./remove-Cx8jC2vY.mjs").then((m) => m.profileRemoveCommand)
|
|
3049
3093
|
}
|
|
3050
3094
|
});
|
|
3051
3095
|
|
|
@@ -3210,7 +3254,10 @@ const connectCommand = defineCommand({
|
|
|
3210
3254
|
});
|
|
3211
3255
|
const displayName = args.name || url;
|
|
3212
3256
|
R.success(`Connected source: ${displayName}`);
|
|
3213
|
-
const shouldSync = await Re({
|
|
3257
|
+
const shouldSync = await Re({
|
|
3258
|
+
message: "Would you like to sync profiles from this source now?",
|
|
3259
|
+
initialValue: false
|
|
3260
|
+
});
|
|
3214
3261
|
if (Ct(shouldSync) || !shouldSync) {
|
|
3215
3262
|
Le("Source connected. Run 'baton init' to set up profiles.");
|
|
3216
3263
|
return;
|
|
@@ -3638,11 +3685,7 @@ const syncCommand = defineCommand({
|
|
|
3638
3685
|
process.exit(1);
|
|
3639
3686
|
}
|
|
3640
3687
|
await promptFirstRunPreferences(projectRoot, !!args.yes);
|
|
3641
|
-
const previousPaths =
|
|
3642
|
-
try {
|
|
3643
|
-
const previousLock = await readLock(resolve(projectRoot, "baton.lock"));
|
|
3644
|
-
for (const pkg of Object.values(previousLock.packages)) for (const filePath of Object.keys(pkg.integrity)) previousPaths.add(filePath);
|
|
3645
|
-
} catch {}
|
|
3688
|
+
const previousPaths = await loadPreviousPlacedPaths(projectRoot);
|
|
3646
3689
|
const spinner = bt();
|
|
3647
3690
|
spinner.start("Resolving profile chain...");
|
|
3648
3691
|
const allProfiles = [];
|
|
@@ -3884,6 +3927,7 @@ const syncCommand = defineCommand({
|
|
|
3884
3927
|
projectRoot
|
|
3885
3928
|
};
|
|
3886
3929
|
const placedFiles = /* @__PURE__ */ new Map();
|
|
3930
|
+
const actualPlacedPaths = /* @__PURE__ */ new Set();
|
|
3887
3931
|
const profileLocalPaths = /* @__PURE__ */ new Map();
|
|
3888
3932
|
for (const profileSource of projectManifest.profiles || []) {
|
|
3889
3933
|
const parsed = parseSource(profileSource.source);
|
|
@@ -3967,18 +4011,18 @@ const syncCommand = defineCommand({
|
|
|
3967
4011
|
const absoluteTargetDir = targetSkillPath.startsWith("/") ? targetSkillPath : resolve(projectRoot, targetSkillPath);
|
|
3968
4012
|
const placed = await copyDirectoryRecursive(skillSourceDir, absoluteTargetDir);
|
|
3969
4013
|
stats.created += placed;
|
|
4014
|
+
actualPlacedPaths.add(targetSkillPath);
|
|
4015
|
+
const canonicalKey = `skills/${skillItem.name}`;
|
|
3970
4016
|
const profileFiles = getOrCreatePlacedFiles(placedFiles, skillItem.profileName);
|
|
3971
|
-
try {
|
|
3972
|
-
profileFiles[
|
|
4017
|
+
if (!profileFiles[canonicalKey]) try {
|
|
4018
|
+
profileFiles[canonicalKey] = {
|
|
3973
4019
|
content: await readFile(resolve(skillSourceDir, "index.md"), "utf-8"),
|
|
3974
|
-
|
|
3975
|
-
category: "ai"
|
|
4020
|
+
type: "skills"
|
|
3976
4021
|
};
|
|
3977
4022
|
} catch {
|
|
3978
|
-
profileFiles[
|
|
4023
|
+
profileFiles[canonicalKey] = {
|
|
3979
4024
|
content: skillItem.name,
|
|
3980
|
-
|
|
3981
|
-
category: "ai"
|
|
4025
|
+
type: "skills"
|
|
3982
4026
|
};
|
|
3983
4027
|
}
|
|
3984
4028
|
if (verbose) {
|
|
@@ -4087,12 +4131,13 @@ const syncCommand = defineCommand({
|
|
|
4087
4131
|
const result = await placeFile(combinedContent, entry.adapter, entry.type, "project", entry.name, placementConfig);
|
|
4088
4132
|
if (result.action !== "skipped") stats.created++;
|
|
4089
4133
|
const relPath = isAbsolute(result.path) ? relative(projectRoot, result.path) : result.path;
|
|
4134
|
+
actualPlacedPaths.add(relPath);
|
|
4135
|
+
const canonicalKey = `${entry.type}/${entry.name}`;
|
|
4090
4136
|
for (const profileName of entry.profiles) {
|
|
4091
4137
|
const pf = getOrCreatePlacedFiles(placedFiles, profileName);
|
|
4092
|
-
pf[
|
|
4138
|
+
if (!pf[canonicalKey]) pf[canonicalKey] = {
|
|
4093
4139
|
content: combinedContent,
|
|
4094
|
-
|
|
4095
|
-
category: "ai"
|
|
4140
|
+
type: entry.type
|
|
4096
4141
|
};
|
|
4097
4142
|
}
|
|
4098
4143
|
if (verbose) {
|
|
@@ -4120,11 +4165,12 @@ const syncCommand = defineCommand({
|
|
|
4120
4165
|
const result = await placeFile(content, adapter, "commands", "project", commandName, placementConfig);
|
|
4121
4166
|
if (result.action !== "skipped") stats.created++;
|
|
4122
4167
|
const cmdRelPath = isAbsolute(result.path) ? relative(projectRoot, result.path) : result.path;
|
|
4168
|
+
actualPlacedPaths.add(cmdRelPath);
|
|
4169
|
+
const canonicalKey = `commands/${commandName}`;
|
|
4123
4170
|
const pf = getOrCreatePlacedFiles(placedFiles, profile.name);
|
|
4124
|
-
pf[
|
|
4171
|
+
if (!pf[canonicalKey]) pf[canonicalKey] = {
|
|
4125
4172
|
content,
|
|
4126
|
-
|
|
4127
|
-
category: "ai"
|
|
4173
|
+
type: "commands"
|
|
4128
4174
|
};
|
|
4129
4175
|
if (verbose) {
|
|
4130
4176
|
const label = result.action === "skipped" ? "unchanged, skipped" : result.action;
|
|
@@ -4153,10 +4199,12 @@ const syncCommand = defineCommand({
|
|
|
4153
4199
|
stats.created++;
|
|
4154
4200
|
if (verbose) R.info(` -> ${fileEntry.target} (created)`);
|
|
4155
4201
|
} else if (verbose) R.info(` -> ${fileEntry.target} (unchanged, skipped)`);
|
|
4202
|
+
actualPlacedPaths.add(fileEntry.target);
|
|
4203
|
+
const canonicalKey = `files/${fileEntry.target}`;
|
|
4156
4204
|
const fpf = getOrCreatePlacedFiles(placedFiles, fileEntry.profileName);
|
|
4157
|
-
fpf[
|
|
4205
|
+
if (!fpf[canonicalKey]) fpf[canonicalKey] = {
|
|
4158
4206
|
content,
|
|
4159
|
-
|
|
4207
|
+
type: "files"
|
|
4160
4208
|
};
|
|
4161
4209
|
} catch (error) {
|
|
4162
4210
|
spinner.message(`Error placing file ${fileEntry.source}: ${error}`);
|
|
@@ -4184,11 +4232,12 @@ const syncCommand = defineCommand({
|
|
|
4184
4232
|
if (verbose) R.info(` -> ${ideEntry.targetDir}/${ideEntry.fileName} (created)`);
|
|
4185
4233
|
} else if (verbose) R.info(` -> ${ideEntry.targetDir}/${ideEntry.fileName} (unchanged, skipped)`);
|
|
4186
4234
|
const ideRelPath = `${ideEntry.targetDir}/${ideEntry.fileName}`;
|
|
4235
|
+
actualPlacedPaths.add(ideRelPath);
|
|
4236
|
+
const canonicalKey = `ide/${ideEntry.ideKey}/${ideEntry.fileName}`;
|
|
4187
4237
|
const ipf = getOrCreatePlacedFiles(placedFiles, ideEntry.profileName);
|
|
4188
|
-
ipf[
|
|
4238
|
+
if (!ipf[canonicalKey]) ipf[canonicalKey] = {
|
|
4189
4239
|
content,
|
|
4190
|
-
|
|
4191
|
-
category: "ide"
|
|
4240
|
+
type: "ide"
|
|
4192
4241
|
};
|
|
4193
4242
|
} catch (error) {
|
|
4194
4243
|
spinner.message(`Error placing IDE config ${ideEntry.fileName}: ${error}`);
|
|
@@ -4208,9 +4257,15 @@ const syncCommand = defineCommand({
|
|
|
4208
4257
|
projectRoot,
|
|
4209
4258
|
spinner
|
|
4210
4259
|
});
|
|
4260
|
+
if (!dryRun) await writeStateData({
|
|
4261
|
+
actualPlacedPaths,
|
|
4262
|
+
syncedAiTools,
|
|
4263
|
+
projectRoot,
|
|
4264
|
+
spinner
|
|
4265
|
+
});
|
|
4211
4266
|
await cleanupOrphanedFiles({
|
|
4212
4267
|
previousPaths,
|
|
4213
|
-
|
|
4268
|
+
currentPaths: actualPlacedPaths,
|
|
4214
4269
|
projectRoot,
|
|
4215
4270
|
dryRun,
|
|
4216
4271
|
autoYes,
|