@hanzlaa/rcode 3.4.32 → 3.5.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 (86) hide show
  1. package/AGENTS.md +6 -6
  2. package/CONTRIBUTING.md +2 -0
  3. package/LICENSE +21 -0
  4. package/README.md +66 -403
  5. package/cli/agent.js +3 -2
  6. package/cli/doctor.js +87 -1
  7. package/cli/install.js +122 -31
  8. package/cli/lib/schemas.cjs +318 -0
  9. package/cli/postinstall.js +19 -3
  10. package/dist/rcode.js +318 -24
  11. package/package.json +8 -4
  12. package/rihal/agents/rihal-cross-platform-auditor.md +15 -0
  13. package/rihal/agents/rihal-dep-auditor.md +15 -0
  14. package/rihal/agents/rihal-docs-auditor.md +3 -145
  15. package/rihal/agents/rihal-i18n-auditor.md +16 -0
  16. package/rihal/agents/rihal-nyquist-auditor.md +4 -156
  17. package/rihal/agents/rihal-observability-auditor.md +16 -0
  18. package/rihal/agents/rihal-phase-researcher.md +1 -1
  19. package/rihal/agents/rihal-planner.md +1 -1
  20. package/rihal/bin/rihal-hooks.cjs +394 -4
  21. package/rihal/bin/rihal-tools.cjs +891 -24
  22. package/rihal/commands/create-prd.md +18 -0
  23. package/rihal/commands/execute-milestone.md +18 -0
  24. package/rihal/commands/plan-milestone.md +18 -0
  25. package/rihal/commands/scaffold-milestone.md +18 -0
  26. package/rihal/commands/scaffold-skill.md +18 -0
  27. package/rihal/references/REFERENCES_INDEX.md +49 -7
  28. package/rihal/references/agent-contracts.md +10 -0
  29. package/rihal/references/design-tokens.md +98 -0
  30. package/rihal/references/docs-auditor-playbook.md +148 -0
  31. package/rihal/references/git-preflight.md +117 -0
  32. package/rihal/references/iterative-retrieval.md +85 -0
  33. package/rihal/references/nyquist-auditor-playbook.md +157 -0
  34. package/rihal/references/workstream-flag.md +2 -2
  35. package/rihal/skills/actions/1-analysis/rihal-prfaq/SKILL.md +9 -0
  36. package/rihal/skills/actions/4-implementation/rihal-checkpoint-preview/SKILL.md +9 -0
  37. package/rihal/skills/actions/4-implementation/rihal-ci/SKILL.md +4 -0
  38. package/rihal/skills/actions/4-implementation/rihal-code-review/steps/step-02-review.md +7 -3
  39. package/rihal/skills/actions/4-implementation/rihal-harden/SKILL.md +4 -0
  40. package/rihal/skills/actions/4-implementation/rihal-migrate/SKILL.md +4 -0
  41. package/rihal/skills/agents/haitham-frontend/SKILL.md +2 -0
  42. package/rihal/skills/agents/majlis-council/SKILL.md +1 -1
  43. package/rihal/team.yaml +32 -0
  44. package/rihal/templates/settings-hooks.json +39 -0
  45. package/rihal/workflows/check-todos.md +4 -0
  46. package/rihal/workflows/code-review-fix.md +4 -3
  47. package/rihal/workflows/code-review.md +1 -1
  48. package/rihal/workflows/debug.md +1 -1
  49. package/rihal/workflows/dev-story.md +4 -0
  50. package/rihal/workflows/diff.md +2 -2
  51. package/rihal/workflows/do.md +16 -8
  52. package/rihal/workflows/docs-update.md +2 -2
  53. package/rihal/workflows/enable-hooks.md +6 -1
  54. package/rihal/workflows/execute-milestone.md +139 -0
  55. package/rihal/workflows/execute-regression-gates.md +1 -1
  56. package/rihal/workflows/execute-sprint.md +54 -2
  57. package/rihal/workflows/execute-verify-phase-goal.md +31 -4
  58. package/rihal/workflows/execute-waves.md +33 -5
  59. package/rihal/workflows/execute.md +40 -6
  60. package/rihal/workflows/help.md +1 -1
  61. package/rihal/workflows/import.md +1 -1
  62. package/rihal/workflows/lens-audit.md +39 -23
  63. package/rihal/workflows/list-workspaces.md +1 -1
  64. package/rihal/workflows/map-codebase.md +4 -4
  65. package/rihal/workflows/new-milestone.md +18 -1
  66. package/rihal/workflows/new-project-research.md +53 -1
  67. package/rihal/workflows/new-workspace.md +1 -1
  68. package/rihal/workflows/plan-milestone.md +105 -0
  69. package/rihal/workflows/plan-research-validation.md +1 -1
  70. package/rihal/workflows/plan-spawn-planner.md +1 -1
  71. package/rihal/workflows/plan.md +31 -3
  72. package/rihal/workflows/plant-seed.md +6 -0
  73. package/rihal/workflows/quick.md +11 -5
  74. package/rihal/workflows/research-phase.md +24 -0
  75. package/rihal/workflows/scaffold-milestone.md +60 -0
  76. package/rihal/workflows/scaffold-skill.md +137 -0
  77. package/rihal/workflows/scan.md +1 -1
  78. package/rihal/workflows/session-report.md +43 -3
  79. package/rihal/workflows/verify-work.md +3 -3
  80. package/server/dashboard.js +53 -6
  81. package/server/lib/api.js +7 -0
  82. package/server/lib/html/client.js +725 -13
  83. package/server/lib/html/css.js +2046 -466
  84. package/server/lib/html/shell.js +227 -134
  85. package/server/lib/scanner.js +33 -0
  86. package/server/orchestrator.js +438 -0
