@mmnto/cli 1.35.0 → 1.37.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/dist/commands/config-drift.test.js +40 -24
- package/dist/commands/config-drift.test.js.map +1 -1
- package/dist/commands/doctor.d.ts +14 -0
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +83 -1
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/doctor.test.js +111 -1
- package/dist/commands/doctor.test.js.map +1 -1
- package/dist/commands/hook-run.d.ts +91 -0
- package/dist/commands/hook-run.d.ts.map +1 -0
- package/dist/commands/hook-run.js +149 -0
- package/dist/commands/hook-run.js.map +1 -0
- package/dist/commands/hook-run.test.d.ts +2 -0
- package/dist/commands/hook-run.test.d.ts.map +1 -0
- package/dist/commands/hook-run.test.js +264 -0
- package/dist/commands/hook-run.test.js.map +1 -0
- package/dist/commands/hook-test.d.ts +29 -0
- package/dist/commands/hook-test.d.ts.map +1 -0
- package/dist/commands/hook-test.js +132 -0
- package/dist/commands/hook-test.js.map +1 -0
- package/dist/hook/classification.d.ts +45 -0
- package/dist/hook/classification.d.ts.map +1 -0
- package/dist/hook/classification.js +24 -0
- package/dist/hook/classification.js.map +1 -0
- package/dist/hook/classification.test.d.ts +2 -0
- package/dist/hook/classification.test.d.ts.map +1 -0
- package/dist/hook/classification.test.js +40 -0
- package/dist/hook/classification.test.js.map +1 -0
- package/dist/hook/loader.d.ts +47 -0
- package/dist/hook/loader.d.ts.map +1 -0
- package/dist/hook/loader.js +66 -0
- package/dist/hook/loader.js.map +1 -0
- package/dist/hook/loader.test.d.ts +2 -0
- package/dist/hook/loader.test.d.ts.map +1 -0
- package/dist/hook/loader.test.js +205 -0
- package/dist/hook/loader.test.js.map +1 -0
- package/dist/hook/runtime.d.ts +47 -0
- package/dist/hook/runtime.d.ts.map +1 -0
- package/dist/hook/runtime.js +85 -0
- package/dist/hook/runtime.js.map +1 -0
- package/dist/hook/runtime.test.d.ts +2 -0
- package/dist/hook/runtime.test.d.ts.map +1 -0
- package/dist/hook/runtime.test.js +135 -0
- package/dist/hook/runtime.test.js.map +1 -0
- package/dist/hook/schema.d.ts +385 -0
- package/dist/hook/schema.d.ts.map +1 -0
- package/dist/hook/schema.js +164 -0
- package/dist/hook/schema.js.map +1 -0
- package/dist/hook/schema.test.d.ts +2 -0
- package/dist/hook/schema.test.d.ts.map +1 -0
- package/dist/hook/schema.test.js +233 -0
- package/dist/hook/schema.test.js.map +1 -0
- package/dist/hook/test-runner.d.ts +64 -0
- package/dist/hook/test-runner.d.ts.map +1 -0
- package/dist/hook/test-runner.js +57 -0
- package/dist/hook/test-runner.js.map +1 -0
- package/dist/hook/test-runner.test.d.ts +2 -0
- package/dist/hook/test-runner.test.d.ts.map +1 -0
- package/dist/hook/test-runner.test.js +237 -0
- package/dist/hook/test-runner.test.js.map +1 -0
- package/dist/index.js +57 -4
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { evaluateHook, formatRejection } from './runtime.js';
|
|
3
|
+
function rule(overrides = {}) {
|
|
4
|
+
return {
|
|
5
|
+
id: 'gca-tag-xor-command',
|
|
6
|
+
packId: '@mmnto/pack-bot-gemini-code-assist',
|
|
7
|
+
trigger: { tool: 'bash', pattern: 'gh\\s+(pr|issue)\\s+comment' },
|
|
8
|
+
check: {
|
|
9
|
+
pattern: '(?=.*@gemini-code-assist)(?=.*\\/gemini review)',
|
|
10
|
+
type: 'reject-if-match',
|
|
11
|
+
},
|
|
12
|
+
message: 'GCA tag XOR command — never both; doubling wastes GCA quota.',
|
|
13
|
+
recoveryHint: 'Choose one: @-mention to comment, /gemini review for fresh review.',
|
|
14
|
+
...overrides,
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
describe('evaluateHook', () => {
|
|
18
|
+
describe('trigger gate', () => {
|
|
19
|
+
it('allows when payload.tool does not match rule.trigger.tool', () => {
|
|
20
|
+
const result = evaluateHook(rule(), { tool: 'write', args: 'whatever' });
|
|
21
|
+
expect(result.decision).toBe('allow');
|
|
22
|
+
});
|
|
23
|
+
it('allows when payload.tool matches but trigger.pattern does not', () => {
|
|
24
|
+
// Trigger requires `gh pr comment` or `gh issue comment`; this is `gh pr list`.
|
|
25
|
+
const result = evaluateHook(rule(), { tool: 'bash', args: 'gh pr list' });
|
|
26
|
+
expect(result.decision).toBe('allow');
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
describe('check gate — reject-if-match', () => {
|
|
30
|
+
it('rejects when both trigger and check patterns match', () => {
|
|
31
|
+
const args = 'gh pr comment 123 --body "@gemini-code-assist /gemini review please"';
|
|
32
|
+
const result = evaluateHook(rule(), { tool: 'bash', args });
|
|
33
|
+
expect(result.decision).toBe('reject');
|
|
34
|
+
if (result.decision === 'reject') {
|
|
35
|
+
expect(result.message).toMatch(/GCA tag XOR/);
|
|
36
|
+
expect(result.packId).toBe('@mmnto/pack-bot-gemini-code-assist');
|
|
37
|
+
expect(result.ruleId).toBe('gca-tag-xor-command');
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
it('allows when trigger matches but check does not (only one of the two tags present)', () => {
|
|
41
|
+
// Trigger matches `gh pr comment` but the check requires BOTH the
|
|
42
|
+
// @mention AND the slash command — this comment has only the mention.
|
|
43
|
+
const args = 'gh pr comment 123 --body "@gemini-code-assist take a look"';
|
|
44
|
+
const result = evaluateHook(rule(), { tool: 'bash', args });
|
|
45
|
+
expect(result.decision).toBe('allow');
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
describe('check gate — reject-if-no-match', () => {
|
|
49
|
+
it('rejects when trigger matches but the required check pattern is absent', () => {
|
|
50
|
+
const r = rule({
|
|
51
|
+
id: 'requires-fixes-block',
|
|
52
|
+
check: { pattern: '## Fixes', type: 'reject-if-no-match' },
|
|
53
|
+
trigger: { tool: 'bash', pattern: 'git\\s+commit' },
|
|
54
|
+
message: 'Commit message must include a `## Fixes` section.',
|
|
55
|
+
});
|
|
56
|
+
const result = evaluateHook(r, { tool: 'bash', args: 'git commit -m "wip"' });
|
|
57
|
+
expect(result.decision).toBe('reject');
|
|
58
|
+
});
|
|
59
|
+
it('allows when the required check pattern is present', () => {
|
|
60
|
+
const r = rule({
|
|
61
|
+
check: { pattern: '## Fixes', type: 'reject-if-no-match' },
|
|
62
|
+
trigger: { tool: 'bash', pattern: 'git\\s+commit' },
|
|
63
|
+
});
|
|
64
|
+
const result = evaluateHook(r, {
|
|
65
|
+
tool: 'bash',
|
|
66
|
+
args: 'git commit -m "feat: x\\n\\n## Fixes\\n- y"',
|
|
67
|
+
});
|
|
68
|
+
expect(result.decision).toBe('allow');
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
describe('reject decision payload', () => {
|
|
72
|
+
it('carries packId and ruleId for provenance', () => {
|
|
73
|
+
const args = 'gh pr comment 1 --body "@gemini-code-assist /gemini review"';
|
|
74
|
+
const result = evaluateHook(rule(), { tool: 'bash', args });
|
|
75
|
+
expect(result).toMatchObject({
|
|
76
|
+
decision: 'reject',
|
|
77
|
+
packId: '@mmnto/pack-bot-gemini-code-assist',
|
|
78
|
+
ruleId: 'gca-tag-xor-command',
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
it('preserves recoveryHint when present', () => {
|
|
82
|
+
const args = 'gh pr comment 1 --body "@gemini-code-assist /gemini review"';
|
|
83
|
+
const result = evaluateHook(rule(), { tool: 'bash', args });
|
|
84
|
+
if (result.decision === 'reject') {
|
|
85
|
+
expect(result.recoveryHint).toMatch(/Choose one/);
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
it('returns undefined recoveryHint when the rule omits it', () => {
|
|
89
|
+
const r = rule({ recoveryHint: undefined });
|
|
90
|
+
const args = 'gh pr comment 1 --body "@gemini-code-assist /gemini review"';
|
|
91
|
+
const result = evaluateHook(r, { tool: 'bash', args });
|
|
92
|
+
if (result.decision === 'reject') {
|
|
93
|
+
expect(result.recoveryHint).toBeUndefined();
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
describe('verification_shadow ignored at runtime', () => {
|
|
98
|
+
it('evaluates as Interpretive Rule even when verification_shadow is present', () => {
|
|
99
|
+
// Per ADR-104 § Convergence: hooks fall into Interpretive Rule class
|
|
100
|
+
// in V1. verification_shadow on a hook rule is reserved schema field
|
|
101
|
+
// for future Spine-Rule promotion; the V1 runtime must not change
|
|
102
|
+
// its decision based on its presence or absence.
|
|
103
|
+
const args = 'gh pr comment 1 --body "@gemini-code-assist /gemini review"';
|
|
104
|
+
const withShadow = rule({ verification_shadow: { rego: 'package x' } });
|
|
105
|
+
const withoutShadow = rule();
|
|
106
|
+
expect(evaluateHook(withShadow, { tool: 'bash', args })).toEqual(evaluateHook(withoutShadow, { tool: 'bash', args }));
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
describe('formatRejection', () => {
|
|
111
|
+
it('formats the structured prefix with packId/ruleId when recoveryHint is absent', () => {
|
|
112
|
+
const decision = {
|
|
113
|
+
decision: 'reject',
|
|
114
|
+
packId: '@mmnto/pack-bot-coderabbit',
|
|
115
|
+
ruleId: 'r1',
|
|
116
|
+
message: 'do not commit secrets',
|
|
117
|
+
};
|
|
118
|
+
expect(formatRejection(decision)).toBe('[totem:hook-block] @mmnto/pack-bot-coderabbit/r1: do not commit secrets');
|
|
119
|
+
});
|
|
120
|
+
it('includes the recovery-hint line when present', () => {
|
|
121
|
+
const decision = {
|
|
122
|
+
decision: 'reject',
|
|
123
|
+
packId: '@mmnto/pack-bot-coderabbit',
|
|
124
|
+
ruleId: 'r1',
|
|
125
|
+
message: 'do not commit secrets',
|
|
126
|
+
recoveryHint: 'use git-crypt or vault',
|
|
127
|
+
};
|
|
128
|
+
expect(formatRejection(decision)).toBe('[totem:hook-block] @mmnto/pack-bot-coderabbit/r1: do not commit secrets\n' +
|
|
129
|
+
' → use git-crypt or vault');
|
|
130
|
+
});
|
|
131
|
+
// The previous "throws when given an allow decision" runtime guard is gone —
|
|
132
|
+
// formatRejection's parameter is now narrowed to RejectDecision so the type
|
|
133
|
+
// system prevents the caller bug at compile time. TS-only enforcement.
|
|
134
|
+
});
|
|
135
|
+
//# sourceMappingURL=runtime.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime.test.js","sourceRoot":"","sources":["../../src/hook/runtime.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,385 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
/**
|
|
3
|
+
* Hook rule schemas for the bot-pack wiring engine (ADR-104).
|
|
4
|
+
*
|
|
5
|
+
* Two surfaces:
|
|
6
|
+
* - `HooksYamlSchema` describes a pack's `hooks.yaml` (authoring surface).
|
|
7
|
+
* - `CompiledHooksManifestSchema` describes `.totem/compiled-hooks.json`
|
|
8
|
+
* (runtime surface produced by `totem sync` from installed packs).
|
|
9
|
+
*
|
|
10
|
+
* The compiled manifest carries the staleness metadata required by
|
|
11
|
+
* ADR-104 § Decision 3: schemaVersion + compiledAt + sourcePackVersions.
|
|
12
|
+
*/
|
|
13
|
+
declare const HookCheckTypeSchema: z.ZodEnum<["reject-if-match", "reject-if-no-match"]>;
|
|
14
|
+
export type HookCheckType = z.infer<typeof HookCheckTypeSchema>;
|
|
15
|
+
/**
|
|
16
|
+
* Authoring-surface schema for a single hook rule in a pack's `hooks.yaml`.
|
|
17
|
+
*
|
|
18
|
+
* The optional `recoveryHint` field (ADR-104 § Decision 1) gives agents the
|
|
19
|
+
* WHAT-INSTEAD on a block — recommended but not required in V1. Adoption
|
|
20
|
+
* tracked toward a V2 upgrade-to-required trigger (>80% of published rules
|
|
21
|
+
* carry it, OR an empirically-observed retry-loop incident).
|
|
22
|
+
*
|
|
23
|
+
* The `verification_shadow` field is reserved for the Spine Rule
|
|
24
|
+
* classification path (ADR-104 § Convergence + Q1 binding). In V1 the engine
|
|
25
|
+
* MUST warn-and-ignore any verification_shadow on a hook rule (hooks are
|
|
26
|
+
* Interpretive Rule class — no formal verification obligation). Schema
|
|
27
|
+
* accepts it permissively so future Spine-Rule promotion does not require
|
|
28
|
+
* a schema break.
|
|
29
|
+
*/
|
|
30
|
+
export declare const HookRuleSchema: z.ZodObject<{
|
|
31
|
+
id: z.ZodString;
|
|
32
|
+
trigger: z.ZodObject<{
|
|
33
|
+
tool: z.ZodString;
|
|
34
|
+
pattern: z.ZodEffects<z.ZodString, string, string>;
|
|
35
|
+
}, "strip", z.ZodTypeAny, {
|
|
36
|
+
tool: string;
|
|
37
|
+
pattern: string;
|
|
38
|
+
}, {
|
|
39
|
+
tool: string;
|
|
40
|
+
pattern: string;
|
|
41
|
+
}>;
|
|
42
|
+
check: z.ZodObject<{
|
|
43
|
+
pattern: z.ZodEffects<z.ZodString, string, string>;
|
|
44
|
+
type: z.ZodEnum<["reject-if-match", "reject-if-no-match"]>;
|
|
45
|
+
}, "strip", z.ZodTypeAny, {
|
|
46
|
+
type: "reject-if-match" | "reject-if-no-match";
|
|
47
|
+
pattern: string;
|
|
48
|
+
}, {
|
|
49
|
+
type: "reject-if-match" | "reject-if-no-match";
|
|
50
|
+
pattern: string;
|
|
51
|
+
}>;
|
|
52
|
+
message: z.ZodString;
|
|
53
|
+
recoveryHint: z.ZodOptional<z.ZodString>;
|
|
54
|
+
verification_shadow: z.ZodOptional<z.ZodUnknown>;
|
|
55
|
+
}, "strip", z.ZodTypeAny, {
|
|
56
|
+
check: {
|
|
57
|
+
type: "reject-if-match" | "reject-if-no-match";
|
|
58
|
+
pattern: string;
|
|
59
|
+
};
|
|
60
|
+
message: string;
|
|
61
|
+
id: string;
|
|
62
|
+
trigger: {
|
|
63
|
+
tool: string;
|
|
64
|
+
pattern: string;
|
|
65
|
+
};
|
|
66
|
+
recoveryHint?: string | undefined;
|
|
67
|
+
verification_shadow?: unknown;
|
|
68
|
+
}, {
|
|
69
|
+
check: {
|
|
70
|
+
type: "reject-if-match" | "reject-if-no-match";
|
|
71
|
+
pattern: string;
|
|
72
|
+
};
|
|
73
|
+
message: string;
|
|
74
|
+
id: string;
|
|
75
|
+
trigger: {
|
|
76
|
+
tool: string;
|
|
77
|
+
pattern: string;
|
|
78
|
+
};
|
|
79
|
+
recoveryHint?: string | undefined;
|
|
80
|
+
verification_shadow?: unknown;
|
|
81
|
+
}>;
|
|
82
|
+
export type HookRule = z.infer<typeof HookRuleSchema>;
|
|
83
|
+
export declare const HOOKS_YAML_SCHEMA_VERSION: 1;
|
|
84
|
+
/**
|
|
85
|
+
* Per-pack `hooks.yaml` file shape. The `version` field is the contract
|
|
86
|
+
* for forward-compat: when `totem sync` parses an unknown version (higher
|
|
87
|
+
* than the runner supports), it warns-and-skips that pack entirely
|
|
88
|
+
* (ADR-104 § Decision 4).
|
|
89
|
+
*/
|
|
90
|
+
export declare const HooksYamlSchema: z.ZodEffects<z.ZodObject<{
|
|
91
|
+
version: z.ZodNumber;
|
|
92
|
+
hooks: z.ZodArray<z.ZodObject<{
|
|
93
|
+
id: z.ZodString;
|
|
94
|
+
trigger: z.ZodObject<{
|
|
95
|
+
tool: z.ZodString;
|
|
96
|
+
pattern: z.ZodEffects<z.ZodString, string, string>;
|
|
97
|
+
}, "strip", z.ZodTypeAny, {
|
|
98
|
+
tool: string;
|
|
99
|
+
pattern: string;
|
|
100
|
+
}, {
|
|
101
|
+
tool: string;
|
|
102
|
+
pattern: string;
|
|
103
|
+
}>;
|
|
104
|
+
check: z.ZodObject<{
|
|
105
|
+
pattern: z.ZodEffects<z.ZodString, string, string>;
|
|
106
|
+
type: z.ZodEnum<["reject-if-match", "reject-if-no-match"]>;
|
|
107
|
+
}, "strip", z.ZodTypeAny, {
|
|
108
|
+
type: "reject-if-match" | "reject-if-no-match";
|
|
109
|
+
pattern: string;
|
|
110
|
+
}, {
|
|
111
|
+
type: "reject-if-match" | "reject-if-no-match";
|
|
112
|
+
pattern: string;
|
|
113
|
+
}>;
|
|
114
|
+
message: z.ZodString;
|
|
115
|
+
recoveryHint: z.ZodOptional<z.ZodString>;
|
|
116
|
+
verification_shadow: z.ZodOptional<z.ZodUnknown>;
|
|
117
|
+
}, "strip", z.ZodTypeAny, {
|
|
118
|
+
check: {
|
|
119
|
+
type: "reject-if-match" | "reject-if-no-match";
|
|
120
|
+
pattern: string;
|
|
121
|
+
};
|
|
122
|
+
message: string;
|
|
123
|
+
id: string;
|
|
124
|
+
trigger: {
|
|
125
|
+
tool: string;
|
|
126
|
+
pattern: string;
|
|
127
|
+
};
|
|
128
|
+
recoveryHint?: string | undefined;
|
|
129
|
+
verification_shadow?: unknown;
|
|
130
|
+
}, {
|
|
131
|
+
check: {
|
|
132
|
+
type: "reject-if-match" | "reject-if-no-match";
|
|
133
|
+
pattern: string;
|
|
134
|
+
};
|
|
135
|
+
message: string;
|
|
136
|
+
id: string;
|
|
137
|
+
trigger: {
|
|
138
|
+
tool: string;
|
|
139
|
+
pattern: string;
|
|
140
|
+
};
|
|
141
|
+
recoveryHint?: string | undefined;
|
|
142
|
+
verification_shadow?: unknown;
|
|
143
|
+
}>, "many">;
|
|
144
|
+
}, "strip", z.ZodTypeAny, {
|
|
145
|
+
hooks: {
|
|
146
|
+
check: {
|
|
147
|
+
type: "reject-if-match" | "reject-if-no-match";
|
|
148
|
+
pattern: string;
|
|
149
|
+
};
|
|
150
|
+
message: string;
|
|
151
|
+
id: string;
|
|
152
|
+
trigger: {
|
|
153
|
+
tool: string;
|
|
154
|
+
pattern: string;
|
|
155
|
+
};
|
|
156
|
+
recoveryHint?: string | undefined;
|
|
157
|
+
verification_shadow?: unknown;
|
|
158
|
+
}[];
|
|
159
|
+
version: number;
|
|
160
|
+
}, {
|
|
161
|
+
hooks: {
|
|
162
|
+
check: {
|
|
163
|
+
type: "reject-if-match" | "reject-if-no-match";
|
|
164
|
+
pattern: string;
|
|
165
|
+
};
|
|
166
|
+
message: string;
|
|
167
|
+
id: string;
|
|
168
|
+
trigger: {
|
|
169
|
+
tool: string;
|
|
170
|
+
pattern: string;
|
|
171
|
+
};
|
|
172
|
+
recoveryHint?: string | undefined;
|
|
173
|
+
verification_shadow?: unknown;
|
|
174
|
+
}[];
|
|
175
|
+
version: number;
|
|
176
|
+
}>, {
|
|
177
|
+
hooks: {
|
|
178
|
+
check: {
|
|
179
|
+
type: "reject-if-match" | "reject-if-no-match";
|
|
180
|
+
pattern: string;
|
|
181
|
+
};
|
|
182
|
+
message: string;
|
|
183
|
+
id: string;
|
|
184
|
+
trigger: {
|
|
185
|
+
tool: string;
|
|
186
|
+
pattern: string;
|
|
187
|
+
};
|
|
188
|
+
recoveryHint?: string | undefined;
|
|
189
|
+
verification_shadow?: unknown;
|
|
190
|
+
}[];
|
|
191
|
+
version: number;
|
|
192
|
+
}, {
|
|
193
|
+
hooks: {
|
|
194
|
+
check: {
|
|
195
|
+
type: "reject-if-match" | "reject-if-no-match";
|
|
196
|
+
pattern: string;
|
|
197
|
+
};
|
|
198
|
+
message: string;
|
|
199
|
+
id: string;
|
|
200
|
+
trigger: {
|
|
201
|
+
tool: string;
|
|
202
|
+
pattern: string;
|
|
203
|
+
};
|
|
204
|
+
recoveryHint?: string | undefined;
|
|
205
|
+
verification_shadow?: unknown;
|
|
206
|
+
}[];
|
|
207
|
+
version: number;
|
|
208
|
+
}>;
|
|
209
|
+
export type HooksYaml = z.infer<typeof HooksYamlSchema>;
|
|
210
|
+
export declare const COMPILED_HOOKS_SCHEMA_VERSION: 1;
|
|
211
|
+
/**
|
|
212
|
+
* A compiled hook rule carries provenance (`packId`) so rejection messages
|
|
213
|
+
* can name `<packId>/<ruleId>` (ADR-104 § Decision 1) and so staleness
|
|
214
|
+
* checks can scope per-pack.
|
|
215
|
+
*/
|
|
216
|
+
export declare const CompiledHookRuleSchema: z.ZodObject<{
|
|
217
|
+
id: z.ZodString;
|
|
218
|
+
trigger: z.ZodObject<{
|
|
219
|
+
tool: z.ZodString;
|
|
220
|
+
pattern: z.ZodEffects<z.ZodString, string, string>;
|
|
221
|
+
}, "strip", z.ZodTypeAny, {
|
|
222
|
+
tool: string;
|
|
223
|
+
pattern: string;
|
|
224
|
+
}, {
|
|
225
|
+
tool: string;
|
|
226
|
+
pattern: string;
|
|
227
|
+
}>;
|
|
228
|
+
check: z.ZodObject<{
|
|
229
|
+
pattern: z.ZodEffects<z.ZodString, string, string>;
|
|
230
|
+
type: z.ZodEnum<["reject-if-match", "reject-if-no-match"]>;
|
|
231
|
+
}, "strip", z.ZodTypeAny, {
|
|
232
|
+
type: "reject-if-match" | "reject-if-no-match";
|
|
233
|
+
pattern: string;
|
|
234
|
+
}, {
|
|
235
|
+
type: "reject-if-match" | "reject-if-no-match";
|
|
236
|
+
pattern: string;
|
|
237
|
+
}>;
|
|
238
|
+
message: z.ZodString;
|
|
239
|
+
recoveryHint: z.ZodOptional<z.ZodString>;
|
|
240
|
+
verification_shadow: z.ZodOptional<z.ZodUnknown>;
|
|
241
|
+
} & {
|
|
242
|
+
packId: z.ZodString;
|
|
243
|
+
}, "strip", z.ZodTypeAny, {
|
|
244
|
+
check: {
|
|
245
|
+
type: "reject-if-match" | "reject-if-no-match";
|
|
246
|
+
pattern: string;
|
|
247
|
+
};
|
|
248
|
+
message: string;
|
|
249
|
+
id: string;
|
|
250
|
+
trigger: {
|
|
251
|
+
tool: string;
|
|
252
|
+
pattern: string;
|
|
253
|
+
};
|
|
254
|
+
packId: string;
|
|
255
|
+
recoveryHint?: string | undefined;
|
|
256
|
+
verification_shadow?: unknown;
|
|
257
|
+
}, {
|
|
258
|
+
check: {
|
|
259
|
+
type: "reject-if-match" | "reject-if-no-match";
|
|
260
|
+
pattern: string;
|
|
261
|
+
};
|
|
262
|
+
message: string;
|
|
263
|
+
id: string;
|
|
264
|
+
trigger: {
|
|
265
|
+
tool: string;
|
|
266
|
+
pattern: string;
|
|
267
|
+
};
|
|
268
|
+
packId: string;
|
|
269
|
+
recoveryHint?: string | undefined;
|
|
270
|
+
verification_shadow?: unknown;
|
|
271
|
+
}>;
|
|
272
|
+
export type CompiledHookRule = z.infer<typeof CompiledHookRuleSchema>;
|
|
273
|
+
/**
|
|
274
|
+
* Runtime-surface manifest produced by `totem sync` and read on every
|
|
275
|
+
* `totem hook run` invocation. The metadata fields are load-bearing for
|
|
276
|
+
* ADR-104 § Decision 3 (staleness detection):
|
|
277
|
+
*
|
|
278
|
+
* - `schemaVersion`: bumps on breaking structural change to this manifest
|
|
279
|
+
* - `compiledAt`: ISO 8601 timestamp of last compile
|
|
280
|
+
* - `sourcePackVersions`: pack name → version at compile time; compared
|
|
281
|
+
* against package.json resolutions to emit `[totem:hook-stale]` warnings
|
|
282
|
+
* when packs have updated since last compile
|
|
283
|
+
*/
|
|
284
|
+
export declare const CompiledHooksManifestSchema: z.ZodObject<{
|
|
285
|
+
schemaVersion: z.ZodLiteral<1>;
|
|
286
|
+
compiledAt: z.ZodString;
|
|
287
|
+
sourcePackVersions: z.ZodRecord<z.ZodString, z.ZodString>;
|
|
288
|
+
hooks: z.ZodArray<z.ZodObject<{
|
|
289
|
+
id: z.ZodString;
|
|
290
|
+
trigger: z.ZodObject<{
|
|
291
|
+
tool: z.ZodString;
|
|
292
|
+
pattern: z.ZodEffects<z.ZodString, string, string>;
|
|
293
|
+
}, "strip", z.ZodTypeAny, {
|
|
294
|
+
tool: string;
|
|
295
|
+
pattern: string;
|
|
296
|
+
}, {
|
|
297
|
+
tool: string;
|
|
298
|
+
pattern: string;
|
|
299
|
+
}>;
|
|
300
|
+
check: z.ZodObject<{
|
|
301
|
+
pattern: z.ZodEffects<z.ZodString, string, string>;
|
|
302
|
+
type: z.ZodEnum<["reject-if-match", "reject-if-no-match"]>;
|
|
303
|
+
}, "strip", z.ZodTypeAny, {
|
|
304
|
+
type: "reject-if-match" | "reject-if-no-match";
|
|
305
|
+
pattern: string;
|
|
306
|
+
}, {
|
|
307
|
+
type: "reject-if-match" | "reject-if-no-match";
|
|
308
|
+
pattern: string;
|
|
309
|
+
}>;
|
|
310
|
+
message: z.ZodString;
|
|
311
|
+
recoveryHint: z.ZodOptional<z.ZodString>;
|
|
312
|
+
verification_shadow: z.ZodOptional<z.ZodUnknown>;
|
|
313
|
+
} & {
|
|
314
|
+
packId: z.ZodString;
|
|
315
|
+
}, "strip", z.ZodTypeAny, {
|
|
316
|
+
check: {
|
|
317
|
+
type: "reject-if-match" | "reject-if-no-match";
|
|
318
|
+
pattern: string;
|
|
319
|
+
};
|
|
320
|
+
message: string;
|
|
321
|
+
id: string;
|
|
322
|
+
trigger: {
|
|
323
|
+
tool: string;
|
|
324
|
+
pattern: string;
|
|
325
|
+
};
|
|
326
|
+
packId: string;
|
|
327
|
+
recoveryHint?: string | undefined;
|
|
328
|
+
verification_shadow?: unknown;
|
|
329
|
+
}, {
|
|
330
|
+
check: {
|
|
331
|
+
type: "reject-if-match" | "reject-if-no-match";
|
|
332
|
+
pattern: string;
|
|
333
|
+
};
|
|
334
|
+
message: string;
|
|
335
|
+
id: string;
|
|
336
|
+
trigger: {
|
|
337
|
+
tool: string;
|
|
338
|
+
pattern: string;
|
|
339
|
+
};
|
|
340
|
+
packId: string;
|
|
341
|
+
recoveryHint?: string | undefined;
|
|
342
|
+
verification_shadow?: unknown;
|
|
343
|
+
}>, "many">;
|
|
344
|
+
}, "strip", z.ZodTypeAny, {
|
|
345
|
+
hooks: {
|
|
346
|
+
check: {
|
|
347
|
+
type: "reject-if-match" | "reject-if-no-match";
|
|
348
|
+
pattern: string;
|
|
349
|
+
};
|
|
350
|
+
message: string;
|
|
351
|
+
id: string;
|
|
352
|
+
trigger: {
|
|
353
|
+
tool: string;
|
|
354
|
+
pattern: string;
|
|
355
|
+
};
|
|
356
|
+
packId: string;
|
|
357
|
+
recoveryHint?: string | undefined;
|
|
358
|
+
verification_shadow?: unknown;
|
|
359
|
+
}[];
|
|
360
|
+
schemaVersion: 1;
|
|
361
|
+
compiledAt: string;
|
|
362
|
+
sourcePackVersions: Record<string, string>;
|
|
363
|
+
}, {
|
|
364
|
+
hooks: {
|
|
365
|
+
check: {
|
|
366
|
+
type: "reject-if-match" | "reject-if-no-match";
|
|
367
|
+
pattern: string;
|
|
368
|
+
};
|
|
369
|
+
message: string;
|
|
370
|
+
id: string;
|
|
371
|
+
trigger: {
|
|
372
|
+
tool: string;
|
|
373
|
+
pattern: string;
|
|
374
|
+
};
|
|
375
|
+
packId: string;
|
|
376
|
+
recoveryHint?: string | undefined;
|
|
377
|
+
verification_shadow?: unknown;
|
|
378
|
+
}[];
|
|
379
|
+
schemaVersion: 1;
|
|
380
|
+
compiledAt: string;
|
|
381
|
+
sourcePackVersions: Record<string, string>;
|
|
382
|
+
}>;
|
|
383
|
+
export type CompiledHooksManifest = z.infer<typeof CompiledHooksManifestSchema>;
|
|
384
|
+
export {};
|
|
385
|
+
//# sourceMappingURL=schema.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/hook/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB;;;;;;;;;;GAUG;AAEH,QAAA,MAAM,mBAAmB,sDAAoD,CAAC;AAE9E,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AA4EhE;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAOzB,CAAC;AAEH,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAEtD,eAAO,MAAM,yBAAyB,EAAG,CAAU,CAAC;AAEpD;;;;;GAKG;AACH,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAqBxB,CAAC;AAEL,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC;AAExD,eAAO,MAAM,6BAA6B,EAAG,CAAU,CAAC;AAExD;;;;GAIG;AACH,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAEjC,CAAC;AAEH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAEtE;;;;;;;;;;GAUG;AACH,eAAO,MAAM,2BAA2B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAKtC,CAAC;AAEH,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,2BAA2B,CAAC,CAAC"}
|