@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.
Files changed (178) hide show
  1. package/dist/config/license-plans.json +1 -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/executive-report.d.ts +3 -1
  11. package/dist/engine/doc-generator/per-spec-report/executive-report.d.ts.map +1 -1
  12. package/dist/engine/doc-generator/per-spec-report/executive-report.js +22 -2
  13. package/dist/engine/doc-generator/per-spec-report/executive-report.js.map +1 -1
  14. package/dist/engine/doc-generator/per-spec-report/html-wrapper.d.ts +5 -3
  15. package/dist/engine/doc-generator/per-spec-report/html-wrapper.d.ts.map +1 -1
  16. package/dist/engine/doc-generator/per-spec-report/html-wrapper.js +27 -6
  17. package/dist/engine/doc-generator/per-spec-report/html-wrapper.js.map +1 -1
  18. package/dist/engine/doc-generator/per-spec-report/spec-data-extractor.d.ts +1 -0
  19. package/dist/engine/doc-generator/per-spec-report/spec-data-extractor.d.ts.map +1 -1
  20. package/dist/engine/doc-generator/per-spec-report/spec-data-extractor.js +29 -0
  21. package/dist/engine/doc-generator/per-spec-report/spec-data-extractor.js.map +1 -1
  22. package/dist/engine/doc-generator/per-spec-report/spec-section-builders.d.ts +8 -1
  23. package/dist/engine/doc-generator/per-spec-report/spec-section-builders.d.ts.map +1 -1
  24. package/dist/engine/doc-generator/per-spec-report/spec-section-builders.js +188 -0
  25. package/dist/engine/doc-generator/per-spec-report/spec-section-builders.js.map +1 -1
  26. package/dist/engine/doc-generator/per-spec-report/technical-report.d.ts +3 -1
  27. package/dist/engine/doc-generator/per-spec-report/technical-report.d.ts.map +1 -1
  28. package/dist/engine/doc-generator/per-spec-report/technical-report.js +24 -7
  29. package/dist/engine/doc-generator/per-spec-report/technical-report.js.map +1 -1
  30. package/dist/engine/doc-generator/portal/analytics-page.d.ts +8 -0
  31. package/dist/engine/doc-generator/portal/analytics-page.d.ts.map +1 -0
  32. package/dist/engine/doc-generator/portal/analytics-page.js +265 -0
  33. package/dist/engine/doc-generator/portal/analytics-page.js.map +1 -0
  34. package/dist/engine/doc-generator/portal/architecture-page.d.ts +6 -0
  35. package/dist/engine/doc-generator/portal/architecture-page.d.ts.map +1 -0
  36. package/dist/engine/doc-generator/portal/architecture-page.js +250 -0
  37. package/dist/engine/doc-generator/portal/architecture-page.js.map +1 -0
  38. package/dist/engine/doc-generator/portal/changelog-page.d.ts +6 -0
  39. package/dist/engine/doc-generator/portal/changelog-page.d.ts.map +1 -0
  40. package/dist/engine/doc-generator/portal/changelog-page.js +204 -0
  41. package/dist/engine/doc-generator/portal/changelog-page.js.map +1 -0
  42. package/dist/engine/doc-generator/portal/data-aggregators/accuracy-aggregator.d.ts +11 -0
  43. package/dist/engine/doc-generator/portal/data-aggregators/accuracy-aggregator.d.ts.map +1 -0
  44. package/dist/engine/doc-generator/portal/data-aggregators/accuracy-aggregator.js +24 -0
  45. package/dist/engine/doc-generator/portal/data-aggregators/accuracy-aggregator.js.map +1 -0
  46. package/dist/engine/doc-generator/portal/data-aggregators/bottleneck-detector.d.ts +9 -0
  47. package/dist/engine/doc-generator/portal/data-aggregators/bottleneck-detector.d.ts.map +1 -0
  48. package/dist/engine/doc-generator/portal/data-aggregators/bottleneck-detector.js +31 -0
  49. package/dist/engine/doc-generator/portal/data-aggregators/bottleneck-detector.js.map +1 -0
  50. package/dist/engine/doc-generator/portal/data-aggregators/burndown-aggregator.d.ts +10 -0
  51. package/dist/engine/doc-generator/portal/data-aggregators/burndown-aggregator.d.ts.map +1 -0
  52. package/dist/engine/doc-generator/portal/data-aggregators/burndown-aggregator.js +77 -0
  53. package/dist/engine/doc-generator/portal/data-aggregators/burndown-aggregator.js.map +1 -0
  54. package/dist/engine/doc-generator/portal/data-aggregators/velocity-aggregator.d.ts +9 -0
  55. package/dist/engine/doc-generator/portal/data-aggregators/velocity-aggregator.d.ts.map +1 -0
  56. package/dist/engine/doc-generator/portal/data-aggregators/velocity-aggregator.js +31 -0
  57. package/dist/engine/doc-generator/portal/data-aggregators/velocity-aggregator.js.map +1 -0
  58. package/dist/engine/doc-generator/portal/decision-page.d.ts +6 -0
  59. package/dist/engine/doc-generator/portal/decision-page.d.ts.map +1 -0
  60. package/dist/engine/doc-generator/portal/decision-page.js +169 -0
  61. package/dist/engine/doc-generator/portal/decision-page.js.map +1 -0
  62. package/dist/engine/doc-generator/portal/decision-timeline-builder.d.ts +8 -0
  63. package/dist/engine/doc-generator/portal/decision-timeline-builder.d.ts.map +1 -0
  64. package/dist/engine/doc-generator/portal/decision-timeline-builder.js +131 -0
  65. package/dist/engine/doc-generator/portal/decision-timeline-builder.js.map +1 -0
  66. package/dist/engine/doc-generator/portal/index.d.ts +19 -0
  67. package/dist/engine/doc-generator/portal/index.d.ts.map +1 -0
  68. package/dist/engine/doc-generator/portal/index.js +21 -0
  69. package/dist/engine/doc-generator/portal/index.js.map +1 -0
  70. package/dist/engine/doc-generator/portal/kanban-view-builder.d.ts +8 -0
  71. package/dist/engine/doc-generator/portal/kanban-view-builder.d.ts.map +1 -0
  72. package/dist/engine/doc-generator/portal/kanban-view-builder.js +140 -0
  73. package/dist/engine/doc-generator/portal/kanban-view-builder.js.map +1 -0
  74. package/dist/engine/doc-generator/portal/portal-breadcrumbs.d.ts +27 -0
  75. package/dist/engine/doc-generator/portal/portal-breadcrumbs.d.ts.map +1 -0
  76. package/dist/engine/doc-generator/portal/portal-breadcrumbs.js +139 -0
  77. package/dist/engine/doc-generator/portal/portal-breadcrumbs.js.map +1 -0
  78. package/dist/engine/doc-generator/portal/portal-landing-cards.d.ts +8 -0
  79. package/dist/engine/doc-generator/portal/portal-landing-cards.d.ts.map +1 -0
  80. package/dist/engine/doc-generator/portal/portal-landing-cards.js +177 -0
  81. package/dist/engine/doc-generator/portal/portal-landing-cards.js.map +1 -0
  82. package/dist/engine/doc-generator/portal/portal-navbar.d.ts +15 -0
  83. package/dist/engine/doc-generator/portal/portal-navbar.d.ts.map +1 -0
  84. package/dist/engine/doc-generator/portal/portal-navbar.js +143 -0
  85. package/dist/engine/doc-generator/portal/portal-navbar.js.map +1 -0
  86. package/dist/engine/doc-generator/portal/portal-page-detector.d.ts +22 -0
  87. package/dist/engine/doc-generator/portal/portal-page-detector.d.ts.map +1 -0
  88. package/dist/engine/doc-generator/portal/portal-page-detector.js +58 -0
  89. package/dist/engine/doc-generator/portal/portal-page-detector.js.map +1 -0
  90. package/dist/engine/doc-generator/portal/portal-theme.d.ts +7 -0
  91. package/dist/engine/doc-generator/portal/portal-theme.d.ts.map +1 -0
  92. package/dist/engine/doc-generator/portal/portal-theme.js +53 -0
  93. package/dist/engine/doc-generator/portal/portal-theme.js.map +1 -0
  94. package/dist/engine/doc-generator/portal/risk-gauge-svg.d.ts +5 -0
  95. package/dist/engine/doc-generator/portal/risk-gauge-svg.d.ts.map +1 -0
  96. package/dist/engine/doc-generator/portal/risk-gauge-svg.js +80 -0
  97. package/dist/engine/doc-generator/portal/risk-gauge-svg.js.map +1 -0
  98. package/dist/engine/doc-generator/portal/risk-matrix-svg.d.ts +11 -0
  99. package/dist/engine/doc-generator/portal/risk-matrix-svg.d.ts.map +1 -0
  100. package/dist/engine/doc-generator/portal/risk-matrix-svg.js +181 -0
  101. package/dist/engine/doc-generator/portal/risk-matrix-svg.js.map +1 -0
  102. package/dist/engine/doc-generator/portal/risk-page.d.ts +7 -0
  103. package/dist/engine/doc-generator/portal/risk-page.d.ts.map +1 -0
  104. package/dist/engine/doc-generator/portal/risk-page.js +219 -0
  105. package/dist/engine/doc-generator/portal/risk-page.js.map +1 -0
  106. package/dist/engine/doc-generator/portal/roadmap-page.d.ts +7 -0
  107. package/dist/engine/doc-generator/portal/roadmap-page.d.ts.map +1 -0
  108. package/dist/engine/doc-generator/portal/roadmap-page.js +204 -0
  109. package/dist/engine/doc-generator/portal/roadmap-page.js.map +1 -0
  110. package/dist/engine/doc-generator/portal/svg-charts/bar-chart.d.ts +4 -0
  111. package/dist/engine/doc-generator/portal/svg-charts/bar-chart.d.ts.map +1 -0
  112. package/dist/engine/doc-generator/portal/svg-charts/bar-chart.js +50 -0
  113. package/dist/engine/doc-generator/portal/svg-charts/bar-chart.js.map +1 -0
  114. package/dist/engine/doc-generator/portal/svg-charts/chart-utils.d.ts +16 -0
  115. package/dist/engine/doc-generator/portal/svg-charts/chart-utils.d.ts.map +1 -0
  116. package/dist/engine/doc-generator/portal/svg-charts/chart-utils.js +45 -0
  117. package/dist/engine/doc-generator/portal/svg-charts/chart-utils.js.map +1 -0
  118. package/dist/engine/doc-generator/portal/svg-charts/line-chart.d.ts +16 -0
  119. package/dist/engine/doc-generator/portal/svg-charts/line-chart.d.ts.map +1 -0
  120. package/dist/engine/doc-generator/portal/svg-charts/line-chart.js +159 -0
  121. package/dist/engine/doc-generator/portal/svg-charts/line-chart.js.map +1 -0
  122. package/dist/engine/doc-generator/portal/svg-charts/pie-chart.d.ts +7 -0
  123. package/dist/engine/doc-generator/portal/svg-charts/pie-chart.d.ts.map +1 -0
  124. package/dist/engine/doc-generator/portal/svg-charts/pie-chart.js +52 -0
  125. package/dist/engine/doc-generator/portal/svg-charts/pie-chart.js.map +1 -0
  126. package/dist/engine/doc-generator/proposal/proposal-gantt-builder.d.ts +8 -0
  127. package/dist/engine/doc-generator/proposal/proposal-gantt-builder.d.ts.map +1 -0
  128. package/dist/engine/doc-generator/proposal/proposal-gantt-builder.js +126 -0
  129. package/dist/engine/doc-generator/proposal/proposal-gantt-builder.js.map +1 -0
  130. package/dist/engine/doc-generator/proposal/proposal-generator.d.ts +10 -0
  131. package/dist/engine/doc-generator/proposal/proposal-generator.d.ts.map +1 -0
  132. package/dist/engine/doc-generator/proposal/proposal-generator.js +93 -0
  133. package/dist/engine/doc-generator/proposal/proposal-generator.js.map +1 -0
  134. package/dist/engine/doc-generator/proposal/proposal-html-wrapper.d.ts +7 -0
  135. package/dist/engine/doc-generator/proposal/proposal-html-wrapper.d.ts.map +1 -0
  136. package/dist/engine/doc-generator/proposal/proposal-html-wrapper.js +31 -0
  137. package/dist/engine/doc-generator/proposal/proposal-html-wrapper.js.map +1 -0
  138. package/dist/engine/doc-generator/proposal/proposal-i18n.d.ts +12 -0
  139. package/dist/engine/doc-generator/proposal/proposal-i18n.d.ts.map +1 -0
  140. package/dist/engine/doc-generator/proposal/proposal-i18n.js +230 -0
  141. package/dist/engine/doc-generator/proposal/proposal-i18n.js.map +1 -0
  142. package/dist/engine/doc-generator/proposal/proposal-kpi-builder.d.ts +8 -0
  143. package/dist/engine/doc-generator/proposal/proposal-kpi-builder.d.ts.map +1 -0
  144. package/dist/engine/doc-generator/proposal/proposal-kpi-builder.js +32 -0
  145. package/dist/engine/doc-generator/proposal/proposal-kpi-builder.js.map +1 -0
  146. package/dist/engine/doc-generator/proposal/proposal-section-builders-advanced.d.ts +14 -0
  147. package/dist/engine/doc-generator/proposal/proposal-section-builders-advanced.d.ts.map +1 -0
  148. package/dist/engine/doc-generator/proposal/proposal-section-builders-advanced.js +248 -0
  149. package/dist/engine/doc-generator/proposal/proposal-section-builders-advanced.js.map +1 -0
  150. package/dist/engine/doc-generator/proposal/proposal-section-builders.d.ts +13 -0
  151. package/dist/engine/doc-generator/proposal/proposal-section-builders.d.ts.map +1 -0
  152. package/dist/engine/doc-generator/proposal/proposal-section-builders.js +423 -0
  153. package/dist/engine/doc-generator/proposal/proposal-section-builders.js.map +1 -0
  154. package/dist/engine/doc-generator/proposal/proposal-themes.d.ts +4 -0
  155. package/dist/engine/doc-generator/proposal/proposal-themes.d.ts.map +1 -0
  156. package/dist/engine/doc-generator/proposal/proposal-themes.js +194 -0
  157. package/dist/engine/doc-generator/proposal/proposal-themes.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 +2 -0
  162. package/dist/index.js.map +1 -1
  163. package/dist/tools/generate-proposal.d.ts +3 -0
  164. package/dist/tools/generate-proposal.d.ts.map +1 -0
  165. package/dist/tools/generate-proposal.js +166 -0
  166. package/dist/tools/generate-proposal.js.map +1 -0
  167. package/dist/types/docs.d.ts +75 -0
  168. package/dist/types/docs.d.ts.map +1 -1
  169. package/dist/types/portal.d.ts +128 -0
  170. package/dist/types/portal.d.ts.map +1 -0
  171. package/dist/types/portal.js +3 -0
  172. package/dist/types/portal.js.map +1 -0
  173. package/dist/types/proposal.d.ts +57 -0
  174. package/dist/types/proposal.d.ts.map +1 -0
  175. package/dist/types/proposal.js +2 -0
  176. package/dist/types/proposal.js.map +1 -0
  177. package/package.json +1 -1
  178. package/src/config/license-plans.json +1 -0
