gm-cc 2.0.247 → 2.0.251

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.
@@ -4,7 +4,7 @@
4
4
  "name": "AnEntrypoint"
5
5
  },
6
6
  "description": "State machine agent with hooks, skills, and automated git enforcement",
7
- "version": "2.0.247",
7
+ "version": "2.0.251",
8
8
  "metadata": {
9
9
  "description": "State machine agent with hooks, skills, and automated git enforcement"
10
10
  },
package/hooks/hooks.json CHANGED
@@ -7,7 +7,7 @@
7
7
  "hooks": [
8
8
  {
9
9
  "type": "command",
10
- "command": "bun ${CLAUDE_PLUGIN_ROOT}/hooks/pre-tool-use-hook.js",
10
+ "command": "${CLAUDE_PLUGIN_ROOT}/bin/plugkit hook pre-tool-use",
11
11
  "timeout": 3600
12
12
  }
13
13
  ]
@@ -19,8 +19,13 @@
19
19
  "hooks": [
20
20
  {
21
21
  "type": "command",
22
- "command": "bun ${CLAUDE_PLUGIN_ROOT}/hooks/session-start-hook.js",
23
- "timeout": 10000
22
+ "command": "node ${CLAUDE_PLUGIN_ROOT}/scripts/bootstrap.js",
23
+ "timeout": 60000
24
+ },
25
+ {
26
+ "type": "command",
27
+ "command": "${CLAUDE_PLUGIN_ROOT}/bin/plugkit hook session-start",
28
+ "timeout": 180000
24
29
  }
25
30
  ]
26
31
  }
@@ -31,8 +36,8 @@
31
36
  "hooks": [
32
37
  {
33
38
  "type": "command",
34
- "command": "bun ${CLAUDE_PLUGIN_ROOT}/hooks/prompt-submit-hook.js",
35
- "timeout": 3600
39
+ "command": "${CLAUDE_PLUGIN_ROOT}/bin/plugkit hook prompt-submit",
40
+ "timeout": 60000
36
41
  }
37
42
  ]
38
43
  }
@@ -43,12 +48,12 @@
43
48
  "hooks": [
44
49
  {
45
50
  "type": "command",
46
- "command": "bun ${CLAUDE_PLUGIN_ROOT}/hooks/stop-hook.js",
51
+ "command": "${CLAUDE_PLUGIN_ROOT}/bin/plugkit hook stop",
47
52
  "timeout": 300000
48
53
  },
49
54
  {
50
55
  "type": "command",
51
- "command": "bun ${CLAUDE_PLUGIN_ROOT}/hooks/stop-hook-git.js",
56
+ "command": "${CLAUDE_PLUGIN_ROOT}/bin/plugkit hook stop-git",
52
57
  "timeout": 60000
53
58
  }
54
59
  ]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gm-cc",
3
- "version": "2.0.247",
3
+ "version": "2.0.251",
4
4
  "description": "State machine agent with hooks, skills, and automated git enforcement",
5
5
  "author": "AnEntrypoint",
6
6
  "license": "MIT",
package/plugin.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gm",
3
- "version": "2.0.247",
3
+ "version": "2.0.251",
4
4
  "description": "State machine agent with hooks, skills, and automated git enforcement",
