xtrm-tools 2.1.4 → 2.1.5

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/config/hooks.json CHANGED
@@ -13,12 +13,12 @@
13
13
  ],
14
14
  "PreToolUse": [
15
15
  {
16
- "matcher": "Write|Edit|MultiEdit",
16
+ "matcher": "Write|Edit|MultiEdit|mcp__serena__rename_symbol|mcp__serena__replace_symbol_body|mcp__serena__insert_after_symbol|mcp__serena__insert_before_symbol",
17
17
  "script": "main-guard.mjs",
18
18
  "timeout": 5000
19
19
  },
20
20
  {
21
- "matcher": "Read|Edit",
21
+ "matcher": "Read|Edit|mcp__serena__rename_symbol|mcp__serena__replace_symbol_body|mcp__serena__insert_after_symbol|mcp__serena__insert_before_symbol",
22
22
  "script": "serena-workflow-reminder.py"
23
23
  },
24
24
  {
@@ -27,7 +27,7 @@
27
27
  "timeout": 30000
28
28
  },
29
29
  {
30
- "matcher": "Edit|Write",
30
+ "matcher": "Edit|Write|mcp__serena__rename_symbol|mcp__serena__replace_symbol_body|mcp__serena__insert_after_symbol|mcp__serena__insert_before_symbol",
31
31
  "script": "type-safety-enforcement.py"
32
32
  },
33
33
  {
@@ -36,7 +36,7 @@
36
36
  "timeout": 8000
37
37
  },
38
38
  {
39
- "matcher": "Edit|Write|MultiEdit|NotebookEdit|mcp__serena__*",
39
+ "matcher": "Edit|Write|MultiEdit|NotebookEdit|mcp__serena__rename_symbol|mcp__serena__replace_symbol_body|mcp__serena__insert_after_symbol|mcp__serena__insert_before_symbol",
40
40
  "script": "beads-edit-gate.mjs",
41
41
  "timeout": 5000
42
42
  },
package/hooks/README.md CHANGED
@@ -147,7 +147,7 @@ Installed globally to `~/.claude/hooks/` by `xtrm install`. Require Node.js.
147
147
 
148
148
  **Purpose**: Blocks direct file edits and dangerous git operations on protected branches (`main`/`master`). Enforces the feature-branch → PR workflow.
149
149
 
150
- **Trigger**: PreToolUse (`Edit|Write|MultiEdit|NotebookEdit|Bash`)
150
+ **Trigger**: PreToolUse (`Edit|Write|MultiEdit|NotebookEdit|mcp__serena__rename_symbol|mcp__serena__replace_symbol_body|mcp__serena__insert_after_symbol|mcp__serena__insert_before_symbol|Bash`)
151
151
 
152
152
  **Blocks**:
153
153
  - Write/Edit/MultiEdit/NotebookEdit on protected branches
@@ -159,7 +159,7 @@ Installed globally to `~/.claude/hooks/` by `xtrm install`. Require Node.js.
159
159
  {
160
160
  "hooks": {
161
161
  "PreToolUse": [{
162
- "matcher": "Edit|Write|MultiEdit|NotebookEdit|Bash",
162
+ "matcher": "Edit|Write|MultiEdit|NotebookEdit|mcp__serena__rename_symbol|mcp__serena__replace_symbol_body|mcp__serena__insert_after_symbol|mcp__serena__insert_before_symbol|Bash",
163
163
  "hooks": [{ "type": "command", "command": "node \"~/.claude/hooks/main-guard.mjs\"", "timeout": 5000 }]
164
164
  }]
165
165
  }
@@ -182,7 +182,7 @@ Installed globally to `~/.claude/hooks/` by `xtrm install`. Require Node.js.
182
182
 
183
183
  **Purpose**: Blocks file edits when the current session has not claimed a beads issue via `bd kv`. Prevents free-riding in multi-agent and multi-session scenarios.
184
184
 
185
- **Trigger**: PreToolUse (`Edit|Write|MultiEdit|NotebookEdit|mcp__serena__*`)
185
+ **Trigger**: PreToolUse (`Edit|Write|MultiEdit|NotebookEdit|mcp__serena__rename_symbol|mcp__serena__replace_symbol_body|mcp__serena__insert_after_symbol|mcp__serena__insert_before_symbol`)
186
186
 
187
187
  **Behavior**:
188
188
  - Session has claim (`bd kv get "claimed:<session_id>"`) → allow
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xtrm-tools",
3
- "version": "2.1.4",
3
+ "version": "2.1.5",
4
4
  "description": "Claude Code tools installer (skills, hooks, MCP servers)",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -2,7 +2,7 @@
2
2
  "hooks": {
3
3
  "PostToolUse": [
4
4
  {
5
- "matcher": "Write|Edit|MultiEdit",
5
+ "matcher": "Write|Edit|MultiEdit|mcp__serena__rename_symbol|mcp__serena__replace_symbol_body|mcp__serena__insert_after_symbol|mcp__serena__insert_before_symbol",
6
6
  "hooks": [
7
7
  {
8
8
  "type": "command",
@@ -12,7 +12,7 @@
12
12
  ],
13
13
  "PreToolUse": [
14
14
  {
15
- "matcher": "Read|Write|Edit|Glob|Grep|Bash",
15
+ "matcher": "Read|Write|Edit|Glob|Grep|Bash|mcp__serena__rename_symbol|mcp__serena__replace_symbol_body|mcp__serena__insert_after_symbol|mcp__serena__insert_before_symbol",
16
16
  "hooks": [
17
17
  {
18
18
  "type": "command",
@@ -23,7 +23,7 @@
23
23
  ],
24
24
  "PostToolUse": [
25
25
  {
26
- "matcher": "Write|Edit",
26
+ "matcher": "Write|Edit|mcp__serena__rename_symbol|mcp__serena__replace_symbol_body|mcp__serena__insert_after_symbol|mcp__serena__insert_before_symbol",
27
27
  "hooks": [
28
28
  {
29
29
  "type": "command",
@@ -41,12 +41,12 @@ SETTINGS_HOOKS = {
41
41
  "command": "python3 \"$CLAUDE_PROJECT_DIR/.claude/skills/using-service-skills/scripts/cataloger.py\""}]}
42
42
  ],
43
43
  "PreToolUse": [
44
- {"matcher": "Read|Write|Edit|Glob|Grep|Bash",
44
+ {"matcher": "Read|Write|Edit|Glob|Grep|Bash|mcp__serena__rename_symbol|mcp__serena__replace_symbol_body|mcp__serena__insert_after_symbol|mcp__serena__insert_before_symbol",
45
45
  "hooks": [{"type": "command",
46
46
  "command": "python3 \"$CLAUDE_PROJECT_DIR/.claude/skills/using-service-skills/scripts/skill_activator.py\""}]}
47
47
  ],
48
48
  "PostToolUse": [
49
- {"matcher": "Write|Edit",
49
+ {"matcher": "Write|Edit|mcp__serena__rename_symbol|mcp__serena__replace_symbol_body|mcp__serena__insert_after_symbol|mcp__serena__insert_before_symbol",
50
50
  "hooks": [{"type": "command",
51
51
  "command": "python3 \"$CLAUDE_PROJECT_DIR/.claude/skills/updating-service-skills/scripts/drift_detector.py\" check-hook",
52
52
  "timeout": 10}]}
@@ -0,0 +1,87 @@
1
+ #!/usr/bin/env node
2
+ const { readFileSync } = require('node:fs');
3
+ const { spawnSync } = require('node:child_process');
4
+ const path = require('node:path');
5
+
6
+ const CODE_EXTENSIONS = new Set([
7
+ '.js', '.jsx', '.ts', '.tsx', '.mjs', '.cjs',
8
+ '.py', '.php', '.go', '.rs', '.java', '.kt', '.kts',
9
+ '.c', '.cc', '.cpp', '.cxx', '.h', '.hh', '.hpp',
10
+ '.cs', '.rb', '.swift', '.scala', '.lua', '.sh', '.zsh', '.bash',
11
+ ]);
12
+
13
+ const SERENA_EDIT_TOOLS = new Set([
14
+ 'mcp__serena__rename_symbol',
15
+ 'mcp__serena__replace_symbol_body',
16
+ 'mcp__serena__insert_after_symbol',
17
+ 'mcp__serena__insert_before_symbol',
18
+ ]);
19
+
20
+ function isEditLikeTool(toolName) {
21
+ if (!toolName) return false;
22
+ if (toolName === 'Edit' || toolName === 'Write' || toolName === 'MultiEdit' || toolName === 'TodoWrite') {
23
+ return true;
24
+ }
25
+ return SERENA_EDIT_TOOLS.has(toolName);
26
+ }
27
+
28
+ function pickFilePath(toolInput) {
29
+ if (!toolInput || typeof toolInput !== 'object') return null;
30
+
31
+ const direct = toolInput.file_path || toolInput.filePath || toolInput.path ||
32
+ toolInput.relative_path || toolInput.relativePath;
33
+ if (typeof direct === 'string' && direct.trim()) return direct;
34
+
35
+ if (Array.isArray(toolInput.edits)) {
36
+ for (const edit of toolInput.edits) {
37
+ const p = edit?.file_path || edit?.filePath || edit?.path || edit?.relative_path || edit?.relativePath;
38
+ if (typeof p === 'string' && p.trim()) return p;
39
+ }
40
+ }
41
+
42
+ return null;
43
+ }
44
+
45
+ function isCodeFile(filePath) {
46
+ if (!filePath) return true; // fail-open when no path is available
47
+ return CODE_EXTENSIONS.has(path.extname(filePath).toLowerCase());
48
+ }
49
+
50
+ let payloadText = '';
51
+ try {
52
+ payloadText = readFileSync(0, 'utf8');
53
+ } catch {
54
+ process.exit(0);
55
+ }
56
+
57
+ let payload;
58
+ try {
59
+ payload = JSON.parse(payloadText);
60
+ } catch {
61
+ process.exit(0);
62
+ }
63
+
64
+ const toolName = payload.tool_name || '';
65
+ if (!isEditLikeTool(toolName)) {
66
+ process.exit(0);
67
+ }
68
+
69
+ const filePath = pickFilePath(payload.tool_input);
70
+ if (!isCodeFile(filePath)) {
71
+ process.exit(0);
72
+ }
73
+
74
+ const result = spawnSync('tdd-guard', {
75
+ input: payloadText,
76
+ encoding: 'utf8',
77
+ stdio: ['pipe', 'pipe', 'pipe'],
78
+ });
79
+
80
+ if (result.stdout) process.stdout.write(result.stdout);
81
+ if (result.stderr) process.stderr.write(result.stderr);
82
+
83
+ if (result.error) {
84
+ process.exit(0);
85
+ }
86
+
87
+ process.exit(result.status ?? 0);
@@ -2,11 +2,11 @@
2
2
  "hooks": {
3
3
  "PreToolUse": [
4
4
  {
5
- "matcher": "Write|Edit|MultiEdit|TodoWrite",
5
+ "matcher": "Write|Edit|MultiEdit|TodoWrite|mcp__serena__rename_symbol|mcp__serena__replace_symbol_body|mcp__serena__insert_after_symbol|mcp__serena__insert_before_symbol",
6
6
  "hooks": [
7
7
  {
8
8
  "type": "command",
9
- "command": "tdd-guard",
9
+ "command": "node \"$CLAUDE_PROJECT_DIR/.claude/hooks/tdd-guard-pretool-bridge.cjs\"",
10
10
  "timeout": 30
11
11
  }
12
12
  ]
@@ -276,8 +276,8 @@ Type `/hooks` in Claude Code to open the hooks menu, then configure each hook. U
276
276
  **PreToolUse Hook**
277
277
 
278
278
  1. Select `PreToolUse - Before tool execution`
279
- 2. Choose `+ Add new matcher...` and enter: `Write|Edit|MultiEdit|TodoWrite`
280
- 3. Select `+ Add new hook...` and enter: `tdd-guard`
279
+ 2. Choose `+ Add new matcher...` and enter: `Write|Edit|MultiEdit|TodoWrite|mcp__serena__rename_symbol|mcp__serena__replace_symbol_body|mcp__serena__insert_after_symbol|mcp__serena__insert_before_symbol`
280
+ 3. Select `+ Add new hook...` and enter: `node "$CLAUDE_PROJECT_DIR/.claude/hooks/tdd-guard-pretool-bridge.cjs"`
281
281
  4. Choose where to save
282
282
 
283
283
  **UserPromptSubmit Hook**
@@ -305,11 +305,11 @@ If you prefer to edit settings files directly, add all three hooks to your chose
305
305
  "hooks": {
306
306
  "PreToolUse": [
307
307
  {
308
- "matcher": "Write|Edit|MultiEdit|TodoWrite",
308
+ "matcher": "Write|Edit|MultiEdit|TodoWrite|mcp__serena__rename_symbol|mcp__serena__replace_symbol_body|mcp__serena__insert_after_symbol|mcp__serena__insert_before_symbol",
309
309
  "hooks": [
310
310
  {
311
311
  "type": "command",
312
- "command": "tdd-guard"
312
+ "command": "node \"$CLAUDE_PROJECT_DIR/.claude/hooks/tdd-guard-pretool-bridge.cjs\""
313
313
  }
314
314
  ]
315
315
  }
@@ -341,6 +341,8 @@ If you prefer to edit settings files directly, add all three hooks to your chose
341
341
 
342
342
  </details>
343
343
 
344
+ **Note**: The pretool bridge skips non-code files (for example `.md`) and forwards code edits to `tdd-guard`, which avoids false positives on documentation-only changes.
345
+
344
346
  ## Additional Configuration
345
347
 
346
348
  - [Custom instructions](docs/custom-instructions.md) - Customize TDD validation rules
@@ -42,7 +42,7 @@ The refactoring support helps by:
42
42
  1. Type `/hooks` in Claude Code
43
43
  2. Select `PostToolUse - After tool execution`
44
44
  3. Choose `+ Add new matcher...`
45
- 4. Enter: `Write|Edit|MultiEdit`
45
+ 4. Enter: `Write|Edit|MultiEdit|mcp__serena__rename_symbol|mcp__serena__replace_symbol_body|mcp__serena__insert_after_symbol|mcp__serena__insert_before_symbol`
46
46
  5. Select `+ Add new hook...`
47
47
  6. Enter command: `tdd-guard`
48
48
  7. Choose where to save
@@ -56,7 +56,7 @@ The refactoring support helps by:
56
56
  "hooks": {
57
57
  "PostToolUse": [
58
58
  {
59
- "matcher": "Write|Edit|MultiEdit",
59
+ "matcher": "Write|Edit|MultiEdit|mcp__serena__rename_symbol|mcp__serena__replace_symbol_body|mcp__serena__insert_after_symbol|mcp__serena__insert_before_symbol",
60
60
  "hooks": [
61
61
  {
62
62
  "type": "command",
@@ -2,7 +2,7 @@
2
2
  "hooks": {
3
3
  "PostToolUse": [
4
4
  {
5
- "matcher": "Write|Edit|MultiEdit",
5
+ "matcher": "Write|Edit|MultiEdit|mcp__serena__rename_symbol|mcp__serena__replace_symbol_body|mcp__serena__insert_after_symbol|mcp__serena__insert_before_symbol",
6
6
  "hooks": [
7
7
  {
8
8
  "type": "command",