iikit-dashboard 1.4.0 → 1.5.1

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
@@ -11,11 +11,12 @@ The dashboard launches automatically early in the IIKit workflow — no manual s
11
11
  You can also start it standalone to browse historical data for any project that has feature specs:
12
12
 
13
13
  ```bash
14
- npx iikit-dashboard # current directory
15
- npx iikit-dashboard /path/to/project # specific project
14
+ npx iikit-dashboard # current directory
15
+ npx iikit-dashboard /path/to/project # specific project
16
+ npx iikit-dashboard --port 3001 # custom port
16
17
  ```
17
18
 
18
- The dashboard opens at `http://localhost:3000`.
19
+ The dashboard opens at `http://localhost:3000` by default. A pidfile (`.specify/dashboard.pid.json`) is written on startup so external tools can discover which project a running dashboard serves and at which port.
19
20
 
20
21
  ## Views
21
22
 
@@ -23,40 +24,48 @@ The pipeline bar at the top shows all nine IIKit workflow phases. Click any phas
23
24
 
24
25
  | Phase | View |
25
26
  |-------|------|
26
- | **Constitution** | Radar chart of governance principles with obligation levels (MUST / SHOULD / MAY) |
27
- | **Spec** | Story map with swim lanes by priority + interactive requirements graph (US / FR / SC nodes and edges) |
28
- | **Clarify** | Q&A trail from clarification sessions, with clickable spec-item references that navigate back to the Spec view |
29
- | **Plan** | Tech stack badge wall, interactive file-structure tree (existing vs. planned files), rendered architecture diagram, and Tessl tile cards |
27
+ | **Constitution** | Radar chart of governance principles with obligation levels (MUST / SHOULD / MAY) and version timeline |
28
+ | **Spec** | Story map with swim lanes by priority + interactive force-directed requirements graph (US / FR / SC nodes and edges) with detail side-panel |
29
+ | **Clarify** | Q&A trail from clarification sessions grouped by date, with clickable spec-item references that navigate to the Spec view |
30
+ | **Plan** | Tech context key-value pairs, interactive file-structure tree (existing vs. planned files), rendered architecture diagram, and Tessl tile cards with live eval scores |
30
31
  | **Checklist** | Progress rings per checklist file with color coding (red/yellow/green), gate traffic light (OPEN/BLOCKED), and accordion detail view with CHK IDs and tag badges |
31
- | **Testify** | *Coming soon* |
32
- | **Tasks** | *Coming soon* |
33
- | **Analyze** | *Coming soon* |
34
- | **Implement** | Kanban board with cards sliding Todo → In Progress → Done as the agent checks off tasks |
32
+ | **Testify** | Assertion integrity seal (Verified/Tampered/Missing), Sankey traceability diagram (Requirements → Test Specs → Tasks), test pyramid, and gap highlighting for untested requirements |
33
+ | **Tasks** | Redirects to the Implement board (tasks are managed there) |
34
+ | **Analyze** | Health gauge (0–100) with four weighted factors, coverage heatmap (Tasks/Tests/Plan per requirement), and sortable/filterable severity table of analysis findings |
35
+ | **Implement** | Kanban board with cards sliding Todo → In Progress → Done as the agent checks off tasks, with collapsible per-story task lists |
35
36
 
36
37
  ## Features
37
38
 
38
39
  - **Live updates** — all views refresh in real time via WebSocket as project files change
39
40
  - **Pipeline navigation** — phase nodes show status (complete / in-progress / skipped / not started) with progress percentages
41
+ - **Cross-panel navigation** — Cmd/Ctrl+click any FR, US, SC, or task identifier to jump to its linked panel (Spec, Testify, Implement, Checklist, or Clarify)
40
42
  - **Feature selector** — dropdown to switch between features in `specs/`, sorted newest-first
41
- - **Clarification traceability** — Q&A entries link back to the FR / US / SC spec items they clarify
42
- - **Integrity badges** — shows whether test assertions have been tampered with
43
+ - **Project label** — header shows the project directory name with full path on hover, so you know which project a dashboard tab belongs to
44
+ - **Integrity badges** — shows whether test assertions have been tampered with (verified / tampered / missing)
45
+ - **Tessl eval scores** — Plan view tile cards display live eval data (score, pass/fail chart) when available
46
+ - **Activity indicator** — green dot pulses in the header when files are actively changing
47
+ - **Multi-project support** — pidfile at `.specify/dashboard.pid.json` lets external scripts identify running instances per project
43
48
  - **Three-state theme** — cycles System (OS preference) → Light → Dark
44
49
  - **Zero build step** — single HTML file with inline CSS and JS
