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,135 @@
1
+ import { useMemo } from "react";
2
+ import {
3
+ DEFAULT_SEED_CONTROL,
4
+ selectSeedDirectives,
5
+ type SeedControl,
6
+ } from "../fiction/seed-control";
7
+ import { cx } from "./util";
8
+
9
+ interface Props {
10
+ control: SeedControl;
11
+ setControl: React.Dispatch<React.SetStateAction<SeedControl>>;
12
+ seed: number;
13
+ previewChapter: number;
14
+ }
15
+
16
+ function SliderRow({ label, value, min, max, step = 1, hint, onChange }: {
17
+ label: string; value: number; min: number; max: number; step?: number; hint: string;
18
+ onChange: (v: number) => void;
19
+ }) {
20
+ return (
21
+ <label className="block rounded-lg border border-zinc-200 bg-white p-2">
22
+ <div className="flex items-baseline justify-between">
23
+ <span className="text-xs font-semibold text-zinc-800">{label}</span>
24
+ <span className="font-mono text-xs font-bold text-teal-700">{value}</span>
25
+ </div>
26
+ <input
27
+ type="range" min={min} max={max} step={step} value={value}
28
+ onChange={(e) => onChange(Number(e.target.value))}
29
+ className="mt-1 w-full accent-teal-600"
30
+ />
31
+ <div className="text-[10px] leading-snug text-zinc-500">{hint}</div>
32
+ </label>
33
+ );
34
+ }
35
+
36
+ function LockField({ label, value, placeholder, onChange }: {
37
+ label: string; value: string; placeholder: string; onChange: (v: string) => void;
38
+ }) {
39
+ const locked = value.trim().length > 0;
40
+ return (
41
+ <label className={cx("block rounded-lg border p-2", locked ? "border-amber-300 bg-amber-50/50" : "border-zinc-200 bg-white")}>
42
+ <div className="flex items-center justify-between">
43
+ <span className="text-xs font-semibold text-zinc-800">{label}</span>
44
+ <span className={cx("rounded px-1.5 py-0.5 text-[9px] font-bold uppercase", locked ? "bg-amber-200 text-amber-900" : "bg-zinc-100 text-zinc-500")}>
45
+ {locked ? "🔒 locked" : "unlocked"}
46
+ </span>
47
+ </div>
48
+ <input
49
+ value={value}
50
+ onChange={(e) => onChange(e.target.value)}
51
+ placeholder={placeholder}
52
+ className="mt-1 w-full rounded-md border border-zinc-300 px-2 py-1 text-[11px] text-zinc-800"
53
+ />
54
+ </label>
55
+ );
56
+ }
57
+
58
+ export function SeedControlPanel({ control, setControl, seed, previewChapter }: Props) {
59
+ const set = (patch: Partial<SeedControl>) => setControl((p) => ({ ...p, ...patch }));
60
+ const setLock = (k: keyof SeedControl["locks"], v: string) =>
61
+ setControl((p) => ({ ...p, locks: { ...p.locks, [k]: v } }));
62
+
63
+ const preview = useMemo(
64
+ () => selectSeedDirectives(seed, Math.max(0, previewChapter - 1), control),
65
+ [seed, previewChapter, control],
66
+ );
67
+
68
+ return (
69
+ <div className="space-y-3 text-[13px]">
70
+ <div className="rounded-xl border border-teal-200 bg-white p-3 shadow-sm">
71
+ <div className="flex flex-wrap items-center justify-between gap-2 border-b border-zinc-100 pb-2">
72
+ <div>
73
+ <h4 className="font-bold text-zinc-900">🌱 Seed Idea-Mix &amp; Author Locks</h4>
74
+ <p className="text-[11px] text-zinc-500">
75
+ Deterministic per-chapter directives (seed {seed}) + hard author locks injected into the live chapter prompt.
76
+ </p>
77
+ </div>
78
+ <label className="flex items-center gap-1.5 text-xs font-semibold text-zinc-700">
79
+ <input type="checkbox" checked={control.enabled} onChange={(e) => set({ enabled: e.target.checked })} className="h-4 w-4 accent-teal-600" />
80
+ Seed block {control.enabled ? "ON" : "OFF"}
81
+ </label>
82
+ </div>
83
+
84
+ <div className="mt-3 grid grid-cols-1 gap-2 sm:grid-cols-3">
85
+ <SliderRow label="Empty-space vs human-seen mix" value={control.emptyVsHumanMix} min={0} max={100}
86
+ hint="Share of system-scale (infrastructure/institution/ecology) beats vs human-scale beats per chapter."
87
+ onChange={(v) => set({ emptyVsHumanMix: v })} />
88
+ <SliderRow label="Motifs per chapter" value={control.motifsPerChapter} min={0} max={6}
89
+ hint="Recurring seed motifs active in each chapter. 0 = none injected."
90
+ onChange={(v) => set({ motifsPerChapter: v })} />
91
+ <SliderRow label="New concepts per chapter" value={control.conceptsPerChapter} min={0} max={4}
92
+ hint="Target count of NEW named worldbuilding concepts. Complements the continuity cap."
93
+ onChange={(v) => set({ conceptsPerChapter: v })} />
94
+ </div>
95
+
96
+ <div className="mt-2 grid grid-cols-1 gap-2 sm:grid-cols-2">
97
+ <LockField label="Locked setting" value={control.locks.setting} placeholder="e.g. Keistlddsto Estuary lime kilns at low tide"
98
+ onChange={(v) => setLock("setting", v)} />
99
+ <LockField label="Locked core concept" value={control.locks.coreConcept} placeholder="e.g. The truth canister must physically change hands each act"
100
+ onChange={(v) => setLock("coreConcept", v)} />
101
+ <LockField label="Locked theme" value={control.locks.theme} placeholder="e.g. Debts are inherited, never forgiven"
102
+ onChange={(v) => setLock("theme", v)} />
103
+ <LockField label="Locked motif seed" value={control.locks.motif} placeholder="e.g. mended cloth"
104
+ onChange={(v) => setLock("motif", v)} />
105
+ </div>
106
+
107
+ <div className="mt-2 flex justify-end">
108
+ <button type="button" onClick={() => setControl({ ...DEFAULT_SEED_CONTROL, locks: { ...DEFAULT_SEED_CONTROL.locks } })}
109
+ className="rounded-lg border border-zinc-300 bg-zinc-50 px-3 py-1 text-xs font-semibold text-zinc-700 hover:bg-zinc-100">
110
+ Reset to defaults
111
+ </button>
112
+ </div>
113
+ </div>
114
+
115
+ <div className="rounded-xl border border-zinc-200 bg-white p-3 shadow-sm">
116
+ <h4 className="font-bold text-zinc-900">🔍 Deterministic preview — chapter {previewChapter}</h4>
117
+ <p className="text-[11px] text-zinc-500">Exactly what the live prompt will carry for this chapter (same seed + controls = same output).</p>
118
+ <div className="mt-2 space-y-1.5 text-[11px] text-zinc-700">
119
+ {preview.emptySpace.map((d, i) => (
120
+ <div key={`e${i}`} className="rounded border border-sky-200 bg-sky-50/60 p-1.5"><b className="text-sky-800">[empty-space]</b> {d}</div>
121
+ ))}
122
+ {preview.humanSeen.map((d, i) => (
123
+ <div key={`h${i}`} className="rounded border border-rose-200 bg-rose-50/60 p-1.5"><b className="text-rose-800">[human-seen]</b> {d}</div>
124
+ ))}
125
+ <div className="rounded border border-zinc-200 bg-zinc-50 p-1.5">
126
+ <b>Motifs ({preview.motifs.length}):</b> {preview.motifs.length ? preview.motifs.join("; ") : "(none)"}
127
+ </div>
128
+ <div className="rounded border border-zinc-200 bg-zinc-50 p-1.5">
129
+ <b>New-concept target:</b> exactly {preview.conceptsTarget}
130
+ </div>
131
+ </div>
132
+ </div>
133
+ </div>
134
+ );
135
+ }
@@ -0,0 +1,443 @@
1
+ import { useState, useRef, useEffect, useCallback, useMemo } from "react";
2
+ import {
3
+ generateSingleChapterWithContinuity,
4
+ parseChaptersFromText,
5
+ createStorySnapshot,
6
+ } from "../fiction/story-engine";
7
+ import { applySeedLocks, type SeedControl } from "../fiction/seed-control";
8
+ import { rebuildLedger, EMPTY_LEDGER, type ContinuityLedger, stripHarnessResidue } from "../fiction/continuity";
9
+ import { StoryCrashProtector, type StoryEngineStatus } from "../fiction/crash-protection";
10
+ import { EntityStateMachine } from "../fiction/entity-state-machine";
11
+ import type { StorySnapshot, ContinuityToggles } from "../fiction/types";
12
+ import { attemptAdoptToEngine } from "./engineBridge";
13
+ import { cx, copyText } from "./util";
14
+
15
+ interface Props {
16
+ manuscript: string;
17
+ setManuscript: (s: string) => void;
18
+ apiKey: string;
19
+ toggles: ContinuityToggles;
20
+ iframeRef: React.RefObject<HTMLIFrameElement | null>;
21
+ modelPool: string[];
22
+ seedControl?: SeedControl | null;
23
+ }
24
+
25
+ export function StoryControllerPanel({
26
+ manuscript,
27
+ setManuscript,
28
+ apiKey,
29
+ toggles,
30
+ iframeRef,
31
+ modelPool,
32
+ seedControl = null,
33
+ }: Props) {
34
+ const [selectedModel, setSelectedModel] = useState<string>("gemini-2.5-flash");
35
+ const [seed, setSeed] = useState<number>(() => {
36
+ const cp = StoryCrashProtector.loadCheckpoint();
37
+ return cp ? cp.seed : (Date.now() % 1000000);
38
+ });
39
+ const [totalChapters, setTotalChapters] = useState<number>(() => {
40
+ const cp = StoryCrashProtector.loadCheckpoint();
41
+ return cp ? cp.totalChapters : 16;
42
+ });
43
+ const [engineStatus, setEngineStatus] = useState<StoryEngineStatus>(() => StoryCrashProtector.getActiveStatus());
44
+ const [currentChIndex, setCurrentChIndex] = useState<number>(0);
45
+ const [log, setLog] = useState<string[]>([]);
46
+ const abortControllerRef = useRef<AbortController | null>(null);
47
+
48
+ // Parse existing chapters from the current manuscript (memoized: O(n) scan must not rerun per keystroke at novel scale)
49
+ const cleanCurrentManuscript = useMemo(() => stripHarnessResidue(manuscript).text, [manuscript]);
50
+ const existingChapters = useMemo(() => parseChaptersFromText(cleanCurrentManuscript), [cleanCurrentManuscript]);
51
+ const completedCount = existingChapters.length;
52
+ const nextChapterToRun = completedCount + 1;
53
+
54
+ const addLog = useCallback((msg: string) => {
55
+ setLog((prev) => [...prev.slice(-50), `[${new Date().toLocaleTimeString()}] ${msg}`]);
56
+ }, []);
57
+
58
+ // Sync external status changes
59
+ useEffect(() => {
60
+ const onStatusChanged = (e: any) => {
61
+ if (e?.detail?.status) setEngineStatus(e.detail.status);
62
+ };
63
+ window.addEventListener("saga:status-changed", onStatusChanged);
64
+ return () => window.removeEventListener("saga:status-changed", onStatusChanged);
65
+ }, []);
66
+
67
+ const handleStop = () => {
68
+ if (abortControllerRef.current) {
69
+ abortControllerRef.current.abort();
70
+ abortControllerRef.current = null;
71
+ }
72
+ setEngineStatus("stopped");
73
+ StoryCrashProtector.updateStatus("stopped");
74
+ addLog("Story generation stopped by user. Checkpoint safely locked.");
75
+ };
76
+
77
+ const handlePause = () => {
78
+ if (abortControllerRef.current) {
79
+ abortControllerRef.current.abort();
80
+ abortControllerRef.current = null;
81
+ }
82
+ setEngineStatus("paused");
83
+ StoryCrashProtector.updateStatus("paused");
84
+ addLog("Story generation paused at chapter boundary.");
85
+ };
86
+
87
+ const runGenerationLoop = async (startFromCh: number) => {
88
+ if (!apiKey.trim()) {
89
+ addLog("Error: Missing API key. Please configure key in Settings first.");
90
+ return;
91
+ }
92
+
93
+ setEngineStatus("running");
94
+ StoryCrashProtector.updateStatus("running");
95
+ abortControllerRef.current = new AbortController();
96
+ const signal = abortControllerRef.current.signal;
97
+
98
+ try {
99
+ addLog(`Initializing deterministic story blueprint (Seed: ${seed}, Chapters: ${totalChapters})...`);
100
+ const snapshot: StorySnapshot = createStorySnapshot(seed, totalChapters);
101
+ if (seedControl?.enabled) {
102
+ applySeedLocks(snapshot, seedControl);
103
+ const locked = Object.entries(seedControl.locks).filter(([, v]) => v.trim()).map(([k]) => k);
104
+ addLog(locked.length ? `Author locks applied: ${locked.join(", ")}.` : "Seed directives enabled (no locks set).");
105
+ }
106
+ const esm = new EntityStateMachine();
107
+
108
+ let ledger: ContinuityLedger = existingChapters.length > 0
109
+ ? rebuildLedger(snapshot, existingChapters)
110
+ : EMPTY_LEDGER;
111
+
112
+ let accumulatedManuscript = cleanCurrentManuscript;
113
+ let priorSummary: string | null = existingChapters.length > 0
114
+ ? existingChapters[existingChapters.length - 1].text.slice(0, 420).replace(/\s+/g, " ")
115
+ : null;
116
+
117
+ let completedThisRun = 0;
118
+ for (let chIdx = startFromCh - 1; chIdx < totalChapters; chIdx++) {
119
+ if (signal.aborted) break;
120
+ const currentChapterNum = chIdx + 1;
121
+ setCurrentChIndex(currentChapterNum);
122
+ addLog(`Executing Chapter ${currentChapterNum} of ${totalChapters} using [${selectedModel}]`);
123
+
124
+ // Check if setting transition triggers modulo-4 carousel warning (advisory only — never blocks).
125
+ const chDef = snapshot.blueprint.chapters[chIdx];
126
+ if (chDef?.settingFocus) {
127
+ const transitCheck = esm.stepLocation(chDef.settingFocus);
128
+ if (!transitCheck.validTransit && transitCheck.warning) {
129
+ addLog(`⚠ Topographic Router: ${transitCheck.warning}`);
130
+ }
131
+ }
132
+
133
+ let chapterBody = "";
134
+ let chTitle = snapshot.blueprint.chapters[chIdx]?.title || `Chapter ${currentChapterNum}`;
135
+ try {
136
+ const res = await generateSingleChapterWithContinuity({
137
+ snapshot,
138
+ chapterIndex: chIdx,
139
+ model: selectedModel,
140
+ apiKey,
141
+ provider: "gemini",
142
+ ledger,
143
+ toggles,
144
+ priorSummary,
145
+ signal,
146
+ onLog: addLog,
147
+ seedControl,
148
+ });
149
+ // Already sanitized inside the generator; residual strip is a no-op safety net.
150
+ chapterBody = stripHarnessResidue(res.chapterText).text;
151
+ ledger = res.updatedLedger;
152
+ } catch (chErr: any) {
153
+ if (signal.aborted || chErr?.message === "Generation aborted by user.") break;
154
+ // Per-chapter fail-open: one bad chapter must not freeze the novel.
155
+ // Commit a draft-gap marker and continue so the run reaches full chapter count.
156
+ const why = chErr instanceof Error ? chErr.message : String(chErr);
157
+ addLog(`✗ Chapter ${currentChapterNum} failed (${why.slice(0, 160)}). Committing draft-gap and continuing…`);
158
+ chapterBody = `[DRAFT GAP] Chapter ${currentChapterNum} generation failed: ${why.slice(0, 240)}. Continue from the next chapter.`;
159
+ }
160
+
161
+ if (signal.aborted) break;
162
+
163
+ const newChapterBlock = `## ${chTitle}\n\n${chapterBody}`;
164
+ accumulatedManuscript = accumulatedManuscript.trim()
165
+ ? `${accumulatedManuscript.trim()}\n\n${newChapterBlock}`
166
+ : newChapterBlock;
167
+
168
+ priorSummary = `${chTitle}: ${chapterBody.slice(0, 420).replace(/\s+/g, " ")}`;
169
+ completedThisRun++;
170
+
171
+ // Clean commit to parent state + engine store (pure prose only).
172
+ setManuscript(accumulatedManuscript);
173
+ const adopt = attemptAdoptToEngine(iframeRef.current, accumulatedManuscript);
174
+ if (!adopt.ok) addLog(`⚠ adopt: ${adopt.detail}`);
175
+
176
+ // Crash-proof checkpoint after every successful commit.
177
+ StoryCrashProtector.saveCheckpoint({
178
+ manuscriptId: `story-${seed}`,
179
+ seed,
180
+ totalChapters,
181
+ completedChapters: currentChapterNum,
182
+ activeModel: selectedModel,
183
+ status: "running",
184
+ timestamp: Date.now(),
185
+ chapters: parseChaptersFromText(accumulatedManuscript).map((c) => ({
186
+ index: c.index,
187
+ title: c.title,
188
+ text: c.text,
189
+ wordCount: (c.text.match(/\S+/g) || []).length,
190
+ })),
191
+ cleanManuscript: accumulatedManuscript,
192
+ });
193
+
194
+ addLog(`✓ Chapter ${currentChapterNum} saved & checkpointed (${chapterBody.length} clean chars).`);
195
+ }
196
+
197
+ if (!signal.aborted) {
198
+ // Only mark complete when the full requested span was produced this session
199
+ // or already existed (resume that finishes the tail).
200
+ const finalCount = parseChaptersFromText(accumulatedManuscript).length;
201
+ if (finalCount >= totalChapters) {
202
+ setEngineStatus("complete");
203
+ StoryCrashProtector.updateStatus("complete");
204
+ addLog(`🎉 Entire novel completed successfully! ${finalCount}/${totalChapters} chapters on page.`);
205
+ } else {
206
+ setEngineStatus("paused");
207
+ StoryCrashProtector.updateStatus("paused");
208
+ addLog(`Run ended early at ${finalCount}/${totalChapters} chapters (${completedThisRun} this session). Status: paused — Resume to continue.`);
209
+ }
210
+ }
211
+ } catch (e: any) {
212
+ if (e?.message !== "Generation aborted by user.") {
213
+ setEngineStatus("error");
214
+ StoryCrashProtector.updateStatus("error");
215
+ addLog(`Error during chapter execution: ${e?.message || String(e)}`);
216
+ }
217
+ // Soft recovery: never leave the UI stuck in "running" after an unexpected throw.
218
+ if (StoryCrashProtector.getActiveStatus() === "running") {
219
+ setEngineStatus("paused");
220
+ StoryCrashProtector.updateStatus("paused");
221
+ }
222
+ } finally {
223
+ abortControllerRef.current = null;
224
+ // Never leave the controller soft-locked in "running" after the loop exits.
225
+ // Pause/Stop handlers set their own status; complete/paused/error set above.
226
+ // This is the last-resort freeze-breaker for edge races.
227
+ if (StoryCrashProtector.getActiveStatus() === "running") {
228
+ setEngineStatus(signal.aborted ? "paused" : "paused");
229
+ StoryCrashProtector.updateStatus("paused");
230
+ }
231
+ }
232
+ };
233
+
234
+ const handleRestoreCheckpoint = () => {
235
+ const cp = StoryCrashProtector.loadCheckpoint();
236
+ if (!cp || !cp.cleanManuscript) {
237
+ addLog("No saved checkpoint found in persistent storage.");
238
+ return;
239
+ }
240
+ const clean = stripHarnessResidue(cp.cleanManuscript).text;
241
+ setManuscript(clean);
242
+ setSeed(cp.seed);
243
+ setTotalChapters(cp.totalChapters);
244
+ setSelectedModel(cp.activeModel || "gemini-2.5-flash");
245
+ setEngineStatus(cp.status || "paused");
246
+ attemptAdoptToEngine(iframeRef.current, clean);
247
+ addLog(`✓ Restored checkpoint: ${cp.completedChapters} chapters restored (${clean.length} chars). Ready to continue.`);
248
+ };
249
+
250
+ useEffect(() => {
251
+ return () => {
252
+ if (abortControllerRef.current) {
253
+ abortControllerRef.current.abort();
254
+ }
255
+ };
256
+ }, []);
257
+
258
+ const isRunning = engineStatus === "running";
259
+
260
+ return (
261
+ <div className="space-y-4 text-[13px]">
262
+ {/* Active Story Controller */}
263
+ <div className="rounded-xl border border-indigo-200 bg-white p-3 shadow-sm">
264
+ <div className="flex flex-wrap items-center justify-between gap-2 border-b border-zinc-100 pb-2">
265
+ <div>
266
+ <h4 className="font-bold text-zinc-900">🚀 Live Story Engine Controller &amp; Crash Protector</h4>
267
+ <p className="text-[11px] text-zinc-500">
268
+ Deterministic checkpointing, mid-story model switching, and resumption without prompt bleed.
269
+ </p>
270
+ </div>
271
+ <div className="flex items-center gap-2">
272
+ <span
273
+ className={cx(
274
+ "rounded-full px-2.5 py-0.5 text-xs font-bold uppercase tracking-wider",
275
+ engineStatus === "running"
276
+ ? "bg-amber-100 text-amber-800 animate-pulse"
277
+ : engineStatus === "paused"
278
+ ? "bg-blue-100 text-blue-800"
279
+ : engineStatus === "complete"
280
+ ? "bg-emerald-100 text-emerald-800"
281
+ : engineStatus === "stopped"
282
+ ? "bg-zinc-200 text-zinc-800"
283
+ : "bg-zinc-100 text-zinc-600"
284
+ )}
285
+ >
286
+ Status: {engineStatus} {isRunning ? `(Ch ${currentChIndex}/${totalChapters})` : ""}
287
+ </span>
288
+ </div>
289
+ </div>
290
+
291
+ {/* Configuration Row */}
292
+ <div className="mt-3 grid grid-cols-1 gap-3 sm:grid-cols-3">
293
+ <label className="text-xs font-semibold text-zinc-700">
294
+ Active Model (Hot-Swappable Mid-Story)
295
+ <select
296
+ value={selectedModel}
297
+ onChange={(e) => {
298
+ setSelectedModel(e.target.value);
299
+ addLog(`Switched active generation model to: ${e.target.value}`);
300
+ }}
301
+ className="mt-1 block w-full rounded-lg border border-zinc-300 bg-white p-1.5 font-mono text-xs text-zinc-800 focus:border-indigo-500"
302
+ >
303
+ {modelPool.map((m) => (
304
+ <option key={m} value={m}>
305
+ {m}
306
+ </option>
307
+ ))}
308
+ </select>
309
+ </label>
310
+
311
+ <label className="text-xs font-semibold text-zinc-700">
312
+ Story Seed
313
+ <div className="flex gap-1.5 mt-1">
314
+ <input
315
+ type="number"
316
+ value={seed}
317
+ disabled={isRunning}
318
+ onChange={(e) => setSeed(Number(e.target.value) || 0)}
319
+ className="w-full rounded-lg border border-zinc-300 p-1.5 font-mono text-xs text-zinc-800"
320
+ />
321
+ <button
322
+ type="button"
323
+ disabled={isRunning}
324
+ onClick={() => setSeed(Math.floor(Math.random() * 900000) + 100000)}
325
+ className="rounded border border-zinc-200 px-2 text-xs hover:bg-zinc-100"
326
+ title="Randomize Seed"
327
+ >
328
+ 🎲
329
+ </button>
330
+ </div>
331
+ </label>
332
+
333
+ <label className="text-xs font-semibold text-zinc-700">
334
+ Total Target Chapters
335
+ <input
336
+ type="number"
337
+ min={1}
338
+ max={64}
339
+ value={totalChapters}
340
+ disabled={isRunning}
341
+ onChange={(e) => setTotalChapters(Math.max(1, Math.min(64, Number(e.target.value) || 16)))}
342
+ className="mt-1 block w-full rounded-lg border border-zinc-300 p-1.5 font-mono text-xs text-zinc-800"
343
+ />
344
+ </label>
345
+ </div>
346
+
347
+ {/* Action Controls */}
348
+ <div className="mt-4 flex flex-wrap items-center gap-2 border-t border-zinc-100 pt-3">
349
+ {!isRunning ? (
350
+ <>
351
+ {completedCount === 0 ? (
352
+ <button
353
+ type="button"
354
+ onClick={() => runGenerationLoop(1)}
355
+ disabled={!apiKey.trim()}
356
+ className="rounded-lg bg-indigo-600 px-4 py-2 font-bold text-white shadow-sm hover:bg-indigo-700 disabled:opacity-40"
357
+ >
358
+ ▶ Start Novel (Chapter 1)
359
+ </button>
360
+ ) : (
361
+ <>
362
+ {nextChapterToRun <= totalChapters && (
363
+ <button
364
+ type="button"
365
+ onClick={() => runGenerationLoop(nextChapterToRun)}
366
+ disabled={!apiKey.trim()}
367
+ className="rounded-lg bg-teal-600 px-4 py-2 font-bold text-white shadow-sm hover:bg-teal-700 disabled:opacity-40"
368
+ >
369
+ ▶ Resume Story from Chapter {nextChapterToRun}
370
+ </button>
371
+ )}
372
+ <button
373
+ type="button"
374
+ onClick={() => {
375
+ if (confirm("Reset manuscript and start fresh from Chapter 1?")) {
376
+ StoryCrashProtector.clearCheckpoint();
377
+ setManuscript("");
378
+ runGenerationLoop(1);
379
+ }
380
+ }}
381
+ disabled={!apiKey.trim()}
382
+ className="rounded-lg border border-zinc-300 bg-zinc-50 px-3 py-2 text-xs font-semibold text-zinc-700 hover:bg-zinc-100"
383
+ >
384
+ ↺ Restart from Ch 1
385
+ </button>
386
+ </>
387
+ )}
388
+ <button
389
+ type="button"
390
+ onClick={handleRestoreCheckpoint}
391
+ className="rounded-lg border border-indigo-200 bg-indigo-50/60 px-3 py-2 text-xs font-semibold text-indigo-700 hover:bg-indigo-100"
392
+ title="Recover last crash-proof checkpoint from localStorage"
393
+ >
394
+ 💾 Recover Crash Checkpoint
395
+ </button>
396
+ </>
397
+ ) : (
398
+ <div className="flex gap-2">
399
+ <button
400
+ type="button"
401
+ onClick={handlePause}
402
+ className="rounded-lg bg-amber-600 px-4 py-2 font-bold text-white shadow-sm hover:bg-amber-700"
403
+ >
404
+ ⏸ Pause
405
+ </button>
406
+ <button
407
+ type="button"
408
+ onClick={handleStop}
409
+ className="rounded-lg bg-rose-600 px-4 py-2 font-bold text-white shadow-sm hover:bg-rose-700"
410
+ >
411
+ ⏹ Stop Generation
412
+ </button>
413
+ </div>
414
+ )}
415
+
416
+ <div className="ml-auto text-xs text-zinc-500 font-medium">
417
+ Chapters completed: <span className="font-bold text-zinc-800">{completedCount}</span> / {totalChapters}
418
+ </div>
419
+ </div>
420
+ </div>
421
+
422
+ {/* Live Pipeline Terminal Log */}
423
+ <div className="rounded-xl border border-zinc-200 bg-zinc-900 p-3 text-zinc-100 shadow-sm">
424
+ <div className="flex items-center justify-between border-b border-zinc-800 pb-1.5 text-xs">
425
+ <span className="font-mono font-bold text-teal-400">⚡ Live Generation Execution Log</span>
426
+ <button
427
+ onClick={() => copyText(log.join("\n"))}
428
+ className="rounded border border-zinc-700 px-2 py-0.5 text-[10px] text-zinc-400 hover:text-white"
429
+ >
430
+ Copy Log
431
+ </button>
432
+ </div>
433
+ <div className="mt-2 h-44 overflow-y-auto space-y-1 font-mono text-[10.5px] leading-relaxed text-zinc-300">
434
+ {log.length === 0 ? (
435
+ <div className="italic text-zinc-500">Pipeline ready. Click Start or Resume to begin generation.</div>
436
+ ) : (
437
+ log.map((line, i) => <div key={i}>{line}</div>)
438
+ )}
439
+ </div>
440
+ </div>
441
+ </div>
442
+ );
443
+ }