gm-skill 0.1.1 → 0.1.2
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/gm-complete.SKILL.md +106 -0
- package/gm-emit.SKILL.md +70 -0
- package/gm-execute.SKILL.md +88 -0
- package/gm.SKILL.md +63 -0
- package/index.js +1 -9
- package/lib/daemon-bootstrap.js +2 -2
- package/lib/git.js +332 -0
- package/lib/index.js +37 -0
- package/lib/loader.js +66 -0
- package/lib/manifest.js +16 -13
- package/lib/prepare.js +14 -0
- package/lib/spool.js +163 -0
- package/package.json +6 -4
- package/planning.SKILL.md +118 -0
- package/skills/gm/SKILL.md +63 -0
- package/skills/gm/index.js +113 -0
- package/skills/gm-complete/SKILL.md +106 -0
- package/skills/gm-complete/index.js +118 -0
- package/skills/gm-complete.SKILL.md +106 -0
- package/skills/gm-emit/SKILL.md +70 -0
- package/skills/gm-emit/index.js +90 -0
- package/skills/gm-emit.SKILL.md +70 -0
- package/skills/gm-execute/SKILL.md +88 -0
- package/skills/gm-execute/index.js +91 -0
- package/skills/gm-execute.SKILL.md +88 -0
- package/skills/gm.SKILL.md +63 -0
- package/skills/planning/SKILL.md +118 -0
- package/skills/planning/index.js +107 -0
- package/skills/planning.SKILL.md +118 -0
- package/skills/update-docs/SKILL.md +66 -0
- package/skills/update-docs/index.js +108 -0
- package/skills/update-docs.SKILL.md +66 -0
- package/test-build.js +29 -0
- package/test-e2e.js +117 -0
- package/test-unified.js +24 -0
- package/update-docs.SKILL.md +66 -0
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: planning
|
|
3
|
+
description: State machine orchestrator. Mutable discovery, PRD construction, and full PLAN→EXECUTE→EMIT→VERIFY→COMPLETE lifecycle. Invoke at session start and on any new unknown.
|
|
4
|
+
allowed-tools: Skill
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Planning — PLAN phase
|
|
8
|
+
|
|
9
|
+
Translate the request into `.gm/prd.yml` and hand to `gm-execute`. Re-enter on any new unknown in any phase.
|
|
10
|
+
|
|
11
|
+
A `@<discipline>` sigil in the request scopes recall, codesearch, and memorize calls during PLAN to that discipline's store. Without one, retrievals fan across default plus enabled disciplines and writes land in default only.
|
|
12
|
+
|
|
13
|
+
Cross-cutting dispositions (autonomy, fix-on-sight, nothing-fake, browser-witness, scope, recall, memorize) live in `gm` SKILL.md; this skill only carries what is unique to PLAN.
|
|
14
|
+
|
|
15
|
+
## Transitions
|
|
16
|
+
|
|
17
|
+
- PLAN done → `gm-execute`
|
|
18
|
+
- New unknown anywhere in chain → re-enter PLAN
|
|
19
|
+
- EXECUTE unresolvable after 2 passes → PLAN
|
|
20
|
+
- VERIFY: `.prd` empty + git clean + pushed → `update-docs`; else → `gm-execute`
|
|
21
|
+
|
|
22
|
+
Cannot stop while `.gm/prd.yml` has items, git is dirty, or commits are unpushed.
|
|
23
|
+
|
|
24
|
+
## Orient
|
|
25
|
+
|
|
26
|
+
Open every plan with one parallel pack of `exec:recall` + `exec:codesearch` against the request's nouns. Hits land as `weak_prior`; misses confirm the unknown is fresh. The pack runs in one message.
|
|
27
|
+
|
|
28
|
+
**Auto-recall injection (skills-only platforms)**: derive a 2–6 word query from the request's nouns (subject, verb objects, key domain terms). Call `exec:recall <query>` at PLAN start before writing `.gm/prd.yml`, inline. This replaces the prompt-submit hook's auto-recall for platforms without hook infrastructure. Recall hits are injected as context into mutable discovery and PRD item acceptance criteria.
|
|
29
|
+
|
|
30
|
+
## Mutable discovery
|
|
31
|
+
|
|
32
|
+
For each aspect of the work, ask: what do I not know, what could go wrong, what depends on what, what am I assuming. Unwitnessed assumptions are mutables.
|
|
33
|
+
|
|
34
|
+
Fault surfaces to scan: file existence, API shape, data format, dep versions, runtime behavior, env differences, error conditions, concurrency, integration seams, backwards compat, rollback paths, CI correctness.
|
|
35
|
+
|
|
36
|
+
Tag every item with a route family (grounding | reasoning | state | execution | observability | boundary | representation) and cross-reference the 16-failure taxonomy. `governance` skill holds the table.
|
|
37
|
+
|
|
38
|
+
`existingImpl=UNKNOWN` is the default; resolve via `exec:codesearch` before adding the item. An existing concern routes to consolidation, not addition.
|
|
39
|
+
|
|
40
|
+
Plan exits when zero new unknowns surfaced last pass AND every item has acceptance criteria AND deps are mapped.
|
|
41
|
+
|
|
42
|
+
## .gm/mutables.yml — co-equal with .gm/prd.yml
|
|
43
|
+
|
|
44
|
+
Every unknown surfaced during PLAN lands as an entry in `.gm/mutables.yml` the same pass. Live during work, deleted when empty. Hook-gated: Write/Edit/NotebookEdit and `git commit`/`git push` are hard-blocked while any entry has `status: unknown`; turn-stop is hard-blocked the same way.
|
|
45
|
+
|
|
46
|
+
```yaml
|
|
47
|
+
- id: kebab-id
|
|
48
|
+
claim: One-line statement of what is assumed
|
|
49
|
+
witness_method: exec:codesearch <query> | exec:nodejs import | exec:recall <query> | Read <path>
|
|
50
|
+
witness_evidence: ""
|
|
51
|
+
status: unknown
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
`status: unknown` → `witnessed` only when `witness_evidence` is filled with concrete proof (file:line, codesearch hit, dispatched test output). Resolution lives in gm-execute. PRD items reference mutables via optional `mutables: [id1, id2]` field; an item is blocked while any referenced mutable is unresolved.
|
|
55
|
+
|
|
56
|
+
## .prd format
|
|
57
|
+
|
|
58
|
+
Path: `./.gm/prd.yml`. Write via the Write tool or by emitting a nodejs spool file (`in/nodejs/<N>.js`) that calls `fs.writeFileSync`. Delete the file when empty.
|
|
59
|
+
|
|
60
|
+
```yaml
|
|
61
|
+
- id: kebab-id
|
|
62
|
+
subject: Imperative verb phrase
|
|
63
|
+
status: pending
|
|
64
|
+
description: Precise criterion
|
|
65
|
+
effort: small|medium|large
|
|
66
|
+
category: feature|bug|refactor|infra
|
|
67
|
+
route_family: grounding|reasoning|state|execution|observability|boundary|representation
|
|
68
|
+
load: 0.0-1.0
|
|
69
|
+
failure_modes: []
|
|
70
|
+
route_fit: unexamined|examined|dominant
|
|
71
|
+
authorization: none|weak_prior|witnessed
|
|
72
|
+
blocking: []
|
|
73
|
+
blockedBy: []
|
|
74
|
+
acceptance:
|
|
75
|
+
- binary criterion
|
|
76
|
+
edge_cases:
|
|
77
|
+
- failure mode
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
`load` is consequence-if-wrong: 0.9 = headline collapses, 0.7 = sub-argument rebuilt, 0.4 = local patch, 0.1 = nothing breaks. Verification budget = `load × (1 − tier_confidence)`. λ>0.75 must reach witnessed before EMIT.
|
|
81
|
+
|
|
82
|
+
`status`: pending → in_progress → completed (then remove). `effort`: small <15min | medium <45min | large >1h.
|
|
83
|
+
|
|
84
|
+
## Parallel subagent launch
|
|
85
|
+
|
|
86
|
+
After `.prd` is written, up to 3 parallel `gm:gm` subagents for independent items in one message. Browser tasks serialize.
|
|
87
|
+
|
|
88
|
+
```
|
|
89
|
+
Agent(subagent_type="gm:gm", prompt="Work on .prd item: <id>. .prd path: <path>. Item: <full YAML>.")
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Items not parallelizable → invoke `gm-execute` directly.
|
|
93
|
+
|
|
94
|
+
## Observability gates in the plan
|
|
95
|
+
|
|
96
|
+
Server: every subsystem exposes `/debug/<subsystem>`; structured logs `{subsystem, severity, ts}`. Client: `window.__debug` live registry; modules register on mount. `console.log` is not observability. Discovery of a gap during PLAN adds a `.prd` item the same pass — never deferred.
|
|
97
|
+
|
|
98
|
+
`window.__debug` is THE in-page registry; `test.js` at project root is the sole out-of-page test asset. Any new file whose purpose is to exercise, smoke-test, demo, or sandbox in-page behavior outside that registry fights the discipline — extend the registry instead.
|
|
99
|
+
|
|
100
|
+
## Test discipline encoded in the plan
|
|
101
|
+
|
|
102
|
+
One `test.js` at project root, 200-line hard cap, real data, real system. No fixtures, mocks, or scattered tests. A second test runner under any name in any directory is a smuggled parallel surface.
|
|
103
|
+
|
|
104
|
+
The 200 lines are a *budget* for maximum surface coverage, not a target. Subsystems get one combined group each — names joined with `+` (`home+config+skin`, `mcp+swe+distributions+account+credpool`). When a new subsystem's failure mode overlaps an existing group's side-effects, fold the assertion in rather than creating a new group. When `wc -l test.js > 200`, the discipline is *merge groups + drop redundancy*, never split.
|
|
105
|
+
|
|
106
|
+
## Execution norms encoded in the plan
|
|
107
|
+
|
|
108
|
+
Code execution AND utility verbs both write to `.gm/exec-spool/in/<lang-or-verb>/<N>.<ext>`. Languages live under `in/<lang>/` (nodejs, python, bash, typescript, go, rust, c, cpp, java, deno); verbs live under `in/<verb>/` (codesearch, recall, memorize, wait, sleep, status, close, browser, runner, type, kill-port, forget, feedback, learn-status, learn-debug, learn-build, discipline, pause, health). The spool watcher runs the file and streams to `out/<N>.out` (stdout) + `out/<N>.err` (stderr) line-by-line, then writes `out/<N>.json` metadata (exitCode, durationMs, timedOut, startedAt, endedAt) at completion. Both streams return as systemMessage with `--- stdout ---` / `--- stderr ---` separators. `in/` and `out/` are wiped at session start and at real-exit session end. Only `git` (and `gh`) run directly via Bash; never `Bash(node/npm/npx/bun)`, never `Bash(exec:<anything>)`. Spool paths in nodejs files are platform-literal — use `os.tmpdir()` and `path.join`. The spool enforces per-task timeouts; on timeout, partial output is preserved and the watcher emits `[exec timed out after Nms; partial output above]`.
|
|
109
|
+
|
|
110
|
+
`exec:codesearch` only — Grep/Glob/Find/Explore are hook-blocked. Start two words, change/add one per pass, minimum four attempts before concluding absent.
|
|
111
|
+
|
|
112
|
+
Pack runs use `Promise.allSettled`, each idea its own try/catch, under 12s per call.
|
|
113
|
+
|
|
114
|
+
## Dev workflow encoded in the plan
|
|
115
|
+
|
|
116
|
+
No comments. 200-line per-file cap. Fail loud. No duplication. Scan before edit. AGENTS.md edits route through the memorize sub-agent only. CHANGELOG.md gets one entry per commit.
|
|
117
|
+
|
|
118
|
+
Minimal-code process, stop at the first that resolves: native → library → structure (map / pipeline) → write.
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const yaml = require('yaml');
|
|
4
|
+
|
|
5
|
+
async function planningSkill(input, parentContext) {
|
|
6
|
+
const context = parentContext || {
|
|
7
|
+
request: input.request || '',
|
|
8
|
+
taskId: input.taskId || require('crypto').randomUUID(),
|
|
9
|
+
sessionId: process.env.SESSION_ID || require('crypto').randomUUID(),
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
const gmDir = path.join(process.cwd(), '.gm');
|
|
13
|
+
const prdPath = path.join(gmDir, 'prd.yml');
|
|
14
|
+
const mutablesPath = path.join(gmDir, 'mutables.yml');
|
|
15
|
+
|
|
16
|
+
console.error(`[planning] PLAN phase starting`);
|
|
17
|
+
console.error(`[planning] request="${context.request}"`);
|
|
18
|
+
|
|
19
|
+
const prd = [];
|
|
20
|
+
const mutables = [];
|
|
21
|
+
|
|
22
|
+
const skillCategories = [
|
|
23
|
+
{
|
|
24
|
+
id: 'gm-skill-gm-skill-index',
|
|
25
|
+
subject: 'Implement core skills (gm, planning, gm-execute, gm-emit, gm-complete, update-docs) as index.js modules',
|
|
26
|
+
description: 'Each skill reads SKILL.md, implements logic, returns end-to-end JSON with nextSkill/context/phase',
|
|
27
|
+
effort: 'large',
|
|
28
|
+
category: 'feature',
|
|
29
|
+
route_family: 'reasoning',
|
|
30
|
+
load: 1.0,
|
|
31
|
+
authorization: 'weak_prior',
|
|
32
|
+
acceptance: [
|
|
33
|
+
'gm/index.js parses request, invokes planning, returns nextSkill="planning"',
|
|
34
|
+
'planning/index.js runs ORIENT, mutable discovery, PRD generation',
|
|
35
|
+
'gm-execute/index.js parallelizes independent PRD items via subagents',
|
|
36
|
+
'gm-emit/index.js writes .gm/ files, verifies from disk',
|
|
37
|
+
'gm-complete/index.js verifies git state, checks tests',
|
|
38
|
+
'update-docs/index.js updates README, commits and pushes',
|
|
39
|
+
'All skills respect timeouts and emit clear error messages',
|
|
40
|
+
],
|
|
41
|
+
},
|
|
42
|
+
];
|
|
43
|
+
|
|
44
|
+
if (!fs.existsSync(gmDir)) {
|
|
45
|
+
fs.mkdirSync(gmDir, { recursive: true });
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
prd.push(...skillCategories.map((item, idx) => ({
|
|
49
|
+
id: item.id,
|
|
50
|
+
subject: item.subject,
|
|
51
|
+
status: 'pending',
|
|
52
|
+
description: item.description,
|
|
53
|
+
effort: item.effort,
|
|
54
|
+
category: item.category,
|
|
55
|
+
route_family: item.route_family,
|
|
56
|
+
load: item.load,
|
|
57
|
+
failure_modes: [
|
|
58
|
+
'skill invocation infinite loops',
|
|
59
|
+
'JSON output malformed or missing nextSkill',
|
|
60
|
+
'context not passed between skills',
|
|
61
|
+
'mutable resolution never completes',
|
|
62
|
+
'async operations timeout',
|
|
63
|
+
],
|
|
64
|
+
route_fit: 'examined',
|
|
65
|
+
authorization: item.authorization,
|
|
66
|
+
blocking: [],
|
|
67
|
+
blockedBy: [],
|
|
68
|
+
acceptance: item.acceptance,
|
|
69
|
+
edge_cases: [],
|
|
70
|
+
})));
|
|
71
|
+
|
|
72
|
+
console.error(`[planning] discovered ${prd.length} PRD items`);
|
|
73
|
+
console.error(`[planning] writing .gm/prd.yml`);
|
|
74
|
+
|
|
75
|
+
try {
|
|
76
|
+
fs.writeFileSync(prdPath, yaml.stringify(prd, { indent: 2 }), 'utf8');
|
|
77
|
+
} catch (err) {
|
|
78
|
+
console.error(`[planning] ERROR writing prd.yml:`, err.message);
|
|
79
|
+
return {
|
|
80
|
+
nextSkill: null,
|
|
81
|
+
context,
|
|
82
|
+
phase: 'ERROR',
|
|
83
|
+
error: `Failed to write PRD: ${err.message}`,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
context.prd = prd;
|
|
88
|
+
context.mutables = mutables;
|
|
89
|
+
|
|
90
|
+
return {
|
|
91
|
+
nextSkill: 'gm-execute',
|
|
92
|
+
context,
|
|
93
|
+
phase: 'PLAN',
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (require.main === module) {
|
|
98
|
+
const input = { request: process.argv[2] || 'default task' };
|
|
99
|
+
planningSkill(input).then(result => {
|
|
100
|
+
console.log(JSON.stringify(result, null, 2));
|
|
101
|
+
}).catch(err => {
|
|
102
|
+
console.error('Fatal error:', err);
|
|
103
|
+
process.exit(1);
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
module.exports = planningSkill;
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: planning
|
|
3
|
+
description: State machine orchestrator. Mutable discovery, PRD construction, and full PLAN→EXECUTE→EMIT→VERIFY→COMPLETE lifecycle. Invoke at session start and on any new unknown.
|
|
4
|
+
allowed-tools: Skill
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Planning — PLAN phase
|
|
8
|
+
|
|
9
|
+
Translate the request into `.gm/prd.yml` and hand to `gm-execute`. Re-enter on any new unknown in any phase.
|
|
10
|
+
|
|
11
|
+
A `@<discipline>` sigil in the request scopes recall, codesearch, and memorize calls during PLAN to that discipline's store. Without one, retrievals fan across default plus enabled disciplines and writes land in default only.
|
|
12
|
+
|
|
13
|
+
Cross-cutting dispositions (autonomy, fix-on-sight, nothing-fake, browser-witness, scope, recall, memorize) live in `gm` SKILL.md; this skill only carries what is unique to PLAN.
|
|
14
|
+
|
|
15
|
+
## Transitions
|
|
16
|
+
|
|
17
|
+
- PLAN done → `gm-execute`
|
|
18
|
+
- New unknown anywhere in chain → re-enter PLAN
|
|
19
|
+
- EXECUTE unresolvable after 2 passes → PLAN
|
|
20
|
+
- VERIFY: `.prd` empty + git clean + pushed → `update-docs`; else → `gm-execute`
|
|
21
|
+
|
|
22
|
+
Cannot stop while `.gm/prd.yml` has items, git is dirty, or commits are unpushed.
|
|
23
|
+
|
|
24
|
+
## Orient
|
|
25
|
+
|
|
26
|
+
Open every plan with one parallel pack of `exec:recall` + `exec:codesearch` against the request's nouns. Hits land as `weak_prior`; misses confirm the unknown is fresh. The pack runs in one message.
|
|
27
|
+
|
|
28
|
+
**Auto-recall injection (skills-only platforms)**: derive a 2–6 word query from the request's nouns (subject, verb objects, key domain terms). Call `exec:recall <query>` at PLAN start before writing `.gm/prd.yml`, inline. This replaces the prompt-submit hook's auto-recall for platforms without hook infrastructure. Recall hits are injected as context into mutable discovery and PRD item acceptance criteria.
|
|
29
|
+
|
|
30
|
+
## Mutable discovery
|
|
31
|
+
|
|
32
|
+
For each aspect of the work, ask: what do I not know, what could go wrong, what depends on what, what am I assuming. Unwitnessed assumptions are mutables.
|
|
33
|
+
|
|
34
|
+
Fault surfaces to scan: file existence, API shape, data format, dep versions, runtime behavior, env differences, error conditions, concurrency, integration seams, backwards compat, rollback paths, CI correctness.
|
|
35
|
+
|
|
36
|
+
Tag every item with a route family (grounding | reasoning | state | execution | observability | boundary | representation) and cross-reference the 16-failure taxonomy. `governance` skill holds the table.
|
|
37
|
+
|
|
38
|
+
`existingImpl=UNKNOWN` is the default; resolve via `exec:codesearch` before adding the item. An existing concern routes to consolidation, not addition.
|
|
39
|
+
|
|
40
|
+
Plan exits when zero new unknowns surfaced last pass AND every item has acceptance criteria AND deps are mapped.
|
|
41
|
+
|
|
42
|
+
## .gm/mutables.yml — co-equal with .gm/prd.yml
|
|
43
|
+
|
|
44
|
+
Every unknown surfaced during PLAN lands as an entry in `.gm/mutables.yml` the same pass. Live during work, deleted when empty. Hook-gated: Write/Edit/NotebookEdit and `git commit`/`git push` are hard-blocked while any entry has `status: unknown`; turn-stop is hard-blocked the same way.
|
|
45
|
+
|
|
46
|
+
```yaml
|
|
47
|
+
- id: kebab-id
|
|
48
|
+
claim: One-line statement of what is assumed
|
|
49
|
+
witness_method: exec:codesearch <query> | exec:nodejs import | exec:recall <query> | Read <path>
|
|
50
|
+
witness_evidence: ""
|
|
51
|
+
status: unknown
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
`status: unknown` → `witnessed` only when `witness_evidence` is filled with concrete proof (file:line, codesearch hit, dispatched test output). Resolution lives in gm-execute. PRD items reference mutables via optional `mutables: [id1, id2]` field; an item is blocked while any referenced mutable is unresolved.
|
|
55
|
+
|
|
56
|
+
## .prd format
|
|
57
|
+
|
|
58
|
+
Path: `./.gm/prd.yml`. Write via the Write tool or by emitting a nodejs spool file (`in/nodejs/<N>.js`) that calls `fs.writeFileSync`. Delete the file when empty.
|
|
59
|
+
|
|
60
|
+
```yaml
|
|
61
|
+
- id: kebab-id
|
|
62
|
+
subject: Imperative verb phrase
|
|
63
|
+
status: pending
|
|
64
|
+
description: Precise criterion
|
|
65
|
+
effort: small|medium|large
|
|
66
|
+
category: feature|bug|refactor|infra
|
|
67
|
+
route_family: grounding|reasoning|state|execution|observability|boundary|representation
|
|
68
|
+
load: 0.0-1.0
|
|
69
|
+
failure_modes: []
|
|
70
|
+
route_fit: unexamined|examined|dominant
|
|
71
|
+
authorization: none|weak_prior|witnessed
|
|
72
|
+
blocking: []
|
|
73
|
+
blockedBy: []
|
|
74
|
+
acceptance:
|
|
75
|
+
- binary criterion
|
|
76
|
+
edge_cases:
|
|
77
|
+
- failure mode
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
`load` is consequence-if-wrong: 0.9 = headline collapses, 0.7 = sub-argument rebuilt, 0.4 = local patch, 0.1 = nothing breaks. Verification budget = `load × (1 − tier_confidence)`. λ>0.75 must reach witnessed before EMIT.
|
|
81
|
+
|
|
82
|
+
`status`: pending → in_progress → completed (then remove). `effort`: small <15min | medium <45min | large >1h.
|
|
83
|
+
|
|
84
|
+
## Parallel subagent launch
|
|
85
|
+
|
|
86
|
+
After `.prd` is written, up to 3 parallel `gm:gm` subagents for independent items in one message. Browser tasks serialize.
|
|
87
|
+
|
|
88
|
+
```
|
|
89
|
+
Agent(subagent_type="gm:gm", prompt="Work on .prd item: <id>. .prd path: <path>. Item: <full YAML>.")
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Items not parallelizable → invoke `gm-execute` directly.
|
|
93
|
+
|
|
94
|
+
## Observability gates in the plan
|
|
95
|
+
|
|
96
|
+
Server: every subsystem exposes `/debug/<subsystem>`; structured logs `{subsystem, severity, ts}`. Client: `window.__debug` live registry; modules register on mount. `console.log` is not observability. Discovery of a gap during PLAN adds a `.prd` item the same pass — never deferred.
|
|
97
|
+
|
|
98
|
+
`window.__debug` is THE in-page registry; `test.js` at project root is the sole out-of-page test asset. Any new file whose purpose is to exercise, smoke-test, demo, or sandbox in-page behavior outside that registry fights the discipline — extend the registry instead.
|
|
99
|
+
|
|
100
|
+
## Test discipline encoded in the plan
|
|
101
|
+
|
|
102
|
+
One `test.js` at project root, 200-line hard cap, real data, real system. No fixtures, mocks, or scattered tests. A second test runner under any name in any directory is a smuggled parallel surface.
|
|
103
|
+
|
|
104
|
+
The 200 lines are a *budget* for maximum surface coverage, not a target. Subsystems get one combined group each — names joined with `+` (`home+config+skin`, `mcp+swe+distributions+account+credpool`). When a new subsystem's failure mode overlaps an existing group's side-effects, fold the assertion in rather than creating a new group. When `wc -l test.js > 200`, the discipline is *merge groups + drop redundancy*, never split.
|
|
105
|
+
|
|
106
|
+
## Execution norms encoded in the plan
|
|
107
|
+
|
|
108
|
+
Code execution AND utility verbs both write to `.gm/exec-spool/in/<lang-or-verb>/<N>.<ext>`. Languages live under `in/<lang>/` (nodejs, python, bash, typescript, go, rust, c, cpp, java, deno); verbs live under `in/<verb>/` (codesearch, recall, memorize, wait, sleep, status, close, browser, runner, type, kill-port, forget, feedback, learn-status, learn-debug, learn-build, discipline, pause, health). The spool watcher runs the file and streams to `out/<N>.out` (stdout) + `out/<N>.err` (stderr) line-by-line, then writes `out/<N>.json` metadata (exitCode, durationMs, timedOut, startedAt, endedAt) at completion. Both streams return as systemMessage with `--- stdout ---` / `--- stderr ---` separators. `in/` and `out/` are wiped at session start and at real-exit session end. Only `git` (and `gh`) run directly via Bash; never `Bash(node/npm/npx/bun)`, never `Bash(exec:<anything>)`. Spool paths in nodejs files are platform-literal — use `os.tmpdir()` and `path.join`. The spool enforces per-task timeouts; on timeout, partial output is preserved and the watcher emits `[exec timed out after Nms; partial output above]`.
|
|
109
|
+
|
|
110
|
+
`exec:codesearch` only — Grep/Glob/Find/Explore are hook-blocked. Start two words, change/add one per pass, minimum four attempts before concluding absent.
|
|
111
|
+
|
|
112
|
+
Pack runs use `Promise.allSettled`, each idea its own try/catch, under 12s per call.
|
|
113
|
+
|
|
114
|
+
## Dev workflow encoded in the plan
|
|
115
|
+
|
|
116
|
+
No comments. 200-line per-file cap. Fail loud. No duplication. Scan before edit. AGENTS.md edits route through the memorize sub-agent only. CHANGELOG.md gets one entry per commit.
|
|
117
|
+
|
|
118
|
+
Minimal-code process, stop at the first that resolves: native → library → structure (map / pipeline) → write.
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: update-docs
|
|
3
|
+
description: UPDATE-DOCS phase. Refresh README.md, AGENTS.md, and docs/index.html to reflect changes made this session. Commits and pushes doc updates. Terminal phase — declares COMPLETE.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# GM UPDATE-DOCS
|
|
7
|
+
|
|
8
|
+
Entry: feature verified, committed, pushed. Exit: docs match disk, committed, pushed → COMPLETE. Unknown architecture change → `planning`.
|
|
9
|
+
|
|
10
|
+
Every claim in docs is verifiable against disk. Phase names match frontmatter, platform names match `platforms/`, file paths exist, constraint counts are accurate. An unverifiable section is removed, not speculated.
|
|
11
|
+
|
|
12
|
+
## Sequence
|
|
13
|
+
|
|
14
|
+
What changed — run directly via Bash:
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
git log -5 --oneline
|
|
18
|
+
git diff HEAD~1 --stat
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Read current docs via Read tool, or via a nodejs spool file (`in/nodejs/<N>.js`):
|
|
22
|
+
|
|
23
|
+
```
|
|
24
|
+
const fs = require('fs');
|
|
25
|
+
['README.md', 'AGENTS.md', 'docs/index.html', 'gm-starter/agents/gm.md'].forEach(f => {
|
|
26
|
+
try { console.log(`=== ${f} ===\n` + fs.readFileSync(f, 'utf8')); }
|
|
27
|
+
catch(e) { console.log(`MISSING: ${f}`); }
|
|
28
|
+
});
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Write changed sections only:
|
|
32
|
+
|
|
33
|
+
- **README.md** — platform count, skill tree diagram, quick-start commands
|
|
34
|
+
- **AGENTS.md** — via `Agent(subagent_type='gm:memorize', model='haiku', run_in_background=true, prompt='## CONTEXT TO MEMORIZE\n<learnings>')`. Never inline-edit.
|
|
35
|
+
- **docs/index.html** — `PHASES` array, platform lists, state machine diagram
|
|
36
|
+
- **gm-starter/agents/gm.md** — skill chain line if new skills added
|
|
37
|
+
|
|
38
|
+
Verify from disk (Read tool, or a nodejs spool file):
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
const content = require('fs').readFileSync('/abs/path/file.md', 'utf8');
|
|
42
|
+
console.log(content.includes('expectedString'), content.length);
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Commit and push directly via Bash:
|
|
46
|
+
|
|
47
|
+
```
|
|
48
|
+
git add README.md docs/index.html gm-starter/agents/gm.md
|
|
49
|
+
git commit -m "docs: update documentation to reflect session changes"
|
|
50
|
+
git push -u origin HEAD
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Exit: browser cleanup
|
|
54
|
+
|
|
55
|
+
After docs push succeeds, close any browser sessions spawned during this or prior skill phases. Write a nodejs spool file calling rs-exec:
|
|
56
|
+
|
|
57
|
+
```javascript
|
|
58
|
+
const sessionId = process.env.CLAUDE_SESSION_ID;
|
|
59
|
+
if (!sessionId) return;
|
|
60
|
+
const rs = require('rs-exec');
|
|
61
|
+
try {
|
|
62
|
+
rs.client().close_sessions_for(sessionId).catch(() => {});
|
|
63
|
+
} catch (e) {}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Best-effort: session context or rs-exec unavailable → skip gracefully. No error thrown.
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const git = require('../../lib/git.js');
|
|
4
|
+
|
|
5
|
+
async function updateDocsSkill(input, parentContext) {
|
|
6
|
+
const context = parentContext || {
|
|
7
|
+
request: input.request || '',
|
|
8
|
+
taskId: input.taskId || require('crypto').randomUUID(),
|
|
9
|
+
sessionId: process.env.SESSION_ID || require('crypto').randomUUID(),
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
console.error(`[update-docs] UPDATE-DOCS phase starting`);
|
|
13
|
+
|
|
14
|
+
const docsUpdates = [];
|
|
15
|
+
|
|
16
|
+
try {
|
|
17
|
+
try {
|
|
18
|
+
const logResult = await git.log(context.sessionId, 5);
|
|
19
|
+
if (logResult.ok) {
|
|
20
|
+
console.error(`[update-docs] Recent commits:\n${logResult.commits.join('\n')}`);
|
|
21
|
+
}
|
|
22
|
+
} catch (err) {
|
|
23
|
+
console.error(`[update-docs] Could not get recent commits:`, err.message);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
try {
|
|
27
|
+
const diffResult = await git.diff(context.sessionId);
|
|
28
|
+
if (diffResult.ok && diffResult.diff.length > 0) {
|
|
29
|
+
console.error(`[update-docs] Changes detected (${diffResult.diff.length} bytes)`);
|
|
30
|
+
}
|
|
31
|
+
} catch (err) {
|
|
32
|
+
console.error(`[update-docs] Could not get diff:`, err.message);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const readmeExists = fs.existsSync('README.md');
|
|
36
|
+
const agentsMdExists = fs.existsSync('AGENTS.md');
|
|
37
|
+
const indexHtmlExists = fs.existsSync('docs/index.html');
|
|
38
|
+
|
|
39
|
+
console.error(`[update-docs] README.md: ${readmeExists}`);
|
|
40
|
+
console.error(`[update-docs] AGENTS.md: ${agentsMdExists}`);
|
|
41
|
+
console.error(`[update-docs] docs/index.html: ${indexHtmlExists}`);
|
|
42
|
+
|
|
43
|
+
const gmDir = path.join(process.cwd(), '.gm');
|
|
44
|
+
if (!fs.existsSync(gmDir)) {
|
|
45
|
+
fs.mkdirSync(gmDir, { recursive: true });
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const updateState = {
|
|
49
|
+
timestamp: new Date().toISOString(),
|
|
50
|
+
documentsChecked: {
|
|
51
|
+
readme: readmeExists,
|
|
52
|
+
agents: agentsMdExists,
|
|
53
|
+
indexHtml: indexHtmlExists,
|
|
54
|
+
},
|
|
55
|
+
updated: [],
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
fs.writeFileSync(path.join(gmDir, 'update-docs-state.json'), JSON.stringify(updateState, null, 2), 'utf8');
|
|
59
|
+
|
|
60
|
+
console.error(`[update-docs] Recorded documentation state`);
|
|
61
|
+
|
|
62
|
+
} catch (err) {
|
|
63
|
+
console.error(`[update-docs] ERROR:`, err.message);
|
|
64
|
+
return {
|
|
65
|
+
nextSkill: null,
|
|
66
|
+
context,
|
|
67
|
+
phase: 'ERROR',
|
|
68
|
+
error: `UPDATE-DOCS failed: ${err.message}`,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
try {
|
|
73
|
+
console.error(`[update-docs] Attempting git operations...`);
|
|
74
|
+
|
|
75
|
+
try {
|
|
76
|
+
const statusResult = await git.status(context.sessionId);
|
|
77
|
+
if (statusResult.ok && !statusResult.isDirty) {
|
|
78
|
+
console.error(`[update-docs] Repository is clean, no docs to commit`);
|
|
79
|
+
} else if (statusResult.ok && statusResult.isDirty) {
|
|
80
|
+
console.error(`[update-docs] Repository has changes: ${statusResult.modified.length} modified, ${statusResult.untracked.length} untracked`);
|
|
81
|
+
}
|
|
82
|
+
} catch (err) {
|
|
83
|
+
console.error(`[update-docs] Git check failed:`, err.message);
|
|
84
|
+
}
|
|
85
|
+
} catch (err) {
|
|
86
|
+
console.error(`[update-docs] Warning during finalization:`, err.message);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
console.error(`[update-docs] UPDATE-DOCS phase complete`);
|
|
90
|
+
|
|
91
|
+
return {
|
|
92
|
+
nextSkill: null,
|
|
93
|
+
context,
|
|
94
|
+
phase: 'UPDATE-DOCS',
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (require.main === module) {
|
|
99
|
+
const input = { request: process.argv[2] || 'default task' };
|
|
100
|
+
updateDocsSkill(input).then(result => {
|
|
101
|
+
console.log(JSON.stringify(result, null, 2));
|
|
102
|
+
}).catch(err => {
|
|
103
|
+
console.error('Fatal error:', err);
|
|
104
|
+
process.exit(1);
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
module.exports = updateDocsSkill;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: update-docs
|
|
3
|
+
description: UPDATE-DOCS phase. Refresh README.md, AGENTS.md, and docs/index.html to reflect changes made this session. Commits and pushes doc updates. Terminal phase — declares COMPLETE.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# GM UPDATE-DOCS
|
|
7
|
+
|
|
8
|
+
Entry: feature verified, committed, pushed. Exit: docs match disk, committed, pushed → COMPLETE. Unknown architecture change → `planning`.
|
|
9
|
+
|
|
10
|
+
Every claim in docs is verifiable against disk. Phase names match frontmatter, platform names match `platforms/`, file paths exist, constraint counts are accurate. An unverifiable section is removed, not speculated.
|
|
11
|
+
|
|
12
|
+
## Sequence
|
|
13
|
+
|
|
14
|
+
What changed — run directly via Bash:
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
git log -5 --oneline
|
|
18
|
+
git diff HEAD~1 --stat
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Read current docs via Read tool, or via a nodejs spool file (`in/nodejs/<N>.js`):
|
|
22
|
+
|
|
23
|
+
```
|
|
24
|
+
const fs = require('fs');
|
|
25
|
+
['README.md', 'AGENTS.md', 'docs/index.html', 'gm-starter/agents/gm.md'].forEach(f => {
|
|
26
|
+
try { console.log(`=== ${f} ===\n` + fs.readFileSync(f, 'utf8')); }
|
|
27
|
+
catch(e) { console.log(`MISSING: ${f}`); }
|
|
28
|
+
});
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Write changed sections only:
|
|
32
|
+
|
|
33
|
+
- **README.md** — platform count, skill tree diagram, quick-start commands
|
|
34
|
+
- **AGENTS.md** — via `Agent(subagent_type='gm:memorize', model='haiku', run_in_background=true, prompt='## CONTEXT TO MEMORIZE\n<learnings>')`. Never inline-edit.
|
|
35
|
+
- **docs/index.html** — `PHASES` array, platform lists, state machine diagram
|
|
36
|
+
- **gm-starter/agents/gm.md** — skill chain line if new skills added
|
|
37
|
+
|
|
38
|
+
Verify from disk (Read tool, or a nodejs spool file):
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
const content = require('fs').readFileSync('/abs/path/file.md', 'utf8');
|
|
42
|
+
console.log(content.includes('expectedString'), content.length);
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Commit and push directly via Bash:
|
|
46
|
+
|
|
47
|
+
```
|
|
48
|
+
git add README.md docs/index.html gm-starter/agents/gm.md
|
|
49
|
+
git commit -m "docs: update documentation to reflect session changes"
|
|
50
|
+
git push -u origin HEAD
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Exit: browser cleanup
|
|
54
|
+
|
|
55
|
+
After docs push succeeds, close any browser sessions spawned during this or prior skill phases. Write a nodejs spool file calling rs-exec:
|
|
56
|
+
|
|
57
|
+
```javascript
|
|
58
|
+
const sessionId = process.env.CLAUDE_SESSION_ID;
|
|
59
|
+
if (!sessionId) return;
|
|
60
|
+
const rs = require('rs-exec');
|
|
61
|
+
try {
|
|
62
|
+
rs.client().close_sessions_for(sessionId).catch(() => {});
|
|
63
|
+
} catch (e) {}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Best-effort: session context or rs-exec unavailable → skip gracefully. No error thrown.
|
package/test-build.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
const gmSkill = require('./lib/index.js');
|
|
2
|
+
|
|
3
|
+
console.log('\n=== GM-SKILL BUILD TEST ===\n');
|
|
4
|
+
|
|
5
|
+
console.log('✓ Module loaded successfully');
|
|
6
|
+
|
|
7
|
+
const req = ['getSkills', 'getSkill', 'loadSkill', 'bootstrapDaemon'];
|
|
8
|
+
req.forEach(k => {
|
|
9
|
+
const ok = typeof gmSkill[k] === 'function';
|
|
10
|
+
console.log(`${ok ? '✓' : '✗'} ${k}: ${typeof gmSkill[k]}`);
|
|
11
|
+
if (!ok) process.exit(1);
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
console.log('\n✓ All required functions exported');
|
|
15
|
+
|
|
16
|
+
const skills = gmSkill.getSkills();
|
|
17
|
+
console.log(`\n✓ getSkills() returned ${skills.length} skills:`);
|
|
18
|
+
skills.forEach(s => {
|
|
19
|
+
console.log(` - ${s.name}: ${s.description.substring(0, 50)}...`);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
const gm = gmSkill.getSkill('gm');
|
|
23
|
+
console.log(`\n✓ getSkill('gm') returned skill with:`);
|
|
24
|
+
console.log(` - name: ${gm.name}`);
|
|
25
|
+
console.log(` - endToEnd: ${gm.endToEnd}`);
|
|
26
|
+
console.log(` - allowedTools: [${gm.allowedTools.join(', ')}]`);
|
|
27
|
+
console.log(` - compatiblePlatforms: ${gm.compatiblePlatforms.length} platforms`);
|
|
28
|
+
|
|
29
|
+
console.log('\n=== BUILD VERIFICATION COMPLETE ===\n');
|