@mmnto/cli 1.100.0 → 1.101.1
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/doctor-parity.d.ts.map +1 -1
- package/dist/commands/doctor-parity.js +11 -5
- package/dist/commands/doctor-parity.js.map +1 -1
- package/dist/commands/doctor.d.ts +19 -0
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +132 -0
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/doctor.test.js +1 -0
- package/dist/commands/doctor.test.js.map +1 -1
- package/dist/commands/gate-install.d.ts.map +1 -1
- package/dist/commands/gate-install.js +12 -3
- package/dist/commands/gate-install.js.map +1 -1
- package/dist/commands/gate-install.test.js +13 -1
- package/dist/commands/gate-install.test.js.map +1 -1
- package/dist/commands/init-templates.d.ts +57 -5
- package/dist/commands/init-templates.d.ts.map +1 -1
- package/dist/commands/init-templates.js +222 -1
- package/dist/commands/init-templates.js.map +1 -1
- package/dist/commands/init.d.ts +38 -4
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +196 -13
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/init.test.js +13 -0
- package/dist/commands/init.test.js.map +1 -1
- package/dist/commands/install-hooks-exit-contract.test.d.ts +2 -0
- package/dist/commands/install-hooks-exit-contract.test.d.ts.map +1 -0
- package/dist/commands/install-hooks-exit-contract.test.js +508 -0
- package/dist/commands/install-hooks-exit-contract.test.js.map +1 -0
- package/dist/commands/install-hooks.d.ts +53 -0
- package/dist/commands/install-hooks.d.ts.map +1 -1
- package/dist/commands/install-hooks.js +277 -42
- package/dist/commands/install-hooks.js.map +1 -1
- package/dist/commands/mail.d.ts.map +1 -1
- package/dist/commands/mail.js +56 -16
- package/dist/commands/mail.js.map +1 -1
- package/dist/commands/mail.test.js +73 -0
- package/dist/commands/mail.test.js.map +1 -1
- package/dist/commands/prepare-wrapper.test.d.ts +2 -0
- package/dist/commands/prepare-wrapper.test.d.ts.map +1 -0
- package/dist/commands/prepare-wrapper.test.js +284 -0
- package/dist/commands/prepare-wrapper.test.js.map +1 -0
- package/dist/parse-nits.d.ts +20 -3
- package/dist/parse-nits.d.ts.map +1 -1
- package/dist/parse-nits.js +111 -6
- package/dist/parse-nits.js.map +1 -1
- package/dist/parse-nits.test.js +141 -0
- package/dist/parse-nits.test.js.map +1 -1
- package/dist/parsers/bot-review-parser.d.ts.map +1 -1
- package/dist/parsers/bot-review-parser.js +12 -2
- package/dist/parsers/bot-review-parser.js.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,508 @@
|
|
|
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 { execFileSync, 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, installHooksCommand, installHooksNonInteractive, regenerateManagedSessionHooks, resolveHooksDir, 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('file-valued core.hooksPath: declares the git-hook skip, session hooks STILL repaired (exit 0)', async () => {
|
|
232
|
+
// CR #2422 round 2 falsifier: an unresolvable hooks dir (core.hooksPath at a
|
|
233
|
+
// non-directory — the hooks-disabled idiom) skips GIT hook installation with
|
|
234
|
+
// the truthful scoped line, while the managed session hooks — vendor
|
|
235
|
+
// artifacts independent of git-hook state (PR-A slice 3 / lc#806) — are
|
|
236
|
+
// still drift-repaired. Continuing past the git-hook skip is the contract,
|
|
237
|
+
// not a leak.
|
|
238
|
+
const notADir = path.join(tmpDir, 'hooks-disabled.txt');
|
|
239
|
+
fs.writeFileSync(notADir, 'not a directory\n');
|
|
240
|
+
execFileSync('git', ['config', 'core.hooksPath', notADir], { cwd: tmpDir });
|
|
241
|
+
const ssPath = path.join(tmpDir, '.claude', 'hooks', 'SessionStart.cjs');
|
|
242
|
+
fs.mkdirSync(path.dirname(ssPath), { recursive: true });
|
|
243
|
+
fs.writeFileSync(ssPath, `${TOTEM_FILE_MARKER}\nstale\n${TOTEM_FILE_END}\n`);
|
|
244
|
+
errorSpy.mockClear();
|
|
245
|
+
await expect(hooksCommand({})).resolves.toBeUndefined();
|
|
246
|
+
expect(exitSpy).not.toHaveBeenCalled();
|
|
247
|
+
expect(errorOutput()).toContain('skipping git hook installation');
|
|
248
|
+
// The non-directory target never receives a write.
|
|
249
|
+
expect(fs.readFileSync(notADir, 'utf-8')).toBe('not a directory\n');
|
|
250
|
+
// The bounded session hook is still repaired after the git-hook skip.
|
|
251
|
+
expect(fs.readFileSync(ssPath, 'utf-8')).toBe(CLAUDE_SESSION_START);
|
|
252
|
+
});
|
|
253
|
+
it('hook-manager repo STILL drift-repairs an existing bounded session hook (lc#806 guard)', async () => {
|
|
254
|
+
// A git-hook manager (husky) means git hooks are the manager's job — a declared
|
|
255
|
+
// skip for the git side. But the session hooks are Claude/Gemini artifacts,
|
|
256
|
+
// independent of the manager, so they must still be regenerated: the fix for the
|
|
257
|
+
// hook-manager early-return that otherwise recreates the lc#806 stale class.
|
|
258
|
+
fs.mkdirSync(path.join(tmpDir, '.husky'), { recursive: true });
|
|
259
|
+
const ssPath = path.join(tmpDir, '.claude', 'hooks', 'SessionStart.cjs');
|
|
260
|
+
fs.mkdirSync(path.dirname(ssPath), { recursive: true });
|
|
261
|
+
fs.writeFileSync(ssPath, `${TOTEM_FILE_MARKER}\nstale\n${TOTEM_FILE_END}\n`);
|
|
262
|
+
errorSpy.mockClear();
|
|
263
|
+
await expect(hooksCommand({})).resolves.toBeUndefined();
|
|
264
|
+
expect(exitSpy).not.toHaveBeenCalled();
|
|
265
|
+
// The bounded session hook is drift-repaired even though git hooks were skipped.
|
|
266
|
+
expect(fs.readFileSync(ssPath, 'utf-8')).toBe(CLAUDE_SESSION_START);
|
|
267
|
+
expect(errorOutput()).toContain('Drift-repaired .claude/hooks/SessionStart.cjs session hook (totem-owned bounded region).');
|
|
268
|
+
});
|
|
269
|
+
// ── exit ≠0: genuine failure ────────────────────────────────────
|
|
270
|
+
it('exit ≠0: a genuine hook-write failure propagates as a thrown error', async () => {
|
|
271
|
+
// Make the first-installed hook PATH a directory: the installer's read/write of it
|
|
272
|
+
// throws EISDIR — a genuine FS failure that must PROPAGATE (fail-loud, Tenet 4),
|
|
273
|
+
// not be swallowed into a false `installed`. (A directory-at-path fault is
|
|
274
|
+
// cross-platform, unlike an ESM fs spy — vitest cannot redefine fs namespace exports.)
|
|
275
|
+
fs.mkdirSync(path.join(hooksDir(), 'pre-commit'), { recursive: true });
|
|
276
|
+
await expect(hooksCommand({})).rejects.toThrow();
|
|
277
|
+
expect(exitSpy).not.toHaveBeenCalled();
|
|
278
|
+
});
|
|
279
|
+
// ── --check: exactly 0/1 ────────────────────────────────────────
|
|
280
|
+
it('--check exit 0: all hooks present with markers', async () => {
|
|
281
|
+
await hooksCommand({});
|
|
282
|
+
errorSpy.mockClear();
|
|
283
|
+
await expect(hooksCommand({ check: true })).resolves.toBeUndefined();
|
|
284
|
+
expect(exitSpy).not.toHaveBeenCalled();
|
|
285
|
+
expect(errorOutput()).toContain('All hooks installed');
|
|
286
|
+
});
|
|
287
|
+
it('--check exit 1: hooks missing (and the remedy names `totem hook install`)', async () => {
|
|
288
|
+
await expect(hooksCommand({ check: true })).rejects.toThrow('process.exit:1');
|
|
289
|
+
expect(exitSpy).toHaveBeenCalledWith(1);
|
|
290
|
+
const out = errorOutput();
|
|
291
|
+
expect(out).toContain('Some hooks are missing');
|
|
292
|
+
expect(out).toContain('totem hook install');
|
|
293
|
+
expect(out).not.toContain('Run `totem hooks`');
|
|
294
|
+
});
|
|
295
|
+
it('--check exit 1: hook present but missing the Totem marker', async () => {
|
|
296
|
+
// Install, then strip the marker from one hook (markerless → not counted).
|
|
297
|
+
await hooksCommand({});
|
|
298
|
+
fs.writeFileSync(path.join(hooksDir(), 'pre-push'), '#!/bin/sh\necho "no marker"\n');
|
|
299
|
+
await expect(hooksCommand({ check: true })).rejects.toThrow('process.exit:1');
|
|
300
|
+
expect(exitSpy).toHaveBeenCalledWith(1);
|
|
301
|
+
});
|
|
302
|
+
it('--check is read-only: it does NOT mutate a drifted session hook', async () => {
|
|
303
|
+
// Install git hooks so --check passes on the git side (exit 0), then plant a
|
|
304
|
+
// drifted-but-bounded session hook. --check is a verify-only path and returns
|
|
305
|
+
// before session-hook regeneration, so the drifted hook must be left untouched.
|
|
306
|
+
await hooksCommand({});
|
|
307
|
+
const ssPath = path.join(tmpDir, '.claude', 'hooks', 'SessionStart.cjs');
|
|
308
|
+
fs.mkdirSync(path.dirname(ssPath), { recursive: true });
|
|
309
|
+
const drifted = `${TOTEM_FILE_MARKER}\nstale\n${TOTEM_FILE_END}\n`;
|
|
310
|
+
fs.writeFileSync(ssPath, drifted);
|
|
311
|
+
await expect(hooksCommand({ check: true })).resolves.toBeUndefined();
|
|
312
|
+
expect(exitSpy).not.toHaveBeenCalled();
|
|
313
|
+
expect(fs.readFileSync(ssPath, 'utf-8')).toBe(drifted);
|
|
314
|
+
});
|
|
315
|
+
// ── the two `overwritten` messages are distinct ─────────────────
|
|
316
|
+
it('bare drift-repair and --force overwrite print DISTINCT messages', async () => {
|
|
317
|
+
await hooksCommand({});
|
|
318
|
+
const staleBounded = `#!/bin/sh\n# ${TOTEM_PREPUSH_MARKER}\nstale\n# ${TOTEM_PREPUSH_END}\n`;
|
|
319
|
+
// Bare (no --force) bounded drift-repair.
|
|
320
|
+
fs.writeFileSync(path.join(hooksDir(), 'pre-push'), staleBounded);
|
|
321
|
+
errorSpy.mockClear();
|
|
322
|
+
await hooksCommand({});
|
|
323
|
+
const bareMsg = errorOutput()
|
|
324
|
+
.split('\n')
|
|
325
|
+
.find((l) => l.includes('pre-push hook'));
|
|
326
|
+
// --force overwrite of the same stale-bounded file.
|
|
327
|
+
fs.writeFileSync(path.join(hooksDir(), 'pre-push'), staleBounded);
|
|
328
|
+
errorSpy.mockClear();
|
|
329
|
+
await hooksCommand({ force: true });
|
|
330
|
+
const forceMsg = errorOutput()
|
|
331
|
+
.split('\n')
|
|
332
|
+
.find((l) => l.includes('pre-push hook'));
|
|
333
|
+
expect(bareMsg).toContain('Drift-repaired');
|
|
334
|
+
expect(forceMsg).toContain('Force-overwritten');
|
|
335
|
+
expect(bareMsg).not.toBe(forceMsg);
|
|
336
|
+
});
|
|
337
|
+
// ── bare install never mutates a non-bounded git hook ───────────
|
|
338
|
+
it('bare install never mutates a user hook with an appended totem block (non-bounded)', async () => {
|
|
339
|
+
const userThenTotem = `#!/bin/sh\nrun_my_tests\n# ${TOTEM_PREPUSH_MARKER}\nstale\n# ${TOTEM_PREPUSH_END}\n`;
|
|
340
|
+
fs.mkdirSync(hooksDir(), { recursive: true });
|
|
341
|
+
fs.writeFileSync(path.join(hooksDir(), 'pre-push'), userThenTotem);
|
|
342
|
+
await expect(hooksCommand({})).resolves.toBeUndefined();
|
|
343
|
+
expect(exitSpy).not.toHaveBeenCalled();
|
|
344
|
+
// User content preserved — only --force may overwrite an unbounded file.
|
|
345
|
+
expect(fs.readFileSync(path.join(hooksDir(), 'pre-push'), 'utf-8')).toBe(userThenTotem);
|
|
346
|
+
});
|
|
347
|
+
});
|
|
348
|
+
// ─── sanity: installHooksNonInteractive still classifies a fresh repo ─
|
|
349
|
+
describe('installHooksNonInteractive (contract sanity)', () => {
|
|
350
|
+
let tmpDir;
|
|
351
|
+
beforeEach(() => {
|
|
352
|
+
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'totem-2410-ni-'));
|
|
353
|
+
});
|
|
354
|
+
afterEach(() => {
|
|
355
|
+
cleanTmpDir(tmpDir);
|
|
356
|
+
});
|
|
357
|
+
it('returns null outside a git repo (declared skip, exit 0 at the command edge)', () => {
|
|
358
|
+
expect(installHooksNonInteractive(tmpDir)).toBeNull();
|
|
359
|
+
});
|
|
360
|
+
});
|
|
361
|
+
// ─── Worktree + gitdir-pointer resolution (mmnto-ai/totem#2418) ──────
|
|
362
|
+
//
|
|
363
|
+
// In a linked worktree `.git` is a FILE (`gitdir: <path>` pointer), so the
|
|
364
|
+
// pre-fix blind `mkdir '.git/hooks'` crashed ENOTDIR and failed the consumer's
|
|
365
|
+
// whole `pnpm install` through the prepare wrapper. The contract names the
|
|
366
|
+
// worktree/submodule pointer cases: resolvable → install into the SHARED hooks
|
|
367
|
+
// dir (what git actually executes); unparseable → declared skip, exit 0.
|
|
368
|
+
describe('hooksCommand in a linked worktree (mmnto-ai/totem#2418)', () => {
|
|
369
|
+
let mainDir;
|
|
370
|
+
let wtParent;
|
|
371
|
+
let wtDir;
|
|
372
|
+
let originalCwd;
|
|
373
|
+
let errorSpy;
|
|
374
|
+
let exitSpy;
|
|
375
|
+
const sharedHooksDir = () => path.join(mainDir, '.git', 'hooks');
|
|
376
|
+
const errorOutput = () => errorSpy.mock.calls
|
|
377
|
+
.map((c) => c.map((a) => String(a)).join(' '))
|
|
378
|
+
.join('\n');
|
|
379
|
+
beforeEach(() => {
|
|
380
|
+
mainDir = fs.mkdtempSync(path.join(os.tmpdir(), 'totem-2418-main-'));
|
|
381
|
+
execSync('git init', { cwd: mainDir, stdio: 'ignore' });
|
|
382
|
+
// `git worktree add` needs a commit to branch from.
|
|
383
|
+
execSync('git -c user.name=totem -c user.email=totem@test.invalid commit --allow-empty -m init', { cwd: mainDir, stdio: 'ignore' });
|
|
384
|
+
wtParent = fs.mkdtempSync(path.join(os.tmpdir(), 'totem-2418-wt-'));
|
|
385
|
+
wtDir = path.join(wtParent, 'wt');
|
|
386
|
+
// Arg-array spawn — no shell, so the tmp path is never shell-interpreted.
|
|
387
|
+
execFileSync('git', ['worktree', 'add', wtDir], { cwd: mainDir, stdio: 'ignore' });
|
|
388
|
+
originalCwd = process.cwd();
|
|
389
|
+
process.chdir(wtDir);
|
|
390
|
+
errorSpy = vi.spyOn(console, 'error').mockImplementation(() => { });
|
|
391
|
+
exitSpy = vi.spyOn(process, 'exit').mockImplementation(((code) => {
|
|
392
|
+
throw new Error(`process.exit:${code ?? 0}`);
|
|
393
|
+
}));
|
|
394
|
+
});
|
|
395
|
+
afterEach(() => {
|
|
396
|
+
process.chdir(originalCwd);
|
|
397
|
+
vi.restoreAllMocks();
|
|
398
|
+
cleanTmpDir(wtParent);
|
|
399
|
+
cleanTmpDir(mainDir);
|
|
400
|
+
});
|
|
401
|
+
it('resolveHooksDir follows the gitdir pointer to the SHARED hooks dir', () => {
|
|
402
|
+
// The worktree's `.git` is a pointer FILE, not a directory.
|
|
403
|
+
expect(fs.statSync(path.join(wtDir, '.git')).isFile()).toBe(true);
|
|
404
|
+
const resolved = resolveHooksDir(wtDir);
|
|
405
|
+
expect(resolved).not.toBeNull();
|
|
406
|
+
// realpathSync.native both sides: git prints the LONG form while os.tmpdir()
|
|
407
|
+
// can carry a Windows 8.3 alias (RUNNER~1 on GH runners) or a symlinked
|
|
408
|
+
// tmpdir (macOS /var → /private/var); only the native variant expands both.
|
|
409
|
+
expect(fs.realpathSync.native(resolved)).toBe(fs.realpathSync.native(sharedHooksDir()));
|
|
410
|
+
});
|
|
411
|
+
it('resolveHooksDir in a plain checkout stays .git/hooks', () => {
|
|
412
|
+
const resolved = resolveHooksDir(mainDir);
|
|
413
|
+
expect(resolved).not.toBeNull();
|
|
414
|
+
expect(fs.realpathSync.native(resolved)).toBe(fs.realpathSync.native(sharedHooksDir()));
|
|
415
|
+
});
|
|
416
|
+
it('exit 0: install from the worktree lands in the shared hooks dir (no ENOTDIR)', async () => {
|
|
417
|
+
await expect(hooksCommand({})).resolves.toBeUndefined();
|
|
418
|
+
expect(exitSpy).not.toHaveBeenCalled();
|
|
419
|
+
for (const hook of ['pre-commit', 'pre-push', 'post-merge', 'post-checkout']) {
|
|
420
|
+
expect(fs.existsSync(path.join(sharedHooksDir(), hook)), `${hook} missing from the shared hooks dir`).toBe(true);
|
|
421
|
+
}
|
|
422
|
+
// The pointer file survives untouched — nothing tried to mkdir through it.
|
|
423
|
+
expect(fs.statSync(path.join(wtDir, '.git')).isFile()).toBe(true);
|
|
424
|
+
});
|
|
425
|
+
it('--check from the worktree sees the shared hooks (exit 0)', async () => {
|
|
426
|
+
await hooksCommand({});
|
|
427
|
+
errorSpy.mockClear();
|
|
428
|
+
await expect(hooksCommand({ check: true })).resolves.toBeUndefined();
|
|
429
|
+
expect(exitSpy).not.toHaveBeenCalled();
|
|
430
|
+
expect(errorOutput()).toContain('All hooks installed');
|
|
431
|
+
});
|
|
432
|
+
it('installHooksNonInteractive from the worktree classifies all four hooks', () => {
|
|
433
|
+
const result = installHooksNonInteractive(wtDir);
|
|
434
|
+
expect(result).not.toBeNull();
|
|
435
|
+
expect(result.preCommit).toBe('installed');
|
|
436
|
+
expect(result.prePush).toBe('installed');
|
|
437
|
+
expect(result.postMerge).toBe('installed');
|
|
438
|
+
expect(result.postCheckout).toBe('installed');
|
|
439
|
+
});
|
|
440
|
+
});
|
|
441
|
+
describe('hooksCommand with an unparseable .git pointer file (declared skip)', () => {
|
|
442
|
+
let tmpDir;
|
|
443
|
+
let originalCwd;
|
|
444
|
+
let errorSpy;
|
|
445
|
+
let exitSpy;
|
|
446
|
+
beforeEach(() => {
|
|
447
|
+
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'totem-2418-badptr-'));
|
|
448
|
+
// A `.git` FILE whose content is not a `gitdir:` pointer — git reports
|
|
449
|
+
// `fatal: invalid gitfile format` for it.
|
|
450
|
+
fs.writeFileSync(path.join(tmpDir, '.git'), 'not a gitdir pointer\n');
|
|
451
|
+
originalCwd = process.cwd();
|
|
452
|
+
process.chdir(tmpDir);
|
|
453
|
+
errorSpy = vi.spyOn(console, 'error').mockImplementation(() => { });
|
|
454
|
+
exitSpy = vi.spyOn(process, 'exit').mockImplementation(((code) => {
|
|
455
|
+
throw new Error(`process.exit:${code ?? 0}`);
|
|
456
|
+
}));
|
|
457
|
+
});
|
|
458
|
+
afterEach(() => {
|
|
459
|
+
process.chdir(originalCwd);
|
|
460
|
+
vi.restoreAllMocks();
|
|
461
|
+
cleanTmpDir(tmpDir);
|
|
462
|
+
});
|
|
463
|
+
it('exit 0: install declares the skip instead of crashing prepare', async () => {
|
|
464
|
+
await expect(hooksCommand({})).resolves.toBeUndefined();
|
|
465
|
+
expect(exitSpy).not.toHaveBeenCalled();
|
|
466
|
+
const out = errorSpy.mock.calls
|
|
467
|
+
.map((c) => c.map((a) => String(a)).join(' '))
|
|
468
|
+
.join('\n');
|
|
469
|
+
expect(out).toContain('not a directory or a resolvable gitdir pointer');
|
|
470
|
+
});
|
|
471
|
+
it('resolveHooksDir returns null for the unparseable pointer (never a blind join)', () => {
|
|
472
|
+
expect(resolveHooksDir(tmpDir)).toBeNull();
|
|
473
|
+
});
|
|
474
|
+
it('legacy installHooksCommand declares the skip too — exit 0, never handleError (#2422 round)', async () => {
|
|
475
|
+
// The hidden `totem install-hooks` command routes here; pre-fix its callees
|
|
476
|
+
// let the resolveGitRoot throw reach handleError → exit 1, violating the
|
|
477
|
+
// #2410 declared-skip contract on that entry point.
|
|
478
|
+
await expect(installHooksCommand()).resolves.toBeUndefined();
|
|
479
|
+
expect(exitSpy).not.toHaveBeenCalled();
|
|
480
|
+
const out = errorSpy.mock.calls
|
|
481
|
+
.map((c) => c.map((a) => String(a)).join(' '))
|
|
482
|
+
.join('\n');
|
|
483
|
+
expect(out).toContain('not a directory or a resolvable gitdir pointer');
|
|
484
|
+
});
|
|
485
|
+
it('installHooksNonInteractive maps the bad pointer to the declared-skip null (direct API path)', () => {
|
|
486
|
+
expect(installHooksNonInteractive(tmpDir)).toBeNull();
|
|
487
|
+
});
|
|
488
|
+
});
|
|
489
|
+
describe('resolveHooksDir with core.hooksPath aimed at a non-directory (#2422 round)', () => {
|
|
490
|
+
let tmpDir;
|
|
491
|
+
beforeEach(() => {
|
|
492
|
+
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'totem-2418-hookspath-'));
|
|
493
|
+
execSync('git init', { cwd: tmpDir, stdio: 'ignore' });
|
|
494
|
+
});
|
|
495
|
+
afterEach(() => {
|
|
496
|
+
cleanTmpDir(tmpDir);
|
|
497
|
+
});
|
|
498
|
+
it('returns null instead of a write-target that can never receive hooks', () => {
|
|
499
|
+
// The /dev/null hooks-disabled idiom, portably: point core.hooksPath at an
|
|
500
|
+
// existing FILE. `git rev-parse --git-path hooks` returns it verbatim; the
|
|
501
|
+
// resolver must classify it as the declared skip, not hand it to mkdir.
|
|
502
|
+
const notADir = path.join(tmpDir, 'hooks-disabled.txt');
|
|
503
|
+
fs.writeFileSync(notADir, 'not a directory\n');
|
|
504
|
+
execFileSync('git', ['config', 'core.hooksPath', notADir], { cwd: tmpDir });
|
|
505
|
+
expect(resolveHooksDir(tmpDir)).toBeNull();
|
|
506
|
+
});
|
|
507
|
+
});
|
|
508
|
+
//# 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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"}
|
|
@@ -7,6 +7,20 @@ export declare const TOTEM_PRECOMMIT_MARKER = "[totem] pre-commit hook";
|
|
|
7
7
|
export declare const TOTEM_PRECOMMIT_END = "[totem] end pre-commit";
|
|
8
8
|
export declare const TOTEM_PREPUSH_MARKER = "[totem] pre-push hook";
|
|
9
9
|
export declare const TOTEM_PREPUSH_END = "[totem] end pre-push";
|
|
10
|
+
/**
|
|
11
|
+
* Resolve the git hooks directory for `gitRoot`. In a plain checkout this is
|
|
12
|
+
* `.git/hooks`, but in a linked worktree (or submodule) `.git` is a FILE
|
|
13
|
+
* (`gitdir: <path>` pointer) and hooks live under the resolved git dir — shared
|
|
14
|
+
* across worktrees via `commondir` — so a blind `.git/hooks` join makes
|
|
15
|
+
* `mkdirSync` crash with ENOTDIR (mmnto-ai/totem#2418; the owner-repo
|
|
16
|
+
* `tools/install-hooks.js` variant already discriminates). Resolution is
|
|
17
|
+
* delegated to `git rev-parse --git-path hooks` — git's own worktree/commondir
|
|
18
|
+
* walk, which also honors `core.hooksPath` — with a filesystem probe as the
|
|
19
|
+
* offline fallback for the plain-directory layout. Returns null when no hooks
|
|
20
|
+
* directory can be resolved: the #2410 declared-skip class — callers skip
|
|
21
|
+
* loudly instead of guessing a path.
|
|
22
|
+
*/
|
|
23
|
+
export declare function resolveHooksDir(gitRoot: string): string | null;
|
|
10
24
|
/**
|
|
11
25
|
* Determine the package-manager fallback command for invoking totem.
|
|
12
26
|
* Used inside the runtime resolve block when `totem` is not on PATH.
|
|
@@ -99,6 +113,45 @@ export declare function hooksCommand(opts: {
|
|
|
99
113
|
strict?: boolean;
|
|
100
114
|
standard?: boolean;
|
|
101
115
|
}): Promise<void>;
|
|
116
|
+
/**
|
|
117
|
+
* The action taken on one managed session-hook artifact by
|
|
118
|
+
* {@link regenerateManagedSessionHooks}:
|
|
119
|
+
* - `exists` — present, marker-headed, already byte-identical to canonical (no write).
|
|
120
|
+
* - `overwritten` — regenerated: a bare bounded drift-repair OR a `--force` overwrite.
|
|
121
|
+
* - `declined` — marker present but the region is NOT bounded-owned (legacy file
|
|
122
|
+
* with no end marker, or user content after the end marker) and no
|
|
123
|
+
* `--force`: left untouched, takes one `totem hook install --force`.
|
|
124
|
+
* - `skipped` — a user-owned file carrying NO totem marker at all: never touched,
|
|
125
|
+
* not even under `--force`.
|
|
126
|
+
*/
|
|
127
|
+
export type ManagedSessionHookAction = 'exists' | 'overwritten' | 'declined' | 'skipped';
|
|
128
|
+
export interface ManagedSessionHookResult {
|
|
129
|
+
/** Repo-relative path of the artifact. */
|
|
130
|
+
file: string;
|
|
131
|
+
action: ManagedSessionHookAction;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Walk the {@link MANAGED_SESSION_HOOKS} roster and regenerate the whole-file
|
|
135
|
+
* session-hook artifacts (`.claude/hooks/*.cjs`, `.gemini/hooks/*.js`) that EXIST
|
|
136
|
+
* under `cwd`, applying the #2406 bounded-ownership semantics generalized to the
|
|
137
|
+
* JS/CJS hook family:
|
|
138
|
+
*
|
|
139
|
+
* - Missing file → not created (creation is `totem init`'s job); omitted
|
|
140
|
+
* from the results entirely.
|
|
141
|
+
* - Marker + identical → `exists` (already current).
|
|
142
|
+
* - Marker + drifted, bounded totem-owned whole file → bare drift-repair
|
|
143
|
+
* (`overwritten`), or `--force` → `overwritten`.
|
|
144
|
+
* - Marker + drifted, unbounded (legacy no-end-marker / trailing user content):
|
|
145
|
+
* bare → `declined`; `--force` → `overwritten`.
|
|
146
|
+
* - Marker does not OPEN the file (no marker, or a merely-quoted marker) →
|
|
147
|
+
* `skipped` even under `--force` (never clobber a
|
|
148
|
+
* user-owned file).
|
|
149
|
+
*
|
|
150
|
+
* Regenerate-only-if-present, single-writer per invocation. A write failure
|
|
151
|
+
* (perms/FS) PROPAGATES (Tenet 4 — a hook the tool cannot write must fail loud,
|
|
152
|
+
* never silently report success), mirroring `installGitHook`.
|
|
153
|
+
*/
|
|
154
|
+
export declare function regenerateManagedSessionHooks(cwd: string, force?: boolean): Promise<ManagedSessionHookResult[]>;
|
|
102
155
|
/**
|
|
103
156
|
* Silently upgrade the pre-push hook if it was installed by Totem but uses
|
|
104
157
|
* 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":"
|
|
1
|
+
{"version":3,"file":"install-hooks.d.ts","sourceRoot":"","sources":["../../src/commands/install-hooks.ts"],"names":[],"mappings":"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"}
|