PluginProbe
Extendify / 3.1.1
Extendify v3.1.1
3.2.1 3.2.0 3.1.6 3.1.5 3.1.4 3.1.3 3.1.2 3.1.1 3.1.0 3.0.6 3.0.5 3.0.4 trunk 0.1.0 0.10.0 0.10.1 0.10.2 0.11.0 0.11.1 0.2.0 0.3.0 0.3.1 0.4.0 0.5.0 0.6.0 All 127 releases
extendify / tests / unit / QuickEdit / lib / agent-cannot-toggle-edit-mode.test.js

agent-cannot-toggle-edit-mode.test.js in Extendify 3.1.1, at tests/unit/QuickEdit/lib/agent-cannot-toggle-edit-mode.test.js

66 lines 2.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 // Hard contract from the rebuild: the AI Agent cannot auto-enable Edit
2 // Mode. Chat.jsx and ChatTools.jsx talk to useEditModeStore directly for
3 // user-gesture writes (Esc handler, the Select chip's toggle). No code
4 // path under src/Agent/ may flip edit mode on without a user gesture.
5 //
6 // Static checks over the source tree, two ways:
7 // 1. Only `Chat.jsx` and `ChatTools.jsx` may import useEditModeStore.
8 // 2. No file under src/Agent/ writes `setOn(true)` literally —
9 // auto-enable shapes (`setOn(true)`, `setOn(!something)`, `toggle()`
10 // from a non-gesture path) are caught by the literal-true check
11 // since the legitimate Select-chip path uses `toggle()` while
12 // reading state and the Esc handler uses `setOn(false)`.
13
14 const fs = require('node:fs');
15 const path = require('node:path');
16
17 const AGENT_ROOT = path.resolve(__dirname, '../../../../src/Agent');
18 const ALLOWED_EDIT_MODE_IMPORTERS = new Set(['Chat.jsx', 'ChatTools.jsx']);
19
20 const walk = (dir) => {
21 const entries = fs.readdirSync(dir, { withFileTypes: true });
22 const files = [];
23 for (const entry of entries) {
24 const full = path.join(dir, entry.name);
25 if (entry.isDirectory()) {
26 files.push(...walk(full));
27 } else if (/\.(js|jsx|ts|tsx)$/.test(entry.name)) {
28 files.push(full);
29 }
30 }
31 return files;
32 };
33
34 const stripComments = (src) =>
35 src.replace(/\/\*[\s\S]*?\*\//g, '').replace(/(^|[^:])\/\/.*$/gm, '$1');
36
37 describe('agent surface — cannot auto-enable Edit Mode', () => {
38 const agentFiles = walk(AGENT_ROOT);
39
40 it('finds agent source files to scan', () => {
41 expect(agentFiles.length).toBeGreaterThan(20);
42 });
43
44 it('only Chat.jsx and ChatTools.jsx may import useEditModeStore', () => {
45 const offenders = [];
46 for (const file of agentFiles) {
47 const src = stripComments(fs.readFileSync(file, 'utf8'));
48 if (!/useEditModeStore/.test(src)) continue;
49 if (ALLOWED_EDIT_MODE_IMPORTERS.has(path.basename(file))) continue;
50 offenders.push(file);
51 }
52 expect(offenders).toEqual([]);
53 });
54
55 it('no file under src/Agent/ calls setOn(true) with a hardcoded enable', () => {
56 const offenders = [];
57 for (const file of agentFiles) {
58 const src = stripComments(fs.readFileSync(file, 'utf8'));
59 if (/setOn\s*\(\s*true\s*\)/.test(src)) {
60 offenders.push(file);
61 }
62 }
63 expect(offenders).toEqual([]);
64 });
65 });
66