@mmnto/cli 1.99.0 → 1.101.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.
Files changed (63) hide show
  1. package/dist/commands/config-drift.test.js +5 -2
  2. package/dist/commands/config-drift.test.js.map +1 -1
  3. package/dist/commands/doctor-parity.d.ts.map +1 -1
  4. package/dist/commands/doctor-parity.js +57 -2
  5. package/dist/commands/doctor-parity.js.map +1 -1
  6. package/dist/commands/doctor-parity.test.js +60 -0
  7. package/dist/commands/doctor-parity.test.js.map +1 -1
  8. package/dist/commands/doctor.d.ts +19 -0
  9. package/dist/commands/doctor.d.ts.map +1 -1
  10. package/dist/commands/doctor.js +132 -0
  11. package/dist/commands/doctor.js.map +1 -1
  12. package/dist/commands/doctor.test.js +1 -0
  13. package/dist/commands/doctor.test.js.map +1 -1
  14. package/dist/commands/gate-install.d.ts.map +1 -1
  15. package/dist/commands/gate-install.js +12 -3
  16. package/dist/commands/gate-install.js.map +1 -1
  17. package/dist/commands/gate-install.test.js +13 -1
  18. package/dist/commands/gate-install.test.js.map +1 -1
  19. package/dist/commands/init-templates.d.ts +59 -7
  20. package/dist/commands/init-templates.d.ts.map +1 -1
  21. package/dist/commands/init-templates.js +223 -2
  22. package/dist/commands/init-templates.js.map +1 -1
  23. package/dist/commands/init.d.ts +38 -4
  24. package/dist/commands/init.d.ts.map +1 -1
  25. package/dist/commands/init.js +196 -13
  26. package/dist/commands/init.js.map +1 -1
  27. package/dist/commands/init.test.js +13 -0
  28. package/dist/commands/init.test.js.map +1 -1
  29. package/dist/commands/install-hooks-exit-contract.test.d.ts +2 -0
  30. package/dist/commands/install-hooks-exit-contract.test.d.ts.map +1 -0
  31. package/dist/commands/install-hooks-exit-contract.test.js +339 -0
  32. package/dist/commands/install-hooks-exit-contract.test.js.map +1 -0
  33. package/dist/commands/install-hooks.d.ts +53 -1
  34. package/dist/commands/install-hooks.d.ts.map +1 -1
  35. package/dist/commands/install-hooks.js +239 -52
  36. package/dist/commands/install-hooks.js.map +1 -1
  37. package/dist/commands/install-hooks.test.js +105 -39
  38. package/dist/commands/install-hooks.test.js.map +1 -1
  39. package/dist/commands/lint-staleness.d.ts +122 -0
  40. package/dist/commands/lint-staleness.d.ts.map +1 -0
  41. package/dist/commands/lint-staleness.js +163 -0
  42. package/dist/commands/lint-staleness.js.map +1 -0
  43. package/dist/commands/lint-staleness.test.d.ts +2 -0
  44. package/dist/commands/lint-staleness.test.d.ts.map +1 -0
  45. package/dist/commands/lint-staleness.test.js +173 -0
  46. package/dist/commands/lint-staleness.test.js.map +1 -0
  47. package/dist/commands/lint.d.ts.map +1 -1
  48. package/dist/commands/lint.js +142 -3
  49. package/dist/commands/lint.js.map +1 -1
  50. package/dist/commands/prepare-wrapper.test.d.ts +2 -0
  51. package/dist/commands/prepare-wrapper.test.d.ts.map +1 -0
  52. package/dist/commands/prepare-wrapper.test.js +284 -0
  53. package/dist/commands/prepare-wrapper.test.js.map +1 -0
  54. package/dist/commands/tools-hook-parity.test.d.ts +2 -0
  55. package/dist/commands/tools-hook-parity.test.d.ts.map +1 -0
  56. package/dist/commands/tools-hook-parity.test.js +37 -0
  57. package/dist/commands/tools-hook-parity.test.js.map +1 -0
  58. package/dist/commands/wrap.d.ts.map +1 -1
  59. package/dist/commands/wrap.js +3 -2
  60. package/dist/commands/wrap.js.map +1 -1
  61. package/dist/commands/wrap.test.js +11 -1
  62. package/dist/commands/wrap.test.js.map +1 -1
  63. package/package.json +2 -2