@@ -1,7 +1,9 @@
1
1
  import type { Spec, GeneratedDocument, SpecDiagram } from '../../../types/index.js';
2
2
  /**
3
3
  * Generate a self-contained HTML technical report for a single spec.
4
- * Includes: header, Mermaid diagrams, affected files, architectural decisions.
4
+ * Includes: header, scope, diagrams, impact analysis, affected files,
5
+ * architectural decisions, acceptance criteria, living spec, estimation reasoning.
6
+ * All rich sections are conditionally rendered based on data availability.
5
7
  */
6
8
  export declare function generatePerSpecTechnicalReport(spec: Spec, diagrams: SpecDiagram[], affectedFiles: string[], architecturalDecisions: string[]): GeneratedDocument;
7
9
  //# sourceMappingURL=technical-report.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"technical-report.d.ts","sourceRoot":"","sources":["../../../../src/engine/doc-generator/per-spec-report/technical-report.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAWpF;;;GAGG;AACH,wBAAgB,8BAA8B,CAC5C,IAAI,EAAE,IAAI,EACV,QAAQ,EAAE,WAAW,EAAE,EACvB,aAAa,EAAE,MAAM,EAAE,EACvB,sBAAsB,EAAE,MAAM,EAAE,GAC/B,iBAAiB,CAuCnB"}
