gm-kilo 2.0.1061 → 2.0.1062

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.
Files changed (2) hide show
  1. package/gm-kilo.mjs +61 -15
  2. package/package.json +1 -1
package/gm-kilo.mjs CHANGED
@@ -2,7 +2,6 @@ import { readFileSync, existsSync, writeFileSync, unlinkSync } from 'fs';
2
2
  import { join, dirname, extname, basename } from 'path';
3
3
  import { fileURLToPath } from 'url';
4
4
  import { spawnSync } from 'child_process';
5
- import { tmpdir } from 'os';
6
5
 
7
6
  const __dirname = dirname(fileURLToPath(import.meta.url));
8
7
  const LANG_ALIASES = { js:'nodejs',javascript:'nodejs',ts:'typescript',node:'nodejs',py:'python',sh:'bash',shell:'bash',zsh:'bash' };
@@ -29,18 +28,53 @@ function stripFooter(s) { return s ? s.replace(/\n\[Running tools\][\s\S]*$/, ''
29
28
  function runExecSync(rawLang, code, cwd) {
30
29
  const lang = LANG_ALIASES[rawLang] || rawLang || 'nodejs';
31
30
  const projectDir = cwd || process.cwd();
32
- if (lang === 'codesearch' || lang === 'search') return runPlugkit(['search', '--path', projectDir, code.trim()]);
33
- if (['runner','status','sleep','close'].includes(lang)) return runPlugkit([lang, code.trim()]);
34
- if (['browser','tail','watch','wait','type','kill-port','health','recall','memorize','forget','feedback','discipline','pause'].includes(lang)) {
35
- return runPlugkit(['exec', '--lang', lang, '--code', code.trim(), '--cwd', projectDir]);
36
- }
37
- if (lang === 'cmd') {
38
- const opts = { encoding: 'utf-8', timeout: 30000, windowsHide: true, cwd: projectDir };
39
- const r = spawnSync('cmd', ['/c', code], opts);
40
- const o = (r.stdout || '').trimEnd(), e = stripFooter(r.stderr || '').trimEnd();
41
- return o && e ? o + '\n[stderr]\n' + e : o || e || '(no output)';
31
+ const spoolBase = join(projectDir, '.gm', 'exec-spool');
32
+ const taskId = Date.now() + '-' + Math.random().toString(16).slice(2, 8);
33
+
34
+ const isVerb = ['codesearch','recall','memorize','wait','sleep','status','close','browser','runner','type','kill-port','forget','feedback','discipline','pause','health'].includes(lang);
35
+ const langDir = lang.match(/^(nodejs|python|bash|typescript|go|rust|c|cpp|java|deno)$/) ? lang : 'nodejs';
36
+ const ext = {nodejs:'js',python:'py',bash:'sh',typescript:'ts',go:'go',rust:'rs',c:'c',cpp:'cpp',java:'java',deno:'ts'}[langDir] || 'js';
37
+
38
+ const inDir = join(spoolBase, 'in', isVerb ? lang : langDir);
39
+ const outDir = join(spoolBase, 'out');
40
+ const inFile = join(inDir, taskId + (isVerb ? '.txt' : '.' + ext));
41
+ const jsonFile = join(outDir, taskId + '.json');
42
+
43
+ try { fs.mkdirSync(inDir, { recursive: true }); fs.mkdirSync(outDir, { recursive: true }); } catch(e) {}
44
+ writeFileSync(inFile, code, 'utf-8');
45
+
46
+ const start = Date.now();
47
+ while (Date.now() - start < 28000) {
48
+ if (existsSync(jsonFile)) {
49
+ try {
50
+ const meta = JSON.parse(readFileSync(jsonFile, 'utf-8'));
51
+ const outFile = jsonFile.replace(/\.json$/, '.out');
52
+ const errFile = jsonFile.replace(/\.json$/, '.err');
53
+ const stdout = existsSync(outFile) ? readFileSync(outFile, 'utf-8') : '';
54
+ const stderr = existsSync(errFile) ? readFileSync(errFile, 'utf-8') : '';
55
+ const o = stdout.trimEnd(), e = stripFooter(stderr).trimEnd();
56
+ return o && e ? o + '\n[stderr]\n' + e : o || e || '(no output)';
57
+ } catch(e) {}
58
+ }
59
+ try { require('child_process').execSync('sleep 0.05', { stdio: 'ignore' }); } catch(e) { const s = Date.now(); while(Date.now()-s<50){} }
42
60
  }
43
- return runPlugkit(['exec', '--lang', lang, '--code', code.trim(), '--cwd', projectDir]);
61
+ return '[spool dispatch timeout after 28s]';
62
+ }
63
+
64
+ function ensureSpoolWatcher(dir) {
65
+ try {
66
+ const spoolBase = join(dir, '.gm', 'exec-spool');
67
+ const pidFile = join(spoolBase, '.watcher.pid');
68
+ try { fs.mkdirSync(spoolBase, { recursive: true }); } catch(e) {}
69
+ const alreadyRunning = existsSync(pidFile) && (() => { try { const p = parseInt(readFileSync(pidFile,'utf-8')); process.kill(p,0); return true; } catch(e) { return false; } })();
70
+ if (!alreadyRunning) {
71
+ const r = spawnSync('node', [join(__dirname, '..', 'bin', 'plugkit.js'), 'spool'], {
72
+ detached: true, stdio: 'ignore', windowsHide: true,
73
+ env: { ...process.env, GM_SPOOL_DIR: spoolBase }
74
+ });
75
+ if (r.pid) { try { writeFileSync(pidFile, String(r.pid), 'utf-8'); } catch(e) {} }
76
+ }
77
+ } catch(e) {}
44
78
  }
45
79
 
46
80
  const BANNED_BASH = ['grep','rg','find','glob','awk','sed','cat','head','tail'];
@@ -61,7 +95,19 @@ export async function GmPlugin({ directory }) {
61
95
  if (!sessionStarted) {
62
96
  sessionStarted = true;
63
97
  try { runPlugkit(['hook', 'session-start']); } catch(e) {}
64
- try { runPlugkit(['bootstrap', directory]); } catch(e) {}
98
+ try {
99
+ const spoolBase = join(directory, '.gm', 'exec-spool');
100
+ const pidFile = join(spoolBase, '.watcher.pid');
101
+ try { fs.mkdirSync(spoolBase, { recursive: true }); } catch(e) {}
102
+ const alreadyRunning = existsSync(pidFile) && (() => { try { const p = parseInt(readFileSync(pidFile,'utf-8')); process.kill(p,0); return true; } catch(e) { return false; } })();
103
+ if (!alreadyRunning) {
104
+ const r = spawnSync('node', [join(__dirname, '..', 'bin', 'plugkit.js'), 'spool'], {
105
+ detached: true, stdio: 'ignore', windowsHide: true,
106
+ env: { ...process.env, GM_SPOOL_DIR: spoolBase }
107
+ });
108
+ if (r.pid) { try { writeFileSync(pidFile, String(r.pid), 'utf-8'); } catch(e) {} }
109
+ }
110
+ } catch(e) {}
65
111
  }
66
112
  },
67
113
 
@@ -81,7 +127,7 @@ export async function GmPlugin({ directory }) {
81
127
  if (!sessionStarted) {
82
128
  sessionStarted = true;
83
129
  try { runPlugkit(['hook', 'session-start']); } catch(e) {}
84
- try { runPlugkit(['bootstrap', directory]); } catch(e) {}
130
+ try { ensureSpoolWatcher(directory); } catch(e) {}
85
131
  }
86
132
  try { const rules = readFileSync(agentMd,'utf-8'); if (rules) output.system.unshift(rules); } catch(e) {}
87
133
  try {
@@ -132,7 +178,7 @@ export async function GmPlugin({ directory }) {
132
178
  if (!sessionStarted) {
133
179
  sessionStarted = true;
134
180
  try { runPlugkit(['hook', 'session-start']); } catch(e) {}
135
- try { runPlugkit(['bootstrap', directory]); } catch(e) {}
181
+ try { ensureSpoolWatcher(directory); } catch(e) {}
136
182
  }
137
183
  const skillName = (args.skill || args.name || '').toString();
138
184
  if (FORBIDDEN_TOOLS.has(input.tool)) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gm-kilo",
3
- "version": "2.0.1061",
3
+ "version": "2.0.1062",
4
4
  "description": "State machine agent with hooks, skills, and automated git enforcement",
5
5
  "author": "AnEntrypoint",
6
6
  "license": "MIT",