@hanzlaa/rcode 4.3.1 → 4.3.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hanzlaa/rcode",
3
- "version": "4.3.1",
3
+ "version": "4.3.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": {
@@ -9,7 +9,7 @@
9
9
 
10
10
  import { html } from '../preact.js';
11
11
  import { useStore } from '../store.js';
12
- import { allSprints, chip } from '../util.js';
12
+ import { allSprints, chip, sessionChip } from '../util.js';
13
13
 
14
14
  /**
15
15
  * Build a `{ [cls]: count }` map from an array of items by normalising each
@@ -27,6 +27,24 @@ function countByStatus(items) {
27
27
  return map;
28
28
  }
29
29
 
30
+ /**
31
+ * Build a `{ [cls]: count }` map from session objects using `sessionChip()`
32
+ * rather than the phase/sprint-oriented `chip()`. Sessions carry a distinct
33
+ * status vocabulary ('running', 'stopped', 'starting', 'error') that maps to
34
+ * separate CSS classes so they can be styled independently.
35
+ *
36
+ * @param {Array<{ status: string }>} sessions
37
+ * @returns {Object.<string, number>}
38
+ */
39
+ function countSessionsByStatus(sessions) {
40
+ const map = {};
41
+ for (const session of sessions) {
42
+ const { cls } = sessionChip(session.status || '');
43
+ map[cls] = (map[cls] || 0) + 1;
44
+ }
45
+ return map;
46
+ }
47
+
30
48
  /**
31
49
  * Render a single group of count chips.
32
50
  *
@@ -58,7 +76,7 @@ export function StatusSummaryBar() {
58
76
 
59
77
  const phaseCounts = countByStatus(phases);
60
78
  const sprintCounts = countByStatus(sprints);
61
- const sessionCounts = countByStatus(sessions);
79
+ const sessionCounts = countSessionsByStatus(sessions);
62
80
 
63
81
  const hasPhases = phases.length > 0;
64
82
  const hasSprints = sprints.length > 0;
@@ -80,6 +80,22 @@ export function allTasks(phases) {
80
80
  );
81
81
  }
82
82
 
83
+ /**
84
+ * Map a numeric phase id to its milestone bucket.
85
+ * Single source of truth — imported by PhasesView and SprintsView so that
86
+ * milestone boundaries (19, 33) never diverge between the two views.
87
+ * M1 = phases 1–19, M2 = 20–33, M3 = 34+.
88
+ *
89
+ * @param {number|string} id — phase id
90
+ * @returns {'M1'|'M2'|'M3'}
91
+ */
92
+ export function phaseMilestone(id) {
93
+ const n = Number(id);
94
+ if (n <= 19) return 'M1';
95
+ if (n <= 33) return 'M2';
96
+ return 'M3';
97
+ }
98
+
83
99
  /**
84
100
  * Return a status chip descriptor — NOT an HTML string.
85
101
  * Components decide how to render the CSS class and label.
@@ -98,6 +114,31 @@ export function chip(status) {
98
114
  return { cls, label: status };
99
115
  }
100
116
 
117
+ /**
118
+ * Return a status chip descriptor for orchestrator session statuses.
119
+ * Session objects use a different vocabulary than phases/sprints
120
+ * ('running', 'stopped', 'starting', 'error'), so a separate normaliser
121
+ * keeps the two status domains from coupling inside chip().
122
+ *
123
+ * Mapping:
124
+ * running → 'sess-running' (accent-blue — live activity)
125
+ * starting → 'sess-starting' (amber — transient / pending)
126
+ * stopped → 'sess-stopped' (text-secondary — idle / muted)
127
+ * error → 'sess-error' (accent-red — needs attention)
128
+ *
129
+ * @param {string} status
130
+ * @returns {{ cls: string, label: string }}
131
+ */
132
+ export function sessionChip(status) {
133
+ const s = String(status || '').toLowerCase();
134
+ const cls =
135
+ s === 'running' ? 'sess-running' :
136
+ s === 'starting' ? 'sess-starting' :
137
+ s === 'error' ? 'sess-error' :
138
+ s === 'stopped' ? 'sess-stopped' : 'sess-stopped';
139
+ return { cls, label: status };
140
+ }
141
+
101
142
  /**
102
143
  * Props for a clickable card row that navigates to a hash route.
103
144
  * Spread onto a list row (`<li ...${rowLink('tasks')}>`) to make it act like
@@ -9,7 +9,7 @@
9
9
 
10
10
  import { html, useState } from '../preact.js';
11
11
  import { useStore } from '../store.js';
12
- import { pct, humanDate, phaseHints, chip } from '../util.js';
12
+ import { pct, humanDate, phaseHints, chip, phaseMilestone } from '../util.js';
13
13
  import {
14
14
  Chip, ProgressBar, Breadcrumb, CmdHints, RunningBadge, SprintCard, PhaseCard,
15
15
  } from '../components/shared.js';
@@ -122,17 +122,6 @@ function PhaseDetail({ phase: p, S }) {
122
122
  `;
123
123
  }
124
124
 
125
- /**
126
- * Map a numeric phase id to its milestone bucket.
127
- * M1 = phases 1–19, M2 = 20–33, M3 = 34+.
128
- */
129
- function phaseMilestone(id) {
130
- const n = Number(id);
131
- if (n <= 19) return 'M1';
132
- if (n <= 33) return 'M2';
133
- return 'M3';
134
- }
135
-
136
125
  export function PhasesView({ subId, filters }) {
137
126
  const S = useStore();
138
127
  const phases = S.phases || [];
@@ -10,7 +10,7 @@
10
10
 
11
11
  import { html, useState } from '../preact.js';
12
12
  import { useStore } from '../store.js';
13
- import { pct, humanDate, allSprints, sprintHints, chip } from '../util.js';
13
+ import { pct, humanDate, allSprints, sprintHints, chip, phaseMilestone } from '../util.js';
14
14
  import {
15
15
  Chip, ProgressBar, Breadcrumb, CmdHints, RunningBadge, SprintCard, TaskCard,
16
16
  } from '../components/shared.js';
@@ -118,17 +118,6 @@ function SprintDetail({ sprint: s, S }) {
118
118
  `;
119
119
  }
120
120
 
121
- /**
122
- * Map a numeric phase id to its milestone bucket.
123
- * M1 = phases 1–19, M2 = 20–33, M3 = 34+.
124
- */
125
- function phaseMilestone(id) {
126
- const n = Number(id);
127
- if (n <= 19) return 'M1';
128
- if (n <= 33) return 'M2';
129
- return 'M3';
130
- }
131
-
132
121
  export function SprintsView({ subId, filters }) {
133
122
  const S = useStore();
134
123
  const sprints = allSprints(S.phases || []);
@@ -4390,6 +4390,11 @@ summary:focus-visible,
4390
4390
  .summary-count-chip.blocked { color: var(--accent-red); }
4391
4391
  .summary-count-chip.planned,
4392
4392
  .summary-count-chip.todo { color: var(--text-secondary); }
4393
+ /* Session status chips — use sessionChip() vocabulary, not chip() */
4394
+ .summary-count-chip.sess-running { color: var(--accent-blue); }
4395
+ .summary-count-chip.sess-starting { color: var(--amber); }
4396
+ .summary-count-chip.sess-stopped { color: var(--text-secondary); }
4397
+ .summary-count-chip.sess-error { color: var(--accent-red); }
4393
4398
 
4394
4399
  /* ── Filter chips ────────────────────────────────────────────────── */
4395
4400
  .filter-chips {