feat(coding-agent): added builtin default rules and disable controls

- Added 14 bundled TTSR rules (TypeScript and Rust conventions) embedded into the binary via the lowest-priority `builtin-defaults` provider.
- Extracted rule bucketing into `bucketRules` with support for `disabledRules` and `builtinRules` settings.
- Added `ttsr.builtinRules` and `ttsr.disabledRules` settings to control which rules are active per session.
This commit is contained in:
can1357
2026-05-31 02:09:55 +02:00
parent 06dc3976f0
commit caeaf4e4d2
26 changed files with 987 additions and 16 deletions
@@ -0,0 +1,64 @@
/**
* Rule bucketing
*
* Single funnel that every discovered rule passes through on its way into a
* session. It applies the user's disable levers, registers TTSR rules with the
* manager, and splits the rest into the always-apply and rulebook buckets.
*
* Bucket precedence (matches docs/rulebook-matching-pipeline.md §5):
* 1. TTSR — non-empty `condition` that `TtsrManager.addRule` accepts
* 2. always — `alwaysApply === true`
* 3. rulebook — has a `description`
*/
import type { TtsrManager } from "../export/ttsr";
import { BUILTIN_DEFAULTS_PROVIDER_ID, type Rule } from "./rule";
export interface RuleBuckets {
rulebookRules: Rule[];
alwaysApplyRules: Rule[];
}
export interface BucketRulesOptions {
/** Rule names to drop entirely (bundled defaults and user rules alike). */
disabledRules?: readonly string[];
/** When false, drop every rule from the bundled `builtin-defaults` provider. */
builtinRules?: boolean;
}
/**
* Filter and bucket rules, registering TTSR rules on `ttsrManager` as a side
* effect. Disabled rules are dropped before any bucket assignment, so a
* disabled rule is neither matched as TTSR nor surfaced via `rule://`.
*/
export function bucketRules(
rules: readonly Rule[],
ttsrManager: TtsrManager,
options: BucketRulesOptions = {},
): RuleBuckets {
const includeBuiltin = options.builtinRules !== false;
const disabled = new Set<string>();
for (const raw of options.disabledRules ?? []) {
const name = raw.trim();
if (name.length > 0) disabled.add(name);
}
const rulebookRules: Rule[] = [];
const alwaysApplyRules: Rule[] = [];
for (const rule of rules) {
if (disabled.has(rule.name)) continue;
if (!includeBuiltin && rule._source?.provider === BUILTIN_DEFAULTS_PROVIDER_ID) continue;
const isTtsrRule = rule.condition && rule.condition.length > 0 ? ttsrManager.addRule(rule) : false;
if (isTtsrRule) continue;
if (rule.alwaysApply === true) {
alwaysApplyRules.push(rule);
continue;
}
if (rule.description) {
rulebookRules.push(rule);
}
}
return { rulebookRules, alwaysApplyRules };
}
@@ -9,6 +9,14 @@ import type { SourceMeta } from "./types";
const CONDITION_GLOB_SCOPE_TOOLS = ["edit", "write"] as const;
/**
* Provider id for the bundled default rules shipped with the agent.
* Lowest priority, so any user/project/tool rule of the same name overrides
* a bundled default. Also used to gate the whole bundled set via
* `ttsr.builtinRules`.
*/
export const BUILTIN_DEFAULTS_PROVIDER_ID = "builtin-defaults";
/**
* Parsed frontmatter from rule files.
*/