@mmnto/totem 1.14.8 → 1.14.9

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.
Files changed (62) hide show
  1. package/dist/ast-grep-query.d.ts +22 -2
  2. package/dist/ast-grep-query.d.ts.map +1 -1
  3. package/dist/ast-grep-query.js +34 -5
  4. package/dist/ast-grep-query.js.map +1 -1
  5. package/dist/ast-grep-query.test.js +45 -1
  6. package/dist/ast-grep-query.test.js.map +1 -1
  7. package/dist/compile-lesson.d.ts +24 -1
  8. package/dist/compile-lesson.d.ts.map +1 -1
  9. package/dist/compile-lesson.js +112 -58
  10. package/dist/compile-lesson.js.map +1 -1
  11. package/dist/compile-lesson.test.js +283 -14
  12. package/dist/compile-lesson.test.js.map +1 -1
  13. package/dist/compile-manifest.d.ts +14 -1
  14. package/dist/compile-manifest.d.ts.map +1 -1
  15. package/dist/compile-manifest.js +107 -3
  16. package/dist/compile-manifest.js.map +1 -1
  17. package/dist/compile-manifest.test.js +123 -1
  18. package/dist/compile-manifest.test.js.map +1 -1
  19. package/dist/compile-smoke-gate.d.ts +42 -0
  20. package/dist/compile-smoke-gate.d.ts.map +1 -0
  21. package/dist/compile-smoke-gate.js +135 -0
  22. package/dist/compile-smoke-gate.js.map +1 -0
  23. package/dist/compile-smoke-gate.test.d.ts +2 -0
  24. package/dist/compile-smoke-gate.test.d.ts.map +1 -0
  25. package/dist/compile-smoke-gate.test.js +202 -0
  26. package/dist/compile-smoke-gate.test.js.map +1 -0
  27. package/dist/compiler-schema.d.ts +286 -24
  28. package/dist/compiler-schema.d.ts.map +1 -1
  29. package/dist/compiler-schema.js +128 -5
  30. package/dist/compiler-schema.js.map +1 -1
  31. package/dist/compiler-schema.test.d.ts +2 -0
  32. package/dist/compiler-schema.test.d.ts.map +1 -0
  33. package/dist/compiler-schema.test.js +263 -0
  34. package/dist/compiler-schema.test.js.map +1 -0
  35. package/dist/compiler.d.ts +22 -5
  36. package/dist/compiler.d.ts.map +1 -1
  37. package/dist/compiler.js +9 -3
  38. package/dist/compiler.js.map +1 -1
  39. package/dist/compiler.test.js +17 -2
  40. package/dist/compiler.test.js.map +1 -1
  41. package/dist/index.d.ts +3 -3
  42. package/dist/index.d.ts.map +1 -1
  43. package/dist/index.js +2 -2
  44. package/dist/index.js.map +1 -1
  45. package/dist/ledger.d.ts +1 -1
  46. package/dist/lesson-pattern.d.ts +26 -0
  47. package/dist/lesson-pattern.d.ts.map +1 -1
  48. package/dist/lesson-pattern.js +35 -1
  49. package/dist/lesson-pattern.js.map +1 -1
  50. package/dist/lesson-pattern.test.js +72 -0
  51. package/dist/lesson-pattern.test.js.map +1 -1
  52. package/dist/rule-engine.d.ts.map +1 -1
  53. package/dist/rule-engine.js +25 -7
  54. package/dist/rule-engine.js.map +1 -1
  55. package/dist/rule-engine.test.js +98 -4
  56. package/dist/rule-engine.test.js.map +1 -1
  57. package/dist/rule-tester.d.ts.map +1 -1
  58. package/dist/rule-tester.js +9 -2
  59. package/dist/rule-tester.js.map +1 -1
  60. package/dist/rule-tester.test.js +41 -0
  61. package/dist/rule-tester.test.js.map +1 -1
  62. package/package.json +1 -1
