@mmnto/cli 1.51.0 → 1.53.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/adapters/github-cli-pr.d.ts.map +1 -1
- package/dist/adapters/github-cli-pr.js +3 -1
- package/dist/adapters/github-cli-pr.js.map +1 -1
- package/dist/adapters/github-cli-pr.test.js +4 -4
- package/dist/adapters/github-cli-pr.test.js.map +1 -1
- package/dist/adapters/github-cli-project.d.ts +21 -0
- package/dist/adapters/github-cli-project.d.ts.map +1 -0
- package/dist/adapters/github-cli-project.js +69 -0
- package/dist/adapters/github-cli-project.js.map +1 -0
- package/dist/adapters/github-cli.d.ts +7 -1
- package/dist/adapters/github-cli.d.ts.map +1 -1
- package/dist/adapters/github-cli.js +30 -0
- package/dist/adapters/github-cli.js.map +1 -1
- package/dist/adapters/github-cli.test.js +26 -0
- package/dist/adapters/github-cli.test.js.map +1 -1
- package/dist/adapters/issue-adapter.d.ts +18 -0
- package/dist/adapters/issue-adapter.d.ts.map +1 -1
- package/dist/adapters/pr-adapter.d.ts +2 -0
- package/dist/adapters/pr-adapter.d.ts.map +1 -1
- package/dist/commands/eject.d.ts.map +1 -1
- package/dist/commands/eject.js +12 -4
- package/dist/commands/eject.js.map +1 -1
- package/dist/commands/gate-install.d.ts +59 -0
- package/dist/commands/gate-install.d.ts.map +1 -0
- package/dist/commands/gate-install.js +111 -0
- package/dist/commands/gate-install.js.map +1 -0
- package/dist/commands/gate-install.test.d.ts +2 -0
- package/dist/commands/gate-install.test.d.ts.map +1 -0
- package/dist/commands/gate-install.test.js +472 -0
- package/dist/commands/gate-install.test.js.map +1 -0
- package/dist/commands/gate.d.ts +31 -0
- package/dist/commands/gate.d.ts.map +1 -1
- package/dist/commands/gate.js +70 -0
- package/dist/commands/gate.js.map +1 -1
- package/dist/commands/host-hooks.d.ts +745 -0
- package/dist/commands/host-hooks.d.ts.map +1 -0
- package/dist/commands/host-hooks.js +229 -0
- package/dist/commands/host-hooks.js.map +1 -0
- package/dist/commands/init-templates.d.ts +8 -0
- package/dist/commands/init-templates.d.ts.map +1 -1
- package/dist/commands/init-templates.js +240 -0
- package/dist/commands/init-templates.js.map +1 -1
- package/dist/commands/init.d.ts +6 -4
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +81 -94
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/orient-coherence.d.ts +33 -0
- package/dist/commands/orient-coherence.d.ts.map +1 -0
- package/dist/commands/orient-coherence.js +64 -0
- package/dist/commands/orient-coherence.js.map +1 -0
- package/dist/commands/orient-coherence.test.d.ts +2 -0
- package/dist/commands/orient-coherence.test.d.ts.map +1 -0
- package/dist/commands/orient-coherence.test.js +99 -0
- package/dist/commands/orient-coherence.test.js.map +1 -0
- package/dist/commands/orient.d.ts +67 -0
- package/dist/commands/orient.d.ts.map +1 -0
- package/dist/commands/orient.js +412 -0
- package/dist/commands/orient.js.map +1 -0
- package/dist/commands/orient.test.d.ts +2 -0
- package/dist/commands/orient.test.d.ts.map +1 -0
- package/dist/commands/orient.test.js +329 -0
- package/dist/commands/orient.test.js.map +1 -0
- package/dist/help.js +1 -1
- package/dist/help.js.map +1 -1
- package/dist/index.js +35 -0
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import * as path from 'node:path';
|
|
2
|
+
import { upsertClaudeHookCommand } from './host-hooks.js';
|
|
3
|
+
import { scaffoldFile } from './init.js';
|
|
4
|
+
import { CLAUDE_GATE_WRAPPER, CLAUDE_GATE_WRAPPER_ENTRY, TOTEM_FILE_MARKER, } from './init-templates.js';
|
|
5
|
+
/**
|
|
6
|
+
* Install the parameterized PreToolUse gate wrapper + one PreToolUse entry per
|
|
7
|
+
* named gate into committed `.claude/settings.json` (PR-C, mmnto-ai/totem#2048).
|
|
8
|
+
*
|
|
9
|
+
* Single source of truth for BOTH the `totem gate install` verb and
|
|
10
|
+
* `totem init --gates=` — neither owns a second copy of the merge logic.
|
|
11
|
+
* Thin caller of the extracted `upsertClaudeHookCommand` upsert (host-hooks.ts).
|
|
12
|
+
*
|
|
13
|
+
* Tier-AWARE upsert keyed on the per-gate `--event <name>` identity (which is
|
|
14
|
+
* tier-independent): installing freeze-check twice at the SAME tier is a no-op,
|
|
15
|
+
* installing it at a DIFFERENT tier rewrites the one existing entry's command
|
|
16
|
+
* in place (never a duplicate), and freeze-check + a future second gate produce
|
|
17
|
+
* two distinct entries under the shared `Write|Edit` matcher.
|
|
18
|
+
*
|
|
19
|
+
* `--all` / unknown-gate validation is done by the CALLER against
|
|
20
|
+
* `knownGateEvents()` (the registry is the single source of truth) — this
|
|
21
|
+
* function trusts that `events` are already-validated known events.
|
|
22
|
+
*/
|
|
23
|
+
/** The PreToolUse matcher every gate entry installs under. */
|
|
24
|
+
const GATE_MATCHER = 'Write|Edit';
|
|
25
|
+
/** The wrapper script's repo-relative install path. */
|
|
26
|
+
export const GATE_WRAPPER_REL = '.claude/hooks/gate-wrapper.cjs';
|
|
27
|
+
/** The wrapper script basename — the eject scrub keys on this substring. */
|
|
28
|
+
const GATE_WRAPPER_BASENAME = 'gate-wrapper.cjs';
|
|
29
|
+
/**
|
|
30
|
+
* Collision-safe gate-identity probe: does `command` install the gate for
|
|
31
|
+
* EXACTLY this `event`?
|
|
32
|
+
*
|
|
33
|
+
* Tokenize on whitespace and require BOTH the wrapper basename AND the token
|
|
34
|
+
* immediately after `--event` to equal `event`. A loose substring `includes`
|
|
35
|
+
* would let `--event freeze-check` spuriously match a future
|
|
36
|
+
* `--event freeze-check-extended`. The probe is tier-INDEPENDENT (it ignores
|
|
37
|
+
* the baked `--strict` / `--pilot` flag), so it identifies the single existing
|
|
38
|
+
* entry for a gate REGARDLESS of tier — the upsert then either no-ops (same
|
|
39
|
+
* tier) or rewrites that one entry's command (tier switch), never duplicating.
|
|
40
|
+
*/
|
|
41
|
+
export function commandInstallsGate(command, event) {
|
|
42
|
+
const tokens = command.split(/\s+/).filter((t) => t.length > 0);
|
|
43
|
+
if (!tokens.some((t) => t.includes(GATE_WRAPPER_BASENAME))) {
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
const eventIdx = tokens.indexOf('--event');
|
|
47
|
+
return eventIdx !== -1 && tokens[eventIdx + 1] === event;
|
|
48
|
+
}
|
|
49
|
+
/** Build the baked PreToolUse command string for a gate at a given tier. */
|
|
50
|
+
function gateCommand(event, tier) {
|
|
51
|
+
return `node ${GATE_WRAPPER_REL} --event ${event} --${tier}`;
|
|
52
|
+
}
|
|
53
|
+
/** Build the PreToolUse entry for a single gate (one wrapper, N gates). */
|
|
54
|
+
function gateEntry(event, tier) {
|
|
55
|
+
return {
|
|
56
|
+
matcher: CLAUDE_GATE_WRAPPER_ENTRY.matcher,
|
|
57
|
+
hooks: [
|
|
58
|
+
{
|
|
59
|
+
type: CLAUDE_GATE_WRAPPER_ENTRY.hooks[0].type,
|
|
60
|
+
command: gateCommand(event, tier),
|
|
61
|
+
},
|
|
62
|
+
],
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Install the gate wrapper script + one PreToolUse entry per `event` into the
|
|
67
|
+
* given repo `cwd`. Returns one result per filesystem operation (the wrapper
|
|
68
|
+
* scaffold, then one entry merge per gate) for caller-side summary reporting.
|
|
69
|
+
*
|
|
70
|
+
* `tier` (default `'strict'`) is BAKED into the installed command string at
|
|
71
|
+
* install time — the wrapper reads it ONLY from argv (no env-var override), so
|
|
72
|
+
* a default install is enforcement-immune to a consumer's environment. `pilot`
|
|
73
|
+
* is an explicit install-time opt-in.
|
|
74
|
+
*
|
|
75
|
+
* `events` MUST already be validated against `knownGateEvents()` by the
|
|
76
|
+
* caller (the verb / `--gates=` parser) — no default-install, fail-loud on
|
|
77
|
+
* unknown happens upstream.
|
|
78
|
+
*/
|
|
79
|
+
export function installGates(cwd, events, tier = 'strict') {
|
|
80
|
+
const results = [];
|
|
81
|
+
const settingsPath = path.join(cwd, '.claude', 'settings.json');
|
|
82
|
+
// 1. Scaffold the ONE parameterized wrapper script (idempotent; marker-keyed).
|
|
83
|
+
// scaffoldFile returns 'exists' when a marker-bearing Totem file is already
|
|
84
|
+
// present (the idempotent re-run case); normalize that to 'skipped' so the
|
|
85
|
+
// GateInstallResult.action stays within created|merged|skipped (both mean
|
|
86
|
+
// "no write happened, no change") — see GateInstallResult below.
|
|
87
|
+
const wrapperPath = path.join(cwd, '.claude', 'hooks', 'gate-wrapper.cjs');
|
|
88
|
+
const wrapperResult = scaffoldFile(wrapperPath, CLAUDE_GATE_WRAPPER, TOTEM_FILE_MARKER);
|
|
89
|
+
results.push({
|
|
90
|
+
file: GATE_WRAPPER_REL,
|
|
91
|
+
action: wrapperResult.action === 'exists' ? 'skipped' : wrapperResult.action,
|
|
92
|
+
err: wrapperResult.err,
|
|
93
|
+
});
|
|
94
|
+
// 2. Tier-AWARE upsert of one PreToolUse entry per gate. The gate-identity
|
|
95
|
+
// probe matches the EXACT --event token (collision-safe and
|
|
96
|
+
// tier-independent), so the upsert keeps EXACTLY ONE entry per gate:
|
|
97
|
+
// a same-tier re-run is a no-op (`skipped`), a different-tier re-install
|
|
98
|
+
// rewrites that entry's command in place (`updated`), and a NEW gate adds
|
|
99
|
+
// a second distinct entry (`merged`).
|
|
100
|
+
for (const event of events) {
|
|
101
|
+
const entryResult = upsertClaudeHookCommand(settingsPath, GATE_MATCHER, gateEntry(event, tier), (cmd) => commandInstallsGate(cmd, event));
|
|
102
|
+
results.push({
|
|
103
|
+
file: '.claude/settings.json',
|
|
104
|
+
action: entryResult.action,
|
|
105
|
+
event,
|
|
106
|
+
err: entryResult.err,
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
return results;
|
|
110
|
+
}
|
|
111
|
+
//# sourceMappingURL=gate-install.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gate-install.js","sourceRoot":"","sources":["../../src/commands/gate-install.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gate-install.test.d.ts","sourceRoot":"","sources":["../../src/commands/gate-install.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,472 @@
|
|
|
1
|
+
import { spawnSync } from 'node:child_process';
|
|
2
|
+
import * as fs from 'node:fs';
|
|
3
|
+
import * as os from 'node:os';
|
|
4
|
+
import * as path from 'node:path';
|
|
5
|
+
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
|
|
6
|
+
import { knownGateEvents, TotemError } from '@mmnto/totem';
|
|
7
|
+
import { ejectCommand } from './eject.js';
|
|
8
|
+
import { gateInstallCommand, resolveGateEvents } from './gate.js';
|
|
9
|
+
import { commandInstallsGate, GATE_WRAPPER_REL, installGates } from './gate-install.js';
|
|
10
|
+
import { initCommand } from './init.js';
|
|
11
|
+
import { CLAUDE_GATE_WRAPPER } from './init-templates.js';
|
|
12
|
+
/**
|
|
13
|
+
* CLI-seam tests for `totem gate install` + the parameterized gate wrapper
|
|
14
|
+
* (PR-C, mmnto-ai/totem#2048).
|
|
15
|
+
*
|
|
16
|
+
* Locks the invariants in spec 2048.md §"Invariants the tests lock":
|
|
17
|
+
* - idempotent merge (re-run is a no-op)
|
|
18
|
+
* - `--all` enumerates `knownGateEvents()`; unknown `--<name>` / `--gates=`
|
|
19
|
+
* member fails loud (no default-install)
|
|
20
|
+
* - the wrapper's disposition → exit-code map, including the LOAD-BEARING
|
|
21
|
+
* empty-subsystem pass-through and the applicable-gate-source-broken
|
|
22
|
+
* fail-closed
|
|
23
|
+
* - `eject` removes the gate entry (parity with install)
|
|
24
|
+
* - `init --gates=` routes through the SAME installer as the verb
|
|
25
|
+
*
|
|
26
|
+
* The engine itself (allow/deny/no-file/side-effect-free) is covered by
|
|
27
|
+
* `@mmnto/totem`'s gate-engine.test.ts and is NOT duplicated here.
|
|
28
|
+
*/
|
|
29
|
+
function makeTmpDir() {
|
|
30
|
+
// `.native` expands Windows 8.3 short names so process.cwd()/realpath agree.
|
|
31
|
+
return fs.realpathSync.native(fs.mkdtempSync(path.join(os.tmpdir(), 'totem-gate-install-')));
|
|
32
|
+
}
|
|
33
|
+
function readSettings(cwd) {
|
|
34
|
+
const raw = fs.readFileSync(path.join(cwd, '.claude', 'settings.json'), 'utf-8');
|
|
35
|
+
return JSON.parse(raw);
|
|
36
|
+
}
|
|
37
|
+
function preToolUseEntries(cwd) {
|
|
38
|
+
const parsed = readSettings(cwd);
|
|
39
|
+
const hooks = (parsed.hooks ?? {});
|
|
40
|
+
return (hooks.PreToolUse ?? []);
|
|
41
|
+
}
|
|
42
|
+
/** Count Write|Edit PreToolUse entries whose command references a given gate. */
|
|
43
|
+
function gateEntryCount(cwd, event) {
|
|
44
|
+
return preToolUseEntries(cwd).filter((e) => e.matcher === 'Write|Edit' &&
|
|
45
|
+
Array.isArray(e.hooks) &&
|
|
46
|
+
e.hooks.some((h) => {
|
|
47
|
+
const cmd = typeof h === 'string' ? h : (h?.command ?? '');
|
|
48
|
+
// Collision-safe exact --event match (tier-independent).
|
|
49
|
+
return commandInstallsGate(cmd, event);
|
|
50
|
+
})).length;
|
|
51
|
+
}
|
|
52
|
+
/** The single baked command string for a gate (or undefined if none/many). */
|
|
53
|
+
function gateCommandFor(cwd, event) {
|
|
54
|
+
const cmds = [];
|
|
55
|
+
for (const e of preToolUseEntries(cwd)) {
|
|
56
|
+
if (e.matcher !== 'Write|Edit' || !Array.isArray(e.hooks))
|
|
57
|
+
continue;
|
|
58
|
+
for (const h of e.hooks) {
|
|
59
|
+
const cmd = typeof h === 'string' ? h : (h?.command ?? '');
|
|
60
|
+
if (commandInstallsGate(cmd, event))
|
|
61
|
+
cmds.push(cmd);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return cmds.length === 1 ? cmds[0] : undefined;
|
|
65
|
+
}
|
|
66
|
+
describe('installGates / gate install (settings merge)', () => {
|
|
67
|
+
let cwd;
|
|
68
|
+
let originalCwd;
|
|
69
|
+
beforeEach(() => {
|
|
70
|
+
cwd = makeTmpDir();
|
|
71
|
+
originalCwd = process.cwd();
|
|
72
|
+
process.chdir(cwd);
|
|
73
|
+
});
|
|
74
|
+
afterEach(() => {
|
|
75
|
+
process.chdir(originalCwd);
|
|
76
|
+
fs.rmSync(cwd, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 });
|
|
77
|
+
});
|
|
78
|
+
it('scaffolds the wrapper and merges one PreToolUse entry per gate', () => {
|
|
79
|
+
const results = installGates(cwd, ['freeze-check']);
|
|
80
|
+
// wrapper scaffold + one entry merge
|
|
81
|
+
expect(results.some((r) => r.file === GATE_WRAPPER_REL && r.action === 'created')).toBe(true);
|
|
82
|
+
expect(fs.existsSync(path.join(cwd, '.claude', 'hooks', 'gate-wrapper.cjs'))).toBe(true);
|
|
83
|
+
expect(gateEntryCount(cwd, 'freeze-check')).toBe(1);
|
|
84
|
+
});
|
|
85
|
+
it('is idempotent: a second install of the same gate is a no-op', () => {
|
|
86
|
+
installGates(cwd, ['freeze-check']);
|
|
87
|
+
const before = JSON.stringify(readSettings(cwd));
|
|
88
|
+
const second = installGates(cwd, ['freeze-check']);
|
|
89
|
+
const entryResult = second.find((r) => r.event === 'freeze-check');
|
|
90
|
+
expect(entryResult?.action).toBe('skipped');
|
|
91
|
+
expect(gateEntryCount(cwd, 'freeze-check')).toBe(1);
|
|
92
|
+
expect(JSON.stringify(readSettings(cwd))).toBe(before);
|
|
93
|
+
});
|
|
94
|
+
it('keys idempotency on the per-gate command substring (distinct gates → distinct entries)', () => {
|
|
95
|
+
// freeze-check installed; a hypothetical future gate keyed on a different
|
|
96
|
+
// --event substring produces a SECOND entry rather than colliding.
|
|
97
|
+
installGates(cwd, ['freeze-check']);
|
|
98
|
+
installGates(cwd, ['some-future-gate']);
|
|
99
|
+
expect(gateEntryCount(cwd, 'freeze-check')).toBe(1);
|
|
100
|
+
expect(gateEntryCount(cwd, 'some-future-gate')).toBe(1);
|
|
101
|
+
// Two distinct Write|Edit gate entries under one matcher.
|
|
102
|
+
const gateEntries = preToolUseEntries(cwd).filter((e) => e.matcher === 'Write|Edit' &&
|
|
103
|
+
Array.isArray(e.hooks) &&
|
|
104
|
+
e.hooks.some((h) => {
|
|
105
|
+
const cmd = typeof h === 'string' ? h : (h?.command ?? '');
|
|
106
|
+
return cmd.includes('gate-wrapper.cjs --event ');
|
|
107
|
+
}));
|
|
108
|
+
expect(gateEntries.length).toBe(2);
|
|
109
|
+
});
|
|
110
|
+
it('preserves a pre-existing user PreToolUse entry when merging', () => {
|
|
111
|
+
fs.mkdirSync(path.join(cwd, '.claude'), { recursive: true });
|
|
112
|
+
fs.writeFileSync(path.join(cwd, '.claude', 'settings.json'), JSON.stringify({
|
|
113
|
+
hooks: {
|
|
114
|
+
PreToolUse: [{ matcher: 'Bash', hooks: [{ type: 'command', command: 'my-hook' }] }],
|
|
115
|
+
},
|
|
116
|
+
}));
|
|
117
|
+
installGates(cwd, ['freeze-check']);
|
|
118
|
+
const entries = preToolUseEntries(cwd);
|
|
119
|
+
expect(entries.some((e) => e.matcher === 'Bash')).toBe(true);
|
|
120
|
+
expect(gateEntryCount(cwd, 'freeze-check')).toBe(1);
|
|
121
|
+
});
|
|
122
|
+
it('gateInstallCommand --all installs every known gate', async () => {
|
|
123
|
+
await gateInstallCommand({ all: true });
|
|
124
|
+
for (const event of knownGateEvents()) {
|
|
125
|
+
expect(gateEntryCount(cwd, event)).toBe(1);
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
// ─── FIX A: tier-AWARE upsert (update in place, never silent no-op/dup) ──
|
|
130
|
+
//
|
|
131
|
+
// Locks the tier-update behavior so it can never regress to either failure
|
|
132
|
+
// mode the pre-fix tier-INDEPENDENT probe had: (a) a tier switch silently
|
|
133
|
+
// dropped as a "skipped — no change" no-op, or (b) a second duplicate entry
|
|
134
|
+
// for the same gate. The invariant: EXACTLY ONE entry per gate, ever, and the
|
|
135
|
+
// baked tier flag flips in place on a different-tier re-install.
|
|
136
|
+
describe('installGates tier-aware upsert (FIX A)', () => {
|
|
137
|
+
let cwd;
|
|
138
|
+
let originalCwd;
|
|
139
|
+
beforeEach(() => {
|
|
140
|
+
cwd = makeTmpDir();
|
|
141
|
+
originalCwd = process.cwd();
|
|
142
|
+
process.chdir(cwd);
|
|
143
|
+
});
|
|
144
|
+
afterEach(() => {
|
|
145
|
+
process.chdir(originalCwd);
|
|
146
|
+
fs.rmSync(cwd, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 });
|
|
147
|
+
});
|
|
148
|
+
it('default(strict) then re-install --strict → skipped, one entry, command keeps --strict', () => {
|
|
149
|
+
installGates(cwd, ['freeze-check']); // default tier === strict
|
|
150
|
+
const second = installGates(cwd, ['freeze-check'], 'strict');
|
|
151
|
+
const entryResult = second.find((r) => r.event === 'freeze-check');
|
|
152
|
+
expect(entryResult?.action).toBe('skipped');
|
|
153
|
+
expect(gateEntryCount(cwd, 'freeze-check')).toBe(1);
|
|
154
|
+
expect(gateCommandFor(cwd, 'freeze-check')).toContain('--strict');
|
|
155
|
+
});
|
|
156
|
+
it('--pilot then --strict → updated, ONE entry, command flips to --strict (not --pilot)', () => {
|
|
157
|
+
installGates(cwd, ['freeze-check'], 'pilot');
|
|
158
|
+
expect(gateCommandFor(cwd, 'freeze-check')).toContain('--pilot');
|
|
159
|
+
const switched = installGates(cwd, ['freeze-check'], 'strict');
|
|
160
|
+
const entryResult = switched.find((r) => r.event === 'freeze-check');
|
|
161
|
+
expect(entryResult?.action).toBe('updated');
|
|
162
|
+
// Exactly one entry — no duplicate created by the tier switch.
|
|
163
|
+
expect(gateEntryCount(cwd, 'freeze-check')).toBe(1);
|
|
164
|
+
const cmd = gateCommandFor(cwd, 'freeze-check');
|
|
165
|
+
expect(cmd).toContain('--strict');
|
|
166
|
+
expect(cmd).not.toContain('--pilot');
|
|
167
|
+
});
|
|
168
|
+
it('--strict then --pilot → updated back to --pilot, one entry', () => {
|
|
169
|
+
installGates(cwd, ['freeze-check'], 'strict');
|
|
170
|
+
const switched = installGates(cwd, ['freeze-check'], 'pilot');
|
|
171
|
+
const entryResult = switched.find((r) => r.event === 'freeze-check');
|
|
172
|
+
expect(entryResult?.action).toBe('updated');
|
|
173
|
+
expect(gateEntryCount(cwd, 'freeze-check')).toBe(1);
|
|
174
|
+
const cmd = gateCommandFor(cwd, 'freeze-check');
|
|
175
|
+
expect(cmd).toContain('--pilot');
|
|
176
|
+
expect(cmd).not.toContain('--strict');
|
|
177
|
+
});
|
|
178
|
+
it('init --gates= routes the tier through the same upsert (default then --pilot re-init)', async () => {
|
|
179
|
+
// First init at default (strict).
|
|
180
|
+
await initCommand({ bare: true, gates: 'freeze-check' });
|
|
181
|
+
expect(gateEntryCount(cwd, 'freeze-check')).toBe(1);
|
|
182
|
+
expect(gateCommandFor(cwd, 'freeze-check')).toContain('--strict');
|
|
183
|
+
// Re-init with --pilot → routes through the same installGates upsert:
|
|
184
|
+
// one entry at the right (pilot) tier, NOT a duplicate.
|
|
185
|
+
await initCommand({ bare: true, gates: 'freeze-check', pilot: true });
|
|
186
|
+
expect(gateEntryCount(cwd, 'freeze-check')).toBe(1);
|
|
187
|
+
const cmd = gateCommandFor(cwd, 'freeze-check');
|
|
188
|
+
expect(cmd).toContain('--pilot');
|
|
189
|
+
expect(cmd).not.toContain('--strict');
|
|
190
|
+
});
|
|
191
|
+
it('coexists with a pre-existing PreWriteShield Write|Edit entry (the post-init layout)', () => {
|
|
192
|
+
// Realistic post-`totem init` state: a PreWriteShield hook already sits in
|
|
193
|
+
// committed settings.json under the SAME 'Write|Edit' matcher the gate uses.
|
|
194
|
+
// The upsert must install the gate as a DISTINCT entry and, on a tier
|
|
195
|
+
// switch, update ONLY the gate entry — never touching PreWriteShield.
|
|
196
|
+
fs.mkdirSync(path.join(cwd, '.claude'), { recursive: true });
|
|
197
|
+
const shieldCommand = 'node .claude/hooks/PreWriteShield.cjs';
|
|
198
|
+
fs.writeFileSync(path.join(cwd, '.claude', 'settings.json'), JSON.stringify({
|
|
199
|
+
hooks: {
|
|
200
|
+
PreToolUse: [
|
|
201
|
+
{ matcher: 'Write|Edit', hooks: [{ type: 'command', command: shieldCommand }] },
|
|
202
|
+
],
|
|
203
|
+
},
|
|
204
|
+
}));
|
|
205
|
+
const hasShield = () => preToolUseEntries(cwd).some((e) => e.matcher === 'Write|Edit' &&
|
|
206
|
+
Array.isArray(e.hooks) &&
|
|
207
|
+
e.hooks.some((h) => {
|
|
208
|
+
const c = typeof h === 'string' ? h : (h?.command ?? '');
|
|
209
|
+
return c === shieldCommand;
|
|
210
|
+
}));
|
|
211
|
+
// Install the gate at pilot → a distinct second Write|Edit entry.
|
|
212
|
+
installGates(cwd, ['freeze-check'], 'pilot');
|
|
213
|
+
expect(gateEntryCount(cwd, 'freeze-check')).toBe(1);
|
|
214
|
+
expect(gateCommandFor(cwd, 'freeze-check')).toContain('--pilot');
|
|
215
|
+
expect(hasShield()).toBe(true);
|
|
216
|
+
expect(preToolUseEntries(cwd).filter((e) => e.matcher === 'Write|Edit').length).toBe(2);
|
|
217
|
+
// Tier switch → updates ONLY the gate entry in place; PreWriteShield stays.
|
|
218
|
+
const switched = installGates(cwd, ['freeze-check'], 'strict');
|
|
219
|
+
expect(switched.find((r) => r.event === 'freeze-check')?.action).toBe('updated');
|
|
220
|
+
expect(gateEntryCount(cwd, 'freeze-check')).toBe(1);
|
|
221
|
+
const cmd2 = gateCommandFor(cwd, 'freeze-check');
|
|
222
|
+
expect(cmd2).toContain('--strict');
|
|
223
|
+
expect(cmd2).not.toContain('--pilot');
|
|
224
|
+
expect(hasShield()).toBe(true);
|
|
225
|
+
expect(preToolUseEntries(cwd).filter((e) => e.matcher === 'Write|Edit').length).toBe(2);
|
|
226
|
+
});
|
|
227
|
+
});
|
|
228
|
+
describe('resolveGateEvents (registry-driven validation)', () => {
|
|
229
|
+
it('--all enumerates knownGateEvents()', async () => {
|
|
230
|
+
expect(await resolveGateEvents({ all: true })).toEqual(knownGateEvents());
|
|
231
|
+
});
|
|
232
|
+
it('a known --<name> resolves to itself', async () => {
|
|
233
|
+
expect(await resolveGateEvents({ name: 'freeze-check' })).toEqual(['freeze-check']);
|
|
234
|
+
});
|
|
235
|
+
it('an unknown --<name> fails loud (never default-install)', async () => {
|
|
236
|
+
await expect(resolveGateEvents({ name: 'made-up-gate' })).rejects.toBeInstanceOf(TotemError);
|
|
237
|
+
await expect(resolveGateEvents({ name: 'made-up-gate' })).rejects.toThrow(/unknown gate/i);
|
|
238
|
+
});
|
|
239
|
+
it('no --all and no --<name> fails loud (no default-install)', async () => {
|
|
240
|
+
await expect(resolveGateEvents({})).rejects.toThrow(/no gate selected/i);
|
|
241
|
+
});
|
|
242
|
+
});
|
|
243
|
+
// ─── The parameterized wrapper's disposition → exit-code map ───────────
|
|
244
|
+
//
|
|
245
|
+
// We render the wrapper template to a temp dir and drive it via stdin with
|
|
246
|
+
// synthetic PreToolUse envelopes. A stub `node_modules/@mmnto/cli/dist/index.js`
|
|
247
|
+
// stands in for the local CLI: it echoes a verdict / exit code driven by env
|
|
248
|
+
// vars so the test controls each disposition deterministically WITHOUT the
|
|
249
|
+
// real engine (the engine is covered by gate-engine.test.ts).
|
|
250
|
+
describe('gate-wrapper.cjs disposition → exit code', () => {
|
|
251
|
+
let cwd;
|
|
252
|
+
beforeEach(() => {
|
|
253
|
+
cwd = makeTmpDir();
|
|
254
|
+
// Render the wrapper exactly as `installGates` would.
|
|
255
|
+
fs.mkdirSync(path.join(cwd, '.claude', 'hooks'), { recursive: true });
|
|
256
|
+
fs.writeFileSync(path.join(cwd, '.claude', 'hooks', 'gate-wrapper.cjs'), CLAUDE_GATE_WRAPPER);
|
|
257
|
+
});
|
|
258
|
+
afterEach(() => {
|
|
259
|
+
fs.rmSync(cwd, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 });
|
|
260
|
+
});
|
|
261
|
+
/** Install a stub local CLI that emits a controlled verdict / exit code. */
|
|
262
|
+
function writeStubCli(opts) {
|
|
263
|
+
const distDir = path.join(cwd, 'node_modules', '@mmnto', 'cli', 'dist');
|
|
264
|
+
fs.mkdirSync(distDir, { recursive: true });
|
|
265
|
+
const verdictJson = opts.verdict === undefined ? '' : JSON.stringify(opts.verdict);
|
|
266
|
+
const exitCode = opts.exit ?? 0;
|
|
267
|
+
// CommonJS stub (the wrapper invokes via `node <path>`); .js is fine here
|
|
268
|
+
// because there is no package.json type:module in the temp dir.
|
|
269
|
+
const stub = [
|
|
270
|
+
'"use strict";',
|
|
271
|
+
`const out = ${JSON.stringify(verdictJson)};`,
|
|
272
|
+
'if (out) process.stdout.write(out + "\\n");',
|
|
273
|
+
`process.exit(${exitCode});`,
|
|
274
|
+
'',
|
|
275
|
+
].join('\n');
|
|
276
|
+
fs.writeFileSync(path.join(distDir, 'index.js'), stub);
|
|
277
|
+
}
|
|
278
|
+
/** Run the rendered wrapper with the given envelope + baked extra args. */
|
|
279
|
+
function runWrapper(envelope, extraArgs = []) {
|
|
280
|
+
const wrapperPath = path.join(cwd, '.claude', 'hooks', 'gate-wrapper.cjs');
|
|
281
|
+
const res = spawnSync(process.execPath, [wrapperPath, '--event', 'freeze-check', ...extraArgs], {
|
|
282
|
+
cwd,
|
|
283
|
+
input: JSON.stringify(envelope),
|
|
284
|
+
encoding: 'utf-8',
|
|
285
|
+
timeout: 30000,
|
|
286
|
+
});
|
|
287
|
+
return { status: res.status, stderr: res.stderr ?? '' };
|
|
288
|
+
}
|
|
289
|
+
const EDIT_NO_SUBSYSTEM = { tool_name: 'Edit', tool_input: { file_path: 'src/foo.ts' } };
|
|
290
|
+
const DECLARED = { tool_name: 'Edit', tool_input: { subsystem: 'rule-compilation' } };
|
|
291
|
+
it('allow → exit 0 (silent)', () => {
|
|
292
|
+
writeStubCli({ verdict: { disposition: 'allow', reason: 'ok', provenance: {} }, exit: 0 });
|
|
293
|
+
const { status } = runWrapper(DECLARED);
|
|
294
|
+
expect(status).toBe(0);
|
|
295
|
+
});
|
|
296
|
+
it('warn → exit 0 + reason/provenance to stderr (advisory, never blocks)', () => {
|
|
297
|
+
writeStubCli({
|
|
298
|
+
verdict: { disposition: 'warn', reason: 'heads up', provenance: { source: 's' } },
|
|
299
|
+
exit: 0,
|
|
300
|
+
});
|
|
301
|
+
const { status, stderr } = runWrapper(DECLARED);
|
|
302
|
+
expect(status).toBe(0);
|
|
303
|
+
expect(stderr).toMatch(/warn/i);
|
|
304
|
+
expect(stderr).toContain('heads up');
|
|
305
|
+
});
|
|
306
|
+
it('deny → exit 2 under --strict (default) + stderr', () => {
|
|
307
|
+
writeStubCli({
|
|
308
|
+
verdict: { disposition: 'deny', reason: 'frozen', provenance: { matched: 'x' } },
|
|
309
|
+
exit: 0,
|
|
310
|
+
});
|
|
311
|
+
const { status, stderr } = runWrapper(DECLARED);
|
|
312
|
+
expect(status).toBe(2);
|
|
313
|
+
expect(stderr).toContain('frozen');
|
|
314
|
+
});
|
|
315
|
+
it('deny → exit 0 under --pilot + stderr (advisory tier)', () => {
|
|
316
|
+
writeStubCli({
|
|
317
|
+
verdict: { disposition: 'deny', reason: 'frozen', provenance: {} },
|
|
318
|
+
exit: 0,
|
|
319
|
+
});
|
|
320
|
+
const { status, stderr } = runWrapper(DECLARED, ['--pilot']);
|
|
321
|
+
expect(status).toBe(0);
|
|
322
|
+
expect(stderr).toContain('frozen');
|
|
323
|
+
});
|
|
324
|
+
it('no-declared-subsystem Edit → exit 0 pass-through (gate NOT invoked)', () => {
|
|
325
|
+
// Stub emits a DENY; if the wrapper invoked it, exit would be 2. The
|
|
326
|
+
// empty-subsystem guardrail must short-circuit to exit 0 WITHOUT shelling
|
|
327
|
+
// out (LOAD-BEARING: protects every ordinary edit from being blocked).
|
|
328
|
+
writeStubCli({ verdict: { disposition: 'deny', reason: 'should not run', provenance: {} } });
|
|
329
|
+
const { status } = runWrapper(EDIT_NO_SUBSYSTEM);
|
|
330
|
+
expect(status).toBe(0);
|
|
331
|
+
});
|
|
332
|
+
it('applicable-gate-source-broken (non-zero gate check) → exit 2 fail-closed', () => {
|
|
333
|
+
// A declared subsystem IS present (gate applies) and `gate check` exits
|
|
334
|
+
// non-zero (corrupt freeze.json etc.) → fail-closed block.
|
|
335
|
+
writeStubCli({ exit: 1 });
|
|
336
|
+
const { status, stderr } = runWrapper(DECLARED);
|
|
337
|
+
expect(status).toBe(2);
|
|
338
|
+
expect(stderr).toMatch(/fail-closed/i);
|
|
339
|
+
});
|
|
340
|
+
it('malformed stdin envelope → exit 0 fail-soft', () => {
|
|
341
|
+
writeStubCli({ verdict: { disposition: 'deny' } });
|
|
342
|
+
const wrapperPath = path.join(cwd, '.claude', 'hooks', 'gate-wrapper.cjs');
|
|
343
|
+
const res = spawnSync(process.execPath, [wrapperPath, '--event', 'freeze-check'], {
|
|
344
|
+
cwd,
|
|
345
|
+
input: '{ not valid json',
|
|
346
|
+
encoding: 'utf-8',
|
|
347
|
+
timeout: 30000,
|
|
348
|
+
});
|
|
349
|
+
expect(res.status).toBe(0);
|
|
350
|
+
});
|
|
351
|
+
// ─── FIX 2: applicable gate but no local CLI dist → fail-closed ────────
|
|
352
|
+
it('applicable gate but the local CLI dist is missing → exit 2 fail-closed (FIX 2)', () => {
|
|
353
|
+
// Deliberately do NOT write the stub CLI. A declared subsystem makes the
|
|
354
|
+
// gate APPLY, but @mmnto/cli is not resolvable. freeze-check has no
|
|
355
|
+
// commit-time hard floor, so an applicable-but-unevaluable gate must fail
|
|
356
|
+
// closed (exit 2) rather than silently allow (exit 0).
|
|
357
|
+
const { status, stderr } = runWrapper(DECLARED);
|
|
358
|
+
expect(status).toBe(2);
|
|
359
|
+
expect(stderr).toMatch(/not resolvable|not installed|failing closed/i);
|
|
360
|
+
});
|
|
361
|
+
it('gate check exits 0 with unparseable stdout → exit 2 fail-closed', () => {
|
|
362
|
+
// verdict undefined → stub emits nothing; the wrapper cannot parse a
|
|
363
|
+
// verdict from a 0-exit gate → fail-closed.
|
|
364
|
+
writeStubCli({ verdict: undefined, exit: 0 });
|
|
365
|
+
const { status, stderr } = runWrapper(DECLARED);
|
|
366
|
+
expect(status).toBe(2);
|
|
367
|
+
expect(stderr).toMatch(/unparseable|parse/i);
|
|
368
|
+
});
|
|
369
|
+
it('well-formed verdict with an unknown disposition → exit 2 fail-closed', () => {
|
|
370
|
+
writeStubCli({ verdict: { disposition: 'bogus', reason: 'x', provenance: {} }, exit: 0 });
|
|
371
|
+
const { status, stderr } = runWrapper(DECLARED);
|
|
372
|
+
expect(status).toBe(2);
|
|
373
|
+
expect(stderr).toMatch(/unknown disposition/i);
|
|
374
|
+
});
|
|
375
|
+
// ─── FIX 3: valid JSON but non-object stdin → fail-soft ────────────────
|
|
376
|
+
it('stdin is valid JSON but non-object (the bytes `null`) → exit 0 fail-soft (FIX 3)', () => {
|
|
377
|
+
writeStubCli({ verdict: { disposition: 'deny' } });
|
|
378
|
+
const wrapperPath = path.join(cwd, '.claude', 'hooks', 'gate-wrapper.cjs');
|
|
379
|
+
const res = spawnSync(process.execPath, [wrapperPath, '--event', 'freeze-check'], {
|
|
380
|
+
cwd,
|
|
381
|
+
input: 'null',
|
|
382
|
+
encoding: 'utf-8',
|
|
383
|
+
timeout: 30000,
|
|
384
|
+
});
|
|
385
|
+
expect(res.status).toBe(0);
|
|
386
|
+
});
|
|
387
|
+
});
|
|
388
|
+
// ─── eject parity ──────────────────────────────────────────────────────
|
|
389
|
+
describe('eject removes the gate entry (parity with install)', () => {
|
|
390
|
+
let cwd;
|
|
391
|
+
let originalCwd;
|
|
392
|
+
beforeEach(() => {
|
|
393
|
+
cwd = makeTmpDir();
|
|
394
|
+
originalCwd = process.cwd();
|
|
395
|
+
process.chdir(cwd);
|
|
396
|
+
fs.mkdirSync(path.join(cwd, '.git', 'hooks'), { recursive: true });
|
|
397
|
+
});
|
|
398
|
+
afterEach(() => {
|
|
399
|
+
process.chdir(originalCwd);
|
|
400
|
+
fs.rmSync(cwd, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 });
|
|
401
|
+
});
|
|
402
|
+
it('scrubs the gate PreToolUse entry and the wrapper script on eject', async () => {
|
|
403
|
+
installGates(cwd, ['freeze-check']);
|
|
404
|
+
expect(gateEntryCount(cwd, 'freeze-check')).toBe(1);
|
|
405
|
+
expect(fs.existsSync(path.join(cwd, '.claude', 'hooks', 'gate-wrapper.cjs'))).toBe(true);
|
|
406
|
+
await ejectCommand({ force: true });
|
|
407
|
+
expect(fs.existsSync(path.join(cwd, '.claude', 'hooks', 'gate-wrapper.cjs'))).toBe(false);
|
|
408
|
+
// Settings file may be removed entirely (if it only held the gate entry)
|
|
409
|
+
// or scrubbed of the gate entry — either way no gate entry survives.
|
|
410
|
+
if (fs.existsSync(path.join(cwd, '.claude', 'settings.json'))) {
|
|
411
|
+
expect(gateEntryCount(cwd, 'freeze-check')).toBe(0);
|
|
412
|
+
}
|
|
413
|
+
});
|
|
414
|
+
it('preserves a user PreToolUse entry while scrubbing the gate entry', async () => {
|
|
415
|
+
fs.mkdirSync(path.join(cwd, '.claude'), { recursive: true });
|
|
416
|
+
fs.writeFileSync(path.join(cwd, '.claude', 'settings.json'), JSON.stringify({
|
|
417
|
+
hooks: { PreToolUse: [{ matcher: 'Bash', hooks: [{ type: 'command', command: 'mine' }] }] },
|
|
418
|
+
}));
|
|
419
|
+
installGates(cwd, ['freeze-check']);
|
|
420
|
+
await ejectCommand({ force: true });
|
|
421
|
+
expect(fs.existsSync(path.join(cwd, '.claude', 'settings.json'))).toBe(true);
|
|
422
|
+
const entries = preToolUseEntries(cwd);
|
|
423
|
+
expect(entries.some((e) => e.matcher === 'Bash')).toBe(true);
|
|
424
|
+
expect(gateEntryCount(cwd, 'freeze-check')).toBe(0);
|
|
425
|
+
});
|
|
426
|
+
});
|
|
427
|
+
// ─── init --gates= routes through the SAME installer ───────────────────
|
|
428
|
+
describe('init --gates= routes through the shared installer', () => {
|
|
429
|
+
let cwd;
|
|
430
|
+
let originalCwd;
|
|
431
|
+
beforeEach(() => {
|
|
432
|
+
cwd = makeTmpDir();
|
|
433
|
+
originalCwd = process.cwd();
|
|
434
|
+
process.chdir(cwd);
|
|
435
|
+
});
|
|
436
|
+
afterEach(() => {
|
|
437
|
+
process.chdir(originalCwd);
|
|
438
|
+
fs.rmSync(cwd, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 });
|
|
439
|
+
});
|
|
440
|
+
it('init --gates=freeze-check installs the same entry installGates would', async () => {
|
|
441
|
+
await initCommand({ bare: true, gates: 'freeze-check' });
|
|
442
|
+
expect(gateEntryCount(cwd, 'freeze-check')).toBe(1);
|
|
443
|
+
expect(fs.existsSync(path.join(cwd, '.claude', 'hooks', 'gate-wrapper.cjs'))).toBe(true);
|
|
444
|
+
});
|
|
445
|
+
it('init --gates=all installs every known gate', async () => {
|
|
446
|
+
await initCommand({ bare: true, gates: 'all' });
|
|
447
|
+
for (const event of knownGateEvents()) {
|
|
448
|
+
expect(gateEntryCount(cwd, event)).toBe(1);
|
|
449
|
+
}
|
|
450
|
+
});
|
|
451
|
+
it('init --gates= with an unknown member fails loud', async () => {
|
|
452
|
+
await expect(initCommand({ bare: true, gates: 'made-up-gate' })).rejects.toThrow(/unknown gate/i);
|
|
453
|
+
});
|
|
454
|
+
// ─── FIX 4: empty --gates= selection fails loud, installs nothing ──────
|
|
455
|
+
it('init --gates=, (empty after parse) throws GATE_INVALID and writes no gate wrapper/entry', async () => {
|
|
456
|
+
const err = await initCommand({ bare: true, gates: ',' }).catch((e) => e);
|
|
457
|
+
expect(err).toBeInstanceOf(TotemError);
|
|
458
|
+
expect(err.code).toBe('GATE_INVALID');
|
|
459
|
+
// No orphan wrapper scaffolded, no PreToolUse gate entry merged.
|
|
460
|
+
expect(fs.existsSync(path.join(cwd, '.claude', 'hooks', 'gate-wrapper.cjs'))).toBe(false);
|
|
461
|
+
if (fs.existsSync(path.join(cwd, '.claude', 'settings.json'))) {
|
|
462
|
+
expect(gateEntryCount(cwd, 'freeze-check')).toBe(0);
|
|
463
|
+
}
|
|
464
|
+
});
|
|
465
|
+
it('init --gates= (whitespace-only) throws GATE_INVALID and writes no gate wrapper/entry', async () => {
|
|
466
|
+
const err = await initCommand({ bare: true, gates: ' ' }).catch((e) => e);
|
|
467
|
+
expect(err).toBeInstanceOf(TotemError);
|
|
468
|
+
expect(err.code).toBe('GATE_INVALID');
|
|
469
|
+
expect(fs.existsSync(path.join(cwd, '.claude', 'hooks', 'gate-wrapper.cjs'))).toBe(false);
|
|
470
|
+
});
|
|
471
|
+
});
|
|
472
|
+
//# sourceMappingURL=gate-install.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gate-install.test.js","sourceRoot":"","sources":["../../src/commands/gate-install.test.ts"],"names":[],"mappings":"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"}
|