@hanzlaa/rcode 2.8.0 β†’ 3.2.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.
Files changed (122) hide show
  1. package/AGENTS.md +11 -1
  2. package/CONTRIBUTING.md +7 -0
  3. package/README.md +39 -20
  4. package/cli/install.js +145 -47
  5. package/dist/rcode.js +134 -43
  6. package/package.json +2 -2
  7. package/rihal/agents/rihal-advisor-researcher.md +1 -1
  8. package/rihal/agents/rihal-assumptions-analyzer.md +1 -1
  9. package/rihal/agents/rihal-codebase-mapper.md +1 -1
  10. package/rihal/agents/rihal-docs-auditor.md +3 -3
  11. package/rihal/agents/rihal-executor.md +10 -0
  12. package/rihal/agents/rihal-integration-checker.md +1 -1
  13. package/rihal/agents/rihal-noor.md +2 -2
  14. package/rihal/agents/rihal-phase-researcher.md +1 -1
  15. package/rihal/agents/rihal-planner.md +25 -0
  16. package/rihal/agents/rihal-project-researcher.md +1 -1
  17. package/rihal/agents/rihal-research-synthesizer.md +1 -1
  18. package/rihal/agents/rihal-roadmapper.md +1 -1
  19. package/rihal/agents/rihal-sprint-checker.md +19 -1
  20. package/rihal/agents/rihal-verifier.md +1 -1
  21. package/rihal/agents/rihal-waleed.md +1 -2
  22. package/rihal/commands/code-review.md +1 -1
  23. package/rihal/commands/memory-audit.md +10 -0
  24. package/rihal/commands/memory-distill.md +11 -0
  25. package/rihal/commands/memory-init.md +12 -0
  26. package/rihal/commands/memory-update.md +12 -0
  27. package/rihal/config/model-profiles.json +5 -5
  28. package/rihal/references/karpathy-guidelines-full.md +1 -1
  29. package/rihal/references/no-unauthorized-git-ops.md +1 -1
  30. package/rihal/references/verb-dictionary.md +1 -1
  31. package/rihal/skills/actions/2-plan/rihal-frontend-design/SKILL.md +49 -139
  32. package/rihal/skills/actions/2-plan/rihal-frontend-design/references.md +79 -0
  33. package/rihal/skills/actions/4-implementation/rihal-browser-verify/SKILL.md +70 -0
  34. package/rihal/skills/actions/4-implementation/rihal-checkpoint-preview/SKILL.md +1 -1
  35. package/rihal/skills/actions/4-implementation/rihal-ci/SKILL.md +108 -0
  36. package/rihal/skills/actions/4-implementation/rihal-debug/SKILL.md +78 -0
  37. package/rihal/skills/actions/4-implementation/rihal-git-flow/SKILL.md +90 -0
  38. package/rihal/skills/actions/4-implementation/rihal-harden/SKILL.md +91 -0
  39. package/rihal/skills/actions/4-implementation/rihal-incremental/SKILL.md +50 -0
  40. package/rihal/skills/actions/4-implementation/rihal-migrate/SKILL.md +86 -0
  41. package/rihal/skills/actions/4-implementation/rihal-perf/SKILL.md +96 -0
  42. package/rihal/skills/actions/4-implementation/rihal-prove-it/SKILL.md +64 -0
  43. package/rihal/skills/actions/4-implementation/rihal-source-truth/SKILL.md +76 -0
  44. package/rihal/skills/actions/4-implementation/rihal-trim/SKILL.md +73 -0
  45. package/rihal/skills/agents/dalil-scout/SKILL.md +43 -125
  46. package/rihal/skills/agents/dalil-scout/references.md +67 -0
  47. package/rihal/skills/agents/majlis-council/SKILL.md +50 -144
  48. package/rihal/skills/agents/majlis-council/references.md +90 -0
  49. package/rihal/skills/agents/raees-orchestrator/SKILL.md +56 -117
  50. package/rihal/skills/agents/raees-orchestrator/references.md +47 -0
  51. package/rihal/skills/core/rihal-advanced-elicitation/SKILL.md +36 -136
  52. package/rihal/skills/core/rihal-advanced-elicitation/references.md +101 -0
  53. package/rihal/skills/core/rihal-auth-audit/SKILL.md +93 -0
  54. package/rihal/skills/core/rihal-brainstorming/SKILL.md +5 -0
  55. package/rihal/skills/core/rihal-client-gate/SKILL.md +91 -0
  56. package/rihal/skills/core/rihal-clone-website/SKILL.md +30 -371
  57. package/rihal/skills/core/rihal-clone-website/references.md +213 -0
  58. package/rihal/skills/core/rihal-deploy-unify/SKILL.md +87 -0
  59. package/rihal/skills/core/rihal-distillator/SKILL.md +37 -187
  60. package/rihal/skills/core/rihal-distillator/references.md +118 -0
  61. package/rihal/skills/core/rihal-editorial-review-prose/SKILL.md +5 -0
  62. package/rihal/skills/core/rihal-editorial-review-structure/SKILL.md +45 -183
  63. package/rihal/skills/core/rihal-editorial-review-structure/references.md +110 -0
  64. package/rihal/skills/core/rihal-help/SKILL.md +6 -1
  65. package/rihal/skills/core/rihal-incident-record/SKILL.md +161 -0
  66. package/rihal/skills/core/rihal-index-docs/SKILL.md +5 -0
  67. package/rihal/skills/core/rihal-init/SKILL.md +5 -0
  68. package/rihal/skills/core/rihal-memory-audit/SKILL.md +88 -0
  69. package/rihal/skills/core/rihal-memory-distill/SKILL.md +87 -0
  70. package/rihal/skills/core/rihal-memory-init/SKILL.md +77 -0
  71. package/rihal/skills/core/rihal-memory-update/SKILL.md +73 -0
  72. package/rihal/skills/core/rihal-mvp-graduate/SKILL.md +116 -0
  73. package/rihal/skills/core/rihal-ocr-consistency/SKILL.md +106 -0
  74. package/rihal/skills/core/rihal-party-mode/SKILL.md +5 -0
  75. package/rihal/skills/core/rihal-rebrand/SKILL.md +133 -0
  76. package/rihal/skills/core/rihal-review-adversarial-general/SKILL.md +5 -0
  77. package/rihal/skills/core/rihal-review-edge-case-hunter/SKILL.md +5 -0
  78. package/rihal/skills/core/rihal-shard-doc/SKILL.md +5 -0
  79. package/rihal/skills/core/rihal-theme-system/SKILL.md +113 -0
  80. package/rihal/team.yaml +3 -22
  81. package/rihal/templates/memory/INDEX.md +46 -0
  82. package/rihal/templates/memory/change-records/.gitkeep +4 -0
  83. package/rihal/templates/memory/distillates/project.distillate.md +11 -0
  84. package/rihal/templates/memory/distillates/stack.distillate.md +11 -0
  85. package/rihal/templates/memory/incidents/known-issues.md +27 -0
  86. package/rihal/templates/memory/incidents/post-mortems/.gitkeep +3 -0
  87. package/rihal/templates/memory/milestones/archive/.gitkeep +2 -0
  88. package/rihal/templates/memory/milestones/current.md +39 -0
  89. package/rihal/templates/memory/people/stakeholders.md +25 -0
  90. package/rihal/templates/memory/people/team.md +35 -0
  91. package/rihal/templates/memory/project/decisions.md +32 -0
  92. package/rihal/templates/memory/project/glossary.md +16 -0
  93. package/rihal/templates/memory/project/stack.md +46 -0
  94. package/rihal/workflows/audit.md +3 -3
  95. package/rihal/workflows/code-review.md +32 -1
  96. package/rihal/workflows/council.md +1 -1
  97. package/rihal/workflows/discuss-phase-power.md +3 -3
  98. package/rihal/workflows/do.md +1 -1
  99. package/rihal/workflows/docs-update.md +4 -4
  100. package/rihal/workflows/execute.md +61 -5
  101. package/rihal/workflows/help.md +5 -5
  102. package/rihal/workflows/karpathy-audit.md +9 -9
  103. package/rihal/workflows/memory-audit.md +83 -0
  104. package/rihal/workflows/memory-distill.md +103 -0
  105. package/rihal/workflows/memory-init.md +102 -0
  106. package/rihal/workflows/memory-update.md +83 -0
  107. package/rihal/workflows/plan.md +66 -1
  108. package/server/dashboard.js +6 -1
  109. package/server/lib/api.js +8 -2
  110. package/server/lib/html/client.js +63 -0
  111. package/server/lib/html/shell.js +5 -0
  112. package/server/lib/scanner.js +76 -1
  113. package/rihal/agents/rihal-architect.md +0 -79
  114. package/rihal/agents/rihal-tech-writer.md +0 -80
  115. package/rihal/commands/check-implementation-readiness.md +0 -8
  116. package/rihal/commands/discuss-phase-power.md +0 -11
  117. package/rihal/commands/karpathy-audit.md +0 -12
  118. package/rihal/commands/new-project-research.md +0 -11
  119. package/rihal/commands/new-project-roadmap.md +0 -11
  120. package/rihal/commands/report.md +0 -10
  121. package/rihal/commands/review-adversarial.md +0 -8
  122. package/rihal/commands/review-edge-case-hunter.md +0 -8