5
5
  "author": {
6
6
  "name": "AnEntrypoint",
@@ -0,0 +1,45 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+ const https = require('https');
6
+
7
+ const pluginRoot = process.env.CLAUDE_PLUGIN_ROOT;
8
+ if (!pluginRoot) process.exit(0);
9
+
10
+ const IS_WIN = process.platform === 'win32';
11
+ const binPath = path.join(pluginRoot, 'bin', IS_WIN ? 'plugkit.exe' : 'plugkit');
12
+
13
+ if (fs.existsSync(binPath)) process.exit(0);
14
+
15
+ function getVersion() {
16
+ try {
17
+ return JSON.parse(fs.readFileSync(path.join(pluginRoot, 'gm.json'), 'utf8')).plugkitVersion || null;
18
+ } catch { return null; }
19
+ }
20
+
21
+ function download(version, dest, cb) {
22
+ const asset = IS_WIN ? 'plugkit.exe' : 'plugkit';
23
+ const urlPath = version
24
+ ? `/AnEntrypoint/rs-plugkit/releases/download/v${version}/${asset}`
25
+ : `/AnEntrypoint/rs-plugkit/releases/latest/download/${asset}`;
26
+ const destDir = path.dirname(dest);
27
+ if (!fs.existsSync(destDir)) fs.mkdirSync(destDir, { recursive: true });
28
+ const follow = (url) => {
29
+ const mod = url.startsWith('https') ? https : require('http');
30
+ const opts = { ...require('url').parse(url), headers: { 'User-Agent': 'gm-bootstrap' } };
31
+ mod.get(opts, res => {
32
+ if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) return follow(res.headers.location);
33
+ if (res.statusCode !== 200) return cb(new Error(`HTTP ${res.statusCode}`));
34
+ const chunks = [];
35
+ res.on('data', c => chunks.push(c));
36
+ res.on('end', () => { try { fs.writeFileSync(dest, Buffer.concat(chunks)); try { fs.chmodSync(dest, 0o755); } catch {} cb(null); } catch (e) { cb(e); } });
37
+ }).on('error', cb);
38
+ };
39
+ follow(`https://github.com${urlPath}`);
40
+ }
41
+
42
+ download(getVersion(), binPath, (err) => {
43
+ if (err) { process.stderr.write(`bootstrap: ${err.message}\n`); process.exit(1); }
44
+ process.exit(0);
45
+ });
@@ -2,7 +2,7 @@
2
2
 
3
3
  const fs = require('fs');
4
4
  const path = require('path');
5
- const { execSync } = require('child_process');
5
+ const https = require('https');
6
6
 
7
7
  function isInsideNodeModules() {
8
8
  return __dirname.includes(path.sep + 'node_modules' + path.sep);
@@ -13,23 +13,18 @@ function getProjectRoot() {
13
13
  let current = __dirname;
14
14
  while (current !== path.dirname(current)) {
15
15
  current = path.dirname(current);
16
- if (path.basename(current) === 'node_modules') {
17
- return path.dirname(current);
18
- }
16
+ if (path.basename(current) === 'node_modules') return path.dirname(current);
19
17
  }
20
18
  return null;
21
19
  }
22
20
 
23
21
  function safeCopyFile(src, dst) {
24
22
  try {
25
- const content = fs.readFileSync(src, 'utf-8');
26
23
  const dstDir = path.dirname(dst);
27
24
  if (!fs.existsSync(dstDir)) fs.mkdirSync(dstDir, { recursive: true });
28
- fs.writeFileSync(dst, content, 'utf-8');
25
+ fs.writeFileSync(dst, fs.readFileSync(src));
29
26
  return true;
30
- } catch (e) {
31
- return false;
32
- }
27
+ } catch { return false; }
33
28
  }
34
29
 
35
30
  function safeCopyDirectory(src, dst) {
@@ -43,9 +38,7 @@ function safeCopyDirectory(src, dst) {
43
38
  else if (entry.isFile()) safeCopyFile(srcPath, dstPath);
44
39
  });
45
40
  return true;
46
- } catch (e) {
47
- return false;
48
- }
41
+ } catch { return false; }
49
42
  }
50
43
 
