@hanzlaa/rcode 4.4.1 → 4.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -23,7 +23,7 @@ pnpm dlx @hanzlaa/rcode install
23
23
  [![CI](https://github.com/hanzlahabib/rcode/actions/workflows/test.yml/badge.svg)](https://github.com/hanzlahabib/rcode/actions/workflows/test.yml)
24
24
  [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
25
25
 
26
- Status: `@hanzlaa/rcode` v4.4.1 on npm. 45 agents · 116 commands · 129 workflows · **1 runtime dependency**. Test status tracked by CI badge above. Actively dogfooded on real projects every week.
26
+ Status: `@hanzlaa/rcode` v4.4.2 on npm. 45 agents · 116 commands · 129 workflows · **1 runtime dependency**. Test status tracked by CI badge above. Actively dogfooded on real projects every week.
27
27
 
28
28
  ---
29
29
 
@@ -127,18 +127,18 @@ The point isn't "I beat LangChain." The point is **you don't need LangChain for
127
127
  > node benchmarks/facts.cjs
128
128
  > ```
129
129
 
130
- <p align="center"><img src="brand/hero-receipt.png" alt="benchmarks/facts.cjs output — 497 tests, 0 failing · 45 agents · 116 commands · 1 runtime dependency, computed from files on disk" width="720"></p>
131
-
132
130
  | Metric | Value | Why it's not a vanity number |
133
131
  |---|---|---|
134
- | **Portable methodology corpus** | **94,481 lines** of markdown | A 10-person eng org's playbooks (agents + commands + workflows + skills + references) — as files you own and grep, not a SaaS you rent. |
135
- | **Automated tests** | **497**, 100% passing across 61 files | The methodology is *guarded*, not vibes. CI runs them on every push; `node --test` reproduces locally in seconds. |
136
- | **Tested CLI engine** | **9,005 lines** (`rcode-tools.cjs` + `lib/`) | The deterministic brain — routing, state, planning math — is real code under test, not prompt soup. |
137
- | **Runtime dependencies** | **1** (`ws`, for the dashboard socket) | The view-only dashboard is pure Node stdlib. Almost nothing to audit, nothing to CVE-scan, nothing to break on `npm install`. |
138
- | **Specialist agents / commands / workflows / skills** | **45 / 116 / 129 / 88** | An entire engineering org, phrase-activated, that travels with you across Claude Code, Cursor, Codex, VS Code, Antigravity, Windsurf. |
139
- | **Core-op latency** | **~33 ms**, **0 LLM tokens** (best-of-7) | Intent routing, state reads, and milestone-health are deterministic *local* compute — a few ms over Node's own cold-start floor. The orchestration layer doesn't burn API tokens on bookkeeping the way pure-LLM agent frameworks do. |
140
-
141
- **The headline:** an entire software-delivery methodology — 94k lines of it — guarded by 497 tests, riding on a single runtime dependency, with an orchestration brain that costs **zero tokens** to think. Not a viral prompt. A system you can verify line by line.
132
+ | **Portable methodology corpus** | **~105,000 lines** of markdown | A 10-person eng org's playbooks (agents + commands + workflows + skills + references) — as files you own and grep, not a SaaS you rent. |
133
+ | **Automated tests** | **495** across 62 files | The methodology is *guarded*, not vibes. Live pass/fail status is on the CI badge above; `node --test` (or `node benchmarks/facts.cjs`) reproduces locally in seconds. |
134
+ | **Tested CLI engine** | **~9,700 lines** (`rcode-tools.cjs` + `lib/`) | The deterministic brain — routing, state, planning math — is real code under test, not prompt soup. |
135
+ | **Runtime dependencies** | **1** (`ws`, for the dashboard socket) | The dashboard is otherwise pure Node stdlib. Almost nothing to audit, nothing to CVE-scan, nothing to break on `npm install`. |
136
+ | **Specialist agents / commands / workflows / skills** | **45 / 117 / 129 / 96** | An entire engineering org, phrase-activated, that travels with you across Claude Code, Cursor, Codex, VS Code, Antigravity, Windsurf. |
137
+ | **Core-op latency** | **~60 ms**, **0 LLM tokens** (best-of-7) | Intent routing, state reads, and milestone-health are deterministic *local* compute — a few ms over Node's own cold-start floor. The orchestration layer doesn't burn API tokens on bookkeeping the way pure-LLM agent frameworks do. |
138
+
139
+ > Counts above are produced by `node benchmarks/facts.cjs` and may drift slightly between releases run it for the exact current figures.
140
+
141
+ **The headline:** an entire software-delivery methodology — ~105k lines of it — guarded by a real test suite, riding on a single runtime dependency, with an orchestration brain that costs **zero tokens** to think. Not a viral prompt. A system you can verify line by line.
142
142
 
143
143
  ---
144
144
 
package/cli/install.js CHANGED
@@ -825,15 +825,20 @@ function seedStarterPlanning(target, projectName) {
825
825
 
826
826
  const state = {
827
827
  version: '1',
828
- project: resolvedProject,
828
+ // #940 — match the canonical schema (cli/lib/schemas.cjs stateSchema):
829
+ // schema_version is required, milestones is a plural array. Without these
830
+ // a freshly-installed state.json failed `rcode-tools validate` until the
831
+ // first migrateState() read. Write conformant state up front.
832
+ schema_version: 2,
833
+ project: resolvedProject || path.basename(target),
829
834
  ...(isStubProject ? { _seeded_stub: true } : {}),
830
835
  created: now,
831
836
  updated: now,
832
837
  current_phase: resolvedPhase,
833
838
  current_plan: 0,
834
839
  current_sprint: null,
835
- milestone: null,
836
840
  phases: [],
841
+ milestones: [],
837
842
  executions: [],
838
843
  decisions: [],
839
844
  blockers: [],
package/dist/rcode.js CHANGED
@@ -196,7 +196,7 @@ _None._
196
196
  ## Next Action
197
197
 
198
198
  Run \`/rcode-new-project <description>\` to bootstrap, or \`/rcode-sprint-planning\` once a real phase exists.
199
- `);let c=p.join(t,".rcode","state.json");function l(){let d=p.join(t,".planning","ROADMAP.md");if(!D.existsSync(d))return!0;try{return D.readFileSync(d,"utf8").includes("<!-- INSTALL STUB")}catch{return!0}}if(!D.existsSync(c)){let d=new Date().toISOString(),f=l(),g=null,m=p.join(t,".rcode","config.yaml");if(D.existsSync(m))try{let F=D.readFileSync(m,"utf8").match(/^project_name:\s*"?([^"\n]+)"?/m);F&&(g=F[1].trim())}catch{}let y=null,h=p.join(t,".planning","ROADMAP.md");if(!f&&D.existsSync(h))try{let b=D.readFileSync(h,"utf8"),F=b.match(/^\|\s*(\d+(?:\.\d+)?)\s*\|/m);if(F)y=String(parseInt(F[1],10));else{let T=b.match(/^#{2,4}\s*Phase\s+(\d+(?:\.\d+)?)/im);T&&(y=String(parseInt(T[1],10)))}}catch{}let w={version:"1",project:g,...f?{_seeded_stub:!0}:{},created:d,updated:d,current_phase:y,current_plan:0,current_sprint:null,milestone:null,phases:[],executions:[],decisions:[],blockers:[],council_sessions:[],chains:[],workstreams:[],active_workstream:null,last_session:null,velocity_history:[]};D.mkdirSync(p.dirname(c),{recursive:!0}),Ft(c,JSON.stringify(w,null,2)+`
199
+ `);let c=p.join(t,".rcode","state.json");function l(){let d=p.join(t,".planning","ROADMAP.md");if(!D.existsSync(d))return!0;try{return D.readFileSync(d,"utf8").includes("<!-- INSTALL STUB")}catch{return!0}}if(!D.existsSync(c)){let d=new Date().toISOString(),f=l(),g=null,m=p.join(t,".rcode","config.yaml");if(D.existsSync(m))try{let F=D.readFileSync(m,"utf8").match(/^project_name:\s*"?([^"\n]+)"?/m);F&&(g=F[1].trim())}catch{}let y=null,h=p.join(t,".planning","ROADMAP.md");if(!f&&D.existsSync(h))try{let b=D.readFileSync(h,"utf8"),F=b.match(/^\|\s*(\d+(?:\.\d+)?)\s*\|/m);if(F)y=String(parseInt(F[1],10));else{let T=b.match(/^#{2,4}\s*Phase\s+(\d+(?:\.\d+)?)/im);T&&(y=String(parseInt(T[1],10)))}}catch{}let w={version:"1",schema_version:2,project:g||p.basename(t),...f?{_seeded_stub:!0}:{},created:d,updated:d,current_phase:y,current_plan:0,current_sprint:null,phases:[],milestones:[],executions:[],decisions:[],blockers:[],council_sessions:[],chains:[],workstreams:[],active_workstream:null,last_session:null,velocity_history:[]};D.mkdirSync(p.dirname(c),{recursive:!0}),Ft(c,JSON.stringify(w,null,2)+`
200
200
  `)}return!0}function uk(t,e={}){let r=e.commitPlanning!==!1,n="# ===== rcode-managed gitignore block (npx @hanzlaa/rcode install) =====",s="# ===== end rcode-managed gitignore block =====",i=["",n,"# Added automatically on first rcode install. Idempotent \u2014 safe to re-run.","# Edit `commit_planning` in .rcode/config.yaml to flip planning-artifact tracking.","","# Installed methodology files (regenerate with: npx @hanzlaa/rcode install)",".claude/",".rcode/bin/",".rcode/workflows/",".rcode/references/",".rcode/commands/",".rcode/skills/","","# Pulled rcode brain content (refresh with: rcode brain pull)",".rcode/brain/rcode-github/",".rcode/brain/rcode-docs/",".rcode/brain/best-practices/","","# Runtime noise","node_modules/",".rcode/state.json.lock",".planning/debug/",".planning/_backup/"];r||i.push("","# Planning artifacts \u2014 kept local (commit_planning: false)",".planning/"),i.push("","# What you DO commit:","# .rcode/config.yaml - project mode/language/profile/commit_planning","# .rcode/state.json - decisions, roadmap pointer, blockers","# .rcode/brain/sources.yaml - brain source manifest",r?"# .planning/ - PRD, roadmap, sprints, SUMMARY.md files":"# (planning artifacts are NOT committed \u2014 see commit_planning in config)",s,"");let o=i.join(`
201
201
  `),a=p.join(t,".gitignore");try{let l=function(d,f){let g=d.indexOf(n);if(g<0)return null;let m=d.indexOf(s,g);if(m<0){let w=g;return w>0&&d[w-1]===`
202
202
  `&&(w-=1),d.slice(0,w)+f}let y=g;y>0&&d[y-1]===`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hanzlaa/rcode",
3
- "version": "4.4.1",
3
+ "version": "4.4.2",
4
4
  "description": "rcode — the AI team that never forgets. Persistent memory, specialist agents, and slash commands for AI IDEs. Works in Claude Code, Cursor, Gemini, VS Code, and Antigravity.",
5
5
  "main": "cli/index.js",
6
6
  "bin": {
@@ -7596,21 +7596,43 @@ async function main() {
7596
7596
  const validateErrors = [];
7597
7597
 
7598
7598
  if (target === 'state' || target === 'all') {
7599
- const state = readState();
7600
- if (!state) {
7601
- validateErrors.push('state: state.json not found or empty');
7599
+ // Read state.json directly readState() is scoped inside cmdState()
7600
+ // and isn't reachable here (#940). Validate against the REAL schema:
7601
+ // phases[] + milestones[], current_phase nullable on fresh installs.
7602
+ const statePathV = path.join(RCODE_DIR, 'state.json');
7603
+ if (!fs.existsSync(statePathV)) {
7604
+ validateErrors.push('state: state.json not found — run rcode install');
7602
7605
  } else {
7603
- if (!state.current_phase) validateErrors.push('state: missing current_phase');
7604
- if (!state.current_milestone) validateErrors.push('state: missing current_milestone');
7605
- if (state.schema_version !== 2) validateErrors.push(`state: schema_version should be 2, got ${state.schema_version}`);
7606
- if (!Array.isArray(state.phases) && typeof state.phases !== 'object') validateErrors.push('state: phases must be array or object');
7606
+ let state = null;
7607
+ try {
7608
+ state = JSON.parse(fs.readFileSync(statePathV, 'utf8'));
7609
+ } catch (e) {
7610
+ validateErrors.push(`state: invalid JSON — ${e.message}`);
7611
+ }
7612
+ if (state) {
7613
+ // current_phase is legitimately null on a fresh / stub project,
7614
+ // so do NOT require it. milestones is an array (no current_milestone field).
7615
+ // schema_version 1 is valid on disk — migrateState() upgrades it to 2
7616
+ // transparently on read, so accept either and only flag the unknown.
7617
+ if (state.schema_version != null && ![1, 2].includes(state.schema_version)) {
7618
+ validateErrors.push(`state: unknown schema_version ${state.schema_version} (expected 1 or 2)`);
7619
+ }
7620
+ if (state.phases != null && !Array.isArray(state.phases) && typeof state.phases !== 'object') {
7621
+ validateErrors.push('state: phases must be an array or object');
7622
+ }
7623
+ if (state.milestones != null && !Array.isArray(state.milestones)) {
7624
+ validateErrors.push('state: milestones must be an array');
7625
+ }
7626
+ }
7607
7627
  }
7608
7628
  }
7609
7629
 
7610
7630
  if (target === 'config' || target === 'all') {
7631
+ // config.yaml holds project identity + workflow prefs only — it does
7632
+ // NOT track current_phase (that lives in state.json). Only require
7633
+ // the fields config actually owns (#940).
7611
7634
  const config = readConfig();
7612
7635
  if (!config.project_name) validateErrors.push('config: missing project_name');
7613
- if (!config.current_phase && !config.phase) validateErrors.push('config: missing current_phase or phase');
7614
7636
  }
7615
7637
 
7616
7638
  if (validateErrors.length) {
@@ -5,6 +5,12 @@ argument-hint: "[challenge or code to simplify] [--intensity=lite|full|ultra]"
5
5
  allowed-tools:
6
6
  - Read
7
7
  - AskUserQuestion
8
+ - Skill
8
9
  ---
9
10
 
10
- @rcode/skills/core/rcode-lazy/SKILL.md
11
+ Invoke the `rcode-lazy` skill (via the Skill tool) and apply it to: $ARGUMENTS
12
+
13
+ `rcode-lazy` is the always-on "lazy senior dev" lens — it forces the simplest
14
+ solution that actually works (YAGNI, stdlib before custom code, native platform
15
+ features before dependencies, one line before fifty) before any code is written.
16
+ Pass `--intensity=lite|full|ultra` through if the user provided it; default is `full`.