rulesync 14.2.0 → 15.0.1
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 +44 -39
- package/dist/cli/index.cjs +84 -85
- package/dist/cli/index.js +84 -85
- package/dist/cli/index.js.map +1 -1
- package/dist/{import-CMCy95RI.js → import-BuxzyDyH.js} +1889 -303
- package/dist/import-BuxzyDyH.js.map +1 -0
- package/dist/{import-Ds8vYv6h.cjs → import-DRN7goJ_.cjs} +1932 -316
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +25 -4
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts +25 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/dist/import-CMCy95RI.js.map +0 -1
package/dist/cli/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { $ as
|
|
2
|
+
import { $ as assertDirectoryIfExists, $t as RULESYNC_SOURCES_LOCK_RELATIVE_FILE_PATH, A as RulesyncMcp, At as RULESYNC_CHECKS_RELATIVE_DIR_PATH, B as stringifyFrontmatter, Bt as RULESYNC_LOCAL_CONFIG_RELATIVE_FILE_PATH, C as RulesyncSubagent, Ct as ALL_TOOL_TARGETS, D as RulesyncRule, Dt as MAX_FILE_SIZE, E as RulesyncSkillFrontmatterSchema, Et as ToolTargetSchema, F as parseJsonc, Ft as RULESYNC_CURATED_SKILLS_RELATIVE_DIR_PATH, G as SourceEntrySchema, Gt as RULESYNC_NPM_SOURCES_LOCK_RELATIVE_FILE_PATH, H as SKILL_FILE_NAME$1, Ht as RULESYNC_MCP_LEGACY_FILE_NAME, I as RulesyncCommand, It as RULESYNC_HOOKS_FILE_NAME, J as JsonLogger, Jt as RULESYNC_PERMISSIONS_RELATIVE_FILE_PATH, K as findControlCharacter, Kt as RULESYNC_PERMISSIONS_FILE_NAME, L as RulesyncCommandFrontmatterSchema, Lt as RULESYNC_HOOKS_LEGACY_FILE_NAME, M as RulesyncHooks, Mt as RULESYNC_CONFIG_RELATIVE_FILE_PATH, N as getRulesyncSourceCandidates, Nt as RULESYNC_CONFIG_SCHEMA_URL, O as RulesyncRuleFrontmatterSchema, Ot as RULESYNC_AIIGNORE_FILE_NAME, P as resolveRulesyncSourceWritePath, Pt as RULESYNC_CURATED_RULES_RELATIVE_DIR_PATH, Q as ErrorCodes, Qt as RULESYNC_SKILLS_RELATIVE_DIR_PATH, R as RulesyncCheck, Rt as RULESYNC_HOOKS_RELATIVE_FILE_PATH, S as getLocalSkillDirNames, St as writeFileContent, T as RulesyncSkill, Tt as PACKAGING_TOOL_TARGETS, U as ConfigResolver, Ut as RULESYNC_MCP_RELATIVE_FILE_PATH, V as loadYaml, Vt as RULESYNC_MCP_FILE_NAME, W as ConfigFileSchema, Wt as RULESYNC_MCP_SCHEMA_URL, X as warnOnConflictingFlags, Xt as RULESYNC_RELATIVE_DIR_PATH, Y as fallbackLogger, Yt as RULESYNC_PERMISSIONS_SCHEMA_URL, Z as CLIError, Zt as RULESYNC_RULES_RELATIVE_DIR_PATH, _ as CLAUDECODE_LOCAL_RULE_FILE_NAME, _t as removeFileStrict, a as convertFromTool, at as ensureDir, b as CLAUDECODE_SKILLS_DIR_PATH, bt as runWithDirectoryRollback, c as SubagentsProcessor, ct as getFileSize, d as IgnoreProcessor, dt as listDirectoryFiles, en as RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH, et as assertTreeContainsNoSymlinks, f as HooksProcessor, ft as readFileContent, g as CLAUDECODE_DIR, gt as removeFile, h as CODEXCLI_DIR, ht as removeDirectoryStrict, i as getProcessorRegistryEntry, it as directoryExists, j as RulesyncIgnore, jt as RULESYNC_COMMANDS_RELATIVE_DIR_PATH, k as RulesyncPermissions, kt as RULESYNC_AIIGNORE_RELATIVE_FILE_PATH, l as SkillsProcessor, lt as getHomeDirectory, m as CODEXCLI_BASH_RULES_FILE_NAME, mt as removeDirectory, n as checkRulesyncDirExists, nn as ALL_FEATURES_WITH_WILDCARD, nt as checkPathTraversal, o as isPackagingToolTarget, ot as fileExists, p as CommandsProcessor, pt as readFileContentOrNull, q as ConsoleLogger, qt as RULESYNC_PERMISSIONS_LEGACY_FILE_NAME, r as generate, rn as formatError, rt as createTempDirectory, s as RulesProcessor, st as findFilesByGlobs, t as importFromTool, tn as ALL_FEATURES, tt as assertWritablePathInsideRoot, u as McpProcessor, ut as isSymlink, v as CLAUDECODE_MEMORIES_DIR_NAME, vt as removeTempDirectory, w as RulesyncSubagentFrontmatterSchema, wt as ALL_TOOL_TARGETS_WITH_WILDCARD, x as ChecksProcessor, xt as toPosixPath, y as CLAUDECODE_SETTINGS_LOCAL_FILE_NAME, yt as resolvePath, z as RulesyncCheckFrontmatterSchema, zt as RULESYNC_IGNORE_RELATIVE_FILE_PATH } from "../import-BuxzyDyH.js";
|
|
3
3
|
import { Command } from "commander";
|
|
4
4
|
import { nonnegative, optional, refine, z } from "zod/mini";
|
|
5
5
|
import { cp, mkdtemp, realpath, rm } from "node:fs/promises";
|
|
@@ -276,8 +276,14 @@ function singletonTemplate(feature) {
|
|
|
276
276
|
"src/**": "allow"
|
|
277
277
|
},
|
|
278
278
|
"read": {
|
|
279
|
-
".env": "deny"
|
|
279
|
+
".env": "deny",
|
|
280
|
+
"credentials/**": "deny"
|
|
280
281
|
}
|
|
282
|
+
},
|
|
283
|
+
"codexcli": {
|
|
284
|
+
"approval_policy": "on-request",
|
|
285
|
+
"approvals_reviewer": "auto_review",
|
|
286
|
+
"base_permission_profile": ":danger-full-access"
|
|
281
287
|
}
|
|
282
288
|
}
|
|
283
289
|
`;
|
|
@@ -317,25 +323,19 @@ function createFeatureScaffold({ feature, name }) {
|
|
|
317
323
|
});
|
|
318
324
|
case "mcp": {
|
|
319
325
|
const paths = RulesyncMcp.getSettablePaths();
|
|
320
|
-
const relativeFilePath = join(paths.recommended.relativeDirPath, paths.recommended.relativeFilePath);
|
|
321
326
|
return {
|
|
322
327
|
feature,
|
|
323
|
-
relativeFilePath,
|
|
324
|
-
candidateRelativeFilePaths:
|
|
325
|
-
...paths.jsonc ? [join(paths.jsonc.relativeDirPath, paths.jsonc.relativeFilePath)] : [],
|
|
326
|
-
relativeFilePath,
|
|
327
|
-
...paths.legacy ? [join(paths.legacy.relativeDirPath, paths.legacy.relativeFilePath)] : []
|
|
328
|
-
],
|
|
328
|
+
relativeFilePath: join(paths.recommended.relativeDirPath, paths.recommended.relativeFilePath),
|
|
329
|
+
candidateRelativeFilePaths: getRulesyncSourceCandidates({ paths }).map((candidate) => join(candidate.relativeDirPath, candidate.relativeFilePath)),
|
|
329
330
|
content: singletonTemplate(feature)
|
|
330
331
|
};
|
|
331
332
|
}
|
|
332
333
|
case "hooks": {
|
|
333
334
|
const paths = RulesyncHooks.getSettablePaths();
|
|
334
|
-
const relativeFilePath = join(paths.relativeDirPath, paths.relativeFilePath);
|
|
335
335
|
return {
|
|
336
336
|
feature,
|
|
337
|
-
relativeFilePath,
|
|
338
|
-
candidateRelativeFilePaths:
|
|
337
|
+
relativeFilePath: join(paths.recommended.relativeDirPath, paths.recommended.relativeFilePath),
|
|
338
|
+
candidateRelativeFilePaths: getRulesyncSourceCandidates({ paths }).map((candidate) => join(candidate.relativeDirPath, candidate.relativeFilePath)),
|
|
339
339
|
content: singletonTemplate(feature)
|
|
340
340
|
};
|
|
341
341
|
}
|
|
@@ -351,11 +351,10 @@ function createFeatureScaffold({ feature, name }) {
|
|
|
351
351
|
}
|
|
352
352
|
case "permissions": {
|
|
353
353
|
const paths = RulesyncPermissions.getSettablePaths();
|
|
354
|
-
const relativeFilePath = join(paths.relativeDirPath, paths.relativeFilePath);
|
|
355
354
|
return {
|
|
356
355
|
feature,
|
|
357
|
-
relativeFilePath,
|
|
358
|
-
candidateRelativeFilePaths:
|
|
356
|
+
relativeFilePath: join(paths.recommended.relativeDirPath, paths.recommended.relativeFilePath),
|
|
357
|
+
candidateRelativeFilePaths: getRulesyncSourceCandidates({ paths }).map((candidate) => join(candidate.relativeDirPath, candidate.relativeFilePath)),
|
|
359
358
|
content: singletonTemplate(feature)
|
|
360
359
|
};
|
|
361
360
|
}
|
|
@@ -3795,6 +3794,8 @@ async function convertCommand(logger, options) {
|
|
|
3795
3794
|
const fromTool = parseToolTarget$1(options.from ?? "", "source");
|
|
3796
3795
|
const toToolsRaw = (options.to ?? []).map((t) => parseToolTarget$1(t, "destination"));
|
|
3797
3796
|
const toTools = Array.from(new Set(toToolsRaw));
|
|
3797
|
+
const packagingTarget = [fromTool, ...toTools].find(isPackagingToolTarget);
|
|
3798
|
+
if (packagingTarget) throw new CLIError(`Plugin packaging target '${packagingTarget}' is not supported by convert. Use import --output-root and generate --output-roots with an explicit plugin directory.`, ErrorCodes.CONVERT_FAILED);
|
|
3798
3799
|
if (toTools.includes(fromTool)) throw new CLIError(`Destination tools must not include the source tool '${fromTool}'. Converting a tool onto itself is likely a mistake and may cause lossy round-trips.`, ErrorCodes.CONVERT_FAILED);
|
|
3799
3800
|
const config = await ConfigResolver.resolve({
|
|
3800
3801
|
...options,
|
|
@@ -3859,9 +3860,9 @@ const FEATURE_PATHS = {
|
|
|
3859
3860
|
skills: ["skills"],
|
|
3860
3861
|
checks: ["checks"],
|
|
3861
3862
|
ignore: [RULESYNC_AIIGNORE_FILE_NAME],
|
|
3862
|
-
mcp: [RULESYNC_MCP_FILE_NAME,
|
|
3863
|
-
hooks: [RULESYNC_HOOKS_FILE_NAME,
|
|
3864
|
-
permissions: [RULESYNC_PERMISSIONS_FILE_NAME,
|
|
3863
|
+
mcp: [RULESYNC_MCP_FILE_NAME, RULESYNC_MCP_LEGACY_FILE_NAME],
|
|
3864
|
+
hooks: [RULESYNC_HOOKS_FILE_NAME, RULESYNC_HOOKS_LEGACY_FILE_NAME],
|
|
3865
|
+
permissions: [RULESYNC_PERMISSIONS_FILE_NAME, RULESYNC_PERMISSIONS_LEGACY_FILE_NAME]
|
|
3865
3866
|
};
|
|
3866
3867
|
/**
|
|
3867
3868
|
* Check if target is a tool target (not rulesync)
|
|
@@ -3999,10 +4000,11 @@ async function convertFetchedFilesToRulesync(params) {
|
|
|
3999
4000
|
};
|
|
4000
4001
|
}
|
|
4001
4002
|
/**
|
|
4002
|
-
* Resolve features from options, handling wildcard
|
|
4003
|
+
* Resolve features from options, defaulting to skills and handling wildcard.
|
|
4003
4004
|
*/
|
|
4004
4005
|
function resolveFeatures(features) {
|
|
4005
|
-
if (
|
|
4006
|
+
if (features === void 0) return ["skills"];
|
|
4007
|
+
if (features.includes("*")) return [...ALL_FEATURES];
|
|
4006
4008
|
return features.filter((f) => ALL_FEATURES.includes(f));
|
|
4007
4009
|
}
|
|
4008
4010
|
/**
|
|
@@ -4821,6 +4823,7 @@ const ALL_GITIGNORE_ENTRIES = (() => {
|
|
|
4821
4823
|
const seen = /* @__PURE__ */ new Set();
|
|
4822
4824
|
const result = [];
|
|
4823
4825
|
for (const tag of GITIGNORE_ENTRY_REGISTRY) {
|
|
4826
|
+
if (normalizeGitignoreEntryTargets(tag.target).every((target) => PACKAGING_TOOL_TARGETS.includes(target))) continue;
|
|
4824
4827
|
if (seen.has(tag.entry)) continue;
|
|
4825
4828
|
seen.add(tag.entry);
|
|
4826
4829
|
result.push(tag.entry);
|
|
@@ -4830,14 +4833,13 @@ const ALL_GITIGNORE_ENTRIES = (() => {
|
|
|
4830
4833
|
const isTargetSelected = (target, selectedTargets) => {
|
|
4831
4834
|
const targets = normalizeGitignoreEntryTargets(target);
|
|
4832
4835
|
if (targets.includes("common")) return true;
|
|
4833
|
-
if (!selectedTargets || selectedTargets.length === 0) return
|
|
4834
|
-
if (selectedTargets.includes("*")) return true;
|
|
4836
|
+
if (!selectedTargets || selectedTargets.length === 0 || selectedTargets.includes("*")) return targets.some((candidate) => selectedTargets?.includes(candidate) || !PACKAGING_TOOL_TARGETS.includes(candidate));
|
|
4835
4837
|
return targets.some((candidate) => selectedTargets.includes(candidate));
|
|
4836
4838
|
};
|
|
4837
4839
|
const getSelectedGitignoreEntryTargets = (target, selectedTargets) => {
|
|
4838
4840
|
const targets = normalizeGitignoreEntryTargets(target);
|
|
4839
4841
|
if (targets.includes("common")) return ["common"];
|
|
4840
|
-
if (!selectedTargets || selectedTargets.length === 0 || selectedTargets.includes("*")) return targets;
|
|
4842
|
+
if (!selectedTargets || selectedTargets.length === 0 || selectedTargets.includes("*")) return targets.filter((candidate) => selectedTargets?.includes(candidate) || !PACKAGING_TOOL_TARGETS.includes(candidate));
|
|
4841
4843
|
return targets.filter((candidate) => selectedTargets.includes(candidate));
|
|
4842
4844
|
};
|
|
4843
4845
|
const isFeatureSelected = (feature, features) => {
|
|
@@ -5158,16 +5160,13 @@ async function createConfigFile() {
|
|
|
5158
5160
|
await writeFileContent(path, JSON.stringify({
|
|
5159
5161
|
$schema: RULESYNC_CONFIG_SCHEMA_URL,
|
|
5160
5162
|
targets: [
|
|
5161
|
-
"
|
|
5162
|
-
"cursor",
|
|
5163
|
+
"codexcli",
|
|
5163
5164
|
"claudecode",
|
|
5164
|
-
"
|
|
5165
|
+
"opencode"
|
|
5165
5166
|
],
|
|
5166
5167
|
features: [
|
|
5167
5168
|
"rules",
|
|
5168
|
-
"ignore",
|
|
5169
5169
|
"mcp",
|
|
5170
|
-
"commands",
|
|
5171
5170
|
"subagents",
|
|
5172
5171
|
"skills",
|
|
5173
5172
|
"hooks",
|
|
@@ -5195,10 +5194,6 @@ async function createSampleFiles() {
|
|
|
5195
5194
|
name: "overview"
|
|
5196
5195
|
}),
|
|
5197
5196
|
createFeatureScaffold({ feature: "mcp" }),
|
|
5198
|
-
createFeatureScaffold({
|
|
5199
|
-
feature: "command",
|
|
5200
|
-
name: "review-pr"
|
|
5201
|
-
}),
|
|
5202
5197
|
createFeatureScaffold({
|
|
5203
5198
|
feature: "subagent",
|
|
5204
5199
|
name: "planner"
|
|
@@ -5207,21 +5202,24 @@ async function createSampleFiles() {
|
|
|
5207
5202
|
feature: "skill",
|
|
5208
5203
|
name: "project-context"
|
|
5209
5204
|
}),
|
|
5210
|
-
createFeatureScaffold({ feature: "ignore" }),
|
|
5211
5205
|
createFeatureScaffold({ feature: "hooks" }),
|
|
5212
5206
|
createFeatureScaffold({ feature: "permissions" })
|
|
5213
5207
|
];
|
|
5214
5208
|
const results = [];
|
|
5215
5209
|
for (const sample of samples) {
|
|
5216
5210
|
await ensureDir(dirname(sample.relativeFilePath));
|
|
5217
|
-
results.push(await writeIfNotExists(
|
|
5211
|
+
results.push(await writeIfNotExists({
|
|
5212
|
+
path: sample.relativeFilePath,
|
|
5213
|
+
candidatePaths: sample.candidateRelativeFilePaths,
|
|
5214
|
+
content: sample.content
|
|
5215
|
+
}));
|
|
5218
5216
|
}
|
|
5219
5217
|
return results;
|
|
5220
5218
|
}
|
|
5221
|
-
async function writeIfNotExists(path, content) {
|
|
5222
|
-
if (await fileExists(
|
|
5219
|
+
async function writeIfNotExists({ path, candidatePaths, content }) {
|
|
5220
|
+
for (const candidatePath of candidatePaths) if (await fileExists(candidatePath)) return {
|
|
5223
5221
|
created: false,
|
|
5224
|
-
path
|
|
5222
|
+
path: candidatePath
|
|
5225
5223
|
};
|
|
5226
5224
|
await writeFileContent(path, content);
|
|
5227
5225
|
return {
|
|
@@ -5257,7 +5255,7 @@ async function initCommand(logger) {
|
|
|
5257
5255
|
}
|
|
5258
5256
|
logger.success("rulesync initialized successfully!");
|
|
5259
5257
|
logger.info("Next steps:");
|
|
5260
|
-
logger.info(`1. Edit ${RULESYNC_RELATIVE_DIR_PATH}/**/*.md, ${RULESYNC_RELATIVE_DIR_PATH}/skills/*/${SKILL_FILE_NAME$1}, ${RULESYNC_MCP_RELATIVE_FILE_PATH}, ${RULESYNC_HOOKS_RELATIVE_FILE_PATH}
|
|
5258
|
+
logger.info(`1. Edit ${RULESYNC_RELATIVE_DIR_PATH}/**/*.md, ${RULESYNC_RELATIVE_DIR_PATH}/skills/*/${SKILL_FILE_NAME$1}, ${RULESYNC_MCP_RELATIVE_FILE_PATH}, ${RULESYNC_HOOKS_RELATIVE_FILE_PATH} and ${RULESYNC_PERMISSIONS_RELATIVE_FILE_PATH}`);
|
|
5261
5259
|
logger.info("2. Run 'rulesync generate' to create configuration files");
|
|
5262
5260
|
}
|
|
5263
5261
|
//#endregion
|
|
@@ -7235,17 +7233,16 @@ async function getHooksFile() {
|
|
|
7235
7233
|
async function putHooksFile({ content }) {
|
|
7236
7234
|
if (content.length > maxHooksSizeBytes) throw new Error(`Hooks file size ${content.length} bytes exceeds maximum ${maxHooksSizeBytes} bytes (1MB) for ${RULESYNC_HOOKS_RELATIVE_FILE_PATH}`);
|
|
7237
7235
|
try {
|
|
7238
|
-
|
|
7236
|
+
parseJsonc(content);
|
|
7239
7237
|
} catch (error) {
|
|
7240
|
-
throw new Error(`Invalid
|
|
7238
|
+
throw new Error(`Invalid JSONC format in hooks file (${RULESYNC_HOOKS_RELATIVE_FILE_PATH}): ${formatError(error)}`, { cause: error });
|
|
7241
7239
|
}
|
|
7242
7240
|
try {
|
|
7243
7241
|
const outputRoot = process.cwd();
|
|
7244
|
-
const
|
|
7245
|
-
|
|
7246
|
-
|
|
7247
|
-
|
|
7248
|
-
const relativeFilePath = paths.relativeFilePath;
|
|
7242
|
+
const { relativeDirPath, relativeFilePath } = await resolveRulesyncSourceWritePath({
|
|
7243
|
+
outputRoot,
|
|
7244
|
+
paths: RulesyncHooks.getSettablePaths()
|
|
7245
|
+
});
|
|
7249
7246
|
const fullPath = join(outputRoot, relativeDirPath, relativeFilePath);
|
|
7250
7247
|
const rulesyncHooks = new RulesyncHooks({
|
|
7251
7248
|
outputRoot,
|
|
@@ -7271,9 +7268,8 @@ async function deleteHooksFile() {
|
|
|
7271
7268
|
try {
|
|
7272
7269
|
const outputRoot = process.cwd();
|
|
7273
7270
|
const paths = RulesyncHooks.getSettablePaths();
|
|
7274
|
-
await removeFile(join(outputRoot,
|
|
7275
|
-
|
|
7276
|
-
return { relativePathFromCwd: join(paths.relativeDirPath, paths.relativeFilePath) };
|
|
7271
|
+
for (const candidate of getRulesyncSourceCandidates({ paths })) await removeFile(join(outputRoot, candidate.relativeDirPath, candidate.relativeFilePath));
|
|
7272
|
+
return { relativePathFromCwd: join(paths.recommended.relativeDirPath, paths.recommended.relativeFilePath) };
|
|
7277
7273
|
} catch (error) {
|
|
7278
7274
|
throw new Error(`Failed to delete hooks file (${RULESYNC_HOOKS_RELATIVE_FILE_PATH}): ${formatError(error)}`, { cause: error });
|
|
7279
7275
|
}
|
|
@@ -7301,7 +7297,7 @@ const hooksTools = {
|
|
|
7301
7297
|
},
|
|
7302
7298
|
putHooksFile: {
|
|
7303
7299
|
name: "putHooksFile",
|
|
7304
|
-
description: "Create or update the hooks configuration file (upsert operation). content parameter is required and must be valid
|
|
7300
|
+
description: "Create or update the hooks configuration file (upsert operation). content parameter is required and must be valid JSONC.",
|
|
7305
7301
|
parameters: hooksToolSchemas.putHooksFile,
|
|
7306
7302
|
execute: async (args) => {
|
|
7307
7303
|
const result = await putHooksFile({ content: args.content });
|
|
@@ -7517,17 +7513,16 @@ async function getMcpFile() {
|
|
|
7517
7513
|
async function putMcpFile({ content }) {
|
|
7518
7514
|
if (content.length > maxMcpSizeBytes) throw new Error(`MCP file size ${content.length} bytes exceeds maximum ${maxMcpSizeBytes} bytes (1MB) for ${RULESYNC_MCP_RELATIVE_FILE_PATH}`);
|
|
7519
7515
|
try {
|
|
7520
|
-
|
|
7516
|
+
parseJsonc(content);
|
|
7521
7517
|
} catch (error) {
|
|
7522
|
-
throw new Error(`Invalid
|
|
7518
|
+
throw new Error(`Invalid JSONC format in MCP file (${RULESYNC_MCP_RELATIVE_FILE_PATH}): ${formatError(error)}`, { cause: error });
|
|
7523
7519
|
}
|
|
7524
7520
|
try {
|
|
7525
7521
|
const outputRoot = process.cwd();
|
|
7526
|
-
const
|
|
7527
|
-
|
|
7528
|
-
|
|
7529
|
-
|
|
7530
|
-
const relativeFilePath = paths.recommended.relativeFilePath;
|
|
7522
|
+
const { relativeDirPath, relativeFilePath } = await resolveRulesyncSourceWritePath({
|
|
7523
|
+
outputRoot,
|
|
7524
|
+
paths: RulesyncMcp.getSettablePaths()
|
|
7525
|
+
});
|
|
7531
7526
|
const fullPath = join(outputRoot, relativeDirPath, relativeFilePath);
|
|
7532
7527
|
const rulesyncMcp = new RulesyncMcp({
|
|
7533
7528
|
outputRoot,
|
|
@@ -7553,11 +7548,7 @@ async function deleteMcpFile() {
|
|
|
7553
7548
|
try {
|
|
7554
7549
|
const outputRoot = process.cwd();
|
|
7555
7550
|
const paths = RulesyncMcp.getSettablePaths();
|
|
7556
|
-
const
|
|
7557
|
-
const legacyPath = join(outputRoot, paths.legacy.relativeDirPath, paths.legacy.relativeFilePath);
|
|
7558
|
-
await removeFile(recommendedPath);
|
|
7559
|
-
await removeFile(join(outputRoot, paths.jsonc.relativeDirPath, paths.jsonc.relativeFilePath));
|
|
7560
|
-
await removeFile(legacyPath);
|
|
7551
|
+
for (const candidate of getRulesyncSourceCandidates({ paths })) await removeFile(join(outputRoot, candidate.relativeDirPath, candidate.relativeFilePath));
|
|
7561
7552
|
return { relativePathFromCwd: join(paths.recommended.relativeDirPath, paths.recommended.relativeFilePath) };
|
|
7562
7553
|
} catch (error) {
|
|
7563
7554
|
throw new Error(`Failed to delete MCP file (${RULESYNC_MCP_RELATIVE_FILE_PATH}): ${formatError(error)}`, { cause: error });
|
|
@@ -7586,7 +7577,7 @@ const mcpTools = {
|
|
|
7586
7577
|
},
|
|
7587
7578
|
putMcpFile: {
|
|
7588
7579
|
name: "putMcpFile",
|
|
7589
|
-
description: "Create or update the MCP configuration file (upsert operation). content parameter is required and must be valid
|
|
7580
|
+
description: "Create or update the MCP configuration file (upsert operation). content parameter is required and must be valid JSONC.",
|
|
7590
7581
|
parameters: mcpToolSchemas.putMcpFile,
|
|
7591
7582
|
execute: async (args) => {
|
|
7592
7583
|
const result = await putMcpFile({ content: args.content });
|
|
@@ -7626,17 +7617,16 @@ async function getPermissionsFile() {
|
|
|
7626
7617
|
async function putPermissionsFile({ content }) {
|
|
7627
7618
|
if (content.length > maxPermissionsSizeBytes) throw new Error(`Permissions file size ${content.length} bytes exceeds maximum ${maxPermissionsSizeBytes} bytes (1MB) for ${RULESYNC_PERMISSIONS_RELATIVE_FILE_PATH}`);
|
|
7628
7619
|
try {
|
|
7629
|
-
|
|
7620
|
+
parseJsonc(content);
|
|
7630
7621
|
} catch (error) {
|
|
7631
|
-
throw new Error(`Invalid
|
|
7622
|
+
throw new Error(`Invalid JSONC format in permissions file (${RULESYNC_PERMISSIONS_RELATIVE_FILE_PATH}): ${formatError(error)}`, { cause: error });
|
|
7632
7623
|
}
|
|
7633
7624
|
try {
|
|
7634
7625
|
const outputRoot = process.cwd();
|
|
7635
|
-
const
|
|
7636
|
-
|
|
7637
|
-
|
|
7638
|
-
|
|
7639
|
-
const relativeFilePath = paths.relativeFilePath;
|
|
7626
|
+
const { relativeDirPath, relativeFilePath } = await resolveRulesyncSourceWritePath({
|
|
7627
|
+
outputRoot,
|
|
7628
|
+
paths: RulesyncPermissions.getSettablePaths()
|
|
7629
|
+
});
|
|
7640
7630
|
const fullPath = join(outputRoot, relativeDirPath, relativeFilePath);
|
|
7641
7631
|
const rulesyncPermissions = new RulesyncPermissions({
|
|
7642
7632
|
outputRoot,
|
|
@@ -7662,9 +7652,8 @@ async function deletePermissionsFile() {
|
|
|
7662
7652
|
try {
|
|
7663
7653
|
const outputRoot = process.cwd();
|
|
7664
7654
|
const paths = RulesyncPermissions.getSettablePaths();
|
|
7665
|
-
await removeFile(join(outputRoot,
|
|
7666
|
-
|
|
7667
|
-
return { relativePathFromCwd: join(paths.relativeDirPath, paths.relativeFilePath) };
|
|
7655
|
+
for (const candidate of getRulesyncSourceCandidates({ paths })) await removeFile(join(outputRoot, candidate.relativeDirPath, candidate.relativeFilePath));
|
|
7656
|
+
return { relativePathFromCwd: join(paths.recommended.relativeDirPath, paths.recommended.relativeFilePath) };
|
|
7668
7657
|
} catch (error) {
|
|
7669
7658
|
throw new Error(`Failed to delete permissions file (${RULESYNC_PERMISSIONS_RELATIVE_FILE_PATH}): ${formatError(error)}`, { cause: error });
|
|
7670
7659
|
}
|
|
@@ -7692,7 +7681,7 @@ const permissionsTools = {
|
|
|
7692
7681
|
},
|
|
7693
7682
|
putPermissionsFile: {
|
|
7694
7683
|
name: "putPermissionsFile",
|
|
7695
|
-
description: "Create or update the permissions configuration file (upsert operation). content parameter is required and must be valid
|
|
7684
|
+
description: "Create or update the permissions configuration file (upsert operation). content parameter is required and must be valid JSONC.",
|
|
7696
7685
|
parameters: permissionsToolSchemas.putPermissionsFile,
|
|
7697
7686
|
execute: async (args) => {
|
|
7698
7687
|
const result = await putPermissionsFile({ content: args.content });
|
|
@@ -8989,8 +8978,9 @@ function wrapCommand$1({ name, errorCode, handler, getVersion, loggerFactory = c
|
|
|
8989
8978
|
};
|
|
8990
8979
|
}
|
|
8991
8980
|
//#endregion
|
|
8992
|
-
//#region src/cli/
|
|
8993
|
-
const getVersion = () => "
|
|
8981
|
+
//#region src/cli/program.ts
|
|
8982
|
+
const getVersion = () => "15.0.1";
|
|
8983
|
+
const FEATURES_HELP = `${ALL_FEATURES.join(",")}; ignore is deprecated, use permissions`;
|
|
8994
8984
|
function wrapCommand(name, errorCode, handler) {
|
|
8995
8985
|
return wrapCommand$1({
|
|
8996
8986
|
name,
|
|
@@ -8999,14 +8989,14 @@ function wrapCommand(name, errorCode, handler) {
|
|
|
8999
8989
|
getVersion
|
|
9000
8990
|
});
|
|
9001
8991
|
}
|
|
9002
|
-
|
|
8992
|
+
function createProgram() {
|
|
9003
8993
|
const program = new Command();
|
|
9004
8994
|
const version = getVersion();
|
|
9005
8995
|
program.name("rulesync").description("Unified AI rules management CLI tool").version(version, "-v, --version", "Show version").option("-j, --json", "Output results as JSON");
|
|
9006
8996
|
program.command("init").description("Initialize rulesync in current directory").option("-V, --verbose", "Verbose output").option("-s, --silent", "Suppress all output").action(wrapCommand("init", "INIT_FAILED", async (logger) => {
|
|
9007
8997
|
await initCommand(logger);
|
|
9008
8998
|
}));
|
|
9009
|
-
program.command("gitignore").description("Add generated files to .gitignore").option("-t, --targets <tools>", "Comma-separated list of tools to include (e.g., 'claudecode,copilot' or '*' for all)", parseCommaSeparatedList).option("-f, --features <features>", `Comma-separated list of features to include (${
|
|
8999
|
+
program.command("gitignore").description("Add generated files to .gitignore").option("-t, --targets <tools>", "Comma-separated list of tools to include (e.g., 'claudecode,copilot' or '*' for all)", parseCommaSeparatedList).option("-f, --features <features>", `Comma-separated list of features to include (${FEATURES_HELP}) or '*' for all`, parseCommaSeparatedList).option("-V, --verbose", "Verbose output").option("-s, --silent", "Suppress all output").action(wrapCommand("gitignore", "GITIGNORE_FAILED", async (logger, options) => {
|
|
9010
9000
|
const cliTargets = options.targets;
|
|
9011
9001
|
const cliFeatures = options.features;
|
|
9012
9002
|
const resolvedTargets = await resolveGitignoreTargets({ cliTargets });
|
|
@@ -9017,7 +9007,7 @@ const main = async () => {
|
|
|
9017
9007
|
silent: options.silent
|
|
9018
9008
|
});
|
|
9019
9009
|
}));
|
|
9020
|
-
program.command("add <source>").description("Add a Rulesync feature file or install a declarative rule or skill source").option("--name <name>", "Name for a rule, command, subagent, skill, or check scaffold").option("-f, --force", "Overwrite an existing scaffold file without prompting").option("--skills <skills>", "Comma-separated skill names to install", parseCommaSeparatedList).option("--rules <rules>", "Comma-separated rule names to install", parseCommaSeparatedList).option("--transport <transport>", "Source transport: github, git, or npm").option("-r, --ref <ref>", "Git ref, npm version, or npm dist-tag").option("-p, --path <path>", "Skills path within the source").option("--rules-path <path>", "Rules path within the source").option("--registry <url>", "npm-compatible registry URL").option("--token-env <name>", "Environment variable containing the npm registry token").option("--token <token>", "GitHub token for private repositories").option("-c, --config <path>", "Path to configuration file").option("-V, --verbose", "Verbose output").option("-s, --silent", "Suppress all output").action(wrapCommand("add", "ADD_FAILED", async (logger, options, _globalOpts, positionalArgs) => {
|
|
9010
|
+
program.command("add <source>").description("Add a Rulesync feature file (ignore is deprecated; use permissions) or install a declarative rule or skill source").option("--name <name>", "Name for a rule, command, subagent, skill, or check scaffold").option("-f, --force", "Overwrite an existing scaffold file without prompting").option("--skills <skills>", "Comma-separated skill names to install", parseCommaSeparatedList).option("--rules <rules>", "Comma-separated rule names to install", parseCommaSeparatedList).option("--transport <transport>", "Source transport: github, git, or npm").option("-r, --ref <ref>", "Git ref, npm version, or npm dist-tag").option("-p, --path <path>", "Skills path within the source").option("--rules-path <path>", "Rules path within the source").option("--registry <url>", "npm-compatible registry URL").option("--token-env <name>", "Environment variable containing the npm registry token").option("--token <token>", "GitHub token for private repositories").option("-c, --config <path>", "Path to configuration file").option("-V, --verbose", "Verbose output").option("-s, --silent", "Suppress all output").action(wrapCommand("add", "ADD_FAILED", async (logger, options, _globalOpts, positionalArgs) => {
|
|
9021
9011
|
const source = positionalArgs[0];
|
|
9022
9012
|
const addOptions = options;
|
|
9023
9013
|
await addCommand(logger, {
|
|
@@ -9026,17 +9016,21 @@ const main = async () => {
|
|
|
9026
9016
|
configPath: addOptions.config
|
|
9027
9017
|
});
|
|
9028
9018
|
}));
|
|
9029
|
-
program.command("fetch <source>").description("Fetch files from a Git repository (GitHub/GitLab)").option("-t, --target <target>", "Target format to interpret files as (e.g., 'rulesync', 'claudecode'). Default: rulesync").option("-f, --features <features>", `Comma-separated list of features to fetch (${
|
|
9019
|
+
program.command("fetch <source>").description("Fetch files from a Git repository (GitHub/GitLab)").option("-t, --target <target>", "Target format to interpret files as (e.g., 'rulesync', 'claudecode'). Default: rulesync").option("-f, --features <features>", `Comma-separated list of features to fetch (${FEATURES_HELP}) or '*' for all. Default: skills`, parseCommaSeparatedList).option("-r, --ref <ref>", "Branch, tag, or commit SHA to fetch from").option("-p, --path <path>", "Subdirectory path within the repository").option("-o, --output <dir>", "Output directory (default: .rulesync)").option("-c, --conflict <strategy>", "Conflict resolution strategy: skip, overwrite (default: overwrite)").option("--token <token>", "Git provider token for private repositories").option("-V, --verbose", "Verbose output").option("-s, --silent", "Suppress all output").action(wrapCommand("fetch", "FETCH_FAILED", async (logger, options, _globalOpts, positionalArgs) => {
|
|
9030
9020
|
const source = positionalArgs[0];
|
|
9031
9021
|
await fetchCommand(logger, {
|
|
9032
9022
|
...options,
|
|
9033
9023
|
source
|
|
9034
9024
|
});
|
|
9035
9025
|
}));
|
|
9036
|
-
program.command("import").description("Import configurations from AI tools to rulesync format").option("-t, --targets <tool>", "Tool to import from (e.g., 'copilot', 'cursor', 'cline')", parseCommaSeparatedList).option("-f, --features <features>", `Comma-separated list of features to import (${
|
|
9037
|
-
|
|
9026
|
+
program.command("import").description("Import configurations from AI tools to rulesync format").option("-t, --targets <tool>", "Tool to import from (e.g., 'copilot', 'cursor', 'cline')", parseCommaSeparatedList).option("-f, --features <features>", `Comma-separated list of features to import (${FEATURES_HELP}) or '*' for all`, parseCommaSeparatedList).option("-V, --verbose", "Verbose output").option("-s, --silent", "Suppress all output").option("-g, --global", "Import for global(user scope) configuration files").option("-o, --output-root <path>", "Root directory containing the tool configuration to import").action(wrapCommand("import", "IMPORT_FAILED", async (logger, options) => {
|
|
9027
|
+
const { outputRoot, ...importOptions } = options;
|
|
9028
|
+
await importCommand(logger, {
|
|
9029
|
+
...importOptions,
|
|
9030
|
+
outputRoots: outputRoot ? [outputRoot] : void 0
|
|
9031
|
+
});
|
|
9038
9032
|
}));
|
|
9039
|
-
program.command("convert").description("Convert configurations from one AI tool to other AI tools without writing .rulesync/ files").requiredOption("--from <tool>", "Source tool to convert from (e.g., 'cursor', 'claudecode')").requiredOption("--to <tools>", "Comma-separated list of destination tools (e.g., 'copilot,claudecode')", parseCommaSeparatedList).option("-f, --features <features>", `Comma-separated list of features to convert (${
|
|
9033
|
+
program.command("convert").description("Convert configurations from one AI tool to other AI tools without writing .rulesync/ files").requiredOption("--from <tool>", "Source tool to convert from (e.g., 'cursor', 'claudecode')").requiredOption("--to <tools>", "Comma-separated list of destination tools (e.g., 'copilot,claudecode')", parseCommaSeparatedList).option("-f, --features <features>", `Comma-separated list of features to convert (${FEATURES_HELP}) or '*' for all`, parseCommaSeparatedList).option("-V, --verbose", "Verbose output").option("-s, --silent", "Suppress all output").option("-g, --global", "Convert for global(user scope) configuration files").option("--dry-run", "Dry run: show changes without writing files").action(wrapCommand("convert", "CONVERT_FAILED", async (logger, options) => {
|
|
9040
9034
|
await convertCommand(logger, options);
|
|
9041
9035
|
}));
|
|
9042
9036
|
program.command("mcp").description("Start MCP server for rulesync").action(wrapCommand("mcp", "MCP_FAILED", async (logger, _options) => {
|
|
@@ -9054,20 +9048,25 @@ const main = async () => {
|
|
|
9054
9048
|
silent: options.silent
|
|
9055
9049
|
});
|
|
9056
9050
|
}));
|
|
9057
|
-
program.command("generate").description("Generate configuration files for AI tools").option("-t, --targets <tools>", "Comma-separated list of tools to generate for (e.g., 'copilot,cursor,cline' or '*' for all)", parseCommaSeparatedList).option("-f, --features <features>", `Comma-separated list of features to generate (${
|
|
9051
|
+
program.command("generate").description("Generate configuration files for AI tools").option("-t, --targets <tools>", "Comma-separated list of tools to generate for (e.g., 'copilot,cursor,cline' or '*' for all)", parseCommaSeparatedList).option("-f, --features <features>", `Comma-separated list of features to generate (${FEATURES_HELP}) or '*' for all`, parseCommaSeparatedList).option("--delete", "Delete all existing files in output directories before generating").option("-o, --output-roots <paths>", "Output root directories to generate files into (comma-separated for multiple paths)", parseCommaSeparatedList).option("-V, --verbose", "Verbose output").option("-s, --silent", "Suppress all output").option("-c, --config <path>", "Path to configuration file").option("-g, --global", "Generate for global(user scope) configuration files").option("--simulate-commands", "Generate simulated commands. This feature is only available for copilot, cursor and codexcli.").option("--simulate-subagents", "Generate simulated subagents. This feature is only available for copilot and codexcli.").option("--simulate-skills", "Generate simulated skills. This feature is only available for copilot, cursor and codexcli.").option("--input-root <path>", "Path to the directory containing .rulesync/ (parent of .rulesync/)").option("--dry-run", "Dry run: show changes without writing files").option("--check", "Check if files are up to date (exits with code 1 if changes needed)").action(wrapCommand("generate", "GENERATION_FAILED", async (logger, options) => {
|
|
9058
9052
|
await generateCommand(logger, options);
|
|
9059
9053
|
}));
|
|
9060
9054
|
program.command("update").description("Update rulesync to the latest version").option("--check", "Check for updates without installing").option("--force", "Force update even if already at latest version").option("--token <token>", "GitHub token for API access").option("-V, --verbose", "Verbose output").option("-s, --silent", "Suppress all output").action(wrapCommand("update", "UPDATE_FAILED", async (logger, options) => {
|
|
9061
9055
|
await updateCommand(logger, version, options);
|
|
9062
9056
|
}));
|
|
9063
|
-
program
|
|
9064
|
-
}
|
|
9057
|
+
return program;
|
|
9058
|
+
}
|
|
9065
9059
|
function parseInstallMode(raw) {
|
|
9066
9060
|
if (raw === void 0) return void 0;
|
|
9067
9061
|
const match = INSTALL_MODES.find((m) => m === raw);
|
|
9068
9062
|
if (!match) throw new Error(`Invalid --mode value "${raw}". Expected one of: ${INSTALL_MODES.join(", ")}.`);
|
|
9069
9063
|
return match;
|
|
9070
9064
|
}
|
|
9065
|
+
//#endregion
|
|
9066
|
+
//#region src/cli/index.ts
|
|
9067
|
+
async function main() {
|
|
9068
|
+
createProgram().parse();
|
|
9069
|
+
}
|
|
9071
9070
|
main().catch((error) => {
|
|
9072
9071
|
console.error(formatError(error));
|
|
9073
9072
|
process.exit(1);
|