@intellectronica/ruler 0.3.35 → 0.3.37

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
@@ -73,7 +73,7 @@ Ruler solves this by providing a **single source of truth** for all your AI agen
73
73
  | Firebase Studio | `.idx/airules.md` | `.idx/mcp.json` | - |
74
74
  | Open Hands | `.openhands/microagents/repo.md` | `config.toml` | - |
75
75
  | Gemini CLI | `AGENTS.md` | `.gemini/settings.json` | `.gemini/skills/` |
76
- | Junie | `.junie/guidelines.md` | - | - |
76
+ | Junie | `.junie/guidelines.md` | `.junie/mcp/mcp.json` | `.junie/skills/` |
77
77
  | AugmentCode | `.augment/rules/ruler_augment_instructions.md` | - | - |
78
78
  | Kilo Code | `AGENTS.md` | `.kilocode/mcp.json` | `.claude/skills/` |
79
79
  | OpenCode | `AGENTS.md` | `opencode.json` | `.opencode/skills/` |
@@ -325,15 +325,15 @@ ruler revert [options]
325
325
 
326
326
  ### Options
327
327
 
328
- | Option | Description |
329
- | ------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
330
- | `--project-root <path>` | Path to your project's root (default: current directory) |
331
- | `--agents <agent1,agent2,...>` | Comma-separated list of agent names to revert (agentsmd, aider, amazonqcli, amp, antigravity, augmentcode, claude, cline, codex, copilot, crush, cursor, factory, firebase, firebender, gemini-cli, goose, jules, junie, kilocode, kiro, mistral, opencode, openhands, pi, qwen, roo, trae, warp, windsurf, zed) |
332
- | `--config <path>` | Path to a custom `ruler.toml` configuration file |
333
- | `--keep-backups` | Keep backup files (.bak) after restoration (default: false) |
334
- | `--dry-run` | Preview changes without actually reverting files |
335
- | `--verbose` / `-v` | Display detailed output during execution |
336
- | `--local-only` | Only search for local .ruler directories, ignore global config |
328
+ | Option | Description |
329
+ | ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
330
+ | `--project-root <path>` | Path to your project's root (default: current directory) |
331
+ | `--agents <agent1,agent2,...>` | Comma-separated list of agent names to revert (agentsmd, aider, amazonqcli, amp, antigravity, augmentcode, claude, cline, codex, copilot, crush, cursor, factory, firebase, firebender, gemini-cli, goose, jetbrains-ai, jules, junie, kilocode, kiro, mistral, opencode, openhands, pi, qwen, roo, trae, warp, windsurf, zed) |
332
+ | `--config <path>` | Path to a custom `ruler.toml` configuration file |
333
+ | `--keep-backups` | Keep backup files (.bak) after restoration (default: false) |
334
+ | `--dry-run` | Preview changes without actually reverting files |
335
+ | `--verbose` / `-v` | Display detailed output during execution |
336
+ | `--local-only` | Only search for local .ruler directories, ignore global config |
337
337
 
338
338
  ### Common Examples
339
339
 
@@ -447,6 +447,10 @@ enabled = true
447
447
  enabled = true
448
448
  output_path = ".junie/guidelines.md"
449
449
 
450
+ [agents.junie.mcp]
451
+ enabled = true
452
+ merge_strategy = "merge"
453
+
450
454
  # Agent-specific MCP configuration
451
455
  [agents.cursor.mcp]
452
456
  enabled = true
@@ -590,6 +594,7 @@ Skills are specialized knowledge packages that extend AI agent capabilities with
590
594
  - **Mistral Vibe**: `.vibe/skills/`
591
595
  - **Roo Code**: `.roo/skills/`
592
596
  - **Gemini CLI**: `.gemini/skills/`
597
+ - **Junie**: `.junie/skills/`
593
598
  - **Cursor**: `.cursor/skills/`
594
599
 
595
600
  ### Skills Directory Structure
@@ -655,13 +660,14 @@ When skills support is enabled and gitignore integration is active, Ruler automa
655
660
  - `.vibe/skills/` (for Mistral Vibe)
656
661
  - `.roo/skills/` (for Roo Code)
657
662
  - `.gemini/skills/` (for Gemini CLI)
663
+ - `.junie/skills/` (for Junie)
658
664
  - `.cursor/skills/` (for Cursor)
659
665
 
660
666
  to your `.gitignore` file within the managed Ruler block.
661
667
 
662
668
  ### Requirements
663
669
 
