@intellectronica/ruler 0.3.40 → 0.3.42
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 +59 -46
- package/dist/agents/AbstractAgent.d.ts +53 -0
- package/dist/agents/AgentsMdAgent.d.ts +14 -0
- package/dist/agents/AiderAgent.d.ts +14 -0
- package/dist/agents/AiderAgent.js +3 -1
- package/dist/agents/AmazonQCliAgent.d.ts +13 -0
- package/dist/agents/AmpAgent.d.ts +6 -0
- package/dist/agents/AntigravityAgent.d.ts +10 -0
- package/dist/agents/AugmentCodeAgent.d.ts +13 -0
- package/dist/agents/ClaudeAgent.d.ts +13 -0
- package/dist/agents/ClineAgent.d.ts +9 -0
- package/dist/agents/CodexCliAgent.d.ts +31 -0
- package/dist/agents/CopilotAgent.d.ts +20 -0
- package/dist/agents/CrushAgent.d.ts +14 -0
- package/dist/agents/CrushAgent.js +5 -2
- package/dist/agents/CursorAgent.d.ts +17 -0
- package/dist/agents/FactoryDroidAgent.d.ts +13 -0
- package/dist/agents/FirebaseAgent.d.ts +11 -0
- package/dist/agents/FirebenderAgent.d.ts +36 -0
- package/dist/agents/GeminiCliAgent.d.ts +11 -0
- package/dist/agents/GeminiCliAgent.js +2 -2
- package/dist/agents/GooseAgent.d.ts +12 -0
- package/dist/agents/IAgent.d.ts +72 -0
- package/dist/agents/JetBrainsAiAssistantAgent.d.ts +10 -0
- package/dist/agents/JulesAgent.d.ts +5 -0
- package/dist/agents/JunieAgent.d.ts +12 -0
- package/dist/agents/KiloCodeAgent.d.ts +14 -0
- package/dist/agents/KiroAgent.d.ts +8 -0
- package/dist/agents/MistralVibeAgent.d.ts +31 -0
- package/dist/agents/OpenCodeAgent.d.ts +11 -0
- package/dist/agents/OpenCodeAgent.js +14 -9
- package/dist/agents/OpenHandsAgent.d.ts +8 -0
- package/dist/agents/PiAgent.d.ts +9 -0
- package/dist/agents/QwenCodeAgent.d.ts +10 -0
- package/dist/agents/QwenCodeAgent.js +2 -2
- package/dist/agents/RooCodeAgent.d.ts +16 -0
- package/dist/agents/TraeAgent.d.ts +10 -0
- package/dist/agents/WarpAgent.d.ts +12 -0
- package/dist/agents/WindsurfAgent.d.ts +13 -0
- package/dist/agents/ZedAgent.d.ts +21 -0
- package/dist/agents/ZedAgent.js +5 -2
- package/dist/agents/agent-utils.d.ts +5 -0
- package/dist/agents/agent-utils.js +8 -5
- package/dist/agents/index.d.ts +9 -0
- package/dist/cli/commands.d.ts +4 -0
- package/dist/cli/commands.js +2 -3
- package/dist/cli/handlers.d.ts +41 -0
- package/dist/cli/handlers.js +76 -60
- package/dist/cli/index.d.ts +2 -0
- package/dist/constants.d.ts +35 -0
- package/dist/core/ConfigLoader.d.ts +57 -0
- package/dist/core/ConfigLoader.js +123 -41
- package/dist/core/FileSystemUtils.d.ts +51 -0
- package/dist/core/FileSystemUtils.js +37 -17
- package/dist/core/GitignoreUtils.d.ts +15 -0
- package/dist/core/GitignoreUtils.js +32 -1
- package/dist/core/RuleProcessor.d.ts +8 -0
- package/dist/core/SkillsProcessor.d.ts +127 -0
- package/dist/core/SkillsProcessor.js +104 -218
- package/dist/core/SkillsUtils.d.ts +26 -0
- package/dist/core/SubagentsProcessor.d.ts +38 -0
- package/dist/core/SubagentsProcessor.js +68 -22
- package/dist/core/SubagentsUtils.d.ts +34 -0
- package/dist/core/UnifiedConfigLoader.d.ts +10 -0
- package/dist/core/UnifiedConfigLoader.js +61 -31
- package/dist/core/UnifiedConfigTypes.d.ts +95 -0
- package/dist/core/agent-selection.d.ts +12 -0
- package/dist/core/agent-selection.js +11 -3
- package/dist/core/apply-engine.d.ts +69 -0
- package/dist/core/apply-engine.js +57 -50
- package/dist/core/config-utils.d.ts +14 -0
- package/dist/core/config-utils.js +9 -3
- package/dist/core/hash.d.ts +2 -0
- package/dist/core/path-utils.d.ts +1 -0
- package/dist/core/path-utils.js +42 -0
- package/dist/core/revert-engine.d.ts +36 -0
- package/dist/core/revert-engine.js +70 -9
- package/dist/lib.d.ts +13 -0
- package/dist/lib.js +23 -5
- package/dist/mcp/capabilities.d.ts +20 -0
- package/dist/mcp/merge.d.ts +10 -0
- package/dist/mcp/merge.js +19 -1
- package/dist/mcp/propagateOpenCodeMcp.d.ts +2 -0
- package/dist/mcp/propagateOpenCodeMcp.js +21 -9
- package/dist/mcp/propagateOpenHandsMcp.d.ts +2 -0
- package/dist/mcp/propagateOpenHandsMcp.js +31 -15
- package/dist/mcp/validate.d.ts +7 -0
- package/dist/mcp/validate.js +6 -1
- package/dist/paths/mcp.d.ts +8 -0
- package/dist/paths/mcp.js +33 -4
- package/dist/revert.d.ts +6 -0
- package/dist/revert.js +39 -27
- package/dist/types.d.ts +87 -0
- package/dist/vscode/settings.d.ts +40 -0
- package/package.json +7 -4
|
@@ -35,6 +35,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.discoverSkills = discoverSkills;
|
|
37
37
|
exports.getSkillsGitignorePaths = getSkillsGitignorePaths;
|
|
38
|
+
exports.replaceSkillsDirectory = replaceSkillsDirectory;
|
|
38
39
|
exports.propagateSkills = propagateSkills;
|
|
39
40
|
exports.propagateSkillsForClaude = propagateSkillsForClaude;
|
|
40
41
|
exports.propagateSkillsForCodex = propagateSkillsForCodex;
|
|
@@ -126,7 +127,7 @@ const SKILL_TARGET_TO_IDENTIFIERS = new Map([
|
|
|
126
127
|
['codex', ['codex']],
|
|
127
128
|
['opencode', ['opencode']],
|
|
128
129
|
['pi', ['pi']],
|
|
129
|
-
['goose', ['goose', 'amp']],
|
|
130
|
+
['goose', ['goose', 'amp', 'zed']],
|
|
130
131
|
['vibe', ['mistral']],
|
|
131
132
|
['roo', ['roo']],
|
|
132
133
|
['gemini', ['gemini-cli']],
|
|
@@ -136,6 +137,21 @@ const SKILL_TARGET_TO_IDENTIFIERS = new Map([
|
|
|
136
137
|
['factory', ['factory']],
|
|
137
138
|
['antigravity', ['antigravity']],
|
|
138
139
|
]);
|
|
140
|
+
const SKILL_TARGET_PATHS = [
|
|
141
|
+
constants_1.CLAUDE_SKILLS_PATH,
|
|
142
|
+
constants_1.CODEX_SKILLS_PATH,
|
|
143
|
+
constants_1.OPENCODE_SKILLS_PATH,
|
|
144
|
+
constants_1.PI_SKILLS_PATH,
|
|
145
|
+
constants_1.GOOSE_SKILLS_PATH,
|
|
146
|
+
constants_1.VIBE_SKILLS_PATH,
|
|
147
|
+
constants_1.ROO_SKILLS_PATH,
|
|
148
|
+
constants_1.GEMINI_SKILLS_PATH,
|
|
149
|
+
constants_1.JUNIE_SKILLS_PATH,
|
|
150
|
+
constants_1.CURSOR_SKILLS_PATH,
|
|
151
|
+
constants_1.WINDSURF_SKILLS_PATH,
|
|
152
|
+
constants_1.FACTORY_SKILLS_PATH,
|
|
153
|
+
constants_1.ANTIGRAVITY_SKILLS_PATH,
|
|
154
|
+
];
|
|
139
155
|
function getSelectedSkillTargets(agents) {
|
|
140
156
|
const selectedIdentifiers = new Set(agents
|
|
141
157
|
.filter((agent) => agent.supportsNativeSkills?.())
|
|
@@ -148,205 +164,75 @@ function getSelectedSkillTargets(agents) {
|
|
|
148
164
|
}
|
|
149
165
|
return targets;
|
|
150
166
|
}
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
const
|
|
159
|
-
const piSkillsPath = path.join(projectRoot, constants_1.PI_SKILLS_PATH);
|
|
160
|
-
const gooseSkillsPath = path.join(projectRoot, constants_1.GOOSE_SKILLS_PATH);
|
|
161
|
-
const vibeSkillsPath = path.join(projectRoot, constants_1.VIBE_SKILLS_PATH);
|
|
162
|
-
const rooSkillsPath = path.join(projectRoot, constants_1.ROO_SKILLS_PATH);
|
|
163
|
-
const geminiSkillsPath = path.join(projectRoot, constants_1.GEMINI_SKILLS_PATH);
|
|
164
|
-
const junieSkillsPath = path.join(projectRoot, constants_1.JUNIE_SKILLS_PATH);
|
|
165
|
-
const cursorSkillsPath = path.join(projectRoot, constants_1.CURSOR_SKILLS_PATH);
|
|
166
|
-
const windsurfSkillsPath = path.join(projectRoot, constants_1.WINDSURF_SKILLS_PATH);
|
|
167
|
-
const factorySkillsPath = path.join(projectRoot, constants_1.FACTORY_SKILLS_PATH);
|
|
168
|
-
const antigravitySkillsPath = path.join(projectRoot, constants_1.ANTIGRAVITY_SKILLS_PATH);
|
|
169
|
-
// Clean up .claude/skills
|
|
170
|
-
try {
|
|
171
|
-
await fs.access(claudeSkillsPath);
|
|
172
|
-
if (dryRun) {
|
|
173
|
-
(0, constants_1.logVerboseInfo)(`DRY RUN: Would remove ${constants_1.CLAUDE_SKILLS_PATH}`, verbose, dryRun);
|
|
174
|
-
}
|
|
175
|
-
else {
|
|
176
|
-
await fs.rm(claudeSkillsPath, { recursive: true, force: true });
|
|
177
|
-
(0, constants_1.logVerboseInfo)(`Removed ${constants_1.CLAUDE_SKILLS_PATH} (skills disabled)`, verbose, dryRun);
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
catch {
|
|
181
|
-
// Directory doesn't exist, nothing to clean
|
|
182
|
-
}
|
|
183
|
-
// Clean up .codex/skills
|
|
184
|
-
try {
|
|
185
|
-
await fs.access(codexSkillsPath);
|
|
186
|
-
if (dryRun) {
|
|
187
|
-
(0, constants_1.logVerboseInfo)(`DRY RUN: Would remove ${constants_1.CODEX_SKILLS_PATH}`, verbose, dryRun);
|
|
188
|
-
}
|
|
189
|
-
else {
|
|
190
|
-
await fs.rm(codexSkillsPath, { recursive: true, force: true });
|
|
191
|
-
(0, constants_1.logVerboseInfo)(`Removed ${constants_1.CODEX_SKILLS_PATH} (skills disabled)`, verbose, dryRun);
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
catch {
|
|
195
|
-
// Directory doesn't exist, nothing to clean
|
|
196
|
-
}
|
|
197
|
-
// Clean up .opencode/skills
|
|
198
|
-
try {
|
|
199
|
-
await fs.access(opencodeSkillsPath);
|
|
200
|
-
if (dryRun) {
|
|
201
|
-
(0, constants_1.logVerboseInfo)(`DRY RUN: Would remove ${constants_1.OPENCODE_SKILLS_PATH}`, verbose, dryRun);
|
|
202
|
-
}
|
|
203
|
-
else {
|
|
204
|
-
await fs.rm(opencodeSkillsPath, { recursive: true, force: true });
|
|
205
|
-
(0, constants_1.logVerboseInfo)(`Removed ${constants_1.OPENCODE_SKILLS_PATH} (skills disabled)`, verbose, dryRun);
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
catch {
|
|
209
|
-
// Directory doesn't exist, nothing to clean
|
|
210
|
-
}
|
|
211
|
-
// Clean up .pi/skills
|
|
212
|
-
try {
|
|
213
|
-
await fs.access(piSkillsPath);
|
|
214
|
-
if (dryRun) {
|
|
215
|
-
(0, constants_1.logVerboseInfo)(`DRY RUN: Would remove ${constants_1.PI_SKILLS_PATH}`, verbose, dryRun);
|
|
216
|
-
}
|
|
217
|
-
else {
|
|
218
|
-
await fs.rm(piSkillsPath, { recursive: true, force: true });
|
|
219
|
-
(0, constants_1.logVerboseInfo)(`Removed ${constants_1.PI_SKILLS_PATH} (skills disabled)`, verbose, dryRun);
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
catch {
|
|
223
|
-
// Directory doesn't exist, nothing to clean
|
|
224
|
-
}
|
|
225
|
-
// Clean up .agents/skills
|
|
226
|
-
try {
|
|
227
|
-
await fs.access(gooseSkillsPath);
|
|
228
|
-
if (dryRun) {
|
|
229
|
-
(0, constants_1.logVerboseInfo)(`DRY RUN: Would remove ${constants_1.GOOSE_SKILLS_PATH}`, verbose, dryRun);
|
|
230
|
-
}
|
|
231
|
-
else {
|
|
232
|
-
await fs.rm(gooseSkillsPath, { recursive: true, force: true });
|
|
233
|
-
(0, constants_1.logVerboseInfo)(`Removed ${constants_1.GOOSE_SKILLS_PATH} (skills disabled)`, verbose, dryRun);
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
catch {
|
|
237
|
-
// Directory doesn't exist, nothing to clean
|
|
238
|
-
}
|
|
239
|
-
// Clean up .vibe/skills
|
|
240
|
-
try {
|
|
241
|
-
await fs.access(vibeSkillsPath);
|
|
242
|
-
if (dryRun) {
|
|
243
|
-
(0, constants_1.logVerboseInfo)(`DRY RUN: Would remove ${constants_1.VIBE_SKILLS_PATH}`, verbose, dryRun);
|
|
244
|
-
}
|
|
245
|
-
else {
|
|
246
|
-
await fs.rm(vibeSkillsPath, { recursive: true, force: true });
|
|
247
|
-
(0, constants_1.logVerboseInfo)(`Removed ${constants_1.VIBE_SKILLS_PATH} (skills disabled)`, verbose, dryRun);
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
catch {
|
|
251
|
-
// Directory doesn't exist, nothing to clean
|
|
252
|
-
}
|
|
253
|
-
// Clean up .roo/skills
|
|
254
|
-
try {
|
|
255
|
-
await fs.access(rooSkillsPath);
|
|
256
|
-
if (dryRun) {
|
|
257
|
-
(0, constants_1.logVerboseInfo)(`DRY RUN: Would remove ${constants_1.ROO_SKILLS_PATH}`, verbose, dryRun);
|
|
258
|
-
}
|
|
259
|
-
else {
|
|
260
|
-
await fs.rm(rooSkillsPath, { recursive: true, force: true });
|
|
261
|
-
(0, constants_1.logVerboseInfo)(`Removed ${constants_1.ROO_SKILLS_PATH} (skills disabled)`, verbose, dryRun);
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
catch {
|
|
265
|
-
// Directory doesn't exist, nothing to clean
|
|
266
|
-
}
|
|
267
|
-
// Clean up .gemini/skills
|
|
268
|
-
try {
|
|
269
|
-
await fs.access(geminiSkillsPath);
|
|
270
|
-
if (dryRun) {
|
|
271
|
-
(0, constants_1.logVerboseInfo)(`DRY RUN: Would remove ${constants_1.GEMINI_SKILLS_PATH}`, verbose, dryRun);
|
|
272
|
-
}
|
|
273
|
-
else {
|
|
274
|
-
await fs.rm(geminiSkillsPath, { recursive: true, force: true });
|
|
275
|
-
(0, constants_1.logVerboseInfo)(`Removed ${constants_1.GEMINI_SKILLS_PATH} (skills disabled)`, verbose, dryRun);
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
catch {
|
|
279
|
-
// Directory doesn't exist, nothing to clean
|
|
280
|
-
}
|
|
281
|
-
// Clean up .junie/skills
|
|
282
|
-
try {
|
|
283
|
-
await fs.access(junieSkillsPath);
|
|
284
|
-
if (dryRun) {
|
|
285
|
-
(0, constants_1.logVerboseInfo)(`DRY RUN: Would remove ${constants_1.JUNIE_SKILLS_PATH}`, verbose, dryRun);
|
|
286
|
-
}
|
|
287
|
-
else {
|
|
288
|
-
await fs.rm(junieSkillsPath, { recursive: true, force: true });
|
|
289
|
-
(0, constants_1.logVerboseInfo)(`Removed ${constants_1.JUNIE_SKILLS_PATH} (skills disabled)`, verbose, dryRun);
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
catch {
|
|
293
|
-
// Directory doesn't exist, nothing to clean
|
|
294
|
-
}
|
|
295
|
-
// Clean up .cursor/skills
|
|
167
|
+
function isMissingPathError(error) {
|
|
168
|
+
return (typeof error === 'object' &&
|
|
169
|
+
error !== null &&
|
|
170
|
+
'code' in error &&
|
|
171
|
+
error.code === 'ENOENT');
|
|
172
|
+
}
|
|
173
|
+
async function cleanupSkillsDirectory(projectRoot, relativePath, dryRun, verbose) {
|
|
174
|
+
const targetPath = path.join(projectRoot, relativePath);
|
|
296
175
|
try {
|
|
297
|
-
await fs.access(
|
|
298
|
-
if (dryRun) {
|
|
299
|
-
(0, constants_1.logVerboseInfo)(`DRY RUN: Would remove ${constants_1.CURSOR_SKILLS_PATH}`, verbose, dryRun);
|
|
300
|
-
}
|
|
301
|
-
else {
|
|
302
|
-
await fs.rm(cursorSkillsPath, { recursive: true, force: true });
|
|
303
|
-
(0, constants_1.logVerboseInfo)(`Removed ${constants_1.CURSOR_SKILLS_PATH} (skills disabled)`, verbose, dryRun);
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
catch {
|
|
307
|
-
// Directory doesn't exist, nothing to clean
|
|
176
|
+
await fs.access(targetPath);
|
|
308
177
|
}
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
if (dryRun) {
|
|
313
|
-
(0, constants_1.logVerboseInfo)(`DRY RUN: Would remove ${constants_1.WINDSURF_SKILLS_PATH}`, verbose, dryRun);
|
|
314
|
-
}
|
|
315
|
-
else {
|
|
316
|
-
await fs.rm(windsurfSkillsPath, { recursive: true, force: true });
|
|
317
|
-
(0, constants_1.logVerboseInfo)(`Removed ${constants_1.WINDSURF_SKILLS_PATH} (skills disabled)`, verbose, dryRun);
|
|
178
|
+
catch (error) {
|
|
179
|
+
if (isMissingPathError(error)) {
|
|
180
|
+
return;
|
|
318
181
|
}
|
|
182
|
+
throw error;
|
|
319
183
|
}
|
|
320
|
-
|
|
321
|
-
|
|
184
|
+
if (dryRun) {
|
|
185
|
+
(0, constants_1.logVerboseInfo)(`DRY RUN: Would remove ${relativePath}`, verbose, dryRun);
|
|
186
|
+
return;
|
|
322
187
|
}
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
188
|
+
await fs.rm(targetPath, { recursive: true, force: true });
|
|
189
|
+
(0, constants_1.logVerboseInfo)(`Removed ${relativePath} (skills disabled)`, verbose, dryRun);
|
|
190
|
+
}
|
|
191
|
+
async function createTempSkillsDir(parentDir) {
|
|
192
|
+
return fs.mkdtemp(path.join(parentDir, 'skills.tmp-'));
|
|
193
|
+
}
|
|
194
|
+
const TRANSIENT_RENAME_ERROR_CODES = new Set(['EPERM', 'EBUSY', 'ENOTEMPTY']);
|
|
195
|
+
const RENAME_RETRY_ATTEMPTS = 5;
|
|
196
|
+
const RENAME_RETRY_DELAY_MS = 50;
|
|
197
|
+
function isTransientRenameError(error) {
|
|
198
|
+
return (typeof error === 'object' &&
|
|
199
|
+
error !== null &&
|
|
200
|
+
'code' in error &&
|
|
201
|
+
typeof error.code === 'string' &&
|
|
202
|
+
TRANSIENT_RENAME_ERROR_CODES.has(error.code));
|
|
203
|
+
}
|
|
204
|
+
function wait(ms) {
|
|
205
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
206
|
+
}
|
|
207
|
+
async function replaceSkillsDirectory(tempDir, targetDir, fsOps = fs) {
|
|
208
|
+
let lastError;
|
|
209
|
+
for (let attempt = 1; attempt <= RENAME_RETRY_ATTEMPTS; attempt += 1) {
|
|
210
|
+
try {
|
|
211
|
+
await fsOps.rename(tempDir, targetDir);
|
|
212
|
+
return;
|
|
328
213
|
}
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
(
|
|
214
|
+
catch (error) {
|
|
215
|
+
lastError = error;
|
|
216
|
+
if (!isTransientRenameError(error) || attempt === RENAME_RETRY_ATTEMPTS) {
|
|
217
|
+
break;
|
|
218
|
+
}
|
|
219
|
+
await wait(RENAME_RETRY_DELAY_MS * attempt);
|
|
332
220
|
}
|
|
333
221
|
}
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
try {
|
|
339
|
-
await fs.access(antigravitySkillsPath);
|
|
340
|
-
if (dryRun) {
|
|
341
|
-
(0, constants_1.logVerboseInfo)(`DRY RUN: Would remove ${constants_1.ANTIGRAVITY_SKILLS_PATH}`, verbose, dryRun);
|
|
342
|
-
}
|
|
343
|
-
else {
|
|
344
|
-
await fs.rm(antigravitySkillsPath, { recursive: true, force: true });
|
|
345
|
-
(0, constants_1.logVerboseInfo)(`Removed ${constants_1.ANTIGRAVITY_SKILLS_PATH} (skills disabled)`, verbose, dryRun);
|
|
346
|
-
}
|
|
222
|
+
if (isTransientRenameError(lastError)) {
|
|
223
|
+
await fsOps.cp(tempDir, targetDir, { recursive: true, force: true });
|
|
224
|
+
await fsOps.rm(tempDir, { recursive: true, force: true });
|
|
225
|
+
return;
|
|
347
226
|
}
|
|
348
|
-
|
|
349
|
-
|
|
227
|
+
throw lastError;
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Cleans up skills directories when skills are disabled.
|
|
231
|
+
* This ensures that stale skills from previous runs don't persist when skills are turned off.
|
|
232
|
+
*/
|
|
233
|
+
async function cleanupSkillsDirectories(projectRoot, dryRun, verbose) {
|
|
234
|
+
for (const skillPath of SKILL_TARGET_PATHS) {
|
|
235
|
+
await cleanupSkillsDirectory(projectRoot, skillPath, dryRun, verbose);
|
|
350
236
|
}
|
|
351
237
|
}
|
|
352
238
|
/**
|
|
@@ -416,7 +302,7 @@ async function propagateSkills(projectRoot, agents, skillsEnabled, verbose, dryR
|
|
|
416
302
|
await propagateSkillsForPi(projectRoot, { dryRun });
|
|
417
303
|
}
|
|
418
304
|
if (selectedTargets.has('goose')) {
|
|
419
|
-
(0, constants_1.logVerboseInfo)(`Copying skills to ${constants_1.GOOSE_SKILLS_PATH} for Goose and
|
|
305
|
+
(0, constants_1.logVerboseInfo)(`Copying skills to ${constants_1.GOOSE_SKILLS_PATH} for Goose, Amp and Zed`, verbose, dryRun);
|
|
420
306
|
await propagateSkillsForGoose(projectRoot, { dryRun });
|
|
421
307
|
}
|
|
422
308
|
if (selectedTargets.has('vibe')) {
|
|
@@ -476,7 +362,7 @@ async function propagateSkillsForClaude(projectRoot, options) {
|
|
|
476
362
|
// Ensure .claude directory exists
|
|
477
363
|
await fs.mkdir(claudeDir, { recursive: true });
|
|
478
364
|
// Use atomic replace: copy to temp, then rename
|
|
479
|
-
const tempDir =
|
|
365
|
+
const tempDir = await createTempSkillsDir(claudeDir);
|
|
480
366
|
try {
|
|
481
367
|
// Copy to temp directory
|
|
482
368
|
await (0, SkillsUtils_1.copySkillsDirectory)(skillsDir, tempDir);
|
|
@@ -489,7 +375,7 @@ async function propagateSkillsForClaude(projectRoot, options) {
|
|
|
489
375
|
// Target didn't exist, that's fine
|
|
490
376
|
}
|
|
491
377
|
// Rename temp to target
|
|
492
|
-
await
|
|
378
|
+
await replaceSkillsDirectory(tempDir, claudeSkillsPath);
|
|
493
379
|
}
|
|
494
380
|
catch (error) {
|
|
495
381
|
// Clean up temp directory on error
|
|
@@ -526,7 +412,7 @@ async function propagateSkillsForCodex(projectRoot, options) {
|
|
|
526
412
|
// Ensure .codex directory exists
|
|
527
413
|
await fs.mkdir(codexDir, { recursive: true });
|
|
528
414
|
// Use atomic replace: copy to temp, then rename
|
|
529
|
-
const tempDir =
|
|
415
|
+
const tempDir = await createTempSkillsDir(codexDir);
|
|
530
416
|
try {
|
|
531
417
|
// Copy to temp directory
|
|
532
418
|
await (0, SkillsUtils_1.copySkillsDirectory)(skillsDir, tempDir);
|
|
@@ -539,7 +425,7 @@ async function propagateSkillsForCodex(projectRoot, options) {
|
|
|
539
425
|
// Target didn't exist, that's fine
|
|
540
426
|
}
|
|
541
427
|
// Rename temp to target
|
|
542
|
-
await
|
|
428
|
+
await replaceSkillsDirectory(tempDir, codexSkillsPath);
|
|
543
429
|
}
|
|
544
430
|
catch (error) {
|
|
545
431
|
// Clean up temp directory on error
|
|
@@ -576,7 +462,7 @@ async function propagateSkillsForOpenCode(projectRoot, options) {
|
|
|
576
462
|
// Ensure .opencode directory exists
|
|
577
463
|
await fs.mkdir(opencodeDir, { recursive: true });
|
|
578
464
|
// Use atomic replace: copy to temp, then rename
|
|
579
|
-
const tempDir =
|
|
465
|
+
const tempDir = await createTempSkillsDir(opencodeDir);
|
|
580
466
|
try {
|
|
581
467
|
// Copy to temp directory
|
|
582
468
|
await (0, SkillsUtils_1.copySkillsDirectory)(skillsDir, tempDir);
|
|
@@ -589,7 +475,7 @@ async function propagateSkillsForOpenCode(projectRoot, options) {
|
|
|
589
475
|
// Target didn't exist, that's fine
|
|
590
476
|
}
|
|
591
477
|
// Rename temp to target
|
|
592
|
-
await
|
|
478
|
+
await replaceSkillsDirectory(tempDir, opencodeSkillsPath);
|
|
593
479
|
}
|
|
594
480
|
catch (error) {
|
|
595
481
|
// Clean up temp directory on error
|
|
@@ -626,7 +512,7 @@ async function propagateSkillsForPi(projectRoot, options) {
|
|
|
626
512
|
// Ensure .pi directory exists
|
|
627
513
|
await fs.mkdir(piDir, { recursive: true });
|
|
628
514
|
// Use atomic replace: copy to temp, then rename
|
|
629
|
-
const tempDir =
|
|
515
|
+
const tempDir = await createTempSkillsDir(piDir);
|
|
630
516
|
try {
|
|
631
517
|
// Copy to temp directory
|
|
632
518
|
await (0, SkillsUtils_1.copySkillsDirectory)(skillsDir, tempDir);
|
|
@@ -639,7 +525,7 @@ async function propagateSkillsForPi(projectRoot, options) {
|
|
|
639
525
|
// Target didn't exist, that's fine
|
|
640
526
|
}
|
|
641
527
|
// Rename temp to target
|
|
642
|
-
await
|
|
528
|
+
await replaceSkillsDirectory(tempDir, piSkillsPath);
|
|
643
529
|
}
|
|
644
530
|
catch (error) {
|
|
645
531
|
// Clean up temp directory on error
|
|
@@ -676,7 +562,7 @@ async function propagateSkillsForGoose(projectRoot, options) {
|
|
|
676
562
|
// Ensure .agents directory exists
|
|
677
563
|
await fs.mkdir(gooseDir, { recursive: true });
|
|
678
564
|
// Use atomic replace: copy to temp, then rename
|
|
679
|
-
const tempDir =
|
|
565
|
+
const tempDir = await createTempSkillsDir(gooseDir);
|
|
680
566
|
try {
|
|
681
567
|
// Copy to temp directory
|
|
682
568
|
await (0, SkillsUtils_1.copySkillsDirectory)(skillsDir, tempDir);
|
|
@@ -689,7 +575,7 @@ async function propagateSkillsForGoose(projectRoot, options) {
|
|
|
689
575
|
// Target didn't exist, that's fine
|
|
690
576
|
}
|
|
691
577
|
// Rename temp to target
|
|
692
|
-
await
|
|
578
|
+
await replaceSkillsDirectory(tempDir, gooseSkillsPath);
|
|
693
579
|
}
|
|
694
580
|
catch (error) {
|
|
695
581
|
// Clean up temp directory on error
|
|
@@ -726,7 +612,7 @@ async function propagateSkillsForVibe(projectRoot, options) {
|
|
|
726
612
|
// Ensure .vibe directory exists
|
|
727
613
|
await fs.mkdir(vibeDir, { recursive: true });
|
|
728
614
|
// Use atomic replace: copy to temp, then rename
|
|
729
|
-
const tempDir =
|
|
615
|
+
const tempDir = await createTempSkillsDir(vibeDir);
|
|
730
616
|
try {
|
|
731
617
|
// Copy to temp directory
|
|
732
618
|
await (0, SkillsUtils_1.copySkillsDirectory)(skillsDir, tempDir);
|
|
@@ -739,7 +625,7 @@ async function propagateSkillsForVibe(projectRoot, options) {
|
|
|
739
625
|
// Target didn't exist, that's fine
|
|
740
626
|
}
|
|
741
627
|
// Rename temp to target
|
|
742
|
-
await
|
|
628
|
+
await replaceSkillsDirectory(tempDir, vibeSkillsPath);
|
|
743
629
|
}
|
|
744
630
|
catch (error) {
|
|
745
631
|
// Clean up temp directory on error
|
|
@@ -776,7 +662,7 @@ async function propagateSkillsForRoo(projectRoot, options) {
|
|
|
776
662
|
// Ensure .roo directory exists
|
|
777
663
|
await fs.mkdir(rooDir, { recursive: true });
|
|
778
664
|
// Use atomic replace: copy to temp, then rename
|
|
779
|
-
const tempDir =
|
|
665
|
+
const tempDir = await createTempSkillsDir(rooDir);
|
|
780
666
|
try {
|
|
781
667
|
// Copy to temp directory
|
|
782
668
|
await (0, SkillsUtils_1.copySkillsDirectory)(skillsDir, tempDir);
|
|
@@ -789,7 +675,7 @@ async function propagateSkillsForRoo(projectRoot, options) {
|
|
|
789
675
|
// Target didn't exist, that's fine
|
|
790
676
|
}
|
|
791
677
|
// Rename temp to target
|
|
792
|
-
await
|
|
678
|
+
await replaceSkillsDirectory(tempDir, rooSkillsPath);
|
|
793
679
|
}
|
|
794
680
|
catch (error) {
|
|
795
681
|
// Clean up temp directory on error
|
|
@@ -826,7 +712,7 @@ async function propagateSkillsForGemini(projectRoot, options) {
|
|
|
826
712
|
// Ensure .gemini directory exists
|
|
827
713
|
await fs.mkdir(geminiDir, { recursive: true });
|
|
828
714
|
// Use atomic replace: copy to temp, then rename
|
|
829
|
-
const tempDir =
|
|
715
|
+
const tempDir = await createTempSkillsDir(geminiDir);
|
|
830
716
|
try {
|
|
831
717
|
// Copy to temp directory
|
|
832
718
|
await (0, SkillsUtils_1.copySkillsDirectory)(skillsDir, tempDir);
|
|
@@ -839,7 +725,7 @@ async function propagateSkillsForGemini(projectRoot, options) {
|
|
|
839
725
|
// Target didn't exist, that's fine
|
|
840
726
|
}
|
|
841
727
|
// Rename temp to target
|
|
842
|
-
await
|
|
728
|
+
await replaceSkillsDirectory(tempDir, geminiSkillsPath);
|
|
843
729
|
}
|
|
844
730
|
catch (error) {
|
|
845
731
|
// Clean up temp directory on error
|
|
@@ -872,7 +758,7 @@ async function propagateSkillsForJunie(projectRoot, options) {
|
|
|
872
758
|
return [`Copy skills from ${constants_1.RULER_SKILLS_PATH} to ${constants_1.JUNIE_SKILLS_PATH}`];
|
|
873
759
|
}
|
|
874
760
|
await fs.mkdir(junieDir, { recursive: true });
|
|
875
|
-
const tempDir =
|
|
761
|
+
const tempDir = await createTempSkillsDir(junieDir);
|
|
876
762
|
try {
|
|
877
763
|
await (0, SkillsUtils_1.copySkillsDirectory)(skillsDir, tempDir);
|
|
878
764
|
try {
|
|
@@ -881,7 +767,7 @@ async function propagateSkillsForJunie(projectRoot, options) {
|
|
|
881
767
|
catch {
|
|
882
768
|
// Target didn't exist, that's fine
|
|
883
769
|
}
|
|
884
|
-
await
|
|
770
|
+
await replaceSkillsDirectory(tempDir, junieSkillsPath);
|
|
885
771
|
}
|
|
886
772
|
catch (error) {
|
|
887
773
|
try {
|
|
@@ -917,7 +803,7 @@ async function propagateSkillsForCursor(projectRoot, options) {
|
|
|
917
803
|
// Ensure .cursor directory exists
|
|
918
804
|
await fs.mkdir(cursorDir, { recursive: true });
|
|
919
805
|
// Use atomic replace: copy to temp, then rename
|
|
920
|
-
const tempDir =
|
|
806
|
+
const tempDir = await createTempSkillsDir(cursorDir);
|
|
921
807
|
try {
|
|
922
808
|
// Copy to temp directory
|
|
923
809
|
await (0, SkillsUtils_1.copySkillsDirectory)(skillsDir, tempDir);
|
|
@@ -930,7 +816,7 @@ async function propagateSkillsForCursor(projectRoot, options) {
|
|
|
930
816
|
// Target didn't exist, that's fine
|
|
931
817
|
}
|
|
932
818
|
// Rename temp to target
|
|
933
|
-
await
|
|
819
|
+
await replaceSkillsDirectory(tempDir, cursorSkillsPath);
|
|
934
820
|
}
|
|
935
821
|
catch (error) {
|
|
936
822
|
// Clean up temp directory on error
|
|
@@ -967,7 +853,7 @@ async function propagateSkillsForWindsurf(projectRoot, options) {
|
|
|
967
853
|
// Ensure .windsurf directory exists
|
|
968
854
|
await fs.mkdir(windsurfDir, { recursive: true });
|
|
969
855
|
// Use atomic replace: copy to temp, then rename
|
|
970
|
-
const tempDir =
|
|
856
|
+
const tempDir = await createTempSkillsDir(windsurfDir);
|
|
971
857
|
try {
|
|
972
858
|
// Copy to temp directory
|
|
973
859
|
await (0, SkillsUtils_1.copySkillsDirectory)(skillsDir, tempDir);
|
|
@@ -980,7 +866,7 @@ async function propagateSkillsForWindsurf(projectRoot, options) {
|
|
|
980
866
|
// Target didn't exist, that's fine
|
|
981
867
|
}
|
|
982
868
|
// Rename temp to target
|
|
983
|
-
await
|
|
869
|
+
await replaceSkillsDirectory(tempDir, windsurfSkillsPath);
|
|
984
870
|
}
|
|
985
871
|
catch (error) {
|
|
986
872
|
// Clean up temp directory on error
|
|
@@ -1017,7 +903,7 @@ async function propagateSkillsForFactory(projectRoot, options) {
|
|
|
1017
903
|
// Ensure .factory directory exists
|
|
1018
904
|
await fs.mkdir(factoryDir, { recursive: true });
|
|
1019
905
|
// Use atomic replace: copy to temp, then rename
|
|
1020
|
-
const tempDir =
|
|
906
|
+
const tempDir = await createTempSkillsDir(factoryDir);
|
|
1021
907
|
try {
|
|
1022
908
|
// Copy to temp directory
|
|
1023
909
|
await (0, SkillsUtils_1.copySkillsDirectory)(skillsDir, tempDir);
|
|
@@ -1030,7 +916,7 @@ async function propagateSkillsForFactory(projectRoot, options) {
|
|
|
1030
916
|
// Target didn't exist, that's fine
|
|
1031
917
|
}
|
|
1032
918
|
// Rename temp to target
|
|
1033
|
-
await
|
|
919
|
+
await replaceSkillsDirectory(tempDir, factorySkillsPath);
|
|
1034
920
|
}
|
|
1035
921
|
catch (error) {
|
|
1036
922
|
// Clean up temp directory on error
|
|
@@ -1069,7 +955,7 @@ async function propagateSkillsForAntigravity(projectRoot, options) {
|
|
|
1069
955
|
// Ensure .agent directory exists
|
|
1070
956
|
await fs.mkdir(antigravityDir, { recursive: true });
|
|
1071
957
|
// Use atomic replace: copy to temp, then rename
|
|
1072
|
-
const tempDir =
|
|
958
|
+
const tempDir = await createTempSkillsDir(antigravityDir);
|
|
1073
959
|
try {
|
|
1074
960
|
// Copy to temp directory
|
|
1075
961
|
await (0, SkillsUtils_1.copySkillsDirectory)(skillsDir, tempDir);
|
|
@@ -1082,7 +968,7 @@ async function propagateSkillsForAntigravity(projectRoot, options) {
|
|
|
1082
968
|
// Target didn't exist, that's fine
|
|
1083
969
|
}
|
|
1084
970
|
// Rename temp to target
|
|
1085
|
-
await
|
|
971
|
+
await replaceSkillsDirectory(tempDir, antigravitySkillsPath);
|
|
1086
972
|
}
|
|
1087
973
|
catch (error) {
|
|
1088
974
|
// Clean up temp directory on error
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { SkillInfo } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* Checks if a directory contains a SKILL.md file.
|
|
4
|
+
*/
|
|
5
|
+
export declare function hasSkillMd(dirPath: string): Promise<boolean>;
|
|
6
|
+
/**
|
|
7
|
+
* Checks if a directory is a grouping directory (contains subdirectories with SKILL.md).
|
|
8
|
+
*/
|
|
9
|
+
export declare function isGroupingDir(dirPath: string): Promise<boolean>;
|
|
10
|
+
/**
|
|
11
|
+
* Walks the skills tree and discovers all skills.
|
|
12
|
+
* Returns skills and any validation warnings.
|
|
13
|
+
*/
|
|
14
|
+
export declare function walkSkillsTree(root: string): Promise<{
|
|
15
|
+
skills: SkillInfo[];
|
|
16
|
+
warnings: string[];
|
|
17
|
+
}>;
|
|
18
|
+
/**
|
|
19
|
+
* Formats validation warnings for display.
|
|
20
|
+
*/
|
|
21
|
+
export declare function formatValidationWarnings(warnings: string[]): string;
|
|
22
|
+
/**
|
|
23
|
+
* Copies the skills directory to the destination, preserving structure.
|
|
24
|
+
* Creates the destination directory if it doesn't exist.
|
|
25
|
+
*/
|
|
26
|
+
export declare function copySkillsDirectory(srcDir: string, destDir: string): Promise<void>;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { SubagentInfo } from '../types';
|
|
2
|
+
import type { IAgent } from '../agents/IAgent';
|
|
3
|
+
/**
|
|
4
|
+
* Discovers subagent definitions in `.ruler/agents/`.
|
|
5
|
+
* Each `.md` file is parsed for YAML frontmatter (name, description, …).
|
|
6
|
+
* Files that fail validation are dropped from the returned list and
|
|
7
|
+
* reported via warnings.
|
|
8
|
+
*/
|
|
9
|
+
export declare function discoverSubagents(projectRoot: string): Promise<{
|
|
10
|
+
subagents: SubagentInfo[];
|
|
11
|
+
warnings: string[];
|
|
12
|
+
}>;
|
|
13
|
+
type SubagentTarget = 'claude' | 'cursor' | 'codex' | 'copilot';
|
|
14
|
+
/**
|
|
15
|
+
* Returns which native subagent targets are reachable through the supplied
|
|
16
|
+
* agent list. An agent only contributes to a target when it implements
|
|
17
|
+
* `supportsNativeSubagents()` returning true.
|
|
18
|
+
*/
|
|
19
|
+
export declare function getSelectedSubagentTargets(agents: IAgent[]): Set<SubagentTarget>;
|
|
20
|
+
/**
|
|
21
|
+
* Returns absolute paths that subagent propagation may generate, for the
|
|
22
|
+
* supplied agents, used for `.gitignore` integration.
|
|
23
|
+
*/
|
|
24
|
+
export declare function getSubagentsGitignorePaths(projectRoot: string, agents: IAgent[]): Promise<string[]>;
|
|
25
|
+
/**
|
|
26
|
+
* Test-only hook to reset the once-per-process experimental warning state.
|
|
27
|
+
*/
|
|
28
|
+
export declare function _resetExperimentalWarningForTests(): void;
|
|
29
|
+
interface PropagateOptions {
|
|
30
|
+
dryRun: boolean;
|
|
31
|
+
verbose?: boolean;
|
|
32
|
+
}
|
|
33
|
+
export declare function propagateSubagentsForClaude(projectRoot: string, subagents: SubagentInfo[], options: PropagateOptions): Promise<string[]>;
|
|
34
|
+
export declare function propagateSubagentsForCursor(projectRoot: string, subagents: SubagentInfo[], options: PropagateOptions): Promise<string[]>;
|
|
35
|
+
export declare function propagateSubagentsForCodex(projectRoot: string, subagents: SubagentInfo[], options: PropagateOptions): Promise<string[]>;
|
|
36
|
+
export declare function propagateSubagentsForCopilot(projectRoot: string, subagents: SubagentInfo[], options: PropagateOptions): Promise<string[]>;
|
|
37
|
+
export declare function propagateSubagents(projectRoot: string, agents: IAgent[], subagentsEnabled: boolean, cleanupOrphaned: boolean, verbose: boolean, dryRun: boolean): Promise<void>;
|
|
38
|
+
export {};
|