@baton-dx/cli 0.3.1 → 0.4.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 { n as __require, r as __toESM, t as __commonJSMin } from "./chunk-BbwQpWto.mjs";
3
3
  import { m as require_dist } from "./context-detection-DqOTnD6_.mjs";
4
- import { i as AGENT_PATHS, r as evaluateDetection } from "./agent-detection-DTiVeO5W.mjs";
4
+ import { i as AI_TOOL_PATHS, r as evaluateDetection } from "./ai-tool-detection-CMsBNa9e.mjs";
5
5
  import { d as esm_default, m as simpleGit } from "./esm-BagM-kVd.mjs";
6
6
  import { access, mkdir, readFile, readdir, rm, rmdir, stat, symlink, unlink, writeFile } from "node:fs/promises";
7
7
  import { dirname, isAbsolute, join, relative, resolve } from "node:path";
@@ -10,29 +10,29 @@ import { homedir } from "node:os";
10
10
  import { createHash } from "node:crypto";
11
11
  import { execFile } from "node:child_process";
12
12
 
13
- //#region ../agent-paths/src/types.ts
13
+ //#region ../ai-tool-paths/src/types.ts
14
14
  /**
15
15
  * Error thrown when an agent is not found in the registry
16
16
  */
17
- var AgentNotFoundError = class extends Error {
17
+ var AIToolNotFoundError = class extends Error {
18
18
  constructor(message) {
19
19
  super(message);
20
- this.name = "AgentNotFoundError";
20
+ this.name = "AIToolNotFoundError";
21
21
  }
22
22
  };
23
23
 
24
24
  //#endregion
25
- //#region ../agent-paths/src/helpers.ts
25
+ //#region ../ai-tool-paths/src/helpers.ts
26
26
  /**
27
27
  * Retrieves the full agent configuration for a given agent key.
28
28
  *
29
29
  * @param agentKey - The unique key of the agent (e.g., 'claude-code', 'cursor')
30
- * @returns The full AgentPathConfig for the agent
31
- * @throws AgentNotFoundError if the agent key is not found in the registry
30
+ * @returns The full AIToolPathConfig for the agent
31
+ * @throws AIToolNotFoundError if the agent key is not found in the registry
32
32
  */
33
- function getAgentConfig(agentKey) {
34
- const config = AGENT_PATHS.find((agent) => agent.key === agentKey);
35
- if (!config) throw new AgentNotFoundError(`Agent with key '${agentKey}' not found in registry`);
33
+ function getAIToolConfig(agentKey) {
34
+ const config = AI_TOOL_PATHS.find((agent) => agent.key === agentKey);
35
+ if (!config) throw new AIToolNotFoundError(`Agent with key '${agentKey}' not found in registry`);
36
36
  return config;
37
37
  }
38
38
  /**
@@ -40,8 +40,8 @@ function getAgentConfig(agentKey) {
40
40
  *
41
41
  * @returns Array of all agent keys
42
42
  */
43
- function getAllAgentKeys() {
44
- return AGENT_PATHS.map((agent) => agent.key);
43
+ function getAllAIToolKeys() {
44
+ return AI_TOOL_PATHS.map((agent) => agent.key);
45
45
  }
46
46
  /**
47
47
  * Resolves a path template with tilde expansion and name placeholder replacement.
@@ -60,14 +60,14 @@ function resolvePath(template, name) {
60
60
  * Retrieves the resolved path for a given agent, config type, scope, and optional name.
61
61
  *
62
62
  * @param agentKey - The unique key of the agent
63
- * @param configType - The type of configuration (skills, rules, agents, memory, settings, commands)
63
+ * @param configType - The type of configuration (skills, rules, agents, memory, commands)
64
64
  * @param scope - The scope (project or global)
65
65
  * @param name - Optional name to replace {name} placeholder
66
66
  * @returns Resolved path string
67
- * @throws AgentNotFoundError if the agent key is not found
67
+ * @throws AIToolNotFoundError if the agent key is not found
68
68
  */
69
- function getAgentPath(agentKey, configType, scope, name) {
70
- const pathTemplate = getAgentConfig(agentKey)[configType][scope];
69
+ function getAIToolPath(agentKey, configType, scope, name) {
70
+ const pathTemplate = getAIToolConfig(agentKey)[configType][scope];
71
71
  return resolvePath(pathTemplate, name);
72
72
  }
73
73
 
@@ -114,7 +114,7 @@ var VersionNotFoundError = class extends BatonError {
114
114
  /**
115
115
  * Thrown when an adapter is not found for a given agent key
116
116
  */
117
- var AdapterNotFoundError = class extends BatonError {
117
+ var AIToolAdapterNotFoundError = class extends BatonError {
118
118
  constructor(message, cause) {
119
119
  super("ADAPTER_NOT_FOUND_ERROR", message, cause);
120
120
  }
@@ -3783,6 +3783,10 @@ const skillItemSchema = objectType({
3783
3783
  */
3784
3784
  const rulesSchema = unionType([arrayType(stringType()), recordType(stringType(), arrayType(stringType()).optional())]);
3785
3785
  /**
3786
+ * Agents in profile manifest - can be either an array or an object
3787
+ */
3788
+ const agentsSchema = unionType([arrayType(stringType()), recordType(stringType(), arrayType(stringType()).optional())]);
3789
+ /**
3786
3790
  * Memory file configuration item
3787
3791
  *
3788
3792
  * Convention: Use "MEMORY.md" as source for generic memory that will be
@@ -3799,18 +3803,14 @@ const memoryItemSchema = objectType({
3799
3803
  */
3800
3804
  const memorySectionSchema = arrayType(memoryItemSchema).optional();
3801
3805
  /**
3802
- * Settings configuration mapping agent key to settings filename
3803
- */
3804
- const settingsSchema = recordType(stringType(), stringType());
3805
- /**
3806
3806
  * AI section in profile manifest
3807
3807
  */
3808
3808
  const aiSectionSchema = objectType({
3809
3809
  tools: arrayType(stringType()).optional(),
3810
3810
  skills: arrayType(skillItemSchema).optional(),
3811
3811
  rules: rulesSchema.optional(),
3812
+ agents: agentsSchema.optional(),
3812
3813
  memory: memorySectionSchema.optional(),
3813
- settings: settingsSchema.optional(),
3814
3814
  commands: arrayType(stringType()).optional()
3815
3815
  }).optional();
3816
3816
  /**
@@ -3874,7 +3874,8 @@ const projectManifestSchema = objectType({
3874
3874
  profiles: arrayType(profileSourceSchema),
3875
3875
  extras: extrasSectionSchema,
3876
3876
  overrides: overridesSectionSchema,
3877
- variables: recordType(stringType(), stringType()).optional()
3877
+ variables: recordType(stringType(), stringType()).optional(),
3878
+ gitignore: booleanType().optional()
3878
3879
  });
3879
3880
 
3880
3881
  //#endregion
@@ -4088,11 +4089,11 @@ function parseFrontmatter(raw) {
4088
4089
  //#endregion
4089
4090
  //#region ../core/src/adapters/base-adapter.ts
4090
4091
  /**
4091
- * Base adapter with default implementations for the ToolAdapter interface.
4092
+ * Base adapter with default implementations for the AIToolAdapter interface.
4092
4093
  *
4093
4094
  * Provides:
4094
- * - isInstalled() via detectInstalledAgents()
4095
- * - getPath() via getAgentPath()
4095
+ * - isInstalled() via detectInstalledAITools()
4096
+ * - getPath() via getAIToolPath()
4096
4097
  * - getLegacyPaths() returns []
4097
4098
  * - transform*() passthrough (return input unchanged)
4098
4099
  * - transformMemory() converts MEMORY.md to this.memoryFilename
@@ -4101,19 +4102,19 @@ function parseFrontmatter(raw) {
4101
4102
  * Subclasses only need to define `key` and `name`.
4102
4103
  * Override `memoryFilename` for tools that don't use AGENTS.md.
4103
4104
  */
4104
- var BaseAdapter = class {
4105
+ var BaseAIToolAdapter = class {
4105
4106
  /** Memory filename this tool uses. Override for non-AGENTS.md tools. */
4106
4107
  memoryFilename = "AGENTS.md";
4107
4108
  async isInstalled() {
4108
4109
  try {
4109
- const { detectInstalledAgents } = await import("./agent-detection-l61K-AbU.mjs");
4110
- return (await detectInstalledAgents()).includes(this.key);
4110
+ const { detectInstalledAITools } = await import("./ai-tool-detection-BFep6YS9.mjs");
4111
+ return (await detectInstalledAITools()).includes(this.key);
4111
4112
  } catch {
4112
4113
  return false;
4113
4114
  }
4114
4115
  }
4115
4116
  getPath(type, scope, name) {
4116
- return getAgentPath(this.key, type, scope, name);
4117
+ return getAIToolPath(this.key, type, scope, name);
4117
4118
  }
4118
4119
  getLegacyPaths(_type) {
4119
4120
  return [];
@@ -4147,8 +4148,7 @@ var BaseAdapter = class {
4147
4148
  validateCommon(type, file) {
4148
4149
  const errors = [];
4149
4150
  if (typeof file !== "object" || file === null) {
4150
- if (type === "settings") errors.push("Settings must be a valid JSON object");
4151
- else errors.push(`${type} must be a valid object`);
4151
+ errors.push(`${type} must be a valid object`);
4152
4152
  return {
4153
4153
  valid: false,
4154
4154
  errors
@@ -4176,7 +4176,6 @@ var BaseAdapter = class {
4176
4176
  if (!record.name) errors.push("Command must have a name");
4177
4177
  if (!record.content) errors.push("Command must have content");
4178
4178
  break;
4179
- case "settings": break;
4180
4179
  }
4181
4180
  return {
4182
4181
  valid: errors.length === 0,
@@ -4191,7 +4190,7 @@ var BaseAdapter = class {
4191
4190
  * Amp adapter — uses canonical formats with AGENTS.md for memory.
4192
4191
  * Project paths: .agents/ | Global paths: ~/.config/agents/
4193
4192
  */
4194
- var AmpAdapter = class extends BaseAdapter {
4193
+ var AmpAdapter = class extends BaseAIToolAdapter {
4195
4194
  key = "amp";
4196
4195
  name = "Amp";
4197
4196
  };
@@ -4204,7 +4203,7 @@ var AmpAdapter = class extends BaseAdapter {
4204
4203
  * Uses GEMINI.md for memory. Custom validate() adds memory filename check.
4205
4204
  * Paths: .agent/skills/, .agent/rules/, .agent/agents/, .agent/workflows/
4206
4205
  */
4207
- var AntigravityAdapter = class extends BaseAdapter {
4206
+ var AntigravityAdapter = class extends BaseAIToolAdapter {
4208
4207
  key = "antigravity";
4209
4208
  name = "Antigravity";
4210
4209
  memoryFilename = "GEMINI.md";
@@ -4224,7 +4223,7 @@ var AntigravityAdapter = class extends BaseAdapter {
4224
4223
  //#endregion
4225
4224
  //#region ../core/src/adapters/claude-code.ts
4226
4225
  /**
4227
- * Claude Code adapter — reference implementation for ToolAdapter interface.
4226
+ * Claude Code adapter — reference implementation for AIToolAdapter interface.
4228
4227
  *
4229
4228
  * Uses canonical formats:
4230
4229
  * - Skills: 1:1 copy (SKILL.md with optional scripts/)
@@ -4233,7 +4232,7 @@ var AntigravityAdapter = class extends BaseAdapter {
4233
4232
  * - Memory: CLAUDE.md or .claude/CLAUDE.md
4234
4233
  * - Commands: .claude/commands/{name}.md
4235
4234
  */
4236
- var ClaudeCodeAdapter = class extends BaseAdapter {
4235
+ var ClaudeCodeAdapter = class extends BaseAIToolAdapter {
4237
4236
  key = "claude-code";
4238
4237
  name = "Claude Code";
4239
4238
  memoryFilename = "CLAUDE.md";
@@ -4245,7 +4244,7 @@ var ClaudeCodeAdapter = class extends BaseAdapter {
4245
4244
  * Cline adapter — uses canonical formats with AGENTS.md for memory.
4246
4245
  * Project paths: .cline/ | Global paths: ~/.cline/
4247
4246
  */
4248
- var ClineAdapter = class extends BaseAdapter {
4247
+ var ClineAdapter = class extends BaseAIToolAdapter {
4249
4248
  key = "cline";
4250
4249
  name = "Cline";
4251
4250
  };
@@ -4258,7 +4257,7 @@ var ClineAdapter = class extends BaseAdapter {
4258
4257
  * Uses AGENTS.md for memory. Custom validate() adds memory filename check.
4259
4258
  * Settings use TOML format (config.toml), not JSON.
4260
4259
  */
4261
- var CodexAdapter = class extends BaseAdapter {
4260
+ var CodexAdapter = class extends BaseAIToolAdapter {
4262
4261
  key = "codex";
4263
4262
  name = "Codex CLI";
4264
4263
  validate(type, file) {
@@ -4284,7 +4283,7 @@ var CodexAdapter = class extends BaseAdapter {
4284
4283
  * - transformRule(): converts to .mdc with description, globs, alwaysApply
4285
4284
  * - validate(): adds Cursor-specific rules + memory checks
4286
4285
  */
4287
- var CursorAdapter = class extends BaseAdapter {
4286
+ var CursorAdapter = class extends BaseAIToolAdapter {
4288
4287
  key = "cursor";
4289
4288
  name = "Cursor";
4290
4289
  getLegacyPaths(type) {
@@ -4349,7 +4348,7 @@ var CursorAdapter = class extends BaseAdapter {
4349
4348
  * GitHub Copilot adapter — uses copilot-instructions.md for memory.
4350
4349
  * Memory path: .github/copilot-instructions.md
4351
4350
  */
4352
- var GitHubCopilotAdapter = class extends BaseAdapter {
4351
+ var GitHubCopilotAdapter = class extends BaseAIToolAdapter {
4353
4352
  key = "github-copilot";
4354
4353
  name = "GitHub Copilot";
4355
4354
  memoryFilename = "copilot-instructions.md";
@@ -4361,7 +4360,7 @@ var GitHubCopilotAdapter = class extends BaseAdapter {
4361
4360
  * Junie adapter — uses canonical formats with AGENTS.md for memory.
4362
4361
  * Project paths: .junie/ | Global paths: ~/.junie/
4363
4362
  */
4364
- var JunieAdapter = class extends BaseAdapter {
4363
+ var JunieAdapter = class extends BaseAIToolAdapter {
4365
4364
  key = "junie";
4366
4365
  name = "Junie";
4367
4366
  };
@@ -4372,7 +4371,7 @@ var JunieAdapter = class extends BaseAdapter {
4372
4371
  * Kiro adapter — uses canonical formats with AGENTS.md for memory.
4373
4372
  * Project paths: .kiro/ | Global paths: ~/.kiro/
4374
4373
  */
4375
- var KiroAdapter = class extends BaseAdapter {
4374
+ var KiroAdapter = class extends BaseAIToolAdapter {
4376
4375
  key = "kiro";
4377
4376
  name = "Kiro";
4378
4377
  };
@@ -4383,7 +4382,7 @@ var KiroAdapter = class extends BaseAdapter {
4383
4382
  * OpenCode adapter — uses canonical formats with AGENTS.md for memory.
4384
4383
  * Global paths: ~/.config/opencode/ (XDG Base Directory)
4385
4384
  */
4386
- var OpenCodeAdapter = class extends BaseAdapter {
4385
+ var OpenCodeAdapter = class extends BaseAIToolAdapter {
4387
4386
  key = "opencode";
4388
4387
  name = "OpenCode";
4389
4388
  };
@@ -4394,7 +4393,7 @@ var OpenCodeAdapter = class extends BaseAdapter {
4394
4393
  * Roo adapter — uses canonical formats with AGENTS.md for memory.
4395
4394
  * Project paths: .roo/ | Global paths: ~/.roo/
4396
4395
  */
4397
- var RooAdapter = class extends BaseAdapter {
4396
+ var RooAdapter = class extends BaseAIToolAdapter {
4398
4397
  key = "roo";
4399
4398
  name = "Roo";
4400
4399
  };
@@ -4405,7 +4404,7 @@ var RooAdapter = class extends BaseAdapter {
4405
4404
  * Trae adapter — uses canonical formats with AGENTS.md for memory.
4406
4405
  * Project paths: .trae/ | Global paths: ~/.trae/
4407
4406
  */
4408
- var TraeAdapter = class extends BaseAdapter {
4407
+ var TraeAdapter = class extends BaseAIToolAdapter {
4409
4408
  key = "trae";
4410
4409
  name = "Trae";
4411
4410
  };
@@ -4420,7 +4419,7 @@ var TraeAdapter = class extends BaseAdapter {
4420
4419
  * - transformRule(): removes all YAML frontmatter
4421
4420
  * - validate(): adds Windsurf-specific rules + memory checks
4422
4421
  */
4423
- var WindsurfAdapter = class extends BaseAdapter {
4422
+ var WindsurfAdapter = class extends BaseAIToolAdapter {
4424
4423
  key = "windsurf";
4425
4424
  name = "Windsurf";
4426
4425
  getLegacyPaths(type) {
@@ -4460,7 +4459,7 @@ var WindsurfAdapter = class extends BaseAdapter {
4460
4459
  * Zed adapter — uses canonical formats with AGENTS.md for memory.
4461
4460
  * Project paths: .zed/ | Global paths: ~/.zed/
4462
4461
  */
4463
- var ZedAdapter = class extends BaseAdapter {
4462
+ var ZedAdapter = class extends BaseAIToolAdapter {
4464
4463
  key = "zed";
4465
4464
  name = "Zed";
4466
4465
  };
@@ -4471,12 +4470,12 @@ var ZedAdapter = class extends BaseAdapter {
4471
4470
  * Registry of all tool adapters
4472
4471
  * Singleton instances are created lazily on first access
4473
4472
  */
4474
- const adapterInstances = /* @__PURE__ */ new Map();
4473
+ const aiToolAdapterInstances = /* @__PURE__ */ new Map();
4475
4474
  /**
4476
4475
  * Initialize all adapters
4477
4476
  */
4478
- function initializeAdapters() {
4479
- if (adapterInstances.size > 0) return;
4477
+ function initializeAIToolAdapters() {
4478
+ if (aiToolAdapterInstances.size > 0) return;
4480
4479
  const adapters = [
4481
4480
  new ClaudeCodeAdapter(),
4482
4481
  new CursorAdapter(),
@@ -4493,35 +4492,35 @@ function initializeAdapters() {
4493
4492
  new JunieAdapter(),
4494
4493
  new TraeAdapter()
4495
4494
  ];
4496
- for (const adapter of adapters) adapterInstances.set(adapter.key, adapter);
4495
+ for (const adapter of adapters) aiToolAdapterInstances.set(adapter.key, adapter);
4497
4496
  }
4498
4497
  /**
4499
4498
  * Get adapter instance by tool key
4500
- * @param agentKey - Tool key (e.g., 'claude-code', 'cursor')
4499
+ * @param toolKey - Tool key (e.g., 'claude-code', 'cursor')
4501
4500
  * @returns Adapter instance
4502
- * @throws AdapterNotFoundError if adapter is not registered
4501
+ * @throws AIToolAdapterNotFoundError if adapter is not registered
4503
4502
  */
4504
- function getAdapter(agentKey) {
4505
- initializeAdapters();
4506
- const adapter = adapterInstances.get(agentKey);
4507
- if (!adapter) throw new AdapterNotFoundError(`Adapter not found for tool: ${agentKey}. Available adapters: ${Array.from(adapterInstances.keys()).join(", ")}`);
4503
+ function getAIToolAdapter(toolKey) {
4504
+ initializeAIToolAdapters();
4505
+ const adapter = aiToolAdapterInstances.get(toolKey);
4506
+ if (!adapter) throw new AIToolAdapterNotFoundError(`Adapter not found for tool: ${toolKey}. Available adapters: ${Array.from(aiToolAdapterInstances.keys()).join(", ")}`);
4508
4507
  return adapter;
4509
4508
  }
4510
4509
  /**
4511
4510
  * Get all registered adapters
4512
4511
  * @returns Array of all adapter instances
4513
4512
  */
4514
- function getAllAdapters() {
4515
- initializeAdapters();
4516
- return Array.from(adapterInstances.values());
4513
+ function getAllAIToolAdapters() {
4514
+ initializeAIToolAdapters();
4515
+ return Array.from(aiToolAdapterInstances.values());
4517
4516
  }
4518
4517
  /**
4519
4518
  * Get adapters for the given tool keys
4520
4519
  * @param keys - Array of tool keys
4521
4520
  * @returns Array of adapter instances
4522
4521
  */
4523
- function getAdaptersForKeys(keys) {
4524
- return keys.map((key) => getAdapter(key));
4522
+ function getAIToolAdaptersForKeys(keys) {
4523
+ return keys.map((key) => getAIToolAdapter(key));
4525
4524
  }
4526
4525
 
4527
4526
  //#endregion
@@ -4665,56 +4664,29 @@ function getRegisteredIdePlatforms() {
4665
4664
  //#endregion
4666
4665
  //#region ../core/src/utils/gitignore.ts
4667
4666
  /**
4668
- * Collect gitignore patterns from the profile's declared tool support.
4669
- *
4670
- * Unlike collectSyncedPatterns (which uses the developer's intersection),
4671
- * this function generates patterns for ALL tools the profile supports.
4672
- * This ensures consistent .gitignore across all team members regardless
4673
- * of which tools each developer has installed.
4667
+ * Extract directory from a dynamic path and add it as a pattern.
4668
+ * For static paths (no `_probe` placeholder resolved), adds the file itself.
4674
4669
  *
4675
- * Returns deduplicated, sorted patterns including baton.lock.
4676
- */
4677
- function collectProfileSupportPatterns(options) {
4678
- const patterns = /* @__PURE__ */ new Set();
4679
- const { profileAiTools, profileIdePlatforms, fileTargets, hasContent } = options;
4680
- if (profileAiTools.length > 0 && hasContent) {
4681
- const adapters = getAdaptersForKeys(profileAiTools);
4682
- for (const adapter of adapters) {
4683
- addDirPattern(patterns, adapter.getPath("commands", "project", "_probe"));
4684
- addDirPattern(patterns, adapter.getPath("skills", "project", "_probe"));
4685
- addPathPattern(patterns, adapter.getPath("rules", "project", "_probe"));
4686
- addPathPattern(patterns, adapter.getPath("memory", "project", "_probe"));
4687
- addDirPattern(patterns, adapter.getPath("agents", "project", "_probe"));
4688
- for (const legacyPath of adapter.getLegacyPaths("rules")) patterns.add(legacyPath);
4689
- }
4690
- }
4691
- for (const ideKey of profileIdePlatforms) {
4692
- const targetDir = getIdePlatformTargetDir(ideKey);
4693
- if (targetDir) {
4694
- const dir = targetDir.endsWith("/") ? targetDir : `${targetDir}/`;
4695
- patterns.add(dir);
4696
- }
4697
- }
4698
- for (const target of fileTargets) patterns.add(target);
4699
- patterns.add("baton.lock");
4700
- return [...patterns].sort();
4701
- }
4702
- /**
4703
- * Extract directory from a path and add it as a pattern.
4704
- * E.g. ".claude/commands/_probe.md" -> ".claude/commands/"
4670
+ * E.g. ".claude/commands/_probe.md" -> ".claude/commands/" (dynamic)
4671
+ * E.g. ".github/copilot-instructions.md" -> ".github/copilot-instructions.md" (static)
4705
4672
  */
4706
4673
  function addDirPattern(patterns, path) {
4707
4674
  const lastSlash = path.lastIndexOf("/");
4708
- if (lastSlash > 0) patterns.add(path.substring(0, lastSlash + 1));
4675
+ if (lastSlash > 0) if (path.includes("_probe")) patterns.add(path.substring(0, lastSlash + 1));
4676
+ else patterns.add(path);
4709
4677
  }
4710
4678
  /**
4711
- * Add a path pattern directory if it contains slashes, root file otherwise.
4712
- * E.g. ".claude/rules/_probe.md" -> ".claude/rules/"
4713
- * E.g. "CLAUDE.md" -> "CLAUDE.md"
4679
+ * Add a path pattern. Dynamic paths (containing `_probe`) are reduced to their
4680
+ * directory; static paths and root-level files are added as-is.
4681
+ *
4682
+ * E.g. ".claude/rules/_probe.md" -> ".claude/rules/" (dynamic)
4683
+ * E.g. ".github/copilot-instructions.md" -> ".github/copilot-instructions.md" (static)
4684
+ * E.g. "CLAUDE.md" -> "CLAUDE.md" (root file)
4714
4685
  */
4715
4686
  function addPathPattern(patterns, path) {
4716
4687
  const lastSlash = path.lastIndexOf("/");
4717
- if (lastSlash > 0) patterns.add(path.substring(0, lastSlash + 1));
4688
+ if (lastSlash > 0) if (path.includes("_probe")) patterns.add(path.substring(0, lastSlash + 1));
4689
+ else patterns.add(path);
4718
4690
  else if (path) patterns.add(path);
4719
4691
  }
4720
4692
  /**
@@ -4758,6 +4730,62 @@ async function updateGitignore(projectRoot, patterns) {
4758
4730
  await writeFile(gitignorePath, newContent, "utf-8");
4759
4731
  return true;
4760
4732
  }
4733
+ /**
4734
+ * Remove the "# Baton managed ... # End Baton managed" section from .gitignore.
4735
+ *
4736
+ * Used when the project has `gitignore: false` to clean up any previously
4737
+ * written managed section.
4738
+ *
4739
+ * @returns true if a section was removed, false if none existed
4740
+ */
4741
+ async function removeGitignoreManagedSection(projectRoot) {
4742
+ const gitignorePath = join(projectRoot, ".gitignore");
4743
+ let content = "";
4744
+ try {
4745
+ content = await readFile(gitignorePath, "utf-8");
4746
+ } catch {
4747
+ return false;
4748
+ }
4749
+ const startIdx = content.indexOf(BATON_SECTION_START);
4750
+ const endIdx = content.indexOf(BATON_SECTION_END);
4751
+ if (startIdx === -1 || endIdx === -1) return false;
4752
+ const newContent = (content.substring(0, startIdx).replace(/\n+$/, "\n") + content.substring(endIdx + 19).replace(/^\n+/, "\n")).trim();
4753
+ await writeFile(gitignorePath, newContent ? `${newContent}\n` : "", "utf-8");
4754
+ return true;
4755
+ }
4756
+ /**
4757
+ * Collect comprehensive gitignore patterns for ALL known AI tools and IDE platforms.
4758
+ *
4759
+ * Generates patterns for the entire tool and IDE registry, ensuring stable,
4760
+ * predictable .gitignore content regardless of which tools a profile supports
4761
+ * or a developer has installed.
4762
+ *
4763
+ * Returns deduplicated, sorted patterns including baton.lock.
4764
+ */
4765
+ function collectComprehensivePatterns(options) {
4766
+ const patterns = /* @__PURE__ */ new Set();
4767
+ const { fileTargets } = options;
4768
+ const allAdapters = getAllAIToolAdapters();
4769
+ for (const adapter of allAdapters) {
4770
+ addDirPattern(patterns, adapter.getPath("commands", "project", "_probe"));
4771
+ addDirPattern(patterns, adapter.getPath("skills", "project", "_probe"));
4772
+ addPathPattern(patterns, adapter.getPath("rules", "project", "_probe"));
4773
+ addPathPattern(patterns, adapter.getPath("memory", "project", "_probe"));
4774
+ addDirPattern(patterns, adapter.getPath("agents", "project", "_probe"));
4775
+ for (const legacyPath of adapter.getLegacyPaths("rules")) patterns.add(legacyPath);
4776
+ }
4777
+ const allIdePlatforms = getRegisteredIdePlatforms();
4778
+ for (const ideKey of allIdePlatforms) {
4779
+ const targetDir = getIdePlatformTargetDir(ideKey);
4780
+ if (targetDir) {
4781
+ const dir = targetDir.endsWith("/") ? targetDir : `${targetDir}/`;
4782
+ patterns.add(dir);
4783
+ }
4784
+ }
4785
+ for (const target of fileTargets) patterns.add(target);
4786
+ patterns.add("baton.lock");
4787
+ return [...patterns].sort();
4788
+ }
4761
4789
 
4762
4790
  //#endregion
4763
4791
  //#region ../core/src/sources/git-clone.ts
@@ -6542,10 +6570,10 @@ async function discoverProfilesInSourceRepo(sourceRoot) {
6542
6570
  */
6543
6571
  const canonicalFiles = /* @__PURE__ */ new Map();
6544
6572
  /**
6545
- * Place a file for a specific agent adapter
6573
+ * Place a file for a specific AI tool adapter
6546
6574
  *
6547
6575
  * @param content - File content to write
6548
- * @param adapter - Agent adapter
6576
+ * @param adapter - AI tool adapter
6549
6577
  * @param type - Config type
6550
6578
  * @param scope - Scope (project or global)
6551
6579
  * @param name - File/directory name
@@ -6638,13 +6666,12 @@ async function readFileIfExists(path) {
6638
6666
  */
6639
6667
  async function detectLegacyPaths(projectRoot) {
6640
6668
  const legacyFiles = [];
6641
- const adapters = getAllAdapters();
6669
+ const adapters = getAllAIToolAdapters();
6642
6670
  for (const adapter of adapters) for (const configType of [
6643
6671
  "skills",
6644
6672
  "rules",
6645
6673
  "agents",
6646
6674
  "memory",
6647
- "settings",
6648
6675
  "commands"
6649
6676
  ]) {
6650
6677
  const legacyPaths = adapter.getLegacyPaths(configType);
@@ -6658,7 +6685,7 @@ async function detectLegacyPaths(projectRoot) {
6658
6685
  legacyPath: absoluteLegacyPath,
6659
6686
  newPath: resolve(projectRoot, newPath),
6660
6687
  configType,
6661
- agentKey: adapter.key
6688
+ toolKey: adapter.key
6662
6689
  });
6663
6690
  } catch {}
6664
6691
  }
@@ -7007,6 +7034,79 @@ function mergeRulesWithWarnings(profiles) {
7007
7034
  };
7008
7035
  }
7009
7036
 
7037
+ //#endregion
7038
+ //#region ../core/src/merge/agents.ts
7039
+ /**
7040
+ * Merge agents with detailed conflict warnings.
7041
+ *
7042
+ * @param profiles - Array of resolved profiles in merge order (base first, overrides last)
7043
+ * @returns Agents and any same-weight conflict warnings
7044
+ */
7045
+ function mergeAgentsWithWarnings(profiles) {
7046
+ const agentMap = /* @__PURE__ */ new Map();
7047
+ const lockedKeys = /* @__PURE__ */ new Set();
7048
+ const warnings = [];
7049
+ const keyOwner = /* @__PURE__ */ new Map();
7050
+ for (const profile of profiles) {
7051
+ const agents = profile.manifest.ai?.agents;
7052
+ if (!agents) continue;
7053
+ const weight = getProfileWeight(profile);
7054
+ const locked = isLockedProfile(profile);
7055
+ if (Array.isArray(agents)) for (const agentName of agents) {
7056
+ const key = `universal:${agentName}`;
7057
+ if (lockedKeys.has(key)) continue;
7058
+ const existing = keyOwner.get(key);
7059
+ if (existing && existing.weight === weight && existing.profileName !== profile.name) warnings.push({
7060
+ key: agentName,
7061
+ category: "agent",
7062
+ profileA: existing.profileName,
7063
+ profileB: profile.name,
7064
+ weight
7065
+ });
7066
+ agentMap.set(key, {
7067
+ name: agentName,
7068
+ agents: [],
7069
+ profileName: profile.name
7070
+ });
7071
+ keyOwner.set(key, {
7072
+ profileName: profile.name,
7073
+ weight
7074
+ });
7075
+ if (locked) lockedKeys.add(key);
7076
+ }
7077
+ else for (const [agentKey, agentNames] of Object.entries(agents)) {
7078
+ if (!agentNames) continue;
7079
+ for (const agentName of agentNames) {
7080
+ const isUniversal = agentKey === "universal";
7081
+ const key = `${agentKey}:${agentName}`;
7082
+ if (lockedKeys.has(key)) continue;
7083
+ const existing = keyOwner.get(key);
7084
+ if (existing && existing.weight === weight && existing.profileName !== profile.name) warnings.push({
7085
+ key: `${agentKey}:${agentName}`,
7086
+ category: "agent",
7087
+ profileA: existing.profileName,
7088
+ profileB: profile.name,
7089
+ weight
7090
+ });
7091
+ agentMap.set(key, {
7092
+ name: agentName,
7093
+ agents: isUniversal ? [] : [agentKey],
7094
+ profileName: profile.name
7095
+ });
7096
+ keyOwner.set(key, {
7097
+ profileName: profile.name,
7098
+ weight
7099
+ });
7100
+ if (locked) lockedKeys.add(key);
7101
+ }
7102
+ }
7103
+ }
7104
+ return {
7105
+ agents: Array.from(agentMap.values()),
7106
+ warnings
7107
+ };
7108
+ }
7109
+
7010
7110
  //#endregion
7011
7111
  //#region ../core/src/merge/memory.ts
7012
7112
  /**
@@ -14321,12 +14421,23 @@ const globalConfigSchema = objectType({
14321
14421
  //#endregion
14322
14422
  //#region ../core/src/config/global-config.ts
14323
14423
  /**
14424
+ * Returns the Baton home directory path.
14425
+ *
14426
+ * Respects the `BATON_HOME` environment variable for testing and custom locations.
14427
+ * Falls back to `~/.baton` when not set.
14428
+ *
14429
+ * @returns Absolute path to the Baton home directory
14430
+ */
14431
+ function getBatonHome() {
14432
+ return process.env.BATON_HOME ?? join(homedir(), ".baton");
14433
+ }
14434
+ /**
14324
14435
  * Returns the path to the global Baton configuration file.
14325
14436
  *
14326
- * @returns Absolute path to ~/.baton/config.yaml
14437
+ * @returns Absolute path to ~/.baton/config.yaml (or $BATON_HOME/config.yaml)
14327
14438
  */
14328
14439
  function getGlobalConfigPath() {
14329
- return join(homedir(), ".baton", "config.yaml");
14440
+ return join(getBatonHome(), "config.yaml");
14330
14441
  }
14331
14442
  /**
14332
14443
  * Loads the global Baton configuration from ~/.baton/config.yaml
@@ -14359,7 +14470,7 @@ async function loadGlobalConfig() {
14359
14470
  async function saveGlobalConfig(config) {
14360
14471
  const validated = globalConfigSchema.parse(config);
14361
14472
  const configPath = getGlobalConfigPath();
14362
- await mkdir(join(homedir(), ".baton"), { recursive: true });
14473
+ await mkdir(getBatonHome(), { recursive: true });
14363
14474
  await writeFile(configPath, (0, import_dist.stringify)(validated), "utf-8");
14364
14475
  }
14365
14476
  /**
@@ -14681,5 +14792,5 @@ async function resolvePreferences(projectRoot) {
14681
14792
  }
14682
14793
 
14683
14794
  //#endregion
14684
- export { SourceParseError as $, discoverProfilesInSourceRepo as A, getIdePlatformTargetDir as B, isLockedProfile as C, resolveProfileChain as D, resolveProfileSupport as E, writeLock as F, getAllAdapters as G, idePlatformRegistry as H, resolveVersion as I, loadLockfile as J, parseFrontmatter as K, cloneGitSource as L, removePlacedFiles as M, generateLock as N, detectLegacyPaths as O, readLock as P, FileNotFoundError as Q, collectProfileSupportPatterns as R, getProfileWeight as S, mergeContentParts as T, isKnownIdePlatform as U, getRegisteredIdePlatforms as V, getAdaptersForKeys as W, loadProjectManifest as X, loadProfileManifest as Y, KEBAB_CASE_REGEX as Z, mergeMemoryWithWarnings as _, clearIdeCache as a, mergeSkills as b, getDefaultGlobalSource as c, getGlobalSources as d, getAgentConfig 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, getAllAgentKeys as nt, detectInstalledIdes as o, setGlobalAiTools as p, parseSource as q, writeProjectPreferences as r, addGlobalSource as s, resolvePreferences as t, getAgentPath as tt, getGlobalIdePlatforms as u, mergeRules as v, sortProfilesByWeight as w, mergeSkillsWithWarnings as x, mergeRulesWithWarnings as y, updateGitignore as z };
14685
- //# sourceMappingURL=src-C3-Vz-R7.mjs.map
14795
+ export { loadLockfile as $, resolveProfileChain as A, cloneGitSource as B, mergeSkills as C, sortProfilesByWeight as D, isLockedProfile as E, removePlacedFiles as F, getIdePlatformTargetDir as G, ensureBatonDirGitignored as H, generateLock as I, isKnownIdePlatform as J, getRegisteredIdePlatforms as K, readLock as L, placeFile as M, discoverProfilesInSourceRepo as N, mergeContentParts as O, findSourceManifest as P, parseSource as Q, writeLock as R, mergeRulesWithWarnings as S, getProfileWeight as T, removeGitignoreManagedSection as U, collectComprehensivePatterns as V, updateGitignore as W, getAllAIToolAdapters as X, getAIToolAdaptersForKeys as Y, parseFrontmatter as Z, require_lib as _, clearIdeCache as a, getAIToolConfig as at, mergeAgentsWithWarnings as b, getBatonHome as c, getGlobalConfigPath as d, loadProfileManifest as et, getGlobalIdePlatforms as f, setGlobalIdePlatforms as g, setGlobalAiTools as h, computeIntersection as i, SourceParseError as it, detectLegacyPaths as j, resolveProfileSupport as k, getDefaultGlobalSource as l, removeGlobalSource as m, readProjectPreferences as n, KEBAB_CASE_REGEX as nt, detectInstalledIdes as o, getAIToolPath as ot, getGlobalSources as p, idePlatformRegistry as q, writeProjectPreferences as r, FileNotFoundError as rt, addGlobalSource as s, getAllAIToolKeys as st, resolvePreferences as t, loadProjectManifest as tt, getGlobalAiTools as u, mergeMemory as v, mergeSkillsWithWarnings as w, mergeRules as x, mergeMemoryWithWarnings as y, resolveVersion as z };
14796
+ //# sourceMappingURL=src-D41VR6ro.mjs.map