@lovrozagar/grunt 0.4.2 → 0.5.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/.agents/agents/grunt.md +2 -1
- package/.agents/agents/implementer.md +1 -1
- package/.agents/agents/orchestrator.md +19 -13
- package/.agents/agents/thinker.md +8 -6
- package/.agents/skills/ask/SKILL.md +18 -0
- package/.agents/skills/auto/SKILL.md +18 -0
- package/.agents/skills/browser/SKILL.md +4 -3
- package/.agents/skills/cascade/SKILL.md +5 -3
- package/.agents/skills/commit-and-push/SKILL.md +3 -3
- package/.agents/skills/explain/SKILL.md +1 -0
- package/.agents/skills/handoff/SKILL.md +1 -1
- package/.agents/skills/implement-plan/SKILL.md +117 -0
- package/.agents/skills/solo/SKILL.md +5 -3
- package/.agents/skills/tmp/SKILL.md +58 -0
- package/.agents/skills/write-plan/SKILL.md +85 -0
- package/.claude/agents/grunt.md +2 -1
- package/.claude/agents/implementer.md +1 -1
- package/.claude/agents/orchestrator.md +19 -13
- package/.claude/agents/thinker.md +8 -6
- package/.claude/skills/ask/SKILL.md +18 -0
- package/.claude/skills/auto/SKILL.md +18 -0
- package/.claude/skills/browser/SKILL.md +4 -3
- package/.claude/skills/cascade/SKILL.md +5 -3
- package/.claude/skills/commit-and-push/SKILL.md +3 -3
- package/.claude/skills/explain/SKILL.md +1 -0
- package/.claude/skills/handoff/SKILL.md +1 -1
- package/.claude/skills/implement-plan/SKILL.md +117 -0
- package/.claude/skills/solo/SKILL.md +5 -3
- package/.claude/skills/tmp/SKILL.md +58 -0
- package/.claude/skills/write-plan/SKILL.md +85 -0
- package/.codex/agents/grunt.toml +2 -1
- package/.codex/agents/implementer.toml +1 -1
- package/.codex/agents/orchestrator.toml +19 -13
- package/.codex/agents/thinker.toml +8 -6
- package/.grok/agents/grunt.md +2 -1
- package/.grok/agents/implementer.md +1 -1
- package/.grok/agents/orchestrator.md +19 -13
- package/.grok/agents/thinker.md +8 -6
- package/.grok/hooks/orchestrate-parent.js +280 -62
- package/.grok/skills/ask/SKILL.md +18 -0
- package/.grok/skills/auto/SKILL.md +18 -0
- package/.grok/skills/browser/SKILL.md +4 -3
- package/.grok/skills/cascade/SKILL.md +5 -3
- package/.grok/skills/commit-and-push/SKILL.md +3 -3
- package/.grok/skills/explain/SKILL.md +1 -0
- package/.grok/skills/handoff/SKILL.md +1 -1
- package/.grok/skills/implement-plan/SKILL.md +49 -20
- package/.grok/skills/solo/SKILL.md +5 -3
- package/.grok/skills/tmp/SKILL.md +58 -0
- package/.grok/skills/write-plan/SKILL.md +17 -14
- package/.rulesync/grunt.config.jsonc +7 -0
- package/.rulesync/reference/INDEX.md +46 -0
- package/.rulesync/reference/cascade.md +19 -15
- package/.rulesync/reference/hooks.md +6 -4
- package/.rulesync/reference/law.md +9 -0
- package/.rulesync/reference/map.md +20 -10
- package/.rulesync/reference/output.md +23 -8
- package/{.grok/skills/shared → .rulesync/reference}/plan-format.md +12 -11
- package/.rulesync/reference/refs-map.md +14 -0
- package/.rulesync/reference/skills-map.md +23 -0
- package/.rulesync/rules/CLAUDE.md +22 -15
- package/.rulesync/rules/overview.md +22 -15
- package/.rulesync/skills/ask/SKILL.md +18 -0
- package/.rulesync/skills/auto/SKILL.md +18 -0
- package/.rulesync/skills/browser/SKILL.md +2 -2
- package/.rulesync/skills/cascade/SKILL.md +5 -3
- package/.rulesync/skills/commit-and-push/SKILL.md +3 -3
- package/.rulesync/skills/explain/SKILL.md +1 -0
- package/.rulesync/skills/handoff/SKILL.md +1 -1
- package/.rulesync/skills/implement-plan/SKILL.md +127 -0
- package/.rulesync/skills/solo/SKILL.md +5 -3
- package/.rulesync/skills/tmp/SKILL.md +58 -0
- package/.rulesync/skills/write-plan/SKILL.md +92 -0
- package/.rulesync/subagents/grunt.md +2 -1
- package/.rulesync/subagents/implementer.md +1 -1
- package/.rulesync/subagents/orchestrator.md +19 -13
- package/.rulesync/subagents/thinker.md +8 -6
- package/AGENTS.md +22 -15
- package/CHANGELOG.md +56 -0
- package/CLAUDE.md +22 -15
- package/README.md +27 -22
- package/cli/grunt.mjs +12 -12
- package/cli/grunt.test.ts +29 -20
- package/cli/init.mjs +135 -22
- package/cli/init.test.ts +624 -36
- package/package.json +11 -4
- package/scripts/doctor.mjs +64 -2
- package/scripts/emit-maps.mjs +422 -0
- package/scripts/gate-fat-tools.mjs +2 -2
- package/scripts/grunt-config.mjs +50 -0
- package/scripts/guarded-roots.mjs +4 -7
- package/scripts/persist-plan.mjs +17 -2
- package/scripts/persist-tmp.mjs +123 -0
- package/scripts/pipeline.mjs +67 -0
- package/scripts/scrub-spawn-prompt.mjs +1 -1
- package/scripts/skill-conflicts.mjs +71 -0
package/CLAUDE.md
CHANGED
|
@@ -1,43 +1,50 @@
|
|
|
1
1
|
<!-- grunt:begin -->
|
|
2
2
|
Voice: `.rulesync/reference/output.md` — cite once; apply every turn.
|
|
3
|
-
en-US unless asked. every output maximal superterse. Fragments OK. Sacrifice grammar; keep meaning. Parent and child. Every turn, not final-only. no mid-turn chat; no narration while Agent runs; user-visible = legal `[role]:` + one-line echo. Advise leftover: numbered pick each on own line
|
|
3
|
+
en-US unless asked. every output maximal superterse. Fragments OK. Sacrifice grammar; keep meaning. Parent and child. Every turn, not final-only. no mid-turn chat; no narration while Agent runs; user-visible = legal `[role]:` + one-line echo (thinker recap verbatim-ish; no-strip how/why). Advise leftover: one empty blank line after recap/body then numbered pick each on own line. Zero user-visible tokens before spawn/peek. In-flight host Stop → only `[orchestrator]: wait grunt`.
|
|
4
4
|
All output exclude AI attribution, Co-Authored-By, trailers, generated markers.
|
|
5
5
|
Protocol: `.rulesync/reference/cascade.md`. Do not paste.
|
|
6
|
+
On-demand (feat/domain; never every-turn; parent does not Read): `.rulesync/reference/INDEX.md` — load this then only the matching row. Never load the folder.
|
|
6
7
|
Always-do:
|
|
7
8
|
|
|
8
9
|
| signal | next |
|
|
9
10
|
|---|---|
|
|
10
|
-
| create/change product files | grunt facts → thinker plan/recap-stop before writes; default thinker unless prompt-is-spec or small/simple → implementer. Thinker recap ≠ spec-ready; advise-stop until
|
|
11
|
-
| plan/spec ready + file writes remain |
|
|
11
|
+
| create/change product files | grunt facts → thinker plan/recap-stop before writes; default thinker unless prompt-is-spec or small/simple → implementer. Thinker recap ≠ spec-ready; advise-stop until pick1/pick2 / `/implement-plan {n}` / explicit implement (=pick1 iff Implement-typed). Never parent Write/Bash/Skill |
|
|
12
|
+
| plan/spec ready + file writes remain | leftover pick1/pick2 / `/implement-plan {n}` / explicit implement (=pick1 iff Implement-typed) only. Implement pick1 = spawn implementer + last [thinker] recap as spec; no `.tmp/grunt/plans`; no write-plan; no implement-plan. Implement pick2 = persist `.tmp/grunt/plans/{n}` then implementer `plan=/abs/...` one-shot skip pause. effective=auto + Implement-typed: pick2 chains write-plan persist → implement-plan `{n}`; skip leftover wait. Write pick1 = `/tmp` persist recap; no implementer. Write pick2 = write-plan persist inspect-pause; remainder `/implement-plan {n}`; no implementer. slash `/write-plan` ≠ leftover 2. `ok`/`yes`/`y`/`continue` ≠ either. Thinker recap alone = recap-stop |
|
|
12
13
|
| tools/facts/git/test/mechanical write | spawn grunt |
|
|
14
|
+
| snippet / cite / "what is X" | spawn grunt `job:web`. URL-in-a-cite ≠ browse |
|
|
15
|
+
| URL / browse / click / fill / snap / live DOM | spawn grunt; child prompt must include abs `.rulesync/skills/browser/SKILL.md` and `.rulesync/reference/browser.md`; Read then `node scripts/browser.mjs`; Lightpanda default; never websearch that page |
|
|
13
16
|
| world fact | spawn grunt `job:web` |
|
|
14
17
|
| write defined solution | spawn implementer; **blocked if advise-class stems present** unless prompt-is-spec / obvious comment-spec false+ |
|
|
15
18
|
| think / plan / advise / recommend / how / why / explain (ask us; not slash `/explain` not one-cmd/last-log/source-token) | spawn thinker; facts=grunt/`need:`; **no implementer this turn**. Repeat how/why/… + last [thinker] still visible + no new input/tools since → no spawn; echo last or /explain. Unsure → thinker |
|
|
16
|
-
| child returned | recap per output.md (echo=report not command). e.g. `[orchestrator]: wrote /abs/a` |
|
|
19
|
+
| child returned | recap per output.md (echo=report not command; thinker recap verbatim-ish; no-strip). e.g. `[orchestrator]: wrote /abs/a` |
|
|
17
20
|
| child `need:` | parse-need + parallel grunt; `resume_from` + new verdicts; max 3 |
|
|
18
21
|
| ⚠ / validate / sim | spawn implementer with findings; do not recap; spawn; no parent-edit |
|
|
19
22
|
| work remains | spawn; do not stop. Advise recap ≠ leftover writes |
|
|
20
23
|
| children done + no findings | recap; advise-first stop wins. Else stop only if no writes remain and spawn count > 0 when the user asked for a file change |
|
|
21
24
|
| `/parent` | spawn-first; hook last-ditch `parent-escape`; never Read/Bash |
|
|
22
25
|
| `/handoff` | one-turn write `.tmp/grunt/handoffs/`; recap `[handoff]:` |
|
|
26
|
+
| `/tmp` | one-turn write `.tmp/grunt/`; recap `[tmp]:` |
|
|
23
27
|
| `/pickup` | spawn-first; grunt resolve if needed; never parent Read; not a mode |
|
|
24
|
-
| `/write-plan` plan-only | recap; remainder `/implement-plan` (ask) |
|
|
28
|
+
| `/write-plan` plan-only | recap; remainder `/implement-plan` (ask). effective=auto + Implement-typed → persist then implement-plan `{n}` skip leftover wait; Write-typed still inspect-pause leftover wait |
|
|
25
29
|
| `/explain` | spawn if facts/work; then human recap of child output; screenshot/visible=context no Read |
|
|
26
|
-
| `/solo` | session escape
|
|
27
|
-
| `/cascade` |
|
|
30
|
+
| `/solo` | session escape; stamp spawn-mode-{sid} iff slash≠config; always unlink grunt-off; else spawn-first |
|
|
31
|
+
| `/cascade` | restore cascade; stamp spawn-mode-{sid} iff slash≠config; always unlink grunt-off; spawn-first |
|
|
32
|
+
| `/auto` | session leftover-gate auto; stamp auto-ask-{sid} iff slash≠config; not spawn-escape; not autofix |
|
|
33
|
+
| `/ask` | session leftover-gate ask; stamp auto-ask-{sid} iff slash≠config; not leftover y/n; not pick 3 |
|
|
28
34
|
|
|
29
|
-
Precedence: slash → obvious fact/false+/reuse → advise-class row → prompt-is-spec → write. Advise-class + write-class → thinker first; implementer only after spec / `/implement-plan`.
|
|
35
|
+
Precedence: slash → obvious fact/false+/reuse → advise-class row → prompt-is-spec → write. Advise-class + write-class → thinker first; implementer only after spec / pick1 / pick2 / `/implement-plan {n}`.
|
|
30
36
|
False+: I think terraform plan /implement-plan /solo source tokens one-cmd how- last-log why.
|
|
31
|
-
Advise
|
|
32
|
-
1. Implement
|
|
33
|
-
2.
|
|
34
|
-
|
|
37
|
+
Advise leftover: numbered pick each on own line after tagged recap; one empty blank line immediately before leftover 1. (leftover last; not adjacent to recap/body). Always-print typed leftover triple (advise-class final recap only). One verb per recap; never jammed Implement/write. No leftover on `need:` JSON wait-grunt grunt/implementer recaps slash-only turns.
|
|
38
|
+
1. {Implement|Write} with verbal plan
|
|
39
|
+
2. {same verb} with file plan
|
|
40
|
+
3. Tweak
|
|
41
|
+
Type Implement = in-repo product writes. Type Write = persist-only/implementer-nonsense (SCA/advise-only/`/tmp`/inspect-pause). Recap remainder still names the human gate; leftover is not `4. Contact bank`. `/handoff` stays slash not Write pick1. No omit 1/2. No frozen 4. Do not relabel 3. Parent echoes printed leftover. Match number or full leftover label (or unique tail `verbal plan` / `file plan`). Always-do leftover match printed lines; not Skill-name (`2` ≠ write-plan). Implement pick1 = spawn implementer; paste last [thinker] recap as spec (how+why; implementer must not paste why into code comments); no `.tmp/grunt/plans`; no write-plan; no implement-plan. Implement pick2 = persist `.tmp/grunt/plans/{n}` then spawn implementer `plan=/abs/...` one-shot skip pause. Write pick1 = `/tmp` persist recap/body under `.tmp/grunt/`; no implementer. Write pick2 = write-plan persist inspect-pause; remainder `/implement-plan {n}`; no implementer this turn. 3 / Tweak → stay advise; extra text = revision notes → thinker; bare 3/Tweak = stop wait notes. Bare `implement`/`implementer` → pick1 iff Implement-typed; else recap “no implementer this remainder”; no spawn. Bare `write` → pick1 iff Write-typed; else not a match. Type-mismatch → that recap no spawn. Alias `Implementer with …` → pick1/pick2 iff Implement-typed. `/write-plan` persist-only inspect-pause; remainder `/implement-plan {n}` (ask); ≠ leftover pick 2. `/implement-plan {n}` disk/file ≠ verbal. `ok`/`yes`/`y`/`continue` ≠ either pick.
|
|
35
42
|
Parent = orchestrator (this file). You do not talk. Spawn wait echo.
|
|
36
43
|
Spawn only grunt|implementer|thinker. Never spawn orchestrator. Children never spawn.
|
|
37
|
-
You do not talk. First token = spawn. Illegal tools (never consider never call): Read read_file Grep grep Glob list_dir Bash run_terminal_command view_file grep_search run_command. Not in toolkit. Hook deny = backstop not UX. Next=spawn not retry. Only /solo (stamp
|
|
44
|
+
You do not talk. First token = spawn. Illegal tools (never consider never call): Read read_file Grep grep Glob list_dir Bash run_terminal_command view_file grep_search run_command. Not in toolkit. Hook deny = backstop not UX. Next=spawn not retry. Only /solo (stamp spawn-mode-{sid} iff slash≠config; unlink grunt-off) escapes spawn workflow. /explain=voice+post-child recap never parent Read. No try-then-spawn. No parent probe. After child: legal tag + one-line recap (no-strip; no compress-to-verdict); advise leftover numbered pick on following lines not crammed (echo printed leftover; always-print typed triple). Echo = report not command. Siblings still run: `[grunt]:` echo. No skip-spawn. /handoff = one-turn in-parent write to `.tmp/grunt/handoffs/`; recap `[handoff]:`. `/tmp` = one-turn in-parent write to `.tmp/grunt/`; recap `[tmp]:`. `/pickup` spawn-first; grunt resolve if needed; never parent Read; not a mode.
|
|
38
45
|
`/parent` hook last-ditch only. Skills spawn-first. Only `/solo` escapes spawn workflow.
|
|
39
|
-
grunt ← tools (facts/search/exec/git/web/test/low-reason mechanical write;
|
|
40
|
-
Child prompt first sentence only: `You are {agent} subagent.` Then task + abs paths + verdicts only.
|
|
46
|
+
grunt ← tools (facts/search/exec/git/web/test/low-reason mechanical write; snippet/cite/"what is X": `job: web`; URL/browse/click/fill/snap/live DOM: paste skill+browser.md abs paths, never websearch that page; never memory). implementer ← write defined solution (spec or small/simple); blocked if advise-class stems unless prompt-is-spec/false+. thinker ← think/plan/advise/recommend/how/why/explain (default product change; no implementer this turn).
|
|
47
|
+
Child prompt first sentence only: `You are {agent} subagent.` Then task + abs paths + verdicts only. Browse tags match → prompt must include abs `.rulesync/skills/browser/SKILL.md` and `.rulesync/reference/browser.md`.
|
|
41
48
|
Peek every 60s/child; quote real host fields; `done|alive|stuck`; no invent; no auto-kill. `timeout_ms=60000` every peek. GAP: block on spawn return = `done`. Stuck/blocked: quote host fields only.
|
|
42
49
|
`need:` JSON → parse-need + parallel grunt; one `resume_from` + new verdicts; max 3; no re-send task; no fresh-spawn.
|
|
43
50
|
Child: this file does not apply; your agent file gates you. Never spawn.
|
package/README.md
CHANGED
|
@@ -55,7 +55,7 @@ Exit 1 if any required missing; 0 if all required ok. Optional `gh` reported onl
|
|
|
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
57
|
|
|
58
|
-
Rulesync schema doctor is separate: `npm run rulesync:doctor`.
|
|
58
|
+
Rulesync schema doctor is separate: `npm run grunt:rulesync:doctor`.
|
|
59
59
|
|
|
60
60
|
## Usage
|
|
61
61
|
|
|
@@ -67,12 +67,12 @@ Rulesync schema doctor is separate: `npm run rulesync:doctor`.
|
|
|
67
67
|
|
|
68
68
|
### Commands
|
|
69
69
|
|
|
70
|
-
- `init` → `init()` — merge SoT, `npm install`, `rulesync:generate`, `sync:globals:apply`, `rulesync:check`
|
|
71
|
-
- `generate` → `npm run rulesync:generate`
|
|
72
|
-
- `check` → `npm run rulesync:check`
|
|
73
|
-
- `sync-globals` → `npm run sync:globals` (dry-run); `--apply` → `sync:globals:apply`
|
|
74
|
-
- `purge-mcps` → `npm run purge:global-mcps` (dry-run); `--apply` → `purge:global-mcps:apply`
|
|
75
|
-
- `doctor` → `npm run doctor` (`node scripts/doctor.mjs`). Rulesync schema: `npm run rulesync:doctor`
|
|
70
|
+
- `init` → `init()` — merge SoT, `npm install`, `grunt:rulesync:generate`, `grunt:sync:globals:apply`, `grunt:rulesync:check`
|
|
71
|
+
- `generate` → `npm run grunt:rulesync:generate`
|
|
72
|
+
- `check` → `npm run grunt:rulesync:check`
|
|
73
|
+
- `sync-globals` → `npm run grunt:sync:globals` (dry-run); `--apply` → `grunt:sync:globals:apply`
|
|
74
|
+
- `purge-mcps` → `npm run grunt:purge:global-mcps` (dry-run); `--apply` → `grunt:purge:global-mcps:apply`
|
|
75
|
+
- `doctor` → `npm run grunt:doctor` (`npx grunt doctor` / `node scripts/doctor.mjs` stay). Rulesync schema: `npm run grunt:rulesync:doctor`
|
|
76
76
|
- `help`
|
|
77
77
|
- `version`
|
|
78
78
|
|
|
@@ -85,11 +85,12 @@ Rulesync schema doctor is separate: `npm run rulesync:doctor`.
|
|
|
85
85
|
|
|
86
86
|
## Init
|
|
87
87
|
|
|
88
|
-
- Merge SoT `npm install` `rulesync:generate` `sync:globals:apply` `rulesync:check`
|
|
88
|
+
- Merge SoT `npm install` `grunt:rulesync:generate` `grunt:sync:globals:apply` `grunt:rulesync:check`
|
|
89
89
|
- `--skip-globals` skips apply
|
|
90
90
|
- Re-init auto-skips globals when `<!-- grunt:begin -->` in `AGENTS.md`/`CLAUDE.md`
|
|
91
91
|
- First init (no sentinel) applies globals unless flagged
|
|
92
92
|
- Owned trees/scripts refresh; extra `.rulesync` files kept; patches to grunt-owned files lost
|
|
93
|
+
- 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`).
|
|
93
94
|
|
|
94
95
|
## Version bump
|
|
95
96
|
|
|
@@ -105,8 +106,8 @@ SoT: `.rulesync/subagents/{orchestrator grunt implementer thinker}.md`
|
|
|
105
106
|
|
|
106
107
|
Emit: `.claude/` `.grok/` `.agents/` `.gemini/`
|
|
107
108
|
|
|
108
|
-
- **orchestrator** (parent) — always spawn+prompt; user-facing `[orchestrator]:` (or child role tag) one-line recap; advise leftover numbered pick each on own line after that recap (do not cram `1.
|
|
109
|
-
- **grunt** — tools: facts/search/exec/git/web/test/low-reason mechanical write. Isolation `verdict:`. Never feature solution. Never spawn.
|
|
109
|
+
- **orchestrator** (parent) — always spawn+prompt; user-facing `[orchestrator]:` (or child role tag) one-line recap; advise leftover numbered pick each on own line after that recap; one empty blank line immediately before leftover 1. (leftover last; not adjacent to recap/body) — do not cram `1. Implementer with verbal plan 2. Implementer with file plan 3. Tweak` onto the recap line. `/parent` one-turn; `/handoff` writes `.tmp/grunt/handoffs/{serial}-{slug}-{stamp}.md`; `/tmp` writes `.tmp/grunt/{serial}-{slug}-{stamp}.{ext}`; `/pickup` spawn-first pickup (inverse of `/handoff`; not a mode). `/solo` session escape; `/cascade` restores it. Small/low router. First token spawn. No parent Read/Bash/Grep. Does not implement, plan, or fetch world facts
|
|
110
|
+
- **grunt** — tools: facts/search/exec/git/web/test/low-reason mechanical write. Isolation `verdict:`. Never feature solution. Never spawn. Snippet/cite/"what is X"/world fact: `job: web`. URL/browse/click/fill/snap/live DOM: browser rail (`node scripts/browser.mjs`; Lightpanda default); child prompt includes `.rulesync/skills/browser/SKILL.md` + `.rulesync/reference/browser.md`; never websearch that page. URL-in-a-cite ≠ browse. No `job:browse`; parent does not Skill-invoke `browser`
|
|
110
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)
|
|
111
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
|
|
112
113
|
|
|
@@ -114,22 +115,24 @@ Children never spawn. Spawn only grunt|implementer|thinker. Omit model on spawn;
|
|
|
114
115
|
|
|
115
116
|
## Browser
|
|
116
117
|
|
|
117
|
-
Lightpanda-first session CLI: `node scripts/browser.mjs nav|snap|click|fill|shot|pdf|stop|doctor|ensure`. Zero MCP. Zero env knobs. Chromium only for `shot`/`pdf`/`trace`, Windows, missing Lightpanda, one probe-fail replay, or paint hosts. Session: `.tmp/grunt/browser/`. Spec: [`.rulesync/reference/browser.md`](.rulesync/reference/browser.md).
|
|
118
|
+
Lightpanda-first session CLI: `node scripts/browser.mjs nav|snap|click|fill|shot|pdf|stop|doctor|ensure`. Zero MCP. Zero env knobs. Chromium only for `shot`/`pdf`/`trace`, Windows, missing Lightpanda, one probe-fail replay, or paint hosts. Session: `.tmp/grunt/browser/`. Spec: [`.rulesync/reference/browser.md`](.rulesync/reference/browser.md). Parent routes URL/browse/click/fill/snap/live DOM to grunt (paste skill+browser.md abs paths; never Skill-invoke `browser`; no `job:browse`). URL-in-a-cite ≠ browse.
|
|
118
119
|
|
|
119
120
|
`node scripts/browser.mjs doctor` (alias `ensure`) runs the unified doctor (`scripts/doctor.mjs`). Install engines: [Prerequisites](#prerequisites).
|
|
120
121
|
|
|
121
122
|
## Skills
|
|
122
123
|
|
|
123
|
-
Present under `.claude` / `.rulesync` / `.agents` (`rulesync -f skills` mirrors SSOT):
|
|
124
|
+
Present under `.claude` / `.rulesync` / `.agents` / `.grok` (`rulesync -f skills` mirrors SSOT):
|
|
124
125
|
|
|
125
|
-
- `browser` `cascade` `commit` `commit-and-push` `commit-push` `commit-push-deploy` `commit-push-release` `explain` `handoff` `pickup` `parent` `solo`
|
|
126
|
+
- `browser` `cascade` `commit` `commit-and-push` (1-release alias → `commit-push`) `commit-push` `commit-push-deploy` `commit-push-release` `explain` `handoff` `pickup` `parent` `solo` `tmp` `write-plan` `implement-plan`
|
|
126
127
|
|
|
127
|
-
|
|
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).
|
|
128
129
|
|
|
129
|
-
|
|
130
|
+
`/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); leftover pick **2. Implementer with file plan** = persist then implement one-shot skip pause; leftover pick **1. Implementer with verbal plan** / explicit implement = verbal spec no plan file; slash `/implement-plan {n}` disk/file ≠ verbal; not `ok`/`yes`/`go`
|
|
130
131
|
|
|
131
132
|
## Generate
|
|
132
133
|
|
|
134
|
+
SoT: `.rulesync/skills` + `.rulesync/reference`. Generate maps anything placed there. `.agents` / `.claude` (and other host trees) are mirrors, not SoT; no mirror scan.
|
|
135
|
+
|
|
133
136
|
Pipeline (no `-t geminicli`):
|
|
134
137
|
|
|
135
138
|
1. `rulesync generate` — emit grok / claude / codex / antigravity
|
|
@@ -177,7 +180,7 @@ Same topology as the session recap; every legal edge labeled.
|
|
|
177
180
|
```
|
|
178
181
|
USER
|
|
179
182
|
│
|
|
180
|
-
│ session in/out (parent only; tagged one-line recap; advise leftover 1./2. own lines)
|
|
183
|
+
│ session in/out (parent only; tagged one-line recap; advise leftover blank then 1./2./3. own lines)
|
|
181
184
|
│ TUI local; completion tokens from Model API (mixed)
|
|
182
185
|
▼
|
|
183
186
|
┌──────────────────────── CLI HOST (this process) ────────────────────────┐
|
|
@@ -266,7 +269,7 @@ Implementer or thinker that still needs a fat dump **stops** on a `need:` JSON l
|
|
|
266
269
|
| node | inside host? | local vs AI-server | notes |
|
|
267
270
|
| --- | --- | --- | --- |
|
|
268
271
|
| User | no | mixed | Speaks only to parent session. Never a child edge. |
|
|
269
|
-
| Session in/out / TUI | yes | mixed | TUI is local; recap tokens come from the model. Legal `[role]:` one-line recap; advise leftover numbered pick each on own line after (not crammed onto the recap line). |
|
|
272
|
+
| Session in/out / TUI | yes | mixed | TUI is local; recap tokens come from the model. Legal `[role]:` one-line recap; advise leftover numbered pick each on own line after; one empty blank line immediately before leftover 1. (not crammed onto the recap line). |
|
|
270
273
|
| CLI host process | yes (is the box) | local process | Grok Build / Claude Code / Codex / Gemini / Antigravity. Not a peer of another CLI. |
|
|
271
274
|
| Parent orchestrator | yes | AI-server **turn** | Spawn-first low router. No parent Read/Bash/Grep. Lives in this session, not a sidecar. |
|
|
272
275
|
| `grunt` sibling | yes | AI-server **turn** | Facts/tools/mechanical write. Never spawn. Never feature solution. |
|
|
@@ -278,7 +281,7 @@ Implementer or thinker that still needs a fat dump **stops** on a `need:` JSON l
|
|
|
278
281
|
| RTK | yes | **local** | Bash/shell stdout compression only. Not Read/Grep/Glob/prompts/images. |
|
|
279
282
|
| `scrub-spawn-prompt` / `parse-need` / `grunt-job` | yes | **local** | Hooks and scripts. Isolation `verdict:` is grunt output, not a model hop. |
|
|
280
283
|
| emit / generate / init | yes (this repo / install) | **local** | Writes other-CLI configs. Not a runtime line to those CLIs. |
|
|
281
|
-
| WebSearch / web_fetch | tool from host | **remote-not-LLM** | Network search/fetch. Not a second Model API box.
|
|
284
|
+
| 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. |
|
|
282
285
|
| MCP | policy deny | n/a | Denied by policy in-tree. Do not draw as a main path. |
|
|
283
286
|
| Model API | **no** (one box outside) | AI-server | This host’s vendor SDK only. Parent and child **turns** complete here. Spawn omits model; frontmatter on `.rulesync/subagents/*.md` picks the model. |
|
|
284
287
|
| Other CLIs | no (not this process) | emit/config only | Same protocol files emitted elsewhere. No hop, no shared peek. |
|
|
@@ -323,6 +326,8 @@ Use these labels. Do not revive “prompt input” or “agent to use”.
|
|
|
323
326
|
|
|
324
327
|
Repo-relative (repository root):
|
|
325
328
|
|
|
329
|
+
- `.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
|
+
- `.rulesync/reference/law.md` — domain law stub (protocol stays cascade/overview)
|
|
326
331
|
- `.rulesync/reference/cascade.md` — parent-only spawn, peek/kill table, `need:` / `resume_from`, isolation `verdict:`
|
|
327
332
|
- `.rulesync/reference/rtk.md` — Bash/shell stdout compression
|
|
328
333
|
- `.rulesync/reference/map.md` — cheap outline of protocol, scripts, generated trees
|
|
@@ -333,7 +338,7 @@ Repo-relative (repository root):
|
|
|
333
338
|
|
|
334
339
|
## Layout
|
|
335
340
|
|
|
336
|
-
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/grunt-job.mjs` `scripts/parse-need.mjs` `scripts/persist-handoff.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`
|
|
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`
|
|
337
342
|
|
|
338
343
|
No `scripts/*.test.ts` `scripts/fixtures/` `docs/` `coverage/` `vitest.config.ts` in `files`. `cli` dir ships whole (includes `cli/*.test.ts`).
|
|
339
344
|
|
|
@@ -344,8 +349,8 @@ Repo root (also): `coverage/` `.gemini/` `GEMINI.md` — no `src/` no `CONTRIBUT
|
|
|
344
349
|
- `bin/grunt.js` — CLI bin
|
|
345
350
|
- `cli/grunt.mjs` — commands
|
|
346
351
|
- `scripts/` — init copies product scripts (`grunt-job.mjs` `scrub-text` …). Re-init sentinels: `.grok/hooks/orchestrate-parent.js` `.rulesync` `<!-- grunt:begin -->`
|
|
347
|
-
- `.rulesync/` — SoT (subagents skills reference)
|
|
348
|
-
- `.claude/` `.grok/` `.codex/` `.agents/` `.gemini/` — host emit
|
|
352
|
+
- `.rulesync/` — SoT (subagents skills reference). Skills + reference maps on generate; host trees are mirrors
|
|
353
|
+
- `.claude/` `.grok/` `.codex/` `.agents/` `.gemini/` — host emit; not SoT; no mirror scan
|
|
349
354
|
- `coverage/` — vitest local not published
|
|
350
355
|
|
|
351
356
|
## Develop
|
|
@@ -366,7 +371,7 @@ npm i && npm test
|
|
|
366
371
|
|
|
367
372
|
Keep these four flows only:
|
|
368
373
|
|
|
369
|
-
1. “Create me a react weather app” → thinker plan/recap-stop + pick 1.
|
|
374
|
+
1. “Create me a react weather app” → thinker plan/recap-stop + pick 1.Implementer with verbal plan 2.Implementer with file plan 3.Tweak → user picks 1 (verbal spec) or 2 (file plan one-shot) or `/implement-plan {n}` → implementer write → recap
|
|
370
375
|
2. “What is 2+2” → grunt → `[grunt]:` echo
|
|
371
376
|
3. Marvel theatrical next → grunt `job:web` → recap
|
|
372
377
|
4. `.logs` 3/6/2021 tag `framework bug` → grunt local search → recap
|
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 } from "./init.mjs"
|
|
5
|
+
import { destAlreadyInited, init, 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)), "..")
|
|
@@ -12,12 +12,12 @@ const USAGE = `Usage: grunt [command]
|
|
|
12
12
|
Default (no command): TTY menu; else init — full setup
|
|
13
13
|
|
|
14
14
|
Commands:
|
|
15
|
-
init Full setup: merge SoT, npm install, rulesync:generate, sync:globals:apply, rulesync:check
|
|
16
|
-
generate npm run rulesync:generate
|
|
17
|
-
check npm run rulesync:check
|
|
18
|
-
sync-globals npm run sync:globals (dry-run; --apply to write)
|
|
19
|
-
purge-mcps npm run purge:global-mcps (dry-run; --apply to write)
|
|
20
|
-
doctor npm run doctor
|
|
15
|
+
init Full setup: merge SoT, npm install, grunt:rulesync:generate, grunt:sync:globals:apply, grunt:rulesync:check
|
|
16
|
+
generate npm run grunt:rulesync:generate
|
|
17
|
+
check npm run grunt:rulesync:check
|
|
18
|
+
sync-globals npm run grunt:sync:globals (dry-run; --apply to write)
|
|
19
|
+
purge-mcps npm run grunt:purge:global-mcps (dry-run; --apply to write)
|
|
20
|
+
doctor npm run grunt:doctor
|
|
21
21
|
help Show this help
|
|
22
22
|
version Print package version
|
|
23
23
|
|
|
@@ -146,24 +146,24 @@ async function dispatch(cmd, flags, interactive) {
|
|
|
146
146
|
return
|
|
147
147
|
}
|
|
148
148
|
if (cmd === "generate") {
|
|
149
|
-
npmRun("rulesync:generate")
|
|
149
|
+
npmRun(toGruntScriptName("rulesync:generate"))
|
|
150
150
|
return
|
|
151
151
|
}
|
|
152
152
|
if (cmd === "check") {
|
|
153
|
-
npmRun("rulesync:check")
|
|
153
|
+
npmRun(toGruntScriptName("rulesync:check"))
|
|
154
154
|
return
|
|
155
155
|
}
|
|
156
156
|
if (cmd === "sync-globals") {
|
|
157
|
-
const script = flags.apply ? "sync:globals:apply" : "sync:globals"
|
|
157
|
+
const script = flags.apply ? toGruntScriptName("sync:globals:apply") : toGruntScriptName("sync:globals")
|
|
158
158
|
npmRun(script, hostExtra(flags.host))
|
|
159
159
|
return
|
|
160
160
|
}
|
|
161
161
|
if (cmd === "purge-mcps") {
|
|
162
|
-
npmRun(flags.apply ? "purge:global-mcps:apply" : "purge:global-mcps")
|
|
162
|
+
npmRun(flags.apply ? toGruntScriptName("purge:global-mcps:apply") : toGruntScriptName("purge:global-mcps"))
|
|
163
163
|
return
|
|
164
164
|
}
|
|
165
165
|
if (cmd === "doctor") {
|
|
166
|
-
npmRun("doctor")
|
|
166
|
+
npmRun(toGruntScriptName("doctor"))
|
|
167
167
|
return
|
|
168
168
|
}
|
|
169
169
|
process.stdout.write(USAGE)
|
package/cli/grunt.test.ts
CHANGED
|
@@ -6,6 +6,9 @@ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
|
6
6
|
const init = vi.hoisted(() => vi.fn());
|
|
7
7
|
const destAlreadyInited = vi.hoisted(() => vi.fn(() => false));
|
|
8
8
|
const shouldAutoSkipGlobals = vi.hoisted(() => vi.fn(() => false));
|
|
9
|
+
const toGruntScriptName = vi.hoisted(
|
|
10
|
+
() => (k) => (String(k).startsWith("grunt:") ? k : `grunt:${k}`),
|
|
11
|
+
);
|
|
9
12
|
const execFileSync = vi.hoisted(() => vi.fn());
|
|
10
13
|
const isInteractive = vi.hoisted(() => vi.fn(() => false));
|
|
11
14
|
const select = vi.hoisted(() => vi.fn());
|
|
@@ -15,7 +18,13 @@ const spinner = vi.hoisted(() =>
|
|
|
15
18
|
);
|
|
16
19
|
const bailIfCancel = vi.hoisted(() => vi.fn((v) => v));
|
|
17
20
|
|
|
18
|
-
vi.mock("./init.mjs", () => ({
|
|
21
|
+
vi.mock("./init.mjs", () => ({
|
|
22
|
+
init,
|
|
23
|
+
destAlreadyInited,
|
|
24
|
+
shouldAutoSkipGlobals,
|
|
25
|
+
toGruntScriptName,
|
|
26
|
+
GRUNT_NPM_PREFIX: "grunt:",
|
|
27
|
+
}));
|
|
19
28
|
vi.mock("node:child_process", () => ({ execFileSync }));
|
|
20
29
|
vi.mock("./prompt.mjs", () => ({
|
|
21
30
|
isInteractive,
|
|
@@ -32,12 +41,12 @@ const USAGE = `Usage: grunt [command]
|
|
|
32
41
|
Default (no command): TTY menu; else init — full setup
|
|
33
42
|
|
|
34
43
|
Commands:
|
|
35
|
-
init Full setup: merge SoT, npm install, rulesync:generate, sync:globals:apply, rulesync:check
|
|
36
|
-
generate npm run rulesync:generate
|
|
37
|
-
check npm run rulesync:check
|
|
38
|
-
sync-globals npm run sync:globals (dry-run; --apply to write)
|
|
39
|
-
purge-mcps npm run purge:global-mcps (dry-run; --apply to write)
|
|
40
|
-
doctor npm run doctor
|
|
44
|
+
init Full setup: merge SoT, npm install, grunt:rulesync:generate, grunt:sync:globals:apply, grunt:rulesync:check
|
|
45
|
+
generate npm run grunt:rulesync:generate
|
|
46
|
+
check npm run grunt:rulesync:check
|
|
47
|
+
sync-globals npm run grunt:sync:globals (dry-run; --apply to write)
|
|
48
|
+
purge-mcps npm run grunt:purge:global-mcps (dry-run; --apply to write)
|
|
49
|
+
doctor npm run grunt:doctor
|
|
41
50
|
help Show this help
|
|
42
51
|
version Print package version
|
|
43
52
|
|
|
@@ -148,22 +157,22 @@ describe("start", () => {
|
|
|
148
157
|
},
|
|
149
158
|
);
|
|
150
159
|
|
|
151
|
-
it("generate npm-runs rulesync:generate", async () => {
|
|
160
|
+
it("generate npm-runs grunt:rulesync:generate", async () => {
|
|
152
161
|
process.argv = ["node", "grunt", "generate"];
|
|
153
162
|
await start();
|
|
154
163
|
expect(execFileSync).toHaveBeenCalledOnce();
|
|
155
|
-
expect(execFileSync).toHaveBeenCalledWith("npm", ["run", "rulesync:generate"], {
|
|
164
|
+
expect(execFileSync).toHaveBeenCalledWith("npm", ["run", "grunt:rulesync:generate"], {
|
|
156
165
|
cwd: process.cwd(),
|
|
157
166
|
stdio: "inherit",
|
|
158
167
|
});
|
|
159
168
|
expect(init).not.toHaveBeenCalled();
|
|
160
169
|
});
|
|
161
170
|
|
|
162
|
-
it("check npm-runs rulesync:check", async () => {
|
|
171
|
+
it("check npm-runs grunt:rulesync:check", async () => {
|
|
163
172
|
process.argv = ["node", "grunt", "check"];
|
|
164
173
|
await start();
|
|
165
174
|
expect(execFileSync).toHaveBeenCalledOnce();
|
|
166
|
-
expect(execFileSync).toHaveBeenCalledWith("npm", ["run", "rulesync:check"], {
|
|
175
|
+
expect(execFileSync).toHaveBeenCalledWith("npm", ["run", "grunt:rulesync:check"], {
|
|
167
176
|
cwd: process.cwd(),
|
|
168
177
|
stdio: "inherit",
|
|
169
178
|
});
|
|
@@ -173,7 +182,7 @@ describe("start", () => {
|
|
|
173
182
|
process.argv = ["node", "grunt", "sync-globals", "--yes"];
|
|
174
183
|
await start();
|
|
175
184
|
expect(execFileSync).toHaveBeenCalledOnce();
|
|
176
|
-
expect(execFileSync).toHaveBeenCalledWith("npm", ["run", "sync:globals"], {
|
|
185
|
+
expect(execFileSync).toHaveBeenCalledWith("npm", ["run", "grunt:sync:globals"], {
|
|
177
186
|
cwd: process.cwd(),
|
|
178
187
|
stdio: "inherit",
|
|
179
188
|
});
|
|
@@ -184,7 +193,7 @@ describe("start", () => {
|
|
|
184
193
|
await start();
|
|
185
194
|
expect(execFileSync).toHaveBeenCalledWith(
|
|
186
195
|
"npm",
|
|
187
|
-
["run", "sync:globals", "--", "--host", "grok"],
|
|
196
|
+
["run", "grunt:sync:globals", "--", "--host", "grok"],
|
|
188
197
|
{ cwd: process.cwd(), stdio: "inherit" },
|
|
189
198
|
);
|
|
190
199
|
});
|
|
@@ -194,7 +203,7 @@ describe("start", () => {
|
|
|
194
203
|
await start();
|
|
195
204
|
expect(execFileSync).toHaveBeenCalledWith(
|
|
196
205
|
"npm",
|
|
197
|
-
["run", "sync:globals:apply", "--", "--host", "grok"],
|
|
206
|
+
["run", "grunt:sync:globals:apply", "--", "--host", "grok"],
|
|
198
207
|
{ cwd: process.cwd(), stdio: "inherit" },
|
|
199
208
|
);
|
|
200
209
|
});
|
|
@@ -212,7 +221,7 @@ describe("start", () => {
|
|
|
212
221
|
await start();
|
|
213
222
|
expect(execFileSync).toHaveBeenCalledWith(
|
|
214
223
|
"npm",
|
|
215
|
-
["run", "sync:globals", "--", "--host", "claude"],
|
|
224
|
+
["run", "grunt:sync:globals", "--", "--host", "claude"],
|
|
216
225
|
{ cwd: process.cwd(), stdio: "inherit" },
|
|
217
226
|
);
|
|
218
227
|
});
|
|
@@ -220,7 +229,7 @@ describe("start", () => {
|
|
|
220
229
|
it("purge-mcps dry-run default", async () => {
|
|
221
230
|
process.argv = ["node", "grunt", "purge-mcps"];
|
|
222
231
|
await start();
|
|
223
|
-
expect(execFileSync).toHaveBeenCalledWith("npm", ["run", "purge:global-mcps"], {
|
|
232
|
+
expect(execFileSync).toHaveBeenCalledWith("npm", ["run", "grunt:purge:global-mcps"], {
|
|
224
233
|
cwd: process.cwd(),
|
|
225
234
|
stdio: "inherit",
|
|
226
235
|
});
|
|
@@ -231,15 +240,15 @@ describe("start", () => {
|
|
|
231
240
|
await start();
|
|
232
241
|
expect(execFileSync).toHaveBeenCalledWith(
|
|
233
242
|
"npm",
|
|
234
|
-
["run", "purge:global-mcps:apply"],
|
|
243
|
+
["run", "grunt:purge:global-mcps:apply"],
|
|
235
244
|
{ cwd: process.cwd(), stdio: "inherit" },
|
|
236
245
|
);
|
|
237
246
|
});
|
|
238
247
|
|
|
239
|
-
it("doctor npm-runs doctor", async () => {
|
|
248
|
+
it("doctor npm-runs grunt:doctor", async () => {
|
|
240
249
|
process.argv = ["node", "grunt", "doctor"];
|
|
241
250
|
await start();
|
|
242
|
-
expect(execFileSync).toHaveBeenCalledWith("npm", ["run", "doctor"], {
|
|
251
|
+
expect(execFileSync).toHaveBeenCalledWith("npm", ["run", "grunt:doctor"], {
|
|
243
252
|
cwd: process.cwd(),
|
|
244
253
|
stdio: "inherit",
|
|
245
254
|
});
|
|
@@ -285,7 +294,7 @@ describe("start", () => {
|
|
|
285
294
|
select.mockResolvedValue("generate");
|
|
286
295
|
process.argv = ["node", "grunt"];
|
|
287
296
|
await start();
|
|
288
|
-
expect(execFileSync).toHaveBeenCalledWith("npm", ["run", "rulesync:generate"], {
|
|
297
|
+
expect(execFileSync).toHaveBeenCalledWith("npm", ["run", "grunt:rulesync:generate"], {
|
|
289
298
|
cwd: process.cwd(),
|
|
290
299
|
stdio: "inherit",
|
|
291
300
|
});
|