@planu/cli 0.55.0 → 0.57.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 (190) hide show
  1. package/dist/config/license-plans.json +2 -0
  2. package/dist/engine/doc-generator/executive-summary/executive-summary-generator.d.ts +7 -1
  3. package/dist/engine/doc-generator/executive-summary/executive-summary-generator.d.ts.map +1 -1
  4. package/dist/engine/doc-generator/executive-summary/executive-summary-generator.js +16 -3
  5. package/dist/engine/doc-generator/executive-summary/executive-summary-generator.js.map +1 -1
  6. package/dist/engine/doc-generator/executive-summary/html-template.d.ts +5 -2
  7. package/dist/engine/doc-generator/executive-summary/html-template.d.ts.map +1 -1
  8. package/dist/engine/doc-generator/executive-summary/html-template.js +7 -3
  9. package/dist/engine/doc-generator/executive-summary/html-template.js.map +1 -1
  10. package/dist/engine/doc-generator/per-spec-report/html-wrapper.d.ts +5 -3
  11. package/dist/engine/doc-generator/per-spec-report/html-wrapper.d.ts.map +1 -1
  12. package/dist/engine/doc-generator/per-spec-report/html-wrapper.js +27 -6
  13. package/dist/engine/doc-generator/per-spec-report/html-wrapper.js.map +1 -1
  14. package/dist/engine/doc-generator/portal/analytics-page.d.ts +8 -0
  15. package/dist/engine/doc-generator/portal/analytics-page.d.ts.map +1 -0
  16. package/dist/engine/doc-generator/portal/analytics-page.js +265 -0
  17. package/dist/engine/doc-generator/portal/analytics-page.js.map +1 -0
  18. package/dist/engine/doc-generator/portal/architecture-page.d.ts +6 -0
  19. package/dist/engine/doc-generator/portal/architecture-page.d.ts.map +1 -0
  20. package/dist/engine/doc-generator/portal/architecture-page.js +250 -0
  21. package/dist/engine/doc-generator/portal/architecture-page.js.map +1 -0
  22. package/dist/engine/doc-generator/portal/changelog-page.d.ts +6 -0
  23. package/dist/engine/doc-generator/portal/changelog-page.d.ts.map +1 -0
  24. package/dist/engine/doc-generator/portal/changelog-page.js +204 -0
  25. package/dist/engine/doc-generator/portal/changelog-page.js.map +1 -0
  26. package/dist/engine/doc-generator/portal/data-aggregators/accuracy-aggregator.d.ts +11 -0
  27. package/dist/engine/doc-generator/portal/data-aggregators/accuracy-aggregator.d.ts.map +1 -0
  28. package/dist/engine/doc-generator/portal/data-aggregators/accuracy-aggregator.js +24 -0
  29. package/dist/engine/doc-generator/portal/data-aggregators/accuracy-aggregator.js.map +1 -0
  30. package/dist/engine/doc-generator/portal/data-aggregators/bottleneck-detector.d.ts +9 -0
  31. package/dist/engine/doc-generator/portal/data-aggregators/bottleneck-detector.d.ts.map +1 -0
  32. package/dist/engine/doc-generator/portal/data-aggregators/bottleneck-detector.js +31 -0
  33. package/dist/engine/doc-generator/portal/data-aggregators/bottleneck-detector.js.map +1 -0
  34. package/dist/engine/doc-generator/portal/data-aggregators/burndown-aggregator.d.ts +10 -0
  35. package/dist/engine/doc-generator/portal/data-aggregators/burndown-aggregator.d.ts.map +1 -0
  36. package/dist/engine/doc-generator/portal/data-aggregators/burndown-aggregator.js +77 -0
  37. package/dist/engine/doc-generator/portal/data-aggregators/burndown-aggregator.js.map +1 -0
  38. package/dist/engine/doc-generator/portal/data-aggregators/velocity-aggregator.d.ts +9 -0
  39. package/dist/engine/doc-generator/portal/data-aggregators/velocity-aggregator.d.ts.map +1 -0
  40. package/dist/engine/doc-generator/portal/data-aggregators/velocity-aggregator.js +31 -0
  41. package/dist/engine/doc-generator/portal/data-aggregators/velocity-aggregator.js.map +1 -0
  42. package/dist/engine/doc-generator/portal/decision-page.d.ts +6 -0
  43. package/dist/engine/doc-generator/portal/decision-page.d.ts.map +1 -0
  44. package/dist/engine/doc-generator/portal/decision-page.js +169 -0
  45. package/dist/engine/doc-generator/portal/decision-page.js.map +1 -0
  46. package/dist/engine/doc-generator/portal/decision-timeline-builder.d.ts +8 -0
  47. package/dist/engine/doc-generator/portal/decision-timeline-builder.d.ts.map +1 -0
  48. package/dist/engine/doc-generator/portal/decision-timeline-builder.js +131 -0
  49. package/dist/engine/doc-generator/portal/decision-timeline-builder.js.map +1 -0
  50. package/dist/engine/doc-generator/portal/index.d.ts +19 -0
  51. package/dist/engine/doc-generator/portal/index.d.ts.map +1 -0
  52. package/dist/engine/doc-generator/portal/index.js +21 -0
  53. package/dist/engine/doc-generator/portal/index.js.map +1 -0
  54. package/dist/engine/doc-generator/portal/kanban-view-builder.d.ts +8 -0
  55. package/dist/engine/doc-generator/portal/kanban-view-builder.d.ts.map +1 -0
  56. package/dist/engine/doc-generator/portal/kanban-view-builder.js +140 -0
  57. package/dist/engine/doc-generator/portal/kanban-view-builder.js.map +1 -0
  58. package/dist/engine/doc-generator/portal/portal-breadcrumbs.d.ts +27 -0
  59. package/dist/engine/doc-generator/portal/portal-breadcrumbs.d.ts.map +1 -0
  60. package/dist/engine/doc-generator/portal/portal-breadcrumbs.js +139 -0
  61. package/dist/engine/doc-generator/portal/portal-breadcrumbs.js.map +1 -0
  62. package/dist/engine/doc-generator/portal/portal-landing-cards.d.ts +8 -0
  63. package/dist/engine/doc-generator/portal/portal-landing-cards.d.ts.map +1 -0
  64. package/dist/engine/doc-generator/portal/portal-landing-cards.js +177 -0
  65. package/dist/engine/doc-generator/portal/portal-landing-cards.js.map +1 -0
  66. package/dist/engine/doc-generator/portal/portal-navbar.d.ts +15 -0
  67. package/dist/engine/doc-generator/portal/portal-navbar.d.ts.map +1 -0
  68. package/dist/engine/doc-generator/portal/portal-navbar.js +143 -0
  69. package/dist/engine/doc-generator/portal/portal-navbar.js.map +1 -0
  70. package/dist/engine/doc-generator/portal/portal-page-detector.d.ts +22 -0
  71. package/dist/engine/doc-generator/portal/portal-page-detector.d.ts.map +1 -0
  72. package/dist/engine/doc-generator/portal/portal-page-detector.js +58 -0
  73. package/dist/engine/doc-generator/portal/portal-page-detector.js.map +1 -0
  74. package/dist/engine/doc-generator/portal/portal-theme.d.ts +7 -0
  75. package/dist/engine/doc-generator/portal/portal-theme.d.ts.map +1 -0
  76. package/dist/engine/doc-generator/portal/portal-theme.js +53 -0
  77. package/dist/engine/doc-generator/portal/portal-theme.js.map +1 -0
  78. package/dist/engine/doc-generator/portal/risk-gauge-svg.d.ts +5 -0
  79. package/dist/engine/doc-generator/portal/risk-gauge-svg.d.ts.map +1 -0
  80. package/dist/engine/doc-generator/portal/risk-gauge-svg.js +80 -0
  81. package/dist/engine/doc-generator/portal/risk-gauge-svg.js.map +1 -0
  82. package/dist/engine/doc-generator/portal/risk-matrix-svg.d.ts +11 -0
  83. package/dist/engine/doc-generator/portal/risk-matrix-svg.d.ts.map +1 -0
  84. package/dist/engine/doc-generator/portal/risk-matrix-svg.js +181 -0
  85. package/dist/engine/doc-generator/portal/risk-matrix-svg.js.map +1 -0
  86. package/dist/engine/doc-generator/portal/risk-page.d.ts +7 -0
  87. package/dist/engine/doc-generator/portal/risk-page.d.ts.map +1 -0
  88. package/dist/engine/doc-generator/portal/risk-page.js +219 -0
  89. package/dist/engine/doc-generator/portal/risk-page.js.map +1 -0
  90. package/dist/engine/doc-generator/portal/roadmap-page.d.ts +7 -0
  91. package/dist/engine/doc-generator/portal/roadmap-page.d.ts.map +1 -0
  92. package/dist/engine/doc-generator/portal/roadmap-page.js +204 -0
  93. package/dist/engine/doc-generator/portal/roadmap-page.js.map +1 -0
  94. package/dist/engine/doc-generator/portal/svg-charts/bar-chart.d.ts +4 -0
  95. package/dist/engine/doc-generator/portal/svg-charts/bar-chart.d.ts.map +1 -0
  96. package/dist/engine/doc-generator/portal/svg-charts/bar-chart.js +50 -0
  97. package/dist/engine/doc-generator/portal/svg-charts/bar-chart.js.map +1 -0
  98. package/dist/engine/doc-generator/portal/svg-charts/chart-utils.d.ts +16 -0
  99. package/dist/engine/doc-generator/portal/svg-charts/chart-utils.d.ts.map +1 -0
  100. package/dist/engine/doc-generator/portal/svg-charts/chart-utils.js +45 -0
  101. package/dist/engine/doc-generator/portal/svg-charts/chart-utils.js.map +1 -0
  102. package/dist/engine/doc-generator/portal/svg-charts/line-chart.d.ts +16 -0
  103. package/dist/engine/doc-generator/portal/svg-charts/line-chart.d.ts.map +1 -0
  104. package/dist/engine/doc-generator/portal/svg-charts/line-chart.js +159 -0
  105. package/dist/engine/doc-generator/portal/svg-charts/line-chart.js.map +1 -0
  106. package/dist/engine/doc-generator/portal/svg-charts/pie-chart.d.ts +7 -0
  107. package/dist/engine/doc-generator/portal/svg-charts/pie-chart.d.ts.map +1 -0
  108. package/dist/engine/doc-generator/portal/svg-charts/pie-chart.js +52 -0
  109. package/dist/engine/doc-generator/portal/svg-charts/pie-chart.js.map +1 -0
  110. package/dist/engine/doc-generator/proposal/proposal-gantt-builder.d.ts +8 -0
  111. package/dist/engine/doc-generator/proposal/proposal-gantt-builder.d.ts.map +1 -0
  112. package/dist/engine/doc-generator/proposal/proposal-gantt-builder.js +126 -0
  113. package/dist/engine/doc-generator/proposal/proposal-gantt-builder.js.map +1 -0
  114. package/dist/engine/doc-generator/proposal/proposal-generator.d.ts +10 -0
  115. package/dist/engine/doc-generator/proposal/proposal-generator.d.ts.map +1 -0
  116. package/dist/engine/doc-generator/proposal/proposal-generator.js +93 -0
  117. package/dist/engine/doc-generator/proposal/proposal-generator.js.map +1 -0
  118. package/dist/engine/doc-generator/proposal/proposal-html-wrapper.d.ts +7 -0
  119. package/dist/engine/doc-generator/proposal/proposal-html-wrapper.d.ts.map +1 -0
  120. package/dist/engine/doc-generator/proposal/proposal-html-wrapper.js +31 -0
  121. package/dist/engine/doc-generator/proposal/proposal-html-wrapper.js.map +1 -0
  122. package/dist/engine/doc-generator/proposal/proposal-i18n.d.ts +12 -0
  123. package/dist/engine/doc-generator/proposal/proposal-i18n.d.ts.map +1 -0
  124. package/dist/engine/doc-generator/proposal/proposal-i18n.js +230 -0
  125. package/dist/engine/doc-generator/proposal/proposal-i18n.js.map +1 -0
  126. package/dist/engine/doc-generator/proposal/proposal-kpi-builder.d.ts +8 -0
  127. package/dist/engine/doc-generator/proposal/proposal-kpi-builder.d.ts.map +1 -0
  128. package/dist/engine/doc-generator/proposal/proposal-kpi-builder.js +32 -0
  129. package/dist/engine/doc-generator/proposal/proposal-kpi-builder.js.map +1 -0
  130. package/dist/engine/doc-generator/proposal/proposal-section-builders-advanced.d.ts +14 -0
  131. package/dist/engine/doc-generator/proposal/proposal-section-builders-advanced.d.ts.map +1 -0
  132. package/dist/engine/doc-generator/proposal/proposal-section-builders-advanced.js +248 -0
  133. package/dist/engine/doc-generator/proposal/proposal-section-builders-advanced.js.map +1 -0
  134. package/dist/engine/doc-generator/proposal/proposal-section-builders.d.ts +13 -0
  135. package/dist/engine/doc-generator/proposal/proposal-section-builders.d.ts.map +1 -0
  136. package/dist/engine/doc-generator/proposal/proposal-section-builders.js +423 -0
  137. package/dist/engine/doc-generator/proposal/proposal-section-builders.js.map +1 -0
  138. package/dist/engine/doc-generator/proposal/proposal-themes.d.ts +4 -0
  139. package/dist/engine/doc-generator/proposal/proposal-themes.d.ts.map +1 -0
  140. package/dist/engine/doc-generator/proposal/proposal-themes.js +194 -0
  141. package/dist/engine/doc-generator/proposal/proposal-themes.js.map +1 -0
  142. package/dist/engine/pdf/browser-finder.d.ts +5 -0
  143. package/dist/engine/pdf/browser-finder.d.ts.map +1 -0
  144. package/dist/engine/pdf/browser-finder.js +119 -0
  145. package/dist/engine/pdf/browser-finder.js.map +1 -0
  146. package/dist/engine/pdf/html-to-pdf.d.ts +3 -0
  147. package/dist/engine/pdf/html-to-pdf.d.ts.map +1 -0
  148. package/dist/engine/pdf/html-to-pdf.js +114 -0
  149. package/dist/engine/pdf/html-to-pdf.js.map +1 -0
  150. package/dist/engine/pdf/index.d.ts +6 -0
  151. package/dist/engine/pdf/index.d.ts.map +1 -0
  152. package/dist/engine/pdf/index.js +4 -0
  153. package/dist/engine/pdf/index.js.map +1 -0
  154. package/dist/engine/pdf/pdf-options.d.ts +6 -0
  155. package/dist/engine/pdf/pdf-options.d.ts.map +1 -0
  156. package/dist/engine/pdf/pdf-options.js +34 -0
  157. package/dist/engine/pdf/pdf-options.js.map +1 -0
  158. package/dist/engine/spec-summary-html.d.ts.map +1 -1
  159. package/dist/engine/spec-summary-html.js +17 -5
  160. package/dist/engine/spec-summary-html.js.map +1 -1
  161. package/dist/index.js +4 -0
  162. package/dist/index.js.map +1 -1
  163. package/dist/tools/export-pdf.d.ts +3 -0
  164. package/dist/tools/export-pdf.d.ts.map +1 -0
  165. package/dist/tools/export-pdf.js +82 -0
  166. package/dist/tools/export-pdf.js.map +1 -0
  167. package/dist/tools/generate-proposal.d.ts +3 -0
  168. package/dist/tools/generate-proposal.d.ts.map +1 -0
  169. package/dist/tools/generate-proposal.js +166 -0
  170. package/dist/tools/generate-proposal.js.map +1 -0
  171. package/dist/types/docs.d.ts +41 -0
  172. package/dist/types/docs.d.ts.map +1 -1
  173. package/dist/types/index.d.ts +1 -0
  174. package/dist/types/index.d.ts.map +1 -1
  175. package/dist/types/index.js +1 -0
  176. package/dist/types/index.js.map +1 -1
  177. package/dist/types/pdf.d.ts +42 -0
  178. package/dist/types/pdf.d.ts.map +1 -0
  179. package/dist/types/pdf.js +3 -0
  180. package/dist/types/pdf.js.map +1 -0
  181. package/dist/types/portal.d.ts +128 -0
  182. package/dist/types/portal.d.ts.map +1 -0
  183. package/dist/types/portal.js +3 -0
  184. package/dist/types/portal.js.map +1 -0
  185. package/dist/types/proposal.d.ts +57 -0
  186. package/dist/types/proposal.d.ts.map +1 -0
  187. package/dist/types/proposal.js +2 -0
  188. package/dist/types/proposal.js.map +1 -0
  189. package/package.json +1 -1
  190. package/src/config/license-plans.json +2 -0