@@ -0,0 +1,339 @@
1
+ /**
2
+ * Exit-code contract for `totem hook install` (`hooksCommand`) + the managed
3
+ * session-hook bounded drift-repair (mmnto-ai/totem#2410 PR-A, slices 2+3).
4
+ *
5
+ * This is the dedicated falsifying test for the contract #2406 stabilized and
6
+ * strategy#894 froze (Tenet 19). It locks:
7
+ * - exit 0 ⟺ {fresh install, already-current, bounded drift-repair (git hook AND
8
+ * session hook), declared skips (not-a-git-repo, hook-manager-detected)};
9
+ * - exit ≠0 ⟺ genuine failure (a hook write throws → propagates → handleError);
10
+ * - `--check` is exactly 0/1 (all-present-with-marker vs missing/markerless);
11
+ * - a bare install never mutates a non-bounded file (git hook OR session hook);
12
+ * `--force` is the only unbounded write; a legacy markerless-end session hook is
13
+ * never bare-repaired; a no-marker user file is never touched even under --force;
14
+ * - regenerated artifacts always carry marker + end marker (so they self-repair);
15
+ * - the two `overwritten` messages are distinct ("Drift-repaired…" vs
16
+ * "Force-overwritten…").
17
+ *
18
+ * `hooksCommand` reads `process.cwd()` and gates via `process.exit` on `--check`
19
+ * failure, so the exit-code cases drive it under `process.chdir` + a `process.exit`
20
+ * spy (the doctor.test.ts idiom); the session-hook matrix drives the pure
21
+ * `regenerateManagedSessionHooks(cwd, force)` seam directly.
22
+ */
23
+ import { execSync } from 'node:child_process';
24
+ import * as fs from 'node:fs';
25
+ import * as os from 'node:os';
26
+ import * as path from 'node:path';
27
+ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
28
+ import { cleanTmpDir } from '../test-utils.js';
29
+ import { CLAUDE_PREWRITESHIELD, CLAUDE_SESSION_START, GEMINI_SESSION_START, MANAGED_SESSION_HOOKS, TOTEM_FILE_END, TOTEM_FILE_MARKER, } from './init-templates.js';
30
+ import { hooksCommand, installHooksNonInteractive, regenerateManagedSessionHooks, TOTEM_PREPUSH_END, TOTEM_PREPUSH_MARKER, } from './install-hooks.js';
31
+ // ─── Roster invariant (locked contract, mmnto-ai/totem#2410) ─────────
32
+ describe('MANAGED_SESSION_HOOKS roster invariant', () => {
33
+ it('every entry embeds its own marker AND end marker (so regenerated artifacts self-repair)', () => {
34
+ expect(MANAGED_SESSION_HOOKS.length).toBeGreaterThan(0);
35
+ for (const { rel, content, marker, endMarker } of MANAGED_SESSION_HOOKS) {
36
+ expect(content.includes(marker), `${rel} content is missing its marker`).toBe(true);
37
+ expect(content.includes(endMarker), `${rel} content is missing its end marker`).toBe(true);
38
+ // The marker must OPEN the file (only whitespace before it) — the ownership
39
+ // precondition for bounded drift-repair.
40
+ expect(content.trimStart().startsWith(marker), `${rel} marker must open the file`).toBe(true);
41
+ // The end marker must CLOSE the region (nothing but whitespace after it).
42
+ const endIdx = content.indexOf(endMarker);
43
+ expect(content.slice(endIdx + endMarker.length).trim()).toBe('');
44
+ }
45
+ });
46
+ it('covers the six distributed managed artifacts (incl. the PR-B prepare wrapper)', () => {
47
+ const rels = MANAGED_SESSION_HOOKS.map((h) => h.rel).sort();
48
+ expect(rels).toEqual([
49
+ '.claude/hooks/PreWriteShield.cjs',
50
+ '.claude/hooks/SessionStart.cjs',
51
+ '.claude/hooks/gate-wrapper.cjs',
52
+ '.gemini/hooks/BeforeTool.js',
53
+ '.gemini/hooks/SessionStart.js',
54
+ '.totem/prepare.cjs',
55
+ ].sort());
56
+ });
57
+ });
58
+ // ─── Managed session-hook bounded drift-repair (slice 3) ─────────────
59
+ describe('regenerateManagedSessionHooks — bounded drift-repair matrix', () => {
60
+ let tmpDir;
61
+ const CLAUDE_SS = '.claude/hooks/SessionStart.cjs';
62
+ function writeHook(rel, content) {
63
+ const p = path.join(tmpDir, ...rel.split('/'));
64
+ fs.mkdirSync(path.dirname(p), { recursive: true });
65
+ fs.writeFileSync(p, content, 'utf-8');
66
+ return p;
67
+ }
68
+ beforeEach(() => {
69
+ tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'totem-2410-sess-'));
70
+ });
71
+ afterEach(() => {
72
+ cleanTmpDir(tmpDir);
73
+ });
74
+ it('does NOT create a missing session hook (regenerate-only-if-present)', async () => {
75
+ const results = await regenerateManagedSessionHooks(tmpDir);
76
+ expect(results).toEqual([]);
77
+ expect(fs.existsSync(path.join(tmpDir, ...CLAUDE_SS.split('/')))).toBe(false);
78
+ });
79
+ it('returns exists for a present, byte-identical session hook (already current)', async () => {
80
+ writeHook(CLAUDE_SS, CLAUDE_SESSION_START);
81
+ const results = await regenerateManagedSessionHooks(tmpDir);
82
+ const r = results.find((x) => x.file === CLAUDE_SS);
83
+ expect(r.action).toBe('exists');
84
+ expect(fs.readFileSync(path.join(tmpDir, ...CLAUDE_SS.split('/')), 'utf-8')).toBe(CLAUDE_SESSION_START);
85
+ });
86
+ it('bare drift-repairs a bounded totem-owned session hook (overwritten, no force)', async () => {
87
+ const p = writeHook(CLAUDE_SS, `${TOTEM_FILE_MARKER}\nstale body\n${TOTEM_FILE_END}\n`);
88
+ const results = await regenerateManagedSessionHooks(tmpDir);
89
+ const r = results.find((x) => x.file === CLAUDE_SS);
90
+ expect(r.action).toBe('overwritten');
91
+ // Regenerated to canonical — and canonical carries marker + end marker.
92
+ const written = fs.readFileSync(p, 'utf-8');
93
+ expect(written).toBe(CLAUDE_SESSION_START);
94
+ expect(written.includes(TOTEM_FILE_MARKER)).toBe(true);
95
+ expect(written.includes(TOTEM_FILE_END)).toBe(true);
96
+ });
97
+ it('does NOT bare-repair a legacy marker-headed session hook missing the end marker', async () => {
98
+ const legacy = `${TOTEM_FILE_MARKER} — Claude Code SessionStart hook\nstale legacy body\n`;
99
+ const p = writeHook(CLAUDE_SS, legacy);
100
+ const results = await regenerateManagedSessionHooks(tmpDir);
101
+ const r = results.find((x) => x.file === CLAUDE_SS);
102
+ expect(r.action).toBe('declined');
103
+ // Untouched — takes one `totem hook install --force`.
104
+ expect(fs.readFileSync(p, 'utf-8')).toBe(legacy);
105
+ });
106
+ it('--force overwrites a legacy markerless-end session hook (the migration path)', async () => {
107
+ const legacy = `${TOTEM_FILE_MARKER} — Claude Code SessionStart hook\nstale legacy body\n`;
108
+ const p = writeHook(CLAUDE_SS, legacy);
109
+ const results = await regenerateManagedSessionHooks(tmpDir, true);
110
+ const r = results.find((x) => x.file === CLAUDE_SS);
111
+ expect(r.action).toBe('overwritten');
112
+ expect(fs.readFileSync(p, 'utf-8')).toBe(CLAUDE_SESSION_START);
113
+ });
114
+ it('does NOT repair a bounded hook with user content AFTER the end marker (bare declines)', async () => {
115
+ const withTrailingUser = `${TOTEM_FILE_MARKER}\nstale\n${TOTEM_FILE_END}\nconsole.log("mine");\n`;
116
+ const p = writeHook(CLAUDE_SS, withTrailingUser);
117
+ const results = await regenerateManagedSessionHooks(tmpDir);
118
+ expect(results.find((x) => x.file === CLAUDE_SS).action).toBe('declined');
119
+ expect(fs.readFileSync(p, 'utf-8')).toBe(withTrailingUser);
120
+ });
121
+ it('never touches a user-owned file with NO totem marker, even under --force (skipped)', async () => {
122
+ const userOwned = '// my own SessionStart hook\nconsole.log("mine");\n';
123
+ const p = writeHook(CLAUDE_SS, userOwned);
124
+ const bare = await regenerateManagedSessionHooks(tmpDir);
125
+ expect(bare.find((x) => x.file === CLAUDE_SS).action).toBe('skipped');
126
+ expect(fs.readFileSync(p, 'utf-8')).toBe(userOwned);
127
+ const forced = await regenerateManagedSessionHooks(tmpDir, true);
128
+ expect(forced.find((x) => x.file === CLAUDE_SS).action).toBe('skipped');
129
+ expect(fs.readFileSync(p, 'utf-8')).toBe(userOwned);
130
+ });
131
+ it('never touches a user file that merely QUOTES the marker (marker not at start), even under --force', async () => {
132
+ // A user-owned hook that quotes the marker string in a comment/string is NOT
133
+ // marker-headed (positional gate, mmnto-ai/totem#2413). The old `includes(marker)`
134
+ // gate would treat it as owned and let --force clobber it.
135
+ const quotesMarker = `// my own hook\n// I copied this line: ${TOTEM_FILE_MARKER}\nconsole.log("mine");\n`;
136
+ const p = writeHook(CLAUDE_SS, quotesMarker);
137
+ const bare = await regenerateManagedSessionHooks(tmpDir);
138
+ expect(bare.find((x) => x.file === CLAUDE_SS).action).toBe('skipped');
139
+ expect(fs.readFileSync(p, 'utf-8')).toBe(quotesMarker);
140
+ const forced = await regenerateManagedSessionHooks(tmpDir, true);
141
+ expect(forced.find((x) => x.file === CLAUDE_SS).action).toBe('skipped');
142
+ expect(fs.readFileSync(p, 'utf-8')).toBe(quotesMarker);
143
+ });
144
+ it('repairs each vendor family independently (claude + gemini)', async () => {
145
+ writeHook('.claude/hooks/PreWriteShield.cjs', `${TOTEM_FILE_MARKER}\nstale\n${TOTEM_FILE_END}\n`);
146
+ writeHook('.gemini/hooks/SessionStart.js', GEMINI_SESSION_START); // already current
147
+ const results = await regenerateManagedSessionHooks(tmpDir);
148
+ expect(results.find((x) => x.file === '.claude/hooks/PreWriteShield.cjs').action).toBe('overwritten');
149
+ expect(fs.readFileSync(path.join(tmpDir, '.claude', 'hooks', 'PreWriteShield.cjs'), 'utf-8')).toBe(CLAUDE_PREWRITESHIELD);
150
+ expect(results.find((x) => x.file === '.gemini/hooks/SessionStart.js').action).toBe('exists');
151
+ });
152
+ });
153
+ // ─── hooksCommand exit-code contract (slice 2) ───────────────────────
154
+ describe('hooksCommand exit-code contract', () => {
155
+ let tmpDir;
156
+ let originalCwd;
157
+ let errorSpy;
158
+ let exitSpy;
159
+ const hooksDir = () => path.join(tmpDir, '.git', 'hooks');
160
+ const errorOutput = () => errorSpy.mock.calls
161
+ .map((c) => c.map((a) => String(a)).join(' '))
162
+ .join('\n');
163
+ beforeEach(() => {
164
+ tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'totem-2410-cmd-'));
165
+ execSync('git init', { cwd: tmpDir, stdio: 'ignore' });
166
+ originalCwd = process.cwd();
167
+ process.chdir(tmpDir);
168
+ errorSpy = vi.spyOn(console, 'error').mockImplementation(() => { });
169
+ // A throwing process.exit surfaces a --check failure as a rejection (the CLI
170
+ // edge would exit non-zero); the install path must never reach it.
171
+ exitSpy = vi.spyOn(process, 'exit').mockImplementation(((code) => {
172
+ throw new Error(`process.exit:${code ?? 0}`);
173
+ }));
174
+ });
175
+ afterEach(() => {
176
+ process.chdir(originalCwd);
177
+ vi.restoreAllMocks();
178
+ cleanTmpDir(tmpDir);
179
+ });
180
+ // ── exit 0 classes ──────────────────────────────────────────────
181
+ it('exit 0: fresh install (no throw, no process.exit)', async () => {
182
+ await expect(hooksCommand({})).resolves.toBeUndefined();
183
+ expect(exitSpy).not.toHaveBeenCalled();
184
+ expect(fs.existsSync(path.join(hooksDir(), 'pre-push'))).toBe(true);
185
+ });
186
+ it('exit 0: already-current (second install is a no-op)', async () => {
187
+ await hooksCommand({});
188
+ errorSpy.mockClear();
189
+ await expect(hooksCommand({})).resolves.toBeUndefined();
190
+ expect(exitSpy).not.toHaveBeenCalled();
191
+ expect(errorOutput()).toContain('already installed');
192
+ });
193
+ it('exit 0: bare git-hook drift-repair prints "Drift-repaired", not "Force-overwritten"', async () => {
194
+ await hooksCommand({});
195
+ // Corrupt pre-push to a stale-but-bounded totem-owned whole file.
196
+ fs.writeFileSync(path.join(hooksDir(), 'pre-push'), `#!/bin/sh\n# ${TOTEM_PREPUSH_MARKER}\nstale\n# ${TOTEM_PREPUSH_END}\n`);
197
+ errorSpy.mockClear();
198
+ await expect(hooksCommand({})).resolves.toBeUndefined();
199
+ expect(exitSpy).not.toHaveBeenCalled();
200
+ const out = errorOutput();
201
+ expect(out).toContain('Drift-repaired pre-push hook (totem-owned bounded region).');
202
+ expect(out).not.toContain('Force-overwritten pre-push');
203
+ });
204
+ it('exit 0: bare session-hook drift-repair prints "Drift-repaired"', async () => {
205
+ fs.mkdirSync(path.join(tmpDir, '.claude', 'hooks'), { recursive: true });
206
+ fs.writeFileSync(path.join(tmpDir, '.claude', 'hooks', 'SessionStart.cjs'), `${TOTEM_FILE_MARKER}\nstale\n${TOTEM_FILE_END}\n`);
207
+ errorSpy.mockClear();
208
+ await expect(hooksCommand({})).resolves.toBeUndefined();
209
+ expect(exitSpy).not.toHaveBeenCalled();
210
+ expect(errorOutput()).toContain('Drift-repaired .claude/hooks/SessionStart.cjs session hook (totem-owned bounded region).');
211
+ expect(fs.readFileSync(path.join(tmpDir, '.claude', 'hooks', 'SessionStart.cjs'), 'utf-8')).toBe(CLAUDE_SESSION_START);
212
+ });
213
+ it('exit 0: declared skip — not a git repository', async () => {
214
+ const nonGit = fs.mkdtempSync(path.join(os.tmpdir(), 'totem-2410-nogit-'));
215
+ process.chdir(nonGit);
216
+ try {
217
+ await expect(hooksCommand({})).resolves.toBeUndefined();
218
+ expect(exitSpy).not.toHaveBeenCalled();
219
+ expect(errorOutput()).toContain('Not a git repository');
220
+ }
221
+ finally {
222
+ process.chdir(tmpDir);
223
+ cleanTmpDir(nonGit);
224
+ }
225
+ });
226
+ it('exit 0: declared skip — hook manager detected', async () => {
227
+ fs.mkdirSync(path.join(tmpDir, '.husky'), { recursive: true });
228
+ await expect(hooksCommand({})).resolves.toBeUndefined();
229
+ expect(exitSpy).not.toHaveBeenCalled();
230
+ });
231
+ it('hook-manager repo STILL drift-repairs an existing bounded session hook (lc#806 guard)', async () => {
232
+ // A git-hook manager (husky) means git hooks are the manager's job — a declared
233
+ // skip for the git side. But the session hooks are Claude/Gemini artifacts,
234
+ // independent of the manager, so they must still be regenerated: the fix for the
235
+ // hook-manager early-return that otherwise recreates the lc#806 stale class.
236
+ fs.mkdirSync(path.join(tmpDir, '.husky'), { recursive: true });
237
+ const ssPath = path.join(tmpDir, '.claude', 'hooks', 'SessionStart.cjs');
238
+ fs.mkdirSync(path.dirname(ssPath), { recursive: true });
239
+ fs.writeFileSync(ssPath, `${TOTEM_FILE_MARKER}\nstale\n${TOTEM_FILE_END}\n`);
240
+ errorSpy.mockClear();
241
+ await expect(hooksCommand({})).resolves.toBeUndefined();
242
+ expect(exitSpy).not.toHaveBeenCalled();
243
+ // The bounded session hook is drift-repaired even though git hooks were skipped.
244
+ expect(fs.readFileSync(ssPath, 'utf-8')).toBe(CLAUDE_SESSION_START);
245
+ expect(errorOutput()).toContain('Drift-repaired .claude/hooks/SessionStart.cjs session hook (totem-owned bounded region).');
246
+ });
247
+ // ── exit ≠0: genuine failure ────────────────────────────────────
248
+ it('exit ≠0: a genuine hook-write failure propagates as a thrown error', async () => {
249
+ // Make the first-installed hook PATH a directory: the installer's read/write of it
250
+ // throws EISDIR — a genuine FS failure that must PROPAGATE (fail-loud, Tenet 4),
251
+ // not be swallowed into a false `installed`. (A directory-at-path fault is
252
+ // cross-platform, unlike an ESM fs spy — vitest cannot redefine fs namespace exports.)
253
+ fs.mkdirSync(path.join(hooksDir(), 'pre-commit'), { recursive: true });
254
+ await expect(hooksCommand({})).rejects.toThrow();
255
+ expect(exitSpy).not.toHaveBeenCalled();
256
+ });
257
+ // ── --check: exactly 0/1 ────────────────────────────────────────
258
+ it('--check exit 0: all hooks present with markers', async () => {
259
+ await hooksCommand({});
260
+ errorSpy.mockClear();
261
+ await expect(hooksCommand({ check: true })).resolves.toBeUndefined();
262
+ expect(exitSpy).not.toHaveBeenCalled();
263
+ expect(errorOutput()).toContain('All hooks installed');
264
+ });
265
+ it('--check exit 1: hooks missing (and the remedy names `totem hook install`)', async () => {
266
+ await expect(hooksCommand({ check: true })).rejects.toThrow('process.exit:1');
267
+ expect(exitSpy).toHaveBeenCalledWith(1);
268
+ const out = errorOutput();
269
+ expect(out).toContain('Some hooks are missing');
270
+ expect(out).toContain('totem hook install');
271
+ expect(out).not.toContain('Run `totem hooks`');
272
+ });
273
+ it('--check exit 1: hook present but missing the Totem marker', async () => {
274
+ // Install, then strip the marker from one hook (markerless → not counted).
275
+ await hooksCommand({});
276
+ fs.writeFileSync(path.join(hooksDir(), 'pre-push'), '#!/bin/sh\necho "no marker"\n');
277
+ await expect(hooksCommand({ check: true })).rejects.toThrow('process.exit:1');
278
+ expect(exitSpy).toHaveBeenCalledWith(1);
279
+ });
280
+ it('--check is read-only: it does NOT mutate a drifted session hook', async () => {
281
+ // Install git hooks so --check passes on the git side (exit 0), then plant a
282
+ // drifted-but-bounded session hook. --check is a verify-only path and returns
283
+ // before session-hook regeneration, so the drifted hook must be left untouched.
284
+ await hooksCommand({});
285
+ const ssPath = path.join(tmpDir, '.claude', 'hooks', 'SessionStart.cjs');
286
+ fs.mkdirSync(path.dirname(ssPath), { recursive: true });
287
+ const drifted = `${TOTEM_FILE_MARKER}\nstale\n${TOTEM_FILE_END}\n`;
288
+ fs.writeFileSync(ssPath, drifted);
289
+ await expect(hooksCommand({ check: true })).resolves.toBeUndefined();
290
+ expect(exitSpy).not.toHaveBeenCalled();
291
+ expect(fs.readFileSync(ssPath, 'utf-8')).toBe(drifted);
292
+ });
293
+ // ── the two `overwritten` messages are distinct ─────────────────
294
+ it('bare drift-repair and --force overwrite print DISTINCT messages', async () => {
295
+ await hooksCommand({});
296
+ const staleBounded = `#!/bin/sh\n# ${TOTEM_PREPUSH_MARKER}\nstale\n# ${TOTEM_PREPUSH_END}\n`;
297
+ // Bare (no --force) bounded drift-repair.
298
+ fs.writeFileSync(path.join(hooksDir(), 'pre-push'), staleBounded);
299
+ errorSpy.mockClear();
300
+ await hooksCommand({});
301
+ const bareMsg = errorOutput()
302
+ .split('\n')
303
+ .find((l) => l.includes('pre-push hook'));
304
+ // --force overwrite of the same stale-bounded file.
305
+ fs.writeFileSync(path.join(hooksDir(), 'pre-push'), staleBounded);
306
+ errorSpy.mockClear();
307
+ await hooksCommand({ force: true });
308
+ const forceMsg = errorOutput()
309
+ .split('\n')
310
+ .find((l) => l.includes('pre-push hook'));
311
+ expect(bareMsg).toContain('Drift-repaired');
312
+ expect(forceMsg).toContain('Force-overwritten');
313
+ expect(bareMsg).not.toBe(forceMsg);
314
+ });
315
+ // ── bare install never mutates a non-bounded git hook ───────────
316
+ it('bare install never mutates a user hook with an appended totem block (non-bounded)', async () => {
317
+ const userThenTotem = `#!/bin/sh\nrun_my_tests\n# ${TOTEM_PREPUSH_MARKER}\nstale\n# ${TOTEM_PREPUSH_END}\n`;
318
+ fs.mkdirSync(hooksDir(), { recursive: true });
319
+ fs.writeFileSync(path.join(hooksDir(), 'pre-push'), userThenTotem);
320
+ await expect(hooksCommand({})).resolves.toBeUndefined();
321
+ expect(exitSpy).not.toHaveBeenCalled();
322
+ // User content preserved — only --force may overwrite an unbounded file.
323
+ expect(fs.readFileSync(path.join(hooksDir(), 'pre-push'), 'utf-8')).toBe(userThenTotem);
324
+ });
325
+ });
326
+ // ─── sanity: installHooksNonInteractive still classifies a fresh repo ─
327
+ describe('installHooksNonInteractive (contract sanity)', () => {
328
+ let tmpDir;
329
+ beforeEach(() => {
330
+ tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'totem-2410-ni-'));
331
+ });
332
+ afterEach(() => {
333
+ cleanTmpDir(tmpDir);
334
+ });
335
+ it('returns null outside a git repo (declared skip, exit 0 at the command edge)', () => {
336
+ expect(installHooksNonInteractive(tmpDir)).toBeNull();
337
+ });
338
+ });
339
+ //# sourceMappingURL=install-hooks-exit-contract.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install-hooks-exit-contract.test.js","sourceRoot":"","sources":["../../src/commands/install-hooks-exit-contract.test.ts"],"names":[],"mappings":"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"}
@@ -4,7 +4,9 @@ export declare const TOTEM_HOOK_END = "[totem] end post-merge";
4
4
  export declare const TOTEM_CHECKOUT_MARKER = "[totem] post-checkout hook";
