@hanzlaa/rcode 4.5.0 → 4.7.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/README.md +47 -14
- package/package.json +1 -1
- package/rcode/agents/rcode-mariam.md +6 -0
- package/rcode/agents/rcode-sadiq.md +6 -0
- package/rcode/agents/rcode-waleed.md +6 -0
- package/rcode/bin/rcode-hooks.cjs +41 -5
- package/rcode/skills/agents/mariam-marketing/SKILL.md +1 -0
- package/rcode/skills/agents/sadiq-analyst/SKILL.md +1 -0
- package/rcode/skills/agents/waleed-architect/SKILL.md +1 -0
- package/rcode/workflows/council.md +29 -1
- package/server/dashboard.js +6 -3
- package/server/lib/html/client/components/App.js +16 -2
- package/server/lib/html/client/components/OrchPanel.js +2 -2
- package/server/lib/html/client/components/PhaseGraph.js +20 -12
- package/server/lib/html/client/components/Sidebar.js +1 -0
- package/server/lib/html/client/components/Topbar.js +3 -3
- package/server/lib/html/client/components/XtermPanel.js +98 -23
- package/server/lib/html/client/components/dashboard/Blockers.js +3 -3
- package/server/lib/html/client/components/dashboard/CompletedTasks.js +4 -2
- package/server/lib/html/client/components/dashboard/InProgress.js +4 -3
- package/server/lib/html/client/components/dashboard/ProgressTimeline.js +11 -6
- package/server/lib/html/client/components/dashboard/RecentDecisions.js +4 -3
- package/server/lib/html/client/components/shared.js +111 -2
- package/server/lib/html/client/orchestrator.js +28 -15
- package/server/lib/html/client/store.js +47 -0
- package/server/lib/html/client/util.js +1 -22
- package/server/lib/html/client/views/BacklogView.js +44 -0
- package/server/lib/html/client/views/DecisionsView.js +4 -3
- package/server/lib/html/client/views/FilesView.js +47 -34
- package/server/lib/html/client/views/KanbanView.js +8 -0
- package/server/lib/html/client/views/OrchestrationView.js +247 -169
- package/server/lib/html/client/views/PhasesView.js +8 -3
- package/server/lib/html/client/views/SprintsView.js +9 -0
- package/server/lib/html/client.js +1 -0
- package/server/lib/html/css.js +692 -246
- package/server/lib/html/shell.js +9 -3
- package/server/lib/scanner.js +21 -6
- package/server/orchestrator.js +3 -4
package/server/lib/html/shell.js
CHANGED
|
@@ -6,8 +6,14 @@ const { renderClientJs } = require('./client');
|
|
|
6
6
|
|
|
7
7
|
function esc(s) { return String(s || '').replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>'); }
|
|
8
8
|
|
|
9
|
-
function renderHtml(state, orchToken) {
|
|
9
|
+
function renderHtml(state, orchToken, orchPort) {
|
|
10
10
|
const projectName = state.projectName || 'No project initialized';
|
|
11
|
+
// #969 — the client used to hardcode port 7718 for the orchestrator API.
|
|
12
|
+
// A dashboard started with ORCH_PORT set (e.g. to test in isolation from a
|
|
13
|
+
// production instance) would silently talk to the wrong orchestrator. The
|
|
14
|
+
// actual port is injected here — both into the CSP connect-src allowlist
|
|
15
|
+
// and into window.__ORCH_PORT__ for orchestrator.js to read at runtime.
|
|
16
|
+
const port = parseInt(orchPort, 10) || 7718;
|
|
11
17
|
|
|
12
18
|
// Agent roster moved to server/lib/html/client/agents-data.js (Sprint 31.3).
|
|
13
19
|
// AgentsView.js renders it client-side; shell.js no longer needs it.
|
|
@@ -17,7 +23,7 @@ function renderHtml(state, orchToken) {
|
|
|
17
23
|
<head>
|
|
18
24
|
<meta charset="UTF-8">
|
|
19
25
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
20
|
-
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net; style-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com data:; img-src 'self' data:; connect-src 'self' http://localhost
|
|
26
|
+
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net; style-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com data:; img-src 'self' data:; connect-src 'self' http://localhost:${port} http://127.0.0.1:${port} ws: wss:; object-src 'none'; base-uri 'self'; frame-ancestors 'none'">
|
|
21
27
|
<meta http-equiv="X-Content-Type-Options" content="nosniff">
|
|
22
28
|
<meta name="referrer" content="strict-origin-when-cross-origin">
|
|
23
29
|
<title>Majlis — ${esc(projectName)}</title>
|
|
@@ -26,7 +32,7 @@ function renderHtml(state, orchToken) {
|
|
|
26
32
|
<script src="https://cdn.jsdelivr.net/npm/marked@18.0.4/lib/marked.umd.js" integrity="sha384-8RA8Ah4c9upJmKfg5nH01OgjZoQ3mRX+ngrKYWXQYj2dHYxFqYz8POSlii33f0wB" crossorigin="anonymous"><\/script>
|
|
27
33
|
<script src="https://cdn.jsdelivr.net/npm/xterm@5.3.0/lib/xterm.js" integrity="sha384-/nfmYPUzWMS6v2atn8hbljz7NE0EI1iGx34lJaNzyVjWGDzMv+ciUZUeJpKA3Glc" crossorigin="anonymous"><\/script>
|
|
28
34
|
<script src="https://cdn.jsdelivr.net/npm/xterm-addon-fit@0.8.0/lib/xterm-addon-fit.js" integrity="sha384-AQLWHRKAgdTxkolJcLOELg4E9rE89CPE2xMy3tIRFn08NcGKPTsELdvKomqji+DL" crossorigin="anonymous"><\/script>
|
|
29
|
-
<script>window.__ORCH_TOKEN__ = ${JSON.stringify(orchToken || '')};<\/script>
|
|
35
|
+
<script>window.__ORCH_TOKEN__ = ${JSON.stringify(orchToken || '')}; window.__ORCH_PORT__ = ${port};<\/script>
|
|
30
36
|
${renderCss()}
|
|
31
37
|
</head>
|
|
32
38
|
<body>
|
package/server/lib/scanner.js
CHANGED
|
@@ -195,7 +195,13 @@ function buildPhaseTree(projectDir, rawPhases, listCached, overrides) {
|
|
|
195
195
|
: (p.status === 'active' || p.status === 'in_progress') ? 'in_progress'
|
|
196
196
|
: 'planned';
|
|
197
197
|
|
|
198
|
-
|
|
198
|
+
// Project-relative path to this sprint's SPRINT.md — same shape as the
|
|
199
|
+
// sprintFile computed below for roadmap cards, so /api/file?path=...
|
|
200
|
+
// resolves it identically. Lets task rows (which point at a specific
|
|
201
|
+
// sprint, not just "latest file in the phase") open the right file.
|
|
202
|
+
const file = path.join('.planning', 'phases', dir.name, f).split(path.sep).join('/');
|
|
203
|
+
|
|
204
|
+
return { id: sid, number: num, goal: goal || `Sprint ${num}`, status, stories, dependsOn, file };
|
|
199
205
|
});
|
|
200
206
|
|
|
201
207
|
// Derive phase-level depends_on by aggregating sprint-level depends_on entries.
|
|
@@ -366,11 +372,15 @@ function buildDashboard(state) {
|
|
|
366
372
|
const stories = Array.isArray(s.stories) ? s.stories : [];
|
|
367
373
|
for (const st of stories) {
|
|
368
374
|
if (/done|complete/i.test(st.status || '')) {
|
|
369
|
-
completedTasks.push({
|
|
375
|
+
completedTasks.push({
|
|
376
|
+
title: st.title || st.id,
|
|
377
|
+
date: fmtISODate(p.completed || s.completed_at || p.created),
|
|
378
|
+
file: s.file || null,
|
|
379
|
+
});
|
|
370
380
|
} else if (p.state === 'active') {
|
|
371
381
|
// No per-task progress tracking exists — pct stays null and the UI
|
|
372
382
|
// omits the percent pill rather than inventing a number.
|
|
373
|
-
inProgressTasks.push({ title: st.title || st.id, pct: null });
|
|
383
|
+
inProgressTasks.push({ title: st.title || st.id, pct: null, file: s.file || null });
|
|
374
384
|
}
|
|
375
385
|
}
|
|
376
386
|
}
|
|
@@ -378,10 +388,10 @@ function buildDashboard(state) {
|
|
|
378
388
|
// Fallbacks so the cards are never empty when stories are unregistered in state.json.
|
|
379
389
|
if (!completedTasks.length) {
|
|
380
390
|
phases.filter(p => p.state === 'done').slice(-6).forEach(p =>
|
|
381
|
-
completedTasks.push({ title: p.name, date: fmtISODate(p.completed || p.created) }));
|
|
391
|
+
completedTasks.push({ title: p.name, date: fmtISODate(p.completed || p.created), file: null }));
|
|
382
392
|
}
|
|
383
393
|
if (!inProgressTasks.length && activePhase && activePhase.state === 'active') {
|
|
384
|
-
inProgressTasks.push({ title: activePhase.name, pct: null });
|
|
394
|
+
inProgressTasks.push({ title: activePhase.name, pct: null, file: null });
|
|
385
395
|
}
|
|
386
396
|
const tasks = {
|
|
387
397
|
completed: completedTasks.slice(-8).reverse(),
|
|
@@ -419,6 +429,11 @@ function buildDashboard(state) {
|
|
|
419
429
|
.sort((a, b) => String(b.date).localeCompare(String(a.date)))
|
|
420
430
|
.slice(0, 8);
|
|
421
431
|
|
|
432
|
+
// ---- backlog (phases not yet started — real state.json data, no invented rows) ----
|
|
433
|
+
const backlog = phases
|
|
434
|
+
.filter(p => p.state === 'todo')
|
|
435
|
+
.map(p => ({ id: p.id, name: p.name, range: p.range }));
|
|
436
|
+
|
|
422
437
|
// ---- project (identity + current user) ----
|
|
423
438
|
// User comes from config, else the real OS account running the server;
|
|
424
439
|
// null when neither exists (UI greets generically, hides the profile row).
|
|
@@ -430,7 +445,7 @@ function buildDashboard(state) {
|
|
|
430
445
|
user: { name: userName, email: cfg.user_email || '' },
|
|
431
446
|
};
|
|
432
447
|
|
|
433
|
-
return { project, progress, currentPhase, timeline: { launchDate, onTrack: blockers.length === 0, points }, tasks, blockers, health, decisions, phases };
|
|
448
|
+
return { project, progress, currentPhase, timeline: { launchDate, onTrack: blockers.length === 0, points }, tasks, blockers, health, decisions, phases, backlog };
|
|
434
449
|
}
|
|
435
450
|
|
|
436
451
|
function scanStateUncached(rcodeDir) {
|
package/server/orchestrator.js
CHANGED
|
@@ -791,10 +791,9 @@ const server = http.createServer(async (req, res) => {
|
|
|
791
791
|
res.writeHead(404); res.end('Not found');
|
|
792
792
|
});
|
|
793
793
|
|
|
794
|
-
server
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
});
|
|
794
|
+
// NOTE: the single server 'error' handler lives below the WebSocket block —
|
|
795
|
+
// a second handler here would fire first and exit(1) before the EADDRINUSE
|
|
796
|
+
// exit(2) path runs, re-triggering the dashboard's 3s respawn loop (#964).
|
|
798
797
|
|
|
799
798
|
// WebSocket upgrade — authenticate, validate the storyId, then hand off.
|
|
800
799
|
if (WebSocketServer) {
|