@@ -0,0 +1,202 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { matchAstGrepPattern } from './ast-grep-query.js';
3
+ import { runSmokeGate } from './compile-smoke-gate.js';
4
+ // ─── Helpers ────────────────────────────────────────
5
+ function makeRegexRule(overrides = {}) {
6
+ return {
7
+ lessonHash: 'deadbeef1234',
8
+ lessonHeading: 'No console.log',
9
+ pattern: 'console\\.log',
10
+ message: 'Do not use console.log',
11
+ engine: 'regex',
12
+ compiledAt: '2026-04-13T12:00:00Z',
13
+ ...overrides,
14
+ };
15
+ }
16
+ function makeAstGrepStringRule(overrides = {}) {
17
+ return {
18
+ lessonHash: 'cafeface5678',
19
+ lessonHeading: 'No debugger',
20
+ pattern: '',
21
+ message: 'Do not commit debugger statements',
22
+ engine: 'ast-grep',
23
+ astGrepPattern: 'debugger',
24
+ compiledAt: '2026-04-13T12:00:00Z',
25
+ ...overrides,
26
+ };
27
+ }
28
+ function makeCompoundRule(overrides = {}) {
29
+ return {
30
+ lessonHash: 'beefcafe9abc',
31
+ lessonHeading: 'Empty catch',
32
+ pattern: '',
33
+ message: 'Empty catch swallows errors',
34
+ engine: 'ast-grep',
35
+ astGrepYamlRule: {
36
+ rule: {
37
+ kind: 'catch_clause',
38
+ not: {
39
+ has: {
40
+ kind: 'statement_block',
41
+ has: {
42
+ any: [
43
+ { kind: 'expression_statement' },
44
+ { kind: 'variable_declaration' },
45
+ { kind: 'if_statement' },
46
+ { kind: 'return_statement' },
47
+ { kind: 'throw_statement' },
48
+ ],
49
+ stopBy: 'end',
50
+ },
51
+ },
52
+ },
53
+ },
54
+ },
55
+ compiledAt: '2026-04-13T12:00:00Z',
56
+ ...overrides,
57
+ };
58
+ }
59
+ // ─── runSmokeGate: regex rules ───────────────────────
60
+ describe('runSmokeGate — regex engine', () => {
61
+ it('matches when the badExample contains the pattern', () => {
62
+ const rule = makeRegexRule();
63
+ const result = runSmokeGate(rule, 'console.log("debug")');
64
+ expect(result.matched).toBe(true);
65
+ expect(result.matchCount).toBeGreaterThanOrEqual(1);
66
+ });
67
+ it('does not match when the badExample is clean', () => {
68
+ const rule = makeRegexRule();
69
+ const result = runSmokeGate(rule, 'const x = 1;');
70
+ expect(result.matched).toBe(false);
71
+ expect(result.matchCount).toBe(0);
72
+ });
73
+ it('returns matched false for an empty badExample', () => {
74
+ const rule = makeRegexRule();
75
+ const result = runSmokeGate(rule, '');
76
+ expect(result.matched).toBe(false);
77
+ expect(result.matchCount).toBe(0);
78
+ });
79
+ it('returns matched false when the regex itself is invalid', () => {
80
+ const rule = makeRegexRule({ pattern: '(unclosed' });
81
+ const result = runSmokeGate(rule, 'console.log(1)');
82
+ expect(result.matched).toBe(false);
83
+ expect(result.matchCount).toBe(0);
84
+ expect(result.reason).toContain('invalid');
85
+ });
86
+ });
87
+ // ─── runSmokeGate: flat ast-grep rules ───────────────
88
+ describe('runSmokeGate — ast-grep flat pattern', () => {
89
+ it('matches when the pattern hits the badExample', () => {
90
+ const rule = makeAstGrepStringRule();
91
+ const result = runSmokeGate(rule, 'debugger;\n');
92
+ expect(result.matched).toBe(true);
93
+ expect(result.matchCount).toBeGreaterThanOrEqual(1);
94
+ });
95
+ it('does not match when the pattern misses the badExample', () => {
96
+ const rule = makeAstGrepStringRule();
97
+ const result = runSmokeGate(rule, 'const x = 1;\n');
98
+ expect(result.matched).toBe(false);
99
+ expect(result.matchCount).toBe(0);
100
+ });
101
+ it('returns matched false when the pattern itself throws at runtime', () => {
102
+ // Invalid kind — the ast-grep engine throws. The gate must surface
103
+ // this as a non-match with a reason rather than propagating.
104
+ const rule = makeAstGrepStringRule({ astGrepPattern: undefined });
105
+ const invalid = makeAstGrepStringRule({ astGrepPattern: 'catch ($E) { $$$ }' });
106
+ // Force an invalid string pattern so findAll throws.
107
+ const result = runSmokeGate(invalid, 'try { work() } catch (err) {}');
108
+ // A bare catch string pattern is multi-root and throws; the gate
109
+ // swallows the throw and reports no match with a reason.
110
+ expect(result.matched).toBe(false);
111
+ expect(rule).toBeDefined(); // silence unused
112
+ });
113
+ });
114
+ // ─── runSmokeGate: compound ast-grep rules ───────────
115
+ describe('runSmokeGate — ast-grep compound (astGrepYamlRule)', () => {
116
+ it('matches when the compound rule fires on the badExample', () => {
117
+ const rule = makeCompoundRule();
118
+ const result = runSmokeGate(rule, 'try {\n work();\n} catch (err) {\n}\n');
119
+ expect(result.matched).toBe(true);
120
+ });
121
+ it('does not match when the compound rule misses the badExample', () => {
122
+ const rule = makeCompoundRule();
123
+ const result = runSmokeGate(rule, 'try {\n work();\n} catch (err) {\n log(err);\n}\n');
124
+ expect(result.matched).toBe(false);
125
+ expect(result.matchCount).toBe(0);
126
+ });
127
+ it('returns matched false with a reason when the compound rule throws', () => {
128
+ const rule = makeCompoundRule({
129
+ astGrepYamlRule: { rule: { kind: '!!!INVALID_KIND!!!' } },
130
+ });
131
+ const result = runSmokeGate(rule, 'const x = 1;\n');
132
+ expect(result.matched).toBe(false);
133
+ expect(result.reason).toBeDefined();
134
+ });
135
+ });
136
+ // ─── extension inference (GCA WARN on design review) ─
137
+ describe('runSmokeGate badExample extension inference', () => {
138
+ it('defaults to a TSX parser so JSX-flavored bad examples still parse', () => {
139
+ const rule = makeAstGrepStringRule({
140
+ astGrepPattern: 'console.log($$$)',
141
+ });
142
+ const jsxSnippet = 'const page = <div>{console.log("hi")}</div>;\n';
143
+ const result = runSmokeGate(rule, jsxSnippet);
144
+ expect(result.matched).toBe(true);
145
+ });
146
+ it('honors a concrete extension from the rule fileGlobs when present', () => {
147
+ const rule = makeAstGrepStringRule({
148
+ fileGlobs: ['**/*.ts'],
149
+ astGrepPattern: 'debugger',
150
+ });
151
+ const tsSnippet = 'debugger;\n';
152
+ const result = runSmokeGate(rule, tsSnippet);
153
+ expect(result.matched).toBe(true);
154
+ });
155
+ // Regression for CR finding on PR #1415: multi-extension fileGlobs must
156
+ // try every declared extension, not just the first match. Otherwise
157
+ // a rule scoped to both `.js` and `.jsx` would gate on JavaScript only
158
+ // and false-reject JSX-flavored bad examples, breaking parity with
159
+ // runtime (which picks Lang.Tsx for `.jsx` files).
160
+ it('tries every positive extension in fileGlobs, not just the first match', () => {
161
+ const rule = makeAstGrepStringRule({
162
+ fileGlobs: ['**/*.js', '**/*.jsx'],
163
+ astGrepPattern: 'console.log($$$)',
164
+ });
165
+ // JSX-flavored snippet: would fail under JavaScript parser but matches
166
+ // under Tsx. Runtime would also use Tsx for a real `.jsx` file.
167
+ const jsxSnippet = 'const el = <div>{console.log("hi")}</div>;\n';
168
+ const result = runSmokeGate(rule, jsxSnippet);
169
+ expect(result.matched).toBe(true);
170
+ });
171
+ // Regression for CR finding on PR #1415: an unscoped rule with a TS
172
+ // angle-bracket cast must not be false-rejected by a TSX-only fallback.
173
+ // TS allows `<Foo>bar` as a type cast; TSX rejects it as an ambiguous
174
+ // JSX tag open. The gate tries `.ts` before `.tsx` in the fallback set.
175
+ it('accepts TS angle-bracket cast syntax on unscoped rules (not just TSX)', () => {
176
+ const rule = makeAstGrepStringRule({
177
+ fileGlobs: undefined, // unscoped
178
+ astGrepPattern: '<$TYPE>$EXPR',
179
+ });
180
+ const tsSnippet = 'const x = <Foo>bar;\n';
181
+ const result = runSmokeGate(rule, tsSnippet);
182
+ expect(result.matched).toBe(true);
183
+ });
184
+ });
185
+ // ─── runtime-parity invariant ────────────────────────
186
+ describe('runSmokeGate runtime parity invariant', () => {
187
+ it('uses the same engine entry points as the runtime — gate-pass implies runtime-match', () => {
188
+ // If runSmokeGate reports matched === true with a non-zero matchCount,
189
+ // matchAstGrepPattern (the runtime entry point) invoked on the same
190
+ // snippet must also produce at least one match. The gate is a thin
191
+ // wrapper around that exact function, so this is a structural
192
+ // guarantee - the test locks in the guarantee against drift.
193
+ const rule = makeAstGrepStringRule();
194
+ const snippet = 'debugger;\nconst x = 1;\n';
195
+ const result = runSmokeGate(rule, snippet);
196
+ expect(result.matched).toBe(true);
197
+ // Reuse the same engine entry point to verify runtime parity.
198
+ const matches = matchAstGrepPattern(snippet, '.ts', 'debugger', snippet.split('\n').map((_, i) => i + 1));
199
+ expect(matches.length).toBeGreaterThanOrEqual(1);
200
+ });
201
+ });
202
+ //# sourceMappingURL=compile-smoke-gate.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compile-smoke-gate.test.js","sourceRoot":"","sources":["../src/compile-smoke-gate.test.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,42 @@
1
1
  import { z } from 'zod';
