@jakkrichm/create-nexus-devflow 2.0.25 → 2.0.27
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/bin/create-nexus-devflow.d.ts +18 -1
- package/dist/bin/create-nexus-devflow.js +439 -11
- package/dist/bin/create-nexus-devflow.js.map +1 -1
- package/dist/lib/command-catalog.d.ts +11 -0
- package/dist/lib/command-catalog.js +63 -0
- package/dist/lib/command-catalog.js.map +1 -0
- package/dist/lib/current-work.js +94 -48
- package/dist/lib/current-work.js.map +1 -1
- package/dist/lib/dashboard-page.d.ts +2 -0
- package/dist/lib/dashboard-page.js +201 -0
- package/dist/lib/dashboard-page.js.map +1 -0
- package/dist/lib/dashboard-snapshot.d.ts +49 -0
- package/dist/lib/dashboard-snapshot.js +96 -0
- package/dist/lib/dashboard-snapshot.js.map +1 -0
- package/dist/lib/dashboard.d.ts +2 -0
- package/dist/lib/dashboard.js +360 -8
- package/dist/lib/dashboard.js.map +1 -1
- package/dist/lib/discoveries.d.ts +19 -0
- package/dist/lib/discoveries.js +81 -0
- package/dist/lib/discoveries.js.map +1 -0
- package/dist/lib/doctor.d.ts +26 -0
- package/dist/lib/doctor.js +474 -0
- package/dist/lib/doctor.js.map +1 -0
- package/dist/lib/findings.d.ts +26 -2
- package/dist/lib/findings.js +165 -1
- package/dist/lib/findings.js.map +1 -1
- package/dist/lib/gatekeeper.d.ts +19 -0
- package/dist/lib/gatekeeper.js +77 -0
- package/dist/lib/gatekeeper.js.map +1 -0
- package/dist/lib/git-hooks.d.ts +16 -0
- package/dist/lib/git-hooks.js +78 -0
- package/dist/lib/git-hooks.js.map +1 -0
- package/dist/lib/history.d.ts +6 -1
- package/dist/lib/history.js +98 -11
- package/dist/lib/history.js.map +1 -1
- package/dist/lib/ideas.d.ts +26 -0
- package/dist/lib/ideas.js +179 -0
- package/dist/lib/ideas.js.map +1 -0
- package/dist/lib/status.d.ts +2 -0
- package/dist/lib/status.js +60 -6
- package/dist/lib/status.js.map +1 -1
- package/dist/lib/update.js +2 -2
- package/dist/lib/update.js.map +1 -1
- package/dist/lib/version-check.d.ts +22 -0
- package/dist/lib/version-check.js +59 -0
- package/dist/lib/version-check.js.map +1 -0
- package/dist/lib/workflow-state.d.ts +23 -0
- package/dist/lib/workflow-state.js +112 -0
- package/dist/lib/workflow-state.js.map +1 -0
- package/dist/scripts/prepare-template.js +3 -3
- package/package.json +1 -1
- package/template/{.claude/skills/00-discover → .agents/skills/00-explore}/SKILL.md +10 -10
- package/template/.agents/skills/10-define/SKILL.md +4 -4
- package/template/.agents/skills/20-spec/SKILL.md +2 -3
- package/template/.agents/skills/30-plan/SKILL.md +2 -3
- package/template/.agents/skills/40-execute/SKILL.md +2 -2
- package/template/.agents/skills/50-verify/SKILL.md +2 -2
- package/template/.agents/skills/60-report/SKILL.md +3 -3
- package/template/{.claude/skills/70-release → .agents/skills/70-deliver}/SKILL.md +7 -13
- package/template/.agents/skills/adopt/SKILL.md +136 -73
- package/template/.agents/skills/audit/SKILL.md +275 -0
- package/template/.agents/skills/autopilot/SKILL.md +228 -147
- package/template/.agents/skills/brainstorm/SKILL.md +3 -3
- package/template/.agents/skills/brief/SKILL.md +74 -51
- package/template/.agents/skills/check/SKILL.md +96 -76
- package/template/.agents/skills/ci/SKILL.md +140 -61
- package/template/.agents/skills/complete/SKILL.md +156 -101
- package/template/.agents/skills/convert-any-to-md/SKILL.md +2 -2
- package/template/.agents/skills/debug/SKILL.md +124 -49
- package/template/.agents/skills/devflow/SKILL.md +16 -10
- package/template/.agents/skills/discovery/SKILL.md +166 -0
- package/template/.agents/skills/doctor/SKILL.md +188 -72
- package/template/.agents/skills/feature/SKILL.md +195 -102
- package/template/.agents/skills/fix/SKILL.md +41 -90
- package/template/.agents/skills/idea/SKILL.md +3 -3
- package/template/.agents/skills/implement/SKILL.md +189 -46
- package/template/.agents/skills/onboard/SKILL.md +215 -85
- package/template/.agents/skills/overview/SKILL.md +51 -85
- package/template/.agents/skills/prototype/SKILL.md +82 -27
- package/template/.agents/skills/release/SKILL.md +160 -0
- package/template/.agents/skills/report-html/SKILL.md +2 -2
- package/template/.agents/skills/rollback/SKILL.md +123 -77
- package/template/.agents/skills/status/SKILL.md +109 -0
- package/template/.agents/skills/test/SKILL.md +2 -2
- package/template/.agents/skills/tests/SKILL.md +126 -0
- package/template/.agents/skills/try/SKILL.md +77 -65
- package/template/{.agents/skills/00-discover → .claude/skills/00-explore}/SKILL.md +9 -9
- package/template/.claude/skills/10-define/SKILL.md +2 -2
- package/template/.claude/skills/20-spec/SKILL.md +1 -1
- package/template/.claude/skills/30-plan/SKILL.md +1 -1
- package/template/.claude/skills/60-report/SKILL.md +1 -1
- package/template/{.agents/skills/70-release → .claude/skills/70-deliver}/SKILL.md +6 -12
- package/template/.claude/skills/adopt/SKILL.md +2 -2
- package/template/.claude/skills/audit/SKILL.md +141 -0
- package/template/.claude/skills/autopilot/SKILL.md +74 -52
- package/template/.claude/skills/brief/SKILL.md +67 -45
- package/template/.claude/skills/ci/SKILL.md +1 -1
- package/template/.claude/skills/complete/SKILL.md +1 -1
- package/template/.claude/skills/debug/SKILL.md +1 -1
- package/template/.claude/skills/devflow/SKILL.md +7 -7
- package/template/.claude/skills/discovery/SKILL.md +145 -0
- package/template/.claude/skills/doctor/SKILL.md +1 -1
- package/template/.claude/skills/feature/SKILL.md +67 -18
- package/template/.claude/skills/fix/SKILL.md +1 -1
- package/template/.claude/skills/idea/SKILL.md +2 -2
- package/template/.claude/skills/onboard/SKILL.md +3 -3
- package/template/.claude/skills/overview/SKILL.md +39 -88
- package/template/.claude/skills/prototype/SKILL.md +1 -1
- package/template/.claude/skills/release/SKILL.md +171 -0
- package/template/.claude/skills/rollback/SKILL.md +2 -2
- package/template/AGENTS.md +5 -5
- package/template/devflow/build-plan.md +40 -0
- package/template/devflow/context/ai-interaction.md +4 -4
- package/template/devflow/context/coding-standards.md +3 -3
- package/template/devflow/context/current-stage.md +1 -1
- package/template/devflow/context/findings.md +1 -1
- package/template/devflow/history/HISTORY.md +2 -2
- package/template/devflow/project-plan.md +27 -0
- package/template/devflow/reference/mockup.html +476 -0
- package/template/devflow/reference/project-overview-template.md +39 -0
- package/template/devflow/reference/running-id-contract.md +24 -2
package/dist/lib/dashboard.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { spawn } from "node:child_process";
|
|
2
2
|
import http from "node:http";
|
|
3
|
+
import { DASHBOARD_PAGE_HTML } from "./dashboard-page.js";
|
|
4
|
+
import { readDashboardSnapshot } from "./dashboard-snapshot.js";
|
|
3
5
|
import { readHistory } from "./history.js";
|
|
4
6
|
import { readProjectStatus } from "./status.js";
|
|
5
7
|
const DASHBOARD_HOST = "127.0.0.1";
|
|
@@ -7,7 +9,7 @@ async function startDashboardServer(startPath = process.cwd(), options = {}) {
|
|
|
7
9
|
const initialStatus = await readProjectStatus(startPath);
|
|
8
10
|
const projectRoot = initialStatus.project.root;
|
|
9
11
|
const server = http.createServer((request, response) => {
|
|
10
|
-
void handleRequest(projectRoot, request, response);
|
|
12
|
+
void handleRequest(projectRoot, request, response, options.snapshotOptions);
|
|
11
13
|
});
|
|
12
14
|
await new Promise((resolve, reject) => {
|
|
13
15
|
const onError = (error) => {
|
|
@@ -32,7 +34,7 @@ async function startDashboardServer(startPath = process.cwd(), options = {}) {
|
|
|
32
34
|
close: () => closeServer(server)
|
|
33
35
|
};
|
|
34
36
|
}
|
|
35
|
-
async function handleRequest(projectRoot, request, response) {
|
|
37
|
+
async function handleRequest(projectRoot, request, response, snapshotOptions) {
|
|
36
38
|
const method = request.method || "GET";
|
|
37
39
|
if (method !== "GET" && method !== "HEAD") {
|
|
38
40
|
response.setHeader("Allow", "GET, HEAD");
|
|
@@ -41,8 +43,8 @@ async function handleRequest(projectRoot, request, response) {
|
|
|
41
43
|
}
|
|
42
44
|
const pathname = new URL(request.url || "/", `http://${DASHBOARD_HOST}`).pathname;
|
|
43
45
|
if (pathname === "/") {
|
|
44
|
-
response.setHeader("Content-Security-Policy", "default-src 'none'; script-src 'unsafe-inline'; style-src 'unsafe-inline'; connect-src
|
|
45
|
-
sendResponse(response, method, 200, "text/html; charset=utf-8",
|
|
46
|
+
response.setHeader("Content-Security-Policy", "default-src 'none'; script-src 'unsafe-inline'; style-src 'unsafe-inline' https://fonts.googleapis.com; font-src https://fonts.gstatic.com; connect-src 'self'; img-src 'self' data:; base-uri 'none'; form-action 'none'; frame-ancestors 'none'");
|
|
47
|
+
sendResponse(response, method, 200, "text/html; charset=utf-8", DASHBOARD_PAGE_HTML);
|
|
46
48
|
return;
|
|
47
49
|
}
|
|
48
50
|
if (pathname === "/api/status") {
|
|
@@ -57,6 +59,18 @@ async function handleRequest(projectRoot, request, response) {
|
|
|
57
59
|
}
|
|
58
60
|
return;
|
|
59
61
|
}
|
|
62
|
+
if (pathname === "/api/dashboard") {
|
|
63
|
+
try {
|
|
64
|
+
const snapshot = await readDashboardSnapshot(projectRoot, snapshotOptions);
|
|
65
|
+
sendResponse(response, method, 200, "application/json; charset=utf-8", `${JSON.stringify(snapshot)}\n`);
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
sendResponse(response, method, 500, "application/json; charset=utf-8", `${JSON.stringify({
|
|
69
|
+
error: error instanceof Error ? error.message : "Unable to read dashboard snapshot."
|
|
70
|
+
})}\n`);
|
|
71
|
+
}
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
60
74
|
if (pathname === "/api/history") {
|
|
61
75
|
try {
|
|
62
76
|
const history = await readHistory(projectRoot);
|
|
@@ -432,11 +446,55 @@ const DASHBOARD_HTML = `<!doctype html>
|
|
|
432
446
|
|
|
433
447
|
.next-action { padding: 24px; }
|
|
434
448
|
|
|
449
|
+
.next-action-header {
|
|
450
|
+
display: flex;
|
|
451
|
+
align-items: center;
|
|
452
|
+
justify-content: space-between;
|
|
453
|
+
gap: 12px;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
.next-copy-btn {
|
|
457
|
+
display: inline-flex;
|
|
458
|
+
align-items: center;
|
|
459
|
+
gap: 6px;
|
|
460
|
+
padding: 5px 12px;
|
|
461
|
+
border-radius: 6px;
|
|
462
|
+
background: rgba(118, 168, 255, 0.12);
|
|
463
|
+
color: var(--code-blue);
|
|
464
|
+
border: 1px solid rgba(118, 168, 255, 0.3);
|
|
465
|
+
font: 600 11px/1.3 var(--font-mono);
|
|
466
|
+
cursor: pointer;
|
|
467
|
+
transition: background-color 0.2s ease, border-color 0.2s ease, transform 0.15s ease, color 0.2s ease;
|
|
468
|
+
user-select: none;
|
|
469
|
+
}
|
|
470
|
+
.next-copy-btn:hover {
|
|
471
|
+
background: var(--blue);
|
|
472
|
+
color: #ffffff;
|
|
473
|
+
border-color: var(--blue);
|
|
474
|
+
transform: translateY(-1px);
|
|
475
|
+
}
|
|
476
|
+
.next-copy-btn:active {
|
|
477
|
+
transform: translateY(0);
|
|
478
|
+
}
|
|
479
|
+
.next-copy-btn.copied {
|
|
480
|
+
background: var(--green);
|
|
481
|
+
color: #ffffff;
|
|
482
|
+
border-color: var(--green);
|
|
483
|
+
}
|
|
484
|
+
|
|
435
485
|
.command {
|
|
436
486
|
margin: 13px 0 8px;
|
|
437
487
|
color: var(--code-blue);
|
|
438
488
|
font: 600 clamp(20px, 3vw, 29px)/1.3 var(--font-mono);
|
|
439
489
|
overflow-wrap: anywhere;
|
|
490
|
+
cursor: pointer;
|
|
491
|
+
border-radius: 6px;
|
|
492
|
+
padding: 4px 6px;
|
|
493
|
+
margin-left: -6px;
|
|
494
|
+
transition: background-color 0.2s ease;
|
|
495
|
+
}
|
|
496
|
+
.command:hover {
|
|
497
|
+
background: rgba(118, 168, 255, 0.08);
|
|
440
498
|
}
|
|
441
499
|
|
|
442
500
|
.command-flip { animation: commandFlip 300ms ease-out; }
|
|
@@ -465,7 +523,135 @@ const DASHBOARD_HTML = `<!doctype html>
|
|
|
465
523
|
li:last-child { border-bottom: 0; }
|
|
466
524
|
li.empty { color: var(--ink-muted); }
|
|
467
525
|
li.empty:hover { background-color: transparent; transform: none; }
|
|
468
|
-
|
|
526
|
+
/* Markdown Inline Formatting */
|
|
527
|
+
.inline-code, code.inline-code {
|
|
528
|
+
display: inline-block;
|
|
529
|
+
padding: 1.5px 6px;
|
|
530
|
+
margin: 0 2px;
|
|
531
|
+
border-radius: 5px;
|
|
532
|
+
background: var(--surface-muted);
|
|
533
|
+
color: var(--blue-dark);
|
|
534
|
+
font-family: var(--font-mono);
|
|
535
|
+
font-size: 0.88em;
|
|
536
|
+
font-weight: 600;
|
|
537
|
+
border: 1px solid var(--line);
|
|
538
|
+
line-height: 1.35;
|
|
539
|
+
vertical-align: baseline;
|
|
540
|
+
word-break: break-word;
|
|
541
|
+
}
|
|
542
|
+
strong {
|
|
543
|
+
color: var(--ink);
|
|
544
|
+
font-weight: 700;
|
|
545
|
+
}
|
|
546
|
+
em {
|
|
547
|
+
font-style: italic;
|
|
548
|
+
color: var(--ink-soft);
|
|
549
|
+
}
|
|
550
|
+
del {
|
|
551
|
+
text-decoration: line-through;
|
|
552
|
+
color: var(--ink-muted);
|
|
553
|
+
}
|
|
554
|
+
.inline-link {
|
|
555
|
+
color: var(--blue);
|
|
556
|
+
text-decoration: none;
|
|
557
|
+
font-weight: 600;
|
|
558
|
+
}
|
|
559
|
+
.inline-link:hover {
|
|
560
|
+
text-decoration: underline;
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
/* Idea Inbox Item Styling */
|
|
564
|
+
.idea-item {
|
|
565
|
+
display: flex;
|
|
566
|
+
flex-direction: column;
|
|
567
|
+
gap: 8px;
|
|
568
|
+
padding: 14px 16px;
|
|
569
|
+
border: 1px solid var(--line);
|
|
570
|
+
border-radius: 10px;
|
|
571
|
+
background: var(--surface-solid);
|
|
572
|
+
margin-bottom: 12px;
|
|
573
|
+
transition: border-color 0.2s ease, box-shadow 0.2s ease, transform 0.2s ease;
|
|
574
|
+
}
|
|
575
|
+
.idea-item:hover {
|
|
576
|
+
border-color: var(--blue);
|
|
577
|
+
box-shadow: 0 4px 16px rgba(21, 94, 239, 0.09);
|
|
578
|
+
transform: translateY(-1px);
|
|
579
|
+
}
|
|
580
|
+
.idea-header {
|
|
581
|
+
display: flex;
|
|
582
|
+
align-items: center;
|
|
583
|
+
justify-content: space-between;
|
|
584
|
+
gap: 12px;
|
|
585
|
+
}
|
|
586
|
+
.idea-id-badge {
|
|
587
|
+
display: inline-flex;
|
|
588
|
+
align-items: center;
|
|
589
|
+
padding: 4px 9px;
|
|
590
|
+
border-radius: 6px;
|
|
591
|
+
background: rgba(21, 94, 239, 0.08);
|
|
592
|
+
color: var(--blue-dark);
|
|
593
|
+
font: 700 11px/1 var(--font-mono);
|
|
594
|
+
letter-spacing: .04em;
|
|
595
|
+
}
|
|
596
|
+
.idea-title-text {
|
|
597
|
+
color: var(--ink);
|
|
598
|
+
font-size: 14px;
|
|
599
|
+
font-weight: 700;
|
|
600
|
+
letter-spacing: -.01em;
|
|
601
|
+
line-height: 1.45;
|
|
602
|
+
}
|
|
603
|
+
.idea-title-text .inline-code {
|
|
604
|
+
font-size: 0.85em;
|
|
605
|
+
background: rgba(21, 94, 239, 0.06);
|
|
606
|
+
border-color: rgba(21, 94, 239, 0.2);
|
|
607
|
+
}
|
|
608
|
+
.idea-desc-text {
|
|
609
|
+
color: var(--ink-soft);
|
|
610
|
+
font-size: 13px;
|
|
611
|
+
line-height: 1.55;
|
|
612
|
+
}
|
|
613
|
+
.idea-meta-row {
|
|
614
|
+
display: flex;
|
|
615
|
+
align-items: center;
|
|
616
|
+
justify-content: space-between;
|
|
617
|
+
flex-wrap: wrap;
|
|
618
|
+
gap: 10px;
|
|
619
|
+
margin-top: 2px;
|
|
620
|
+
padding-top: 8px;
|
|
621
|
+
border-top: 1px dashed var(--line);
|
|
622
|
+
}
|
|
623
|
+
.idea-feasibility-tag {
|
|
624
|
+
color: var(--ink-soft);
|
|
625
|
+
font-size: 12px;
|
|
626
|
+
background: var(--surface-muted);
|
|
627
|
+
padding: 4px 9px;
|
|
628
|
+
border-radius: 6px;
|
|
629
|
+
line-height: 1.4;
|
|
630
|
+
}
|
|
631
|
+
.idea-feasibility-tag strong {
|
|
632
|
+
color: var(--ink);
|
|
633
|
+
}
|
|
634
|
+
.idea-feasibility-tag .inline-code {
|
|
635
|
+
font-size: 0.85em;
|
|
636
|
+
background: rgba(0, 0, 0, 0.04);
|
|
637
|
+
}
|
|
638
|
+
.idea-cmd-code {
|
|
639
|
+
display: inline-block;
|
|
640
|
+
padding: 4px 10px;
|
|
641
|
+
border-radius: 6px;
|
|
642
|
+
background: var(--surface-muted);
|
|
643
|
+
color: var(--blue-dark);
|
|
644
|
+
font: 600 11px/1.3 var(--font-mono);
|
|
645
|
+
cursor: pointer;
|
|
646
|
+
border: 1px solid var(--line);
|
|
647
|
+
transition: background-color 0.15s ease, color 0.15s ease, border-color 0.15s ease;
|
|
648
|
+
user-select: none;
|
|
649
|
+
}
|
|
650
|
+
.idea-cmd-code:hover {
|
|
651
|
+
background: var(--blue);
|
|
652
|
+
color: #ffffff;
|
|
653
|
+
border-color: var(--blue);
|
|
654
|
+
}
|
|
469
655
|
|
|
470
656
|
footer { margin-top: 24px; color: var(--ink-muted); font: 11px/1.6 var(--font-mono); }
|
|
471
657
|
|
|
@@ -551,6 +737,12 @@ const DASHBOARD_HTML = `<!doctype html>
|
|
|
551
737
|
<ul id="warnings-list" aria-live="polite"><li class="empty">Loading warnings...</li></ul>
|
|
552
738
|
</article>
|
|
553
739
|
|
|
740
|
+
<article class="card full card-enter" style="animation-delay: 0.26s;">
|
|
741
|
+
<div class="card-head"><span class="label">Idea Inbox & Backlog</span><span class="value" id="ideas-count">-</span></div>
|
|
742
|
+
<div class="muted">Pending ideas from devflow/ideas.md. Start any idea with /feature IDEA-xxx or /00-explore IDEA-xxx.</div>
|
|
743
|
+
<ul id="ideas-list" tabindex="0" aria-label="Idea Inbox"><li class="empty">Loading ideas...</li></ul>
|
|
744
|
+
</article>
|
|
745
|
+
|
|
554
746
|
<article class="card full card-enter" style="animation-delay: 0.28s;">
|
|
555
747
|
<div class="card-head"><span class="label">Completed Work Archive</span><span class="value" id="history-count">-</span></div>
|
|
556
748
|
<div class="muted">Categorized history of features, fixes, and rollbacks.</div>
|
|
@@ -558,8 +750,17 @@ const DASHBOARD_HTML = `<!doctype html>
|
|
|
558
750
|
</article>
|
|
559
751
|
|
|
560
752
|
<article class="card full code-panel next-action card-enter" style="animation-delay: 0.32s;" id="next-panel">
|
|
561
|
-
<
|
|
562
|
-
|
|
753
|
+
<div class="next-action-header">
|
|
754
|
+
<span class="label">Next Action</span>
|
|
755
|
+
<button class="next-copy-btn" id="next-copy-btn" type="button" aria-label="Copy next command" title="Click to copy next action command">
|
|
756
|
+
<svg viewBox="0 0 24 24" width="13" height="13" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
757
|
+
<rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect>
|
|
758
|
+
<path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path>
|
|
759
|
+
</svg>
|
|
760
|
+
<span id="next-copy-text">Copy Command</span>
|
|
761
|
+
</button>
|
|
762
|
+
</div>
|
|
763
|
+
<div class="command" id="next-command" aria-live="polite" title="Click to copy command">Loading...</div>
|
|
563
764
|
<div class="muted" id="next-reason"></div>
|
|
564
765
|
</article>
|
|
565
766
|
</section>
|
|
@@ -619,6 +820,40 @@ const DASHBOARD_HTML = `<!doctype html>
|
|
|
619
820
|
setTimeout(() => node.classList.remove(className), 600);
|
|
620
821
|
}
|
|
621
822
|
|
|
823
|
+
function escapeHtml(str) {
|
|
824
|
+
if (typeof str !== 'string') return '';
|
|
825
|
+
return str
|
|
826
|
+
.replace(/&/g, '&')
|
|
827
|
+
.replace(/</g, '<')
|
|
828
|
+
.replace(/>/g, '>')
|
|
829
|
+
.replace(/"/g, '"')
|
|
830
|
+
.replace(/'/g, ''');
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
function renderMarkdownInline(text) {
|
|
834
|
+
if (!text) return '';
|
|
835
|
+
var str = escapeHtml(text);
|
|
836
|
+
|
|
837
|
+
// Inline code
|
|
838
|
+
str = str.replace(new RegExp('\\x60([^\\x60]+)\\x60', 'g'), '<code class="inline-code">$1</code>');
|
|
839
|
+
|
|
840
|
+
// Bold
|
|
841
|
+
str = str.replace(new RegExp('\\\\*\\\\*(.+?)\\\\*\\\\*', 'g'), '<strong>$1</strong>');
|
|
842
|
+
str = str.replace(new RegExp('__(.+?)__', 'g'), '<strong>$1</strong>');
|
|
843
|
+
|
|
844
|
+
// Strikethrough
|
|
845
|
+
str = str.replace(new RegExp('~~(.+?)~~', 'g'), '<del>$1</del>');
|
|
846
|
+
|
|
847
|
+
// Italic
|
|
848
|
+
str = str.replace(new RegExp('(^|[^*])\\\\*([^*\\\\r\\\\n]+)\\\\*([^*]|$)', 'g'), '$1<em>$2</em>$3');
|
|
849
|
+
str = str.replace(new RegExp('(^|[^_])_([^_\\\\r\\\\n]+)_([^_]|$)', 'g'), '$1<em>$2</em>$3');
|
|
850
|
+
|
|
851
|
+
// Links
|
|
852
|
+
str = str.replace(new RegExp('\\\\[([^\\\\]]+)\\\\]\\\\((https?:\\\\/\\\\/[^\\\\s\\\\)]+|#[^\\\\s\\\\)]+)\\\\)', 'g'), '<a href="$2" target="_blank" rel="noopener noreferrer" class="inline-link">$1</a>');
|
|
853
|
+
|
|
854
|
+
return str;
|
|
855
|
+
}
|
|
856
|
+
|
|
622
857
|
function setList(id, values, emptyMessage) {
|
|
623
858
|
const list = byId(id);
|
|
624
859
|
if (!list) return;
|
|
@@ -628,7 +863,7 @@ const DASHBOARD_HTML = `<!doctype html>
|
|
|
628
863
|
|
|
629
864
|
items.forEach((value, idx) => {
|
|
630
865
|
const item = document.createElement("li");
|
|
631
|
-
item.
|
|
866
|
+
item.innerHTML = renderMarkdownInline(value);
|
|
632
867
|
if (values.length === 0) {
|
|
633
868
|
item.className = "empty";
|
|
634
869
|
} else if (!isFirstLoad && !prevItemsText.includes(value)) {
|
|
@@ -639,6 +874,86 @@ const DASHBOARD_HTML = `<!doctype html>
|
|
|
639
874
|
});
|
|
640
875
|
}
|
|
641
876
|
|
|
877
|
+
function setIdeas(ideas) {
|
|
878
|
+
const list = byId('ideas-list');
|
|
879
|
+
if (!list) return;
|
|
880
|
+
list.replaceChildren();
|
|
881
|
+
|
|
882
|
+
const items = ideas && ideas.pending && ideas.pending.length > 0 ? ideas.pending : [];
|
|
883
|
+
if (items.length === 0) {
|
|
884
|
+
const emptyItem = document.createElement('li');
|
|
885
|
+
emptyItem.className = 'empty';
|
|
886
|
+
emptyItem.textContent = 'No pending ideas in devflow/ideas.md';
|
|
887
|
+
list.append(emptyItem);
|
|
888
|
+
return;
|
|
889
|
+
}
|
|
890
|
+
|
|
891
|
+
items.forEach((idea, idx) => {
|
|
892
|
+
const li = document.createElement('li');
|
|
893
|
+
li.className = 'idea-item';
|
|
894
|
+
if (!isFirstLoad) {
|
|
895
|
+
li.classList.add('fade-slide-in');
|
|
896
|
+
li.style.animationDelay = (idx * 40) + 'ms';
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
const headerDiv = document.createElement('div');
|
|
900
|
+
headerDiv.className = 'idea-header';
|
|
901
|
+
|
|
902
|
+
const badgeSpan = document.createElement('span');
|
|
903
|
+
badgeSpan.className = 'idea-id-badge';
|
|
904
|
+
badgeSpan.textContent = idea.id;
|
|
905
|
+
|
|
906
|
+
const cmdCode = document.createElement('code');
|
|
907
|
+
cmdCode.className = 'idea-cmd-code';
|
|
908
|
+
cmdCode.textContent = '/feature ' + idea.id;
|
|
909
|
+
cmdCode.title = 'Click to copy command';
|
|
910
|
+
cmdCode.onclick = () => {
|
|
911
|
+
if (navigator.clipboard) {
|
|
912
|
+
navigator.clipboard.writeText('/feature ' + idea.id);
|
|
913
|
+
const orig = cmdCode.textContent;
|
|
914
|
+
cmdCode.textContent = 'Copied!';
|
|
915
|
+
setTimeout(() => { cmdCode.textContent = orig; }, 1200);
|
|
916
|
+
}
|
|
917
|
+
};
|
|
918
|
+
|
|
919
|
+
headerDiv.append(badgeSpan, cmdCode);
|
|
920
|
+
|
|
921
|
+
const titleDiv = document.createElement('div');
|
|
922
|
+
titleDiv.className = 'idea-title-text';
|
|
923
|
+
titleDiv.innerHTML = renderMarkdownInline(idea.title);
|
|
924
|
+
|
|
925
|
+
li.append(headerDiv, titleDiv);
|
|
926
|
+
|
|
927
|
+
if (idea.rawInput) {
|
|
928
|
+
const descDiv = document.createElement('div');
|
|
929
|
+
descDiv.className = 'idea-desc-text';
|
|
930
|
+
descDiv.innerHTML = renderMarkdownInline(idea.rawInput);
|
|
931
|
+
li.append(descDiv);
|
|
932
|
+
}
|
|
933
|
+
|
|
934
|
+
if (idea.feasibility || idea.value || idea.date) {
|
|
935
|
+
const metaDiv = document.createElement('div');
|
|
936
|
+
metaDiv.className = 'idea-meta-row';
|
|
937
|
+
if (idea.feasibility) {
|
|
938
|
+
const feasSpan = document.createElement('span');
|
|
939
|
+
feasSpan.className = 'idea-feasibility-tag';
|
|
940
|
+
feasSpan.innerHTML = '⚡ ' + renderMarkdownInline(idea.feasibility);
|
|
941
|
+
metaDiv.append(feasSpan);
|
|
942
|
+
}
|
|
943
|
+
if (idea.date) {
|
|
944
|
+
const dateSpan = document.createElement('span');
|
|
945
|
+
dateSpan.className = 'muted';
|
|
946
|
+
dateSpan.style.fontSize = '11px';
|
|
947
|
+
dateSpan.textContent = idea.date;
|
|
948
|
+
metaDiv.append(dateSpan);
|
|
949
|
+
}
|
|
950
|
+
li.append(metaDiv);
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
list.append(li);
|
|
954
|
+
});
|
|
955
|
+
}
|
|
956
|
+
|
|
642
957
|
async function refreshStatus() {
|
|
643
958
|
if (refreshing) return;
|
|
644
959
|
refreshing = true;
|
|
@@ -732,6 +1047,17 @@ const DASHBOARD_HTML = `<!doctype html>
|
|
|
732
1047
|
}
|
|
733
1048
|
setList('warnings-list', warnings.map(w => w.message), 'No active warnings or drift');
|
|
734
1049
|
|
|
1050
|
+
const ideas = data.ideas || { totalPending: 0, pending: [] };
|
|
1051
|
+
const prevIdeasCount = prevData?.ideas?.totalPending ?? 0;
|
|
1052
|
+
const ideasNode = byId('ideas-count');
|
|
1053
|
+
if (!isFirstLoad && ideas.totalPending !== prevIdeasCount) {
|
|
1054
|
+
animateCount(ideasNode, prevIdeasCount, ideas.totalPending);
|
|
1055
|
+
triggerFlash(ideasNode, 'green');
|
|
1056
|
+
} else {
|
|
1057
|
+
ideasNode.textContent = ideas.totalPending + ' pending';
|
|
1058
|
+
}
|
|
1059
|
+
setIdeas(ideas);
|
|
1060
|
+
|
|
735
1061
|
const historyItems = historyData.items || [];
|
|
736
1062
|
const prevHistoryCount = prevData?.historyCount ?? 0;
|
|
737
1063
|
const historyNode = byId('history-count');
|
|
@@ -778,6 +1104,32 @@ const DASHBOARD_HTML = `<!doctype html>
|
|
|
778
1104
|
}
|
|
779
1105
|
}
|
|
780
1106
|
|
|
1107
|
+
function setupNextActionCopy() {
|
|
1108
|
+
const copyBtn = byId('next-copy-btn');
|
|
1109
|
+
const cmdNode = byId('next-command');
|
|
1110
|
+
const copyText = byId('next-copy-text');
|
|
1111
|
+
|
|
1112
|
+
const performCopy = () => {
|
|
1113
|
+
const textToCopy = cmdNode ? cmdNode.textContent.trim() : '';
|
|
1114
|
+
if (!textToCopy || textToCopy === 'Loading...') return;
|
|
1115
|
+
if (navigator.clipboard) {
|
|
1116
|
+
navigator.clipboard.writeText(textToCopy);
|
|
1117
|
+
if (copyBtn && copyText) {
|
|
1118
|
+
copyBtn.classList.add('copied');
|
|
1119
|
+
copyText.textContent = '✓ Copied!';
|
|
1120
|
+
setTimeout(() => {
|
|
1121
|
+
copyBtn.classList.remove('copied');
|
|
1122
|
+
copyText.textContent = 'Copy Command';
|
|
1123
|
+
}, 1400);
|
|
1124
|
+
}
|
|
1125
|
+
}
|
|
1126
|
+
};
|
|
1127
|
+
|
|
1128
|
+
if (copyBtn) copyBtn.onclick = performCopy;
|
|
1129
|
+
if (cmdNode) cmdNode.onclick = performCopy;
|
|
1130
|
+
}
|
|
1131
|
+
|
|
1132
|
+
setupNextActionCopy();
|
|
781
1133
|
refreshStatus();
|
|
782
1134
|
setInterval(refreshStatus, 2000);
|
|
783
1135
|
</script>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dashboard.js","sourceRoot":"","sources":["../../lib/dashboard.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"dashboard.js","sourceRoot":"","sources":["../../lib/dashboard.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
interface DiscoveryItem {
|
|
2
|
+
id: string;
|
|
3
|
+
title: string;
|
|
4
|
+
date: string | null;
|
|
5
|
+
decision: "Proceed" | "Defer" | "Reject" | "Unknown";
|
|
6
|
+
approvalStatus: string | null;
|
|
7
|
+
status: string | null;
|
|
8
|
+
file: string;
|
|
9
|
+
}
|
|
10
|
+
interface DiscoverySummary {
|
|
11
|
+
total: number;
|
|
12
|
+
activeId: string | null;
|
|
13
|
+
active: DiscoveryItem | null;
|
|
14
|
+
recent: DiscoveryItem[];
|
|
15
|
+
}
|
|
16
|
+
declare function readDiscoveries(projectRoot: string, activeId?: string | null): Promise<DiscoverySummary>;
|
|
17
|
+
declare function parseDiscovery(markdown: string, file: string, fallbackId: string): DiscoveryItem;
|
|
18
|
+
export { parseDiscovery, readDiscoveries };
|
|
19
|
+
export type { DiscoveryItem, DiscoverySummary };
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
async function readDiscoveries(projectRoot, activeId = null) {
|
|
4
|
+
const root = path.join(projectRoot, "devflow", "discoveries");
|
|
5
|
+
let entries;
|
|
6
|
+
try {
|
|
7
|
+
entries = await fs.readdir(root, { withFileTypes: true });
|
|
8
|
+
}
|
|
9
|
+
catch (error) {
|
|
10
|
+
if (getErrorCode(error) === "ENOENT")
|
|
11
|
+
return emptySummary(activeId);
|
|
12
|
+
throw error;
|
|
13
|
+
}
|
|
14
|
+
const items = await Promise.all(entries
|
|
15
|
+
.filter((entry) => entry.isDirectory() && !entry.isSymbolicLink())
|
|
16
|
+
.map(async (entry) => {
|
|
17
|
+
const file = path.join(entry.name, "00-explore.md");
|
|
18
|
+
try {
|
|
19
|
+
const markdown = await fs.readFile(path.join(root, file), "utf8");
|
|
20
|
+
return parseDiscovery(markdown, file, entry.name);
|
|
21
|
+
}
|
|
22
|
+
catch (error) {
|
|
23
|
+
if (getErrorCode(error) === "ENOENT")
|
|
24
|
+
return null;
|
|
25
|
+
throw error;
|
|
26
|
+
}
|
|
27
|
+
}));
|
|
28
|
+
const valid = items.filter((item) => item !== null)
|
|
29
|
+
.sort((left, right) => right.id.localeCompare(left.id));
|
|
30
|
+
return {
|
|
31
|
+
total: valid.length,
|
|
32
|
+
activeId,
|
|
33
|
+
active: valid.find((item) => item.id === activeId) || null,
|
|
34
|
+
recent: valid.slice(0, 6)
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
function parseDiscovery(markdown, file, fallbackId) {
|
|
38
|
+
const id = field(markdown, "Discovery ID") || fallbackId.match(/DISC-\d{8}-\d{3}/)?.[0] || fallbackId;
|
|
39
|
+
const heading = markdown.match(/^#\s+(.+)$/m)?.[1]?.trim() || fallbackId;
|
|
40
|
+
const title = heading
|
|
41
|
+
.replace(/^.*?\]\s*/, "")
|
|
42
|
+
.replace(/^Discovery Document:\s*/i, "")
|
|
43
|
+
.trim();
|
|
44
|
+
const finalDecision = markdown.match(/Final Decision:\s*`?(Proceed|Defer|Reject)`?/i)?.[1];
|
|
45
|
+
const status = field(markdown, "Status");
|
|
46
|
+
const statusDecision = status?.match(/\b(Proceed|Defer|Reject)\b/i)?.[1];
|
|
47
|
+
const normalizedDecision = finalDecision || statusDecision;
|
|
48
|
+
return {
|
|
49
|
+
id,
|
|
50
|
+
title,
|
|
51
|
+
date: field(markdown, "Date"),
|
|
52
|
+
decision: normalizeDecision(normalizedDecision),
|
|
53
|
+
approvalStatus: field(markdown, "Approval Status"),
|
|
54
|
+
status,
|
|
55
|
+
file: file.replaceAll("\\", "/")
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
function field(markdown, label) {
|
|
59
|
+
const escaped = label.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
60
|
+
return markdown.match(new RegExp(`\\*\\*${escaped}\\*\\*:\\s*\\x60?([^\\r\\n\\x60]+)`, "i"))?.[1]?.trim() || null;
|
|
61
|
+
}
|
|
62
|
+
function normalizeDecision(value) {
|
|
63
|
+
const normalized = value?.toLowerCase();
|
|
64
|
+
if (normalized === "proceed")
|
|
65
|
+
return "Proceed";
|
|
66
|
+
if (normalized === "defer")
|
|
67
|
+
return "Defer";
|
|
68
|
+
if (normalized === "reject")
|
|
69
|
+
return "Reject";
|
|
70
|
+
return "Unknown";
|
|
71
|
+
}
|
|
72
|
+
function emptySummary(activeId) {
|
|
73
|
+
return { total: 0, activeId, active: null, recent: [] };
|
|
74
|
+
}
|
|
75
|
+
function getErrorCode(error) {
|
|
76
|
+
return typeof error === "object" && error !== null && "code" in error && typeof error.code === "string"
|
|
77
|
+
? error.code
|
|
78
|
+
: undefined;
|
|
79
|
+
}
|
|
80
|
+
export { parseDiscovery, readDiscoveries };
|
|
81
|
+
//# sourceMappingURL=discoveries.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discoveries.js","sourceRoot":"","sources":["../../lib/discoveries.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export interface DoctorCheck {
|
|
2
|
+
id: string;
|
|
3
|
+
name: string;
|
|
4
|
+
status: "pass" | "warn" | "fail";
|
|
5
|
+
message: string;
|
|
6
|
+
fixable: boolean;
|
|
7
|
+
fixed?: boolean;
|
|
8
|
+
}
|
|
9
|
+
export interface DoctorReport {
|
|
10
|
+
projectRoot: string;
|
|
11
|
+
isDevFlowProject: boolean;
|
|
12
|
+
checks: DoctorCheck[];
|
|
13
|
+
totalChecks: number;
|
|
14
|
+
passCount: number;
|
|
15
|
+
warnCount: number;
|
|
16
|
+
failCount: number;
|
|
17
|
+
fixedCount: number;
|
|
18
|
+
}
|
|
19
|
+
export interface DoctorOptions {
|
|
20
|
+
fix?: boolean;
|
|
21
|
+
color?: boolean;
|
|
22
|
+
}
|
|
23
|
+
export declare function runDoctor(projectRoot: string, options?: DoctorOptions): Promise<DoctorReport>;
|
|
24
|
+
export declare function formatDoctorHuman(report: DoctorReport, options?: {
|
|
25
|
+
color?: boolean;
|
|
26
|
+
}): string;
|