2sagaco48 1.0.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 (365) hide show
  1. package/diagnostics.mjs +141 -0
  2. package/dist/compute.worker-j5ahIpF-.js +1 -0
  3. package/dist/graph.worker-DG6iGCB9.js +1 -0
  4. package/dist/index.html +2314 -0
  5. package/flatten-guide.md +248 -0
  6. package/index.html +12 -0
  7. package/package.json +38 -0
  8. package/src/App.orig.tsx +204 -0
  9. package/src/App.orig1.tsx +27 -0
  10. package/src/App.orig2.tsx +25 -0
  11. package/src/App.tsx +3 -0
  12. package/src/BaseApp.tsx +18 -0
  13. package/src/INTEGRATION_LEDGER.md +22 -0
  14. package/src/PERSIST_CANARY.orig.txt +1 -0
  15. package/src/PERSIST_CANARY.txt +1 -0
  16. package/src/REGRESSION_LEDGER.md +651 -0
  17. package/src/TEMPLATE_PIPELINE_AUDIT.md +208 -0
  18. package/src/WILLIAMS_PERSONA_GUIDE.md +62 -0
  19. package/src/chat/VeritasChat.tsx +69 -0
  20. package/src/chat/synthesis.ts +31 -0
  21. package/src/chat/tier.ts +45 -0
  22. package/src/components/AdaptersPage.orig.tsx +99 -0
  23. package/src/components/AdaptersPage.tsx +3 -0
  24. package/src/components/AdversarialPanel.tsx +136 -0
  25. package/src/components/AnchorBaselinePanel.tsx +75 -0
  26. package/src/components/AnswerPanel.tsx +60 -0
  27. package/src/components/ArtifactPanel.tsx +43 -0
  28. package/src/components/ChatApp.orig.tsx +1582 -0
  29. package/src/components/ChatApp.orig1.tsx +722 -0
  30. package/src/components/ChatApp.tsx +95 -0
  31. package/src/components/ChatAugmentPanels.tsx +73 -0
  32. package/src/components/CitationLedgerPanel.tsx +313 -0
  33. package/src/components/ComputeSandboxPanel.tsx +130 -0
  34. package/src/components/ConfigPanel.tsx +110 -0
  35. package/src/components/ControlPlanePage.tsx +195 -0
  36. package/src/components/CreativeTreeLifePage.tsx +234 -0
  37. package/src/components/CreativeTreeOfLifePanel.tsx +149 -0
  38. package/src/components/DebugTracePanel.tsx +137 -0
  39. package/src/components/DeepReasoningTrace.tsx +48 -0
  40. package/src/components/EntitySheetPanel.tsx +51 -0
  41. package/src/components/FailureModesPanel.tsx +104 -0
  42. package/src/components/GBSDashboard.tsx +239 -0
  43. package/src/components/GraphView.tsx +116 -0
  44. package/src/components/HUD.tsx +125 -0
  45. package/src/components/HypothesisPanel.tsx +67 -0
  46. package/src/components/InnovationGenomeEngine.tsx +792 -0
  47. package/src/components/InnovationPersonaGuide.tsx +348 -0
  48. package/src/components/InnovationPersonaPanel.tsx +289 -0
  49. package/src/components/LiveResourceHUD.tsx +109 -0
  50. package/src/components/LongWriterPanel.tsx +112 -0
  51. package/src/components/MainPipelineV10Bridge.tsx +72 -0
  52. package/src/components/MarkdownLite.tsx +63 -0
  53. package/src/components/MemoryInspector.tsx +38 -0
  54. package/src/components/MemoryMonitor.tsx +52 -0
  55. package/src/components/MemoryStressPanel.tsx +176 -0
  56. package/src/components/ModulesPage.tsx +171 -0
  57. package/src/components/PipelineDebugConsole.orig.tsx +1856 -0
  58. package/src/components/PipelineDebugConsole.tsx +3 -0
  59. package/src/components/PreFlightHUD.tsx +67 -0
  60. package/src/components/PrismaFetchTracePanel.tsx +87 -0
  61. package/src/components/ReportOSPanel.tsx +165 -0
  62. package/src/components/ResourceEstimatorPage.tsx +327 -0
  63. package/src/components/RichText.tsx +181 -0
  64. package/src/components/SagaOsPanel.tsx +605 -0
  65. package/src/components/SagaOsReference.tsx +421 -0
  66. package/src/components/SagaOsV2Panel.tsx +594 -0
  67. package/src/components/SagaStyleTab.tsx +382 -0
  68. package/src/components/SageBlueprintPanel.tsx +416 -0
  69. package/src/components/SharedChatInput.tsx +77 -0
  70. package/src/components/StatFinancePanel.tsx +190 -0
  71. package/src/components/StylePersonaPanel.tsx +128 -0
  72. package/src/components/TemplatesPage.tsx +300 -0
  73. package/src/components/TestPanel.tsx +63 -0
  74. package/src/components/TraceLog.tsx +89 -0
  75. package/src/components/V15CalibrationAugment.tsx +1134 -0
  76. package/src/components/V15CalibrationDialog.tsx +1871 -0
  77. package/src/components/V15Overlay.orig.tsx +120 -0
  78. package/src/components/V15Overlay.tsx +4 -0
  79. package/src/components/V15OverlayWrapper.tsx +362 -0
  80. package/src/components/V15Toggle.tsx +34 -0
  81. package/src/console/DiagnosticRecoveryPanel.tsx +358 -0
  82. package/src/console/EngineeringConsole.tsx +103 -0
  83. package/src/console/FictionSystemPanels.tsx +882 -0
  84. package/src/console/InspectorPanels.tsx +254 -0
  85. package/src/console/ManuscriptGraderPanel.tsx +182 -0
  86. package/src/console/RecursiveReviserPanel.tsx +245 -0
  87. package/src/console/SeedControlPanel.tsx +135 -0
  88. package/src/console/StoryControllerPanel.tsx +443 -0
  89. package/src/console/engineBridge.ts +258 -0
  90. package/src/console/gemini.ts +106 -0
  91. package/src/console/grading.ts +250 -0
  92. package/src/console/util.ts +45 -0
  93. package/src/fiction/continuity.ts +372 -0
  94. package/src/fiction/crash-protection.ts +111 -0
  95. package/src/fiction/diagnostics.ts +208 -0
  96. package/src/fiction/diff.ts +74 -0
  97. package/src/fiction/entity-state-machine.ts +214 -0
  98. package/src/fiction/nive-engine.ts +404 -0
  99. package/src/fiction/pipeline-selftest.ts +132 -0
  100. package/src/fiction/seed-control.ts +193 -0
  101. package/src/fiction/story-engine.ts +326 -0
  102. package/src/fiction/types.ts +68 -0
  103. package/src/flatten-guide.md +379 -0
  104. package/src/index.css +14 -0
  105. package/src/index.orig.css +13 -0
  106. package/src/lib/academic-sources.base.ts +188 -0
  107. package/src/lib/academic-sources.orig.ts +28 -0
  108. package/src/lib/academic-sources.ts +10 -0
  109. package/src/lib/advanced-math.ts +119 -0
  110. package/src/lib/adversarial-engine.base.ts +409 -0
  111. package/src/lib/adversarial-engine.ts +82 -0
  112. package/src/lib/ai-revision.ts +623 -0
  113. package/src/lib/app-state.tsx +426 -0
  114. package/src/lib/artifact-registry.ts +97 -0
  115. package/src/lib/artifacts.ts +180 -0
  116. package/src/lib/atlas-dr.ts +167 -0
  117. package/src/lib/browser-mtls.ts +127 -0
  118. package/src/lib/browser-queue.ts +221 -0
  119. package/src/lib/browser-search-scraper.base.ts +382 -0
  120. package/src/lib/browser-search-scraper.orig.ts +90 -0
  121. package/src/lib/browser-search-scraper.ts +10 -0
  122. package/src/lib/calc-interceptor.ts +82 -0
  123. package/src/lib/citation-lane-tap.ts +78 -0
  124. package/src/lib/citation-ledger-store.ts +369 -0
  125. package/src/lib/citation-ledger.ts +203 -0
  126. package/src/lib/compute-sandbox.ts +215 -0
  127. package/src/lib/compute.worker.ts +153 -0
  128. package/src/lib/connectors/gemini.ts +120 -0
  129. package/src/lib/connectors/jina.ts +233 -0
  130. package/src/lib/connectors/marketdata.ts +51 -0
  131. package/src/lib/connectors/prismafetch.base.ts +175 -0
  132. package/src/lib/connectors/prismafetch.ts +1 -0
  133. package/src/lib/connectors/serpapi.ts +65 -0
  134. package/src/lib/connectors/wikidata.ts +44 -0
  135. package/src/lib/constraints.ts +331 -0
  136. package/src/lib/continuation-detector.base.ts +153 -0
  137. package/src/lib/continuation-detector.ts +48 -0
  138. package/src/lib/contradraft.ts +168 -0
  139. package/src/lib/cors-proxy.ts +120 -0
  140. package/src/lib/coverage.ts +81 -0
  141. package/src/lib/debug/architecture-prescription.ts +556 -0
  142. package/src/lib/debug/covea-repair.ts +543 -0
  143. package/src/lib/debug/helios-ground.ts +319 -0
  144. package/src/lib/debug/intent-decomposer.ts +281 -0
  145. package/src/lib/debug/intent-lattice.ts +349 -0
  146. package/src/lib/debug/pipeline-diagnosis.ts +1149 -0
  147. package/src/lib/debug/pipeline-trace-bus.ts +424 -0
  148. package/src/lib/debug/prompt-forge.ts +678 -0
  149. package/src/lib/debug/repair-sites.ts +513 -0
  150. package/src/lib/debug/research-phase.ts +266 -0
  151. package/src/lib/debug/retrieval-context.ts +76 -0
  152. package/src/lib/debug/retrieval-hardener.ts +142 -0
  153. package/src/lib/debug/scraper-debug-runner.ts +576 -0
  154. package/src/lib/debug/scraper-forensics.ts +418 -0
  155. package/src/lib/debug/scraper-lane-roadmap.ts +136 -0
  156. package/src/lib/debug/self-test.ts +415 -0
  157. package/src/lib/debug/step-attribution.ts +211 -0
  158. package/src/lib/debug/template-rubric.ts +301 -0
  159. package/src/lib/debug/unified-innovation.ts +126 -0
  160. package/src/lib/debug/veritas-hybrid-scraper.ts +335 -0
  161. package/src/lib/defense-registry.ts +104 -0
  162. package/src/lib/defenses.ts +162 -0
  163. package/src/lib/deterministic-citation-ledger.ts +174 -0
  164. package/src/lib/elo-registry.base.ts +117 -0
  165. package/src/lib/elo-registry.ts +1 -0
  166. package/src/lib/entity-resolver.ts +291 -0
  167. package/src/lib/failure-modes.ts +267 -0
  168. package/src/lib/feature-registry.ts +69 -0
  169. package/src/lib/flaw-registry.ts +143 -0
  170. package/src/lib/flaws/_template.ts +52 -0
  171. package/src/lib/flaws/builtins.ts +63 -0
  172. package/src/lib/flaws/finance.ts +169 -0
  173. package/src/lib/flaws/fixers.ts +10 -0
  174. package/src/lib/flaws/index.ts +32 -0
  175. package/src/lib/flaws/legal.ts +157 -0
  176. package/src/lib/flaws/medical.ts +188 -0
  177. package/src/lib/flaws/original-defenses-pack.ts +81 -0
  178. package/src/lib/flaws/sample-declarative-pack.json +38 -0
  179. package/src/lib/flaws/selftest.ts +201 -0
  180. package/src/lib/flaws/software-extended.ts +125 -0
  181. package/src/lib/flaws/software-rn-webgl.ts +182 -0
  182. package/src/lib/flaws/statistics-advanced.ts +46 -0
  183. package/src/lib/flaws/statistics.ts +61 -0
  184. package/src/lib/gbse/config.ts +20 -0
  185. package/src/lib/gbse/engine.ts +226 -0
  186. package/src/lib/gbse/graph.ts +118 -0
  187. package/src/lib/gbse/graph.worker.ts +21 -0
  188. package/src/lib/gbse/tests.ts +117 -0
  189. package/src/lib/gbse/tiers.ts +65 -0
  190. package/src/lib/gbse/types.ts +94 -0
  191. package/src/lib/innovation-genome-engine-v2.orig.ts +1001 -0
  192. package/src/lib/innovation-genome-engine-v2.ts +3 -0
  193. package/src/lib/innovation-genome-engine.orig.ts +330 -0
  194. package/src/lib/innovation-genome-engine.ts +3 -0
  195. package/src/lib/innovation-genome-v10.orig.ts +314 -0
  196. package/src/lib/innovation-genome-v10.ts +2 -0
  197. package/src/lib/innovation-genome-v3.orig.ts +2015 -0
  198. package/src/lib/innovation-genome-v3.ts +2 -0
  199. package/src/lib/innovation-genome-v4.orig.ts +1959 -0
  200. package/src/lib/innovation-genome-v4.ts +2 -0
  201. package/src/lib/innovation-genome-v5.orig.ts +1210 -0
  202. package/src/lib/innovation-genome-v5.ts +2 -0
  203. package/src/lib/innovation-genome-v7.orig.ts +2549 -0
  204. package/src/lib/innovation-genome-v7.ts +2 -0
  205. package/src/lib/innovation-genome-v8.orig.ts +1485 -0
  206. package/src/lib/innovation-genome-v8.ts +2 -0
  207. package/src/lib/innovation-genome-v9.orig.ts +643 -0
  208. package/src/lib/innovation-genome-v9.ts +2 -0
  209. package/src/lib/jina.base.ts +293 -0
  210. package/src/lib/jina.ts +1 -0
  211. package/src/lib/live-telemetry.ts +61 -0
  212. package/src/lib/longwriter.ts +84 -0
  213. package/src/lib/manuscript-grade-v2.ts +298 -0
  214. package/src/lib/memory-governor.ts +173 -0
  215. package/src/lib/memory-stress-tests.ts +248 -0
  216. package/src/lib/model-intelligence.ts +48 -0
  217. package/src/lib/model-rotator.ts +75 -0
  218. package/src/lib/models.orig.ts +513 -0
  219. package/src/lib/models.ts +151 -0
  220. package/src/lib/n-deep.base.ts +592 -0
  221. package/src/lib/n-deep.ts +51 -0
  222. package/src/lib/nih-simulator.ts +56 -0
  223. package/src/lib/nih-vulnerability-fixes.ts +460 -0
  224. package/src/lib/omega-templates.base.ts +294 -0
  225. package/src/lib/omega-templates.ts +225 -0
  226. package/src/lib/omni-nexus.ts +64 -0
  227. package/src/lib/oracle-adapters.ts +67 -0
  228. package/src/lib/oracle-registry.ts +163 -0
  229. package/src/lib/orchestrator.ts +357 -0
  230. package/src/lib/output-boundary.ts +235 -0
  231. package/src/lib/overrides/vite-native-chaos-harness.ts +154 -0
  232. package/src/lib/overrides/vite-native-contract-plane.ts +245 -0
  233. package/src/lib/overrides/vite-native-doctor-plane.ts +208 -0
  234. package/src/lib/overrides/vite-native-knowledge-store.ts +267 -0
  235. package/src/lib/overrides/vite-native-policy-plane.ts +190 -0
  236. package/src/lib/overrides/vite-native-replay-plane.ts +197 -0
  237. package/src/lib/overrides/vite-native-runtime-plane.ts +106 -0
  238. package/src/lib/overrides/vite-native-scraper.ts +848 -0
  239. package/src/lib/overrides/vite-native-selftest-functional.ts +217 -0
  240. package/src/lib/overrides/vite-native-selftest.ts +183 -0
  241. package/src/lib/overrides/vite-native-snapshot-plane.ts +123 -0
  242. package/src/lib/philosophy-toolkit.ts +75 -0
  243. package/src/lib/pipeline.orig.ts +659 -0
  244. package/src/lib/pipeline.ts +42 -0
  245. package/src/lib/precache.ts +128 -0
  246. package/src/lib/py-sandbox.ts +205 -0
  247. package/src/lib/quality-score.ts +96 -0
  248. package/src/lib/quant-engine.ts +231 -0
  249. package/src/lib/quant-lib.ts +80 -0
  250. package/src/lib/reportos.ts +175 -0
  251. package/src/lib/research-os.ts +306 -0
  252. package/src/lib/resource-estimator.ts +114 -0
  253. package/src/lib/rpm-governor.ts +93 -0
  254. package/src/lib/runtime-estimator.ts +135 -0
  255. package/src/lib/sage/empty-space-v6.ts +560 -0
  256. package/src/lib/sage/empty-space-v7.ts +222 -0
  257. package/src/lib/sage/empty-space.ts +733 -0
  258. package/src/lib/sage/engine.ts +786 -0
  259. package/src/lib/sage/index.ts +17 -0
  260. package/src/lib/sage/judge.ts +246 -0
  261. package/src/lib/sage/prng.ts +53 -0
  262. package/src/lib/sage/reality-grounding.ts +380 -0
  263. package/src/lib/sage/repetition.ts +151 -0
  264. package/src/lib/sage/saga-os-v2-engines.ts +1870 -0
  265. package/src/lib/sage/saga-os-v2.ts +274 -0
  266. package/src/lib/sage/saga-os-v3-core.ts +1491 -0
  267. package/src/lib/sage/saga-os-v3-release.ts +739 -0
  268. package/src/lib/sage/saga-os-v4-aureate.ts +1161 -0
  269. package/src/lib/sage/saga-os-v4.ts +212 -0
  270. package/src/lib/sage/saga-os-v5.ts +205 -0
  271. package/src/lib/sage/saga-os-v6.ts +346 -0
  272. package/src/lib/sage/saga-os-v7.ts +314 -0
  273. package/src/lib/sage/saga-os-v8.ts +505 -0
  274. package/src/lib/sage/saga-os.ts +329 -0
  275. package/src/lib/sage/taxonomy.ts +403 -0
  276. package/src/lib/sage/unified-roll.ts +524 -0
  277. package/src/lib/sage/worked-sketches.ts +44 -0
  278. package/src/lib/sage.ts +166 -0
  279. package/src/lib/scraper-debug-bus.ts +53 -0
  280. package/src/lib/scraper-enhanced.orig.ts +153 -0
  281. package/src/lib/scraper-enhanced.ts +10 -0
  282. package/src/lib/scraper-hardener.base.orig.ts +155 -0
  283. package/src/lib/scraper-hardener.base.ts +317 -0
  284. package/src/lib/scraper-hardener.ts +1 -0
  285. package/src/lib/scraper-palisade/palisade-adjudicator.orig.ts +419 -0
  286. package/src/lib/scraper-palisade/palisade-adjudicator.ts +13 -0
  287. package/src/lib/scraper-vnext/arbiter-omega.orig.ts +688 -0
  288. package/src/lib/scraper-vnext/arbiter-omega.ts +13 -0
  289. package/src/lib/scraper-vnext/canonical-portfolio-augments.ts +479 -0
  290. package/src/lib/scraper-vnext/canonical-portfolio-orchestrator.orig.ts +1529 -0
  291. package/src/lib/scraper-vnext/canonical-portfolio-orchestrator.ts +13 -0
  292. package/src/lib/scraper-vnext/conclave-omega.ts +1830 -0
  293. package/src/lib/scraper-vnext/content-extractor-v2.ts +226 -0
  294. package/src/lib/scraper-vnext/diagnostics-suite.ts +36 -0
  295. package/src/lib/scraper-vnext/epistemic-packer.ts +97 -0
  296. package/src/lib/scraper-vnext/fusion-v2.ts +65 -0
  297. package/src/lib/scraper-vnext/hydra-reader.orig.ts +1216 -0
  298. package/src/lib/scraper-vnext/hydra-reader.ts +13 -0
  299. package/src/lib/scraper-vnext/native-scraper-browser-vnext.orig.ts +91 -0
  300. package/src/lib/scraper-vnext/native-scraper-browser-vnext.ts +13 -0
  301. package/src/lib/scraper-vnext/nexus-consensus.orig.ts +905 -0
  302. package/src/lib/scraper-vnext/nexus-consensus.ts +13 -0
  303. package/src/lib/scraper-vnext/portfolio-consensus-adjudicator.ts +804 -0
  304. package/src/lib/scraper-vnext/portfolio-consensus-memory.ts +377 -0
  305. package/src/lib/scraper-vnext/portfolio-terminal-governor.ts +548 -0
  306. package/src/lib/scraper-vnext/query-strategist.orig.ts +224 -0
  307. package/src/lib/scraper-vnext/query-strategist.ts +423 -0
  308. package/src/lib/scraper-vnext/retrieval-accelerator.ts +708 -0
  309. package/src/lib/scraper-vnext/retrieval-audit-augments.ts +477 -0
  310. package/src/lib/scraper-vnext/retrieval-control-plane.ts +904 -0
  311. package/src/lib/scraper-vnext/retrieval-policy-augments.ts +358 -0
  312. package/src/lib/scraper-vnext/safe-fetch-v2.ts +157 -0
  313. package/src/lib/scraper-vnext/sentinel-omega.ts +56 -0
  314. package/src/lib/scraper-vnext/sentinel-orchestrator.ts +69 -0
  315. package/src/lib/scraper-vnext/sibyl-oracle.orig.ts +413 -0
  316. package/src/lib/scraper-vnext/sibyl-oracle.ts +13 -0
  317. package/src/lib/scraper-vnext/smart-read-v2.ts +55 -0
  318. package/src/lib/scraper-vnext/spa-rescue-bridge.ts +608 -0
  319. package/src/lib/scraper-vnext/strata-engine.orig.ts +2666 -0
  320. package/src/lib/scraper-vnext/strata-engine.ts +13 -0
  321. package/src/lib/scraper-vnext/structured-source-adapter.orig.ts +369 -0
  322. package/src/lib/scraper-vnext/structured-source-adapter.ts +34 -0
  323. package/src/lib/scraper-vnext/terminal-complete.ts +224 -0
  324. package/src/lib/scraper-vnext/terminal-final.ts +277 -0
  325. package/src/lib/scraper-vnext/terminal-saturation.ts +345 -0
  326. package/src/lib/scraper-vnext/terminal-wire.ts +425 -0
  327. package/src/lib/scraper-vnext/vanguard-titanium.orig.ts +467 -0
  328. package/src/lib/scraper-vnext/vanguard-titanium.ts +17 -0
  329. package/src/lib/search-cache.ts +138 -0
  330. package/src/lib/sloop-runner.base.ts +223 -0
  331. package/src/lib/sloop-runner.ts +104 -0
  332. package/src/lib/sloop.ts +114 -0
  333. package/src/lib/small-model-adapters.ts +82 -0
  334. package/src/lib/sscp.ts +86 -0
  335. package/src/lib/system-map.ts +54 -0
  336. package/src/lib/uni-node.ts +86 -0
  337. package/src/lib/universal-rigor-guard.ts +433 -0
  338. package/src/lib/v15-gate-testbed.ts +274 -0
  339. package/src/lib/v15-gemini.base.ts +89 -0
  340. package/src/lib/v15-gemini.ts +1 -0
  341. package/src/lib/v15-grounding.orig.ts +241 -0
  342. package/src/lib/v15-grounding.ts +79 -0
  343. package/src/lib/v15-pipeline.base.ts +769 -0
  344. package/src/lib/v15-pipeline.orig.ts +1154 -0
  345. package/src/lib/v15-pipeline.ts +674 -0
  346. package/src/lib/v15-questions.ts +64 -0
  347. package/src/lib/v15-rate-limiter.orig.ts +91 -0
  348. package/src/lib/v15-rate-limiter.ts +48 -0
  349. package/src/lib/v15-state.base.ts +87 -0
  350. package/src/lib/v15-state.ts +28 -0
  351. package/src/lib/visual-table-generator.tsx +207 -0
  352. package/src/lib/wasm-runtime.ts +133 -0
  353. package/src/lib/williams-persona-guide.ts +265 -0
  354. package/src/lib/williams-style.base.ts +464 -0
  355. package/src/lib/williams-style.ts +59 -0
  356. package/src/lib/worker-pool.ts +96 -0
  357. package/src/lib/writing-tiers.ts +125 -0
  358. package/src/main.orig.tsx +10 -0
  359. package/src/main.tsx +10 -0
  360. package/src/utils/cn.orig.ts +6 -0
  361. package/src/utils/cn.ts +6 -0
  362. package/src/vite-env.d.ts +1 -0
  363. package/tsconfig.json +31 -0
  364. package/unify.mjs +537 -0
  365. package/vite.config.ts +18 -0
