skiller 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.
Files changed (62) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +989 -0
  3. package/dist/agents/AbstractAgent.js +92 -0
  4. package/dist/agents/AgentsMdAgent.js +85 -0
  5. package/dist/agents/AiderAgent.js +108 -0
  6. package/dist/agents/AmazonQCliAgent.js +103 -0
  7. package/dist/agents/AmpAgent.js +13 -0
  8. package/dist/agents/AugmentCodeAgent.js +70 -0
  9. package/dist/agents/ClaudeAgent.js +95 -0
  10. package/dist/agents/ClineAgent.js +53 -0
  11. package/dist/agents/CodexCliAgent.js +143 -0
  12. package/dist/agents/CopilotAgent.js +43 -0
  13. package/dist/agents/CrushAgent.js +128 -0
  14. package/dist/agents/CursorAgent.js +93 -0
  15. package/dist/agents/FirebaseAgent.js +61 -0
  16. package/dist/agents/FirebenderAgent.js +205 -0
  17. package/dist/agents/GeminiCliAgent.js +99 -0
  18. package/dist/agents/GooseAgent.js +58 -0
  19. package/dist/agents/IAgent.js +2 -0
  20. package/dist/agents/JulesAgent.js +14 -0
  21. package/dist/agents/JunieAgent.js +53 -0
  22. package/dist/agents/KiloCodeAgent.js +63 -0
  23. package/dist/agents/KiroAgent.js +50 -0
  24. package/dist/agents/OpenCodeAgent.js +99 -0
  25. package/dist/agents/OpenHandsAgent.js +56 -0
  26. package/dist/agents/QwenCodeAgent.js +82 -0
  27. package/dist/agents/RooCodeAgent.js +139 -0
  28. package/dist/agents/TraeAgent.js +54 -0
  29. package/dist/agents/WarpAgent.js +61 -0
  30. package/dist/agents/WindsurfAgent.js +27 -0
  31. package/dist/agents/ZedAgent.js +132 -0
  32. package/dist/agents/agent-utils.js +37 -0
  33. package/dist/agents/index.js +77 -0
  34. package/dist/cli/commands.js +136 -0
  35. package/dist/cli/handlers.js +221 -0
  36. package/dist/cli/index.js +5 -0
  37. package/dist/constants.js +58 -0
  38. package/dist/core/ConfigLoader.js +274 -0
  39. package/dist/core/FileSystemUtils.js +421 -0
  40. package/dist/core/FrontmatterParser.js +142 -0
  41. package/dist/core/GitignoreUtils.js +171 -0
  42. package/dist/core/RuleProcessor.js +60 -0
  43. package/dist/core/SkillsProcessor.js +528 -0
  44. package/dist/core/SkillsUtils.js +230 -0
  45. package/dist/core/UnifiedConfigLoader.js +432 -0
  46. package/dist/core/UnifiedConfigTypes.js +2 -0
  47. package/dist/core/agent-selection.js +52 -0
  48. package/dist/core/apply-engine.js +668 -0
  49. package/dist/core/config-utils.js +30 -0
  50. package/dist/core/hash.js +24 -0
  51. package/dist/core/revert-engine.js +413 -0
  52. package/dist/lib.js +196 -0
  53. package/dist/mcp/capabilities.js +65 -0
  54. package/dist/mcp/merge.js +39 -0
  55. package/dist/mcp/propagateOpenCodeMcp.js +116 -0
  56. package/dist/mcp/propagateOpenHandsMcp.js +169 -0
  57. package/dist/mcp/validate.js +17 -0
  58. package/dist/paths/mcp.js +120 -0
  59. package/dist/revert.js +186 -0
  60. package/dist/types.js +2 -0
  61. package/dist/vscode/settings.js +117 -0
  62. package/package.json +77 -0