51
44
  function updateGitignore(projectRoot) {
@@ -53,13 +46,48 @@ function updateGitignore(projectRoot) {
53
46
  const gitignorePath = path.join(projectRoot, '.gitignore');
54
47
  const entry = '.gm-stop-verified';
55
48
  let content = fs.existsSync(gitignorePath) ? fs.readFileSync(gitignorePath, 'utf-8') : '';
56
- if (content.includes(entry)) return true;
49
+ if (content.includes(entry)) return;
57
50
  if (content && !content.endsWith('\n')) content += '\n';
58
51
  fs.writeFileSync(gitignorePath, content + entry + '\n', 'utf-8');
59
- return true;
60
- } catch (e) {
61
- return false;
62
- }
52
+ } catch {}
53
+ }
54
+
55
+ function getRequiredVersion(sourceDir) {
56
+ try {
57
+ const gm = JSON.parse(fs.readFileSync(path.join(sourceDir, 'gm.json'), 'utf-8'));
58
+ return gm.plugkitVersion || null;
59
+ } catch { return null; }
60
+ }
61
+
62
+ function getInstalledVersion(binPath) {
63
+ try {
64
+ const { spawnSync } = require('child_process');
65
+ const r = spawnSync(binPath, ['--version'], { encoding: 'utf8', timeout: 5000 });
66
+ const m = (r.stdout || '').trim().match(/(\d+\.\d+\.\d+)/);
67
+ return m ? m[1] : null;
68
+ } catch { return null; }
69
+ }
70
+
71
+ function downloadBin(version, dest, callback) {
72
+ const IS_WIN = process.platform === 'win32';
73
+ const asset = IS_WIN ? 'plugkit.exe' : 'plugkit';
74
+ const urlPath = version
75
+ ? `/AnEntrypoint/rs-plugkit/releases/download/v${version}/${asset}`
76
+ : `/AnEntrypoint/rs-plugkit/releases/latest/download/${asset}`;
77
+ const destDir = path.dirname(dest);
78
+ if (!fs.existsSync(destDir)) fs.mkdirSync(destDir, { recursive: true });
79
+ const follow = (url) => {
80
+ const mod = url.startsWith('https') ? https : require('http');
81
+ const opts = { ...require('url').parse(url), headers: { 'User-Agent': 'gm-postinstall' } };
82
+ mod.get(opts, res => {
83
+ if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) return follow(res.headers.location);
84
+ if (res.statusCode !== 200) return callback(new Error(`HTTP ${res.statusCode}`));
85
+ const chunks = [];
86
+ res.on('data', c => chunks.push(c));
87
+ res.on('end', () => { try { fs.writeFileSync(dest, Buffer.concat(chunks)); try { fs.chmodSync(dest, 0o755); } catch {} callback(null); } catch (e) { callback(e); } });
88
+ }).on('error', callback);
89
+ };
90
+ follow(`https://github.com${urlPath}`);
63
91
  }
64
92
 
