gm-skill 2.0.2072 → 2.0.2074
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/bin/plugkit-slim.wasm.sha256 +1 -1
- package/bin/plugkit.version +1 -1
- package/bin/plugkit.wasm.sha256 +1 -1
- package/gm-plugkit/bootstrap.js +8 -47
- package/gm-plugkit/gm-process.js +1 -1
- package/gm-plugkit/package.json +1 -1
- package/gm-plugkit/plugkit-slim.wasm.sha256 +1 -1
- package/gm-plugkit/plugkit.version +1 -1
- package/gm.json +2 -2
- package/package.json +1 -1
- package/scripts/check-prose-bundle.mjs +120 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
52edc96a3174126830758063c7907c1df38cc98824604eacc4cec7bbe0dd0d81 plugkit-slim.wasm
|
package/bin/plugkit.version
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.1.
|
|
1
|
+
0.1.956
|
package/bin/plugkit.wasm.sha256
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
e48bfd12a8d27e6c813f8a1473eab68ab8c48f637fa91d94ae020282257194f2 plugkit.wasm
|
package/gm-plugkit/bootstrap.js
CHANGED
|
@@ -28,13 +28,15 @@ const {
|
|
|
28
28
|
killPid,
|
|
29
29
|
killSpoolWatcherInCwd,
|
|
30
30
|
proactiveKillForNewInstall,
|
|
31
|
+
ensureNextStepWiring: ensureNextStepWiringShared,
|
|
31
32
|
} = shared;
|
|
32
33
|
|
|
33
|
-
// ensureNextStepWiring
|
|
34
|
-
//
|
|
35
|
-
//
|
|
36
|
-
//
|
|
37
|
-
//
|
|
34
|
+
// This file's own ensureNextStepWiring below delegates the shared prefix
|
|
35
|
+
// (seed next-step.md, prepend CLAUDE.md, append AGENTS.md) to
|
|
36
|
+
// bootstrap-shared's ensureNextStepWiringShared, then adds strictly more
|
|
37
|
+
// (a managed .npmignore block) that bootstrap-shared's leaner version does
|
|
38
|
+
// not need -- genuinely-different logic on top of a shared base, not two
|
|
39
|
+
// independent copies of the same first 40 lines.
|
|
38
40
|
|
|
39
41
|
function resolveWindowsExe(cmd) {
|
|
40
42
|
if (process.platform !== 'win32') return cmd;
|
|
@@ -177,48 +179,7 @@ function ensureInstructionsBundle(cwd) {
|
|
|
177
179
|
}
|
|
178
180
|
|
|
179
181
|
function ensureNextStepWiring(cwd) {
|
|
180
|
-
const changes =
|
|
181
|
-
const gmDir = path.join(cwd, '.gm');
|
|
182
|
-
try { fs.mkdirSync(gmDir, { recursive: true }); }
|
|
183
|
-
catch (e) { obsEvent('bootstrap', 'next-step.wiring.target-failed', { target: gmDir, error: e.message }); }
|
|
184
|
-
|
|
185
|
-
const nextStepPath = path.join(gmDir, 'next-step.md');
|
|
186
|
-
const nextStepBody = '# Next step\n\nDispatch the `instruction` verb to plugkit by writing `.gm/exec-spool/in/instruction/<N>.txt` (any unique N) with body `{}` (or `{"prompt":"<user request>"}` on the first dispatch of the turn). Read the response from `.gm/exec-spool/out/<N>.json` and follow the imperative in the `instruction` field.\n\nThis file is auto-rewritten by plugkit on every instruction dispatch.\n';
|
|
187
|
-
try {
|
|
188
|
-
if (!fs.existsSync(nextStepPath)) {
|
|
189
|
-
fs.writeFileSync(nextStepPath, nextStepBody);
|
|
190
|
-
changes.push('seeded .gm/next-step.md');
|
|
191
|
-
}
|
|
192
|
-
} catch (e) { obsEvent('bootstrap', 'next-step.wiring.target-failed', { target: nextStepPath, error: e.message }); }
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
const claudeMdPath = path.join(cwd, 'CLAUDE.md');
|
|
196
|
-
try {
|
|
197
|
-
if (!fs.existsSync(claudeMdPath)) {
|
|
198
|
-
fs.writeFileSync(claudeMdPath, '@AGENTS.md\n');
|
|
199
|
-
changes.push('created CLAUDE.md');
|
|
200
|
-
} else {
|
|
201
|
-
const cur = fs.readFileSync(claudeMdPath, 'utf8');
|
|
202
|
-
const hasLine = cur.split(/\r?\n/).some(l => l.trim() === '@AGENTS.md');
|
|
203
|
-
if (!hasLine) {
|
|
204
|
-
fs.writeFileSync(claudeMdPath, '@AGENTS.md\n' + cur);
|
|
205
|
-
changes.push('prepended @AGENTS.md to CLAUDE.md');
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
} catch (e) { obsEvent('bootstrap', 'next-step.wiring.target-failed', { target: claudeMdPath, error: e.message }); }
|
|
209
|
-
|
|
210
|
-
const agentsMdPath = path.join(cwd, 'AGENTS.md');
|
|
211
|
-
try {
|
|
212
|
-
if (fs.existsSync(agentsMdPath)) {
|
|
213
|
-
const cur = fs.readFileSync(agentsMdPath, 'utf8');
|
|
214
|
-
const hasLine = cur.split(/\r?\n/).some(l => l.trim() === '@.gm/next-step.md');
|
|
215
|
-
if (!hasLine) {
|
|
216
|
-
const sep = cur.endsWith('\n') ? '' : '\n';
|
|
217
|
-
fs.writeFileSync(agentsMdPath, cur + sep + '\n@.gm/next-step.md\n');
|
|
218
|
-
changes.push('appended @.gm/next-step.md to AGENTS.md');
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
} catch (e) { obsEvent('bootstrap', 'next-step.wiring.target-failed', { target: agentsMdPath, error: e.message }); }
|
|
182
|
+
const changes = ensureNextStepWiringShared(cwd);
|
|
222
183
|
|
|
223
184
|
// gm writes its own runtime data into .gm/ in every project it drives; if that
|
|
224
185
|
// project is an npm package, that data must never be published. Maintain a
|
package/gm-plugkit/gm-process.js
CHANGED
|
@@ -42,7 +42,7 @@ function sha256OfFileSync(filePath) {
|
|
|
42
42
|
function pidCommandLineForKillGuard(pid) {
|
|
43
43
|
try {
|
|
44
44
|
if (process.platform === 'win32') {
|
|
45
|
-
const r = spawnSync('powershell.exe', ['-NoProfile', '-NonInteractive', '-Command', `(Get-
|
|
45
|
+
const r = spawnSync('powershell.exe', ['-NoProfile', '-NonInteractive', '-Command', `(Get-CimInstance Win32_Process -Filter "ProcessId=${Number(pid)}").CommandLine`], { encoding: 'utf8', windowsHide: true, timeout: 5000 });
|
|
46
46
|
return String((r && r.stdout) || '');
|
|
47
47
|
}
|
|
48
48
|
const r = spawnSync('ps', ['-p', String(pid), '-o', 'args='], { encoding: 'utf8', timeout: 5000 });
|
package/gm-plugkit/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gm-plugkit",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.2074",
|
|
4
4
|
"description": "Bootstrap and daemon-spawn tool for gm plugkit binary. Downloads the correct platform wasm, verifies SHA256, and launches agentplug-runner (the native wasm host) as the spool watcher daemon.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
52edc96a3174126830758063c7907c1df38cc98824604eacc4cec7bbe0dd0d81 plugkit-slim.wasm
|
|
@@ -1 +1 @@
|
|
|
1
|
-
0.1.
|
|
1
|
+
0.1.956
|
package/gm.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gm",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.2074",
|
|
4
4
|
"description": "Spool-dispatch orchestration engine with unified state machine, skills, and automated git enforcement",
|
|
5
5
|
"author": "AnEntrypoint",
|
|
6
6
|
"license": "MIT",
|
|
@@ -17,5 +17,5 @@
|
|
|
17
17
|
"publishConfig": {
|
|
18
18
|
"access": "public"
|
|
19
19
|
},
|
|
20
|
-
"plugkitVersion": "0.1.
|
|
20
|
+
"plugkitVersion": "0.1.956"
|
|
21
21
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gm-skill",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.2074",
|
|
4
4
|
"description": "Canonical universal harness — AI-native software engineering via skill-driven orchestration; bootstraps plugkit for task execution and session isolation. Install in any AI coding agent host.",
|
|
5
5
|
"author": "AnEntrypoint",
|
|
6
6
|
"license": "MIT",
|
|
@@ -19,9 +19,128 @@ for (const key of KEYS) {
|
|
|
19
19
|
if (fs.readFileSync(fp, 'utf8').trim() === '') empty.push(key);
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
+
let bundleFailed = false;
|
|
22
23
|
if (missing.length || empty.length) {
|
|
24
|
+
bundleFailed = true;
|
|
23
25
|
if (missing.length) console.error(`prose bundle missing entries: ${missing.join(', ')}`);
|
|
24
26
|
if (empty.length) console.error(`prose bundle empty entries: ${empty.join(', ')}`);
|
|
27
|
+
} else {
|
|
28
|
+
console.log(`prose bundle complete: ${KEYS.length} keys present and non-empty`);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Real conformance run: extract every `browser` verb mode-prefix and
|
|
32
|
+
// exec_js `opts.*` field the served prose promises, and check that the
|
|
33
|
+
// implementing native source (agentplug-host, the sole loader per this
|
|
34
|
+
// repo's own architecture) actually references it. Static, not a live
|
|
35
|
+
// dispatch -- this is a "did anyone even write the code" check, not a
|
|
36
|
+
// behavioral one, but that is exactly what catches a "documented, zero
|
|
37
|
+
// implementing code" gap: this check is what found the browser.md
|
|
38
|
+
// screenshot/dom= gap live (agentplug-host/src/browser.rs had zero
|
|
39
|
+
// BrowserMode variant for either, confirmed by grep before this script
|
|
40
|
+
// was written). Runs against the checked-out submodules, so it only fires
|
|
41
|
+
// in CI/local contexts where they're actually populated (a plain `git
|
|
42
|
+
// clone` without --recurse-submodules leaves them empty per README.md's
|
|
43
|
+
// own documented note -- absence there is skipped, not failed, matching
|
|
44
|
+
// this repo's existing plain-clone tolerance).
|
|
45
|
+
const proseSourceDir = path.join(root, 'rs-plugkit', 'crates', 'plugkit-core', 'src', 'orchestrator', 'instructions', 'prose');
|
|
46
|
+
const browserMdPath = path.join(proseSourceDir, 'browser.md');
|
|
47
|
+
const executeMdPath = path.join(proseSourceDir, 'execute.md');
|
|
48
|
+
const browserRsPath = path.join(root, 'agentplug', 'crates', 'agentplug-host', 'src', 'browser.rs');
|
|
49
|
+
const cdpEvalJsPath = path.join(root, 'agentplug', 'crates', 'agentplug-host', 'src', 'cdp_eval.js');
|
|
50
|
+
const execJsRsPath = path.join(root, 'agentplug', 'crates', 'agentplug-host', 'src', 'exec_js.rs');
|
|
51
|
+
|
|
52
|
+
// Every INDIVIDUAL file this check reads, not just the containing
|
|
53
|
+
// directories -- a submodule can be present but shallow/partial (a
|
|
54
|
+
// degenerate state distinct from "not cloned at all"), and the directory-
|
|
55
|
+
// only check previously crashed with an unhandled ENOENT the moment any one
|
|
56
|
+
// file was individually missing (live-reproduced this session: temporarily
|
|
57
|
+
// removing browser.md alone, with every directory still present, crashed
|
|
58
|
+
// the script instead of skipping gracefully).
|
|
59
|
+
const requiredFiles = [browserMdPath, executeMdPath, browserRsPath, cdpEvalJsPath, execJsRsPath];
|
|
60
|
+
const missingFiles = requiredFiles.filter((p) => !fs.existsSync(p));
|
|
61
|
+
const submodulesPresent = missingFiles.length === 0;
|
|
62
|
+
|
|
63
|
+
let conformanceFailed = false;
|
|
64
|
+
if (!submodulesPresent) {
|
|
65
|
+
console.log(`prose-conformance: skipping -- missing file(s) (submodules not populated, or a partial/shallow checkout): ${missingFiles.map((p) => path.relative(root, p)).join(', ')}`);
|
|
66
|
+
} else {
|
|
67
|
+
const browserMd = fs.readFileSync(path.join(proseSourceDir, 'browser.md'), 'utf8');
|
|
68
|
+
const browserRs = fs.readFileSync(browserRsPath, 'utf8');
|
|
69
|
+
const cdpEvalJs = fs.readFileSync(cdpEvalJsPath, 'utf8');
|
|
70
|
+
const executeMd = fs.readFileSync(path.join(proseSourceDir, 'execute.md'), 'utf8');
|
|
71
|
+
const execJsRs = fs.readFileSync(execJsRsPath, 'utf8');
|
|
72
|
+
|
|
73
|
+
// Extract every backtick-quoted `<word>\n<expression>` / `<word>=` mode
|
|
74
|
+
// prefix from browser.md's "Body shapes" code block -- the exact syntax
|
|
75
|
+
// the served prose promises as a real body-shape prefix.
|
|
76
|
+
const bodyShapesMatch = browserMd.match(/## Body shapes[\s\S]*?```\r?\n([\s\S]*?)```/);
|
|
77
|
+
const promisedPrefixes = [];
|
|
78
|
+
if (bodyShapesMatch) {
|
|
79
|
+
for (const line of bodyShapesMatch[1].split(/\r?\n/)) {
|
|
80
|
+
const t = line.trim();
|
|
81
|
+
if (!t) continue;
|
|
82
|
+
// "session new" / "session list" / "session close <id>" -> session subcommands
|
|
83
|
+
const sessionMatch = t.match(/^session (\w+)/);
|
|
84
|
+
if (sessionMatch) { promisedPrefixes.push({ kind: 'session', name: sessionMatch[1] }); continue; }
|
|
85
|
+
// "<word>\n<expression>" or "<word> interval=...\n<expression>" -> bare mode word
|
|
86
|
+
const modeMatch = t.match(/^(\w+)(?:\s+\w+=<[^>]+>)*\\n/);
|
|
87
|
+
if (modeMatch && !['url', 'timeout', 'dom'].includes(modeMatch[1])) { promisedPrefixes.push({ kind: 'mode', name: modeMatch[1] }); continue; }
|
|
88
|
+
// "<word>=<...>" -> key= prefix (url=, timeout=, dom=)
|
|
89
|
+
const kvMatch = t.match(/^(\w+)=</);
|
|
90
|
+
if (kvMatch) { promisedPrefixes.push({ kind: 'kv', name: kvMatch[1] }); continue; }
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const conformanceFindings = [];
|
|
95
|
+
for (const { kind, name } of promisedPrefixes) {
|
|
96
|
+
// Every promised prefix must appear as a real string literal in either
|
|
97
|
+
// the Rust prefix-stripping logic or the JS mode-dispatch logic -- one
|
|
98
|
+
// hit in either is sufficient (some prefixes are parsed Rust-side,
|
|
99
|
+
// others are only checked JS-side against the `mode` string agentplug
|
|
100
|
+
// passes through). `session <word>` prefixes are matched as the real
|
|
101
|
+
// "session <word>" literal parse_session_command uses, not the bare
|
|
102
|
+
// word alone (which would false-positive-pass on any incidental
|
|
103
|
+
// substring match).
|
|
104
|
+
let inRust, inJs;
|
|
105
|
+
if (kind === 'session') {
|
|
106
|
+
inRust = browserRs.includes(`"session ${name}`);
|
|
107
|
+
inJs = false;
|
|
108
|
+
} else if (kind === 'kv') {
|
|
109
|
+
inRust = browserRs.includes(`"${name}="`);
|
|
110
|
+
inJs = cdpEvalJs.includes(`${name}=`);
|
|
111
|
+
} else {
|
|
112
|
+
inRust = browserRs.includes(`"${name}\\n"`) || browserRs.includes(`"${name}"`);
|
|
113
|
+
inJs = cdpEvalJs.includes(`'${name}'`) || cdpEvalJs.includes(`"${name}"`);
|
|
114
|
+
}
|
|
115
|
+
if (!inRust && !inJs) {
|
|
116
|
+
conformanceFindings.push(`browser.md promises ${kind} prefix "${name}" with zero implementing-code reference in browser.rs or cdp_eval.js`);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// exec_js opts.* fields: extract every `opts.<fieldName>` token referenced
|
|
121
|
+
// in execute.md's prose and check exec_js.rs actually reads it via
|
|
122
|
+
// opts.get("<fieldName>").
|
|
123
|
+
const optsFieldRe = /opts\.([a-zA-Z][a-zA-Z0-9]*)/g;
|
|
124
|
+
const promisedOptsFields = new Set();
|
|
125
|
+
let m;
|
|
126
|
+
while ((m = optsFieldRe.exec(executeMd)) !== null) promisedOptsFields.add(m[1]);
|
|
127
|
+
for (const field of promisedOptsFields) {
|
|
128
|
+
if (field === 'true' || field === 'false') continue;
|
|
129
|
+
const needle = `opts.get("${field}")`;
|
|
130
|
+
if (!execJsRs.includes(needle)) {
|
|
131
|
+
conformanceFindings.push(`execute.md promises exec_js opts.${field} with no matching opts.get("${field}") in exec_js.rs`);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
if (conformanceFindings.length) {
|
|
136
|
+
conformanceFailed = true;
|
|
137
|
+
console.error('prose-conformance FAILED -- prose promises capabilities with no confirmed implementing-code reference:');
|
|
138
|
+
for (const f of conformanceFindings) console.error(` - ${f}`);
|
|
139
|
+
} else {
|
|
140
|
+
console.log(`prose-conformance: ${promisedPrefixes.length} browser mode-prefixes + ${promisedOptsFields.size} exec_js opts fields all have a matching implementing-code reference`);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if (bundleFailed || conformanceFailed) {
|
|
25
145
|
process.exit(1);
|
|
26
146
|
}
|
|
27
|
-
console.log(`prose bundle complete: ${KEYS.length} keys present and non-empty`);
|