@intellectronica/ruler 0.3.40 → 0.3.41

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 CHANGED
@@ -245,7 +245,7 @@ The `apply` command looks for `.ruler/` in the current directory tree, reading t
245
245
  | `--no-backup` | Disable creation of `.bak` backup files. |
246
246
  | `--skills` | Enable skills support (experimental, default: enabled). |
247
247
  | `--no-skills` | Disable skills support. |
248
- | `--subagents` | Enable subagents support (experimental, default: enabled). |
248
+ | `--subagents` | Enable subagents support (experimental, default: disabled). |
249
249
  | `--no-subagents` | Disable subagents support. |
250
250
  | `--dry-run` | Preview changes without writing files. |
251
251
  | `--local-only` | Skip `$XDG_CONFIG_HOME` when looking for configuration. |
@@ -740,18 +740,18 @@ Ruler can distribute named, delegatable **subagents** from a single source of tr
740
740
 
741
741
  For agents with a native subagent primitive, Ruler writes one file per subagent into the target directory:
742
742
 
743
- | Agent | Target location | Format |
744
- | ----------------- | ------------------------------ | ------ |
745
- | Claude Code | `.claude/agents/<name>.md` | Markdown + YAML frontmatter |
746
- | Cursor | `.cursor/agents/<name>.md` | Markdown + YAML frontmatter |
747
- | OpenAI Codex CLI | `.codex/agents/<name>.toml` | TOML (one self-contained file per agent) |
748
- | GitHub Copilot | `.github/agents/<name>.md` | Markdown + YAML frontmatter |
743
+ | Agent | Target location | Format |
744
+ | ---------------- | ------------------------------------ | ---------------------------------------- |
745
+ | Claude Code | `.claude/agents/<relative-path>.md` | Markdown + YAML frontmatter |
746
+ | Cursor | `.cursor/agents/<relative-path>.md` | Markdown + YAML frontmatter |
747
+ | OpenAI Codex CLI | `.codex/agents/<relative-path>.toml` | TOML (one self-contained file per agent) |
748
+ | GitHub Copilot | `.github/agents/<relative-path>.md` | Markdown + YAML frontmatter |
749
749
 
750
750
  Other agents (Windsurf, RooCode, Aider, Gemini CLI, …) do not yet have a comparable native subagent primitive and are skipped with a warning. Subagent propagation will be added when those agents ship a comparable file format.
751
751
 
752
752
  ### Source Format
753
753
 
754
- Author each subagent as `.ruler/agents/<name>.md`:
754
+ Author each subagent as `.ruler/agents/<name>.md` (nested folders are supported and preserved in outputs):
755
755
 
756
756
  ```markdown
757
757
  ---
@@ -772,19 +772,19 @@ a structured verdict.
772
772
 
773
773
  **Required frontmatter fields:**
774
774
 
775
- | Field | Type | Notes |
776
- | ------------- | ------ | ----------------------------------------------------- |
775
+ | Field | Type | Notes |
776
+ | ------------- | ------ | -------------------------------------------------------------------------- |
777
777
  | `name` | string | Must match the filename stem (`code-reviewer.md` → `name: code-reviewer`). |
778
- | `description` | string | When the parent agent should delegate to this subagent. |
778
+ | `description` | string | When the parent agent should delegate to this subagent. |
779
779
 
780
780
  **Optional frontmatter fields:**
781
781
 
782
- | Field | Type | Used by | Default behavior |
783
- | --------------- | ---------------- | ------------------------------------------------ | --------------------------------------------- |
784
- | `tools` | string[] | Claude (verbatim), Copilot (mapped to aliases) | Cursor / Codex ignore; omitted if absent. |
785
- | `model` | string | All four targets | Cursor defaults to `inherit`; others omit. |
786
- | `readonly` | boolean | Cursor (verbatim), Codex (`sandbox_mode`), Copilot (`disable-model-invocation`) | Defaults to `false` for Cursor; omitted otherwise. |
787
- | `is_background` | boolean | Cursor only | Defaults to `false` for Cursor. |
782
+ | Field | Type | Used by | Default behavior |
783
+ | --------------- | -------- | ------------------------------------------------------------------------------- | -------------------------------------------------- |
784
+ | `tools` | string[] | Claude (verbatim), Copilot (mapped to aliases) | Cursor / Codex ignore; omitted if absent. |
785
+ | `model` | string | All four targets | Cursor defaults to `inherit`; others omit. |
786
+ | `readonly` | boolean | Cursor (verbatim), Codex (`sandbox_mode`), Copilot (`disable-model-invocation`) | Defaults to `false` for Cursor; omitted otherwise. |
787
+ | `is_background` | boolean | Cursor only | Defaults to `false` for Cursor. |
788
788
 
789
789
  For GitHub Copilot, source `tools` (Claude vocabulary: `Read`, `Grep`, `Bash`, …) are translated to Copilot's aliases (`read`, `search`, `execute`, …). Tools that do not have a Copilot equivalent are dropped silently on a normal apply; pass `--verbose` (or use `--dry-run` to preview) to see which tools were dropped.
790
790
 
@@ -801,6 +801,7 @@ ruler apply --subagents # enable subagent propagation for one run
801
801
  [agents]
802
802
  enabled = true
803
803
  # include_in_rules = true # also append .ruler/agents/*.md into top-level CLAUDE.md / AGENTS.md (default: false)
804
+ # cleanup_orphaned = true # allow ruler to delete stale native subagent dirs (default: false)
804
805
  ```
