@jakkrichm/create-nexus-devflow 2.9.4 → 2.10.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 (46) hide show
  1. package/README.md +3 -3
  2. package/dist/lib/dashboard-page.d.ts +1 -1
  3. package/dist/lib/dashboard-page.js +5 -1
  4. package/dist/lib/dashboard-page.js.map +1 -1
  5. package/dist/lib/project-config.d.ts +2 -0
  6. package/dist/lib/project-config.js +5 -2
  7. package/dist/lib/project-config.js.map +1 -1
  8. package/dist/lib/review.d.ts +38 -0
  9. package/dist/lib/review.js +429 -0
  10. package/dist/lib/review.js.map +1 -0
  11. package/dist/lib/status.d.ts +19 -2
  12. package/dist/lib/status.js +83 -15
  13. package/dist/lib/status.js.map +1 -1
  14. package/package.json +1 -1
  15. package/template/.agents/skills/audit/SKILL.md +119 -144
  16. package/template/.agents/skills/audit/reference/independent-review.md +128 -0
  17. package/template/.agents/skills/autopilot/SKILL.md +22 -1
  18. package/template/.agents/skills/browser-tests/SKILL.md +163 -0
  19. package/template/.agents/skills/check/SKILL.md +32 -23
  20. package/template/.agents/skills/complete/SKILL.md +28 -39
  21. package/template/.agents/skills/continuous/SKILL.md +12 -0
  22. package/template/.agents/skills/doctor/SKILL.md +8 -4
  23. package/template/.agents/skills/feature/SKILL.md +22 -1
  24. package/template/.agents/skills/implement/SKILL.md +21 -1
  25. package/template/.agents/skills/onboard/SKILL.md +17 -1
  26. package/template/.agents/skills/status/SKILL.md +12 -1
  27. package/template/.agents/skills/tests/SKILL.md +1 -1
  28. package/template/.agents/skills/try/SKILL.md +9 -24
  29. package/template/.claude/skills/audit/SKILL.md +119 -144
  30. package/template/.claude/skills/audit/reference/independent-review.md +128 -0
  31. package/template/.claude/skills/autopilot/SKILL.md +22 -1
  32. package/template/.claude/skills/browser-tests/SKILL.md +163 -0
  33. package/template/.claude/skills/check/SKILL.md +32 -23
  34. package/template/.claude/skills/complete/SKILL.md +28 -39
  35. package/template/.claude/skills/continuous/SKILL.md +12 -0
  36. package/template/.claude/skills/doctor/SKILL.md +9 -4
  37. package/template/.claude/skills/feature/SKILL.md +22 -1
  38. package/template/.claude/skills/implement/SKILL.md +21 -1
  39. package/template/.claude/skills/onboard/SKILL.md +17 -1
  40. package/template/.claude/skills/status/SKILL.md +12 -1
  41. package/template/.claude/skills/tests/SKILL.md +1 -1
  42. package/template/.claude/skills/try/SKILL.md +9 -24
  43. package/template/AGENTS.md +4 -4
  44. package/template/devflow/build-plan.md +6 -0
  45. package/template/devflow/config.json +2 -0
  46. package/template/devflow/context/coding-standards.md +8 -1
package/README.md CHANGED
@@ -26,13 +26,13 @@ npx @jakkrichm/create-nexus-devflow@latest
26
26
 
27
27
  The installer overlays the DevFlow workflow layer into your workspace:
28
28
  - `AGENTS.md` & `CLAUDE.md` (Universal AI guidelines & cross-tool entry point)
29
- - `.agents/skills/` (29 Core Skills for Google Antigravity, OpenAI Codex, Cursor, Copilot)
30
- - `.claude/skills/` (29 Core Skills for Claude Code)
29
+ - `.agents/skills/` (30 Core Skills for Google Antigravity, OpenAI Codex, Cursor, Copilot)
30
+ - `.claude/skills/` (30 Core Skills for Claude Code)
31
31
  - `devflow/ideas.md` (Idea inbox with AI feasibility scoring)
32
32
  - `devflow/context/` (Living spec & active delivery context)
33
33
  - `devflow/history/` (Categorized delivery archives)
34
34
 
35
- The 29 names come from the canonical bundled inventory. Local or Personal Skills
35
+ The 30 names come from the canonical bundled inventory. Local or Personal Skills
36
36
  may coexist in a maintainer workspace, but the package builder excludes them
37
37
  unless they are explicitly promoted into that inventory.
38
38
 
