@baton-dx/cli 0.2.0 → 0.3.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.
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { c as Ve, h as defineCommand, i as Le, l as We, n as isInSourceRepo } from "./context-detection-DqOTnD6_.mjs";
3
- import { D as discoverProfilesInSourceRepo } from "./src-DBbk6iAs.mjs";
3
+ import { A as discoverProfilesInSourceRepo } from "./src-BgiJfm14.mjs";
4
4
  import "./agent-detection-DTiVeO5W.mjs";
5
5
  import "./esm-BagM-kVd.mjs";
6
6
 
@@ -53,4 +53,4 @@ Note: Must be run from a source repository (directory with baton.source.yaml)`
53
53
 
54
54
  //#endregion
55
55
  export { profileListCommand };
56
- //# sourceMappingURL=list-CGmYHSHW.mjs.map
56
+ //# sourceMappingURL=list-CCzjta6J.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"list-CGmYHSHW.mjs","names":[],"sources":["../src/commands/profile/list.ts"],"sourcesContent":["import { discoverProfilesInSourceRepo } from \"@baton-dx/core\";\nimport * as p from \"@clack/prompts\";\nimport { defineCommand } from \"citty\";\nimport { isInSourceRepo } from \"../../utils/context-detection.js\";\n\nexport const profileListCommand = defineCommand({\n meta: {\n name: \"profile list\",\n description: `List all profiles in the current source repository\n\nShows a table of all profiles with:\n - Profile name (root profile marked with \"(root)\")\n - Version from baton.profile.yaml\n - Description from profile manifest\n\nExamples:\n baton profile list\n\nNote: Must be run from a source repository (directory with baton.source.yaml)`,\n },\n run: async () => {\n p.intro(\"List Profiles\");\n\n // Check if we're in a source repo\n const inSourceRepo = await isInSourceRepo();\n if (!inSourceRepo) {\n p.outro(\n \"Error: Not in a source repository. Run this command from a directory containing baton.source.yaml\",\n );\n process.exit(1);\n }\n\n const cwd = process.cwd();\n\n // Discover all profiles in the profiles/ directory\n const profiles = await discoverProfilesInSourceRepo(cwd);\n\n if (profiles.length === 0) {\n p.outro(\"No profiles found.\");\n process.exit(0);\n }\n\n // Build table output\n const lines: string[] = [];\n lines.push(\"┌─────────────────────┬─────────┬────────────────────────────────────┐\");\n lines.push(\"│ Name │ Version │ Description │\");\n lines.push(\"├─────────────────────┼─────────┼────────────────────────────────────┤\");\n\n for (const profile of profiles) {\n const name = profile.name;\n const version = profile.version || \"-\";\n const description = profile.description || \"-\";\n\n // Pad columns to fixed width\n const namePadded = name.padEnd(19);\n const versionPadded = version.padEnd(7);\n const descPadded = description.padEnd(34);\n\n lines.push(`│ ${namePadded} │ ${versionPadded} │ ${descPadded} │`);\n }\n\n lines.push(\"└─────────────────────┴─────────┴────────────────────────────────────┘\");\n\n p.note(lines.join(\"\\n\"), \"Profiles\");\n p.outro(`Found ${profiles.length} profile${profiles.length === 1 ? \"\" : \"s\"}`);\n process.exit(0);\n },\n});\n"],"mappings":";;;;;;;AAKA,MAAa,qBAAqB,cAAc;CAC9C,MAAM;EACJ,MAAM;EACN,aAAa;;;;;;;;;;;EAWd;CACD,KAAK,YAAY;AACf,KAAQ,gBAAgB;AAIxB,MAAI,CADiB,MAAM,gBAAgB,EACxB;AACjB,MACE,oGACD;AACD,WAAQ,KAAK,EAAE;;EAMjB,MAAM,WAAW,MAAM,6BAHX,QAAQ,KAAK,CAG+B;AAExD,MAAI,SAAS,WAAW,GAAG;AACzB,MAAQ,qBAAqB;AAC7B,WAAQ,KAAK,EAAE;;EAIjB,MAAM,QAAkB,EAAE;AAC1B,QAAM,KAAK,yEAAyE;AACpF,QAAM,KAAK,yEAAyE;AACpF,QAAM,KAAK,yEAAyE;AAEpF,OAAK,MAAM,WAAW,UAAU;GAC9B,MAAM,OAAO,QAAQ;GACrB,MAAM,UAAU,QAAQ,WAAW;GACnC,MAAM,cAAc,QAAQ,eAAe;GAG3C,MAAM,aAAa,KAAK,OAAO,GAAG;GAClC,MAAM,gBAAgB,QAAQ,OAAO,EAAE;GACvC,MAAM,aAAa,YAAY,OAAO,GAAG;AAEzC,SAAM,KAAK,KAAK,WAAW,KAAK,cAAc,KAAK,WAAW,IAAI;;AAGpE,QAAM,KAAK,yEAAyE;AAEpF,KAAO,MAAM,KAAK,KAAK,EAAE,WAAW;AACpC,KAAQ,SAAS,SAAS,OAAO,UAAU,SAAS,WAAW,IAAI,KAAK,MAAM;AAC9E,UAAQ,KAAK,EAAE;;CAElB,CAAC"}
1
+ {"version":3,"file":"list-CCzjta6J.mjs","names":[],"sources":["../src/commands/profile/list.ts"],"sourcesContent":["import { discoverProfilesInSourceRepo } from \"@baton-dx/core\";\nimport * as p from \"@clack/prompts\";\nimport { defineCommand } from \"citty\";\nimport { isInSourceRepo } from \"../../utils/context-detection.js\";\n\nexport const profileListCommand = defineCommand({\n meta: {\n name: \"profile list\",\n description: `List all profiles in the current source repository\n\nShows a table of all profiles with:\n - Profile name (root profile marked with \"(root)\")\n - Version from baton.profile.yaml\n - Description from profile manifest\n\nExamples:\n baton profile list\n\nNote: Must be run from a source repository (directory with baton.source.yaml)`,\n },\n run: async () => {\n p.intro(\"List Profiles\");\n\n // Check if we're in a source repo\n const inSourceRepo = await isInSourceRepo();\n if (!inSourceRepo) {\n p.outro(\n \"Error: Not in a source repository. Run this command from a directory containing baton.source.yaml\",\n );\n process.exit(1);\n }\n\n const cwd = process.cwd();\n\n // Discover all profiles in the profiles/ directory\n const profiles = await discoverProfilesInSourceRepo(cwd);\n\n if (profiles.length === 0) {\n p.outro(\"No profiles found.\");\n process.exit(0);\n }\n\n // Build table output\n const lines: string[] = [];\n lines.push(\"┌─────────────────────┬─────────┬────────────────────────────────────┐\");\n lines.push(\"│ Name │ Version │ Description │\");\n lines.push(\"├─────────────────────┼─────────┼────────────────────────────────────┤\");\n\n for (const profile of profiles) {\n const name = profile.name;\n const version = profile.version || \"-\";\n const description = profile.description || \"-\";\n\n // Pad columns to fixed width\n const namePadded = name.padEnd(19);\n const versionPadded = version.padEnd(7);\n const descPadded = description.padEnd(34);\n\n lines.push(`│ ${namePadded} │ ${versionPadded} │ ${descPadded} │`);\n }\n\n lines.push(\"└─────────────────────┴─────────┴────────────────────────────────────┘\");\n\n p.note(lines.join(\"\\n\"), \"Profiles\");\n p.outro(`Found ${profiles.length} profile${profiles.length === 1 ? \"\" : \"s\"}`);\n process.exit(0);\n },\n});\n"],"mappings":";;;;;;;AAKA,MAAa,qBAAqB,cAAc;CAC9C,MAAM;EACJ,MAAM;EACN,aAAa;;;;;;;;;;;EAWd;CACD,KAAK,YAAY;AACf,KAAQ,gBAAgB;AAIxB,MAAI,CADiB,MAAM,gBAAgB,EACxB;AACjB,MACE,oGACD;AACD,WAAQ,KAAK,EAAE;;EAMjB,MAAM,WAAW,MAAM,6BAHX,QAAQ,KAAK,CAG+B;AAExD,MAAI,SAAS,WAAW,GAAG;AACzB,MAAQ,qBAAqB;AAC7B,WAAQ,KAAK,EAAE;;EAIjB,MAAM,QAAkB,EAAE;AAC1B,QAAM,KAAK,yEAAyE;AACpF,QAAM,KAAK,yEAAyE;AACpF,QAAM,KAAK,yEAAyE;AAEpF,OAAK,MAAM,WAAW,UAAU;GAC9B,MAAM,OAAO,QAAQ;GACrB,MAAM,UAAU,QAAQ,WAAW;GACnC,MAAM,cAAc,QAAQ,eAAe;GAG3C,MAAM,aAAa,KAAK,OAAO,GAAG;GAClC,MAAM,gBAAgB,QAAQ,OAAO,EAAE;GACvC,MAAM,aAAa,YAAY,OAAO,GAAG;AAEzC,SAAM,KAAK,KAAK,WAAW,KAAK,cAAc,KAAK,WAAW,IAAI;;AAGpE,QAAM,KAAK,yEAAyE;AAEpF,KAAO,MAAM,KAAK,KAAK,EAAE,WAAW;AACpC,KAAQ,SAAS,SAAS,OAAO,UAAU,SAAS,WAAW,IAAI,KAAK,MAAM;AAC9E,UAAQ,KAAK,EAAE;;CAElB,CAAC"}
@@ -4717,6 +4717,21 @@ function addPathPattern(patterns, path) {
4717
4717
  if (lastSlash > 0) patterns.add(path.substring(0, lastSlash + 1));
4718
4718
  else if (path) patterns.add(path);
4719
4719
  }