45
50
 
46
51
  ## How It Works
47
52
 
48
- The server reads directly from your project's `specs/` directory:
53
+ The server reads directly from your project's directory:
49
54
 
50
55
  | File | Purpose |
51
56
  |------|---------|
52
- | `spec.md` | User stories, requirements, success criteria, and clarification Q&A |
53
- | `plan.md` | Tech stack, file structure, and architecture diagram |
54
- | `tasks.md` | Task checkboxes grouped by `[US1]`, `[US2]` tags |
55
- | `checklists/*.md` | Checklist items with completion status, CHK IDs, and category groupings |
56
57
  | `CONSTITUTION.md` | Governance principles and obligation levels |
57
- | `tessl.json` | Installed Tessl tiles for the dependency panel |
58
-
59
- A file watcher (chokidar) detects changes and pushes updates to the browser via WebSocket with 300 ms debounce.
58
+ | `specs/<feature>/spec.md` | User stories, requirements, success criteria, and clarification Q&A |
59
+ | `specs/<feature>/plan.md` | Tech stack, file structure, and architecture diagram |
60
+ | `specs/<feature>/research.md` | Research decisions (displayed as tooltips in Plan view) |
61
+ | `specs/<feature>/tasks.md` | Task checkboxes grouped by `[US1]`, `[US2]` tags |
62
+ | `specs/<feature>/checklists/*.md` | Checklist items with completion status, CHK IDs, and category groupings |
63
+ | `specs/<feature>/tests/test-specs.md` | Test specifications for the Testify traceability view |
64
+ | `specs/<feature>/context.json` | Assertion hash for integrity verification |
65
+ | `specs/<feature>/analysis.md` | Consistency analysis findings, coverage, and metrics |
66
+ | `tessl.json` | Installed Tessl tiles for the Plan dependency panel |
67
+
68
+ A file watcher (chokidar) monitors the project tree (excluding `node_modules` and `.git`) and pushes updates to the browser via WebSocket with 300 ms debounce.
60
69
 
61
70
  ## Requirements
62
71
 
@@ -2,11 +2,11 @@
2
2
  'use strict';
3
3
 
4
4
  const path = require('path');
5
- const { createServer } = require('../src/server');
5
+ const { createServer, removePidfile } = require('../src/server');
6
6
 
7
7
  // Parse arguments
8
8
  const args = process.argv.slice(2);
9
- let projectPath = process.cwd();
9
+ let projectPath = path.resolve(process.cwd());
10
10
  let port = 3000;
11
11
 
