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/README.md +1 -1
- package/cli/dist/index.cjs +615 -505
- package/cli/dist/index.cjs.map +1 -1
- package/config/hooks.json +4 -4
- package/hooks/README.md +3 -3
- package/package.json +1 -1
- package/project-skills/py-quality-gate/.claude/settings.json +1 -1
- package/project-skills/service-skills-set/.claude/settings.json +2 -2
- package/project-skills/service-skills-set/install-service-skills.py +2 -2
- package/project-skills/tdd-guard/.claude/hooks/tdd-guard-pretool-bridge.cjs +87 -0
- package/project-skills/tdd-guard/.claude/settings.json +2 -2
- package/project-skills/tdd-guard/README.md +6 -4
- package/project-skills/tdd-guard/docs/linting.md +2 -2
- package/project-skills/ts-quality-gate/.claude/settings.json +1 -1
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|
|
|
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|
|
|
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
|
@@ -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",
|