@hanzlaa/rcode 3.4.10 → 3.4.11

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/cli/digest.js CHANGED
@@ -12,7 +12,12 @@ const fs = require('fs');
12
12
  const path = require('path');
13
13
 
14
14
  function normalize(name) {
15
- return name.replace(/^rihal-/, '');
15
+ const stripped = name.replace(/^rihal-/, '');
16
+ // Reject path traversal attempts — names must be simple identifiers
17
+ if (stripped.includes('..') || stripped.includes('/') || stripped.includes('\\')) {
18
+ throw new Error(`Invalid agent name: '${name}'`);
19
+ }
20
+ return stripped;
16
21
  }
17
22
 
18
23
  function listAvailable(digestDir, agentsDir) {
package/cli/index.js CHANGED
@@ -51,7 +51,7 @@ Usage:
51
51
 
52
52
  📦 PROJECT
53
53
  install Install Rihal Code into the current project
54
- (sets up .rihal/, .claude/skills/, .claude/commands/rihal/,
54
+ (sets up .rihal/, .claude/skills/, .claude/commands/,
55
55
  .cursor/rules/, .windsurf/rules/, .antigravity/agents/, AGENTS.md)
56
56
  init Alias for install
57
57
  update Refresh skill files (backs up .rihal/ state first)
@@ -43,7 +43,7 @@ function writeFileAtomic(filePath, content, opts = {}) {
43
43
 
44
44
  let fd;
45
45
  try {
46
- fd = fs.openSync(tmpPath, 'w', mode ?? 0o644);
46
+ fd = fs.openSync(tmpPath, 'wx', mode ?? 0o644);
47
47
  fs.writeSync(fd, content, 0, encoding);
48
48
  // fsync the data to disk before rename — otherwise a crash between
49
49
  // write() and rename() could leave the target renamed but with zero
@@ -18,6 +18,14 @@ const { execSync, spawnSync } = require('child_process');
18
18
 
19
19
  // ---------- Utility: run gh commands safely ----------
20
20
 
21
+ function sanitizeGhOutput(text) {
22
+ if (!text) return '';
23
+ // Strip anything that looks like a token (ghp_*, ghs_*, github_pat_*)
24
+ return text
25
+ .replace(/\b(ghp_|ghs_|github_pat_)[A-Za-z0-9_]{10,}\b/g, '[REDACTED]')
26
+ .slice(0, 2000);
27
+ }
28
+
21
29
  function runGh(args, { input = null, allowFailure = false } = {}) {
22
30
  const result = spawnSync('gh', args, {
23
31
  encoding: 'utf8',
@@ -26,9 +34,8 @@ function runGh(args, { input = null, allowFailure = false } = {}) {
26
34
  });
27
35
 
28
36
  if (result.status !== 0 && !allowFailure) {
29
- throw new Error(
30
- `gh ${args.join(' ')} failed:\n${result.stderr || result.stdout || '(no output)'}`
31
- );
37
+ const detail = sanitizeGhOutput(result.stderr || result.stdout || '(no output)');
38
+ throw new Error(`gh ${args.join(' ')} failed:\n${detail}`);
32
39
  }
33
40
 
34
41
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hanzlaa/rcode",
3
- "version": "3.4.10",
3
+ "version": "3.4.11",
4
4
  "description": "rcode — the memory bank for AI-driven SaaS teams. Persistent project context, distinctive engineering personas, and phase-based workflows. Built by Rihal. Works in Claude Code, Cursor, Gemini, VS Code, and Antigravity.",
5
5
  "main": "cli/index.js",
6
6
  "bin": {
@@ -8,15 +8,6 @@
8
8
  "rihal": "dist/rcode.js",
9
9
  "rihal-code": "dist/rcode.js"
10
10
  },
11
- "scripts": {
12
- "dashboard": "node server/dashboard.js",
13
- "test": "node --test",
14
- "test:ci": "node --test --test-reporter=spec",
15
- "postinstall": "node cli/postinstall.js",
16
- "build:cli": "node scripts/build.cjs",
17
- "build": "node scripts/build.cjs",
18
- "dogfood": "bash scripts/dogfood-check.sh"
19
- },
20
11
  "files": [
21
12
  "cli/",
22
13
  "rihal/",
@@ -69,5 +60,14 @@
69
60
  },
70
61
  "publishConfig": {
71
62
  "access": "public"
63
+ },
64
+ "scripts": {
65
+ "dashboard": "node server/dashboard.js",
66
+ "test": "node --test",
67
+ "test:ci": "node --test --test-reporter=spec",
68
+ "postinstall": "node cli/postinstall.js",
69
+ "build:cli": "node scripts/build.cjs",
70
+ "build": "node scripts/build.cjs",
71
+ "dogfood": "bash scripts/dogfood-check.sh"
72
72
  }
73
- }
73
+ }
@@ -4688,11 +4688,11 @@ function cmdProgress(args) {
4688
4688
  byNum[num] = {
4689
4689
  path: full,
4690
4690
  dirName: entry,
4691
- plan_count: files.filter(f => /PLAN\.md$|-PLAN\.md$|SPRINT\.md$/.test(f)).length,
4691
+ plan_count: files.filter(f => /-SPRINT\.md$/i.test(f)).length,
4692
4692
  summary_count: files.filter(f => /SUMMARY\.md$|-SUMMARY\.md$/.test(f)).length,
4693
4693
  has_research: files.includes('RESEARCH.md'),
4694
4694
  has_context: files.includes('CONTEXT.md'),
4695
- has_verification: files.includes('VERIFICATION.md'),
4695
+ has_verification: files.some(f => /VERIFICATION\.md$/i.test(f)),
4696
4696
  };
4697
4697
  }
4698
4698
  return byNum;
@@ -103,8 +103,8 @@ Auditor returns structured JSON:
103
103
  **If `MODE=phase-status` (Phase 8 / #461):**
104
104
 
105
105
  Spawn `rihal-docs-auditor` with `--mode=phase-status`. Pass:
106
- - `roadmap_phases[]` — output of `node rihal/bin/rihal-tools.cjs roadmap list-phases` (post-#464 fix)
107
- - `phase_dirs[]` — output of `node rihal/bin/rihal-tools.cjs init phase-op N` for each phase number, OR a direct walk of `.planning/phases/*` that captures: dir name, presence of `*-SUMMARY.md`, `*-SPRINT.md`, `*-PLAN.md`, `*-CONTEXT.md`, `*-RESEARCH.md`, `*-VERIFICATION.md`
106
+ - `roadmap_phases[]` — output of `node .rihal/bin/rihal-tools.cjs roadmap list-phases` (post-#464 fix)
107
+ - `phase_dirs[]` — output of `node .rihal/bin/rihal-tools.cjs init phase-op N` for each phase number, OR a direct walk of `.planning/phases/*` that captures: dir name, presence of `*-SUMMARY.md`, `*-SPRINT.md`, `*-PLAN.md`, `*-CONTEXT.md`, `*-RESEARCH.md`, `*-VERIFICATION.md`
108
108
  - For each phase, the most recent commit hash that touches files in `${phase_dir}/` (used as a freshness signal)
109
109
 
110
110
  Auditor returns structured JSON:
@@ -58,12 +58,15 @@ the weighted bar as the primary progress indicator to avoid a misleading `0/N (0
58
58
  For each entry in `SNAPSHOT.phases[]`:
59
59
 
60
60
  - `▶` if `phase.number === SNAPSHOT.current_phase`
61
- - `✓` if `phase.disk.summary_count > 0` AND matches `phase.disk.plan_count` AND `phase.disk.has_verification` (complete + verified; if VERIFICATION.md absent, use `◎` and label "complete-unverified")
61
+ - `✓` if `phase.disk.summary_count > 0` AND `phase.disk.summary_count >= phase.disk.plan_count` AND `phase.disk.has_verification` (complete + verified; if VERIFICATION.md absent, use `◎` and label "complete-unverified")
62
+ - `◎` if `phase.disk.summary_count > 0` AND `phase.disk.summary_count >= phase.disk.plan_count` AND NOT `phase.disk.has_verification` (work done, awaiting verification)
62
63
  - `◆` if `phase.disk.plan_count > phase.disk.summary_count` (executing — has plans, not all summarized)
63
64
  - `◇` if `phase.disk.has_context && !phase.disk.plan_count` (discussing — CONTEXT.md exists but no plan yet)
64
65
  - `◈` if `phase.disk.has_research && !phase.disk.plan_count` (researched — RESEARCH.md but no plan)
65
66
  - `○` otherwise (planned — no artifacts on disk)
66
67
 
68
+ **Edge case — summary without sprint:** If `summary_count > 0` AND `plan_count === 0`, treat as `◎ complete-unverified` (sprint was archived or the phase used an older single-file workflow; summary is evidence of completed work).
69
+
67
70
  ```
68
71
  Phases:
69
72
  ▶ [04] Component compaction — executing (1/3 plans)