5
5
  export declare const TOTEM_CHECKOUT_END = "[totem] end post-checkout";
6
6
  export declare const TOTEM_PRECOMMIT_MARKER = "[totem] pre-commit hook";
7
+ export declare const TOTEM_PRECOMMIT_END = "[totem] end pre-commit";
7
8
  export declare const TOTEM_PREPUSH_MARKER = "[totem] pre-push hook";
9
+ export declare const TOTEM_PREPUSH_END = "[totem] end pre-push";
8
10
  /**
9
11
  * Determine the package-manager fallback command for invoking totem.
10
12
  * Used inside the runtime resolve block when `totem` is not on PATH.
@@ -45,8 +47,19 @@ export declare function buildPrePushHook(fallbackCmd: string, tier?: 'strict' |
45
47
  /**
46
48
  * Install a single git hook with idempotency and chain preservation.
47
49
  * Returns the action taken.
50
+ *
51
+ * When the hook already carries the totem marker and `force` is not set, a
52
+ * totem-OWNED whole file whose content has drifted from the regenerated canonical
53
+ * is repaired in place (`overwritten`) — this makes bare `totem hook install`
54
+ * actually fix a stale hook, so the doctor's drift remediation is truthful
55
+ * (mmnto-ai/totem#2138). A user hook with an appended totem block is left untouched
56
+ * (`exists`); overwriting it still requires `--force`. `endMarker` bounds the totem
57
+ * region so appended user content downstream of it is never clobbered; all four hook
58
+ * templates now emit one. Drift-repair fires only when the caller threads the end
59
+ * marker AND the on-disk hook carries it — a legacy pre-end-marker hook declines to
60
+ * `exists` and takes one `totem hook install --force`.
48
61
  */
