@baton-dx/cli 0.5.0 → 0.6.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.
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
- import { a as Ne, h as defineCommand, i as Le, l as We, p as Ct, t as findSourceRoot, u as Ze, y as __toESM } from "./context-detection-C7T1evnW.mjs";
3
- import { _ as require_lib, nt as KEBAB_CASE_REGEX } from "./src-n95I0s2u.mjs";
2
+ import { a as Ne, h as defineCommand, i as Le, l as We, p as Ct, t as findSourceRoot, u as Ze, y as __toESM } from "./context-detection-CGh_5f6N.mjs";
3
+ import { ot as KEBAB_CASE_REGEX, x as require_lib } from "./src-B-Z49jsg.mjs";
4
4
  import "./ai-tool-detection-DMnwwNBI.mjs";
5
5
  import { mkdir, readFile, readdir, writeFile } from "node:fs/promises";
6
6
  import { dirname, join } from "node:path";
@@ -77,4 +77,4 @@ async function copyProfileTemplate(sourceDir, targetDir, variables) {
77
77
 
78
78
  //#endregion
79
79
  export { createCommand };
80
- //# sourceMappingURL=create-Cx1nCS3X.mjs.map
80
+ //# sourceMappingURL=create-Cq7dvT9C.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"create-Cx1nCS3X.mjs","names":["p.text","p.isCancel","Handlebars"],"sources":["../src/commands/profile/create.ts"],"sourcesContent":["import { mkdir, readFile, readdir, writeFile } from \"node:fs/promises\";\nimport { dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { KEBAB_CASE_REGEX } from \"@baton-dx/core\";\nimport * as p from \"@clack/prompts\";\nimport { defineCommand } from \"citty\";\nimport Handlebars from \"handlebars\";\nimport { findSourceRoot } from \"../../utils/context-detection.js\";\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n\nexport const createCommand = defineCommand({\n meta: {\n name: \"create\",\n description: \"Create a new profile in your source repository\",\n },\n args: {\n name: {\n type: \"positional\",\n description: \"Profile name (kebab-case)\",\n required: false,\n },\n },\n async run({ args }) {\n p.intro(\"Create Profile\");\n\n // Check for baton.source.yaml in current or parent directories\n const sourceRoot = await findSourceRoot();\n if (!sourceRoot) {\n p.cancel(\"This command must be run inside a source directory (baton.source.yaml not found)\");\n process.exit(1);\n }\n\n // Get profile name — from argument or wizard prompt\n let name = args.name as string | undefined;\n\n if (!name) {\n const nameInput = await p.text({\n message: \"Profile name (kebab-case)\",\n placeholder: \"e.g., backend, frontend, my-profile\",\n validate(value) {\n if (!value || value.trim().length === 0) {\n return \"Profile name is required\";\n }\n if (!KEBAB_CASE_REGEX.test(value.trim())) {\n return \"Profile name must be in kebab-case (e.g., my-profile, backend, frontend)\";\n }\n },\n });\n\n if (p.isCancel(nameInput)) {\n p.cancel(\"Cancelled.\");\n process.exit(0);\n }\n\n name = (nameInput as string).trim();\n }\n\n // Validate name format (kebab-case)\n if (!KEBAB_CASE_REGEX.test(name)) {\n p.cancel(\"Profile name must be in kebab-case (e.g., my-profile, backend, frontend)\");\n process.exit(1);\n }\n\n // Check if profile already exists in profiles/ directory\n const targetDir = join(sourceRoot, \"profiles\", name);\n try {\n await readdir(targetDir);\n p.cancel(`Profile '${name}' already exists in profiles/${name}/`);\n process.exit(1);\n } catch {\n // Directory doesn't exist - good to proceed\n }\n\n // Create profile directory\n await mkdir(targetDir, { recursive: true });\n\n // Copy minimal template files\n const templateDir = join(__dirname, \"templates\", \"profile\", \"minimal\");\n await copyProfileTemplate(templateDir, targetDir, { name });\n\n p.outro(`Profile '${name}' created in profiles/${name}/`);\n },\n});\n\n/**\n * Recursively copy profile template with variable substitution\n */\nasync function copyProfileTemplate(\n sourceDir: string,\n targetDir: string,\n variables: { name: string },\n): Promise<void> {\n const entries = await readdir(sourceDir, { withFileTypes: true });\n\n for (const entry of entries) {\n const sourcePath = join(sourceDir, entry.name);\n const targetPath = join(targetDir, entry.name);\n\n if (entry.isDirectory()) {\n await mkdir(targetPath, { recursive: true });\n await copyProfileTemplate(sourcePath, targetPath, variables);\n } else {\n // Read file content\n const content = await readFile(sourcePath, \"utf-8\");\n\n // Apply Handlebars substitution for text files\n const processed = Handlebars.compile(content, { noEscape: true })(variables);\n\n // Write processed content\n await writeFile(targetPath, processed, \"utf-8\");\n }\n }\n}\n"],"mappings":";;;;;;;;;;AASA,MAAM,YAAY,QAAQ,cAAc,OAAO,KAAK,IAAI,CAAC;AAEzD,MAAa,gBAAgB,cAAc;CACzC,MAAM;EACJ,MAAM;EACN,aAAa;EACd;CACD,MAAM,EACJ,MAAM;EACJ,MAAM;EACN,aAAa;EACb,UAAU;EACX,EACF;CACD,MAAM,IAAI,EAAE,QAAQ;AAClB,KAAQ,iBAAiB;EAGzB,MAAM,aAAa,MAAM,gBAAgB;AACzC,MAAI,CAAC,YAAY;AACf,MAAS,mFAAmF;AAC5F,WAAQ,KAAK,EAAE;;EAIjB,IAAI,OAAO,KAAK;AAEhB,MAAI,CAAC,MAAM;GACT,MAAM,YAAY,MAAMA,GAAO;IAC7B,SAAS;IACT,aAAa;IACb,SAAS,OAAO;AACd,SAAI,CAAC,SAAS,MAAM,MAAM,CAAC,WAAW,EACpC,QAAO;AAET,SAAI,CAAC,iBAAiB,KAAK,MAAM,MAAM,CAAC,CACtC,QAAO;;IAGZ,CAAC;AAEF,OAAIC,GAAW,UAAU,EAAE;AACzB,OAAS,aAAa;AACtB,YAAQ,KAAK,EAAE;;AAGjB,UAAQ,UAAqB,MAAM;;AAIrC,MAAI,CAAC,iBAAiB,KAAK,KAAK,EAAE;AAChC,MAAS,2EAA2E;AACpF,WAAQ,KAAK,EAAE;;EAIjB,MAAM,YAAY,KAAK,YAAY,YAAY,KAAK;AACpD,MAAI;AACF,SAAM,QAAQ,UAAU;AACxB,MAAS,YAAY,KAAK,+BAA+B,KAAK,GAAG;AACjE,WAAQ,KAAK,EAAE;UACT;AAKR,QAAM,MAAM,WAAW,EAAE,WAAW,MAAM,CAAC;AAI3C,QAAM,oBADc,KAAK,WAAW,aAAa,WAAW,UAAU,EAC/B,WAAW,EAAE,MAAM,CAAC;AAE3D,KAAQ,YAAY,KAAK,wBAAwB,KAAK,GAAG;;CAE5D,CAAC;;;;AAKF,eAAe,oBACb,WACA,WACA,WACe;CACf,MAAM,UAAU,MAAM,QAAQ,WAAW,EAAE,eAAe,MAAM,CAAC;AAEjE,MAAK,MAAM,SAAS,SAAS;EAC3B,MAAM,aAAa,KAAK,WAAW,MAAM,KAAK;EAC9C,MAAM,aAAa,KAAK,WAAW,MAAM,KAAK;AAE9C,MAAI,MAAM,aAAa,EAAE;AACvB,SAAM,MAAM,YAAY,EAAE,WAAW,MAAM,CAAC;AAC5C,SAAM,oBAAoB,YAAY,YAAY,UAAU;SACvD;GAEL,MAAM,UAAU,MAAM,SAAS,YAAY,QAAQ;AAMnD,SAAM,UAAU,YAHEC,mBAAW,QAAQ,SAAS,EAAE,UAAU,MAAM,CAAC,CAAC,UAAU,EAGrC,QAAQ"}
1
+ {"version":3,"file":"create-Cq7dvT9C.mjs","names":["p.text","p.isCancel","Handlebars"],"sources":["../src/commands/profile/create.ts"],"sourcesContent":["import { mkdir, readFile, readdir, writeFile } from \"node:fs/promises\";\nimport { dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { KEBAB_CASE_REGEX } from \"@baton-dx/core\";\nimport * as p from \"@clack/prompts\";\nimport { defineCommand } from \"citty\";\nimport Handlebars from \"handlebars\";\nimport { findSourceRoot } from \"../../utils/context-detection.js\";\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n\nexport const createCommand = defineCommand({\n meta: {\n name: \"create\",\n description: \"Create a new profile in your source repository\",\n },\n args: {\n name: {\n type: \"positional\",\n description: \"Profile name (kebab-case)\",\n required: false,\n },\n },\n async run({ args }) {\n p.intro(\"Create Profile\");\n\n // Check for baton.source.yaml in current or parent directories\n const sourceRoot = await findSourceRoot();\n if (!sourceRoot) {\n p.cancel(\"This command must be run inside a source directory (baton.source.yaml not found)\");\n process.exit(1);\n }\n\n // Get profile name — from argument or wizard prompt\n let name = args.name as string | undefined;\n\n if (!name) {\n const nameInput = await p.text({\n message: \"Profile name (kebab-case)\",\n placeholder: \"e.g., backend, frontend, my-profile\",\n validate(value) {\n if (!value || value.trim().length === 0) {\n return \"Profile name is required\";\n }\n if (!KEBAB_CASE_REGEX.test(value.trim())) {\n return \"Profile name must be in kebab-case (e.g., my-profile, backend, frontend)\";\n }\n },\n });\n\n if (p.isCancel(nameInput)) {\n p.cancel(\"Cancelled.\");\n process.exit(0);\n }\n\n name = (nameInput as string).trim();\n }\n\n // Validate name format (kebab-case)\n if (!KEBAB_CASE_REGEX.test(name)) {\n p.cancel(\"Profile name must be in kebab-case (e.g., my-profile, backend, frontend)\");\n process.exit(1);\n }\n\n // Check if profile already exists in profiles/ directory\n const targetDir = join(sourceRoot, \"profiles\", name);\n try {\n await readdir(targetDir);\n p.cancel(`Profile '${name}' already exists in profiles/${name}/`);\n process.exit(1);\n } catch {\n // Directory doesn't exist - good to proceed\n }\n\n // Create profile directory\n await mkdir(targetDir, { recursive: true });\n\n // Copy minimal template files\n const templateDir = join(__dirname, \"templates\", \"profile\", \"minimal\");\n await copyProfileTemplate(templateDir, targetDir, { name });\n\n p.outro(`Profile '${name}' created in profiles/${name}/`);\n },\n});\n\n/**\n * Recursively copy profile template with variable substitution\n */\nasync function copyProfileTemplate(\n sourceDir: string,\n targetDir: string,\n variables: { name: string },\n): Promise<void> {\n const entries = await readdir(sourceDir, { withFileTypes: true });\n\n for (const entry of entries) {\n const sourcePath = join(sourceDir, entry.name);\n const targetPath = join(targetDir, entry.name);\n\n if (entry.isDirectory()) {\n await mkdir(targetPath, { recursive: true });\n await copyProfileTemplate(sourcePath, targetPath, variables);\n } else {\n // Read file content\n const content = await readFile(sourcePath, \"utf-8\");\n\n // Apply Handlebars substitution for text files\n const processed = Handlebars.compile(content, { noEscape: true })(variables);\n\n // Write processed content\n await writeFile(targetPath, processed, \"utf-8\");\n }\n }\n}\n"],"mappings":";;;;;;;;;;AASA,MAAM,YAAY,QAAQ,cAAc,OAAO,KAAK,IAAI,CAAC;AAEzD,MAAa,gBAAgB,cAAc;CACzC,MAAM;EACJ,MAAM;EACN,aAAa;EACd;CACD,MAAM,EACJ,MAAM;EACJ,MAAM;EACN,aAAa;EACb,UAAU;EACX,EACF;CACD,MAAM,IAAI,EAAE,QAAQ;AAClB,KAAQ,iBAAiB;EAGzB,MAAM,aAAa,MAAM,gBAAgB;AACzC,MAAI,CAAC,YAAY;AACf,MAAS,mFAAmF;AAC5F,WAAQ,KAAK,EAAE;;EAIjB,IAAI,OAAO,KAAK;AAEhB,MAAI,CAAC,MAAM;GACT,MAAM,YAAY,MAAMA,GAAO;IAC7B,SAAS;IACT,aAAa;IACb,SAAS,OAAO;AACd,SAAI,CAAC,SAAS,MAAM,MAAM,CAAC,WAAW,EACpC,QAAO;AAET,SAAI,CAAC,iBAAiB,KAAK,MAAM,MAAM,CAAC,CACtC,QAAO;;IAGZ,CAAC;AAEF,OAAIC,GAAW,UAAU,EAAE;AACzB,OAAS,aAAa;AACtB,YAAQ,KAAK,EAAE;;AAGjB,UAAQ,UAAqB,MAAM;;AAIrC,MAAI,CAAC,iBAAiB,KAAK,KAAK,EAAE;AAChC,MAAS,2EAA2E;AACpF,WAAQ,KAAK,EAAE;;EAIjB,MAAM,YAAY,KAAK,YAAY,YAAY,KAAK;AACpD,MAAI;AACF,SAAM,QAAQ,UAAU;AACxB,MAAS,YAAY,KAAK,+BAA+B,KAAK,GAAG;AACjE,WAAQ,KAAK,EAAE;UACT;AAKR,QAAM,MAAM,WAAW,EAAE,WAAW,MAAM,CAAC;AAI3C,QAAM,oBADc,KAAK,WAAW,aAAa,WAAW,UAAU,EAC/B,WAAW,EAAE,MAAM,CAAC;AAE3D,KAAQ,YAAY,KAAK,wBAAwB,KAAK,GAAG;;CAE5D,CAAC;;;;AAKF,eAAe,oBACb,WACA,WACA,WACe;CACf,MAAM,UAAU,MAAM,QAAQ,WAAW,EAAE,eAAe,MAAM,CAAC;AAEjE,MAAK,MAAM,SAAS,SAAS;EAC3B,MAAM,aAAa,KAAK,WAAW,MAAM,KAAK;EAC9C,MAAM,aAAa,KAAK,WAAW,MAAM,KAAK;AAE9C,MAAI,MAAM,aAAa,EAAE;AACvB,SAAM,MAAM,YAAY,EAAE,WAAW,MAAM,CAAC;AAC5C,SAAM,oBAAoB,YAAY,YAAY,UAAU;SACvD;GAEL,MAAM,UAAU,MAAM,SAAS,YAAY,QAAQ;AAMnD,SAAM,UAAU,YAHEC,mBAAW,QAAQ,SAAS,EAAE,UAAU,MAAM,CAAC,CAAC,UAAU,EAGrC,QAAQ"}
package/dist/index.mjs CHANGED
@@ -1,10 +1,11 @@
1
1
  #!/usr/bin/env node
2
- 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, y as __toESM } from "./context-detection-C7T1evnW.mjs";
3
- import { $ as parseSource, A as resolveProfileChain, B as cloneGitSource, C as mergeSkills, D as sortProfilesByWeight, E as isLockedProfile, F as removePlacedFiles, G as updateGitignore, H as collectComprehensivePatterns, I as generateLock, J as idePlatformRegistry, K as getIdePlatformTargetDir, L as readLock, M as placeFile, N as discoverProfilesInSourceRepo, O as mergeContentParts, P as findSourceManifest, Q as parseFrontmatter, R as writeLock, S as mergeRulesWithWarnings, T as getProfileWeight, U as ensureBatonDirGitignored, V as esm_default, W as removeGitignoreManagedSection, X as getAIToolAdaptersForKeys, Y as isKnownIdePlatform, Z as getAllAIToolAdapters, _ as require_lib, a as clearIdeCache, at as getAIToolConfig, b as mergeAgentsWithWarnings, c as getDefaultGlobalSource, d as getGlobalSources, et as loadProfileManifest, f as loadGlobalConfig, g as setGlobalIdePlatforms, h as setGlobalAiTools, i as computeIntersection, it as SourceParseError, j as detectLegacyPaths, k as resolveProfileSupport, l as getGlobalAiTools, m as saveGlobalConfig, n as readProjectPreferences, nt as KEBAB_CASE_REGEX, o as detectInstalledIdes, ot as getAIToolPath, p as removeGlobalSource, q as getRegisteredIdePlatforms, r as writeProjectPreferences, rt as FileNotFoundError, s as addGlobalSource, st as getAllAIToolKeys, t as resolvePreferences, tt as loadProjectManifest, u as getGlobalIdePlatforms, v as mergeMemory, w as mergeSkillsWithWarnings, x as mergeRules, y as mergeMemoryWithWarnings, z as resolveVersion } from "./src-n95I0s2u.mjs";
2
+ 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, y as __toESM } from "./context-detection-CGh_5f6N.mjs";
3
+ import { $ as isKnownIdePlatform, A as isLockedProfile, B as generateLock, C as mergeMemoryWithWarnings, D as mergeSkills, E as mergeRulesWithWarnings, F as detectLegacyPaths, G as esm_default, H as writeLock, I as placeFile, J as removeGitignoreManagedSection, K as collectComprehensivePatterns, L as discoverProfilesInSourceRepo, M as mergeContentParts, N as resolveProfileSupport, O as mergeSkillsWithWarnings, P as resolveProfileChain, Q as idePlatformRegistry, R as findSourceManifest, S as mergeMemory, T as mergeRules, U as resolveVersion, V as readLock, W as cloneGitSource, X as getIdePlatformTargetDir, Y as updateGitignore, Z as getRegisteredIdePlatforms, _ as removeGlobalSource, a as resolvePreferences, at as loadProjectManifest, b as setGlobalIdePlatforms, c as computeIntersection, ct as SourceParseError, d as addGlobalSource, dt as getAllAIToolKeys, et as getAIToolAdaptersForKeys, f as getDefaultGlobalSource, g as loadGlobalConfig, h as getGlobalSources, i as formatInstallCommand, it as loadProfileManifest, j as sortProfilesByWeight, k as getProfileWeight, l as clearIdeCache, lt as getAIToolConfig, m as getGlobalIdePlatforms, n as isUpdateAvailable, nt as parseFrontmatter, o as readProjectPreferences, ot as KEBAB_CASE_REGEX, p as getGlobalAiTools, q as ensureBatonDirGitignored, r as detectInstallMethod, rt as parseSource, s as writeProjectPreferences, st as FileNotFoundError, t as checkLatestVersion, tt as getAllAIToolAdapters, u as detectInstalledIdes, ut as getAIToolPath, v as saveGlobalConfig, w as mergeAgentsWithWarnings, x as require_lib, y as setGlobalAiTools, z as removePlacedFiles } from "./src-B-Z49jsg.mjs";
4
4
  import { n as detectInstalledAITools, t as clearAIToolCache } from "./ai-tool-detection-DMnwwNBI.mjs";
