@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,45 @@
|
|
|
1
|
+
import type { HookRule } from './schema.js';
|
|
2
|
+
/**
|
|
3
|
+
* Rule classification per ADR-104 § Convergence + § Target-aware dispatch
|
|
4
|
+
* (strategy-Gemini Q1 binding synthesis, T1930Z 2026-05-11).
|
|
5
|
+
*
|
|
6
|
+
* Two classes:
|
|
7
|
+
* - `spine`: has Rego-shadow representation; formally verified by SMT;
|
|
8
|
+
* eligible for the top ~30 invariant set. Ships in ADR-103's lint-rule
|
|
9
|
+
* pipeline. Not produced by this V1 hook engine.
|
|
10
|
+
* - `interpretive`: ast-grep / regex only; no formal verification obligation;
|
|
11
|
+
* ships outside the core invariant set. All bot-pack hooks in V1 fall here.
|
|
12
|
+
*
|
|
13
|
+
* The hook runtime treats every rule as `interpretive`. The class is named
|
|
14
|
+
* explicitly so the loader's warn-and-ignore signal on a future Spine-Rule
|
|
15
|
+
* promotion attempt (`verification_shadow:` on a hook rule) carries the
|
|
16
|
+
* dispatch contract in its error message rather than relying on prose docs.
|
|
17
|
+
*
|
|
18
|
+
* V2 may promote bot-pack hooks to `spine` via a follow-on ADR; this seam
|
|
19
|
+
* is where that promotion lands.
|
|
20
|
+
*/
|
|
21
|
+
export type RuleClassification = 'spine' | 'interpretive';
|
|
22
|
+
export interface ClassificationResult {
|
|
23
|
+
classification: RuleClassification;
|
|
24
|
+
/**
|
|
25
|
+
* When set, the loader SHOULD emit this string to stderr but continue
|
|
26
|
+
* loading the rule. Empty when no warn-and-ignore signal applies.
|
|
27
|
+
*/
|
|
28
|
+
warning?: string;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Classify a hook rule for V1 dispatch.
|
|
32
|
+
*
|
|
33
|
+
* Always returns `interpretive` per ADR-104 § Target-aware dispatch (hooks
|
|
34
|
+
* are Interpretive Rule class — no formal-verification obligation; PreToolUse
|
|
35
|
+
* payloads are not source code, so the Rego/OPA value proposition is weaker
|
|
36
|
+
* than for lint rules).
|
|
37
|
+
*
|
|
38
|
+
* If the rule carries a `verification_shadow:` block (forward-compat schema
|
|
39
|
+
* permits this for future Spine promotion), the returned result includes a
|
|
40
|
+
* structured warning. Per ADR-104 § Convergence: "the engine MUST
|
|
41
|
+
* warn-and-ignore the block (the rule itself still executes as
|
|
42
|
+
* Interpretive)."
|
|
43
|
+
*/
|
|
44
|
+
export declare function classifyHookRule(rule: HookRule): ClassificationResult;
|
|
45
|
+
//# sourceMappingURL=classification.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"classification.d.ts","sourceRoot":"","sources":["../../src/hook/classification.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAE5C;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,MAAM,kBAAkB,GAAG,OAAO,GAAG,cAAc,CAAC;AAE1D,MAAM,WAAW,oBAAoB;IACnC,cAAc,EAAE,kBAAkB,CAAC;IACnC;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,QAAQ,GAAG,oBAAoB,CAQrE"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Classify a hook rule for V1 dispatch.
|
|
3
|
+
*
|
|
4
|
+
* Always returns `interpretive` per ADR-104 § Target-aware dispatch (hooks
|
|
5
|
+
* are Interpretive Rule class — no formal-verification obligation; PreToolUse
|
|
6
|
+
* payloads are not source code, so the Rego/OPA value proposition is weaker
|
|
7
|
+
* than for lint rules).
|
|
8
|
+
*
|
|
9
|
+
* If the rule carries a `verification_shadow:` block (forward-compat schema
|
|
10
|
+
* permits this for future Spine promotion), the returned result includes a
|
|
11
|
+
* structured warning. Per ADR-104 § Convergence: "the engine MUST
|
|
12
|
+
* warn-and-ignore the block (the rule itself still executes as
|
|
13
|
+
* Interpretive)."
|
|
14
|
+
*/
|
|
15
|
+
export function classifyHookRule(rule) {
|
|
16
|
+
if (rule.verification_shadow !== undefined) {
|
|
17
|
+
return {
|
|
18
|
+
classification: 'interpretive',
|
|
19
|
+
warning: `[totem:hook-shadow-ignored] ${rule.id}: verification_shadow block ignored in V1 (hooks are Interpretive Rule class); rule still executes`,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
return { classification: 'interpretive' };
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=classification.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"classification.js","sourceRoot":"","sources":["../../src/hook/classification.ts"],"names":[],"mappings":"AAgCA;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAc;IAC7C,IAAI,IAAI,CAAC,mBAAmB,KAAK,SAAS,EAAE,CAAC;QAC3C,OAAO;YACL,cAAc,EAAE,cAAc;YAC9B,OAAO,EAAE,+BAA+B,IAAI,CAAC,EAAE,oGAAoG;SACpJ,CAAC;IACJ,CAAC;IACD,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,CAAC;AAC5C,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"classification.test.d.ts","sourceRoot":"","sources":["../../src/hook/classification.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { classifyHookRule } from './classification.js';
|
|
3
|
+
const baseRule = {
|
|
4
|
+
id: 'r1',
|
|
5
|
+
trigger: { tool: 'bash', pattern: '.*' },
|
|
6
|
+
check: { pattern: 'x', type: 'reject-if-match' },
|
|
7
|
+
message: 'm',
|
|
8
|
+
};
|
|
9
|
+
describe('classifyHookRule', () => {
|
|
10
|
+
it('returns interpretive with no warning for a plain hook rule', () => {
|
|
11
|
+
const result = classifyHookRule(baseRule);
|
|
12
|
+
expect(result.classification).toBe('interpretive');
|
|
13
|
+
expect(result.warning).toBeUndefined();
|
|
14
|
+
});
|
|
15
|
+
it('returns interpretive but emits a warn-and-ignore signal when verification_shadow is present', () => {
|
|
16
|
+
const withShadow = {
|
|
17
|
+
...baseRule,
|
|
18
|
+
verification_shadow: { rego: 'package x' },
|
|
19
|
+
};
|
|
20
|
+
const result = classifyHookRule(withShadow);
|
|
21
|
+
expect(result.classification).toBe('interpretive');
|
|
22
|
+
expect(result.warning).toBeDefined();
|
|
23
|
+
expect(result.warning).toContain('[totem:hook-shadow-ignored]');
|
|
24
|
+
expect(result.warning).toContain('r1');
|
|
25
|
+
});
|
|
26
|
+
it('treats verification_shadow: null as present (warns and continues)', () => {
|
|
27
|
+
// null is a JS-truthy distinct from undefined; if the schema admits it the
|
|
28
|
+
// classification helper should still emit the warn-and-ignore signal so
|
|
29
|
+
// the dispatch contract holds for any non-undefined value.
|
|
30
|
+
const withNullShadow = {
|
|
31
|
+
...baseRule,
|
|
32
|
+
id: 'r-null',
|
|
33
|
+
verification_shadow: null,
|
|
34
|
+
};
|
|
35
|
+
const result = classifyHookRule(withNullShadow);
|
|
36
|
+
expect(result.classification).toBe('interpretive');
|
|
37
|
+
expect(result.warning).toBeDefined();
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
//# sourceMappingURL=classification.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"classification.test.js","sourceRoot":"","sources":["../../src/hook/classification.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAE9C,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAGvD,MAAM,QAAQ,GAAa;IACzB,EAAE,EAAE,IAAI;IACR,OAAO,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE;IACxC,KAAK,EAAE,EAAE,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,iBAAiB,EAAE;IAChD,OAAO,EAAE,GAAG;CACb,CAAC;AAEF,QAAQ,CAAC,kBAAkB,EAAE,GAAG,EAAE;IAChC,EAAE,CAAC,4DAA4D,EAAE,GAAG,EAAE;QACpE,MAAM,MAAM,GAAG,gBAAgB,CAAC,QAAQ,CAAC,CAAC;QAC1C,MAAM,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QACnD,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,aAAa,EAAE,CAAC;IACzC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6FAA6F,EAAE,GAAG,EAAE;QACrG,MAAM,UAAU,GAAa;YAC3B,GAAG,QAAQ;YACX,mBAAmB,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE;SAC3C,CAAC;QACF,MAAM,MAAM,GAAG,gBAAgB,CAAC,UAAU,CAAC,CAAC;QAC5C,MAAM,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QACnD,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,WAAW,EAAE,CAAC;QACrC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,6BAA6B,CAAC,CAAC;QAChE,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IACzC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mEAAmE,EAAE,GAAG,EAAE;QAC3E,2EAA2E;QAC3E,wEAAwE;QACxE,2DAA2D;QAC3D,MAAM,cAAc,GAAa;YAC/B,GAAG,QAAQ;YACX,EAAE,EAAE,QAAQ;YACZ,mBAAmB,EAAE,IAAI;SAC1B,CAAC;QACF,MAAM,MAAM,GAAG,gBAAgB,CAAC,cAAc,CAAC,CAAC;QAChD,MAAM,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QACnD,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,WAAW,EAAE,CAAC;IACvC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { TotemError } from '@mmnto/totem';
|
|
2
|
+
import { type CompiledHookRule } from './schema.js';
|
|
3
|
+
/**
|
|
4
|
+
* Compiled-hooks manifest loader (ADR-104 § Decision 3 staleness check + a
|
|
5
|
+
* forward-compat warn-and-skip path for an evolving manifest schema).
|
|
6
|
+
*
|
|
7
|
+
* The loader is a pure function over `(manifestPath, installedPackVersions)`.
|
|
8
|
+
* It does NOT read `package.json` itself — callers (typically a
|
|
9
|
+
* bootstrap helper) resolve installed pack versions once and pass them in.
|
|
10
|
+
* Keeps the loader testable in isolation; mirrors the substrate-wiring
|
|
11
|
+
* pattern from `bootstrapEngine` (1.25.0 wiring lesson).
|
|
12
|
+
*
|
|
13
|
+
* Three failure modes are surfaced via the `warnings` array, not by
|
|
14
|
+
* throwing:
|
|
15
|
+
*
|
|
16
|
+
* 1. Manifest file missing — empty result, no warnings (a fresh repo without
|
|
17
|
+
* installed pack hooks is a valid state).
|
|
18
|
+
* 2. Manifest schemaVersion is not the runner's expected version — warn and
|
|
19
|
+
* skip the entire manifest (no hooks loaded). Composes with ADR-104
|
|
20
|
+
* § Decision 4's forward-compat ethos.
|
|
21
|
+
* 3. Pack version drift — for each pack whose installed version differs from
|
|
22
|
+
* the compiled-against version, emit a `[totem:hook-stale]` warning per
|
|
23
|
+
* the format in ADR-104 § Decision 3. Hooks still load (Tenet 4 carve-out:
|
|
24
|
+
* hooks are best-effort; staleness is signal, not a fail-closed condition).
|
|
25
|
+
*
|
|
26
|
+
* Structural errors (corrupt JSON, schema-validation failure on a manifest
|
|
27
|
+
* claiming the supported schemaVersion) populate `errors` and yield an empty
|
|
28
|
+
* hooks array — distinct from a missing manifest.
|
|
29
|
+
*/
|
|
30
|
+
export interface LoadCompiledHooksOptions {
|
|
31
|
+
manifestPath: string;
|
|
32
|
+
installedPackVersions: Record<string, string>;
|
|
33
|
+
}
|
|
34
|
+
export interface LoadCompiledHooksResult {
|
|
35
|
+
hooks: CompiledHookRule[];
|
|
36
|
+
warnings: string[];
|
|
37
|
+
/**
|
|
38
|
+
* Errors carry the original cause via `Error.cause` so debug consumers
|
|
39
|
+
* can traverse the chain (per the codebase styleguide rule against
|
|
40
|
+
* concatenating `err.message` into new strings — destroys the stack).
|
|
41
|
+
* Callers that just need to log can use `err.message`; debug tooling
|
|
42
|
+
* walks `err.cause` recursively.
|
|
43
|
+
*/
|
|
44
|
+
errors: TotemError[];
|
|
45
|
+
}
|
|
46
|
+
export declare function loadCompiledHooks(options: LoadCompiledHooksOptions): LoadCompiledHooksResult;
|
|
47
|
+
//# sourceMappingURL=loader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../src/hook/loader.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE1C,OAAO,EAEL,KAAK,gBAAgB,EAEtB,MAAM,aAAa,CAAC;AAErB;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,MAAM,WAAW,wBAAwB;IACvC,YAAY,EAAE,MAAM,CAAC;IACrB,qBAAqB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC/C;AAED,MAAM,WAAW,uBAAuB;IACtC,KAAK,EAAE,gBAAgB,EAAE,CAAC;IAC1B,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB;;;;;;OAMG;IACH,MAAM,EAAE,UAAU,EAAE,CAAC;CACtB;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,wBAAwB,GAAG,uBAAuB,CA+F5F"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import { TotemError } from '@mmnto/totem';
|
|
3
|
+
import { COMPILED_HOOKS_SCHEMA_VERSION, CompiledHooksManifestSchema, } from './schema.js';
|
|
4
|
+
export function loadCompiledHooks(options) {
|
|
5
|
+
const warnings = [];
|
|
6
|
+
const errors = [];
|
|
7
|
+
// No `fs.existsSync` pre-check: that returns false for any filesystem
|
|
8
|
+
// error (permission denied, symlink loops, EBUSY, etc.), not just ENOENT.
|
|
9
|
+
// Treating those as "missing manifest" would silently swallow real
|
|
10
|
+
// diagnostics. Catch ENOENT explicitly inside the read; everything else
|
|
11
|
+
// surfaces as a HOOKS_LOAD_FAILED entry.
|
|
12
|
+
let raw;
|
|
13
|
+
try {
|
|
14
|
+
raw = fs.readFileSync(options.manifestPath, 'utf8');
|
|
15
|
+
// totem-context: intentional — error captured into diagnostics array (the loader's contract is diagnostics-not-throws per Tenet 4 carve-out for hooks being best-effort)
|
|
16
|
+
}
|
|
17
|
+
catch (err) {
|
|
18
|
+
if (err.code === 'ENOENT') {
|
|
19
|
+
// Fresh repo without installed pack hooks is a valid state, not a fault.
|
|
20
|
+
return { hooks: [], warnings, errors };
|
|
21
|
+
}
|
|
22
|
+
errors.push(new TotemError('HOOKS_LOAD_FAILED', `failed to read compiled-hooks manifest at ${options.manifestPath}`, 'verify the file is readable and re-run `totem sync` to regenerate', err));
|
|
23
|
+
return { hooks: [], warnings, errors };
|
|
24
|
+
}
|
|
25
|
+
let parsed;
|
|
26
|
+
try {
|
|
27
|
+
parsed = JSON.parse(raw);
|
|
28
|
+
// totem-context: intentional — error captured into diagnostics array (the loader's contract is diagnostics-not-throws per Tenet 4 carve-out for hooks being best-effort)
|
|
29
|
+
}
|
|
30
|
+
catch (err) {
|
|
31
|
+
errors.push(new TotemError('HOOKS_LOAD_FAILED', `compiled-hooks manifest at ${options.manifestPath} is not valid JSON`, 're-run `totem sync` to regenerate the manifest', err));
|
|
32
|
+
return { hooks: [], warnings, errors };
|
|
33
|
+
}
|
|
34
|
+
// Forward-compat: peek at schemaVersion BEFORE invoking the strict z.literal
|
|
35
|
+
// schema validator, so an unknown version surfaces as a warn-and-skip
|
|
36
|
+
// rather than a thrown ZodError. Mirrors the per-pack warn-and-skip pattern
|
|
37
|
+
// for `hooks.yaml :: version` from ADR-104 § Decision 4.
|
|
38
|
+
const peekedVersion = typeof parsed === 'object' && parsed !== null
|
|
39
|
+
? parsed.schemaVersion
|
|
40
|
+
: undefined;
|
|
41
|
+
if (peekedVersion !== COMPILED_HOOKS_SCHEMA_VERSION) {
|
|
42
|
+
warnings.push(`[totem:hook-schema] compiled-hooks manifest schemaVersion ${JSON.stringify(peekedVersion)} unsupported by this runner (expected ${COMPILED_HOOKS_SCHEMA_VERSION})\n → upgrade totem CLI or re-run \`totem sync\` to regenerate`);
|
|
43
|
+
return { hooks: [], warnings, errors };
|
|
44
|
+
}
|
|
45
|
+
const validation = CompiledHooksManifestSchema.safeParse(parsed);
|
|
46
|
+
if (!validation.success) {
|
|
47
|
+
const summary = validation.error.issues
|
|
48
|
+
.map((i) => `${i.path.join('.')}: ${i.message}`)
|
|
49
|
+
.join('; ');
|
|
50
|
+
errors.push(new TotemError('HOOKS_LOAD_FAILED', `compiled-hooks manifest at ${options.manifestPath} failed schema validation: ${summary}`, 're-run `totem sync` to regenerate the manifest, or upgrade totem CLI if the manifest was authored by a newer version', validation.error));
|
|
51
|
+
return { hooks: [], warnings, errors };
|
|
52
|
+
}
|
|
53
|
+
const manifest = validation.data;
|
|
54
|
+
for (const [packId, compiledVersion] of Object.entries(manifest.sourcePackVersions)) {
|
|
55
|
+
const installedVersion = options.installedPackVersions[packId];
|
|
56
|
+
if (installedVersion === undefined) {
|
|
57
|
+
warnings.push(`[totem:hook-stale] ${packId}: compiled against ${compiledVersion}, not currently installed\n → run \`totem sync\` to refresh .totem/compiled-hooks.json`);
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
if (installedVersion !== compiledVersion) {
|
|
61
|
+
warnings.push(`[totem:hook-stale] ${packId}: compiled against ${compiledVersion}, installed ${installedVersion}\n → run \`totem sync\` to refresh .totem/compiled-hooks.json`);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return { hooks: manifest.hooks, warnings, errors };
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../../src/hook/loader.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.test.d.ts","sourceRoot":"","sources":["../../src/hook/loader.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import os from 'node:os';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
|
|
5
|
+
import { loadCompiledHooks } from './loader.js';
|
|
6
|
+
let workDir;
|
|
7
|
+
beforeEach(() => {
|
|
8
|
+
workDir = fs.mkdtempSync(path.join(os.tmpdir(), 'totem-hook-loader-'));
|
|
9
|
+
});
|
|
10
|
+
afterEach(() => {
|
|
11
|
+
fs.rmSync(workDir, { recursive: true, force: true });
|
|
12
|
+
});
|
|
13
|
+
function writeManifest(content) {
|
|
14
|
+
const manifestPath = path.join(workDir, 'compiled-hooks.json');
|
|
15
|
+
fs.writeFileSync(manifestPath, JSON.stringify(content), 'utf8');
|
|
16
|
+
return manifestPath;
|
|
17
|
+
}
|
|
18
|
+
const validRule = {
|
|
19
|
+
id: 'r1',
|
|
20
|
+
packId: '@mmnto/pack-bot-coderabbit',
|
|
21
|
+
trigger: { tool: 'bash', pattern: '.*' },
|
|
22
|
+
check: { pattern: 'x', type: 'reject-if-match' },
|
|
23
|
+
message: 'm',
|
|
24
|
+
};
|
|
25
|
+
describe('loadCompiledHooks', () => {
|
|
26
|
+
it('returns an empty result when the manifest file does not exist (fresh repo, ENOENT)', () => {
|
|
27
|
+
const result = loadCompiledHooks({
|
|
28
|
+
manifestPath: path.join(workDir, 'missing.json'),
|
|
29
|
+
installedPackVersions: {},
|
|
30
|
+
});
|
|
31
|
+
expect(result.hooks).toEqual([]);
|
|
32
|
+
expect(result.warnings).toEqual([]);
|
|
33
|
+
expect(result.errors).toEqual([]);
|
|
34
|
+
});
|
|
35
|
+
it('surfaces non-ENOENT read errors as HOOKS_LOAD_FAILED (does not pretend the file is missing)', () => {
|
|
36
|
+
// Reading a directory as a file produces EISDIR on POSIX / EBADF or
|
|
37
|
+
// ENOTSUP-flavoured failures on Windows. Whatever the platform-specific
|
|
38
|
+
// errno, it is NOT ENOENT — so the loader must surface it, not silently
|
|
39
|
+
// return the "manifest absent" result that the prior existsSync pre-check
|
|
40
|
+
// would have masked.
|
|
41
|
+
const dirAsManifest = path.join(workDir, 'a-directory');
|
|
42
|
+
fs.mkdirSync(dirAsManifest);
|
|
43
|
+
const result = loadCompiledHooks({
|
|
44
|
+
manifestPath: dirAsManifest,
|
|
45
|
+
installedPackVersions: {},
|
|
46
|
+
});
|
|
47
|
+
expect(result.hooks).toEqual([]);
|
|
48
|
+
expect(result.errors.length).toBe(1);
|
|
49
|
+
const err = result.errors[0];
|
|
50
|
+
expect(err.code).toBe('HOOKS_LOAD_FAILED');
|
|
51
|
+
expect(err.message).toContain('failed to read compiled-hooks manifest');
|
|
52
|
+
expect(err.cause).toBeDefined();
|
|
53
|
+
});
|
|
54
|
+
it('records a structural error on invalid JSON and preserves the original SyntaxError via cause', () => {
|
|
55
|
+
const manifestPath = path.join(workDir, 'compiled-hooks.json');
|
|
56
|
+
fs.writeFileSync(manifestPath, '{ not valid json', 'utf8');
|
|
57
|
+
const result = loadCompiledHooks({
|
|
58
|
+
manifestPath,
|
|
59
|
+
installedPackVersions: {},
|
|
60
|
+
});
|
|
61
|
+
expect(result.hooks).toEqual([]);
|
|
62
|
+
expect(result.errors.length).toBe(1);
|
|
63
|
+
const err = result.errors[0];
|
|
64
|
+
expect(err.message).toContain('not valid JSON');
|
|
65
|
+
expect(err.code).toBe('HOOKS_LOAD_FAILED');
|
|
66
|
+
// Original parse error preserved on `.cause` so debug consumers can
|
|
67
|
+
// walk the chain without the stack being collapsed into a string.
|
|
68
|
+
expect(err.cause).toBeInstanceOf(SyntaxError);
|
|
69
|
+
});
|
|
70
|
+
it('warns and skips when schemaVersion is higher than the runner supports', () => {
|
|
71
|
+
const manifestPath = writeManifest({
|
|
72
|
+
schemaVersion: 2,
|
|
73
|
+
compiledAt: '2026-05-11T18:43:00Z',
|
|
74
|
+
sourcePackVersions: {},
|
|
75
|
+
hooks: [],
|
|
76
|
+
});
|
|
77
|
+
const result = loadCompiledHooks({
|
|
78
|
+
manifestPath,
|
|
79
|
+
installedPackVersions: {},
|
|
80
|
+
});
|
|
81
|
+
expect(result.hooks).toEqual([]);
|
|
82
|
+
expect(result.errors).toEqual([]);
|
|
83
|
+
expect(result.warnings.length).toBe(1);
|
|
84
|
+
expect(result.warnings[0]).toContain('[totem:hook-schema]');
|
|
85
|
+
expect(result.warnings[0]).toContain('schemaVersion 2');
|
|
86
|
+
});
|
|
87
|
+
it('warns and skips when schemaVersion is missing', () => {
|
|
88
|
+
const manifestPath = writeManifest({
|
|
89
|
+
compiledAt: '2026-05-11T18:43:00Z',
|
|
90
|
+
sourcePackVersions: {},
|
|
91
|
+
hooks: [],
|
|
92
|
+
});
|
|
93
|
+
const result = loadCompiledHooks({
|
|
94
|
+
manifestPath,
|
|
95
|
+
installedPackVersions: {},
|
|
96
|
+
});
|
|
97
|
+
expect(result.hooks).toEqual([]);
|
|
98
|
+
expect(result.warnings.length).toBe(1);
|
|
99
|
+
expect(result.warnings[0]).toContain('[totem:hook-schema]');
|
|
100
|
+
});
|
|
101
|
+
it('records a structural error when the supported-version manifest fails schema validation', () => {
|
|
102
|
+
const manifestPath = writeManifest({
|
|
103
|
+
schemaVersion: 1,
|
|
104
|
+
compiledAt: 'not-a-real-date',
|
|
105
|
+
sourcePackVersions: {},
|
|
106
|
+
hooks: [],
|
|
107
|
+
});
|
|
108
|
+
const result = loadCompiledHooks({
|
|
109
|
+
manifestPath,
|
|
110
|
+
installedPackVersions: {},
|
|
111
|
+
});
|
|
112
|
+
expect(result.hooks).toEqual([]);
|
|
113
|
+
expect(result.errors.length).toBe(1);
|
|
114
|
+
const err = result.errors[0];
|
|
115
|
+
expect(err.message).toContain('schema validation');
|
|
116
|
+
expect(err.code).toBe('HOOKS_LOAD_FAILED');
|
|
117
|
+
// Zod's ZodError preserved as the cause for debug-mode chain traversal.
|
|
118
|
+
expect(err.cause).toBeDefined();
|
|
119
|
+
});
|
|
120
|
+
it('returns hooks with no warnings when installed pack versions match compiled versions', () => {
|
|
121
|
+
const manifestPath = writeManifest({
|
|
122
|
+
schemaVersion: 1,
|
|
123
|
+
compiledAt: '2026-05-11T18:43:00Z',
|
|
124
|
+
sourcePackVersions: { '@mmnto/pack-bot-coderabbit': '1.0.0' },
|
|
125
|
+
hooks: [validRule],
|
|
126
|
+
});
|
|
127
|
+
const result = loadCompiledHooks({
|
|
128
|
+
manifestPath,
|
|
129
|
+
installedPackVersions: { '@mmnto/pack-bot-coderabbit': '1.0.0' },
|
|
130
|
+
});
|
|
131
|
+
expect(result.hooks).toHaveLength(1);
|
|
132
|
+
expect(result.warnings).toEqual([]);
|
|
133
|
+
expect(result.errors).toEqual([]);
|
|
134
|
+
});
|
|
135
|
+
it('emits a staleness warning when the installed pack version differs from compiled', () => {
|
|
136
|
+
const manifestPath = writeManifest({
|
|
137
|
+
schemaVersion: 1,
|
|
138
|
+
compiledAt: '2026-05-11T18:43:00Z',
|
|
139
|
+
sourcePackVersions: { '@mmnto/pack-bot-coderabbit': '1.0.0' },
|
|
140
|
+
hooks: [validRule],
|
|
141
|
+
});
|
|
142
|
+
const result = loadCompiledHooks({
|
|
143
|
+
manifestPath,
|
|
144
|
+
installedPackVersions: { '@mmnto/pack-bot-coderabbit': '1.1.0' },
|
|
145
|
+
});
|
|
146
|
+
expect(result.hooks).toHaveLength(1);
|
|
147
|
+
expect(result.warnings.length).toBe(1);
|
|
148
|
+
expect(result.warnings[0]).toContain('[totem:hook-stale]');
|
|
149
|
+
expect(result.warnings[0]).toContain('@mmnto/pack-bot-coderabbit');
|
|
150
|
+
expect(result.warnings[0]).toContain('compiled against 1.0.0, installed 1.1.0');
|
|
151
|
+
});
|
|
152
|
+
it('emits a staleness warning when a compiled-against pack is not installed at all', () => {
|
|
153
|
+
const manifestPath = writeManifest({
|
|
154
|
+
schemaVersion: 1,
|
|
155
|
+
compiledAt: '2026-05-11T18:43:00Z',
|
|
156
|
+
sourcePackVersions: { '@mmnto/pack-bot-coderabbit': '1.0.0' },
|
|
157
|
+
hooks: [validRule],
|
|
158
|
+
});
|
|
159
|
+
const result = loadCompiledHooks({
|
|
160
|
+
manifestPath,
|
|
161
|
+
installedPackVersions: {},
|
|
162
|
+
});
|
|
163
|
+
expect(result.hooks).toHaveLength(1);
|
|
164
|
+
expect(result.warnings.length).toBe(1);
|
|
165
|
+
expect(result.warnings[0]).toContain('not currently installed');
|
|
166
|
+
});
|
|
167
|
+
it('ignores extra installed packs not in sourcePackVersions (no warning)', () => {
|
|
168
|
+
// A pack installed after the last `totem sync` is benign — its hooks
|
|
169
|
+
// are not yet active, but that is not staleness in the compiled set.
|
|
170
|
+
const manifestPath = writeManifest({
|
|
171
|
+
schemaVersion: 1,
|
|
172
|
+
compiledAt: '2026-05-11T18:43:00Z',
|
|
173
|
+
sourcePackVersions: { '@mmnto/pack-bot-coderabbit': '1.0.0' },
|
|
174
|
+
hooks: [validRule],
|
|
175
|
+
});
|
|
176
|
+
const result = loadCompiledHooks({
|
|
177
|
+
manifestPath,
|
|
178
|
+
installedPackVersions: {
|
|
179
|
+
'@mmnto/pack-bot-coderabbit': '1.0.0',
|
|
180
|
+
'@mmnto/pack-bot-gemini-code-assist': '1.0.0',
|
|
181
|
+
},
|
|
182
|
+
});
|
|
183
|
+
expect(result.warnings).toEqual([]);
|
|
184
|
+
});
|
|
185
|
+
it('emits one staleness warning per drifting pack', () => {
|
|
186
|
+
const manifestPath = writeManifest({
|
|
187
|
+
schemaVersion: 1,
|
|
188
|
+
compiledAt: '2026-05-11T18:43:00Z',
|
|
189
|
+
sourcePackVersions: {
|
|
190
|
+
'@mmnto/pack-bot-coderabbit': '1.0.0',
|
|
191
|
+
'@mmnto/pack-bot-gemini-code-assist': '2.0.0',
|
|
192
|
+
},
|
|
193
|
+
hooks: [validRule],
|
|
194
|
+
});
|
|
195
|
+
const result = loadCompiledHooks({
|
|
196
|
+
manifestPath,
|
|
197
|
+
installedPackVersions: {
|
|
198
|
+
'@mmnto/pack-bot-coderabbit': '1.1.0',
|
|
199
|
+
'@mmnto/pack-bot-gemini-code-assist': '2.0.1',
|
|
200
|
+
},
|
|
201
|
+
});
|
|
202
|
+
expect(result.warnings.length).toBe(2);
|
|
203
|
+
});
|
|
204
|
+
});
|
|
205
|
+
//# sourceMappingURL=loader.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.test.js","sourceRoot":"","sources":["../../src/hook/loader.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { CompiledHookRule } from './schema.js';
|
|
2
|
+
/**
|
|
3
|
+
* Hook runtime evaluator (ADR-104 § Decisions 1, 2 + § Convergence).
|
|
4
|
+
*
|
|
5
|
+
* Takes a single hook rule plus a tool-call payload (tool name + tool args
|
|
6
|
+
* as a single string) and returns a structured allow/reject decision. The
|
|
7
|
+
* runtime is deterministic Node.js — no LLM calls in this path (Tenet 15
|
|
8
|
+
* corollary, ADR-103 § 8).
|
|
9
|
+
*
|
|
10
|
+
* V1 matcher class is regex-only per execution plan § 4. ast-grep and
|
|
11
|
+
* other matcher classes are deferred to V2; the schema permits future
|
|
12
|
+
* `verification_shadow` blocks but the V1 runtime ignores them.
|
|
13
|
+
*/
|
|
14
|
+
export interface ToolCallPayload {
|
|
15
|
+
/** The tool the agent is attempting to invoke (e.g. "bash"). */
|
|
16
|
+
tool: string;
|
|
17
|
+
/** Serialized tool arguments. For bash this is the command string;
|
|
18
|
+
* for structured tools, callers serialize to a stable string form. */
|
|
19
|
+
args: string;
|
|
20
|
+
}
|
|
21
|
+
export type AllowDecision = {
|
|
22
|
+
decision: 'allow';
|
|
23
|
+
};
|
|
24
|
+
export type RejectDecision = {
|
|
25
|
+
decision: 'reject';
|
|
26
|
+
message: string;
|
|
27
|
+
packId: string;
|
|
28
|
+
ruleId: string;
|
|
29
|
+
recoveryHint?: string;
|
|
30
|
+
};
|
|
31
|
+
export type HookDecision = AllowDecision | RejectDecision;
|
|
32
|
+
/**
|
|
33
|
+
* Build the structured rejection message per ADR-104 § Decision 1:
|
|
34
|
+
*
|
|
35
|
+
* [totem:hook-block] <packId>/<ruleId>: <message>
|
|
36
|
+
* → <recoveryHint>
|
|
37
|
+
*
|
|
38
|
+
* The `→ <recoveryHint>` line is omitted when no recoveryHint is provided.
|
|
39
|
+
* Agents and operators grep for the `[totem:hook-block]` prefix; the
|
|
40
|
+
* `<packId>/<ruleId>` carries provenance.
|
|
41
|
+
*
|
|
42
|
+
* Parameter is narrowed to `RejectDecision` so the type system prevents
|
|
43
|
+
* passing an allow decision — no runtime guard needed.
|
|
44
|
+
*/
|
|
45
|
+
export declare function formatRejection(decision: RejectDecision): string;
|
|
46
|
+
export declare function evaluateHook(rule: CompiledHookRule, payload: ToolCallPayload): HookDecision;
|
|
47
|
+
//# sourceMappingURL=runtime.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../src/hook/runtime.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAEpD;;;;;;;;;;;GAWG;AAEH,MAAM,WAAW,eAAe;IAC9B,gEAAgE;IAChE,IAAI,EAAE,MAAM,CAAC;IACb;2EACuE;IACvE,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,MAAM,aAAa,GAAG;IAAE,QAAQ,EAAE,OAAO,CAAA;CAAE,CAAC;AAElD,MAAM,MAAM,cAAc,GAAG;IAC3B,QAAQ,EAAE,QAAQ,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG,aAAa,GAAG,cAAc,CAAC;AAE1D;;;;;;;;;;;;GAYG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,cAAc,GAAG,MAAM,CAMhE;AA4CD,wBAAgB,YAAY,CAAC,IAAI,EAAE,gBAAgB,EAAE,OAAO,EAAE,eAAe,GAAG,YAAY,CA4B3F"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build the structured rejection message per ADR-104 § Decision 1:
|
|
3
|
+
*
|
|
4
|
+
* [totem:hook-block] <packId>/<ruleId>: <message>
|
|
5
|
+
* → <recoveryHint>
|
|
6
|
+
*
|
|
7
|
+
* The `→ <recoveryHint>` line is omitted when no recoveryHint is provided.
|
|
8
|
+
* Agents and operators grep for the `[totem:hook-block]` prefix; the
|
|
9
|
+
* `<packId>/<ruleId>` carries provenance.
|
|
10
|
+
*
|
|
11
|
+
* Parameter is narrowed to `RejectDecision` so the type system prevents
|
|
12
|
+
* passing an allow decision — no runtime guard needed.
|
|
13
|
+
*/
|
|
14
|
+
export function formatRejection(decision) {
|
|
15
|
+
const header = `[totem:hook-block] ${decision.packId}/${decision.ruleId}: ${decision.message}`;
|
|
16
|
+
if (decision.recoveryHint) {
|
|
17
|
+
return `${header}\n → ${decision.recoveryHint}`;
|
|
18
|
+
}
|
|
19
|
+
return header;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Evaluate a single compiled hook rule against a tool-call payload.
|
|
23
|
+
*
|
|
24
|
+
* Two-stage gate:
|
|
25
|
+
* 1. Trigger gate: does this rule apply to this tool + args?
|
|
26
|
+
* Rule applies when `rule.trigger.tool` equals `payload.tool` AND
|
|
27
|
+
* `rule.trigger.pattern` matches `payload.args`.
|
|
28
|
+
* 2. Check gate: when the trigger matches, apply `rule.check.pattern` to
|
|
29
|
+
* args. `reject-if-match` rejects on match; `reject-if-no-match`
|
|
30
|
+
* rejects on non-match.
|
|
31
|
+
*
|
|
32
|
+
* Returns `{ decision: 'allow' }` when either gate passes the call through.
|
|
33
|
+
*
|
|
34
|
+
* V1 invariant: regex matching only. Future matcher classes (ast-grep,
|
|
35
|
+
* Rego-shadow) ship in V2 follow-on ADRs.
|
|
36
|
+
*
|
|
37
|
+
* Per ADR-104 § Convergence, any `verification_shadow` block on the rule
|
|
38
|
+
* is silently ignored at the runtime layer (V1 hooks are Interpretive
|
|
39
|
+
* Rule class — no formal-verification obligation). Warn-and-ignore of
|
|
40
|
+
* verification_shadow happens at the load layer when compiling pack
|
|
41
|
+
* hooks.yaml, not on every hook-run invocation.
|
|
42
|
+
*/
|
|
43
|
+
/**
|
|
44
|
+
* Memoizes compiled RegExp instances keyed by pattern string. Pack rule
|
|
45
|
+
* patterns are stable for the lifetime of a CLI process (the manifest is
|
|
46
|
+
* loaded once at startup), so a string-keyed cache is sufficient — there
|
|
47
|
+
* is no unbounded-growth concern in the single-shot CLI use case.
|
|
48
|
+
*
|
|
49
|
+
* Safe to memoize because the patterns are compiled with no flags, so the
|
|
50
|
+
* returned RegExp has no stateful `lastIndex` carry-over between `.test()`
|
|
51
|
+
* calls.
|
|
52
|
+
*/
|
|
53
|
+
const regexCache = new Map();
|
|
54
|
+
function getCompiledRegex(pattern) {
|
|
55
|
+
const cached = regexCache.get(pattern);
|
|
56
|
+
if (cached)
|
|
57
|
+
return cached;
|
|
58
|
+
const compiled = new RegExp(pattern);
|
|
59
|
+
regexCache.set(pattern, compiled);
|
|
60
|
+
return compiled;
|
|
61
|
+
}
|
|
62
|
+
export function evaluateHook(rule, payload) {
|
|
63
|
+
if (rule.trigger.tool !== payload.tool) {
|
|
64
|
+
return { decision: 'allow' };
|
|
65
|
+
}
|
|
66
|
+
const triggerRegex = getCompiledRegex(rule.trigger.pattern);
|
|
67
|
+
if (!triggerRegex.test(payload.args)) {
|
|
68
|
+
return { decision: 'allow' };
|
|
69
|
+
}
|
|
70
|
+
const checkRegex = getCompiledRegex(rule.check.pattern);
|
|
71
|
+
const matched = checkRegex.test(payload.args);
|
|
72
|
+
const shouldReject = (rule.check.type === 'reject-if-match' && matched) ||
|
|
73
|
+
(rule.check.type === 'reject-if-no-match' && !matched);
|
|
74
|
+
if (!shouldReject) {
|
|
75
|
+
return { decision: 'allow' };
|
|
76
|
+
}
|
|
77
|
+
return {
|
|
78
|
+
decision: 'reject',
|
|
79
|
+
message: rule.message,
|
|
80
|
+
packId: rule.packId,
|
|
81
|
+
ruleId: rule.id,
|
|
82
|
+
recoveryHint: rule.recoveryHint,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=runtime.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime.js","sourceRoot":"","sources":["../../src/hook/runtime.ts"],"names":[],"mappings":"AAmCA;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,eAAe,CAAC,QAAwB;IACtD,MAAM,MAAM,GAAG,sBAAsB,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,MAAM,KAAK,QAAQ,CAAC,OAAO,EAAE,CAAC;IAC/F,IAAI,QAAQ,CAAC,YAAY,EAAE,CAAC;QAC1B,OAAO,GAAG,MAAM,SAAS,QAAQ,CAAC,YAAY,EAAE,CAAC;IACnD,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH;;;;;;;;;GASG;AACH,MAAM,UAAU,GAAG,IAAI,GAAG,EAAkB,CAAC;AAE7C,SAAS,gBAAgB,CAAC,OAAe;IACvC,MAAM,MAAM,GAAG,UAAU,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IACvC,IAAI,MAAM;QAAE,OAAO,MAAM,CAAC;IAC1B,MAAM,QAAQ,GAAG,IAAI,MAAM,CAAC,OAAO,CAAC,CAAC;IACrC,UAAU,CAAC,GAAG,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IAClC,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,IAAsB,EAAE,OAAwB;IAC3E,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,KAAK,OAAO,CAAC,IAAI,EAAE,CAAC;QACvC,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC;IAC/B,CAAC;IAED,MAAM,YAAY,GAAG,gBAAgB,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IAC5D,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;QACrC,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC;IAC/B,CAAC;IAED,MAAM,UAAU,GAAG,gBAAgB,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IACxD,MAAM,OAAO,GAAG,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAE9C,MAAM,YAAY,GAChB,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,KAAK,iBAAiB,IAAI,OAAO,CAAC;QAClD,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,KAAK,oBAAoB,IAAI,CAAC,OAAO,CAAC,CAAC;IAEzD,IAAI,CAAC,YAAY,EAAE,CAAC;QAClB,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC;IAC/B,CAAC;IAED,OAAO;QACL,QAAQ,EAAE,QAAQ;QAClB,OAAO,EAAE,IAAI,CAAC,OAAO;QACrB,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,MAAM,EAAE,IAAI,CAAC,EAAE;QACf,YAAY,EAAE,IAAI,CAAC,YAAY;KAChC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime.test.d.ts","sourceRoot":"","sources":["../../src/hook/runtime.test.ts"],"names":[],"mappings":""}
|