65
93
  function install() {
@@ -67,9 +95,8 @@ function install() {
67
95
  const projectRoot = getProjectRoot();
68
96
  if (!projectRoot) return;
69
97
  const kiloDir = path.join(projectRoot, '.config', 'kilo');
70
- const sourceDir = __dirname.replace(/[/\\]scripts$/, '');
98
+ const sourceDir = path.dirname(__dirname);
71
99
 
72
- // Copy files
73
100
  safeCopyDirectory(path.join(sourceDir, 'agents'), path.join(kiloDir, 'agents'));
74
101
  safeCopyDirectory(path.join(sourceDir, 'hooks'), path.join(kiloDir, 'hooks'));
75
102
  safeCopyDirectory(path.join(sourceDir, 'skills'), path.join(kiloDir, 'skills'));
@@ -83,36 +110,22 @@ function install() {
83
110
  safeCopyFile(path.join(sourceDir, '.gitignore'), path.join(kiloDir, '.gitignore'));
84
111
  safeCopyFile(path.join(sourceDir, '.editorconfig'), path.join(kiloDir, '.editorconfig'));
85
112
 
86
- // Also write plugin/ directory - Kilo loads from ~/.config/kilo/plugin/ as a local file plugin
87
113
  const pluginDir = path.join(kiloDir, 'plugin');
88
114
  if (!fs.existsSync(pluginDir)) fs.mkdirSync(pluginDir, { recursive: true });
89
115
  const gmMjsSrc = path.join(sourceDir, 'gm.mjs');
90
- if (fs.existsSync(gmMjsSrc)) {
91
- safeCopyFile(gmMjsSrc, path.join(pluginDir, 'gm.mjs'));
92
- }
116
+ if (fs.existsSync(gmMjsSrc)) safeCopyFile(gmMjsSrc, path.join(pluginDir, 'gm.mjs'));
93
117
  fs.writeFileSync(path.join(pluginDir, 'index.js'), "export { default } from './gm.mjs';\n", 'utf-8');
94
118
 
95
- // Update .gitignore
96
119
  updateGitignore(projectRoot);
97
120
 
98
- // Warm bun x cache for packages used by hooks
99
- warmBunCache();
100
-
101
- // Silent success
102
- }
103
-
104
- function warmBunCache() {
105
- const packages = [];
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
- }
121
+ const IS_WIN = process.platform === 'win32';
122
+ const binDest = path.join(kiloDir, 'hooks', 'bin', IS_WIN ? 'plugkit.exe' : 'plugkit');
123
+ const requiredVersion = getRequiredVersion(sourceDir);
124
+ const installedVersion = fs.existsSync(binDest) ? getInstalledVersion(binDest) : null;
125
+ if (!installedVersion || (requiredVersion && installedVersion !== requiredVersion)) {
126
+ downloadBin(requiredVersion, binDest, (err) => {
127
+ if (err) process.stderr.write('plugkit download failed: ' + err.message + '\n');
128
+ });
116
129
  }
117
130
  }
118
131
 
@@ -2,7 +2,9 @@
2
2
 
3
3
  const fs = require('fs');
4
4
  const path = require('path');
5
- const { execSync } = require('child_process');
5
+ const https = require('https');
6
+
7
+ const PLUGKIT_REPO = 'AnEntrypoint/rs-plugkit';
6
8
 
7
9
  function isInsideNodeModules() {
8
10
  return __dirname.includes(path.sep + 'node_modules' + path.sep);
@@ -13,23 +15,18 @@ function getProjectRoot() {
13
15
  let current = __dirname;
14
16
  while (current !== path.dirname(current)) {
15
17
  current = path.dirname(current);
16
- if (path.basename(current) === 'node_modules') {
17
- return path.dirname(current);
18
- }
18
+ if (path.basename(current) === 'node_modules') return path.dirname(current);
19
19
  }
20
20
  return null;
21
21
  }
22
22
 
23
23
  function safeCopyFile(src, dst) {
24
24
  try {
25
- const content = fs.readFileSync(src, 'utf-8');
26
25
  const dstDir = path.dirname(dst);
27
26
  if (!fs.existsSync(dstDir)) fs.mkdirSync(dstDir, { recursive: true });
28
- fs.writeFileSync(dst, content, 'utf-8');
27
+ fs.writeFileSync(dst, fs.readFileSync(src));
29
28
  return true;
30
- } catch (e) {
31
- return false;
32
- }
29
+ } catch { return false; }
33
30
  }
34
31
 
35
32
  function safeCopyDirectory(src, dst) {
@@ -43,9 +40,7 @@ function safeCopyDirectory(src, dst) {
43
40
  else if (entry.isFile()) safeCopyFile(srcPath, dstPath);
44
41
  });
45
42
  return true;
46
- } catch (e) {
47
- return false;
48
- }
43
+ } catch { return false; }
49
44
  }
50
45
 
51
46
  function updateGitignore(projectRoot) {
@@ -53,13 +48,48 @@ function updateGitignore(projectRoot) {
53
48
  const gitignorePath = path.join(projectRoot, '.gitignore');
54
49
  const entry = '.gm-stop-verified';
55
50
  let content = fs.existsSync(gitignorePath) ? fs.readFileSync(gitignorePath, 'utf-8') : '';
56
- if (content.includes(entry)) return true;
51
+ if (content.includes(entry)) return;
57
52
  if (content && !content.endsWith('\n')) content += '\n';
58
53
  fs.writeFileSync(gitignorePath, content + entry + '\n', 'utf-8');
59
- return true;
60
- } catch (e) {
61
- return false;
62
- }
54
+ } catch {}
55
+ }
56
+
57
+ function getRequiredVersion(sourceDir) {
58
+ try {
59
+ const gm = JSON.parse(fs.readFileSync(path.join(sourceDir, 'gm.json'), 'utf-8'));
60
+ return gm.plugkitVersion || null;
61
+ } catch { return null; }
62
+ }
63
+
64
+ function getInstalledVersion(binPath) {
65
+ try {
66
+ const { spawnSync } = require('child_process');
67
+ const r = spawnSync(binPath, ['--version'], { encoding: 'utf8', timeout: 5000 });
68
+ const m = (r.stdout || '').trim().match(/(\d+\.\d+\.\d+)/);
69
+ return m ? m[1] : null;
70
+ } catch { return null; }
71
+ }
72
+
73
+ function downloadBin(version, dest, callback) {
74
+ const IS_WIN = process.platform === 'win32';
75
+ const asset = IS_WIN ? 'plugkit.exe' : 'plugkit';
76
+ const urlPath = version
77
+ ? `/AnEntrypoint/rs-plugkit/releases/download/v${version}/${asset}`
78
+ : `/AnEntrypoint/rs-plugkit/releases/latest/download/${asset}`;
79
+ const destDir = path.dirname(dest);
80
+ if (!fs.existsSync(destDir)) fs.mkdirSync(destDir, { recursive: true });
81
+ const follow = (url) => {
82
+ const mod = url.startsWith('https') ? https : require('http');
83
+ const opts = { ...require('url').parse(url), headers: { 'User-Agent': 'gm-postinstall' } };
84
+ mod.get(opts, res => {
85
+ if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) return follow(res.headers.location);
86
+ if (res.statusCode !== 200) return callback(new Error(`HTTP ${res.statusCode}`));
87
+ const chunks = [];
88
+ res.on('data', c => chunks.push(c));
89
+ res.on('end', () => { try { fs.writeFileSync(dest, Buffer.concat(chunks)); try { fs.chmodSync(dest, 0o755); } catch {} callback(null); } catch (e) { callback(e); } });
90
+ }).on('error', callback);
91
+ };
92
+ follow(`https://github.com${urlPath}`);
63
93
  }
