gm-copilot-cli 2.0.152 → 2.0.153
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/agents/gm.md +3 -3
- package/copilot-profile.md +1 -1
- package/hooks/session-end-git-hook.js +3 -3
- package/hooks/session-end-hook.js +1 -8
- package/hooks/session-start-hook.js +23 -71
- package/manifest.yml +1 -1
- package/package.json +1 -1
- package/tools.json +1 -1
package/agents/gm.md
CHANGED
|
@@ -185,7 +185,7 @@ Server + client split:
|
|
|
185
185
|
- `git` — version control only
|
|
186
186
|
- `bun x gm-exec` — all other shell/code execution:
|
|
187
187
|
- `bun x gm-exec bash [--cwd=<dir>] <cmd>` — run shell commands
|
|
188
|
-
- `bun x gm-exec exec [--lang=<lang>] [--cwd=<dir>] [--file=<path>] <code>` — execute code (nodejs default; langs: nodejs, python, go, rust, c, cpp, java, deno, bash)
|
|
188
|
+
- `bun x gm-exec exec [--lang=<lang>] [--cwd=<dir>] [--file=<path>] <code>` — execute code (nodejs default; langs: nodejs, python, go, rust, c, cpp, java, deno, bash, cmd)
|
|
189
189
|
- `bun x gm-exec status <task_id>` — poll status + drain output of background task
|
|
190
190
|
- `bun x gm-exec sleep <task_id> [seconds]` — wait for task completion (default 30s timeout)
|
|
191
191
|
- `bun x gm-exec close <task_id>` — delete background task
|
|
@@ -194,8 +194,8 @@ Server + client split:
|
|
|
194
194
|
- Everything else is blocked
|
|
195
195
|
|
|
196
196
|
**gm-exec EXEC SAFETY RULES** — prevent stray files and working directory pollution:
|
|
197
|
-
- NEVER run `bun x gm-exec exec` without `--cwd` pointing to a safe scratch directory, not the project root. Use
|
|
198
|
-
- For any code longer than a single expression, use `--file=<path>` instead of inline `<code>`. Write the code to a temp file first via `bun x gm-exec exec "require('fs').writeFileSync('/
|
|
197
|
+
- NEVER run `bun x gm-exec exec` without `--cwd` pointing to a safe scratch directory, not the project root. Use the system temp directory (`os.tmpdir()` — `/tmp` on Unix, `C:\Users\<user>\AppData\Local\Temp` on Windows) for throwaway runs. Only use `--cwd=<project>` when the code explicitly needs to import from that project.
|
|
198
|
+
- For any code longer than a single expression, use `--file=<path>` instead of inline `<code>`. Write the code to a temp file first via `bun x gm-exec exec "require('fs').writeFileSync(require('os').tmpdir()+'/run.mjs', \`...\`)"` then run `bun x gm-exec exec --file=<tmpdir>/run.mjs`. This prevents shell quoting failures from leaking code fragments as filenames in the working directory.
|
|
199
199
|
- Single-line inline code is safe only when it contains no shell metacharacters (backticks, quotes, parens, brackets). If in doubt, use `--file`.
|
|
200
200
|
- After any exec session, verify no stray files were created: `bun x gm-exec bash --cwd=<project> "git status --porcelain"` must be empty. If stray files appear, delete them before proceeding.
|
|
201
201
|
|
package/copilot-profile.md
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
#!/usr/bin/env
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
2
|
|
|
3
|
-
// Skip hooks when running inside agentgui subprocess to prevent spurious injections
|
|
4
3
|
if (process.env.AGENTGUI_SUBPROCESS === '1') {
|
|
5
4
|
console.log(JSON.stringify({ decision: 'approve' }));
|
|
6
5
|
process.exit(0);
|
|
@@ -9,13 +8,14 @@ if (process.env.AGENTGUI_SUBPROCESS === '1') {
|
|
|
9
8
|
const { execSync } = require('child_process');
|
|
10
9
|
const fs = require('fs');
|
|
11
10
|
const path = require('path');
|
|
11
|
+
const os = require('os');
|
|
12
12
|
const crypto = require('crypto');
|
|
13
13
|
|
|
14
14
|
const projectDir = process.env.CLAUDE_PROJECT_DIR || process.cwd();
|
|
15
15
|
|
|
16
16
|
const getCounterPath = () => {
|
|
17
17
|
const hash = crypto.createHash('md5').update(projectDir).digest('hex');
|
|
18
|
-
return path.join(
|
|
18
|
+
return path.join(os.tmpdir(), `gm-git-block-counter-${hash}.json`);
|
|
19
19
|
};
|
|
20
20
|
|
|
21
21
|
const readCounter = () => {
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
#!/usr/bin/env
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
2
|
|
|
3
|
-
// Skip hooks when running inside agentgui subprocess to prevent spurious injections
|
|
4
3
|
if (process.env.AGENTGUI_SUBPROCESS === '1') {
|
|
5
4
|
console.log(JSON.stringify({ decision: 'approve' }));
|
|
6
5
|
process.exit(0);
|
|
@@ -9,8 +8,6 @@ if (process.env.AGENTGUI_SUBPROCESS === '1') {
|
|
|
9
8
|
const fs = require('fs');
|
|
10
9
|
const path = require('path');
|
|
11
10
|
|
|
12
|
-
// Always use current working directory for .prd location
|
|
13
|
-
// Explicitly resolve to ./.prd in the current folder
|
|
14
11
|
const projectDir = process.cwd();
|
|
15
12
|
const prdFile = path.resolve(projectDir, '.prd');
|
|
16
13
|
|
|
@@ -22,19 +19,15 @@ const run = () => {
|
|
|
22
19
|
if (aborted) return { ok: true };
|
|
23
20
|
|
|
24
21
|
try {
|
|
25
|
-
// Check if .prd file exists and has content
|
|
26
22
|
if (fs.existsSync(prdFile)) {
|
|
27
23
|
const prdContent = fs.readFileSync(prdFile, 'utf-8').trim();
|
|
28
24
|
if (prdContent.length > 0) {
|
|
29
|
-
// .prd has content, block stopping
|
|
30
25
|
return {
|
|
31
26
|
ok: false,
|
|
32
27
|
reason: `Work items remain in ${prdFile}. Remove completed items as they finish. Current items:\n\n${prdContent}`
|
|
33
28
|
};
|
|
34
29
|
}
|
|
35
30
|
}
|
|
36
|
-
|
|
37
|
-
// .prd doesn't exist or is empty, allow stop
|
|
38
31
|
return { ok: true };
|
|
39
32
|
} catch (error) {
|
|
40
33
|
return { ok: true };
|
|
@@ -4,8 +4,8 @@ const fs = require('fs');
|
|
|
4
4
|
const path = require('path');
|
|
5
5
|
const { execSync } = require('child_process');
|
|
6
6
|
|
|
7
|
-
const pluginRoot = process.env.CLAUDE_PLUGIN_ROOT || process.env.GEMINI_PROJECT_DIR || process.env.OC_PLUGIN_ROOT;
|
|
8
|
-
const projectDir = process.env.CLAUDE_PROJECT_DIR || process.env.GEMINI_PROJECT_DIR || process.env.OC_PROJECT_DIR;
|
|
7
|
+
const pluginRoot = process.env.CLAUDE_PLUGIN_ROOT || process.env.GEMINI_PROJECT_DIR || process.env.OC_PLUGIN_ROOT || process.env.KILO_PLUGIN_ROOT;
|
|
8
|
+
const projectDir = process.env.CLAUDE_PROJECT_DIR || process.env.GEMINI_PROJECT_DIR || process.env.OC_PROJECT_DIR || process.env.KILO_PROJECT_DIR;
|
|
9
9
|
|
|
10
10
|
const ensureGitignore = () => {
|
|
11
11
|
if (!projectDir) return;
|
|
@@ -22,9 +22,7 @@ const ensureGitignore = () => {
|
|
|
22
22
|
: content + '\n' + entry + '\n';
|
|
23
23
|
fs.writeFileSync(gitignorePath, newContent);
|
|
24
24
|
}
|
|
25
|
-
} catch (e) {
|
|
26
|
-
// Silently fail - not critical
|
|
27
|
-
}
|
|
25
|
+
} catch (e) {}
|
|
28
26
|
};
|
|
29
27
|
|
|
30
28
|
ensureGitignore();
|
|
@@ -32,41 +30,24 @@ ensureGitignore();
|
|
|
32
30
|
try {
|
|
33
31
|
let outputs = [];
|
|
34
32
|
|
|
35
|
-
// 1. Read ./start.md
|
|
36
33
|
if (pluginRoot) {
|
|
37
|
-
const
|
|
34
|
+
const gmMdPath = path.join(pluginRoot, '/agents/gm.md');
|
|
38
35
|
try {
|
|
39
|
-
const
|
|
40
|
-
outputs.push(
|
|
41
|
-
} catch (e) {
|
|
42
|
-
// File may not exist in this context
|
|
43
|
-
}
|
|
36
|
+
const gmMdContent = fs.readFileSync(gmMdPath, 'utf-8');
|
|
37
|
+
outputs.push(gmMdContent);
|
|
38
|
+
} catch (e) {}
|
|
44
39
|
}
|
|
45
40
|
|
|
46
|
-
|
|
47
|
-
const codeSearchContext = `## 🔍 Semantic Code Search Now Available
|
|
48
|
-
|
|
49
|
-
Your prompts will trigger **semantic code search** - intelligent, intent-based exploration of your codebase.
|
|
41
|
+
const codeSearchContext = `## Semantic Code Search Available
|
|
50
42
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
- "
|
|
54
|
-
- "
|
|
55
|
-
- "Show error handling patterns" → discovers try/catch patterns, error boundaries
|
|
43
|
+
Describe what you need in plain language to search the codebase:
|
|
44
|
+
- "Find authentication validation" locates auth checks, guards, permission logic
|
|
45
|
+
- "Where is database initialization?" finds connection setup, migrations, schemas
|
|
46
|
+
- "Show error handling patterns" discovers try/catch patterns, error boundaries
|
|
56
47
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
### Example
|
|
60
|
-
Instead of regex patterns, simply describe your intent:
|
|
61
|
-
"Find where API authorization is checked"
|
|
62
|
-
|
|
63
|
-
The search will find permission validations, role checks, authentication guards - however they're implemented.
|
|
64
|
-
|
|
65
|
-
### When to Use Code Search
|
|
66
|
-
When exploring unfamiliar code, finding similar patterns, understanding integrations, or locating feature implementations across your codebase.`;
|
|
48
|
+
Use the code-search skill for all codebase exploration.`;
|
|
67
49
|
outputs.push(codeSearchContext);
|
|
68
50
|
|
|
69
|
-
// 3. Run mcp-thorns (bun x with npx fallback)
|
|
70
51
|
if (projectDir && fs.existsSync(projectDir)) {
|
|
71
52
|
try {
|
|
72
53
|
let thornOutput;
|
|
@@ -97,55 +78,26 @@ When exploring unfamiliar code, finding similar patterns, understanding integrat
|
|
|
97
78
|
|
|
98
79
|
const isGemini = process.env.GEMINI_PROJECT_DIR !== undefined;
|
|
99
80
|
const isOpenCode = process.env.OC_PLUGIN_ROOT !== undefined;
|
|
81
|
+
const isKilo = process.env.KILO_PLUGIN_ROOT !== undefined;
|
|
100
82
|
|
|
101
83
|
if (isGemini) {
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
};
|
|
105
|
-
console.log(JSON.stringify(result, null, 2));
|
|
106
|
-
} else if (isOpenCode) {
|
|
107
|
-
const result = {
|
|
108
|
-
hookSpecificOutput: {
|
|
109
|
-
hookEventName: 'session.created',
|
|
110
|
-
additionalContext
|
|
111
|
-
}
|
|
112
|
-
};
|
|
113
|
-
console.log(JSON.stringify(result, null, 2));
|
|
84
|
+
console.log(JSON.stringify({ systemMessage: additionalContext }, null, 2));
|
|
85
|
+
} else if (isOpenCode || isKilo) {
|
|
86
|
+
console.log(JSON.stringify({ hookSpecificOutput: { hookEventName: 'session.created', additionalContext } }, null, 2));
|
|
114
87
|
} else {
|
|
115
|
-
|
|
116
|
-
hookSpecificOutput: {
|
|
117
|
-
hookEventName: 'SessionStart',
|
|
118
|
-
additionalContext
|
|
119
|
-
}
|
|
120
|
-
};
|
|
121
|
-
console.log(JSON.stringify(result, null, 2));
|
|
88
|
+
console.log(JSON.stringify({ hookSpecificOutput: { hookEventName: 'SessionStart', additionalContext } }, null, 2));
|
|
122
89
|
}
|
|
123
90
|
} catch (error) {
|
|
124
91
|
const isGemini = process.env.GEMINI_PROJECT_DIR !== undefined;
|
|
125
92
|
const isOpenCode = process.env.OC_PLUGIN_ROOT !== undefined;
|
|
93
|
+
const isKilo = process.env.KILO_PLUGIN_ROOT !== undefined;
|
|
126
94
|
|
|
127
95
|
if (isGemini) {
|
|
128
|
-
console.log(JSON.stringify({
|
|
129
|
-
|
|
130
|
-
}, null, 2));
|
|
131
|
-
} else if (isOpenCode) {
|
|
132
|
-
console.log(JSON.stringify({
|
|
133
|
-
hookSpecificOutput: {
|
|
134
|
-
hookEventName: 'session.created',
|
|
135
|
-
additionalContext: `Error executing hook: ${error.message}`
|
|
136
|
-
}
|
|
137
|
-
}, null, 2));
|
|
96
|
+
console.log(JSON.stringify({ systemMessage: `Error executing hook: ${error.message}` }, null, 2));
|
|
97
|
+
} else if (isOpenCode || isKilo) {
|
|
98
|
+
console.log(JSON.stringify({ hookSpecificOutput: { hookEventName: 'session.created', additionalContext: `Error executing hook: ${error.message}` } }, null, 2));
|
|
138
99
|
} else {
|
|
139
|
-
console.log(JSON.stringify({
|
|
140
|
-
hookSpecificOutput: {
|
|
141
|
-
hookEventName: 'SessionStart',
|
|
142
|
-
additionalContext: `Error executing hook: ${error.message}`
|
|
143
|
-
}
|
|
144
|
-
}, null, 2));
|
|
100
|
+
console.log(JSON.stringify({ hookSpecificOutput: { hookEventName: 'SessionStart', additionalContext: `Error executing hook: ${error.message}` } }, null, 2));
|
|
145
101
|
}
|
|
146
102
|
process.exit(0);
|
|
147
103
|
}
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
package/manifest.yml
CHANGED
package/package.json
CHANGED