@lovrozagar/grunt 0.5.2 → 0.6.0
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/agents/grunt.md +2 -24
- package/.agents/agents/orchestrator.md +5 -50
- package/.agents/skills/ask/SKILL.md +5 -12
- package/.agents/skills/auto/SKILL.md +7 -12
- package/.agents/skills/browser/SKILL.md +4 -8
- package/.agents/skills/clasp/SKILL.md +11 -0
- package/.agents/skills/commit/SKILL.md +3 -1
- package/.agents/skills/commit-push/SKILL.md +2 -0
- package/.agents/skills/commit-push-deploy/SKILL.md +2 -0
- package/.agents/skills/commit-push-release/SKILL.md +2 -0
- package/.agents/skills/explain/SKILL.md +7 -13
- package/.agents/skills/google-workspace/SKILL.md +13 -0
- package/.agents/skills/handoff/SKILL.md +7 -11
- package/.agents/skills/implement-plan/SKILL.md +5 -109
- package/.agents/skills/listen/SKILL.md +15 -0
- package/.agents/skills/pickup/SKILL.md +6 -12
- package/.agents/skills/speak/SKILL.md +13 -0
- package/.agents/skills/tmp/SKILL.md +6 -10
- package/.agents/skills/write-plan/SKILL.md +5 -77
- package/.claude/agents/grunt.md +2 -26
- package/.claude/agents/orchestrator.md +12 -50
- package/.claude/skills/ask/SKILL.md +5 -12
- package/.claude/skills/auto/SKILL.md +7 -12
- package/.claude/skills/browser/SKILL.md +4 -8
- package/.claude/skills/clasp/SKILL.md +11 -0
- package/.claude/skills/commit/SKILL.md +3 -1
- package/.claude/skills/commit-push/SKILL.md +2 -0
- package/.claude/skills/commit-push-deploy/SKILL.md +2 -0
- package/.claude/skills/commit-push-release/SKILL.md +2 -0
- package/.claude/skills/explain/SKILL.md +7 -13
- package/.claude/skills/google-workspace/SKILL.md +13 -0
- package/.claude/skills/handoff/SKILL.md +7 -11
- package/.claude/skills/implement-plan/SKILL.md +5 -109
- package/.claude/skills/listen/SKILL.md +15 -0
- package/.claude/skills/pickup/SKILL.md +6 -12
- package/.claude/skills/speak/SKILL.md +13 -0
- package/.claude/skills/tmp/SKILL.md +6 -10
- package/.claude/skills/write-plan/SKILL.md +5 -77
- package/.codex/agents/grunt.toml +2 -26
- package/.codex/agents/orchestrator.toml +4 -50
- package/.grok/agents/grunt.md +2 -24
- package/.grok/agents/orchestrator.md +4 -48
- package/.grok/global-settings.toml +1 -3
- package/.grok/hooks/orchestrate-parent.js +190 -358
- package/.grok/skills/ask/SKILL.md +5 -12
- package/.grok/skills/auto/SKILL.md +7 -12
- package/.grok/skills/browser/SKILL.md +4 -8
- package/.grok/skills/clasp/SKILL.md +11 -0
- package/.grok/skills/commit/SKILL.md +3 -1
- package/.grok/skills/commit-push/SKILL.md +2 -0
- package/.grok/skills/commit-push-deploy/SKILL.md +2 -0
- package/.grok/skills/commit-push-release/SKILL.md +2 -0
- package/.grok/skills/explain/SKILL.md +7 -13
- package/.grok/skills/google-workspace/SKILL.md +13 -0
- package/.grok/skills/handoff/SKILL.md +7 -11
- package/.grok/skills/implement-plan/SKILL.md +5 -109
- package/.grok/skills/listen/SKILL.md +15 -0
- package/.grok/skills/pickup/SKILL.md +6 -12
- package/.grok/skills/speak/SKILL.md +13 -0
- package/.grok/skills/tmp/SKILL.md +6 -10
- package/.grok/skills/write-plan/SKILL.md +5 -77
- package/.rulesync/hooks.jsonc +1 -1
- package/.rulesync/mcp-policy.jsonc +0 -2
- package/.rulesync/reference/INDEX.md +30 -20
- package/.rulesync/reference/browser.md +13 -6
- package/.rulesync/reference/cascade.md +6 -86
- package/.rulesync/reference/clasp.md +21 -0
- package/.rulesync/reference/google-workspace.md +79 -0
- package/.rulesync/reference/hooks.md +7 -11
- package/.rulesync/reference/implementation-format.md +113 -0
- package/.rulesync/reference/law.md +5 -3
- package/.rulesync/reference/listen.md +80 -0
- package/.rulesync/reference/map.md +39 -36
- package/.rulesync/reference/output.md +3 -51
- package/.rulesync/reference/plan-format.md +4 -2
- package/.rulesync/reference/refs-map.md +12 -5
- package/.rulesync/reference/rtk.md +3 -2
- package/.rulesync/reference/scope.md +37 -0
- package/.rulesync/reference/setup.md +27 -0
- package/.rulesync/reference/skills-map.md +13 -12
- package/.rulesync/reference/speak.md +59 -0
- package/.rulesync/rules/CLAUDE.md +3 -49
- package/.rulesync/rules/overview.md +9 -47
- package/.rulesync/skills/ask/SKILL.md +5 -12
- package/.rulesync/skills/auto/SKILL.md +5 -12
- package/.rulesync/skills/browser/SKILL.md +4 -8
- package/.rulesync/skills/clasp/SKILL.md +9 -0
- package/.rulesync/skills/commit/SKILL.md +3 -1
- package/.rulesync/skills/commit-push/SKILL.md +2 -0
- package/.rulesync/skills/commit-push-deploy/SKILL.md +2 -0
- package/.rulesync/skills/commit-push-release/SKILL.md +2 -0
- package/.rulesync/skills/explain/SKILL.md +7 -14
- package/.rulesync/skills/google-workspace/SKILL.md +11 -0
- package/.rulesync/skills/handoff/SKILL.md +7 -11
- package/.rulesync/skills/implement-plan/SKILL.md +5 -119
- package/.rulesync/skills/listen/SKILL.md +13 -0
- package/.rulesync/skills/pickup/SKILL.md +6 -12
- package/.rulesync/skills/speak/SKILL.md +13 -0
- package/.rulesync/skills/tmp/SKILL.md +6 -10
- package/.rulesync/skills/write-plan/SKILL.md +5 -84
- package/.rulesync/subagents/grunt.md +2 -24
- package/.rulesync/subagents/orchestrator.md +14 -59
- package/AGENTS.md +9 -47
- package/CHANGELOG.md +56 -0
- package/CLAUDE.md +1 -49
- package/README.md +88 -80
- package/cli/grunt.mjs +18 -2
- package/cli/grunt.test.ts +33 -0
- package/cli/init.mjs +103 -10
- package/cli/init.test.ts +147 -35
- package/cli/prompt.mjs +8 -0
- package/cli/prompt.test.ts +14 -0
- package/package.json +7 -2
- package/scripts/browser.mjs +98 -5
- package/scripts/doctor.mjs +82 -1
- package/scripts/emit-gemini.mjs +1 -1
- package/scripts/emit-mcp-policy.mjs +1 -1
- package/scripts/gate-fat-tools.mjs +223 -173
- package/scripts/google-workspace.mjs +713 -0
- package/scripts/grunt-job.mjs +453 -69
- package/scripts/listen.mjs +829 -0
- package/scripts/parse-need.mjs +21 -2
- package/scripts/persist-implementation.mjs +278 -0
- package/scripts/scrub-spawn-prompt.mjs +3 -50
- package/scripts/setup.mjs +746 -0
- package/scripts/speak.mjs +291 -0
- package/.agents/agents/implementer.md +0 -32
- package/.agents/agents/thinker.md +0 -29
- package/.agents/skills/cascade/SKILL.md +0 -28
- package/.agents/skills/parent/SKILL.md +0 -6
- package/.agents/skills/solo/SKILL.md +0 -25
- package/.claude/agents/implementer.md +0 -37
- package/.claude/agents/thinker.md +0 -36
- package/.claude/skills/cascade/SKILL.md +0 -28
- package/.claude/skills/parent/SKILL.md +0 -6
- package/.claude/skills/solo/SKILL.md +0 -25
- package/.codex/agents/implementer.toml +0 -26
- package/.codex/agents/thinker.toml +0 -26
- package/.grok/agents/implementer.md +0 -27
- package/.grok/agents/thinker.md +0 -27
- package/.grok/parent.md +0 -1
- package/.grok/roles/implementer.toml +0 -5
- package/.grok/roles/thinker.toml +0 -5
- package/.grok/skills/cascade/SKILL.md +0 -28
- package/.grok/skills/parent/SKILL.md +0 -6
- package/.grok/skills/solo/SKILL.md +0 -25
- package/.rulesync/grunt.config.jsonc +0 -7
- package/.rulesync/skills/cascade/SKILL.md +0 -28
- package/.rulesync/skills/parent/SKILL.md +0 -6
- package/.rulesync/skills/solo/SKILL.md +0 -25
- package/.rulesync/subagents/implementer.md +0 -49
- package/.rulesync/subagents/thinker.md +0 -49
- package/scripts/grunt-config.mjs +0 -50
package/README.md
CHANGED
|
@@ -27,23 +27,23 @@ OSS drop-in; merges existing configs; switches default provider flow to Grunt.
|
|
|
27
27
|
|
|
28
28
|
```
|
|
29
29
|
npm i -D @lovrozagar/grunt
|
|
30
|
-
|
|
30
|
+
npm exec grunt
|
|
31
31
|
```
|
|
32
32
|
|
|
33
|
-
- Same as `
|
|
33
|
+
- Same as `npm exec grunt init` when no command
|
|
34
34
|
- Do not `npm test` as a consumer
|
|
35
|
-
- Package: `@lovrozagar/grunt` `0.
|
|
35
|
+
- Package: `@lovrozagar/grunt` `0.6.0` MIT · https://github.com/lovrozagar/grunt
|
|
36
36
|
|
|
37
37
|
## Prerequisites
|
|
38
38
|
|
|
39
39
|
All OS. Print-only. Never auto-install.
|
|
40
40
|
|
|
41
41
|
```
|
|
42
|
-
|
|
42
|
+
npm exec grunt doctor
|
|
43
43
|
node scripts/doctor.mjs
|
|
44
44
|
```
|
|
45
45
|
|
|
46
|
-
Exit 1 if any required missing; 0 if all required ok. Optional
|
|
46
|
+
Exit 1 if any required missing; 0 if all required ok. Optional tools are reported; missing optional does not fail.
|
|
47
47
|
|
|
48
48
|
| tool | required | install |
|
|
49
49
|
| --- | --- | --- |
|
|
@@ -54,12 +54,18 @@ Exit 1 if any required missing; 0 if all required ok. Optional `gh` reported onl
|
|
|
54
54
|
| lightpanda | yes | `curl -fsSL https://pkg.lightpanda.io/install.sh \| bash` · mac `brew tap lightpanda-io/browser` · win WSL only |
|
|
55
55
|
| chromium-family | yes | linux `sudo apt install chromium` · mac `brew install --cask chromium` or `google-chrome` · win `winget install Google.Chrome` / `Microsoft.Edge` + PATH |
|
|
56
56
|
| gh | no | report only |
|
|
57
|
+
| clasp | no | `npm i -g @google/clasp` · custom Apps Script only |
|
|
58
|
+
| google-workspace | no | `node scripts/google-workspace.mjs` · Sheets Docs Slides Calendar Gmail · doctor reports `oauth`/`tokens`/`adc`/`clasprc` (no secrets) · `grunt setup` / `node scripts/setup.mjs google-workspace` |
|
|
59
|
+
| speak | no | `node scripts/speak.mjs` · TTS output (ElevenLabs or OpenAI) · `grunt setup` / `node scripts/setup.mjs speak` · or `ELEVENLABS_API_KEY` / `OPENAI_API_KEY` / `~/.grunt/speak.json` |
|
|
60
|
+
| ffmpeg | no | mic capture for `/listen` · mac `brew install ffmpeg` · linux `sudo apt install ffmpeg` · win `winget install Gyan.FFmpeg` |
|
|
61
|
+
| whisper-cli | no | local STT for `/listen` · mac `brew install whisper-cpp` · first listen downloads `ggml-base.en.bin` · setup in `.rulesync/reference/listen.md` |
|
|
62
|
+
| listen | no | `node scripts/listen.mjs` · STT input · `grunt setup` / `node scripts/setup.mjs listen` · local whisper.cpp then OpenAI Whisper |
|
|
57
63
|
|
|
58
64
|
Rulesync schema doctor is separate: `npm run grunt:rulesync:doctor`.
|
|
59
65
|
|
|
60
66
|
## Usage
|
|
61
67
|
|
|
62
|
-
- TTY no command → menu (init default; generate check sync-globals purge-mcps doctor help quit)
|
|
68
|
+
- TTY no command → menu (init default; generate check sync-globals purge-mcps doctor setup upgrade help quit)
|
|
63
69
|
- Piped / CI / `--yes` / `-y` / `--non-interactive` no command → still `init`
|
|
64
70
|
- Bin: `grunt` → `./bin/grunt.js` (`type: module`)
|
|
65
71
|
|
|
@@ -72,7 +78,9 @@ Rulesync schema doctor is separate: `npm run grunt:rulesync:doctor`.
|
|
|
72
78
|
- `check` → `npm run grunt:rulesync:check`
|
|
73
79
|
- `sync-globals` → `npm run grunt:sync:globals` (dry-run); `--apply` → `grunt:sync:globals:apply`
|
|
74
80
|
- `purge-mcps` → `npm run grunt:purge:global-mcps` (dry-run); `--apply` → `grunt:purge:global-mcps:apply`
|
|
75
|
-
- `doctor` → `npm run grunt:doctor` (`
|
|
81
|
+
- `doctor` → `npm run grunt:doctor` (`npm exec grunt doctor` / `node scripts/doctor.mjs` stay). Rulesync schema: `npm run grunt:rulesync:doctor`
|
|
82
|
+
- `setup` → `npm run grunt:setup` (`node scripts/setup.mjs`) — handheld speak / listen / google-workspace / browser. TTY walks each; flags for non-TTY keys/`--creds`
|
|
83
|
+
- `upgrade` → same merge as init for an already-inited repo: copy owned trees/scripts, prune retired grunt-owned names, print reserved skill names
|
|
76
84
|
- `help`
|
|
77
85
|
- `version`
|
|
78
86
|
|
|
@@ -90,32 +98,34 @@ Rulesync schema doctor is separate: `npm run grunt:rulesync:doctor`.
|
|
|
90
98
|
- Re-init auto-skips globals when `<!-- grunt:begin -->` in `AGENTS.md`/`CLAUDE.md`
|
|
91
99
|
- First init (no sentinel) applies globals unless flagged
|
|
92
100
|
- Owned trees/scripts refresh; extra `.rulesync` files kept; patches to grunt-owned files lost
|
|
101
|
+
- `cp` cannot delete dest extras. Init/upgrade then prune: retired skills `parent` `solo` `cascade`, agents `implementer` `thinker` (plus `.grok/roles/{implementer,thinker}.toml` and `.gemini/agents/{name}/`), scripts `telemetry.mjs` `grunt-config.mjs`, paths `.grok/parent.md` `.grok/skills/shared` `.rulesync/grunt.config.jsonc` plus local overlay and example, and reserved skill dirs this package no longer ships. Consumer extras stay.
|
|
93
102
|
- Breaking: consumer npm scripts are `grunt:<SoT-key>` (`grunt:rulesync:generate`, `grunt:doctor`). Re-init migrates `package.json` (owned unprefixed keys + suffixes; `npm run` refs in other dest scripts). CI/husky/`npm run rulesync:*` / `npm run doctor` must switch. No aliases. SoT repo scripts stay unprefixed (`npm run rulesync:generate`).
|
|
94
103
|
|
|
95
104
|
## Version bump
|
|
96
105
|
|
|
106
|
+
Already-inited consumer (0.5.x → 0.6, and later):
|
|
107
|
+
|
|
97
108
|
```
|
|
98
|
-
npm i -D @lovrozagar/grunt@latest
|
|
109
|
+
npm i -D @lovrozagar/grunt@latest
|
|
110
|
+
npm exec grunt upgrade
|
|
99
111
|
```
|
|
100
112
|
|
|
101
|
-
- Same
|
|
113
|
+
`upgrade` is init plus a reserved-names print. Same merge, prune, and globals-skip rules as Init. New skills/scripts appear because they are in the package copy list. Dropped grunt-owned files disappear only if they are on the retired lists (or a reserved skill this package no longer ships). Do not expect a blind dest-dir mirror-delete; that would wipe consumer extras.
|
|
102
114
|
|
|
103
115
|
## Agents
|
|
104
116
|
|
|
105
|
-
SoT: `.rulesync/subagents/{orchestrator grunt
|
|
117
|
+
SoT: `.rulesync/subagents/{orchestrator grunt}.md`
|
|
106
118
|
|
|
107
119
|
Emit: `.claude/` `.grok/` `.agents/` `.gemini/`
|
|
108
120
|
|
|
109
|
-
- **orchestrator**
|
|
110
|
-
- **grunt** —
|
|
111
|
-
- **implementer** — write already-defined solution on allowlisted paths. TDD when spec/plan says tests. Validate + sim after write. Fat dumps via `need:`. Never spawn. Never plan. Id is **implementer** (not Implementor)
|
|
112
|
-
- **thinker** — think/plan/advise/recommend/how/why/explain; unsure→thinker; cheap false+; edge cases. Read-only named-file Read of prompt SSOT; trees/search/exec/web/test → `need:`. Never spawn. No bash. Never implement
|
|
121
|
+
- **orchestrator** — session agent. Tools on. Does the work. en-US unless asked. Concise complete sentences with natural grammar. Skip filler and fluff. Optimal solutions only; rewrite if not. Flag blockers. Do not monkey-patch. Runs `node scripts/grunt-job.mjs` for fat dumps; spawn grunt only when the dump needs judgment.
|
|
122
|
+
- **grunt** — isolation worker. Facts only (≤8 lines, stash receipt when needed).
|
|
113
123
|
|
|
114
|
-
|
|
124
|
+
Fat dumps rewrite to `scripts/grunt-job.mjs` (squeez + stash). Scratch goes in `.tmp/grunt/`. Voice: `.rulesync/reference/output.md`. `GEMINI.md` → `@AGENTS.md`.
|
|
115
125
|
|
|
116
126
|
## Browser
|
|
117
127
|
|
|
118
|
-
Lightpanda-first session CLI: `node scripts/browser.mjs
|
|
128
|
+
Lightpanda-first session CLI: `node scripts/browser.mjs`. Zero MCP. Zero env knobs. The rail swaps to Chromium for `shot`/`pdf`/`trace`, Windows, missing Lightpanda, probe-fail, Chromium-first hosts (figma, Google docs/sheets/slides, Gmail, earth, Amazon), or a blocked/empty/client-rendered snap. Session: `.tmp/grunt/browser/`. Spec: [`.rulesync/reference/browser.md`](.rulesync/reference/browser.md). App e2e uses Playwright. URL-in-a-cite is a cite.
|
|
119
129
|
|
|
120
130
|
`node scripts/browser.mjs doctor` (alias `ensure`) runs the unified doctor (`scripts/doctor.mjs`). Install engines: [Prerequisites](#prerequisites).
|
|
121
131
|
|
|
@@ -123,11 +133,15 @@ Lightpanda-first session CLI: `node scripts/browser.mjs nav|snap|click|fill|shot
|
|
|
123
133
|
|
|
124
134
|
Present under `.claude` / `.rulesync` / `.agents` / `.grok` (`rulesync -f skills` mirrors SSOT):
|
|
125
135
|
|
|
126
|
-
- `browser` `
|
|
136
|
+
- `ask` `auto` `browser` `clasp` `commit` `commit-and-push` (1-release alias → `commit-push`) `commit-push` `commit-push-deploy` `commit-push-release` `explain` `google-workspace` `handoff` `implement-plan` `listen` `pickup` `speak` `tmp` `write-plan`
|
|
137
|
+
|
|
138
|
+
`/auto` (default) keeps going and asks on blockers. `/ask` finishes one step, recaps, then asks. `/auto` returns the session to auto.
|
|
127
139
|
|
|
128
|
-
Reserved names: do not reuse those stems for consumer custom skills. Same name → one SSOT under `.rulesync/skills/<name>/`; re-init force-refresh overwrites grunt-owned names; extras kept; maps `origin` badge ≠ content picker. See `.rulesync/reference/law.md` (flows into INDEX).
|
|
140
|
+
Reserved names: do not reuse those stems for consumer custom skills. Same name → one SSOT under `.rulesync/skills/<name>/`; re-init force-refresh overwrites grunt-owned names; extras kept; maps `origin` badge ≠ content picker. Retired 0.5 names (`parent` `solo` `cascade` plus subagents `implementer` `thinker`) are pruned on init/upgrade. See `.rulesync/reference/law.md` (flows into INDEX).
|
|
129
141
|
|
|
130
|
-
|
|
142
|
+
Size first: `.rulesync/reference/scope.md`. Straight shot → do it. Else that file.
|
|
143
|
+
|
|
144
|
+
`/write-plan` and `/implement-plan` SSOT: `.rulesync/skills/{write-plan,implement-plan}/`; format SSOT `.rulesync/reference/plan-format.md`. `/write-plan` plan-only inspect-pause → `next: /implement-plan {n}`; empty `/implement-plan` resumes unique in-progress or starts unique ready, else lists (need serial); slash `/implement-plan {n}` disk/file. The session agent executes the plan. `/implement-plan` also writes `.tmp/grunt/implementations/` (format `.rulesync/reference/implementation-format.md`): Files / Log / Done for commits. Straight shots skip the journal.
|
|
131
145
|
|
|
132
146
|
## Generate
|
|
133
147
|
|
|
@@ -151,15 +165,32 @@ Emit writes other-CLI trees from `.rulesync` for the **next** process of that CL
|
|
|
151
165
|
- `sync-globals` / `purge-mcps`: dry-run default; `--apply` writes
|
|
152
166
|
- Hosts: grok claude codex gemini antigravity
|
|
153
167
|
|
|
168
|
+
### Secrets (machine)
|
|
169
|
+
|
|
170
|
+
Not git. Not `sync-globals`.
|
|
171
|
+
|
|
172
|
+
First-hand: `npm exec grunt setup` (TTY). Per target: `node scripts/setup.mjs speak|listen|google-workspace|browser`. Spec: `.rulesync/reference/setup.md`.
|
|
173
|
+
|
|
174
|
+
| | where |
|
|
175
|
+
| --- | --- |
|
|
176
|
+
| Speak / listen OpenAI | `OPENAI_API_KEY` or `~/.grunt/speak.json` `openai.apiKey` |
|
|
177
|
+
| Speak ElevenLabs | `ELEVENLABS_API_KEY` or `~/.grunt/speak.json` `elevenlabs.apiKey` |
|
|
178
|
+
| Listen extras | `WHISPER_MODEL` `LISTEN_DEVICE` `LISTEN_STT` `SPEAK_PROVIDER` — optional |
|
|
179
|
+
| Google Workspace | OAuth under `~/.grunt/` |
|
|
180
|
+
|
|
181
|
+
`~/.grunt/speak.json` chmod 600. Env wins over that file. Copy the file or export env on another machine. Doctor reports optional google-workspace / speak / ffmpeg / whisper-cli.
|
|
182
|
+
|
|
183
|
+
`sync-globals` is host CLI globals (MCP and friends), not API keys.
|
|
184
|
+
|
|
154
185
|
## Architecture
|
|
155
186
|
|
|
156
|
-
Protocol picture: one CLI host process,
|
|
187
|
+
Protocol picture: one CLI host process, session orchestrator in that session with tools on, optional grunt isolation sibling, local workspace tools with RTK on Bash stdout only, one vendor Model API outside the host bubble. Not a product walkthrough. `@lovrozagar/grunt` = protocol SoT + CLI (init/generate/check); not a model runtime. Do not paste `.rulesync/reference/cascade.md` here — boxes and edges only.
|
|
157
188
|
|
|
158
189
|
### Containment
|
|
159
190
|
|
|
160
191
|
Draw **one** CLI host bubble. That bubble is **this** session’s CLI: Grok Build, Claude Code, Codex, Gemini CLI, or Antigravity. The CLI **is** the host — not a peer router beside another CLI. Parent lives **inside** that host session. Children spawn **inside the same process**. Other CLIs = emit/config on disk only; no runtime hop; no shared spawn/peek line.
|
|
161
192
|
|
|
162
|
-
User-visible conversation attaches only to the
|
|
193
|
+
User-visible conversation attaches only to the session agent. Children never talk to the user. Children never spawn. The session agent does the work. Spawn grunt only when isolation is cheaper.
|
|
163
194
|
|
|
164
195
|
### Host support (GAP)
|
|
165
196
|
|
|
@@ -180,30 +211,23 @@ Same topology as the session recap; every legal edge labeled.
|
|
|
180
211
|
```
|
|
181
212
|
USER
|
|
182
213
|
│
|
|
183
|
-
│ session in/out (
|
|
214
|
+
│ session in/out (session agent only; tagged recap)
|
|
184
215
|
│ TUI local; completion tokens from Model API (mixed)
|
|
185
216
|
▼
|
|
186
217
|
┌──────────────────────── CLI HOST (this process) ────────────────────────┐
|
|
187
218
|
│ TUI · hooks · emit/generate · RTK PreToolUse · fs workspace │
|
|
188
219
|
│ │
|
|
189
|
-
│
|
|
190
|
-
│ legal spawn
|
|
220
|
+
│ Session orchestrator (tools on; grunt-job first) │
|
|
221
|
+
│ legal spawn type: grunt │
|
|
191
222
|
│ omit model on spawn; FM on agent files picks haiku/sonnet/opus │
|
|
192
223
|
│ vs grok-4.5 / grok-4.6 / etc. │
|
|
193
224
|
│ │
|
|
194
|
-
│ spawn / peek
|
|
225
|
+
│ spawn / peek (optional) │
|
|
195
226
|
│ │ │
|
|
196
227
|
│ ▼ │
|
|
197
|
-
│
|
|
198
|
-
│
|
|
199
|
-
│
|
|
200
|
-
│ │ facts/ │ specified │ plan/deep │ │
|
|
201
|
-
│ │ tools │ writes + TDD │ reason │ │
|
|
202
|
-
│ │ Bash+fs │ Write/Bash/ │ Read / need: │ │
|
|
203
|
-
│ │ web/test │ fs │ no Bash │ │
|
|
204
|
-
│ └─────┬─────┴───────┬───────┴───────┬──────┘ │
|
|
205
|
-
│ │ │ │ │
|
|
206
|
-
│ └──────── tool call ──────────┘ │
|
|
228
|
+
│ grunt sibling (never spawn; facts ≤8 lines) │
|
|
229
|
+
│ │ │
|
|
230
|
+
│ └──────── tool call ──────────┐ │
|
|
207
231
|
│ │ │
|
|
208
232
|
│ ▼ │
|
|
209
233
|
│ host tools (same process) │
|
|
@@ -238,48 +262,36 @@ Same topology as the session recap; every legal edge labeled.
|
|
|
238
262
|
(no fake peeks)
|
|
239
263
|
```
|
|
240
264
|
|
|
241
|
-
### `need:` /
|
|
265
|
+
### `need:` / grunt-job
|
|
242
266
|
|
|
243
|
-
|
|
267
|
+
The session agent runs `node scripts/grunt-job.mjs --job search|exec|slice|fetch|test` for fat dumps. A grunt child that still needs a fat dump **stops** on a `need:` JSON line. SubagentStop intercepts `search|exec|slice|fetch` (cap 4) in-hook. Spawn a grunt **model** only when the dump needs judgment. Grunt does not emit `need:` for its own tool use.
|
|
244
268
|
|
|
245
269
|
```
|
|
246
|
-
|
|
247
|
-
│
|
|
248
|
-
│ stop on JSON only (≤4 jobs/batch)
|
|
249
|
-
▼
|
|
250
|
-
need: [{"job":"search|exec|web|test","query":"..."}]
|
|
251
|
-
│
|
|
252
|
-
│ parent parse-need (or SubagentStop intercept
|
|
253
|
-
│ when every job is search|exec)
|
|
254
|
-
▼
|
|
255
|
-
parallel grunt spawns (same host; not a new CLI)
|
|
270
|
+
session agent
|
|
256
271
|
│
|
|
257
|
-
│
|
|
272
|
+
│ grunt-job first
|
|
258
273
|
▼
|
|
259
|
-
|
|
274
|
+
node scripts/grunt-job.mjs --job search|exec|slice|fetch|test
|
|
260
275
|
│
|
|
261
|
-
│
|
|
262
|
-
│ do not re-send original task; max 3
|
|
276
|
+
│ spawn grunt model only if the dump needs judgment
|
|
263
277
|
▼
|
|
264
|
-
|
|
278
|
+
grunt isolation facts (≤8 lines, optional stash=)
|
|
265
279
|
```
|
|
266
280
|
|
|
267
281
|
### Node table
|
|
268
282
|
|
|
269
283
|
| node | inside host? | local vs AI-server | notes |
|
|
270
284
|
| --- | --- | --- | --- |
|
|
271
|
-
| User | no | mixed | Speaks only to
|
|
272
|
-
| Session in/out / TUI | yes | mixed | TUI is local; recap tokens come from the model. Legal `[role]:`
|
|
285
|
+
| User | no | mixed | Speaks only to the session agent. Never a child edge. |
|
|
286
|
+
| Session in/out / TUI | yes | mixed | TUI is local; recap tokens come from the model. Legal `[role]:` tagged recap. |
|
|
273
287
|
| CLI host process | yes (is the box) | local process | Grok Build / Claude Code / Codex / Gemini / Antigravity. Not a peer of another CLI. |
|
|
274
|
-
|
|
|
275
|
-
| `grunt` sibling | yes | AI-server **turn** | Facts/tools/mechanical write. Never spawn. Never feature solution. |
|
|
276
|
-
|
|
|
277
|
-
|
|
|
278
|
-
|
|
|
279
|
-
| Workspace fs tools | yes | **local** | Read/Grep/Glob/Write (and host aliases). Parent is denied these except documented persist paths / `/solo`. |
|
|
280
|
-
| Bash / `run_terminal_command` | yes | **local** | RTK wraps stdout on PreToolUse. Thinker has no Bash. |
|
|
288
|
+
| Session orchestrator | yes | AI-server **turn** | Does the work. Tools on. grunt-job first. Lives in this session, not a sidecar. |
|
|
289
|
+
| `grunt` sibling | yes | AI-server **turn** | Facts/tools/mechanical write. Never spawn. Never feature solution. Optional. |
|
|
290
|
+
| Host spawn / peek | yes | **local** | `spawn_subagent` / `Agent` and host peek tools. Gemini spawn/peek = GAP; block on return, classify `done`; no fake peeks. Other hosts: spawn is an optimization; grunt-job still runs in-process. |
|
|
291
|
+
| Workspace fs tools | yes | **local** | Read/Grep/Glob/Write (and host aliases). Fat dumps still gate. |
|
|
292
|
+
| Bash / `run_terminal_command` | yes | **local** | RTK wraps stdout on PreToolUse. |
|
|
281
293
|
| RTK | yes | **local** | Bash/shell stdout compression only. Not Read/Grep/Glob/prompts/images. |
|
|
282
|
-
| `scrub-spawn-prompt` / `parse-need` / `grunt-job` | yes | **local** | Hooks and scripts. Isolation
|
|
294
|
+
| `scrub-spawn-prompt` / `parse-need` / `grunt-job` | yes | **local** | Hooks and scripts. Isolation facts are grunt-job output, not a model hop. |
|
|
283
295
|
| emit / generate / init | yes (this repo / install) | **local** | Writes other-CLI configs. Not a runtime line to those CLIs. |
|
|
284
296
|
| WebSearch / web_fetch | tool from host | **remote-not-LLM** | Network search/fetch. Not a second Model API box. Snippet/cite/"what is X"/world fact: grunt `job: web`. Live URL/DOM: grunt browser rail, not this box. |
|
|
285
297
|
| MCP | policy deny | n/a | Denied by policy in-tree. Do not draw as a main path. |
|
|
@@ -293,12 +305,11 @@ Use these labels. Do not revive “prompt input” or “agent to use”.
|
|
|
293
305
|
|
|
294
306
|
| edge | meaning |
|
|
295
307
|
| --- | --- |
|
|
296
|
-
| **session in/out** | User ↔
|
|
297
|
-
| **spawn** |
|
|
298
|
-
| **peek** |
|
|
299
|
-
| **
|
|
300
|
-
| **
|
|
301
|
-
| **verdict:** | Grunt isolation result back onto `resume_from`. `ok\|fail\|empty`. Short facts, not dumps. |
|
|
308
|
+
| **session in/out** | User ↔ session agent only. Children have no user edge. |
|
|
309
|
+
| **spawn** | Session agent → `grunt`. First sentence: `You are grunt subagent.` Omit model. Optional. |
|
|
310
|
+
| **peek** | Session agent reads host status on the child id. Real host fields. `timeout_ms=60000`. GAP hosts: no fake peeks; block on spawn return = `done`. |
|
|
311
|
+
| **need:** | Child stop line: fat dump jobs interceptable as grunt-job. Cap 4 jobs per batch. |
|
|
312
|
+
| **facts** | Grunt isolation result back onto `resume_from`. Sentence plus dash facts, not dumps. |
|
|
302
313
|
| **tool call** | Child (or, illegally if parent, denied) → host tools. |
|
|
303
314
|
| **RTK** | PreToolUse Bash/shell → compressed stdout. No other tools. |
|
|
304
315
|
| **completion** | Parent and children → **one** Model API (this host’s SDK). |
|
|
@@ -307,13 +318,12 @@ Use these labels. Do not revive “prompt input” or “agent to use”.
|
|
|
307
318
|
### What not to draw
|
|
308
319
|
|
|
309
320
|
- A **CLI Provider** box as a peer of the host, or a router that hops between CLIs at runtime
|
|
310
|
-
- **
|
|
311
|
-
- The spelling **Implementor** — id is **implementer**
|
|
321
|
+
- **implementer** or **thinker** siblings — gone in 0.6
|
|
312
322
|
- **Per-agent Model API** boxes — one Model API outside the host, this SDK only
|
|
313
|
-
- **Child → child spawn** — isolation is
|
|
323
|
+
- **Child → child spawn** — isolation is grunt-job or a grunt sibling
|
|
314
324
|
- **MCP** as a happy-path tool rail
|
|
315
325
|
- **RTK** on Read/Grep/Glob/prompts/images
|
|
316
|
-
- **User** arrows into grunt
|
|
326
|
+
- **User** arrows into grunt
|
|
317
327
|
- Gemini **fake peek** loops. GAP: no invented status API; block on return
|
|
318
328
|
|
|
319
329
|
### Emit footnote and Gemini GAP
|
|
@@ -328,17 +338,15 @@ Repo-relative (repository root):
|
|
|
328
338
|
|
|
329
339
|
- `.rulesync/reference/INDEX.md` — aggregate catalog composed from slices (law.md, skills-map.md, refs-map.md). Maps/law = slices for deep dive. Always. Not if-maps-else
|
|
330
340
|
- `.rulesync/reference/law.md` — domain law stub (protocol stays cascade/overview)
|
|
331
|
-
- `.rulesync/reference/cascade.md` — parent-only spawn, peek/kill table, `need:` / `resume_from`, isolation
|
|
341
|
+
- `.rulesync/reference/cascade.md` — parent-only spawn, peek/kill table, `need:` / `resume_from`, isolation facts
|
|
332
342
|
- `.rulesync/reference/rtk.md` — Bash/shell stdout compression
|
|
333
343
|
- `.rulesync/reference/map.md` — cheap outline of protocol, scripts, generated trees
|
|
334
344
|
- `.rulesync/subagents/orchestrator.md`
|
|
335
345
|
- `.rulesync/subagents/grunt.md`
|
|
336
|
-
- `.rulesync/subagents/implementer.md`
|
|
337
|
-
- `.rulesync/subagents/thinker.md`
|
|
338
346
|
|
|
339
347
|
## Layout
|
|
340
348
|
|
|
341
|
-
Published (`package.json` `files`): `bin/grunt.js` `cli` `scripts/check-globals.mjs` `scripts/emit-agent-shell-tools.mjs` `scripts/emit-gemini.mjs` `scripts/guarded-roots.mjs` `scripts/emit-mcp-policy.mjs` `scripts/gate-fat-tools.mjs` `scripts/hooks-union.mjs` `scripts/pipeline.mjs` `scripts/grunt-job.mjs` `scripts/parse-need.mjs` `scripts/persist-handoff.mjs` `scripts/persist-tmp.mjs` `scripts/persist-plan.mjs` `scripts/purge-global-mcps.mjs` `scripts/scrub-spawn-prompt.mjs` `scripts/scrub-text-lib.mjs` `scripts/sync-global-settings.mjs` `scripts/browser.mjs` `scripts/doctor.mjs` `scripts/scrub-text` `.rulesync` `.grok` `.codex` `.claude` `.agents` `AGENTS.md` `CLAUDE.md` `.mcp.json` `README.md` `LICENSE` `CHANGELOG.md`
|
|
349
|
+
Published (`package.json` `files`): `bin/grunt.js` `cli` `scripts/check-globals.mjs` `scripts/emit-agent-shell-tools.mjs` `scripts/emit-gemini.mjs` `scripts/guarded-roots.mjs` `scripts/emit-mcp-policy.mjs` `scripts/gate-fat-tools.mjs` `scripts/hooks-union.mjs` `scripts/pipeline.mjs` `scripts/grunt-job.mjs` `scripts/parse-need.mjs` `scripts/persist-handoff.mjs` `scripts/persist-implementation.mjs` `scripts/persist-tmp.mjs` `scripts/persist-plan.mjs` `scripts/purge-global-mcps.mjs` `scripts/scrub-spawn-prompt.mjs` `scripts/scrub-text-lib.mjs` `scripts/sync-global-settings.mjs` `scripts/browser.mjs` `scripts/speak.mjs` `scripts/listen.mjs` `scripts/google-workspace.mjs` `scripts/setup.mjs` `scripts/doctor.mjs` `scripts/scrub-text` `.rulesync` `.grok` `.codex` `.claude` `.agents` `AGENTS.md` `CLAUDE.md` `.mcp.json` `README.md` `LICENSE` `CHANGELOG.md`
|
|
342
350
|
|
|
343
351
|
No `scripts/*.test.ts` `scripts/fixtures/` `docs/` `coverage/` `vitest.config.ts` in `files`. `cli` dir ships whole (includes `cli/*.test.ts`).
|
|
344
352
|
|
|
@@ -371,10 +379,10 @@ npm i && npm test
|
|
|
371
379
|
|
|
372
380
|
Keep these four flows only:
|
|
373
381
|
|
|
374
|
-
1. “Create me a react weather app” →
|
|
375
|
-
2. “What is 2+2” →
|
|
376
|
-
3. Marvel theatrical next →
|
|
377
|
-
4. `.logs` 3/6/2021 tag `framework bug` → grunt
|
|
382
|
+
1. “Create me a react weather app” → session agent writes (or `/write-plan` then `/implement-plan {n}`) → recap
|
|
383
|
+
2. “What is 2+2” → session agent → recap
|
|
384
|
+
3. Marvel theatrical next → session agent web search → recap
|
|
385
|
+
4. `.logs` 3/6/2021 tag `framework bug` → `grunt-job --job search` → recap
|
|
378
386
|
|
|
379
387
|
## License
|
|
380
388
|
|
package/cli/grunt.mjs
CHANGED
|
@@ -2,7 +2,7 @@ import { execFileSync } from "node:child_process"
|
|
|
2
2
|
import { readFileSync } from "node:fs"
|
|
3
3
|
import path from "node:path"
|
|
4
4
|
import { fileURLToPath } from "node:url"
|
|
5
|
-
import { destAlreadyInited, init, shouldAutoSkipGlobals, toGruntScriptName } from "./init.mjs"
|
|
5
|
+
import { destAlreadyInited, init, RESERVED_SKILLS, shouldAutoSkipGlobals, toGruntScriptName } from "./init.mjs"
|
|
6
6
|
import { confirm, isInteractive, select, spinner } from "./prompt.mjs"
|
|
7
7
|
|
|
8
8
|
const PKG_ROOT = path.join(path.dirname(fileURLToPath(import.meta.url)), "..")
|
|
@@ -18,6 +18,8 @@ Commands:
|
|
|
18
18
|
sync-globals npm run grunt:sync:globals (dry-run; --apply to write)
|
|
19
19
|
purge-mcps npm run grunt:purge:global-mcps (dry-run; --apply to write)
|
|
20
20
|
doctor npm run grunt:doctor
|
|
21
|
+
setup npm run grunt:setup — handheld keys/OAuth (speak, listen, google-workspace, browser)
|
|
22
|
+
upgrade Re-init: copy owned files, prune retired grunt-owned names, print reserved skills
|
|
21
23
|
help Show this help
|
|
22
24
|
version Print package version
|
|
23
25
|
|
|
@@ -36,6 +38,8 @@ const MENU_OPTIONS = [
|
|
|
36
38
|
{ value: "sync-globals", label: "sync-globals" },
|
|
37
39
|
{ value: "purge-mcps", label: "purge-mcps" },
|
|
38
40
|
{ value: "doctor", label: "doctor" },
|
|
41
|
+
{ value: "setup", label: "setup" },
|
|
42
|
+
{ value: "upgrade", label: "upgrade" },
|
|
39
43
|
{ value: "help", label: "help" },
|
|
40
44
|
{ value: "quit", label: "quit" },
|
|
41
45
|
]
|
|
@@ -90,7 +94,7 @@ export function parseArgv(argv) {
|
|
|
90
94
|
}
|
|
91
95
|
positionals.push(a)
|
|
92
96
|
}
|
|
93
|
-
return { cmd: positionals[0], skipGlobals, apply, host, hostError }
|
|
97
|
+
return { cmd: positionals[0], args: positionals.slice(1), skipGlobals, apply, host, hostError }
|
|
94
98
|
}
|
|
95
99
|
|
|
96
100
|
function hostExtra(host) {
|
|
@@ -166,6 +170,18 @@ async function dispatch(cmd, flags, interactive) {
|
|
|
166
170
|
npmRun(toGruntScriptName("doctor"))
|
|
167
171
|
return
|
|
168
172
|
}
|
|
173
|
+
if (cmd === "setup") {
|
|
174
|
+
npmRun(toGruntScriptName("setup"), flags.args)
|
|
175
|
+
return
|
|
176
|
+
}
|
|
177
|
+
if (cmd === "upgrade") {
|
|
178
|
+
await runInit(process.cwd(), {
|
|
179
|
+
skipGlobals: flags.skipGlobals,
|
|
180
|
+
interactive: false,
|
|
181
|
+
})
|
|
182
|
+
process.stdout.write(`reserved: ${RESERVED_SKILLS.join(" ")}\n`)
|
|
183
|
+
return
|
|
184
|
+
}
|
|
169
185
|
process.stdout.write(USAGE)
|
|
170
186
|
process.exitCode = 1
|
|
171
187
|
}
|
package/cli/grunt.test.ts
CHANGED
|
@@ -23,6 +23,7 @@ vi.mock("./init.mjs", () => ({
|
|
|
23
23
|
destAlreadyInited,
|
|
24
24
|
shouldAutoSkipGlobals,
|
|
25
25
|
toGruntScriptName,
|
|
26
|
+
RESERVED_SKILLS: ["browser", "tmp", "write-plan"],
|
|
26
27
|
GRUNT_NPM_PREFIX: "grunt:",
|
|
27
28
|
}));
|
|
28
29
|
vi.mock("node:child_process", () => ({ execFileSync }));
|
|
@@ -47,6 +48,8 @@ Commands:
|
|
|
47
48
|
sync-globals npm run grunt:sync:globals (dry-run; --apply to write)
|
|
48
49
|
purge-mcps npm run grunt:purge:global-mcps (dry-run; --apply to write)
|
|
49
50
|
doctor npm run grunt:doctor
|
|
51
|
+
setup npm run grunt:setup — handheld keys/OAuth (speak, listen, google-workspace, browser)
|
|
52
|
+
upgrade Re-init: copy owned files, prune retired grunt-owned names, print reserved skills
|
|
50
53
|
help Show this help
|
|
51
54
|
version Print package version
|
|
52
55
|
|
|
@@ -254,6 +257,34 @@ describe("start", () => {
|
|
|
254
257
|
});
|
|
255
258
|
});
|
|
256
259
|
|
|
260
|
+
it("setup npm-runs grunt:setup", async () => {
|
|
261
|
+
process.argv = ["node", "grunt", "setup"];
|
|
262
|
+
await start();
|
|
263
|
+
expect(execFileSync).toHaveBeenCalledWith("npm", ["run", "grunt:setup"], {
|
|
264
|
+
cwd: process.cwd(),
|
|
265
|
+
stdio: "inherit",
|
|
266
|
+
});
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
it("setup npm-runs grunt:setup with extra args", async () => {
|
|
270
|
+
process.argv = ["node", "grunt", "setup", "speak", "--skip-verify"];
|
|
271
|
+
await start();
|
|
272
|
+
expect(execFileSync).toHaveBeenCalledWith(
|
|
273
|
+
"npm",
|
|
274
|
+
["run", "grunt:setup", "--", "speak", "--skip-verify"],
|
|
275
|
+
{ cwd: process.cwd(), stdio: "inherit" },
|
|
276
|
+
);
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
it("upgrade runs init and prints reserved", async () => {
|
|
280
|
+
process.argv = ["node", "grunt", "upgrade"];
|
|
281
|
+
await start();
|
|
282
|
+
expect(init).toHaveBeenCalledOnce();
|
|
283
|
+
expect(init).toHaveBeenCalledWith(process.cwd(), { skipGlobals: false });
|
|
284
|
+
expect(chunks.join("")).toBe("reserved: browser tmp write-plan\n");
|
|
285
|
+
expect(select).not.toHaveBeenCalled();
|
|
286
|
+
});
|
|
287
|
+
|
|
257
288
|
it("unknown writes usage and exitCode 1", async () => {
|
|
258
289
|
process.argv = ["node", "grunt", "nope"];
|
|
259
290
|
await start();
|
|
@@ -282,6 +313,8 @@ describe("start", () => {
|
|
|
282
313
|
"sync-globals",
|
|
283
314
|
"purge-mcps",
|
|
284
315
|
"doctor",
|
|
316
|
+
"setup",
|
|
317
|
+
"upgrade",
|
|
285
318
|
"help",
|
|
286
319
|
"quit",
|
|
287
320
|
]);
|
package/cli/init.mjs
CHANGED
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
WORKSPACE_SKILLS_REL,
|
|
7
7
|
findSkillContentConflicts,
|
|
8
8
|
formatSkillConflictWarn,
|
|
9
|
+
listSkillDirNames,
|
|
9
10
|
} from "../scripts/skill-conflicts.mjs"
|
|
10
11
|
|
|
11
12
|
const PKG_ROOT = path.join(path.dirname(fileURLToPath(import.meta.url)), "..")
|
|
@@ -21,9 +22,9 @@ const PRODUCT_SCRIPTS = [
|
|
|
21
22
|
"hooks-union.mjs",
|
|
22
23
|
"pipeline.mjs",
|
|
23
24
|
"grunt-job.mjs",
|
|
24
|
-
"grunt-config.mjs",
|
|
25
25
|
"parse-need.mjs",
|
|
26
26
|
"persist-handoff.mjs",
|
|
27
|
+
"persist-implementation.mjs",
|
|
27
28
|
"persist-tmp.mjs",
|
|
28
29
|
"persist-plan.mjs",
|
|
29
30
|
"purge-global-mcps.mjs",
|
|
@@ -31,12 +32,61 @@ const PRODUCT_SCRIPTS = [
|
|
|
31
32
|
"scrub-text-lib.mjs",
|
|
32
33
|
"sync-global-settings.mjs",
|
|
33
34
|
"browser.mjs",
|
|
35
|
+
"speak.mjs",
|
|
36
|
+
"listen.mjs",
|
|
37
|
+
"google-workspace.mjs",
|
|
38
|
+
"setup.mjs",
|
|
34
39
|
"doctor.mjs",
|
|
35
40
|
"skill-conflicts.mjs",
|
|
36
41
|
"scrub-text",
|
|
37
42
|
]
|
|
38
43
|
|
|
39
44
|
const COPY_DIRS = [".rulesync", ".grok", ".codex", ".claude", ".agents"]
|
|
45
|
+
export const RETIRED_SKILLS = ["parent", "solo", "cascade"]
|
|
46
|
+
export const RETIRED_AGENTS = ["implementer", "thinker"]
|
|
47
|
+
/** Cumulative. Dest `scripts/<name>` deleted on init/upgrade even if no longer shipped. */
|
|
48
|
+
export const RETIRED_SCRIPTS = ["telemetry.mjs", "grunt-config.mjs"]
|
|
49
|
+
/** Repo-relative paths grunt used to ship. Deleted on init/upgrade. Consumer extras elsewhere kept. */
|
|
50
|
+
export const RETIRED_PATHS = [
|
|
51
|
+
".grok/parent.md",
|
|
52
|
+
".grok/skills/shared",
|
|
53
|
+
".rulesync/grunt.config.jsonc",
|
|
54
|
+
".rulesync/grunt.config.local.jsonc",
|
|
55
|
+
".rulesync/grunt.config.local.jsonc.example",
|
|
56
|
+
]
|
|
57
|
+
export const RESERVED_SKILLS = [
|
|
58
|
+
"ask",
|
|
59
|
+
"auto",
|
|
60
|
+
"browser",
|
|
61
|
+
"clasp",
|
|
62
|
+
"commit",
|
|
63
|
+
"commit-and-push",
|
|
64
|
+
"commit-push",
|
|
65
|
+
"commit-push-deploy",
|
|
66
|
+
"commit-push-release",
|
|
67
|
+
"explain",
|
|
68
|
+
"google-workspace",
|
|
69
|
+
"handoff",
|
|
70
|
+
"implement-plan",
|
|
71
|
+
"listen",
|
|
72
|
+
"pickup",
|
|
73
|
+
"speak",
|
|
74
|
+
"tmp",
|
|
75
|
+
"write-plan",
|
|
76
|
+
]
|
|
77
|
+
const SKILL_MIRROR_DIRS = [
|
|
78
|
+
[".rulesync", "skills"],
|
|
79
|
+
[".grok", "skills"],
|
|
80
|
+
[".claude", "skills"],
|
|
81
|
+
[".agents", "skills"],
|
|
82
|
+
]
|
|
83
|
+
const AGENT_MIRROR_DIRS = [
|
|
84
|
+
[".rulesync", "subagents"],
|
|
85
|
+
[".claude", "agents"],
|
|
86
|
+
[".grok", "agents"],
|
|
87
|
+
[".agents", "agents"],
|
|
88
|
+
[".codex", "agents"],
|
|
89
|
+
]
|
|
40
90
|
const GUARDED_MD_FILES = ["AGENTS.md", "CLAUDE.md"]
|
|
41
91
|
export const GUARDED_ROOT_FILES = ["AGENTS.md", "CLAUDE.md", "GEMINI.md"]
|
|
42
92
|
// .mcp.json is intentionally not copied here: scripts/emit-mcp-policy.mjs
|
|
@@ -77,17 +127,58 @@ export function samePath(a, b) {
|
|
|
77
127
|
}
|
|
78
128
|
}
|
|
79
129
|
|
|
130
|
+
const GITIGNORE_ENTRIES = [{ re: /^\.tmp\/?$/, line: ".tmp/" }]
|
|
131
|
+
|
|
132
|
+
function rmQuiet(abs) {
|
|
133
|
+
fs.rmSync(abs, { recursive: true, force: true })
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export function pruneRetired(dest, { pkgRoot } = {}) {
|
|
137
|
+
const root = path.resolve(dest)
|
|
138
|
+
for (const segs of SKILL_MIRROR_DIRS) {
|
|
139
|
+
for (const name of RETIRED_SKILLS) {
|
|
140
|
+
rmQuiet(path.join(root, ...segs, name))
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
if (pkgRoot) {
|
|
144
|
+
const packaged = new Set(
|
|
145
|
+
listSkillDirNames(path.join(path.resolve(pkgRoot), WORKSPACE_SKILLS_REL)),
|
|
146
|
+
)
|
|
147
|
+
for (const segs of SKILL_MIRROR_DIRS) {
|
|
148
|
+
for (const name of RESERVED_SKILLS) {
|
|
149
|
+
if (packaged.has(name)) continue
|
|
150
|
+
rmQuiet(path.join(root, ...segs, name))
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
for (const segs of AGENT_MIRROR_DIRS) {
|
|
155
|
+
for (const name of RETIRED_AGENTS) {
|
|
156
|
+
rmQuiet(path.join(root, ...segs, `${name}.md`))
|
|
157
|
+
rmQuiet(path.join(root, ...segs, `${name}.toml`))
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
for (const name of RETIRED_AGENTS) {
|
|
161
|
+
rmQuiet(path.join(root, ".gemini", "agents", name))
|
|
162
|
+
rmQuiet(path.join(root, ".grok", "roles", `${name}.toml`))
|
|
163
|
+
}
|
|
164
|
+
for (const name of RETIRED_SCRIPTS) {
|
|
165
|
+
rmQuiet(path.join(root, "scripts", name))
|
|
166
|
+
}
|
|
167
|
+
for (const rel of RETIRED_PATHS) {
|
|
168
|
+
rmQuiet(path.join(root, ...rel.split("/")))
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
80
172
|
export function mergeGitignore(dest) {
|
|
81
173
|
const gi = path.join(dest, ".gitignore")
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
fs.appendFileSync(gi, `${prefix}.tmp/\n`)
|
|
174
|
+
const text = fs.existsSync(gi) ? fs.readFileSync(gi, "utf8") : ""
|
|
175
|
+
const present = text.split(/\r?\n/)
|
|
176
|
+
const missing = GITIGNORE_ENTRIES.filter(
|
|
177
|
+
({ re }) => !present.some((line) => re.test(line)),
|
|
178
|
+
).map(({ line }) => line)
|
|
179
|
+
if (missing.length === 0) return
|
|
180
|
+
const prefix = text.length === 0 || text.endsWith("\n") ? "" : "\n"
|
|
181
|
+
fs.writeFileSync(gi, `${text}${prefix}${missing.join("\n")}\n`)
|
|
91
182
|
}
|
|
92
183
|
|
|
93
184
|
function destHasGruntSentinel(dest) {
|
|
@@ -536,6 +627,8 @@ export function init(dest, { pkgRoot: pkgRootOpt, execFileSync: exec = execFileS
|
|
|
536
627
|
}
|
|
537
628
|
}
|
|
538
629
|
|
|
630
|
+
pruneRetired(dest, { pkgRoot })
|
|
631
|
+
|
|
539
632
|
for (const file of GUARDED_MD_FILES) {
|
|
540
633
|
mergeGuardedMarkdown(dest, pkgRoot, file)
|
|
541
634
|
}
|