@lovrozagar/grunt 0.10.0 → 0.11.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/orchestrator.md +1 -1
- package/.agents/hooks.json +2 -2
- package/.agents/skills/browser/SKILL.md +3 -3
- package/.agents/skills/clasp/SKILL.md +1 -1
- package/.agents/skills/explain/SKILL.md +1 -1
- package/.agents/skills/google-workspace/SKILL.md +3 -3
- package/.agents/skills/handoff/SKILL.md +2 -2
- package/.agents/skills/implement-plan/SKILL.md +2 -2
- package/.agents/skills/jev/SKILL.md +3 -3
- package/.agents/skills/listen/SKILL.md +3 -3
- package/.agents/skills/pickup/SKILL.md +1 -1
- package/.agents/skills/speak/SKILL.md +3 -3
- package/.agents/skills/tmp/SKILL.md +2 -2
- package/.agents/skills/write-plan/SKILL.md +4 -2
- package/.claude/agents/orchestrator.md +1 -1
- package/.claude/settings.json +3 -3
- package/.claude/skills/browser/SKILL.md +3 -3
- package/.claude/skills/clasp/SKILL.md +1 -1
- package/.claude/skills/explain/SKILL.md +1 -1
- package/.claude/skills/google-workspace/SKILL.md +3 -3
- package/.claude/skills/handoff/SKILL.md +2 -2
- package/.claude/skills/implement-plan/SKILL.md +2 -2
- package/.claude/skills/jev/SKILL.md +3 -3
- package/.claude/skills/listen/SKILL.md +3 -3
- package/.claude/skills/pickup/SKILL.md +1 -1
- package/.claude/skills/speak/SKILL.md +3 -3
- package/.claude/skills/tmp/SKILL.md +2 -2
- package/.claude/skills/write-plan/SKILL.md +4 -2
- package/.codex/agents/orchestrator.toml +1 -1
- package/.codex/hooks.json +3 -3
- package/.grok/agents/orchestrator.md +1 -1
- package/.grok/hooks/orchestrate-parent.js +9 -9
- package/.grok/skills/browser/SKILL.md +3 -3
- package/.grok/skills/clasp/SKILL.md +1 -1
- package/.grok/skills/explain/SKILL.md +1 -1
- package/.grok/skills/google-workspace/SKILL.md +3 -3
- package/.grok/skills/handoff/SKILL.md +2 -2
- package/.grok/skills/implement-plan/SKILL.md +2 -2
- package/.grok/skills/jev/SKILL.md +3 -3
- package/.grok/skills/listen/SKILL.md +3 -3
- package/.grok/skills/pickup/SKILL.md +1 -1
- package/.grok/skills/speak/SKILL.md +3 -3
- package/.grok/skills/tmp/SKILL.md +2 -2
- package/.grok/skills/write-plan/SKILL.md +4 -2
- package/.rulesync/hooks.jsonc +3 -3
- package/.rulesync/reference/INDEX.md +10 -10
- package/.rulesync/reference/browser.md +4 -4
- package/.rulesync/reference/cascade.md +2 -2
- package/.rulesync/reference/clasp.md +1 -1
- package/.rulesync/reference/google-workspace.md +29 -29
- package/.rulesync/reference/hooks.md +3 -3
- package/.rulesync/reference/implementation-format.md +2 -2
- package/.rulesync/reference/jev.md +3 -3
- package/.rulesync/reference/law.md +1 -1
- package/.rulesync/reference/listen.md +12 -12
- package/.rulesync/reference/map.md +25 -25
- package/.rulesync/reference/output.md +9 -1
- package/.rulesync/reference/refs-map.md +4 -4
- package/.rulesync/reference/rtk.md +1 -1
- package/.rulesync/reference/scope.md +12 -14
- package/.rulesync/reference/setup.md +7 -7
- package/.rulesync/reference/skills-map.md +5 -5
- package/.rulesync/reference/speak.md +6 -6
- package/.rulesync/rules/overview.md +9 -5
- package/{scripts → .rulesync/scripts}/doctor.mjs +2 -2
- package/{scripts → .rulesync/scripts}/feature-packs.mjs +1 -1
- package/{scripts → .rulesync/scripts}/folder-map.mjs +7 -3
- package/{scripts → .rulesync/scripts}/gate-fat-tools.mjs +3 -3
- package/{scripts → .rulesync/scripts}/google-workspace.mjs +2 -2
- package/{scripts → .rulesync/scripts}/grunt-job.mjs +2 -0
- package/{scripts → .rulesync/scripts}/guarded-md.mjs +10 -4
- package/{scripts → .rulesync/scripts}/hooks-union.mjs +13 -8
- package/{scripts → .rulesync/scripts}/jev.mjs +2 -2
- package/{scripts → .rulesync/scripts}/listen.mjs +6 -6
- package/{scripts → .rulesync/scripts}/pipeline.mjs +14 -14
- package/{scripts → .rulesync/scripts}/session-map.mjs +1 -1
- package/{scripts → .rulesync/scripts}/setup.mjs +4 -4
- package/{scripts → .rulesync/scripts}/speak.mjs +4 -4
- package/.rulesync/skills/browser/SKILL.md +3 -3
- package/.rulesync/skills/clasp/SKILL.md +1 -1
- package/.rulesync/skills/explain/SKILL.md +1 -1
- package/.rulesync/skills/google-workspace/SKILL.md +3 -3
- package/.rulesync/skills/handoff/SKILL.md +2 -2
- package/.rulesync/skills/implement-plan/SKILL.md +2 -2
- package/.rulesync/skills/jev/SKILL.md +3 -3
- package/.rulesync/skills/listen/SKILL.md +3 -3
- package/.rulesync/skills/pickup/SKILL.md +1 -1
- package/.rulesync/skills/speak/SKILL.md +3 -3
- package/.rulesync/skills/tmp/SKILL.md +2 -2
- package/.rulesync/skills/write-plan/SKILL.md +4 -2
- package/.rulesync/subagents/orchestrator.md +1 -1
- package/AGENTS.md +11 -5
- package/CHANGELOG.md +22 -0
- package/CLAUDE.md +2 -0
- package/README.md +23 -23
- package/cli/grunt.mjs +3 -3
- package/cli/grunt.test.ts +6 -6
- package/cli/init.mjs +64 -16
- package/cli/init.test.ts +310 -163
- package/cli/prompt.mjs +1 -1
- package/cli/self-update.mjs +1 -1
- package/package.json +15 -50
- /package/{scripts → .rulesync/scripts}/board.mjs +0 -0
- /package/{scripts → .rulesync/scripts}/browser.mjs +0 -0
- /package/{scripts → .rulesync/scripts}/check-globals.mjs +0 -0
- /package/{scripts → .rulesync/scripts}/emit-agent-shell-tools.mjs +0 -0
- /package/{scripts → .rulesync/scripts}/emit-gemini.mjs +0 -0
- /package/{scripts → .rulesync/scripts}/emit-maps.mjs +0 -0
- /package/{scripts → .rulesync/scripts}/emit-mcp-policy.mjs +0 -0
- /package/{scripts → .rulesync/scripts}/guarded-roots.mjs +0 -0
- /package/{scripts → .rulesync/scripts}/interactive.mjs +0 -0
- /package/{scripts → .rulesync/scripts}/jsonc.mjs +0 -0
- /package/{scripts → .rulesync/scripts}/package-manager.mjs +0 -0
- /package/{scripts → .rulesync/scripts}/parse-need.mjs +0 -0
- /package/{scripts → .rulesync/scripts}/persist-handoff.mjs +0 -0
- /package/{scripts → .rulesync/scripts}/persist-implementation.mjs +0 -0
- /package/{scripts → .rulesync/scripts}/persist-plan.mjs +0 -0
- /package/{scripts → .rulesync/scripts}/persist-tmp.mjs +0 -0
- /package/{scripts → .rulesync/scripts}/prompt.mjs +0 -0
- /package/{scripts → .rulesync/scripts}/purge-global-mcps.mjs +0 -0
- /package/{scripts → .rulesync/scripts}/scrub-spawn-prompt.mjs +0 -0
- /package/{scripts → .rulesync/scripts}/scrub-text +0 -0
- /package/{scripts → .rulesync/scripts}/scrub-text-lib.mjs +0 -0
- /package/{scripts → .rulesync/scripts}/skill-conflicts.mjs +0 -0
- /package/{scripts → .rulesync/scripts}/sync-global-settings.mjs +0 -0
|
@@ -5,18 +5,18 @@
|
|
|
5
5
|
| path | title | tags | summary |
|
|
6
6
|
| --- | --- | --- | --- |
|
|
7
7
|
| .rulesync/reference/browser.md | Browser | browser | Zero-config in-tree session rail. Not MCP. Not env. Not raw Playwright. Lightpanda first; swap to Chromium when blocked. |
|
|
8
|
-
| .rulesync/reference/cascade.md | Protocol | cascade | The session agent has tools. Fat Read/Grep/Bash dumps are rewritten to
|
|
8
|
+
| .rulesync/reference/cascade.md | Protocol | cascade | The session agent has tools. Fat Read/Grep/Bash dumps are rewritten to `.rulesync/scripts/grunt-job.mjs` (squeez + stas… |
|
|
9
9
|
| .rulesync/reference/clasp.md | Clasp | clasp | Low-level Apps Script CLI. Optional. Doctor reports it. |
|
|
10
10
|
| .rulesync/reference/google-workspace.md | google-workspace | google-workspace | Create and edit Google Sheets, Docs, Slides, Calendar events, and Gmail from the session. |
|
|
11
|
-
| .rulesync/reference/hooks.md | Hooks | hooks | SessionStart carries only the folder map: Claude / Codex run
|
|
11
|
+
| .rulesync/reference/hooks.md | Hooks | hooks | SessionStart carries only the folder map: Claude / Codex run `../../.rulesync/scripts/session-map.mjs`, which injects t… |
|
|
12
12
|
| .rulesync/reference/implementation-format.md | Implementation format (SSOT) | | Local session journal for `/implement-plan`. Not a plan, handoff, or git commit. |
|
|
13
13
|
| .rulesync/reference/jev.md | Jev | jev | Closed external decision. The source text is already saved. The question is a yes/no or a named choice. One call. Not o… |
|
|
14
14
|
| .rulesync/reference/law.md | Law | | Protocol stays overview; domain fills this. |
|
|
15
15
|
| .rulesync/reference/listen.md | Listen | listen | Speech-to-text from the session. Input only. Not TTS. Not a live voice agent. Not MCP. |
|
|
16
16
|
| .rulesync/reference/map.md | Map | map | Cheap outline. Not a file dump. |
|
|
17
|
-
| .rulesync/reference/output.md | Output | output | en-US unless asked. Concise complete sentences with natural grammar. Skip filler and fluff. |
|
|
17
|
+
| .rulesync/reference/output.md | Output | output | en-US unless asked. Concise complete sentences with natural grammar. Skip filler and fluff. Examples are a class. |
|
|
18
18
|
| .rulesync/reference/plan-format.md | Plan format (SSOT) | | Local session checklist. Not a design doc, PR stack, or DAG. |
|
|
19
19
|
| .rulesync/reference/rtk.md | RTK | rtk | Shell stdout compression. PreToolUse: Bash → `rtk <cmd>`. Not Read/Grep/Glob/prompts/images. |
|
|
20
|
-
| .rulesync/reference/scope.md | Scope | scope |
|
|
20
|
+
| .rulesync/reference/scope.md | Scope | scope | Plan by default. A straight shot is the exception. The plan caps the result, so its depth scales with the work. This fi… |
|
|
21
21
|
| .rulesync/reference/setup.md | Setup | setup | Handheld machine setup for optional integrations. Any OS. Secrets stay in `~/.grunt/` (Windows `%USERPROFILE%\.grunt`).… |
|
|
22
22
|
| .rulesync/reference/speak.md | Speak | speak | Text-to-speech from the session. Output only. Not STT. Not a mic. Not MCP. Speech-to-text is `/listen`: `.rulesync/refe… |
|
|
@@ -24,4 +24,4 @@ Flags: `-v`/`-vv`/`-vvv` · `--ultra-compact` · `--skip-env` · `-h` · `-V`
|
|
|
24
24
|
Unknown cmds passthrough. `rtk run` unfiltered.
|
|
25
25
|
|
|
26
26
|
**playwright:** test-runner family only — not the browser rail.
|
|
27
|
-
**lightpanda:** browser-rail CDP via
|
|
27
|
+
**lightpanda:** browser-rail CDP via `.rulesync/scripts/browser.mjs` (not MCP, not env).
|
|
@@ -4,34 +4,32 @@ tags: [scope]
|
|
|
4
4
|
|
|
5
5
|
# Scope
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Plan by default. A straight shot is the exception. The plan caps the result, so its depth scales with the work. This file is the size-gate SSOT.
|
|
8
8
|
|
|
9
9
|
## Gate
|
|
10
10
|
|
|
11
|
-
Straight shot: one obvious
|
|
11
|
+
Straight shot: one file, one obvious edit, nothing to decide. Do it. Also skip planning for questions, lookups, commits, a follow-up inside an approved plan, and an explicit "just do it".
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
Plan: two or more files, two or more items in the message, two or more valid approaches, cross-cutting or hard-to-undo work, or the user asked to plan. A named goal is not a named edit.
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
`/ask` is not this loop. `/ask` pauses after each execution step. This loop pauses until the approach is agreed. `/auto` already treats a real choice as a blocker; "which approach?" is that blocker.
|
|
15
|
+
`/ask` is not this loop. `/ask` pauses after each execution step. This loop pauses on questions and on the plan. `/auto` continues after approval; it does not skip approval.
|
|
18
16
|
|
|
19
17
|
## Research
|
|
20
18
|
|
|
21
|
-
Read and search until
|
|
19
|
+
Read and search until every leaf is defensible and needs no re-planning. Depth scales with stakes and ambiguity: a clear task needs enough to write the leaves; an unclear, cross-cutting, or hard-to-undo one needs the alternatives checked against the code, docs, and data. Fat notes go under `.tmp/grunt/`.
|
|
22
20
|
|
|
23
|
-
##
|
|
21
|
+
## Questions
|
|
24
22
|
|
|
25
|
-
|
|
23
|
+
Ask only what research cannot settle and what changes the plan's shape: intent, scope, a trade-off the user owns. Batch them into one round, each with your recommendation. Research again on each answer, and ask again only if a new plan-shaping gap appears. When research settles everything, skip this step and write the plan in one shot.
|
|
26
24
|
|
|
27
|
-
##
|
|
25
|
+
## Plan
|
|
28
26
|
|
|
29
|
-
|
|
27
|
+
`/write-plan`. Format: `.rulesync/reference/plan-format.md`. The plan is the proposal: the chosen approach and its rejected alternative sit in Context or Constraints. A minor open choice is written as the default plus "confirm"; a plan-shaping one goes back to Questions. Report the goal, phases, top risks, open assumptions, and path, then stop for approval.
|
|
30
28
|
|
|
31
|
-
##
|
|
29
|
+
## Approval
|
|
32
30
|
|
|
33
|
-
|
|
31
|
+
Feedback revises the same plan file; research again if needed. Stop again until the user approves. Approval is the user saying go, or an explicit "plan and do it" in the request.
|
|
34
32
|
|
|
35
33
|
## Implement
|
|
36
34
|
|
|
37
|
-
`/implement-plan`
|
|
35
|
+
`/implement-plan` after approval, in the same turn only on an explicit "plan and do it". Skip `[x]`. Write-allowlist = paths listed in the plan. Do not skip test leaves. Journal: `.rulesync/reference/implementation-format.md` under `.tmp/grunt/implementations/` (create on start; not for straight shots). Straight-shot behavior change: run the nearest existing test if the repo has one. Bugfix: repro first. Do not scaffold a test file on a straight shot unless it is a bug.
|
|
@@ -8,15 +8,15 @@ Handheld machine setup for optional integrations. Any OS. Secrets stay in `~/.gr
|
|
|
8
8
|
|
|
9
9
|
```
|
|
10
10
|
npm exec grunt setup
|
|
11
|
-
node scripts/setup.mjs
|
|
12
|
-
node scripts/setup.mjs speak
|
|
13
|
-
node scripts/setup.mjs listen
|
|
14
|
-
node scripts/setup.mjs google-workspace
|
|
15
|
-
node scripts/setup.mjs browser
|
|
16
|
-
node scripts/setup.mjs jev
|
|
11
|
+
node .rulesync/scripts/setup.mjs
|
|
12
|
+
node .rulesync/scripts/setup.mjs speak
|
|
13
|
+
node .rulesync/scripts/setup.mjs listen
|
|
14
|
+
node .rulesync/scripts/setup.mjs google-workspace
|
|
15
|
+
node .rulesync/scripts/setup.mjs browser
|
|
16
|
+
node .rulesync/scripts/setup.mjs jev
|
|
17
17
|
```
|
|
18
18
|
|
|
19
|
-
TTY: menu with ok/missing. The menu lists enabled packs and always lists browser and jev. A pack is enabled when `.rulesync/grunt.features.jsonc` names it. `node scripts/setup.mjs <pack>` when that pack is off prints how to enable it (`grunt init` or `grunt upgrade`) and exits 1. Already ok asks redo (`--redo` skips the ask). Missing bins: print the OS command (never run it), then re-check PATH. Ends with one status line per listed target. Non-TTY needs flags (keys / `--creds`). Doctor never installs bins; setup never installs bins either.
|
|
19
|
+
TTY: menu with ok/missing. The menu lists enabled packs and always lists browser and jev. A pack is enabled when `.rulesync/grunt.features.jsonc` names it. `node .rulesync/scripts/setup.mjs <pack>` when that pack is off prints how to enable it (`grunt init` or `grunt upgrade`) and exits 1. Already ok asks redo (`--redo` skips the ask). Missing bins: print the OS command (never run it), then re-check PATH. Ends with one status line per listed target. Non-TTY needs flags (keys / `--creds`). Doctor never installs bins; setup never installs bins either.
|
|
20
20
|
|
|
21
21
|
| target | what it writes | flags |
|
|
22
22
|
| --- | --- | --- |
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
| --- | --- | --- | --- | --- | --- |
|
|
7
7
|
| ask | local | Session flag. Finish one step, recap, then ask before the next. | | | |
|
|
8
8
|
| auto | local | Session flag. Default. Work the task through. Ask on blockers instead of monkey-patching. | | | |
|
|
9
|
-
| browser | local | Browse via node scripts/browser.mjs (Lightpanda). App e2e uses Playwright. | | | |
|
|
9
|
+
| browser | local | Browse via node .rulesync/scripts/browser.mjs (Lightpanda). App e2e uses Playwright. | | | |
|
|
10
10
|
| clasp | local | Low-level Apps Script CLI. Prefer /google-workspace for sheet, doc, meeting, mail. | | | |
|
|
11
11
|
| commit | local | Inspect the diff and commit with a Conventional Commits subject line. Use for /commit, "commit this", "commit these cha… | | | |
|
|
12
12
|
| commit-and-push | local | Alias of commit-push (1-release stub). Use for /commit-and-push, "commit and push", "commit this and push". Must push.… | | | |
|
|
@@ -14,13 +14,13 @@
|
|
|
14
14
|
| commit-push-deploy | local | Commit, push, then deploy only if allowlisted infra already exists. Use for /commit-push-deploy, "commit push deploy",… | | | |
|
|
15
15
|
| commit-push-release | local | Commit, push, bump package.json, tag vX.Y.Z, push the tag. CI publishes. Use for /commit-push-release, "commit push rel… | | | |
|
|
16
16
|
| explain | local | Longer human recap this reply only. | | | |
|
|
17
|
-
| google-workspace | local | Google Sheets, Docs, Slides, Calendar, Gmail via node scripts/google-workspace.mjs. | | | |
|
|
17
|
+
| google-workspace | local | Google Sheets, Docs, Slides, Calendar, Gmail via node .rulesync/scripts/google-workspace.mjs. | | | |
|
|
18
18
|
| handoff | local | Write a session handoff under .tmp/grunt/handoffs/. Continue with /pickup. | | | |
|
|
19
19
|
| implement-plan | local | Execute remaining leaves in a .tmp/grunt/plans checklist. Skip [x]. | | | |
|
|
20
|
-
| jev | local | Yes/no or named-option decision on text already saved. Run node scripts/jev.mjs --available first. On yes,
|
|
21
|
-
| listen | local | Speech-to-text via node scripts/listen.mjs (ffmpeg mic + local whisper.cpp, OpenAI fallback). Input only. | | | |
|
|
20
|
+
| jev | local | Yes/no or named-option decision on text already saved. Run node .rulesync/scripts/jev.mjs --available first. On yes, on… | | | |
|
|
21
|
+
| listen | local | Speech-to-text via node .rulesync/scripts/listen.mjs (ffmpeg mic + local whisper.cpp, OpenAI fallback). Input only. | | | |
|
|
22
22
|
| pickup | local | Continue a handoff under .tmp/grunt/handoffs/. | | | |
|
|
23
|
-
| speak | local | Text-to-speech via node scripts/speak.mjs (ElevenLabs or OpenAI). Output only. | | | |
|
|
23
|
+
| speak | local | Text-to-speech via node .rulesync/scripts/speak.mjs (ElevenLabs or OpenAI). Output only. | | | |
|
|
24
24
|
| su | local | Short status update: done, next, and blockers or on-track ETA. | | | |
|
|
25
25
|
| tmp | local | Dump a one-off convo artifact under .tmp/grunt/. | | | |
|
|
26
26
|
| write-plan | local | Write a local checklist under .tmp/grunt/plans/. Then /implement-plan {n}. | | | |
|
|
@@ -4,21 +4,21 @@ tags: [speak]
|
|
|
4
4
|
|
|
5
5
|
# Speak
|
|
6
6
|
|
|
7
|
-
Text-to-speech from the session. Output only. Not STT. Not a mic. Not MCP. Speech-to-text is `/listen`: `.rulesync/reference/listen.md` and `node scripts/listen.mjs`.
|
|
7
|
+
Text-to-speech from the session. Output only. Not STT. Not a mic. Not MCP. Speech-to-text is `/listen`: `.rulesync/reference/listen.md` and `node .rulesync/scripts/listen.mjs`.
|
|
8
8
|
|
|
9
9
|
```
|
|
10
|
-
node scripts/speak.mjs whoami
|
|
11
|
-
node scripts/speak.mjs voices [--provider elevenlabs|openai]
|
|
12
|
-
node scripts/speak.mjs say --text "hello" [--provider elevenlabs|openai] [--voice ID] [--out path] [--play]
|
|
10
|
+
node .rulesync/scripts/speak.mjs whoami
|
|
11
|
+
node .rulesync/scripts/speak.mjs voices [--provider elevenlabs|openai]
|
|
12
|
+
node .rulesync/scripts/speak.mjs say --text "hello" [--provider elevenlabs|openai] [--voice ID] [--out path] [--play]
|
|
13
13
|
```
|
|
14
14
|
|
|
15
15
|
`say` writes an mp3 under `.tmp/grunt/speak/` (or `--out`) and prints the path. `--play` is local `afplay` (mac) or `ffplay`.
|
|
16
16
|
|
|
17
17
|
## Auth
|
|
18
18
|
|
|
19
|
-
Handheld (any OS): `node scripts/setup.mjs speak` or `npm exec grunt setup` → speak. Opens the key page, hides the paste, writes `~/.grunt/speak.json`, verifies. Non-TTY: `--elevenlabs-key` / `--openai-key`.
|
|
19
|
+
Handheld (any OS): `node .rulesync/scripts/setup.mjs speak` or `npm exec grunt setup` → speak. Opens the key page, hides the paste, writes `~/.grunt/speak.json`, verifies. Non-TTY: `--elevenlabs-key` / `--openai-key`.
|
|
20
20
|
|
|
21
|
-
If a key is missing or rejected, the CLI prints `setup: node scripts/setup.mjs speak` and exits 1. Agents should show that line, not a stack or JSON. Do not invent a key.
|
|
21
|
+
If a key is missing or rejected, the CLI prints `setup: node .rulesync/scripts/setup.mjs speak` and exits 1. Agents should show that line, not a stack or JSON. Do not invent a key.
|
|
22
22
|
|
|
23
23
|
One key is enough. Never commit it.
|
|
24
24
|
|
|
@@ -8,16 +8,20 @@ targets:
|
|
|
8
8
|
globs:
|
|
9
9
|
- "**/*"
|
|
10
10
|
---
|
|
11
|
-
You are the session agent. Do the work. Use en-US unless asked. Write concise complete sentences with natural grammar. Skip filler and fluff. Ship optimal solutions only; rewrite if not. Flag blockers. Do not monkey-patch. When advising, recommend the optimal choice based on research, data, and reasoning, not the user's preference. Change it only for new evidence or a flaw found in it. Pushback or a leading question is not a reason to switch; keep the recommendation and explain why. Do and verify the work yourself with every tool and credential you have. Don't guess, say "likely" or similar, trust older memory, stop short, leave placeholders, or hand the user anything you could do. Ask only when you truly lack the means, and say what you tried. Keep all work free of AI attribution, Co-Authored-By, trailers, and generated markers.
|
|
11
|
+
You are the session agent. Do the work. Use en-US unless asked. Write concise complete sentences with natural grammar. Skip filler and fluff. Ship optimal solutions only; rewrite if not. Flag blockers. Do not monkey-patch. When advising, recommend the optimal choice based on research, data, and reasoning, not the user's preference. Change it only for new evidence or a flaw found in it. Pushback or a leading question is not a reason to switch; keep the recommendation and explain why. Do and verify the work yourself with every tool and credential you have. Don't guess, say "likely" or similar, trust older memory, stop short, leave placeholders, or hand the user anything you could do. Stopping for approval of a written plan is not stopping short. Ask only when you truly lack the means (the user's intent and preferences count), and say what you tried. Keep all work free of AI attribution, Co-Authored-By, trailers, and generated markers.
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
Examples are a class. `...`, `etc` / etcetera, and a `;` between specimens are that same class. An example, an open list, or a negative example means infer the class and do what reasonably fits this case, including what they did not name. Do not copy the example's words, stop at the named items, or add work outside the class. In a plan or a spawn prompt, pass the class. A `;` in code or an ordinary clause is not that cue. Closed instructions stay literal. Detail: `.rulesync/reference/output.md`.
|
|
14
|
+
|
|
15
|
+
A question or a work result opens with the verdict, the counts, or the outcome, failures included. The middle is the concise explanation. The last line lands those same facts as the decision or the one real next step. Do not invent a question or change the numbers. Skip this shape for a one-line answer, a raw artifact, or a reply a skill already shapes.
|
|
16
|
+
|
|
17
|
+
Plan first. A straight shot is one file, one obvious edit, and nothing to decide: do it. Anything else: the plan caps the result, so research until every leaf is defensible, ask what only the user can answer, and research again on each answer. A clear task gets one plan; an unclear one gets rounds. Then `/write-plan`, stop for approval, revise on feedback, and `/implement-plan`. Detail: `.rulesync/reference/scope.md`.
|
|
14
18
|
Default `/auto`: keep going; ask on blockers. `/ask`: one step, then ask.
|
|
15
19
|
Ask before destructive git (stash, reset, checkout, restore, clean, rebase, push -f); others share the tree. In a loop, skip it and edit code instead.
|
|
16
20
|
|
|
17
21
|
Read `.rulesync/reference/INDEX.md` once. When a row matches the work, read that reference in full.
|
|
18
|
-
To learn the repo layout, use the folder map if it is in your context. If it is missing, or you need more depth, run `node scripts/folder-map.mjs [dir]` instead of exploring with `ls` or `find`.
|
|
22
|
+
To learn the repo layout, use the folder map if it is in your context. If it is missing, or you need more depth, run `node .rulesync/scripts/folder-map.mjs [dir]` instead of exploring with `ls` or `find`.
|
|
19
23
|
|
|
20
24
|
Large dumps are compressed (search, test logs, snaps). Scratch and dumps live in `.tmp/grunt/` (gitignored). After a write, recap the path; edit with an offset slice when you need lines.
|
|
21
|
-
Fat dumps: `node scripts/grunt-job.mjs --job search|exec|slice|fetch|test` first; spawn grunt only when the dump needs judgment.
|
|
25
|
+
Fat dumps: `node .rulesync/scripts/grunt-job.mjs --job search|exec|slice|fetch|test` first; spawn grunt only when the dump needs judgment.
|
|
22
26
|
|
|
23
|
-
Browse with `node scripts/browser.mjs`. Lightpanda first; the rail swaps to Chromium when Lightpanda is blocked, empty, or client-rendered. Do not stop and say you cannot. App e2e is `playwright test`.
|
|
27
|
+
Browse with `node .rulesync/scripts/browser.mjs`. Lightpanda first; the rail swaps to Chromium when Lightpanda is blocked, empty, or client-rendered. Do not stop and say you cannot. App e2e is `playwright test`.
|
|
@@ -469,9 +469,9 @@ export function runDoctor({
|
|
|
469
469
|
return { code: missingRequired.length || missingMaps.length ? 1 : 0, stdout, stderr: "" };
|
|
470
470
|
}
|
|
471
471
|
|
|
472
|
-
/** Load
|
|
472
|
+
/** Load the consumer's root `scripts/lib/env.mjs` `loadEnv` when it exists (this script is `.rulesync/scripts/doctor.mjs`). */
|
|
473
473
|
export async function loadOptionalConsumerEnv(baseHref = import.meta.url) {
|
|
474
|
-
const file = fileURLToPath(new URL("
|
|
474
|
+
const file = fileURLToPath(new URL("../../scripts/lib/env.mjs", baseHref));
|
|
475
475
|
if (!fs.existsSync(file)) return false;
|
|
476
476
|
const { loadEnv } = await import(pathToFileURL(file).href);
|
|
477
477
|
if (typeof loadEnv === "function") loadEnv();
|
|
@@ -107,7 +107,7 @@ export function unselectedPackRels(selected) {
|
|
|
107
107
|
if (on.has(pack.name)) continue;
|
|
108
108
|
for (const dir of SKILL_DIRS) rels.push(`${dir}/${pack.skill}`);
|
|
109
109
|
if (pack.ref) rels.push(`.rulesync/reference/${pack.ref}`);
|
|
110
|
-
if (pack.script) rels.push(
|
|
110
|
+
if (pack.script) rels.push(`.rulesync/scripts/${pack.script}`);
|
|
111
111
|
}
|
|
112
112
|
return rels;
|
|
113
113
|
}
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* Depth is uniform per package: the deepest level that fits the size limit;
|
|
10
10
|
* deeper folders end in `…`.
|
|
11
11
|
*
|
|
12
|
-
* node scripts/folder-map.mjs [dir]
|
|
12
|
+
* node .rulesync/scripts/folder-map.mjs [dir]
|
|
13
13
|
*/
|
|
14
14
|
import { spawnSync } from "node:child_process";
|
|
15
15
|
import fs from "node:fs";
|
|
@@ -32,6 +32,8 @@ export const DEFAULTS = Object.freeze({
|
|
|
32
32
|
});
|
|
33
33
|
|
|
34
34
|
export const CONFIG_REL = ".rulesync/grunt.map.jsonc";
|
|
35
|
+
/** Grunt's product scripts run in every repo; map them despite the dot segment. */
|
|
36
|
+
const DOT_CODE_DIRS = [".rulesync/scripts"];
|
|
35
37
|
const MANIFESTS = ["package.json", "go.mod", "Cargo.toml", "pyproject.toml"];
|
|
36
38
|
|
|
37
39
|
/** DEFAULTS merged with known keys from CONFIG_REL; bad file → defaults + warn. */
|
|
@@ -133,7 +135,9 @@ export function buildTree(root, files, opts = {}) {
|
|
|
133
135
|
const segs = dir.split("/");
|
|
134
136
|
if (!forced) {
|
|
135
137
|
if (!code.test(f)) continue;
|
|
136
|
-
|
|
138
|
+
const under = DOT_CODE_DIRS.find((d) => dir === d || dir.startsWith(`${d}/`));
|
|
139
|
+
const checked = under ? segs.slice(under.split("/").length) : segs;
|
|
140
|
+
if (checked.some((s) => s.startsWith(".") || skip.has(s))) continue;
|
|
137
141
|
}
|
|
138
142
|
let node = top;
|
|
139
143
|
for (const s of segs) {
|
|
@@ -254,7 +258,7 @@ export function folderMap({ root, dir = "", ...opts } = {}) {
|
|
|
254
258
|
return { text, rows: lines.length, tokens: tokens(text), depth };
|
|
255
259
|
}
|
|
256
260
|
|
|
257
|
-
/** Text for `grunt map [dir]` / `node scripts/folder-map.mjs [dir]` run from `cwd`. */
|
|
261
|
+
/** Text for `grunt map [dir]` / `node .rulesync/scripts/folder-map.mjs [dir]` run from `cwd`. */
|
|
258
262
|
export function mapCommand(cwd, dir = "") {
|
|
259
263
|
const out = folderMap({ root: cwd, dir });
|
|
260
264
|
if (!out) return "grunt map: not a git repository\n";
|
|
@@ -348,7 +348,7 @@ export function quoteQuery(q) {
|
|
|
348
348
|
}
|
|
349
349
|
|
|
350
350
|
export function gruntJobCommand(workspaceRoot, args) {
|
|
351
|
-
const script = path.join(workspaceRoot, "scripts", "grunt-job.mjs");
|
|
351
|
+
const script = path.join(workspaceRoot, ".rulesync", "scripts", "grunt-job.mjs");
|
|
352
352
|
return `node ${script} ${args}`;
|
|
353
353
|
}
|
|
354
354
|
|
|
@@ -498,12 +498,12 @@ function gruntJobRest(command, workspaceRoot) {
|
|
|
498
498
|
const abs = path.isAbsolute(scriptArg)
|
|
499
499
|
? path.resolve(scriptArg)
|
|
500
500
|
: path.resolve(workspaceRoot, scriptArg);
|
|
501
|
-
const expected = path.resolve(workspaceRoot, "scripts", "grunt-job.mjs");
|
|
501
|
+
const expected = path.resolve(workspaceRoot, ".rulesync", "scripts", "grunt-job.mjs");
|
|
502
502
|
if (abs !== expected) return null;
|
|
503
503
|
return parts.slice(i + 1);
|
|
504
504
|
}
|
|
505
505
|
|
|
506
|
-
/** True when argv targets workspace scripts/grunt-job.mjs (flags may be messy). */
|
|
506
|
+
/** True when argv targets workspace .rulesync/scripts/grunt-job.mjs (flags may be messy). */
|
|
507
507
|
export function isWorkspaceGruntJobScript(command, workspaceRoot) {
|
|
508
508
|
return gruntJobRest(command, workspaceRoot) != null;
|
|
509
509
|
}
|
|
@@ -146,7 +146,7 @@ function persistToken(t, access, expiry) {
|
|
|
146
146
|
|
|
147
147
|
async function accessToken() {
|
|
148
148
|
const t = loadToken();
|
|
149
|
-
if (!t) throw new Error("not logged in; run node scripts/google-workspace.mjs login");
|
|
149
|
+
if (!t) throw new Error("not logged in; run node .rulesync/scripts/google-workspace.mjs login");
|
|
150
150
|
if (t.access_token && Number(t.expiry_date) > Date.now() + 60_000) {
|
|
151
151
|
return t.access_token;
|
|
152
152
|
}
|
|
@@ -288,7 +288,7 @@ async function runLogin(flags) {
|
|
|
288
288
|
return ok("logged in via gcloud ADC");
|
|
289
289
|
}
|
|
290
290
|
return fail(
|
|
291
|
-
`missing Desktop OAuth JSON (${creds}). setup: node scripts/setup.mjs google-workspace`,
|
|
291
|
+
`missing Desktop OAuth JSON (${creds}). setup: node .rulesync/scripts/setup.mjs google-workspace`,
|
|
292
292
|
);
|
|
293
293
|
}
|
|
294
294
|
|
|
@@ -485,8 +485,10 @@ export function runSearch(query, { cwd, path: searchPath, glob } = {}) {
|
|
|
485
485
|
}
|
|
486
486
|
const globs = Array.isArray(glob) ? glob.filter(Boolean) : glob ? [String(glob)] : [];
|
|
487
487
|
const relStart = path.relative(root, start) || ".";
|
|
488
|
+
// --hidden: grunt code (.rulesync/scripts) and rulesync SSOT live in dot dirs; .gitignore still applies.
|
|
488
489
|
const rgArgs = [
|
|
489
490
|
"-n",
|
|
491
|
+
"--hidden",
|
|
490
492
|
"--max-count",
|
|
491
493
|
String(MAX_HITS),
|
|
492
494
|
"--max-filesize",
|
|
@@ -26,6 +26,10 @@ function trimTrailingNewlines(text) {
|
|
|
26
26
|
return String(text).replace(/(?:\r?\n)+$/, "");
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
+
function trimLeadingBlankLines(text) {
|
|
30
|
+
return String(text).replace(/^(?:[ \t]*\r?\n)+/, "");
|
|
31
|
+
}
|
|
32
|
+
|
|
29
33
|
function normEq(a, b) {
|
|
30
34
|
return (
|
|
31
35
|
trimTrailingNewlines(String(a).replace(/\r\n/g, "\n")) ===
|
|
@@ -55,7 +59,7 @@ function unwrapStackedMarkers(text) {
|
|
|
55
59
|
const lines = String(text).split(/\r?\n/);
|
|
56
60
|
let start = 0;
|
|
57
61
|
let end = lines.length;
|
|
58
|
-
while (start < end && BEGIN_LINE_RE.test(lines[start])) start++;
|
|
62
|
+
while (start < end && (BEGIN_LINE_RE.test(lines[start]) || !lines[start].trim())) start++;
|
|
59
63
|
while (end > start && lines[end - 1] === "") end--;
|
|
60
64
|
while (end > start && END_LINE_RE.test(lines[end - 1])) {
|
|
61
65
|
end--;
|
|
@@ -87,13 +91,15 @@ function userRemainderIsBlank(user) {
|
|
|
87
91
|
return String(user).replace(/\r\n/g, "\n").replace(/\n/g, "") === "";
|
|
88
92
|
}
|
|
89
93
|
|
|
94
|
+
/** Blank lines around each sentinel: the markdown formatter fixed point (prettier, remark, mdformat). */
|
|
90
95
|
export function composeGuardedMarkdown(gruntBody, userRemainder, nl = "\n") {
|
|
91
96
|
const raw = extractGruntBody(gruntBody) ?? gruntBody;
|
|
92
|
-
const body = toNewline(trimTrailingNewlines(raw), nl);
|
|
93
|
-
const
|
|
97
|
+
const body = toNewline(trimTrailingNewlines(trimLeadingBlankLines(raw)), nl);
|
|
98
|
+
const inner = body ? `${nl}${body}${nl}${nl}` : nl;
|
|
99
|
+
const block = `${SENTINEL_BEGIN}${nl}${inner}${SENTINEL_END}${nl}`;
|
|
94
100
|
const user = extractUserMarkdown(userRemainder == null ? "" : String(userRemainder));
|
|
95
101
|
if (!user || userRemainderIsBlank(user)) return block;
|
|
96
|
-
return block
|
|
102
|
+
return `${block}${nl}${toNewline(trimLeadingBlankLines(user), nl)}`;
|
|
97
103
|
}
|
|
98
104
|
|
|
99
105
|
export function mergeGuardedContent(existingText, gruntBody) {
|
|
@@ -13,14 +13,14 @@
|
|
|
13
13
|
* validate+sim. Path deny from consumer `.rulesync/permissions.json`.
|
|
14
14
|
* Gemini: SessionStart + AfterTool only; check-behind / path deny stay caveats.
|
|
15
15
|
*
|
|
16
|
-
* node scripts/hooks-union.mjs apply then check
|
|
17
|
-
* node scripts/hooks-union.mjs --check keep-list only
|
|
16
|
+
* node .rulesync/scripts/hooks-union.mjs apply then check
|
|
17
|
+
* node .rulesync/scripts/hooks-union.mjs --check keep-list only
|
|
18
18
|
*/
|
|
19
19
|
import fs from "node:fs";
|
|
20
20
|
import path from "node:path";
|
|
21
21
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
22
22
|
|
|
23
|
-
const ROOT = path.join(path.dirname(fileURLToPath(import.meta.url)), "..");
|
|
23
|
+
const ROOT = path.join(path.dirname(fileURLToPath(import.meta.url)), "..", "..");
|
|
24
24
|
|
|
25
25
|
export const PULL = "node scripts/daily-pull-check.mjs";
|
|
26
26
|
export const RTK = "node scripts/rtk-check.mjs";
|
|
@@ -29,11 +29,11 @@ export const BEHIND = "node scripts/check-behind.mjs --hook";
|
|
|
29
29
|
export const VALIDATE = "node scripts/validate.mjs --hook";
|
|
30
30
|
export const SIM = "node scripts/sim.mjs --hook";
|
|
31
31
|
export const SCRUB =
|
|
32
|
-
'node "${GROK_WORKSPACE_ROOT:-${CLAUDE_PROJECT_DIR:-.}}/scripts/scrub-spawn-prompt.mjs"';
|
|
32
|
+
'node "${GROK_WORKSPACE_ROOT:-${CLAUDE_PROJECT_DIR:-.}}/.rulesync/scripts/scrub-spawn-prompt.mjs"';
|
|
33
33
|
export const GATE_FAT =
|
|
34
|
-
'node "${GROK_WORKSPACE_ROOT:-${CLAUDE_PROJECT_DIR:-.}}/scripts/gate-fat-tools.mjs"';
|
|
34
|
+
'node "${GROK_WORKSPACE_ROOT:-${CLAUDE_PROJECT_DIR:-.}}/.rulesync/scripts/gate-fat-tools.mjs"';
|
|
35
35
|
export const MAP =
|
|
36
|
-
'node "${GROK_WORKSPACE_ROOT:-${CLAUDE_PROJECT_DIR:-.}}/scripts/session-map.mjs"';
|
|
36
|
+
'node "${GROK_WORKSPACE_ROOT:-${CLAUDE_PROJECT_DIR:-.}}/.rulesync/scripts/session-map.mjs"';
|
|
37
37
|
const MAP_NEEDLE = "session-map.mjs";
|
|
38
38
|
|
|
39
39
|
export const AUTORUN_NEEDLES = [
|
|
@@ -83,10 +83,15 @@ function resolveRoot(opts) {
|
|
|
83
83
|
return process.cwd();
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
+
/** Consumer-owned extras live in the consumer's root `scripts/`. */
|
|
86
87
|
function hasScript(root, name) {
|
|
87
88
|
return fs.existsSync(path.join(root, "scripts", name));
|
|
88
89
|
}
|
|
89
90
|
|
|
91
|
+
function hasGruntScript(root, name) {
|
|
92
|
+
return fs.existsSync(path.join(root, ".rulesync", "scripts", name));
|
|
93
|
+
}
|
|
94
|
+
|
|
90
95
|
function withoutWritePath(arr) {
|
|
91
96
|
return arr.filter((x) => typeof x === "string" && !x.startsWith("Write("));
|
|
92
97
|
}
|
|
@@ -179,13 +184,13 @@ function desiredPre(root) {
|
|
|
179
184
|
}
|
|
180
185
|
|
|
181
186
|
function mapNeedles(root) {
|
|
182
|
-
return
|
|
187
|
+
return hasGruntScript(root, MAP_NEEDLE) ? [MAP_NEEDLE] : [];
|
|
183
188
|
}
|
|
184
189
|
|
|
185
190
|
/** `map: false` for hosts rulesync emits no sessionStart for (Antigravity). */
|
|
186
191
|
function desiredSession(root, { map = true } = {}) {
|
|
187
192
|
const hooks = [];
|
|
188
|
-
if (map &&
|
|
193
|
+
if (map && hasGruntScript(root, MAP_NEEDLE)) hooks.push(hookCmd(MAP, 5));
|
|
189
194
|
if (hasScript(root, "daily-pull-check.mjs")) hooks.push(hookCmd(PULL));
|
|
190
195
|
if (hasScript(root, "rtk-check.mjs")) hooks.push(hookCmd(RTK));
|
|
191
196
|
if (hasScript(root, "daily-fleet-check.mjs")) hooks.push(hookCmd(FLEET));
|
|
@@ -15,9 +15,9 @@ export const TIMEOUT_MS = 10_000;
|
|
|
15
15
|
export const MAX_RETRY_WAIT_MS = 2_000;
|
|
16
16
|
export const LOCK_STALE_MS = 10_000;
|
|
17
17
|
|
|
18
|
-
const USAGE = "usage: node scripts/jev.mjs --available | --state FILE --questions FILE\n";
|
|
18
|
+
const USAGE = "usage: node .rulesync/scripts/jev.mjs --available | --state FILE --questions FILE\n";
|
|
19
19
|
const MISSING_KEY =
|
|
20
|
-
"missing TYPESAFE_API_KEY or ~/.grunt/jev.json. setup: node scripts/setup.mjs jev\n";
|
|
20
|
+
"missing TYPESAFE_API_KEY or ~/.grunt/jev.json. setup: node .rulesync/scripts/setup.mjs jev\n";
|
|
21
21
|
|
|
22
22
|
export function jevJsonPath(home) {
|
|
23
23
|
return path.join(home, ".grunt", "jev.json");
|
|
@@ -14,15 +14,15 @@ export const DEFAULT_SECONDS = 8;
|
|
|
14
14
|
export const MAX_SECONDS = 120;
|
|
15
15
|
export const USAGE =
|
|
16
16
|
"usage: listen whoami | devices | rec [--seconds N] [--device D] [--clip] | start [--device D] | stop [--clip] | toggle [--clip] | status | file --path P [--clip] | latest";
|
|
17
|
-
export const SETUP = "node scripts/setup.mjs listen";
|
|
17
|
+
export const SETUP = "node .rulesync/scripts/setup.mjs listen";
|
|
18
18
|
export const NEED_STT =
|
|
19
|
-
"missing whisper-cli (mac: brew install whisper-cpp) or OPENAI_API_KEY / ~/.grunt/speak.json openai.apiKey. setup: node scripts/setup.mjs listen";
|
|
19
|
+
"missing whisper-cli (mac: brew install whisper-cpp) or OPENAI_API_KEY / ~/.grunt/speak.json openai.apiKey. setup: node .rulesync/scripts/setup.mjs listen";
|
|
20
20
|
export const NEED_FFMPEG =
|
|
21
|
-
"missing ffmpeg. mac: brew install ffmpeg · linux: sudo apt install ffmpeg · win: winget install Gyan.FFmpeg. setup: node scripts/setup.mjs listen";
|
|
21
|
+
"missing ffmpeg. mac: brew install ffmpeg · linux: sudo apt install ffmpeg · win: winget install Gyan.FFmpeg. setup: node .rulesync/scripts/setup.mjs listen";
|
|
22
22
|
export const NEED_OPENAI =
|
|
23
|
-
"missing OPENAI_API_KEY (or ~/.grunt/speak.json openai.apiKey). setup: node scripts/setup.mjs listen";
|
|
23
|
+
"missing OPENAI_API_KEY (or ~/.grunt/speak.json openai.apiKey). setup: node .rulesync/scripts/setup.mjs listen";
|
|
24
24
|
export const NEED_GGML =
|
|
25
|
-
"whisper-cli found but no ggml model (auto-download failed). set WHISPER_MODEL or retry. setup: node scripts/setup.mjs listen";
|
|
25
|
+
"whisper-cli found but no ggml model (auto-download failed). set WHISPER_MODEL or retry. setup: node .rulesync/scripts/setup.mjs listen";
|
|
26
26
|
|
|
27
27
|
export function formatHttpError(status, body, provider = "openai") {
|
|
28
28
|
const n = Number(status);
|
|
@@ -254,7 +254,7 @@ export function ffmpegInputArgs(platform, device, ffmpegFormat = "") {
|
|
|
254
254
|
if (platform === "win32") {
|
|
255
255
|
if (!d) {
|
|
256
256
|
throw new Error(
|
|
257
|
-
"missing --device or LISTEN_DEVICE. run: node scripts/listen.mjs devices. setup: node scripts/setup.mjs listen",
|
|
257
|
+
"missing --device or LISTEN_DEVICE. run: node .rulesync/scripts/listen.mjs devices. setup: node .rulesync/scripts/setup.mjs listen",
|
|
258
258
|
);
|
|
259
259
|
}
|
|
260
260
|
const spec = d.startsWith("audio=") ? d : `audio=${d}`;
|
|
@@ -12,27 +12,27 @@ export const COMMANDS = {
|
|
|
12
12
|
generate: [
|
|
13
13
|
"rulesync generate -t claudecode,codexcli,antigravity-cli,grokcli -f rules,subagents,skills",
|
|
14
14
|
"rulesync generate -t claudecode,codexcli,antigravity-cli -f hooks",
|
|
15
|
-
"node scripts/emit-mcp-policy.mjs",
|
|
16
|
-
"node scripts/emit-gemini.mjs",
|
|
17
|
-
"node scripts/emit-agent-shell-tools.mjs",
|
|
18
|
-
"node scripts/emit-maps.mjs",
|
|
19
|
-
"node scripts/hooks-union.mjs",
|
|
15
|
+
"node .rulesync/scripts/emit-mcp-policy.mjs",
|
|
16
|
+
"node .rulesync/scripts/emit-gemini.mjs",
|
|
17
|
+
"node .rulesync/scripts/emit-agent-shell-tools.mjs",
|
|
18
|
+
"node .rulesync/scripts/emit-maps.mjs",
|
|
19
|
+
"node .rulesync/scripts/hooks-union.mjs",
|
|
20
20
|
],
|
|
21
21
|
check: [
|
|
22
22
|
"rulesync generate -t claudecode,codexcli,antigravity-cli,grokcli -f rules,skills --check",
|
|
23
23
|
"rulesync generate -t codexcli,antigravity-cli,grokcli -f subagents --check",
|
|
24
24
|
"rulesync generate -t claudecode,codexcli,antigravity-cli -f hooks --check",
|
|
25
|
-
"node scripts/emit-mcp-policy.mjs --check",
|
|
26
|
-
"node scripts/emit-gemini.mjs --check",
|
|
27
|
-
"node scripts/emit-agent-shell-tools.mjs --check",
|
|
28
|
-
"node scripts/emit-maps.mjs --check",
|
|
29
|
-
"node scripts/check-globals.mjs",
|
|
30
|
-
"node scripts/hooks-union.mjs --check",
|
|
25
|
+
"node .rulesync/scripts/emit-mcp-policy.mjs --check",
|
|
26
|
+
"node .rulesync/scripts/emit-gemini.mjs --check",
|
|
27
|
+
"node .rulesync/scripts/emit-agent-shell-tools.mjs --check",
|
|
28
|
+
"node .rulesync/scripts/emit-maps.mjs --check",
|
|
29
|
+
"node .rulesync/scripts/check-globals.mjs",
|
|
30
|
+
"node .rulesync/scripts/hooks-union.mjs --check",
|
|
31
31
|
],
|
|
32
32
|
watch: [
|
|
33
|
-
"node scripts/emit-mcp-policy.mjs",
|
|
34
|
-
"node scripts/emit-gemini.mjs",
|
|
35
|
-
"node scripts/emit-agent-shell-tools.mjs",
|
|
33
|
+
"node .rulesync/scripts/emit-mcp-policy.mjs",
|
|
34
|
+
"node .rulesync/scripts/emit-gemini.mjs",
|
|
35
|
+
"node .rulesync/scripts/emit-agent-shell-tools.mjs",
|
|
36
36
|
"rulesync generate -t claudecode,codexcli,antigravity-cli,grokcli -f rules,subagents,skills --watch",
|
|
37
37
|
],
|
|
38
38
|
};
|
|
@@ -13,7 +13,7 @@ import { folderMap } from "./folder-map.mjs";
|
|
|
13
13
|
/** First line of the injected map; `depth` = levels per package, null when nothing was cut. */
|
|
14
14
|
export function header(depth) {
|
|
15
15
|
const scope = depth == null ? "complete" : `${depth} levels per package`;
|
|
16
|
-
return `Folder map (code folders, ${scope}; \`…\` = deeper, run \`node scripts/folder-map.mjs <dir>\`):`;
|
|
16
|
+
return `Folder map (code folders, ${scope}; \`…\` = deeper, run \`node .rulesync/scripts/folder-map.mjs <dir>\`):`;
|
|
17
17
|
}
|
|
18
18
|
/** Claude Code caps each hook's additionalContext at 10,000 chars; above it, only a 2KB preview stays inline. */
|
|
19
19
|
export const HOOK_CONTEXT_CHARS = 10000;
|
|
@@ -427,7 +427,7 @@ export async function setupSpeak({
|
|
|
427
427
|
throw new Error(
|
|
428
428
|
interactive
|
|
429
429
|
? "need an ElevenLabs or OpenAI key"
|
|
430
|
-
: "need --elevenlabs-key or --openai-key (or TTY: node scripts/setup.mjs speak)",
|
|
430
|
+
: "need --elevenlabs-key or --openai-key (or TTY: node .rulesync/scripts/setup.mjs speak)",
|
|
431
431
|
);
|
|
432
432
|
}
|
|
433
433
|
|
|
@@ -502,7 +502,7 @@ export async function setupListen({
|
|
|
502
502
|
openaiKey = str(await io.password({ message: "OpenAI API key (fallback STT)" }));
|
|
503
503
|
} else {
|
|
504
504
|
throw new Error(
|
|
505
|
-
"need whisper-cli or --openai-key (or TTY: node scripts/setup.mjs listen)",
|
|
505
|
+
"need whisper-cli or --openai-key (or TTY: node .rulesync/scripts/setup.mjs listen)",
|
|
506
506
|
);
|
|
507
507
|
}
|
|
508
508
|
}
|
|
@@ -611,7 +611,7 @@ export async function setupGoogleWorkspace({
|
|
|
611
611
|
installOAuthJson({ src: credsFlag, dest });
|
|
612
612
|
} else if (!fs.existsSync(dest)) {
|
|
613
613
|
throw new Error(
|
|
614
|
-
`need --creds PATH (or TTY: node scripts/setup.mjs google-workspace)`,
|
|
614
|
+
`need --creds PATH (or TTY: node .rulesync/scripts/setup.mjs google-workspace)`,
|
|
615
615
|
);
|
|
616
616
|
}
|
|
617
617
|
|
|
@@ -678,7 +678,7 @@ export async function setupJev({
|
|
|
678
678
|
throw new Error(
|
|
679
679
|
interactive
|
|
680
680
|
? "need a TypeSafe API key"
|
|
681
|
-
: "need --api-key (or TTY: node scripts/setup.mjs jev)",
|
|
681
|
+
: "need --api-key (or TTY: node .rulesync/scripts/setup.mjs jev)",
|
|
682
682
|
);
|
|
683
683
|
}
|
|
684
684
|
const dest = writeSecretJson(path.join(home, ".grunt", "jev.json"), { apiKey });
|
|
@@ -27,13 +27,13 @@ export const USAGE =
|
|
|
27
27
|
"usage: speak whoami | voices | say --text T [--provider elevenlabs|openai] [--voice ID] [--out path] [--play]";
|
|
28
28
|
const ELEVEN_API = "https://api.elevenlabs.io/v1";
|
|
29
29
|
const OPENAI_API = "https://api.openai.com/v1";
|
|
30
|
-
export const SETUP = "node scripts/setup.mjs speak";
|
|
30
|
+
export const SETUP = "node .rulesync/scripts/setup.mjs speak";
|
|
31
31
|
export const NEED_KEY =
|
|
32
|
-
"missing ELEVENLABS_API_KEY or OPENAI_API_KEY (or ~/.grunt/speak.json). setup: node scripts/setup.mjs speak";
|
|
32
|
+
"missing ELEVENLABS_API_KEY or OPENAI_API_KEY (or ~/.grunt/speak.json). setup: node .rulesync/scripts/setup.mjs speak";
|
|
33
33
|
export const NEED_ELEVEN =
|
|
34
|
-
"missing ELEVENLABS_API_KEY (or ~/.grunt/speak.json elevenlabs.apiKey). setup: node scripts/setup.mjs speak";
|
|
34
|
+
"missing ELEVENLABS_API_KEY (or ~/.grunt/speak.json elevenlabs.apiKey). setup: node .rulesync/scripts/setup.mjs speak";
|
|
35
35
|
export const NEED_OPENAI =
|
|
36
|
-
"missing OPENAI_API_KEY (or ~/.grunt/speak.json openai.apiKey). setup: node scripts/setup.mjs speak";
|
|
36
|
+
"missing OPENAI_API_KEY (or ~/.grunt/speak.json openai.apiKey). setup: node .rulesync/scripts/setup.mjs speak";
|
|
37
37
|
|
|
38
38
|
export function formatHttpError(status, body, provider) {
|
|
39
39
|
const n = Number(status);
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: browser
|
|
3
|
-
description: "Browse via node scripts/browser.mjs (Lightpanda). App e2e uses Playwright."
|
|
3
|
+
description: "Browse via node .rulesync/scripts/browser.mjs (Lightpanda). App e2e uses Playwright."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
Zero-config. `node scripts/browser.mjs <verb>`.
|
|
6
|
+
Zero-config. `node .rulesync/scripts/browser.mjs <verb>`.
|
|
7
7
|
|
|
8
8
|
Verbs: `nav <url>` · `snap` · `click <ref>` · `fill <ref> <text>` · `scroll [ref|down|up|N]` · `wait [ms]` · `hover <ref>` · `select <ref> <value>` · `shot` · `pdf` · `stop` · `doctor` · `ensure`.
|
|
9
9
|
|
|
@@ -11,5 +11,5 @@ Verbs: `nav <url>` · `snap` · `click <ref>` · `fill <ref> <text>` · `scroll
|
|
|
11
11
|
- Lightpanda default. The rail swaps to Chromium when `shot`/`pdf`/`trace`, win32, missing Lightpanda, probe-fail once, Chromium-first hosts (figma docs/sheets/slides mail.google earth amazon), or a blocked/empty/client-rendered snap. One swap. Do not stop and say you cannot.
|
|
12
12
|
- Session/profile: `.tmp/grunt/browser/`. `stop` reaps; second `stop` ok.
|
|
13
13
|
- Windows: Chromium even if Lightpanda exists.
|
|
14
|
-
- `doctor`/`ensure` → `node scripts/doctor.mjs` or `grunt doctor`. Engine hints: `node scripts/setup.mjs browser`. Do not read a README unless doctor/setup is missing; then https://github.com/lovrozagar/grunt#prerequisites (not the consumer README).
|
|
14
|
+
- `doctor`/`ensure` → `node .rulesync/scripts/doctor.mjs` or `grunt doctor`. Engine hints: `node .rulesync/scripts/setup.mjs browser`. Do not read a README unless doctor/setup is missing; then https://github.com/lovrozagar/grunt#prerequisites (not the consumer README).
|
|
15
15
|
- No env. No MCP. No raw Playwright. Spec: `.rulesync/reference/browser.md`.
|
|
@@ -6,4 +6,4 @@ description: "Low-level Apps Script CLI. Prefer /google-workspace for sheet, doc
|
|
|
6
6
|
|
|
7
7
|
Custom Apps Script in-repo only. Spec: `.rulesync/reference/clasp.md`.
|
|
8
8
|
|
|
9
|
-
Sheets, Docs, Slides, Calendar, Gmail: `node scripts/google-workspace.mjs` and `.rulesync/reference/google-workspace.md`.
|
|
9
|
+
Sheets, Docs, Slides, Calendar, Gmail: `node .rulesync/scripts/google-workspace.mjs` and `.rulesync/reference/google-workspace.md`.
|