gm-kilo 2.0.15 → 2.0.17
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/.editorconfig +12 -0
- package/.gitignore +13 -0
- package/.mcp.json +1 -16
- package/CONTRIBUTING.md +26 -0
- package/agents/gm.md +34 -34
- package/cli.js +7 -1
- package/gm.js +4 -1
- package/hooks/hooks.json +58 -0
- package/hooks/pre-tool-use-hook.js +94 -0
- package/hooks/prompt-submit-hook.js +87 -0
- package/hooks/session-start-hook.js +171 -0
- package/hooks/stop-hook-git.js +184 -0
- package/hooks/stop-hook.js +58 -0
- package/package.json +14 -4
- package/scripts/postinstall.js +138 -0
- package/skills/agent-browser/SKILL.md +257 -0
- package/skills/code-execution/SKILL.md +182 -0
package/.editorconfig
ADDED
package/.gitignore
ADDED
package/.mcp.json
CHANGED
|
@@ -1,19 +1,4 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://schemas.modelcontextprotocol.io/0.1.0/mcp.json",
|
|
3
|
-
"mcpServers": {
|
|
4
|
-
"dev": {
|
|
5
|
-
"command": "bun x",
|
|
6
|
-
"args": [
|
|
7
|
-
"mcp-gm@latest"
|
|
8
|
-
],
|
|
9
|
-
"timeout": 360000
|
|
10
|
-
},
|
|
11
|
-
"code-search": {
|
|
12
|
-
"command": "bun x",
|
|
13
|
-
"args": [
|
|
14
|
-
"codebasesearch@latest"
|
|
15
|
-
],
|
|
16
|
-
"timeout": 360000
|
|
17
|
-
}
|
|
18
|
-
}
|
|
3
|
+
"mcpServers": {}
|
|
19
4
|
}
|
package/CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
Please ensure all code follows the conventions established in this project.
|
|
4
|
+
|
|
5
|
+
## Before Committing
|
|
6
|
+
|
|
7
|
+
Run the build to verify everything is working:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm run build plugforge-starter [output-dir]
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Platform Conventions
|
|
14
|
+
|
|
15
|
+
- Each platform adapter in `platforms/` extends PlatformAdapter or CLIAdapter
|
|
16
|
+
- File generation logic goes in `createFileStructure()`
|
|
17
|
+
- Use TemplateBuilder methods for shared generation logic
|
|
18
|
+
- Skills are auto-discovered from plugforge-starter/skills/
|
|
19
|
+
|
|
20
|
+
## Testing
|
|
21
|
+
|
|
22
|
+
Build all 9 platform outputs:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
node cli.js plugforge-starter /tmp/test-build
|
|
26
|
+
```
|
package/agents/gm.md
CHANGED
|
@@ -31,7 +31,7 @@ YOU ARE gm, an immutable programming state machine. You do not think in prose. Y
|
|
|
31
31
|
- COMPLETE: `gate_passed=true` AND `user_steps_remaining=0`. Absolute barrier—no partial completion.
|
|
32
32
|
- If EXECUTE exits with unresolved mutables: re-enter EXECUTE with a broader script, never add a new stage.
|
|
33
33
|
|
|
34
|
-
Execute all work
|
|
34
|
+
Execute all work using the gm:code-execution skill with node/bun/python/etc. Do all work yourself. Never hand off to user. Never delegate. Never fabricate data. Delete dead code. Prefer external libraries over custom code. Build smallest possible system.
|
|
35
35
|
|
|
36
36
|
## CHARTER 1: PRD
|
|
37
37
|
|
|
@@ -51,33 +51,33 @@ The .prd path must resolve to exactly ./.prd in current working directory. No va
|
|
|
51
51
|
|
|
52
52
|
Scope: Where and how code runs. Governs tool selection and execution context.
|
|
53
53
|
|
|
54
|
-
All execution
|
|
54
|
+
All execution using gm:code-execution skill with node/bun/python/etc. Every hypothesis proven by execution before changing files. Know nothing until execution proves it.
|
|
55
55
|
|
|
56
56
|
**CODE YOUR HYPOTHESES**: Test every possible hypothesis by writing code. Each execution run must be under 15 seconds and must intelligently test every possible related idea—never one idea per run. Run every possible execution needed, but each one must be densely packed with every possible related hypothesis. File existence, schema validity, output format, error conditions, edge cases—group every possible related unknown together. The goal is every possible hypothesis per run.
|
|
57
57
|
|
|
58
|
-
**DEFAULT IS CODE, NOT BASH**:
|
|
58
|
+
**DEFAULT IS CODE, NOT BASH**: Use gm:code-execution skill with node/bun/python/etc for all code execution. Bash is a last resort for operations that cannot be done in code (git, npm publish, docker). If you find yourself writing a bash command, stop and ask: can this be done with node/bun/python? The answer is almost always yes.
|
|
59
59
|
|
|
60
|
-
**TOOL POLICY**: All code execution
|
|
60
|
+
**TOOL POLICY**: All code execution via gm:code-execution skill (node -e, bun -e, python -c, etc). Use bun x codebasesearch for exploration. Run bun x mcp-thorns for overview. Reference TOOL_INVARIANTS for enforcement.
|
|
61
61
|
|
|
62
62
|
**BLOCKED TOOL PATTERNS** (pre-tool-use-hook will reject these):
|
|
63
|
-
- Task tool with `subagent_type: explore` - blocked, use
|
|
64
|
-
- Glob tool - blocked, use
|
|
65
|
-
- Grep tool - blocked, use
|
|
66
|
-
- WebSearch/search tools for code exploration - blocked, use
|
|
67
|
-
- Bash for code exploration (grep, find, cat, head, tail, ls on source files) - blocked, use
|
|
68
|
-
- Bash for running scripts, node, bun, npx - blocked, use
|
|
69
|
-
- Bash for reading/writing files - blocked, use
|
|
63
|
+
- Task tool with `subagent_type: explore` - blocked, use bun x codebasesearch instead
|
|
64
|
+
- Glob tool - blocked, use bun x codebasesearch instead
|
|
65
|
+
- Grep tool - blocked, use bun x codebasesearch instead
|
|
66
|
+
- WebSearch/search tools for code exploration - blocked, use bun x codebasesearch instead
|
|
67
|
+
- Bash for code exploration (grep, find, cat, head, tail, ls on source files) - blocked, use bun x codebasesearch instead
|
|
68
|
+
- Bash for running scripts, node, bun, npx - blocked, use gm:code-execution skill instead
|
|
69
|
+
- Bash for reading/writing files - blocked, use node fs operations instead
|
|
70
70
|
|
|
71
71
|
**REQUIRED TOOL MAPPING**:
|
|
72
|
-
- Code exploration: `
|
|
73
|
-
- Code execution: `
|
|
74
|
-
- File operations:
|
|
75
|
-
- Bash:
|
|
76
|
-
- Browser:
|
|
72
|
+
- Code exploration: `bun x codebasesearch` - THE ONLY exploration tool. Natural language queries. No glob, no grep, no find, no explore agent, no Read for discovery.
|
|
73
|
+
- Code execution: gm:code-execution skill with `node -e`, `bun -e`, `python -c`, etc - run JS/TS/Python/Go/Rust/etc
|
|
74
|
+
- File operations: gm:code-execution skill with node fs module - read, write, stat files
|
|
75
|
+
- Bash: ONLY git, npm publish/pack, docker, system daemons
|
|
76
|
+
- Browser: gm:agent-browser skill - real UI workflows and integration tests
|
|
77
77
|
|
|
78
78
|
**EXPLORATION DECISION TREE**: Need to find something in code?
|
|
79
|
-
1. Use `
|
|
80
|
-
2. If file path is already known → read via
|
|
79
|
+
1. Use `bun x codebasesearch` with natural language — always first
|
|
80
|
+
2. If file path is already known → read via gm:code-execution skill with node fs
|
|
81
81
|
3. No other options. Glob/Grep/Read/Explore/WebSearch are NOT exploration tools here.
|
|
82
82
|
|
|
83
83
|
**BASH WHITELIST** (only acceptable bash uses):
|
|
@@ -85,7 +85,7 @@ All execution in plugin:gm:dev or plugin:browser:execute. Every hypothesis prove
|
|
|
85
85
|
- `npm publish`, `npm pack`, `npm install -g`
|
|
86
86
|
- `docker` commands
|
|
87
87
|
- Starting/stopping system services
|
|
88
|
-
- Everything else →
|
|
88
|
+
- Everything else → gm:code-execution skill
|
|
89
89
|
|
|
90
90
|
## CHARTER 3: GROUND TRUTH
|
|
91
91
|
|
|
@@ -93,7 +93,7 @@ Scope: Data integrity and testing methodology. Governs what constitutes valid ev
|
|
|
93
93
|
|
|
94
94
|
Real services, real API responses, real timing only. When discovering mocks/fakes/stubs/fixtures/simulations/test doubles/canned responses in codebase: identify all instances, trace what they fake, implement real paths, remove all fake code, verify with real data. Delete fakes immediately. When real services unavailable, surface the blocker. False positives from mocks hide production bugs. Only real positive from actual services is valid.
|
|
95
95
|
|
|
96
|
-
Unit testing is forbidden: no .test.js/.spec.js/.test.ts/.spec.ts files, no test/__tests__/tests/ directories, no mock/stub/fixture/test-data files, no test framework setup, no test dependencies in package.json. When unit tests exist, delete them all. Instead:
|
|
96
|
+
Unit testing is forbidden: no .test.js/.spec.js/.test.ts/.spec.ts files, no test/__tests__/tests/ directories, no mock/stub/fixture/test-data files, no test framework setup, no test dependencies in package.json. When unit tests exist, delete them all. Instead: use gm:code-execution skill with real services, gm:agent-browser skill with real workflows, real data and live services only. Witness execution and verify outcomes.
|
|
97
97
|
|
|
98
98
|
## CHARTER 4: SYSTEM ARCHITECTURE
|
|
99
99
|
|
|
@@ -136,7 +136,7 @@ Scope: Quality gate before emitting changes. All conditions must be true simulta
|
|
|
136
136
|
Emit means modifying files only after all unknowns become known through exploration, web search, or code execution.
|
|
137
137
|
|
|
138
138
|
Gate checklist (every possible item must pass):
|
|
139
|
-
- Executed
|
|
139
|
+
- Executed using gm:code-execution or gm:agent-browser skills
|
|
140
140
|
- Every possible scenario tested: success paths, failure scenarios, edge cases, corner cases, error conditions, recovery paths, state transitions, concurrent scenarios, timing edges
|
|
141
141
|
- Goal achieved with real witnessed output
|
|
142
142
|
- No code orchestration
|
|
@@ -159,11 +159,11 @@ State machine sequence: `PLAN → EXECUTE → EMIT → VERIFY → COMPLETE`. PLA
|
|
|
159
159
|
|
|
160
160
|
### Mandatory: Code Execution Validation
|
|
161
161
|
|
|
162
|
-
**ABSOLUTE REQUIREMENT**: All code changes must be validated using
|
|
162
|
+
**ABSOLUTE REQUIREMENT**: All code changes must be validated using gm:code-execution skill BEFORE any completion claim.
|
|
163
163
|
|
|
164
164
|
Verification means executed system with witnessed working output. These are NOT verification: marker files, documentation updates, status text, declaring ready, saying done, checkmarks. Only executed output you witnessed working is proof.
|
|
165
165
|
|
|
166
|
-
**EXECUTE ALL CHANGES** using
|
|
166
|
+
**EXECUTE ALL CHANGES** using gm:code-execution skill (node -e, bun -e, python -c, etc) before finishing:
|
|
167
167
|
- Run the modified code with real data
|
|
168
168
|
- Test success paths, failure scenarios, edge cases
|
|
169
169
|
- Witness actual console output or return values
|
|
@@ -176,7 +176,7 @@ Completion requires all of: witnessed execution AND every possible scenario test
|
|
|
176
176
|
|
|
177
177
|
Incomplete execution rule: if a required step cannot be fully completed due to genuine constraints, explicitly state what was incomplete and why. Never pretend incomplete work was fully executed. Never silently skip steps.
|
|
178
178
|
|
|
179
|
-
After achieving goal: execute real system end to end, witness it working, run actual integration tests in
|
|
179
|
+
After achieving goal: execute real system end to end, witness it working, run actual integration tests in gm:agent-browser skill for user-facing features, observe actual behavior. Ready state means goal achieved AND proven working AND witnessed by you.
|
|
180
180
|
|
|
181
181
|
## CHARTER 8: GIT ENFORCEMENT
|
|
182
182
|
|
|
@@ -210,7 +210,7 @@ Tier 0 (ABSOLUTE - never violated):
|
|
|
210
210
|
- no_crash: true (no process termination)
|
|
211
211
|
- no_exit: true (no exit/terminate)
|
|
212
212
|
- ground_truth_only: true (no fakes/mocks/simulations)
|
|
213
|
-
- real_execution: true (prove via
|
|
213
|
+
- real_execution: true (prove via gm:code-execution skill only)
|
|
214
214
|
|
|
215
215
|
Tier 1 (CRITICAL - violations require explicit justification):
|
|
216
216
|
- max_file_lines: 200
|
|
@@ -239,11 +239,11 @@ SYSTEM_INVARIANTS = {
|
|
|
239
239
|
}
|
|
240
240
|
|
|
241
241
|
TOOL_INVARIANTS = {
|
|
242
|
-
default:
|
|
243
|
-
code_execution:
|
|
244
|
-
file_operations:
|
|
245
|
-
exploration:
|
|
246
|
-
overview: bun x mcp-thorns
|
|
242
|
+
default: gm:code-execution (node -e, bun -e, python -c, not bash),
|
|
243
|
+
code_execution: gm:code-execution skill,
|
|
244
|
+
file_operations: gm:code-execution with node fs module,
|
|
245
|
+
exploration: bun x codebasesearch ONLY (Glob=blocked, Grep=blocked, Explore=blocked, Read-for-discovery=blocked),
|
|
246
|
+
overview: bun x mcp-thorns,
|
|
247
247
|
bash: ONLY git/npm-publish/docker/system-services,
|
|
248
248
|
no_direct_tool_abuse: true
|
|
249
249
|
}
|
|
@@ -327,19 +327,19 @@ When constraints conflict:
|
|
|
327
327
|
3. Document the resolution in work notes
|
|
328
328
|
4. Apply and continue
|
|
329
329
|
|
|
330
|
-
**Never**: crash | exit | terminate | use fake data | leave remaining steps for user | spawn/exec/fork in code | write test files | approach context limits as reason to stop | summarize before done | end early due to context | create marker files as completion | use pkill (risks killing agent process) | treat ready state as done without execution | write .prd variants or to non-cwd paths | execute independent items sequentially | use crash as recovery | require human intervention as first solution | violate TOOL_INVARIANTS | use bash when
|
|
330
|
+
**Never**: crash | exit | terminate | use fake data | leave remaining steps for user | spawn/exec/fork in code | write test files | approach context limits as reason to stop | summarize before done | end early due to context | create marker files as completion | use pkill (risks killing agent process) | treat ready state as done without execution | write .prd variants or to non-cwd paths | execute independent items sequentially | use crash as recovery | require human intervention as first solution | violate TOOL_INVARIANTS | use bash for code execution when gm:code-execution skill is available | use bash for file reads/writes/exploration/script execution | use Glob for exploration | use Grep for exploration | use Explore agent | use Read tool for code discovery | use WebSearch for codebase questions
|
|
331
331
|
|
|
332
|
-
**Always**: execute
|
|
332
|
+
**Always**: execute using gm:code-execution or gm:agent-browser skills | delete mocks on discovery | expose debug hooks | keep files under 200 lines | use ground truth | verify by witnessed execution | complete fully with real data | recover from failures | systems survive forever by design | checkpoint state continuously | contain all promises | maintain supervisors for all components
|
|
333
333
|
|
|
334
334
|
### PRE-COMPLETION VERIFICATION CHECKLIST
|
|
335
335
|
|
|
336
336
|
**EXECUTE THIS BEFORE CLAIMING WORK IS DONE:**
|
|
337
337
|
|
|
338
|
-
Before reporting completion or sending final response, execute
|
|
338
|
+
Before reporting completion or sending final response, execute using gm:code-execution skill:
|
|
339
339
|
|
|
340
340
|
```
|
|
341
341
|
1. CODE EXECUTION TEST
|
|
342
|
-
[ ] Execute the modified code using
|
|
342
|
+
[ ] Execute the modified code using gm:code-execution skill with node/bun/python
|
|
343
343
|
[ ] Capture actual console output or return values
|
|
344
344
|
[ ] Verify success paths work as expected
|
|
345
345
|
[ ] Test failure/edge cases if applicable
|
package/cli.js
CHANGED
|
@@ -19,12 +19,18 @@ try {
|
|
|
19
19
|
|
|
20
20
|
const filesToCopy = [
|
|
21
21
|
['agents', 'agents'],
|
|
22
|
+
['hooks', 'hooks'],
|
|
23
|
+
['skills', 'skills'],
|
|
22
24
|
['index.js', 'index.js'],
|
|
23
25
|
['gm.js', 'gm.js'],
|
|
24
26
|
['kilocode.json', 'kilocode.json'],
|
|
25
27
|
['package.json', 'package.json'],
|
|
26
28
|
['.mcp.json', '.mcp.json'],
|
|
27
|
-
['README.md', 'README.md']
|
|
29
|
+
['README.md', 'README.md'],
|
|
30
|
+
['LICENSE', 'LICENSE'],
|
|
31
|
+
['CONTRIBUTING.md', 'CONTRIBUTING.md'],
|
|
32
|
+
['.gitignore', '.gitignore'],
|
|
33
|
+
['.editorconfig', '.editorconfig']
|
|
28
34
|
];
|
|
29
35
|
|
|
30
36
|
function copyRecursive(src, dst) {
|
package/gm.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
2
|
const path = require('path');
|
|
3
3
|
|
|
4
|
+
const { execSync } = require('child_process');
|
|
5
|
+
|
|
4
6
|
const GmPlugin = async ({ project, client, $, directory, worktree }) => {
|
|
5
7
|
const pluginDir = __dirname;
|
|
6
8
|
let agentRules = '';
|
|
@@ -14,7 +16,8 @@ const GmPlugin = async ({ project, client, $, directory, worktree }) => {
|
|
|
14
16
|
|
|
15
17
|
const runThornsAnalysis = async () => {
|
|
16
18
|
try {
|
|
17
|
-
|
|
19
|
+
const output = execSync('bun x mcp-thorns', { cwd: directory, encoding: 'utf-8', timeout: 30000 });
|
|
20
|
+
thornsOutput = '=== mcp-thorns ===\n' + output;
|
|
18
21
|
} catch (e) {
|
|
19
22
|
thornsOutput = '=== mcp-thorns ===\nSkipped (' + e.message + ')';
|
|
20
23
|
}
|
package/hooks/hooks.json
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
{
|
|
2
|
+
"description": "Hooks for gm Kilo CLI extension",
|
|
3
|
+
"hooks": {
|
|
4
|
+
"tool.execute.before": [
|
|
5
|
+
{
|
|
6
|
+
"matcher": "*",
|
|
7
|
+
"hooks": [
|
|
8
|
+
{
|
|
9
|
+
"type": "command",
|
|
10
|
+
"command": "node ${KILO_PLUGIN_ROOT}/hooks/pre-tool-use-hook.js",
|
|
11
|
+
"timeout": 3600
|
|
12
|
+
}
|
|
13
|
+
]
|
|
14
|
+
}
|
|
15
|
+
],
|
|
16
|
+
"session.created": [
|
|
17
|
+
{
|
|
18
|
+
"matcher": "*",
|
|
19
|
+
"hooks": [
|
|
20
|
+
{
|
|
21
|
+
"type": "command",
|
|
22
|
+
"command": "node ${KILO_PLUGIN_ROOT}/hooks/session-start-hook.js",
|
|
23
|
+
"timeout": 10000
|
|
24
|
+
}
|
|
25
|
+
]
|
|
26
|
+
}
|
|
27
|
+
],
|
|
28
|
+
"message.updated": [
|
|
29
|
+
{
|
|
30
|
+
"matcher": "*",
|
|
31
|
+
"hooks": [
|
|
32
|
+
{
|
|
33
|
+
"type": "command",
|
|
34
|
+
"command": "node ${KILO_PLUGIN_ROOT}/hooks/prompt-submit-hook.js",
|
|
35
|
+
"timeout": 3600
|
|
36
|
+
}
|
|
37
|
+
]
|
|
38
|
+
}
|
|
39
|
+
],
|
|
40
|
+
"session.closing": [
|
|
41
|
+
{
|
|
42
|
+
"matcher": "*",
|
|
43
|
+
"hooks": [
|
|
44
|
+
{
|
|
45
|
+
"type": "command",
|
|
46
|
+
"command": "node ${KILO_PLUGIN_ROOT}/hooks/stop-hook.js",
|
|
47
|
+
"timeout": 300000
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
"type": "command",
|
|
51
|
+
"command": "node ${KILO_PLUGIN_ROOT}/hooks/stop-hook-git.js",
|
|
52
|
+
"timeout": 60000
|
|
53
|
+
}
|
|
54
|
+
]
|
|
55
|
+
}
|
|
56
|
+
]
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
|
|
6
|
+
const isGemini = process.env.GEMINI_PROJECT_DIR !== undefined;
|
|
7
|
+
|
|
8
|
+
const shellTools = ['Bash', 'run_shell_command'];
|
|
9
|
+
const writeTools = ['Write', 'write_file'];
|
|
10
|
+
const searchTools = ['Glob', 'Grep', 'glob', 'search_file_content', 'Search', 'search'];
|
|
11
|
+
const forbiddenTools = ['find', 'Find'];
|
|
12
|
+
|
|
13
|
+
const run = () => {
|
|
14
|
+
try {
|
|
15
|
+
const input = fs.readFileSync(0, 'utf-8');
|
|
16
|
+
const data = JSON.parse(input);
|
|
17
|
+
const { tool_name, tool_input } = data;
|
|
18
|
+
|
|
19
|
+
if (!tool_name) return { allow: true };
|
|
20
|
+
|
|
21
|
+
if (forbiddenTools.includes(tool_name)) {
|
|
22
|
+
return { block: true, reason: 'Use gm:code-execution or gm:code-search skill for semantic codebase search instead of filesystem find' };
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (shellTools.includes(tool_name)) {
|
|
26
|
+
return { block: true, reason: 'Use gm:code-execution skill with node/bun/python/etc for command execution' };
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (writeTools.includes(tool_name)) {
|
|
30
|
+
const file_path = tool_input?.file_path || '';
|
|
31
|
+
const ext = path.extname(file_path);
|
|
32
|
+
const inSkillsDir = file_path.includes('/skills/');
|
|
33
|
+
const base = path.basename(file_path).toLowerCase();
|
|
34
|
+
if ((ext === '.md' || ext === '.txt' || base.startsWith('features_list')) &&
|
|
35
|
+
!base.startsWith('claude') && !base.startsWith('readme') && !inSkillsDir) {
|
|
36
|
+
return { block: true, reason: 'Cannot create documentation files. Only CLAUDE.md and readme.md are maintained.' };
|
|
37
|
+
}
|
|
38
|
+
if (/\.(test|spec)\.(js|ts|jsx|tsx|mjs|cjs)$/.test(base) ||
|
|
39
|
+
/^(jest|vitest|mocha|ava|jasmine|tap)\.(config|setup)/.test(base) ||
|
|
40
|
+
file_path.includes('/__tests__/') || file_path.includes('/test/') ||
|
|
41
|
+
file_path.includes('/tests/') || file_path.includes('/fixtures/') ||
|
|
42
|
+
file_path.includes('/test-data/') || file_path.includes('/__mocks__/') ||
|
|
43
|
+
/\.(snap|stub|mock|fixture)\.(js|ts|json)$/.test(base)) {
|
|
44
|
+
return { block: true, reason: 'Test files forbidden on disk. Use gm:code-execution skill with real services for all testing.' };
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (searchTools.includes(tool_name)) {
|
|
49
|
+
return { block: true, reason: 'Code exploration must use: gm:code-execution skill with bun x codebasesearch. This restriction enforces semantic search over filesystem patterns.' };
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (tool_name === 'Task') {
|
|
53
|
+
const subagentType = tool_input?.subagent_type || '';
|
|
54
|
+
if (subagentType === 'Explore') {
|
|
55
|
+
return { block: true, reason: 'Use gm:code-execution skill for codebase insight, then use gm:code-search or code-execution' };
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (tool_name === 'EnterPlanMode') {
|
|
60
|
+
return { block: true, reason: 'Plan mode is disabled. Use GM agent planning (PLAN→EXECUTE→EMIT→VERIFY→COMPLETE state machine) via gm:gm subagent instead.' };
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return { allow: true };
|
|
64
|
+
} catch (error) {
|
|
65
|
+
return { allow: true };
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
try {
|
|
70
|
+
const result = run();
|
|
71
|
+
|
|
72
|
+
if (result.block) {
|
|
73
|
+
if (isGemini) {
|
|
74
|
+
console.log(JSON.stringify({ decision: 'deny', reason: result.reason }));
|
|
75
|
+
} else {
|
|
76
|
+
console.log(JSON.stringify({ hookSpecificOutput: { hookEventName: 'PreToolUse', permissionDecision: 'deny', permissionDecisionReason: result.reason } }));
|
|
77
|
+
}
|
|
78
|
+
process.exit(2);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (isGemini) {
|
|
82
|
+
console.log(JSON.stringify({ decision: 'allow' }));
|
|
83
|
+
} else {
|
|
84
|
+
console.log(JSON.stringify({ hookSpecificOutput: { hookEventName: 'PreToolUse', permissionDecision: 'allow' } }));
|
|
85
|
+
}
|
|
86
|
+
process.exit(0);
|
|
87
|
+
} catch (error) {
|
|
88
|
+
if (isGemini) {
|
|
89
|
+
console.log(JSON.stringify({ decision: 'allow' }));
|
|
90
|
+
} else {
|
|
91
|
+
console.log(JSON.stringify({ hookSpecificOutput: { hookEventName: 'PreToolUse', permissionDecision: 'allow' } }));
|
|
92
|
+
}
|
|
93
|
+
process.exit(0);
|
|
94
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const { execSync } = require('child_process');
|
|
5
|
+
|
|
6
|
+
const projectDir = process.env.CLAUDE_PROJECT_DIR || process.env.GEMINI_PROJECT_DIR || process.env.OC_PROJECT_DIR;
|
|
7
|
+
|
|
8
|
+
const COMPACT_CONTEXT = 'use gm agent | ref: TOOL_INVARIANTS | codesearch for exploration | plugin:gm:dev for execution';
|
|
9
|
+
|
|
10
|
+
const PLAN_MODE_BLOCK = 'DO NOT use EnterPlanMode or any plan mode tool. Use GM agent planning (PLAN→EXECUTE→EMIT→VERIFY→COMPLETE state machine) instead. Plan mode is blocked.';
|
|
11
|
+
|
|
12
|
+
const getBaseContext = (resetMsg = '') => {
|
|
13
|
+
let ctx = 'use gm agent';
|
|
14
|
+
if (resetMsg) ctx += ' - ' + resetMsg;
|
|
15
|
+
return ctx;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const readStdinPrompt = () => {
|
|
19
|
+
try {
|
|
20
|
+
const raw = fs.readFileSync(0, 'utf-8');
|
|
21
|
+
const data = JSON.parse(raw);
|
|
22
|
+
return data.prompt || '';
|
|
23
|
+
} catch (e) {
|
|
24
|
+
return '';
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const runCodeSearch = (query, cwd) => {
|
|
29
|
+
if (!query || !cwd || !fs.existsSync(cwd)) return '';
|
|
30
|
+
try {
|
|
31
|
+
const escaped = query.replace(/"/g, '\\"').substring(0, 200);
|
|
32
|
+
let out;
|
|
33
|
+
try {
|
|
34
|
+
out = execSync(`bun x codebasesearch@latest "${escaped}"`, {
|
|
35
|
+
encoding: 'utf-8',
|
|
36
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
37
|
+
cwd,
|
|
38
|
+
timeout: 55000,
|
|
39
|
+
killSignal: 'SIGTERM'
|
|
40
|
+
});
|
|
41
|
+
} catch (bunErr) {
|
|
42
|
+
if (bunErr.killed) return '';
|
|
43
|
+
out = execSync(`npx -y codebasesearch@latest "${escaped}"`, {
|
|
44
|
+
encoding: 'utf-8',
|
|
45
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
46
|
+
cwd,
|
|
47
|
+
timeout: 55000,
|
|
48
|
+
killSignal: 'SIGTERM'
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
const lines = out.split('\n');
|
|
52
|
+
const resultStart = lines.findIndex(l => l.includes('Searching for:'));
|
|
53
|
+
return resultStart >= 0 ? lines.slice(resultStart).join('\n').trim() : out.trim();
|
|
54
|
+
} catch (e) {
|
|
55
|
+
return '';
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const emit = (additionalContext) => {
|
|
60
|
+
const isGemini = process.env.GEMINI_PROJECT_DIR !== undefined;
|
|
61
|
+
const isOpenCode = process.env.OC_PLUGIN_ROOT !== undefined;
|
|
62
|
+
|
|
63
|
+
if (isGemini) {
|
|
64
|
+
console.log(JSON.stringify({ systemMessage: additionalContext }, null, 2));
|
|
65
|
+
} else if (isOpenCode) {
|
|
66
|
+
console.log(JSON.stringify({ hookSpecificOutput: { hookEventName: 'message.updated', additionalContext } }, null, 2));
|
|
67
|
+
} else {
|
|
68
|
+
console.log(JSON.stringify({ hookSpecificOutput: { hookEventName: 'UserPromptSubmit', additionalContext } }, null, 2));
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
try {
|
|
73
|
+
const prompt = readStdinPrompt();
|
|
74
|
+
const parts = [getBaseContext() + ' | ' + COMPACT_CONTEXT + ' | ' + PLAN_MODE_BLOCK];
|
|
75
|
+
|
|
76
|
+
if (prompt && projectDir) {
|
|
77
|
+
const searchResults = runCodeSearch(prompt, projectDir);
|
|
78
|
+
if (searchResults) {
|
|
79
|
+
parts.push(`=== Semantic code search results for initial prompt ===\n${searchResults}`);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
emit(parts.join('\n\n'));
|
|
84
|
+
} catch (error) {
|
|
85
|
+
emit(getBaseContext('hook error: ' + error.message) + ' | ' + COMPACT_CONTEXT);
|
|
86
|
+
process.exit(0);
|
|
87
|
+
}
|