@planu/cli 0.54.2 → 0.56.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/config/license-plans.json +1 -0
- package/dist/engine/doc-generator/executive-summary/executive-summary-generator.d.ts +7 -1
- package/dist/engine/doc-generator/executive-summary/executive-summary-generator.d.ts.map +1 -1
- package/dist/engine/doc-generator/executive-summary/executive-summary-generator.js +16 -3
- package/dist/engine/doc-generator/executive-summary/executive-summary-generator.js.map +1 -1
- package/dist/engine/doc-generator/executive-summary/html-template.d.ts +5 -2
- package/dist/engine/doc-generator/executive-summary/html-template.d.ts.map +1 -1
- package/dist/engine/doc-generator/executive-summary/html-template.js +7 -3
- package/dist/engine/doc-generator/executive-summary/html-template.js.map +1 -1
- package/dist/engine/doc-generator/per-spec-report/executive-report.d.ts +3 -1
- package/dist/engine/doc-generator/per-spec-report/executive-report.d.ts.map +1 -1
- package/dist/engine/doc-generator/per-spec-report/executive-report.js +22 -2
- package/dist/engine/doc-generator/per-spec-report/executive-report.js.map +1 -1
- package/dist/engine/doc-generator/per-spec-report/html-wrapper.d.ts +5 -3
- package/dist/engine/doc-generator/per-spec-report/html-wrapper.d.ts.map +1 -1
- package/dist/engine/doc-generator/per-spec-report/html-wrapper.js +27 -6
- package/dist/engine/doc-generator/per-spec-report/html-wrapper.js.map +1 -1
- package/dist/engine/doc-generator/per-spec-report/spec-data-extractor.d.ts +1 -0
- package/dist/engine/doc-generator/per-spec-report/spec-data-extractor.d.ts.map +1 -1
- package/dist/engine/doc-generator/per-spec-report/spec-data-extractor.js +29 -0
- package/dist/engine/doc-generator/per-spec-report/spec-data-extractor.js.map +1 -1
- package/dist/engine/doc-generator/per-spec-report/spec-section-builders.d.ts +8 -1
- package/dist/engine/doc-generator/per-spec-report/spec-section-builders.d.ts.map +1 -1
- package/dist/engine/doc-generator/per-spec-report/spec-section-builders.js +188 -0
- package/dist/engine/doc-generator/per-spec-report/spec-section-builders.js.map +1 -1
- package/dist/engine/doc-generator/per-spec-report/technical-report.d.ts +3 -1
- package/dist/engine/doc-generator/per-spec-report/technical-report.d.ts.map +1 -1
- package/dist/engine/doc-generator/per-spec-report/technical-report.js +24 -7
- package/dist/engine/doc-generator/per-spec-report/technical-report.js.map +1 -1
- package/dist/engine/doc-generator/portal/analytics-page.d.ts +8 -0
- package/dist/engine/doc-generator/portal/analytics-page.d.ts.map +1 -0
- package/dist/engine/doc-generator/portal/analytics-page.js +265 -0
- package/dist/engine/doc-generator/portal/analytics-page.js.map +1 -0
- package/dist/engine/doc-generator/portal/architecture-page.d.ts +6 -0
- package/dist/engine/doc-generator/portal/architecture-page.d.ts.map +1 -0
- package/dist/engine/doc-generator/portal/architecture-page.js +250 -0
- package/dist/engine/doc-generator/portal/architecture-page.js.map +1 -0
- package/dist/engine/doc-generator/portal/changelog-page.d.ts +6 -0
- package/dist/engine/doc-generator/portal/changelog-page.d.ts.map +1 -0
- package/dist/engine/doc-generator/portal/changelog-page.js +204 -0
- package/dist/engine/doc-generator/portal/changelog-page.js.map +1 -0
- package/dist/engine/doc-generator/portal/data-aggregators/accuracy-aggregator.d.ts +11 -0
- package/dist/engine/doc-generator/portal/data-aggregators/accuracy-aggregator.d.ts.map +1 -0
- package/dist/engine/doc-generator/portal/data-aggregators/accuracy-aggregator.js +24 -0
- package/dist/engine/doc-generator/portal/data-aggregators/accuracy-aggregator.js.map +1 -0
- package/dist/engine/doc-generator/portal/data-aggregators/bottleneck-detector.d.ts +9 -0
- package/dist/engine/doc-generator/portal/data-aggregators/bottleneck-detector.d.ts.map +1 -0
- package/dist/engine/doc-generator/portal/data-aggregators/bottleneck-detector.js +31 -0
- package/dist/engine/doc-generator/portal/data-aggregators/bottleneck-detector.js.map +1 -0
- package/dist/engine/doc-generator/portal/data-aggregators/burndown-aggregator.d.ts +10 -0
- package/dist/engine/doc-generator/portal/data-aggregators/burndown-aggregator.d.ts.map +1 -0
- package/dist/engine/doc-generator/portal/data-aggregators/burndown-aggregator.js +77 -0
- package/dist/engine/doc-generator/portal/data-aggregators/burndown-aggregator.js.map +1 -0
- package/dist/engine/doc-generator/portal/data-aggregators/velocity-aggregator.d.ts +9 -0
- package/dist/engine/doc-generator/portal/data-aggregators/velocity-aggregator.d.ts.map +1 -0
- package/dist/engine/doc-generator/portal/data-aggregators/velocity-aggregator.js +31 -0
- package/dist/engine/doc-generator/portal/data-aggregators/velocity-aggregator.js.map +1 -0
- package/dist/engine/doc-generator/portal/decision-page.d.ts +6 -0
- package/dist/engine/doc-generator/portal/decision-page.d.ts.map +1 -0
- package/dist/engine/doc-generator/portal/decision-page.js +169 -0
- package/dist/engine/doc-generator/portal/decision-page.js.map +1 -0
- package/dist/engine/doc-generator/portal/decision-timeline-builder.d.ts +8 -0
- package/dist/engine/doc-generator/portal/decision-timeline-builder.d.ts.map +1 -0
- package/dist/engine/doc-generator/portal/decision-timeline-builder.js +131 -0
- package/dist/engine/doc-generator/portal/decision-timeline-builder.js.map +1 -0
- package/dist/engine/doc-generator/portal/index.d.ts +19 -0
- package/dist/engine/doc-generator/portal/index.d.ts.map +1 -0
- package/dist/engine/doc-generator/portal/index.js +21 -0
- package/dist/engine/doc-generator/portal/index.js.map +1 -0
- package/dist/engine/doc-generator/portal/kanban-view-builder.d.ts +8 -0
- package/dist/engine/doc-generator/portal/kanban-view-builder.d.ts.map +1 -0
- package/dist/engine/doc-generator/portal/kanban-view-builder.js +140 -0
- package/dist/engine/doc-generator/portal/kanban-view-builder.js.map +1 -0
- package/dist/engine/doc-generator/portal/portal-breadcrumbs.d.ts +27 -0
- package/dist/engine/doc-generator/portal/portal-breadcrumbs.d.ts.map +1 -0
- package/dist/engine/doc-generator/portal/portal-breadcrumbs.js +139 -0
- package/dist/engine/doc-generator/portal/portal-breadcrumbs.js.map +1 -0
- package/dist/engine/doc-generator/portal/portal-landing-cards.d.ts +8 -0
- package/dist/engine/doc-generator/portal/portal-landing-cards.d.ts.map +1 -0
- package/dist/engine/doc-generator/portal/portal-landing-cards.js +177 -0
- package/dist/engine/doc-generator/portal/portal-landing-cards.js.map +1 -0
- package/dist/engine/doc-generator/portal/portal-navbar.d.ts +15 -0
- package/dist/engine/doc-generator/portal/portal-navbar.d.ts.map +1 -0
- package/dist/engine/doc-generator/portal/portal-navbar.js +143 -0
- package/dist/engine/doc-generator/portal/portal-navbar.js.map +1 -0
- package/dist/engine/doc-generator/portal/portal-page-detector.d.ts +22 -0
- package/dist/engine/doc-generator/portal/portal-page-detector.d.ts.map +1 -0
- package/dist/engine/doc-generator/portal/portal-page-detector.js +58 -0
- package/dist/engine/doc-generator/portal/portal-page-detector.js.map +1 -0
- package/dist/engine/doc-generator/portal/portal-theme.d.ts +7 -0
- package/dist/engine/doc-generator/portal/portal-theme.d.ts.map +1 -0
- package/dist/engine/doc-generator/portal/portal-theme.js +53 -0
- package/dist/engine/doc-generator/portal/portal-theme.js.map +1 -0
- package/dist/engine/doc-generator/portal/risk-gauge-svg.d.ts +5 -0
- package/dist/engine/doc-generator/portal/risk-gauge-svg.d.ts.map +1 -0
- package/dist/engine/doc-generator/portal/risk-gauge-svg.js +80 -0
- package/dist/engine/doc-generator/portal/risk-gauge-svg.js.map +1 -0
- package/dist/engine/doc-generator/portal/risk-matrix-svg.d.ts +11 -0
- package/dist/engine/doc-generator/portal/risk-matrix-svg.d.ts.map +1 -0
- package/dist/engine/doc-generator/portal/risk-matrix-svg.js +181 -0
- package/dist/engine/doc-generator/portal/risk-matrix-svg.js.map +1 -0
- package/dist/engine/doc-generator/portal/risk-page.d.ts +7 -0
- package/dist/engine/doc-generator/portal/risk-page.d.ts.map +1 -0
- package/dist/engine/doc-generator/portal/risk-page.js +219 -0
- package/dist/engine/doc-generator/portal/risk-page.js.map +1 -0
- package/dist/engine/doc-generator/portal/roadmap-page.d.ts +7 -0
- package/dist/engine/doc-generator/portal/roadmap-page.d.ts.map +1 -0
- package/dist/engine/doc-generator/portal/roadmap-page.js +204 -0
- package/dist/engine/doc-generator/portal/roadmap-page.js.map +1 -0
- package/dist/engine/doc-generator/portal/svg-charts/bar-chart.d.ts +4 -0
- package/dist/engine/doc-generator/portal/svg-charts/bar-chart.d.ts.map +1 -0
- package/dist/engine/doc-generator/portal/svg-charts/bar-chart.js +50 -0
- package/dist/engine/doc-generator/portal/svg-charts/bar-chart.js.map +1 -0
- package/dist/engine/doc-generator/portal/svg-charts/chart-utils.d.ts +16 -0
- package/dist/engine/doc-generator/portal/svg-charts/chart-utils.d.ts.map +1 -0
- package/dist/engine/doc-generator/portal/svg-charts/chart-utils.js +45 -0
- package/dist/engine/doc-generator/portal/svg-charts/chart-utils.js.map +1 -0
- package/dist/engine/doc-generator/portal/svg-charts/line-chart.d.ts +16 -0
- package/dist/engine/doc-generator/portal/svg-charts/line-chart.d.ts.map +1 -0
- package/dist/engine/doc-generator/portal/svg-charts/line-chart.js +159 -0
- package/dist/engine/doc-generator/portal/svg-charts/line-chart.js.map +1 -0
- package/dist/engine/doc-generator/portal/svg-charts/pie-chart.d.ts +7 -0
- package/dist/engine/doc-generator/portal/svg-charts/pie-chart.d.ts.map +1 -0
- package/dist/engine/doc-generator/portal/svg-charts/pie-chart.js +52 -0
- package/dist/engine/doc-generator/portal/svg-charts/pie-chart.js.map +1 -0
- package/dist/engine/doc-generator/proposal/proposal-gantt-builder.d.ts +8 -0
- package/dist/engine/doc-generator/proposal/proposal-gantt-builder.d.ts.map +1 -0
- package/dist/engine/doc-generator/proposal/proposal-gantt-builder.js +126 -0
- package/dist/engine/doc-generator/proposal/proposal-gantt-builder.js.map +1 -0
- package/dist/engine/doc-generator/proposal/proposal-generator.d.ts +10 -0
- package/dist/engine/doc-generator/proposal/proposal-generator.d.ts.map +1 -0
- package/dist/engine/doc-generator/proposal/proposal-generator.js +93 -0
- package/dist/engine/doc-generator/proposal/proposal-generator.js.map +1 -0
- package/dist/engine/doc-generator/proposal/proposal-html-wrapper.d.ts +7 -0
- package/dist/engine/doc-generator/proposal/proposal-html-wrapper.d.ts.map +1 -0
- package/dist/engine/doc-generator/proposal/proposal-html-wrapper.js +31 -0
- package/dist/engine/doc-generator/proposal/proposal-html-wrapper.js.map +1 -0
- package/dist/engine/doc-generator/proposal/proposal-i18n.d.ts +12 -0
- package/dist/engine/doc-generator/proposal/proposal-i18n.d.ts.map +1 -0
- package/dist/engine/doc-generator/proposal/proposal-i18n.js +230 -0
- package/dist/engine/doc-generator/proposal/proposal-i18n.js.map +1 -0
- package/dist/engine/doc-generator/proposal/proposal-kpi-builder.d.ts +8 -0
- package/dist/engine/doc-generator/proposal/proposal-kpi-builder.d.ts.map +1 -0
- package/dist/engine/doc-generator/proposal/proposal-kpi-builder.js +32 -0
- package/dist/engine/doc-generator/proposal/proposal-kpi-builder.js.map +1 -0
- package/dist/engine/doc-generator/proposal/proposal-section-builders-advanced.d.ts +14 -0
- package/dist/engine/doc-generator/proposal/proposal-section-builders-advanced.d.ts.map +1 -0
- package/dist/engine/doc-generator/proposal/proposal-section-builders-advanced.js +248 -0
- package/dist/engine/doc-generator/proposal/proposal-section-builders-advanced.js.map +1 -0
- package/dist/engine/doc-generator/proposal/proposal-section-builders.d.ts +13 -0
- package/dist/engine/doc-generator/proposal/proposal-section-builders.d.ts.map +1 -0
- package/dist/engine/doc-generator/proposal/proposal-section-builders.js +423 -0
- package/dist/engine/doc-generator/proposal/proposal-section-builders.js.map +1 -0
- package/dist/engine/doc-generator/proposal/proposal-themes.d.ts +4 -0
- package/dist/engine/doc-generator/proposal/proposal-themes.d.ts.map +1 -0
- package/dist/engine/doc-generator/proposal/proposal-themes.js +194 -0
- package/dist/engine/doc-generator/proposal/proposal-themes.js.map +1 -0
- package/dist/engine/spec-summary-html.d.ts.map +1 -1
- package/dist/engine/spec-summary-html.js +17 -5
- package/dist/engine/spec-summary-html.js.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/tools/generate-proposal.d.ts +3 -0
- package/dist/tools/generate-proposal.d.ts.map +1 -0
- package/dist/tools/generate-proposal.js +166 -0
- package/dist/tools/generate-proposal.js.map +1 -0
- package/dist/types/docs.d.ts +75 -0
- package/dist/types/docs.d.ts.map +1 -1
- package/dist/types/portal.d.ts +128 -0
- package/dist/types/portal.d.ts.map +1 -0
- package/dist/types/portal.js +3 -0
- package/dist/types/portal.js.map +1 -0
- package/dist/types/proposal.d.ts +57 -0
- package/dist/types/proposal.d.ts.map +1 -0
- package/dist/types/proposal.js +2 -0
- package/dist/types/proposal.js.map +1 -0
- package/package.json +1 -1
- package/src/config/license-plans.json +1 -0
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
import type { ProjectKnowledge, Spec, GeneratedDocument } from '../../../types/index.js';
|
|
2
2
|
/**
|
|
3
3
|
* Generate a self-contained HTML executive summary document.
|
|
4
|
+
* Output is placed at planu/executive-summary.html (portal hub location).
|
|
4
5
|
* Returns a GeneratedDocument with type 'executive-summary'.
|
|
6
|
+
*
|
|
7
|
+
* @param knowledge - Project knowledge data.
|
|
8
|
+
* @param specs - All project specs.
|
|
9
|
+
* @param _language - Language hint (reserved for future i18n).
|
|
10
|
+
* @param availablePages - Portal pages that exist on disk (for navbar display).
|
|
5
11
|
*/
|
|
6
|
-
export declare function generateExecutiveSummary(knowledge: ProjectKnowledge, specs: Spec[], _language: string): GeneratedDocument;
|
|
12
|
+
export declare function generateExecutiveSummary(knowledge: ProjectKnowledge, specs: Spec[], _language: string, availablePages?: string[]): GeneratedDocument;
|
|
7
13
|
//# sourceMappingURL=executive-summary-generator.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"executive-summary-generator.d.ts","sourceRoot":"","sources":["../../../../src/engine/doc-generator/executive-summary/executive-summary-generator.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,IAAI,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"executive-summary-generator.d.ts","sourceRoot":"","sources":["../../../../src/engine/doc-generator/executive-summary/executive-summary-generator.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,IAAI,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAqBzF;;;;;;;;;GASG;AACH,wBAAgB,wBAAwB,CACtC,SAAS,EAAE,gBAAgB,EAC3B,KAAK,EAAE,IAAI,EAAE,EACb,SAAS,EAAE,MAAM,EACjB,cAAc,CAAC,EAAE,MAAM,EAAE,GACxB,iBAAiB,CAuCnB"}
|
|
@@ -2,17 +2,28 @@ import { buildExecutiveSummaryData } from './data-extractors.js';
|
|
|
2
2
|
import { generateArchitectureSvg, generateTimelineSvg, generateRiskDistributionSvg, } from './svg-diagrams.js';
|
|
3
3
|
import { wrapInHtmlDocument } from './html-template.js';
|
|
4
4
|
import { buildHeaderSection, buildOverviewSection, buildSpecsTableSection, buildEstimationSection, buildRiskSection, buildArchitectureSection, buildTimelineSection, buildFooterSection, } from './section-builders.js';
|
|
5
|
+
import { buildNavbar } from '../portal/portal-navbar.js';
|
|
6
|
+
import { getPortalThemeCSS } from '../portal/portal-theme.js';
|
|
5
7
|
/**
|
|
6
8
|
* Generate a self-contained HTML executive summary document.
|
|
9
|
+
* Output is placed at planu/executive-summary.html (portal hub location).
|
|
7
10
|
* Returns a GeneratedDocument with type 'executive-summary'.
|
|
11
|
+
*
|
|
12
|
+
* @param knowledge - Project knowledge data.
|
|
13
|
+
* @param specs - All project specs.
|
|
14
|
+
* @param _language - Language hint (reserved for future i18n).
|
|
15
|
+
* @param availablePages - Portal pages that exist on disk (for navbar display).
|
|
8
16
|
*/
|
|
9
|
-
export function generateExecutiveSummary(knowledge, specs, _language) {
|
|
17
|
+
export function generateExecutiveSummary(knowledge, specs, _language, availablePages) {
|
|
10
18
|
const data = buildExecutiveSummaryData(knowledge, specs);
|
|
11
19
|
const archSvg = generateArchitectureSvg(data.architecture);
|
|
12
20
|
const timelineSvg = generateTimelineSvg(data.specs);
|
|
13
21
|
const riskSvg = generateRiskDistributionSvg(data.riskProfile);
|
|
14
22
|
const hasActuals = data.specs.some((s) => s.actualDevHours !== undefined);
|
|
23
|
+
// Navbar is at root level (planu/), so basePath is empty
|
|
24
|
+
const navbar = buildNavbar('executive-summary', '', availablePages);
|
|
15
25
|
const body = [
|
|
26
|
+
navbar,
|
|
16
27
|
buildHeaderSection(data.projectName, data.generatedAt, data.specs.length),
|
|
17
28
|
buildOverviewSection(data.architecture),
|
|
18
29
|
buildSpecsTableSection(data.specs),
|
|
@@ -23,11 +34,13 @@ export function generateExecutiveSummary(knowledge, specs, _language) {
|
|
|
23
34
|
buildFooterSection(),
|
|
24
35
|
].join('\n');
|
|
25
36
|
const title = `Executive Summary — ${data.projectName}`;
|
|
26
|
-
|
|
37
|
+
// Inject portal theme CSS before the existing document CSS
|
|
38
|
+
const content = wrapInHtmlDocument(title, body, getPortalThemeCSS());
|
|
27
39
|
return {
|
|
28
40
|
type: 'executive-summary',
|
|
29
41
|
title,
|
|
30
|
-
|
|
42
|
+
// Changed from docs/ to planu/ — this is now part of the portal hub
|
|
43
|
+
path: 'planu/executive-summary.html',
|
|
31
44
|
content,
|
|
32
45
|
audience: 'stakeholder',
|
|
33
46
|
sections: [],
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"executive-summary-generator.js","sourceRoot":"","sources":["../../../../src/engine/doc-generator/executive-summary/executive-summary-generator.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,yBAAyB,EAAE,MAAM,sBAAsB,CAAC;AACjE,OAAO,EACL,uBAAuB,EACvB,mBAAmB,EACnB,2BAA2B,GAC5B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,EACL,kBAAkB,EAClB,oBAAoB,EACpB,sBAAsB,EACtB,sBAAsB,EACtB,gBAAgB,EAChB,wBAAwB,EACxB,oBAAoB,EACpB,kBAAkB,GACnB,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"executive-summary-generator.js","sourceRoot":"","sources":["../../../../src/engine/doc-generator/executive-summary/executive-summary-generator.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,yBAAyB,EAAE,MAAM,sBAAsB,CAAC;AACjE,OAAO,EACL,uBAAuB,EACvB,mBAAmB,EACnB,2BAA2B,GAC5B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,EACL,kBAAkB,EAClB,oBAAoB,EACpB,sBAAsB,EACtB,sBAAsB,EACtB,gBAAgB,EAChB,wBAAwB,EACxB,oBAAoB,EACpB,kBAAkB,GACnB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AACzD,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAE9D;;;;;;;;;GASG;AACH,MAAM,UAAU,wBAAwB,CACtC,SAA2B,EAC3B,KAAa,EACb,SAAiB,EACjB,cAAyB;IAEzB,MAAM,IAAI,GAAG,yBAAyB,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;IAEzD,MAAM,OAAO,GAAG,uBAAuB,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IAC3D,MAAM,WAAW,GAAG,mBAAmB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACpD,MAAM,OAAO,GAAG,2BAA2B,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IAE9D,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,cAAc,KAAK,SAAS,CAAC,CAAC;IAE1E,yDAAyD;IACzD,MAAM,MAAM,GAAG,WAAW,CAAC,mBAAmB,EAAE,EAAE,EAAE,cAAc,CAAC,CAAC;IAEpE,MAAM,IAAI,GAAG;QACX,MAAM;QACN,kBAAkB,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC;QACzE,oBAAoB,CAAC,IAAI,CAAC,YAAY,CAAC;QACvC,sBAAsB,CAAC,IAAI,CAAC,KAAK,CAAC;QAClC,sBAAsB,CAAC,IAAI,CAAC,UAAU,EAAE,UAAU,CAAC;QACnD,gBAAgB,CAAC,IAAI,CAAC,WAAW,EAAE,OAAO,CAAC;QAC3C,wBAAwB,CAAC,IAAI,CAAC,YAAY,EAAE,OAAO,CAAC;QACpD,oBAAoB,CAAC,WAAW,CAAC;QACjC,kBAAkB,EAAE;KACrB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAEb,MAAM,KAAK,GAAG,uBAAuB,IAAI,CAAC,WAAW,EAAE,CAAC;IACxD,2DAA2D;IAC3D,MAAM,OAAO,GAAG,kBAAkB,CAAC,KAAK,EAAE,IAAI,EAAE,iBAAiB,EAAE,CAAC,CAAC;IAErE,OAAO;QACL,IAAI,EAAE,mBAAmB;QACzB,KAAK;QACL,oEAAoE;QACpE,IAAI,EAAE,8BAA8B;QACpC,OAAO;QACP,QAAQ,EAAE,aAAa;QACvB,QAAQ,EAAE,EAAE;QACZ,QAAQ,EAAE,EAAE;QACZ,YAAY,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC1C,CAAC;AACJ,CAAC"}
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
-
/**
|
|
2
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Wrap body content in a full HTML document with inline CSS.
|
|
3
|
+
* Optionally prepend extra CSS (e.g. portal theme variables) before the page CSS.
|
|
4
|
+
*/
|
|
5
|
+
export declare function wrapInHtmlDocument(title: string, bodyContent: string, extraCss?: string): string;
|
|
3
6
|
//# sourceMappingURL=html-template.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"html-template.d.ts","sourceRoot":"","sources":["../../../../src/engine/doc-generator/executive-summary/html-template.ts"],"names":[],"mappings":"AAgCA
|
|
1
|
+
{"version":3,"file":"html-template.d.ts","sourceRoot":"","sources":["../../../../src/engine/doc-generator/executive-summary/html-template.ts"],"names":[],"mappings":"AAgCA;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAchG"}
|
|
@@ -28,15 +28,19 @@ const CSS = `
|
|
|
28
28
|
svg { max-width: 100%; height: auto; }
|
|
29
29
|
.footer { margin-top: 32px; padding-top: 16px; border-top: 1px solid #e5e7eb; font-size: 0.78em; color: #9ca3af; text-align: center; }
|
|
30
30
|
`;
|
|
31
|
-
/**
|
|
32
|
-
|
|
31
|
+
/**
|
|
32
|
+
* Wrap body content in a full HTML document with inline CSS.
|
|
33
|
+
* Optionally prepend extra CSS (e.g. portal theme variables) before the page CSS.
|
|
34
|
+
*/
|
|
35
|
+
export function wrapInHtmlDocument(title, bodyContent, extraCss) {
|
|
36
|
+
const styles = extraCss !== undefined ? `${extraCss}${CSS}` : CSS;
|
|
33
37
|
return `<!DOCTYPE html>
|
|
34
38
|
<html lang="en">
|
|
35
39
|
<head>
|
|
36
40
|
<meta charset="UTF-8"/>
|
|
37
41
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
|
38
42
|
<title>${escapeHtml(title)}</title>
|
|
39
|
-
<style>${
|
|
43
|
+
<style>${styles}</style>
|
|
40
44
|
</head>
|
|
41
45
|
<body>
|
|
42
46
|
${bodyContent}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"html-template.js","sourceRoot":"","sources":["../../../../src/engine/doc-generator/executive-summary/html-template.ts"],"names":[],"mappings":"AAAA,sEAAsE;AAEtE,MAAM,GAAG,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4BX,CAAC;AAEF
|
|
1
|
+
{"version":3,"file":"html-template.js","sourceRoot":"","sources":["../../../../src/engine/doc-generator/executive-summary/html-template.ts"],"names":[],"mappings":"AAAA,sEAAsE;AAEtE,MAAM,GAAG,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4BX,CAAC;AAEF;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAC,KAAa,EAAE,WAAmB,EAAE,QAAiB;IACtF,MAAM,MAAM,GAAG,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,GAAG,QAAQ,GAAG,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC;IAClE,OAAO;;;;;WAKE,UAAU,CAAC,KAAK,CAAC;WACjB,MAAM;;;EAGf,WAAW;;QAEL,CAAC;AACT,CAAC;AAED,SAAS,UAAU,CAAC,GAAW;IAC7B,OAAO,GAAG;SACP,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC;SACtB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;AAC7B,CAAC"}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import type { Spec, GeneratedDocument } from '../../../types/index.js';
|
|
2
2
|
/**
|
|
3
3
|
* Generate a self-contained HTML executive report for a single spec.
|
|
4
|
-
* Includes: header, metrics,
|
|
4
|
+
* Includes: header, metrics, actuals comparison, acceptance criteria,
|
|
5
|
+
* risk scorecard, living spec status, dependencies, effort SVG, tags.
|
|
6
|
+
* All rich sections are conditionally rendered based on data availability.
|
|
5
7
|
*/
|
|
6
8
|
export declare function generatePerSpecExecutiveReport(spec: Spec, affectedFiles: string[], architecturalDecisions: string[]): GeneratedDocument;
|
|
7
9
|
//# sourceMappingURL=executive-report.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"executive-report.d.ts","sourceRoot":"","sources":["../../../../src/engine/doc-generator/per-spec-report/executive-report.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"executive-report.d.ts","sourceRoot":"","sources":["../../../../src/engine/doc-generator/per-spec-report/executive-report.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAiBvE;;;;;GAKG;AACH,wBAAgB,8BAA8B,CAC5C,IAAI,EAAE,IAAI,EACV,aAAa,EAAE,MAAM,EAAE,EACvB,sBAAsB,EAAE,MAAM,EAAE,GAC/B,iBAAiB,CA4DnB"}
|
|
@@ -1,18 +1,38 @@
|
|
|
1
1
|
import { extractPerSpecData } from './spec-data-extractor.js';
|
|
2
|
-
import { buildSpecHeaderSection, buildSpecMetricsSection, buildSpecDependenciesSection, buildSpecTagsSection, buildEffortDistributionSvg, buildSpecFooterSection, } from './spec-section-builders.js';
|
|
2
|
+
import { buildSpecHeaderSection, buildSpecMetricsSection, buildSpecDependenciesSection, buildSpecTagsSection, buildEffortDistributionSvg, buildSpecFooterSection, buildAcceptanceCriteriaSection, buildActualsComparisonSection, buildRiskScorecard, buildLivingSpecSection, buildSimilarSpecsSection, } from './spec-section-builders.js';
|
|
3
3
|
import { wrapPerSpecHtml } from './html-wrapper.js';
|
|
4
4
|
/**
|
|
5
5
|
* Generate a self-contained HTML executive report for a single spec.
|
|
6
|
-
* Includes: header, metrics,
|
|
6
|
+
* Includes: header, metrics, actuals comparison, acceptance criteria,
|
|
7
|
+
* risk scorecard, living spec status, dependencies, effort SVG, tags.
|
|
8
|
+
* All rich sections are conditionally rendered based on data availability.
|
|
7
9
|
*/
|
|
8
10
|
export function generatePerSpecExecutiveReport(spec, affectedFiles, architecturalDecisions) {
|
|
9
11
|
const data = extractPerSpecData(spec, affectedFiles, architecturalDecisions);
|
|
12
|
+
const actualsSection = data.actuals !== undefined
|
|
13
|
+
? buildActualsComparisonSection(data.actuals, data.devHours, data.reviewHours, data.totalCostUsd)
|
|
14
|
+
: '';
|
|
15
|
+
const acSection = data.acceptanceCriteria !== undefined && data.acceptanceCriteria.length > 0
|
|
16
|
+
? buildAcceptanceCriteriaSection(data.acceptanceCriteria)
|
|
17
|
+
: '';
|
|
18
|
+
const riskSection = data.riskBreakdown !== undefined && data.riskBreakdown.length > 0
|
|
19
|
+
? buildRiskScorecard(data.riskBreakdown)
|
|
20
|
+
: '';
|
|
21
|
+
const livingSection = data.livingSpec !== undefined ? buildLivingSpecSection(data.livingSpec) : '';
|
|
22
|
+
const similarSection = data.similarSpecs !== undefined && data.similarSpecs.length > 0
|
|
23
|
+
? buildSimilarSpecsSection(data.similarSpecs)
|
|
24
|
+
: '';
|
|
10
25
|
const body = [
|
|
11
26
|
buildSpecHeaderSection(data),
|
|
12
27
|
buildSpecMetricsSection(data),
|
|
28
|
+
actualsSection,
|
|
13
29
|
buildEffortDistributionSvg(data.devHours, data.reviewHours),
|
|
30
|
+
acSection,
|
|
31
|
+
riskSection,
|
|
32
|
+
livingSection,
|
|
14
33
|
buildSpecDependenciesSection(data),
|
|
15
34
|
buildSpecTagsSection(data),
|
|
35
|
+
similarSection,
|
|
16
36
|
buildSpecFooterSection(),
|
|
17
37
|
]
|
|
18
38
|
.filter(Boolean)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"executive-report.js","sourceRoot":"","sources":["../../../../src/engine/doc-generator/per-spec-report/executive-report.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAC9D,OAAO,EACL,sBAAsB,EACtB,uBAAuB,EACvB,4BAA4B,EAC5B,oBAAoB,EACpB,0BAA0B,EAC1B,sBAAsB,
|
|
1
|
+
{"version":3,"file":"executive-report.js","sourceRoot":"","sources":["../../../../src/engine/doc-generator/per-spec-report/executive-report.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAC9D,OAAO,EACL,sBAAsB,EACtB,uBAAuB,EACvB,4BAA4B,EAC5B,oBAAoB,EACpB,0BAA0B,EAC1B,sBAAsB,EACtB,8BAA8B,EAC9B,6BAA6B,EAC7B,kBAAkB,EAClB,sBAAsB,EACtB,wBAAwB,GACzB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEpD;;;;;GAKG;AACH,MAAM,UAAU,8BAA8B,CAC5C,IAAU,EACV,aAAuB,EACvB,sBAAgC;IAEhC,MAAM,IAAI,GAAG,kBAAkB,CAAC,IAAI,EAAE,aAAa,EAAE,sBAAsB,CAAC,CAAC;IAE7E,MAAM,cAAc,GAClB,IAAI,CAAC,OAAO,KAAK,SAAS;QACxB,CAAC,CAAC,6BAA6B,CAC3B,IAAI,CAAC,OAAO,EACZ,IAAI,CAAC,QAAQ,EACb,IAAI,CAAC,WAAW,EAChB,IAAI,CAAC,YAAY,CAClB;QACH,CAAC,CAAC,EAAE,CAAC;IAET,MAAM,SAAS,GACb,IAAI,CAAC,kBAAkB,KAAK,SAAS,IAAI,IAAI,CAAC,kBAAkB,CAAC,MAAM,GAAG,CAAC;QACzE,CAAC,CAAC,8BAA8B,CAAC,IAAI,CAAC,kBAAkB,CAAC;QACzD,CAAC,CAAC,EAAE,CAAC;IAET,MAAM,WAAW,GACf,IAAI,CAAC,aAAa,KAAK,SAAS,IAAI,IAAI,CAAC,aAAa,CAAC,MAAM,GAAG,CAAC;QAC/D,CAAC,CAAC,kBAAkB,CAAC,IAAI,CAAC,aAAa,CAAC;QACxC,CAAC,CAAC,EAAE,CAAC;IAET,MAAM,aAAa,GACjB,IAAI,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,sBAAsB,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAE/E,MAAM,cAAc,GAClB,IAAI,CAAC,YAAY,KAAK,SAAS,IAAI,IAAI,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC;QAC7D,CAAC,CAAC,wBAAwB,CAAC,IAAI,CAAC,YAAY,CAAC;QAC7C,CAAC,CAAC,EAAE,CAAC;IAET,MAAM,IAAI,GAAG;QACX,sBAAsB,CAAC,IAAI,CAAC;QAC5B,uBAAuB,CAAC,IAAI,CAAC;QAC7B,cAAc;QACd,0BAA0B,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,WAAW,CAAC;QAC3D,SAAS;QACT,WAAW;QACX,aAAa;QACb,4BAA4B,CAAC,IAAI,CAAC;QAClC,oBAAoB,CAAC,IAAI,CAAC;QAC1B,cAAc;QACd,sBAAsB,EAAE;KACzB;SACE,MAAM,CAAC,OAAO,CAAC;SACf,IAAI,CAAC,IAAI,CAAC,CAAC;IAEd,MAAM,KAAK,GAAG,sBAAsB,IAAI,CAAC,MAAM,KAAK,IAAI,CAAC,KAAK,EAAE,CAAC;IACjE,MAAM,OAAO,GAAG,eAAe,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IAE7C,OAAO;QACL,IAAI,EAAE,oBAAoB;QAC1B,KAAK;QACL,IAAI,EAAE,uBAAuB;QAC7B,OAAO;QACP,QAAQ,EAAE,aAAa;QACvB,QAAQ,EAAE,EAAE;QACZ,QAAQ,EAAE,EAAE;QACZ,YAAY,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC;KAC5B,CAAC;AACJ,CAAC"}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import type { PerSpecHtmlOptions } from '../../../types/docs.js';
|
|
2
|
+
export type { PerSpecHtmlOptions };
|
|
1
3
|
/**
|
|
2
|
-
* Wrap body content in a full HTML document with per-spec report CSS.
|
|
3
|
-
*
|
|
4
|
+
* Wrap body content in a full HTML document with per-spec report CSS + portal navbar.
|
|
5
|
+
* basePath is always "../../" because per-spec reports live in planu/specs/SPEC-XXX/.
|
|
4
6
|
*/
|
|
5
|
-
export declare function wrapPerSpecHtml(title: string, bodyContent: string,
|
|
7
|
+
export declare function wrapPerSpecHtml(title: string, bodyContent: string, extraScriptsOrOptions?: string | PerSpecHtmlOptions): string;
|
|
6
8
|
//# sourceMappingURL=html-wrapper.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"html-wrapper.d.ts","sourceRoot":"","sources":["../../../../src/engine/doc-generator/per-spec-report/html-wrapper.ts"],"names":[],"mappings":"AA+
|
|
1
|
+
{"version":3,"file":"html-wrapper.d.ts","sourceRoot":"","sources":["../../../../src/engine/doc-generator/per-spec-report/html-wrapper.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AA+BjE,YAAY,EAAE,kBAAkB,EAAE,CAAC;AAEnC;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,MAAM,EACnB,qBAAqB,CAAC,EAAE,MAAM,GAAG,kBAAkB,GAClD,MAAM,CA0CR"}
|
|
@@ -1,9 +1,12 @@
|
|
|
1
|
-
// Planu — HTML wrapper for per-spec reports (shared CSS)
|
|
1
|
+
// Planu — HTML wrapper for per-spec reports (shared CSS + portal navbar)
|
|
2
|
+
import { getPortalThemeCSS } from '../portal/portal-theme.js';
|
|
3
|
+
import { buildNavbar } from '../portal/portal-navbar.js';
|
|
4
|
+
import { buildBreadcrumbs } from '../portal/portal-breadcrumbs.js';
|
|
2
5
|
const CSS = `
|
|
3
6
|
@page { margin: 2cm; size: A4; }
|
|
4
7
|
@media print { print-color-adjust: exact; -webkit-print-color-adjust: exact; }
|
|
5
8
|
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
6
|
-
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; font-size: 14px; color: #1f2937; max-width:
|
|
9
|
+
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; font-size: 14px; color: #1f2937; max-width: 960px; margin: 0 auto; padding: 24px; background: #fff; }
|
|
7
10
|
.header { border-bottom: 3px solid #4F46E5; padding-bottom: 16px; margin-bottom: 24px; }
|
|
8
11
|
.header h1 { font-size: 1.1em; color: #6b7280; font-weight: 400; margin-bottom: 4px; }
|
|
9
12
|
.header h2 { font-size: 1.8em; color: #111827; font-weight: 700; }
|
|
@@ -28,24 +31,42 @@ const CSS = `
|
|
|
28
31
|
.footer { margin-top: 32px; padding-top: 16px; border-top: 1px solid #e5e7eb; font-size: 0.78em; color: #9ca3af; text-align: center; }
|
|
29
32
|
`;
|
|
30
33
|
/**
|
|
31
|
-
* Wrap body content in a full HTML document with per-spec report CSS.
|
|
32
|
-
*
|
|
34
|
+
* Wrap body content in a full HTML document with per-spec report CSS + portal navbar.
|
|
35
|
+
* basePath is always "../../" because per-spec reports live in planu/specs/SPEC-XXX/.
|
|
33
36
|
*/
|
|
34
|
-
export function wrapPerSpecHtml(title, bodyContent,
|
|
37
|
+
export function wrapPerSpecHtml(title, bodyContent, extraScriptsOrOptions) {
|
|
38
|
+
// Backward-compatible: accept plain string (extraScripts) or options object
|
|
39
|
+
let extraScripts;
|
|
40
|
+
let options = {};
|
|
41
|
+
if (typeof extraScriptsOrOptions === 'string') {
|
|
42
|
+
extraScripts = extraScriptsOrOptions;
|
|
43
|
+
}
|
|
44
|
+
else if (extraScriptsOrOptions !== undefined) {
|
|
45
|
+
options = extraScriptsOrOptions;
|
|
46
|
+
extraScripts = options.extraScripts;
|
|
47
|
+
}
|
|
35
48
|
const escapedTitle = title
|
|
36
49
|
.replace(/&/g, '&')
|
|
37
50
|
.replace(/</g, '<')
|
|
38
51
|
.replace(/>/g, '>')
|
|
39
52
|
.replace(/"/g, '"');
|
|
53
|
+
// Per-spec reports are always 2 levels deep: planu/specs/SPEC-XXX/report.html
|
|
54
|
+
const basePath = '../../';
|
|
55
|
+
const navbar = buildNavbar(options.activePage ?? 'dashboard', basePath, options.availablePages);
|
|
56
|
+
const breadcrumbsHtml = options.breadcrumbs && options.breadcrumbs.length > 0
|
|
57
|
+
? buildBreadcrumbs(options.breadcrumbs)
|
|
58
|
+
: '';
|
|
40
59
|
return `<!DOCTYPE html>
|
|
41
60
|
<html lang="en">
|
|
42
61
|
<head>
|
|
43
62
|
<meta charset="UTF-8"/>
|
|
44
63
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
|
45
64
|
<title>${escapedTitle}</title>
|
|
46
|
-
<style>${CSS}</style>
|
|
65
|
+
<style>${getPortalThemeCSS()}${CSS}</style>
|
|
47
66
|
</head>
|
|
48
67
|
<body>
|
|
68
|
+
${navbar}
|
|
69
|
+
${breadcrumbsHtml}
|
|
49
70
|
${bodyContent}
|
|
50
71
|
${extraScripts ?? ''}
|
|
51
72
|
</body>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"html-wrapper.js","sourceRoot":"","sources":["../../../../src/engine/doc-generator/per-spec-report/html-wrapper.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"html-wrapper.js","sourceRoot":"","sources":["../../../../src/engine/doc-generator/per-spec-report/html-wrapper.ts"],"names":[],"mappings":"AAAA,yEAAyE;AACzE,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AACzD,OAAO,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AAGnE,MAAM,GAAG,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2BX,CAAC;AAIF;;;GAGG;AACH,MAAM,UAAU,eAAe,CAC7B,KAAa,EACb,WAAmB,EACnB,qBAAmD;IAEnD,4EAA4E;IAC5E,IAAI,YAAgC,CAAC;IACrC,IAAI,OAAO,GAAuB,EAAE,CAAC;IAErC,IAAI,OAAO,qBAAqB,KAAK,QAAQ,EAAE,CAAC;QAC9C,YAAY,GAAG,qBAAqB,CAAC;IACvC,CAAC;SAAM,IAAI,qBAAqB,KAAK,SAAS,EAAE,CAAC;QAC/C,OAAO,GAAG,qBAAqB,CAAC;QAChC,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC;IACtC,CAAC;IAED,MAAM,YAAY,GAAG,KAAK;SACvB,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC;SACtB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IAE3B,8EAA8E;IAC9E,MAAM,QAAQ,GAAG,QAAQ,CAAC;IAC1B,MAAM,MAAM,GAAG,WAAW,CAAC,OAAO,CAAC,UAAU,IAAI,WAAW,EAAE,QAAQ,EAAE,OAAO,CAAC,cAAc,CAAC,CAAC;IAEhG,MAAM,eAAe,GACnB,OAAO,CAAC,WAAW,IAAI,OAAO,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC;QACnD,CAAC,CAAC,gBAAgB,CAAC,OAAO,CAAC,WAAW,CAAC;QACvC,CAAC,CAAC,EAAE,CAAC;IAET,OAAO;;;;;WAKE,YAAY;WACZ,iBAAiB,EAAE,GAAG,GAAG;;;EAGlC,MAAM;EACN,eAAe;EACf,WAAW;EACX,YAAY,IAAI,EAAE;;QAEZ,CAAC;AACT,CAAC"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Spec, PerSpecReportData } from '../../../types/index.js';
|
|
2
2
|
/**
|
|
3
3
|
* Extract report data from a single spec for HTML reports.
|
|
4
|
+
* Populates all available fields including impactAnalysis, actuals, etc.
|
|
4
5
|
*/
|
|
5
6
|
export declare function extractPerSpecData(spec: Spec, affectedFiles: string[], architecturalDecisions: string[]): PerSpecReportData;
|
|
6
7
|
//# sourceMappingURL=spec-data-extractor.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"spec-data-extractor.d.ts","sourceRoot":"","sources":["../../../../src/engine/doc-generator/per-spec-report/spec-data-extractor.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"spec-data-extractor.d.ts","sourceRoot":"","sources":["../../../../src/engine/doc-generator/per-spec-report/spec-data-extractor.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,IAAI,EACJ,iBAAiB,EAIlB,MAAM,yBAAyB,CAAC;AAEjC;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,IAAI,EACV,aAAa,EAAE,MAAM,EAAE,EACvB,sBAAsB,EAAE,MAAM,EAAE,GAC/B,iBAAiB,CAwBnB"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Extract report data from a single spec for HTML reports.
|
|
3
|
+
* Populates all available fields including impactAnalysis, actuals, etc.
|
|
3
4
|
*/
|
|
4
5
|
export function extractPerSpecData(spec, affectedFiles, architecturalDecisions) {
|
|
5
6
|
return {
|
|
@@ -21,6 +22,34 @@ export function extractPerSpecData(spec, affectedFiles, architecturalDecisions)
|
|
|
21
22
|
affectedFiles,
|
|
22
23
|
architecturalDecisions,
|
|
23
24
|
generatedAt: new Date().toISOString(),
|
|
25
|
+
impactAnalysis: extractImpactAnalysis(spec),
|
|
26
|
+
actuals: extractActuals(spec),
|
|
27
|
+
estimationReasoning: spec.estimation.tokenOptimization.reasoning || undefined,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
function extractImpactAnalysis(spec) {
|
|
31
|
+
if (!spec.impactAnalysis) {
|
|
32
|
+
return undefined;
|
|
33
|
+
}
|
|
34
|
+
const ia = spec.impactAnalysis;
|
|
35
|
+
return {
|
|
36
|
+
affectedModules: ia.affectedModules,
|
|
37
|
+
affectedFiles: ia.affectedFiles,
|
|
38
|
+
breakingChanges: ia.breakingChanges,
|
|
39
|
+
rollbackPlan: ia.rollbackPlan,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
function extractActuals(spec) {
|
|
43
|
+
if (!spec.actuals) {
|
|
44
|
+
return undefined;
|
|
45
|
+
}
|
|
46
|
+
const a = spec.actuals;
|
|
47
|
+
return {
|
|
48
|
+
devHours: a.devHours,
|
|
49
|
+
reviewHours: a.reviewHours,
|
|
50
|
+
totalCostUsd: a.totalCostUsd,
|
|
51
|
+
completedAt: a.completedAt,
|
|
52
|
+
notes: a.notes,
|
|
24
53
|
};
|
|
25
54
|
}
|
|
26
55
|
//# sourceMappingURL=spec-data-extractor.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"spec-data-extractor.js","sourceRoot":"","sources":["../../../../src/engine/doc-generator/per-spec-report/spec-data-extractor.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"spec-data-extractor.js","sourceRoot":"","sources":["../../../../src/engine/doc-generator/per-spec-report/spec-data-extractor.ts"],"names":[],"mappings":"AASA;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAChC,IAAU,EACV,aAAuB,EACvB,sBAAgC;IAEhC,OAAO;QACL,MAAM,EAAE,IAAI,CAAC,EAAE;QACf,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,UAAU,EAAE,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC;QACnC,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,QAAQ,EAAE,IAAI,CAAC,UAAU,CAAC,QAAQ;QAClC,WAAW,EAAE,IAAI,CAAC,UAAU,CAAC,WAAW;QACxC,YAAY,EAAE,IAAI,CAAC,UAAU,CAAC,YAAY;QAC1C,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,YAAY,EAAE,IAAI,CAAC,YAAY;QAC/B,SAAS,EAAE,IAAI,CAAC,SAAS;QACzB,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,SAAS,EAAE,IAAI,CAAC,SAAS;QACzB,QAAQ,EAAE,EAAmB;QAC7B,aAAa;QACb,sBAAsB;QACtB,WAAW,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACrC,cAAc,EAAE,qBAAqB,CAAC,IAAI,CAAC;QAC3C,OAAO,EAAE,cAAc,CAAC,IAAI,CAAC;QAC7B,mBAAmB,EAAE,IAAI,CAAC,UAAU,CAAC,iBAAiB,CAAC,SAAS,IAAI,SAAS;KAC9E,CAAC;AACJ,CAAC;AAED,SAAS,qBAAqB,CAAC,IAAU;IACvC,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,CAAC;QACzB,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,MAAM,EAAE,GAAG,IAAI,CAAC,cAAc,CAAC;IAC/B,OAAO;QACL,eAAe,EAAE,EAAE,CAAC,eAAe;QACnC,aAAa,EAAE,EAAE,CAAC,aAAa;QAC/B,eAAe,EAAE,EAAE,CAAC,eAAe;QACnC,YAAY,EAAE,EAAE,CAAC,YAAY;KAC9B,CAAC;AACJ,CAAC;AAED,SAAS,cAAc,CAAC,IAAU;IAChC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;QAClB,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,MAAM,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC;IACvB,OAAO;QACL,QAAQ,EAAE,CAAC,CAAC,QAAQ;QACpB,WAAW,EAAE,CAAC,CAAC,WAAW;QAC1B,YAAY,EAAE,CAAC,CAAC,YAAY;QAC5B,WAAW,EAAE,CAAC,CAAC,WAAW;QAC1B,KAAK,EAAE,CAAC,CAAC,KAAK;KACf,CAAC;AACJ,CAAC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { PerSpecReportData } from '../../../types/index.js';
|
|
1
|
+
import type { PerSpecReportData, PerSpecAcceptanceCriterion, PerSpecActuals, PerSpecImpactAnalysis, PerSpecLivingSpec, PerSpecRiskDimension } from '../../../types/index.js';
|
|
2
2
|
export declare function buildSpecHeaderSection(data: PerSpecReportData): string;
|
|
3
3
|
export declare function buildSpecMetricsSection(data: PerSpecReportData): string;
|
|
4
4
|
export declare function buildSpecDependenciesSection(data: PerSpecReportData): string;
|
|
@@ -7,4 +7,11 @@ export declare function buildEffortDistributionSvg(devHours: number, reviewHours
|
|
|
7
7
|
export declare function buildAffectedFilesSection(files: string[]): string;
|
|
8
8
|
export declare function buildArchDecisionsSection(decisions: string[]): string;
|
|
9
9
|
export declare function buildSpecFooterSection(): string;
|
|
10
|
+
export declare function buildAcceptanceCriteriaSection(criteria: PerSpecAcceptanceCriterion[]): string;
|
|
11
|
+
export declare function buildActualsComparisonSection(actuals: PerSpecActuals, devHours: number, reviewHours: number, totalCostUsd: number): string;
|
|
12
|
+
export declare function buildImpactAnalysisSection(impact: PerSpecImpactAnalysis): string;
|
|
13
|
+
export declare function buildRiskScorecard(risks: PerSpecRiskDimension[]): string;
|
|
14
|
+
export declare function buildLivingSpecSection(living: PerSpecLivingSpec): string;
|
|
15
|
+
export declare function buildEstimationReasoningSection(reasoning: string): string;
|
|
16
|
+
export declare function buildSimilarSpecsSection(similarSpecs: string[]): string;
|
|
10
17
|
//# sourceMappingURL=spec-section-builders.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"spec-section-builders.d.ts","sourceRoot":"","sources":["../../../../src/engine/doc-generator/per-spec-report/spec-section-builders.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"spec-section-builders.d.ts","sourceRoot":"","sources":["../../../../src/engine/doc-generator/per-spec-report/spec-section-builders.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,iBAAiB,EACjB,0BAA0B,EAC1B,cAAc,EACd,qBAAqB,EACrB,iBAAiB,EACjB,oBAAoB,EACrB,MAAM,yBAAyB,CAAC;AAUjC,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,iBAAiB,GAAG,MAAM,CAiBtE;AAED,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,iBAAiB,GAAG,MAAM,CAWvE;AAED,wBAAgB,4BAA4B,CAAC,IAAI,EAAE,iBAAiB,GAAG,MAAM,CAkB5E;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,iBAAiB,GAAG,MAAM,CAapE;AAED,wBAAgB,0BAA0B,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CAoBxF;AAED,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,CAWjE;AAED,wBAAgB,yBAAyB,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,MAAM,CAWrE;AAED,wBAAgB,sBAAsB,IAAI,MAAM,CAI/C;AAUD,wBAAgB,8BAA8B,CAAC,QAAQ,EAAE,0BAA0B,EAAE,GAAG,MAAM,CA8B7F;AAED,wBAAgB,6BAA6B,CAC3C,OAAO,EAAE,cAAc,EACvB,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,MAAM,GACnB,MAAM,CA0DR;AAED,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,qBAAqB,GAAG,MAAM,CA6BhF;AASD,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,oBAAoB,EAAE,GAAG,MAAM,CAgCxE;AAED,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,iBAAiB,GAAG,MAAM,CAexE;AAED,wBAAgB,+BAA+B,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAQzE;AAED,wBAAgB,wBAAwB,CAAC,YAAY,EAAE,MAAM,EAAE,GAAG,MAAM,CAWvE"}
|
|
@@ -105,6 +105,194 @@ export function buildSpecFooterSection() {
|
|
|
105
105
|
Generated by <strong>Planu</strong> — Spec Driven Development
|
|
106
106
|
</div>`;
|
|
107
107
|
}
|
|
108
|
+
// ── SPEC-139: Rich data section builders ──────────────────────────────────────
|
|
109
|
+
const AC_STATUS_CONFIG = {
|
|
110
|
+
met: { icon: '●', color: '#059669', label: 'Met' },
|
|
111
|
+
pending: { icon: '○', color: '#d97706', label: 'Pending' },
|
|
112
|
+
drift: { icon: '▲', color: '#dc2626', label: 'Drift' },
|
|
113
|
+
};
|
|
114
|
+
export function buildAcceptanceCriteriaSection(criteria) {
|
|
115
|
+
if (criteria.length === 0) {
|
|
116
|
+
return '';
|
|
117
|
+
}
|
|
118
|
+
const rows = criteria
|
|
119
|
+
.map((c) => {
|
|
120
|
+
const defaultAcConfig = { icon: '○', color: '#d97706', label: 'Pending' };
|
|
121
|
+
const cfg = AC_STATUS_CONFIG[c.status] ?? defaultAcConfig;
|
|
122
|
+
return `<tr>
|
|
123
|
+
<td style="padding:8px 12px;border-bottom:1px solid #e5e7eb;">${escapeHtml(c.criterion)}</td>
|
|
124
|
+
<td style="padding:8px 12px;border-bottom:1px solid #e5e7eb;white-space:nowrap;">
|
|
125
|
+
<span style="color:${cfg.color};font-weight:600;">${cfg.icon} ${escapeHtml(cfg.label)}</span>
|
|
126
|
+
</td>
|
|
127
|
+
</tr>`;
|
|
128
|
+
})
|
|
129
|
+
.join('\n');
|
|
130
|
+
return `<div class="section">
|
|
131
|
+
<h2>Acceptance Criteria</h2>
|
|
132
|
+
<table style="width:100%;border-collapse:collapse;font-size:14px;">
|
|
133
|
+
<thead>
|
|
134
|
+
<tr style="background:#f9fafb;">
|
|
135
|
+
<th style="padding:10px 12px;text-align:left;border-bottom:2px solid #e5e7eb;font-weight:600;">Criterion</th>
|
|
136
|
+
<th style="padding:10px 12px;text-align:left;border-bottom:2px solid #e5e7eb;font-weight:600;">Status</th>
|
|
137
|
+
</tr>
|
|
138
|
+
</thead>
|
|
139
|
+
<tbody>${rows}</tbody>
|
|
140
|
+
</table>
|
|
141
|
+
</div>`;
|
|
142
|
+
}
|
|
143
|
+
export function buildActualsComparisonSection(actuals, devHours, reviewHours, totalCostUsd) {
|
|
144
|
+
const devVariance = actuals.devHours - devHours;
|
|
145
|
+
const costVariance = actuals.totalCostUsd - totalCostUsd;
|
|
146
|
+
const devVariancePct = devHours > 0 ? Math.round((Math.abs(devVariance) / devHours) * 100) : 0;
|
|
147
|
+
const costVariancePct = totalCostUsd > 0 ? Math.round((Math.abs(costVariance) / totalCostUsd) * 100) : 0;
|
|
148
|
+
const devSign = devVariance >= 0 ? '+' : '-';
|
|
149
|
+
const costSign = costVariance >= 0 ? '+' : '-';
|
|
150
|
+
const devColor = devVariance > 0 ? '#dc2626' : '#059669';
|
|
151
|
+
const costColor = costVariance > 0 ? '#dc2626' : '#059669';
|
|
152
|
+
const completedDate = actuals.completedAt
|
|
153
|
+
? new Date(actuals.completedAt).toLocaleDateString('en-US', {
|
|
154
|
+
year: 'numeric',
|
|
155
|
+
month: 'long',
|
|
156
|
+
day: 'numeric',
|
|
157
|
+
})
|
|
158
|
+
: '—';
|
|
159
|
+
const notesRow = actuals.notes
|
|
160
|
+
? `<p style="margin-top:12px;font-size:13px;color:#6b7280;"><strong>Notes:</strong> ${escapeHtml(actuals.notes)}</p>`
|
|
161
|
+
: '';
|
|
162
|
+
return `<div class="section">
|
|
163
|
+
<h2>Estimated vs Actual</h2>
|
|
164
|
+
<p style="font-size:13px;color:#6b7280;margin-bottom:12px;">Completed: ${escapeHtml(completedDate)}</p>
|
|
165
|
+
<table style="width:100%;border-collapse:collapse;font-size:14px;">
|
|
166
|
+
<thead>
|
|
167
|
+
<tr style="background:#f9fafb;">
|
|
168
|
+
<th style="padding:10px 12px;text-align:left;border-bottom:2px solid #e5e7eb;font-weight:600;">Metric</th>
|
|
169
|
+
<th style="padding:10px 12px;text-align:right;border-bottom:2px solid #e5e7eb;font-weight:600;">Estimated</th>
|
|
170
|
+
<th style="padding:10px 12px;text-align:right;border-bottom:2px solid #e5e7eb;font-weight:600;">Actual</th>
|
|
171
|
+
<th style="padding:10px 12px;text-align:right;border-bottom:2px solid #e5e7eb;font-weight:600;">Variance</th>
|
|
172
|
+
</tr>
|
|
173
|
+
</thead>
|
|
174
|
+
<tbody>
|
|
175
|
+
<tr>
|
|
176
|
+
<td style="padding:8px 12px;border-bottom:1px solid #e5e7eb;">Dev Hours</td>
|
|
177
|
+
<td style="padding:8px 12px;border-bottom:1px solid #e5e7eb;text-align:right;">${String(devHours)}h</td>
|
|
178
|
+
<td style="padding:8px 12px;border-bottom:1px solid #e5e7eb;text-align:right;">${String(actuals.devHours)}h</td>
|
|
179
|
+
<td style="padding:8px 12px;border-bottom:1px solid #e5e7eb;text-align:right;color:${devColor};font-weight:600;">${devSign}${String(devVariancePct)}%</td>
|
|
180
|
+
</tr>
|
|
181
|
+
<tr>
|
|
182
|
+
<td style="padding:8px 12px;border-bottom:1px solid #e5e7eb;">Review Hours</td>
|
|
183
|
+
<td style="padding:8px 12px;border-bottom:1px solid #e5e7eb;text-align:right;">${String(reviewHours)}h</td>
|
|
184
|
+
<td style="padding:8px 12px;border-bottom:1px solid #e5e7eb;text-align:right;">${String(actuals.reviewHours)}h</td>
|
|
185
|
+
<td style="padding:8px 12px;border-bottom:1px solid #e5e7eb;text-align:right;color:#6b7280;">—</td>
|
|
186
|
+
</tr>
|
|
187
|
+
<tr>
|
|
188
|
+
<td style="padding:8px 12px;">Total Cost</td>
|
|
189
|
+
<td style="padding:8px 12px;text-align:right;">$${String(totalCostUsd)}</td>
|
|
190
|
+
<td style="padding:8px 12px;text-align:right;">$${String(actuals.totalCostUsd)}</td>
|
|
191
|
+
<td style="padding:8px 12px;text-align:right;color:${costColor};font-weight:600;">${costSign}${String(costVariancePct)}%</td>
|
|
192
|
+
</tr>
|
|
193
|
+
</tbody>
|
|
194
|
+
</table>
|
|
195
|
+
${notesRow}
|
|
196
|
+
</div>`;
|
|
197
|
+
}
|
|
198
|
+
export function buildImpactAnalysisSection(impact) {
|
|
199
|
+
const breakingBadge = impact.breakingChanges
|
|
200
|
+
? `<span style="background:#fee2e2;color:#dc2626;padding:2px 8px;border-radius:4px;font-size:12px;font-weight:600;">BREAKING CHANGES</span>`
|
|
201
|
+
: `<span style="background:#d1fae5;color:#059669;padding:2px 8px;border-radius:4px;font-size:12px;font-weight:600;">No Breaking Changes</span>`;
|
|
202
|
+
const modulesHtml = impact.affectedModules.length > 0
|
|
203
|
+
? `<p><strong>Affected Modules:</strong> ${impact.affectedModules.map(escapeHtml).join(', ')}</p>`
|
|
204
|
+
: '';
|
|
205
|
+
const filesHtml = impact.affectedFiles.length > 0
|
|
206
|
+
? `<p><strong>Affected Files (${String(impact.affectedFiles.length)}):</strong></p>
|
|
207
|
+
<ul style="font-size:13px;margin:4px 0 8px 0;">
|
|
208
|
+
${impact.affectedFiles.map((f) => `<li><code>${escapeHtml(f)}</code></li>`).join('\n ')}
|
|
209
|
+
</ul>`
|
|
210
|
+
: '';
|
|
211
|
+
const rollbackHtml = impact.rollbackPlan
|
|
212
|
+
? `<p><strong>Rollback Plan:</strong> ${escapeHtml(impact.rollbackPlan)}</p>`
|
|
213
|
+
: '';
|
|
214
|
+
return `<div class="section">
|
|
215
|
+
<h2>Impact Analysis</h2>
|
|
216
|
+
<p>${breakingBadge}</p>
|
|
217
|
+
${modulesHtml}
|
|
218
|
+
${filesHtml}
|
|
219
|
+
${rollbackHtml}
|
|
220
|
+
</div>`;
|
|
221
|
+
}
|
|
222
|
+
const RISK_LEVEL_COLORS = {
|
|
223
|
+
low: { bg: '#d1fae5', fg: '#065f46' },
|
|
224
|
+
medium: { bg: '#fef3c7', fg: '#92400e' },
|
|
225
|
+
high: { bg: '#fee2e2', fg: '#991b1b' },
|
|
226
|
+
critical: { bg: '#fce7f3', fg: '#9d174d' },
|
|
227
|
+
};
|
|
228
|
+
export function buildRiskScorecard(risks) {
|
|
229
|
+
if (risks.length === 0) {
|
|
230
|
+
return '';
|
|
231
|
+
}
|
|
232
|
+
const rows = risks
|
|
233
|
+
.map((r) => {
|
|
234
|
+
const defaultColors = { bg: '#e5e7eb', fg: '#374151' };
|
|
235
|
+
const colors = RISK_LEVEL_COLORS[r.level.toLowerCase()] ?? defaultColors;
|
|
236
|
+
return `<tr>
|
|
237
|
+
<td style="padding:8px 12px;border-bottom:1px solid #e5e7eb;font-weight:500;">${escapeHtml(r.dimension)}</td>
|
|
238
|
+
<td style="padding:8px 12px;border-bottom:1px solid #e5e7eb;">
|
|
239
|
+
<span style="background:${colors.bg};color:${colors.fg};padding:2px 8px;border-radius:4px;font-size:12px;font-weight:600;">${escapeHtml(r.level)}</span>
|
|
240
|
+
</td>
|
|
241
|
+
<td style="padding:8px 12px;border-bottom:1px solid #e5e7eb;font-size:13px;color:#6b7280;">${escapeHtml(r.detail)}</td>
|
|
242
|
+
</tr>`;
|
|
243
|
+
})
|
|
244
|
+
.join('\n');
|
|
245
|
+
return `<div class="section">
|
|
246
|
+
<h2>Risk Scorecard</h2>
|
|
247
|
+
<table style="width:100%;border-collapse:collapse;font-size:14px;">
|
|
248
|
+
<thead>
|
|
249
|
+
<tr style="background:#f9fafb;">
|
|
250
|
+
<th style="padding:10px 12px;text-align:left;border-bottom:2px solid #e5e7eb;font-weight:600;">Dimension</th>
|
|
251
|
+
<th style="padding:10px 12px;text-align:left;border-bottom:2px solid #e5e7eb;font-weight:600;">Level</th>
|
|
252
|
+
<th style="padding:10px 12px;text-align:left;border-bottom:2px solid #e5e7eb;font-weight:600;">Detail</th>
|
|
253
|
+
</tr>
|
|
254
|
+
</thead>
|
|
255
|
+
<tbody>${rows}</tbody>
|
|
256
|
+
</table>
|
|
257
|
+
</div>`;
|
|
258
|
+
}
|
|
259
|
+
export function buildLivingSpecSection(living) {
|
|
260
|
+
const pct = Math.min(100, Math.max(0, living.completionPercent));
|
|
261
|
+
const barColor = pct >= 80 ? '#059669' : pct >= 50 ? '#d97706' : '#dc2626';
|
|
262
|
+
const driftBadge = living.driftDetected
|
|
263
|
+
? `<span style="background:#fee2e2;color:#dc2626;padding:2px 8px;border-radius:4px;font-size:12px;font-weight:600;margin-left:8px;">DRIFT DETECTED</span>`
|
|
264
|
+
: `<span style="background:#d1fae5;color:#059669;padding:2px 8px;border-radius:4px;font-size:12px;font-weight:600;margin-left:8px;">In Sync</span>`;
|
|
265
|
+
return `<div class="section">
|
|
266
|
+
<h2>Living Spec Status</h2>
|
|
267
|
+
<p><strong>Completion:</strong> ${String(pct)}%${driftBadge}</p>
|
|
268
|
+
<div style="background:#e5e7eb;border-radius:8px;height:12px;width:100%;margin:8px 0;">
|
|
269
|
+
<div style="background:${barColor};border-radius:8px;height:12px;width:${String(pct)}%;transition:width 0.3s;"></div>
|
|
270
|
+
</div>
|
|
271
|
+
<p style="font-size:13px;color:#6b7280;">Changed files tracked: ${String(living.changedFileCount)}</p>
|
|
272
|
+
</div>`;
|
|
273
|
+
}
|
|
274
|
+
export function buildEstimationReasoningSection(reasoning) {
|
|
275
|
+
if (!reasoning) {
|
|
276
|
+
return '';
|
|
277
|
+
}
|
|
278
|
+
return `<div class="section">
|
|
279
|
+
<h2>Estimation Reasoning</h2>
|
|
280
|
+
<p style="font-size:14px;color:#374151;line-height:1.6;">${escapeHtml(reasoning)}</p>
|
|
281
|
+
</div>`;
|
|
282
|
+
}
|
|
283
|
+
export function buildSimilarSpecsSection(similarSpecs) {
|
|
284
|
+
if (similarSpecs.length === 0) {
|
|
285
|
+
return '';
|
|
286
|
+
}
|
|
287
|
+
const badges = similarSpecs
|
|
288
|
+
.map((s) => `<span class="badge badge-draft" style="margin-right:4px;">${escapeHtml(s)}</span>`)
|
|
289
|
+
.join('');
|
|
290
|
+
return `<div class="section">
|
|
291
|
+
<h2>Similar Specs</h2>
|
|
292
|
+
<p>${badges}</p>
|
|
293
|
+
</div>`;
|
|
294
|
+
}
|
|
295
|
+
// ── Internal helpers ──────────────────────────────────────────────────────────
|
|
108
296
|
function metricCard(value, label) {
|
|
109
297
|
return `<div class="metric-card">
|
|
110
298
|
<div class="metric-value">${escapeHtml(value)}</div>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"spec-section-builders.js","sourceRoot":"","sources":["../../../../src/engine/doc-generator/per-spec-report/spec-section-builders.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"spec-section-builders.js","sourceRoot":"","sources":["../../../../src/engine/doc-generator/per-spec-report/spec-section-builders.ts"],"names":[],"mappings":"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"}
|