@@ -0,0 +1,327 @@
1
+ import { useEffect, useMemo, useState } from "react";
2
+ import { aegisPanel, estimateResources, zeroActuals, type Actuals, type DriverId, type EstimateInput } from "../lib/resource-estimator";
3
+ import { TIERS } from "../lib/gbse/tiers";
4
+ import { useAppState } from "../lib/app-state";
5
+ import { HUD } from "./HUD";
6
+ import { extractConstraints, summarizeConstraints } from "../lib/constraints";
7
+
8
+ const DRIVER_OPTIONS: { id: DriverId; label: string; notes: string }[] = [
9
+ { id: "frontier", label: "Frontier cloud", notes: "GPT-4o / Claude 3.7 class" },
10
+ { id: "gemma4-31b", label: "Gemma 4 31B", notes: "Full orchestrator via Gemini API" },
11
+ { id: "qwen3.6", label: "Qwen 3.6 class", notes: "Reasoning toggle, large context" },
12
+ { id: "gemma4-e4b", label: "Gemma 4 E4B class", notes: "Laptop / browser / WebGPU" },
13
+ { id: "apple-ondevice",label: "Apple on-device", notes: "Privacy-first, anchor-required" },
14
+ { id: "bonsai-8b", label: "Bonsai 8B class", notes: "~1.15 GB, phone-class, anchor-required" },
15
+ ];
16
+
17
+ function Calib({ label, est, actual, suffix }: { label: string; est: number; actual: number; suffix?: string }) {
18
+ const delta = actual - est;
19
+ const pct = est > 0 ? (delta / est) * 100 : 0;
20
+ const tone = Math.abs(pct) < 15 ? "text-emerald-700" : Math.abs(pct) < 35 ? "text-amber-700" : "text-rose-700";
21
+ return (
22
+ <div className="rounded-xl border border-zinc-200 bg-white p-3">
23
+ <div className="text-[10px] font-bold uppercase tracking-wider text-zinc-400">{label}</div>
24
+ <div className="mt-1 font-mono text-sm text-zinc-500">est {est.toLocaleString()}{suffix ?? ""}</div>
25
+ <div className="font-mono text-sm font-bold text-zinc-900">act {actual.toLocaleString()}{suffix ?? ""}</div>
26
+ <div className={`mt-1 font-mono text-[11px] ${tone}`}>{delta >= 0 ? "+" : ""}{delta.toLocaleString()}{suffix ?? ""} ({pct >= 0 ? "+" : ""}{pct.toFixed(0)}%)</div>
27
+ </div>
28
+ );
29
+ }
30
+
31
+ export function ResourceEstimatorPage() {
32
+ const { input: sharedInput, lastRun, busyState, settings, telemetry } = useAppState();
33
+
34
+ const [mode, setMode] = useState<"preflight" | "live" | "postrun">(lastRun ? "postrun" : "preflight");
35
+ const [startedAt, setStartedAt] = useState<number | null>(null);
36
+ const [now, setNow] = useState(Date.now());
37
+ const [input, setInput] = useState<EstimateInput>({
38
+ query: sharedInput || "Is a heat pump lower-carbon than a gas furnace in a cold climate?",
39
+ tier: 3, driver: "gemma4-31b", anchorMode: "preferred",
40
+ webAccess: "on", verifierAlpha: 0.25, councilWidth: 5, workerDepth: 9,
41
+ });
42
+
43
+ // Keep estimator query in sync with shared input
44
+ useEffect(() => {
45
+ if (sharedInput !== input.query) {
46
+ setInput(prev => ({ ...prev, query: sharedInput || "Is a heat pump lower-carbon than a gas furnace in a cold climate?" }));
47
+ }
48
+ }, [sharedInput]); // eslint-disable-line react-hooks/exhaustive-deps
49
+
50
+ // When lastRun changes, switch to postrun
51
+ useEffect(() => {
52
+ if (lastRun) {
53
+ setMode("postrun");
54
+ setStartedAt(lastRun.startedAt);
55
+ }
56
+ }, [lastRun]);
57
+
58
+ // Track live run from busyState
59
+ useEffect(() => {
60
+ if (busyState && mode !== "live") {
61
+ setMode("live");
62
+ if (!startedAt) setStartedAt(Date.now());
63
+ }
64
+ if (!busyState && mode === "live" && lastRun) {
65
+ setMode("postrun");
66
+ }
67
+ }, [busyState]); // eslint-disable-line react-hooks/exhaustive-deps
68
+
69
+ useEffect(() => {
70
+ if (mode !== "live" || !startedAt) return;
71
+ const id = window.setInterval(() => setNow(Date.now()), 500);
72
+ return () => window.clearInterval(id);
73
+ }, [mode, startedAt]);
74
+
75
+ const detectedConstraints = useMemo(() => input.query.trim() ? extractConstraints(input.query) : null, [input.query]);
76
+ const est = useMemo(() => estimateResources(input), [input]);
77
+ const elapsed = startedAt ? (now - startedAt) / 1000 : 0;
78
+ const progress = mode === "postrun" ? 1 : startedAt ? Math.min(1, elapsed / Math.max(1, est.time_s)) : 0;
79
+ // Prefer REAL measured telemetry; fall back to projection only with no run data.
80
+ const hasReal = telemetry.phase !== "idle";
81
+ const actual: Actuals = hasReal ? {
82
+ actual_in: telemetry.tokensIn,
83
+ actual_out: telemetry.tokensOut,
84
+ actual_tools: telemetry.toolCalls,
85
+ actual_paths: telemetry.hypotheses,
86
+ actual_states: telemetry.claimsTotal,
87
+ actual_ram: est.ram_bytes,
88
+ entropy: telemetry.entropy,
89
+ contradictions: telemetry.contradictions,
90
+ token_saved: Math.max(0, (est.tokens_in + est.tokens_out) - (telemetry.tokensIn + telemetry.tokensOut)),
91
+ } : (lastRun ? {
92
+ actual_in: Math.round(lastRun.totalTokens * 0.7),
93
+ actual_out: Math.round(lastRun.totalTokens * 0.3),
94
+ actual_tools: lastRun.sources,
95
+ actual_paths: lastRun.totalClaims,
96
+ actual_states: lastRun.totalClaims * 1.5,
97
+ actual_ram: est.ram_bytes,
98
+ entropy: 0.12,
99
+ contradictions: 0,
100
+ token_saved: Math.round(lastRun.totalTokens * 0.25),
101
+ } : zeroActuals());
102
+ const panelElapsed = hasReal ? telemetry.elapsedMs / 1000 : (mode === "postrun" && lastRun ? lastRun.elapsedMs / 1000 : elapsed);
103
+ const panel = aegisPanel(est, actual, panelElapsed);
104
+
105
+ const realActual = lastRun ? {
106
+ actual_time_s: lastRun.elapsedMs / 1000,
107
+ actual_sources: lastRun.sources,
108
+ actual_claims: lastRun.totalClaims,
109
+ actual_verified: lastRun.verifiedClaims,
110
+ actual_tokens: lastRun.totalTokens,
111
+ } : null;
112
+
113
+ function set<K extends keyof EstimateInput>(key: K, value: EstimateInput[K]) {
114
+ setInput(prev => ({ ...prev, [key]: value }));
115
+ }
116
+
117
+ const isComplete = mode === "postrun" && lastRun !== null;
118
+ const cards = [
119
+ { icon: "⏱", label: "Time", value: isComplete ? `${(lastRun.elapsedMs / 1000).toFixed(1)}s` : `${est.time_s}s`, sub: isComplete ? "real-time" : "forecast wall time" },
120
+ { icon: "🪙", label: "Tokens", value: isComplete ? `${(telemetry.tokensIn + telemetry.tokensOut).toLocaleString()}` : (est.tokens_in + est.tokens_out).toLocaleString(), sub: isComplete ? `${telemetry.tokensIn.toLocaleString()} in / ${telemetry.tokensOut.toLocaleString()} out` : `${est.tokens_in.toLocaleString()} in / ${est.tokens_out.toLocaleString()} out` },
121
+ { icon: "🔧", label: "Tools", value: isComplete ? String(telemetry.toolCalls) : String(est.tools), sub: "web + anchor + verifier calls" },
122
+ { icon: "🧭", label: "Paths", value: isComplete ? String(telemetry.hypotheses) : String(est.paths), sub: "council × worker branches" },
123
+ { icon: "🎯", label: "Coverage", value: isComplete && lastRun?.measuredCoverage ? `${(lastRun.measuredCoverage * 100).toFixed(1)}%` : `${(est.coverage * 100).toFixed(1)}%`, sub: isComplete && lastRun ? `${lastRun.coverageNumerator}/${lastRun.coverageDenominator} facets` : "required facets" },
124
+ { icon: "💾", label: "Sparse RAM", value: `${(est.ram_bytes / 1024).toFixed(1)} KB`, sub: "graph/state bookkeeping" },
125
+ ];
126
+
127
+ return (
128
+ <div className="bg-zinc-50 pb-10">
129
+ <div className="mx-auto max-w-6xl space-y-5 px-4 py-6">
130
+ {/* Header */}
131
+ <section className="rounded-2xl border border-zinc-200 bg-white p-5 shadow-sm">
132
+ <div className="flex flex-wrap items-start justify-between gap-4">
133
+ <div>
134
+ <div className="text-xs font-bold uppercase tracking-[0.2em] text-indigo-600">AEGIS-PHI Resource Estimator</div>
135
+ <h1 className="mt-1 text-2xl font-bold tracking-tight text-zinc-900">Pre-flight · live-run · post-run telemetry</h1>
136
+ <p className="mt-2 max-w-3xl text-sm text-zinc-600">
137
+ Estimates auto-populate from the shared input and last run. Switch to <strong>Live</strong> during a GBSE run to see real-time deltas.
138
+ Post-run calibrates forecast accuracy against measured actuals.
139
+ </p>
140
+ </div>
141
+ <div className="flex rounded-xl border border-zinc-200 bg-zinc-50 p-1 text-xs font-semibold">
142
+ {(["preflight", "live", "postrun"] as const).map(m => (
143
+ <button key={m} onClick={() => setMode(m)}
144
+ className={`rounded-lg px-3 py-2 ${mode === m ? "bg-zinc-900 text-white" : "text-zinc-600 hover:bg-white"}`}>
145
+ {m === "preflight" ? "Pre-flight" : m === "live" ? "Live" : "Post-run"}
146
+ {m === "live" && busyState && <span className="ml-1.5 inline-block h-1.5 w-1.5 animate-pulse rounded-full bg-amber-400" />}
147
+ {m === "postrun" && lastRun && <span className="ml-1.5 inline-block h-1.5 w-1.5 rounded-full bg-emerald-400" />}
148
+ </button>
149
+ ))}
150
+ </div>
151
+ </div>
152
+ </section>
153
+
154
+ {/* Live AEGIS-PHI HUD — real measured telemetry */}
155
+ {hasReal && <HUD />}
156
+
157
+ {/* Live activity indicator */}
158
+ {mode === "live" && busyState && (
159
+ <div className="rounded-2xl border border-amber-200 bg-amber-50 p-4 shadow-sm flex items-center gap-3">
160
+ <span className="h-4 w-4 animate-spin rounded-full border-2 border-amber-600 border-t-transparent shrink-0" />
161
+ <div>
162
+ <div className="text-xs font-bold uppercase text-amber-700">Live run in progress</div>
163
+ <div className="text-sm text-amber-900">{busyState}</div>
164
+ </div>
165
+ <div className="ml-auto font-mono text-sm text-amber-700">{elapsed.toFixed(1)}s elapsed</div>
166
+ </div>
167
+ )}
168
+
169
+ {/* Post-run summary from real data */}
170
+ {mode === "postrun" && lastRun && (
171
+ <div className="rounded-2xl border border-emerald-200 bg-emerald-50 p-4 shadow-sm">
172
+ <div className="mb-2 text-xs font-bold uppercase tracking-wider text-emerald-700">Real run data — {new Date(lastRun.finishedAt).toLocaleTimeString()}</div>
173
+ <div className="grid grid-cols-2 gap-3 sm:grid-cols-4 text-xs">
174
+ <div><div className="text-emerald-600 font-bold">Query</div><div className="text-zinc-800 truncate">{lastRun.query.slice(0, 60)}</div></div>
175
+ <div><div className="text-emerald-600 font-bold">Elapsed</div><div className="font-mono font-bold text-zinc-900">{(lastRun.elapsedMs / 1000).toFixed(1)}s</div></div>
176
+ <div><div className="text-emerald-600 font-bold">Sources</div><div className="font-mono font-bold text-zinc-900">{lastRun.sources}</div></div>
177
+ <div><div className="text-emerald-600 font-bold">Claims</div><div className="font-mono font-bold text-zinc-900">{lastRun.verifiedClaims}/{lastRun.totalClaims} verified</div></div>
178
+ {lastRun.constraints && (
179
+ <div className="sm:col-span-4"><div className="text-emerald-600 font-bold">Constraints enforced</div><div className="font-mono text-zinc-800">{summarizeConstraints(lastRun.constraints)}</div></div>
180
+ )}
181
+ </div>
182
+ </div>
183
+ )}
184
+
185
+ <section className="grid gap-5 lg:grid-cols-[360px_1fr]">
186
+ {/* Controls */}
187
+ <div className="rounded-2xl border border-zinc-200 bg-white p-4 shadow-sm">
188
+ <div className="flex items-center justify-between mb-4">
189
+ <h2 className="text-sm font-bold text-zinc-900">Pre-flight details</h2>
190
+ {settings.deepResearch && <span className="rounded-full bg-indigo-100 px-2 py-0.5 text-[10px] font-bold text-indigo-800">4-Stage pipeline</span>}
191
+ </div>
192
+ <div className="space-y-4">
193
+ <div className="rounded-xl border border-zinc-200 bg-zinc-50 px-3 py-2.5 text-sm text-zinc-600">
194
+ <div className="text-[10px] font-bold uppercase tracking-wider text-zinc-400 mb-1">Target query (from shared input)</div>
195
+ {input.query || "No query entered yet."}
196
+ </div>
197
+ {detectedConstraints && (
198
+ <div className="rounded-xl border border-indigo-100 bg-indigo-50 p-2 text-[11px] text-indigo-900">
199
+ Detected: {summarizeConstraints(detectedConstraints)}
200
+ {detectedConstraints.isShortHorizon && " · SHORT HORIZON — 1yr targets excluded"}
201
+ </div>
202
+ )}
203
+ <div className="grid grid-cols-2 gap-3">
204
+ <label className="block text-xs font-semibold text-zinc-600">
205
+ Tier
206
+ <select value={input.tier} onChange={e => set("tier", Number(e.target.value))} className="mt-1 w-full rounded-xl border border-zinc-300 px-3 py-2 text-sm">
207
+ {Object.values(TIERS).map(t => <option key={t.tier} value={t.tier}>T{t.tier} {t.name}</option>)}
208
+ </select>
209
+ </label>
210
+ <label className="block text-xs font-semibold text-zinc-600">
211
+ Driver
212
+ <select value={input.driver} onChange={e => set("driver", e.target.value as DriverId)} className="mt-1 w-full rounded-xl border border-zinc-300 px-3 py-2 text-sm">
213
+ {DRIVER_OPTIONS.map(d => <option key={d.id} value={d.id}>{d.label}</option>)}
214
+ </select>
215
+ </label>
216
+ </div>
217
+ {input.driver && (
218
+ <div className="rounded-xl border border-zinc-100 bg-zinc-50 p-2 text-[11px] text-zinc-600">
219
+ {DRIVER_OPTIONS.find(d => d.id === input.driver)?.notes}
220
+ </div>
221
+ )}
222
+ <div className="grid grid-cols-2 gap-3">
223
+ <label className="block text-xs font-semibold text-zinc-600">
224
+ Anchor mode
225
+ <select value={input.anchorMode} onChange={e => set("anchorMode", e.target.value as EstimateInput["anchorMode"])} className="mt-1 w-full rounded-xl border border-zinc-300 px-3 py-2 text-sm">
226
+ <option value="required">required</option>
227
+ <option value="preferred">preferred</option>
228
+ <option value="off">off</option>
229
+ </select>
230
+ </label>
231
+ <label className="block text-xs font-semibold text-zinc-600">
232
+ Web access
233
+ <select value={input.webAccess} onChange={e => set("webAccess", e.target.value as EstimateInput["webAccess"])} className="mt-1 w-full rounded-xl border border-zinc-300 px-3 py-2 text-sm">
234
+ <option value="on">on</option>
235
+ <option value="trusted">trusted only</option>
236
+ <option value="off">off (anchor-only)</option>
237
+ </select>
238
+ </label>
239
+ </div>
240
+ <label className="block text-xs font-semibold text-zinc-600">
241
+ Verifier alpha {(input.verifierAlpha * 100).toFixed(0)}%
242
+ <input type="range" min="0.1" max="0.4" step="0.01" value={input.verifierAlpha} onChange={e => set("verifierAlpha", Number(e.target.value))} className="mt-2 w-full" />
243
+ </label>
244
+ <div className="grid grid-cols-2 gap-3">
245
+ <label className="block text-xs font-semibold text-zinc-600">
246
+ Council width
247
+ <input type="number" min="1" max="32" value={input.councilWidth} onChange={e => set("councilWidth", Number(e.target.value))} className="mt-1 w-full rounded-xl border border-zinc-300 px-3 py-2 text-sm" />
248
+ </label>
249
+ <label className="block text-xs font-semibold text-zinc-600">
250
+ Worker depth
251
+ <input type="number" min="1" max="32" value={input.workerDepth} onChange={e => set("workerDepth", Number(e.target.value))} className="mt-1 w-full rounded-xl border border-zinc-300 px-3 py-2 text-sm" />
252
+ </label>
253
+ </div>
254
+ </div>
255
+ </div>
256
+
257
+ <div className="space-y-4">
258
+ {/* Metric cards */}
259
+ <div className="grid gap-3 sm:grid-cols-3">
260
+ {cards.map(({ icon, label, value, sub }) => (
261
+ <div key={label} className="rounded-xl border border-zinc-200 bg-white p-4 shadow-sm">
262
+ <div className="flex items-center gap-1.5 text-[10px] font-bold uppercase tracking-[0.15em] text-zinc-400">
263
+ <span>{icon}</span>{label}
264
+ </div>
265
+ <div className="mt-1.5 font-mono text-xl font-bold text-zinc-900">{value}</div>
266
+ <div className="mt-0.5 text-[10px] text-zinc-500">{sub}</div>
267
+ </div>
268
+ ))}
269
+ </div>
270
+
271
+ {/* Coverage bar */}
272
+ <div className="rounded-xl border border-zinc-200 bg-white p-4 shadow-sm">
273
+ <div className="flex items-center justify-between mb-2">
274
+ <span className="text-xs font-bold text-zinc-700">Forecast coverage</span>
275
+ <span className="font-mono text-sm font-bold text-indigo-700">{(est.coverage * 100).toFixed(1)}%</span>
276
+ </div>
277
+ <div className="h-2.5 w-full overflow-hidden rounded-full bg-zinc-100">
278
+ <div className="h-full bg-gradient-to-r from-sky-400 to-indigo-500 rounded-full" style={{ width: `${est.coverage * 100}%` }} />
279
+ </div>
280
+ <div className="mt-2 flex justify-between text-[10px] text-zinc-400">
281
+ <span>Residual ~{(100 - est.coverage * 100).toFixed(0)}%: paywalled / post-cutoff / non-existent</span>
282
+ </div>
283
+ </div>
284
+
285
+ {/* Calibration vs real run */}
286
+ {mode === "postrun" && realActual && (
287
+ <div className="rounded-xl border border-emerald-200 bg-emerald-50 p-4 shadow-sm">
288
+ <div className="mb-3 text-xs font-bold uppercase tracking-wider text-emerald-700">Calibration: forecast vs. real measured data</div>
289
+ <div className="grid gap-2 sm:grid-cols-4">
290
+ <Calib label="Time" est={est.time_s} actual={realActual.actual_time_s} suffix="s" />
291
+ <Calib label="Sources" est={est.tools} actual={realActual.actual_sources} />
292
+ <Calib label="Claims" est={est.paths} actual={realActual.actual_claims} />
293
+ <Calib label="Verified" est={Math.round(est.paths * 0.6)} actual={realActual.actual_verified} />
294
+ </div>
295
+ </div>
296
+ )}
297
+
298
+ {/* AEGIS panel (ASCII) */}
299
+ <div className="rounded-2xl border border-zinc-200 bg-zinc-950 p-4 shadow-sm overflow-x-auto">
300
+ <pre className="whitespace-pre font-mono text-[11px] leading-snug text-emerald-200">{panel}</pre>
301
+ </div>
302
+
303
+ {/* Lifecycle phases */}
304
+ <div className="rounded-xl border border-zinc-200 bg-white p-4 shadow-sm">
305
+ <div className="flex items-center justify-between mb-3">
306
+ <h2 className="text-sm font-bold text-zinc-900">Run lifecycle phases</h2>
307
+ <span className="font-mono text-xs text-zinc-500">progress {(progress * 100).toFixed(0)}%</span>
308
+ </div>
309
+ <div className="grid gap-3 md:grid-cols-3">
310
+ {[
311
+ { label: "Pre-flight", desc: "Estimate before spending — edit tier, driver, anchor mode", active: mode === "preflight" },
312
+ { label: "Live", desc: "Estimate vs. actual deltas update in real time during run", active: mode === "live" },
313
+ { label: "Post-run", desc: "Calibration: measured actuals vs. forecast — Brier-style accuracy", active: mode === "postrun" },
314
+ ].map(({ label, desc, active }) => (
315
+ <div key={label} className={`rounded-xl border p-3 ${active ? "border-indigo-300 bg-indigo-50" : "border-zinc-200 bg-zinc-50"}`}>
316
+ <div className="text-sm font-bold text-zinc-900">{label}</div>
317
+ <div className="mt-1 text-xs text-zinc-600">{desc}</div>
318
+ </div>
319
+ ))}
320
+ </div>
321
+ </div>
322
+ </div>
323
+ </section>
324
+ </div>
325
+ </div>
326
+ );
327
+ }
@@ -0,0 +1,181 @@
1
+ import { ReactNode } from "react";
2
+
3
+ /**
4
+ * Enhanced Safe Rich-Text Renderer.
5
+ * Supports:
6
+ * - bold **text**
7
+ * - headings ###
8
+ * - Visually pleasing tables (Markdown pipe syntax)
9
+ * - Bullets / numbered lists
10
+ * - Mermaid diagrams spec (deterministic speccing)
11
+ *
12
+ * This addresses the "visually please table" and "graphs/flow charts" requirements.
13
+ */
14
+ export function RichText({ text }: { text: string }) {
15
+ const blocks = splitBlocks(text);
16
+ return (
17
+ <div className="space-y-4">
18
+ {blocks.map((b, i) => <Block key={i} block={b} />)}
19
+ </div>
20
+ );
21
+ }
22
+
23
+ type BlockType =
24
+ | { kind: "heading"; level: number; text: string }
25
+ | { kind: "table"; rows: string[][] }
26
+ | { kind: "ul"; items: string[] }
27
+ | { kind: "ol"; items: string[] }
28
+ | { kind: "mermaid"; code: string }
29
+ | { kind: "p"; text: string };
30
+
31
+ function splitBlocks(src: string): BlockType[] {
32
+ const lines = src.replace(/\r\n/g, "\n").split("\n");
33
+ const out: BlockType[] = [];
34
+ let i = 0;
35
+ while (i < lines.length) {
36
+ const line = lines[i];
37
+ if (!line.trim()) { i++; continue; }
38
+
39
+ // Mermaid code block
40
+ if (line.startsWith("```mermaid")) {
41
+ const buf: string[] = [];
42
+ i++;
43
+ while (i < lines.length && !lines[i].startsWith("```")) {
44
+ buf.push(lines[i]);
45
+ i++;
46
+ }
47
+ i++;
48
+ out.push({ kind: "mermaid", code: buf.join("\n") });
49
+ continue;
50
+ }
51
+
52
+ // Heading
53
+ const hm = line.match(/^(#{1,6})\s+(.*)$/);
54
+ if (hm) {
55
+ out.push({ kind: "heading", level: hm[1].length, text: hm[2] });
56
+ i++; continue;
57
+ }
58
+
59
+ // Table
60
+ if (/^\|.*\|\s*$/.test(line) && i + 1 < lines.length && /^\|?\s*:?[- ]+:?/.test(lines[i + 1])) {
61
+ const rows: string[][] = [];
62
+ rows.push(parseTableRow(line));
63
+ i += 2; // skip separator
64
+ while (i < lines.length && /^\|.*\|\s*$/.test(lines[i])) {
65
+ rows.push(parseTableRow(lines[i]));
66
+ i++;
67
+ }
68
+ out.push({ kind: "table", rows });
69
+ continue;
70
+ }
71
+
72
+ // Lists
73
+ if (/^[-*]\s+/.test(line)) {
74
+ const items: string[] = [];
75
+ while (i < lines.length && /^[-*]\s+/.test(lines[i])) {
76
+ items.push(lines[i].replace(/^[-*]\s+/, ""));
77
+ i++;
78
+ }
79
+ out.push({ kind: "ul", items });
80
+ continue;
81
+ }
82
+ if (/^\d+\.\s+/.test(line)) {
83
+ const items: string[] = [];
84
+ while (i < lines.length && /^\d+\.\s+/.test(lines[i])) {
85
+ items.push(lines[i].replace(/^\d+\.\s+/, ""));
86
+ i++;
87
+ }
88
+ out.push({ kind: "ol", items });
89
+ continue;
90
+ }
91
+
92
+ // Paragraph
93
+ const buf: string[] = [];
94
+ while (i < lines.length && lines[i].trim() && !/^(#{1,6}|```|\||[-*]|\d+\.)/.test(lines[i])) {
95
+ buf.push(lines[i]);
96
+ i++;
97
+ }
98
+ out.push({ kind: "p", text: buf.join(" ") });
99
+ }
100
+ return out;
101
+ }
102
+
103
+ function parseTableRow(line: string): string[] {
104
+ return line.trim().replace(/^\|/, "").replace(/\|$/, "").split("|").map(c => c.trim());
105
+ }
106
+
107
+ function renderInline(s: string): ReactNode[] {
108
+ const out: ReactNode[] = [];
109
+ let i = 0;
110
+ while (i < s.length) {
111
+ const bold = s.slice(i).match(/^\*\*([^*]+)\*\*/);
112
+ if (bold) {
113
+ out.push(<strong key={out.length} className="font-bold text-zinc-900">{bold[1]}</strong>);
114
+ i += bold[0].length;
115
+ continue;
116
+ }
117
+ const italic = s.slice(i).match(/^\*([^*]+)\*/);
118
+ if (italic) {
119
+ out.push(<em key={out.length}>{italic[1]}</em>);
120
+ i += italic[0].length;
121
+ continue;
122
+ }
123
+ out.push(s[i]);
124
+ i++;
125
+ }
126
+ return out;
127
+ }
128
+
129
+ function Block({ block }: { block: BlockType }) {
130
+ switch (block.kind) {
131
+ case "heading": {
132
+ const cls = block.level <= 2 ? "text-xl font-bold text-zinc-900 border-b border-zinc-200 pb-1 mt-6 mb-4" : "text-sm font-bold text-zinc-800 mt-4 mb-2 uppercase tracking-wide";
133
+ if (block.level === 1) return <h1 className={cls}>{renderInline(block.text)}</h1>;
134
+ if (block.level === 2) return <h2 className={cls}>{renderInline(block.text)}</h2>;
135
+ if (block.level === 3) return <h3 className={cls}>{renderInline(block.text)}</h3>;
136
+ if (block.level === 4) return <h4 className={cls}>{renderInline(block.text)}</h4>;
137
+ return <div className={cls}>{renderInline(block.text)}</div>;
138
+ }
139
+ case "table":
140
+ return (
141
+ <div className="overflow-x-auto my-6 rounded-xl border border-zinc-200 shadow-sm">
142
+ <table className="w-full text-sm border-collapse">
143
+ <thead className="bg-zinc-50/80 backdrop-blur border-b border-zinc-200">
144
+ <tr>
145
+ {block.rows[0].map((c, i) => (
146
+ <th key={i} className="px-4 py-3 text-left font-bold text-zinc-700 uppercase tracking-wider text-[11px] border-r border-zinc-200 last:border-0">{renderInline(c)}</th>
147
+ ))}
148
+ </tr>
149
+ </thead>
150
+ <tbody className="divide-y divide-zinc-100">
151
+ {block.rows.slice(1).map((r, i) => (
152
+ <tr key={i} className="hover:bg-indigo-50/30 transition-colors">
153
+ {r.map((c, j) => (
154
+ <td key={j} className="px-4 py-3 text-zinc-800 border-r border-zinc-100 last:border-0">{renderInline(c)}</td>
155
+ ))}
156
+ </tr>
157
+ ))}
158
+ </tbody>
159
+ </table>
160
+ </div>
161
+ );
162
+ case "ul":
163
+ return <ul className="list-disc pl-6 space-y-2 text-sm text-zinc-800 my-4">{block.items.map((x, i) => <li key={i}>{renderInline(x)}</li>)}</ul>;
164
+ case "ol":
165
+ return <ol className="list-decimal pl-6 space-y-2 text-sm text-zinc-800 my-4">{block.items.map((x, i) => <li key={i}>{renderInline(x)}</li>)}</ol>;
166
+ case "mermaid":
167
+ return (
168
+ <div className="my-6 p-4 bg-zinc-50 border border-zinc-200 rounded-2xl flex flex-col items-center">
169
+ <div className="text-[10px] font-bold text-zinc-400 uppercase mb-3">Diagram Specification (Mermaid)</div>
170
+ <pre className="text-[10px] font-mono text-indigo-700 bg-white border border-indigo-100 p-4 rounded-xl w-full overflow-auto">
171
+ {block.code}
172
+ </pre>
173
+ <div className="mt-2 text-[9px] text-zinc-400 italic">Visualizing via deterministic specs...</div>
174
+ </div>
175
+ );
176
+ case "p":
177
+ return <p className="text-sm leading-relaxed text-zinc-800 my-3">{renderInline(block.text)}</p>;
178
+ default:
179
+ return null;
180
+ }
181
+ }