@@ -75,7 +75,40 @@ Extract counts:
75
75
  - **Chains:** count of `*-chain.md` files
76
76
  - **Discusses:** count of `*-discuss.md` files
77
77
 
78
- ## Step 5 — Estimate token usage
78
+ ## Step 5 — Token usage (measured or estimated)
79
+
80
+ ### Step 5a — Prefer measured totals from cost.jsonl
81
+
82
+ If the `cost-track` hook (#745) is enabled, it appends one usage record per
83
+ response to `.rihal/telemetry/cost.jsonl`. Check for it first:
84
+
85
+ ```bash
86
+ test -f .rihal/telemetry/cost.jsonl && echo "measured" || echo "estimated"
87
+ ```
88
+
89
+ **If `.rihal/telemetry/cost.jsonl` exists:** sum the `input_tokens` and
90
+ `output_tokens` across every line and report the **measured** totals — label
91
+ them clearly as "measured":
92
+
93
+ ```bash
94
+ node -e "
95
+ const fs=require('fs');
96
+ let i=0,o=0,n=0;
97
+ for(const l of fs.readFileSync('.rihal/telemetry/cost.jsonl','utf8').split('\n').filter(Boolean)){
98
+ try{const r=JSON.parse(l);i+=r.input_tokens||0;o+=r.output_tokens||0;n++;}catch{}
99
+ }
100
+ console.log('responses='+n,'input='+i,'output='+o,'total='+(i+o));
101
+ "
102
+ ```
103
+
104
+ Report: `Total (measured): {input} input + {output} output = {total} tokens
105
+ across {responses} responses`. Skip the heuristic estimate below — measured
106
+ data supersedes it.
107
+
108
+ **If `.rihal/telemetry/cost.jsonl` does NOT exist:** fall back to the heuristic
109
+ estimate in Step 5b and label the result "estimated".
110
+
111
+ ### Step 5b — Heuristic estimate (fallback only)
79
112
 
80
113
  Calculate estimated tokens (note: these are rough approximations, not actual measurements).
81
114
 
@@ -135,9 +168,16 @@ Write `.planning/SESSION-REPORT-{YYYY-MM-DD-HHmmss}.md` with this structure:
135
168
  - **Blockers Identified:** {count} ({open_count} open)
136
169
  - **Commits:** {count}
137
170
 
138
- ## Estimated Token Usage
171
+ ## Token Usage ({measured|estimated})
172
+
173
+ **If cost.jsonl exists — measured:**
174
+
175
+ - Responses tracked: {count}
176
+ - Input tokens: {input}
177
+ - Output tokens: {output}
178
+ - **Total (measured): {grand_total} tokens**
139
179
 
140
- **Note:** Token estimates are approximations based on artifact counts.
180
+ **If cost.jsonl absent estimated** (approximations based on artifact counts):
141
181
 
142
182
  - Council Sessions: {count} × 50K = {total}K
143
183
  - Chains: {count} × 30K = {total}K
@@ -523,7 +523,7 @@ Plans must be executable prompts.
523
523
  </downstream_consumer>
524
524
  """,
525
525
  subagent_type="rihal-planner",
526
- model="sonnet",
526
+ model="{model}",
527
527
  model="{planner_model}",
528
528
  description="Plan gap fixes for Phase {phase}"
529
529
  )
@@ -573,7 +573,7 @@ Return one of:
573
573
  </expected_output>
574
574
  """,
575
575
  subagent_type="rihal-sprint-checker",
576
- model="sonnet",
576
+ model="{model}",
577
577
  model="{checker_model}",
578
578
  description="Verify Phase {phase} fix plans"
579
579
  )
@@ -618,7 +618,7 @@ Do NOT replan from scratch unless issues are fundamental.
618
618
  </instructions>
