@baton-dx/cli 0.7.1 → 0.8.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,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import { i as __toESM } from "./dist-BoZnMvNi.mjs";
3
- import { a as Ne, i as Le, l as We, m as defineCommand, p as Ct, t as findSourceRoot, u as Ze } from "./context-detection-DO0ZeRyQ.mjs";
4
- import { Lt as KEBAB_CASE_REGEX, T as require_lib } from "./src-C0c228gb.mjs";
3
+ import { a as Ne, i as Le, l as We, m as defineCommand, p as Ct, t as findSourceRoot, u as Ze } from "./context-detection-BxY5Qs8X.mjs";
4
+ import { E as require_lib, Rt as KEBAB_CASE_REGEX } from "./src-qYK6F_wF.mjs";
5
5
  import "./ai-tool-detection-CMsBNa9e.mjs";
6
6
  import { mkdir, readFile, readdir, writeFile } from "node:fs/promises";
7
7
  import { dirname, join } from "node:path";
@@ -78,4 +78,4 @@ async function copyProfileTemplate(sourceDir, targetDir, variables) {
78
78
 
79
79
  //#endregion
80
80
  export { createCommand };
81
- //# sourceMappingURL=create-BiE2_2Fo.mjs.map
81
+ //# sourceMappingURL=create-DFhPMuBR.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"create-BiE2_2Fo.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-DFhPMuBR.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,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
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";
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-BxY5Qs8X.mjs";
4
+ import { $ as resolveVersion, A as mergeRules, At as parseSource, B as resolveProfileChain, C as saveGlobalConfig, D as mergeMemory, E as require_lib, F as getProfileWeight, Gt as SourceParseError, H as placeFile, Ht as FileNotFoundError, I as isLockedProfile, J as writeState, Jt as getAIToolPath, L as sortProfilesByWeight, M as mergeSkills, Mt as loadProjectManifest, N as mergeSkillsWithWarnings, O as mergeMemoryWithWarnings, Q as writeLock, R as mergeContentParts, Rt as KEBAB_CASE_REGEX, S as removeGlobalSource, T as setGlobalIdePlatforms, U as discoverProfilesInSourceRepo, V as detectLegacyPaths, W as findSourceManifest, X as generateLock, Y as removePlacedFiles, Yt as getAllAIToolKeys, Z as readLock, _ as getGlobalAiTools, a as formatInstallCommand, at as removeGitignoreManagedSection, b as getGlobalSources, c as readProjectPreferences, ct as getRegisteredIdePlatforms, d as computeIntersection, et as cloneGitSource, f as clearIdeCache, ft as getAIToolAdaptersForKeys, g as getDefaultGlobalSource, i as detectInstallMethod, it as ensureBatonDirGitignored, j as mergeRulesWithWarnings, jt as loadProfileManifest, k as mergeAgentsWithWarnings, kt as parseFrontmatter, l as writeProjectPreferences, lt as idePlatformRegistry, m as addGlobalSource, n as checkLatestVersion, nt as esm_default, o as resolvePreferences, ot as updateGitignore, p as detectInstalledIdes, pt as getAllAIToolAdapters, q as readState, qt as getAIToolConfig, r as isUpdateAvailable, rt as collectComprehensivePatterns, st as getIdePlatformTargetDir, t as validateSource, ut as isKnownIdePlatform, w as setGlobalAiTools, x as loadGlobalConfig, y as getGlobalIdePlatforms, z as resolveProfileSupport } from "./src-qYK6F_wF.mjs";
5
5
  import { n as detectInstalledAITools, t as clearAIToolCache } from "./ai-tool-detection-CMsBNa9e.mjs";
6
6
  import { access, mkdir, readFile, readdir, rm, stat, writeFile } from "node:fs/promises";
7
7
  import { dirname, isAbsolute, join, relative, resolve } from "node:path";
@@ -632,7 +632,7 @@ async function loadPreviousPlacedPaths(projectRoot) {
632
632
  const state = await readState(projectRoot);
633
633
  if (state) return new Set(state.placed_files);
634
634
  try {
635
- const { readLock } = await import("./src-C-rwSQpx.mjs");
635
+ const { readLock } = await import("./src-Cjti8F9a.mjs");
636
636
  const previousLock = await readLock(resolve(projectRoot, "baton.lock"));
637
637
  const paths = /* @__PURE__ */ new Set();
638
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);
@@ -3087,9 +3087,9 @@ const profileCommand = defineCommand({
3087
3087
  description: "Manage profiles (create, list, remove)"
3088
3088
  },
3089
3089
  subCommands: {
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)
3090
+ create: () => import("./create-DFhPMuBR.mjs").then((m) => m.createCommand),
3091
+ list: () => import("./list-TKfJJ1i-.mjs").then((m) => m.profileListCommand),
3092
+ remove: () => import("./remove-Lb4YUPYV.mjs").then((m) => m.profileRemoveCommand)
3093
3093
  }
3094
3094
  });
3095
3095
 
@@ -3607,18 +3607,55 @@ function truncate(str, maxLength) {
3607
3607
  return `${str.slice(0, maxLength - 3)}...`;
3608
3608
  }
3609
3609
 
3610
+ //#endregion
3611
+ //#region src/commands/source/validate.ts
3612
+ const validateCommand = defineCommand({
3613
+ meta: {
3614
+ name: "validate",
3615
+ description: "Validate a source repository structure and manifests"
3616
+ },
3617
+ args: { path: {
3618
+ type: "positional",
3619
+ description: "Path to source repository (defaults to current directory)",
3620
+ required: false
3621
+ } },
3622
+ async run({ args }) {
3623
+ const sourceRoot = resolve(args.path ? String(args.path) : process.cwd());
3624
+ We("Validating source repository");
3625
+ const spinner = bt();
3626
+ spinner.start("Running validation checks...");
3627
+ const report = await validateSource(sourceRoot);
3628
+ spinner.stop("Validation complete");
3629
+ for (const issue of report.issues) if (issue.severity === "error") R.error(issue.message);
3630
+ else R.warn(issue.message);
3631
+ const summaryLines = [
3632
+ `Errors: ${report.summary.errors}`,
3633
+ `Warnings: ${report.summary.warnings}`,
3634
+ `Profiles checked: ${report.summary.profilesChecked}`
3635
+ ];
3636
+ Ve(summaryLines.join("\n"), "Result");
3637
+ if (report.valid && report.summary.warnings === 0) Le("Source is valid");
3638
+ else if (report.valid) Le("Source is valid (with warnings)");
3639
+ else {
3640
+ Le("Source has errors");
3641
+ process.exit(1);
3642
+ }
3643
+ }
3644
+ });
3645
+
3610
3646
  //#endregion
3611
3647
  //#region src/commands/source/index.ts
3612
3648
  const sourceCommand = defineCommand({
3613
3649
  meta: {
3614
3650
  name: "source",
3615
- description: "Manage source repositories (create, list, connect, disconnect)"
3651
+ description: "Manage source repositories (create, list, connect, disconnect, validate)"
3616
3652
  },
3617
3653
  subCommands: {
3618
3654
  create: sourceCreateCommand,
3619
3655
  list: listCommand,
3620
3656
  connect: connectCommand,
3621
- disconnect: disconnectCommand
3657
+ disconnect: disconnectCommand,
3658
+ validate: validateCommand
3622
3659
  }
3623
3660
  });
3624
3661