gm-skill 2.0.1628 → 2.0.1630
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/AGENTS.md +4 -0
- package/gm-plugkit/cli.js +36 -2
- package/gm-plugkit/package.json +1 -1
- package/gm.json +1 -1
- package/package.json +1 -1
- package/skills/gm/SKILL.md +3 -3
package/AGENTS.md
CHANGED
|
@@ -130,6 +130,8 @@ Every skill's `allowed-tools:` is reduced to `Skill, Read, Write` (plus the SKIL
|
|
|
130
130
|
|
|
131
131
|
**The agent IS the LLM rs-learn calls**: no separate judge model; all decisions are inline via spool. Internals in rs-learn (`recall: rs-learn self-report core internals`).
|
|
132
132
|
|
|
133
|
+
**Idempotency contract (f∘f≡f)**: the spool dispatch layer is at-least-once by design (the in-memory processed-Map guards only concurrent double-pickup, not cross-time replay or restart), so correctness rests on every state-mutating verb being individually convergent: `memorize`/`memorize-fire` content-hash key + dedup, `git_finalize`/`git_commit` nothing-to-commit/already-pushed, `insert_edge` kv-overwrite-by-id + dedup-guarded index, `invalidate_edge` early-return, `ensure_managed_gitignore` strip-rebuild-changed-gate, codeinsight digest-gate, publish.yml already-published-skip + porcelain-gated version-commit-back. Read-only verbs (recall/codesearch/git_status/instruction/health/filter) recompute every dispatch, never cache. `exec_js`/`browser` re-run on replay (at-most-once-by-nature); a persistent dedup ledger was rejected as net-additive. Detail in rs-learn (`recall: idempotency contract per-verb convergence`).
|
|
134
|
+
|
|
133
135
|
**host_exec_js is synchronous**: pass a real per-call `timeoutMs` (zero/missing is a hard error). Detail in rs-learn (`recall: host_exec_js synchronous`).
|
|
134
136
|
|
|
135
137
|
**Sync-before-emit (codeinsight + search)**: output must come from a freshly-synced index this invocation (cache serves only on digest match). Mechanics in rs-learn (`recall: sync-before-emit codeinsight search`).
|
|
@@ -160,6 +162,8 @@ Orchestration state is tracked via `.gm/` marker files, not hook events; the CLI
|
|
|
160
162
|
|
|
161
163
|
**Dead-watcher recovery uses `bun x gm-plugkit@latest spool`, never direct-node boot** (mechanism in rs-learn: `recall: dead-watcher recovery bun x not direct-node`).
|
|
162
164
|
|
|
165
|
+
**Starting the spool is one atomic blocking call -- `bun x gm-plugkit@latest spool` daemonizes the watcher AND blocks until `.status.json` heartbeats fresh, returning exit 0 only when serving (loud non-zero on timeout).** No `& + sleep + re-cat` boot dance; the agent writes to `instruction/` the moment the call returns. The wait lives in `gm-plugkit/cli.js` (`waitForWatcherHeartbeat`, `Atomics.wait` sync-sleep), cli-side because `startSpoolDaemon` is sync and shared by non-blocking callers. rs-plugkit carries no server-boot logic -- the daemonize lifecycle is entirely gm-plugkit JS, so this change needs no Rust/cascade rebuild.
|
|
166
|
+
|
|
163
167
|
**Apparent tooling failure is mechanical self-recovery, NEVER a question for the user and never an a/b-test/blind-restart.** A missing spool response / stale watcher is the agent's own job: honor a future `busy_until` else boot the watcher and re-dispatch -- the spooler is sound by construction, so asking the user to do what a verb can do is a paper-spirit violation. Recovery mechanics (atomic `.status.json`, `FailedToOpenSocket` retry, debug-via-`window.*`-globals) in rs-learn (`recall: spooler self-recovery mechanics`).
|
|
164
168
|
|
|
165
169
|
**Process-of-elimination is the debugging paradigm EVERYWHERE, and manual real-services witness is the verification paradigm EVERYWHERE** -- both stated in `instructions/execute.md` (served EXECUTE prose). Detail in rs-learn (`recall: process-of-elimination manual-real-services-witness paradigm`).
|
package/gm-plugkit/cli.js
CHANGED
|
@@ -132,6 +132,31 @@ function spoolDir() {
|
|
|
132
132
|
return path.join(projectDir, '.gm', 'exec-spool');
|
|
133
133
|
}
|
|
134
134
|
|
|
135
|
+
function readStatus(dir) {
|
|
136
|
+
try { return JSON.parse(fs.readFileSync(path.join(dir, '.status.json'), 'utf-8')); } catch (_) { return null; }
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function statusServing(st, freshMs) {
|
|
140
|
+
if (!st || !st.pid) return false;
|
|
141
|
+
const now = Date.now();
|
|
142
|
+
if (Number.isFinite(st.busy_until) && st.busy_until > now) return true;
|
|
143
|
+
return Number.isFinite(st.ts) && (now - st.ts) < freshMs;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function sleepSync(ms) {
|
|
147
|
+
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function waitForWatcherHeartbeat(dir, deadlineMs, freshMs) {
|
|
151
|
+
const t0 = Date.now();
|
|
152
|
+
while (Date.now() - t0 < deadlineMs) {
|
|
153
|
+
const st = readStatus(dir);
|
|
154
|
+
if (statusServing(st, freshMs)) return st;
|
|
155
|
+
sleepSync(300);
|
|
156
|
+
}
|
|
157
|
+
return null;
|
|
158
|
+
}
|
|
159
|
+
|
|
135
160
|
function ensureSpoolDir() {
|
|
136
161
|
try { fs.mkdirSync(spoolDir(), { recursive: true }); } catch (_) {}
|
|
137
162
|
}
|
|
@@ -207,13 +232,22 @@ function writeCliError(phase, err) {
|
|
|
207
232
|
process.exit(1);
|
|
208
233
|
}
|
|
209
234
|
|
|
210
|
-
|
|
235
|
+
const serving = waitForWatcherHeartbeat(spoolDir(), 30000, 12000);
|
|
236
|
+
if (!serving) {
|
|
237
|
+
const errMsg = `watcher spawned (pid=${daemon.pid}) but .status.json heartbeat not fresh within 30s`;
|
|
238
|
+
writeCliError('watcher-heartbeat-timeout', new Error(errMsg));
|
|
239
|
+
console.error('Daemon start failed:', errMsg);
|
|
240
|
+
process.exit(1);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
writeCliStatus({ phase: 'ready', version: bootstrapResult.version, daemon_pid: daemon.pid, watcher_pid: serving.pid, log: daemon.logPath });
|
|
211
244
|
|
|
212
245
|
console.log(JSON.stringify({
|
|
213
246
|
ok: true,
|
|
214
247
|
binary: bootstrapResult.binaryPath,
|
|
215
248
|
daemon,
|
|
216
|
-
|
|
249
|
+
watcher_pid: serving.pid,
|
|
250
|
+
message: 'plugkit ready, spool watcher serving'
|
|
217
251
|
}));
|
|
218
252
|
process.exit(0);
|
|
219
253
|
})().catch((err) => {
|
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.1630",
|
|
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": {
|
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.1630",
|
|
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",
|
package/skills/gm/SKILL.md
CHANGED
|
@@ -34,15 +34,15 @@ Every turn: dispatch `instruction`, read it, follow the imperative, dispatch the
|
|
|
34
34
|
cat .gm/exec-spool/.status.json 2>/dev/null; echo ---; cat .gm/exec-spool/.turn-summary.json 2>/dev/null; echo ---; date +%s%3N
|
|
35
35
|
```
|
|
36
36
|
|
|
37
|
-
`.turn-summary.json` carries `phase`, `last_skill`, `prd_pending`, `last_instruction_ts`, `last_instruction_age_ms`, `long_gap_threshold_ms`, `browser_sessions_alive`, `update_available`, `deviations_30m`, `watcher_uptime_ms`. Age over threshold: your next non-orienting verb is gated, dispatch `instruction` first. `update_available` non-null: eager-upgrade with `bun x gm-plugkit@latest --kill-stale-watchers; bun x gm-plugkit@latest spool
|
|
37
|
+
`.turn-summary.json` carries `phase`, `last_skill`, `prd_pending`, `last_instruction_ts`, `last_instruction_age_ms`, `long_gap_threshold_ms`, `browser_sessions_alive`, `update_available`, `deviations_30m`, `watcher_uptime_ms`. Age over threshold: your next non-orienting verb is gated, dispatch `instruction` first. `update_available` non-null: eager-upgrade with `bun x gm-plugkit@latest --kill-stale-watchers; bun x gm-plugkit@latest spool` (the spool call blocks until serving), then read `.status.json` to confirm `version`. `deviations_30m` non-zero indicates active drift to investigate before continuing.
|
|
38
38
|
|
|
39
39
|
Compare `.status.json` `ts` to the printed epoch: gap > 15000 = dead, boot it. Exception: a future `busy_until` means a long verb (browser/chromium spawn blocks the heartbeat ~15-18s) -- wait, do not boot a second watcher.
|
|
40
40
|
|
|
41
41
|
```bash
|
|
42
|
-
bun x gm-plugkit@latest spool
|
|
42
|
+
bun x gm-plugkit@latest spool
|
|
43
43
|
```
|
|
44
44
|
|
|
45
|
-
(`npx -y gm-plugkit@latest spool
|
|
45
|
+
(`npx -y gm-plugkit@latest spool` if `bun` missing.) This call is atomic: it daemonizes the watcher and blocks until `.status.json` reports a fresh heartbeat, returning only once the spool is serving (exit 0) or failing loud on timeout. No `&`, no `sleep`, no re-`cat` -- when it returns you write to `instruction/` directly. (An already-alive watcher makes it return at once.)
|
|
46
46
|
|
|
47
47
|
**Dispatch shape: Write request + Read response in the SAME tool-call block.** The shape is `Write .gm/exec-spool/in/instruction/<N>.txt` AND `Read .gm/exec-spool/out/instruction-<N>.json` (or `out/<N>.json` for nested verbs) in one block. A first-read "file does not exist" while plugkit is mid-verb is normal -- re-Read next message. Do not proceed, narrate readiness, or begin work before reading the response and following its `instruction` field. Never poll with `sleep && ls`: plugkit is synchronous, so a missing response means dead watcher (re-check `ts`) or slow verb (check `.gm/exec-spool/.watcher.log`), not "still processing."
|
|
48
48
|
|