rulix 0.1.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.
@@ -0,0 +1,298 @@
1
+ /**
2
+ * Intermediate Representation (IR) types for Rulix.
3
+ *
4
+ * All logic operates on these types, never on raw tool-specific formats.
5
+ * This module defines the core contract between the engine and adapters.
6
+ */
7
+ type RuleScope = "always" | "file-scoped" | "agent-selected";
8
+ type RuleCategory = "style" | "security" | "testing" | "architecture" | "workflow" | "general";
9
+ type ValidationSeverity = "error" | "warning" | "info";
10
+ type ExportStrategy = "overwrite" | "merge";
11
+ type TokenEstimation = "heuristic" | "tiktoken";
12
+ type ClaudeMdStrategy = "concatenate" | "reference";
13
+ /**
14
+ * Use for operations that can fail in predictable ways (parsing, validation).
15
+ * Reserve exceptions for unexpected errors (filesystem, permissions).
16
+ */
17
+ type Result<T, E = RulixError> = {
18
+ readonly ok: true;
19
+ readonly value: T;
20
+ } | {
21
+ readonly ok: false;
22
+ readonly error: E;
23
+ };
24
+ /**
25
+ * Every error carries a machine-readable `code` so callers can handle
26
+ * specific failure modes programmatically without parsing message strings.
27
+ */
28
+ declare class RulixError extends Error {
29
+ readonly code: string;
30
+ readonly cause?: unknown | undefined;
31
+ readonly name = "RulixError";
32
+ constructor(code: string, message: string, cause?: unknown | undefined);
33
+ }
34
+ /**
35
+ * Tracks where a rule was imported from so users can trace back
36
+ * to the original source file when debugging conflicts.
37
+ */
38
+ interface RuleSource {
39
+ /** E.g. `"cursor"`, `"claude-code"`, `"rulix"`. */
40
+ readonly adapter: string;
41
+ /** Relative to the project root. */
42
+ readonly filePath: string;
43
+ /** ISO 8601 timestamp. */
44
+ readonly importedAt: string;
45
+ }
46
+ /**
47
+ * The fundamental unit of the Rulix IR. All adapters convert
48
+ * their tool-specific formats to and from this representation.
49
+ */
50
+ interface Rule {
51
+ /** Kebab-case. Used for deduplication and preset composition. */
52
+ readonly id: string;
53
+ readonly scope: RuleScope;
54
+ /** Used by agent-selected rules to let the AI decide relevance. */
55
+ readonly description: string;
56
+ readonly content: string;
57
+ /** Required when `scope` is `"file-scoped"`. */
58
+ readonly globs?: string[];
59
+ readonly category: RuleCategory;
60
+ /** 1 (critical) to 5 (nice-to-have). Drives token budget optimization. */
61
+ readonly priority: number;
62
+ /** E.g. `"@rulix/typescript/strict"`. */
63
+ readonly extends?: string;
64
+ /** Auto-computed by the tokenizer. */
65
+ readonly estimatedTokens: number;
66
+ readonly source?: RuleSource;
67
+ }
68
+ interface RulixConfigOptions {
69
+ readonly tokenEstimation: TokenEstimation;
70
+ /** Controls the "Generated by Rulix" header in AGENTS.md output. */
71
+ readonly agentsMdHeader: boolean;
72
+ readonly claudeMdStrategy: ClaudeMdStrategy;
73
+ /** Used by the `watch` command. */
74
+ readonly syncOnSave: boolean;
75
+ }
76
+ /**
77
+ * Fully-resolved project configuration with all defaults applied.
78
+ */
79
+ interface RulixConfig {
80
+ /** Adapter names, e.g. `["cursor", "claude-code", "agents-md"]`. */
81
+ readonly targets: string[];
82
+ /** npm packages or local paths to preset rule collections. */
83
+ readonly presets: string[];
84
+ /** Keyed by rule ID. */
85
+ readonly overrides: Record<string, Partial<Rule>>;
86
+ readonly options: RulixConfigOptions;
87
+ }
88
+ interface Ruleset {
89
+ /** Local + preset rules, after overrides are applied. */
90
+ readonly rules: Rule[];
91
+ readonly config: RulixConfig;
92
+ }
93
+ /**
94
+ * Each adapter provides its own budget based on the tool's known limits
95
+ * (e.g. Claude Code ~150 instructions, Cursor ~500).
96
+ */
97
+ interface TokenBudget {
98
+ readonly maxTokens: number;
99
+ readonly maxInstructions: number;
100
+ /** Fraction of max (e.g. 0.8 for 80%). */
101
+ readonly warningThreshold: number;
102
+ /** Where the limit comes from (e.g. documentation URL). */
103
+ readonly source: string;
104
+ }
105
+ interface ExportOptions {
106
+ readonly strategy: ExportStrategy;
107
+ /** Preview changes without writing to disk. */
108
+ readonly dryRun?: boolean | undefined;
109
+ }
110
+ interface ImportWarning {
111
+ readonly ruleId?: string | undefined;
112
+ /** Source file that produced the warning. */
113
+ readonly filePath: string;
114
+ readonly message: string;
115
+ }
116
+ interface ExportWarning {
117
+ readonly ruleId?: string | undefined;
118
+ /** Target file that produced the warning. */
119
+ readonly filePath: string;
120
+ readonly message: string;
121
+ }
122
+ interface ImportResult {
123
+ readonly rules: Rule[];
124
+ readonly warnings: ImportWarning[];
125
+ /** E.g. `".cursor/rules/"`. */
126
+ readonly source: string;
127
+ }
128
+ interface ExportResult {
129
+ readonly filesWritten: string[];
130
+ /** Files removed because the corresponding rule was deleted from source. */
131
+ readonly filesDeleted: string[];
132
+ readonly warnings: ExportWarning[];
133
+ }
134
+ /**
135
+ * Contract that every tool-specific adapter must implement.
136
+ *
137
+ * Import reads tool-specific files into `Rule[]`; export writes `Rule[]`
138
+ * back to the tool's native format.
139
+ */
140
+ interface RulixAdapter {
141
+ /** E.g. `"cursor"`, `"claude-code"`. */
142
+ readonly name: string;
143
+ /** E.g. `"Cursor"`, `"Claude Code"`. */
144
+ readonly displayName: string;
145
+ detect(projectRoot: string): Promise<boolean>;
146
+ import(projectRoot: string): Promise<ImportResult>;
147
+ export(rules: Rule[], projectRoot: string, options?: ExportOptions): Promise<ExportResult>;
148
+ getTokenBudget(): TokenBudget;
149
+ }
150
+ /**
151
+ * Codes follow the pattern `V001`–`V999` as defined in PRD section 11.1.
152
+ */
153
+ interface ValidationIssue {
154
+ /** E.g. `"V001"`. */
155
+ readonly code: string;
156
+ readonly severity: ValidationSeverity;
157
+ readonly message: string;
158
+ readonly ruleId?: string | undefined;
159
+ readonly filePath?: string | undefined;
160
+ /** Actionable fix suggestion. */
161
+ readonly suggestion?: string | undefined;
162
+ }
163
+ interface ValidationResult {
164
+ /** `true` when no errors were found (warnings and info are allowed). */
165
+ readonly passed: boolean;
166
+ readonly errors: ValidationIssue[];
167
+ readonly warnings: ValidationIssue[];
168
+ readonly info: ValidationIssue[];
169
+ }
170
+
171
+ /**
172
+ * AGENTS.md adapter: export-only.
173
+ *
174
+ * Import is not supported in v0.1 because AGENTS.md is too
175
+ * unstructured to parse reliably into discrete rules.
176
+ */
177
+
178
+ declare const agentsMdAdapter: RulixAdapter;
179
+
180
+ /**
181
+ * Claude Code adapter: imports from `CLAUDE.md` and `.claude/rules/*.md`,
182
+ * exports IR rules to Claude Code format.
183
+ *
184
+ * Never touches `.claude/skills/`, `.claude/commands/`,
185
+ * `.claude/agents/`, or `.claude/settings.json`.
186
+ */
187
+
188
+ declare const claudeCodeAdapter: RulixAdapter;
189
+
190
+ /**
191
+ * Cursor adapter: imports from `.cursor/rules/*.mdc` and `.cursorrules`,
192
+ * exports IR rules to `.cursor/rules/*.mdc`.
193
+ */
194
+
195
+ declare const cursorAdapter: RulixAdapter;
196
+
197
+ /**
198
+ * Adapter registry: lookup by name and auto-detection.
199
+ */
200
+
201
+ /** Returns all registered adapters. */
202
+ declare function getAdapters(): RulixAdapter[];
203
+ /** Returns an adapter by name, or `undefined` if not found. */
204
+ declare function getAdapter(name: string): RulixAdapter | undefined;
205
+ /** Returns all adapter names. */
206
+ declare function getAdapterNames(): string[];
207
+ /** Detects which adapters have existing rules in a project. */
208
+ declare function detectAdapters(projectRoot: string): Promise<RulixAdapter[]>;
209
+
210
+ /**
211
+ * Lightweight token estimation without external dependencies.
212
+ *
213
+ * Uses a character-based heuristic (~4 chars per token) that's accurate
214
+ * enough for budget warnings. Exact counting via tiktoken is planned for v0.2.
215
+ */
216
+ /** Estimates token count using the ~4 chars/token heuristic for English/code. */
217
+ declare function estimateTokens(text: string): number;
218
+ /**
219
+ * Builds the full text that a rule contributes to a tool's context window:
220
+ * frontmatter metadata + markdown content.
221
+ */
222
+ declare function estimateRuleTokens(content: string, description: string): number;
223
+ /** Sums estimated tokens across multiple content strings. */
224
+ declare function sumTokens(tokenCounts: number[]): number;
225
+ interface TokenBudgetUsage {
226
+ readonly used: number;
227
+ readonly max: number;
228
+ readonly percentage: number;
229
+ readonly exceeded: boolean;
230
+ }
231
+ /** Computes usage against a budget, returning percentage and exceeded flag. */
232
+ declare function computeBudgetUsage(used: number, max: number): TokenBudgetUsage;
233
+
234
+ /**
235
+ * High-level convenience API for programmatic usage.
236
+ *
237
+ * These functions compose lower-level core and adapter APIs into
238
+ * ergonomic one-call operations. They throw RulixError on failure
239
+ * instead of returning Result, for simpler consumer code.
240
+ */
241
+
242
+ /** Loads the full ruleset (config + rules) from a project directory. */
243
+ declare function loadRuleset(projectRoot: string): Promise<Ruleset>;
244
+ /** Imports rules from a specific tool adapter into canonical IR. */
245
+ declare function importRules(adapterName: string, projectRoot: string): Promise<ImportResult>;
246
+ /** Exports canonical rules to a specific tool's format. */
247
+ declare function exportRules(adapterName: string, rules: Rule[], projectRoot: string, options?: ExportOptions): Promise<ExportResult>;
248
+ /** Validates rules for structural issues. */
249
+ declare function validateRuleset(ruleset: Ruleset): ValidationResult;
250
+ /** Returns token budget usage for a specific adapter. */
251
+ declare function getTokenBudget(adapterName: string, rules: Rule[]): TokenBudgetUsage;
252
+
253
+ /**
254
+ * Schema, defaults, and loader for `.rulix/config.json`.
255
+ *
256
+ * Pure validation lives in `resolveConfig`; filesystem I/O lives in `loadConfig`.
257
+ */
258
+
259
+ declare const RULIX_DIR = ".rulix";
260
+ declare const CONFIG_FILENAME = "config.json";
261
+ declare const RULES_DIR = "rules";
262
+ declare function configPath(projectRoot: string): string;
263
+ declare function rulesPath(projectRoot: string): string;
264
+ declare function createDefaultConfig(): RulixConfig;
265
+ /** Validates raw JSON and merges with defaults to produce a fully-resolved config. */
266
+ declare function resolveConfig(raw: unknown): Result<RulixConfig>;
267
+ /** Reads `.rulix/config.json` from disk. Returns defaults if file is missing. */
268
+ declare function loadConfig(projectRoot: string): Promise<Result<RulixConfig>>;
269
+
270
+ /**
271
+ * Hand-rolled frontmatter parser for `.rulix/rules/*.md`.
272
+ *
273
+ * Supports the subset of YAML needed by Rulix frontmatter:
274
+ * simple key-value pairs, quoted strings, numbers, and arrays
275
+ * (both inline `[a, b]` and multi-line `- a`).
276
+ */
277
+
278
+ /** Parses a markdown file with YAML frontmatter into a Rule. */
279
+ declare function parseRule(raw: string, filePath: string): Result<Rule>;
280
+ /** Serializes a Rule back to markdown with YAML frontmatter. */
281
+ declare function serializeRule(rule: Rule): string;
282
+ /** Reads and parses all `.md` rule files from `.rulix/rules/`. */
283
+ declare function loadRules(projectRoot: string): Promise<Result<Rule[]>>;
284
+ /** Writes a single rule to `.rulix/rules/{id}.md`. Creates the directory if needed. */
285
+ declare function writeRule(projectRoot: string, rule: Rule): Promise<void>;
286
+
287
+ /**
288
+ * Validation engine for Rulix rules (V001–V010).
289
+ *
290
+ * Each check is a pure function that inspects rules structurally.
291
+ * V006 (token budgets) and V008 (agent-selected support) are deferred
292
+ * to the adapter layer where tool-specific limits are known.
293
+ */
294
+
295
+ /** Validates rules for structural issues (V001–V005, V007, V009, V010). */
296
+ declare function validateRules(rules: Rule[]): ValidationResult;
297
+
298
+ export { CONFIG_FILENAME, type ClaudeMdStrategy, type ExportOptions, type ExportResult, type ExportStrategy, type ExportWarning, type ImportResult, type ImportWarning, RULES_DIR, RULIX_DIR, type Result, type Rule, type RuleCategory, type RuleScope, type RuleSource, type Ruleset, type RulixAdapter, type RulixConfig, type RulixConfigOptions, RulixError, type TokenBudget, type TokenBudgetUsage, type TokenEstimation, type ValidationIssue, type ValidationResult, type ValidationSeverity, agentsMdAdapter, claudeCodeAdapter, computeBudgetUsage, configPath, createDefaultConfig, cursorAdapter, detectAdapters, estimateRuleTokens, estimateTokens, exportRules, getAdapter, getAdapterNames, getAdapters, getTokenBudget, importRules, loadConfig, loadRules, loadRuleset, parseRule, resolveConfig, rulesPath, serializeRule, sumTokens, validateRules, validateRuleset, writeRule };
@@ -0,0 +1,298 @@
1
+ /**
2
+ * Intermediate Representation (IR) types for Rulix.
3
+ *
4
+ * All logic operates on these types, never on raw tool-specific formats.
5
+ * This module defines the core contract between the engine and adapters.
6
+ */
7
+ type RuleScope = "always" | "file-scoped" | "agent-selected";
8
+ type RuleCategory = "style" | "security" | "testing" | "architecture" | "workflow" | "general";
9
+ type ValidationSeverity = "error" | "warning" | "info";
10
+ type ExportStrategy = "overwrite" | "merge";
11
+ type TokenEstimation = "heuristic" | "tiktoken";
12
+ type ClaudeMdStrategy = "concatenate" | "reference";
13
+ /**
14
+ * Use for operations that can fail in predictable ways (parsing, validation).
15
+ * Reserve exceptions for unexpected errors (filesystem, permissions).
16
+ */
17
+ type Result<T, E = RulixError> = {
18
+ readonly ok: true;
19
+ readonly value: T;
20
+ } | {
21
+ readonly ok: false;
22
+ readonly error: E;
23
+ };
24
+ /**
25
+ * Every error carries a machine-readable `code` so callers can handle
26
+ * specific failure modes programmatically without parsing message strings.
27
+ */
28
+ declare class RulixError extends Error {
29
+ readonly code: string;
30
+ readonly cause?: unknown | undefined;
31
+ readonly name = "RulixError";
32
+ constructor(code: string, message: string, cause?: unknown | undefined);
33
+ }
34
+ /**
35
+ * Tracks where a rule was imported from so users can trace back
36
+ * to the original source file when debugging conflicts.
37
+ */
38
+ interface RuleSource {
39
+ /** E.g. `"cursor"`, `"claude-code"`, `"rulix"`. */
40
+ readonly adapter: string;
41
+ /** Relative to the project root. */
42
+ readonly filePath: string;
43
+ /** ISO 8601 timestamp. */
44
+ readonly importedAt: string;
45
+ }
46
+ /**
47
+ * The fundamental unit of the Rulix IR. All adapters convert
48
+ * their tool-specific formats to and from this representation.
49
+ */
50
+ interface Rule {
51
+ /** Kebab-case. Used for deduplication and preset composition. */
52
+ readonly id: string;
53
+ readonly scope: RuleScope;
54
+ /** Used by agent-selected rules to let the AI decide relevance. */
55
+ readonly description: string;
56
+ readonly content: string;
57
+ /** Required when `scope` is `"file-scoped"`. */
58
+ readonly globs?: string[];
59
+ readonly category: RuleCategory;
60
+ /** 1 (critical) to 5 (nice-to-have). Drives token budget optimization. */
61
+ readonly priority: number;
62
+ /** E.g. `"@rulix/typescript/strict"`. */
63
+ readonly extends?: string;
64
+ /** Auto-computed by the tokenizer. */
65
+ readonly estimatedTokens: number;
66
+ readonly source?: RuleSource;
67
+ }
68
+ interface RulixConfigOptions {
69
+ readonly tokenEstimation: TokenEstimation;
70
+ /** Controls the "Generated by Rulix" header in AGENTS.md output. */
71
+ readonly agentsMdHeader: boolean;
72
+ readonly claudeMdStrategy: ClaudeMdStrategy;
73
+ /** Used by the `watch` command. */
74
+ readonly syncOnSave: boolean;
75
+ }
76
+ /**
77
+ * Fully-resolved project configuration with all defaults applied.
78
+ */
79
+ interface RulixConfig {
80
+ /** Adapter names, e.g. `["cursor", "claude-code", "agents-md"]`. */
81
+ readonly targets: string[];
82
+ /** npm packages or local paths to preset rule collections. */
83
+ readonly presets: string[];
84
+ /** Keyed by rule ID. */
85
+ readonly overrides: Record<string, Partial<Rule>>;
86
+ readonly options: RulixConfigOptions;
87
+ }
88
+ interface Ruleset {
89
+ /** Local + preset rules, after overrides are applied. */
90
+ readonly rules: Rule[];
91
+ readonly config: RulixConfig;
92
+ }
93
+ /**
94
+ * Each adapter provides its own budget based on the tool's known limits
95
+ * (e.g. Claude Code ~150 instructions, Cursor ~500).
96
+ */
97
+ interface TokenBudget {
98
+ readonly maxTokens: number;
99
+ readonly maxInstructions: number;
100
+ /** Fraction of max (e.g. 0.8 for 80%). */
101
+ readonly warningThreshold: number;
102
+ /** Where the limit comes from (e.g. documentation URL). */
103
+ readonly source: string;
104
+ }
105
+ interface ExportOptions {
106
+ readonly strategy: ExportStrategy;
107
+ /** Preview changes without writing to disk. */
108
+ readonly dryRun?: boolean | undefined;
109
+ }
110
+ interface ImportWarning {
111
+ readonly ruleId?: string | undefined;
112
+ /** Source file that produced the warning. */
113
+ readonly filePath: string;
114
+ readonly message: string;
115
+ }
116
+ interface ExportWarning {
117
+ readonly ruleId?: string | undefined;
118
+ /** Target file that produced the warning. */
119
+ readonly filePath: string;
120
+ readonly message: string;
121
+ }
122
+ interface ImportResult {
123
+ readonly rules: Rule[];
124
+ readonly warnings: ImportWarning[];
125
+ /** E.g. `".cursor/rules/"`. */
126
+ readonly source: string;
127
+ }
128
+ interface ExportResult {
129
+ readonly filesWritten: string[];
130
+ /** Files removed because the corresponding rule was deleted from source. */
131
+ readonly filesDeleted: string[];
132
+ readonly warnings: ExportWarning[];
133
+ }
134
+ /**
135
+ * Contract that every tool-specific adapter must implement.
136
+ *
137
+ * Import reads tool-specific files into `Rule[]`; export writes `Rule[]`
138
+ * back to the tool's native format.
139
+ */
140
+ interface RulixAdapter {
141
+ /** E.g. `"cursor"`, `"claude-code"`. */
142
+ readonly name: string;
143
+ /** E.g. `"Cursor"`, `"Claude Code"`. */
144
+ readonly displayName: string;
145
+ detect(projectRoot: string): Promise<boolean>;
146
+ import(projectRoot: string): Promise<ImportResult>;
147
+ export(rules: Rule[], projectRoot: string, options?: ExportOptions): Promise<ExportResult>;
148
+ getTokenBudget(): TokenBudget;
149
+ }
150
+ /**
151
+ * Codes follow the pattern `V001`–`V999` as defined in PRD section 11.1.
152
+ */
153
+ interface ValidationIssue {
154
+ /** E.g. `"V001"`. */
155
+ readonly code: string;
156
+ readonly severity: ValidationSeverity;
157
+ readonly message: string;
158
+ readonly ruleId?: string | undefined;
159
+ readonly filePath?: string | undefined;
160
+ /** Actionable fix suggestion. */
161
+ readonly suggestion?: string | undefined;
162
+ }
163
+ interface ValidationResult {
164
+ /** `true` when no errors were found (warnings and info are allowed). */
165
+ readonly passed: boolean;
166
+ readonly errors: ValidationIssue[];
167
+ readonly warnings: ValidationIssue[];
168
+ readonly info: ValidationIssue[];
169
+ }
170
+
171
+ /**
172
+ * AGENTS.md adapter: export-only.
173
+ *
174
+ * Import is not supported in v0.1 because AGENTS.md is too
175
+ * unstructured to parse reliably into discrete rules.
176
+ */
177
+
178
+ declare const agentsMdAdapter: RulixAdapter;
179
+
180
+ /**
181
+ * Claude Code adapter: imports from `CLAUDE.md` and `.claude/rules/*.md`,
182
+ * exports IR rules to Claude Code format.
183
+ *
184
+ * Never touches `.claude/skills/`, `.claude/commands/`,
185
+ * `.claude/agents/`, or `.claude/settings.json`.
186
+ */
187
+
188
+ declare const claudeCodeAdapter: RulixAdapter;
189
+
190
+ /**
191
+ * Cursor adapter: imports from `.cursor/rules/*.mdc` and `.cursorrules`,
192
+ * exports IR rules to `.cursor/rules/*.mdc`.
193
+ */
194
+
195
+ declare const cursorAdapter: RulixAdapter;
196
+
197
+ /**
198
+ * Adapter registry: lookup by name and auto-detection.
199
+ */
200
+
201
+ /** Returns all registered adapters. */
202
+ declare function getAdapters(): RulixAdapter[];
203
+ /** Returns an adapter by name, or `undefined` if not found. */
204
+ declare function getAdapter(name: string): RulixAdapter | undefined;
205
+ /** Returns all adapter names. */
206
+ declare function getAdapterNames(): string[];
207
+ /** Detects which adapters have existing rules in a project. */
208
+ declare function detectAdapters(projectRoot: string): Promise<RulixAdapter[]>;
209
+
210
+ /**
211
+ * Lightweight token estimation without external dependencies.
212
+ *
213
+ * Uses a character-based heuristic (~4 chars per token) that's accurate
214
+ * enough for budget warnings. Exact counting via tiktoken is planned for v0.2.
215
+ */
216
+ /** Estimates token count using the ~4 chars/token heuristic for English/code. */
217
+ declare function estimateTokens(text: string): number;
218
+ /**
219
+ * Builds the full text that a rule contributes to a tool's context window:
220
+ * frontmatter metadata + markdown content.
221
+ */
222
+ declare function estimateRuleTokens(content: string, description: string): number;
223
+ /** Sums estimated tokens across multiple content strings. */
224
+ declare function sumTokens(tokenCounts: number[]): number;
225
+ interface TokenBudgetUsage {
226
+ readonly used: number;
227
+ readonly max: number;
228
+ readonly percentage: number;
229
+ readonly exceeded: boolean;
230
+ }
231
+ /** Computes usage against a budget, returning percentage and exceeded flag. */
232
+ declare function computeBudgetUsage(used: number, max: number): TokenBudgetUsage;
233
+
234
+ /**
235
+ * High-level convenience API for programmatic usage.
236
+ *
237
+ * These functions compose lower-level core and adapter APIs into
238
+ * ergonomic one-call operations. They throw RulixError on failure
239
+ * instead of returning Result, for simpler consumer code.
240
+ */
241
+
242
+ /** Loads the full ruleset (config + rules) from a project directory. */
243
+ declare function loadRuleset(projectRoot: string): Promise<Ruleset>;
244
+ /** Imports rules from a specific tool adapter into canonical IR. */
245
+ declare function importRules(adapterName: string, projectRoot: string): Promise<ImportResult>;
246
+ /** Exports canonical rules to a specific tool's format. */
247
+ declare function exportRules(adapterName: string, rules: Rule[], projectRoot: string, options?: ExportOptions): Promise<ExportResult>;
248
+ /** Validates rules for structural issues. */
249
+ declare function validateRuleset(ruleset: Ruleset): ValidationResult;
250
+ /** Returns token budget usage for a specific adapter. */
251
+ declare function getTokenBudget(adapterName: string, rules: Rule[]): TokenBudgetUsage;
252
+
253
+ /**
254
+ * Schema, defaults, and loader for `.rulix/config.json`.
255
+ *
256
+ * Pure validation lives in `resolveConfig`; filesystem I/O lives in `loadConfig`.
257
+ */
258
+
259
+ declare const RULIX_DIR = ".rulix";
260
+ declare const CONFIG_FILENAME = "config.json";
261
+ declare const RULES_DIR = "rules";
262
+ declare function configPath(projectRoot: string): string;
263
+ declare function rulesPath(projectRoot: string): string;
264
+ declare function createDefaultConfig(): RulixConfig;
265
+ /** Validates raw JSON and merges with defaults to produce a fully-resolved config. */
266
+ declare function resolveConfig(raw: unknown): Result<RulixConfig>;
267
+ /** Reads `.rulix/config.json` from disk. Returns defaults if file is missing. */
268
+ declare function loadConfig(projectRoot: string): Promise<Result<RulixConfig>>;
269
+
270
+ /**
271
+ * Hand-rolled frontmatter parser for `.rulix/rules/*.md`.
272
+ *
273
+ * Supports the subset of YAML needed by Rulix frontmatter:
274
+ * simple key-value pairs, quoted strings, numbers, and arrays
275
+ * (both inline `[a, b]` and multi-line `- a`).
276
+ */
277
+
278
+ /** Parses a markdown file with YAML frontmatter into a Rule. */
279
+ declare function parseRule(raw: string, filePath: string): Result<Rule>;
280
+ /** Serializes a Rule back to markdown with YAML frontmatter. */
281
+ declare function serializeRule(rule: Rule): string;
282
+ /** Reads and parses all `.md` rule files from `.rulix/rules/`. */
283
+ declare function loadRules(projectRoot: string): Promise<Result<Rule[]>>;
284
+ /** Writes a single rule to `.rulix/rules/{id}.md`. Creates the directory if needed. */
285
+ declare function writeRule(projectRoot: string, rule: Rule): Promise<void>;
286
+
287
+ /**
288
+ * Validation engine for Rulix rules (V001–V010).
289
+ *
290
+ * Each check is a pure function that inspects rules structurally.
291
+ * V006 (token budgets) and V008 (agent-selected support) are deferred
292
+ * to the adapter layer where tool-specific limits are known.
293
+ */
294
+
295
+ /** Validates rules for structural issues (V001–V005, V007, V009, V010). */
296
+ declare function validateRules(rules: Rule[]): ValidationResult;
297
+
298
+ export { CONFIG_FILENAME, type ClaudeMdStrategy, type ExportOptions, type ExportResult, type ExportStrategy, type ExportWarning, type ImportResult, type ImportWarning, RULES_DIR, RULIX_DIR, type Result, type Rule, type RuleCategory, type RuleScope, type RuleSource, type Ruleset, type RulixAdapter, type RulixConfig, type RulixConfigOptions, RulixError, type TokenBudget, type TokenBudgetUsage, type TokenEstimation, type ValidationIssue, type ValidationResult, type ValidationSeverity, agentsMdAdapter, claudeCodeAdapter, computeBudgetUsage, configPath, createDefaultConfig, cursorAdapter, detectAdapters, estimateRuleTokens, estimateTokens, exportRules, getAdapter, getAdapterNames, getAdapters, getTokenBudget, importRules, loadConfig, loadRules, loadRuleset, parseRule, resolveConfig, rulesPath, serializeRule, sumTokens, validateRules, validateRuleset, writeRule };
package/dist/index.js ADDED
@@ -0,0 +1,91 @@
1
+ import {
2
+ CONFIG_FILENAME,
3
+ RULES_DIR,
4
+ RULIX_DIR,
5
+ RulixError,
6
+ agentsMdAdapter,
7
+ claudeCodeAdapter,
8
+ computeBudgetUsage,
9
+ configPath,
10
+ createDefaultConfig,
11
+ cursorAdapter,
12
+ detectAdapters,
13
+ estimateRuleTokens,
14
+ estimateTokens,
15
+ getAdapter,
16
+ getAdapterNames,
17
+ getAdapters,
18
+ loadConfig,
19
+ loadRules,
20
+ parseRule,
21
+ resolveConfig,
22
+ rulesPath,
23
+ serializeRule,
24
+ sumTokens,
25
+ validateRules,
26
+ writeRule
27
+ } from "./chunk-IX4ZOAKV.js";
28
+
29
+ // src/api.ts
30
+ function requireAdapter(name) {
31
+ const adapter = getAdapter(name);
32
+ if (!adapter) {
33
+ throw new RulixError("UNKNOWN_ADAPTER", `Unknown adapter: "${name}"`);
34
+ }
35
+ return adapter;
36
+ }
37
+ async function loadRuleset(projectRoot) {
38
+ const configResult = await loadConfig(projectRoot);
39
+ if (!configResult.ok) throw configResult.error;
40
+ const rulesResult = await loadRules(projectRoot);
41
+ if (!rulesResult.ok) throw rulesResult.error;
42
+ return { rules: rulesResult.value, config: configResult.value };
43
+ }
44
+ async function importRules(adapterName, projectRoot) {
45
+ return requireAdapter(adapterName).import(projectRoot);
46
+ }
47
+ async function exportRules(adapterName, rules, projectRoot, options) {
48
+ return requireAdapter(adapterName).export(rules, projectRoot, options);
49
+ }
50
+ function validateRuleset(ruleset) {
51
+ return validateRules(ruleset.rules);
52
+ }
53
+ function getTokenBudget(adapterName, rules) {
54
+ const adapter = requireAdapter(adapterName);
55
+ const budget = adapter.getTokenBudget();
56
+ const used = sumTokens(rules.map((r) => r.estimatedTokens));
57
+ return computeBudgetUsage(used, budget.maxTokens);
58
+ }
59
+ export {
60
+ CONFIG_FILENAME,
61
+ RULES_DIR,
62
+ RULIX_DIR,
63
+ RulixError,
64
+ agentsMdAdapter,
65
+ claudeCodeAdapter,
66
+ computeBudgetUsage,
67
+ configPath,
68
+ createDefaultConfig,
69
+ cursorAdapter,
70
+ detectAdapters,
71
+ estimateRuleTokens,
72
+ estimateTokens,
73
+ exportRules,
74
+ getAdapter,
75
+ getAdapterNames,
76
+ getAdapters,
77
+ getTokenBudget,
78
+ importRules,
79
+ loadConfig,
80
+ loadRules,
81
+ loadRuleset,
82
+ parseRule,
83
+ resolveConfig,
84
+ rulesPath,
85
+ serializeRule,
86
+ sumTokens,
87
+ validateRules,
88
+ validateRuleset,
89
+ writeRule
90
+ };
91
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/api.ts"],"sourcesContent":["/**\n * High-level convenience API for programmatic usage.\n *\n * These functions compose lower-level core and adapter APIs into\n * ergonomic one-call operations. They throw RulixError on failure\n * instead of returning Result, for simpler consumer code.\n */\n\nimport { getAdapter } from \"./adapters/registry.js\";\nimport { loadConfig } from \"./core/config.js\";\nimport type {\n\tExportOptions,\n\tExportResult,\n\tImportResult,\n\tRule,\n\tRuleset,\n\tValidationResult,\n} from \"./core/ir.js\";\nimport { RulixError } from \"./core/ir.js\";\nimport { loadRules } from \"./core/parser.js\";\nimport type { TokenBudgetUsage } from \"./core/tokenizer.js\";\nimport { computeBudgetUsage, sumTokens } from \"./core/tokenizer.js\";\nimport { validateRules } from \"./core/validator.js\";\n\nfunction requireAdapter(name: string) {\n\tconst adapter = getAdapter(name);\n\tif (!adapter) {\n\t\tthrow new RulixError(\"UNKNOWN_ADAPTER\", `Unknown adapter: \"${name}\"`);\n\t}\n\treturn adapter;\n}\n\n/** Loads the full ruleset (config + rules) from a project directory. */\nexport async function loadRuleset(projectRoot: string): Promise<Ruleset> {\n\tconst configResult = await loadConfig(projectRoot);\n\tif (!configResult.ok) throw configResult.error;\n\n\tconst rulesResult = await loadRules(projectRoot);\n\tif (!rulesResult.ok) throw rulesResult.error;\n\n\treturn { rules: rulesResult.value, config: configResult.value };\n}\n\n/** Imports rules from a specific tool adapter into canonical IR. */\nexport async function importRules(\n\tadapterName: string,\n\tprojectRoot: string,\n): Promise<ImportResult> {\n\treturn requireAdapter(adapterName).import(projectRoot);\n}\n\n/** Exports canonical rules to a specific tool's format. */\nexport async function exportRules(\n\tadapterName: string,\n\trules: Rule[],\n\tprojectRoot: string,\n\toptions?: ExportOptions,\n): Promise<ExportResult> {\n\treturn requireAdapter(adapterName).export(rules, projectRoot, options);\n}\n\n/** Validates rules for structural issues. */\nexport function validateRuleset(ruleset: Ruleset): ValidationResult {\n\treturn validateRules(ruleset.rules);\n}\n\n/** Returns token budget usage for a specific adapter. */\nexport function getTokenBudget(\n\tadapterName: string,\n\trules: Rule[],\n): TokenBudgetUsage {\n\tconst adapter = requireAdapter(adapterName);\n\tconst budget = adapter.getTokenBudget();\n\tconst used = sumTokens(rules.map((r) => r.estimatedTokens));\n\treturn computeBudgetUsage(used, budget.maxTokens);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwBA,SAAS,eAAe,MAAc;AACrC,QAAM,UAAU,WAAW,IAAI;AAC/B,MAAI,CAAC,SAAS;AACb,UAAM,IAAI,WAAW,mBAAmB,qBAAqB,IAAI,GAAG;AAAA,EACrE;AACA,SAAO;AACR;AAGA,eAAsB,YAAY,aAAuC;AACxE,QAAM,eAAe,MAAM,WAAW,WAAW;AACjD,MAAI,CAAC,aAAa,GAAI,OAAM,aAAa;AAEzC,QAAM,cAAc,MAAM,UAAU,WAAW;AAC/C,MAAI,CAAC,YAAY,GAAI,OAAM,YAAY;AAEvC,SAAO,EAAE,OAAO,YAAY,OAAO,QAAQ,aAAa,MAAM;AAC/D;AAGA,eAAsB,YACrB,aACA,aACwB;AACxB,SAAO,eAAe,WAAW,EAAE,OAAO,WAAW;AACtD;AAGA,eAAsB,YACrB,aACA,OACA,aACA,SACwB;AACxB,SAAO,eAAe,WAAW,EAAE,OAAO,OAAO,aAAa,OAAO;AACtE;AAGO,SAAS,gBAAgB,SAAoC;AACnE,SAAO,cAAc,QAAQ,KAAK;AACnC;AAGO,SAAS,eACf,aACA,OACmB;AACnB,QAAM,UAAU,eAAe,WAAW;AAC1C,QAAM,SAAS,QAAQ,eAAe;AACtC,QAAM,OAAO,UAAU,MAAM,IAAI,CAAC,MAAM,EAAE,eAAe,CAAC;AAC1D,SAAO,mBAAmB,MAAM,OAAO,SAAS;AACjD;","names":[]}