64
94
 
65
95
  function install() {
@@ -67,9 +97,8 @@ function install() {
67
97
  const projectRoot = getProjectRoot();
68
98
  if (!projectRoot) return;
69
99
  const ocDir = path.join(projectRoot, '.config', 'opencode');
70
- const sourceDir = __dirname.replace(/[/\\]scripts$/, '');
100
+ const sourceDir = path.dirname(__dirname);
71
101
 
72
- // Copy files
73
102
  safeCopyDirectory(path.join(sourceDir, 'agents'), path.join(ocDir, 'agents'));
74
103
  safeCopyDirectory(path.join(sourceDir, 'hooks'), path.join(ocDir, 'hooks'));
75
104
  safeCopyDirectory(path.join(sourceDir, 'skills'), path.join(ocDir, 'skills'));
@@ -83,35 +112,21 @@ function install() {
83
112
  safeCopyFile(path.join(sourceDir, '.gitignore'), path.join(ocDir, '.gitignore'));
84
113
  safeCopyFile(path.join(sourceDir, '.editorconfig'), path.join(ocDir, '.editorconfig'));
85
114
 
86
- // Also write to plugins/gm-oc.mjs - the actual file OpenCode loads
87
115
  const pluginsDir = path.join(ocDir, 'plugins');
88
116
  if (!fs.existsSync(pluginsDir)) fs.mkdirSync(pluginsDir, { recursive: true });
89
117
  const gmMjsSrc = path.join(sourceDir, 'gm.mjs');
90
- if (fs.existsSync(gmMjsSrc)) {
91
- safeCopyFile(gmMjsSrc, path.join(pluginsDir, 'gm-oc.mjs'));
92
- }
118
+ if (fs.existsSync(gmMjsSrc)) safeCopyFile(gmMjsSrc, path.join(pluginsDir, 'gm-oc.mjs'));
93
119
 
94
- // Update .gitignore
95
120
  updateGitignore(projectRoot);
96
121
 
97
- // Warm bun x cache for packages used by hooks
98
- warmBunCache();
99
-
100
- // Silent success
101
- }
102
-
103
- function warmBunCache() {
104
- const packages = [];
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
- }
122
+ const IS_WIN = process.platform === 'win32';
123
+ const binDest = path.join(ocDir, 'hooks', 'bin', IS_WIN ? 'plugkit.exe' : 'plugkit');
124
+ const requiredVersion = getRequiredVersion(sourceDir);
125
+ const installedVersion = fs.existsSync(binDest) ? getInstalledVersion(binDest) : null;
126
+ if (!installedVersion || (requiredVersion && installedVersion !== requiredVersion)) {
127
+ downloadBin(requiredVersion, binDest, (err) => {
128
+ if (err) process.stderr.write('plugkit download failed: ' + err.message + '\n');
129
+ });
115
130
  }
116
131
  }
117
132