805
806
 
806
807
  > **Note:** the previous release used `[subagents]` for these keys. `[subagents]` is still honored as a fallback with a deprecation warning, and will be removed in a future release. Please migrate to `[agents]`.
@@ -837,7 +838,7 @@ Use `--no-gitignore` to opt out.
837
838
 
838
839
  ### Cleanup
839
840
 
840
- Subagent propagation does **not** currently have explicit `ruler revert` support. To remove generated subagent directories, set `[agents] enabled = false` (or pass `--no-subagents`) and run `ruler apply` once. Cleanup will run for all four targets even if no source `.ruler/agents/` directory exists.
841
+ Subagent propagation does **not** currently have explicit `ruler revert` support. By default, `ruler apply` is non-destructive and leaves existing native subagent directories untouched when subagents are disabled or missing. To allow automatic cleanup of stale generated directories, set `[agents] cleanup_orphaned = true`, then disable subagents (`[agents] enabled = false` or `--no-subagents`) and run `ruler apply`.
841
842
 
842
843
  ### Example Workflow
843
844
 
@@ -870,7 +871,7 @@ ruler apply
870
871
 
871
872
  ### Limitations
872
873
 
873
- - **No explicit revert command.** Cleanup happens via `[agents] enabled = false` on a subsequent `apply`.
874
+ - **No explicit revert command.** Optional cleanup is available via `[agents] cleanup_orphaned = true` and a subsequent `apply`.
874
875
  - **Atomic replace, not merge.** Ruler regenerates each agent's subagent directory from the source on every apply. Manual edits to generated files will be overwritten.
875
876
  - **No support yet for agents without a native subagent primitive.** Windsurf, RooCode, Aider, Gemini CLI, and others are skipped with a warning. Propagation will be added when those agents ship a comparable file format.
876
877
 
@@ -80,7 +80,7 @@ function run() {
80
80
  })
81
81
  .option('subagents', {
82
82
  type: 'boolean',
83
- description: 'Enable/disable subagents support (experimental, default: enabled)',
83
+ description: 'Enable/disable subagents support (experimental, default: disabled)',
84
84
  });
85
85
  }, handlers_1.applyHandler)
