gm-skill 2.0.1907 → 2.0.1909
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.
|
@@ -46,6 +46,8 @@ Data first -- correct structures/invariants make the code write itself; convolut
|
|
|
46
46
|
|
|
47
47
|
**Process of elimination is the debugging paradigm on every surface; manual labour against real services is how you witness.** Thinking-in-code at its sharpest: each candidate cause is a hypothesis, tested by running it, never reasoned around. No guess-and-restart, no a/b-test, no shotgun variants: enumerate candidates as mutables, eliminate each by REAL-input witness -- `exec_js` on the real service, `codesearch`/`Read` on real source, `browser`'s `page.evaluate` on a live `window.*` global, monkeypatching each candidate function/handler in-page to isolate which one actually fires. Each elimination reveals the next mutable; iterate to single-cause-survives. One live-runtime read outweighs a hundred blind restarts.
|
|
48
48
|
|
|
49
|
+
**Before the first hypothesis, name the loop that will falsify it.** A hard bug gets a single named command -- an `exec_js`/`browser` dispatch, a CLI invocation, a curl against a live dev surface -- that is red-capable (drives the exact reported symptom, not a nearby one), deterministic (same verdict every run; for flaky bugs, driven to a high-enough reproduction rate to debug against), and fast. Name and run that command once, unmodified, before reading code for a theory -- reading code first to build a theory is the failure this clause exists to catch. Every mutable elimination pass afterward reuses the same loop; a loop that only sometimes reproduces gets tightened (narrower scope, pinned time/seed, isolated fs/network) before it's trusted as a witness surface.
|
|
50
|
+
|
|
49
51
|
Profile the real surface, never intuit. `exec_js`: `duration_ms` free, own timing + `process.memoryUsage()` on stdout, thrown-`stack` on stderr -- read both channels. Browser: `capture\n<script>` prefix auto-returns `{result, debug:{console, pageErrors, network, performance}}`, zero boilerplate. Slow-node-not-obvious: `exec_js opts.profile:true` / browser `profile\n<script>` prefix both return `{result, profile:{timeframe:{start_us,end_us,total_us,sample_count}, culprits:[{location,function,self_us,self_pct,hits}]}}` -- worst-N `file:line` self-time, identical shape both surfaces. Both also return `mem` (rss/heap/delta) and `wall_vs_cpu:{wall_us, offcpu_us}` -- sampler sees only on-CPU JS, large `offcpu_us` = IO/async-wait/GPU time invisible to it; tune via `opts.sampleIntervalUs`/`opts.profileTopN` (cli) or `interval=`/`topN=` (browser). Cheap non-profile path: `opts.mem:true` -> `{result, mem, wall_ms}` + structured `error:{name,message,stack}` on throw -- read `error.name` directly; default path (no `opts.mem`) byte-unchanged. CPU sampler is GPU-blind -- wall >> CPU self-time on render/canvas/WebGL -> browser `trace\n<script>` prefix opens CDP Tracing, returns `trace:{wall_us, gpu_us, viz_us, cc_us, by_category}`. Profile to LOCATE, then eliminate by live measurement. Verification is the same labour: run the real thing, witness the real output (live page, real service) -- never a unit/mock harness standing in for real-services witness. Apparent tooling failure is the same mechanical self-recovery-by-elimination, never a question for the user.
|
|
50
52
|
|
|
51
53
|
## No test files, ever (hard rule)
|
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.1909",
|
|
4
4
|
"description": "Bootstrap and daemon-spawn tool for gm plugkit binary. Downloads the correct platform binary, verifies SHA256, and starts the spool watcher daemon. Includes plugkit-wasm-wrapper for WASM-based spool watching.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
@@ -758,20 +758,78 @@ function findCachedBunRunnerBin() {
|
|
|
758
758
|
return null;
|
|
759
759
|
}
|
|
760
760
|
|
|
761
|
+
// playwriter's CLI `--timeout` option is parsed as a raw string (its own arg parser does not
|
|
762
|
+
// coerce it despite the zod schema declaring z.number()), and that string is forwarded verbatim
|
|
763
|
+
// into `vm.runInContext(..., { timeout })`, which throws
|
|
764
|
+
// `TypeError: The "options.timeout" property must be of type number` -- every managed browser
|
|
765
|
+
// session then fails, and each spawn's relay/Chromium never gets torn down (an "orphan-chrome
|
|
766
|
+
// pileup"). Idempotently patch it in whatever playwriter dist copy we're about to invoke.
|
|
767
|
+
const _patchedPlaywriterDistDirs = new Set();
|
|
768
|
+
function patchPlaywriterTimeoutBug(binJs) {
|
|
769
|
+
try {
|
|
770
|
+
const distDir = path.dirname(binJs);
|
|
771
|
+
if (_patchedPlaywriterDistDirs.has(distDir)) return;
|
|
772
|
+
_patchedPlaywriterDistDirs.add(distDir);
|
|
773
|
+
const executorPath = path.join(distDir, 'executor.js');
|
|
774
|
+
if (fs.existsSync(executorPath)) {
|
|
775
|
+
const src = fs.readFileSync(executorPath, 'utf-8');
|
|
776
|
+
if (/async execute\(code, timeout = 10000\) \{(?!\s*timeout = Number)/.test(src)) {
|
|
777
|
+
const patched = src.replace(
|
|
778
|
+
/(async execute\(code, timeout = 10000\) \{)/,
|
|
779
|
+
'$1\n timeout = Number(timeout) || 10000;'
|
|
780
|
+
);
|
|
781
|
+
fs.writeFileSync(executorPath, patched);
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
const cliPath = path.join(distDir, 'cli.js');
|
|
785
|
+
if (fs.existsSync(cliPath)) {
|
|
786
|
+
const src = fs.readFileSync(cliPath, 'utf-8');
|
|
787
|
+
if (src.includes('timeout: options.timeout || 10000') && !src.includes('timeout: Number(options.timeout)')) {
|
|
788
|
+
const patched = src.replace(
|
|
789
|
+
'timeout: options.timeout || 10000',
|
|
790
|
+
'timeout: Number(options.timeout) || 10000'
|
|
791
|
+
);
|
|
792
|
+
fs.writeFileSync(cliPath, patched);
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
} catch (_) {}
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
function patchAllCachedPlaywriterCopies() {
|
|
799
|
+
try {
|
|
800
|
+
const cacheDir = path.join(os.homedir(), '.bun', 'install', 'cache');
|
|
801
|
+
const entries = fs.readdirSync(cacheDir).filter(n => n.startsWith(`${BROWSER_RUNNER_BIN}@`));
|
|
802
|
+
for (const name of entries) {
|
|
803
|
+
const binJs = path.join(cacheDir, name, 'bin.js');
|
|
804
|
+
if (fs.existsSync(binJs)) patchPlaywriterTimeoutBug(binJs);
|
|
805
|
+
}
|
|
806
|
+
} catch (_) {}
|
|
807
|
+
}
|
|
808
|
+
|
|
761
809
|
function findBrowserRunner() {
|
|
810
|
+
// bun's global-install node_modules root has real dependency resolution (npm-style
|
|
811
|
+
// node_modules tree), so a bin.js found there is safe to invoke directly.
|
|
762
812
|
const bunGlobalRoots = [
|
|
763
813
|
path.join(os.homedir(), '.bun', 'install', 'global', 'node_modules', BROWSER_RUNNER_BIN, 'bin.js'),
|
|
764
814
|
];
|
|
765
815
|
for (const binJs of bunGlobalRoots) {
|
|
766
|
-
if (fs.existsSync(binJs)) return { cmd: process.execPath, baseArgs: [binJs], shell: false };
|
|
816
|
+
if (fs.existsSync(binJs)) { patchPlaywriterTimeoutBug(binJs); return { cmd: process.execPath, baseArgs: [binJs], shell: false }; }
|
|
767
817
|
}
|
|
768
|
-
|
|
769
|
-
|
|
818
|
+
// `~/.bun/install/cache/<pkg>@version` is bun's *content-addressed package cache*, not an
|
|
819
|
+
// installed tree -- it has no node_modules of its own, so invoking its bin.js directly with
|
|
820
|
+
// plain node/bun fails to resolve the package's own dependencies (e.g. "Cannot find package
|
|
821
|
+
// 'hono'"). Only `bun x` (or an npm-global install) sets up real dependency resolution, so
|
|
822
|
+
// prefer that over the cached bin.js. `bun x` still ultimately runs the same content-addressed
|
|
823
|
+
// cache copy (symlinked node_modules alongside it), so patch every cached copy proactively --
|
|
824
|
+
// there is no separate resolved-tree location to target for the `bun x` path specifically.
|
|
825
|
+
patchAllCachedPlaywriterCopies();
|
|
770
826
|
const whichCmd = process.platform === 'win32' ? 'where' : 'which';
|
|
771
827
|
const bunR = spawnSync(whichCmd, ['bun'], { encoding: 'utf-8', shell: true });
|
|
772
828
|
if (bunR.status === 0 && bunR.stdout.trim()) {
|
|
773
829
|
return { cmd: 'bun', baseArgs: ['x', `${BROWSER_RUNNER_BIN}@latest`], shell: true };
|
|
774
830
|
}
|
|
831
|
+
const cachedBin = findCachedBunRunnerBin();
|
|
832
|
+
if (cachedBin) return { cmd: process.execPath, baseArgs: [cachedBin], shell: false };
|
|
775
833
|
const r = spawnSync(whichCmd, [BROWSER_RUNNER_BIN], { encoding: 'utf-8', shell: true });
|
|
776
834
|
if (r.status === 0 && r.stdout.trim()) {
|
|
777
835
|
const candidates = r.stdout.split(/\r?\n/).map(l => l.trim()).filter(Boolean);
|
package/gm.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gm-skill",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.1909",
|
|
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",
|