12
12
  for (let i = 0; i < args.length; i++) {
@@ -46,6 +46,7 @@ async function main() {
46
46
  // Handle graceful shutdown
47
47
  process.on('SIGINT', () => {
48
48
  console.log('\n Shutting down...');
49
+ removePidfile(projectPath);
49
50
  result.server.close(() => {
50
51
  if (result.watcher) result.watcher.close();
51
52
  process.exit(0);
@@ -53,6 +54,7 @@ async function main() {
53
54
  });
54
55
 
55
56
  process.on('SIGTERM', () => {
57
+ removePidfile(projectPath);
56
58
  result.server.close(() => {
57
59
  if (result.watcher) result.watcher.close();
58
60
  process.exit(0);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "iikit-dashboard",
3
- "version": "1.4.0",
3
+ "version": "1.5.1",
4
4
  "description": "Real-time dashboard for Intent Integrity Kit (IIKit) — visualizes every phase of specification-driven AI development",
5
5
  "main": "src/server.js",
6
6
  "bin": {
@@ -12,7 +12,9 @@
12
12
  ],
13
13
  "scripts": {
14
14
  "start": "node bin/iikit-dashboard.js",
15
- "test": "jest --forceExit"
15
+ "test": "jest --forceExit --testPathIgnorePatterns=test/visual",
16
+ "test:visual": "npx playwright test",
17
+ "test:visual:update": "npx playwright test --update-snapshots"
16
18
  },
17
19
  "keywords": [
18
20
  "iikit",
@@ -40,6 +42,7 @@
40
42
  "ws": "^8.19.0"
41
43
  },
42
44
  "devDependencies": {
45
+ "@playwright/test": "^1.58.2",
43
46
  "jest": "^30.2.0"
44
47
  }
45
48
  }
@@ -93,6 +93,17 @@
93
93
  flex: 1 1 auto;
94
94
  }
95
95
 
96
+ .project-label {
97
+ font-size: 12px;
98
+ color: var(--color-text-muted);
99
+ max-width: 160px;
100
+ overflow: hidden;
101
+ text-overflow: ellipsis;
102
+ white-space: nowrap;
103
+ border-left: 1px solid var(--color-border);
104
+ padding-left: 12px;
105
+ }
106
+
96
107
  .feature-selector {
97
108
  position: relative;
98
109
  min-width: 100px;
@@ -713,8 +724,7 @@
713
724
  border-radius: var(--radius-md);
714
725
  cursor: pointer;
715
726
  transition: background var(--transition-fast), transform var(--transition-fast);
716
- flex: 0 1 96px;
717
- width: 96px;
727
+ flex: 0 1 auto;
718
728
  min-width: 40px;
719
729
  position: relative;
720
730
  border: 1px solid var(--color-border-subtle);
@@ -2368,6 +2378,7 @@
2368
2378
  <div class="logo-icon" aria-hidden="true">D</div>
2369
2379
  <span>IIKit Dashboard</span>
2370
2380
  </div>
2381
+ <div class="project-label" id="projectLabel" title=""></div>
2371
2382
  <div class="feature-selector" role="navigation" aria-label="Feature selector">
2372
2383
  <select id="featureSelect" aria-label="Select feature to display" tabindex="0">
2373
2384
  <option value="">Loading features...</option>
@@ -5188,6 +5199,12 @@
5188
5199
  applyTheme(themeMode);
5189
5200
 
5190
5201
  // ====== Init ======
5202
+ fetch('/api/meta').then(r => r.json()).then(meta => {
5203
+ const label = document.getElementById('projectLabel');
5204
+ const dirName = meta.projectPath.split('/').pop();
5205
+ label.textContent = dirName;
5206
+ label.title = meta.projectPath;
5207
+ }).catch(() => {});
5191
5208
  loadFeatures();
5192
5209
  connectWebSocket();
5193
5210
  })();
package/src/server.js CHANGED
@@ -98,6 +98,33 @@ function getBoardState(projectPath, featureId) {
98
98
  return { ...board, integrity };
99
99
  }
100
100
 
101
+ /**
102
+ * Write a pidfile with metadata so external scripts can identify this dashboard instance.
103
+ */
104
+ function writePidfile(projectPath, port) {
105
+ const resolved = path.resolve(projectPath);
106
+ const specifyDir = path.join(resolved, '.specify');
107
+ fs.mkdirSync(specifyDir, { recursive: true });
108
+ const pidData = {
109
+ pid: process.pid,
110
+ port,
111
+ directory: resolved,
112
+ startedAt: new Date().toISOString()
113
+ };
114
+ fs.writeFileSync(path.join(specifyDir, 'dashboard.pid.json'), JSON.stringify(pidData, null, 2));
115
+ }
116
+
117
+ /**
118
+ * Remove the pidfile on shutdown.
119
+ */
120
+ function removePidfile(projectPath) {
121
+ try {
122
+ fs.unlinkSync(path.join(path.resolve(projectPath), '.specify', 'dashboard.pid.json'));
123
+ } catch (err) {
124
+ if (err.code !== 'ENOENT') throw err;
125
+ }
126
+ }
127
+
101
128
  /**
102
129
  * Create and configure the Express server with WebSocket support.
103
130
  *
@@ -107,11 +134,17 @@ function getBoardState(projectPath, featureId) {
107
134
  * @returns {Promise<{server: http.Server, port: number, wss: WebSocketServer}>}
108
135
  */
109
136
  function createServer({ projectPath, port = 3000 }) {
137
+ const resolvedPath = path.resolve(projectPath);
110
138
  const app = express();
111
139
 
112
140
  // Serve static files from src/public
113
141
  app.use(express.static(path.join(__dirname, 'public')));
114
142
 
143
+ // API: project metadata
144
+ app.get('/api/meta', (req, res) => {
145
+ res.json({ projectPath: resolvedPath });
146
+ });
147
+
115
148
  // API: list features
116
149
  app.get('/api/features', (req, res) => {
117
150
  try {
@@ -363,9 +396,10 @@ function createServer({ projectPath, port = 3000 }) {
363
396
  return new Promise((resolve) => {
364
397
  server.listen(port, () => {
365
398
  const actualPort = server.address().port;
366
- resolve({ server, port: actualPort, wss, watcher });
399
+ writePidfile(resolvedPath, actualPort);
400
+ resolve({ server, port: actualPort, wss, watcher, projectPath: resolvedPath });
367
401
  });
368
402
  });
369
403
  }
370
404
 
371
- module.exports = { createServer, listFeatures, getBoardState };
405
+ module.exports = { createServer, listFeatures, getBoardState, removePidfile };