5
5
  import { access, mkdir, readFile, readdir, rm, stat, writeFile } from "node:fs/promises";
6
6
  import { dirname, isAbsolute, join, relative, resolve } from "node:path";
7
7
  import { fileURLToPath } from "node:url";
8
+ import { execFile } from "node:child_process";
8
9
 
9
10
  //#region src/commands/ai-tools/configure.ts
10
11
  const aiToolsConfigureCommand = defineCommand({
@@ -3042,9 +3043,121 @@ const profileCommand = defineCommand({
3042
3043
  description: "Manage profiles (create, list, remove)"
3043
3044
  },
3044
3045
  subCommands: {
3045
- create: () => import("./create-Cx1nCS3X.mjs").then((m) => m.createCommand),
3046
- list: () => import("./list-BsAASsXi.mjs").then((m) => m.profileListCommand),
3047
- remove: () => import("./remove-36qv7yQ3.mjs").then((m) => m.profileRemoveCommand)
3046
+ create: () => import("./create-Cq7dvT9C.mjs").then((m) => m.createCommand),
3047
+ list: () => import("./list-xZTyCWwl.mjs").then((m) => m.profileListCommand),
3048
+ remove: () => import("./remove-DSBMNbtP.mjs").then((m) => m.profileRemoveCommand)
3049
+ }
3050
+ });
3051
+
3052
+ //#endregion
3053
+ //#region src/commands/self-update.ts
3054
+ const __dirname$2 = dirname(fileURLToPath(import.meta.url));
3055
+ async function readCurrentVersion() {
3056
+ try {
3057
+ const pkg = JSON.parse(await readFile(join(__dirname$2, "../package.json"), "utf-8"));
3058
+ return typeof pkg.version === "string" ? pkg.version : "0.0.0";
3059
+ } catch {
3060
+ return "0.0.0";
3061
+ }
3062
+ }
3063
+ const selfUpdateCommand = defineCommand({
3064
+ meta: {
3065
+ name: "self-update",
3066
+ description: "Update Baton to the latest stable version"
3067
+ },
3068
+ args: {
3069
+ changelog: {
3070
+ type: "boolean",
3071
+ description: "Show release notes for the new version",
3072
+ default: false
3073
+ },
3074
+ "dry-run": {
3075
+ type: "boolean",
3076
+ description: "Check for updates without performing the update",
3077
+ default: false
3078
+ },
3079
+ yes: {
3080
+ type: "boolean",
3081
+ alias: "y",
3082
+ description: "Skip confirmation prompt",
3083
+ default: false
3084
+ }
3085
+ },
3086
+ async run({ args }) {
3087
+ We("baton self-update");
3088
+ const currentVersion = await readCurrentVersion();
3089
+ const s = bt();
3090
+ s.start("Checking for updates...");
3091
+ let latestVersion;
3092
+ try {
3093
+ latestVersion = (await checkLatestVersion()).version;
3094
+ } catch (error) {
3095
+ s.stop("Failed to check for updates");
3096
+ R.error(error instanceof Error ? error.message : "Unknown error occurred");
3097
+ Le("Update check failed.");
3098
+ process.exit(1);
3099
+ }
3100
+ s.stop("Version check complete");
3101
+ const { updateAvailable } = isUpdateAvailable(currentVersion, latestVersion);
3102
+ if (!updateAvailable) {
3103
+ R.success(`Already up to date (v${currentVersion}).`);
3104
+ Le("No update needed.");
3105
+ return;
3106
+ }
3107
+ const installMethod = await detectInstallMethod();
3108
+ const displayCommand = formatInstallCommand(installMethod);
3109
+ R.info([
3110
+ `Current version: v${currentVersion}`,
3111
+ `Latest version: v${latestVersion}`,
3112
+ installMethod.type !== "unknown" ? `Install method: ${installMethod.type}` : ""
3113
+ ].filter(Boolean).join("\n"));
3114
+ if (installMethod.type === "unknown") {
3115
+ R.warn("Could not detect installation method.");
3116
+ R.message([
3117
+ "Please update manually using one of:",
3118
+ " npm update -g @baton-dx/cli",
3119
+ " pnpm update -g @baton-dx/cli",
3120
+ " bun update -g @baton-dx/cli",
3121
+ " brew upgrade baton-dx"
3122
+ ].join("\n"));
3123
+ Le("Manual update required.");
3124
+ return;
3125
+ }
3126
+ if (args["dry-run"]) {
3127
+ R.info(`Would run: ${displayCommand}`);
3128
+ Le("Dry run complete.");
3129
+ return;
3130
+ }
3131
+ if (args.changelog) {
3132
+ const changelogUrl = `https://github.com/baton-dx/baton/releases/tag/v${latestVersion}`;
3133
+ R.info(`Release notes: ${changelogUrl}`);
3134
+ }
3135
+ if (!args.yes) {
3136
+ const confirmed = await Re({ message: `Update to v${latestVersion}?` });
3137
+ if (Ct(confirmed) || !confirmed) {
3138
+ Le("Update cancelled.");
3139
+ return;
3140
+ }
3141
+ }
3142
+ const updateSpinner = bt();
3143
+ updateSpinner.start(`Running: ${displayCommand}`);
3144
+ try {
3145
+ await new Promise((resolve, reject) => {
3146
+ execFile(installMethod.bin, installMethod.args, (error) => {
3147
+ if (error) reject(error);
3148
+ else resolve();
3149
+ });
3150
+ });
3151
+ updateSpinner.stop(`Successfully updated to v${latestVersion}`);
3152
+ Le("Update complete!");
3153
+ } catch (error) {
3154
+ updateSpinner.stop("Update failed");
3155
+ const message = error instanceof Error ? error.message : "Unknown error";
3156
+ R.error(`Failed to run: ${displayCommand}`);
3157
+ R.error(message);
3158
+ Le("Update failed. Please try updating manually.");
3159
+ process.exit(1);
3160
+ }
3048
3161
  }
3049
3162
  });
3050
3163
 
@@ -3097,7 +3210,10 @@ const connectCommand = defineCommand({
3097
3210
  });
3098
3211
  const displayName = args.name || url;
3099
3212
  R.success(`Connected source: ${displayName}`);
3100
- const shouldSync = await Re({ message: "Would you like to sync profiles from this source now?" });
3213
+ const shouldSync = await Re({
3214
+ message: "Would you like to sync profiles from this source now?",
3215
+ initialValue: false
3216
+ });
3101
3217
  if (Ct(shouldSync) || !shouldSync) {
3102
3218
  Le("Source connected. Run 'baton init' to set up profiles.");
3103
3219
  return;
@@ -4212,7 +4328,8 @@ runMain(defineCommand({
4212
4328
  source: sourceCommand,
4213
4329
  profile: profileCommand,
4214
4330
  "ai-tools": aiToolsCommand,
4215
- ides: idesCommand
4331
+ ides: idesCommand,
4332
+ "self-update": selfUpdateCommand
4216
4333
  },
4217
4334
  run({ args }) {
4218
4335
  if (Object.keys(args).length === 0) {
@@ -4238,6 +4355,9 @@ runMain(defineCommand({
4238
4355
  console.log(" ai-tools Manage AI tool detection and configuration");
4239
4356
  console.log(" ides Manage IDE platform detection and configuration");
4240
4357
  console.log("");
4358
+ console.log("Maintenance:");
4359
+ console.log(" self-update Update Baton to the latest stable version");
4360
+ console.log("");
4241
4361
  console.log("Global Options:");
4242
4362
  console.log(" --help, -h Show this help message");
4243
4363
  console.log(" --version, -v Show version number");