@@ -1,2 +1,2 @@
1
- declare const DASHBOARD_PAGE_HTML = "<!doctype html>\n<html lang=\"th\">\n<head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n <title>Nexus-DevFlow Enterprise Dashboard</title>\n <link rel=\"preconnect\" href=\"https://fonts.googleapis.com\">\n <link rel=\"preconnect\" href=\"https://fonts.gstatic.com\" crossorigin>\n <link rel=\"preconnect\" href=\"https://fonts.googleapis.com\" />\n <link rel=\"preconnect\" href=\"https://fonts.gstatic.com\" crossorigin />\n <link href=\"https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;500;600;700&family=Noto+Sans+Thai:wght@400;500;600;700&family=Space+Grotesk:wght@500;600;700&display=swap\" rel=\"stylesheet\">\n <style>\n :root{\n --font-display:\"Google Sans Thai\",\"Google Sans\",\"Noto Sans Thai\",\"Space Grotesk\",sans-serif;\n --font-sans:\"Google Sans Thai\",\"Google Sans\",\"Noto Sans Thai\",sans-serif;\n --font-mono:\"IBM Plex Mono\",monospace;\n --bg:#0a2540;--bg-deep:#061a2e;--panel:rgba(255,255,255,.04);--panel-strong:#0c2b49;\n --ink:#edf6ff;--soft:#b7d3ef;--muted:#7598ba;--line:rgba(191,224,255,.17);--line-strong:rgba(191,224,255,.36);\n --cyan:#7dd8ff;--mint:#6fe3b4;--gold:#f2c14e;--red:#ff7061;--violet:#b8a4ff;\n --mint-soft:rgba(111,227,180,.14);--gold-soft:rgba(242,193,78,.14);--red-soft:rgba(255,112,97,.14);--violet-soft:rgba(184,164,255,.14);\n }\n *{box-sizing:border-box}\n html{color-scheme:dark}\n body{margin:0;min-height:100vh;background-color:var(--bg);color:var(--ink);font-family:var(--font-sans);-webkit-font-smoothing:antialiased;background-image:linear-gradient(rgba(125,216,255,.065) 1px,transparent 1px),linear-gradient(90deg,rgba(125,216,255,.065) 1px,transparent 1px),radial-gradient(circle at 8% -5%,rgba(125,216,255,.16),transparent 42rem);background-size:34px 34px,34px 34px,auto}\n button,input{font:inherit}\n code{font-family:var(--font-mono);color:var(--cyan)}\n .sheet{width:min(1180px,calc(100% - 40px));margin:0 auto;padding:34px 0 64px}\n .titleblock{display:flex;align-items:flex-end;justify-content:space-between;gap:26px;padding-bottom:20px;border-bottom:1px solid var(--line-strong);flex-wrap:wrap}\n .eyebrow,.label{font:600 10px/1 var(--font-mono);letter-spacing:.13em;text-transform:uppercase;color:var(--cyan)}\n .eyebrow{display:flex;align-items:center;gap:8px;margin-bottom:12px}.eyebrow:before{content:\"\";width:20px;height:1px;background:var(--cyan)}\n h1{margin:0 0 6px;font:700 clamp(32px,4vw,48px)/1.05 var(--font-display);letter-spacing:-.03em}\n .path,.muted{color:var(--muted);font-size:12px;line-height:1.65}.path{font-family:var(--font-mono)}\n .badges{display:flex;flex-wrap:wrap;gap:8px;margin-top:12px}.badge,.pill{padding:4px 9px;border:1px solid var(--line-strong);border-radius:3px;background:rgba(255,255,255,.025);color:var(--muted);font:600 10px/1.5 var(--font-mono);text-transform:uppercase}\n .ok,.healthy,.current,.ready,.idle{border-color:rgba(111,227,180,.42)!important;color:var(--mint)!important;background:var(--mint-soft)!important}\n .warning,.available,.offline,.blocked,.fail{border-color:rgba(255,112,97,.42)!important;color:var(--red)!important;background:var(--red-soft)!important}\n .active,.deep,.fast,.configured{border-color:rgba(184,164,255,.42)!important;color:var(--violet)!important;background:var(--violet-soft)!important}\n .meta{display:grid;grid-template-columns:auto auto;gap:4px 20px;margin:0;font:11px/1.55 var(--font-mono)}.meta dt{color:var(--muted);text-transform:uppercase}.meta dd{margin:0;color:var(--soft);text-align:right}\n .live{display:flex;align-items:center;gap:8px;margin:14px 0 24px;font:11px var(--font-mono);color:var(--muted)}.live-dot{width:7px;height:7px;border-radius:50%;background:var(--gold)}.live-dot.on{background:var(--mint);box-shadow:0 0 0 4px rgba(111,227,180,.12)}\n .panel,.card{position:relative;min-width:0;border:1px solid var(--line);border-radius:4px;background:var(--panel)}\n #dual-track{overflow:hidden}\n .stepper{justify-content:center}.step{display:flex;flex-direction:column;align-items:center;text-align:center}.step-icon{display:grid;place-items:center;width:30px;height:30px;margin:10px auto 8px;border:1px solid currentColor;border-radius:8px;background:rgba(255,255,255,.035)}.icon-glyph{display:block;font-size:17px;line-height:1}.step.flow-0,.step.flow-4{color:var(--cyan)}.step.flow-1,.step.flow-5{color:var(--violet)}.step.flow-2,.step.flow-6{color:var(--gold)}.step.flow-3,.step.flow-7{color:var(--mint)}.step .step-name{color:currentColor}.step .step-cmd{color:var(--muted)}\n .panel{padding:24px 26px;margin-bottom:20px}.panel-head,.card-head{display:flex;align-items:center;justify-content:space-between;gap:14px;flex-wrap:wrap}.panel-head{margin-bottom:20px}.card-head{margin-bottom:17px}\n .track-tabs{display:flex;gap:7px;flex-wrap:wrap}.tab{display:inline-flex;align-items:center;gap:7px;padding:7px 13px;border:1px solid var(--line-strong);border-radius:99px;background:transparent;color:var(--muted);font:600 10px var(--font-mono);cursor:pointer}.tab:hover,.tab:focus-visible{border-color:var(--cyan);color:var(--cyan);outline:none}.tab.on{background:var(--cyan);border-color:var(--cyan);color:var(--bg-deep)}.tab-active-dot{display:none;padding:2px 6px;border-radius:99px;font:700 8px/1 var(--font-mono);letter-spacing:.05em;text-transform:uppercase;background:var(--mint);color:var(--bg-deep)}.tab.is-active-track .tab-active-dot{display:inline-flex;align-items:center;gap:3px;box-shadow:0 0 0 2px rgba(111,227,180,.25)}.tab.on.is-active-track .tab-active-dot{background:var(--bg-deep);color:var(--mint)}\n .track-view{display:none;min-width:0}.track-view.on{display:block}.stepper{display:flex;width:100%;max-width:100%;overflow-x:auto;padding:4px 0 7px}.step{flex:1 1 0;min-width:104px;position:relative;padding-right:12px}.step-line{position:absolute;top:10px;left:21px;right:0;height:1px;background:var(--line-strong)}.step:last-child .step-line{display:none}.step.done .step-line{background:var(--mint)}\n .step-dot{position:relative;z-index:1;width:21px;height:21px;border-radius:50%;display:grid;place-items:center;border:2px solid var(--line-strong);background:var(--bg-deep);color:var(--muted);font:700 8px var(--font-mono)}.step.done .step-dot{border-color:var(--mint);color:var(--mint)}.step.active .step-dot{border-color:var(--gold);color:var(--gold);box-shadow:0 0 0 4px rgba(242,193,78,.16)}\n .step-name{margin-top:9px;color:var(--soft);font:600 10px/1.35 var(--font-mono)}.step.active .step-name{color:var(--gold)}.step.done .step-name{color:var(--mint)}.step-cmd{margin-top:3px;color:var(--muted);font:9px/1.4 var(--font-mono)}.track-note{margin-top:12px;padding-top:12px;border-top:1px dashed var(--line);color:var(--muted);font:11px/1.65 var(--font-mono)}\n .next-action{background:var(--bg-deep);border-color:var(--line-strong)}.next-head{display:flex;justify-content:space-between;gap:12px;align-items:center}.command{margin:8px 0 6px;color:var(--gold);font:700 clamp(22px,3vw,30px)/1.3 var(--font-mono)}.copy{padding:7px 12px;border:1px solid var(--cyan);border-radius:3px;background:transparent;color:var(--cyan);font:600 10px var(--font-mono);cursor:pointer}.copy:hover,.copy:focus-visible{background:var(--cyan);color:var(--bg-deep);outline:none}\n .stats{display:grid;grid-template-columns:repeat(5,1fr);gap:1px;margin:0 0 20px;border:1px solid var(--line);border-radius:4px;overflow:hidden;background:var(--line)}.stat{padding:16px 18px;background:var(--bg-deep)}.stat-value{font:700 25px/1 var(--font-display)}.stat-label{margin-top:6px;color:var(--muted);font:10px var(--font-mono);text-transform:uppercase;letter-spacing:.08em}\n .grid{display:grid;grid-template-columns:repeat(12,1fr);gap:20px;margin-bottom:20px}.card{grid-column:span 4;min-width:0;padding:clamp(20px,2.4vw,28px)}.card.wide{grid-column:span 8}.card.full{grid-column:1/-1}.value{font:700 18px/1.4 var(--font-display)}\n .facts{display:grid;gap:10px}.fact{display:flex;justify-content:space-between;gap:16px;padding-bottom:10px;border-bottom:1px dashed var(--line)}.fact:last-child{padding-bottom:0;border:0}.fact span:first-child{color:var(--muted);font-size:11px}.fact span:last-child{color:var(--soft);font:11px var(--font-mono);text-align:right;overflow-wrap:anywhere}\n .progress{height:6px;margin:14px 0 9px;border-radius:99px;background:rgba(255,255,255,.07);overflow:hidden}.progress span{display:block;height:100%;width:0;background:var(--gold);transition:width .35s ease}\n ul{list-style:none;margin:0;padding:0}li{padding:10px 0;border-bottom:1px dashed var(--line);color:var(--soft);font-size:12px;line-height:1.55}li:last-child{border:0}.empty{color:var(--muted)}\n .severity{display:grid;grid-template-columns:repeat(4,1fr);gap:8px}.sev{padding:9px 6px;border:1px solid var(--line);border-radius:3px;text-align:center}.sev b{display:block;font:700 17px var(--font-display)}.sev small{color:var(--muted);font:9px var(--font-mono)}\n .commands{display:flex;flex-wrap:wrap;gap:10px}.cmd{position:relative;padding:8px 13px;border:1px solid var(--line-strong);border-radius:3px;background:rgba(255,255,255,.025);color:var(--soft);font:11px var(--font-mono);cursor:pointer}.cmd:hover,.cmd:focus-visible,.cmd:focus{border-color:var(--cyan);color:var(--cyan);outline:2px solid rgba(125,216,255,.2);outline-offset:2px}.cmd:after{content:attr(data-tip);position:absolute;z-index:30;left:50%;bottom:calc(100% + 10px);width:max-content;max-width:min(300px,80vw);padding:9px 11px;border:1px solid var(--line-strong);border-radius:3px;background:#031421;color:var(--soft);font:10px/1.5 var(--font-mono);white-space:normal;text-align:left;opacity:0;visibility:hidden;transform:translate(-50%,5px);box-shadow:0 12px 30px rgba(0,0,0,.4);transition:.15s;pointer-events:none}.cmd:hover:after,.cmd:focus-visible:after,.cmd:focus:after{opacity:1;visibility:visible;transform:translate(-50%,0)}\n .adapters,.roster-grid,.mcp-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:12px}.adapter,.roster-card,.mcp-card{padding:15px;border:1px solid var(--line);border-radius:4px;background:rgba(255,255,255,.02)}.adapter strong,.roster-card strong,.mcp-card strong{display:block;margin-bottom:6px;text-transform:capitalize}.adapter-path,.roster-desc,.mcp-desc{color:var(--muted);font:10px var(--font-mono);line-height:1.4}.adapter-state{margin-top:9px;font:10px var(--font-mono)}\n .mcp-grid{grid-template-columns:repeat(3,1fr)}\n .search-row{display:flex;gap:10px;margin-bottom:16px}.search-input{flex:1;padding:10px 14px;background:var(--bg-deep);border:1px solid var(--line-strong);border-radius:4px;color:var(--ink);font-family:var(--font-mono);font-size:12px}.search-btn{padding:10px 18px;border:1px solid var(--cyan);border-radius:4px;background:var(--cyan);color:var(--bg-deep);font-weight:700;cursor:pointer}\n .blast-result{padding:16px;border:1px solid var(--line-strong);border-radius:4px;background:var(--bg-deep);margin-top:12px;display:none}\n .section-note{margin:-2px 0 14px;color:var(--muted);font:10px/1.5 var(--font-mono)}.record-list{display:grid;gap:8px}.record-item{display:grid;grid-template-columns:38px minmax(0,1fr) auto;gap:13px;align-items:center;padding:13px 15px;border:1px solid var(--line);border-left:3px solid var(--record-color,var(--cyan));border-radius:3px;background:rgba(255,255,255,.02)}.record-icon{display:grid;place-items:center;width:31px;height:31px;border-radius:8px;background:color-mix(in srgb,var(--record-color,var(--cyan)) 14%,transparent)}.record-body{min-width:0}.record-meta{color:var(--record-color,var(--cyan));font:700 10px var(--font-mono);letter-spacing:.06em;text-transform:uppercase}.record-title{margin-top:3px;color:var(--ink);font-weight:650}.record-desc{margin-top:3px;color:var(--soft);font-size:12px}.record-desc:empty{display:none}.record-title strong,.record-desc strong{color:var(--record-color,var(--cyan));font-weight:750}.record-title em,.record-desc em{color:var(--gold)}.record-title code,.record-desc code{padding:1px 4px;border:1px solid var(--line);border-radius:3px;color:var(--cyan);font:10px var(--font-mono)}.record-title a,.record-desc a{color:var(--cyan);text-decoration:underline}.record-actions{display:flex;align-items:center;justify-content:flex-end;gap:7px;flex-wrap:wrap}.record-action{border:1px solid var(--record-color,var(--cyan));border-radius:3px;padding:8px 11px;background:transparent;color:var(--record-color,var(--cyan));font:700 10px var(--font-mono);cursor:pointer}.record-action:hover,.record-action:focus-visible{background:var(--record-color,var(--cyan));color:var(--bg)}.record-badge{align-self:start;border:1px solid rgba(111,227,180,.36);border-radius:99px;padding:4px 8px;background:var(--mint-soft);color:var(--mint);font:700 9px var(--font-mono);letter-spacing:.04em;text-transform:uppercase}.record-item.tone-cyan{--record-color:var(--cyan)}.record-item.tone-mint{--record-color:var(--mint)}.record-item.tone-gold{--record-color:var(--gold)}.record-item.tone-red{--record-color:var(--red)}.record-item.tone-violet{--record-color:var(--violet)}.stepper{gap:0;justify-content:center}.step{padding-right:0;overflow:visible}.step-line{left:calc(50% + 10px);right:calc(-50% + 10px);width:auto}#sev-p0{color:var(--red)}#sev-p1{color:var(--gold)}#sev-p2{color:var(--violet)}#sev-p3{color:var(--cyan)}#stat-runs.tone{color:var(--mint)}#stat-findings.tone-ok{color:var(--mint)}#stat-findings.tone-alert{color:var(--red)}#stat-ideas.tone-ok{color:var(--mint)}#stat-ideas.tone-pending{color:var(--gold)}#stat-adapters.tone-ok{color:var(--mint)}#stat-adapters.tone-partial{color:var(--gold)}#stat-state.tone-idle{color:var(--cyan)}#stat-state.tone-active{color:var(--violet)}#stat-state.tone-blocked{color:var(--red)}\n .multitask-panel{border-color:rgba(56,189,248,.35)}.workspace-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(340px,1fr));gap:14px;margin-top:10px}.workspace-card{background:rgba(255,255,255,.025);border:1px solid var(--line);border-radius:6px;padding:16px;display:flex;flex-direction:column;gap:8px;transition:all .2s ease}.workspace-card:hover{border-color:var(--cyan);background:rgba(255,255,255,.04)}.ws-header{display:flex;align-items:center;justify-content:space-between;gap:8px}.ws-id{font-family:var(--font-mono);font-weight:700;font-size:11px;color:var(--cyan);background:var(--cyan-soft);padding:2px 8px;border-radius:3px}.ws-stage{font-family:var(--font-mono);font-size:10px;font-weight:700;text-transform:uppercase;padding:2px 6px;border-radius:3px;background:var(--gold-soft);color:var(--gold);border:1px solid rgba(242,193,78,.3)}.ws-stage.stage-check{background:var(--mint-soft);color:var(--mint);border-color:rgba(111,227,180,.3)}.ws-title{font-weight:650;font-size:13px;color:var(--ink);line-height:1.4}.ws-progress-bar{height:6px;background:rgba(0,0,0,.3);border-radius:99px;overflow:hidden;margin:4px 0}.ws-progress-fill{height:100%;background:linear-gradient(135deg,var(--cyan),var(--violet));transition:width .3s}.ws-meta{display:flex;align-items:center;justify-content:space-between;font-size:11px;color:var(--muted)}.ws-actions{display:flex;align-items:center;gap:6px;padding-top:8px;border-top:1px dashed var(--line);flex-wrap:wrap}.btn-ws{padding:4px 9px;border-radius:3px;font-family:var(--font-mono);font-size:10px;font-weight:700;background:rgba(255,255,255,.04);border:1px solid var(--line);color:var(--soft);cursor:pointer;transition:all .15s}.btn-ws:hover{background:var(--cyan-soft);border-color:var(--cyan);color:var(--cyan)}\n footer{display:flex;justify-content:space-between;gap:10px;flex-wrap:wrap;margin-top:26px;padding-top:17px;border-top:1px solid var(--line);color:var(--muted);font:10px var(--font-mono)}\n @media(max-width:920px){.grid .card,.grid .card.wide{grid-column:1/-1}.stats{grid-template-columns:repeat(2,1fr)}.adapters,.roster-grid,.mcp-grid{grid-template-columns:repeat(2,1fr)}.titleblock{align-items:flex-start;flex-direction:column}.meta dd{text-align:left}.stepper{gap:0}.cmd:after{position:fixed;left:12px;right:12px;bottom:16px;width:auto;max-width:none;transform:translateY(5px)}.cmd:hover:after,.cmd:focus-visible:after,.cmd:focus:after{transform:none}}\n @media(max-width:560px){.sheet{width:calc(100% - 24px);padding-top:22px}.panel,.card{padding:18px}.grid{gap:14px;margin-bottom:14px}.stats{margin-bottom:14px}.adapters,.roster-grid,.mcp-grid{grid-template-columns:1fr}.cmd:after{position:fixed;left:12px;right:12px;bottom:16px;width:auto;max-width:none;transform:translateY(5px)}.cmd:hover:after,.cmd:focus-visible:after,.cmd:focus:after{transform:none}.meta{grid-template-columns:1fr}.track-tabs{width:100%}.tab{flex:1}.fact{align-items:flex-start}.record-item{grid-template-columns:34px minmax(0,1fr)}.record-action{grid-column:2;justify-self:start}}\n @media(prefers-reduced-motion:reduce){*,*:before,*:after{animation-duration:.001ms!important;transition-duration:.001ms!important}}\n </style>\n</head>\n<body>\n <main class=\"sheet\">\n <header class=\"titleblock\">\n <div>\n <div class=\"eyebrow\">Nexus-DevFlow \u00B7 Enterprise Workspace Status</div>\n <h1 id=\"project-name\">Nexus-DevFlow</h1>\n <div class=\"path\" id=\"project-path\">Connecting...</div>\n <div class=\"badges\">\n <span class=\"badge\" id=\"version-badge\">v2.5.0</span>\n <span class=\"badge\" id=\"health-badge\">health</span>\n <span class=\"badge\" id=\"gate-badge\">Gate: checking</span>\n <span class=\"badge\" id=\"drift-badge\">Drift: checking</span>\n <span class=\"badge\" id=\"track-badge\">track</span>\n </div>\n </div>\n <dl class=\"meta\">\n <dt>Package</dt><dd id=\"package-name\">@jakkrichm/create-nexus-devflow</dd>\n <dt>Adapters</dt><dd id=\"adapter-count\">-</dd>\n <dt>Branch</dt><dd id=\"header-branch\">-</dd>\n <dt>Snapshot</dt><dd id=\"generated-at\">-</dd>\n </dl>\n </header>\n <div class=\"live\"><span class=\"live-dot\" id=\"live-dot\"></span><span id=\"live-label\">Connecting to local dashboard...</span></div>\n\n <section class=\"panel\" id=\"dual-track\">\n <div class=\"panel-head\">\n <span class=\"label\">Unified Living Spec Model (DevFlow 2.5.0)</span>\n <div class=\"track-tabs\" role=\"tablist\" aria-label=\"Delivery tracks\">\n <button class=\"tab on\" id=\"tab-preflight\" role=\"tab\" aria-selected=\"true\" aria-controls=\"view-preflight\" data-track=\"preflight\"><span>\uD83D\uDD2E Pre-Flight Discovery</span><span class=\"tab-active-dot\">\u25CF ACTIVE</span></button>\n <button class=\"tab\" id=\"tab-fast\" role=\"tab\" aria-selected=\"false\" aria-controls=\"view-fast\" data-track=\"fast\"><span>\u26A1 Living Spec \u00B7 4 steps</span><span class=\"tab-active-dot\">\u25CF ACTIVE</span></button>\n <button class=\"tab\" id=\"tab-swarm\" role=\"tab\" aria-selected=\"false\" aria-controls=\"view-swarm\" data-track=\"swarm\"><span>\uD83E\uDD16 Multi-Agent Swarm</span></button>\n <button class=\"tab\" id=\"tab-graph\" role=\"tab\" aria-selected=\"false\" aria-controls=\"view-graph\" data-track=\"graph\"><span>\uD83D\uDDFA\uFE0F Code Graph</span></button>\n </div>\n </div>\n <div class=\"track-view on\" id=\"view-preflight\" role=\"tabpanel\" aria-labelledby=\"tab-preflight\">\n <div class=\"stepper\" id=\"pipeline-preflight\"></div>\n <div class=\"track-note\" id=\"note-preflight\">Pre-Flight Discovery & Architectural Alignment (/idea, /grill, /brainstorm, /discovery).</div>\n </div>\n <div class=\"track-view\" id=\"view-fast\" role=\"tabpanel\" aria-labelledby=\"tab-fast\">\n <div class=\"stepper\" id=\"pipeline-fast\"></div>\n <div class=\"track-note\" id=\"note-fast\">Single Living Spec (/feature, /implement, /check, /complete) with TDD Discipline & QA Matrix.</div>\n </div>\n <div class=\"track-view\" id=\"view-swarm\" role=\"tabpanel\" aria-labelledby=\"tab-swarm\">\n <div class=\"section-note\">Role-based specialized AI Subagents roster & execution matrix</div>\n <div class=\"roster-grid\" id=\"swarm-roster\"></div>\n </div>\n <div class=\"track-view\" id=\"view-graph\" role=\"tabpanel\" aria-labelledby=\"tab-graph\">\n <div class=\"section-note\">Semantic dependency graph & instant Blast Radius analyzer</div>\n <div class=\"search-row\">\n <input class=\"search-input\" id=\"graph-file-input\" placeholder=\"Type file path (e.g. packages/create-nexus-devflow/lib/code-graph.ts)...\" />\n <button class=\"search-btn\" id=\"graph-search-btn\" type=\"button\">Analyze Impact</button>\n </div>\n <div class=\"blast-result\" id=\"blast-result\"></div>\n </div>\n </section>\n\n <section class=\"panel next-action\" id=\"next-panel\">\n <div class=\"next-head\"><span class=\"label\">Next Action</span><button class=\"copy\" id=\"next-copy\" type=\"button\">Copy command</button></div>\n <div class=\"command\" id=\"next-command\" aria-live=\"polite\">Loading...</div>\n <div class=\"muted\" id=\"next-reason\"></div>\n </section>\n\n <section class=\"stats\" aria-label=\"Workspace summary\">\n <div class=\"stat\"><div class=\"stat-value\" id=\"stat-runs\">-</div><div class=\"stat-label\">Runs released</div></div>\n <div class=\"stat\"><div class=\"stat-value\" id=\"stat-findings\">-</div><div class=\"stat-label\">Active findings</div></div>\n <div class=\"stat\"><div class=\"stat-value\" id=\"stat-ideas\">-</div><div class=\"stat-label\">Pending ideas</div></div>\n <div class=\"stat\"><div class=\"stat-value\" id=\"stat-mcp\">-</div><div class=\"stat-label\">MCP Tools Ready</div></div>\n <div class=\"stat\"><div class=\"stat-value\" id=\"stat-state\">-</div><div class=\"stat-label\">Current state</div></div>\n </section>\n\n <!-- Multi-Task Living Spec Workspaces Grid -->\n <section class=\"card full panel multitask-panel\" id=\"active-workspaces-panel\">\n <div class=\"panel-head\">\n <div>\n <span class=\"label\">Active Living Specs (Pure Task-Isolated Workspaces)</span>\n <div class=\"muted\" id=\"active-workspaces-summary\" style=\"margin-top:3px;font-size:11px;\">Scanned from devflow/context/{xxx-slug}/</div>\n </div>\n <span class=\"pill active\" id=\"active-workspaces-pill\">0 Active</span>\n </div>\n <div class=\"workspace-grid\" id=\"active-workspaces-list\"></div>\n </section>\n\n <section class=\"grid\">\n <article class=\"card\"><div class=\"card-head\"><span class=\"label\">Nexus-DevFlow</span><span class=\"pill\" id=\"update-pill\">checking</span></div><div class=\"facts\"><div class=\"fact\"><span>Installed / latest</span><span id=\"installed-latest\">-</span></div><div class=\"fact\"><span>Health</span><span id=\"system-health\">-</span></div><div class=\"fact\"><span>Architecture</span><span>3-Pillars + Swarm RAG</span></div></div></article>\n <article class=\"card wide\"><div class=\"card-head\"><span class=\"label\">Current Work</span><span class=\"pill\" id=\"work-pill\">loading</span></div><div class=\"value\" id=\"work-title\">Loading...</div><div class=\"progress\"><span id=\"work-progress\"></span></div><div class=\"muted\" id=\"work-meta\"></div></article>\n <article class=\"card\"><div class=\"card-head\"><span class=\"label\">Git & Drift</span><span class=\"pill\" id=\"git-pill\">loading</span></div><div class=\"facts\"><div class=\"fact\"><span>Branch</span><span id=\"git-branch\">-</span></div><div class=\"fact\"><span>Working tree</span><span id=\"git-changed\">-</span></div><div class=\"fact\"><span>Drift Status</span><span id=\"git-drift\">-</span></div><div class=\"fact\"><span>Last commit</span><span id=\"git-commit\">-</span></div></div></article>\n <article class=\"card\"><div class=\"card-head\"><span class=\"label\">Findings Ledger</span><span class=\"value\" id=\"findings-count\">-</span></div><div class=\"severity\"><div class=\"sev\"><b id=\"sev-p0\">0</b><small>P0</small></div><div class=\"sev\"><b id=\"sev-p1\">0</b><small>P1</small></div><div class=\"sev\"><b id=\"sev-p2\">0</b><small>P2</small></div><div class=\"sev\"><b id=\"sev-p3\">0</b><small>P3</small></div></div><ul id=\"findings-list\"></ul></article>\n <article class=\"card\"><div class=\"card-head\"><span class=\"label\">Completion & Gate</span><span class=\"pill\" id=\"completion-pill\">-</span></div><ul id=\"completion-list\"></ul></article>\n <article class=\"card\"><div class=\"card-head\"><span class=\"label\">Warnings</span><span class=\"value\" id=\"warnings-count\">-</span></div><ul id=\"warnings-list\"></ul></article>\n </section>\n\n <section class=\"card full panel\"><div class=\"card-head\"><span class=\"label\">Model Context Protocol (MCP) Tools Hub</span><span class=\"value\" id=\"mcp-count\">12 Tools</span></div><div class=\"section-note\">Typed JSON-RPC tools exposed to AI Coding Assistants</div><div class=\"mcp-grid\" id=\"mcp-list\"></div></section>\n <section class=\"card full panel\"><div class=\"card-head\"><span class=\"label\">Quick Commands</span><span class=\"muted\">hover or focus for help \u00B7 click to copy</span></div><div class=\"commands\" id=\"command-list\"></div></section>\n <section class=\"grid\"><article class=\"card full\"><div class=\"card-head\"><span class=\"label\">Doctor \u00B7 Health Check</span><span class=\"pill\" id=\"doctor-pill\">-</span></div><div class=\"record-list\" id=\"doctor-list\"></div></article></section>\n <section class=\"card full panel\"><div class=\"card-head\"><span class=\"label\">Discoveries</span><span class=\"value\" id=\"discovery-count\">-</span></div><div class=\"record-list\" id=\"discovery-list\"></div></section>\n <section class=\"card full panel\"><div class=\"card-head\"><span class=\"label\">Idea Inbox & Backlog</span><span class=\"value\" id=\"ideas-count\">-</span></div><div class=\"section-note\">From devflow/ideas.md \u00B7 start a selected item with /feature IDEA-xxx</div><div class=\"record-list\" id=\"ideas-list\"></div></section>\n <section class=\"card full panel\"><div class=\"card-head\"><span class=\"label\">Completed Work Archive</span><span class=\"value\" id=\"history-count\">-</span></div><div class=\"section-note\">Categorized delivery history \u00B7 features, fixes and rollbacks</div><div class=\"record-list\" id=\"history-list\"></div></section>\n <footer><span>Nexus-DevFlow 2.5.0 Enterprise Dashboard \u00B7 refreshes every 2 seconds</span><span id=\"footer-revision\">snapshot pending</span></footer>\n </main>\n <script>\n const byId = (id) => document.getElementById(id);\n const escapeHtml = (str) => String(str == null ? '' : str).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;').replace(/'/g, '&#039;');\n const text = (id, value) => { const node = byId(id); if (node) node.textContent = value == null ? '-' : String(value); };\n const pill = (id, state, label) => { const node = byId(id); if (!node) return; node.className = 'pill ' + (state || 'configured'); node.textContent = label || state || '-'; };\n const list = (id, values, empty) => { const node = byId(id); if (!node) return; node.replaceChildren(); const rows = values.length ? values : [empty]; rows.forEach((value) => { const li = document.createElement('li'); li.textContent = value; if (!values.length) li.className = 'empty'; node.append(li); }); };\n const titleCase = (value) => String(value || '').replaceAll('_',' ').replace(/\bw/g, (c) => c.toUpperCase());\n const FLOW_ICON_NAMES = ['target','code','shield','package'];\n const EMOJI_ICONS = { compass:'\uD83D\uDD0E',discovery:'\uD83D\uDD0E',target:'\uD83C\uDFAF',document:'\uD83D\uDCC4',list:'\uD83E\uDDE9',code:'\u2699\uFE0F',shield:'\uD83E\uDDEA',report:'\uD83D\uDCCA',package:'\uD83D\uDCE6',bulb:'\uD83D\uDCA1',check:'\u2705',wrench:'\uD83D\uDEE0\uFE0F',rollback:'\u21A9\uFE0F',search:'\uD83D\uDD0D',alert:'\u26A0\uFE0F',grill:'\uD83D\uDD25',brainstorm:'\uD83D\uDCAD',idea:'\uD83D\uDCA1' };\n function iconImage(name) { const icon = document.createElement('span'); icon.className = 'icon-glyph'; icon.setAttribute('aria-hidden','true'); icon.textContent = EMOJI_ICONS[name] || '\uD83D\uDCC4'; return icon; }\n function decoratePipeline(id) { byId(id)?.querySelectorAll('.step').forEach((step,index) => { step.classList.add('flow-' + index); const icon = document.createElement('span'); icon.className = 'step-icon'; icon.setAttribute('aria-hidden','true'); const cmd = step.querySelector('.step-cmd')?.textContent?.replace('/','').split(' ')[0] || ''; const iconKey = id.includes('preflight') ? (cmd || ['idea','grill','brainstorm','discovery'][index] || 'search') : (FLOW_ICON_NAMES[index] || 'document'); icon.append(iconImage(iconKey)); const name = step.querySelector('.step-name'); step.insertBefore(icon,name || null); }); }\n function richText(root,value) { const source = String(value || ''); let cursor = 0; const plain = (end) => { if (end > cursor) root.append(document.createTextNode(source.slice(cursor,end))); cursor = end; }; while (cursor < source.length) { if (source.startsWith('**',cursor)) { const end = source.indexOf('**',cursor + 2); if (end > cursor + 2) { const node = document.createElement('strong'); node.textContent = source.slice(cursor + 2,end); root.append(node); cursor = end + 2; continue; } } if (source[cursor] === '*') { const end = source.indexOf('*',cursor + 1); if (end > cursor + 1) { const node = document.createElement('em'); node.textContent = source.slice(cursor + 1,end); root.append(node); cursor = end + 1; continue; } } if (source.charCodeAt(cursor) === 96) { const end = source.indexOf(String.fromCharCode(96),cursor + 1); if (end > cursor + 1) { const node = document.createElement('code'); node.textContent = source.slice(cursor + 1,end); root.append(node); cursor = end + 1; continue; } } const next = [source.indexOf('**',cursor + 1),source.indexOf('*',cursor + 1),source.indexOf(String.fromCharCode(96),cursor + 1)].filter((index) => index >= 0).sort((a,b) => a-b)[0] ?? source.length; plain(next > cursor ? next : cursor + 1); } }\n function recordCard(options) { const card = document.createElement('article'); card.className = 'record-item tone-' + (options.tone || 'cyan'); const icon = document.createElement('span'); icon.className = 'record-icon'; icon.append(iconImage(options.icon || 'document')); const body = document.createElement('div'); body.className = 'record-body'; const meta = document.createElement('div'); meta.className = 'record-meta'; richText(meta,options.meta); const title = document.createElement('div'); title.className = 'record-title'; richText(title,options.title); const desc = document.createElement('div'); desc.className = 'record-desc'; richText(desc,options.description); body.append(meta,title,desc); card.append(icon,body); if (options.badge) { const badge = document.createElement('span'); badge.className = 'record-badge'; badge.textContent = options.badge; card.append(badge); } return card; }\n function renderRecords(id,items,empty,mapper) { const root = byId(id); root.replaceChildren(); if (!items?.length) { const node = document.createElement('div'); node.className = 'empty'; node.textContent = empty; root.append(node); return; } items.forEach((item,index) => root.append(recordCard(mapper(item,index)))); }\n function renderIdeas(items) { renderRecords('ideas-list',items,'No pending ideas',(item) => ({ icon:'bulb',tone:'gold',meta:item.id,title:item.title,description:(item.description || '\u26A1') + ' \u00B7 ' + (item.feasibility || 'Not scored') })); }\n function renderHistory(items) { const map = { feature:{icon:'package',tone:'cyan'},fix:{icon:'wrench',tone:'gold'},rollback:{icon:'rollback',tone:'red'} }; renderRecords('history-list',(items || []).slice(0,10),'No completed work in history archive',(item) => { const type = String(item.type || 'other').toLowerCase(); const style = map[type] || {icon:'report',tone:'violet'}; return { ...style,meta:type + ' ' + (item.buildPlanItem || ''),title:item.title,description:'',badge:'Released' }; }); }\n function renderDoctor(items) { renderRecords('doctor-list',items,'No doctor checks available',(item) => ({ icon:item.status === 'pass' ? 'check' : 'alert',tone:item.status === 'pass' ? 'mint' : item.status === 'warn' ? 'gold' : 'red',meta:item.status,title:item.name,description:item.message })); }\n function renderDiscoveries(items) { renderRecords('discovery-list',items,'No discoveries recorded',(item) => ({ icon:'search',tone:'mint',meta:item.id,title:item.title,description:'',badge:'Decision: ' + (item.decision || 'Pending') })); }\n\n function renderPipeline(id, nodes) {\n const root = byId(id); root.replaceChildren();\n (nodes || []).forEach((node, index) => {\n const step = document.createElement('div'); step.className = 'step ' + node.state;\n const line = document.createElement('span'); line.className = 'step-line';\n const dot = document.createElement('span'); dot.className = 'step-dot'; dot.textContent = node.state === 'done' ? '\u2713' : String(index + 1).padStart(nodes.length > 4 ? 2 : 1, '0');\n const name = document.createElement('div'); name.className = 'step-name'; name.textContent = node.label;\n const command = document.createElement('div'); command.className = 'step-cmd'; command.textContent = node.command;\n step.append(line, dot, name, command); root.append(step);\n });\n }\n\n let userHasSwitchedTab = false;\n function selectTrack(track) {\n document.querySelectorAll('.tab').forEach((node) => { const on = node.dataset.track === track; node.classList.toggle('on', on); node.setAttribute('aria-selected', String(on)); });\n document.querySelectorAll('.track-view').forEach((node) => node.classList.toggle('on', node.id === 'view-' + track));\n }\n\n function wireCopy(button, getValue) {\n button.addEventListener('click', async () => {\n const original = button.textContent;\n button.textContent = 'Copied!';\n try { await navigator.clipboard.writeText(getValue()); }\n catch { button.textContent = 'Copy unavailable'; }\n setTimeout(() => { button.textContent = original; }, 1100);\n });\n }\n\n document.querySelectorAll('.tab').forEach((node) => node.addEventListener('click', () => { userHasSwitchedTab = true; selectTrack(node.dataset.track); }));\n wireCopy(byId('next-copy'), () => byId('next-command').textContent.trim());\n\n function renderCommands(commands) {\n const root = byId('command-list'); root.replaceChildren();\n const allCommands = [...(commands || [])];\n ['nexus-devflow check-gate', 'nexus-devflow drift', 'nexus-devflow reconcile --fix', 'nexus-devflow slice --stage implement', 'nexus-devflow swarm', 'nexus-devflow studio'].forEach(c => {\n if (!allCommands.some(item => item.command === c)) {\n allCommands.push({ name: c.replace('nexus-devflow ', ''), command: c, family: 'companion', description: 'Run ' + c });\n }\n });\n allCommands.forEach((item) => {\n const button = document.createElement('button'); button.type = 'button'; button.className = 'cmd'; button.textContent = item.name; button.dataset.tip = item.description; wireCopy(button, () => item.command); root.append(button);\n });\n }\n\n function renderSwarm(swarm) {\n const root = byId('swarm-roster'); if (!root) return; root.replaceChildren();\n (swarm?.agentRoster || []).forEach(agent => {\n const card = document.createElement('div'); card.className = 'roster-card';\n card.innerHTML = '<strong>' + agent.avatar + ' ' + agent.name + '</strong><div class=\"roster-desc\">' + agent.responsibility + '</div>';\n root.append(card);\n });\n }\n\n function renderMcp(tools) {\n const root = byId('mcp-list'); if (!root) return; root.replaceChildren();\n (tools || []).forEach(t => {\n const card = document.createElement('div'); card.className = 'mcp-card';\n card.innerHTML = '<strong>\u2699\uFE0F ' + t.name + '</strong><div class=\"mcp-desc\">' + t.description + '</div>';\n root.append(card);\n });\n }\n\n byId('graph-search-btn')?.addEventListener('click', async () => {\n const input = byId('graph-file-input'); const res = byId('blast-result');\n if (!input || !res) return;\n const file = input.value.trim();\n if (!file) return;\n res.style.display = 'block'; res.innerHTML = 'Analyzing Blast Radius...';\n try {\n const resp = await fetch('/api/graph?file=' + encodeURIComponent(file));\n const data = await resp.json();\n if (data.error) { res.innerHTML = '<span style=\"color:var(--red)\">' + data.error + '</span>'; return; }\n let html = '<strong>Impact Score: <span style=\"color:var(--gold)\">' + data.impactScore + '</span> | Total Affected: ' + data.totalAffected + ' files</strong><br/><br/>';\n if (data.directDependents?.length) {\n html += '<strong>Direct Dependents:</strong><ul>' + data.directDependents.map(d => '<li>' + d + '</li>').join('') + '</ul>';\n }\n if (data.transitiveDependents?.length) {\n html += '<br/><strong>Transitive Dependents:</strong><ul>' + data.transitiveDependents.map(t => '<li>' + t + '</li>').join('') + '</ul>';\n }\n res.innerHTML = html;\n } catch (e) {\n res.innerHTML = '<span style=\"color:var(--red)\">Error: ' + e.message + '</span>';\n }\n });\n\n function renderActiveWorkspaces(activeRuns, work) {\n const root = byId('active-workspaces-list');\n if (!root) return;\n root.replaceChildren();\n const runs = (activeRuns && activeRuns.length > 0) ? activeRuns : (work && work.state === 'active' ? [{\n runId: work.runId || 'ACTIVE',\n title: work.title || 'Active Spec',\n status: work.status || 'implementing',\n branch: 'current',\n totalTasks: work.total || 0,\n completedTasks: work.completed || 0,\n remainingTasks: work.remaining || 0,\n hasOpenFindings: false\n }] : []);\n\n pill('active-workspaces-pill', runs.length > 0 ? 'active' : 'idle', runs.length + ' Active');\n text('active-workspaces-summary', runs.length > 0 ? 'Found ' + runs.length + ' active workspace(s) in devflow/context/' : 'No active workspace folders. Run /feature or /fix to start.');\n\n if (runs.length === 0) {\n const empty = document.createElement('div');\n empty.className = 'empty';\n empty.style.padding = '18px';\n empty.textContent = 'No active delivery runs in progress. Use /feature or /fix to create a living spec.';\n root.append(empty);\n return;\n }\n\n runs.forEach((run) => {\n const card = document.createElement('article');\n card.className = 'workspace-card';\n const pct = run.totalTasks > 0 ? Math.round((run.completedTasks / run.totalTasks) * 100) : 0;\n const stageClass = (run.status || '').includes('check') ? 'ws-stage stage-check' : 'ws-stage';\n const findingTag = run.hasOpenFindings ? '<span style=\"color:var(--red);font-size:10px;font-weight:700;\">\u26A0 Open Findings</span>' : '<span style=\"color:var(--mint);font-size:10px;font-weight:700;\">\u2714 0 Blockers</span>';\n\n card.innerHTML = '<div class=\"ws-header\">' +\n '<span class=\"ws-id\">' + escapeHtml(run.runId) + '</span>' +\n '<span class=\"' + stageClass + '\">Stage: ' + escapeHtml(run.status || 'active') + '</span>' +\n '</div>' +\n '<div class=\"ws-title\">' + escapeHtml(run.title || 'Living Spec') + '</div>' +\n '<div class=\"ws-progress-bar\"><div class=\"ws-progress-fill\" style=\"width:' + pct + '%;\"></div></div>' +\n '<div class=\"ws-meta\">' +\n '<span>\uD83C\uDF3F <code>' + escapeHtml(run.branch || 'main') + '</code></span>' +\n '<span><strong>' + pct + '%</strong> (' + run.completedTasks + '/' + run.totalTasks + ' Tasks)</span>' +\n '</div>' +\n '<div style=\"display:flex;justify-content:space-between;align-items:center;margin-top:2px;\">' +\n findingTag +\n '<span style=\"font-size:10px;color:var(--muted);\">' + run.remainingTasks + ' remaining</span>' +\n '</div>' +\n '<div class=\"ws-actions\">' +\n '<button class=\"btn-ws\" type=\"button\" data-cmd=\"/implement ' + escapeHtml(run.runId) + '\">\u25B6 /implement</button>' +\n '<button class=\"btn-ws\" type=\"button\" data-cmd=\"/check ' + escapeHtml(run.runId) + '\">\uD83E\uDDEA /check</button>' +\n '<button class=\"btn-ws\" type=\"button\" data-cmd=\"/complete ' + escapeHtml(run.runId) + '\">\uD83D\uDCE6 /complete</button>' +\n '</div>';\n\n card.querySelectorAll('.btn-ws').forEach(btn => {\n wireCopy(btn, () => btn.getAttribute('data-cmd'));\n });\n root.append(card);\n });\n }\n\n function renderSnapshot(data) {\n const status = data.status || {}; const project = status.project || {}; const devflow = status.devflow || {}; const work = status.currentWork || {}; const git = status.git || {}; const findings = status.findings || { active: [], blockers: [] }; const workflow = data.workflow || {}; const update = data.update || {}; const doctor = data.doctor || { checks: [] }; const discoveries = data.discoveries || { recent: [] }; const history = data.history || { items: [], total: 0 }; const ideas = status.ideas || { pending: [], totalPending: 0 }; const gate = data.gatekeeper || { passed: true }; const drift = data.drift || { hasDrift: false };\n\n text('project-name', project.name || 'Nexus-DevFlow'); text('project-path', project.root || ''); text('version-badge', 'v' + (devflow.version || '2.5.0'));\n pill('health-badge', status.health, status.health === 'ok' ? 'Health OK' : 'Health warning');\n pill('gate-badge', gate.passed ? 'ok' : 'blocked', gate.passed ? '\u2714 Gate Passed' : '\u2716 Gate Blocked');\n pill('drift-badge', !drift.hasDrift ? 'ok' : 'warning', !drift.hasDrift ? '\u2714 In Sync' : '\u26A0 Drift Detected');\n pill('track-badge', workflow.track, 'Track ' + titleCase(workflow.track || 'idle'));\n\n text('adapter-count', (devflow.adapters || []).length + ' configured'); text('header-branch', git.branch || 'unknown'); text('generated-at', new Date(data.generatedAt).toLocaleTimeString()); text('footer-revision', 'snapshot ' + data.generatedAt);\n renderPipeline('pipeline-preflight', workflow.deep || workflow.preflight); renderPipeline('pipeline-fast', workflow.fast); decoratePipeline('pipeline-preflight'); decoratePipeline('pipeline-fast');\n if (!userHasSwitchedTab) {\n if (work.state === 'active' || workflow.track === 'fast') {\n selectTrack('fast');\n } else {\n selectTrack('preflight');\n }\n }\n renderSwarm(data.swarm); renderMcp(data.mcpTools); text('stat-mcp', (data.mcpTools || []).length + ' Ready');\n renderActiveWorkspaces(status.activeRuns, work);\n\n const nextCommand = data.nextAction?.command || status.nextAction?.command || '/feature'; text('next-command', nextCommand); text('next-reason', data.nextAction?.reason || 'Ready for new work.');\n text('stat-runs', history.total || 0); text('stat-findings', (findings.active || []).length); text('stat-ideas', ideas.totalPending || 0); text('stat-state', titleCase(work.state || 'idle'));\n pill('update-pill', update.state, update.state === 'current' ? 'up to date' : update.state); text('installed-latest', (update.installedVersion || '2.5.0') + ' / ' + (update.latestVersion || '2.5.0')); text('system-health', status.health || 'ok');\n pill('work-pill', work.state, work.state || 'idle'); text('work-title', work.title || 'No active delivery run'); const pct = work.total > 0 ? Math.round((work.completed / work.total) * 100) : 0; byId('work-progress').style.width = pct + '%'; text('work-meta', work.state === 'active' ? work.completed + ' of ' + work.total + ' steps completed' : 'Ready');\n pill('git-pill', git.clean ? 'ok' : 'warning', git.clean ? 'clean' : (git.changedFiles || 0) + ' changed'); text('git-branch', git.branch || 'unknown'); text('git-changed', git.clean ? 'clean' : (git.changedFiles || 0) + ' changed files'); text('git-drift', drift.clean ? 'In Sync' : 'Drift detected'); text('git-commit', git.lastCommit || '-');\n text('findings-count', findings.total || 0); ['P0','P1','P2','P3'].forEach((severity) => text('sev-' + severity.toLowerCase(), (findings.active || []).filter((item) => item.severity === severity).length)); list('findings-list', (findings.active || []).map((item) => item.id + ' \u00B7 ' + item.title), 'No active findings');\n pill('completion-pill', status.completion?.state, status.completion?.state || 'unknown'); list('completion-list', status.completion?.blockers || [], work.state === 'idle' ? 'No active run to complete' : 'All readiness checks passed'); text('warnings-count', (status.warnings || []).length); list('warnings-list', (status.warnings || []).map((item) => item.message), 'No active warnings or drift');\n pill('doctor-pill', doctor.failCount ? 'fail' : doctor.warnCount ? 'warning' : 'ok', doctor.passCount + '/' + doctor.totalChecks + ' pass'); renderDoctor(doctor.checks || []);\n text('discovery-count', discoveries.total || 0); renderDiscoveries(discoveries.recent || []); renderCommands(data.commands);\n text('ideas-count', (ideas.totalPending || 0) + ' pending'); renderIdeas(ideas.pending || []); text('history-count', (history.total || 0) + ' released'); renderHistory(history.items || []);\n }\n\n window.__INITIAL_SNAPSHOT__ = null;\n if (window.__INITIAL_SNAPSHOT__) {\n try {\n renderSnapshot(window.__INITIAL_SNAPSHOT__);\n byId('live-dot').classList.add('on');\n text('live-label','Connected \u00B7 live snapshot every 2 seconds');\n } catch (e) {\n console.error('Initial hydration error:', e);\n }\n }\n\n let refreshing = false;\n async function refresh() { if (refreshing) return; refreshing = true; try { const response = await fetch('/api/dashboard'); if (!response.ok) throw new Error('HTTP ' + response.status); renderSnapshot(await response.json()); byId('live-dot').classList.add('on'); text('live-label','Connected \u00B7 live snapshot every 2 seconds'); } catch (error) { byId('live-dot').classList.remove('on'); text('live-label','Disconnected \u00B7 ' + error.message); } finally { refreshing = false; } }\n if (!window.__INITIAL_SNAPSHOT__) { refresh(); }\n setInterval(refresh, 2000);\n </script>\n</body>\n</html>";
1
+ declare const DASHBOARD_PAGE_HTML = "<!doctype html>\n<html lang=\"th\">\n<head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n <title>Nexus-DevFlow Enterprise Dashboard</title>\n <link rel=\"preconnect\" href=\"https://fonts.googleapis.com\">\n <link rel=\"preconnect\" href=\"https://fonts.gstatic.com\" crossorigin>\n <link rel=\"preconnect\" href=\"https://fonts.googleapis.com\" />\n <link rel=\"preconnect\" href=\"https://fonts.gstatic.com\" crossorigin />\n <link href=\"https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;500;600;700&family=Noto+Sans+Thai:wght@400;500;600;700&family=Space+Grotesk:wght@500;600;700&display=swap\" rel=\"stylesheet\">\n <style>\n :root{\n --font-display:\"Google Sans Thai\",\"Google Sans\",\"Noto Sans Thai\",\"Space Grotesk\",sans-serif;\n --font-sans:\"Google Sans Thai\",\"Google Sans\",\"Noto Sans Thai\",sans-serif;\n --font-mono:\"IBM Plex Mono\",monospace;\n --bg:#0a2540;--bg-deep:#061a2e;--panel:rgba(255,255,255,.04);--panel-strong:#0c2b49;\n --ink:#edf6ff;--soft:#b7d3ef;--muted:#7598ba;--line:rgba(191,224,255,.17);--line-strong:rgba(191,224,255,.36);\n --cyan:#7dd8ff;--mint:#6fe3b4;--gold:#f2c14e;--red:#ff7061;--violet:#b8a4ff;\n --mint-soft:rgba(111,227,180,.14);--gold-soft:rgba(242,193,78,.14);--red-soft:rgba(255,112,97,.14);--violet-soft:rgba(184,164,255,.14);\n }\n *{box-sizing:border-box}\n html{color-scheme:dark}\n body{margin:0;min-height:100vh;background-color:var(--bg);color:var(--ink);font-family:var(--font-sans);-webkit-font-smoothing:antialiased;background-image:linear-gradient(rgba(125,216,255,.065) 1px,transparent 1px),linear-gradient(90deg,rgba(125,216,255,.065) 1px,transparent 1px),radial-gradient(circle at 8% -5%,rgba(125,216,255,.16),transparent 42rem);background-size:34px 34px,34px 34px,auto}\n button,input{font:inherit}\n code{font-family:var(--font-mono);color:var(--cyan)}\n .sheet{width:min(1180px,calc(100% - 40px));margin:0 auto;padding:34px 0 64px}\n .titleblock{display:flex;align-items:flex-end;justify-content:space-between;gap:26px;padding-bottom:20px;border-bottom:1px solid var(--line-strong);flex-wrap:wrap}\n .eyebrow,.label{font:600 10px/1 var(--font-mono);letter-spacing:.13em;text-transform:uppercase;color:var(--cyan)}\n .eyebrow{display:flex;align-items:center;gap:8px;margin-bottom:12px}.eyebrow:before{content:\"\";width:20px;height:1px;background:var(--cyan)}\n h1{margin:0 0 6px;font:700 clamp(32px,4vw,48px)/1.05 var(--font-display);letter-spacing:-.03em}\n .path,.muted{color:var(--muted);font-size:12px;line-height:1.65}.path{font-family:var(--font-mono)}\n .badges{display:flex;flex-wrap:wrap;gap:8px;margin-top:12px}.badge,.pill{padding:4px 9px;border:1px solid var(--line-strong);border-radius:3px;background:rgba(255,255,255,.025);color:var(--muted);font:600 10px/1.5 var(--font-mono);text-transform:uppercase}\n .ok,.healthy,.current,.ready,.idle{border-color:rgba(111,227,180,.42)!important;color:var(--mint)!important;background:var(--mint-soft)!important}\n .warning,.available,.offline,.blocked,.fail{border-color:rgba(255,112,97,.42)!important;color:var(--red)!important;background:var(--red-soft)!important}\n .active,.deep,.fast,.configured{border-color:rgba(184,164,255,.42)!important;color:var(--violet)!important;background:var(--violet-soft)!important}\n .meta{display:grid;grid-template-columns:auto auto;gap:4px 20px;margin:0;font:11px/1.55 var(--font-mono)}.meta dt{color:var(--muted);text-transform:uppercase}.meta dd{margin:0;color:var(--soft);text-align:right}\n .live{display:flex;align-items:center;gap:8px;margin:14px 0 24px;font:11px var(--font-mono);color:var(--muted)}.live-dot{width:7px;height:7px;border-radius:50%;background:var(--gold)}.live-dot.on{background:var(--mint);box-shadow:0 0 0 4px rgba(111,227,180,.12)}\n .panel,.card{position:relative;min-width:0;border:1px solid var(--line);border-radius:4px;background:var(--panel)}\n #dual-track{overflow:hidden}\n .stepper{justify-content:center}.step{display:flex;flex-direction:column;align-items:center;text-align:center}.step-icon{display:grid;place-items:center;width:30px;height:30px;margin:10px auto 8px;border:1px solid currentColor;border-radius:8px;background:rgba(255,255,255,.035)}.icon-glyph{display:block;font-size:17px;line-height:1}.step.flow-0,.step.flow-4{color:var(--cyan)}.step.flow-1,.step.flow-5{color:var(--violet)}.step.flow-2,.step.flow-6{color:var(--gold)}.step.flow-3,.step.flow-7{color:var(--mint)}.step .step-name{color:currentColor}.step .step-cmd{color:var(--muted)}\n .panel{padding:24px 26px;margin-bottom:20px}.panel-head,.card-head{display:flex;align-items:center;justify-content:space-between;gap:14px;flex-wrap:wrap}.panel-head{margin-bottom:20px}.card-head{margin-bottom:17px}\n .track-tabs{display:flex;gap:7px;flex-wrap:wrap}.tab{display:inline-flex;align-items:center;gap:7px;padding:7px 13px;border:1px solid var(--line-strong);border-radius:99px;background:transparent;color:var(--muted);font:600 10px var(--font-mono);cursor:pointer}.tab:hover,.tab:focus-visible{border-color:var(--cyan);color:var(--cyan);outline:none}.tab.on{background:var(--cyan);border-color:var(--cyan);color:var(--bg-deep)}.tab-active-dot{display:none;padding:2px 6px;border-radius:99px;font:700 8px/1 var(--font-mono);letter-spacing:.05em;text-transform:uppercase;background:var(--mint);color:var(--bg-deep)}.tab.is-active-track .tab-active-dot{display:inline-flex;align-items:center;gap:3px;box-shadow:0 0 0 2px rgba(111,227,180,.25)}.tab.on.is-active-track .tab-active-dot{background:var(--bg-deep);color:var(--mint)}\n .track-view{display:none;min-width:0}.track-view.on{display:block}.stepper{display:flex;width:100%;max-width:100%;overflow-x:auto;padding:4px 0 7px}.step{flex:1 1 0;min-width:104px;position:relative;padding-right:12px}.step-line{position:absolute;top:10px;left:21px;right:0;height:1px;background:var(--line-strong)}.step:last-child .step-line{display:none}.step.done .step-line{background:var(--mint)}\n .step-dot{position:relative;z-index:1;width:21px;height:21px;border-radius:50%;display:grid;place-items:center;border:2px solid var(--line-strong);background:var(--bg-deep);color:var(--muted);font:700 8px var(--font-mono)}.step.done .step-dot{border-color:var(--mint);color:var(--mint)}.step.active .step-dot{border-color:var(--gold);color:var(--gold);box-shadow:0 0 0 4px rgba(242,193,78,.16)}\n .step-name{margin-top:9px;color:var(--soft);font:600 10px/1.35 var(--font-mono)}.step.active .step-name{color:var(--gold)}.step.done .step-name{color:var(--mint)}.step-cmd{margin-top:3px;color:var(--muted);font:9px/1.4 var(--font-mono)}.track-note{margin-top:12px;padding-top:12px;border-top:1px dashed var(--line);color:var(--muted);font:11px/1.65 var(--font-mono)}\n .next-action{background:var(--bg-deep);border-color:var(--line-strong)}.next-head{display:flex;justify-content:space-between;gap:12px;align-items:center}.command{margin:8px 0 6px;color:var(--gold);font:700 clamp(22px,3vw,30px)/1.3 var(--font-mono)}.copy{padding:7px 12px;border:1px solid var(--cyan);border-radius:3px;background:transparent;color:var(--cyan);font:600 10px var(--font-mono);cursor:pointer}.copy:hover,.copy:focus-visible{background:var(--cyan);color:var(--bg-deep);outline:none}\n .stats{display:grid;grid-template-columns:repeat(5,1fr);gap:1px;margin:0 0 20px;border:1px solid var(--line);border-radius:4px;overflow:hidden;background:var(--line)}.stat{padding:16px 18px;background:var(--bg-deep)}.stat-value{font:700 25px/1 var(--font-display)}.stat-label{margin-top:6px;color:var(--muted);font:10px var(--font-mono);text-transform:uppercase;letter-spacing:.08em}\n .grid{display:grid;grid-template-columns:repeat(12,1fr);gap:20px;margin-bottom:20px}.card{grid-column:span 4;min-width:0;padding:clamp(20px,2.4vw,28px)}.card.wide{grid-column:span 8}.card.full{grid-column:1/-1}.value{font:700 18px/1.4 var(--font-display)}\n .facts{display:grid;gap:10px}.fact{display:flex;justify-content:space-between;gap:16px;padding-bottom:10px;border-bottom:1px dashed var(--line)}.fact:last-child{padding-bottom:0;border:0}.fact span:first-child{color:var(--muted);font-size:11px}.fact span:last-child{color:var(--soft);font:11px var(--font-mono);text-align:right;overflow-wrap:anywhere}\n .progress{height:6px;margin:14px 0 9px;border-radius:99px;background:rgba(255,255,255,.07);overflow:hidden}.progress span{display:block;height:100%;width:0;background:var(--gold);transition:width .35s ease}\n ul{list-style:none;margin:0;padding:0}li{padding:10px 0;border-bottom:1px dashed var(--line);color:var(--soft);font-size:12px;line-height:1.55}li:last-child{border:0}.empty{color:var(--muted)}\n .severity{display:grid;grid-template-columns:repeat(4,1fr);gap:8px}.sev{padding:9px 6px;border:1px solid var(--line);border-radius:3px;text-align:center}.sev b{display:block;font:700 17px var(--font-display)}.sev small{color:var(--muted);font:9px var(--font-mono)}\n .commands{display:flex;flex-wrap:wrap;gap:10px}.cmd{position:relative;padding:8px 13px;border:1px solid var(--line-strong);border-radius:3px;background:rgba(255,255,255,.025);color:var(--soft);font:11px var(--font-mono);cursor:pointer}.cmd:hover,.cmd:focus-visible,.cmd:focus{border-color:var(--cyan);color:var(--cyan);outline:2px solid rgba(125,216,255,.2);outline-offset:2px}.cmd:after{content:attr(data-tip);position:absolute;z-index:30;left:50%;bottom:calc(100% + 10px);width:max-content;max-width:min(300px,80vw);padding:9px 11px;border:1px solid var(--line-strong);border-radius:3px;background:#031421;color:var(--soft);font:10px/1.5 var(--font-mono);white-space:normal;text-align:left;opacity:0;visibility:hidden;transform:translate(-50%,5px);box-shadow:0 12px 30px rgba(0,0,0,.4);transition:.15s;pointer-events:none}.cmd:hover:after,.cmd:focus-visible:after,.cmd:focus:after{opacity:1;visibility:visible;transform:translate(-50%,0)}\n .adapters,.roster-grid,.mcp-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:12px}.adapter,.roster-card,.mcp-card{padding:15px;border:1px solid var(--line);border-radius:4px;background:rgba(255,255,255,.02)}.adapter strong,.roster-card strong,.mcp-card strong{display:block;margin-bottom:6px;text-transform:capitalize}.adapter-path,.roster-desc,.mcp-desc{color:var(--muted);font:10px var(--font-mono);line-height:1.4}.adapter-state{margin-top:9px;font:10px var(--font-mono)}\n .mcp-grid{grid-template-columns:repeat(3,1fr)}\n .search-row{display:flex;gap:10px;margin-bottom:16px}.search-input{flex:1;padding:10px 14px;background:var(--bg-deep);border:1px solid var(--line-strong);border-radius:4px;color:var(--ink);font-family:var(--font-mono);font-size:12px}.search-btn{padding:10px 18px;border:1px solid var(--cyan);border-radius:4px;background:var(--cyan);color:var(--bg-deep);font-weight:700;cursor:pointer}\n .blast-result{padding:16px;border:1px solid var(--line-strong);border-radius:4px;background:var(--bg-deep);margin-top:12px;display:none}\n .section-note{margin:-2px 0 14px;color:var(--muted);font:10px/1.5 var(--font-mono)}.record-list{display:grid;gap:8px}.record-item{display:grid;grid-template-columns:38px minmax(0,1fr) auto;gap:13px;align-items:center;padding:13px 15px;border:1px solid var(--line);border-left:3px solid var(--record-color,var(--cyan));border-radius:3px;background:rgba(255,255,255,.02)}.record-icon{display:grid;place-items:center;width:31px;height:31px;border-radius:8px;background:color-mix(in srgb,var(--record-color,var(--cyan)) 14%,transparent)}.record-body{min-width:0}.record-meta{color:var(--record-color,var(--cyan));font:700 10px var(--font-mono);letter-spacing:.06em;text-transform:uppercase}.record-title{margin-top:3px;color:var(--ink);font-weight:650}.record-desc{margin-top:3px;color:var(--soft);font-size:12px}.record-desc:empty{display:none}.record-title strong,.record-desc strong{color:var(--record-color,var(--cyan));font-weight:750}.record-title em,.record-desc em{color:var(--gold)}.record-title code,.record-desc code{padding:1px 4px;border:1px solid var(--line);border-radius:3px;color:var(--cyan);font:10px var(--font-mono)}.record-title a,.record-desc a{color:var(--cyan);text-decoration:underline}.record-actions{display:flex;align-items:center;justify-content:flex-end;gap:7px;flex-wrap:wrap}.record-action{border:1px solid var(--record-color,var(--cyan));border-radius:3px;padding:8px 11px;background:transparent;color:var(--record-color,var(--cyan));font:700 10px var(--font-mono);cursor:pointer}.record-action:hover,.record-action:focus-visible{background:var(--record-color,var(--cyan));color:var(--bg)}.record-badge{align-self:start;border:1px solid rgba(111,227,180,.36);border-radius:99px;padding:4px 8px;background:var(--mint-soft);color:var(--mint);font:700 9px var(--font-mono);letter-spacing:.04em;text-transform:uppercase}.record-item.tone-cyan{--record-color:var(--cyan)}.record-item.tone-mint{--record-color:var(--mint)}.record-item.tone-gold{--record-color:var(--gold)}.record-item.tone-red{--record-color:var(--red)}.record-item.tone-violet{--record-color:var(--violet)}.stepper{gap:0;justify-content:center}.step{padding-right:0;overflow:visible}.step-line{left:calc(50% + 10px);right:calc(-50% + 10px);width:auto}#sev-p0{color:var(--red)}#sev-p1{color:var(--gold)}#sev-p2{color:var(--violet)}#sev-p3{color:var(--cyan)}#stat-runs.tone{color:var(--mint)}#stat-findings.tone-ok{color:var(--mint)}#stat-findings.tone-alert{color:var(--red)}#stat-ideas.tone-ok{color:var(--mint)}#stat-ideas.tone-pending{color:var(--gold)}#stat-adapters.tone-ok{color:var(--mint)}#stat-adapters.tone-partial{color:var(--gold)}#stat-state.tone-idle{color:var(--cyan)}#stat-state.tone-active{color:var(--violet)}#stat-state.tone-blocked{color:var(--red)}\n .multitask-panel{border-color:rgba(56,189,248,.35)}.workspace-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(340px,1fr));gap:14px;margin-top:10px}.workspace-card{background:rgba(255,255,255,.025);border:1px solid var(--line);border-radius:6px;padding:16px;display:flex;flex-direction:column;gap:8px;transition:all .2s ease}.workspace-card:hover{border-color:var(--cyan);background:rgba(255,255,255,.04)}.ws-header{display:flex;align-items:center;justify-content:space-between;gap:8px}.ws-id{font-family:var(--font-mono);font-weight:700;font-size:11px;color:var(--cyan);background:var(--cyan-soft);padding:2px 8px;border-radius:3px}.ws-stage{font-family:var(--font-mono);font-size:10px;font-weight:700;text-transform:uppercase;padding:2px 6px;border-radius:3px;background:var(--gold-soft);color:var(--gold);border:1px solid rgba(242,193,78,.3)}.ws-stage.stage-check{background:var(--mint-soft);color:var(--mint);border-color:rgba(111,227,180,.3)}.ws-title{font-weight:650;font-size:13px;color:var(--ink);line-height:1.4}.ws-progress-bar{height:6px;background:rgba(0,0,0,.3);border-radius:99px;overflow:hidden;margin:4px 0}.ws-progress-fill{height:100%;background:linear-gradient(135deg,var(--cyan),var(--violet));transition:width .3s}.ws-meta{display:flex;align-items:center;justify-content:space-between;font-size:11px;color:var(--muted)}.ws-actions{display:flex;align-items:center;gap:6px;padding-top:8px;border-top:1px dashed var(--line);flex-wrap:wrap}.btn-ws{padding:4px 9px;border-radius:3px;font-family:var(--font-mono);font-size:10px;font-weight:700;background:rgba(255,255,255,.04);border:1px solid var(--line);color:var(--soft);cursor:pointer;transition:all .15s}.btn-ws:hover{background:var(--cyan-soft);border-color:var(--cyan);color:var(--cyan)}\n footer{display:flex;justify-content:space-between;gap:10px;flex-wrap:wrap;margin-top:26px;padding-top:17px;border-top:1px solid var(--line);color:var(--muted);font:10px var(--font-mono)}\n @media(max-width:920px){.grid .card,.grid .card.wide{grid-column:1/-1}.stats{grid-template-columns:repeat(2,1fr)}.adapters,.roster-grid,.mcp-grid{grid-template-columns:repeat(2,1fr)}.titleblock{align-items:flex-start;flex-direction:column}.meta dd{text-align:left}.stepper{gap:0}.cmd:after{position:fixed;left:12px;right:12px;bottom:16px;width:auto;max-width:none;transform:translateY(5px)}.cmd:hover:after,.cmd:focus-visible:after,.cmd:focus:after{transform:none}}\n @media(max-width:560px){.sheet{width:calc(100% - 24px);padding-top:22px}.panel,.card{padding:18px}.grid{gap:14px;margin-bottom:14px}.stats{margin-bottom:14px}.adapters,.roster-grid,.mcp-grid{grid-template-columns:1fr}.cmd:after{position:fixed;left:12px;right:12px;bottom:16px;width:auto;max-width:none;transform:translateY(5px)}.cmd:hover:after,.cmd:focus-visible:after,.cmd:focus:after{transform:none}.meta{grid-template-columns:1fr}.track-tabs{width:100%}.tab{flex:1}.fact{align-items:flex-start}.record-item{grid-template-columns:34px minmax(0,1fr)}.record-action{grid-column:2;justify-self:start}}\n @media(prefers-reduced-motion:reduce){*,*:before,*:after{animation-duration:.001ms!important;transition-duration:.001ms!important}}\n </style>\n</head>\n<body>\n <main class=\"sheet\">\n <header class=\"titleblock\">\n <div>\n <div class=\"eyebrow\">Nexus-DevFlow \u00B7 Enterprise Workspace Status</div>\n <h1 id=\"project-name\">Nexus-DevFlow</h1>\n <div class=\"path\" id=\"project-path\">Connecting...</div>\n <div class=\"badges\">\n <span class=\"badge\" id=\"version-badge\">v2.5.0</span>\n <span class=\"badge\" id=\"health-badge\">health</span>\n <span class=\"badge\" id=\"gate-badge\">Gate: checking</span>\n <span class=\"badge\" id=\"drift-badge\">Drift: checking</span>\n <span class=\"badge\" id=\"track-badge\">track</span>\n </div>\n </div>\n <dl class=\"meta\">\n <dt>Package</dt><dd id=\"package-name\">@jakkrichm/create-nexus-devflow</dd>\n <dt>Adapters</dt><dd id=\"adapter-count\">-</dd>\n <dt>Branch</dt><dd id=\"header-branch\">-</dd>\n <dt>Snapshot</dt><dd id=\"generated-at\">-</dd>\n </dl>\n </header>\n <div class=\"live\"><span class=\"live-dot\" id=\"live-dot\"></span><span id=\"live-label\">Connecting to local dashboard...</span></div>\n\n <section class=\"panel\" id=\"dual-track\">\n <div class=\"panel-head\">\n <span class=\"label\">Unified Living Spec Model (DevFlow 2.5.0)</span>\n <div class=\"track-tabs\" role=\"tablist\" aria-label=\"Delivery tracks\">\n <button class=\"tab on\" id=\"tab-preflight\" role=\"tab\" aria-selected=\"true\" aria-controls=\"view-preflight\" data-track=\"preflight\"><span>\uD83D\uDD2E Pre-Flight Discovery</span><span class=\"tab-active-dot\">\u25CF ACTIVE</span></button>\n <button class=\"tab\" id=\"tab-fast\" role=\"tab\" aria-selected=\"false\" aria-controls=\"view-fast\" data-track=\"fast\"><span>\u26A1 Living Spec \u00B7 4 steps</span><span class=\"tab-active-dot\">\u25CF ACTIVE</span></button>\n <button class=\"tab\" id=\"tab-swarm\" role=\"tab\" aria-selected=\"false\" aria-controls=\"view-swarm\" data-track=\"swarm\"><span>\uD83E\uDD16 Multi-Agent Swarm</span></button>\n <button class=\"tab\" id=\"tab-graph\" role=\"tab\" aria-selected=\"false\" aria-controls=\"view-graph\" data-track=\"graph\"><span>\uD83D\uDDFA\uFE0F Code Graph</span></button>\n </div>\n </div>\n <div class=\"track-view on\" id=\"view-preflight\" role=\"tabpanel\" aria-labelledby=\"tab-preflight\">\n <div class=\"stepper\" id=\"pipeline-preflight\"></div>\n <div class=\"track-note\" id=\"note-preflight\">Pre-Flight Discovery & Architectural Alignment (/idea, /grill, /brainstorm, /discovery).</div>\n </div>\n <div class=\"track-view\" id=\"view-fast\" role=\"tabpanel\" aria-labelledby=\"tab-fast\">\n <div class=\"stepper\" id=\"pipeline-fast\"></div>\n <div class=\"track-note\" id=\"note-fast\">Single Living Spec (/feature, /implement, /check, /complete) with TDD Discipline & QA Matrix.</div>\n </div>\n <div class=\"track-view\" id=\"view-swarm\" role=\"tabpanel\" aria-labelledby=\"tab-swarm\">\n <div class=\"section-note\">Role-based specialized AI Subagents roster & execution matrix</div>\n <div class=\"roster-grid\" id=\"swarm-roster\"></div>\n </div>\n <div class=\"track-view\" id=\"view-graph\" role=\"tabpanel\" aria-labelledby=\"tab-graph\">\n <div class=\"section-note\">Semantic dependency graph & instant Blast Radius analyzer</div>\n <div class=\"search-row\">\n <input class=\"search-input\" id=\"graph-file-input\" placeholder=\"Type file path (e.g. packages/create-nexus-devflow/lib/code-graph.ts)...\" />\n <button class=\"search-btn\" id=\"graph-search-btn\" type=\"button\">Analyze Impact</button>\n </div>\n <div class=\"blast-result\" id=\"blast-result\"></div>\n </div>\n </section>\n\n <section class=\"panel next-action\" id=\"next-panel\">\n <div class=\"next-head\"><span class=\"label\">Next Action</span><button class=\"copy\" id=\"next-copy\" type=\"button\">Copy command</button></div>\n <div class=\"command\" id=\"next-command\" aria-live=\"polite\">Loading...</div>\n <div class=\"muted\" id=\"next-reason\"></div>\n </section>\n\n <section class=\"stats\" aria-label=\"Workspace summary\">\n <div class=\"stat\"><div class=\"stat-value\" id=\"stat-runs\">-</div><div class=\"stat-label\">Runs released</div></div>\n <div class=\"stat\"><div class=\"stat-value\" id=\"stat-findings\">-</div><div class=\"stat-label\">Active findings</div></div>\n <div class=\"stat\"><div class=\"stat-value\" id=\"stat-ideas\">-</div><div class=\"stat-label\">Pending ideas</div></div>\n <div class=\"stat\"><div class=\"stat-value\" id=\"stat-mcp\">-</div><div class=\"stat-label\">MCP Tools Ready</div></div>\n <div class=\"stat\"><div class=\"stat-value\" id=\"stat-state\">-</div><div class=\"stat-label\">Current state</div></div>\n </section>\n\n <!-- Multi-Task Living Spec Workspaces Grid -->\n <section class=\"card full panel multitask-panel\" id=\"active-workspaces-panel\">\n <div class=\"panel-head\">\n <div>\n <span class=\"label\">Active Living Specs (Pure Task-Isolated Workspaces)</span>\n <div class=\"muted\" id=\"active-workspaces-summary\" style=\"margin-top:3px;font-size:11px;\">Scanned from devflow/context/{xxx-slug}/</div>\n </div>\n <span class=\"pill active\" id=\"active-workspaces-pill\">0 Active</span>\n </div>\n <div class=\"workspace-grid\" id=\"active-workspaces-list\"></div>\n </section>\n\n <section class=\"grid\">\n <article class=\"card\"><div class=\"card-head\"><span class=\"label\">Nexus-DevFlow</span><span class=\"pill\" id=\"update-pill\">checking</span></div><div class=\"facts\"><div class=\"fact\"><span>Installed / latest</span><span id=\"installed-latest\">-</span></div><div class=\"fact\"><span>Health</span><span id=\"system-health\">-</span></div><div class=\"fact\"><span>Architecture</span><span>3-Pillars + Swarm RAG</span></div></div></article>\n <article class=\"card wide\"><div class=\"card-head\"><span class=\"label\">Current Work</span><span class=\"pill\" id=\"work-pill\">loading</span></div><div class=\"value\" id=\"work-title\">Loading...</div><div class=\"progress\"><span id=\"work-progress\"></span></div><div class=\"muted\" id=\"work-meta\"></div></article>\n <article class=\"card\"><div class=\"card-head\"><span class=\"label\">Git & Drift</span><span class=\"pill\" id=\"git-pill\">loading</span></div><div class=\"facts\"><div class=\"fact\"><span>Branch</span><span id=\"git-branch\">-</span></div><div class=\"fact\"><span>Working tree</span><span id=\"git-changed\">-</span></div><div class=\"fact\"><span>Drift Status</span><span id=\"git-drift\">-</span></div><div class=\"fact\"><span>Last commit</span><span id=\"git-commit\">-</span></div></div></article>\n <article class=\"card\"><div class=\"card-head\"><span class=\"label\">Findings Ledger</span><span class=\"value\" id=\"findings-count\">-</span></div><div class=\"severity\"><div class=\"sev\"><b id=\"sev-p0\">0</b><small>P0</small></div><div class=\"sev\"><b id=\"sev-p1\">0</b><small>P1</small></div><div class=\"sev\"><b id=\"sev-p2\">0</b><small>P2</small></div><div class=\"sev\"><b id=\"sev-p3\">0</b><small>P3</small></div></div><ul id=\"findings-list\"></ul></article>\n <article class=\"card\"><div class=\"card-head\"><span class=\"label\">Completion & Gate</span><span class=\"pill\" id=\"completion-pill\">-</span></div><ul id=\"completion-list\"></ul></article>\n <article class=\"card\"><div class=\"card-head\"><span class=\"label\">Independent Review</span><span class=\"pill\" id=\"review-state\">none</span></div><div class=\"facts\"><div class=\"fact\"><span>Verdict</span><span id=\"review-verdict\">-</span></div><div class=\"fact\"><span>Freshness</span><span id=\"review-freshness\">-</span></div><div class=\"fact\"><span>Check</span><span id=\"review-check\">-</span></div></div><ul id=\"review-warnings\"></ul></article>\n <article class=\"card\"><div class=\"card-head\"><span class=\"label\">Warnings</span><span class=\"value\" id=\"warnings-count\">-</span></div><ul id=\"warnings-list\"></ul></article>\n </section>\n\n <section class=\"card full panel\"><div class=\"card-head\"><span class=\"label\">Model Context Protocol (MCP) Tools Hub</span><span class=\"value\" id=\"mcp-count\">12 Tools</span></div><div class=\"section-note\">Typed JSON-RPC tools exposed to AI Coding Assistants</div><div class=\"mcp-grid\" id=\"mcp-list\"></div></section>\n <section class=\"card full panel\"><div class=\"card-head\"><span class=\"label\">Quick Commands</span><span class=\"muted\">hover or focus for help \u00B7 click to copy</span></div><div class=\"commands\" id=\"command-list\"></div></section>\n <section class=\"grid\"><article class=\"card full\"><div class=\"card-head\"><span class=\"label\">Doctor \u00B7 Health Check</span><span class=\"pill\" id=\"doctor-pill\">-</span></div><div class=\"record-list\" id=\"doctor-list\"></div></article></section>\n <section class=\"card full panel\"><div class=\"card-head\"><span class=\"label\">Discoveries</span><span class=\"value\" id=\"discovery-count\">-</span></div><div class=\"record-list\" id=\"discovery-list\"></div></section>\n <section class=\"card full panel\"><div class=\"card-head\"><span class=\"label\">Idea Inbox & Backlog</span><span class=\"value\" id=\"ideas-count\">-</span></div><div class=\"section-note\">From devflow/ideas.md \u00B7 start a selected item with /feature IDEA-xxx</div><div class=\"record-list\" id=\"ideas-list\"></div></section>\n <section class=\"card full panel\"><div class=\"card-head\"><span class=\"label\">Completed Work Archive</span><span class=\"value\" id=\"history-count\">-</span></div><div class=\"section-note\">Categorized delivery history \u00B7 features, fixes and rollbacks</div><div class=\"record-list\" id=\"history-list\"></div></section>\n <footer><span>Nexus-DevFlow 2.5.0 Enterprise Dashboard \u00B7 refreshes every 2 seconds</span><span id=\"footer-revision\">snapshot pending</span></footer>\n </main>\n <script>\n const byId = (id) => document.getElementById(id);\n const escapeHtml = (str) => String(str == null ? '' : str).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;').replace(/'/g, '&#039;');\n const text = (id, value) => { const node = byId(id); if (node) node.textContent = value == null ? '-' : String(value); };\n const pill = (id, state, label) => { const node = byId(id); if (!node) return; node.className = 'pill ' + (state || 'configured'); node.textContent = label || state || '-'; };\n const list = (id, values, empty) => { const node = byId(id); if (!node) return; node.replaceChildren(); const rows = values.length ? values : [empty]; rows.forEach((value) => { const li = document.createElement('li'); li.textContent = value; if (!values.length) li.className = 'empty'; node.append(li); }); };\n const titleCase = (value) => String(value || '').replaceAll('_',' ').replace(/\bw/g, (c) => c.toUpperCase());\n const FLOW_ICON_NAMES = ['target','code','shield','package'];\n const EMOJI_ICONS = { compass:'\uD83D\uDD0E',discovery:'\uD83D\uDD0E',target:'\uD83C\uDFAF',document:'\uD83D\uDCC4',list:'\uD83E\uDDE9',code:'\u2699\uFE0F',shield:'\uD83E\uDDEA',report:'\uD83D\uDCCA',package:'\uD83D\uDCE6',bulb:'\uD83D\uDCA1',check:'\u2705',wrench:'\uD83D\uDEE0\uFE0F',rollback:'\u21A9\uFE0F',search:'\uD83D\uDD0D',alert:'\u26A0\uFE0F',grill:'\uD83D\uDD25',brainstorm:'\uD83D\uDCAD',idea:'\uD83D\uDCA1' };\n function iconImage(name) { const icon = document.createElement('span'); icon.className = 'icon-glyph'; icon.setAttribute('aria-hidden','true'); icon.textContent = EMOJI_ICONS[name] || '\uD83D\uDCC4'; return icon; }\n function decoratePipeline(id) { byId(id)?.querySelectorAll('.step').forEach((step,index) => { step.classList.add('flow-' + index); const icon = document.createElement('span'); icon.className = 'step-icon'; icon.setAttribute('aria-hidden','true'); const cmd = step.querySelector('.step-cmd')?.textContent?.replace('/','').split(' ')[0] || ''; const iconKey = id.includes('preflight') ? (cmd || ['idea','grill','brainstorm','discovery'][index] || 'search') : (FLOW_ICON_NAMES[index] || 'document'); icon.append(iconImage(iconKey)); const name = step.querySelector('.step-name'); step.insertBefore(icon,name || null); }); }\n function richText(root,value) { const source = String(value || ''); let cursor = 0; const plain = (end) => { if (end > cursor) root.append(document.createTextNode(source.slice(cursor,end))); cursor = end; }; while (cursor < source.length) { if (source.startsWith('**',cursor)) { const end = source.indexOf('**',cursor + 2); if (end > cursor + 2) { const node = document.createElement('strong'); node.textContent = source.slice(cursor + 2,end); root.append(node); cursor = end + 2; continue; } } if (source[cursor] === '*') { const end = source.indexOf('*',cursor + 1); if (end > cursor + 1) { const node = document.createElement('em'); node.textContent = source.slice(cursor + 1,end); root.append(node); cursor = end + 1; continue; } } if (source.charCodeAt(cursor) === 96) { const end = source.indexOf(String.fromCharCode(96),cursor + 1); if (end > cursor + 1) { const node = document.createElement('code'); node.textContent = source.slice(cursor + 1,end); root.append(node); cursor = end + 1; continue; } } const next = [source.indexOf('**',cursor + 1),source.indexOf('*',cursor + 1),source.indexOf(String.fromCharCode(96),cursor + 1)].filter((index) => index >= 0).sort((a,b) => a-b)[0] ?? source.length; plain(next > cursor ? next : cursor + 1); } }\n function recordCard(options) { const card = document.createElement('article'); card.className = 'record-item tone-' + (options.tone || 'cyan'); const icon = document.createElement('span'); icon.className = 'record-icon'; icon.append(iconImage(options.icon || 'document')); const body = document.createElement('div'); body.className = 'record-body'; const meta = document.createElement('div'); meta.className = 'record-meta'; richText(meta,options.meta); const title = document.createElement('div'); title.className = 'record-title'; richText(title,options.title); const desc = document.createElement('div'); desc.className = 'record-desc'; richText(desc,options.description); body.append(meta,title,desc); card.append(icon,body); if (options.badge) { const badge = document.createElement('span'); badge.className = 'record-badge'; badge.textContent = options.badge; card.append(badge); } return card; }\n function renderRecords(id,items,empty,mapper) { const root = byId(id); root.replaceChildren(); if (!items?.length) { const node = document.createElement('div'); node.className = 'empty'; node.textContent = empty; root.append(node); return; } items.forEach((item,index) => root.append(recordCard(mapper(item,index)))); }\n function renderIdeas(items) { renderRecords('ideas-list',items,'No pending ideas',(item) => ({ icon:'bulb',tone:'gold',meta:item.id,title:item.title,description:(item.description || '\u26A1') + ' \u00B7 ' + (item.feasibility || 'Not scored') })); }\n function renderHistory(items) { const map = { feature:{icon:'package',tone:'cyan'},fix:{icon:'wrench',tone:'gold'},rollback:{icon:'rollback',tone:'red'} }; renderRecords('history-list',(items || []).slice(0,10),'No completed work in history archive',(item) => { const type = String(item.type || 'other').toLowerCase(); const style = map[type] || {icon:'report',tone:'violet'}; return { ...style,meta:type + ' ' + (item.buildPlanItem || ''),title:item.title,description:'',badge:'Released' }; }); }\n function renderDoctor(items) { renderRecords('doctor-list',items,'No doctor checks available',(item) => ({ icon:item.status === 'pass' ? 'check' : 'alert',tone:item.status === 'pass' ? 'mint' : item.status === 'warn' ? 'gold' : 'red',meta:item.status,title:item.name,description:item.message })); }\n function renderDiscoveries(items) { renderRecords('discovery-list',items,'No discoveries recorded',(item) => ({ icon:'search',tone:'mint',meta:item.id,title:item.title,description:'',badge:'Decision: ' + (item.decision || 'Pending') })); }\n\n function renderPipeline(id, nodes) {\n const root = byId(id); root.replaceChildren();\n (nodes || []).forEach((node, index) => {\n const step = document.createElement('div'); step.className = 'step ' + node.state;\n const line = document.createElement('span'); line.className = 'step-line';\n const dot = document.createElement('span'); dot.className = 'step-dot'; dot.textContent = node.state === 'done' ? '\u2713' : String(index + 1).padStart(nodes.length > 4 ? 2 : 1, '0');\n const name = document.createElement('div'); name.className = 'step-name'; name.textContent = node.label;\n const command = document.createElement('div'); command.className = 'step-cmd'; command.textContent = node.command;\n step.append(line, dot, name, command); root.append(step);\n });\n }\n\n let userHasSwitchedTab = false;\n function selectTrack(track) {\n document.querySelectorAll('.tab').forEach((node) => { const on = node.dataset.track === track; node.classList.toggle('on', on); node.setAttribute('aria-selected', String(on)); });\n document.querySelectorAll('.track-view').forEach((node) => node.classList.toggle('on', node.id === 'view-' + track));\n }\n\n function wireCopy(button, getValue) {\n button.addEventListener('click', async () => {\n const original = button.textContent;\n button.textContent = 'Copied!';\n try { await navigator.clipboard.writeText(getValue()); }\n catch { button.textContent = 'Copy unavailable'; }\n setTimeout(() => { button.textContent = original; }, 1100);\n });\n }\n\n document.querySelectorAll('.tab').forEach((node) => node.addEventListener('click', () => { userHasSwitchedTab = true; selectTrack(node.dataset.track); }));\n wireCopy(byId('next-copy'), () => byId('next-command').textContent.trim());\n\n function renderCommands(commands) {\n const root = byId('command-list'); root.replaceChildren();\n const allCommands = [...(commands || [])];\n ['nexus-devflow check-gate', 'nexus-devflow drift', 'nexus-devflow reconcile --fix', 'nexus-devflow slice --stage implement', 'nexus-devflow swarm', 'nexus-devflow studio'].forEach(c => {\n if (!allCommands.some(item => item.command === c)) {\n allCommands.push({ name: c.replace('nexus-devflow ', ''), command: c, family: 'companion', description: 'Run ' + c });\n }\n });\n allCommands.forEach((item) => {\n const button = document.createElement('button'); button.type = 'button'; button.className = 'cmd'; button.textContent = item.name; button.dataset.tip = item.description; wireCopy(button, () => item.command); root.append(button);\n });\n }\n\n function renderSwarm(swarm) {\n const root = byId('swarm-roster'); if (!root) return; root.replaceChildren();\n (swarm?.agentRoster || []).forEach(agent => {\n const card = document.createElement('div'); card.className = 'roster-card';\n card.innerHTML = '<strong>' + agent.avatar + ' ' + agent.name + '</strong><div class=\"roster-desc\">' + agent.responsibility + '</div>';\n root.append(card);\n });\n }\n\n function renderMcp(tools) {\n const root = byId('mcp-list'); if (!root) return; root.replaceChildren();\n (tools || []).forEach(t => {\n const card = document.createElement('div'); card.className = 'mcp-card';\n card.innerHTML = '<strong>\u2699\uFE0F ' + t.name + '</strong><div class=\"mcp-desc\">' + t.description + '</div>';\n root.append(card);\n });\n }\n\n byId('graph-search-btn')?.addEventListener('click', async () => {\n const input = byId('graph-file-input'); const res = byId('blast-result');\n if (!input || !res) return;\n const file = input.value.trim();\n if (!file) return;\n res.style.display = 'block'; res.innerHTML = 'Analyzing Blast Radius...';\n try {\n const resp = await fetch('/api/graph?file=' + encodeURIComponent(file));\n const data = await resp.json();\n if (data.error) { res.innerHTML = '<span style=\"color:var(--red)\">' + data.error + '</span>'; return; }\n let html = '<strong>Impact Score: <span style=\"color:var(--gold)\">' + data.impactScore + '</span> | Total Affected: ' + data.totalAffected + ' files</strong><br/><br/>';\n if (data.directDependents?.length) {\n html += '<strong>Direct Dependents:</strong><ul>' + data.directDependents.map(d => '<li>' + d + '</li>').join('') + '</ul>';\n }\n if (data.transitiveDependents?.length) {\n html += '<br/><strong>Transitive Dependents:</strong><ul>' + data.transitiveDependents.map(t => '<li>' + t + '</li>').join('') + '</ul>';\n }\n res.innerHTML = html;\n } catch (e) {\n res.innerHTML = '<span style=\"color:var(--red)\">Error: ' + e.message + '</span>';\n }\n });\n\n function renderActiveWorkspaces(activeRuns, work) {\n const root = byId('active-workspaces-list');\n if (!root) return;\n root.replaceChildren();\n const runs = (activeRuns && activeRuns.length > 0) ? activeRuns : (work && work.state === 'active' ? [{\n runId: work.runId || 'ACTIVE',\n title: work.title || 'Active Spec',\n status: work.status || 'implementing',\n branch: 'current',\n totalTasks: work.total || 0,\n completedTasks: work.completed || 0,\n remainingTasks: work.remaining || 0,\n hasOpenFindings: false\n }] : []);\n\n pill('active-workspaces-pill', runs.length > 0 ? 'active' : 'idle', runs.length + ' Active');\n text('active-workspaces-summary', runs.length > 0 ? 'Found ' + runs.length + ' active workspace(s) in devflow/context/' : 'No active workspace folders. Run /feature or /fix to start.');\n\n if (runs.length === 0) {\n const empty = document.createElement('div');\n empty.className = 'empty';\n empty.style.padding = '18px';\n empty.textContent = 'No active delivery runs in progress. Use /feature or /fix to create a living spec.';\n root.append(empty);\n return;\n }\n\n runs.forEach((run) => {\n const card = document.createElement('article');\n card.className = 'workspace-card';\n const review = run.review || { state: 'none', freshness: 'not-applicable', verdict: null, checkResult: null };\n const pct = run.totalTasks > 0 ? Math.round((run.completedTasks / run.totalTasks) * 100) : 0;\n const stageClass = (run.status || '').includes('check') ? 'ws-stage stage-check' : 'ws-stage';\n const findingTag = run.hasOpenFindings ? '<span style=\"color:var(--red);font-size:10px;font-weight:700;\">\u26A0 Open Findings</span>' : '<span style=\"color:var(--mint);font-size:10px;font-weight:700;\">\u2714 0 Blockers</span>';\n\n card.innerHTML = '<div class=\"ws-header\">' +\n '<span class=\"ws-id\">' + escapeHtml(run.runId) + '</span>' +\n '<span class=\"' + stageClass + '\">Stage: ' + escapeHtml(run.status || 'active') + '</span>' +\n '</div>' +\n '<div class=\"ws-title\">' + escapeHtml(run.title || 'Living Spec') + '</div>' +\n '<div class=\"ws-progress-bar\"><div class=\"ws-progress-fill\" style=\"width:' + pct + '%;\"></div></div>' +\n '<div class=\"ws-meta\">' +\n '<span>\uD83C\uDF3F <code>' + escapeHtml(run.branch || 'main') + '</code></span>' +\n '<span><strong>' + pct + '%</strong> (' + run.completedTasks + '/' + run.totalTasks + ' Tasks)</span>' +\n '</div>' +\n '<div style=\"display:flex;justify-content:space-between;align-items:center;margin-top:2px;\">' +\n findingTag +\n '<span style=\"font-size:10px;color:var(--muted);\">' + run.remainingTasks + ' remaining</span>' +\n '</div>' +\n '<div style=\"font-size:10px;color:var(--muted);margin-top:6px;\">Review: <strong>' + escapeHtml(review.verdict || review.state) + '</strong> \u00B7 ' + escapeHtml(review.freshness) + '</div>' +\n '<div class=\"ws-actions\">' +\n '<button class=\"btn-ws\" type=\"button\" data-cmd=\"/implement ' + escapeHtml(run.runId) + '\">\u25B6 /implement</button>' +\n '<button class=\"btn-ws\" type=\"button\" data-cmd=\"/check ' + escapeHtml(run.runId) + '\">\uD83E\uDDEA /check</button>' +\n '<button class=\"btn-ws\" type=\"button\" data-cmd=\"/complete ' + escapeHtml(run.runId) + '\">\uD83D\uDCE6 /complete</button>' +\n '</div>';\n\n card.querySelectorAll('.btn-ws').forEach(btn => {\n wireCopy(btn, () => btn.getAttribute('data-cmd'));\n });\n root.append(card);\n });\n }\n\n function renderSnapshot(data) {\n const status = data.status || {}; const project = status.project || {}; const devflow = status.devflow || {}; const work = status.currentWork || {}; const git = status.git || {}; const findings = status.findings || { active: [], blockers: [] }; const review = status.review || { state: 'none', freshness: 'not-applicable', verdict: null, checkResult: null, warnings: [] }; const workflow = data.workflow || {}; const update = data.update || {}; const doctor = data.doctor || { checks: [] }; const discoveries = data.discoveries || { recent: [] }; const history = data.history || { items: [], total: 0 }; const ideas = status.ideas || { pending: [], totalPending: 0 }; const gate = data.gatekeeper || { passed: true }; const drift = data.drift || { hasDrift: false };\n\n text('project-name', project.name || 'Nexus-DevFlow'); text('project-path', project.root || ''); text('version-badge', 'v' + (devflow.version || '2.5.0'));\n pill('health-badge', status.health, status.health === 'ok' ? 'Health OK' : 'Health warning');\n pill('gate-badge', gate.passed ? 'ok' : 'blocked', gate.passed ? '\u2714 Gate Passed' : '\u2716 Gate Blocked');\n pill('drift-badge', !drift.hasDrift ? 'ok' : 'warning', !drift.hasDrift ? '\u2714 In Sync' : '\u26A0 Drift Detected');\n pill('track-badge', workflow.track, 'Track ' + titleCase(workflow.track || 'idle'));\n\n text('adapter-count', (devflow.adapters || []).length + ' configured'); text('header-branch', git.branch || 'unknown'); text('generated-at', new Date(data.generatedAt).toLocaleTimeString()); text('footer-revision', 'snapshot ' + data.generatedAt);\n renderPipeline('pipeline-preflight', workflow.deep || workflow.preflight); renderPipeline('pipeline-fast', workflow.fast); decoratePipeline('pipeline-preflight'); decoratePipeline('pipeline-fast');\n if (!userHasSwitchedTab) {\n if (work.state === 'active' || workflow.track === 'fast') {\n selectTrack('fast');\n } else {\n selectTrack('preflight');\n }\n }\n renderSwarm(data.swarm); renderMcp(data.mcpTools); text('stat-mcp', (data.mcpTools || []).length + ' Ready');\n renderActiveWorkspaces(status.activeRuns, work);\n\n const nextCommand = data.nextAction?.command || status.nextAction?.command || '/feature'; text('next-command', nextCommand); text('next-reason', data.nextAction?.reason || 'Ready for new work.');\n text('stat-runs', history.total || 0); text('stat-findings', (findings.active || []).length); text('stat-ideas', ideas.totalPending || 0); text('stat-state', titleCase(work.state || 'idle'));\n pill('update-pill', update.state, update.state === 'current' ? 'up to date' : update.state); text('installed-latest', (update.installedVersion || '2.5.0') + ' / ' + (update.latestVersion || '2.5.0')); text('system-health', status.health || 'ok');\n pill('work-pill', work.state, work.state || 'idle'); text('work-title', work.title || 'No active delivery run'); const pct = work.total > 0 ? Math.round((work.completed / work.total) * 100) : 0; byId('work-progress').style.width = pct + '%'; text('work-meta', work.state === 'active' ? work.completed + ' of ' + work.total + ' steps completed' : 'Ready');\n pill('git-pill', git.clean ? 'ok' : 'warning', git.clean ? 'clean' : (git.changedFiles || 0) + ' changed'); text('git-branch', git.branch || 'unknown'); text('git-changed', git.clean ? 'clean' : (git.changedFiles || 0) + ' changed files'); text('git-drift', drift.clean ? 'In Sync' : 'Drift detected'); text('git-commit', git.lastCommit || '-');\n text('findings-count', findings.total || 0); ['P0','P1','P2','P3'].forEach((severity) => text('sev-' + severity.toLowerCase(), (findings.active || []).filter((item) => item.severity === severity).length)); list('findings-list', (findings.active || []).map((item) => item.id + ' \u00B7 ' + item.title), 'No active findings');\n pill('completion-pill', status.completion?.state, status.completion?.state || 'unknown'); list('completion-list', status.completion?.blockers || [], work.state === 'idle' ? 'No active run to complete' : 'All readiness checks passed'); text('warnings-count', (status.warnings || []).length); list('warnings-list', (status.warnings || []).map((item) => item.message), 'No active warnings or drift');\n pill('review-state', review.state, review.state); text('review-verdict', review.verdict || '-'); text('review-freshness', review.freshness); text('review-check', review.checkResult || '-'); list('review-warnings', (review.warnings || []).map((item) => item.message), 'No review warnings');\n pill('doctor-pill', doctor.failCount ? 'fail' : doctor.warnCount ? 'warning' : 'ok', doctor.passCount + '/' + doctor.totalChecks + ' pass'); renderDoctor(doctor.checks || []);\n text('discovery-count', discoveries.total || 0); renderDiscoveries(discoveries.recent || []); renderCommands(data.commands);\n text('ideas-count', (ideas.totalPending || 0) + ' pending'); renderIdeas(ideas.pending || []); text('history-count', (history.total || 0) + ' released'); renderHistory(history.items || []);\n }\n\n window.__INITIAL_SNAPSHOT__ = null;\n if (window.__INITIAL_SNAPSHOT__) {\n try {\n renderSnapshot(window.__INITIAL_SNAPSHOT__);\n byId('live-dot').classList.add('on');\n text('live-label','Connected \u00B7 live snapshot every 2 seconds');\n } catch (e) {\n console.error('Initial hydration error:', e);\n }\n }\n\n let refreshing = false;\n async function refresh() { if (refreshing) return; refreshing = true; try { const response = await fetch('/api/dashboard'); if (!response.ok) throw new Error('HTTP ' + response.status); renderSnapshot(await response.json()); byId('live-dot').classList.add('on'); text('live-label','Connected \u00B7 live snapshot every 2 seconds'); } catch (error) { byId('live-dot').classList.remove('on'); text('live-label','Disconnected \u00B7 ' + error.message); } finally { refreshing = false; } }\n if (!window.__INITIAL_SNAPSHOT__) { refresh(); }\n setInterval(refresh, 2000);\n </script>\n</body>\n</html>";
2
2
  export { DASHBOARD_PAGE_HTML };