@@ -0,0 +1,159 @@
1
+ import { scaleLinear, svgText, CHART_COLORS, escapeXml } from './chart-utils.js';
2
+ const PADDING = { top: 40, right: 20, bottom: 50, left: 50 };
3
+ /**
4
+ * Build a responsive SVG line chart for one or two series.
5
+ * When a second series is passed via options it is drawn with a dashed line.
6
+ * Returns empty string when points array is empty.
7
+ */
8
+ export function buildSvgLineChart(points, options) {
9
+ if (points.length === 0) {
10
+ return '';
11
+ }
12
+ const vbW = options?.width ?? 500;
13
+ const vbH = options?.height ?? 300;
14
+ const title = options?.title ?? '';
15
+ const showDots = options?.showDots ?? true;
16
+ const innerW = vbW - PADDING.left - PADDING.right;
17
+ const innerH = vbH - PADDING.top - PADDING.bottom;
18
+ const xs = points.map((p) => p.x);
19
+ const ys = points.map((p) => p.y);
20
+ const minX = Math.min(...xs);
21
+ const maxX = Math.max(...xs, minX + 1);
22
+ const maxY = Math.max(...ys, 1);
23
+ const xScale = scaleLinear([minX, maxX], [0, innerW]);
24
+ const yScale = scaleLinear([0, maxY], [innerH, 0]);
25
+ const color0 = CHART_COLORS[0] ?? '#e94560';
26
+ const pathD = points
27
+ .map((p, i) => {
28
+ const px = (PADDING.left + xScale(p.x)).toFixed(1);
29
+ const py = (PADDING.top + yScale(p.y)).toFixed(1);
30
+ return `${i === 0 ? 'M' : 'L'} ${px} ${py}`;
31
+ })
32
+ .join(' ');
33
+ const dotsHtml = showDots
34
+ ? points
35
+ .map((p) => {
36
+ const cx = (PADDING.left + xScale(p.x)).toFixed(1);
37
+ const cy = (PADDING.top + yScale(p.y)).toFixed(1);
38
+ const dotLabel = p.label
39
+ ? svgText(Number(cx), Number(cy) - 8, p.label, {
40
+ fontSize: 9,
41
+ anchor: 'middle',
42
+ fill: '#6b7280',
43
+ })
44
+ : '';
45
+ return `<circle cx="${cx}" cy="${cy}" r="4" fill="${escapeXml(color0)}"/>${dotLabel}`;
46
+ })
47
+ .join('\n ')
48
+ : '';
49
+ const yTicks = buildYTicks(maxY, innerW, PADDING, innerH, yScale);
50
+ const xTicks = buildXTicks(points, xScale, PADDING, vbH);
51
+ const titleEl = title
52
+ ? svgText(vbW / 2, 20, title, { fontSize: 13, anchor: 'middle', fill: '#1a1a2e' })
53
+ : '';
54
+ return `<svg viewBox="0 0 ${vbW} ${vbH}" xmlns="http://www.w3.org/2000/svg" style="width:100%;max-width:${vbW}px">
55
+ ${titleEl}
56
+ ${yTicks}
57
+ ${xTicks}
58
+ <path d="${pathD}" fill="none" stroke="${escapeXml(color0)}" stroke-width="2.5" stroke-linejoin="round"/>
59
+ ${dotsHtml}
60
+ <line x1="${PADDING.left}" y1="${PADDING.top}" x2="${PADDING.left}" y2="${PADDING.top + innerH}" stroke="#e9ecef" stroke-width="1"/>
61
+ <line x1="${PADDING.left}" y1="${PADDING.top + innerH}" x2="${PADDING.left + innerW}" y2="${PADDING.top + innerH}" stroke="#e9ecef" stroke-width="1"/>
62
+ </svg>`;
63
+ }
64
+ /**
65
+ * Build a dual-series SVG line chart (real vs ideal).
66
+ * Returns empty string when either series is empty.
67
+ */
68
+ export function buildSvgDualLineChart(series1, series2, options) {
69
+ if (series1.length === 0 && series2.length === 0) {
70
+ return '';
71
+ }
72
+ const vbW = options?.width ?? 500;
73
+ const vbH = options?.height ?? 300;
74
+ const title = options?.title ?? '';
75
+ const showDots = options?.showDots ?? true;
76
+ const innerW = vbW - PADDING.left - PADDING.right;
77
+ const innerH = vbH - PADDING.top - PADDING.bottom;
78
+ const allPoints = [...series1, ...series2];
79
+ const xs = allPoints.map((p) => p.x);
80
+ const ys = allPoints.map((p) => p.y);
81
+ const minX = Math.min(...xs, 0);
82
+ const maxX = Math.max(...xs, minX + 1);
83
+ const maxY = Math.max(...ys, 1);
84
+ const xScale = scaleLinear([minX, maxX], [0, innerW]);
85
+ const yScale = scaleLinear([0, maxY], [innerH, 0]);
86
+ const color0 = CHART_COLORS[0] ?? '#e94560';
87
+ const color1 = CHART_COLORS[1] ?? '#0891b2';
88
+ const makePath = (pts, color, dashed) => {
89
+ if (pts.length === 0) {
90
+ return '';
91
+ }
92
+ const d = pts
93
+ .map((p, i) => {
94
+ const px = (PADDING.left + xScale(p.x)).toFixed(1);
95
+ const py = (PADDING.top + yScale(p.y)).toFixed(1);
96
+ return `${i === 0 ? 'M' : 'L'} ${px} ${py}`;
97
+ })
98
+ .join(' ');
99
+ const dash = dashed ? ' stroke-dasharray="6 3"' : '';
100
+ return `<path d="${d}" fill="none" stroke="${escapeXml(color)}" stroke-width="2.5" stroke-linejoin="round"${dash}/>`;
101
+ };
102
+ const makeDots = (pts, color) => {
103
+ if (!showDots) {
104
+ return '';
105
+ }
106
+ return pts
107
+ .map((p) => {
108
+ const cx = (PADDING.left + xScale(p.x)).toFixed(1);
109
+ const cy = (PADDING.top + yScale(p.y)).toFixed(1);
110
+ return `<circle cx="${cx}" cy="${cy}" r="3" fill="${escapeXml(color)}"/>`;
111
+ })
112
+ .join('\n ');
113
+ };
114
+ const label1 = options?.label1 ?? 'Real';
115
+ const label2 = options?.label2 ?? 'Ideal';
116
+ const legendY = vbH - 8;
117
+ const legend = `${svgText(PADDING.left, legendY, label1, { fontSize: 10, anchor: 'start', fill: color0 })}
118
+ ${svgText(PADDING.left + 80, legendY, label2, { fontSize: 10, anchor: 'start', fill: color1 })}`;
119
+ const yTicks = buildYTicks(maxY, innerW, PADDING, innerH, yScale);
120
+ const titleEl = title
121
+ ? svgText(vbW / 2, 20, title, { fontSize: 13, anchor: 'middle', fill: '#1a1a2e' })
122
+ : '';
123
+ return `<svg viewBox="0 0 ${vbW} ${vbH}" xmlns="http://www.w3.org/2000/svg" style="width:100%;max-width:${vbW}px">
124
+ ${titleEl}
125
+ ${yTicks}
126
+ ${makePath(series1, color0, false)}
127
+ ${makePath(series2, color1, true)}
128
+ ${makeDots(series1, color0)}
129
+ ${makeDots(series2, color1)}
130
+ ${legend}
131
+ <line x1="${PADDING.left}" y1="${PADDING.top}" x2="${PADDING.left}" y2="${PADDING.top + innerH}" stroke="#e9ecef" stroke-width="1"/>
132
+ <line x1="${PADDING.left}" y1="${PADDING.top + innerH}" x2="${PADDING.left + innerW}" y2="${PADDING.top + innerH}" stroke="#e9ecef" stroke-width="1"/>
133
+ </svg>`;
134
+ }
135
+ function buildYTicks(maxVal, innerW, padding, _innerH, yScale) {
136
+ const tickCount = 4;
137
+ return Array.from({ length: tickCount + 1 }, (_, i) => {
138
+ const val = (maxVal / tickCount) * i;
139
+ const y = padding.top + yScale(val);
140
+ const label = Number.isInteger(val) ? String(val) : val.toFixed(1);
141
+ return `<line x1="${padding.left}" y1="${y.toFixed(1)}" x2="${(padding.left + innerW).toFixed(1)}" y2="${y.toFixed(1)}" stroke="#f3f4f6" stroke-width="1"/>
142
+ ${svgText(padding.left - 6, y + 4, label, { fontSize: 9, anchor: 'end', fill: '#9ca3af' })}`;
143
+ }).join('\n ');
144
+ }
145
+ function buildXTicks(points, xScale, padding, vbH) {
146
+ const maxTicks = 6;
147
+ const step = Math.max(1, Math.ceil(points.length / maxTicks));
148
+ return points
149
+ .filter((_, i) => i % step === 0)
150
+ .map((p) => {
151
+ const x = padding.left + xScale(p.x);
152
+ const y = vbH - padding.bottom + 14;
153
+ const lbl = p.label ?? String(p.x);
154
+ const short = lbl.length > 8 ? lbl.slice(0, 7) + '…' : lbl;
155
+ return svgText(x, y, short, { fontSize: 9, anchor: 'middle', fill: '#9ca3af' });
156
+ })
157
+ .join('\n ');
158
+ }
159
+ //# sourceMappingURL=line-chart.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"line-chart.js","sourceRoot":"","sources":["../../../../../src/engine/doc-generator/portal/svg-charts/line-chart.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import type { PieSlice } from '../../../../types/portal.js';
2
+ /**
3
+ * Build a responsive SVG pie chart.
4
+ * Returns empty string when slices array is empty or all values are zero.
5
+ */
6
+ export declare function buildSvgPieChart(slices: PieSlice[], size?: number): string;
7
+ //# sourceMappingURL=pie-chart.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pie-chart.d.ts","sourceRoot":"","sources":["../../../../../src/engine/doc-generator/portal/svg-charts/pie-chart.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,6BAA6B,CAAC;AAG5D;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,QAAQ,EAAE,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CA0D1E"}
@@ -0,0 +1,52 @@
1
+ import { svgText, escapeXml } from './chart-utils.js';
2
+ /**
3
+ * Build a responsive SVG pie chart.
4
+ * Returns empty string when slices array is empty or all values are zero.
5
+ */
6
+ export function buildSvgPieChart(slices, size) {
7
+ if (slices.length === 0) {
8
+ return '';
9
+ }
10
+ const total = slices.reduce((s, p) => s + p.value, 0);
11
+ if (total === 0) {
12
+ return '';
13
+ }
14
+ const vbSize = size ?? 220;
15
+ const cx = vbSize / 2;
16
+ const cy = vbSize / 2;
17
+ const r = (vbSize / 2) * 0.65;
18
+ let startAngle = -Math.PI / 2; // start at top
19
+ const paths = [];
20
+ for (const slice of slices) {
21
+ const angle = (slice.value / total) * 2 * Math.PI;
22
+ const endAngle = startAngle + angle;
23
+ const largeArc = angle > Math.PI ? 1 : 0;
24
+ const x1 = cx + r * Math.cos(startAngle);
25
+ const y1 = cy + r * Math.sin(startAngle);
26
+ const x2 = cx + r * Math.cos(endAngle);
27
+ const y2 = cy + r * Math.sin(endAngle);
28
+ const d = [
29
+ `M ${cx.toFixed(1)} ${cy.toFixed(1)}`,
30
+ `L ${x1.toFixed(2)} ${y1.toFixed(2)}`,
31
+ `A ${r.toFixed(1)} ${r.toFixed(1)} 0 ${largeArc} 1 ${x2.toFixed(2)} ${y2.toFixed(2)}`,
32
+ 'Z',
33
+ ].join(' ');
34
+ paths.push(`<path d="${d}" fill="${escapeXml(slice.color)}" stroke="white" stroke-width="1.5"/>`);
35
+ startAngle = endAngle;
36
+ }
37
+ // Legend below the pie
38
+ const legendItems = slices.map((s, i) => {
39
+ const lx = 8;
40
+ const ly = vbSize + 14 + i * 16;
41
+ const pct = ((s.value / total) * 100).toFixed(1);
42
+ const short = s.label.length > 20 ? s.label.slice(0, 19) + '…' : s.label;
43
+ return `<rect x="${lx}" y="${ly - 9}" width="10" height="10" fill="${escapeXml(s.color)}" rx="2"/>
44
+ ${svgText(lx + 14, ly, `${short}: ${pct}%`, { fontSize: 10, anchor: 'start', fill: '#4b5563' })}`;
45
+ });
46
+ const totalHeight = vbSize + 14 + slices.length * 16;
47
+ return `<svg viewBox="0 0 ${vbSize} ${totalHeight}" xmlns="http://www.w3.org/2000/svg" style="width:100%;max-width:${vbSize}px">
48
+ ${paths.join('\n ')}
49
+ ${legendItems.join('\n ')}
50
+ </svg>`;
51
+ }
52
+ //# sourceMappingURL=pie-chart.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pie-chart.js","sourceRoot":"","sources":["../../../../../src/engine/doc-generator/portal/svg-charts/pie-chart.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ import type { Spec } from '../../../types/index.js';
2
+ import type { ProposalPhase } from '../../../types/docs.js';
3
+ /**
4
+ * Build a CSS Grid Gantt chart from specs and optional phases.
5
+ * Returns an HTML string with the full Gantt visualization.
6
+ */
7
+ export declare function buildGanttChart(specs: Spec[], phases?: ProposalPhase[], _startDate?: string): string;
8
+ //# sourceMappingURL=proposal-gantt-builder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proposal-gantt-builder.d.ts","sourceRoot":"","sources":["../../../../src/engine/doc-generator/proposal/proposal-gantt-builder.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,yBAAyB,CAAC;AACpD,OAAO,KAAK,EAAE,aAAa,EAAY,MAAM,wBAAwB,CAAC;AA6FtE;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,KAAK,EAAE,IAAI,EAAE,EACb,MAAM,CAAC,EAAE,aAAa,EAAE,EACxB,UAAU,CAAC,EAAE,MAAM,GAClB,MAAM,CAyCR"}
@@ -0,0 +1,126 @@
1
+ const PHASE_COLORS = [
2
+ '#7c3aed',
3
+ '#0891b2',
4
+ '#059669',
5
+ '#d97706',
6
+ '#e94560',
7
+ '#6366f1',
8
+ '#0f766e',
9
+ '#b45309',
10
+ ];
11
+ /**
12
+ * Assign specs to weeks using a simple sequential schedule with parallelism.
13
+ * Each spec duration = ceil(totalHours / 40) weeks (1 week = 40 dev hours).
14
+ */
15
+ function assignWeeks(specs, phases) {
16
+ if (specs.length === 0) {
17
+ return [];
18
+ }
19
+ const phaseColorMap = new Map();
20
+ if (phases && phases.length > 0) {
21
+ phases.forEach((p, i) => {
22
+ phaseColorMap.set(p.name, PHASE_COLORS[i % PHASE_COLORS.length] ?? '#7c3aed');
23
+ });
24
+ }
25
+ let currentWeek = 1;
26
+ const rows = [];
27
+ const specWeekMap = new Map();
28
+ // Build dependency map
29
+ const specMap = new Map(specs.map((s) => [s.id, s]));
30
+ for (const spec of specs) {
31
+ const totalHours = spec.estimation.devHours + spec.estimation.reviewHours;
32
+ const durationWeeks = Math.max(1, Math.ceil(totalHours / 40));
33
+ // Determine start: after all dependencies
34
+ let startWeek = currentWeek;
35
+ for (const dep of spec.dependencies) {
36
+ const depEnd = specWeekMap.get(dep)?.end ?? 0;
37
+ startWeek = Math.max(startWeek, depEnd + 1);
38
+ }
39
+ if (!spec.dependencies.length) {
40
+ startWeek = currentWeek;
41
+ }
42
+ specWeekMap.set(spec.id, { start: startWeek, end: startWeek + durationWeeks - 1 });
43
+ // Find phase name
44
+ let phaseName = 'Default';
45
+ let color = PHASE_COLORS[0] ?? '#7c3aed';
46
+ if (phases && phases.length > 0) {
47
+ const foundPhase = phases.find((p) => p.specIds.includes(spec.id));
48
+ if (foundPhase) {
49
+ phaseName = foundPhase.name;
50
+ const phaseIdx = phases.indexOf(foundPhase);
51
+ color = foundPhase.color ?? PHASE_COLORS[phaseIdx % PHASE_COLORS.length] ?? '#7c3aed';
52
+ phaseColorMap.set(phaseName, color);
53
+ }
54
+ }
55
+ else {
56
+ // Color by index
57
+ const idx = rows.length;
58
+ color = PHASE_COLORS[idx % PHASE_COLORS.length] ?? '#7c3aed';
59
+ }
60
+ rows.push({
61
+ id: spec.id,
62
+ label: `${spec.id}: ${spec.title.length > 30 ? spec.title.slice(0, 30) + '…' : spec.title}`,
63
+ color,
64
+ startWeek,
65
+ durationWeeks,
66
+ phase: phaseName,
67
+ });
68
+ // Advance current week only when no dependencies (sequential default)
69
+ if (!spec.dependencies.length) {
70
+ currentWeek = startWeek + durationWeeks;
71
+ }
72
+ // Cross-dep: track if we need to reset
73
+ const depSpec = specMap.get(spec.id);
74
+ if (!depSpec?.dependencies.length) {
75
+ currentWeek = startWeek + durationWeeks;
76
+ }
77
+ }
78
+ return rows;
79
+ }
80
+ /**
81
+ * Build a CSS Grid Gantt chart from specs and optional phases.
82
+ * Returns an HTML string with the full Gantt visualization.
83
+ */
84
+ export function buildGanttChart(specs, phases, _startDate) {
85
+ if (specs.length === 0) {
86
+ return '';
87
+ }
88
+ const rows = assignWeeks(specs, phases);
89
+ if (rows.length === 0) {
90
+ return '';
91
+ }
92
+ const totalWeeks = Math.max(...rows.map((r) => r.startWeek + r.durationWeeks - 1), 4);
93
+ // Week headers
94
+ const weekHeaders = Array.from({ length: totalWeeks }, (_, i) => `<div class="gantt-week">W${String(i + 1)}</div>`).join('');
95
+ // Gantt rows
96
+ const ganttRows = rows.map((row) => {
97
+ const startPct = ((row.startWeek - 1) / totalWeeks) * 100;
98
+ const widthPct = (row.durationWeeks / totalWeeks) * 100;
99
+ return `<div class="gantt-row">
100
+ <div class="gantt-label" title="${escapeHtml(row.label)}">${escapeHtml(row.label)}</div>
101
+ <div class="gantt-track">
102
+ <div class="gantt-bar" style="left:${startPct.toFixed(1)}%;width:${widthPct.toFixed(1)}%;background:${escapeHtml(row.color)};">
103
+ ${String(row.durationWeeks)}w
104
+ </div>
105
+ </div>
106
+ </div>`;
107
+ });
108
+ return `<div class="gantt-container">
109
+ <div class="gantt-header">
110
+ <div class="gantt-header-label"></div>
111
+ <div class="gantt-header-weeks">${weekHeaders}</div>
112
+ </div>
113
+ <div class="gantt-grid">
114
+ ${ganttRows.join('\n')}
115
+ </div>
116
+ </div>`;
117
+ }
118
+ // Internal helper
119
+ function escapeHtml(str) {
120
+ return str
121
+ .replace(/&/g, '&amp;')
122
+ .replace(/</g, '&lt;')
123
+ .replace(/>/g, '&gt;')
124
+ .replace(/"/g, '&quot;');
125
+ }
126
+ //# sourceMappingURL=proposal-gantt-builder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proposal-gantt-builder.js","sourceRoot":"","sources":["../../../../src/engine/doc-generator/proposal/proposal-gantt-builder.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import type { ProposalData } from '../../../types/docs.js';
2
+ /** Canonical section IDs for includeSections / excludeSections filtering. */
3
+ export declare const SECTION_IDS: readonly ["hero", "executive-summary", "scope", "spec-breakdown", "timeline", "budget", "investment-summary", "architecture", "risk", "decisions", "impact-analysis", "gap-analysis", "team-resources", "pricing-methodology", "design-system", "quality-metrics", "living-spec", "assumptions", "alternatives", "post-launch", "module-mapping"];
4
+ /**
5
+ * Generate a self-contained HTML proposal document.
6
+ * All sections are conditional — empty string returned when data is insufficient.
7
+ * Sections can be filtered via ProposalConfig.includeSections / excludeSections.
8
+ */
9
+ export declare function generateProposal(data: ProposalData): string;
10
+ //# sourceMappingURL=proposal-generator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proposal-generator.d.ts","sourceRoot":"","sources":["../../../../src/engine/doc-generator/proposal/proposal-generator.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAa,MAAM,wBAAwB,CAAC;AA4BtE,6EAA6E;AAC7E,eAAO,MAAM,WAAW,mVAsBd,CAAC;AAwDX;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,YAAY,GAAG,MAAM,CAoB3D"}
@@ -0,0 +1,93 @@
1
+ import { buildHeroSection, buildExecutiveSummarySection, buildScopeSection, buildSpecBreakdownSection, buildTimelineSection, buildBudgetSection, buildInvestmentSummarySection, buildArchitectureSection, buildRiskSection, buildDecisionsSection, buildImpactAnalysisSection, buildGapAnalysisSection, buildTeamResourcesSection, buildPricingMethodologySection, buildDesignSystemSection, buildQualityMetricsSection, buildLivingSpecSection, buildAssumptionsSection, buildAlternativesSection, buildPostLaunchSection, buildModuleMappingSection, buildFooterSection, } from './proposal-section-builders.js';
2
+ import { wrapProposalHtml } from './proposal-html-wrapper.js';
3
+ /** Canonical section IDs for includeSections / excludeSections filtering. */
4
+ export const SECTION_IDS = [
5
+ 'hero',
6
+ 'executive-summary',
7
+ 'scope',
8
+ 'spec-breakdown',
9
+ 'timeline',
10
+ 'budget',
11
+ 'investment-summary',
12
+ 'architecture',
13
+ 'risk',
14
+ 'decisions',
15
+ 'impact-analysis',
16
+ 'gap-analysis',
17
+ 'team-resources',
18
+ 'pricing-methodology',
19
+ 'design-system',
20
+ 'quality-metrics',
21
+ 'living-spec',
22
+ 'assumptions',
23
+ 'alternatives',
24
+ 'post-launch',
25
+ 'module-mapping',
26
+ ];
27
+ /** Build a section filter based on include/exclude lists. */
28
+ function makeSectionFilter(include, exclude) {
29
+ if (include && include.length > 0) {
30
+ return (id) => include.includes(id);
31
+ }
32
+ if (exclude && exclude.length > 0) {
33
+ return (id) => !exclude.includes(id);
34
+ }
35
+ return () => true;
36
+ }
37
+ function buildCoreSections(data, isEnabled) {
38
+ return [
39
+ isEnabled('executive-summary') ? buildExecutiveSummarySection(data) : '',
40
+ isEnabled('scope') ? buildScopeSection(data) : '',
41
+ isEnabled('spec-breakdown') ? buildSpecBreakdownSection(data) : '',
42
+ isEnabled('timeline') ? buildTimelineSection(data) : '',
43
+ isEnabled('budget') ? buildBudgetSection(data) : '',
44
+ isEnabled('investment-summary') ? buildInvestmentSummarySection(data) : '',
45
+ isEnabled('architecture') ? buildArchitectureSection(data) : '',
46
+ isEnabled('risk') ? buildRiskSection(data) : '',
47
+ isEnabled('decisions') ? buildDecisionsSection(data) : '',
48
+ isEnabled('impact-analysis') ? buildImpactAnalysisSection(data) : '',
49
+ ];
50
+ }
51
+ function buildAdvancedSections(data, isEnabled) {
52
+ return [
53
+ isEnabled('gap-analysis') ? buildGapAnalysisSection(data) : '',
54
+ isEnabled('team-resources') ? buildTeamResourcesSection(data) : '',
55
+ isEnabled('pricing-methodology') ? buildPricingMethodologySection(data) : '',
56
+ isEnabled('design-system') ? buildDesignSystemSection(data) : '',
57
+ isEnabled('quality-metrics') ? buildQualityMetricsSection(data) : '',
58
+ isEnabled('living-spec') ? buildLivingSpecSection(data) : '',
59
+ isEnabled('assumptions') ? buildAssumptionsSection(data) : '',
60
+ isEnabled('alternatives') ? buildAlternativesSection(data) : '',
61
+ isEnabled('post-launch') ? buildPostLaunchSection(data) : '',
62
+ isEnabled('module-mapping') ? buildModuleMappingSection(data) : '',
63
+ ];
64
+ }
65
+ /** Build all content sections (everything except hero and footer). */
66
+ function buildContentSections(data, isEnabled) {
67
+ return [...buildCoreSections(data, isEnabled), ...buildAdvancedSections(data, isEnabled)]
68
+ .filter(Boolean)
69
+ .join('\n');
70
+ }
71
+ /**
72
+ * Generate a self-contained HTML proposal document.
73
+ * All sections are conditional — empty string returned when data is insufficient.
74
+ * Sections can be filtered via ProposalConfig.includeSections / excludeSections.
75
+ */
76
+ export function generateProposal(data) {
77
+ const { includeSections, excludeSections, theme, language } = data.config;
78
+ const isEnabled = makeSectionFilter(includeSections, excludeSections);
79
+ const hero = isEnabled('hero') ? buildHeroSection(data) : '';
80
+ const contentSections = buildContentSections(data, isEnabled);
81
+ const body = [
82
+ hero,
83
+ contentSections ? `<div class="content">\n${contentSections}\n</div>` : '',
84
+ buildFooterSection(data),
85
+ ]
86
+ .filter(Boolean)
87
+ .join('\n');
88
+ const docTitle = data.config.title ?? data.projectName;
89
+ const docTheme = theme ?? 'light';
90
+ const docLang = language ?? 'en';
91
+ return wrapProposalHtml(docTitle, body, docTheme, docLang);
92
+ }
93
+ //# sourceMappingURL=proposal-generator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proposal-generator.js","sourceRoot":"","sources":["../../../../src/engine/doc-generator/proposal/proposal-generator.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,gBAAgB,EAChB,4BAA4B,EAC5B,iBAAiB,EACjB,yBAAyB,EACzB,oBAAoB,EACpB,kBAAkB,EAClB,6BAA6B,EAC7B,wBAAwB,EACxB,gBAAgB,EAChB,qBAAqB,EACrB,0BAA0B,EAC1B,uBAAuB,EACvB,yBAAyB,EACzB,8BAA8B,EAC9B,wBAAwB,EACxB,0BAA0B,EAC1B,sBAAsB,EACtB,uBAAuB,EACvB,wBAAwB,EACxB,sBAAsB,EACtB,yBAAyB,EACzB,kBAAkB,GACnB,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAG9D,6EAA6E;AAC7E,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,MAAM;IACN,mBAAmB;IACnB,OAAO;IACP,gBAAgB;IAChB,UAAU;IACV,QAAQ;IACR,oBAAoB;IACpB,cAAc;IACd,MAAM;IACN,WAAW;IACX,iBAAiB;IACjB,cAAc;IACd,gBAAgB;IAChB,qBAAqB;IACrB,eAAe;IACf,iBAAiB;IACjB,aAAa;IACb,aAAa;IACb,cAAc;IACd,aAAa;IACb,gBAAgB;CACR,CAAC;AAEX,6DAA6D;AAC7D,SAAS,iBAAiB,CACxB,OAA6B,EAC7B,OAA6B;IAE7B,IAAI,OAAO,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAClC,OAAO,CAAC,EAAE,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;IACtC,CAAC;IACD,IAAI,OAAO,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAClC,OAAO,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;IACvC,CAAC;IACD,OAAO,GAAG,EAAE,CAAC,IAAI,CAAC;AACpB,CAAC;AAED,SAAS,iBAAiB,CAAC,IAAkB,EAAE,SAAqC;IAClF,OAAO;QACL,SAAS,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC,4BAA4B,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE;QACxE,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE;QACjD,SAAS,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,yBAAyB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE;QAClE,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,oBAAoB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE;QACvD,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,kBAAkB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE;QACnD,SAAS,CAAC,oBAAoB,CAAC,CAAC,CAAC,CAAC,6BAA6B,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE;QAC1E,SAAS,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,wBAAwB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE;QAC/D,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE;QAC/C,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,qBAAqB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE;QACzD,SAAS,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,0BAA0B,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE;KACrE,CAAC;AACJ,CAAC;AAED,SAAS,qBAAqB,CAC5B,IAAkB,EAClB,SAAqC;IAErC,OAAO;QACL,SAAS,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,uBAAuB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE;QAC9D,SAAS,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,yBAAyB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE;QAClE,SAAS,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC,8BAA8B,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE;QAC5E,SAAS,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,wBAAwB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE;QAChE,SAAS,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,0BAA0B,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE;QACpE,SAAS,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,sBAAsB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE;QAC5D,SAAS,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,uBAAuB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE;QAC7D,SAAS,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,wBAAwB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE;QAC/D,SAAS,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,sBAAsB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE;QAC5D,SAAS,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,yBAAyB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE;KACnE,CAAC;AACJ,CAAC;AAED,sEAAsE;AACtE,SAAS,oBAAoB,CAAC,IAAkB,EAAE,SAAqC;IACrF,OAAO,CAAC,GAAG,iBAAiB,CAAC,IAAI,EAAE,SAAS,CAAC,EAAE,GAAG,qBAAqB,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;SACtF,MAAM,CAAC,OAAO,CAAC;SACf,IAAI,CAAC,IAAI,CAAC,CAAC;AAChB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAkB;IACjD,MAAM,EAAE,eAAe,EAAE,eAAe,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC;IAC1E,MAAM,SAAS,GAAG,iBAAiB,CAAC,eAAe,EAAE,eAAe,CAAC,CAAC;IAEtE,MAAM,IAAI,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAC7D,MAAM,eAAe,GAAG,oBAAoB,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;IAE9D,MAAM,IAAI,GAAG;QACX,IAAI;QACJ,eAAe,CAAC,CAAC,CAAC,0BAA0B,eAAe,UAAU,CAAC,CAAC,CAAC,EAAE;QAC1E,kBAAkB,CAAC,IAAI,CAAC;KACzB;SACE,MAAM,CAAC,OAAO,CAAC;SACf,IAAI,CAAC,IAAI,CAAC,CAAC;IAEd,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,IAAI,IAAI,CAAC,WAAW,CAAC;IACvD,MAAM,QAAQ,GAAkB,KAAK,IAAI,OAAO,CAAC;IACjD,MAAM,OAAO,GAAG,QAAQ,IAAI,IAAI,CAAC;IAEjC,OAAO,gBAAgB,CAAC,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;AAC7D,CAAC"}
@@ -0,0 +1,7 @@
1
+ import { type ProposalTheme } from './proposal-themes.js';
2
+ /**
3
+ * Wrap body content in a full self-contained HTML document for the proposal.
4
+ * Includes inline CSS (theme), print styles, and responsive layout.
5
+ */
6
+ export declare function wrapProposalHtml(title: string, bodyContent: string, theme?: ProposalTheme, lang?: string): string;
7
+ //# sourceMappingURL=proposal-html-wrapper.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proposal-html-wrapper.d.ts","sourceRoot":"","sources":["../../../../src/engine/doc-generator/proposal/proposal-html-wrapper.ts"],"names":[],"mappings":"AACA,OAAO,EAAuB,KAAK,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAE/E;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,MAAM,EACnB,KAAK,GAAE,aAAuB,EAC9B,IAAI,SAAO,GACV,MAAM,CAsBR"}
@@ -0,0 +1,31 @@
1
+ // Planu — HTML wrapper for project proposal documents
2
+ import { getProposalThemeCSS } from './proposal-themes.js';
3
+ /**
4
+ * Wrap body content in a full self-contained HTML document for the proposal.
5
+ * Includes inline CSS (theme), print styles, and responsive layout.
6
+ */
7
+ export function wrapProposalHtml(title, bodyContent, theme = 'light', lang = 'en') {
8
+ const escapedTitle = title
9
+ .replace(/&/g, '&amp;')
10
+ .replace(/</g, '&lt;')
11
+ .replace(/>/g, '&gt;')
12
+ .replace(/"/g, '&quot;');
13
+ const css = getProposalThemeCSS(theme);
14
+ return `<!DOCTYPE html>
15
+ <html lang="${escapeAttr(lang)}">
16
+ <head>
17
+ <meta charset="UTF-8"/>
18
+ <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
19
+ <meta name="generator" content="Planu — Spec Driven Development"/>
20
+ <title>${escapedTitle}</title>
21
+ <style>${css}</style>
22
+ </head>
23
+ <body>
24
+ ${bodyContent}
25
+ </body>
26
+ </html>`;
27
+ }
28
+ function escapeAttr(str) {
29
+ return str.replace(/"/g, '&quot;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
30
+ }
31
+ //# sourceMappingURL=proposal-html-wrapper.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proposal-html-wrapper.js","sourceRoot":"","sources":["../../../../src/engine/doc-generator/proposal/proposal-html-wrapper.ts"],"names":[],"mappings":"AAAA,sDAAsD;AACtD,OAAO,EAAE,mBAAmB,EAAsB,MAAM,sBAAsB,CAAC;AAE/E;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAC9B,KAAa,EACb,WAAmB,EACnB,QAAuB,OAAO,EAC9B,IAAI,GAAG,IAAI;IAEX,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,MAAM,GAAG,GAAG,mBAAmB,CAAC,KAAK,CAAC,CAAC;IAEvC,OAAO;cACK,UAAU,CAAC,IAAI,CAAC;;;;;WAKnB,YAAY;WACZ,GAAG;;;EAGZ,WAAW;;QAEL,CAAC;AACT,CAAC;AAED,SAAS,UAAU,CAAC,GAAW;IAC7B,OAAO,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;AACjF,CAAC"}
@@ -0,0 +1,12 @@
1
+ import type { ProposalLang, TranslationKey } from '../../../types/docs.js';
2
+ export type { ProposalLang, TranslationKey };
3
+ /**
4
+ * Get all translation strings for the given language.
5
+ * Falls back to English for unknown keys.
6
+ */
7
+ export declare function getTranslations(lang?: string): Record<TranslationKey, string>;
8
+ /**
9
+ * Translate a single key.
10
+ */
11
+ export declare function t(lang: string, key: string): string;
12
+ //# sourceMappingURL=proposal-i18n.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proposal-i18n.d.ts","sourceRoot":"","sources":["../../../../src/engine/doc-generator/proposal/proposal-i18n.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAE3E,YAAY,EAAE,YAAY,EAAE,cAAc,EAAE,CAAC;AA6N7C;;;GAGG;AACH,wBAAgB,eAAe,CAAC,IAAI,SAAO,GAAG,MAAM,CAAC,cAAc,EAAE,MAAM,CAAC,CAE3E;AAED;;GAEG;AACH,wBAAgB,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAGnD"}