@mmnto/cli 0.23.0 → 0.25.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.
@@ -0,0 +1,221 @@
1
+ import * as fs from 'node:fs';
2
+ import * as os from 'node:os';
3
+ import * as path from 'node:path';
4
+ import { afterEach, beforeEach, describe, expect, it } from 'vitest';
5
+ import { buildPreCommitHook, buildPrePushHook, detectTotemPrefix, installGitHook, TOTEM_PRECOMMIT_MARKER, TOTEM_PREPUSH_MARKER, } from './install-hooks.js';
6
+ describe('detectTotemPrefix', () => {
7
+ let tmpDir;
8
+ beforeEach(() => {
9
+ tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'totem-detect-'));
10
+ });
11
+ afterEach(() => {
12
+ fs.rmSync(tmpDir, { recursive: true, force: true });
13
+ });
14
+ it('returns pnpm exec when pnpm-lock.yaml exists', () => {
15
+ fs.writeFileSync(path.join(tmpDir, 'pnpm-lock.yaml'), '');
16
+ expect(detectTotemPrefix(tmpDir)).toBe('pnpm exec totem');
17
+ });
18
+ it('returns yarn when yarn.lock exists', () => {
19
+ fs.writeFileSync(path.join(tmpDir, 'yarn.lock'), '');
20
+ expect(detectTotemPrefix(tmpDir)).toBe('yarn totem');
21
+ });
22
+ it('returns bunx when bun.lockb exists (legacy)', () => {
23
+ fs.writeFileSync(path.join(tmpDir, 'bun.lockb'), '');
24
+ expect(detectTotemPrefix(tmpDir)).toBe('bunx totem');
25
+ });
26
+ it('returns bunx when bun.lock exists (Bun >= 1.2)', () => {
27
+ fs.writeFileSync(path.join(tmpDir, 'bun.lock'), '');
28
+ expect(detectTotemPrefix(tmpDir)).toBe('bunx totem');
29
+ });
30
+ it('falls back to npx when no lockfile exists', () => {
31
+ expect(detectTotemPrefix(tmpDir)).toBe('npx totem');
32
+ });
33
+ it('prefers pnpm over bun when both lockfiles exist', () => {
34
+ fs.writeFileSync(path.join(tmpDir, 'pnpm-lock.yaml'), '');
35
+ fs.writeFileSync(path.join(tmpDir, 'bun.lock'), '');
36
+ expect(detectTotemPrefix(tmpDir)).toBe('pnpm exec totem');
37
+ });
38
+ it('prefers yarn over bun when both lockfiles exist', () => {
39
+ fs.writeFileSync(path.join(tmpDir, 'yarn.lock'), '');
40
+ fs.writeFileSync(path.join(tmpDir, 'bun.lockb'), '');
41
+ expect(detectTotemPrefix(tmpDir)).toBe('yarn totem');
42
+ });
43
+ });
44
+ describe('buildPreCommitHook', () => {
45
+ it('contains the marker for idempotency', () => {
46
+ const hook = buildPreCommitHook();
47
+ expect(hook).toContain(TOTEM_PRECOMMIT_MARKER);
48
+ });
49
+ it('blocks main and master branches', () => {
50
+ const hook = buildPreCommitHook();
51
+ expect(hook).toContain('"main"');
52
+ expect(hook).toContain('"master"');
53
+ });
54
+ it('prints a helpful error message with override instructions', () => {
55
+ const hook = buildPreCommitHook();
56
+ expect(hook).toContain('git checkout -b feat/my-feature');
57
+ expect(hook).toContain('git commit --no-verify');
58
+ });
59
+ it('starts with a shebang', () => {
60
+ const hook = buildPreCommitHook();
61
+ expect(hook).toMatch(/^#!\/bin\/sh\n/);
62
+ });
63
+ it('exits with code 1 when on protected branch', () => {
64
+ const hook = buildPreCommitHook();
65
+ expect(hook).toContain('exit 1');
66
+ });
67
+ });
68
+ describe('buildPrePushHook', () => {
69
+ const shieldCmd = 'pnpm exec totem shield --deterministic';
70
+ it('contains the marker for idempotency', () => {
71
+ const hook = buildPrePushHook(shieldCmd);
72
+ expect(hook).toContain(TOTEM_PREPUSH_MARKER);
73
+ });
74
+ it('only runs shield when compiled-rules.json exists (if/fi, safe for appending)', () => {
75
+ const hook = buildPrePushHook(shieldCmd);
76
+ expect(hook).toContain('if [ -f ".totem/compiled-rules.json" ]; then');
77
+ expect(hook).toContain('fi');
78
+ // Must use if/fi guard, NOT `&& exit 0` which would terminate appended hooks early
79
+ expect(hook).not.toContain('&& exit 0');
80
+ });
81
+ it('runs the shield command when rules exist', () => {
82
+ const hook = buildPrePushHook(shieldCmd);
83
+ expect(hook).toContain(shieldCmd);
84
+ });
85
+ it('mentions --no-verify override', () => {
86
+ const hook = buildPrePushHook(shieldCmd);
87
+ expect(hook).toContain('git push --no-verify');
88
+ });
89
+ it('starts with a shebang', () => {
90
+ const hook = buildPrePushHook(shieldCmd);
91
+ expect(hook).toMatch(/^#!\/bin\/sh\n/);
92
+ });
93
+ it('uses the provided shield command (respects package manager)', () => {
94
+ const npxHook = buildPrePushHook('npx totem shield --deterministic');
95
+ expect(npxHook).toContain('npx totem shield --deterministic');
96
+ const yarnHook = buildPrePushHook('yarn totem shield --deterministic');
97
+ expect(yarnHook).toContain('yarn totem shield --deterministic');
98
+ });
99
+ });
100
+ describe('installGitHook', () => {
101
+ let tmpDir;
102
+ let hooksDir;
103
+ beforeEach(() => {
104
+ tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'totem-hooks-'));
105
+ hooksDir = path.join(tmpDir, '.git', 'hooks');
106
+ });
107
+ afterEach(() => {
108
+ fs.rmSync(tmpDir, { recursive: true, force: true });
109
+ });
110
+ it('creates a new hook file when none exists', () => {
111
+ const content = buildPreCommitHook();
112
+ const result = installGitHook(hooksDir, 'pre-commit', content, TOTEM_PRECOMMIT_MARKER);
113
+ expect(result).toBe('installed');
114
+ expect(fs.existsSync(path.join(hooksDir, 'pre-commit'))).toBe(true);
115
+ const written = fs.readFileSync(path.join(hooksDir, 'pre-commit'), 'utf-8');
116
+ expect(written).toContain(TOTEM_PRECOMMIT_MARKER);
117
+ });
118
+ it('creates parent directories as needed', () => {
119
+ expect(fs.existsSync(hooksDir)).toBe(false);
120
+ installGitHook(hooksDir, 'pre-commit', buildPreCommitHook(), TOTEM_PRECOMMIT_MARKER);
121
+ expect(fs.existsSync(hooksDir)).toBe(true);
122
+ });
123
+ it('returns exists when marker is already present (idempotent)', () => {
124
+ const content = buildPreCommitHook();
125
+ installGitHook(hooksDir, 'pre-commit', content, TOTEM_PRECOMMIT_MARKER);
126
+ const result = installGitHook(hooksDir, 'pre-commit', content, TOTEM_PRECOMMIT_MARKER);
127
+ expect(result).toBe('exists');
128
+ });
129
+ it('appends to existing hook without marker (preserves user hooks)', () => {
130
+ fs.mkdirSync(hooksDir, { recursive: true });
131
+ const hookPath = path.join(hooksDir, 'pre-commit');
132
+ const userHook = '#!/bin/sh\necho "user hook"\n';
133
+ fs.writeFileSync(hookPath, userHook);
134
+ const result = installGitHook(hooksDir, 'pre-commit', buildPreCommitHook(), TOTEM_PRECOMMIT_MARKER);
135
+ expect(result).toBe('appended');
136
+ const written = fs.readFileSync(hookPath, 'utf-8');
137
+ expect(written).toContain('echo "user hook"');
138
+ expect(written).toContain(TOTEM_PRECOMMIT_MARKER);
139
+ // Should not duplicate shebang when appending
140
+ expect((written.match(/^#!\/bin\/sh$/gm) ?? []).length).toBe(1);
141
+ });
142
+ it('does not clobber existing hook content', () => {
143
+ fs.mkdirSync(hooksDir, { recursive: true });
144
+ const hookPath = path.join(hooksDir, 'pre-push');
145
+ const userHook = '#!/bin/sh\nrun_my_tests\n';
146
+ fs.writeFileSync(hookPath, userHook);
147
+ installGitHook(hooksDir, 'pre-push', buildPrePushHook('npx totem shield --deterministic'), TOTEM_PREPUSH_MARKER);
148
+ const written = fs.readFileSync(hookPath, 'utf-8');
149
+ expect(written).toContain('run_my_tests');
150
+ expect(written).toContain(TOTEM_PREPUSH_MARKER);
151
+ });
152
+ it('is idempotent — double install does not duplicate', () => {
153
+ const content = buildPrePushHook('npx totem shield --deterministic');
154
+ installGitHook(hooksDir, 'pre-push', content, TOTEM_PREPUSH_MARKER);
155
+ installGitHook(hooksDir, 'pre-push', content, TOTEM_PREPUSH_MARKER);
156
+ const written = fs.readFileSync(path.join(hooksDir, 'pre-push'), 'utf-8');
157
+ const matches = written.match(new RegExp(TOTEM_PREPUSH_MARKER.replace(/[[\]]/g, '\\$&'), 'g'));
158
+ expect(matches).toHaveLength(1);
159
+ });
160
+ it('returns skipped-non-shell for Node hook (does not corrupt file)', () => {
161
+ fs.mkdirSync(hooksDir, { recursive: true });
162
+ const hookPath = path.join(hooksDir, 'pre-commit');
163
+ const nodeHook = '#!/usr/bin/env node\nconsole.log("lint");\n'; // totem-ignore — test fixture, not real logging
164
+ fs.writeFileSync(hookPath, nodeHook);
165
+ const result = installGitHook(hooksDir, 'pre-commit', buildPreCommitHook(), TOTEM_PRECOMMIT_MARKER);
166
+ expect(result).toBe('skipped-non-shell');
167
+ const written = fs.readFileSync(hookPath, 'utf-8');
168
+ expect(written).toBe(nodeHook); // File untouched
169
+ });
170
+ it('returns skipped-non-shell for Python hook', () => {
171
+ fs.mkdirSync(hooksDir, { recursive: true });
172
+ const hookPath = path.join(hooksDir, 'pre-push');
173
+ const pythonHook = '#!/usr/bin/env python3\nimport subprocess\n';
174
+ fs.writeFileSync(hookPath, pythonHook);
175
+ const result = installGitHook(hooksDir, 'pre-push', buildPrePushHook('npx totem shield --deterministic'), TOTEM_PREPUSH_MARKER);
176
+ expect(result).toBe('skipped-non-shell');
177
+ const written = fs.readFileSync(hookPath, 'utf-8');
178
+ expect(written).toBe(pythonHook); // File untouched
179
+ });
180
+ it('appends normally to sh hooks', () => {
181
+ fs.mkdirSync(hooksDir, { recursive: true });
182
+ const hookPath = path.join(hooksDir, 'pre-commit');
183
+ fs.writeFileSync(hookPath, '#!/bin/sh\necho "existing"\n');
184
+ const result = installGitHook(hooksDir, 'pre-commit', buildPreCommitHook(), TOTEM_PRECOMMIT_MARKER);
185
+ expect(result).toBe('appended');
186
+ });
187
+ it('appends normally to bash hooks', () => {
188
+ fs.mkdirSync(hooksDir, { recursive: true });
189
+ const hookPath = path.join(hooksDir, 'pre-commit');
190
+ fs.writeFileSync(hookPath, '#!/bin/bash\necho "existing"\n');
191
+ const result = installGitHook(hooksDir, 'pre-commit', buildPreCommitHook(), TOTEM_PRECOMMIT_MARKER);
192
+ expect(result).toBe('appended');
193
+ });
194
+ it('appends normally to env bash hooks', () => {
195
+ fs.mkdirSync(hooksDir, { recursive: true });
196
+ const hookPath = path.join(hooksDir, 'pre-commit');
197
+ fs.writeFileSync(hookPath, '#!/usr/bin/env bash\necho "existing"\n');
198
+ const result = installGitHook(hooksDir, 'pre-commit', buildPreCommitHook(), TOTEM_PRECOMMIT_MARKER);
199
+ expect(result).toBe('appended');
200
+ });
201
+ it('appends to hooks without a shebang (plain text)', () => {
202
+ fs.mkdirSync(hooksDir, { recursive: true });
203
+ const hookPath = path.join(hooksDir, 'pre-commit');
204
+ fs.writeFileSync(hookPath, 'echo "no shebang"\n');
205
+ const result = installGitHook(hooksDir, 'pre-commit', buildPreCommitHook(), TOTEM_PRECOMMIT_MARKER);
206
+ expect(result).toBe('appended');
207
+ });
208
+ it('handles pre-commit and pre-push independently', () => {
209
+ installGitHook(hooksDir, 'pre-commit', buildPreCommitHook(), TOTEM_PRECOMMIT_MARKER);
210
+ installGitHook(hooksDir, 'pre-push', buildPrePushHook('pnpm exec totem shield --deterministic'), TOTEM_PREPUSH_MARKER);
211
+ expect(fs.existsSync(path.join(hooksDir, 'pre-commit'))).toBe(true);
212
+ expect(fs.existsSync(path.join(hooksDir, 'pre-push'))).toBe(true);
213
+ const preCommit = fs.readFileSync(path.join(hooksDir, 'pre-commit'), 'utf-8');
214
+ const prePush = fs.readFileSync(path.join(hooksDir, 'pre-push'), 'utf-8');
215
+ expect(preCommit).toContain(TOTEM_PRECOMMIT_MARKER);
216
+ expect(preCommit).not.toContain(TOTEM_PREPUSH_MARKER);
217
+ expect(prePush).toContain(TOTEM_PREPUSH_MARKER);
218
+ expect(prePush).not.toContain(TOTEM_PRECOMMIT_MARKER);
219
+ });
220
+ });
221
+ //# sourceMappingURL=install-hooks.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install-hooks.test.js","sourceRoot":"","sources":["../../src/commands/install-hooks.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=shield-eval.integration.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shield-eval.integration.test.d.ts","sourceRoot":"","sources":["../../src/commands/shield-eval.integration.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,321 @@
1
+ /**
2
+ * Adversarial Evaluation Harness — Model Drift Detection
3
+ *
4
+ * Sets up a real git repository with planted architectural violations
5
+ * and corresponding Totem lessons, then runs `totem shield` to verify
6
+ * that both deterministic and LLM modes catch the planted traps.
7
+ *
8
+ * Deterministic tests run on every CI run (no API keys needed).
9
+ * LLM tests are gated behind CI_INTEGRATION=true (nightly only).
10
+ *
11
+ * Run locally:
12
+ * pnpm --filter @mmnto/cli vitest run -c vitest.integration.config.ts shield-eval
13
+ * CI_INTEGRATION=true GEMINI_API_KEY=... pnpm --filter @mmnto/cli vitest run -c vitest.integration.config.ts shield-eval
14
+ *
15
+ * @see https://github.com/mmnto-ai/totem/issues/196
16
+ */
17
+ import { execSync } from 'node:child_process';
18
+ import * as fs from 'node:fs';
19
+ import * as os from 'node:os';
20
+ import * as path from 'node:path';
21
+ import { afterEach, beforeEach, describe, expect, it } from 'vitest';
22
+ import { applyRules, applyRulesToAdditions, extractAddedLines, hashLesson, } from '@mmnto/totem';
23
+ import { parseVerdict } from './shield.js';
24
+ // ─── Adversarial Fixtures ────────────────────────────
25
+ /** Planted trap rules that map to specific violations in the bad code. */
26
+ const TRAP_RULES = [
27
+ {
28
+ lessonHash: hashLesson('Use fs/promises not fs', 'TRAP-001: Never import fs directly'),
29
+ lessonHeading: 'Use fs/promises not fs',
30
+ pattern: 'import\\s+.*\\bfrom\\s+[\'"]fs[\'"]',
31
+ message: 'TRAP-001: Never import fs directly — use fs/promises for async safety',
32
+ engine: 'regex',
33
+ compiledAt: new Date().toISOString(),
34
+ },
35
+ {
36
+ lessonHash: hashLesson('No console.log in library code', 'TRAP-002'),
37
+ lessonHeading: 'No console.log in library code',
38
+ pattern: 'console\\.log\\(',
39
+ message: 'TRAP-002: Use structured logger, not console.log, in library code',
40
+ engine: 'regex',
41
+ compiledAt: new Date().toISOString(),
42
+ },
43
+ {
44
+ lessonHash: hashLesson('Catch blocks use err not error', 'TRAP-003'),
45
+ lessonHeading: 'Catch blocks use err not error',
46
+ pattern: 'catch\\s*\\(\\s*error\\s*[\\):]',
47
+ message: 'TRAP-003: Use err (not error) in catch blocks — project convention',
48
+ engine: 'regex',
49
+ compiledAt: new Date().toISOString(),
50
+ },
51
+ {
52
+ lessonHash: hashLesson('No sync file reads', 'TRAP-004'),
53
+ lessonHeading: 'No sync file reads',
54
+ pattern: 'readFileSync',
55
+ message: 'TRAP-004: Use async readFile, not readFileSync, in request handlers',
56
+ engine: 'regex',
57
+ compiledAt: new Date().toISOString(),
58
+ },
59
+ ];
60
+ /** Totem lessons that match the trap rules (for LLM mode context). */
61
+ const TRAP_LESSONS = `# Lessons
62
+
63
+ ## Lesson — Use fs/promises not fs
64
+ TRAP-001: Never import \`fs\` directly in library code. Always use \`fs/promises\`
65
+ for async safety. Direct \`fs\` imports lead to blocking I/O in request handlers.
66
+
67
+ ## Lesson — No console.log in library code
68
+ TRAP-002: Library modules must use a structured logger (onWarn callback or
69
+ similar pattern), never \`console.log()\`. Console output breaks MCP stdio
70
+ transport and pollutes test output.
71
+
72
+ ## Lesson — Catch blocks use err not error
73
+ TRAP-003: All catch blocks must use \`err\` as the variable name, never \`error\`.
74
+ This is a project-wide convention enforced by the style guide.
75
+
76
+ ## Lesson — No sync file reads
77
+ TRAP-004: Never use \`readFileSync\` in request handlers or hot paths. Use
78
+ \`readFile\` from \`fs/promises\` for non-blocking I/O.
79
+ `;
80
+ /** Clean code that passes all rules — used as baseline commit. */
81
+ const CLEAN_CODE = `import { readFile } from 'fs/promises';
82
+
83
+ export async function loadConfig(configPath: string): Promise<string> {
84
+ try {
85
+ const content = await readFile(configPath, 'utf-8');
86
+ return content;
87
+ } catch (err) {
88
+ throw new Error(\`Failed to load config: \${(err as Error).message}\`);
89
+ }
90
+ }
91
+ `;
92
+ /** Bad code with 4 planted violations — staged after baseline. */
93
+ const BAD_CODE = `import fs from 'fs';
94
+
95
+ export async function loadConfig(configPath: string): Promise<string> {
96
+ try {
97
+ console.log('Loading config from', configPath);
98
+ const content = fs.readFileSync(configPath, 'utf-8');
99
+ return content;
100
+ } catch (error) {
101
+ throw new Error(\`Failed to load config: \${(error as Error).message}\`);
102
+ }
103
+ }
104
+ `;
105
+ /** The diff that shield will see (pre-computed for deterministic tests). */
106
+ const EXPECTED_DIFF = `diff --git a/src/config.ts b/src/config.ts
107
+ --- a/src/config.ts
108
+ +++ b/src/config.ts
109
+ @@ -1,9 +1,10 @@
110
+ -import { readFile } from 'fs/promises';
111
+ +import fs from 'fs';
112
+
113
+ export async function loadConfig(configPath: string): Promise<string> {
114
+ try {
115
+ - const content = await readFile(configPath, 'utf-8');
116
+ + console.log('Loading config from', configPath);
117
+ + const content = fs.readFileSync(configPath, 'utf-8');
118
+ return content;
119
+ - } catch (err) {
120
+ - throw new Error(\`Failed to load config: \${(err as Error).message}\`);
121
+ + } catch (error) {
122
+ + throw new Error(\`Failed to load config: \${(error as Error).message}\`);
123
+ }
124
+ }
125
+ `;
126
+ // ─── Test helpers ────────────────────────────────────
127
+ function git(cmd, cwd) {
128
+ return execSync(`git ${cmd}`, {
129
+ cwd,
130
+ encoding: 'utf-8',
131
+ timeout: 15_000,
132
+ env: { ...process.env, GIT_TERMINAL_PROMPT: '0' },
133
+ }).trim();
134
+ }
135
+ function scaffoldAdversarialRepo(tmpDir) {
136
+ // Initialize git repo
137
+ git('init', tmpDir);
138
+ git('config user.email "eval@totem.dev"', tmpDir);
139
+ git('config user.name "Totem Eval"', tmpDir);
140
+ // Create directory structure
141
+ const srcDir = path.join(tmpDir, 'src');
142
+ const totemDir = path.join(tmpDir, '.totem');
143
+ fs.mkdirSync(srcDir, { recursive: true });
144
+ fs.mkdirSync(totemDir, { recursive: true });
145
+ // Write clean baseline
146
+ fs.writeFileSync(path.join(srcDir, 'config.ts'), CLEAN_CODE);
147
+ fs.writeFileSync(path.join(totemDir, 'lessons.md'), TRAP_LESSONS);
148
+ // Write compiled rules for deterministic mode
149
+ const rulesFile = {
150
+ version: 1,
151
+ rules: TRAP_RULES,
152
+ };
153
+ fs.writeFileSync(path.join(totemDir, 'compiled-rules.json'), JSON.stringify(rulesFile, null, 2));
154
+ // Commit baseline
155
+ git('add -A', tmpDir);
156
+ git('commit -m "baseline: clean code"', tmpDir);
157
+ // Stage bad code (this creates the diff shield will see)
158
+ fs.writeFileSync(path.join(srcDir, 'config.ts'), BAD_CODE);
159
+ git('add -A', tmpDir);
160
+ }
161
+ // ─── Deterministic evaluation (no API keys) ─────────
162
+ describe('Adversarial Eval — Deterministic', () => {
163
+ it('catches all 4 planted traps via compiled rules against expected diff', () => {
164
+ const violations = applyRules(TRAP_RULES, EXPECTED_DIFF);
165
+ expect(violations.length).toBeGreaterThanOrEqual(4); // totem-ignore
166
+ const headings = new Set(violations.map((v) => v.rule.lessonHeading));
167
+ expect(headings.has('Use fs/promises not fs')).toBe(true);
168
+ expect(headings.has('No console.log in library code')).toBe(true);
169
+ expect(headings.has('Catch blocks use err not error')).toBe(true);
170
+ expect(headings.has('No sync file reads')).toBe(true);
171
+ });
172
+ it('catches all traps with AST-aware additions pipeline', () => {
173
+ const additions = extractAddedLines(EXPECTED_DIFF);
174
+ const violations = applyRulesToAdditions(TRAP_RULES, additions);
175
+ // extractAddedLines only processes + lines, so we should still catch violations
176
+ const headings = new Set(violations.map((v) => v.rule.lessonHeading));
177
+ expect(headings.has('Use fs/promises not fs')).toBe(true);
178
+ expect(headings.has('No console.log in library code')).toBe(true);
179
+ expect(headings.has('No sync file reads')).toBe(true);
180
+ expect(headings.has('Catch blocks use err not error')).toBe(true);
181
+ });
182
+ it('passes a clean diff with zero violations', () => {
183
+ const cleanDiff = `diff --git a/src/clean.ts b/src/clean.ts
184
+ --- a/src/clean.ts
185
+ +++ b/src/clean.ts
186
+ @@ -1,3 +1,5 @@
187
+ export function greet(name: string): string {
188
+ - return 'hello';
189
+ + return \`Hello, \${name}!\`;
190
+ }
191
+ `;
192
+ const violations = applyRules(TRAP_RULES, cleanDiff);
193
+ expect(violations).toHaveLength(0);
194
+ });
195
+ it('sets up a real git repo and produces a valid diff', () => {
196
+ const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'totem-eval-'));
197
+ try {
198
+ scaffoldAdversarialRepo(tmpDir);
199
+ // Verify the staged diff contains our planted violations
200
+ const diff = git('diff --staged', tmpDir);
201
+ expect(diff).toContain("import fs from 'fs'");
202
+ expect(diff).toContain('console.log');
203
+ expect(diff).toContain('readFileSync');
204
+ expect(diff).toContain('catch (error)');
205
+ // Run compiled rules against the real diff
206
+ const violations = applyRules(TRAP_RULES, diff);
207
+ expect(violations.length).toBeGreaterThanOrEqual(4); // totem-ignore
208
+ }
209
+ finally {
210
+ fs.rmSync(tmpDir, { recursive: true, force: true });
211
+ }
212
+ });
213
+ });
214
+ // ─── LLM evaluation (nightly, requires API keys) ────
215
+ const EVAL_TIMEOUT_MS = 120_000; // 2 min — LLM can be slow
216
+ describe.runIf(process.env['CI_INTEGRATION'] === 'true')('Adversarial Eval — LLM Model Drift', () => {
217
+ let tmpDir;
218
+ beforeEach(() => {
219
+ tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'totem-eval-llm-'));
220
+ scaffoldAdversarialRepo(tmpDir);
221
+ });
222
+ afterEach(() => {
223
+ fs.rmSync(tmpDir, { recursive: true, force: true });
224
+ });
225
+ /**
226
+ * Run shield as a subprocess against the adversarial repo.
227
+ * Returns stdout, stderr, and exit code.
228
+ */
229
+ function runShield(args, env = {}) {
230
+ const cliEntry = path.resolve('dist/index.js');
231
+ const cmd = `node ${cliEntry} shield ${args.join(' ')}`;
232
+ try {
233
+ const stdout = execSync(cmd, {
234
+ cwd: tmpDir,
235
+ encoding: 'utf-8',
236
+ timeout: EVAL_TIMEOUT_MS,
237
+ env: {
238
+ ...process.env,
239
+ ...env,
240
+ GIT_TERMINAL_PROMPT: '0',
241
+ },
242
+ stdio: ['pipe', 'pipe', 'pipe'],
243
+ });
244
+ return { stdout, stderr: '', exitCode: 0 };
245
+ }
246
+ catch (err) {
247
+ const e = err;
248
+ return {
249
+ stdout: e.stdout ?? '',
250
+ stderr: e.stderr ?? '',
251
+ exitCode: e.status ?? 1,
252
+ };
253
+ }
254
+ }
255
+ it('deterministic shield exits 1 and catches planted traps via subprocess', () => {
256
+ const { exitCode, stdout, stderr } = runShield(['--deterministic', '--staged']);
257
+ const output = stdout + stderr;
258
+ expect(exitCode).toBe(1);
259
+ expect(output).toContain('TRAP-001');
260
+ expect(output).toContain('TRAP-002');
261
+ expect(output).toContain('TRAP-003');
262
+ expect(output).toContain('TRAP-004');
263
+ }, EVAL_TIMEOUT_MS);
264
+ // Gemini model drift test
265
+ it.runIf(!!process.env['GEMINI_API_KEY'])('Gemini catches planted traps (FAIL verdict expected)', async () => {
266
+ // Write a minimal totem.config.ts for the adversarial repo
267
+ const config = `
268
+ export default {
269
+ targets: [{ glob: 'src/**/*.ts', type: 'code', strategy: 'typescript-ast' }],
270
+ totemDir: '.totem',
271
+ lanceDir: '.lancedb',
272
+ orchestrator: { provider: 'gemini', model: 'gemini-2.5-flash' },
273
+ };
274
+ `;
275
+ fs.writeFileSync(path.join(tmpDir, 'totem.config.ts'), config);
276
+ const { exitCode, stdout, stderr } = runShield(['--staged', '--mode=structural'], {
277
+ GEMINI_API_KEY: process.env['GEMINI_API_KEY'],
278
+ });
279
+ const output = stdout + stderr;
280
+ // The model should detect at least some of the violations and FAIL
281
+ const verdict = parseVerdict(stdout);
282
+ expect(exitCode === 1 || (verdict && !verdict.pass), `Expected FAIL verdict but got exitCode=${exitCode}, verdict=${JSON.stringify(verdict)}\nOutput:\n${output}`).toBe(true);
283
+ }, EVAL_TIMEOUT_MS);
284
+ // Anthropic model drift test
285
+ it.runIf(!!process.env['ANTHROPIC_API_KEY'])('Anthropic catches planted traps (FAIL verdict expected)', async () => {
286
+ const config = `
287
+ export default {
288
+ targets: [{ glob: 'src/**/*.ts', type: 'code', strategy: 'typescript-ast' }],
289
+ totemDir: '.totem',
290
+ lanceDir: '.lancedb',
291
+ orchestrator: { provider: 'anthropic', model: 'claude-haiku-4-5-20251001' },
292
+ };
293
+ `;
294
+ fs.writeFileSync(path.join(tmpDir, 'totem.config.ts'), config);
295
+ const { exitCode, stdout, stderr } = runShield(['--staged', '--mode=structural'], {
296
+ ANTHROPIC_API_KEY: process.env['ANTHROPIC_API_KEY'],
297
+ });
298
+ const output = stdout + stderr;
299
+ const verdict = parseVerdict(stdout);
300
+ expect(exitCode === 1 || (verdict && !verdict.pass), `Expected FAIL verdict but got exitCode=${exitCode}, verdict=${JSON.stringify(verdict)}\nOutput:\n${output}`).toBe(true);
301
+ }, EVAL_TIMEOUT_MS);
302
+ // OpenAI model drift test
303
+ it.runIf(!!process.env['OPENAI_API_KEY'])('OpenAI catches planted traps (FAIL verdict expected)', async () => {
304
+ const config = `
305
+ export default {
306
+ targets: [{ glob: 'src/**/*.ts', type: 'code', strategy: 'typescript-ast' }],
307
+ totemDir: '.totem',
308
+ lanceDir: '.lancedb',
309
+ orchestrator: { provider: 'openai', model: 'gpt-5-mini' },
310
+ };
311
+ `;
312
+ fs.writeFileSync(path.join(tmpDir, 'totem.config.ts'), config);
313
+ const { exitCode, stdout, stderr } = runShield(['--staged', '--mode=structural'], {
314
+ OPENAI_API_KEY: process.env['OPENAI_API_KEY'],
315
+ });
316
+ const output = stdout + stderr;
317
+ const verdict = parseVerdict(stdout);
318
+ expect(exitCode === 1 || (verdict && !verdict.pass), `Expected FAIL verdict but got exitCode=${exitCode}, verdict=${JSON.stringify(verdict)}\nOutput:\n${output}`).toBe(true);
319
+ }, EVAL_TIMEOUT_MS);
320
+ });
321
+ //# sourceMappingURL=shield-eval.integration.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shield-eval.integration.test.js","sourceRoot":"","sources":["../../src/commands/shield-eval.integration.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAElC,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAErE,OAAO,EACL,UAAU,EACV,qBAAqB,EAGrB,iBAAiB,EACjB,UAAU,GACX,MAAM,cAAc,CAAC;AAEtB,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,wDAAwD;AAExD,0EAA0E;AAC1E,MAAM,UAAU,GAAmB;IACjC;QACE,UAAU,EAAE,UAAU,CAAC,wBAAwB,EAAE,oCAAoC,CAAC;QACtF,aAAa,EAAE,wBAAwB;QACvC,OAAO,EAAE,qCAAqC;QAC9C,OAAO,EAAE,uEAAuE;QAChF,MAAM,EAAE,OAAgB;QACxB,UAAU,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KACrC;IACD;QACE,UAAU,EAAE,UAAU,CAAC,gCAAgC,EAAE,UAAU,CAAC;QACpE,aAAa,EAAE,gCAAgC;QAC/C,OAAO,EAAE,kBAAkB;QAC3B,OAAO,EAAE,mEAAmE;QAC5E,MAAM,EAAE,OAAgB;QACxB,UAAU,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KACrC;IACD;QACE,UAAU,EAAE,UAAU,CAAC,gCAAgC,EAAE,UAAU,CAAC;QACpE,aAAa,EAAE,gCAAgC;QAC/C,OAAO,EAAE,iCAAiC;QAC1C,OAAO,EAAE,oEAAoE;QAC7E,MAAM,EAAE,OAAgB;QACxB,UAAU,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KACrC;IACD;QACE,UAAU,EAAE,UAAU,CAAC,oBAAoB,EAAE,UAAU,CAAC;QACxD,aAAa,EAAE,oBAAoB;QACnC,OAAO,EAAE,cAAc;QACvB,OAAO,EAAE,qEAAqE;QAC9E,MAAM,EAAE,OAAgB;QACxB,UAAU,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KACrC;CACF,CAAC;AAEF,sEAAsE;AACtE,MAAM,YAAY,GAAG;;;;;;;;;;;;;;;;;;CAkBpB,CAAC;AAEF,kEAAkE;AAClE,MAAM,UAAU,GAAG;;;;;;;;;;CAUlB,CAAC;AAEF,kEAAkE;AAClE,MAAM,QAAQ,GAAG;;;;;;;;;;;CAWhB,CAAC;AAEF,4EAA4E;AAC5E,MAAM,aAAa,GAAG;;;;;;;;;;;;;;;;;;;CAmBrB,CAAC;AAEF,wDAAwD;AAExD,SAAS,GAAG,CAAC,GAAW,EAAE,GAAW;IACnC,OAAO,QAAQ,CAAC,OAAO,GAAG,EAAE,EAAE;QAC5B,GAAG;QACH,QAAQ,EAAE,OAAO;QACjB,OAAO,EAAE,MAAM;QACf,GAAG,EAAE,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,mBAAmB,EAAE,GAAG,EAAE;KAClD,CAAC,CAAC,IAAI,EAAE,CAAC;AACZ,CAAC;AAED,SAAS,uBAAuB,CAAC,MAAc;IAC7C,sBAAsB;IACtB,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpB,GAAG,CAAC,oCAAoC,EAAE,MAAM,CAAC,CAAC;IAClD,GAAG,CAAC,+BAA+B,EAAE,MAAM,CAAC,CAAC;IAE7C,6BAA6B;IAC7B,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IACxC,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IAC7C,EAAE,CAAC,SAAS,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC1C,EAAE,CAAC,SAAS,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAE5C,uBAAuB;IACvB,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,WAAW,CAAC,EAAE,UAAU,CAAC,CAAC;IAC7D,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,YAAY,CAAC,EAAE,YAAY,CAAC,CAAC;IAElE,8CAA8C;IAC9C,MAAM,SAAS,GAAsB;QACnC,OAAO,EAAE,CAAC;QACV,KAAK,EAAE,UAAU;KAClB,CAAC;IACF,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,qBAAqB,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IAEjG,kBAAkB;IAClB,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IACtB,GAAG,CAAC,kCAAkC,EAAE,MAAM,CAAC,CAAC;IAEhD,yDAAyD;IACzD,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,WAAW,CAAC,EAAE,QAAQ,CAAC,CAAC;IAC3D,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;AACxB,CAAC;AAED,uDAAuD;AAEvD,QAAQ,CAAC,kCAAkC,EAAE,GAAG,EAAE;IAChD,EAAE,CAAC,sEAAsE,EAAE,GAAG,EAAE;QAC9E,MAAM,UAAU,GAAG,UAAU,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC;QAEzD,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe;QAEpE,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC;QACtE,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,wBAAwB,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC1D,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,gCAAgC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAClE,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,gCAAgC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAClE,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACxD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qDAAqD,EAAE,GAAG,EAAE;QAC7D,MAAM,SAAS,GAAG,iBAAiB,CAAC,aAAa,CAAC,CAAC;QACnD,MAAM,UAAU,GAAG,qBAAqB,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC;QAEhE,gFAAgF;QAChF,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC;QACtE,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,wBAAwB,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC1D,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,gCAAgC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAClE,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACtD,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,gCAAgC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACpE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0CAA0C,EAAE,GAAG,EAAE;QAClD,MAAM,SAAS,GAAG;;;;;;;;CAQrB,CAAC;QACE,MAAM,UAAU,GAAG,UAAU,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC;QACrD,MAAM,CAAC,UAAU,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IACrC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mDAAmD,EAAE,GAAG,EAAE;QAC3D,MAAM,MAAM,GAAG,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,aAAa,CAAC,CAAC,CAAC;QACrE,IAAI,CAAC;YACH,uBAAuB,CAAC,MAAM,CAAC,CAAC;YAEhC,yDAAyD;YACzD,MAAM,IAAI,GAAG,GAAG,CAAC,eAAe,EAAE,MAAM,CAAC,CAAC;YAC1C,MAAM,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,qBAAqB,CAAC,CAAC;YAC9C,MAAM,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC;YACtC,MAAM,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC;YACvC,MAAM,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,eAAe,CAAC,CAAC;YAExC,2CAA2C;YAC3C,MAAM,UAAU,GAAG,UAAU,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;YAChD,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe;QACtE,CAAC;gBAAS,CAAC;YACT,EAAE,CAAC,MAAM,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QACtD,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,uDAAuD;AAEvD,MAAM,eAAe,GAAG,OAAO,CAAC,CAAC,0BAA0B;AAE3D,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,KAAK,MAAM,CAAC,CACtD,oCAAoC,EACpC,GAAG,EAAE;IACH,IAAI,MAAc,CAAC;IAEnB,UAAU,CAAC,GAAG,EAAE;QACd,MAAM,GAAG,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,iBAAiB,CAAC,CAAC,CAAC;QACnE,uBAAuB,CAAC,MAAM,CAAC,CAAC;IAClC,CAAC,CAAC,CAAC;IAEH,SAAS,CAAC,GAAG,EAAE;QACb,EAAE,CAAC,MAAM,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACtD,CAAC,CAAC,CAAC;IAEH;;;OAGG;IACH,SAAS,SAAS,CAChB,IAAc,EACd,MAA8B,EAAE;QAEhC,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;QAC/C,MAAM,GAAG,GAAG,QAAQ,QAAQ,WAAW,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;QAExD,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,QAAQ,CAAC,GAAG,EAAE;gBAC3B,GAAG,EAAE,MAAM;gBACX,QAAQ,EAAE,OAAO;gBACjB,OAAO,EAAE,eAAe;gBACxB,GAAG,EAAE;oBACH,GAAG,OAAO,CAAC,GAAG;oBACd,GAAG,GAAG;oBACN,mBAAmB,EAAE,GAAG;iBACzB;gBACD,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;aAChC,CAAC,CAAC;YACH,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;QAC7C,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,CAAC,GAAG,GAA4D,CAAC;YACvE,OAAO;gBACL,MAAM,EAAE,CAAC,CAAC,MAAM,IAAI,EAAE;gBACtB,MAAM,EAAE,CAAC,CAAC,MAAM,IAAI,EAAE;gBACtB,QAAQ,EAAE,CAAC,CAAC,MAAM,IAAI,CAAC;aACxB,CAAC;QACJ,CAAC;IACH,CAAC;IAED,EAAE,CACA,uEAAuE,EACvE,GAAG,EAAE;QACH,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC,CAAC,iBAAiB,EAAE,UAAU,CAAC,CAAC,CAAC;QAChF,MAAM,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;QAE/B,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACzB,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;QACrC,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;QACrC,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;QACrC,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;IACvC,CAAC,EACD,eAAe,CAChB,CAAC;IAEF,0BAA0B;IAC1B,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC,CACvC,sDAAsD,EACtD,KAAK,IAAI,EAAE;QACT,2DAA2D;QAC3D,MAAM,MAAM,GAAG;;;;;;;SAOd,CAAC;QACF,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,iBAAiB,CAAC,EAAE,MAAM,CAAC,CAAC;QAE/D,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC,CAAC,UAAU,EAAE,mBAAmB,CAAC,EAAE;YAChF,cAAc,EAAE,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAE;SAC/C,CAAC,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;QAE/B,mEAAmE;QACnE,MAAM,OAAO,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;QACrC,MAAM,CACJ,QAAQ,KAAK,CAAC,IAAI,CAAC,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAC5C,0CAA0C,QAAQ,aAAa,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,cAAc,MAAM,EAAE,CAC7G,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACf,CAAC,EACD,eAAe,CAChB,CAAC;IAEF,6BAA6B;IAC7B,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC,CAC1C,yDAAyD,EACzD,KAAK,IAAI,EAAE;QACT,MAAM,MAAM,GAAG;;;;;;;SAOd,CAAC;QACF,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,iBAAiB,CAAC,EAAE,MAAM,CAAC,CAAC;QAE/D,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC,CAAC,UAAU,EAAE,mBAAmB,CAAC,EAAE;YAChF,iBAAiB,EAAE,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAE;SACrD,CAAC,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;QAE/B,MAAM,OAAO,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;QACrC,MAAM,CACJ,QAAQ,KAAK,CAAC,IAAI,CAAC,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAC5C,0CAA0C,QAAQ,aAAa,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,cAAc,MAAM,EAAE,CAC7G,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACf,CAAC,EACD,eAAe,CAChB,CAAC;IAEF,0BAA0B;IAC1B,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC,CACvC,sDAAsD,EACtD,KAAK,IAAI,EAAE;QACT,MAAM,MAAM,GAAG;;;;;;;SAOd,CAAC;QACF,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,iBAAiB,CAAC,EAAE,MAAM,CAAC,CAAC;QAE/D,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC,CAAC,UAAU,EAAE,mBAAmB,CAAC,EAAE;YAChF,cAAc,EAAE,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAE;SAC/C,CAAC,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;QAE/B,MAAM,OAAO,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;QACrC,MAAM,CACJ,QAAQ,KAAK,CAAC,IAAI,CAAC,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAC5C,0CAA0C,QAAQ,aAAa,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,cAAc,MAAM,EAAE,CAC7G,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACf,CAAC,EACD,eAAe,CAChB,CAAC;AACJ,CAAC,CACF,CAAC"}
@@ -16,7 +16,7 @@ vi.mock('../ui.js', () => ({
16
16
  describe('invokeAnthropicOrchestrator', () => {
17
17
  const baseOpts = {
18
18
  prompt: 'test prompt',
19
- model: 'claude-sonnet-4-5-20250514',
19
+ model: 'claude-sonnet-4-6',
20
20
  cwd: '.',
21
21
  tag: 'Test',
22
22
  totemDir: '.totem',
@@ -49,7 +49,7 @@ describe('invokeAnthropicOrchestrator', () => {
49
49
  });
50
50
  await invokeAnthropicOrchestrator(baseOpts);
51
51
  expect(mockCreate).toHaveBeenCalledWith(expect.objectContaining({
52
- model: 'claude-sonnet-4-5-20250514',
52
+ model: 'claude-sonnet-4-6',
53
53
  messages: [{ role: 'user', content: 'test prompt' }],
54
54
  }));
55
55
  });
@@ -1 +1 @@
1
- {"version":3,"file":"anthropic-orchestrator.test.js","sourceRoot":"","sources":["../../src/orchestrators/anthropic-orchestrator.test.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"anthropic-orchestrator.test.js","sourceRoot":"","sources":["../../src/orchestrators/anthropic-orchestrator.test.ts"],"names":[],"mappings":"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"}