2
- export declare const CompiledRuleSchema: z.ZodObject<{
2
+ /**
3
+ * Schema mirroring `@ast-grep/napi`'s `NapiConfig` interface for compound
4
+ * structural rules. The `rule` key is required at the Zod layer so the
5
+ * parse-time failure is loud and readable; the inner tree shape is handed
6
+ * off to `@ast-grep/napi` at the engine boundary for the authoritative
7
+ * validity check (see `validateAstGrepPattern`). `passthrough()` lets
8
+ * future napi fields (e.g. `constraints`, `transform`) survive a parse
9
+ * without a schema bump.
10
+ *
11
+ * The rule body is a recursive structural tree (combinators like `all`,
12
+ * `any`, `not`, `inside`, `has`, `precedes`, `follows`). Rather than
13
+ * modelling the full recursive schema with `z.lazy()`, we accept any
14
+ * object shape here and lean on napi to reject malformed trees. That
15
+ * keeps the Zod layer cheap and the authoritative check centralized.
16
+ */
17
+ export declare const NapiConfigSchema: z.ZodObject<{
18
+ rule: z.ZodRecord<z.ZodString, z.ZodUnknown>;
19
+ }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
20
+ rule: z.ZodRecord<z.ZodString, z.ZodUnknown>;
21
+ }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
22
+ rule: z.ZodRecord<z.ZodString, z.ZodUnknown>;
23
+ }, z.ZodTypeAny, "passthrough">>;
24
+ export type NapiConfig = z.infer<typeof NapiConfigSchema>;
25
+ /**
26
+ * Named alias of `NapiConfigSchema` for grep-ability. The field on
27
+ * `CompiledRule` is named `astGrepYamlRule` (see ADR-087); the alias
28
+ * lets a reader search for `AstGrepYamlRuleSchema` and land on the
29
+ * right definition without first knowing it's a napi config.
30
+ */
31
+ export declare const AstGrepYamlRuleSchema: z.ZodObject<{
32
+ rule: z.ZodRecord<z.ZodString, z.ZodUnknown>;
33
+ }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
34
+ rule: z.ZodRecord<z.ZodString, z.ZodUnknown>;
35
+ }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
36
+ rule: z.ZodRecord<z.ZodString, z.ZodUnknown>;
37
+ }, z.ZodTypeAny, "passthrough">>;
38
+ export type AstGrepYamlRule = NapiConfig;
39
+ export declare const CompiledRuleSchema: z.ZodEffects<z.ZodObject<{
3
40
  /** SHA-256 hash (first 16 hex chars) of heading + body — detects edits */
4
41
  lessonHash: z.ZodString;
5
42
  /** Human-readable heading from the lesson (for diagnostics) */
@@ -12,8 +49,33 @@ export declare const CompiledRuleSchema: z.ZodObject<{
12
49
  engine: z.ZodEnum<["regex", "ast", "ast-grep"]>;
13
50
  /** Tree-sitter S-expression query (required when engine is 'ast') */
14
51
  astQuery: z.ZodOptional<z.ZodString>;
15
- /** ast-grep pattern — string for simple patterns, object for compound rules (has/inside/not) */
16
- astGrepPattern: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodRecord<z.ZodString, z.ZodUnknown>]>>;
52
+ /**
53
+ * Flat ast-grep pattern source (a single JS/TS expression). Mutually
54
+ * exclusive with `astGrepYamlRule` when `engine === 'ast-grep'`; the
55
+ * superRefine below enforces that.
56
+ */
57
+ astGrepPattern: z.ZodOptional<z.ZodString>;
58
+ /**
59
+ * Compound ast-grep rule (NapiConfig shape). Holds structural trees
60
+ * that cannot be expressed as a single source snippet (all / any /
61
+ * not / inside / has / precedes / follows combinators). Mutually
62
+ * exclusive with `astGrepPattern`; see the superRefine on this
63
+ * schema. Smoke-test wiring lands in mmnto/totem#1408.
64
+ */
65
+ astGrepYamlRule: z.ZodOptional<z.ZodObject<{
66
+ rule: z.ZodRecord<z.ZodString, z.ZodUnknown>;
67
+ }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
68
+ rule: z.ZodRecord<z.ZodString, z.ZodUnknown>;
69
+ }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
70
+ rule: z.ZodRecord<z.ZodString, z.ZodUnknown>;
71
+ }, z.ZodTypeAny, "passthrough">>>;
72
+ /**
73
+ * Optional code snippet the rule is expected to match. Stored from
74
+ * compiler output so the smoke-test runner (wired in
75
+ * mmnto/totem#1408) can re-validate the rule offline. Optional in
76
+ * 1.14.9; flips to required when #1408 turns on the gate.
77
+ */
78
+ badExample: z.ZodOptional<z.ZodString>;
17
79
  /** ISO timestamp of when this rule was compiled */
