rulesync 21.0.0 → 23.0.0
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 +1 -1
- package/dist/cli/index.cjs +7 -7
- package/dist/cli/index.js +7 -7
- package/dist/cli/index.js.map +1 -1
- package/dist/{import-CSKYRGa5.js → import-CGIOcUpR.js} +836 -307
- package/dist/import-CGIOcUpR.js.map +1 -0
- package/dist/{import-CGT8v9bO.cjs → import-CeSvBhiv.cjs} +835 -306
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/dist/import-CSKYRGa5.js.map +0 -1
|
@@ -2703,6 +2703,7 @@ var Config = class Config {
|
|
|
2703
2703
|
*/
|
|
2704
2704
|
objectFormTargetKeys;
|
|
2705
2705
|
configFileTargets;
|
|
2706
|
+
configFileSelection;
|
|
2706
2707
|
verbose;
|
|
2707
2708
|
delete;
|
|
2708
2709
|
global;
|
|
@@ -2737,7 +2738,7 @@ var Config = class Config {
|
|
|
2737
2738
|
inputRoots;
|
|
2738
2739
|
configFilePath;
|
|
2739
2740
|
sources;
|
|
2740
|
-
constructor({ outputRoots, targets, features, verbose, delete: isDelete, global, silent, simulateCommands, simulateSubagents, simulateSkills, preserveUnownedHooks, deriveSubprojectPathFromGlobs, flattenedCommandNaming, language, gitignoreTargetsOnly, gitignoreDestination, dryRun, check, inputRoot, inputRoots, configFilePath, sources, configFileTargets }) {
|
|
2741
|
+
constructor({ outputRoots, targets, features, verbose, delete: isDelete, global, silent, simulateCommands, simulateSubagents, simulateSkills, preserveUnownedHooks, deriveSubprojectPathFromGlobs, flattenedCommandNaming, language, gitignoreTargetsOnly, gitignoreDestination, dryRun, check, inputRoot, inputRoots, configFilePath, sources, configFileTargets, configFileSelection }) {
|
|
2741
2742
|
assertTargetsFeaturesExclusive({
|
|
2742
2743
|
targets,
|
|
2743
2744
|
features
|
|
@@ -2762,6 +2763,7 @@ var Config = class Config {
|
|
|
2762
2763
|
this.features = resolvedFeatures;
|
|
2763
2764
|
this.objectFormTargetKeys = isRulesyncConfigTargetsObject(resolvedTargets) ? Config.filterValidToolTargets(Object.keys(resolvedTargets)) : void 0;
|
|
2764
2765
|
this.configFileTargets = configFileTargets;
|
|
2766
|
+
this.configFileSelection = configFileSelection;
|
|
2765
2767
|
this.verbose = verbose;
|
|
2766
2768
|
this.delete = isDelete;
|
|
2767
2769
|
this.global = global ?? false;
|
|
@@ -2852,17 +2854,54 @@ var Config = class Config {
|
|
|
2852
2854
|
getConfigFileTargets() {
|
|
2853
2855
|
return this.configFileTargets ?? this.getTargets();
|
|
2854
2856
|
}
|
|
2857
|
+
/**
|
|
2858
|
+
* The features `target` has for a run over the configuration file's
|
|
2859
|
+
* targets, i.e. what `rulesync generate` without `--targets` would produce
|
|
2860
|
+
* for it (a CLI `--features` still applies to array-form targets). Falls
|
|
2861
|
+
* back to {@link getFeatures} when no configuration file declared `targets`.
|
|
2862
|
+
*/
|
|
2863
|
+
getConfigFileFeatures(target) {
|
|
2864
|
+
const selection = this.configFileSelection;
|
|
2865
|
+
if (selection === void 0) return this.getFeatures(target);
|
|
2866
|
+
return Config.resolveTargetFeatures({
|
|
2867
|
+
targets: selection.targets,
|
|
2868
|
+
features: selection.features ?? [],
|
|
2869
|
+
target
|
|
2870
|
+
});
|
|
2871
|
+
}
|
|
2872
|
+
/**
|
|
2873
|
+
* The options `target` sets for `feature` in the configuration file, for
|
|
2874
|
+
* the same run as {@link getConfigFileFeatures}. Falls back to
|
|
2875
|
+
* {@link getFeatureOptions} when no configuration file declared `targets`.
|
|
2876
|
+
*/
|
|
2877
|
+
getConfigFileFeatureOptions(target, feature) {
|
|
2878
|
+
const selection = this.configFileSelection;
|
|
2879
|
+
if (selection === void 0) return this.getFeatureOptions(target, feature);
|
|
2880
|
+
return Config.resolveFeatureOptions({
|
|
2881
|
+
targets: selection.targets,
|
|
2882
|
+
target,
|
|
2883
|
+
feature
|
|
2884
|
+
});
|
|
2885
|
+
}
|
|
2855
2886
|
getFeatures(target) {
|
|
2856
|
-
if (
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
|
|
2860
|
-
|
|
2861
|
-
|
|
2862
|
-
|
|
2887
|
+
if (target) return Config.resolveTargetFeatures({
|
|
2888
|
+
targets: this.targets,
|
|
2889
|
+
features: this.features,
|
|
2890
|
+
target
|
|
2891
|
+
});
|
|
2892
|
+
if (isRulesyncConfigTargetsObject(this.targets)) return Config.collectAllFeatures(Object.values(this.targets));
|
|
2893
|
+
return Config.normalizeFeatureList(this.features);
|
|
2894
|
+
}
|
|
2895
|
+
static resolveTargetFeatures({ targets, features, target }) {
|
|
2896
|
+
if (isRulesyncConfigTargetsObject(targets)) {
|
|
2897
|
+
const value = targets[target];
|
|
2898
|
+
return value ? Config.normalizeTargetFeatures(value) : [];
|
|
2863
2899
|
}
|
|
2864
|
-
|
|
2865
|
-
|
|
2900
|
+
return Config.normalizeFeatureList(features);
|
|
2901
|
+
}
|
|
2902
|
+
static normalizeFeatureList(features) {
|
|
2903
|
+
if (features.includes("*")) return [...ALL_FEATURES];
|
|
2904
|
+
return features.filter((feature) => feature !== "*");
|
|
2866
2905
|
}
|
|
2867
2906
|
/**
|
|
2868
2907
|
* Normalize a per-target features value (array or per-feature object) into
|
|
@@ -2903,7 +2942,14 @@ var Config = class Config {
|
|
|
2903
2942
|
* feature is not enabled for the given target.
|
|
2904
2943
|
*/
|
|
2905
2944
|
getFeatureOptions(target, feature) {
|
|
2906
|
-
|
|
2945
|
+
return Config.resolveFeatureOptions({
|
|
2946
|
+
targets: this.targets,
|
|
2947
|
+
target,
|
|
2948
|
+
feature
|
|
2949
|
+
});
|
|
2950
|
+
}
|
|
2951
|
+
static resolveFeatureOptions({ targets, target, feature }) {
|
|
2952
|
+
const value = isRulesyncConfigTargetsObject(targets) ? targets[target] : void 0;
|
|
2907
2953
|
if (!value || Array.isArray(value)) return;
|
|
2908
2954
|
const featureValue = value[feature];
|
|
2909
2955
|
if (featureValue && typeof featureValue === "object" && isFeatureValueEnabled(featureValue)) return featureValue;
|
|
@@ -3338,7 +3384,15 @@ var ConfigResolver = class {
|
|
|
3338
3384
|
sources: configByFile.sources ?? getDefaults().sources,
|
|
3339
3385
|
flattenedCommandNaming: configByFile.flattenedCommandNaming ?? getDefaults().flattenedCommandNaming,
|
|
3340
3386
|
language: configByFile.language,
|
|
3341
|
-
configFileTargets: extractConfigFileTargets(configByFile.targets)
|
|
3387
|
+
configFileTargets: extractConfigFileTargets(configByFile.targets),
|
|
3388
|
+
configFileSelection: configByFile.targets === void 0 ? void 0 : {
|
|
3389
|
+
targets: configByFile.targets,
|
|
3390
|
+
features: resolveFeaturesAndTargets({
|
|
3391
|
+
features,
|
|
3392
|
+
targets: void 0,
|
|
3393
|
+
configByFile
|
|
3394
|
+
}).resolvedFeatures
|
|
3395
|
+
}
|
|
3342
3396
|
});
|
|
3343
3397
|
}
|
|
3344
3398
|
};
|
|
@@ -12270,7 +12324,7 @@ const CODEXCLI_AGENTS_DIR_PATH = join(CODEXCLI_DIR, "agents");
|
|
|
12270
12324
|
const CODEXCLI_SKILLS_DIR_PATH = join(".agents", "skills");
|
|
12271
12325
|
const CODEXCLI_HOOKS_FILE_NAME = "hooks.json";
|
|
12272
12326
|
const CODEXCLI_MCP_FILE_NAME = "config.toml";
|
|
12273
|
-
const
|
|
12327
|
+
const CODEXCLI_PROJECT_DOC_MAX_BYTES = 32768;
|
|
12274
12328
|
const CODEXCLI_BASH_RULES_FILE_NAME = "rulesync.rules";
|
|
12275
12329
|
const CODEXCLI_OPENAI_YAML_RELATIVE_PATH = join("agents", "openai.yaml");
|
|
12276
12330
|
const CODEXCLI_OVERRIDE_KEYS = [
|
|
@@ -14940,6 +14994,7 @@ const ANTIGRAVITY_GLOBAL_AGENTS_DIR_PATH = join(ANTIGRAVITY_GLOBAL_CONFIG_DIR_PA
|
|
|
14940
14994
|
const ANTIGRAVITY_AGENTS_DIR = ANTIGRAVITY_DIR;
|
|
14941
14995
|
const ANTIGRAVITY_RULE_FILE_NAME = "AGENTS.md";
|
|
14942
14996
|
const ANTIGRAVITY_GLOBAL_RULE_FILE_NAME = "GEMINI.md";
|
|
14997
|
+
const ANTIGRAVITY_GLOBAL_RULES_SUBDIR = join(ANTIGRAVITY_GLOBAL_CONFIG_SUBDIR, "rules");
|
|
14943
14998
|
//#endregion
|
|
14944
14999
|
//#region src/features/commands/antigravity-command.ts
|
|
14945
15000
|
const AntigravityWorkflowFrontmatterSchema = z.looseObject({
|
|
@@ -15455,12 +15510,50 @@ var BobCommand = class BobCommand extends ToolCommand {
|
|
|
15455
15510
|
}
|
|
15456
15511
|
};
|
|
15457
15512
|
//#endregion
|
|
15513
|
+
//#region src/features/shared/claudecode-argument-hint.ts
|
|
15514
|
+
/**
|
|
15515
|
+
* Turns a YAML-list `argument-hint` back into the bracketed string form Claude
|
|
15516
|
+
* Code documents (`[issue-number]`, `[filename] [format]`), one bracketed
|
|
15517
|
+
* placeholder per list entry. The per-entry form is chosen over re-joining with
|
|
15518
|
+
* commas because it is the shape every Claude Code example uses. An empty list
|
|
15519
|
+
* carries no hint, so it yields `undefined` and the key is dropped.
|
|
15520
|
+
*/
|
|
15521
|
+
function joinArgumentHint(value) {
|
|
15522
|
+
if (typeof value === "string") return value;
|
|
15523
|
+
if (value.length === 0) return;
|
|
15524
|
+
return value.map((entry) => `[${String(entry)}]`).join(" ");
|
|
15525
|
+
}
|
|
15526
|
+
/**
|
|
15527
|
+
* `argument-hint` as Claude Code reads it from skill and command frontmatter.
|
|
15528
|
+
*
|
|
15529
|
+
* The documented examples (`[issue-number]`) are written unquoted, and YAML
|
|
15530
|
+
* parses an unquoted `[issue-number]` as a one-element list. Claude Code
|
|
15531
|
+
* accepts that form, so it is accepted here too and normalized to the
|
|
15532
|
+
* bracketed string, keeping the parsed value (and everything downstream of it)
|
|
15533
|
+
* a plain string. A scalar entry YAML did not read as a string (`[1]`,
|
|
15534
|
+
* `[true]`, `[~]`) is stringified rather than rejected.
|
|
15535
|
+
* https://code.claude.com/docs/en/skills
|
|
15536
|
+
*
|
|
15537
|
+
* A list entry is stringified from the value YAML produced, so its original
|
|
15538
|
+
* spelling is not kept (`[1.0]` becomes `[1]`), and an entry YAML reads as a
|
|
15539
|
+
* date (`[2026-01-01]`) is rejected.
|
|
15540
|
+
*
|
|
15541
|
+
* The unquoted multi-placeholder form (`argument-hint: [filename] [format]`)
|
|
15542
|
+
* is not valid YAML at all, so it fails before this schema is reached.
|
|
15543
|
+
*/
|
|
15544
|
+
const ClaudecodeArgumentHintSchema = z.pipe(z.union([z.string(), z.array(z.union([
|
|
15545
|
+
z.string(),
|
|
15546
|
+
z.number(),
|
|
15547
|
+
z.boolean(),
|
|
15548
|
+
z.null()
|
|
15549
|
+
]))]), z.transform(joinArgumentHint));
|
|
15550
|
+
//#endregion
|
|
15458
15551
|
//#region src/features/commands/claudecode-command.ts
|
|
15459
15552
|
const ClaudecodeCommandFrontmatterSchema = z.looseObject({
|
|
15460
15553
|
description: z.optional(z.string()),
|
|
15461
15554
|
"allowed-tools": z.optional(z.union([z.string(), z.array(z.string())])),
|
|
15462
15555
|
"disallowed-tools": z.optional(z.union([z.string(), z.array(z.string())])),
|
|
15463
|
-
"argument-hint": z.optional(
|
|
15556
|
+
"argument-hint": z.optional(ClaudecodeArgumentHintSchema),
|
|
15464
15557
|
model: z.optional(z.string()),
|
|
15465
15558
|
"disable-model-invocation": z.optional(z.boolean())
|
|
15466
15559
|
});
|
|
@@ -15489,7 +15582,8 @@ var ClaudecodeCommand = class ClaudecodeCommand extends ToolCommand {
|
|
|
15489
15582
|
return this.frontmatter;
|
|
15490
15583
|
}
|
|
15491
15584
|
toRulesyncCommand() {
|
|
15492
|
-
const { description, ...
|
|
15585
|
+
const { description, ...extraFields } = this.frontmatter;
|
|
15586
|
+
const restFields = Object.fromEntries(Object.entries(extraFields).filter(([, value]) => value !== void 0));
|
|
15493
15587
|
const rulesyncFrontmatter = {
|
|
15494
15588
|
targets: ["*"],
|
|
15495
15589
|
description,
|
|
@@ -33122,6 +33216,74 @@ function translateCanonicalKeyToCodex({ key, value, isStdio, serverName }) {
|
|
|
33122
33216
|
}
|
|
33123
33217
|
}
|
|
33124
33218
|
/**
|
|
33219
|
+
* A header value that is exactly one canonical `${VAR}` reference. Anchored and
|
|
33220
|
+
* without the `g` flag, so `.exec()` carries no `lastIndex` state between
|
|
33221
|
+
* calls. `${VAR:-default}` does not match (the name excludes `:`), because
|
|
33222
|
+
* Codex has no way to express the fallback.
|
|
33223
|
+
*/
|
|
33224
|
+
const WHOLE_ENV_VAR_REF_PATTERN = /^\$\{([A-Za-z_][A-Za-z0-9_]*)\}$/;
|
|
33225
|
+
/**
|
|
33226
|
+
* An `Authorization` value that is exactly `Bearer ${VAR}`. The scheme is
|
|
33227
|
+
* matched case-insensitively, as HTTP authentication schemes are.
|
|
33228
|
+
*/
|
|
33229
|
+
const BEARER_ENV_VAR_REF_PATTERN = /^Bearer \$\{([A-Za-z_][A-Za-z0-9_]*)\}$/i;
|
|
33230
|
+
const AUTHORIZATION_HEADER_NAME = "authorization";
|
|
33231
|
+
/**
|
|
33232
|
+
* Whether a string still contains an unexpanded `${…}` reference. Codex writes
|
|
33233
|
+
* `url` and `http_headers` values as-is and never expands them, so such a value
|
|
33234
|
+
* reaches the server literally.
|
|
33235
|
+
*/
|
|
33236
|
+
function hasUnexpandedEnvVarRef(value) {
|
|
33237
|
+
return value.includes("${");
|
|
33238
|
+
}
|
|
33239
|
+
/**
|
|
33240
|
+
* Rewrite canonical `${VAR}` header references into the keys Codex reads them
|
|
33241
|
+
* from, since Codex sends `http_headers` values verbatim:
|
|
33242
|
+
* - `Authorization: Bearer ${VAR}` → `bearer_token_env_var = "VAR"`
|
|
33243
|
+
* - a header whose whole value is `${VAR}` → `env_http_headers.<name> = "VAR"`
|
|
33244
|
+
*
|
|
33245
|
+
* Runs after every key is translated, so a `bearer_token_env_var` or
|
|
33246
|
+
* `env_http_headers` the source already carries (they pass through under their
|
|
33247
|
+
* own names) is seen regardless of key order. Those explicit values win: a
|
|
33248
|
+
* derived bearer is not written over an existing one, and an existing
|
|
33249
|
+
* `env_http_headers` entry for the same header is kept. Any value the rewrite
|
|
33250
|
+
* cannot express — a partial reference, a `${VAR:-default}` fallback — stays in
|
|
33251
|
+
* `http_headers` verbatim with a warning, as does a `${…}` in `url`, for which
|
|
33252
|
+
* Codex has no environment-sourced counterpart at all.
|
|
33253
|
+
* @see https://learn.chatgpt.com/docs/config-file/config-reference
|
|
33254
|
+
*/
|
|
33255
|
+
function convertEnvVarRefsForCodex({ converted, serverName }) {
|
|
33256
|
+
const url = converted["url"];
|
|
33257
|
+
if (typeof url === "string" && hasUnexpandedEnvVarRef(url)) warnWithFallback(void 0, `[CodexCliMcp] MCP server "${serverName}": 'url' contains an environment variable reference that Codex does not expand, so it is written verbatim and the server will likely fail to start.`);
|
|
33258
|
+
const httpHeaders = converted["http_headers"];
|
|
33259
|
+
if (!isHeadersRecord(httpHeaders)) return;
|
|
33260
|
+
const existingEnvHeaders = converted["env_http_headers"];
|
|
33261
|
+
const canWriteEnvHeaders = existingEnvHeaders === void 0 || isHeadersRecord(existingEnvHeaders);
|
|
33262
|
+
const envHeaders = {};
|
|
33263
|
+
const staticHeaders = {};
|
|
33264
|
+
let bearerTokenEnvVar;
|
|
33265
|
+
for (const [name, value] of Object.entries(httpHeaders)) {
|
|
33266
|
+
const bearerMatch = BEARER_ENV_VAR_REF_PATTERN.exec(value);
|
|
33267
|
+
if (bearerMatch?.[1] && name.toLowerCase() === AUTHORIZATION_HEADER_NAME) {
|
|
33268
|
+
if (converted["bearer_token_env_var"] === void 0 && bearerTokenEnvVar === void 0) bearerTokenEnvVar = bearerMatch[1];
|
|
33269
|
+
continue;
|
|
33270
|
+
}
|
|
33271
|
+
const wholeMatch = WHOLE_ENV_VAR_REF_PATTERN.exec(value);
|
|
33272
|
+
if (wholeMatch?.[1] && canWriteEnvHeaders) {
|
|
33273
|
+
envHeaders[name] = wholeMatch[1];
|
|
33274
|
+
continue;
|
|
33275
|
+
}
|
|
33276
|
+
if (hasUnexpandedEnvVarRef(value)) warnWithFallback(void 0, `[CodexCliMcp] MCP server "${serverName}": header '${name}' contains an environment variable reference that Codex cannot source from the environment, so it is written verbatim to 'http_headers' and sent literally. Only 'Authorization: Bearer \${VAR}' and a whole-value '\${VAR}' are converted.`);
|
|
33277
|
+
staticHeaders[name] = value;
|
|
33278
|
+
}
|
|
33279
|
+
converted["http_headers"] = staticHeaders;
|
|
33280
|
+
if (bearerTokenEnvVar !== void 0) converted["bearer_token_env_var"] = bearerTokenEnvVar;
|
|
33281
|
+
if (Object.keys(envHeaders).length > 0) converted["env_http_headers"] = {
|
|
33282
|
+
...envHeaders,
|
|
33283
|
+
...isHeadersRecord(existingEnvHeaders) ? existingEnvHeaders : {}
|
|
33284
|
+
};
|
|
33285
|
+
}
|
|
33286
|
+
/**
|
|
33125
33287
|
* Codex states no transport of its own — it infers one from `command` versus
|
|
33126
33288
|
* `url`, which is why generate drops the canonical `type`. Restate it for a url
|
|
33127
33289
|
* server on the way back, so a config imported from Codex reaches the adapters
|
|
@@ -33208,6 +33370,10 @@ function convertToCodexFormat(mcpServers) {
|
|
|
33208
33370
|
}
|
|
33209
33371
|
} else converted[key] = value;
|
|
33210
33372
|
}
|
|
33373
|
+
convertEnvVarRefsForCodex({
|
|
33374
|
+
converted,
|
|
33375
|
+
serverName: name
|
|
33376
|
+
});
|
|
33211
33377
|
const previousName = originalNames.get(codexName);
|
|
33212
33378
|
if (previousName !== void 0) warnWithFallback(void 0, `Codex MCP server name collision: "${previousName}" and "${name}" both normalize to "${codexName}"; "${name}" (processed last) overwrites "${previousName}".`);
|
|
33213
33379
|
originalNames.set(codexName, name);
|
|
@@ -59207,7 +59373,7 @@ const ClaudecodeSkillFrontmatterSchema = z.looseObject({
|
|
|
59207
59373
|
"disallowed-tools": z.optional(z.union([z.string(), z.array(z.string())])),
|
|
59208
59374
|
model: z.optional(z.string()),
|
|
59209
59375
|
effort: z.optional(z.string()),
|
|
59210
|
-
"argument-hint": z.optional(
|
|
59376
|
+
"argument-hint": z.optional(ClaudecodeArgumentHintSchema),
|
|
59211
59377
|
arguments: z.optional(z.union([z.string(), z.array(z.string())])),
|
|
59212
59378
|
context: z.optional(z.string()),
|
|
59213
59379
|
agent: z.optional(z.string()),
|
|
@@ -65363,7 +65529,8 @@ const toolSkillFactories = /* @__PURE__ */ new Map([
|
|
|
65363
65529
|
meta: {
|
|
65364
65530
|
supportsProject: true,
|
|
65365
65531
|
supportsSimulated: false,
|
|
65366
|
-
supportsGlobal: true
|
|
65532
|
+
supportsGlobal: true,
|
|
65533
|
+
lenientImport: true
|
|
65367
65534
|
}
|
|
65368
65535
|
}],
|
|
65369
65536
|
["claudecode-plugin", {
|
|
@@ -72312,7 +72479,7 @@ var ToolRule = class extends ToolFile {
|
|
|
72312
72479
|
static buildToolRuleParamsAgentsmd({ outputRoot = process.cwd(), rulesyncRule, validate = true, rootPath = {
|
|
72313
72480
|
relativeDirPath: ".",
|
|
72314
72481
|
relativeFilePath: "AGENTS.md"
|
|
72315
|
-
}, nonRootPath = { relativeDirPath: AGENTSMD_MEMORIES_DIR_PATH } }) {
|
|
72482
|
+
}, nonRootPath = { relativeDirPath: AGENTSMD_MEMORIES_DIR_PATH }, global = false }) {
|
|
72316
72483
|
const params = this.buildToolRuleParamsDefault({
|
|
72317
72484
|
outputRoot,
|
|
72318
72485
|
rulesyncRule,
|
|
@@ -72321,7 +72488,7 @@ var ToolRule = class extends ToolFile {
|
|
|
72321
72488
|
nonRootPath
|
|
72322
72489
|
});
|
|
72323
72490
|
const rulesyncFrontmatter = rulesyncRule.getFrontmatter();
|
|
72324
|
-
if (!rulesyncFrontmatter.root && rulesyncFrontmatter.agentsmd?.subprojectPath) {
|
|
72491
|
+
if (!global && !rulesyncFrontmatter.root && rulesyncFrontmatter.agentsmd?.subprojectPath) {
|
|
72325
72492
|
params.relativeDirPath = join(rulesyncFrontmatter.agentsmd.subprojectPath);
|
|
72326
72493
|
params.relativeFilePath = "AGENTS.md";
|
|
72327
72494
|
}
|
|
@@ -72978,7 +73145,8 @@ var AmpRule = class AmpRule extends ToolRule {
|
|
|
72978
73145
|
rulesyncRule,
|
|
72979
73146
|
validate,
|
|
72980
73147
|
rootPath: paths.root,
|
|
72981
|
-
nonRootPath: paths.nonRoot
|
|
73148
|
+
nonRootPath: paths.nonRoot,
|
|
73149
|
+
global
|
|
72982
73150
|
});
|
|
72983
73151
|
if (!params.root && params.globs !== void 0 && params.globs.length > 0) params.fileContent = stringifyFrontmatter(params.fileContent, { globs: params.globs });
|
|
72984
73152
|
return new AmpRule(params);
|
|
@@ -73024,97 +73192,6 @@ var AmpRule = class AmpRule extends ToolRule {
|
|
|
73024
73192
|
}
|
|
73025
73193
|
};
|
|
73026
73194
|
//#endregion
|
|
73027
|
-
//#region src/features/rules/antigravity-cli-rule.ts
|
|
73028
|
-
/**
|
|
73029
|
-
* Rule generator for the Google Antigravity CLI (`agy`, the Gemini-CLI
|
|
73030
|
-
* successor in Antigravity 2.0).
|
|
73031
|
-
*
|
|
73032
|
-
* The CLI reads the same plain-markdown context files as Gemini CLI — a root
|
|
73033
|
-
* context file plus non-root memory files in `.agents/rules/` — so this class
|
|
73034
|
-
* follows that same plain-markdown approach but points at the new `.agents/` tree.
|
|
73035
|
-
*
|
|
73036
|
-
* - Project scope: root `AGENTS.md` (the cross-tool standard, matching
|
|
73037
|
-
* `antigravity-ide`); non-root `.agents/rules/*.md`.
|
|
73038
|
-
* - Global scope: a single plain `~/.gemini/GEMINI.md` (shared with the IDE).
|
|
73039
|
-
*/
|
|
73040
|
-
var AntigravityCliRule = class AntigravityCliRule extends ToolRule {
|
|
73041
|
-
static getSettablePaths({ global, excludeToolDir } = {}) {
|
|
73042
|
-
if (global) return { root: {
|
|
73043
|
-
relativeDirPath: buildToolPath(ANTIGRAVITY_GEMINI_DIR, ".", excludeToolDir),
|
|
73044
|
-
relativeFilePath: ANTIGRAVITY_GLOBAL_RULE_FILE_NAME
|
|
73045
|
-
} };
|
|
73046
|
-
return {
|
|
73047
|
-
root: {
|
|
73048
|
-
relativeDirPath: ".",
|
|
73049
|
-
relativeFilePath: ANTIGRAVITY_RULE_FILE_NAME
|
|
73050
|
-
},
|
|
73051
|
-
nonRoot: { relativeDirPath: buildToolPath(ANTIGRAVITY_AGENTS_DIR, "rules", excludeToolDir) }
|
|
73052
|
-
};
|
|
73053
|
-
}
|
|
73054
|
-
static async fromFile({ outputRoot = process.cwd(), relativeFilePath, validate = true, global = false }) {
|
|
73055
|
-
const paths = this.getSettablePaths({ global });
|
|
73056
|
-
if (relativeFilePath === paths.root.relativeFilePath) {
|
|
73057
|
-
const relativePath = paths.root.relativeFilePath;
|
|
73058
|
-
const fileContent = await readFileContent(join(outputRoot, paths.root.relativeDirPath, relativePath));
|
|
73059
|
-
return new AntigravityCliRule({
|
|
73060
|
-
outputRoot,
|
|
73061
|
-
relativeDirPath: paths.root.relativeDirPath,
|
|
73062
|
-
relativeFilePath: paths.root.relativeFilePath,
|
|
73063
|
-
fileContent,
|
|
73064
|
-
validate,
|
|
73065
|
-
root: true
|
|
73066
|
-
});
|
|
73067
|
-
}
|
|
73068
|
-
if (!paths.nonRoot) throw new Error(`nonRoot path is not set for ${relativeFilePath}`);
|
|
73069
|
-
const relativePath = join(paths.nonRoot.relativeDirPath, relativeFilePath);
|
|
73070
|
-
const fileContent = await readFileContent(join(outputRoot, relativePath));
|
|
73071
|
-
return new AntigravityCliRule({
|
|
73072
|
-
outputRoot,
|
|
73073
|
-
relativeDirPath: paths.nonRoot.relativeDirPath,
|
|
73074
|
-
relativeFilePath,
|
|
73075
|
-
fileContent,
|
|
73076
|
-
validate,
|
|
73077
|
-
root: false
|
|
73078
|
-
});
|
|
73079
|
-
}
|
|
73080
|
-
static fromRulesyncRule({ outputRoot = process.cwd(), rulesyncRule, validate = true, global = false }) {
|
|
73081
|
-
const paths = this.getSettablePaths({ global });
|
|
73082
|
-
return new AntigravityCliRule(this.buildToolRuleParamsDefault({
|
|
73083
|
-
outputRoot,
|
|
73084
|
-
rulesyncRule,
|
|
73085
|
-
validate,
|
|
73086
|
-
rootPath: paths.root,
|
|
73087
|
-
nonRootPath: paths.nonRoot
|
|
73088
|
-
}));
|
|
73089
|
-
}
|
|
73090
|
-
toRulesyncRule() {
|
|
73091
|
-
return this.toRulesyncRuleDefault();
|
|
73092
|
-
}
|
|
73093
|
-
validate() {
|
|
73094
|
-
return {
|
|
73095
|
-
success: true,
|
|
73096
|
-
error: null
|
|
73097
|
-
};
|
|
73098
|
-
}
|
|
73099
|
-
static forDeletion({ outputRoot = process.cwd(), relativeDirPath, relativeFilePath, global = false }) {
|
|
73100
|
-
const isRoot = relativeFilePath === this.getSettablePaths({ global }).root.relativeFilePath;
|
|
73101
|
-
return new AntigravityCliRule({
|
|
73102
|
-
outputRoot,
|
|
73103
|
-
relativeDirPath,
|
|
73104
|
-
relativeFilePath,
|
|
73105
|
-
fileContent: "",
|
|
73106
|
-
validate: false,
|
|
73107
|
-
root: isRoot
|
|
73108
|
-
});
|
|
73109
|
-
}
|
|
73110
|
-
static isTargetedByRulesyncRule(rulesyncRule) {
|
|
73111
|
-
return this.isTargetedByRulesyncRuleDefault({
|
|
73112
|
-
rulesyncRule,
|
|
73113
|
-
toolTarget: "antigravity-cli"
|
|
73114
|
-
});
|
|
73115
|
-
}
|
|
73116
|
-
};
|
|
73117
|
-
//#endregion
|
|
73118
73195
|
//#region src/features/rules/antigravity-rule.ts
|
|
73119
73196
|
const AntigravityRuleFrontmatterSchema = z.looseObject({
|
|
73120
73197
|
trigger: z.optional(z.union([
|
|
@@ -73261,6 +73338,185 @@ const STRATEGIES$1 = [
|
|
|
73261
73338
|
}
|
|
73262
73339
|
];
|
|
73263
73340
|
//#endregion
|
|
73341
|
+
//#region src/features/rules/antigravity-cli-rule.ts
|
|
73342
|
+
/**
|
|
73343
|
+
* Rule generator for the Google Antigravity CLI (`agy`, the Gemini-CLI
|
|
73344
|
+
* successor in Antigravity 2.0).
|
|
73345
|
+
*
|
|
73346
|
+
* The CLI reads the same plain-markdown context files as Gemini CLI — a root
|
|
73347
|
+
* context file plus non-root memory files in `.agents/rules/` — so this class
|
|
73348
|
+
* follows that same plain-markdown approach but points at the new `.agents/` tree.
|
|
73349
|
+
*
|
|
73350
|
+
* - Project scope: root `AGENTS.md` (the cross-tool standard, matching
|
|
73351
|
+
* `antigravity-ide`); non-root `.agents/rules/*.md`.
|
|
73352
|
+
* - Global scope: root plain `~/.gemini/GEMINI.md` (shared with the IDE);
|
|
73353
|
+
* non-root `~/.gemini/config/rules/*.md`. The CLI truncates each rule file at
|
|
73354
|
+
* 24,000 bytes, so keeping non-root rules as separate files stops a large rule
|
|
73355
|
+
* set from being cut off. Every file in that directory must carry a valid
|
|
73356
|
+
* `trigger` frontmatter or the CLI discards it, so these files get the same
|
|
73357
|
+
* trigger-strategy frontmatter as the IDE's non-root rules.
|
|
73358
|
+
*
|
|
73359
|
+
* @see https://antigravity.google/docs/rules
|
|
73360
|
+
*/
|
|
73361
|
+
var AntigravityCliRule = class AntigravityCliRule extends ToolRule {
|
|
73362
|
+
static getSettablePaths({ global, excludeToolDir } = {}) {
|
|
73363
|
+
if (global) return {
|
|
73364
|
+
root: {
|
|
73365
|
+
relativeDirPath: buildToolPath(ANTIGRAVITY_GEMINI_DIR, ".", excludeToolDir),
|
|
73366
|
+
relativeFilePath: ANTIGRAVITY_GLOBAL_RULE_FILE_NAME
|
|
73367
|
+
},
|
|
73368
|
+
nonRoot: { relativeDirPath: buildToolPath(ANTIGRAVITY_GEMINI_DIR, ANTIGRAVITY_GLOBAL_RULES_SUBDIR, excludeToolDir) }
|
|
73369
|
+
};
|
|
73370
|
+
return {
|
|
73371
|
+
root: {
|
|
73372
|
+
relativeDirPath: ".",
|
|
73373
|
+
relativeFilePath: ANTIGRAVITY_RULE_FILE_NAME
|
|
73374
|
+
},
|
|
73375
|
+
nonRoot: { relativeDirPath: buildToolPath(ANTIGRAVITY_AGENTS_DIR, "rules", excludeToolDir) }
|
|
73376
|
+
};
|
|
73377
|
+
}
|
|
73378
|
+
static async fromFile({ outputRoot = process.cwd(), relativeDirPath, relativeFilePath, validate = true, global = false }) {
|
|
73379
|
+
const paths = this.getSettablePaths({ global });
|
|
73380
|
+
if (relativeFilePath === paths.root.relativeFilePath && (relativeDirPath === void 0 || relativeDirPath === paths.root.relativeDirPath)) {
|
|
73381
|
+
const relativePath = paths.root.relativeFilePath;
|
|
73382
|
+
const fileContent = await readFileContent(join(outputRoot, paths.root.relativeDirPath, relativePath));
|
|
73383
|
+
return new AntigravityCliRule({
|
|
73384
|
+
outputRoot,
|
|
73385
|
+
relativeDirPath: paths.root.relativeDirPath,
|
|
73386
|
+
relativeFilePath: paths.root.relativeFilePath,
|
|
73387
|
+
fileContent,
|
|
73388
|
+
validate,
|
|
73389
|
+
root: true,
|
|
73390
|
+
global
|
|
73391
|
+
});
|
|
73392
|
+
}
|
|
73393
|
+
if (!paths.nonRoot) throw new Error(`nonRoot path is not set for ${relativeFilePath}`);
|
|
73394
|
+
const relativePath = join(paths.nonRoot.relativeDirPath, relativeFilePath);
|
|
73395
|
+
const fileContent = await readFileContent(join(outputRoot, relativePath));
|
|
73396
|
+
const rule = new AntigravityCliRule({
|
|
73397
|
+
outputRoot,
|
|
73398
|
+
relativeDirPath: paths.nonRoot.relativeDirPath,
|
|
73399
|
+
relativeFilePath,
|
|
73400
|
+
fileContent,
|
|
73401
|
+
validate,
|
|
73402
|
+
root: false,
|
|
73403
|
+
global
|
|
73404
|
+
});
|
|
73405
|
+
if (validate) {
|
|
73406
|
+
const result = rule.validate();
|
|
73407
|
+
if (!result.success) throw new Error(`Invalid frontmatter in ${relativePath}: ${result.error.message}`);
|
|
73408
|
+
}
|
|
73409
|
+
return rule;
|
|
73410
|
+
}
|
|
73411
|
+
static fromRulesyncRule({ outputRoot = process.cwd(), rulesyncRule, validate = true, global = false }) {
|
|
73412
|
+
const paths = this.getSettablePaths({ global });
|
|
73413
|
+
const params = this.buildToolRuleParamsDefault({
|
|
73414
|
+
outputRoot,
|
|
73415
|
+
rulesyncRule,
|
|
73416
|
+
validate,
|
|
73417
|
+
rootPath: paths.root,
|
|
73418
|
+
nonRootPath: paths.nonRoot
|
|
73419
|
+
});
|
|
73420
|
+
if (!global || params.root) return new AntigravityCliRule({
|
|
73421
|
+
...params,
|
|
73422
|
+
global
|
|
73423
|
+
});
|
|
73424
|
+
const rulesyncFrontmatter = rulesyncRule.getFrontmatter();
|
|
73425
|
+
const storedAntigravity = rulesyncFrontmatter.antigravity;
|
|
73426
|
+
const storedTrigger = storedAntigravity?.trigger;
|
|
73427
|
+
const strategy = STRATEGIES$1.find((s) => s.canHandle(storedTrigger));
|
|
73428
|
+
if (!strategy) throw new Error(`No strategy found for trigger: ${storedTrigger}`);
|
|
73429
|
+
const frontmatter = strategy.generateFrontmatter(normalizeStoredAntigravity(storedAntigravity), rulesyncFrontmatter);
|
|
73430
|
+
return new AntigravityCliRule({
|
|
73431
|
+
...params,
|
|
73432
|
+
relativeFilePath: params.relativeFilePath.split(/[\\/]/).join("-"),
|
|
73433
|
+
fileContent: stringifyFrontmatter(rulesyncRule.getBody(), frontmatter),
|
|
73434
|
+
global
|
|
73435
|
+
});
|
|
73436
|
+
}
|
|
73437
|
+
toRulesyncRule() {
|
|
73438
|
+
if (!this.global || this.root) return this.toRulesyncRuleDefault();
|
|
73439
|
+
const { frontmatter, body } = this.parseGlobalNonRootContent();
|
|
73440
|
+
const strategy = STRATEGIES$1.find((s) => s.canHandle(frontmatter.trigger));
|
|
73441
|
+
const rulesyncData = strategy ? strategy.exportRulesyncData(frontmatter) : {
|
|
73442
|
+
globs: [],
|
|
73443
|
+
antigravity: frontmatter
|
|
73444
|
+
};
|
|
73445
|
+
return new RulesyncRule({
|
|
73446
|
+
outputRoot: process.cwd(),
|
|
73447
|
+
relativeDirPath: RulesyncRule.getSettablePaths().recommended.relativeDirPath,
|
|
73448
|
+
relativeFilePath: this.getRelativeFilePath(),
|
|
73449
|
+
frontmatter: {
|
|
73450
|
+
root: false,
|
|
73451
|
+
targets: ["*"],
|
|
73452
|
+
...rulesyncData,
|
|
73453
|
+
antigravity: {
|
|
73454
|
+
...rulesyncData.antigravity,
|
|
73455
|
+
globs: frontmatter.globs ? parseGlobsString$1(frontmatter.globs) : void 0
|
|
73456
|
+
}
|
|
73457
|
+
},
|
|
73458
|
+
body
|
|
73459
|
+
});
|
|
73460
|
+
}
|
|
73461
|
+
validate() {
|
|
73462
|
+
if (!this.global || this.root) return {
|
|
73463
|
+
success: true,
|
|
73464
|
+
error: null
|
|
73465
|
+
};
|
|
73466
|
+
try {
|
|
73467
|
+
const { frontmatter } = this.parseGlobalNonRootContent();
|
|
73468
|
+
const result = AntigravityRuleFrontmatterSchema.safeParse(frontmatter);
|
|
73469
|
+
if (!result.success) return {
|
|
73470
|
+
success: false,
|
|
73471
|
+
error: new Error(formatError(result.error))
|
|
73472
|
+
};
|
|
73473
|
+
} catch (error) {
|
|
73474
|
+
return {
|
|
73475
|
+
success: false,
|
|
73476
|
+
error: error instanceof Error ? error : new Error(String(error))
|
|
73477
|
+
};
|
|
73478
|
+
}
|
|
73479
|
+
return {
|
|
73480
|
+
success: true,
|
|
73481
|
+
error: null
|
|
73482
|
+
};
|
|
73483
|
+
}
|
|
73484
|
+
/**
|
|
73485
|
+
* `~/.gemini/config/rules/` is shared with the Antigravity IDE and holds
|
|
73486
|
+
* global rules the user created outside rulesync, which cannot be told apart
|
|
73487
|
+
* from generated ones, so the orphan sweep never removes files there.
|
|
73488
|
+
*/
|
|
73489
|
+
isDeletable() {
|
|
73490
|
+
return !this.global || this.root;
|
|
73491
|
+
}
|
|
73492
|
+
parseGlobalNonRootContent() {
|
|
73493
|
+
const { frontmatter, body } = parseFrontmatter(this.getFileContent(), this.getFilePath());
|
|
73494
|
+
return {
|
|
73495
|
+
frontmatter,
|
|
73496
|
+
body
|
|
73497
|
+
};
|
|
73498
|
+
}
|
|
73499
|
+
static forDeletion({ outputRoot = process.cwd(), relativeDirPath, relativeFilePath, global = false }) {
|
|
73500
|
+
const paths = this.getSettablePaths({ global });
|
|
73501
|
+
const isRoot = relativeFilePath === paths.root.relativeFilePath && relativeDirPath === paths.root.relativeDirPath;
|
|
73502
|
+
return new AntigravityCliRule({
|
|
73503
|
+
outputRoot,
|
|
73504
|
+
relativeDirPath,
|
|
73505
|
+
relativeFilePath,
|
|
73506
|
+
fileContent: "",
|
|
73507
|
+
validate: false,
|
|
73508
|
+
root: isRoot,
|
|
73509
|
+
global
|
|
73510
|
+
});
|
|
73511
|
+
}
|
|
73512
|
+
static isTargetedByRulesyncRule(rulesyncRule) {
|
|
73513
|
+
return this.isTargetedByRulesyncRuleDefault({
|
|
73514
|
+
rulesyncRule,
|
|
73515
|
+
toolTarget: "antigravity-cli"
|
|
73516
|
+
});
|
|
73517
|
+
}
|
|
73518
|
+
};
|
|
73519
|
+
//#endregion
|
|
73264
73520
|
//#region src/features/rules/antigravity-ide-rule.ts
|
|
73265
73521
|
/**
|
|
73266
73522
|
* Rule generator for the Google Antigravity IDE (Antigravity 2.0).
|
|
@@ -74273,7 +74529,8 @@ var ClineRule = class ClineRule extends ToolRule {
|
|
|
74273
74529
|
outputRoot,
|
|
74274
74530
|
rulesyncRule,
|
|
74275
74531
|
validate,
|
|
74276
|
-
rootPath: paths.root
|
|
74532
|
+
rootPath: paths.root,
|
|
74533
|
+
global
|
|
74277
74534
|
}));
|
|
74278
74535
|
}
|
|
74279
74536
|
if (isRoot) return new ClineRule({
|
|
@@ -74693,26 +74950,62 @@ var CodebuddyRule = class CodebuddyRule extends ToolRule {
|
|
|
74693
74950
|
}
|
|
74694
74951
|
};
|
|
74695
74952
|
//#endregion
|
|
74696
|
-
//#region src/features/rules/
|
|
74697
|
-
|
|
74698
|
-
|
|
74699
|
-
|
|
74700
|
-
|
|
74701
|
-
|
|
74702
|
-
|
|
74703
|
-
|
|
74953
|
+
//#region src/features/rules/nested-agentsmd-rule.ts
|
|
74954
|
+
/**
|
|
74955
|
+
* Shared adapter for the targets that read instructions exactly the way the
|
|
74956
|
+
* AGENTS.md standard describes them and nothing more: a root `AGENTS.md` at the
|
|
74957
|
+
* project root, nested per-directory `AGENTS.md` files loaded only while working
|
|
74958
|
+
* under that directory, and a single personal root file under a tool-specific
|
|
74959
|
+
* home directory. Such a target has no modular non-root instruction directory,
|
|
74960
|
+
* so every other non-root rule folds into the root file.
|
|
74961
|
+
*
|
|
74962
|
+
* Concrete targets (Codex CLI, Pool, Vibe, DeepSeek Harness) only supply the global
|
|
74963
|
+
* directory and their tool target through {@link getFamily}; the vendor docs
|
|
74964
|
+
* describing each one's discovery walk live on the subclass.
|
|
74965
|
+
*
|
|
74966
|
+
* The nested-file scan mirrors the AGENTS.md standard's nested discovery —
|
|
74967
|
+
* same file name, same exclusions, import-only, project scope — because it
|
|
74968
|
+
* discovers literally the same files.
|
|
74969
|
+
*/
|
|
74970
|
+
var NestedAgentsmdRule = class extends ToolRule {
|
|
74971
|
+
static getFamily() {
|
|
74972
|
+
throw new Error("Please implement this method in the subclass.");
|
|
74704
74973
|
}
|
|
74705
74974
|
static getSettablePaths({ global = false } = {}) {
|
|
74975
|
+
if (global) return { root: {
|
|
74976
|
+
relativeDirPath: this.getFamily().globalDir,
|
|
74977
|
+
relativeFilePath: AGENTSMD_RULE_FILE_NAME
|
|
74978
|
+
} };
|
|
74706
74979
|
return { root: {
|
|
74707
|
-
relativeDirPath:
|
|
74708
|
-
relativeFilePath:
|
|
74980
|
+
relativeDirPath: ".",
|
|
74981
|
+
relativeFilePath: AGENTSMD_RULE_FILE_NAME
|
|
74709
74982
|
} };
|
|
74710
74983
|
}
|
|
74711
|
-
static
|
|
74984
|
+
static getNestedFilePatterns() {
|
|
74985
|
+
return this.buildNestedFilePatterns({ fileName: AGENTSMD_RULE_FILE_NAME });
|
|
74986
|
+
}
|
|
74987
|
+
/**
|
|
74988
|
+
* The subproject directory this rule scopes, or `undefined` for the root file
|
|
74989
|
+
* (project or global).
|
|
74990
|
+
*/
|
|
74991
|
+
getSubprojectPath() {
|
|
74992
|
+
return this.getNestedSubprojectPath({ fileName: AGENTSMD_RULE_FILE_NAME });
|
|
74993
|
+
}
|
|
74994
|
+
static async fromFile({ outputRoot = process.cwd(), relativeFilePath: _relativeFilePath, relativeDirPath: overrideDirPath, validate = true, global = false }) {
|
|
74712
74995
|
const { root } = this.getSettablePaths({ global });
|
|
74713
|
-
|
|
74714
|
-
|
|
74715
|
-
|
|
74996
|
+
if (overrideDirPath !== void 0 && overrideDirPath !== root.relativeDirPath && overrideDirPath !== ".") {
|
|
74997
|
+
const fileContent = await readFileContent(join(outputRoot, overrideDirPath, AGENTSMD_RULE_FILE_NAME));
|
|
74998
|
+
return new this({
|
|
74999
|
+
outputRoot,
|
|
75000
|
+
relativeDirPath: overrideDirPath,
|
|
75001
|
+
relativeFilePath: AGENTSMD_RULE_FILE_NAME,
|
|
75002
|
+
fileContent,
|
|
75003
|
+
validate,
|
|
75004
|
+
root: false
|
|
75005
|
+
});
|
|
75006
|
+
}
|
|
75007
|
+
const fileContent = await readFileContent(join(outputRoot, root.relativeDirPath, root.relativeFilePath));
|
|
75008
|
+
return new this({
|
|
74716
75009
|
outputRoot,
|
|
74717
75010
|
relativeDirPath: root.relativeDirPath,
|
|
74718
75011
|
relativeFilePath: root.relativeFilePath,
|
|
@@ -74723,8 +75016,18 @@ var CodexcliRule = class CodexcliRule extends ToolRule {
|
|
|
74723
75016
|
}
|
|
74724
75017
|
static fromRulesyncRule({ outputRoot = process.cwd(), rulesyncRule, validate = true, global = false }) {
|
|
74725
75018
|
const { root } = this.getSettablePaths({ global });
|
|
74726
|
-
const
|
|
74727
|
-
|
|
75019
|
+
const frontmatter = rulesyncRule.getFrontmatter();
|
|
75020
|
+
const isRoot = frontmatter.root ?? false;
|
|
75021
|
+
const subprojectPath = frontmatter.agentsmd?.subprojectPath;
|
|
75022
|
+
if (!global && !isRoot && subprojectPath) return new this({
|
|
75023
|
+
outputRoot,
|
|
75024
|
+
relativeDirPath: join(subprojectPath),
|
|
75025
|
+
relativeFilePath: AGENTSMD_RULE_FILE_NAME,
|
|
75026
|
+
fileContent: rulesyncRule.getBody(),
|
|
75027
|
+
validate,
|
|
75028
|
+
root: false
|
|
75029
|
+
});
|
|
75030
|
+
return new this({
|
|
74728
75031
|
outputRoot,
|
|
74729
75032
|
relativeDirPath: root.relativeDirPath,
|
|
74730
75033
|
relativeFilePath: root.relativeFilePath,
|
|
@@ -74734,7 +75037,9 @@ var CodexcliRule = class CodexcliRule extends ToolRule {
|
|
|
74734
75037
|
});
|
|
74735
75038
|
}
|
|
74736
75039
|
toRulesyncRule() {
|
|
74737
|
-
|
|
75040
|
+
const subprojectPath = this.getSubprojectPath();
|
|
75041
|
+
if (subprojectPath === void 0) return this.toRulesyncRuleDefault();
|
|
75042
|
+
return this.toRulesyncRuleNestedAgentsmd({ subprojectPath });
|
|
74738
75043
|
}
|
|
74739
75044
|
validate() {
|
|
74740
75045
|
return {
|
|
@@ -74743,23 +75048,54 @@ var CodexcliRule = class CodexcliRule extends ToolRule {
|
|
|
74743
75048
|
};
|
|
74744
75049
|
}
|
|
74745
75050
|
static forDeletion({ outputRoot = process.cwd(), relativeDirPath, relativeFilePath }) {
|
|
74746
|
-
|
|
75051
|
+
const isRoot = relativeFilePath === "AGENTS.md" && (relativeDirPath === "." || relativeDirPath === this.getFamily().globalDir);
|
|
75052
|
+
return new this({
|
|
74747
75053
|
outputRoot,
|
|
74748
75054
|
relativeDirPath,
|
|
74749
75055
|
relativeFilePath,
|
|
74750
75056
|
fileContent: "",
|
|
74751
75057
|
validate: false,
|
|
74752
|
-
root:
|
|
75058
|
+
root: isRoot
|
|
74753
75059
|
});
|
|
74754
75060
|
}
|
|
74755
75061
|
static isTargetedByRulesyncRule(rulesyncRule) {
|
|
74756
75062
|
return this.isTargetedByRulesyncRuleDefault({
|
|
74757
75063
|
rulesyncRule,
|
|
74758
|
-
toolTarget:
|
|
75064
|
+
toolTarget: this.getFamily().toolTarget
|
|
74759
75065
|
});
|
|
74760
75066
|
}
|
|
74761
75067
|
};
|
|
74762
75068
|
//#endregion
|
|
75069
|
+
//#region src/features/rules/codexcli-rule.ts
|
|
75070
|
+
/**
|
|
75071
|
+
* Rule generator for OpenAI Codex CLI.
|
|
75072
|
+
*
|
|
75073
|
+
* Codex CLI loads instructions only from the `AGENTS.md` family: the global
|
|
75074
|
+
* `~/.codex/AGENTS.md` (or `AGENTS.override.md`), then one file per directory
|
|
75075
|
+
* level from the project root down to the current working directory, joined
|
|
75076
|
+
* root-first so deeper files take precedence. Nested per-directory files are
|
|
75077
|
+
* therefore a real scoping surface, and Codex's docs recommend splitting large
|
|
75078
|
+
* instruction sets across nested directories. It does NOT scan a
|
|
75079
|
+
* `.codex/memories/` directory for instruction files — that directory belongs
|
|
75080
|
+
* to Codex's separate SQLite-backed auto-memory system.
|
|
75081
|
+
*
|
|
75082
|
+
* A non-root rule carrying `agentsmd.subprojectPath` is emitted as a nested
|
|
75083
|
+
* `<subprojectPath>/AGENTS.md` (project scope only); every other non-root rule
|
|
75084
|
+
* folds into the root `AGENTS.md`, since Codex has no modular rules directory.
|
|
75085
|
+
* The project files on the root-to-cwd chain share one `project_doc_max_bytes`
|
|
75086
|
+
* budget (32 KiB by default), which the RulesProcessor warns about.
|
|
75087
|
+
*
|
|
75088
|
+
* @see https://learn.chatgpt.com/docs/agent-configuration/agents-md
|
|
75089
|
+
*/
|
|
75090
|
+
var CodexcliRule = class extends NestedAgentsmdRule {
|
|
75091
|
+
static getFamily() {
|
|
75092
|
+
return {
|
|
75093
|
+
globalDir: CODEXCLI_DIR,
|
|
75094
|
+
toolTarget: "codexcli"
|
|
75095
|
+
};
|
|
75096
|
+
}
|
|
75097
|
+
};
|
|
75098
|
+
//#endregion
|
|
74763
75099
|
//#region src/features/rules/commandcode-rule.ts
|
|
74764
75100
|
var CommandcodeRule = class CommandcodeRule extends ToolRule {
|
|
74765
75101
|
constructor({ fileContent, root, ...rest }) {
|
|
@@ -76064,122 +76400,6 @@ var DevinRule = class DevinRule extends ToolRule {
|
|
|
76064
76400
|
}
|
|
76065
76401
|
};
|
|
76066
76402
|
//#endregion
|
|
76067
|
-
//#region src/features/rules/nested-agentsmd-rule.ts
|
|
76068
|
-
/**
|
|
76069
|
-
* Shared adapter for the targets that read instructions exactly the way the
|
|
76070
|
-
* AGENTS.md standard describes them and nothing more: a root `AGENTS.md` at the
|
|
76071
|
-
* project root, nested per-directory `AGENTS.md` files loaded only while working
|
|
76072
|
-
* under that directory, and a single personal root file under a tool-specific
|
|
76073
|
-
* home directory. Such a target has no modular non-root instruction directory,
|
|
76074
|
-
* so every other non-root rule folds into the root file.
|
|
76075
|
-
*
|
|
76076
|
-
* Concrete targets (Pool, Vibe, DeepSeek Harness) only supply the global
|
|
76077
|
-
* directory and their tool target through {@link getFamily}; the vendor docs
|
|
76078
|
-
* describing each one's discovery walk live on the subclass.
|
|
76079
|
-
*
|
|
76080
|
-
* The nested-file scan mirrors the AGENTS.md standard's nested discovery —
|
|
76081
|
-
* same file name, same exclusions, import-only, project scope — because it
|
|
76082
|
-
* discovers literally the same files.
|
|
76083
|
-
*/
|
|
76084
|
-
var NestedAgentsmdRule = class extends ToolRule {
|
|
76085
|
-
static getFamily() {
|
|
76086
|
-
throw new Error("Please implement this method in the subclass.");
|
|
76087
|
-
}
|
|
76088
|
-
static getSettablePaths({ global = false } = {}) {
|
|
76089
|
-
if (global) return { root: {
|
|
76090
|
-
relativeDirPath: this.getFamily().globalDir,
|
|
76091
|
-
relativeFilePath: AGENTSMD_RULE_FILE_NAME
|
|
76092
|
-
} };
|
|
76093
|
-
return { root: {
|
|
76094
|
-
relativeDirPath: ".",
|
|
76095
|
-
relativeFilePath: AGENTSMD_RULE_FILE_NAME
|
|
76096
|
-
} };
|
|
76097
|
-
}
|
|
76098
|
-
static getNestedFilePatterns() {
|
|
76099
|
-
return this.buildNestedFilePatterns({ fileName: AGENTSMD_RULE_FILE_NAME });
|
|
76100
|
-
}
|
|
76101
|
-
/**
|
|
76102
|
-
* The subproject directory this rule scopes, or `undefined` for the root file
|
|
76103
|
-
* (project or global).
|
|
76104
|
-
*/
|
|
76105
|
-
getSubprojectPath() {
|
|
76106
|
-
return this.getNestedSubprojectPath({ fileName: AGENTSMD_RULE_FILE_NAME });
|
|
76107
|
-
}
|
|
76108
|
-
static async fromFile({ outputRoot = process.cwd(), relativeFilePath: _relativeFilePath, relativeDirPath: overrideDirPath, validate = true, global = false }) {
|
|
76109
|
-
const { root } = this.getSettablePaths({ global });
|
|
76110
|
-
if (overrideDirPath !== void 0 && overrideDirPath !== root.relativeDirPath && overrideDirPath !== ".") {
|
|
76111
|
-
const fileContent = await readFileContent(join(outputRoot, overrideDirPath, AGENTSMD_RULE_FILE_NAME));
|
|
76112
|
-
return new this({
|
|
76113
|
-
outputRoot,
|
|
76114
|
-
relativeDirPath: overrideDirPath,
|
|
76115
|
-
relativeFilePath: AGENTSMD_RULE_FILE_NAME,
|
|
76116
|
-
fileContent,
|
|
76117
|
-
validate,
|
|
76118
|
-
root: false
|
|
76119
|
-
});
|
|
76120
|
-
}
|
|
76121
|
-
const fileContent = await readFileContent(join(outputRoot, root.relativeDirPath, root.relativeFilePath));
|
|
76122
|
-
return new this({
|
|
76123
|
-
outputRoot,
|
|
76124
|
-
relativeDirPath: root.relativeDirPath,
|
|
76125
|
-
relativeFilePath: root.relativeFilePath,
|
|
76126
|
-
fileContent,
|
|
76127
|
-
validate,
|
|
76128
|
-
root: true
|
|
76129
|
-
});
|
|
76130
|
-
}
|
|
76131
|
-
static fromRulesyncRule({ outputRoot = process.cwd(), rulesyncRule, validate = true, global = false }) {
|
|
76132
|
-
const { root } = this.getSettablePaths({ global });
|
|
76133
|
-
const frontmatter = rulesyncRule.getFrontmatter();
|
|
76134
|
-
const isRoot = frontmatter.root ?? false;
|
|
76135
|
-
const subprojectPath = frontmatter.agentsmd?.subprojectPath;
|
|
76136
|
-
if (!global && !isRoot && subprojectPath) return new this({
|
|
76137
|
-
outputRoot,
|
|
76138
|
-
relativeDirPath: join(subprojectPath),
|
|
76139
|
-
relativeFilePath: AGENTSMD_RULE_FILE_NAME,
|
|
76140
|
-
fileContent: rulesyncRule.getBody(),
|
|
76141
|
-
validate,
|
|
76142
|
-
root: false
|
|
76143
|
-
});
|
|
76144
|
-
return new this({
|
|
76145
|
-
outputRoot,
|
|
76146
|
-
relativeDirPath: root.relativeDirPath,
|
|
76147
|
-
relativeFilePath: root.relativeFilePath,
|
|
76148
|
-
fileContent: rulesyncRule.getBody(),
|
|
76149
|
-
validate,
|
|
76150
|
-
root: isRoot
|
|
76151
|
-
});
|
|
76152
|
-
}
|
|
76153
|
-
toRulesyncRule() {
|
|
76154
|
-
const subprojectPath = this.getSubprojectPath();
|
|
76155
|
-
if (subprojectPath === void 0) return this.toRulesyncRuleDefault();
|
|
76156
|
-
return this.toRulesyncRuleNestedAgentsmd({ subprojectPath });
|
|
76157
|
-
}
|
|
76158
|
-
validate() {
|
|
76159
|
-
return {
|
|
76160
|
-
success: true,
|
|
76161
|
-
error: null
|
|
76162
|
-
};
|
|
76163
|
-
}
|
|
76164
|
-
static forDeletion({ outputRoot = process.cwd(), relativeDirPath, relativeFilePath }) {
|
|
76165
|
-
const isRoot = relativeFilePath === "AGENTS.md" && (relativeDirPath === "." || relativeDirPath === this.getFamily().globalDir);
|
|
76166
|
-
return new this({
|
|
76167
|
-
outputRoot,
|
|
76168
|
-
relativeDirPath,
|
|
76169
|
-
relativeFilePath,
|
|
76170
|
-
fileContent: "",
|
|
76171
|
-
validate: false,
|
|
76172
|
-
root: isRoot
|
|
76173
|
-
});
|
|
76174
|
-
}
|
|
76175
|
-
static isTargetedByRulesyncRule(rulesyncRule) {
|
|
76176
|
-
return this.isTargetedByRulesyncRuleDefault({
|
|
76177
|
-
rulesyncRule,
|
|
76178
|
-
toolTarget: this.getFamily().toolTarget
|
|
76179
|
-
});
|
|
76180
|
-
}
|
|
76181
|
-
};
|
|
76182
|
-
//#endregion
|
|
76183
76403
|
//#region src/features/rules/dsh-rule.ts
|
|
76184
76404
|
/**
|
|
76185
76405
|
* DeepSeek Harness (`dsh`) rules.
|
|
@@ -76391,7 +76611,8 @@ var FactorydroidRule = class FactorydroidRule extends ToolRule {
|
|
|
76391
76611
|
rulesyncRule,
|
|
76392
76612
|
validate,
|
|
76393
76613
|
rootPath: paths.root,
|
|
76394
|
-
nonRootPath: paths.nonRoot
|
|
76614
|
+
nonRootPath: paths.nonRoot,
|
|
76615
|
+
global
|
|
76395
76616
|
}));
|
|
76396
76617
|
}
|
|
76397
76618
|
toRulesyncRule() {
|
|
@@ -76858,7 +77079,8 @@ var KiloRule = class KiloRule extends ToolRule {
|
|
|
76858
77079
|
rulesyncRule,
|
|
76859
77080
|
validate,
|
|
76860
77081
|
rootPath: paths.root,
|
|
76861
|
-
nonRootPath: paths.nonRoot
|
|
77082
|
+
nonRootPath: paths.nonRoot,
|
|
77083
|
+
global
|
|
76862
77084
|
}));
|
|
76863
77085
|
}
|
|
76864
77086
|
toRulesyncRule() {
|
|
@@ -77362,7 +77584,8 @@ var OpenCodeRule = class OpenCodeRule extends ToolRule {
|
|
|
77362
77584
|
rulesyncRule,
|
|
77363
77585
|
validate,
|
|
77364
77586
|
rootPath: paths.root,
|
|
77365
|
-
nonRootPath: paths.nonRoot
|
|
77587
|
+
nonRootPath: paths.nonRoot,
|
|
77588
|
+
global
|
|
77366
77589
|
}));
|
|
77367
77590
|
}
|
|
77368
77591
|
toRulesyncRule() {
|
|
@@ -78831,6 +79054,14 @@ var ZoocodeRule = class extends RooRule {
|
|
|
78831
79054
|
//#endregion
|
|
78832
79055
|
//#region src/features/rules/rules-processor.ts
|
|
78833
79056
|
const RulesProcessorToolTargetSchema = z.enum(rulesProcessorToolTargetTuple);
|
|
79057
|
+
/**
|
|
79058
|
+
* Normalizes a relative directory path for comparison: POSIX separators, no
|
|
79059
|
+
* `./` segments and no trailing slash, with the current directory as `"."`
|
|
79060
|
+
* (so `"./"`, `"a/"` and `"a"` compare the way `join()` groups them).
|
|
79061
|
+
*/
|
|
79062
|
+
const normalizeRelativeDir = (dir) => posix.normalize(toPosixPath(dir)).replace(/\/+$/, "") || ".";
|
|
79063
|
+
/** A tool rule's output path relative to its output root, for comparison. */
|
|
79064
|
+
const toolOutputPath = (toolRule) => posix.join(normalizeRelativeDir(toolRule.getRelativeDirPath()), toolRule.getRelativeFilePath());
|
|
78834
79065
|
const formatRulePaths = (rules) => rules.map((r) => join(r.getRelativeDirPath(), r.getRelativeFilePath())).join(", ");
|
|
78835
79066
|
const RulesFeatureOptionsSchema = z.looseObject({
|
|
78836
79067
|
ruleDiscoveryMode: z.optional(z.enum(["none", "explicit"])),
|
|
@@ -78912,7 +79143,9 @@ const toolRuleFactories = /* @__PURE__ */ new Map([
|
|
|
78912
79143
|
meta: {
|
|
78913
79144
|
extension: "md",
|
|
78914
79145
|
supportsGlobal: true,
|
|
78915
|
-
ruleDiscoveryMode: "toon"
|
|
79146
|
+
ruleDiscoveryMode: "toon",
|
|
79147
|
+
ruleDiscoveryModeGlobal: "auto",
|
|
79148
|
+
sharedGlobalNonRootDir: true
|
|
78916
79149
|
}
|
|
78917
79150
|
}],
|
|
78918
79151
|
["antigravity-ide", {
|
|
@@ -78999,7 +79232,11 @@ const toolRuleFactories = /* @__PURE__ */ new Map([
|
|
|
78999
79232
|
extension: "md",
|
|
79000
79233
|
supportsGlobal: true,
|
|
79001
79234
|
ruleDiscoveryMode: "auto",
|
|
79002
|
-
collisionPolicy: "fold"
|
|
79235
|
+
collisionPolicy: "fold",
|
|
79236
|
+
projectInstructionBudget: {
|
|
79237
|
+
bytes: CODEXCLI_PROJECT_DOC_MAX_BYTES,
|
|
79238
|
+
remedy: "Codex CLI stops reading project `AGENTS.md` files once their combined size on the root-to-working-directory chain reaches `project_doc_max_bytes` (32 KiB by default) and silently drops the rest. Move directory-scoped rules into nested `AGENTS.md` files with `agentsmd.subprojectPath` (or `deriveSubprojectPathFromGlobs: true` in rulesync.jsonc), trim the rules, or raise `project_doc_max_bytes` in `.codex/config.toml` (ignore this warning if you already have)."
|
|
79239
|
+
}
|
|
79003
79240
|
}
|
|
79004
79241
|
}],
|
|
79005
79242
|
["commandcode", {
|
|
@@ -79457,9 +79694,61 @@ var RulesProcessor = class extends FeatureProcessor {
|
|
|
79457
79694
|
toolRules,
|
|
79458
79695
|
factory
|
|
79459
79696
|
});
|
|
79697
|
+
this.warnForInstructionBudget({
|
|
79698
|
+
toolRules,
|
|
79699
|
+
meta
|
|
79700
|
+
});
|
|
79460
79701
|
return outputFiles;
|
|
79461
79702
|
}
|
|
79462
79703
|
/**
|
|
79704
|
+
* Warn when a generated project instruction chain exceeds the tool's byte
|
|
79705
|
+
* budget (`meta.projectInstructionBudget`).
|
|
79706
|
+
*
|
|
79707
|
+
* Codex CLI concatenates the project `AGENTS.md` files from the project root
|
|
79708
|
+
* down to the cwd and stops once their combined size reaches
|
|
79709
|
+
* `project_doc_max_bytes`, truncating the file that crosses it — silently, so
|
|
79710
|
+
* without this warning the rules past the limit simply never reach the model.
|
|
79711
|
+
* Each generated file is measured together with the generated files in its
|
|
79712
|
+
* ancestor directories, since that is the chain Codex loads while working
|
|
79713
|
+
* there. When the root file alone is over the budget every chain is, so only
|
|
79714
|
+
* the root is reported; likewise each over-budget nested chain is reported
|
|
79715
|
+
* once, at its shallowest directory. With several output roots the warning
|
|
79716
|
+
* names the root it refers to. An output root below the git root is measured
|
|
79717
|
+
* without the parent directories' files Codex would also load, so the
|
|
79718
|
+
* estimate can come out low there. The budget checked is the tool's default: a value
|
|
79719
|
+
* raised by hand in the tool's own config is not read. Global scope is not
|
|
79720
|
+
* checked because Codex loads the personal `~/.codex/AGENTS.md` outside the
|
|
79721
|
+
* project budget.
|
|
79722
|
+
*/
|
|
79723
|
+
warnForInstructionBudget({ toolRules, meta }) {
|
|
79724
|
+
const budget = meta.projectInstructionBudget;
|
|
79725
|
+
if (budget === void 0 || this.global) return;
|
|
79726
|
+
const files = toolRules.map((rule) => ({
|
|
79727
|
+
dir: normalizeRelativeDir(rule.getRelativeDirPath()),
|
|
79728
|
+
path: toPosixPath(join(rule.getRelativeDirPath(), rule.getRelativeFilePath())),
|
|
79729
|
+
bytes: Buffer.byteLength(addTrailingNewline(rule.getFileContent()), "utf8")
|
|
79730
|
+
}));
|
|
79731
|
+
const isAncestorOrSelf = (ancestor, dir) => ancestor === "." || ancestor === dir || dir.startsWith(`${ancestor}/`);
|
|
79732
|
+
const location = this.outputRoot === process.cwd() ? "" : ` under '${this.outputRoot}'`;
|
|
79733
|
+
const rootFiles = files.filter(({ dir }) => dir === ".");
|
|
79734
|
+
const rootBytes = rootFiles.reduce((sum, { bytes }) => sum + bytes, 0);
|
|
79735
|
+
if (rootBytes > budget.bytes) {
|
|
79736
|
+
this.logger.warn(`The generated ${this.toolTarget} root instruction file${location} (${rootFiles.map(({ path }) => path).join(", ")}) is ${rootBytes} bytes, over the ${budget.bytes}-byte limit. ${budget.remedy}`);
|
|
79737
|
+
return;
|
|
79738
|
+
}
|
|
79739
|
+
const reportedDirs = [];
|
|
79740
|
+
const nestedFiles = files.filter(({ dir }) => dir !== ".").toSorted((a, b) => a.dir.split("/").length - b.dir.split("/").length);
|
|
79741
|
+
for (const file of nestedFiles) {
|
|
79742
|
+
if (reportedDirs.some((dir) => isAncestorOrSelf(dir, file.dir))) continue;
|
|
79743
|
+
const chain = files.filter(({ dir }) => isAncestorOrSelf(dir, file.dir));
|
|
79744
|
+
const chainBytes = chain.reduce((sum, { bytes }) => sum + bytes, 0);
|
|
79745
|
+
if (chainBytes > budget.bytes) {
|
|
79746
|
+
reportedDirs.push(file.dir);
|
|
79747
|
+
this.logger.warn(`The generated ${this.toolTarget} instruction files${location} loaded while working in '${file.dir}' (${chain.map(({ path }) => path).join(", ")}) total ${chainBytes} bytes, over the ${budget.bytes}-byte limit (as is every directory below it). ${budget.remedy}`);
|
|
79748
|
+
}
|
|
79749
|
+
}
|
|
79750
|
+
}
|
|
79751
|
+
/**
|
|
79463
79752
|
* Handle localRoot rules (only in non-global mode and when enabled). Mutates
|
|
79464
79753
|
* `toolRules` in place.
|
|
79465
79754
|
*/
|
|
@@ -79935,7 +80224,7 @@ var RulesProcessor = class extends FeatureProcessor {
|
|
|
79935
80224
|
*/
|
|
79936
80225
|
generateReferenceSectionFromMeta(meta, toolRules) {
|
|
79937
80226
|
switch (resolveRuleDiscoveryMode({
|
|
79938
|
-
defaultMode: meta.ruleDiscoveryMode,
|
|
80227
|
+
defaultMode: this.global && meta.ruleDiscoveryModeGlobal ? meta.ruleDiscoveryModeGlobal : meta.ruleDiscoveryMode,
|
|
79939
80228
|
options: this.featureOptions
|
|
79940
80229
|
})) {
|
|
79941
80230
|
case "toon": return this.generateToonReferencesSection(toolRules);
|
|
@@ -80131,14 +80420,14 @@ As this project's AI coding tool, you must follow the additional conventions bel
|
|
|
80131
80420
|
* decides for all of them: its `pi.contextFile` is copied onto the non-root
|
|
80132
80421
|
* rules, and the flag set only on a non-root rule is dropped with a warning.
|
|
80133
80422
|
*/
|
|
80134
|
-
alignPiContextFile(rules) {
|
|
80423
|
+
alignPiContextFile(rules, { warn = true } = {}) {
|
|
80135
80424
|
if (this.toolTarget !== "pi") return rules;
|
|
80136
80425
|
const factory = this.getFactory(this.toolTarget);
|
|
80137
80426
|
const targeted = rules.filter((rule) => factory.class.isTargetedByRulesyncRule(rule));
|
|
80138
80427
|
const rootContextFile = targeted.some((rule) => rule.getFrontmatter().root === true && rule.getFrontmatter().pi?.contextFile === "override") ? "override" : void 0;
|
|
80139
80428
|
const mismatched = targeted.filter((rule) => rule.getFrontmatter().pi?.contextFile !== rootContextFile);
|
|
80140
80429
|
if (mismatched.length === 0) return rules;
|
|
80141
|
-
if (rootContextFile === void 0) this.logger.warn(`pi.contextFile is set on ${mismatched.length} non-root rule(s) but not on the root rule, so it is ignored: Pi folds every rule body into the root context file, and emitting AGENTS.override.md for some of them would hide the rest. Set it on the root rule instead: ${formatRulePaths(mismatched)}`);
|
|
80430
|
+
if (warn && rootContextFile === void 0) this.logger.warn(`pi.contextFile is set on ${mismatched.length} non-root rule(s) but not on the root rule, so it is ignored: Pi folds every rule body into the root context file, and emitting AGENTS.override.md for some of them would hide the rest. Set it on the root rule instead: ${formatRulePaths(mismatched)}`);
|
|
80142
80431
|
const mismatchedSet = new Set(mismatched);
|
|
80143
80432
|
return rules.map((rule) => {
|
|
80144
80433
|
if (!mismatchedSet.has(rule)) return rule;
|
|
@@ -80192,14 +80481,72 @@ As this project's AI coding tool, you must follow the additional conventions bel
|
|
|
80192
80481
|
* duplication check the same way `loadRulesyncFiles`'s global-mode branch
|
|
80193
80482
|
* excludes it from `nonRootRules`: `generate` ignores `localRoot` entirely
|
|
80194
80483
|
* in global mode, so such a rule is never actually folded into the global
|
|
80195
|
-
* root output and warning about it here would be inaccurate.
|
|
80484
|
+
* root output and warning about it here would be inaccurate. The same goes
|
|
80485
|
+
* for a tool that writes `localRoot` to a dedicated local file.
|
|
80486
|
+
*
|
|
80487
|
+
* Non-root rules written to a file other than the root (nested
|
|
80488
|
+
* per-directory files, Pi's `APPEND_SYSTEM.md`) get a separate warning when
|
|
80489
|
+
* that file already exists and would import under a different name.
|
|
80196
80490
|
*/
|
|
80197
80491
|
async warnForFoldImportDuplicationRisk() {
|
|
80198
80492
|
const factory = this.getFactory(this.toolTarget);
|
|
80199
80493
|
if (factory.meta.collisionPolicy !== "fold") return;
|
|
80200
|
-
const
|
|
80201
|
-
|
|
80202
|
-
|
|
80494
|
+
const targetedRules = this.alignPiContextFile(await this.loadMergedRulesyncRules(), { warn: false }).filter((rule) => factory.class.isTargetedByRulesyncRule(rule));
|
|
80495
|
+
let includeLocalRoot = !this.global;
|
|
80496
|
+
try {
|
|
80497
|
+
includeLocalRoot &&= resolveIncludeLocalRoot(this.featureOptions);
|
|
80498
|
+
} catch {}
|
|
80499
|
+
const targetedNonRootRules = targetedRules.filter((rule) => !rule.getFrontmatter().root && !(rule.getFrontmatter().localRoot && (!includeLocalRoot || factory.meta.localRootMode === "separate-local-file")));
|
|
80500
|
+
const rootPaths = /* @__PURE__ */ new Set();
|
|
80501
|
+
const { root } = factory.class.getSettablePaths({ global: this.global });
|
|
80502
|
+
if (root) rootPaths.add(posix.join(normalizeRelativeDir(root.relativeDirPath), root.relativeFilePath));
|
|
80503
|
+
for (const rulesyncRule of targetedRules.filter((rule) => rule.getFrontmatter().root)) {
|
|
80504
|
+
const toolRule = this.toToolRuleForImportCheck({
|
|
80505
|
+
factory,
|
|
80506
|
+
rulesyncRule
|
|
80507
|
+
});
|
|
80508
|
+
rootPaths.add(toolOutputPath(toolRule));
|
|
80509
|
+
}
|
|
80510
|
+
const separateRules = [];
|
|
80511
|
+
const foldedRules = [];
|
|
80512
|
+
let localRootCounted = false;
|
|
80513
|
+
for (const rulesyncRule of targetedNonRootRules) {
|
|
80514
|
+
if (rulesyncRule.getFrontmatter().localRoot) {
|
|
80515
|
+
if (!localRootCounted) {
|
|
80516
|
+
foldedRules.push(rulesyncRule);
|
|
80517
|
+
localRootCounted = true;
|
|
80518
|
+
}
|
|
80519
|
+
continue;
|
|
80520
|
+
}
|
|
80521
|
+
const toolRule = this.toToolRuleForImportCheck({
|
|
80522
|
+
factory,
|
|
80523
|
+
rulesyncRule
|
|
80524
|
+
});
|
|
80525
|
+
if (rootPaths.size === 0 || rootPaths.has(toolOutputPath(toolRule))) foldedRules.push(rulesyncRule);
|
|
80526
|
+
else separateRules.push({
|
|
80527
|
+
toolRule,
|
|
80528
|
+
rulesyncRule
|
|
80529
|
+
});
|
|
80530
|
+
}
|
|
80531
|
+
if (foldedRules.length > 0) this.logger.warn(`Importing ${this.toolTarget}'s root file will re-add content already folded from ${formatRulePaths(foldedRules)}: ${this.toolTarget} concatenates every non-root rule into its single root output file, so the imported copy duplicates them the next time you run \`rulesync generate --targets ${this.toolTarget}\`. Review the imported rule and remove the duplicated content, or remove the original non-root rule files, before generating again.`);
|
|
80532
|
+
const duplicated = [];
|
|
80533
|
+
for (const conversion of separateRules) {
|
|
80534
|
+
const { toolRule, rulesyncRule } = conversion;
|
|
80535
|
+
if (toolRule.toRulesyncRule().getRelativeFilePath().toLowerCase() === rulesyncRule.getRelativeFilePath().toLowerCase()) continue;
|
|
80536
|
+
if (await fileExists(toolRule.getFilePath())) duplicated.push(conversion);
|
|
80537
|
+
}
|
|
80538
|
+
if (duplicated.length > 0) {
|
|
80539
|
+
const fileNames = [...new Set(duplicated.map(({ toolRule }) => toolRule.getRelativeFilePath()))].join(", ");
|
|
80540
|
+
this.logger.warn(`Importing ${this.toolTarget}'s ${fileNames} files outside the root file will re-add content already written from ${formatRulePaths(duplicated.map(({ rulesyncRule }) => rulesyncRule))}: each such file is imported as its own rule under a name derived from its path, so the imported copy and the original rule resolve to the same file and are concatenated the next time you run \`rulesync generate --targets ${this.toolTarget}\`. Remove one of the two copies before generating again.`);
|
|
80541
|
+
}
|
|
80542
|
+
}
|
|
80543
|
+
toToolRuleForImportCheck({ factory, rulesyncRule }) {
|
|
80544
|
+
return factory.class.fromRulesyncRule({
|
|
80545
|
+
outputRoot: this.outputRoot,
|
|
80546
|
+
rulesyncRule,
|
|
80547
|
+
validate: false,
|
|
80548
|
+
global: this.global
|
|
80549
|
+
});
|
|
80203
80550
|
}
|
|
80204
80551
|
/**
|
|
80205
80552
|
* Implementation of abstract method from FeatureProcessor
|
|
@@ -80396,7 +80743,8 @@ As this project's AI coding tool, you must follow the additional conventions bel
|
|
|
80396
80743
|
const nonRootToolRules = await (async () => {
|
|
80397
80744
|
if (!settablePaths.nonRoot) return [];
|
|
80398
80745
|
const nonRootOutputRoot = join(this.outputRoot, settablePaths.nonRoot.relativeDirPath);
|
|
80399
|
-
const
|
|
80746
|
+
const isSharedGlobalNonRootDir = this.global && factory.meta.sharedGlobalNonRootDir === true;
|
|
80747
|
+
const nonRootFilePaths = await findFilesByGlobs(`${isSharedGlobalNonRootDir ? "" : "**/"}*.${factory.meta.extension}`, { cwd: nonRootOutputRoot });
|
|
80400
80748
|
if (forDeletion) return buildDeletionRulesFromPaths(nonRootFilePaths, {
|
|
80401
80749
|
outputRootOverride: nonRootOutputRoot,
|
|
80402
80750
|
relativeDirPathOverride: settablePaths.nonRoot.relativeDirPath
|
|
@@ -80409,19 +80757,25 @@ As this project's AI coding tool, you must follow the additional conventions bel
|
|
|
80409
80757
|
if (!ok) this.logger.warn(`Skipping reserved Rovodev path under modular-rules (import): ${join(modularRootRelative, relativeFilePath)}`);
|
|
80410
80758
|
return ok;
|
|
80411
80759
|
}) : nonRootFilePaths).filter((filePath) => rootFileNameInSameDir === void 0 || relative(nonRootOutputRoot, filePath) !== rootFileNameInSameDir);
|
|
80412
|
-
return await Promise.all(nonRootPathsForImport.map((filePath) => {
|
|
80760
|
+
return (await Promise.all(nonRootPathsForImport.map(async (filePath) => {
|
|
80413
80761
|
const relativeFilePath = relative(nonRootOutputRoot, filePath);
|
|
80414
80762
|
checkPathTraversal({
|
|
80415
80763
|
relativePath: relativeFilePath,
|
|
80416
80764
|
intendedRootDir: nonRootOutputRoot
|
|
80417
80765
|
});
|
|
80418
|
-
|
|
80419
|
-
|
|
80420
|
-
|
|
80421
|
-
|
|
80422
|
-
|
|
80423
|
-
|
|
80424
|
-
|
|
80766
|
+
try {
|
|
80767
|
+
return await factory.class.fromFile({
|
|
80768
|
+
outputRoot: this.outputRoot,
|
|
80769
|
+
relativeDirPath: modularRootRelative,
|
|
80770
|
+
relativeFilePath,
|
|
80771
|
+
global: this.global
|
|
80772
|
+
});
|
|
80773
|
+
} catch (error) {
|
|
80774
|
+
if (!isSharedGlobalNonRootDir) throw error;
|
|
80775
|
+
this.logger.warn(`Skipping ${stripControlCharacters(join(modularRootRelative, relativeFilePath))} for ${this.toolTarget}: ${formatError(error)}`);
|
|
80776
|
+
return;
|
|
80777
|
+
}
|
|
80778
|
+
}))).filter((rule) => rule !== void 0);
|
|
80425
80779
|
})();
|
|
80426
80780
|
this.logger.debug(`Found ${nonRootToolRules.length} non-root tool rule files`);
|
|
80427
80781
|
return [
|
|
@@ -80493,6 +80847,14 @@ As this project's AI coding tool, you must follow the additional conventions bel
|
|
|
80493
80847
|
function isPackagingToolTarget(toolTarget) {
|
|
80494
80848
|
return PACKAGING_TOOL_TARGETS.includes(toolTarget);
|
|
80495
80849
|
}
|
|
80850
|
+
/**
|
|
80851
|
+
* Packaging targets write into a plugin directory and support project scope
|
|
80852
|
+
* only. In global mode their output root would be the home directory, so
|
|
80853
|
+
* callers reject or skip them up front instead of checking all of $HOME.
|
|
80854
|
+
*/
|
|
80855
|
+
function formatPackagingTargetGlobalMessage(toolTarget) {
|
|
80856
|
+
return `Target '${toolTarget}' is a plugin packaging target and supports only project scope. Re-run without '--global'.`;
|
|
80857
|
+
}
|
|
80496
80858
|
async function assertPluginRootSafe(params) {
|
|
80497
80859
|
if (!isPackagingToolTarget(params.toolTarget)) return;
|
|
80498
80860
|
await assertDirectoryIfExists(params.outputRoot);
|
|
@@ -81412,14 +81774,17 @@ function warnUnsupportedTargets(params) {
|
|
|
81412
81774
|
} catch {
|
|
81413
81775
|
oppositeScopeTargets = [];
|
|
81414
81776
|
}
|
|
81415
|
-
for (const target of config.getTargets())
|
|
81416
|
-
|
|
81417
|
-
if (
|
|
81418
|
-
|
|
81419
|
-
|
|
81420
|
-
|
|
81421
|
-
|
|
81422
|
-
|
|
81777
|
+
for (const target of config.getTargets()) {
|
|
81778
|
+
if (config.getGlobal() && isPackagingToolTarget(target)) continue;
|
|
81779
|
+
if (!supportedTargets.includes(target) && config.getFeatures(target).includes(featureName)) {
|
|
81780
|
+
const simulateOption = SIMULATE_OPTION_MAP[featureName];
|
|
81781
|
+
if (simulateOption && simulatedTargets.includes(target)) logger.warn(`Target '${target}' only supports simulated '${featureName}'. Use '${simulateOption}' to enable it. Skipping.`);
|
|
81782
|
+
else if (oppositeScopeTargets.includes(target)) {
|
|
81783
|
+
const supportedScope = config.getGlobal() ? "project" : "global";
|
|
81784
|
+
const retry = config.getGlobal() ? "without '--global'" : "with '--global'";
|
|
81785
|
+
logger.warn(`Target '${target}' supports the feature '${featureName}' only in ${supportedScope} scope. Re-run ${retry}. Skipping.`);
|
|
81786
|
+
} else logger.warn(`Target '${target}' does not support the feature '${featureName}'. Skipping.`);
|
|
81787
|
+
}
|
|
81423
81788
|
}
|
|
81424
81789
|
}
|
|
81425
81790
|
/**
|
|
@@ -81672,10 +82037,16 @@ async function generate(params) {
|
|
|
81672
82037
|
const { config, logger } = params;
|
|
81673
82038
|
resetRootShadowingWarnings({ logger });
|
|
81674
82039
|
resetRunWarningState();
|
|
81675
|
-
for (const toolTarget of config.getTargets())
|
|
81676
|
-
toolTarget
|
|
81677
|
-
|
|
81678
|
-
|
|
82040
|
+
for (const toolTarget of config.getTargets()) {
|
|
82041
|
+
if (config.getGlobal() && isPackagingToolTarget(toolTarget)) {
|
|
82042
|
+
logger.warn(`${formatPackagingTargetGlobalMessage(toolTarget)} Skipping.`);
|
|
82043
|
+
continue;
|
|
82044
|
+
}
|
|
82045
|
+
for (const outputRoot of config.getOutputRoots(toolTarget)) await assertPluginRootSafe({
|
|
82046
|
+
toolTarget,
|
|
82047
|
+
outputRoot
|
|
82048
|
+
});
|
|
82049
|
+
}
|
|
81679
82050
|
await warnSkillSubagentNameCollisions({
|
|
81680
82051
|
config,
|
|
81681
82052
|
logger
|
|
@@ -81798,6 +82169,115 @@ function computeRootFileOwnership(params) {
|
|
|
81798
82169
|
}
|
|
81799
82170
|
return ownerByPath;
|
|
81800
82171
|
}
|
|
82172
|
+
function createSkippedRootFileCheck({ rootFileOwner }) {
|
|
82173
|
+
const skippedByRoot = /* @__PURE__ */ new Map();
|
|
82174
|
+
const emittedByRoot = /* @__PURE__ */ new Map();
|
|
82175
|
+
const emittedKey = (toolTarget, relativePath) => `${toolTarget}\0${relativePath}`;
|
|
82176
|
+
const loadOwnerToolFiles = async (processor) => {
|
|
82177
|
+
const rulesyncFiles = await processor.loadRulesyncFiles();
|
|
82178
|
+
return {
|
|
82179
|
+
toolFiles: rulesyncFiles.length > 0 ? await processor.convertRulesyncFilesToToolFiles(rulesyncFiles) : [],
|
|
82180
|
+
sourceLoadFailed: processor.hasRulesyncSourceLoadFailure()
|
|
82181
|
+
};
|
|
82182
|
+
};
|
|
82183
|
+
return {
|
|
82184
|
+
observe: ({ toolTarget, outputRoot, processor, toolFiles, skipFilePaths }) => {
|
|
82185
|
+
if (rootFileOwner.size === 0) return;
|
|
82186
|
+
for (const toolFile of toolFiles) {
|
|
82187
|
+
const relativePath = toolFile.getRelativePathFromCwd();
|
|
82188
|
+
if (!rootFileOwner.has(relativePath)) continue;
|
|
82189
|
+
const emitted = emittedByRoot.get(outputRoot) ?? /* @__PURE__ */ new Set();
|
|
82190
|
+
emittedByRoot.set(outputRoot, emitted);
|
|
82191
|
+
emitted.add(emittedKey(toolTarget, relativePath));
|
|
82192
|
+
if (!skipFilePaths.has(relativePath)) continue;
|
|
82193
|
+
const skipped = skippedByRoot.get(outputRoot) ?? /* @__PURE__ */ new Map();
|
|
82194
|
+
skippedByRoot.set(outputRoot, skipped);
|
|
82195
|
+
skipped.set(relativePath, {
|
|
82196
|
+
processor,
|
|
82197
|
+
toolFile
|
|
82198
|
+
});
|
|
82199
|
+
}
|
|
82200
|
+
},
|
|
82201
|
+
verify: async ({ isOwnerProcessed, createOwnerProcessor }) => {
|
|
82202
|
+
let count = 0;
|
|
82203
|
+
const paths = [];
|
|
82204
|
+
let sourceLoadFailed = false;
|
|
82205
|
+
for (const [outputRoot, skipped] of skippedByRoot) {
|
|
82206
|
+
const ownerOutputs = /* @__PURE__ */ new Map();
|
|
82207
|
+
for (const [relativePath, fallback] of skipped) {
|
|
82208
|
+
const owner = rootFileOwner.get(relativePath);
|
|
82209
|
+
if (owner === void 0) continue;
|
|
82210
|
+
if (emittedByRoot.get(outputRoot)?.has(emittedKey(owner, relativePath))) continue;
|
|
82211
|
+
let expected = fallback;
|
|
82212
|
+
if (!isOwnerProcessed(owner)) {
|
|
82213
|
+
if (!ownerOutputs.has(owner)) {
|
|
82214
|
+
const processor = await createOwnerProcessor({
|
|
82215
|
+
toolTarget: owner,
|
|
82216
|
+
outputRoot
|
|
82217
|
+
});
|
|
82218
|
+
if (processor === void 0) ownerOutputs.set(owner, void 0);
|
|
82219
|
+
else {
|
|
82220
|
+
const loaded = await loadOwnerToolFiles(processor);
|
|
82221
|
+
if (loaded.sourceLoadFailed) sourceLoadFailed = true;
|
|
82222
|
+
ownerOutputs.set(owner, {
|
|
82223
|
+
processor,
|
|
82224
|
+
toolFiles: loaded.toolFiles
|
|
82225
|
+
});
|
|
82226
|
+
}
|
|
82227
|
+
}
|
|
82228
|
+
const ownerOutput = ownerOutputs.get(owner);
|
|
82229
|
+
const ownerFile = ownerOutput?.toolFiles.find((file) => file.getRelativePathFromCwd() === relativePath && file.getFilePath() === fallback.toolFile.getFilePath());
|
|
82230
|
+
if (ownerOutput !== void 0 && ownerFile !== void 0) expected = {
|
|
82231
|
+
processor: ownerOutput.processor,
|
|
82232
|
+
toolFile: ownerFile
|
|
82233
|
+
};
|
|
82234
|
+
}
|
|
82235
|
+
const result = await expected.processor.writeAiFiles([expected.toolFile]);
|
|
82236
|
+
count += result.count;
|
|
82237
|
+
paths.push(...result.paths);
|
|
82238
|
+
}
|
|
82239
|
+
}
|
|
82240
|
+
return {
|
|
82241
|
+
count,
|
|
82242
|
+
paths,
|
|
82243
|
+
hasDiff: count > 0,
|
|
82244
|
+
sourceLoadFailed
|
|
82245
|
+
};
|
|
82246
|
+
}
|
|
82247
|
+
};
|
|
82248
|
+
}
|
|
82249
|
+
/**
|
|
82250
|
+
* The skills a full `rulesync generate` hands to the rules step: what the
|
|
82251
|
+
* skills step collects for every config-file target that generates skills, in
|
|
82252
|
+
* the same order. Simulated skill sections in a root file list these, so a
|
|
82253
|
+
* narrowed check needs them to rebuild another target's root file.
|
|
82254
|
+
*/
|
|
82255
|
+
async function loadConfigFileSkills({ config, logger }) {
|
|
82256
|
+
const supportedSkillsTargets = SkillsProcessor.getToolTargets({
|
|
82257
|
+
global: config.getGlobal(),
|
|
82258
|
+
includeSimulated: config.getSimulateSkills()
|
|
82259
|
+
});
|
|
82260
|
+
const skills = [];
|
|
82261
|
+
for (const toolTarget of intersection(config.getConfigFileTargets(), supportedSkillsTargets)) {
|
|
82262
|
+
if (!config.getConfigFileFeatures(toolTarget).includes("skills")) continue;
|
|
82263
|
+
for (const outputRoot of config.getOutputRoots(toolTarget)) {
|
|
82264
|
+
const processor = new SkillsProcessor({
|
|
82265
|
+
outputRoot: resolveToolOutputRoot({
|
|
82266
|
+
outputRoot,
|
|
82267
|
+
toolTarget,
|
|
82268
|
+
global: config.getGlobal()
|
|
82269
|
+
}),
|
|
82270
|
+
inputRoots: config.getInputRoots(),
|
|
82271
|
+
toolTarget,
|
|
82272
|
+
global: config.getGlobal(),
|
|
82273
|
+
dryRun: true,
|
|
82274
|
+
logger
|
|
82275
|
+
});
|
|
82276
|
+
for (const rulesyncDir of await processor.loadRulesyncDirs()) if (rulesyncDir instanceof RulesyncSkill) skills.push(rulesyncDir);
|
|
82277
|
+
}
|
|
82278
|
+
}
|
|
82279
|
+
return skills;
|
|
82280
|
+
}
|
|
81801
82281
|
async function generateRulesCore(params) {
|
|
81802
82282
|
const { config, logger, sweepPlan, skills } = params;
|
|
81803
82283
|
let totalCount = 0;
|
|
@@ -81813,32 +82293,47 @@ async function generateRulesCore(params) {
|
|
|
81813
82293
|
logger
|
|
81814
82294
|
});
|
|
81815
82295
|
const foldRootOverwriteWatch = createFoldRootOverwriteWatch({ logger });
|
|
82296
|
+
let fullRunSkills;
|
|
82297
|
+
const loadFullRunSkills = () => {
|
|
82298
|
+
fullRunSkills ??= loadConfigFileSkills({
|
|
82299
|
+
config,
|
|
82300
|
+
logger
|
|
82301
|
+
});
|
|
82302
|
+
return fullRunSkills;
|
|
82303
|
+
};
|
|
82304
|
+
const createProcessor = ({ toolTarget, outputRoot, featureOptions, skills: processorSkills }) => new RulesProcessor({
|
|
82305
|
+
outputRoot: resolveToolOutputRoot({
|
|
82306
|
+
outputRoot,
|
|
82307
|
+
toolTarget,
|
|
82308
|
+
global: config.getGlobal()
|
|
82309
|
+
}),
|
|
82310
|
+
inputRoots: config.getInputRoots(),
|
|
82311
|
+
toolTarget,
|
|
82312
|
+
global: config.getGlobal(),
|
|
82313
|
+
simulateCommands: config.getSimulateCommands(),
|
|
82314
|
+
simulateSubagents: config.getSimulateSubagents(),
|
|
82315
|
+
simulateSkills: config.getSimulateSkills(),
|
|
82316
|
+
language: config.getLanguage(),
|
|
82317
|
+
deriveSubprojectPathFromGlobs: config.getDeriveSubprojectPathFromGlobs(),
|
|
82318
|
+
skills: processorSkills,
|
|
82319
|
+
featureOptions,
|
|
82320
|
+
delete: config.getDelete(),
|
|
82321
|
+
dryRun: config.isPreviewMode(),
|
|
82322
|
+
logger
|
|
82323
|
+
});
|
|
81816
82324
|
const isCheck = config.getCheck();
|
|
81817
82325
|
const rootFileOwner = isCheck ? computeRootFileOwnership({
|
|
81818
|
-
targets: config.getConfigFileTargets(),
|
|
82326
|
+
targets: config.getConfigFileTargets().filter((target) => (toolTargets.includes(target) ? config.getFeatures(target) : config.getConfigFileFeatures(target)).includes("rules")),
|
|
81819
82327
|
global: config.getGlobal()
|
|
81820
82328
|
}) : /* @__PURE__ */ new Map();
|
|
82329
|
+
const skippedRootFileCheck = createSkippedRootFileCheck({ rootFileOwner });
|
|
81821
82330
|
for (const toolTarget of toolTargets) for (const outputRoot of config.getOutputRoots(toolTarget)) {
|
|
81822
82331
|
if (!config.getFeatures(toolTarget).includes("rules")) continue;
|
|
81823
|
-
const processor =
|
|
81824
|
-
outputRoot: resolveToolOutputRoot({
|
|
81825
|
-
outputRoot,
|
|
81826
|
-
toolTarget,
|
|
81827
|
-
global: config.getGlobal()
|
|
81828
|
-
}),
|
|
81829
|
-
inputRoots: config.getInputRoots(),
|
|
82332
|
+
const processor = createProcessor({
|
|
81830
82333
|
toolTarget,
|
|
81831
|
-
|
|
81832
|
-
simulateCommands: config.getSimulateCommands(),
|
|
81833
|
-
simulateSubagents: config.getSimulateSubagents(),
|
|
81834
|
-
simulateSkills: config.getSimulateSkills(),
|
|
81835
|
-
language: config.getLanguage(),
|
|
81836
|
-
deriveSubprojectPathFromGlobs: config.getDeriveSubprojectPathFromGlobs(),
|
|
81837
|
-
skills,
|
|
82334
|
+
outputRoot,
|
|
81838
82335
|
featureOptions: config.getFeatureOptions(toolTarget, "rules"),
|
|
81839
|
-
|
|
81840
|
-
dryRun: config.isPreviewMode(),
|
|
81841
|
-
logger
|
|
82336
|
+
skills
|
|
81842
82337
|
});
|
|
81843
82338
|
const rulesyncFiles = await processor.loadRulesyncFiles();
|
|
81844
82339
|
const skipFilePaths = /* @__PURE__ */ new Set();
|
|
@@ -81851,16 +82346,39 @@ async function generateRulesCore(params) {
|
|
|
81851
82346
|
rulesyncFiles,
|
|
81852
82347
|
sweepPlan,
|
|
81853
82348
|
skipFilePaths: skipFilePaths.size > 0 ? skipFilePaths : void 0,
|
|
81854
|
-
onToolFiles: (toolFiles) =>
|
|
81855
|
-
|
|
81856
|
-
|
|
81857
|
-
|
|
82349
|
+
onToolFiles: (toolFiles) => {
|
|
82350
|
+
foldRootOverwriteWatch.observe({
|
|
82351
|
+
toolTarget,
|
|
82352
|
+
toolFiles
|
|
82353
|
+
});
|
|
82354
|
+
skippedRootFileCheck.observe({
|
|
82355
|
+
toolTarget,
|
|
82356
|
+
outputRoot,
|
|
82357
|
+
processor,
|
|
82358
|
+
toolFiles,
|
|
82359
|
+
skipFilePaths
|
|
82360
|
+
});
|
|
82361
|
+
}
|
|
81858
82362
|
});
|
|
81859
82363
|
totalCount += result.count;
|
|
81860
82364
|
allPaths.push(...result.paths);
|
|
81861
82365
|
if (result.hasDiff) hasDiff = true;
|
|
81862
82366
|
if (result.sourceLoadFailed) sourceLoadFailed = true;
|
|
81863
82367
|
}
|
|
82368
|
+
if (isCheck) {
|
|
82369
|
+
const skippedResult = await skippedRootFileCheck.verify({
|
|
82370
|
+
isOwnerProcessed: (owner) => toolTargets.includes(owner) && config.getFeatures(owner).includes("rules"),
|
|
82371
|
+
createOwnerProcessor: async (ownerParams) => supportedTargets.includes(ownerParams.toolTarget) && config.getOutputRoots(ownerParams.toolTarget).includes(ownerParams.outputRoot) ? createProcessor({
|
|
82372
|
+
...ownerParams,
|
|
82373
|
+
featureOptions: config.getConfigFileFeatureOptions(ownerParams.toolTarget, "rules"),
|
|
82374
|
+
skills: config.getSimulateSkills() && SkillsProcessor.getToolTargetsSimulated().includes(ownerParams.toolTarget) ? await loadFullRunSkills() : void 0
|
|
82375
|
+
}) : void 0
|
|
82376
|
+
});
|
|
82377
|
+
totalCount += skippedResult.count;
|
|
82378
|
+
allPaths.push(...skippedResult.paths);
|
|
82379
|
+
if (skippedResult.hasDiff) hasDiff = true;
|
|
82380
|
+
if (skippedResult.sourceLoadFailed) sourceLoadFailed = true;
|
|
82381
|
+
}
|
|
81864
82382
|
foldRootOverwriteWatch.report();
|
|
81865
82383
|
return {
|
|
81866
82384
|
count: totalCount,
|
|
@@ -82292,6 +82810,7 @@ function getToolOutputRoot({ config, tool }) {
|
|
|
82292
82810
|
async function importFromTool(params) {
|
|
82293
82811
|
const { config, tool, logger } = params;
|
|
82294
82812
|
resetRunWarningState();
|
|
82813
|
+
if (config.getGlobal() && isPackagingToolTarget(tool)) throw new Error(formatPackagingTargetGlobalMessage(tool));
|
|
82295
82814
|
await assertPluginRootSafe({
|
|
82296
82815
|
toolTarget: tool,
|
|
82297
82816
|
outputRoot: getToolOutputRoot({
|
|
@@ -82352,7 +82871,7 @@ async function importRulesCore(params) {
|
|
|
82352
82871
|
if (!config.getFeatures(tool).includes("rules")) return 0;
|
|
82353
82872
|
const global = config.getGlobal();
|
|
82354
82873
|
if (!RulesProcessor.getToolTargets({ global }).includes(tool)) return 0;
|
|
82355
|
-
const
|
|
82874
|
+
const baseParams = {
|
|
82356
82875
|
outputRoot: getToolOutputRoot({
|
|
82357
82876
|
config,
|
|
82358
82877
|
tool
|
|
@@ -82360,13 +82879,23 @@ async function importRulesCore(params) {
|
|
|
82360
82879
|
toolTarget: tool,
|
|
82361
82880
|
global,
|
|
82362
82881
|
logger
|
|
82363
|
-
}
|
|
82882
|
+
};
|
|
82883
|
+
const rulesProcessor = new RulesProcessor(baseParams);
|
|
82364
82884
|
const toolFiles = await rulesProcessor.loadToolFiles();
|
|
82365
82885
|
if (toolFiles.length === 0) {
|
|
82366
82886
|
logger.warn(`No rule files found for ${tool}. Skipping import.`);
|
|
82367
82887
|
return 0;
|
|
82368
82888
|
}
|
|
82369
|
-
|
|
82889
|
+
try {
|
|
82890
|
+
await new RulesProcessor({
|
|
82891
|
+
...baseParams,
|
|
82892
|
+
inputRoots: config.getInputRoots(),
|
|
82893
|
+
deriveSubprojectPathFromGlobs: config.getDeriveSubprojectPathFromGlobs(),
|
|
82894
|
+
featureOptions: config.getFeatureOptions(tool, "rules")
|
|
82895
|
+
}).warnForFoldImportDuplicationRisk();
|
|
82896
|
+
} catch (error) {
|
|
82897
|
+
logger.warn(`Skipped the ${tool} import duplication check: ${formatError(error)}`);
|
|
82898
|
+
}
|
|
82370
82899
|
const rulesyncFiles = await rulesProcessor.convertToolFilesToRulesyncFiles(toolFiles);
|
|
82371
82900
|
const { count: writtenCount } = await rulesProcessor.writeAiFiles(rulesyncFiles);
|
|
82372
82901
|
if (config.getVerbose() && writtenCount > 0) logger.success(`Created ${writtenCount} rule files`);
|
|
@@ -82616,4 +83145,4 @@ async function importChecksCore(params) {
|
|
|
82616
83145
|
//#endregion
|
|
82617
83146
|
export { RulesyncCommand as $, toPosixPath as $t, CLAUDECODE_MEMORIES_DIR_NAME as A, RULESYNC_XDG_CONFIG_HOME_DEFAULT_DIR_NAME as An, checkPathTraversal as At, RulesyncSubagent as B, stripControlCharacters as Bn, listDirectoryEntryNames as Bt, COMMANDCODE_DIR as C, RULESYNC_PERMISSIONS_SCHEMA_URL as Cn, withWarnOnceScope as Ct, CODEXCLI_DIR as D, RULESYNC_SOURCES_LOCK_RELATIVE_FILE_PATH as Dn, assertDirectoryIfExists as Dt, CODEXCLI_BASH_RULES_FILE_NAME as E, RULESYNC_SKILLS_RELATIVE_DIR_PATH as En, applyFileMode as Et, caseFoldIdentity as F, formatError as Fn, getFileSize as Ft, RulesyncRuleFrontmatterSchema as G, readFileContentOrNull as Gt, RulesyncSkill as H, stripHiddenCharacters as Hn, listSubdirectoryNames as Ht, groupSpellingsByCaseFoldedIdentity as I, truncateText as In, getHomeDirectory as It, RulesyncIgnore as J, removeFile as Jt, RulesyncPermissions as K, removeDirectory as Kt, AUGMENTCODE_DIR as L, hasDeceptiveHiddenCharacters as Ln, isFileNotFoundError as Lt, CLAUDECODE_SKILLS_DIR_PATH as M, ALL_FEATURES as Mn, directoryExists as Mt, FACTORYDROID_DIR as N, ALL_FEATURES_WITH_WILDCARD as Nn, ensureDir as Nt, CLAUDECODE_DIR as O, RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH as On, assertTreeContainsNoSymlinks as Ot, FACTORYDROID_SETTINGS_LOCAL_FILE_NAME as P, DEPRECATED_FEATURE_REPLACEMENTS as Pn, fileExists as Pt, parseJsonc as Q, runWithDirectoryRollback as Qt, AUGMENTCODE_SETTINGS_LOCAL_FILE_NAME as R, hasEnclosingMarkOutsideKeycap as Rn, isFileSystemError as Rt, QWENCODE_LOCAL_RULE_FILE_NAME as S, RULESYNC_PERMISSIONS_RELATIVE_FILE_PATH as Sn, resetRunWarningState as St, ChecksProcessor as T, RULESYNC_RULES_RELATIVE_DIR_PATH as Tn, ErrorCodes as Tt, RulesyncSkillFrontmatterSchema as U, pathEscapesRoot as Ut, RulesyncSubagentFrontmatterSchema as V, stripControlCharactersKeepingLineFeeds as Vn, listFilePathsRecursively as Vt, RulesyncRule as W, readFileContent as Wt, getRulesyncSourceCandidates as X, removeTempDirectory as Xt, RulesyncHooks as Y, removeFileStrict as Yt, resolveRulesyncSourceWritePath as Z, resolvePath as Zt, IgnoreProcessor as _, RULESYNC_IGNORE_RELATIVE_FILE_PATH as _n, JsonLogger as _t, getProcessorRegistryEntry as a, ToolTargetSchema as an, SHARED_USER_MANAGED_CONFIG_PATHS as at, CommandsProcessor as b, RULESYNC_MCP_SCHEMA_URL as bn, warnOnConflictingFlags as bt, RulesProcessor as c, MAX_FILE_SIZE as cn, mergeInputRootConfigs as ct, CODEBUDDY_DIR as d, RULESYNC_COMMANDS_RELATIVE_DIR_PATH as dn, ConfigFileSchema as dt, writeFileBuffer as en, RulesyncCommandFrontmatterSchema as et, CODEBUDDY_LOCAL_RULE_FILE_NAME as f, RULESYNC_CONFIG_RELATIVE_FILE_PATH as fn, GITIGNORE_DESTINATION_KEY as ft, McpProcessor as g, RULESYNC_HOOKS_RELATIVE_FILE_PATH as gn, ConsoleLogger as gt, shortenToWidth as h, RULESYNC_CURATED_SKILLS_RELATIVE_DIR_PATH as hn, findControlCharacter as ht, inspectInputRoots as i, PACKAGING_TOOL_TARGETS as in, loadYaml as it, CLAUDECODE_SETTINGS_LOCAL_FILE_NAME as j, parseCommaSeparatedList as jn, createTempDirectory as jt, CLAUDECODE_LOCAL_RULE_FILE_NAME as k, RULESYNC_USER_CONFIG_DIR_NAME as kn, assertWritablePathInsideRoot as kt, SubagentsProcessor as l, RULESYNC_AIIGNORE_RELATIVE_FILE_PATH as ln, resolveEffectiveInputRoots as lt, displayWidthOf as m, RULESYNC_CURATED_RULES_RELATIVE_DIR_PATH as mn, assertTargetsFeaturesExclusive as mt, formatSourceLoadFailure as n, ALL_TOOL_TARGETS as nn, RulesyncCheckFrontmatterSchema as nt, convertFromTool as o, CURATED_RULES_FEATURE_SUBDIR as on, SKILL_FILE_NAME as ot, ELLIPSIS_WIDTH as p, RULESYNC_CONFIG_SCHEMA_URL as pn, SourceEntrySchema as pt, RulesyncMcp as q, removeDirectoryStrict as qt, generate as r, ALL_TOOL_TARGETS_WITH_WILDCARD as rn, stringifyFrontmatter as rt, isPackagingToolTarget as s, FEATURE_SOURCE_TREE_ENTRIES as sn, ConfigResolver as st, importFromTool as t, writeFileContent as tn, RulesyncCheck as tt, SkillsProcessor as u, RULESYNC_CHECKS_RELATIVE_DIR_PATH as un, CONFLICTING_TARGET_PAIRS as ut, HooksProcessor as v, RULESYNC_LOCAL_CONFIG_RELATIVE_FILE_PATH as vn, WarningCollectingLogger as vt, COMMANDCODE_SETTINGS_LOCAL_FILE_NAME as w, RULESYNC_RELATIVE_DIR_PATH as wn, CLIError as wt, QWENCODE_DIR as x, RULESYNC_NPM_SOURCES_LOCK_RELATIVE_FILE_PATH as xn, withFallbackLoggerTarget as xt, CRUSH_LOCAL_RULE_FILE_NAME as y, RULESYNC_MCP_RELATIVE_FILE_PATH as yn, fallbackLogger as yt, getLocalSkillDirNames as z, quoteForLog as zn, isSymlink as zt };
|
|
82618
83147
|
|
|
82619
|
-
//# sourceMappingURL=import-
|
|
83148
|
+
//# sourceMappingURL=import-CGIOcUpR.js.map
|