619
619
  """,
620
620
  subagent_type="rihal-planner",
621
- model="sonnet",
621
+ model="{model}",
622
622
  model="{planner_model}",
623
623
  description="Revise Phase {phase} plans"
624
624
  )
@@ -20,8 +20,10 @@
20
20
  * Stop: kill $(lsof -t -i:7717)
21
21
  */
22
22
 
23
- const http = require('http');
24
- const path = require('path');
23
+ const http = require('http');
24
+ const path = require('path');
25
+ const crypto = require('crypto');
26
+ const { spawn } = require('child_process');
25
27
 
26
28
  const { scanState } = require('./lib/scanner');
27
29
  const { handleApiState, handleApiFiles, handleApiFile, handleApiHierarchy, handleApiMemory } = require('./lib/api');
@@ -32,6 +34,9 @@ const PORT = parseInt(process.env.PORT || '7717', 10);
32
34
  const RIHAL_DIR = process.env.RIHAL_DIR || path.join(process.cwd(), '.rihal');
33
35
  const PROJECT_ROOT = path.dirname(RIHAL_DIR);
34
36
 
37
+ // Shared orchestrator token — generated once, passed to orchestrator via env and embedded in HTML
38
+ const ORCH_TOKEN = process.env.ORCH_TOKEN || crypto.randomBytes(24).toString('hex');
39
+
35
40
  // ---------- HTTP Server ----------
36
41
  const server = http.createServer((req, res) => {
37
42
  const url = req.url || '/';
@@ -69,7 +74,7 @@ const server = http.createServer((req, res) => {
69
74
 
70
75
  if (url === '/' || url === '/index.html') {
71
76
  const state = scanState(RIHAL_DIR);
72
- const html = renderHtml(state);
77
+ const html = renderHtml(state, ORCH_TOKEN);
73
78
  res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
74
79
  res.end(html);
75
80
  return;
@@ -79,7 +84,7 @@ const server = http.createServer((req, res) => {
79
84
  res.end('Not found');
80
85
  });
81
86
 
82
- server.listen(PORT, () => {
87
+ server.listen(PORT, '127.0.0.1', () => {
83
88
  console.log(`\n🕌 Majlis (مجلس) — Rihal Code Dashboard`);
84
89
  console.log(`━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━`);
85
90
  console.log(` Mode: view-only`);
@@ -91,6 +96,48 @@ server.listen(PORT, () => {
91
96
  console.log(`━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n`);
92
97
  });
93
98
 
99
+ // ── Auto-spawn orchestrator (port 7718) ──────────────────────────
100
+ const ORCH_BIN = path.join(__dirname, 'orchestrator.js');
101
+ let _orchProc = null;
102
+
103
+ function spawnOrchestrator() {
104
+ try {
105
+ _orchProc = spawn(process.execPath, [ORCH_BIN], {
106
+ cwd: path.join(__dirname, '..'),
107
+ env: { ...process.env, ORCH_TOKEN },
108
+ stdio: 'pipe',
109
+ });
110
+ _orchProc.stdout.on('data', chunk => {
111
+ const msg = chunk.toString().trim();
112
+ if (msg) console.log('[orch]', msg);
113
+ });
114
+ _orchProc.stderr.on('data', chunk => {
115
+ const msg = chunk.toString().trim();
116
+ if (msg && !msg.includes('no stdin')) console.error('[orch]', msg);
117
+ });
118
+ _orchProc.on('exit', (code, signal) => {
119
+ _orchProc = null;
120
+ if (signal !== 'SIGTERM' && signal !== 'SIGINT') {
121
+ console.log(`[orch] exited (${code}) — restarting in 3s…`);
122
+ setTimeout(spawnOrchestrator, 3000);
123
+ }
124
+ });
125
+ _orchProc.on('error', err => {
126
+ console.error('[orch] spawn error:', err.message);
127
+ _orchProc = null;
128
+ });
129
+ console.log('[orch] orchestrator started (port 7718)');
130
+ } catch (err) {
131
+ console.error('[orch] failed to start:', err.message);
132
+ }
133
+ }
134
+
135
+ spawnOrchestrator();
136
+
94
137
  // Graceful shutdown
95
- process.on('SIGTERM', () => server.close(() => process.exit(0)));
96
- process.on('SIGINT', () => server.close(() => process.exit(0)));
138
+ function shutdown() {
139
+ if (_orchProc) { try { _orchProc.kill('SIGTERM'); } catch {} }
140
+ server.close(() => process.exit(0));
141
+ }
142
+ process.on('SIGTERM', shutdown);
143
+ process.on('SIGINT', shutdown);
package/server/lib/api.js CHANGED
@@ -132,6 +132,13 @@ function handleApiFile(req, res, projectRoot) {
132
132
  if (!resolved.startsWith(projectRoot + path.sep) && resolved !== projectRoot) {
133
133
  res.writeHead(403); res.end('Forbidden'); return;
134
134
  }
135
+ // Dereference symlinks so a symlink outside projectRoot cannot bypass the guard
136
+ let realResolved;
137
+ try { realResolved = fs.realpathSync(resolved); }
138
+ catch { res.writeHead(404); res.end('File not found'); return; }
139
+ if (!realResolved.startsWith(projectRoot + path.sep) && realResolved !== projectRoot) {
140
+ res.writeHead(403); res.end('Forbidden'); return;
141
+ }
135
142
  if (!resolved.endsWith('.md')) {
136
143
  res.writeHead(403); res.end('Forbidden: only .md files'); return;
137
144
  }