@baton-dx/cli 0.6.1 → 0.7.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-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-Cq7dvT9C.mjs → create-BiE2_2Fo.mjs} +5 -4
- package/dist/{create-Cq7dvT9C.mjs.map → create-BiE2_2Fo.mjs.map} +1 -1
- package/dist/{context-detection-CGh_5f6N.mjs → dist-BoZnMvNi.mjs} +2 -3188
- package/dist/dist-BoZnMvNi.mjs.map +1 -0
- package/dist/index.mjs +111 -59
- package/dist/index.mjs.map +1 -1
- package/dist/{list-xZTyCWwl.mjs → list-7GvmRp3q.mjs} +5 -4
- package/dist/{list-xZTyCWwl.mjs.map → list-7GvmRp3q.mjs.map} +1 -1
- package/dist/{prompt-JYaE4U2w.mjs → prompt-DXfUeR3X.mjs} +4 -4
- package/dist/prompt-DXfUeR3X.mjs.map +1 -0
- package/dist/{remove-DSBMNbtP.mjs → remove-Cx8jC2vY.mjs} +3 -2
- package/dist/{remove-DSBMNbtP.mjs.map → remove-Cx8jC2vY.mjs.map} +1 -1
- package/dist/src-C-rwSQpx.mjs +6 -0
- package/dist/{src-B-Z49jsg.mjs → src-C0c228gb.mjs} +76 -16
- package/dist/src-C0c228gb.mjs.map +1 -0
- package/package.json +1 -1
- package/dist/context-detection-CGh_5f6N.mjs.map +0 -1
- package/dist/prompt-JYaE4U2w.mjs.map +0 -1
- package/dist/src-B-Z49jsg.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-C0c228gb.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-C-rwSQpx.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-BiE2_2Fo.mjs").then((m) => m.createCommand),
|
|
3091
|
+
list: () => import("./list-7GvmRp3q.mjs").then((m) => m.profileListCommand),
|
|
3092
|
+
remove: () => import("./remove-Cx8jC2vY.mjs").then((m) => m.profileRemoveCommand)
|
|
3049
3093
|
}
|
|
3050
3094
|
});
|
|
3051
3095
|
|
|
@@ -3115,9 +3159,9 @@ const selfUpdateCommand = defineCommand({
|
|
|
3115
3159
|
R.warn("Could not detect installation method.");
|
|
3116
3160
|
R.message([
|
|
3117
3161
|
"Please update manually using one of:",
|
|
3118
|
-
" npm
|
|
3119
|
-
" pnpm update -g @baton-dx/cli",
|
|
3120
|
-
" bun update -g @baton-dx/cli",
|
|
3162
|
+
" npm install -g @baton-dx/cli@latest",
|
|
3163
|
+
" pnpm update -g @baton-dx/cli --latest",
|
|
3164
|
+
" bun update -g @baton-dx/cli --latest",
|
|
3121
3165
|
" brew upgrade baton-dx"
|
|
3122
3166
|
].join("\n"));
|
|
3123
3167
|
Le("Manual update required.");
|
|
@@ -3641,11 +3685,7 @@ const syncCommand = defineCommand({
|
|
|
3641
3685
|
process.exit(1);
|
|
3642
3686
|
}
|
|
3643
3687
|
await promptFirstRunPreferences(projectRoot, !!args.yes);
|
|
3644
|
-
const previousPaths =
|
|
3645
|
-
try {
|
|
3646
|
-
const previousLock = await readLock(resolve(projectRoot, "baton.lock"));
|
|
3647
|
-
for (const pkg of Object.values(previousLock.packages)) for (const filePath of Object.keys(pkg.integrity)) previousPaths.add(filePath);
|
|
3648
|
-
} catch {}
|
|
3688
|
+
const previousPaths = await loadPreviousPlacedPaths(projectRoot);
|
|
3649
3689
|
const spinner = bt();
|
|
3650
3690
|
spinner.start("Resolving profile chain...");
|
|
3651
3691
|
const allProfiles = [];
|
|
@@ -3887,6 +3927,7 @@ const syncCommand = defineCommand({
|
|
|
3887
3927
|
projectRoot
|
|
3888
3928
|
};
|
|
3889
3929
|
const placedFiles = /* @__PURE__ */ new Map();
|
|
3930
|
+
const actualPlacedPaths = /* @__PURE__ */ new Set();
|
|
3890
3931
|
const profileLocalPaths = /* @__PURE__ */ new Map();
|
|
3891
3932
|
for (const profileSource of projectManifest.profiles || []) {
|
|
3892
3933
|
const parsed = parseSource(profileSource.source);
|
|
@@ -3970,18 +4011,18 @@ const syncCommand = defineCommand({
|
|
|
3970
4011
|
const absoluteTargetDir = targetSkillPath.startsWith("/") ? targetSkillPath : resolve(projectRoot, targetSkillPath);
|
|
3971
4012
|
const placed = await copyDirectoryRecursive(skillSourceDir, absoluteTargetDir);
|
|
3972
4013
|
stats.created += placed;
|
|
4014
|
+
actualPlacedPaths.add(targetSkillPath);
|
|
4015
|
+
const canonicalKey = `skills/${skillItem.name}`;
|
|
3973
4016
|
const profileFiles = getOrCreatePlacedFiles(placedFiles, skillItem.profileName);
|
|
3974
|
-
try {
|
|
3975
|
-
profileFiles[
|
|
4017
|
+
if (!profileFiles[canonicalKey]) try {
|
|
4018
|
+
profileFiles[canonicalKey] = {
|
|
3976
4019
|
content: await readFile(resolve(skillSourceDir, "index.md"), "utf-8"),
|
|
3977
|
-
|
|
3978
|
-
category: "ai"
|
|
4020
|
+
type: "skills"
|
|
3979
4021
|
};
|
|
3980
4022
|
} catch {
|
|
3981
|
-
profileFiles[
|
|
4023
|
+
profileFiles[canonicalKey] = {
|
|
3982
4024
|
content: skillItem.name,
|
|
3983
|
-
|
|
3984
|
-
category: "ai"
|
|
4025
|
+
type: "skills"
|
|
3985
4026
|
};
|
|
3986
4027
|
}
|
|
3987
4028
|
if (verbose) {
|
|
@@ -4090,12 +4131,13 @@ const syncCommand = defineCommand({
|
|
|
4090
4131
|
const result = await placeFile(combinedContent, entry.adapter, entry.type, "project", entry.name, placementConfig);
|
|
4091
4132
|
if (result.action !== "skipped") stats.created++;
|
|
4092
4133
|
const relPath = isAbsolute(result.path) ? relative(projectRoot, result.path) : result.path;
|
|
4134
|
+
actualPlacedPaths.add(relPath);
|
|
4135
|
+
const canonicalKey = `${entry.type}/${entry.name}`;
|
|
4093
4136
|
for (const profileName of entry.profiles) {
|
|
4094
4137
|
const pf = getOrCreatePlacedFiles(placedFiles, profileName);
|
|
4095
|
-
pf[
|
|
4138
|
+
if (!pf[canonicalKey]) pf[canonicalKey] = {
|
|
4096
4139
|
content: combinedContent,
|
|
4097
|
-
|
|
4098
|
-
category: "ai"
|
|
4140
|
+
type: entry.type
|
|
4099
4141
|
};
|
|
4100
4142
|
}
|
|
4101
4143
|
if (verbose) {
|
|
@@ -4123,11 +4165,12 @@ const syncCommand = defineCommand({
|
|
|
4123
4165
|
const result = await placeFile(content, adapter, "commands", "project", commandName, placementConfig);
|
|
4124
4166
|
if (result.action !== "skipped") stats.created++;
|
|
4125
4167
|
const cmdRelPath = isAbsolute(result.path) ? relative(projectRoot, result.path) : result.path;
|
|
4168
|
+
actualPlacedPaths.add(cmdRelPath);
|
|
4169
|
+
const canonicalKey = `commands/${commandName}`;
|
|
4126
4170
|
const pf = getOrCreatePlacedFiles(placedFiles, profile.name);
|
|
4127
|
-
pf[
|
|
4171
|
+
if (!pf[canonicalKey]) pf[canonicalKey] = {
|
|
4128
4172
|
content,
|
|
4129
|
-
|
|
4130
|
-
category: "ai"
|
|
4173
|
+
type: "commands"
|
|
4131
4174
|
};
|
|
4132
4175
|
if (verbose) {
|
|
4133
4176
|
const label = result.action === "skipped" ? "unchanged, skipped" : result.action;
|
|
@@ -4156,10 +4199,12 @@ const syncCommand = defineCommand({
|
|
|
4156
4199
|
stats.created++;
|
|
4157
4200
|
if (verbose) R.info(` -> ${fileEntry.target} (created)`);
|
|
4158
4201
|
} else if (verbose) R.info(` -> ${fileEntry.target} (unchanged, skipped)`);
|
|
4202
|
+
actualPlacedPaths.add(fileEntry.target);
|
|
4203
|
+
const canonicalKey = `files/${fileEntry.target}`;
|
|
4159
4204
|
const fpf = getOrCreatePlacedFiles(placedFiles, fileEntry.profileName);
|
|
4160
|
-
fpf[
|
|
4205
|
+
if (!fpf[canonicalKey]) fpf[canonicalKey] = {
|
|
4161
4206
|
content,
|
|
4162
|
-
|
|
4207
|
+
type: "files"
|
|
4163
4208
|
};
|
|
4164
4209
|
} catch (error) {
|
|
4165
4210
|
spinner.message(`Error placing file ${fileEntry.source}: ${error}`);
|
|
@@ -4187,11 +4232,12 @@ const syncCommand = defineCommand({
|
|
|
4187
4232
|
if (verbose) R.info(` -> ${ideEntry.targetDir}/${ideEntry.fileName} (created)`);
|
|
4188
4233
|
} else if (verbose) R.info(` -> ${ideEntry.targetDir}/${ideEntry.fileName} (unchanged, skipped)`);
|
|
4189
4234
|
const ideRelPath = `${ideEntry.targetDir}/${ideEntry.fileName}`;
|
|
4235
|
+
actualPlacedPaths.add(ideRelPath);
|
|
4236
|
+
const canonicalKey = `ide/${ideEntry.ideKey}/${ideEntry.fileName}`;
|
|
4190
4237
|
const ipf = getOrCreatePlacedFiles(placedFiles, ideEntry.profileName);
|
|
4191
|
-
ipf[
|
|
4238
|
+
if (!ipf[canonicalKey]) ipf[canonicalKey] = {
|
|
4192
4239
|
content,
|
|
4193
|
-
|
|
4194
|
-
category: "ide"
|
|
4240
|
+
type: "ide"
|
|
4195
4241
|
};
|
|
4196
4242
|
} catch (error) {
|
|
4197
4243
|
spinner.message(`Error placing IDE config ${ideEntry.fileName}: ${error}`);
|
|
@@ -4211,9 +4257,15 @@ const syncCommand = defineCommand({
|
|
|
4211
4257
|
projectRoot,
|
|
4212
4258
|
spinner
|
|
4213
4259
|
});
|
|
4260
|
+
if (!dryRun) await writeStateData({
|
|
4261
|
+
actualPlacedPaths,
|
|
4262
|
+
syncedAiTools,
|
|
4263
|
+
projectRoot,
|
|
4264
|
+
spinner
|
|
4265
|
+
});
|
|
4214
4266
|
await cleanupOrphanedFiles({
|
|
4215
4267
|
previousPaths,
|
|
4216
|
-
|
|
4268
|
+
currentPaths: actualPlacedPaths,
|
|
4217
4269
|
projectRoot,
|
|
4218
4270
|
dryRun,
|
|
4219
4271
|
autoYes,
|