package/AGENTS.md CHANGED
@@ -24,7 +24,7 @@ If a user says "just keep going" or "don't stop until done", that authorization
24
24
 
25
25
  - Follow [Conventional Commits](https://www.conventionalcommits.org/) format: `type(scope): subject`
26
26
  - Types allowed: `feat`, `fix`, `docs`, `style`, `refactor`, `test`, `chore`, `perf`, `revert`
27
- - Scopes allowed: `agents`, `skills`, `workflows`, `templates`, `dashboard`, `docs`, `config`, `github`
27
+ - Scopes allowed: `agents`, `skills`, `workflows`, `templates`, `dashboard`, `docs`, `config`, `github`, `commands`, `memory`, `brand`, `cli`, `ci`, `release`, `meta`, `tasks`, `migrations`, `refs`
28
28
  - Subject: lowercase first letter, imperative mood, no trailing period, under 72 chars
29
29
  - **NEVER add Claude/AI attribution to commit messages.** No "Generated with Claude Code", no "Co-Authored-By: Claude", no "πŸ€– Generated". The user does not want this.
30
30
  - **NEVER use `--no-verify`** to bypass hooks. If hooks fail, fix the underlying issue.
@@ -46,6 +46,16 @@ If a user says "just keep going" or "don't stop until done", that authorization
46
46
 
47
47
  ---
48
48
 
49
+ ## Naming & Branding (per `BRAND.md`)
50
+
51
+ - **Skill names** in frontmatter: `rihal-<verb>-<noun>` for legacy skills; new branded skills use `rcode-<verb>-<noun>` ONLY in slash command surface (`/rcode:<name>`); folder names stay `rihal-*` because `cli/install.js` hardcodes that prefix.
52
+ - **Persona IDs** in `team.yaml` stay `rihal-<name>` (dashboard scanner reads them by id; renaming breaks rendering).
53
+ - **Persona display names** keep Arabic alongside Latin: `Sadiq (Ψ΅Ψ§Ψ―Ω‚)`, `Dalil (Ψ―Ω„ΩŠΩ„)`, etc.
54
+ - **Concept primitives** (Memory Bank, Distillate, Majlis, Diwan) are named tooling β€” capitalised, used consistently in user-facing copy.
55
+ - **Plain English over jargon in flags.** Prefer `--attack` over `--adversarial`, `--edge-cases` over `--edge-case-hunter`. Audience includes non-native English speakers.
56
+
57
+ ---
58
+
49
59
  ## File Modification Rules
50
60
 
51
61
  - **Maximum file size: 1000 lines** β€” refactor before exceeding
package/CONTRIBUTING.md CHANGED
@@ -2,6 +2,13 @@
2
2
 
3
3
  Thank you for contributing. These guidelines exist to keep the module maintainable and impressive when demoed.
4
4
 
5
+ > **Before you contribute, also read:**
6
+ > - [`BRAND.md`](BRAND.md) β€” voice, naming conventions, persona glossary
7
+ > - [`AGENTS.md`](AGENTS.md) β€” non-negotiable rules for AI coding agents (commit policy, push policy, off-limits files)
8
+ > - [`MIGRATIONS.md`](MIGRATIONS.md) β€” every renamed/dropped surface in the rcode improvement programme
9
+ > - [`MEMORY_BANK.md`](MEMORY_BANK.md) β€” Memory Bank specification
10
+ > - [`TASKS.md`](TASKS.md) β€” master task tracker driving GitHub issues
11
+
5
12
  ---
6
13
 
7
14
  ## Architecture overview β€” what are all these files?
package/README.md CHANGED
@@ -1,16 +1,31 @@
1
- # Rihal Code
1
+ # Rihal Code (rcode)
2
2
 
3
3
  <div dir="rtl">Ψ·Ψ±ΩŠΩ‚Ψ© Ψ±Ψ­Ψ§Ω„</div>
4
4
 
5
- > **Install Rihal's brain into your project in one command.** Every Rihalian β€” engineer, PM, designer, CTO, QA β€” gets an AI assistant that already knows how Rihal builds: PR standards, commit conventions, architecture patterns, sprint cadence, the Rihal team's agent personas. No onboarding. No prompting. Works in Claude Code, Cursor, and any compatible AI IDE.
5
+ > **rcode is the memory bank for AI-driven SaaS teams β€” your project's context, structured, visible, and never lost.**
6
+ >
7
+ > Built by Rihal. Designed for solo devs, startup teams, and SaaS builders. Install once, and your AI assistant gets a persistent project brain: structured memory, decisions log, distinctive personas, and phase-based workflows. Works in Claude Code, Cursor, and any compatible AI IDE.
8
+
9
+ ---
10
+
11
+ ## Who is rcode for
12
+
13
+ You'll feel rcode pay off if you've lived any of these:
14
+
15
+ - **AI agents lose context mid-project.** Three sessions in, the assistant has forgotten the architectural decision you made on day one.
16
+ - **Onboarding a teammate** means a 30-minute archaeology dig through Slack, Notion, and review comments to explain "why we did it this way".
17
+ - **Late client requirements** keep shifting the goal posts, and there's no record of what was decided when.
18
+ - **MVPs that work but can't be revamped** without rewriting from scratch β€” the original context is lost.
19
+
20
+ rcode addresses these with a checked-in **Memory Bank** (`.rihal/memory/`), distinctive engineering personas, and a phased workflow that survives session resets. **For everything in one place, read [`DOCS.md`](DOCS.md).** See [`MEMORY_BANK.md`](MEMORY_BANK.md) for the spec, and [`BRAND.md`](BRAND.md) for naming and voice conventions.
6
21
 
7
22
  ---
8
23
 
9
24
  ## Why this exists
10
25
 
11
- Every Rihal project carries unwritten context β€” how we review PRs, what "done" means, how we sequence milestones, how PRDs travel from Product into Engineering. That context sits in people's heads, Slack, Notion, senior engineers' review comments. AI assistants pick it up never, because every new chat session starts knowing nothing about how Rihal works.
26
+ Every project carries unwritten context β€” how the team reviews PRs, what "done" means, how milestones sequence, how PRDs travel from Product into Engineering. That context sits in people's heads, Slack, Notion, and senior engineers' review comments. AI assistants pick it up never, because every new chat session starts knowing nothing about how this project actually works.
12
27
 
13
- **Rihal Code fixes that.** One install, and the AI knows. Every session. Every repo. Every Rihalian.
28
+ **rcode fixes that.** One install, and the AI knows. Every session. Every repo. Every contributor.
14
29
 
15
30
  See [`docs/what-is-rihal-code.md`](docs/what-is-rihal-code.md) for the full story, and [`docs/ROADMAP.md`](docs/ROADMAP.md) for where this is going (next: live MCP server in v3.0).
16
31
 
@@ -37,8 +52,10 @@ Rihal Code packages a lot. To keep things approachable, everything is organized
37
52
 
38
53
  Most AI tools give you one assistant pretending to be everything. **Rihal Code gives you Rihal's team β€” and Rihal's brain β€” inside every project.**
39
54
 
40
- - **43 agents** with clear roles, cultural identity (Arabic names), and hard scope boundaries
41
- - **99 slash commands** covering research, planning, execution, verification, and recovery
55
+ - **45 agents** with clear roles, cultural identity (Arabic names), and hard scope boundaries
56
+ - **95 slash commands** covering research, planning, execution, verification, and recovery
57
+ - **80 skills** including Memory Bank primitives, 11 engineering-rigor skills (TDD, harden, perf, debug, trim, etc.), and 8 real-pain skills (auth-audit, mvp-graduate, deploy-unify, etc.)
58
+ - **Persistent project memory** at `.rihal/memory/` β€” checked into git, visible in the Diwan dashboard, lossless distillates for fast LLM hydration
42
59
  - **3 execution modes**: parallel debate (`/rihal:council`), sequential pipelines (`/rihal:chain`), and quick-sync (`/rihal:discuss`)
43
60
  - **File-based state** in `.rihal/` that every workflow reads and updates
44
61
  - **Intent guards** on every workflow β€” catch wrong commands early with copy-paste redirects
@@ -48,6 +65,8 @@ Most AI tools give you one assistant pretending to be everything. **Rihal Code g
48
65
  - **Post-execute gates** (integration-checker, nyquist-auditor) verify completeness
49
66
  - **Global agents** at `~/.rihal/agents/` β€” customize without forking
50
67
 
68
+ See [`MIGRATIONS.md`](MIGRATIONS.md) if you're upgrading from a pre-Memory-Bank install.
69
+
51
70
  It's not a chatbot. It's a methodology.
52
71
 
53
72
  ---
@@ -65,9 +84,9 @@ npx @hanzlaa/rcode install
65
84
  One unified installer. Pure file shipping, no runtime dependencies. Installs into:
66
85
 
67
86
  - `.rihal/` β€” config, workflows, references, bin (Rihal infrastructure)
68
- - `.claude/agents/` β€” 43 first-class subagents
69
- - `.claude/commands/rihal/` β€” 99 slash commands
70
- - `.claude/skills/` β€” 56 phrase-activated skills (scaffold-project, create-prd, prfaq, retrospective, etc.)
87
+ - `.claude/agents/` β€” 45 first-class subagents
88
+ - `.claude/commands/rihal/` β€” 95 slash commands
89
+ - `.claude/skills/` β€” 80 phrase-activated skills (scaffold-project, create-prd, prfaq, memory-init, retrospective, etc.)
71
90
  - `rihal/brain/` β€” Rihal standards pulled from upstream (PR / commit / architecture docs)
72
91
  - `.planning/` β€” where your artifacts land (council sessions, plans, chains, summaries)
73
92
 
@@ -111,7 +130,7 @@ npx @hanzlaa/rcode install --ide gemini
111
130
  /rihal:plan --research build a rental app β†’ researcher grounds, plan-checker verifies
112
131
  /rihal:execute .planning/plans/01/PLAN.md β†’ atomic commits + post-gates
113
132
  /rihal:status β†’ phases, decisions, blockers, sessions
114
- /rihal:karpathy-audit HEAD~5..HEAD β†’ audit changes vs 4 coding principles
133
+ /rihal:code-review HEAD~5..HEAD --karpathy β†’ audit changes vs 4 coding principles
115
134
  ```
116
135
 
117
136
  ---
@@ -165,7 +184,7 @@ npx @hanzlaa/rcode install --ide gemini
165
184
  - **Execution**: rihal-executor, rihal-planner, rihal-verifier, rihal-plan-checker, rihal-debugger
166
185
  - **Discovery**: rihal-codebase-mapper, rihal-project-researcher, rihal-roadmapper, rihal-phase-researcher, rihal-advisor-researcher, rihal-assumptions-analyzer, rihal-research-synthesizer
167
186
  - **Verification**: rihal-integration-checker, rihal-nyquist-auditor
168
- - **Quality**: rihal-tech-writer, rihal-ux-designer, rihal-architect, rihal-code-reviewer, rihal-code-fixer, rihal-edge-case-hunter, rihal-deviation-analyzer
187
+ - **Quality**: rihal-noor, rihal-ux-designer, rihal-code-reviewer, rihal-code-fixer, rihal-edge-case-hunter, rihal-deviation-analyzer
169
188
  - **And more**: rihal-docs-auditor, rihal-doc-verifier, rihal-doc-writer, rihal-repo-metrics, rihal-security-auditor, etc.
170
189
 
171
190
  **Customize globally:** Define reusable agents in `~/.rihal/agents/rihal-<name>.md`. They appear in every project alongside project-local agents, without forking the repo.
@@ -256,11 +275,11 @@ Amazon's "Working Backwards" method: write the finished-product press release *b
256
275
  3. **Surgical changes** β€” touch only what's needed, match existing style
257
276
  4. **Goal-driven execution** β€” define verifiable success criteria
258
277
 
259
- `/rihal:karpathy-audit` runs these 4 principles as a post-hoc audit against any diff or phase. Use it after implementation to catch bloated, over-engineered, or scope-creeping changes before they land in a PR.
278
+ `/rihal:code-review --karpathy` runs these 4 principles as a post-hoc audit against any diff or phase. Use it after implementation to catch bloated, over-engineered, or scope-creeping changes before they land in a PR.
260
279
 
261
280
  ```
262
- /rihal:karpathy-audit HEAD~5..HEAD
263
- /rihal:karpathy-audit 03 --files=src/auth/
281
+ /rihal:code-review HEAD~5..HEAD --karpathy
282
+ /rihal:code-review 03 --files=src/auth/ --karpathy
264
283
  ```
265
284
 
266
285
  ### Plan verification + post-execute gates
@@ -309,13 +328,13 @@ Recent additions in this session:
309
328
 
310
329
  ---
311
330
 
312
- ## Full command surface (99 commands)
331
+ ## Full command surface (95 commands)
313
332
 
314
333
  ### Router + lifecycle
315
334
  `init` Β· `do` Β· `help` Β· `status` Β· `stats` Β· `health` Β· `forensics` Β· `update`
316
335
 
317
336
  ### Discovery + research
318
- `new-project` Β· `map-codebase` Β· `scan` Β· `explore` Β· `document-project` Β· `analyze-dependencies` Β· `discuss-phase-power`
337
+ `new-project` Β· `map-codebase` Β· `scan` Β· `explore` Β· `document-project` Β· `analyze-dependencies`
319
338
 
320
339
  ### Discovery + validation
321
340
  `prfaq` Β· `brainstorm` Β· `market-research` Β· `domain-research` Β· `technical-research` Β· `product-brief`
@@ -324,10 +343,10 @@ Recent additions in this session:
324
343
  `plan` Β· `chain` Β· `create-epics-and-stories` Β· `create-story` Β· `dev-story` Β· `sprint-planning`
325
344
 
326
345
  ### Execution
327
- `execute` Β· `quick` Β· `autonomous` Β· `audit-fix` Β· `undo` Β· `check-implementation-readiness`
346
+ `execute` Β· `quick` Β· `autonomous` Β· `audit-fix` Β· `undo`
328
347
 
329
348
  ### Observability + review
330
- `code-review` Β· `code-review-fix` Β· `review-adversarial` Β· `review-edge-case-hunter` Β· `karpathy-audit` Β· `checkpoint-preview` Β· `secure-phase` Β· `show` Β· `why` Β· `rerun` Β· `diff`
349
+ `code-review` Β· `code-review-fix` Β· `checkpoint-preview` Β· `secure-phase` Β· `show` Β· `why` Β· `rerun` Β· `diff`
331
350
 
332
351
  ### Recovery + correction
333
352
  `pause-work` Β· `resume-work` Β· `correct-course` Β· `next` Β· `config`
@@ -446,8 +465,8 @@ Every install runs 5 automated smoke tests before exiting:
446
465
  βœ“ rihal-tools.cjs runs β€” syntax ok
447
466
  βœ“ .rihal/config.yaml present β€” 412 bytes
448
467
  βœ“ .rihal/state.json parses β€” valid JSON
449
- βœ“ agents installed β€” 43
450
- βœ“ skills + commands installed β€” 56 skills + 99 commands
468
+ βœ“ agents installed β€” 45
469
+ βœ“ skills + commands installed β€” 80 skills + 95 commands
451
470
  ```
452
471
 
453
472
  A failed check prints the debug command and returns exit code 1 so CI catches broken installs.
package/cli/install.js CHANGED
@@ -268,20 +268,26 @@ function printInstallHeader(targetVersion) {
268
268
  * Returns a set like { claude: true, cursor: false, gemini: false }.
269
269
  */
270
270
  function detectIdeSignals(target) {
271
- const signals = { claude: false, cursor: false, gemini: false };
271
+ const signals = { claude: false, cursor: false, gemini: false, vscode: false, antigravity: false };
272
272
  // 1. Project-local install dirs (strongest signal β€” they already use one)
273
273
  if (fs.existsSync(path.join(target, '.claude'))) signals.claude = true;
274
274
  if (fs.existsSync(path.join(target, '.cursor'))) signals.cursor = true;
275
275
  if (fs.existsSync(path.join(target, '.gemini'))) signals.gemini = true;
276
+ if (fs.existsSync(path.join(target, '.vscode'))) signals.vscode = true;
277
+ if (fs.existsSync(path.join(target, '.antigravity'))) signals.antigravity = true;
276
278
  // 2. User-level config dirs
277
279
  const home = os.homedir();
278
280
  if (fs.existsSync(path.join(home, '.claude'))) signals.claude = true;
279
281
  if (fs.existsSync(path.join(home, '.cursor'))) signals.cursor = true;
280
282
  if (fs.existsSync(path.join(home, '.config', 'Cursor'))) signals.cursor = true;
281
283
  if (fs.existsSync(path.join(home, '.gemini'))) signals.gemini = true;
284
+ if (fs.existsSync(path.join(home, '.vscode'))) signals.vscode = true;
285
+ if (fs.existsSync(path.join(home, '.config', 'Code'))) signals.vscode = true;
286
+ if (fs.existsSync(path.join(home, '.antigravity'))) signals.antigravity = true;
282
287
  // 3. Env vars commonly set by editor terminals
283
288
  if (process.env.CURSOR_TRACE_ID || /cursor/i.test(process.env.TERM_PROGRAM || '')) signals.cursor = true;
284
289
  if (process.env.CLAUDECODE === '1' || process.env.CLAUDE_CODE_ENTRYPOINT) signals.claude = true;
290
+ if (process.env.VSCODE_PID || /vscode/i.test(process.env.TERM_PROGRAM || '')) signals.vscode = true;
285
291
  return signals;
286
292
  }
287
293
 
@@ -297,43 +303,32 @@ async function resolveIde(opts) {
297
303
  if (opts.yes || !process.stdin.isTTY) return opts.ide || 'claude';
298
304
 
299
305
  const signals = detectIdeSignals(opts.target);
300
- const detected = ['claude', 'cursor', 'gemini'].filter(k => signals[k]);
301
-
302
- // Build the menu β€” detected IDEs marked with a hint
303
- const choices = [
304
- { key: '1', value: 'claude', label: 'Claude Code', hint: signals.claude ? dim('(detected)') : '' },
305
- { key: '2', value: 'cursor', label: 'Cursor', hint: signals.cursor ? dim('(detected)') : '' },
306
- { key: '3', value: 'gemini', label: 'Gemini CLI', hint: signals.gemini ? dim('(detected)') : dim('(beta β€” limited)') },
307
- ];
306
+ const detected = ['claude', 'cursor', 'gemini', 'vscode'].filter(k => signals[k]);
308
307
 
309
308
  // Pick a default: prefer the single detected IDE; otherwise claude
310
309
  let defaultValue = 'claude';
311
310
  if (detected.length === 1) defaultValue = detected[0];
312
311
 
313
- const readline = require('readline');
314
- const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
315
- const prompt = (q) => new Promise(r => rl.question(q, a => r(a)));
312
+ // Use @clack/prompts for arrow-key navigation. Closes #449 / #450.
313
+ const choice = await clack.select({
314
+ message: '🎯 Which editor will you use rcode with?',
315
+ initialValue: defaultValue,
316
+ options: [
317
+ { value: 'claude', label: 'Claude Code', hint: signals.claude ? '(detected)' : undefined },
318
+ { value: 'cursor', label: 'Cursor', hint: signals.cursor ? '(detected)' : undefined },
319
+ { value: 'gemini', label: 'Gemini CLI', hint: signals.gemini ? '(detected)' : '(beta β€” limited)' },
320
+ { value: 'vscode', label: 'VS Code', hint: signals.vscode ? '(detected)' : '(via Continue / Copilot extensions)' },
321
+ { value: 'antigravity', label: 'Antigravity', hint: '(experimental β€” installs to .antigravity/)' },
322
+ ],
323
+ });
316
324
 
317
- console.log(pc.bold('🎯 Which editor will you use Rihal with?'));
318
- console.log('');
319
- for (const c of choices) {
320
- const marker = c.value === defaultValue ? pc.green('●') : dim('β—‹');
321
- const label = c.value === defaultValue ? pc.bold(c.label) : c.label;
322
- console.log(` ${marker} ${pc.cyan('[' + c.key + ']')} ${label} ${c.hint}`);
325
+ // Handle Ctrl-C cleanly
326
+ if (clack.isCancel(choice)) {
327
+ clack.cancel('Install cancelled.');
328
+ process.exit(0);
323
329
  }
324
- console.log('');
325
- const defaultKey = choices.find(c => c.value === defaultValue).key;
326
- const answer = (await prompt(` Pick an editor [${defaultKey}]: `)).trim().toLowerCase();
327
- rl.close();
328
-
329
- if (!answer) return defaultValue;
330
- // Accept either the number key or the name
331
- const byKey = choices.find(c => c.key === answer);
332
- if (byKey) return byKey.value;
333
- const byName = choices.find(c => c.value === answer || c.label.toLowerCase().startsWith(answer));
334
- if (byName) return byName.value;
335
- console.log(dim(` Unrecognised choice "${answer}" β€” falling back to ${defaultValue}.`));
336
- return defaultValue;
330
+
331
+ return choice;
337
332
  }
338
333
 
339
334
  /**
@@ -345,19 +340,21 @@ async function resolveCommitPlanning(opts) {
345
340
  if (opts.commitPlanning !== null) return opts.commitPlanning;
346
341
  if (opts.yes || !process.stdin.isTTY) return true; // non-interactive default
347
342
 
348
- const readline = require('readline');
349
- const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
350
- const prompt = (q) => new Promise(r => rl.question(q, a => r(a)));
351
- console.log('');
352
- console.log('πŸ“‹ .planning/ holds PRDs, roadmaps, sprints, SUMMARY files.');
353
- console.log(' Commit them to git, or keep them local?');
354
- console.log('');
355
- console.log(' [Y] Commit β€” collaborators see the same plans (default, recommended)');
356
- console.log(' [n] Gitignore β€” planning stays local (good for sensitive PRDs)');
357
- console.log('');
358
- const answer = (await prompt(' Commit planning artifacts? [Y/n]: ')).trim().toLowerCase();
359
- rl.close();
360
- return !(answer === 'n' || answer === 'no');
343
+ const choice = await clack.select({
344
+ message: 'πŸ“‹ .planning/ holds PRDs, roadmaps, sprints, SUMMARY files. How should they be tracked?',
345
+ initialValue: 'commit',
346
+ options: [
347
+ { value: 'commit', label: 'Commit', hint: 'collaborators see the same plans (recommended)' },
348
+ { value: 'gitignore', label: 'Gitignore', hint: 'planning stays local (good for sensitive PRDs)' },
349
+ ],
350
+ });
351
+
352
+ if (clack.isCancel(choice)) {
353
+ clack.cancel('Install cancelled.');
354
+ process.exit(0);
355
+ }
356
+
357
+ return choice === 'commit';
361
358
  }
362
359
 
363
360
  function printHelp() {
@@ -1342,6 +1339,7 @@ async function install(opts) {
1342
1339
  let preserved = 0;
1343
1340
  const preservedFiles = [];
1344
1341
  const preservedDiffs = []; // { rel, insertions, deletions, patch } for #251
1342
+ const conflictedFiles = []; // { rel, src, destPath, existingContent, sourceContent } for #451 / #453
1345
1343
  const spinner = createSpinner(dim(`Installing ${plan.length} files…`), { color: 'cyan' }).start();
1346
1344
 
1347
1345
  for (const entry of plan) {
@@ -1381,9 +1379,15 @@ async function install(opts) {
1381
1379
  const sourceHash = sha256(fs.readFileSync(entry.src));
1382
1380
  if (existingHash === sourceHash) { skipped++; continue; }
1383
1381
  if (!opts.yes && !opts.nonDestructive) {
1384
- spinner.stop();
1385
- console.warn(' ' + warn(`${entry.rel} differs from package version β€” use --force-overwrite to overwrite`));
1386
- spinner.start();
1382
+ // Buffer the conflict instead of spamming a warning per file (#451).
1383
+ // Surfaced as a categorised summary post-install + interactive offer (#453).
1384
+ conflictedFiles.push({
1385
+ rel: relForward,
1386
+ src: entry.src,
1387
+ destPath,
1388
+ existingContent: fs.readFileSync(destPath, 'utf8'),
1389
+ sourceContent: fs.readFileSync(entry.src, 'utf8'),
1390
+ });
1387
1391
  skipped++;
1388
1392
  continue;
1389
1393
  }
@@ -1406,6 +1410,100 @@ async function install(opts) {
1406
1410
 
1407
1411
  spinner.success({ text: ok(`${copied} files installed`) });
1408
1412
 
1413
+ // Categorised conflict summary (#451) + interactive resolution offer (#453).
1414
+ // Replaces the per-file 'differs from package version' warning spam.
1415
+ if (conflictedFiles.length > 0) {
1416
+ const byCategory = { workflows: [], agents: [], commands: [], skills: [], references: [], other: [] };
1417
+ for (const c of conflictedFiles) {
1418
+ if (c.rel.includes('/workflows/')) byCategory.workflows.push(c);
1419
+ else if (c.rel.includes('/agents/')) byCategory.agents.push(c);
1420
+ else if (c.rel.includes('/commands/')) byCategory.commands.push(c);
1421
+ else if (c.rel.includes('/skills/')) byCategory.skills.push(c);
1422
+ else if (c.rel.includes('/references/')) byCategory.references.push(c);
1423
+ else byCategory.other.push(c);
1424
+ }
1425
+ console.log('');
1426
+ console.log(' ' + warn(`${conflictedFiles.length} file${conflictedFiles.length === 1 ? '' : 's'} have local edits AND v${readPackageVersion()} updates:`));
1427
+ for (const [cat, list] of Object.entries(byCategory)) {
1428
+ if (list.length === 0) continue;
1429
+ console.log(' ' + dim(`${list.length} ${cat}`));
1430
+ }
1431
+ console.log('');
1432
+
1433
+ if (!opts.yes && process.stdin.isTTY) {
1434
+ const action = await clack.select({
1435
+ message: 'How should we handle these?',
1436
+ initialValue: 'review',
1437
+ options: [
1438
+ { value: 'review', label: 'Review each one', hint: 'see the diff, decide per file' },
1439
+ { value: 'upstream', label: 'Take v' + readPackageVersion() + ' for all', hint: 'lose local edits, get all bug fixes' },
1440
+ { value: 'keep', label: 'Keep my local edits', hint: 'skip v' + readPackageVersion() + ' updates for these files (current behaviour)' },
1441
+ ],
1442
+ });
1443
+ if (clack.isCancel(action)) {
1444
+ clack.note('Skipped β€” local edits preserved.');
1445
+ } else if (action === 'upstream') {
1446
+ let applied = 0;
1447
+ for (const c of conflictedFiles) {
1448
+ fs.writeFileSync(c.destPath, c.sourceContent, 'utf8');
1449
+ applied++;
1450
+ }
1451
+ console.log(' ' + ok(`Applied v${readPackageVersion()} to ${applied} file${applied === 1 ? '' : 's'}.`));
1452
+ } else if (action === 'review') {
1453
+ let applied = 0, kept = 0;
1454
+ for (const c of conflictedFiles) {
1455
+ const patch = createTwoFilesPatch(c.rel, c.rel, c.existingContent, c.sourceContent, 'local', 'v' + readPackageVersion());
1456
+ let ins = 0, del = 0;
1457
+ for (const line of patch.split('\n')) {
1458
+ if (line.startsWith('+') && !line.startsWith('+++')) ins++;
1459
+ if (line.startsWith('-') && !line.startsWith('---')) del++;
1460
+ }
1461
+ console.log('');
1462
+ console.log(' ' + pc.bold(c.rel) + dim(' ') + pc.green(`+${ins}`) + ' ' + pc.red(`-${del}`));
1463
+ const decision = await clack.select({
1464
+ message: 'Take upstream, keep local, or view diff?',
1465
+ initialValue: 'view',
1466
+ options: [
1467
+ { value: 'upstream', label: 'Take v' + readPackageVersion() },
1468
+ { value: 'keep', label: 'Keep local' },
1469
+ { value: 'view', label: 'View diff first' },
1470
+ ],
1471
+ });
1472
+ let finalAction = decision;
1473
+ if (clack.isCancel(decision) || decision === 'view') {
1474
+ for (const line of patch.split('\n').slice(4)) {
1475
+ if (line.startsWith('+')) process.stdout.write(pc.green(line) + '\n');
1476
+ else if (line.startsWith('-')) process.stdout.write(pc.red(line) + '\n');
1477
+ else if (line.startsWith('@')) process.stdout.write(pc.cyan(line) + '\n');
1478
+ else process.stdout.write(dim(line) + '\n');
1479
+ }
1480
+ const after = await clack.select({
1481
+ message: 'Now: take upstream or keep local?',
1482
+ initialValue: 'keep',
1483
+ options: [
1484
+ { value: 'upstream', label: 'Take v' + readPackageVersion() },
1485
+ { value: 'keep', label: 'Keep local' },
1486
+ ],
1487
+ });
1488
+ finalAction = clack.isCancel(after) ? 'keep' : after;
1489
+ }
1490
+ if (finalAction === 'upstream') {
1491
+ fs.writeFileSync(c.destPath, c.sourceContent, 'utf8');
1492
+ applied++;
1493
+ } else {
1494
+ kept++;
1495
+ }
1496
+ }
1497
+ console.log(' ' + ok(`Review complete: ${applied} applied, ${kept} kept local.`));
1498
+ } else {
1499
+ console.log(' ' + dim(`${conflictedFiles.length} file${conflictedFiles.length === 1 ? '' : 's'} kept local. Re-run with --force-overwrite or 'rcode update' anytime.`));
1500
+ }
1501
+ } else {
1502
+ console.log(' ' + dim(`Re-run with --force-overwrite to apply v${readPackageVersion()} updates, or pipe through an interactive shell to resolve per-file.`));
1503
+ }
1504
+ console.log('');
1505
+ }
1506
+
1409
1507
  // Write .rihal/_config/manifest.yaml + agent-manifest.csv + files-manifest.csv
1410
1508
  const configDir = path.join(opts.target, '.rihal', '_config');
1411
1509
  ensureDir(configDir);