@baton-dx/cli 0.4.2 → 0.4.3
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/{create-W7AYGROv.mjs → create-C1zm03eE.mjs} +2 -2
- package/dist/{create-W7AYGROv.mjs.map → create-C1zm03eE.mjs.map} +1 -1
- package/dist/index.mjs +90 -8
- package/dist/index.mjs.map +1 -1
- package/dist/{list-D5O_m1e5.mjs → list-BHFeSiTO.mjs} +2 -2
- package/dist/{list-D5O_m1e5.mjs.map → list-BHFeSiTO.mjs.map} +1 -1
- package/dist/{src-BPYdPWlV.mjs → src-YrWWPWNR.mjs} +114 -24
- package/dist/src-YrWWPWNR.mjs.map +1 -0
- package/package.json +1 -1
- package/dist/src-BPYdPWlV.mjs.map +0 -1
- package/dist/templates/profile/minimal/ai/memory/CLAUDE.md +0 -3
- package/dist/templates/profile/team/ai/memory/CLAUDE.md +0 -9
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { r as __toESM } from "./chunk-BbwQpWto.mjs";
|
|
3
3
|
import { a as Ne, h as defineCommand, i as Le, l as We, p as Ct, t as findSourceRoot, u as Ze } from "./context-detection-DdbrKid3.mjs";
|
|
4
|
-
import {
|
|
4
|
+
import { _ as require_lib, nt as KEBAB_CASE_REGEX } from "./src-YrWWPWNR.mjs";
|
|
5
5
|
import "./ai-tool-detection-CMsBNa9e.mjs";
|
|
6
6
|
import "./esm-BagM-kVd.mjs";
|
|
7
7
|
import { mkdir, readFile, readdir, writeFile } from "node:fs/promises";
|
|
@@ -79,4 +79,4 @@ async function copyProfileTemplate(sourceDir, targetDir, variables) {
|
|
|
79
79
|
|
|
80
80
|
//#endregion
|
|
81
81
|
export { createCommand };
|
|
82
|
-
//# sourceMappingURL=create-
|
|
82
|
+
//# sourceMappingURL=create-C1zm03eE.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-
|
|
1
|
+
{"version":3,"file":"create-C1zm03eE.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 { r as __toESM } from "./chunk-BbwQpWto.mjs";
|
|
3
3
|
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 } from "./context-detection-DdbrKid3.mjs";
|
|
4
|
-
import { $ as
|
|
4
|
+
import { $ as loadLockfile, A as resolveProfileChain, B as cloneGitSource, C as mergeSkills, D as sortProfilesByWeight, E as isLockedProfile, F as removePlacedFiles, G as getIdePlatformTargetDir, H as ensureBatonDirGitignored, I as generateLock, J as isKnownIdePlatform, K as getRegisteredIdePlatforms, L as readLock, M as placeFile, N as discoverProfilesInSourceRepo, O as mergeContentParts, P as findSourceManifest, Q as parseSource, R as writeLock, S as mergeRulesWithWarnings, T as getProfileWeight, U as removeGitignoreManagedSection, V as collectComprehensivePatterns, W as updateGitignore, X as getAllAIToolAdapters, Y as getAIToolAdaptersForKeys, Z as parseFrontmatter, _ 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 idePlatformRegistry, 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-YrWWPWNR.mjs";
|
|
5
5
|
import { n as detectInstalledAITools, t as clearAIToolCache } from "./ai-tool-detection-CMsBNa9e.mjs";
|
|
6
6
|
import { d as esm_default } from "./esm-BagM-kVd.mjs";
|
|
7
7
|
import { access, mkdir, readFile, readdir, rm, stat, writeFile } from "node:fs/promises";
|
|
@@ -418,7 +418,70 @@ function formatIntersectionSummary(intersection) {
|
|
|
418
418
|
}
|
|
419
419
|
|
|
420
420
|
//#endregion
|
|
421
|
-
//#region src/commands/config.ts
|
|
421
|
+
//#region src/commands/config/set.ts
|
|
422
|
+
/**
|
|
423
|
+
* Set a value in the global Baton config (~/.baton/config.yaml).
|
|
424
|
+
*
|
|
425
|
+
* Supports dotted paths like "sync.cacheTtlHours" to set nested values.
|
|
426
|
+
* Usage: baton config set <key> <value>
|
|
427
|
+
*/
|
|
428
|
+
const configSetCommand = defineCommand({
|
|
429
|
+
meta: {
|
|
430
|
+
name: "set",
|
|
431
|
+
description: "Set a global config value (e.g., baton config set sync.cacheTtlHours 1)"
|
|
432
|
+
},
|
|
433
|
+
args: {
|
|
434
|
+
key: {
|
|
435
|
+
type: "positional",
|
|
436
|
+
description: "Config key using dot notation (e.g., sync.cacheTtlHours)",
|
|
437
|
+
required: true
|
|
438
|
+
},
|
|
439
|
+
value: {
|
|
440
|
+
type: "positional",
|
|
441
|
+
description: "Value to set",
|
|
442
|
+
required: true
|
|
443
|
+
}
|
|
444
|
+
},
|
|
445
|
+
async run({ args }) {
|
|
446
|
+
const { key, value } = args;
|
|
447
|
+
const segments = key.split(".");
|
|
448
|
+
if (segments.length === 0 || segments.some((s) => s === "")) {
|
|
449
|
+
Ne(`Invalid config key: "${key}"`);
|
|
450
|
+
process.exit(1);
|
|
451
|
+
}
|
|
452
|
+
const config = await loadGlobalConfig();
|
|
453
|
+
const parsed = parseValue(value);
|
|
454
|
+
setNestedValue(config, segments, parsed);
|
|
455
|
+
try {
|
|
456
|
+
await saveGlobalConfig(config);
|
|
457
|
+
} catch (error) {
|
|
458
|
+
Ne(`Invalid config value: ${error instanceof Error ? error.message : String(error)}`);
|
|
459
|
+
process.exit(1);
|
|
460
|
+
}
|
|
461
|
+
R.success(`Set ${key} = ${JSON.stringify(parsed)}`);
|
|
462
|
+
}
|
|
463
|
+
});
|
|
464
|
+
/** Parse a string value into a number, boolean, or string. */
|
|
465
|
+
function parseValue(raw) {
|
|
466
|
+
if (raw === "true") return true;
|
|
467
|
+
if (raw === "false") return false;
|
|
468
|
+
const num = Number(raw);
|
|
469
|
+
if (!Number.isNaN(num) && raw.trim() !== "") return num;
|
|
470
|
+
return raw;
|
|
471
|
+
}
|
|
472
|
+
/** Set a value at a dotted path on an object, creating intermediate objects as needed. */
|
|
473
|
+
function setNestedValue(obj, segments, value) {
|
|
474
|
+
let current = obj;
|
|
475
|
+
for (let i = 0; i < segments.length - 1; i++) {
|
|
476
|
+
const seg = segments[i];
|
|
477
|
+
if (current[seg] === void 0 || current[seg] === null) current[seg] = {};
|
|
478
|
+
current = current[seg];
|
|
479
|
+
}
|
|
480
|
+
current[segments[segments.length - 1]] = value;
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
//#endregion
|
|
484
|
+
//#region src/commands/config/index.ts
|
|
422
485
|
async function showDashboard() {
|
|
423
486
|
We("Baton Dashboard");
|
|
424
487
|
const [sources, aiTools, idePlatforms, projectManifest] = await Promise.all([
|
|
@@ -511,8 +574,9 @@ async function loadProjectManifestSafe$1() {
|
|
|
511
574
|
const configCommand = defineCommand({
|
|
512
575
|
meta: {
|
|
513
576
|
name: "config",
|
|
514
|
-
description: "Show Baton dashboard overview"
|
|
577
|
+
description: "Show Baton dashboard overview or configure settings"
|
|
515
578
|
},
|
|
579
|
+
subCommands: { set: configSetCommand },
|
|
516
580
|
async run() {
|
|
517
581
|
await showDashboard();
|
|
518
582
|
}
|
|
@@ -2168,8 +2232,8 @@ const profileCommand = defineCommand({
|
|
|
2168
2232
|
description: "Manage profiles (create, list, remove)"
|
|
2169
2233
|
},
|
|
2170
2234
|
subCommands: {
|
|
2171
|
-
create: () => import("./create-
|
|
2172
|
-
list: () => import("./list-
|
|
2235
|
+
create: () => import("./create-C1zm03eE.mjs").then((m) => m.createCommand),
|
|
2236
|
+
list: () => import("./list-BHFeSiTO.mjs").then((m) => m.profileListCommand),
|
|
2173
2237
|
remove: () => import("./remove-iaf_gkie.mjs").then((m) => m.profileRemoveCommand)
|
|
2174
2238
|
}
|
|
2175
2239
|
});
|
|
@@ -2728,6 +2792,11 @@ const syncCommand = defineCommand({
|
|
|
2728
2792
|
alias: "v",
|
|
2729
2793
|
description: "Show detailed output for each placed file",
|
|
2730
2794
|
default: false
|
|
2795
|
+
},
|
|
2796
|
+
fresh: {
|
|
2797
|
+
type: "boolean",
|
|
2798
|
+
description: "Force an immediate source refresh (ignore cache TTL)",
|
|
2799
|
+
default: false
|
|
2731
2800
|
}
|
|
2732
2801
|
},
|
|
2733
2802
|
async run({ args }) {
|
|
@@ -2735,6 +2804,7 @@ const syncCommand = defineCommand({
|
|
|
2735
2804
|
const categoryArg = args.category;
|
|
2736
2805
|
const autoYes = args.yes;
|
|
2737
2806
|
const verbose = args.verbose;
|
|
2807
|
+
const fresh = args.fresh;
|
|
2738
2808
|
let category;
|
|
2739
2809
|
if (categoryArg) {
|
|
2740
2810
|
if (!validCategories.includes(categoryArg)) {
|
|
@@ -2763,6 +2833,11 @@ const syncCommand = defineCommand({
|
|
|
2763
2833
|
process.exit(1);
|
|
2764
2834
|
}
|
|
2765
2835
|
await promptFirstRunPreferences(projectRoot, !!args.yes);
|
|
2836
|
+
let cacheTtlHours = 24;
|
|
2837
|
+
try {
|
|
2838
|
+
cacheTtlHours = (await loadGlobalConfig()).sync?.cacheTtlHours ?? 24;
|
|
2839
|
+
} catch {}
|
|
2840
|
+
const maxCacheAgeMs = fresh ? 0 : cacheTtlHours * 60 * 60 * 1e3;
|
|
2766
2841
|
const previousPaths = /* @__PURE__ */ new Set();
|
|
2767
2842
|
try {
|
|
2768
2843
|
const previousLock = await readLock(resolve(projectRoot, "baton.lock"));
|
|
@@ -2776,6 +2851,7 @@ const syncCommand = defineCommand({
|
|
|
2776
2851
|
if (verbose) R.info(`Resolving source: ${profileSource.source}`);
|
|
2777
2852
|
const parsed = parseSource(profileSource.source);
|
|
2778
2853
|
let manifestPath;
|
|
2854
|
+
let cloneContext;
|
|
2779
2855
|
if (parsed.provider === "local" || parsed.provider === "file") {
|
|
2780
2856
|
const absolutePath = parsed.path.startsWith("/") ? parsed.path : resolve(projectRoot, parsed.path);
|
|
2781
2857
|
manifestPath = resolve(absolutePath, "baton.profile.yaml");
|
|
@@ -2794,14 +2870,19 @@ const syncCommand = defineCommand({
|
|
|
2794
2870
|
url,
|
|
2795
2871
|
ref: profileSource.version,
|
|
2796
2872
|
subpath: "subpath" in parsed ? parsed.subpath : void 0,
|
|
2797
|
-
useCache: true
|
|
2873
|
+
useCache: true,
|
|
2874
|
+
maxCacheAgeMs
|
|
2798
2875
|
});
|
|
2799
2876
|
manifestPath = resolve(cloned.localPath, "baton.profile.yaml");
|
|
2800
2877
|
sourceShas.set(profileSource.source, cloned.sha);
|
|
2878
|
+
cloneContext = {
|
|
2879
|
+
cachePath: cloned.cachePath,
|
|
2880
|
+
sparseCheckout: cloned.sparseCheckout
|
|
2881
|
+
};
|
|
2801
2882
|
}
|
|
2802
2883
|
const manifest = await loadProfileManifest(manifestPath);
|
|
2803
2884
|
const profileDir = dirname(manifestPath);
|
|
2804
|
-
const chain = await resolveProfileChain(manifest, profileSource.source, profileDir);
|
|
2885
|
+
const chain = await resolveProfileChain(manifest, profileSource.source, profileDir, cloneContext);
|
|
2805
2886
|
allProfiles.push(...chain);
|
|
2806
2887
|
} catch (error) {
|
|
2807
2888
|
spinner.stop(`Failed to resolve profile ${profileSource.source}: ${error}`);
|
|
@@ -3007,7 +3088,8 @@ const syncCommand = defineCommand({
|
|
|
3007
3088
|
url: parsed.provider === "git" ? parsed.url : parsed.url,
|
|
3008
3089
|
ref: profileSource.version,
|
|
3009
3090
|
subpath: "subpath" in parsed ? parsed.subpath : void 0,
|
|
3010
|
-
useCache: true
|
|
3091
|
+
useCache: true,
|
|
3092
|
+
maxCacheAgeMs
|
|
3011
3093
|
});
|
|
3012
3094
|
for (const prof of allProfiles) if (prof.source === profileSource.source) profileLocalPaths.set(prof.name, cloned.localPath);
|
|
3013
3095
|
}
|