1
+ {"version":3,"file":"technical-report.d.ts","sourceRoot":"","sources":["../../../../src/engine/doc-generator/per-spec-report/technical-report.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAepF;;;;;GAKG;AACH,wBAAgB,8BAA8B,CAC5C,IAAI,EAAE,IAAI,EACV,QAAQ,EAAE,WAAW,EAAE,EACvB,aAAa,EAAE,MAAM,EAAE,EACvB,sBAAsB,EAAE,MAAM,EAAE,GAC/B,iBAAiB,CAuDnB"}
@@ -1,27 +1,37 @@
1
1
  import { extractPerSpecData } from './spec-data-extractor.js';
2
- import { buildSpecHeaderSection, buildAffectedFilesSection, buildArchDecisionsSection, buildSpecFooterSection, } from './spec-section-builders.js';
2
+ import { buildSpecHeaderSection, buildAffectedFilesSection, buildArchDecisionsSection, buildSpecFooterSection, buildImpactAnalysisSection, buildEstimationReasoningSection, buildLivingSpecSection, buildAcceptanceCriteriaSection, } from './spec-section-builders.js';
3
3
  import { renderMermaidDiagrams, getMermaidScript } from './mermaid-renderer.js';
4
4
  import { wrapPerSpecHtml } from './html-wrapper.js';
5
5
  /**
6
6
  * Generate a self-contained HTML technical report for a single spec.
7
- * Includes: header, Mermaid diagrams, affected files, architectural decisions.
7
+ * Includes: header, scope, diagrams, impact analysis, affected files,
8
+ * architectural decisions, acceptance criteria, living spec, estimation reasoning.
9
+ * All rich sections are conditionally rendered based on data availability.
8
10
  */
9
11
  export function generatePerSpecTechnicalReport(spec, diagrams, affectedFiles, architecturalDecisions) {
10
12
  const data = extractPerSpecData(spec, affectedFiles, architecturalDecisions);
11
- const scopeInfo = `<div class="section">
12
- <h2>Scope</h2>
13
- <p><strong>Scope:</strong> ${escapeHtml(data.scope)} &middot; <strong>Target:</strong> ${escapeHtml(data.target)}</p>
14
- ${data.gitBranch ? `<p><strong>Branch:</strong> <code>${escapeHtml(data.gitBranch)}</code></p>` : ''}
15
- </div>`;
13
+ const scopeInfo = buildScopeSection(data.scope, data.target, data.gitBranch);
16
14
  const diagramsSection = diagrams.length > 0
17
15
  ? `<div class="section"><h2>Diagrams</h2>${renderMermaidDiagrams(diagrams)}</div>`
18
16
  : '';
17
+ const impactSection = data.impactAnalysis !== undefined ? buildImpactAnalysisSection(data.impactAnalysis) : '';
18
+ const acSection = data.acceptanceCriteria !== undefined && data.acceptanceCriteria.length > 0
19
+ ? buildAcceptanceCriteriaSection(data.acceptanceCriteria)
20
+ : '';
21
+ const livingSection = data.livingSpec !== undefined ? buildLivingSpecSection(data.livingSpec) : '';
22
+ const reasoningSection = data.estimationReasoning !== undefined && data.estimationReasoning.length > 0
23
+ ? buildEstimationReasoningSection(data.estimationReasoning)
24
+ : '';
19
25
  const body = [
20
26
  buildSpecHeaderSection(data),
21
27
  scopeInfo,
22
28
  diagramsSection,
29
+ impactSection,
23
30
  buildAffectedFilesSection(data.affectedFiles),
24
31
  buildArchDecisionsSection(data.architecturalDecisions),
32
+ acSection,
33
+ livingSection,
34
+ reasoningSection,
25
35
  buildSpecFooterSection(),
26
36
  ]
27
37
  .filter(Boolean)
@@ -40,6 +50,13 @@ export function generatePerSpecTechnicalReport(spec, diagrams, affectedFiles, ar
40
50
  relatedSpecs: [data.specId],
41
51
  };
42
52
  }
53
+ function buildScopeSection(scope, target, gitBranch) {
54
+ return `<div class="section">
55
+ <h2>Scope</h2>
56
+ <p><strong>Scope:</strong> ${escapeHtml(scope)} &middot; <strong>Target:</strong> ${escapeHtml(target)}</p>
57
+ ${gitBranch ? `<p><strong>Branch:</strong> <code>${escapeHtml(gitBranch)}</code></p>` : ''}
58
+ </div>`;
59
+ }
43
60
  function escapeHtml(str) {
44
61
  return str
45
62
  .replace(/&/g, '&amp;')
@@ -1 +1 @@
1
- {"version":3,"file":"technical-report.js","sourceRoot":"","sources":["../../../../src/engine/doc-generator/per-spec-report/technical-report.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAC9D,OAAO,EACL,sBAAsB,EACtB,yBAAyB,EACzB,yBAAyB,EACzB,sBAAsB,GACvB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAChF,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEpD;;;GAGG;AACH,MAAM,UAAU,8BAA8B,CAC5C,IAAU,EACV,QAAuB,EACvB,aAAuB,EACvB,sBAAgC;IAEhC,MAAM,IAAI,GAAG,kBAAkB,CAAC,IAAI,EAAE,aAAa,EAAE,sBAAsB,CAAC,CAAC;IAE7E,MAAM,SAAS,GAAG;;+BAEW,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,sCAAsC,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC;IAC9G,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,qCAAqC,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE;OAC/F,CAAC;IAEN,MAAM,eAAe,GACnB,QAAQ,CAAC,MAAM,GAAG,CAAC;QACjB,CAAC,CAAC,yCAAyC,qBAAqB,CAAC,QAAQ,CAAC,QAAQ;QAClF,CAAC,CAAC,EAAE,CAAC;IAET,MAAM,IAAI,GAAG;QACX,sBAAsB,CAAC,IAAI,CAAC;QAC5B,SAAS;QACT,eAAe;QACf,yBAAyB,CAAC,IAAI,CAAC,aAAa,CAAC;QAC7C,yBAAyB,CAAC,IAAI,CAAC,sBAAsB,CAAC;QACtD,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,aAAa,GAAG,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,gBAAgB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IACpE,MAAM,OAAO,GAAG,eAAe,CAAC,KAAK,EAAE,IAAI,EAAE,aAAa,CAAC,CAAC;IAE5D,OAAO;QACL,IAAI,EAAE,oBAAoB;QAC1B,KAAK;QACL,IAAI,EAAE,uBAAuB;QAC7B,OAAO;QACP,QAAQ,EAAE,WAAW;QACrB,QAAQ,EAAE,EAAE;QACZ,QAAQ;QACR,YAAY,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC;KAC5B,CAAC;AACJ,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
+ {"version":3,"file":"technical-report.js","sourceRoot":"","sources":["../../../../src/engine/doc-generator/per-spec-report/technical-report.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ import type { Spec } from '../../../types/index.js';
2
+ import type { MetricsHistory } from '../../../types/project/config-metrics.js';
3
+ /**
4
+ * Generate the full analytics.html page for the Planu portal.
5
+ * Returns an HTML string ready to write to disk.
6
+ */
7
+ export declare function generateAnalyticsPage(specs: Spec[], metrics?: MetricsHistory): string;
8
+ //# sourceMappingURL=analytics-page.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analytics-page.d.ts","sourceRoot":"","sources":["../../../../src/engine/doc-generator/portal/analytics-page.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,yBAAyB,CAAC;AACpD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0CAA0C,CAAC;AAa/E;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,MAAM,CAkDrF"}
@@ -0,0 +1,265 @@
1
+ import { getPortalThemeCSS } from './portal-theme.js';
2
+ import { buildNavbar } from './portal-navbar.js';
3
+ import { buildSvgBarChart } from './svg-charts/bar-chart.js';
4
+ import { buildSvgDualLineChart } from './svg-charts/line-chart.js';
5
+ import { buildSvgPieChart } from './svg-charts/pie-chart.js';
6
+ import { CHART_COLORS } from './svg-charts/chart-utils.js';
7
+ import { computeVelocity } from './data-aggregators/velocity-aggregator.js';
8
+ import { computeBurndown } from './data-aggregators/burndown-aggregator.js';
9
+ import { detectBottlenecks } from './data-aggregators/bottleneck-detector.js';
10
+ import { computeAccuracy } from './data-aggregators/accuracy-aggregator.js';
11
+ /**
12
+ * Generate the full analytics.html page for the Planu portal.
13
+ * Returns an HTML string ready to write to disk.
14
+ */
15
+ export function generateAnalyticsPage(specs, metrics) {
16
+ const navbar = buildNavbar('analytics', '', ['analytics', 'dashboard']);
17
+ const kpiHtml = buildKpiSection(specs);
18
+ const burndownHtml = buildBurndownSection(specs);
19
+ const velocityHtml = buildVelocitySection(specs);
20
+ const accuracyHtml = buildAccuracySection(specs, metrics);
21
+ const distributionHtml = buildDistributionSection(specs);
22
+ const bottleneckHtml = buildBottleneckSection(specs);
23
+ return `<!DOCTYPE html>
24
+ <html lang="en">
25
+ <head>
26
+ <meta charset="UTF-8"/>
27
+ <meta name="viewport" content="width=device-width,initial-scale=1"/>
28
+ <title>Analytics — Planu</title>
29
+ <style>
30
+ ${getPortalThemeCSS()}
31
+ ${ANALYTICS_CSS}
32
+ </style>
33
+ </head>
34
+ <body>
35
+ ${navbar}
36
+ <main class="analytics-main">
37
+ <h1 class="analytics-title">📈 Analytics</h1>
38
+ ${kpiHtml}
39
+ <div class="analytics-charts-row">
40
+ <section class="planu-card analytics-section">
41
+ <h2>Burn-down</h2>
42
+ ${burndownHtml}
43
+ </section>
44
+ <section class="planu-card analytics-section">
45
+ <h2>Velocity</h2>
46
+ ${velocityHtml}
47
+ </section>
48
+ </div>
49
+ <section class="planu-card analytics-section">
50
+ <h2>Estimated vs Actual Hours</h2>
51
+ ${accuracyHtml}
52
+ </section>
53
+ <section class="planu-card analytics-section">
54
+ <h2>Distribution</h2>
55
+ ${distributionHtml}
56
+ </section>
57
+ <section class="planu-card analytics-section">
58
+ <h2>Bottlenecks</h2>
59
+ ${bottleneckHtml}
60
+ </section>
61
+ </main>
62
+ </body>
63
+ </html>`;
64
+ }
65
+ // --- Section builders ---
66
+ function buildKpiSection(specs) {
67
+ if (specs.length === 0) {
68
+ return '<p class="analytics-empty">No specs available.</p>';
69
+ }
70
+ const total = specs.length;
71
+ const done = specs.filter((s) => s.status === 'done').length;
72
+ const pct = total > 0 ? Math.round((done / total) * 100) : 0;
73
+ const accuracyRecords = computeAccuracy(specs);
74
+ const avgAccuracy = accuracyRecords.length > 0
75
+ ? Math.round(accuracyRecords.reduce((s, r) => s + r.accuracy, 0) / accuracyRecords.length)
76
+ : 0;
77
+ const totalHours = specs.reduce((s, sp) => s + sp.estimation.devHours, 0);
78
+ const velocity = computeVelocity(specs);
79
+ const avgVelocity = velocity.length > 0
80
+ ? Math.round(velocity.reduce((s, v) => s + v.count, 0) / velocity.length)
81
+ : 0;
82
+ const kpis = [
83
+ { label: 'Total Specs', value: String(total), icon: '📋' },
84
+ { label: 'Done', value: String(done), icon: '✅' },
85
+ { label: 'Completion', value: `${pct}%`, icon: '📊' },
86
+ { label: 'Avg Accuracy', value: `${avgAccuracy}%`, icon: '🎯' },
87
+ { label: 'Total Hours', value: String(totalHours), icon: '⏱️' },
88
+ { label: 'Avg Velocity', value: `${avgVelocity}/mo`, icon: '🚀' },
89
+ ];
90
+ const cards = kpis
91
+ .map((k) => `<div class="kpi-card planu-card">
92
+ <div class="kpi-icon">${k.icon}</div>
93
+ <div class="kpi-value">${escapeHtml(k.value)}</div>
94
+ <div class="kpi-label">${escapeHtml(k.label)}</div>
95
+ </div>`)
96
+ .join('\n');
97
+ return `<div class="kpi-row">${cards}</div>`;
98
+ }
99
+ function buildBurndownSection(specs) {
100
+ const points = computeBurndown(specs);
101
+ if (points.length === 0) {
102
+ return '<p class="analytics-empty">Insufficient data for burndown.</p>';
103
+ }
104
+ const series1 = points.map((p, i) => ({ x: i, y: p.remaining, label: p.date }));
105
+ const series2 = points.map((p, i) => ({ x: i, y: p.ideal }));
106
+ return buildSvgDualLineChart(series1, series2, {
107
+ title: 'Remaining vs Ideal',
108
+ label1: 'Remaining',
109
+ label2: 'Ideal',
110
+ showDots: false,
111
+ });
112
+ }
113
+ function buildVelocitySection(specs) {
114
+ const velocity = computeVelocity(specs);
115
+ if (velocity.length === 0) {
116
+ return '<p class="analytics-empty">No completed specs with dates.</p>';
117
+ }
118
+ const data = velocity.map((v, i) => ({
119
+ label: v.period,
120
+ value: v.count,
121
+ color: CHART_COLORS[i % CHART_COLORS.length],
122
+ }));
123
+ return buildSvgBarChart(data, { title: 'Specs Completed per Month' });
124
+ }
125
+ function buildAccuracySection(specs, _metrics) {
126
+ const records = computeAccuracy(specs);
127
+ if (records.length === 0) {
128
+ return '<p class="analytics-empty">No completed specs with estimation data.</p>';
129
+ }
130
+ const estimated = records.map((r) => ({
131
+ label: r.specId,
132
+ value: r.estimated,
133
+ color: CHART_COLORS[0],
134
+ }));
135
+ const actual = records.map((r) => ({
136
+ label: r.specId,
137
+ value: r.actual,
138
+ color: CHART_COLORS[1],
139
+ }));
140
+ const estSvg = buildSvgBarChart(estimated, { title: 'Estimated Hours' });
141
+ const actSvg = buildSvgBarChart(actual, { title: 'Actual Hours' });
142
+ return `<div class="analytics-charts-row">${estSvg}${actSvg}</div>`;
143
+ }
144
+ function buildDistributionSection(specs) {
145
+ if (specs.length === 0) {
146
+ return '<p class="analytics-empty">No specs to distribute.</p>';
147
+ }
148
+ const byType = countBy(specs, (s) => s.type);
149
+ const byRisk = countBy(specs, (s) => s.risk);
150
+ const byDifficulty = countBy(specs, (s) => String(s.difficulty));
151
+ const typePie = buildSvgPieChart(mapToPieSlices(byType));
152
+ const riskPie = buildSvgPieChart(mapToPieSlices(byRisk));
153
+ const diffPie = buildSvgPieChart(mapToPieSlices(byDifficulty));
154
+ return `<div class="distribution-row">
155
+ <div class="distribution-col">
156
+ <h3>By Type</h3>${typePie}
157
+ </div>
158
+ <div class="distribution-col">
159
+ <h3>By Risk</h3>${riskPie}
160
+ </div>
161
+ <div class="distribution-col">
162
+ <h3>By Difficulty</h3>${diffPie}
163
+ </div>
164
+ </div>`;
165
+ }
166
+ function buildBottleneckSection(specs) {
167
+ const bottlenecks = detectBottlenecks(specs);
168
+ if (bottlenecks.length === 0) {
169
+ return '<p class="analytics-empty">No bottlenecks detected. 🎉</p>';
170
+ }
171
+ const rows = bottlenecks.map((b) => {
172
+ const badgeClass = b.staleDays > 30 ? 'planu-badge-danger' : 'planu-badge-warning';
173
+ return `<tr>
174
+ <td>${escapeHtml(b.specId)}</td>
175
+ <td>${escapeHtml(b.title)}</td>
176
+ <td><span class="planu-badge planu-badge-muted">${escapeHtml(b.status)}</span></td>
177
+ <td><span class="planu-badge ${badgeClass}">${b.staleDays}d</span></td>
178
+ </tr>`;
179
+ });
180
+ return `<table class="bottleneck-table">
181
+ <thead>
182
+ <tr><th>ID</th><th>Title</th><th>Status</th><th>Stale</th></tr>
183
+ </thead>
184
+ <tbody>
185
+ ${rows.join('\n')}
186
+ </tbody>
187
+ </table>`;
188
+ }
189
+ // --- Helpers ---
190
+ function countBy(arr, key) {
191
+ const map = new Map();
192
+ for (const item of arr) {
193
+ const k = key(item);
194
+ map.set(k, (map.get(k) ?? 0) + 1);
195
+ }
196
+ return map;
197
+ }
198
+ function mapToPieSlices(counts) {
199
+ return Array.from(counts.entries()).map(([label, value], i) => ({
200
+ label,
201
+ value,
202
+ color: CHART_COLORS[i % CHART_COLORS.length] ?? '#e94560',
203
+ }));
204
+ }
205
+ function escapeHtml(str) {
206
+ return str
207
+ .replace(/&/g, '&amp;')
208
+ .replace(/</g, '&lt;')
209
+ .replace(/>/g, '&gt;')
210
+ .replace(/"/g, '&quot;');
211
+ }
212
+ const ANALYTICS_CSS = `
213
+ .analytics-main {
214
+ max-width: 1100px;
215
+ margin: 0 auto;
216
+ padding: 0 16px 40px;
217
+ }
218
+ .analytics-title { font-size: 1.5rem; color: var(--planu-primary); margin-bottom: 20px; }
219
+ .analytics-empty { color: #9ca3af; font-style: italic; padding: 12px 0; }
220
+ .analytics-section { margin-bottom: 24px; }
221
+ .analytics-section h2 {
222
+ font-size: 1.05rem;
223
+ color: var(--planu-secondary);
224
+ margin-bottom: 14px;
225
+ border-bottom: 1px solid var(--planu-border);
226
+ padding-bottom: 6px;
227
+ }
228
+ .analytics-charts-row {
229
+ display: grid;
230
+ grid-template-columns: 1fr 1fr;
231
+ gap: 16px;
232
+ margin-bottom: 24px;
233
+ }
234
+ @media (max-width: 700px) { .analytics-charts-row { grid-template-columns: 1fr; } }
235
+ .kpi-row {
236
+ display: grid;
237
+ grid-template-columns: repeat(6, 1fr);
238
+ gap: 12px;
239
+ margin-bottom: 24px;
240
+ }
241
+ @media (max-width: 900px) { .kpi-row { grid-template-columns: repeat(3, 1fr); } }
242
+ @media (max-width: 500px) { .kpi-row { grid-template-columns: repeat(2, 1fr); } }
243
+ .kpi-card { text-align: center; padding: 14px 10px; }
244
+ .kpi-icon { font-size: 1.6rem; margin-bottom: 4px; }
245
+ .kpi-value { font-size: 1.5rem; font-weight: 700; color: var(--planu-primary); }
246
+ .kpi-label { font-size: 0.75rem; color: #6b7280; margin-top: 2px; }
247
+ .distribution-row {
248
+ display: grid;
249
+ grid-template-columns: repeat(3, 1fr);
250
+ gap: 16px;
251
+ }
252
+ @media (max-width: 700px) { .distribution-row { grid-template-columns: 1fr; } }
253
+ .distribution-col h3 { font-size: 0.9rem; color: #4b5563; margin-bottom: 8px; text-align: center; }
254
+ .bottleneck-table { width: 100%; border-collapse: collapse; font-size: 0.85rem; }
255
+ .bottleneck-table th {
256
+ background: #f3f4f6;
257
+ text-align: left;
258
+ padding: 8px 10px;
259
+ font-size: 0.8rem;
260
+ color: #6b7280;
261
+ }
262
+ .bottleneck-table td { padding: 8px 10px; border-bottom: 1px solid #f3f4f6; }
263
+ @media print { .analytics-charts-row { grid-template-columns: 1fr; } }
264
+ `;
265
+ //# sourceMappingURL=analytics-page.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analytics-page.js","sourceRoot":"","sources":["../../../../src/engine/doc-generator/portal/analytics-page.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import type { ProjectKnowledge } from '../../../types/project/core.js';
2
+ /**
3
+ * Generate the architecture.html portal page.
4
+ */
5
+ export declare function generateArchitecturePage(knowledge: ProjectKnowledge): string;
6
+ //# sourceMappingURL=architecture-page.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"architecture-page.d.ts","sourceRoot":"","sources":["../../../../src/engine/doc-generator/portal/architecture-page.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAc,MAAM,gCAAgC,CAAC;AAuPnF;;GAEG;AACH,wBAAgB,wBAAwB,CAAC,SAAS,EAAE,gBAAgB,GAAG,MAAM,CAoC5E"}
@@ -0,0 +1,250 @@
1
+ import { buildNavbar } from './portal-navbar.js';
2
+ import { getPortalThemeCSS } from './portal-theme.js';
3
+ function escapeHtml(s) {
4
+ return s
5
+ .replace(/&/g, '&amp;')
6
+ .replace(/</g, '&lt;')
7
+ .replace(/>/g, '&gt;')
8
+ .replace(/"/g, '&quot;');
9
+ }
10
+ const TECH_ICONS = {
11
+ typescript: '🔷',
12
+ javascript: '🟡',
13
+ python: '🐍',
14
+ rust: '🦀',
15
+ go: '🐹',
16
+ java: '☕',
17
+ ruby: '💎',
18
+ php: '🐘',
19
+ swift: '🍎',
20
+ kotlin: '🟣',
21
+ 'c#': '🔵',
22
+ elixir: '💧',
23
+ next: '▲',
24
+ nextjs: '▲',
25
+ react: '⚛️',
26
+ vue: '💚',
27
+ angular: '🔴',
28
+ svelte: '🔥',
29
+ express: '🚂',
30
+ fastapi: '⚡',
31
+ django: '🟢',
32
+ rails: '💎',
33
+ laravel: '🔴',
34
+ spring: '🌿',
35
+ postgres: '🐘',
36
+ postgresql: '🐘',
37
+ mysql: '🐬',
38
+ mongodb: '🍃',
39
+ redis: '🔴',
40
+ sqlite: '📦',
41
+ prisma: '⬟',
42
+ drizzle: '💧',
43
+ pnpm: '📦',
44
+ npm: '📦',
45
+ yarn: '🧶',
46
+ bun: '🐰',
47
+ vite: '⚡',
48
+ webpack: '📦',
49
+ esbuild: '⚡',
50
+ docker: '🐋',
51
+ kubernetes: '☸️',
52
+ node: '🟢',
53
+ };
54
+ function techIcon(name) {
55
+ const key = name.toLowerCase();
56
+ return TECH_ICONS[key] ?? '🔧';
57
+ }
58
+ function buildStackCards(knowledge) {
59
+ const entries = [
60
+ { key: 'language', label: 'Language', value: knowledge.language },
61
+ { key: 'framework', label: 'Framework', value: knowledge.framework },
62
+ { key: 'database', label: 'Database', value: knowledge.database },
63
+ { key: 'orm', label: 'ORM', value: knowledge.orm },
64
+ { key: 'packageManager', label: 'Package Manager', value: knowledge.packageManager },
65
+ ];
66
+ const buildToolName = knowledge.buildTool?.buildTool ?? null;
67
+ if (buildToolName && buildToolName !== 'unknown') {
68
+ entries.push({ key: 'buildTool', label: 'Build Tool', value: buildToolName });
69
+ }
70
+ const cards = entries
71
+ .filter((e) => e.value !== null && e.value !== 'none' && e.value !== 'null')
72
+ .map((e) => {
73
+ const icon = techIcon(e.value);
74
+ return `<div class="stack-card planu-card">
75
+ <div class="stack-icon">${icon}</div>
76
+ <div class="stack-info">
77
+ <div class="stack-label">${escapeHtml(e.label)}</div>
78
+ <div class="stack-value">${escapeHtml(e.value)}</div>
79
+ </div>
80
+ </div>`;
81
+ })
82
+ .join('\n');
83
+ if (!cards) {
84
+ return '<p class="empty-message">No stack information detected.</p>';
85
+ }
86
+ return `<div class="stack-grid">${cards}</div>`;
87
+ }
88
+ function buildLayersSection(knowledge) {
89
+ const layers = knowledge.architecture.layers;
90
+ if (layers.length === 0) {
91
+ return '';
92
+ }
93
+ const boxes = layers
94
+ .map((layer) => `<div class="layer-box">
95
+ <div class="layer-name">${escapeHtml(layer.name)}</div>
96
+ <div class="layer-resp">${escapeHtml(layer.responsibility)}</div>
97
+ ${layer.directories.length > 0 ? `<div class="layer-dirs">${layer.directories.map((d) => `<code>${escapeHtml(d)}</code>`).join(' ')}</div>` : ''}
98
+ </div>`)
99
+ .join('\n <div class="layer-arrow">↓</div>\n ');
100
+ return `<section class="planu-card section-card">
101
+ <h2>Architecture Layers</h2>
102
+ <div class="layers-stack">
103
+ ${boxes}
104
+ </div>
105
+ </section>`;
106
+ }
107
+ function appTypeIcon(type) {
108
+ const icons = {
109
+ frontend: '🖥️',
110
+ backend: '⚙️',
111
+ mobile: '📱',
112
+ ios: '🍎',
113
+ android: '🤖',
114
+ desktop: '💻',
115
+ shared: '📦',
116
+ worker: '⚡',
117
+ docs: '📄',
118
+ };
119
+ return icons[type] ?? '📦';
120
+ }
121
+ function buildAppsSection(knowledge) {
122
+ const { apps } = knowledge;
123
+ if (apps.length === 0) {
124
+ return '';
125
+ }
126
+ const cards = apps
127
+ .map((app) => `<div class="app-card planu-card">
128
+ <div class="app-header">
129
+ <span class="app-icon">${appTypeIcon(app.type)}</span>
130
+ <span class="app-name">${escapeHtml(app.name)}</span>
131
+ <span class="app-type-badge">${escapeHtml(app.type)}</span>
132
+ </div>
133
+ <div class="app-details">
134
+ <span>${escapeHtml(app.language)}</span>
135
+ ${app.framework ? `<span class="sep">·</span><span>${escapeHtml(app.framework)}</span>` : ''}
136
+ ${app.database ? `<span class="sep">·</span><span>DB: ${escapeHtml(app.database)}</span>` : ''}
137
+ </div>
138
+ ${app.path ? `<div class="app-path"><code>${escapeHtml(app.path)}</code></div>` : ''}
139
+ </div>`)
140
+ .join('\n');
141
+ return `<section class="planu-card section-card">
142
+ <h2>Applications</h2>
143
+ <div class="apps-grid">${cards}</div>
144
+ </section>`;
145
+ }
146
+ function buildConventionsSection(knowledge) {
147
+ const entries = Object.entries(knowledge.conventions);
148
+ if (entries.length === 0) {
149
+ return '';
150
+ }
151
+ const rows = entries
152
+ .map(([k, v]) => `<tr>
153
+ <td class="conv-key">${escapeHtml(k)}</td>
154
+ <td>${escapeHtml(v)}</td>
155
+ </tr>`)
156
+ .join('\n');
157
+ return `<section class="planu-card section-card">
158
+ <h2>Conventions</h2>
159
+ <table class="simple-table">
160
+ <thead><tr><th>Convention</th><th>Value</th></tr></thead>
161
+ <tbody>${rows}</tbody>
162
+ </table>
163
+ </section>`;
164
+ }
165
+ function buildExternalServicesSection(knowledge) {
166
+ const services = knowledge.externalServices;
167
+ if (services.length === 0) {
168
+ return '';
169
+ }
170
+ const items = services.map((s) => `<li class="service-item">🔌 ${escapeHtml(s)}</li>`).join('\n');
171
+ return `<section class="planu-card section-card">
172
+ <h2>External Services</h2>
173
+ <ul class="services-list">${items}</ul>
174
+ </section>`;
175
+ }
176
+ function buildPageCSS() {
177
+ return `
178
+ body { font-family: system-ui, sans-serif; margin: 0; padding: 0 16px 48px; background: var(--planu-bg); color: var(--planu-text); }
179
+ .page-title { font-size: 1.6rem; font-weight: 700; margin: 0 0 6px; }
180
+ .page-subtitle { color: #6b7280; margin: 0 0 24px; font-size: 0.95rem; }
181
+ .section-card { margin-bottom: 24px; }
182
+ h2 { font-size: 1.1rem; font-weight: 600; margin: 0 0 16px; color: var(--planu-primary); }
183
+ .stack-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); gap: 12px; }
184
+ .stack-card { display: flex; align-items: center; gap: 10px; padding: 12px; }
185
+ .stack-icon { font-size: 1.8rem; }
186
+ .stack-label { font-size: 0.75rem; color: #6b7280; }
187
+ .stack-value { font-weight: 600; font-size: 0.9rem; }
188
+ .layers-stack { display: flex; flex-direction: column; align-items: center; gap: 0; }
189
+ .layer-box { width: 100%; max-width: 560px; padding: 12px 16px; background: white; border: 1px solid var(--planu-border); border-radius: 8px; box-shadow: 0 1px 3px rgba(0,0,0,0.05); }
190
+ .layer-name { font-weight: 700; color: var(--planu-primary); margin-bottom: 2px; }
191
+ .layer-resp { font-size: 0.84rem; color: #4b5563; }
192
+ .layer-dirs { margin-top: 6px; font-size: 0.78rem; color: #6b7280; }
193
+ .layer-dirs code { background: #f3f4f6; padding: 1px 4px; border-radius: 3px; margin-right: 4px; }
194
+ .layer-arrow { font-size: 1.2rem; color: #9ca3af; }
195
+ .apps-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 12px; }
196
+ .app-card { padding: 12px 14px; }
197
+ .app-header { display: flex; align-items: center; gap: 8px; margin-bottom: 6px; }
198
+ .app-icon { font-size: 1.4rem; }
199
+ .app-name { font-weight: 700; }
200
+ .app-type-badge { font-size: 0.75rem; padding: 2px 6px; border-radius: 4px; background: #f3f4f6; color: #374151; }
201
+ .app-details { font-size: 0.82rem; color: #6b7280; }
202
+ .sep { margin: 0 4px; color: #d1d5db; }
203
+ .app-path { margin-top: 6px; font-size: 0.75rem; color: #9ca3af; }
204
+ .app-path code { background: #f9fafb; padding: 1px 4px; border-radius: 3px; }
205
+ .simple-table { width: 100%; border-collapse: collapse; font-size: 0.83rem; }
206
+ .simple-table th { background: #f3f4f6; padding: 8px 10px; text-align: left; border-bottom: 2px solid var(--planu-border); }
207
+ .simple-table td { padding: 8px 10px; border-bottom: 1px solid var(--planu-border); }
208
+ .conv-key { font-weight: 600; color: var(--planu-primary); }
209
+ .services-list { list-style: none; padding: 0; margin: 0; display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 8px; }
210
+ .service-item { padding: 8px 12px; background: #f9fafb; border-radius: 6px; font-size: 0.86rem; }
211
+ .empty-state { text-align: center; padding: 64px 24px; color: #6b7280; }
212
+ .empty-message { color: #9ca3af; font-style: italic; }`;
213
+ }
214
+ /**
215
+ * Generate the architecture.html portal page.
216
+ */
217
+ export function generateArchitecturePage(knowledge) {
218
+ const navbar = buildNavbar('architecture', '');
219
+ const themeCSS = getPortalThemeCSS();
220
+ const pageCSS = buildPageCSS();
221
+ const hasContent = knowledge.language !== '' || knowledge.framework !== null || knowledge.apps.length > 0;
222
+ const bodyContent = hasContent
223
+ ? `<section class="planu-card section-card">
224
+ <h2>Tech Stack</h2>
225
+ ${buildStackCards(knowledge)}
226
+ </section>
227
+ ${buildLayersSection(knowledge)}
228
+ ${buildAppsSection(knowledge)}
229
+ ${buildConventionsSection(knowledge)}
230
+ ${buildExternalServicesSection(knowledge)}`
231
+ : `<div class="empty-state"><h3>No architecture data available</h3><p>Run <code>scan_project</code> to populate this page.</p></div>`;
232
+ return `<!DOCTYPE html>
233
+ <html lang="en">
234
+ <head>
235
+ <meta charset="UTF-8">
236
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
237
+ <title>Architecture — Planu Portal</title>
238
+ <style>${themeCSS}${pageCSS}</style>
239
+ </head>
240
+ <body>
241
+ ${navbar}
242
+ <main>
243
+ <h1 class="page-title">🔧 Architecture</h1>
244
+ <p class="page-subtitle">Tech stack, layers, apps, and conventions for this project.</p>
245
+ ${bodyContent}
246
+ </main>
247
+ </body>
248
+ </html>`;
249
+ }
250
+ //# sourceMappingURL=architecture-page.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"architecture-page.js","sourceRoot":"","sources":["../../../../src/engine/doc-generator/portal/architecture-page.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAEtD,SAAS,UAAU,CAAC,CAAS;IAC3B,OAAO,CAAC;SACL,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;AAED,MAAM,UAAU,GAA2B;IACzC,UAAU,EAAE,IAAI;IAChB,UAAU,EAAE,IAAI;IAChB,MAAM,EAAE,IAAI;IACZ,IAAI,EAAE,IAAI;IACV,EAAE,EAAE,IAAI;IACR,IAAI,EAAE,GAAG;IACT,IAAI,EAAE,IAAI;IACV,GAAG,EAAE,IAAI;IACT,KAAK,EAAE,IAAI;IACX,MAAM,EAAE,IAAI;IACZ,IAAI,EAAE,IAAI;IACV,MAAM,EAAE,IAAI;IACZ,IAAI,EAAE,GAAG;IACT,MAAM,EAAE,GAAG;IACX,KAAK,EAAE,IAAI;IACX,GAAG,EAAE,IAAI;IACT,OAAO,EAAE,IAAI;IACb,MAAM,EAAE,IAAI;IACZ,OAAO,EAAE,IAAI;IACb,OAAO,EAAE,GAAG;IACZ,MAAM,EAAE,IAAI;IACZ,KAAK,EAAE,IAAI;IACX,OAAO,EAAE,IAAI;IACb,MAAM,EAAE,IAAI;IACZ,QAAQ,EAAE,IAAI;IACd,UAAU,EAAE,IAAI;IAChB,KAAK,EAAE,IAAI;IACX,OAAO,EAAE,IAAI;IACb,KAAK,EAAE,IAAI;IACX,MAAM,EAAE,IAAI;IACZ,MAAM,EAAE,GAAG;IACX,OAAO,EAAE,IAAI;IACb,IAAI,EAAE,IAAI;IACV,GAAG,EAAE,IAAI;IACT,IAAI,EAAE,IAAI;IACV,GAAG,EAAE,IAAI;IACT,IAAI,EAAE,GAAG;IACT,OAAO,EAAE,IAAI;IACb,OAAO,EAAE,GAAG;IACZ,MAAM,EAAE,IAAI;IACZ,UAAU,EAAE,IAAI;IAChB,IAAI,EAAE,IAAI;CACX,CAAC;AAEF,SAAS,QAAQ,CAAC,IAAY;IAC5B,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;IAC/B,OAAO,UAAU,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC;AACjC,CAAC;AAED,SAAS,eAAe,CAAC,SAA2B;IAClD,MAAM,OAAO,GAAiB;QAC5B,EAAE,GAAG,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,SAAS,CAAC,QAAQ,EAAE;QACjE,EAAE,GAAG,EAAE,WAAW,EAAE,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,SAAS,CAAC,SAAS,EAAE;QACpE,EAAE,GAAG,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,SAAS,CAAC,QAAQ,EAAE;QACjE,EAAE,GAAG,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,SAAS,CAAC,GAAG,EAAE;QAClD,EAAE,GAAG,EAAE,gBAAgB,EAAE,KAAK,EAAE,iBAAiB,EAAE,KAAK,EAAE,SAAS,CAAC,cAAc,EAAE;KACrF,CAAC;IAEF,MAAM,aAAa,GAAG,SAAS,CAAC,SAAS,EAAE,SAAS,IAAI,IAAI,CAAC;IAC7D,IAAI,aAAa,IAAI,aAAa,KAAK,SAAS,EAAE,CAAC;QACjD,OAAO,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,WAAW,EAAE,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,aAAa,EAAE,CAAC,CAAC;IAChF,CAAC;IAED,MAAM,KAAK,GAAG,OAAO;SAClB,MAAM,CACL,CAAC,CAAC,EAAuC,EAAE,CACzC,CAAC,CAAC,KAAK,KAAK,IAAI,IAAI,CAAC,CAAC,KAAK,KAAK,MAAM,IAAI,CAAC,CAAC,KAAK,KAAK,MAAM,CAC/D;SACA,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QACT,MAAM,IAAI,GAAG,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;QAC/B,OAAO;kCACqB,IAAI;;qCAED,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC;qCACnB,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC;;aAE3C,CAAC;IACV,CAAC,CAAC;SACD,IAAI,CAAC,IAAI,CAAC,CAAC;IAEd,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,6DAA6D,CAAC;IACvE,CAAC;IAED,OAAO,2BAA2B,KAAK,QAAQ,CAAC;AAClD,CAAC;AAED,SAAS,kBAAkB,CAAC,SAA2B;IACrD,MAAM,MAAM,GAAG,SAAS,CAAC,YAAY,CAAC,MAAM,CAAC;IAC7C,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,MAAM,KAAK,GAAG,MAAM;SACjB,GAAG,CACF,CAAC,KAAK,EAAE,EAAE,CAAC;kCACiB,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC;kCACtB,UAAU,CAAC,KAAK,CAAC,cAAc,CAAC;UACxD,KAAK,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,2BAA2B,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,SAAS,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE;aAC3I,CACR;SACA,IAAI,CAAC,8CAA8C,CAAC,CAAC;IAExD,OAAO;;;QAGD,KAAK;;aAEA,CAAC;AACd,CAAC;AAED,SAAS,WAAW,CAAC,IAAwB;IAC3C,MAAM,KAAK,GAA2B;QACpC,QAAQ,EAAE,KAAK;QACf,OAAO,EAAE,IAAI;QACb,MAAM,EAAE,IAAI;QACZ,GAAG,EAAE,IAAI;QACT,OAAO,EAAE,IAAI;QACb,OAAO,EAAE,IAAI;QACb,MAAM,EAAE,IAAI;QACZ,MAAM,EAAE,GAAG;QACX,IAAI,EAAE,IAAI;KACX,CAAC;IACF,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC;AAC7B,CAAC;AAED,SAAS,gBAAgB,CAAC,SAA2B;IACnD,MAAM,EAAE,IAAI,EAAE,GAAG,SAAS,CAAC;IAC3B,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtB,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,MAAM,KAAK,GAAG,IAAI;SACf,GAAG,CACF,CAAC,GAAG,EAAE,EAAE,CAAC;;mCAEoB,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC;mCACrB,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC;yCACd,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC;;;kBAG3C,UAAU,CAAC,GAAG,CAAC,QAAQ,CAAC;YAC9B,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,mCAAmC,UAAU,CAAC,GAAG,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE;YAC1F,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,uCAAuC,UAAU,CAAC,GAAG,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE;;UAE9F,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,+BAA+B,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE;aAC/E,CACR;SACA,IAAI,CAAC,IAAI,CAAC,CAAC;IAEd,OAAO;;6BAEoB,KAAK;aACrB,CAAC;AACd,CAAC;AAED,SAAS,uBAAuB,CAAC,SAA2B;IAC1D,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;IACtD,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,MAAM,IAAI,GAAG,OAAO;SACjB,GAAG,CACF,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC;6BACW,UAAU,CAAC,CAAC,CAAC;YAC9B,UAAU,CAAC,CAAC,CAAC;UACf,CACL;SACA,IAAI,CAAC,IAAI,CAAC,CAAC;IAEd,OAAO;;;;eAIM,IAAI;;aAEN,CAAC;AACd,CAAC;AAED,SAAS,4BAA4B,CAAC,SAA2B;IAC/D,MAAM,QAAQ,GAAG,SAAS,CAAC,gBAAgB,CAAC;IAC5C,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,MAAM,KAAK,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,+BAA+B,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAElG,OAAO;;gCAEuB,KAAK;aACxB,CAAC;AACd,CAAC;AAED,SAAS,YAAY;IACnB,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;yDAmCgD,CAAC;AAC1D,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,wBAAwB,CAAC,SAA2B;IAClE,MAAM,MAAM,GAAG,WAAW,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC;IAC/C,MAAM,QAAQ,GAAG,iBAAiB,EAAE,CAAC;IACrC,MAAM,OAAO,GAAG,YAAY,EAAE,CAAC;IAE/B,MAAM,UAAU,GACd,SAAS,CAAC,QAAQ,KAAK,EAAE,IAAI,SAAS,CAAC,SAAS,KAAK,IAAI,IAAI,SAAS,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;IAEzF,MAAM,WAAW,GAAG,UAAU;QAC5B,CAAC,CAAC;;MAEA,eAAe,CAAC,SAAS,CAAC;;IAE5B,kBAAkB,CAAC,SAAS,CAAC;IAC7B,gBAAgB,CAAC,SAAS,CAAC;IAC3B,uBAAuB,CAAC,SAAS,CAAC;IAClC,4BAA4B,CAAC,SAAS,CAAC,EAAE;QACzC,CAAC,CAAC,mIAAmI,CAAC;IAExI,OAAO;;;;;;WAME,QAAQ,GAAG,OAAO;;;IAGzB,MAAM;;;;MAIJ,WAAW;;;QAGT,CAAC;AACT,CAAC"}