gm-gc 2.0.74 → 2.0.77
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/gemini-extension.json
CHANGED
|
@@ -76,22 +76,12 @@ try {
|
|
|
76
76
|
if (isGemini) {
|
|
77
77
|
console.log(JSON.stringify({ decision: 'deny', reason: result.reason }));
|
|
78
78
|
} else {
|
|
79
|
-
console.log(JSON.stringify({
|
|
79
|
+
console.log(JSON.stringify({ decision: 'block', reason: result.reason }));
|
|
80
80
|
}
|
|
81
81
|
process.exit(0);
|
|
82
82
|
}
|
|
83
83
|
|
|
84
|
-
if (isGemini) {
|
|
85
|
-
console.log(JSON.stringify({ decision: 'allow' }));
|
|
86
|
-
} else {
|
|
87
|
-
console.log(JSON.stringify({ hookSpecificOutput: { hookEventName: 'PreToolUse', permissionDecision: 'allow' } }));
|
|
88
|
-
}
|
|
89
84
|
process.exit(0);
|
|
90
85
|
} catch (error) {
|
|
91
|
-
if (isGemini) {
|
|
92
|
-
console.log(JSON.stringify({ decision: 'allow' }));
|
|
93
|
-
} else {
|
|
94
|
-
console.log(JSON.stringify({ hookSpecificOutput: { hookEventName: 'PreToolUse', permissionDecision: 'allow' } }));
|
|
95
|
-
}
|
|
96
86
|
process.exit(0);
|
|
97
87
|
}
|
|
@@ -31,7 +31,7 @@ const runCodeSearch = (query, cwd) => {
|
|
|
31
31
|
const escaped = query.replace(/"/g, '\\"').substring(0, 200);
|
|
32
32
|
let out;
|
|
33
33
|
try {
|
|
34
|
-
out = execSync(`bun x codebasesearch
|
|
34
|
+
out = execSync(`bun x codebasesearch "${escaped}"`, {
|
|
35
35
|
encoding: 'utf-8',
|
|
36
36
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
37
37
|
cwd,
|
|
@@ -40,7 +40,7 @@ const runCodeSearch = (query, cwd) => {
|
|
|
40
40
|
});
|
|
41
41
|
} catch (bunErr) {
|
|
42
42
|
if (bunErr.killed) return '';
|
|
43
|
-
out = execSync(`npx -y codebasesearch
|
|
43
|
+
out = execSync(`npx -y codebasesearch "${escaped}"`, {
|
|
44
44
|
encoding: 'utf-8',
|
|
45
45
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
46
46
|
cwd,
|
|
@@ -65,7 +65,7 @@ const emit = (additionalContext) => {
|
|
|
65
65
|
} else if (isOpenCode) {
|
|
66
66
|
console.log(JSON.stringify({ hookSpecificOutput: { hookEventName: 'message.updated', additionalContext } }, null, 2));
|
|
67
67
|
} else {
|
|
68
|
-
console.log(JSON.stringify({
|
|
68
|
+
console.log(JSON.stringify({ additionalContext }, null, 2));
|
|
69
69
|
}
|
|
70
70
|
};
|
|
71
71
|
|
|
@@ -4,7 +4,7 @@ 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 || process.env.KILO_PLUGIN_ROOT;
|
|
7
|
+
const pluginRoot = process.env.CLAUDE_PLUGIN_ROOT || process.env.GEMINI_PROJECT_DIR || process.env.OC_PLUGIN_ROOT || process.env.KILO_PLUGIN_ROOT || path.join(__dirname, '..');
|
|
8
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 = () => {
|
|
@@ -71,7 +71,7 @@ When exploring unfamiliar code, finding similar patterns, understanding integrat
|
|
|
71
71
|
try {
|
|
72
72
|
let thornOutput;
|
|
73
73
|
try {
|
|
74
|
-
thornOutput = execSync(`bun x mcp-thorns
|
|
74
|
+
thornOutput = execSync(`bun x mcp-thorns`, {
|
|
75
75
|
encoding: 'utf-8',
|
|
76
76
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
77
77
|
cwd: projectDir,
|
|
@@ -83,7 +83,7 @@ When exploring unfamiliar code, finding similar patterns, understanding integrat
|
|
|
83
83
|
thornOutput = '=== mcp-thorns ===\nSkipped (3min timeout)';
|
|
84
84
|
} else {
|
|
85
85
|
try {
|
|
86
|
-
thornOutput = execSync(`npx -y mcp-thorns
|
|
86
|
+
thornOutput = execSync(`npx -y mcp-thorns`, {
|
|
87
87
|
encoding: 'utf-8',
|
|
88
88
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
89
89
|
cwd: projectDir,
|
|
@@ -116,26 +116,11 @@ When exploring unfamiliar code, finding similar patterns, understanding integrat
|
|
|
116
116
|
const isKilo = process.env.KILO_PLUGIN_ROOT !== undefined;
|
|
117
117
|
|
|
118
118
|
if (isGemini) {
|
|
119
|
-
|
|
120
|
-
systemMessage: additionalContext
|
|
121
|
-
};
|
|
122
|
-
console.log(JSON.stringify(result, null, 2));
|
|
119
|
+
console.log(JSON.stringify({ systemMessage: additionalContext }, null, 2));
|
|
123
120
|
} else if (isOpenCode || isKilo) {
|
|
124
|
-
|
|
125
|
-
hookSpecificOutput: {
|
|
126
|
-
hookEventName: 'session.created',
|
|
127
|
-
additionalContext
|
|
128
|
-
}
|
|
129
|
-
};
|
|
130
|
-
console.log(JSON.stringify(result, null, 2));
|
|
121
|
+
console.log(JSON.stringify({ hookSpecificOutput: { hookEventName: 'session.created', additionalContext } }, null, 2));
|
|
131
122
|
} else {
|
|
132
|
-
|
|
133
|
-
hookSpecificOutput: {
|
|
134
|
-
hookEventName: 'SessionStart',
|
|
135
|
-
additionalContext
|
|
136
|
-
}
|
|
137
|
-
};
|
|
138
|
-
console.log(JSON.stringify(result, null, 2));
|
|
123
|
+
console.log(JSON.stringify({ additionalContext }, null, 2));
|
|
139
124
|
}
|
|
140
125
|
} catch (error) {
|
|
141
126
|
const isGemini = process.env.GEMINI_PROJECT_DIR !== undefined;
|
|
@@ -143,23 +128,11 @@ When exploring unfamiliar code, finding similar patterns, understanding integrat
|
|
|
143
128
|
const isKilo = process.env.KILO_PLUGIN_ROOT !== undefined;
|
|
144
129
|
|
|
145
130
|
if (isGemini) {
|
|
146
|
-
console.log(JSON.stringify({
|
|
147
|
-
systemMessage: `Error executing hook: ${error.message}`
|
|
148
|
-
}, null, 2));
|
|
131
|
+
console.log(JSON.stringify({ systemMessage: `Error executing hook: ${error.message}` }, null, 2));
|
|
149
132
|
} else if (isOpenCode || isKilo) {
|
|
150
|
-
console.log(JSON.stringify({
|
|
151
|
-
hookSpecificOutput: {
|
|
152
|
-
hookEventName: 'session.created',
|
|
153
|
-
additionalContext: `Error executing hook: ${error.message}`
|
|
154
|
-
}
|
|
155
|
-
}, null, 2));
|
|
133
|
+
console.log(JSON.stringify({ hookSpecificOutput: { hookEventName: 'session.created', additionalContext: `Error executing hook: ${error.message}` } }, null, 2));
|
|
156
134
|
} else {
|
|
157
|
-
console.log(JSON.stringify({
|
|
158
|
-
hookSpecificOutput: {
|
|
159
|
-
hookEventName: 'SessionStart',
|
|
160
|
-
additionalContext: `Error executing hook: ${error.message}`
|
|
161
|
-
}
|
|
162
|
-
}, null, 2));
|
|
135
|
+
console.log(JSON.stringify({ additionalContext: `Error executing hook: ${error.message}` }, null, 2));
|
|
163
136
|
}
|
|
164
137
|
process.exit(0);
|
|
165
138
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gm-gc",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.77",
|
|
4
4
|
"description": "State machine agent with hooks, skills, and automated git enforcement",
|
|
5
5
|
"author": "AnEntrypoint",
|
|
6
6
|
"license": "MIT",
|
|
@@ -38,5 +38,12 @@
|
|
|
38
38
|
".gitignore",
|
|
39
39
|
".editorconfig",
|
|
40
40
|
"CONTRIBUTING.md"
|
|
41
|
-
]
|
|
41
|
+
],
|
|
42
|
+
"dependencies": {
|
|
43
|
+
"mcp-thorns": "latest",
|
|
44
|
+
"codebasesearch": "latest"
|
|
45
|
+
},
|
|
46
|
+
"scripts": {
|
|
47
|
+
"postinstall": "node scripts/postinstall.js"
|
|
48
|
+
}
|
|
42
49
|
}
|
package/scripts/postinstall.js
CHANGED
|
@@ -2,38 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
const fs = require('fs');
|
|
4
4
|
const path = require('path');
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Postinstall script for gm-cc
|
|
8
|
-
* Implements Mode 1: Standalone .claude/ directory installation
|
|
9
|
-
*
|
|
10
|
-
* When installed via npm in a project:
|
|
11
|
-
* - Copies agents/, hooks/, .mcp.json to project's .claude/
|
|
12
|
-
* - Updates .gitignore with .gm-stop-verified
|
|
13
|
-
* - Runs silently, never breaks npm install
|
|
14
|
-
* - Safe to run multiple times (idempotent)
|
|
15
|
-
*/
|
|
5
|
+
const { execSync } = require('child_process');
|
|
16
6
|
|
|
17
7
|
function isInsideNodeModules() {
|
|
18
|
-
// Check if __dirname contains /node_modules/ in its path
|
|
19
|
-
// Example: /project/node_modules/gm-cc/scripts
|
|
20
8
|
return __dirname.includes(path.sep + 'node_modules' + path.sep);
|
|
21
9
|
}
|
|
22
10
|
|
|
23
11
|
function getProjectRoot() {
|
|
24
|
-
|
|
25
|
-
// Navigate to /project
|
|
26
|
-
if (!isInsideNodeModules()) {
|
|
27
|
-
return null;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
// Find the node_modules parent (project root)
|
|
12
|
+
if (!isInsideNodeModules()) return null;
|
|
31
13
|
let current = __dirname;
|
|
32
|
-
while (current !== path.dirname(current)) {
|
|
14
|
+
while (current !== path.dirname(current)) {
|
|
33
15
|
current = path.dirname(current);
|
|
34
|
-
const parent = path.dirname(current);
|
|
35
16
|
if (path.basename(current) === 'node_modules') {
|
|
36
|
-
return
|
|
17
|
+
return path.dirname(current);
|
|
37
18
|
}
|
|
38
19
|
}
|
|
39
20
|
return null;
|
|
@@ -43,39 +24,26 @@ function safeCopyFile(src, dst) {
|
|
|
43
24
|
try {
|
|
44
25
|
const content = fs.readFileSync(src, 'utf-8');
|
|
45
26
|
const dstDir = path.dirname(dst);
|
|
46
|
-
if (!fs.existsSync(dstDir)) {
|
|
47
|
-
fs.mkdirSync(dstDir, { recursive: true });
|
|
48
|
-
}
|
|
27
|
+
if (!fs.existsSync(dstDir)) fs.mkdirSync(dstDir, { recursive: true });
|
|
49
28
|
fs.writeFileSync(dst, content, 'utf-8');
|
|
50
29
|
return true;
|
|
51
30
|
} catch (err) {
|
|
52
|
-
// Silently skip errors
|
|
53
31
|
return false;
|
|
54
32
|
}
|
|
55
33
|
}
|
|
56
34
|
|
|
57
35
|
function safeCopyDirectory(src, dst) {
|
|
58
36
|
try {
|
|
59
|
-
if (!fs.existsSync(src))
|
|
60
|
-
return false; // Source doesn't exist, skip
|
|
61
|
-
}
|
|
62
|
-
|
|
37
|
+
if (!fs.existsSync(src)) return false;
|
|
63
38
|
fs.mkdirSync(dst, { recursive: true });
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
entries.forEach(entry => {
|
|
39
|
+
fs.readdirSync(src, { withFileTypes: true }).forEach(entry => {
|
|
67
40
|
const srcPath = path.join(src, entry.name);
|
|
68
41
|
const dstPath = path.join(dst, entry.name);
|
|
69
|
-
|
|
70
|
-
if (entry.
|
|
71
|
-
safeCopyDirectory(srcPath, dstPath);
|
|
72
|
-
} else if (entry.isFile()) {
|
|
73
|
-
safeCopyFile(srcPath, dstPath);
|
|
74
|
-
}
|
|
42
|
+
if (entry.isDirectory()) safeCopyDirectory(srcPath, dstPath);
|
|
43
|
+
else if (entry.isFile()) safeCopyFile(srcPath, dstPath);
|
|
75
44
|
});
|
|
76
45
|
return true;
|
|
77
46
|
} catch (err) {
|
|
78
|
-
// Silently skip errors
|
|
79
47
|
return false;
|
|
80
48
|
}
|
|
81
49
|
}
|
|
@@ -84,45 +52,22 @@ function updateGitignore(projectRoot) {
|
|
|
84
52
|
try {
|
|
85
53
|
const gitignorePath = path.join(projectRoot, '.gitignore');
|
|
86
54
|
const entry = '.gm-stop-verified';
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
content = fs.readFileSync(gitignorePath, 'utf-8');
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
// Check if entry already exists
|
|
95
|
-
if (content.includes(entry)) {
|
|
96
|
-
return true; // Already there
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
// Append entry
|
|
100
|
-
if (content && !content.endsWith('\n')) {
|
|
101
|
-
content += '\n';
|
|
102
|
-
}
|
|
103
|
-
content += entry + '\n';
|
|
104
|
-
|
|
105
|
-
fs.writeFileSync(gitignorePath, content, 'utf-8');
|
|
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');
|
|
106
59
|
return true;
|
|
107
60
|
} catch (err) {
|
|
108
|
-
// Silently skip errors
|
|
109
61
|
return false;
|
|
110
62
|
}
|
|
111
63
|
}
|
|
112
64
|
|
|
113
65
|
function install() {
|
|
114
|
-
|
|
115
|
-
if (!isInsideNodeModules()) {
|
|
116
|
-
return; // Silent exit
|
|
117
|
-
}
|
|
118
|
-
|
|
66
|
+
if (!isInsideNodeModules()) return;
|
|
119
67
|
const projectRoot = getProjectRoot();
|
|
120
|
-
if (!projectRoot)
|
|
121
|
-
return; // Silent exit
|
|
122
|
-
}
|
|
123
|
-
|
|
68
|
+
if (!projectRoot) return;
|
|
124
69
|
const claudeDir = path.join(projectRoot, '.claude');
|
|
125
|
-
const sourceDir = __dirname.replace(/[
|
|
70
|
+
const sourceDir = __dirname.replace(/[/\\]scripts$/, '');
|
|
126
71
|
|
|
127
72
|
// Copy files
|
|
128
73
|
safeCopyDirectory(path.join(sourceDir, 'agents'), path.join(claudeDir, 'agents'));
|
|
@@ -131,8 +76,26 @@ function install() {
|
|
|
131
76
|
|
|
132
77
|
// Update .gitignore
|
|
133
78
|
updateGitignore(projectRoot);
|
|
134
|
-
|
|
79
|
+
|
|
80
|
+
// Warm bun x cache for packages used by hooks
|
|
81
|
+
warmBunCache();
|
|
82
|
+
|
|
135
83
|
// Silent success
|
|
136
84
|
}
|
|
137
85
|
|
|
86
|
+
function warmBunCache() {
|
|
87
|
+
const packages = ['mcp-thorns@latest', 'codebasesearch@latest'];
|
|
88
|
+
for (const pkg of packages) {
|
|
89
|
+
try {
|
|
90
|
+
execSync(`bun x ${pkg} --version`, {
|
|
91
|
+
encoding: 'utf-8',
|
|
92
|
+
stdio: 'pipe',
|
|
93
|
+
timeout: 60000
|
|
94
|
+
});
|
|
95
|
+
} catch (e) {
|
|
96
|
+
// Silent - cache warming is best-effort
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
138
101
|
install();
|