gm-gc 2.0.77 → 2.0.79
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 +8 -0
- package/gemini-extension.json +1 -1
- package/package.json +1 -1
- package/scripts/postinstall-kilo.js +119 -0
- package/scripts/postinstall-oc.js +118 -0
- package/skills/gm/SKILL.md +15 -0
- package/skills/process-management/SKILL.md +20 -0
package/agents/gm.md
CHANGED
|
@@ -365,6 +365,14 @@ Scope: Runtime process execution. Governs how all applications are started, moni
|
|
|
365
365
|
- Windows 11+: `spawn wmic ENOENT` in daemon logs is cosmetic — app processes work; fix with `npm install -g pm2@latest`
|
|
366
366
|
- Linux watch exhaustion: `echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p`
|
|
367
367
|
|
|
368
|
+
**Windows Terminal Suppression (CRITICAL)**:
|
|
369
|
+
- All terminal spawning in code MUST use `windowsHide: true` in spawn/exec options
|
|
370
|
+
- Prevents popup windows on Windows during subprocess execution
|
|
371
|
+
- Example: `spawn('node', [...], { windowsHide: true })`
|
|
372
|
+
- Applies to all `child_process.spawn()`, `child_process.exec()`, and similar calls
|
|
373
|
+
- PM2 processes automatically hide windows; code-spawned subprocesses must explicitly set this
|
|
374
|
+
- Forgetting this creates visible popup windows during automation—unacceptable UX
|
|
375
|
+
|
|
368
376
|
**Log monitoring**:
|
|
369
377
|
```bash
|
|
370
378
|
pm2 logs <name> # stream live output
|
package/gemini-extension.json
CHANGED
package/package.json
CHANGED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const { execSync } = require('child_process');
|
|
6
|
+
|
|
7
|
+
function isInsideNodeModules() {
|
|
8
|
+
return __dirname.includes(path.sep + 'node_modules' + path.sep);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function getProjectRoot() {
|
|
12
|
+
if (!isInsideNodeModules()) return null;
|
|
13
|
+
let current = __dirname;
|
|
14
|
+
while (current !== path.dirname(current)) {
|
|
15
|
+
current = path.dirname(current);
|
|
16
|
+
if (path.basename(current) === 'node_modules') {
|
|
17
|
+
return path.dirname(current);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function safeCopyFile(src, dst) {
|
|
24
|
+
try {
|
|
25
|
+
const content = fs.readFileSync(src, 'utf-8');
|
|
26
|
+
const dstDir = path.dirname(dst);
|
|
27
|
+
if (!fs.existsSync(dstDir)) fs.mkdirSync(dstDir, { recursive: true });
|
|
28
|
+
fs.writeFileSync(dst, content, 'utf-8');
|
|
29
|
+
return true;
|
|
30
|
+
} catch (e) {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function safeCopyDirectory(src, dst) {
|
|
36
|
+
try {
|
|
37
|
+
if (!fs.existsSync(src)) return false;
|
|
38
|
+
fs.mkdirSync(dst, { recursive: true });
|
|
39
|
+
fs.readdirSync(src, { withFileTypes: true }).forEach(entry => {
|
|
40
|
+
const srcPath = path.join(src, entry.name);
|
|
41
|
+
const dstPath = path.join(dst, entry.name);
|
|
42
|
+
if (entry.isDirectory()) safeCopyDirectory(srcPath, dstPath);
|
|
43
|
+
else if (entry.isFile()) safeCopyFile(srcPath, dstPath);
|
|
44
|
+
});
|
|
45
|
+
return true;
|
|
46
|
+
} catch (e) {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function updateGitignore(projectRoot) {
|
|
52
|
+
try {
|
|
53
|
+
const gitignorePath = path.join(projectRoot, '.gitignore');
|
|
54
|
+
const entry = '.gm-stop-verified';
|
|
55
|
+
let content = fs.existsSync(gitignorePath) ? fs.readFileSync(gitignorePath, 'utf-8') : '';
|
|
56
|
+
if (content.includes(entry)) return true;
|
|
57
|
+
if (content && !content.endsWith('\n')) content += '\n';
|
|
58
|
+
fs.writeFileSync(gitignorePath, content + entry + '\n', 'utf-8');
|
|
59
|
+
return true;
|
|
60
|
+
} catch (e) {
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function install() {
|
|
66
|
+
if (!isInsideNodeModules()) return;
|
|
67
|
+
const projectRoot = getProjectRoot();
|
|
68
|
+
if (!projectRoot) return;
|
|
69
|
+
const kiloDir = path.join(projectRoot, '.config', 'kilo');
|
|
70
|
+
const sourceDir = __dirname.replace(/[/\\]scripts$/, '');
|
|
71
|
+
|
|
72
|
+
// Copy files
|
|
73
|
+
safeCopyDirectory(path.join(sourceDir, 'agents'), path.join(kiloDir, 'agents'));
|
|
74
|
+
safeCopyDirectory(path.join(sourceDir, 'hooks'), path.join(kiloDir, 'hooks'));
|
|
75
|
+
safeCopyDirectory(path.join(sourceDir, 'skills'), path.join(kiloDir, 'skills'));
|
|
76
|
+
safeCopyFile(path.join(sourceDir, 'kilocode.json'), path.join(kiloDir, 'kilocode.json'));
|
|
77
|
+
safeCopyFile(path.join(sourceDir, '.mcp.json'), path.join(kiloDir, '.mcp.json'));
|
|
78
|
+
safeCopyFile(path.join(sourceDir, 'gm.mjs'), path.join(kiloDir, 'gm.mjs'));
|
|
79
|
+
safeCopyFile(path.join(sourceDir, 'index.mjs'), path.join(kiloDir, 'index.mjs'));
|
|
80
|
+
safeCopyFile(path.join(sourceDir, 'README.md'), path.join(kiloDir, 'README.md'));
|
|
81
|
+
safeCopyFile(path.join(sourceDir, 'LICENSE'), path.join(kiloDir, 'LICENSE'));
|
|
82
|
+
safeCopyFile(path.join(sourceDir, 'CONTRIBUTING.md'), path.join(kiloDir, 'CONTRIBUTING.md'));
|
|
83
|
+
safeCopyFile(path.join(sourceDir, '.gitignore'), path.join(kiloDir, '.gitignore'));
|
|
84
|
+
safeCopyFile(path.join(sourceDir, '.editorconfig'), path.join(kiloDir, '.editorconfig'));
|
|
85
|
+
|
|
86
|
+
// Also write plugin/ directory - Kilo loads from ~/.config/kilo/plugin/ as a local file plugin
|
|
87
|
+
const pluginDir = path.join(kiloDir, 'plugin');
|
|
88
|
+
if (!fs.existsSync(pluginDir)) fs.mkdirSync(pluginDir, { recursive: true });
|
|
89
|
+
const gmMjsSrc = path.join(sourceDir, 'gm.mjs');
|
|
90
|
+
if (fs.existsSync(gmMjsSrc)) {
|
|
91
|
+
safeCopyFile(gmMjsSrc, path.join(pluginDir, 'gm.mjs'));
|
|
92
|
+
}
|
|
93
|
+
fs.writeFileSync(path.join(pluginDir, 'index.js'), "export { default } from './gm.mjs';\n", 'utf-8');
|
|
94
|
+
|
|
95
|
+
// Update .gitignore
|
|
96
|
+
updateGitignore(projectRoot);
|
|
97
|
+
|
|
98
|
+
// Warm bun x cache for packages used by hooks
|
|
99
|
+
warmBunCache();
|
|
100
|
+
|
|
101
|
+
// Silent success
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function warmBunCache() {
|
|
105
|
+
const packages = ['mcp-thorns@latest', 'codebasesearch@latest'];
|
|
106
|
+
for (const pkg of packages) {
|
|
107
|
+
try {
|
|
108
|
+
execSync(`bun x ${pkg} --version`, {
|
|
109
|
+
encoding: 'utf-8',
|
|
110
|
+
stdio: 'pipe',
|
|
111
|
+
timeout: 60000
|
|
112
|
+
});
|
|
113
|
+
} catch (e) {
|
|
114
|
+
// Silent - cache warming is best-effort
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
install();
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const { execSync } = require('child_process');
|
|
6
|
+
|
|
7
|
+
function isInsideNodeModules() {
|
|
8
|
+
return __dirname.includes(path.sep + 'node_modules' + path.sep);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function getProjectRoot() {
|
|
12
|
+
if (!isInsideNodeModules()) return null;
|
|
13
|
+
let current = __dirname;
|
|
14
|
+
while (current !== path.dirname(current)) {
|
|
15
|
+
current = path.dirname(current);
|
|
16
|
+
if (path.basename(current) === 'node_modules') {
|
|
17
|
+
return path.dirname(current);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function safeCopyFile(src, dst) {
|
|
24
|
+
try {
|
|
25
|
+
const content = fs.readFileSync(src, 'utf-8');
|
|
26
|
+
const dstDir = path.dirname(dst);
|
|
27
|
+
if (!fs.existsSync(dstDir)) fs.mkdirSync(dstDir, { recursive: true });
|
|
28
|
+
fs.writeFileSync(dst, content, 'utf-8');
|
|
29
|
+
return true;
|
|
30
|
+
} catch (e) {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function safeCopyDirectory(src, dst) {
|
|
36
|
+
try {
|
|
37
|
+
if (!fs.existsSync(src)) return false;
|
|
38
|
+
fs.mkdirSync(dst, { recursive: true });
|
|
39
|
+
fs.readdirSync(src, { withFileTypes: true }).forEach(entry => {
|
|
40
|
+
const srcPath = path.join(src, entry.name);
|
|
41
|
+
const dstPath = path.join(dst, entry.name);
|
|
42
|
+
if (entry.isDirectory()) safeCopyDirectory(srcPath, dstPath);
|
|
43
|
+
else if (entry.isFile()) safeCopyFile(srcPath, dstPath);
|
|
44
|
+
});
|
|
45
|
+
return true;
|
|
46
|
+
} catch (e) {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function updateGitignore(projectRoot) {
|
|
52
|
+
try {
|
|
53
|
+
const gitignorePath = path.join(projectRoot, '.gitignore');
|
|
54
|
+
const entry = '.gm-stop-verified';
|
|
55
|
+
let content = fs.existsSync(gitignorePath) ? fs.readFileSync(gitignorePath, 'utf-8') : '';
|
|
56
|
+
if (content.includes(entry)) return true;
|
|
57
|
+
if (content && !content.endsWith('\n')) content += '\n';
|
|
58
|
+
fs.writeFileSync(gitignorePath, content + entry + '\n', 'utf-8');
|
|
59
|
+
return true;
|
|
60
|
+
} catch (e) {
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function install() {
|
|
66
|
+
if (!isInsideNodeModules()) return;
|
|
67
|
+
const projectRoot = getProjectRoot();
|
|
68
|
+
if (!projectRoot) return;
|
|
69
|
+
const ocDir = path.join(projectRoot, '.config', 'opencode');
|
|
70
|
+
const sourceDir = __dirname.replace(/[/\\]scripts$/, '');
|
|
71
|
+
|
|
72
|
+
// Copy files
|
|
73
|
+
safeCopyDirectory(path.join(sourceDir, 'agents'), path.join(ocDir, 'agents'));
|
|
74
|
+
safeCopyDirectory(path.join(sourceDir, 'hooks'), path.join(ocDir, 'hooks'));
|
|
75
|
+
safeCopyDirectory(path.join(sourceDir, 'skills'), path.join(ocDir, 'skills'));
|
|
76
|
+
safeCopyFile(path.join(sourceDir, 'opencode.json'), path.join(ocDir, 'opencode.json'));
|
|
77
|
+
safeCopyFile(path.join(sourceDir, '.mcp.json'), path.join(ocDir, '.mcp.json'));
|
|
78
|
+
safeCopyFile(path.join(sourceDir, 'gm.mjs'), path.join(ocDir, 'gm.mjs'));
|
|
79
|
+
safeCopyFile(path.join(sourceDir, 'index.mjs'), path.join(ocDir, 'index.mjs'));
|
|
80
|
+
safeCopyFile(path.join(sourceDir, 'README.md'), path.join(ocDir, 'README.md'));
|
|
81
|
+
safeCopyFile(path.join(sourceDir, 'LICENSE'), path.join(ocDir, 'LICENSE'));
|
|
82
|
+
safeCopyFile(path.join(sourceDir, 'CONTRIBUTING.md'), path.join(ocDir, 'CONTRIBUTING.md'));
|
|
83
|
+
safeCopyFile(path.join(sourceDir, '.gitignore'), path.join(ocDir, '.gitignore'));
|
|
84
|
+
safeCopyFile(path.join(sourceDir, '.editorconfig'), path.join(ocDir, '.editorconfig'));
|
|
85
|
+
|
|
86
|
+
// Also write to plugins/gm-oc.mjs - the actual file OpenCode loads
|
|
87
|
+
const pluginsDir = path.join(ocDir, 'plugins');
|
|
88
|
+
if (!fs.existsSync(pluginsDir)) fs.mkdirSync(pluginsDir, { recursive: true });
|
|
89
|
+
const gmMjsSrc = path.join(sourceDir, 'gm.mjs');
|
|
90
|
+
if (fs.existsSync(gmMjsSrc)) {
|
|
91
|
+
safeCopyFile(gmMjsSrc, path.join(pluginsDir, 'gm-oc.mjs'));
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Update .gitignore
|
|
95
|
+
updateGitignore(projectRoot);
|
|
96
|
+
|
|
97
|
+
// Warm bun x cache for packages used by hooks
|
|
98
|
+
warmBunCache();
|
|
99
|
+
|
|
100
|
+
// Silent success
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function warmBunCache() {
|
|
104
|
+
const packages = ['mcp-thorns@latest', 'codebasesearch@latest'];
|
|
105
|
+
for (const pkg of packages) {
|
|
106
|
+
try {
|
|
107
|
+
execSync(`bun x ${pkg} --version`, {
|
|
108
|
+
encoding: 'utf-8',
|
|
109
|
+
stdio: 'pipe',
|
|
110
|
+
timeout: 60000
|
|
111
|
+
});
|
|
112
|
+
} catch (e) {
|
|
113
|
+
// Silent - cache warming is best-effort
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
install();
|
package/skills/gm/SKILL.md
CHANGED
|
@@ -93,6 +93,21 @@ All execution via Bash tool or `agent-browser` skill. Every hypothesis proven by
|
|
|
93
93
|
- Starting/stopping system services
|
|
94
94
|
- Everything else → Bash tool
|
|
95
95
|
|
|
96
|
+
**CRITICAL: Windows Terminal Suppression**:
|
|
97
|
+
When code spawns subprocesses, ALWAYS use `windowsHide: true` to prevent popup windows on Windows:
|
|
98
|
+
|
|
99
|
+
```javascript
|
|
100
|
+
// ❌ WRONG - popup windows on Windows
|
|
101
|
+
const { spawn } = require('child_process');
|
|
102
|
+
spawn('node', ['script.js']);
|
|
103
|
+
|
|
104
|
+
// ✅ CORRECT - hides windows, works cross-platform
|
|
105
|
+
const { spawn } = require('child_process');
|
|
106
|
+
spawn('node', ['script.js'], { windowsHide: true });
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Applies to: `spawn()`, `exec()`, `execFile()`, `fork()`. See `process-management` skill for full details.
|
|
110
|
+
|
|
96
111
|
## CHARTER 3: GROUND TRUTH
|
|
97
112
|
|
|
98
113
|
Scope: Data integrity and testing methodology. Governs what constitutes valid evidence.
|
|
@@ -168,6 +168,26 @@ Get-Command myapp | Select-Object -ExpandProperty Source
|
|
|
168
168
|
```
|
|
169
169
|
Point `script` at the resolved `.js` file — never at the `.cmd` wrapper.
|
|
170
170
|
|
|
171
|
+
### Terminal Suppression on Windows (CRITICAL)
|
|
172
|
+
|
|
173
|
+
All code that spawns subprocesses MUST use `windowsHide: true` to prevent popup windows.
|
|
174
|
+
|
|
175
|
+
```javascript
|
|
176
|
+
// ❌ WRONG - will show popup windows on Windows
|
|
177
|
+
spawn('node', ['script.js']);
|
|
178
|
+
|
|
179
|
+
// ✅ CORRECT - hides windows, safe for all platforms
|
|
180
|
+
spawn('node', ['script.js'], { windowsHide: true });
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
Applies to all subprocess execution:
|
|
184
|
+
- `child_process.spawn()` → `{ windowsHide: true }`
|
|
185
|
+
- `child_process.exec()` → `{ windowsHide: true }`
|
|
186
|
+
- `child_process.execFile()` → `{ windowsHide: true }`
|
|
187
|
+
- `child_process.fork()` → `{ silent: true }` (alternative for fork)
|
|
188
|
+
|
|
189
|
+
PM2-started processes automatically hide windows. Code-spawned subprocesses must explicitly set this. Forgetting creates visible popups during automation—unacceptable UX.
|
|
190
|
+
|
|
171
191
|
### Windows 11+ wmic Error
|
|
172
192
|
|
|
173
193
|
PM2 uses `wmic` for process stats — removed in Windows 11+.
|