@@ -0,0 +1,221 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.applyHandler = applyHandler;
37
+ exports.initHandler = initHandler;
38
+ exports.revertHandler = revertHandler;
39
+ const lib_1 = require("../lib");
40
+ const revert_1 = require("../revert");
41
+ const path = __importStar(require("path"));
42
+ const os = __importStar(require("os"));
43
+ const fs = __importStar(require("fs/promises"));
44
+ const constants_1 = require("../constants");
45
+ const ConfigLoader_1 = require("../core/ConfigLoader");
46
+ /**
47
+ * Handler for the 'apply' command.
48
+ */
49
+ async function applyHandler(argv) {
50
+ const projectRoot = argv['project-root'];
51
+ const agents = argv.agents
52
+ ? argv.agents.split(',').map((a) => a.trim())
53
+ : undefined;
54
+ const configPath = argv.config;
55
+ const mcpEnabled = argv.mcp;
56
+ const mcpStrategy = argv['mcp-overwrite']
57
+ ? 'overwrite'
58
+ : undefined;
59
+ const verbose = argv.verbose;
60
+ const dryRun = argv['dry-run'];
61
+ const localOnly = argv['local-only'];
62
+ // Determine backup preference: CLI > TOML > Default (enabled)
63
+ // yargs handles --no-backup by setting backup to false
64
+ let backupPreference;
65
+ if (argv.backup !== undefined) {
66
+ backupPreference = argv.backup;
67
+ }
68
+ else {
69
+ backupPreference = undefined; // Let TOML/default decide
70
+ }
71
+ // Determine gitignore preference: CLI > TOML > Default (enabled)
72
+ // yargs handles --no-gitignore by setting gitignore to false
73
+ let gitignorePreference;
74
+ if (argv.gitignore !== undefined) {
75
+ gitignorePreference = argv.gitignore;
76
+ }
77
+ else {
78
+ gitignorePreference = undefined; // Let TOML/default decide
79
+ }
80
+ // Determine nested preference: CLI > TOML > Default (false)
81
+ let nested;
82
+ if (argv.nested !== undefined) {
83
+ // CLI explicitly set nested (either --nested or --no-nested)
84
+ nested = argv.nested;
85
+ }
86
+ else {
87
+ // CLI didn't set nested, check TOML configuration
88
+ try {
89
+ const config = await (0, ConfigLoader_1.loadConfig)({
90
+ projectRoot,
91
+ configPath,
92
+ });
93
+ // Use TOML setting if available, otherwise default to false
94
+ nested = config.nested ?? false;
95
+ }
96
+ catch {
97
+ // If config loading fails, use default (false)
98
+ nested = false;
99
+ }
100
+ }
101
+ // Determine skills preference: CLI > TOML > Default (enabled)
102
+ let skillsEnabled;
103
+ if (argv.skills !== undefined) {
104
+ skillsEnabled = argv.skills;
105
+ }
106
+ else {
107
+ skillsEnabled = undefined; // Let config/default decide
108
+ }
109
+ try {
110
+ await (0, lib_1.applyAllAgentConfigs)(projectRoot, agents, configPath, mcpEnabled, mcpStrategy, gitignorePreference, verbose, dryRun, localOnly, nested, backupPreference, skillsEnabled);
111
+ console.log('Ruler apply completed successfully.');
112
+ }
113
+ catch (err) {
114
+ const message = err instanceof Error ? err.message : String(err);
115
+ console.error(`${constants_1.ERROR_PREFIX} ${message}`);
116
+ process.exit(1);
117
+ }
118
+ }
119
+ /**
120
+ * Handler for the 'init' command.
121
+ */
122
+ async function initHandler(argv) {
123
+ const projectRoot = argv['project-root'];
124
+ const isGlobal = argv['global'];
125
+ const useClaude = argv['claude'] ?? false;
126
+ const folderName = useClaude ? '.claude' : '.ruler';
127
+ const rulerDir = isGlobal
128
+ ? path.join(process.env.XDG_CONFIG_HOME || path.join(os.homedir(), '.config'), 'ruler')
129
+ : path.join(projectRoot, folderName);
130
+ await fs.mkdir(rulerDir, { recursive: true });
131
+ const instructionsPath = path.join(rulerDir, constants_1.DEFAULT_RULES_FILENAME); // .ruler/AGENTS.md or .claude/AGENTS.md
132
+ const tomlPath = path.join(rulerDir, 'ruler.toml');
133
+ const exists = async (p) => {
134
+ try {
135
+ await fs.access(p);
136
+ return true;
137
+ }
138
+ catch {
139
+ return false;
140
+ }
141
+ };
142
+ const DEFAULT_INSTRUCTIONS = `# AGENTS.md\n\nCentralised AI agent instructions. Add coding guidelines, style guides, and project context here.\n\nRuler concatenates all .md files in this directory (and subdirectories), starting with AGENTS.md (if present), then remaining files in sorted order.\n`;
143
+ const DEFAULT_TOML = `# Ruler Configuration File
144
+ # See https://ai.intellectronica.net/ruler for documentation.
145
+
146
+ # To specify which agents are active by default when --agents is not used,
147
+ # uncomment and populate the following line. If omitted, all agents are active.
148
+ # default_agents = ["copilot", "claude"]
149
+ ${useClaude ? '\n# Root folder for ruler files\nroot_folder = ".claude"\n' : ''}
150
+ # Enable nested rule loading from nested ${folderName} directories
151
+ # When enabled, ruler will search for and process ${folderName} directories throughout the project hierarchy
152
+ # nested = false
153
+
154
+ # --- Agent Specific Configurations ---
155
+ # You can enable/disable agents and override their default output paths here.
156
+ # Use lowercase agent identifiers: amp, copilot, claude, codex, cursor, windsurf, cline, aider, kilocode
157
+
158
+ # [agents.copilot]
159
+ # enabled = true
160
+ # output_path = ".github/copilot-instructions.md"
161
+
162
+ # [agents.aider]
163
+ # enabled = true
164
+ # output_path_instructions = "AGENTS.md"
165
+ # output_path_config = ".aider.conf.yml"
166
+
167
+ # [agents.gemini-cli]
168
+ # enabled = true
169
+
170
+ # --- MCP Servers ---
171
+ # Define Model Context Protocol servers here. Two examples:
172
+ # 1. A stdio server (local executable)
173
+ # 2. A remote server (HTTP-based)
174
+
175
+ # [mcp_servers.example_stdio]
176
+ # command = "node"
177
+ # args = ["scripts/your-mcp-server.js"]
178
+ # env = { API_KEY = "replace_me" }
179
+
180
+ # [mcp_servers.example_remote]
181
+ # url = "https://api.example.com/mcp"
182
+ # headers = { Authorization = "Bearer REPLACE_ME" }
183
+ `;
184
+ if (!(await exists(instructionsPath))) {
185
+ // Create new AGENTS.md regardless of legacy presence.
186
+ await fs.writeFile(instructionsPath, DEFAULT_INSTRUCTIONS);
187
+ console.log(`[ruler] Created ${instructionsPath}`);
188
+ }
189
+ else {
190
+ console.log(`[ruler] ${constants_1.DEFAULT_RULES_FILENAME} already exists, skipping`);
191
+ }
192
+ if (!(await exists(tomlPath))) {
193
+ await fs.writeFile(tomlPath, DEFAULT_TOML);
194
+ console.log(`[ruler] Created ${tomlPath}`);
195
+ }
196
+ else {
197
+ console.log(`[ruler] ruler.toml already exists, skipping`);
198
+ }
199
+ }
200
+ /**
201
+ * Handler for the 'revert' command.
202
+ */
203
+ async function revertHandler(argv) {
204
+ const projectRoot = argv['project-root'];
205
+ const agents = argv.agents
206
+ ? argv.agents.split(',').map((a) => a.trim())
207
+ : undefined;
208
+ const configPath = argv.config;
209
+ const keepBackups = argv['keep-backups'];
210
+ const verbose = argv.verbose;
211
+ const dryRun = argv['dry-run'];
212
+ const localOnly = argv['local-only'];
213
+ try {
214
+ await (0, revert_1.revertAllAgentConfigs)(projectRoot, agents, configPath, keepBackups, verbose, dryRun, localOnly);
215
+ }
216
+ catch (err) {
217
+ const message = err instanceof Error ? err.message : String(err);
218
+ console.error(`${constants_1.ERROR_PREFIX} ${message}`);
219
+ process.exit(1);
220
+ }
221
+ }
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ const commands_1 = require("./commands");
5
+ (0, commands_1.run)();
@@ -0,0 +1,58 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SKILLZ_MCP_SERVER_NAME = exports.SKILL_MD_FILENAME = exports.SKILLZ_DIR = exports.CLAUDE_SKILLS_PATH = exports.RULER_SKILLS_PATH = exports.SKILLS_DIR = exports.DEFAULT_RULES_FILENAME = exports.ERROR_PREFIX = void 0;
4
+ exports.actionPrefix = actionPrefix;
5
+ exports.createRulerError = createRulerError;
6
+ exports.logVerbose = logVerbose;
7
+ exports.logInfo = logInfo;
8
+ exports.logWarn = logWarn;
9
+ exports.logError = logError;
10
+ exports.logVerboseInfo = logVerboseInfo;
11
+ exports.ERROR_PREFIX = '[ruler]';
12
+ // Centralized default rules filename. Now points to 'AGENTS.md'.
13
+ // Legacy '.ruler/instructions.md' is still supported as a fallback with a warning.
14
+ exports.DEFAULT_RULES_FILENAME = 'AGENTS.md';
15
+ function actionPrefix(dry) {
16
+ return dry ? '[ruler:dry-run]' : '[ruler]';
17
+ }
18
+ function createRulerError(message, context) {
19
+ const fullMessage = context
20
+ ? `${exports.ERROR_PREFIX} ${message} (Context: ${context})`
21
+ : `${exports.ERROR_PREFIX} ${message}`;
22
+ return new Error(fullMessage);
23
+ }
24
+ function logVerbose(message, isVerbose) {
25
+ if (isVerbose) {
26
+ console.error(`[ruler:verbose] ${message}`);
27
+ }
28
+ }
29
+ /**
30
+ * Centralized logging functions with consistent output streams and prefixing.
31
+ * - info/verbose go to stdout (user-visible progress)
32
+ * - warn/error go to stderr (problems)
33
+ */
34
+ function logInfo(message, dryRun = false) {
35
+ const prefix = actionPrefix(dryRun);
36
+ console.log(`${prefix} ${message}`);
37
+ }
38
+ function logWarn(message, dryRun = false) {
39
+ const prefix = actionPrefix(dryRun);
40
+ console.warn(`${prefix} ${message}`);
41
+ }
42
+ function logError(message, dryRun = false) {
43
+ const prefix = actionPrefix(dryRun);
44
+ console.error(`${prefix} ${message}`);
45
+ }
46
+ function logVerboseInfo(message, isVerbose, dryRun = false) {
47
+ if (isVerbose) {
48
+ const prefix = actionPrefix(dryRun);
49
+ console.log(`${prefix} ${message}`);
50
+ }
51
+ }
52
+ // Skills-related constants
53
+ exports.SKILLS_DIR = 'skills';
54
+ exports.RULER_SKILLS_PATH = '.ruler/skills';
55
+ exports.CLAUDE_SKILLS_PATH = '.claude/skills';
56
+ exports.SKILLZ_DIR = '.skillz';
57
+ exports.SKILL_MD_FILENAME = 'SKILL.md';
58
+ exports.SKILLZ_MCP_SERVER_NAME = 'skillz';
@@ -0,0 +1,274 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.loadConfig = loadConfig;
37
+ const fs_1 = require("fs");
38
+ const path = __importStar(require("path"));
39
+ const os = __importStar(require("os"));
40
+ const toml_1 = require("@iarna/toml");
41
+ const zod_1 = require("zod");
42
+ const constants_1 = require("../constants");
43
+ const mcpConfigSchema = zod_1.z
44
+ .object({
45
+ enabled: zod_1.z.boolean().optional(),
46
+ merge_strategy: zod_1.z.enum(['merge', 'overwrite']).optional(),
47
+ })
48
+ .optional();
49
+ const agentConfigSchema = zod_1.z
50
+ .object({
51
+ enabled: zod_1.z.boolean().optional(),
52
+ output_path: zod_1.z.string().optional(),
53
+ output_path_instructions: zod_1.z.string().optional(),
54
+ output_path_config: zod_1.z.string().optional(),
55
+ mcp: mcpConfigSchema,
56
+ })
57
+ .optional();
58
+ const rulerConfigSchema = zod_1.z.object({
59
+ default_agents: zod_1.z.array(zod_1.z.string()).optional(),
60
+ root_folder: zod_1.z.string().optional(),
61
+ agents: zod_1.z.record(zod_1.z.string(), agentConfigSchema).optional(),
62
+ mcp: zod_1.z
63
+ .object({
64
+ enabled: zod_1.z.boolean().optional(),
65
+ merge_strategy: zod_1.z.enum(['merge', 'overwrite']).optional(),
66
+ })
67
+ .optional(),
68
+ gitignore: zod_1.z
69
+ .object({
70
+ enabled: zod_1.z.boolean().optional(),
71
+ })
72
+ .optional(),
73
+ backup: zod_1.z
74
+ .object({
75
+ enabled: zod_1.z.boolean().optional(),
76
+ })
77
+ .optional(),
78
+ skills: zod_1.z
79
+ .object({
80
+ enabled: zod_1.z.boolean().optional(),
81
+ })
82
+ .optional(),
83
+ rules: zod_1.z
84
+ .object({
85
+ include: zod_1.z.array(zod_1.z.string()).optional(),
86
+ exclude: zod_1.z.array(zod_1.z.string()).optional(),
87
+ merge_strategy: zod_1.z.enum(['all', 'cursor']).optional(),
88
+ })
89
+ .optional(),
90
+ nested: zod_1.z.boolean().optional(),
91
+ });
92
+ /**
93
+ * Recursively creates a new object with only enumerable string keys,
94
+ * effectively excluding Symbol properties.
95
+ * The @iarna/toml parser adds Symbol properties (Symbol(type), Symbol(declared))
96
+ * for metadata, which Zod v4+ validates and rejects as invalid record keys.
97
+ * By rebuilding the object structure using Object.keys(), we create clean objects
98
+ * that only contain the actual data without Symbol metadata.
99
+ */
100
+ function stripSymbols(obj) {
101
+ if (obj === null || typeof obj !== 'object') {
102
+ return obj;
103
+ }
104
+ if (Array.isArray(obj)) {
105
+ return obj.map(stripSymbols);
106
+ }
107
+ const result = {};
108
+ for (const key of Object.keys(obj)) {
109
+ result[key] = stripSymbols(obj[key]);
110
+ }
111
+ return result;
112
+ }
113
+ /**
114
+ * Loads and parses the ruler TOML configuration file, applying defaults.
115
+ * If the file is missing or invalid, returns empty/default config.
116
+ */
117
+ async function loadConfig(options) {
118
+ const { projectRoot, configPath, cliAgents } = options;
119
+ let configFile;
120
+ if (configPath) {
121
+ configFile = path.resolve(configPath);
122
+ }
123
+ else {
124
+ // Try local .ruler/ruler.toml first
125
+ const localConfigFile = path.join(projectRoot, '.ruler', 'ruler.toml');
126
+ try {
127
+ await fs_1.promises.access(localConfigFile);
128
+ configFile = localConfigFile;
129
+ }
130
+ catch {
131
+ // If .ruler config doesn't exist, try .claude/ruler.toml
132
+ const claudeConfigFile = path.join(projectRoot, '.claude', 'ruler.toml');
133
+ try {
134
+ await fs_1.promises.access(claudeConfigFile);
135
+ configFile = claudeConfigFile;
136
+ }
137
+ catch {
138
+ // If neither local config exists, try global config
139
+ const xdgConfigDir = process.env.XDG_CONFIG_HOME || path.join(os.homedir(), '.config');
140
+ configFile = path.join(xdgConfigDir, 'ruler', 'ruler.toml');
141
+ }
142
+ }
143
+ }
144
+ let raw = {};
145
+ try {
146
+ const text = await fs_1.promises.readFile(configFile, 'utf8');
147
+ const parsed = text.trim() ? (0, toml_1.parse)(text) : {};
148
+ // Strip Symbol properties added by @iarna/toml (required for Zod v4+)
149
+ raw = stripSymbols(parsed);
150
+ // Validate the configuration with zod
151
+ const validationResult = rulerConfigSchema.safeParse(raw);
152
+ if (!validationResult.success) {
153
+ throw (0, constants_1.createRulerError)('Invalid configuration file format', `File: ${configFile}, Errors: ${validationResult.error.issues.map((i) => `${i.path.join('.')}: ${i.message}`).join(', ')}`);
154
+ }
155
+ }
156
+ catch (err) {
157
+ if (err instanceof Error && err.code !== 'ENOENT') {
158
+ if (err.message.includes('[ruler]')) {
159
+ throw err; // Re-throw validation errors
160
+ }
161
+ console.warn(`[ruler] Warning: could not read config file at ${configFile}: ${err.message}`);
162
+ }
163
+ raw = {};
164
+ }
165
+ const defaultAgents = Array.isArray(raw.default_agents)
166
+ ? raw.default_agents.map((a) => String(a))
167
+ : undefined;
168
+ const rootFolder = typeof raw.root_folder === 'string' ? raw.root_folder : undefined;
169
+ const agentsSection = raw.agents && typeof raw.agents === 'object' && !Array.isArray(raw.agents)
170
+ ? raw.agents
171
+ : {};
172
+ const agentConfigs = {};
173
+ for (const [name, section] of Object.entries(agentsSection)) {
174
+ if (section && typeof section === 'object') {
175
+ const sectionObj = section;
176
+ const cfg = {};
177
+ if (typeof sectionObj.enabled === 'boolean') {
178
+ cfg.enabled = sectionObj.enabled;
179
+ }
180
+ if (typeof sectionObj.output_path === 'string') {
181
+ cfg.outputPath = path.resolve(projectRoot, sectionObj.output_path);
182
+ }
183
+ if (typeof sectionObj.output_path_instructions === 'string') {
184
+ cfg.outputPathInstructions = path.resolve(projectRoot, sectionObj.output_path_instructions);
185
+ }
186
+ if (typeof sectionObj.output_path_config === 'string') {
187
+ cfg.outputPathConfig = path.resolve(projectRoot, sectionObj.output_path_config);
188
+ }
189
+ if (sectionObj.mcp && typeof sectionObj.mcp === 'object') {
190
+ const m = sectionObj.mcp;
191
+ const mcpCfg = {};
192
+ if (typeof m.enabled === 'boolean') {
193
+ mcpCfg.enabled = m.enabled;
194
+ }
195
+ if (typeof m.merge_strategy === 'string') {
196
+ const ms = m.merge_strategy;
197
+ if (ms === 'merge' || ms === 'overwrite') {
198
+ mcpCfg.strategy = ms;
199
+ }
200
+ }
201
+ cfg.mcp = mcpCfg;
202
+ }
203
+ agentConfigs[name] = cfg;
204
+ }
205
+ }
206
+ const rawMcpSection = raw.mcp && typeof raw.mcp === 'object' && !Array.isArray(raw.mcp)
207
+ ? raw.mcp
208
+ : {};
209
+ const globalMcpConfig = {};
210
+ if (typeof rawMcpSection.enabled === 'boolean') {
211
+ globalMcpConfig.enabled = rawMcpSection.enabled;
212
+ }
213
+ if (typeof rawMcpSection.merge_strategy === 'string') {
214
+ const strat = rawMcpSection.merge_strategy;
215
+ if (strat === 'merge' || strat === 'overwrite') {
216
+ globalMcpConfig.strategy = strat;
217
+ }
218
+ }
219
+ const rawGitignoreSection = raw.gitignore &&
220
+ typeof raw.gitignore === 'object' &&
221
+ !Array.isArray(raw.gitignore)
222
+ ? raw.gitignore
223
+ : {};
224
+ const gitignoreConfig = {};
225
+ if (typeof rawGitignoreSection.enabled === 'boolean') {
226
+ gitignoreConfig.enabled = rawGitignoreSection.enabled;
227
+ }
228
+ const rawBackupSection = raw.backup && typeof raw.backup === 'object' && !Array.isArray(raw.backup)
229
+ ? raw.backup
230
+ : {};
231
+ const backupConfig = {};
232
+ if (typeof rawBackupSection.enabled === 'boolean') {
233
+ backupConfig.enabled = rawBackupSection.enabled;
234
+ }
235
+ const rawSkillsSection = raw.skills && typeof raw.skills === 'object' && !Array.isArray(raw.skills)
236
+ ? raw.skills
237
+ : {};
238
+ const skillsConfig = {};
239
+ if (typeof rawSkillsSection.enabled === 'boolean') {
240
+ skillsConfig.enabled = rawSkillsSection.enabled;
241
+ }
242
+ if (typeof rawSkillsSection.generate_from_rules === 'boolean') {
243
+ skillsConfig.generate_from_rules = rawSkillsSection.generate_from_rules;
244
+ }
245
+ const rawRulesSection = raw.rules && typeof raw.rules === 'object' && !Array.isArray(raw.rules)
246
+ ? raw.rules
247
+ : {};
248
+ const rulesConfig = {};
249
+ if (Array.isArray(rawRulesSection.include)) {
250
+ rulesConfig.include = rawRulesSection.include.map((p) => String(p));
251
+ }
252
+ if (Array.isArray(rawRulesSection.exclude)) {
253
+ rulesConfig.exclude = rawRulesSection.exclude.map((p) => String(p));
254
+ }
255
+ if (rawRulesSection.merge_strategy === 'all' ||
256
+ rawRulesSection.merge_strategy === 'cursor') {
257
+ rulesConfig.merge_strategy = rawRulesSection.merge_strategy;
258
+ }
259
+ const nestedDefined = typeof raw.nested === 'boolean';
260
+ const nested = nestedDefined ? raw.nested : false;
261
+ return {
262
+ defaultAgents,
263
+ rootFolder,
264
+ agentConfigs,
265
+ cliAgents,
266
+ mcp: globalMcpConfig,
267
+ gitignore: gitignoreConfig,
268
+ backup: backupConfig,
269
+ skills: skillsConfig,
270
+ rules: rulesConfig,
271
+ nested,
272
+ nestedDefined,
273
+ };
274
+ }