4720
+ /**
4721
+ * Ensures `.baton/` is listed in the project's .gitignore.
4722
+ *
4723
+ * Uses the same "# Baton cache" format as `baton init`.
4724
+ * Idempotent: no-op if `.baton/` is already present (by any mechanism).
4725
+ */
4726
+ async function ensureBatonDirGitignored(projectRoot) {
4727
+ const gitignorePath = join(projectRoot, ".gitignore");
4728
+ let content = "";
4729
+ try {
4730
+ content = await readFile(gitignorePath, "utf-8");
4731
+ } catch {}
4732
+ if (content.includes(".baton/")) return;
4733
+ await writeFile(gitignorePath, content ? `${content.trimEnd()}\n\n# Baton cache\n.baton/\n` : "# Baton cache\n.baton/\n", "utf-8");
4734
+ }
4720
4735
  const BATON_SECTION_START = "# Baton managed";
4721
4736
  const BATON_SECTION_END = "# End Baton managed";
4722
4737
  /**
@@ -14505,5 +14520,125 @@ function computeDimensionIntersection(developerItems, profileItems) {
14505
14520
  }
14506
14521
 
14507
14522
  //#endregion
14508
- export { readLock as A, getAdaptersForKeys as B, resolveProfileSupport as C, discoverProfilesInSourceRepo as D, placeFile as E, updateGitignore as F, loadProjectManifest as G, parseSource as H, getIdePlatformTargetDir as I, SourceParseError as J, KEBAB_CASE_REGEX as K, getRegisteredIdePlatforms as L, resolveVersion as M, cloneGitSource as N, findSourceManifest as O, collectProfileSupportPatterns as P, idePlatformRegistry as R, mergeContentParts as S, detectLegacyPaths as T, loadLockfile as U, parseFrontmatter as V, loadProfileManifest as W, getAgentPath as X, getAgentConfig as Y, getAllAgentKeys as Z, mergeSkills as _, getDefaultGlobalSource as a, isLockedProfile as b, getGlobalSources as c, setGlobalIdePlatforms as d, require_lib as f, mergeRulesWithWarnings as g, mergeRules as h, addGlobalSource as i, writeLock as j, generateLock as k, removeGlobalSource as l, mergeMemoryWithWarnings as m, clearIdeCache as n, getGlobalAiTools as o, mergeMemory as p, FileNotFoundError as q, detectInstalledIdes as r, getGlobalIdePlatforms as s, computeIntersection as t, setGlobalAiTools as u, mergeSkillsWithWarnings as v, resolveProfileChain as w, sortProfilesByWeight as x, getProfileWeight as y, isKnownIdePlatform as z };
14509
- //# sourceMappingURL=src-DBbk6iAs.mjs.map
14523
+ //#region ../core/src/preferences/preferences-schema.ts
14524
+ /**
14525
+ * Schema for .baton/preferences.yaml - project-level tool and IDE preferences
14526
+ *
14527
+ * Controls which AI tools and IDE platforms Baton configures for this project.
14528
+ * Resolution chain: Detection -> Global Config -> Project Preferences
14529
+ */
14530
+ const projectPreferencesSchema = objectType({
14531
+ version: literalType("1.0"),
14532
+ ai: objectType({
14533
+ useGlobal: booleanType(),
14534
+ tools: arrayType(stringType()).default([])
14535
+ }).default({
14536
+ useGlobal: true,
14537
+ tools: []
14538
+ }),
14539
+ ide: objectType({
14540
+ useGlobal: booleanType(),
14541
+ platforms: arrayType(stringType()).default([])
14542
+ }).default({
14543
+ useGlobal: true,
14544
+ platforms: []
14545
+ })
14546
+ });
14547
+
14548
+ //#endregion
14549
+ //#region ../core/src/preferences/preferences-io.ts
14550
+ /**
14551
+ * Returns the path to the project preferences file.
14552
+ *
14553
+ * @param projectRoot - Absolute path to the project root
14554
+ * @returns Absolute path to .baton/preferences.yaml
14555
+ */
14556
+ function getPreferencesPath(projectRoot) {
14557
+ return join(projectRoot, ".baton", "preferences.yaml");
14558
+ }
14559
+ /**
14560
+ * Reads project preferences from .baton/preferences.yaml
14561
+ *
14562
+ * @param projectRoot - Absolute path to the project root
14563
+ * @returns Parsed ProjectPreferences, or null if the file doesn't exist
14564
+ * @throws {ManifestValidationError} If the file exists but contains invalid data
14565
+ */
14566
+ async function readProjectPreferences(projectRoot) {
14567
+ const prefsPath = getPreferencesPath(projectRoot);
14568
+ try {
14569
+ const parsed = (0, import_dist.parse)(await readFile(prefsPath, "utf-8"));
14570
+ return projectPreferencesSchema.parse(parsed);
14571
+ } catch (error) {
14572
+ if (error.code === "ENOENT") return null;
14573
+ throw new ManifestValidationError(`Invalid project preferences at ${prefsPath}: ${error.message}`, { cause: error });
14574
+ }
14575
+ }
14576
+ /**
14577
+ * Writes project preferences to .baton/preferences.yaml
14578
+ *
14579
+ * Creates the .baton/ directory if it doesn't exist.
14580
+ *
14581
+ * @param projectRoot - Absolute path to the project root
14582
+ * @param prefs - The preferences to write (will be validated)
14583
+ * @throws {ManifestValidationError} If preferences validation fails
14584
+ */
14585
+ async function writeProjectPreferences(projectRoot, prefs) {
14586
+ const validated = projectPreferencesSchema.parse(prefs);
14587
+ const prefsPath = getPreferencesPath(projectRoot);
14588
+ await mkdir(dirname(prefsPath), { recursive: true });
14589
+ await writeFile(prefsPath, (0, import_dist.stringify)(validated), "utf-8");
14590
+ await ensureBatonDirGitignored(projectRoot);
14591
+ }
14592
+
14593
+ //#endregion
14594
+ //#region ../core/src/preferences/preferences-resolver.ts
14595
+ /**
14596
+ * Resolves the effective AI tools and IDE platforms for a project.
14597
+ *
14598
+ * Resolution chain:
14599
+ * 1. If no .baton/preferences.yaml exists → use global config
14600
+ * 2. If useGlobal: true → use global config for that dimension
14601
+ * 3. If useGlobal: false → use project-level preferences
14602
+ *
14603
+ * AI and IDE dimensions are resolved independently, allowing mixed configs
14604
+ * (e.g., AI from project, IDE from global).
14605
+ *
14606
+ * @param projectRoot - Absolute path to the project root
14607
+ * @returns Resolved preferences with source attribution
14608
+ */
14609
+ async function resolvePreferences(projectRoot) {
14610
+ const prefs = await readProjectPreferences(projectRoot);
14611
+ if (!prefs) {
14612
+ const [tools, platforms] = await Promise.all([getGlobalAiTools(), getGlobalIdePlatforms()]);
14613
+ return {
14614
+ ai: {
14615
+ source: "global",
14616
+ tools
14617
+ },
14618
+ ide: {
14619
+ source: "global",
14620
+ platforms
14621
+ }
14622
+ };
14623
+ }
14624
+ return {
14625
+ ai: prefs.ai.useGlobal ? {
14626
+ source: "global",
14627
+ tools: await getGlobalAiTools()
14628
+ } : {
14629
+ source: "project",
14630
+ tools: prefs.ai.tools
14631
+ },
14632
+ ide: prefs.ide.useGlobal ? {
14633
+ source: "global",
14634
+ platforms: await getGlobalIdePlatforms()
14635
+ } : {
14636
+ source: "project",
14637
+ platforms: prefs.ide.platforms
14638
+ }
14639
+ };
14640
+ }
14641
+
14642
+ //#endregion
14643
+ export { getAgentConfig as $, discoverProfilesInSourceRepo as A, getRegisteredIdePlatforms as B, isLockedProfile as C, resolveProfileChain as D, resolveProfileSupport as E, resolveVersion as F, parseFrontmatter as G, isKnownIdePlatform as H, cloneGitSource as I, loadProfileManifest as J, parseSource as K, collectProfileSupportPatterns as L, generateLock as M, readLock as N, detectLegacyPaths as O, writeLock as P, SourceParseError as Q, updateGitignore as R, getProfileWeight as S, mergeContentParts as T, getAdaptersForKeys as U, idePlatformRegistry as V, getAllAdapters as W, KEBAB_CASE_REGEX as X, loadProjectManifest as Y, FileNotFoundError as Z, mergeMemoryWithWarnings as _, clearIdeCache as a, mergeSkills as b, getDefaultGlobalSource as c, getGlobalSources as d, getAgentPath as et, removeGlobalSource as f, mergeMemory as g, require_lib as h, computeIntersection as i, findSourceManifest as j, placeFile as k, getGlobalAiTools as l, setGlobalIdePlatforms as m, readProjectPreferences as n, detectInstalledIdes as o, setGlobalAiTools as p, loadLockfile as q, writeProjectPreferences as r, addGlobalSource as s, resolvePreferences as t, getAllAgentKeys as tt, getGlobalIdePlatforms as u, mergeRules as v, sortProfilesByWeight as w, mergeSkillsWithWarnings as x, mergeRulesWithWarnings as y, getIdePlatformTargetDir as z };
14644
+ //# sourceMappingURL=src-BgiJfm14.mjs.map