664
- - **For agents with native skills support** (Claude Code, GitHub Copilot, Kilo Code, OpenAI Codex CLI, OpenCode, Pi Coding Agent, Goose, Amp, Antigravity, Factory Droid, Mistral Vibe, Roo Code, Gemini CLI, Cursor): No additional requirements.
670
+ - **For agents with native skills support** (Claude Code, GitHub Copilot, Kilo Code, OpenAI Codex CLI, OpenCode, Pi Coding Agent, Goose, Amp, Antigravity, Factory Droid, Mistral Vibe, Roo Code, Gemini CLI, Junie, Cursor): No additional requirements.
665
671
 
666
672
  ### Validation
667
673
 
@@ -714,6 +720,7 @@ ruler apply
714
720
  # - Mistral Vibe: .vibe/skills/my-skill/
715
721
  # - Roo Code: .roo/skills/my-skill/
716
722
  # - Gemini CLI: .gemini/skills/my-skill/
723
+ # - Junie: .junie/skills/my-skill/
717
724
  # - Cursor: .cursor/skills/my-skill/
718
725
  ```
719
726
 
@@ -49,5 +49,14 @@ class JunieAgent extends AbstractAgent_1.AbstractAgent {
49
49
  getDefaultOutputPath(projectRoot) {
50
50
  return path.join(projectRoot, '.junie', 'guidelines.md');
51
51
  }
52
+ supportsMcpStdio() {
53
+ return true;
54
+ }
55
+ supportsMcpRemote() {
56
+ return true;
57
+ }
58
+ supportsNativeSkills() {
59
+ return true;
60
+ }
52
61
  }
53
62
  exports.JunieAgent = JunieAgent;
package/dist/constants.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.SKILL_MD_FILENAME = exports.ANTIGRAVITY_SKILLS_PATH = exports.FACTORY_SKILLS_PATH = exports.CURSOR_SKILLS_PATH = exports.GEMINI_SKILLS_PATH = exports.ROO_SKILLS_PATH = exports.VIBE_SKILLS_PATH = exports.GOOSE_SKILLS_PATH = exports.PI_SKILLS_PATH = exports.OPENCODE_SKILLS_PATH = exports.CODEX_SKILLS_PATH = exports.CLAUDE_SKILLS_PATH = exports.RULER_SKILLS_PATH = exports.SKILLS_DIR = exports.DEFAULT_RULES_FILENAME = exports.ERROR_PREFIX = void 0;
3
+ exports.SKILL_MD_FILENAME = exports.ANTIGRAVITY_SKILLS_PATH = exports.FACTORY_SKILLS_PATH = exports.CURSOR_SKILLS_PATH = exports.JUNIE_SKILLS_PATH = exports.GEMINI_SKILLS_PATH = exports.ROO_SKILLS_PATH = exports.VIBE_SKILLS_PATH = exports.GOOSE_SKILLS_PATH = exports.PI_SKILLS_PATH = exports.OPENCODE_SKILLS_PATH = exports.CODEX_SKILLS_PATH = exports.CLAUDE_SKILLS_PATH = exports.RULER_SKILLS_PATH = exports.SKILLS_DIR = exports.DEFAULT_RULES_FILENAME = exports.ERROR_PREFIX = void 0;
4
4
  exports.actionPrefix = actionPrefix;
5
5
  exports.createRulerError = createRulerError;
6
6
  exports.logVerbose = logVerbose;
@@ -60,6 +60,7 @@ exports.GOOSE_SKILLS_PATH = '.agents/skills';
60
60
  exports.VIBE_SKILLS_PATH = '.vibe/skills';
61
61
  exports.ROO_SKILLS_PATH = '.roo/skills';
62
62
  exports.GEMINI_SKILLS_PATH = '.gemini/skills';
63
+ exports.JUNIE_SKILLS_PATH = '.junie/skills';
63
64
  exports.CURSOR_SKILLS_PATH = '.cursor/skills';
64
65
  exports.FACTORY_SKILLS_PATH = '.factory/skills';
65
66
  exports.ANTIGRAVITY_SKILLS_PATH = '.agent/skills';
@@ -44,6 +44,7 @@ exports.propagateSkillsForGoose = propagateSkillsForGoose;
44
44
  exports.propagateSkillsForVibe = propagateSkillsForVibe;
45
45
  exports.propagateSkillsForRoo = propagateSkillsForRoo;
46
46
  exports.propagateSkillsForGemini = propagateSkillsForGemini;
47
+ exports.propagateSkillsForJunie = propagateSkillsForJunie;
47
48
  exports.propagateSkillsForCursor = propagateSkillsForCursor;
48
49
  exports.propagateSkillsForFactory = propagateSkillsForFactory;
49
50
  exports.propagateSkillsForAntigravity = propagateSkillsForAntigravity;
@@ -82,7 +83,7 @@ async function getSkillsGitignorePaths(projectRoot, agents) {
82
83
  return [];
83
84
  }
84
85
  // Import here to avoid circular dependency
85
- const { CLAUDE_SKILLS_PATH, CODEX_SKILLS_PATH, OPENCODE_SKILLS_PATH, PI_SKILLS_PATH, GOOSE_SKILLS_PATH, VIBE_SKILLS_PATH, ROO_SKILLS_PATH, GEMINI_SKILLS_PATH, CURSOR_SKILLS_PATH, FACTORY_SKILLS_PATH, ANTIGRAVITY_SKILLS_PATH, } = await Promise.resolve().then(() => __importStar(require('../constants')));
86
+ const { CLAUDE_SKILLS_PATH, CODEX_SKILLS_PATH, OPENCODE_SKILLS_PATH, PI_SKILLS_PATH, GOOSE_SKILLS_PATH, VIBE_SKILLS_PATH, ROO_SKILLS_PATH, GEMINI_SKILLS_PATH, JUNIE_SKILLS_PATH, CURSOR_SKILLS_PATH, FACTORY_SKILLS_PATH, ANTIGRAVITY_SKILLS_PATH, } = await Promise.resolve().then(() => __importStar(require('../constants')));
86
87
  const selectedTargets = getSelectedSkillTargets(agents);
87
88
  const targetPaths = {
88
89
  claude: CLAUDE_SKILLS_PATH,
@@ -93,6 +94,7 @@ async function getSkillsGitignorePaths(projectRoot, agents) {
93
94
  vibe: VIBE_SKILLS_PATH,
94
95
  roo: ROO_SKILLS_PATH,
95
96
  gemini: GEMINI_SKILLS_PATH,
97
+ junie: JUNIE_SKILLS_PATH,
96
98
  cursor: CURSOR_SKILLS_PATH,
97
99
  factory: FACTORY_SKILLS_PATH,
98
100
  antigravity: ANTIGRAVITY_SKILLS_PATH,
@@ -126,6 +128,7 @@ const SKILL_TARGET_TO_IDENTIFIERS = new Map([
126
128
  ['vibe', ['mistral']],
127
129
  ['roo', ['roo']],
128
130
  ['gemini', ['gemini-cli']],
131
+ ['junie', ['junie']],
129
132
  ['cursor', ['cursor']],
130
133
  ['factory', ['factory']],
131
134
  ['antigravity', ['antigravity']],
@@ -155,6 +158,7 @@ async function cleanupSkillsDirectories(projectRoot, dryRun, verbose) {
155
158
  const vibeSkillsPath = path.join(projectRoot, constants_1.VIBE_SKILLS_PATH);
156
159
  const rooSkillsPath = path.join(projectRoot, constants_1.ROO_SKILLS_PATH);
157
160
  const geminiSkillsPath = path.join(projectRoot, constants_1.GEMINI_SKILLS_PATH);
161
+ const junieSkillsPath = path.join(projectRoot, constants_1.JUNIE_SKILLS_PATH);
158
162
  const cursorSkillsPath = path.join(projectRoot, constants_1.CURSOR_SKILLS_PATH);
159
163
  const factorySkillsPath = path.join(projectRoot, constants_1.FACTORY_SKILLS_PATH);
160
164
  const antigravitySkillsPath = path.join(projectRoot, constants_1.ANTIGRAVITY_SKILLS_PATH);
@@ -270,6 +274,20 @@ async function cleanupSkillsDirectories(projectRoot, dryRun, verbose) {
270
274
  catch {
271
275
  // Directory doesn't exist, nothing to clean
272
276
  }
277
+ // Clean up .junie/skills
278
+ try {
279
+ await fs.access(junieSkillsPath);
280
+ if (dryRun) {
281
+ (0, constants_1.logVerboseInfo)(`DRY RUN: Would remove ${constants_1.JUNIE_SKILLS_PATH}`, verbose, dryRun);
282
+ }
283
+ else {
284
+ await fs.rm(junieSkillsPath, { recursive: true, force: true });
285
+ (0, constants_1.logVerboseInfo)(`Removed ${constants_1.JUNIE_SKILLS_PATH} (skills disabled)`, verbose, dryRun);
286
+ }
287
+ }
288
+ catch {
289
+ // Directory doesn't exist, nothing to clean
290
+ }
273
291
  // Clean up .cursor/skills
274
292
  try {
275
293
  await fs.access(cursorSkillsPath);
@@ -395,6 +413,10 @@ async function propagateSkills(projectRoot, agents, skillsEnabled, verbose, dryR
395
413
  (0, constants_1.logVerboseInfo)(`Copying skills to ${constants_1.GEMINI_SKILLS_PATH} for Gemini CLI`, verbose, dryRun);
396
414
  await propagateSkillsForGemini(projectRoot, { dryRun });
397
415
  }
416
+ if (selectedTargets.has('junie')) {
417
+ (0, constants_1.logVerboseInfo)(`Copying skills to ${constants_1.JUNIE_SKILLS_PATH} for Junie`, verbose, dryRun);
418
+ await propagateSkillsForJunie(projectRoot, { dryRun });
419
+ }
398
420
  if (selectedTargets.has('cursor')) {
399
421
  (0, constants_1.logVerboseInfo)(`Copying skills to ${constants_1.CURSOR_SKILLS_PATH} for Cursor`, verbose, dryRun);
400
422
  await propagateSkillsForCursor(projectRoot, { dryRun });
@@ -809,6 +831,47 @@ async function propagateSkillsForGemini(projectRoot, options) {
809
831
  }
810
832
  return [];
811
833
  }
834
+ /**
835
+ * Propagates skills for Junie by copying .ruler/skills to .junie/skills.
836
+ * Uses atomic replace to ensure safe overwriting of existing skills.
837
+ * Returns dry-run steps if dryRun is true, otherwise returns empty array.
838
+ */
839
+ async function propagateSkillsForJunie(projectRoot, options) {
840
+ const skillsDir = path.join(projectRoot, constants_1.RULER_SKILLS_PATH);
841
+ const junieSkillsPath = path.join(projectRoot, constants_1.JUNIE_SKILLS_PATH);
842
+ const junieDir = path.dirname(junieSkillsPath);
843
+ try {
844
+ await fs.access(skillsDir);
845
+ }
846
+ catch {
847
+ return [];
848
+ }
849
+ if (options.dryRun) {
850
+ return [`Copy skills from ${constants_1.RULER_SKILLS_PATH} to ${constants_1.JUNIE_SKILLS_PATH}`];
851
+ }
852
+ await fs.mkdir(junieDir, { recursive: true });
853
+ const tempDir = path.join(junieDir, `skills.tmp-${Date.now()}`);
854
+ try {
855
+ await (0, SkillsUtils_1.copySkillsDirectory)(skillsDir, tempDir);
856
+ try {
857
+ await fs.rm(junieSkillsPath, { recursive: true, force: true });
858
+ }
859
+ catch {
860
+ // Target didn't exist, that's fine
861
+ }
862
+ await fs.rename(tempDir, junieSkillsPath);
863
+ }
864
+ catch (error) {
865
+ try {
866
+ await fs.rm(tempDir, { recursive: true, force: true });
867
+ }
868
+ catch {
869
+ // Ignore cleanup errors
870
+ }
871
+ throw error;
872
+ }
873
+ return [];
874
+ }
812
875
  /**
813
876
  * Propagates skills for Cursor by copying .ruler/skills to .cursor/skills.
814
877
  * Uses atomic replace to ensure safe overwriting of existing skills.
@@ -247,6 +247,7 @@ async function removeAdditionalAgentFiles(projectRoot, verbose, dryRun) {
247
247
  '.mcp.json',
248
248
  '.vscode/mcp.json',
249
249
  '.cursor/mcp.json',
250
+ '.junie/mcp/mcp.json',
250
251
  '.kilocode/mcp.json',
251
252
  'config.toml',
252
253
  ];
package/dist/paths/mcp.js CHANGED
@@ -71,6 +71,9 @@ async function getNativeMcpPath(adapterName, projectRoot) {
71
71
  case 'Gemini CLI':
72
72
  candidates.push(path.join(projectRoot, '.gemini', 'settings.json'));
73
73
  break;
74
+ case 'Junie':
75
+ candidates.push(path.join(projectRoot, '.junie', 'mcp', 'mcp.json'));
76
+ break;
74
77
  case 'Qwen Code':
75
78
  candidates.push(path.join(projectRoot, '.qwen', 'settings.json'));
76
79
  break;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@intellectronica/ruler",
3
- "version": "0.3.35",
3
+ "version": "0.3.37",
4
4
  "description": "Ruler — apply the same rules to all coding agents",
5
5
  "main": "dist/lib.js",
6
6
  "scripts": {