49
- export declare function installGitHook(hooksDir: string, hookName: string, hookContent: string, marker: string, force?: boolean): 'installed' | 'exists' | 'appended' | 'skipped-non-shell' | 'overwritten';
62
+ export declare function installGitHook(hooksDir: string, hookName: string, hookContent: string, marker: string, force?: boolean, endMarker?: string): 'installed' | 'exists' | 'appended' | 'skipped-non-shell' | 'overwritten';
50
63
  export interface EnforcementHookResult {
51
64
  preCommit: 'installed' | 'exists' | 'appended' | 'skipped' | 'skipped-non-shell' | 'overwritten';
52
65
  prePush: 'installed' | 'exists' | 'appended' | 'skipped' | 'skipped-non-shell' | 'overwritten';
@@ -86,6 +99,45 @@ export declare function hooksCommand(opts: {
86
99
  strict?: boolean;
87
100
  standard?: boolean;
88
101
  }): Promise<void>;
102
+ /**
103
+ * The action taken on one managed session-hook artifact by
104
+ * {@link regenerateManagedSessionHooks}:
105
+ * - `exists` — present, marker-headed, already byte-identical to canonical (no write).
106
+ * - `overwritten` — regenerated: a bare bounded drift-repair OR a `--force` overwrite.
107
+ * - `declined` — marker present but the region is NOT bounded-owned (legacy file
108
+ * with no end marker, or user content after the end marker) and no
109
+ * `--force`: left untouched, takes one `totem hook install --force`.
110
+ * - `skipped` — a user-owned file carrying NO totem marker at all: never touched,
111
+ * not even under `--force`.
112
+ */
113
+ export type ManagedSessionHookAction = 'exists' | 'overwritten' | 'declined' | 'skipped';
114
+ export interface ManagedSessionHookResult {
115
+ /** Repo-relative path of the artifact. */
116
+ file: string;
117
+ action: ManagedSessionHookAction;
118
+ }
119
+ /**
120
+ * Walk the {@link MANAGED_SESSION_HOOKS} roster and regenerate the whole-file
121
+ * session-hook artifacts (`.claude/hooks/*.cjs`, `.gemini/hooks/*.js`) that EXIST
122
+ * under `cwd`, applying the #2406 bounded-ownership semantics generalized to the
123
+ * JS/CJS hook family:
124
+ *
125
+ * - Missing file → not created (creation is `totem init`'s job); omitted
126
+ * from the results entirely.
127
+ * - Marker + identical → `exists` (already current).
128
+ * - Marker + drifted, bounded totem-owned whole file → bare drift-repair
129
+ * (`overwritten`), or `--force` → `overwritten`.
130
+ * - Marker + drifted, unbounded (legacy no-end-marker / trailing user content):
131
+ * bare → `declined`; `--force` → `overwritten`.
132
+ * - Marker does not OPEN the file (no marker, or a merely-quoted marker) →
133
+ * `skipped` even under `--force` (never clobber a
134
+ * user-owned file).
135
+ *
136
+ * Regenerate-only-if-present, single-writer per invocation. A write failure
137
+ * (perms/FS) PROPAGATES (Tenet 4 — a hook the tool cannot write must fail loud,
138
+ * never silently report success), mirroring `installGitHook`.
139
+ */
140
+ export declare function regenerateManagedSessionHooks(cwd: string, force?: boolean): Promise<ManagedSessionHookResult[]>;
89
141
  /**
90
142
  * Silently upgrade the pre-push hook if it was installed by Totem but uses
91
143
  * an old format (flag-checking or command-executing) instead of the new
@@ -1 +1 @@
1
- {"version":3,"file":"install-hooks.d.ts","sourceRoot":"","sources":["../../src/commands/install-hooks.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"install-hooks.d.ts","sourceRoot":"","sources":["../../src/commands/install-hooks.ts"],"names":[],"mappings":"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"}