86
86
  .command('init', 'Scaffold a .ruler directory with default files', (y) => {
@@ -114,7 +114,7 @@ async function applyHandler(argv) {
114
114
  else {
115
115
  skillsEnabled = undefined; // Let config/default decide
116
116
  }
117
- // Determine subagents preference: CLI > TOML > Default (enabled)
117
+ // Determine subagents preference: CLI > TOML > Default (disabled)
118
118
  let subagentsEnabled;
119
119
  if (argv.subagents !== undefined) {
120
120
  subagentsEnabled = argv.subagents;
@@ -76,13 +76,18 @@ const agentConfigSchema = zod_1.z
76
76
  // - one nested table per coding-agent integration (`[agents.claude]`, etc.)
77
77
  // Reserved keys are validated by the object shape; everything else falls
78
78
  // through `catchall` and is treated as a per-agent config record.
79
- const SUBAGENT_RESERVED_KEYS = new Set(['enabled', 'include_in_rules']);
79
+ const SUBAGENT_RESERVED_KEYS = new Set([
80
+ 'enabled',
81
+ 'include_in_rules',
82
+ 'cleanup_orphaned',
83
+ ]);
80
84
  const rulerConfigSchema = zod_1.z.object({
81
85
  default_agents: zod_1.z.array(zod_1.z.string()).optional(),
82
86
  agents: zod_1.z
83
87
  .object({
84
88
  enabled: zod_1.z.boolean().optional(),
85
89
  include_in_rules: zod_1.z.boolean().optional(),
90
+ cleanup_orphaned: zod_1.z.boolean().optional(),
86
91
  })
87
92
  .catchall(agentConfigSchema)
88
93
  .optional(),
@@ -111,6 +116,7 @@ const rulerConfigSchema = zod_1.z.object({
111
116
  .object({
112
117
  enabled: zod_1.z.boolean().optional(),
113
118
  include_in_rules: zod_1.z.boolean().optional(),
119
+ cleanup_orphaned: zod_1.z.boolean().optional(),
114
120
  })
115
121
  .optional(),
116
122
  nested: zod_1.z.boolean().optional(),
@@ -272,7 +278,8 @@ async function loadConfig(options) {
272
278
  ? raw.subagents
273
279
  : {};
274
280
  const legacyHasContent = typeof rawLegacySubagentsSection.enabled === 'boolean' ||
275
- typeof rawLegacySubagentsSection.include_in_rules === 'boolean';
281
+ typeof rawLegacySubagentsSection.include_in_rules === 'boolean' ||
282
+ typeof rawLegacySubagentsSection.cleanup_orphaned === 'boolean';
276
283
  if (legacyHasContent) {
277
284
  warnLegacySubagentsSection();
278
285
  }
@@ -291,6 +298,14 @@ async function loadConfig(options) {
291
298
  subagentsConfig.include_in_rules =
292
299
  rawLegacySubagentsSection.include_in_rules;
293
300
  }
301
+ if (typeof agentsSection.cleanup_orphaned === 'boolean') {
302
+ subagentsConfig.cleanup_orphaned =
303
+ agentsSection.cleanup_orphaned;
304
+ }
305
+ else if (typeof rawLegacySubagentsSection.cleanup_orphaned === 'boolean') {
306
+ subagentsConfig.cleanup_orphaned =
307
+ rawLegacySubagentsSection.cleanup_orphaned;
308
+ }
294
309
  const nestedDefined = typeof raw.nested === 'boolean';
295
310
  const nested = nestedDefined ? raw.nested : false;
296
311
  return {
@@ -62,16 +62,13 @@ async function discoverSubagents(projectRoot) {
62
62
  catch {
63
63
  return { subagents: [], warnings: [] };
64
64
  }
65
- const entries = await fs.readdir(dir, { withFileTypes: true });
66
- const mdFiles = entries
67
- .filter((entry) => entry.isFile() && entry.name.endsWith('.md'))
68
- .map((entry) => path.join(dir, entry.name))
69
- .sort();
65
+ const mdFiles = await listMarkdownFilesRecursive(dir);
70
66
  const subagents = [];
71
67
  const warnings = [];
72
68
  for (const filePath of mdFiles) {
73
69
  const info = await (0, SubagentsUtils_1.loadSubagentFile)(filePath);
74
70
  if (info.valid) {
71
+ info.sourceRelativePath = path.relative(dir, filePath);
75
72
  subagents.push(info);
76
73
  }
77
74
  else if (info.error) {
@@ -80,6 +77,22 @@ async function discoverSubagents(projectRoot) {
80
77
  }
81
78
  return { subagents, warnings };
82
79
  }
80
+ async function listMarkdownFilesRecursive(dir) {
81
+ const results = [];
82
+ const entries = await fs.readdir(dir, { withFileTypes: true });
83
+ for (const entry of entries) {
84
+ const fullPath = path.join(dir, entry.name);
85
+ if (entry.isDirectory()) {
86
+ const nested = await listMarkdownFilesRecursive(fullPath);
87
+ results.push(...nested);
88
+ continue;
89
+ }
90
+ if (entry.isFile() && entry.name.endsWith('.md')) {
91
+ results.push(fullPath);
92
+ }
93
+ }
94
+ return results.sort();
95
+ }
83
96
  const SUBAGENT_TARGET_TO_IDENTIFIERS = new Map([
84
97
  ['claude', ['claude']],
85
98
  ['cursor', ['cursor']],
@@ -167,7 +180,9 @@ async function writeAgentsDirectoryAtomic(targetDir, files) {
167
180
  await fs.mkdir(tempDir, { recursive: true });
168
181
  try {
169
182
  for (const { name, content } of files) {
170
- await fs.writeFile(path.join(tempDir, name), content, 'utf8');
183
+ const outputPath = path.join(tempDir, name);
184
+ await fs.mkdir(path.dirname(outputPath), { recursive: true });
185
+ await fs.writeFile(outputPath, content, 'utf8');
171
186
  }
172
187
  try {
173
188
  await fs.rm(targetDir, { recursive: true, force: true });
@@ -187,6 +202,19 @@ async function writeAgentsDirectoryAtomic(targetDir, files) {
187
202
  throw error;
188
203
  }
189
204
  }
205
+ function getSourceRelativeMdPath(sub) {
206
+ const fromSource = sub.sourceRelativePath;
207
+ if (typeof fromSource === 'string' &&
208
+ fromSource.length > 0 &&
209
+ !path.isAbsolute(fromSource) &&
210
+ !fromSource.startsWith('..')) {
211
+ return fromSource;
212
+ }
213
+ return `${sub.name}.md`;
214
+ }
215
+ function withExtension(filePath, ext) {
216
+ return filePath.replace(/\.md$/i, ext);
217
+ }
190
218
  function buildClaudeFile(sub) {
191
219
  const fm = sub.frontmatter;
192
220
  const meta = {
@@ -276,10 +304,10 @@ async function propagateSubagentsForClaude(projectRoot, subagents, options) {
276
304
  return [];
277
305
  const targetDir = path.join(projectRoot, constants_1.CLAUDE_SUBAGENTS_PATH);
278
306
  if (options.dryRun) {
279
- return subagents.map((s) => `Write ${path.join(constants_1.CLAUDE_SUBAGENTS_PATH, `${s.name}.md`)}`);
307
+ return subagents.map((s) => `Write ${path.join(constants_1.CLAUDE_SUBAGENTS_PATH, getSourceRelativeMdPath(s))}`);
280
308
  }
281
309
  const files = subagents.map((s) => ({
282
- name: `${s.name}.md`,
310
+ name: getSourceRelativeMdPath(s),
283
311
  content: buildClaudeFile(s),
284
312
  }));
285
313
  await writeAgentsDirectoryAtomic(targetDir, files);
@@ -290,10 +318,10 @@ async function propagateSubagentsForCursor(projectRoot, subagents, options) {
290
318
  return [];
291
319
  const targetDir = path.join(projectRoot, constants_1.CURSOR_SUBAGENTS_PATH);
292
320
  if (options.dryRun) {
293
- return subagents.map((s) => `Write ${path.join(constants_1.CURSOR_SUBAGENTS_PATH, `${s.name}.md`)}`);
321
+ return subagents.map((s) => `Write ${path.join(constants_1.CURSOR_SUBAGENTS_PATH, getSourceRelativeMdPath(s))}`);
294
322
  }
295
323
  const files = subagents.map((s) => ({
296
- name: `${s.name}.md`,
324
+ name: getSourceRelativeMdPath(s),
297
325
  content: buildCursorFile(s),
298
326
  }));
299
327
  await writeAgentsDirectoryAtomic(targetDir, files);
@@ -304,10 +332,10 @@ async function propagateSubagentsForCodex(projectRoot, subagents, options) {
304
332
  return [];
305
333
  const targetDir = path.join(projectRoot, constants_1.CODEX_SUBAGENTS_PATH);
306
334
  if (options.dryRun) {
307
- return subagents.map((s) => `Write ${path.join(constants_1.CODEX_SUBAGENTS_PATH, `${s.name}.toml`)}`);
335
+ return subagents.map((s) => `Write ${path.join(constants_1.CODEX_SUBAGENTS_PATH, withExtension(getSourceRelativeMdPath(s), '.toml'))}`);
308
336
  }
309
337
  const files = subagents.map((s) => ({
310
- name: `${s.name}.toml`,
338
+ name: withExtension(getSourceRelativeMdPath(s), '.toml'),
311
339
  content: buildCodexFile(s),
312
340
  }));
313
341
  await writeAgentsDirectoryAtomic(targetDir, files);
@@ -325,12 +353,12 @@ async function propagateSubagentsForCopilot(projectRoot, subagents, options) {
325
353
  // emits when dryRun is true so users previewing a change can see
326
354
  // which tools would be dropped before it actually happens.
327
355
  buildCopilotFile(s, true, verbose);
328
- planLines.push(`Write ${path.join(constants_1.COPILOT_SUBAGENTS_PATH, `${s.name}.md`)}`);
356
+ planLines.push(`Write ${path.join(constants_1.COPILOT_SUBAGENTS_PATH, getSourceRelativeMdPath(s))}`);
329
357
  }
330
358
  return planLines;
331
359
  }
332
360
  const files = subagents.map((s) => ({
333
- name: `${s.name}.md`,
361
+ name: getSourceRelativeMdPath(s),
334
362
  content: buildCopilotFile(s, false, verbose).content,
335
363
  }));
336
364
  await writeAgentsDirectoryAtomic(targetDir, files);
@@ -363,10 +391,24 @@ async function cleanupAllSubagentsDirectories(projectRoot, dryRun, verbose) {
363
391
  /* ------------------------------------------------------------------ */
364
392
  /* Orchestrator */
365
393
  /* ------------------------------------------------------------------ */
366
- async function propagateSubagents(projectRoot, agents, subagentsEnabled, verbose, dryRun) {
367
- if (!subagentsEnabled) {
368
- (0, constants_1.logVerboseInfo)('Subagents support disabled, cleaning up subagent directories', verbose, dryRun);
394
+ async function propagateSubagents(projectRoot, agents, subagentsEnabled, cleanupOrphaned, verbose, dryRun) {
395
+ const maybeCleanupAllSubagentsDirectories = async () => {
396
+ if (!cleanupOrphaned) {
397
+ (0, constants_1.logVerboseInfo)('Subagent cleanup skipped (set [agents] cleanup_orphaned = true to enable directory cleanup)', verbose, dryRun);
398
+ return;
399
+ }
369
400
  await cleanupAllSubagentsDirectories(projectRoot, dryRun, verbose);
401
+ };
402
+ const maybeCleanupSubagentsDir = async (relPath) => {
403
+ if (!cleanupOrphaned)
404
+ return;
405
+ await cleanupSubagentsDir(projectRoot, relPath, dryRun, verbose);
406
+ };
407
+ if (!subagentsEnabled) {
408
+ (0, constants_1.logVerboseInfo)(cleanupOrphaned
409
+ ? 'Subagents support disabled, cleaning up subagent directories'
410
+ : 'Subagents support disabled, leaving existing subagent directories unchanged', verbose, dryRun);
411
+ await maybeCleanupAllSubagentsDirectories();
370
412
  return;
371
413
  }
372
414
  const sourceDir = path.join(projectRoot, constants_1.RULER_SUBAGENTS_PATH);
@@ -374,16 +416,20 @@ async function propagateSubagents(projectRoot, agents, subagentsEnabled, verbose
374
416
  await fs.access(sourceDir);
375
417
  }
376
418
  catch {
377
- (0, constants_1.logVerboseInfo)('No .ruler/agents directory found, cleaning up any stale managed subagent directories', verbose, dryRun);
378
- await cleanupAllSubagentsDirectories(projectRoot, dryRun, verbose);
419
+ (0, constants_1.logVerboseInfo)(cleanupOrphaned
420
+ ? 'No .ruler/agents directory found, cleaning up any stale managed subagent directories'
421
+ : 'No .ruler/agents directory found; leaving existing subagent directories unchanged', verbose, dryRun);
422
+ await maybeCleanupAllSubagentsDirectories();
379
423
  return;
380
424
  }
381
425
  const { subagents, warnings } = await discoverSubagents(projectRoot);
382
426
  for (const w of warnings)
383
427
  (0, constants_1.logWarn)(w, dryRun);
384
428
  if (subagents.length === 0) {
385
- (0, constants_1.logVerboseInfo)('No valid subagents found in .ruler/agents; cleaning up any stale managed subagent directories', verbose, dryRun);
386
- await cleanupAllSubagentsDirectories(projectRoot, dryRun, verbose);
429
+ (0, constants_1.logVerboseInfo)(cleanupOrphaned
430
+ ? 'No valid subagents found in .ruler/agents; cleaning up any stale managed subagent directories'
431
+ : 'No valid subagents found in .ruler/agents; leaving existing subagent directories unchanged', verbose, dryRun);
432
+ await maybeCleanupAllSubagentsDirectories();
387
433
  return;
388
434
  }
389
435
  (0, constants_1.logVerboseInfo)(`Discovered ${subagents.length} subagent(s)`, verbose, dryRun);
@@ -401,7 +447,7 @@ async function propagateSubagents(projectRoot, agents, subagentsEnabled, verbose
401
447
  const allTargets = ['claude', 'cursor', 'codex', 'copilot'];
402
448
  for (const target of allTargets) {
403
449
  if (!targets.has(target)) {
404
- await cleanupSubagentsDir(projectRoot, SUBAGENT_TARGET_PATHS[target], dryRun, verbose);
450
+ await maybeCleanupSubagentsDir(SUBAGENT_TARGET_PATHS[target]);
405
451
  }
406
452
  }
407
453
  if (supporting.length === 0) {
package/dist/lib.js CHANGED
@@ -70,6 +70,9 @@ function resolveSubagentsEnabled(cliFlag, configSetting) {
70
70
  ? configSetting
71
71
  : false; // default to disabled — see spec: subagents must opt in
72
72
  }
73
+ function resolveSubagentsCleanupOrphaned(configSetting) {
74
+ return configSetting === true;
75
+ }
73
76
  /**
74
77
  * Applies ruler configurations for all supported AI agents.
75
78
  * @param projectRoot Root directory of the project
@@ -119,12 +122,13 @@ async function applyAllAgentConfigs(projectRoot, includedAgents, configPath, cli
119
122
  }
120
123
  // Propagate subagents (mirrors skills handling for nested mode).
121
124
  const subagentsEnabledResolved = resolveSubagentsEnabled(subagentsEnabled, rootConfig.subagents?.enabled);
125
+ const subagentsCleanupOrphaned = resolveSubagentsCleanupOrphaned(rootConfig.subagents?.cleanup_orphaned);
122
126
  {
123
127
  const { propagateSubagents } = await Promise.resolve().then(() => __importStar(require('./core/SubagentsProcessor')));
124
128
  for (const configEntry of hierarchicalConfigs) {
125
129
  const nestedRoot = path.dirname(configEntry.rulerDir);
126
130
  (0, constants_1.logVerbose)(`Propagating subagents for nested directory: ${nestedRoot}`, verbose);
127
- await propagateSubagents(nestedRoot, selectedAgents, subagentsEnabledResolved, verbose, dryRun);
131
+ await propagateSubagents(nestedRoot, selectedAgents, subagentsEnabledResolved, subagentsCleanupOrphaned, verbose, dryRun);
128
132
  }
129
133
  }
130
134
  generatedPaths = await (0, apply_engine_1.processHierarchicalConfigurations)(selectedAgents, hierarchicalConfigs, verbose, dryRun, cliMcpEnabled, cliMcpStrategy, backup);
@@ -146,9 +150,10 @@ async function applyAllAgentConfigs(projectRoot, includedAgents, configPath, cli
146
150
  }
147
151
  // Propagate subagents (mirrors skills handling).
148
152
  const subagentsEnabledResolvedSingle = resolveSubagentsEnabled(subagentsEnabled, singleConfig.config.subagents?.enabled);
153
+ const subagentsCleanupOrphanedSingle = resolveSubagentsCleanupOrphaned(singleConfig.config.subagents?.cleanup_orphaned);
149
154
  {
150
155
  const { propagateSubagents } = await Promise.resolve().then(() => __importStar(require('./core/SubagentsProcessor')));
151
- await propagateSubagents(projectRoot, selectedAgents, subagentsEnabledResolvedSingle, verbose, dryRun);
156
+ await propagateSubagents(projectRoot, selectedAgents, subagentsEnabledResolvedSingle, subagentsCleanupOrphanedSingle, verbose, dryRun);
152
157
  }
153
158
  generatedPaths = await (0, apply_engine_1.processSingleConfiguration)(selectedAgents, singleConfig, projectRoot, verbose, dryRun, cliMcpEnabled, cliMcpStrategy, backup);
154
159
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@intellectronica/ruler",
3
- "version": "0.3.40",
3
+ "version": "0.3.41",
4
4
  "description": "Ruler — apply the same rules to all coding agents",
5
5
  "main": "dist/lib.js",
6
6
  "scripts": {
@@ -58,6 +58,7 @@
58
58
  "eslint-config-prettier": "^10.1.8",
59
59
  "eslint-plugin-prettier": "^5.5.4",
60
60
  "jest": "^29.7.0",
61
+ "jest-util": "^29.7.0",
61
62
  "prettier": "^3.6.2",
62
63
  "ts-jest": "^29.4.5",
63
64
  "typescript": "^5.9.3",