@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.
- package/AGENTS.md +11 -1
- package/CONTRIBUTING.md +7 -0
- package/README.md +39 -20
- package/cli/install.js +145 -47
- package/dist/rcode.js +134 -43
- package/package.json +2 -2
- package/rihal/agents/rihal-advisor-researcher.md +1 -1
- package/rihal/agents/rihal-assumptions-analyzer.md +1 -1
- package/rihal/agents/rihal-codebase-mapper.md +1 -1
- package/rihal/agents/rihal-docs-auditor.md +3 -3
- package/rihal/agents/rihal-executor.md +10 -0
- package/rihal/agents/rihal-integration-checker.md +1 -1
- package/rihal/agents/rihal-noor.md +2 -2
- package/rihal/agents/rihal-phase-researcher.md +1 -1
- package/rihal/agents/rihal-planner.md +25 -0
- package/rihal/agents/rihal-project-researcher.md +1 -1
- package/rihal/agents/rihal-research-synthesizer.md +1 -1
- package/rihal/agents/rihal-roadmapper.md +1 -1
- package/rihal/agents/rihal-sprint-checker.md +19 -1
- package/rihal/agents/rihal-verifier.md +1 -1
- package/rihal/agents/rihal-waleed.md +1 -2
- package/rihal/commands/code-review.md +1 -1
- package/rihal/commands/memory-audit.md +10 -0
- package/rihal/commands/memory-distill.md +11 -0
- package/rihal/commands/memory-init.md +12 -0
- package/rihal/commands/memory-update.md +12 -0
- package/rihal/config/model-profiles.json +5 -5
- package/rihal/references/karpathy-guidelines-full.md +1 -1
- package/rihal/references/no-unauthorized-git-ops.md +1 -1
- package/rihal/references/verb-dictionary.md +1 -1
- package/rihal/skills/actions/2-plan/rihal-frontend-design/SKILL.md +49 -139
- package/rihal/skills/actions/2-plan/rihal-frontend-design/references.md +79 -0
- package/rihal/skills/actions/4-implementation/rihal-browser-verify/SKILL.md +70 -0
- package/rihal/skills/actions/4-implementation/rihal-checkpoint-preview/SKILL.md +1 -1
- package/rihal/skills/actions/4-implementation/rihal-ci/SKILL.md +108 -0
- package/rihal/skills/actions/4-implementation/rihal-debug/SKILL.md +78 -0
- package/rihal/skills/actions/4-implementation/rihal-git-flow/SKILL.md +90 -0
- package/rihal/skills/actions/4-implementation/rihal-harden/SKILL.md +91 -0
- package/rihal/skills/actions/4-implementation/rihal-incremental/SKILL.md +50 -0
- package/rihal/skills/actions/4-implementation/rihal-migrate/SKILL.md +86 -0
- package/rihal/skills/actions/4-implementation/rihal-perf/SKILL.md +96 -0
- package/rihal/skills/actions/4-implementation/rihal-prove-it/SKILL.md +64 -0
- package/rihal/skills/actions/4-implementation/rihal-source-truth/SKILL.md +76 -0
- package/rihal/skills/actions/4-implementation/rihal-trim/SKILL.md +73 -0
- package/rihal/skills/agents/dalil-scout/SKILL.md +43 -125
- package/rihal/skills/agents/dalil-scout/references.md +67 -0
- package/rihal/skills/agents/majlis-council/SKILL.md +50 -144
- package/rihal/skills/agents/majlis-council/references.md +90 -0
- package/rihal/skills/agents/raees-orchestrator/SKILL.md +56 -117
- package/rihal/skills/agents/raees-orchestrator/references.md +47 -0
- package/rihal/skills/core/rihal-advanced-elicitation/SKILL.md +36 -136
- package/rihal/skills/core/rihal-advanced-elicitation/references.md +101 -0
- package/rihal/skills/core/rihal-auth-audit/SKILL.md +93 -0
- package/rihal/skills/core/rihal-brainstorming/SKILL.md +5 -0
- package/rihal/skills/core/rihal-client-gate/SKILL.md +91 -0
- package/rihal/skills/core/rihal-clone-website/SKILL.md +30 -371
- package/rihal/skills/core/rihal-clone-website/references.md +213 -0
- package/rihal/skills/core/rihal-deploy-unify/SKILL.md +87 -0
- package/rihal/skills/core/rihal-distillator/SKILL.md +37 -187
- package/rihal/skills/core/rihal-distillator/references.md +118 -0
- package/rihal/skills/core/rihal-editorial-review-prose/SKILL.md +5 -0
- package/rihal/skills/core/rihal-editorial-review-structure/SKILL.md +45 -183
- package/rihal/skills/core/rihal-editorial-review-structure/references.md +110 -0
- package/rihal/skills/core/rihal-help/SKILL.md +6 -1
- package/rihal/skills/core/rihal-incident-record/SKILL.md +161 -0
- package/rihal/skills/core/rihal-index-docs/SKILL.md +5 -0
- package/rihal/skills/core/rihal-init/SKILL.md +5 -0
- package/rihal/skills/core/rihal-memory-audit/SKILL.md +88 -0
- package/rihal/skills/core/rihal-memory-distill/SKILL.md +87 -0
- package/rihal/skills/core/rihal-memory-init/SKILL.md +77 -0
- package/rihal/skills/core/rihal-memory-update/SKILL.md +73 -0
- package/rihal/skills/core/rihal-mvp-graduate/SKILL.md +116 -0
- package/rihal/skills/core/rihal-ocr-consistency/SKILL.md +106 -0
- package/rihal/skills/core/rihal-party-mode/SKILL.md +5 -0
- package/rihal/skills/core/rihal-rebrand/SKILL.md +133 -0
- package/rihal/skills/core/rihal-review-adversarial-general/SKILL.md +5 -0
- package/rihal/skills/core/rihal-review-edge-case-hunter/SKILL.md +5 -0
- package/rihal/skills/core/rihal-shard-doc/SKILL.md +5 -0
- package/rihal/skills/core/rihal-theme-system/SKILL.md +113 -0
- package/rihal/team.yaml +3 -22
- package/rihal/templates/memory/INDEX.md +46 -0
- package/rihal/templates/memory/change-records/.gitkeep +4 -0
- package/rihal/templates/memory/distillates/project.distillate.md +11 -0
- package/rihal/templates/memory/distillates/stack.distillate.md +11 -0
- package/rihal/templates/memory/incidents/known-issues.md +27 -0
- package/rihal/templates/memory/incidents/post-mortems/.gitkeep +3 -0
- package/rihal/templates/memory/milestones/archive/.gitkeep +2 -0
- package/rihal/templates/memory/milestones/current.md +39 -0
- package/rihal/templates/memory/people/stakeholders.md +25 -0
- package/rihal/templates/memory/people/team.md +35 -0
- package/rihal/templates/memory/project/decisions.md +32 -0
- package/rihal/templates/memory/project/glossary.md +16 -0
- package/rihal/templates/memory/project/stack.md +46 -0
- package/rihal/workflows/audit.md +3 -3
- package/rihal/workflows/code-review.md +32 -1
- package/rihal/workflows/council.md +1 -1
- package/rihal/workflows/discuss-phase-power.md +3 -3
- package/rihal/workflows/do.md +1 -1
- package/rihal/workflows/docs-update.md +4 -4
- package/rihal/workflows/execute.md +61 -5
- package/rihal/workflows/help.md +5 -5
- package/rihal/workflows/karpathy-audit.md +9 -9
- package/rihal/workflows/memory-audit.md +83 -0
- package/rihal/workflows/memory-distill.md +103 -0
- package/rihal/workflows/memory-init.md +102 -0
- package/rihal/workflows/memory-update.md +83 -0
- package/rihal/workflows/plan.md +66 -1
- package/server/dashboard.js +6 -1
- package/server/lib/api.js +8 -2
- package/server/lib/html/client.js +63 -0
- package/server/lib/html/shell.js +5 -0
- package/server/lib/scanner.js +76 -1
- package/rihal/agents/rihal-architect.md +0 -79
- package/rihal/agents/rihal-tech-writer.md +0 -80
- package/rihal/commands/check-implementation-readiness.md +0 -8
- package/rihal/commands/discuss-phase-power.md +0 -11
- package/rihal/commands/karpathy-audit.md +0 -12
- package/rihal/commands/new-project-research.md +0 -11
- package/rihal/commands/new-project-roadmap.md +0 -11
- package/rihal/commands/report.md +0 -10
- package/rihal/commands/review-adversarial.md +0 -8
- 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
|
-
> **
|
|
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
|
|
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
|
-
**
|
|
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
|
-
- **
|
|
41
|
-
- **
|
|
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/` β
|
|
69
|
-
- `.claude/commands/rihal/` β
|
|
70
|
-
- `.claude/skills/` β
|
|
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:
|
|
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-
|
|
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
|
|
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:
|
|
263
|
-
/rihal:
|
|
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 (
|
|
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`
|
|
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`
|
|
346
|
+
`execute` Β· `quick` Β· `autonomous` Β· `audit-fix` Β· `undo`
|
|
328
347
|
|
|
329
348
|
### Observability + review
|
|
330
|
-
`code-review` Β· `code-review-fix` Β· `
|
|
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 β
|
|
450
|
-
β skills + commands installed β
|
|
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
|
-
|
|
314
|
-
const
|
|
315
|
-
|
|
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
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
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
|
-
|
|
325
|
-
|
|
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
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
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
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
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);
|