@@ -152,6 +152,7 @@ const DASHBOARD_PAGE_HTML = `<!doctype html>
152
152
  <article class="card"><div class="card-head"><span class="label">Git & Drift</span><span class="pill" id="git-pill">loading</span></div><div class="facts"><div class="fact"><span>Branch</span><span id="git-branch">-</span></div><div class="fact"><span>Working tree</span><span id="git-changed">-</span></div><div class="fact"><span>Drift Status</span><span id="git-drift">-</span></div><div class="fact"><span>Last commit</span><span id="git-commit">-</span></div></div></article>
153
153
  <article class="card"><div class="card-head"><span class="label">Findings Ledger</span><span class="value" id="findings-count">-</span></div><div class="severity"><div class="sev"><b id="sev-p0">0</b><small>P0</small></div><div class="sev"><b id="sev-p1">0</b><small>P1</small></div><div class="sev"><b id="sev-p2">0</b><small>P2</small></div><div class="sev"><b id="sev-p3">0</b><small>P3</small></div></div><ul id="findings-list"></ul></article>
154
154
  <article class="card"><div class="card-head"><span class="label">Completion & Gate</span><span class="pill" id="completion-pill">-</span></div><ul id="completion-list"></ul></article>
155
+ <article class="card"><div class="card-head"><span class="label">Independent Review</span><span class="pill" id="review-state">none</span></div><div class="facts"><div class="fact"><span>Verdict</span><span id="review-verdict">-</span></div><div class="fact"><span>Freshness</span><span id="review-freshness">-</span></div><div class="fact"><span>Check</span><span id="review-check">-</span></div></div><ul id="review-warnings"></ul></article>
155
156
  <article class="card"><div class="card-head"><span class="label">Warnings</span><span class="value" id="warnings-count">-</span></div><ul id="warnings-list"></ul></article>
156
157
  </section>
157
158
 
@@ -297,6 +298,7 @@ const DASHBOARD_PAGE_HTML = `<!doctype html>
297
298
  runs.forEach((run) => {
298
299
  const card = document.createElement('article');
299
300
  card.className = 'workspace-card';
301
+ const review = run.review || { state: 'none', freshness: 'not-applicable', verdict: null, checkResult: null };
300
302
  const pct = run.totalTasks > 0 ? Math.round((run.completedTasks / run.totalTasks) * 100) : 0;
301
303
  const stageClass = (run.status || '').includes('check') ? 'ws-stage stage-check' : 'ws-stage';
302
304
  const findingTag = run.hasOpenFindings ? '<span style="color:var(--red);font-size:10px;font-weight:700;">⚠ Open Findings</span>' : '<span style="color:var(--mint);font-size:10px;font-weight:700;">✔ 0 Blockers</span>';
@@ -315,6 +317,7 @@ const DASHBOARD_PAGE_HTML = `<!doctype html>
315
317
  findingTag +
316
318
  '<span style="font-size:10px;color:var(--muted);">' + run.remainingTasks + ' remaining</span>' +
317
319
  '</div>' +
320
+ '<div style="font-size:10px;color:var(--muted);margin-top:6px;">Review: <strong>' + escapeHtml(review.verdict || review.state) + '</strong> · ' + escapeHtml(review.freshness) + '</div>' +
318
321
  '<div class="ws-actions">' +
319
322
  '<button class="btn-ws" type="button" data-cmd="/implement ' + escapeHtml(run.runId) + '">▶ /implement</button>' +
320
323
  '<button class="btn-ws" type="button" data-cmd="/check ' + escapeHtml(run.runId) + '">🧪 /check</button>' +
@@ -329,7 +332,7 @@ const DASHBOARD_PAGE_HTML = `<!doctype html>
329
332
  }
330
333
 
331
334
  function renderSnapshot(data) {
332
- const status = data.status || {}; const project = status.project || {}; const devflow = status.devflow || {}; const work = status.currentWork || {}; const git = status.git || {}; const findings = status.findings || { active: [], blockers: [] }; const workflow = data.workflow || {}; const update = data.update || {}; const doctor = data.doctor || { checks: [] }; const discoveries = data.discoveries || { recent: [] }; const history = data.history || { items: [], total: 0 }; const ideas = status.ideas || { pending: [], totalPending: 0 }; const gate = data.gatekeeper || { passed: true }; const drift = data.drift || { hasDrift: false };
335
+ const status = data.status || {}; const project = status.project || {}; const devflow = status.devflow || {}; const work = status.currentWork || {}; const git = status.git || {}; const findings = status.findings || { active: [], blockers: [] }; const review = status.review || { state: 'none', freshness: 'not-applicable', verdict: null, checkResult: null, warnings: [] }; const workflow = data.workflow || {}; const update = data.update || {}; const doctor = data.doctor || { checks: [] }; const discoveries = data.discoveries || { recent: [] }; const history = data.history || { items: [], total: 0 }; const ideas = status.ideas || { pending: [], totalPending: 0 }; const gate = data.gatekeeper || { passed: true }; const drift = data.drift || { hasDrift: false };
333
336
 
334
337
  text('project-name', project.name || 'Nexus-DevFlow'); text('project-path', project.root || ''); text('version-badge', 'v' + (devflow.version || '2.5.0'));
335
338
  pill('health-badge', status.health, status.health === 'ok' ? 'Health OK' : 'Health warning');
@@ -356,6 +359,7 @@ const DASHBOARD_PAGE_HTML = `<!doctype html>
356
359
  pill('git-pill', git.clean ? 'ok' : 'warning', git.clean ? 'clean' : (git.changedFiles || 0) + ' changed'); text('git-branch', git.branch || 'unknown'); text('git-changed', git.clean ? 'clean' : (git.changedFiles || 0) + ' changed files'); text('git-drift', drift.clean ? 'In Sync' : 'Drift detected'); text('git-commit', git.lastCommit || '-');
357
360
  text('findings-count', findings.total || 0); ['P0','P1','P2','P3'].forEach((severity) => text('sev-' + severity.toLowerCase(), (findings.active || []).filter((item) => item.severity === severity).length)); list('findings-list', (findings.active || []).map((item) => item.id + ' · ' + item.title), 'No active findings');
358
361
  pill('completion-pill', status.completion?.state, status.completion?.state || 'unknown'); list('completion-list', status.completion?.blockers || [], work.state === 'idle' ? 'No active run to complete' : 'All readiness checks passed'); text('warnings-count', (status.warnings || []).length); list('warnings-list', (status.warnings || []).map((item) => item.message), 'No active warnings or drift');
362
+ pill('review-state', review.state, review.state); text('review-verdict', review.verdict || '-'); text('review-freshness', review.freshness); text('review-check', review.checkResult || '-'); list('review-warnings', (review.warnings || []).map((item) => item.message), 'No review warnings');
359
363
  pill('doctor-pill', doctor.failCount ? 'fail' : doctor.warnCount ? 'warning' : 'ok', doctor.passCount + '/' + doctor.totalChecks + ' pass'); renderDoctor(doctor.checks || []);
360
364
  text('discovery-count', discoveries.total || 0); renderDiscoveries(discoveries.recent || []); renderCommands(data.commands);
361
365
  text('ideas-count', (ideas.totalPending || 0) + ' pending'); renderIdeas(ideas.pending || []); text('history-count', (history.total || 0) + ' released'); renderHistory(history.items || []);
@@ -1 +1 @@
1
- {"version":3,"file":"dashboard-page.js","sourceRoot":"","sources":["../../lib/dashboard-page.ts"],"names":[],"mappings":"AAAA,MAAM,mBAAmB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QA4XpB,CAAC;AAET,OAAO,EAAE,mBAAmB,EAAE,CAAC"}
1
+ {"version":3,"file":"dashboard-page.js","sourceRoot":"","sources":["../../lib/dashboard-page.ts"],"names":[],"mappings":"AAAA,MAAM,mBAAmB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAgYpB,CAAC;AAET,OAAO,EAAE,mBAAmB,EAAE,CAAC"}
@@ -5,11 +5,13 @@ type CheckpointCommitPolicy = "disabled" | "enabled";
5
5
  type LogicTestPolicy = "required" | "when-configured";
6
6
  type UiEvidencePolicy = "required" | "when-available";
7
7
  type AuditGatePolicy = "always" | "manual" | "when-sensitive";
8
+ type IndependentReviewGatePolicy = "always" | "manual" | "when-sensitive";
8
9
  type CheckGatePolicy = "always" | "manual" | "when-behavioral";
9
10
  type TryGuideGatePolicy = "always" | "manual" | "when-user-facing";
10
11
  type ProjectConfigState = "defaults" | "invalid" | "project";
11
12
  interface QualityGatePolicy {
12
13
  audit: AuditGatePolicy;
14
+ independentReview: IndependentReviewGatePolicy;
13
15
  check: CheckGatePolicy;
14
16
  tryGuide: TryGuideGatePolicy;
15
17
  }
@@ -24,11 +24,13 @@ function createDefaultProjectConfig() {
24
24
  qualityGates: {
25
25
  regular: {
26
26
  audit: "manual",
27
+ independentReview: "manual",
27
28
  check: "manual",
28
29
  tryGuide: "manual"
29
30
  },
30
31
  continuous: {
31
32
  audit: "manual",
33
+ independentReview: "manual",
32
34
  check: "manual",
33
35
  tryGuide: "manual"
34
36
  }
@@ -118,8 +120,8 @@ function parseProjectConfig(value) {
118
120
  assertKnownKeys(git, ["featureBranchPrefix", "fixBranchPrefix", "rollbackBranchPrefix"], "git");
119
121
  assertKnownKeys(verification, ["logicTests", "uiEvidence"], "verification");
120
122
  assertKnownKeys(qualityGates, ["regular", "continuous"], "qualityGates");
121
- assertKnownKeys(regularGates, ["audit", "check", "tryGuide"], "qualityGates.regular");
122
- assertKnownKeys(continuousGates, ["audit", "check", "tryGuide"], "qualityGates.continuous");
123
+ assertKnownKeys(regularGates, ["audit", "independentReview", "check", "tryGuide"], "qualityGates.regular");
124
+ assertKnownKeys(continuousGates, ["audit", "independentReview", "check", "tryGuide"], "qualityGates.continuous");
123
125
  assertKnownKeys(continuous, ["maxFeatures", "maxRepairAttempts", "finalIntegrationAudit"], "continuous");
124
126
  return {
125
127
  schemaVersion: PROJECT_CONFIG_SCHEMA_VERSION,
@@ -150,6 +152,7 @@ function parseProjectConfig(value) {
150
152
  function parseQualityGatePolicy(value, defaults, label) {
151
153
  return {
152
154
  audit: optionalEnum(value.audit, ["always", "manual", "when-sensitive"], defaults.audit, `${label}.audit`),
155
+ independentReview: optionalEnum(value.independentReview, ["always", "manual", "when-sensitive"], defaults.independentReview, `${label}.independentReview`),
153
156
  check: optionalEnum(value.check, ["always", "manual", "when-behavioral"], defaults.check, `${label}.check`),
154
157
  tryGuide: optionalEnum(value.tryGuide, ["always", "manual", "when-user-facing"], defaults.tryGuide, `${label}.tryGuide`)
155
158
  };
@@ -1 +1 @@
1
- {"version":3,"file":"project-config.js","sourceRoot":"","sources":["../../lib/project-config.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"project-config.js","sourceRoot":"","sources":["../../lib/project-config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ type ReviewAdapter = "antigravity" | "claude" | "codex" | "copilot" | "opencode";
2
+ type ReviewCheckResult = "failed" | "not-required" | "passed" | "unavailable";
3
+ type ReviewState = "changes-requested" | "malformed" | "none" | "passed" | "pending";
4
+ type ReviewFreshness = "current" | "not-applicable" | "stale" | "unknown";
5
+ type ReviewWarningCode = "invalid_review_path" | "malformed_review" | "unsafe_review_path";
6
+ interface ReviewWarning {
7
+ code: ReviewWarningCode;
8
+ message: string;
9
+ }
10
+ interface IndependentReviewSummary {
11
+ state: ReviewState;
12
+ freshness: ReviewFreshness;
13
+ targetCommit: string | null;
14
+ baseCommit: string | null;
15
+ baseRef: string | null;
16
+ specHash: string | null;
17
+ preparedBy: ReviewAdapter | null;
18
+ builderModel: string | null;
19
+ requestedReviewer: ReviewAdapter | null;
20
+ requestedModel: string | null;
21
+ requestedAt: string | null;
22
+ workflow: "continuous" | "regular" | null;
23
+ checkRequired: boolean | null;
24
+ reviewerAdapter: ReviewAdapter | null;
25
+ reviewerModel: string | null;
26
+ reviewerContext: string | null;
27
+ reviewedAt: string | null;
28
+ scope: string | null;
29
+ lenses: string[];
30
+ verdict: "changes-requested" | "passed" | null;
31
+ checkResult: ReviewCheckResult | null;
32
+ warnings: ReviewWarning[];
33
+ }
34
+ declare const DEFAULT_REVIEW_PATH: string;
35
+ declare function readIndependentReview(projectRoot: string, taskSlug?: string): Promise<IndependentReviewSummary>;
36
+ declare function parseIndependentReview(markdown: string): IndependentReviewSummary;
37
+ export { DEFAULT_REVIEW_PATH, parseIndependentReview, readIndependentReview };
38
+ export type { IndependentReviewSummary, ReviewAdapter, ReviewCheckResult, ReviewFreshness, ReviewState, ReviewWarning, ReviewWarningCode };