@baton-dx/cli 0.1.2 → 0.1.4
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/README.md
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# Baton
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@baton-dx/cli)
|
|
4
|
+
[](https://github.com/baton-dx/baton-dx/actions)
|
|
5
|
+
[](https://opensource.org/licenses/MIT)
|
|
6
|
+
|
|
7
|
+
**Baton is a CLI package manager for Developer Experience & AI configuration.** Manage Skills, Rules, Agents, Memory Files, and file configs as versioned, composable profiles for 14 AI coding tools.
|
|
8
|
+
|
|
9
|
+
## Quick Start
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
# Install
|
|
13
|
+
bun install -g @baton-dx/cli
|
|
14
|
+
|
|
15
|
+
# Connect your team's source repository
|
|
16
|
+
baton source connect github:your-org/dx-configs --name my-team
|
|
17
|
+
|
|
18
|
+
# Initialize in any project
|
|
19
|
+
baton init
|
|
20
|
+
|
|
21
|
+
# Sync all configurations
|
|
22
|
+
baton sync
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Features
|
|
26
|
+
|
|
27
|
+
- **Unified AI Configuration** — One manifest for 14 AI coding tools
|
|
28
|
+
- **Profile Inheritance** — Compose profiles with `extends` for layered configuration
|
|
29
|
+
- **Smart Sync** — Transform and place files in the correct format for each tool
|
|
30
|
+
- **Version Control** — Lockfile-based reproducibility with SHA-256 integrity
|
|
31
|
+
- **Merge Strategies** — replace, deep, append, prepend, skip, prompt, directory, import
|
|
32
|
+
- **Auto-Detection** — Automatically detect installed AI tools and IDEs
|
|
33
|
+
- **Scaffold Templates** — Bootstrap source repositories with `baton source create`
|
|
34
|
+
|
|
35
|
+
## Supported AI Tools
|
|
36
|
+
|
|
37
|
+
| Tool | Key | Tool | Key |
|
|
38
|
+
|------|-----|------|-----|
|
|
39
|
+
| Claude Code | `claude-code` | OpenCode | `opencode` |
|
|
40
|
+
| Cursor | `cursor` | Amp | `amp` |
|
|
41
|
+
| Windsurf | `windsurf` | Kiro | `kiro` |
|
|
42
|
+
| Antigravity | `antigravity` | Zed | `zed` |
|
|
43
|
+
| Codex CLI | `codex` | Cline | `cline` |
|
|
44
|
+
| GitHub Copilot | `github-copilot` | Roo | `roo` |
|
|
45
|
+
| Junie | `junie` | Trae | `trae` |
|
|
46
|
+
|
|
47
|
+
## Documentation
|
|
48
|
+
|
|
49
|
+
- [Installation](docs/01-installation.md) — Prerequisites and install methods
|
|
50
|
+
- [Quick Start Guide](docs/02-quickstart.md) — Get running in 5 minutes
|
|
51
|
+
- [Creating Sources](docs/03-creating-sources.md) — Build source repositories
|
|
52
|
+
- [Creating Profiles](docs/04-creating-profiles.md) — Design profile manifests
|
|
53
|
+
- [Using Profiles](docs/05-using-profiles.md) — Use profiles in your projects
|
|
54
|
+
- [CLI Reference](docs/06-cli-reference.md) — Complete command reference
|
|
55
|
+
- [Configuration Reference](docs/07-configuration-reference.md) — All config file schemas
|
|
56
|
+
- [AI Tools Reference](docs/08-ai-tools-reference.md) — All 14 supported AI tools
|
|
57
|
+
- [IDE Platforms](docs/09-ide-platforms-reference.md) — Supported IDE platforms
|
|
58
|
+
- [Merge Strategies](docs/10-merge-strategies.md) — Deep dive into merge strategies
|
|
59
|
+
|
|
60
|
+
## Contributing
|
|
61
|
+
|
|
62
|
+
See [Contributing Guide](docs/11-contributing.md) for development setup, coding conventions, and PR workflow.
|
|
63
|
+
|
|
64
|
+
## License
|
|
65
|
+
|
|
66
|
+
MIT © 2026 Baton Contributors
|
|
@@ -54,7 +54,7 @@ const createCommand = defineCommand({
|
|
|
54
54
|
process.exit(1);
|
|
55
55
|
} catch {}
|
|
56
56
|
await mkdir(targetDir, { recursive: true });
|
|
57
|
-
await copyProfileTemplate(join(__dirname, "
|
|
57
|
+
await copyProfileTemplate(join(__dirname, "templates", "profile", "minimal"), targetDir, { name });
|
|
58
58
|
Le(`Profile '${name}' created in profiles/${name}/`);
|
|
59
59
|
}
|
|
60
60
|
});
|
|
@@ -78,4 +78,4 @@ async function copyProfileTemplate(sourceDir, targetDir, variables) {
|
|
|
78
78
|
|
|
79
79
|
//#endregion
|
|
80
80
|
export { createCommand };
|
|
81
|
-
//# sourceMappingURL=create-
|
|
81
|
+
//# sourceMappingURL=create-Bo1zwMs0.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-
|
|
1
|
+
{"version":3,"file":"create-Bo1zwMs0.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
|
@@ -1640,7 +1640,7 @@ const profileCommand = defineCommand({
|
|
|
1640
1640
|
description: "Manage profiles (create, list, remove)"
|
|
1641
1641
|
},
|
|
1642
1642
|
subCommands: {
|
|
1643
|
-
create: () => import("./create-
|
|
1643
|
+
create: () => import("./create-Bo1zwMs0.mjs").then((m) => m.createCommand),
|
|
1644
1644
|
list: () => import("./list-B5xUVBTU.mjs").then((m) => m.profileListCommand),
|
|
1645
1645
|
remove: () => import("./remove-6S8F9xcE.mjs").then((m) => m.profileRemoveCommand)
|
|
1646
1646
|
}
|
|
@@ -1891,7 +1891,7 @@ metadata:
|
|
|
1891
1891
|
if (withInitialProfile) {
|
|
1892
1892
|
const profileDir = join(targetDir, "profiles", "default");
|
|
1893
1893
|
await mkdir(profileDir, { recursive: true });
|
|
1894
|
-
await copyDirectory(join(__dirname$1, "
|
|
1894
|
+
await copyDirectory(join(__dirname$1, "templates", "profile", "minimal"), profileDir, { name: "default" });
|
|
1895
1895
|
}
|
|
1896
1896
|
await generateReadme(targetDir, options);
|
|
1897
1897
|
if (git) await initializeGit(targetDir);
|