18
80
  compiledAt: z.ZodString;
19
81
  /** ISO timestamp of when this rule was first created (survives recompilation) */
@@ -42,15 +104,19 @@ export declare const CompiledRuleSchema: z.ZodObject<{
42
104
  */
43
105
  manual: z.ZodOptional<z.ZodBoolean>;
44
106
  }, "strip", z.ZodTypeAny, {
107
+ message: string;
45
108
  lessonHash: string;
46
109
  lessonHeading: string;
47
110
  pattern: string;
48
- message: string;
49
111
  engine: "regex" | "ast" | "ast-grep";
50
112
  compiledAt: string;
51
113
  status?: "active" | "archived" | undefined;
52
114
  astQuery?: string | undefined;
53
- astGrepPattern?: string | Record<string, unknown> | undefined;
115
+ astGrepPattern?: string | undefined;
116
+ astGrepYamlRule?: z.objectOutputType<{
117
+ rule: z.ZodRecord<z.ZodString, z.ZodUnknown>;
118
+ }, z.ZodTypeAny, "passthrough"> | undefined;
119
+ badExample?: string | undefined;
54
120
  createdAt?: string | undefined;
55
121
  fileGlobs?: string[] | undefined;
56
122
  category?: "security" | "architecture" | "style" | "performance" | undefined;
@@ -58,15 +124,59 @@ export declare const CompiledRuleSchema: z.ZodObject<{
58
124
  archivedReason?: string | undefined;
59
125
  manual?: boolean | undefined;
60
126
  }, {
127
+ message: string;
128
+ lessonHash: string;
129
+ lessonHeading: string;
130
+ pattern: string;
131
+ engine: "regex" | "ast" | "ast-grep";
132
+ compiledAt: string;
133
+ status?: "active" | "archived" | undefined;
134
+ astQuery?: string | undefined;
135
+ astGrepPattern?: string | undefined;
136
+ astGrepYamlRule?: z.objectInputType<{
137
+ rule: z.ZodRecord<z.ZodString, z.ZodUnknown>;
138
+ }, z.ZodTypeAny, "passthrough"> | undefined;
139
+ badExample?: string | undefined;
140
+ createdAt?: string | undefined;
141
+ fileGlobs?: string[] | undefined;
142
+ category?: "security" | "architecture" | "style" | "performance" | undefined;
143
+ severity?: "error" | "warning" | undefined;
144
+ archivedReason?: string | undefined;
145
+ manual?: boolean | undefined;
146
+ }>, {
147
+ message: string;
61
148
  lessonHash: string;
62
149
  lessonHeading: string;
63
150
  pattern: string;
151
+ engine: "regex" | "ast" | "ast-grep";
152
+ compiledAt: string;
153
+ status?: "active" | "archived" | undefined;
154
+ astQuery?: string | undefined;
155
+ astGrepPattern?: string | undefined;
156
+ astGrepYamlRule?: z.objectOutputType<{
157
+ rule: z.ZodRecord<z.ZodString, z.ZodUnknown>;
158
+ }, z.ZodTypeAny, "passthrough"> | undefined;
159
+ badExample?: string | undefined;
160
+ createdAt?: string | undefined;
161
+ fileGlobs?: string[] | undefined;
162
+ category?: "security" | "architecture" | "style" | "performance" | undefined;
163
+ severity?: "error" | "warning" | undefined;
164
+ archivedReason?: string | undefined;
165
+ manual?: boolean | undefined;
166
+ }, {
64
167
  message: string;
168
+ lessonHash: string;
169
+ lessonHeading: string;
170
+ pattern: string;
65
171
  engine: "regex" | "ast" | "ast-grep";
66
172
  compiledAt: string;
67
173
  status?: "active" | "archived" | undefined;
68
174
  astQuery?: string | undefined;
69
- astGrepPattern?: string | Record<string, unknown> | undefined;
175
+ astGrepPattern?: string | undefined;
176
+ astGrepYamlRule?: z.objectInputType<{
177
+ rule: z.ZodRecord<z.ZodString, z.ZodUnknown>;
178
+ }, z.ZodTypeAny, "passthrough"> | undefined;
179
+ badExample?: string | undefined;
70
180
  createdAt?: string | undefined;
71
181
  fileGlobs?: string[] | undefined;
72
182
  category?: "security" | "architecture" | "style" | "performance" | undefined;
@@ -100,7 +210,7 @@ export declare const NonCompilableEntrySchema: z.ZodEffects<z.ZodUnion<[z.ZodStr
100
210
  export type NonCompilableEntry = z.infer<typeof NonCompilableEntrySchema>;
101
211
  export declare const CompiledRulesFileSchema: z.ZodObject<{
102
212
  version: z.ZodLiteral<1>;
103
- rules: z.ZodArray<z.ZodObject<{
213
+ rules: z.ZodArray<z.ZodEffects<z.ZodObject<{
104
214
  /** SHA-256 hash (first 16 hex chars) of heading + body — detects edits */
105
215
  lessonHash: z.ZodString;
106
216
  /** Human-readable heading from the lesson (for diagnostics) */
@@ -113,8 +223,33 @@ export declare const CompiledRulesFileSchema: z.ZodObject<{
113
223
  engine: z.ZodEnum<["regex", "ast", "ast-grep"]>;
114
224
  /** Tree-sitter S-expression query (required when engine is 'ast') */
115
225
  astQuery: z.ZodOptional<z.ZodString>;
116
- /** ast-grep pattern — string for simple patterns, object for compound rules (has/inside/not) */
117
- astGrepPattern: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodRecord<z.ZodString, z.ZodUnknown>]>>;
226
+ /**
227
+ * Flat ast-grep pattern source (a single JS/TS expression). Mutually
228
+ * exclusive with `astGrepYamlRule` when `engine === 'ast-grep'`; the
229
+ * superRefine below enforces that.
230
+ */
231
+ astGrepPattern: z.ZodOptional<z.ZodString>;
232
+ /**
233
+ * Compound ast-grep rule (NapiConfig shape). Holds structural trees
234
+ * that cannot be expressed as a single source snippet (all / any /
235
+ * not / inside / has / precedes / follows combinators). Mutually
236
+ * exclusive with `astGrepPattern`; see the superRefine on this
237
+ * schema. Smoke-test wiring lands in mmnto/totem#1408.
238
+ */
239
+ astGrepYamlRule: z.ZodOptional<z.ZodObject<{
240
+ rule: z.ZodRecord<z.ZodString, z.ZodUnknown>;
241
+ }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
242
+ rule: z.ZodRecord<z.ZodString, z.ZodUnknown>;
243
+ }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
244
+ rule: z.ZodRecord<z.ZodString, z.ZodUnknown>;
245
+ }, z.ZodTypeAny, "passthrough">>>;
246
+ /**
247
+ * Optional code snippet the rule is expected to match. Stored from
248
+ * compiler output so the smoke-test runner (wired in
249
+ * mmnto/totem#1408) can re-validate the rule offline. Optional in
250
+ * 1.14.9; flips to required when #1408 turns on the gate.
251
+ */
252
+ badExample: z.ZodOptional<z.ZodString>;
118
253
  /** ISO timestamp of when this rule was compiled */
119
254
  compiledAt: z.ZodString;
120
255
  /** ISO timestamp of when this rule was first created (survives recompilation) */
@@ -143,15 +278,19 @@ export declare const CompiledRulesFileSchema: z.ZodObject<{
143
278
  */
144
279
  manual: z.ZodOptional<z.ZodBoolean>;
145
280
  }, "strip", z.ZodTypeAny, {
281
+ message: string;
146
282
  lessonHash: string;
147
283
  lessonHeading: string;
148
284
  pattern: string;
149
- message: string;
150
285
  engine: "regex" | "ast" | "ast-grep";
151
286
  compiledAt: string;
152
287
  status?: "active" | "archived" | undefined;
153
288
  astQuery?: string | undefined;
154
- astGrepPattern?: string | Record<string, unknown> | undefined;
289
+ astGrepPattern?: string | undefined;
290
+ astGrepYamlRule?: z.objectOutputType<{
291
+ rule: z.ZodRecord<z.ZodString, z.ZodUnknown>;
292
+ }, z.ZodTypeAny, "passthrough"> | undefined;
293
+ badExample?: string | undefined;
155
294
  createdAt?: string | undefined;
156
295
  fileGlobs?: string[] | undefined;
157
296
  category?: "security" | "architecture" | "style" | "performance" | undefined;
@@ -159,15 +298,59 @@ export declare const CompiledRulesFileSchema: z.ZodObject<{
159
298
  archivedReason?: string | undefined;
160
299
  manual?: boolean | undefined;
161
300
  }, {
301
+ message: string;
162
302
  lessonHash: string;
163
303
  lessonHeading: string;
164
304
  pattern: string;
305
+ engine: "regex" | "ast" | "ast-grep";
306
+ compiledAt: string;
307
+ status?: "active" | "archived" | undefined;
308
+ astQuery?: string | undefined;
309
+ astGrepPattern?: string | undefined;
310
+ astGrepYamlRule?: z.objectInputType<{
311
+ rule: z.ZodRecord<z.ZodString, z.ZodUnknown>;
312
+ }, z.ZodTypeAny, "passthrough"> | undefined;
313
+ badExample?: string | undefined;
314
+ createdAt?: string | undefined;
315
+ fileGlobs?: string[] | undefined;
316
+ category?: "security" | "architecture" | "style" | "performance" | undefined;
317
+ severity?: "error" | "warning" | undefined;
318
+ archivedReason?: string | undefined;
319
+ manual?: boolean | undefined;
320
+ }>, {
165
321
  message: string;
322
+ lessonHash: string;
323
+ lessonHeading: string;
324
+ pattern: string;
166
325
  engine: "regex" | "ast" | "ast-grep";
167
326
  compiledAt: string;
168
327
  status?: "active" | "archived" | undefined;
169
328
  astQuery?: string | undefined;
170
- astGrepPattern?: string | Record<string, unknown> | undefined;
329
+ astGrepPattern?: string | undefined;
330
+ astGrepYamlRule?: z.objectOutputType<{
331
+ rule: z.ZodRecord<z.ZodString, z.ZodUnknown>;
332
+ }, z.ZodTypeAny, "passthrough"> | undefined;
333
+ badExample?: string | undefined;
334
+ createdAt?: string | undefined;
335
+ fileGlobs?: string[] | undefined;
336
+ category?: "security" | "architecture" | "style" | "performance" | undefined;
337
+ severity?: "error" | "warning" | undefined;
338
+ archivedReason?: string | undefined;
339
+ manual?: boolean | undefined;
340
+ }, {
341
+ message: string;
342
+ lessonHash: string;
343
+ lessonHeading: string;
344
+ pattern: string;
345
+ engine: "regex" | "ast" | "ast-grep";
346
+ compiledAt: string;
347
+ status?: "active" | "archived" | undefined;
348
+ astQuery?: string | undefined;
349
+ astGrepPattern?: string | undefined;
350
+ astGrepYamlRule?: z.objectInputType<{
351
+ rule: z.ZodRecord<z.ZodString, z.ZodUnknown>;
352
+ }, z.ZodTypeAny, "passthrough"> | undefined;
353
+ badExample?: string | undefined;
171
354
  createdAt?: string | undefined;
172
355
  fileGlobs?: string[] | undefined;
173
356
  category?: "security" | "architecture" | "style" | "performance" | undefined;
@@ -199,15 +382,19 @@ export declare const CompiledRulesFileSchema: z.ZodObject<{
199
382
  }, "strip", z.ZodTypeAny, {
200
383
  version: 1;
201
384
  rules: {
385
+ message: string;
202
386
  lessonHash: string;
203
387
  lessonHeading: string;
204
388
  pattern: string;
205
- message: string;
206
389
  engine: "regex" | "ast" | "ast-grep";
207
390
  compiledAt: string;
208
391
  status?: "active" | "archived" | undefined;
209
392
  astQuery?: string | undefined;
210
- astGrepPattern?: string | Record<string, unknown> | undefined;
393
+ astGrepPattern?: string | undefined;
394
+ astGrepYamlRule?: z.objectOutputType<{
395
+ rule: z.ZodRecord<z.ZodString, z.ZodUnknown>;
396
+ }, z.ZodTypeAny, "passthrough"> | undefined;
397
+ badExample?: string | undefined;
211
398
  createdAt?: string | undefined;
212
399
  fileGlobs?: string[] | undefined;
213
400
  category?: "security" | "architecture" | "style" | "performance" | undefined;
@@ -222,15 +409,19 @@ export declare const CompiledRulesFileSchema: z.ZodObject<{
222
409
  }, {
223
410
  version: 1;
224
411
  rules: {
412
+ message: string;
225
413
  lessonHash: string;
226
414
  lessonHeading: string;
227
415
  pattern: string;
228
- message: string;
229
416
  engine: "regex" | "ast" | "ast-grep";
230
417
  compiledAt: string;
231
418
  status?: "active" | "archived" | undefined;
232
419
  astQuery?: string | undefined;
233
- astGrepPattern?: string | Record<string, unknown> | undefined;
420
+ astGrepPattern?: string | undefined;
421
+ astGrepYamlRule?: z.objectInputType<{
422
+ rule: z.ZodRecord<z.ZodString, z.ZodUnknown>;
423
+ }, z.ZodTypeAny, "passthrough"> | undefined;
424
+ badExample?: string | undefined;
234
425
  createdAt?: string | undefined;
235
426
  fileGlobs?: string[] | undefined;
236
427
  category?: "security" | "architecture" | "style" | "performance" | undefined;
@@ -244,35 +435,90 @@ export declare const CompiledRulesFileSchema: z.ZodObject<{
244
435
  })[] | undefined;
245
436
  }>;
246
437
  export type CompiledRulesFile = z.infer<typeof CompiledRulesFileSchema>;
247
- /** Schema for the structured JSON the LLM returns when compiling a lesson. */
248
- export declare const CompilerOutputSchema: z.ZodObject<{
438
+ export declare const CompilerOutputSchema: z.ZodEffects<z.ZodObject<{
249
439
  compilable: z.ZodBoolean;
250
440
  pattern: z.ZodOptional<z.ZodString>;
251
441
  message: z.ZodOptional<z.ZodString>;
252
442
  fileGlobs: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
253
443
  engine: z.ZodOptional<z.ZodEnum<["regex", "ast", "ast-grep"]>>;
254
444
  astQuery: z.ZodOptional<z.ZodString>;
255
- astGrepPattern: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodRecord<z.ZodString, z.ZodUnknown>]>>;
445
+ /** Flat ast-grep pattern source. Mutually exclusive with `astGrepYamlRule`. */
446
+ astGrepPattern: z.ZodOptional<z.ZodString>;
447
+ /** Compound ast-grep rule (NapiConfig). Mutually exclusive with `astGrepPattern`. */
448
+ astGrepYamlRule: z.ZodOptional<z.ZodObject<{
449
+ rule: z.ZodRecord<z.ZodString, z.ZodUnknown>;
450
+ }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
451
+ rule: z.ZodRecord<z.ZodString, z.ZodUnknown>;
452
+ }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
453
+ rule: z.ZodRecord<z.ZodString, z.ZodUnknown>;
454
+ }, z.ZodTypeAny, "passthrough">>>;
455
+ /**
456
+ * Code snippet the rule is expected to match. Flipped from optional to
457
+ * engine-conditional required in mmnto-ai/totem#1409 - regex and
458
+ * ast-grep rules must carry a non-empty snippet so the compile-time
459
+ * smoke gate (#1408) can execute the rule against known-bad code
460
+ * before it lands in compiled-rules.json. The Zod field stays
461
+ * optional here; the `refineBadExampleRequired` superRefine below
462
+ * enforces the engine-conditional requirement so the error message
463
+ * can name the engine and cite the ticket.
464
+ */
465
+ badExample: z.ZodOptional<z.ZodString>;
256
466
  severity: z.ZodOptional<z.ZodEnum<["error", "warning"]>>;
257
467
  /** LLM explanation for why a lesson was marked non-compilable */
258
468
  reason: z.ZodOptional<z.ZodString>;
259
469
  }, "strip", z.ZodTypeAny, {
260
470
  compilable: boolean;
261
- pattern?: string | undefined;
262
471
  message?: string | undefined;
472
+ pattern?: string | undefined;
263
473
  engine?: "regex" | "ast" | "ast-grep" | undefined;
264
474
  astQuery?: string | undefined;
265
- astGrepPattern?: string | Record<string, unknown> | undefined;
475
+ astGrepPattern?: string | undefined;
476
+ astGrepYamlRule?: z.objectOutputType<{
477
+ rule: z.ZodRecord<z.ZodString, z.ZodUnknown>;
478
+ }, z.ZodTypeAny, "passthrough"> | undefined;
479
+ badExample?: string | undefined;
266
480
  fileGlobs?: string[] | undefined;
267
481
  severity?: "error" | "warning" | undefined;
268
482
  reason?: string | undefined;
269
483
  }, {
270
484
  compilable: boolean;
485
+ message?: string | undefined;
486
+ pattern?: string | undefined;
487
+ engine?: "regex" | "ast" | "ast-grep" | undefined;
488
+ astQuery?: string | undefined;
489
+ astGrepPattern?: string | undefined;
490
+ astGrepYamlRule?: z.objectInputType<{
491
+ rule: z.ZodRecord<z.ZodString, z.ZodUnknown>;
492
+ }, z.ZodTypeAny, "passthrough"> | undefined;
493
+ badExample?: string | undefined;
494
+ fileGlobs?: string[] | undefined;
495
+ severity?: "error" | "warning" | undefined;
496
+ reason?: string | undefined;
497
+ }>, {
498
+ compilable: boolean;
499
+ message?: string | undefined;
271
500
  pattern?: string | undefined;
501
+ engine?: "regex" | "ast" | "ast-grep" | undefined;
502
+ astQuery?: string | undefined;
503
+ astGrepPattern?: string | undefined;
504
+ astGrepYamlRule?: z.objectOutputType<{
505
+ rule: z.ZodRecord<z.ZodString, z.ZodUnknown>;
506
+ }, z.ZodTypeAny, "passthrough"> | undefined;
507
+ badExample?: string | undefined;
508
+ fileGlobs?: string[] | undefined;
509
+ severity?: "error" | "warning" | undefined;
510
+ reason?: string | undefined;
511
+ }, {
512
+ compilable: boolean;
272
513
  message?: string | undefined;
514
+ pattern?: string | undefined;
273
515
  engine?: "regex" | "ast" | "ast-grep" | undefined;
274
516
  astQuery?: string | undefined;
275
- astGrepPattern?: string | Record<string, unknown> | undefined;
517
+ astGrepPattern?: string | undefined;
518
+ astGrepYamlRule?: z.objectInputType<{
519
+ rule: z.ZodRecord<z.ZodString, z.ZodUnknown>;
520
+ }, z.ZodTypeAny, "passthrough"> | undefined;
521
+ badExample?: string | undefined;
276
522
  fileGlobs?: string[] | undefined;
277
523
  severity?: "error" | "warning" | undefined;
278
524
  reason?: string | undefined;
@@ -310,7 +556,23 @@ export interface RuleEventContext {
310
556
  justification?: string;
311
557
  /** AST context where the rule fired (code, string, comment, regex). */
312
558
  astContext?: AstContext;
559
+ /**
560
+ * Populated on `'failure'` events only. Holds the error message surfaced by
561
+ * the runtime engine (ast-grep `findAll`, regex `exec`, etc.) so `totem
562
+ * doctor` telemetry can aggregate rules that fail at execution time. Not
563
+ * used by `'trigger'` or `'suppress'` events. Kept as a string rather than
564
+ * the raw `unknown` so the callback interface stays cheap to consume.
565
+ */
566
+ failureReason?: string;
313
567
  }
314
- /** Callback for observability — invoked when a rule is suppressed or triggered. */
315
- export type RuleEventCallback = (event: 'trigger' | 'suppress', lessonHash: string, context?: RuleEventContext) => void;
568
+ /**
569
+ * Callback for observability - invoked when a rule is suppressed, triggered,
570
+ * or fails at runtime. The `'failure'` variant was added in mmnto/totem#1408
571
+ * alongside per-rule try/catch in `executeQuery`. It is intentionally distinct
572
+ * from `'suppress'`: suppression is a user-initiated directive (totem-ignore /
573
+ * totem-context), while failure is a runtime engine error on a rule that
574
+ * otherwise compiled. The #1412 postmerge GCA fix established this boundary,
575
+ * so the two values must NEVER be conflated in the Trap Ledger.
576
+ */
577
+ export type RuleEventCallback = (event: 'trigger' | 'suppress' | 'failure', lessonHash: string, context?: RuleEventContext) => void;
316
578
  //# sourceMappingURL=compiler-schema.d.ts.map