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,254 @@
1
+ import { useEffect, useRef, useState, type RefObject } from "react";
2
+ import {
3
+ getActiveModel,
4
+ getCustomTemplateCount,
5
+ getLastRun,
6
+ getPersonaSeed,
7
+ getSettings,
8
+ observeRuntime,
9
+ type RuntimeSnapshot,
10
+ } from "./engineBridge";
11
+
12
+ type FrameRef = RefObject<HTMLIFrameElement | null>;
13
+
14
+ /* ------------------------------------------------------------------ */
15
+ /* Fiction Input inspector */
16
+ /* ------------------------------------------------------------------ */
17
+ export function FictionInputInspector({ iframeRef }: { iframeRef: FrameRef }) {
18
+ const [tick, setTick] = useState(0);
19
+ const refresh = () => setTick((t) => t + 1);
20
+ useEffect(() => {
21
+ const id = window.setInterval(refresh, 2500);
22
+ return () => window.clearInterval(id);
23
+ }, []);
24
+
25
+ const frame = iframeRef.current;
26
+ const settings = getSettings(frame);
27
+ const seed = getPersonaSeed(frame);
28
+ const model = getActiveModel(frame);
29
+ const templates = getCustomTemplateCount(frame);
30
+ const lastRun = getLastRun(frame);
31
+
32
+ // Only surface prompt text that the engine ACTUALLY exposed. No fabrication.
33
+ const exposedPrompt =
34
+ lastRun &&
35
+ (typeof lastRun.prompt === "string"
36
+ ? (lastRun.prompt as string)
37
+ : typeof lastRun.compiledPrompt === "string"
38
+ ? (lastRun.compiledPrompt as string)
39
+ : typeof lastRun.input === "string"
40
+ ? (lastRun.input as string)
41
+ : null);
42
+
43
+ const rows: Array<[string, string]> = [
44
+ ["Active model", model || "(default)"],
45
+ ["Persona seed", seed != null ? String(seed) : "(none)"],
46
+ ["Template enabled", String(!!settings.templateEnabled)],
47
+ ["Active template", String(settings.activeTemplateId ?? "—")],
48
+ ["Style mode", String(settings.styleMode ?? "—")],
49
+ ["Deep research", String(!!settings.deepResearch)],
50
+ ["Search depth", String(settings.searchDepth ?? "—")],
51
+ ["n-Deep passes", settings.nDeepEnabled ? String(settings.nDeepMaxPasses ?? "—") : "off"],
52
+ ["Cluster search", settings.clusterSearch ? String(settings.clusterSize ?? "on") : "off"],
53
+ ["SLOOP long-form", settings.forceSloop ? String(settings.sloopPages ?? "on") + " pages" : "off"],
54
+ ["Custom templates", String(templates)],
55
+ ];
56
+
57
+ return (
58
+ <div className="space-y-3 text-[13px]" data-tick={tick}>
59
+ <div className="flex items-center justify-between">
60
+ <p className="text-[12px] text-zinc-600">
61
+ The <b>real parameters</b> the engine uses to compile each chapter prompt (read live from engine storage).
62
+ </p>
63
+ <button onClick={refresh} className="rounded-lg border border-zinc-300 px-2 py-1 text-[11px] hover:bg-zinc-50">
64
+ Refresh
65
+ </button>
66
+ </div>
67
+
68
+ <div className="grid grid-cols-2 gap-x-3 gap-y-1 rounded-lg border border-zinc-200 bg-white p-3">
69
+ {rows.map(([k, v]) => (
70
+ <div key={k} className="flex items-center justify-between gap-2 border-b border-zinc-50 py-0.5">
71
+ <span className="text-[11px] text-zinc-500">{k}</span>
72
+ <span className="font-mono text-[11px] font-semibold text-zinc-800">{v}</span>
73
+ </div>
74
+ ))}
75
+ </div>
76
+
77
+ <div>
78
+ <h4 className="mb-1 text-[12px] font-bold text-zinc-700">Compiled Fiction Input (as exposed by the engine)</h4>
79
+ {exposedPrompt ? (
80
+ <pre className="max-h-64 overflow-auto whitespace-pre-wrap rounded-lg border border-zinc-200 bg-zinc-900 p-2 text-[11px] leading-relaxed text-zinc-100">
81
+ {exposedPrompt}
82
+ </pre>
83
+ ) : (
84
+ <p className="rounded-md bg-amber-50 px-2 py-1.5 text-[12px] text-amber-800">
85
+ The current engine build does not export the fully compiled prompt to <code>veritas.lastrun.v1</code>. Enable
86
+ <b> Debug Trace</b> inside the engine (Chat settings) to surface the exact per-chapter prompt; it will appear here
87
+ once written. The parameters above are the honest, verified inputs that drive that prompt.
88
+ </p>
89
+ )}
90
+ </div>
91
+ </div>
92
+ );
93
+ }
94
+
95
+ /* ------------------------------------------------------------------ */
96
+ /* System map (real module inventory) */
97
+ /* ------------------------------------------------------------------ */
98
+ type Group = { title: string; blurb: string; items: Array<[string, string]> };
99
+ const SYSTEM_MAP: Group[] = [
100
+ {
101
+ title: "SAGA / SAGE core",
102
+ blurb: "Story Archetype Generation Engine — deterministic seeded rolls that fix genre, archetype, and structure.",
103
+ items: [
104
+ ["lib/sage/engine.ts", "rollSage() — master seeded roll"],
105
+ ["lib/sage/index.ts", "public barrel (taxonomy, prng, judge, saga-os v1-v8)"],
106
+ ["lib/sage/saga-os-v2..v8.ts", "successive Saga-OS capability layers"],
107
+ ["lib/sage/saga-os-v3-core.ts / -release.ts", "v3 pipeline compile + release rules"],
108
+ ["lib/sage/saga-os-v4-aureate.ts", "v4 aureate style/reality layer"],
109
+ ["lib/sage/unified-roll.ts", "unifiedRoll() — merges archetype + genre + scale"],
110
+ ["lib/sage/taxonomy.ts", "genre/archetype taxonomy tables"],
111
+ ["lib/sage/prng.ts", "seeded deterministic PRNG"],
112
+ ],
113
+ },
114
+ {
115
+ title: "Quality & grounding",
116
+ blurb: "Reality-grounding, repetition control, and self-judging feed the chapter prompt and the after-write audit.",
117
+ items: [
118
+ ["lib/sage/reality-grounding.ts", "loadRealityLevel() — grounding constraints"],
119
+ ["lib/sage/judge.ts", "rubric self-judge"],
120
+ ["lib/sage/repetition.ts", "repetition/echo suppression"],
121
+ ["lib/sage/empty-space.ts (v6/v7)", "negative-space / what-is-left-unsaid engine"],
122
+ ["lib/sage/worked-sketches.ts", "worked scene sketches"],
123
+ ],
124
+ },
125
+ {
126
+ title: "Innovation & persona",
127
+ blurb: "Genome + persona guides shape voice, novelty, and the 'creative tree of life'.",
128
+ items: [
129
+ ["lib/innovation-genome-v3..v10.ts", "successive novelty/discovery genomes"],
130
+ ["lib/innovation-genome-engine(.v2).ts", "seedToGenome() + diagnostics"],
131
+ ["lib/williams-style.ts", "ARCHETYPES + getPersonaDirective()"],
132
+ ["lib/williams-persona-guide.ts", "persona guidance tables"],
133
+ ["lib/omega-templates.ts", "STYLE_OVERRIDES + authoritative output templates"],
134
+ ],
135
+ },
136
+ {
137
+ title: "Long-form & pipeline",
138
+ blurb: "The runners that turn a blueprint into chapters and multi-pass drafts.",
139
+ items: [
140
+ ["lib/longwriter.ts / writing-tiers.ts", "long-form chapter tiering"],
141
+ ["lib/v15-pipeline.ts", "runV15OnQuestion / baseline / judge panel"],
142
+ ["lib/pipeline.ts", "core generation pipeline"],
143
+ ["lib/n-deep.ts", "n-Deep multi-pass convergence"],
144
+ ["lib/sloop-runner.ts", "SLOOP paged long-output runner"],
145
+ ],
146
+ },
147
+ {
148
+ title: "Studio UI panels",
149
+ blurb: "The front-end surfaces already wired into the engine (rendered inside the app).",
150
+ items: [
151
+ ["components/SagaOsPanel.tsx", "primary Saga-OS studio controls"],
152
+ ["components/SageBlueprintPanel.tsx", "blueprint / 'story in one glance'"],
153
+ ["components/InnovationPersonaPanel.tsx", "persona genome UI"],
154
+ ["components/CreativeTreeOfLifePanel.tsx", "creative tree explorer"],
155
+ ["components/CitationLedgerPanel.tsx", "citation ledger"],
156
+ ],
157
+ },
158
+ ];
159
+
160
+ export function SystemMapPanel() {
161
+ return (
162
+ <div className="space-y-3 text-[13px]">
163
+ <p className="text-[12px] text-zinc-600">
164
+ Capability map of SAGA OS Studio. Module <b>paths are verified</b> against the packaged source
165
+ (<code>node_modules/src</code>); one-line roles are inferred from source structure and marked as such.
166
+ </p>
167
+ <div className="space-y-3">
168
+ {SYSTEM_MAP.map((g) => (
169
+ <div key={g.title} className="rounded-lg border border-zinc-200 bg-white p-3">
170
+ <h4 className="text-[12px] font-bold text-zinc-800">{g.title}</h4>
171
+ <p className="mb-2 text-[11px] text-zinc-500">{g.blurb}</p>
172
+ <div className="space-y-0.5">
173
+ {g.items.map(([path, role]) => (
174
+ <div key={path} className="flex flex-col gap-0.5 border-b border-zinc-50 py-0.5 sm:flex-row sm:items-baseline sm:justify-between">
175
+ <code className="text-[11px] font-semibold text-teal-700">{path}</code>
176
+ <span className="text-[11px] text-zinc-500">{role}</span>
177
+ </div>
178
+ ))}
179
+ </div>
180
+ </div>
181
+ ))}
182
+ </div>
183
+ </div>
184
+ );
185
+ }
186
+
187
+ /* ------------------------------------------------------------------ */
188
+ /* Live runtime (observed proxy signals) */
189
+ /* ------------------------------------------------------------------ */
190
+ export function RuntimePanel({ iframeRef }: { iframeRef: FrameRef }) {
191
+ const [snap, setSnap] = useState<RuntimeSnapshot | null>(null);
192
+ const [live, setLive] = useState(true);
193
+ const timer = useRef<number | null>(null);
194
+
195
+ useEffect(() => {
196
+ const poll = () => setSnap(observeRuntime(iframeRef.current));
197
+ poll();
198
+ if (live) timer.current = window.setInterval(poll, 1500);
199
+ return () => {
200
+ if (timer.current) window.clearInterval(timer.current);
201
+ };
202
+ }, [live, iframeRef]);
203
+
204
+ return (
205
+ <div className="space-y-3 text-[13px]">
206
+ <div className="flex items-center justify-between">
207
+ <p className="text-[12px] text-zinc-600">Live runtime of SAGA subsystems in the current story.</p>
208
+ <label className="flex items-center gap-1.5 text-[11px] text-zinc-600">
209
+ <input type="checkbox" checked={live} onChange={(e) => setLive(e.target.checked)} /> live
210
+ </label>
211
+ </div>
212
+
213
+ {snap && (
214
+ <>
215
+ <div className="grid grid-cols-3 gap-2">
216
+ <Stat label="Engine reachable" value={snap.reachable ? "yes" : "no"} />
217
+ <Stat label="Chapters detected" value={String(snap.chapters)} />
218
+ <Stat label="Trace size" value={snap.traceChars.toLocaleString() + " ch"} />
219
+ </div>
220
+ <div className="rounded-lg border border-zinc-200 bg-white p-2">
221
+ <div className="mb-1 text-[11px] font-semibold text-zinc-600">Engine phase: <span className="font-mono">{snap.phase}</span></div>
222
+ <div className="space-y-1">
223
+ {snap.signals.map((s) => (
224
+ <div key={s.label} className="flex items-center gap-2">
225
+ <span className="w-40 shrink-0 text-[11px] text-zinc-600">{s.label}</span>
226
+ <div className="h-2 flex-1 overflow-hidden rounded bg-zinc-100">
227
+ <div
228
+ className={s.count > 0 ? "h-full bg-teal-500" : "h-full bg-zinc-200"}
229
+ style={{ width: Math.min(100, s.count * 8) + "%" }}
230
+ />
231
+ </div>
232
+ <span className="w-8 text-right font-mono text-[11px] font-semibold text-zinc-700">{s.count}</span>
233
+ </div>
234
+ ))}
235
+ </div>
236
+ </div>
237
+ <p className="text-[10px] text-zinc-400">
238
+ Activation counts are a <b>DOM keyword census</b> — an honest proxy observed from the engine's rendered output, not
239
+ source-level instrumentation (which is not accessible in the prebuilt bundle). Chapters = assistant turns detected.
240
+ </p>
241
+ </>
242
+ )}
243
+ </div>
244
+ );
245
+ }
246
+
247
+ function Stat({ label, value }: { label: string; value: string }) {
248
+ return (
249
+ <div className="rounded-lg border border-zinc-200 bg-white p-2 text-center">
250
+ <div className="font-mono text-sm font-bold text-zinc-800">{value}</div>
251
+ <div className="text-[10px] uppercase tracking-wide text-zinc-400">{label}</div>
252
+ </div>
253
+ );
254
+ }
@@ -0,0 +1,182 @@
1
+ import { useState } from "react";
2
+ import { callGeminiResilient, callGemini } from "./gemini";
3
+ import {
4
+ buildGradingPrompt,
5
+ parseGrade,
6
+ buildAsciiReport,
7
+ type GradeReport,
8
+ } from "./grading";
9
+ import { copyText, cx, download } from "./util";
10
+
11
+ type Props = { manuscript: string; apiKey: string; modelPool: string[] };
12
+
13
+ export function ManuscriptGraderPanel({ manuscript, apiKey, modelPool }: Props) {
14
+ const [report, setReport] = useState<GradeReport | null>(null);
15
+ const [busy, setBusy] = useState(false);
16
+ const [err, setErr] = useState<string>("");
17
+ const [modelChoice, setModelChoice] = useState<string>("auto");
18
+ const [log, setLog] = useState<string>("");
19
+
20
+ const canRun = !!manuscript.trim() && !!apiKey.trim() && !busy;
21
+
22
+ async function grade() {
23
+ setBusy(true);
24
+ setErr("");
25
+ setReport(null);
26
+ const { system, prompt } = buildGradingPrompt(manuscript);
27
+ setLog("Grading " + manuscript.length.toLocaleString() + " chars (fresh context)…");
28
+ try {
29
+ const res =
30
+ modelChoice === "auto"
31
+ ? await callGeminiResilient(modelPool, undefined, { apiKey, prompt, system, temperature: 0.2 })
32
+ : await callGemini({ apiKey, model: modelChoice, prompt, system, temperature: 0.2 });
33
+ if (!res.ok) {
34
+ setErr(res.error || "Grading failed.");
35
+ setLog("Failed on model " + (res.model || "?") + " after " + res.ms + " ms.");
36
+ return;
37
+ }
38
+ const parsed = parseGrade(res.text, res.model, res.ms);
39
+ setReport(parsed);
40
+ setLog("Graded by " + res.model + " in " + res.ms + " ms." + (parsed.parseError ? " (parse warning)" : ""));
41
+ } finally {
42
+ setBusy(false);
43
+ }
44
+ }
45
+
46
+ return (
47
+ <div className="space-y-3 text-[13px]">
48
+ <div className="flex flex-wrap items-center gap-2">
49
+ <button
50
+ onClick={grade}
51
+ disabled={!canRun}
52
+ className={cx(
53
+ "rounded-lg px-3 py-1.5 text-[13px] font-semibold text-white",
54
+ canRun ? "bg-teal-600 hover:bg-teal-500" : "bg-zinc-300",
55
+ )}
56
+ >
57
+ {busy ? "Grading…" : "Grade full manuscript"}
58
+ </button>
59
+ <select
60
+ value={modelChoice}
61
+ onChange={(e) => setModelChoice(e.target.value)}
62
+ className="rounded-lg border border-zinc-300 px-2 py-1.5 text-[12px]"
63
+ >
64
+ <option value="auto">Model: random (rotation)</option>
65
+ {modelPool.map((m) => (
66
+ <option key={m} value={m}>
67
+ {m}
68
+ </option>
69
+ ))}
70
+ </select>
71
+ {report && (
72
+ <>
73
+ <button
74
+ onClick={() => copyText(buildAsciiReport(report))}
75
+ className="rounded-lg border border-zinc-300 px-2.5 py-1.5 text-[12px] font-medium hover:bg-zinc-50"
76
+ >
77
+ Copy report
78
+ </button>
79
+ <button
80
+ onClick={() => download("manuscript-grade.txt", buildAsciiReport(report))}
81
+ className="rounded-lg border border-zinc-300 px-2.5 py-1.5 text-[12px] font-medium hover:bg-zinc-50"
82
+ >
83
+ Download
84
+ </button>
85
+ </>
86
+ )}
87
+ </div>
88
+
89
+ {!apiKey.trim() && (
90
+ <p className="rounded-md bg-amber-50 px-2 py-1 text-[12px] text-amber-800">
91
+ No Gemini key detected. Enter one in the engine (Chat → Keys) or in the console header, then reload the manuscript.
92
+ </p>
93
+ )}
94
+ {log && <p className="text-[11px] text-zinc-500">{log}</p>}
95
+ {err && <p className="rounded-md bg-rose-50 px-2 py-1 text-[12px] text-rose-700">{err}</p>}
96
+
97
+ {report && (
98
+ <div className="space-y-4">
99
+ <div className="overflow-x-auto rounded-lg border border-zinc-200">
100
+ <table className="w-full border-collapse text-left text-[12px]">
101
+ <thead className="bg-zinc-100 text-[11px] uppercase tracking-wide text-zinc-600">
102
+ <tr>
103
+ <th className="px-2 py-1.5">Evaluation Criteria (Weight)</th>
104
+ <th className="px-2 py-1.5 text-center">Score</th>
105
+ <th className="px-2 py-1.5 text-center">Weighted</th>
106
+ <th className="px-2 py-1.5 text-center">Grade</th>
107
+ </tr>
108
+ </thead>
109
+ <tbody>
110
+ {report.criteria.map((c) => (
111
+ <tr key={c.key} className="border-t border-zinc-100 align-top">
112
+ <td className="px-2 py-1.5">
113
+ <div className="font-semibold text-zinc-800">
114
+ {c.label} <span className="text-zinc-400">({Math.round(c.weight * 100)}%)</span>
115
+ </div>
116
+ {c.justification && <div className="mt-0.5 text-[11px] text-zinc-500">{c.justification}</div>}
117
+ </td>
118
+ <td className="px-2 py-1.5 text-center font-mono">{c.score}</td>
119
+ <td className="px-2 py-1.5 text-center font-mono">{c.weighted.toFixed(2)}</td>
120
+ <td className="px-2 py-1.5 text-center font-bold">{c.grade}</td>
121
+ </tr>
122
+ ))}
123
+ <tr className="border-t-2 border-zinc-300 bg-zinc-50">
124
+ <td className="px-2 py-2 font-bold text-zinc-900">Weighted Composite Score (100%)</td>
125
+ <td className="px-2 py-2 text-center font-mono font-bold">{report.composite.toFixed(2)}</td>
126
+ <td className="px-2 py-2" />
127
+ <td className="px-2 py-2 text-center text-base font-black">{report.compositeGrade}</td>
128
+ </tr>
129
+ </tbody>
130
+ </table>
131
+ </div>
132
+
133
+ {report.narrative && <p className="text-[12px] italic text-zinc-600">{report.narrative}</p>}
134
+
135
+ {report.supplementary.length > 0 && (
136
+ <div>
137
+ <h4 className="mb-1 text-[12px] font-bold text-zinc-700">Supplementary dimensions</h4>
138
+ <div className="flex flex-wrap gap-1.5">
139
+ {report.supplementary.map((s, i) => (
140
+ <span
141
+ key={i}
142
+ title={s.note}
143
+ className="rounded-md border border-zinc-200 bg-white px-2 py-0.5 text-[11px] text-zinc-700"
144
+ >
145
+ {s.label}: <span className="font-mono font-semibold">{s.score}</span>
146
+ </span>
147
+ ))}
148
+ </div>
149
+ <p className="mt-1 text-[10px] text-zinc-400">
150
+ Supplementary set uses a standard editorial format (the uploaded criteria image was not available to this build).
151
+ </p>
152
+ </div>
153
+ )}
154
+
155
+ {report.rewrites.length > 0 && (
156
+ <div>
157
+ <h4 className="mb-1 text-[12px] font-bold text-zinc-700">Line-level rewrite suggestions</h4>
158
+ <div className="space-y-2">
159
+ {report.rewrites.map((r, i) => (
160
+ <div key={i} className="rounded-lg border border-zinc-200 bg-white p-2">
161
+ {r.location && <div className="text-[10px] font-semibold uppercase text-zinc-400">{r.location}</div>}
162
+ <div className="text-[12px] text-rose-700">“{r.excerpt}”</div>
163
+ <div className="mt-0.5 text-[11px] text-zinc-500">Diagnosis: {r.diagnosis}</div>
164
+ <div className="mt-0.5 text-[12px] text-emerald-700">→ {r.suggestedRewrite}</div>
165
+ {r.rationale && <div className="mt-0.5 text-[11px] text-zinc-400">Why: {r.rationale}</div>}
166
+ </div>
167
+ ))}
168
+ </div>
169
+ </div>
170
+ )}
171
+
172
+ {report.parseError && (
173
+ <details className="rounded-lg border border-zinc-200 bg-zinc-50 p-2">
174
+ <summary className="cursor-pointer text-[12px] font-semibold text-zinc-600">Raw model output</summary>
175
+ <pre className="mt-1 max-h-64 overflow-auto whitespace-pre-wrap text-[11px] text-zinc-600">{report.raw}</pre>
176
+ </details>
177
+ )}
178
+ </div>
179
+ )}
180
+ </div>
181
+ );
182
+ }
@@ -0,0 +1,245 @@
1
+ import { useRef, useState } from "react";
2
+ import { callGeminiResilient } from "./gemini";
3
+ import { buildGradingPrompt, buildRevisionPrompt, parseGrade, type GradeReport } from "./grading";
4
+ import { clampNum, copyText, cx, download, nowStamp } from "./util";
5
+
6
+ type Props = {
7
+ manuscript: string;
8
+ setManuscript: (s: string) => void;
9
+ apiKey: string;
10
+ modelPool: string[];
11
+ };
12
+
13
+ type Step = {
14
+ n: number;
15
+ kind: "grade" | "revise";
16
+ model: string;
17
+ composite?: number;
18
+ grade?: string;
19
+ ms: number;
20
+ note?: string;
21
+ ok: boolean;
22
+ };
23
+
24
+ type Draft = { n: number; text: string; report: GradeReport };
25
+
26
+ export function RecursiveReviserPanel({ manuscript, setManuscript, apiKey, modelPool }: Props) {
27
+ const [target, setTarget] = useState(85);
28
+ const [maxIters, setMaxIters] = useState(4);
29
+ const [running, setRunning] = useState(false);
30
+ const [steps, setSteps] = useState<Step[]>([]);
31
+ const [drafts, setDrafts] = useState<Draft[]>([]);
32
+ const [best, setBest] = useState<Draft | null>(null);
33
+ const [err, setErr] = useState("");
34
+ const abortRef = useRef<AbortController | null>(null);
35
+
36
+ const canRun = !!manuscript.trim() && !!apiKey.trim() && !running;
37
+
38
+ async function gradeText(text: string, excludeModel: string | undefined) {
39
+ const { system, prompt } = buildGradingPrompt(text);
40
+ const res = await callGeminiResilient(modelPool, excludeModel, {
41
+ apiKey,
42
+ prompt,
43
+ system,
44
+ temperature: 0.2,
45
+ signal: abortRef.current?.signal,
46
+ });
47
+ return { res, report: res.ok ? parseGrade(res.text, res.model, res.ms) : null };
48
+ }
49
+
50
+ async function run() {
51
+ setRunning(true);
52
+ setErr("");
53
+ setSteps([]);
54
+ setDrafts([]);
55
+ setBest(null);
56
+ abortRef.current = new AbortController();
57
+ const localSteps: Step[] = [];
58
+ const localDrafts: Draft[] = [];
59
+ const push = (s: Step) => {
60
+ localSteps.push(s);
61
+ setSteps([...localSteps]);
62
+ };
63
+
64
+ try {
65
+ // Draft 0 baseline grade — fresh context, random model.
66
+ const g0 = await gradeText(manuscript, undefined);
67
+ if (!g0.res.ok || !g0.report) {
68
+ push({ n: 0, kind: "grade", model: g0.res.model, ms: g0.res.ms, ok: false, note: g0.res.error });
69
+ setErr("Baseline grading failed: " + (g0.res.error || "unknown"));
70
+ return;
71
+ }
72
+ push({ n: 0, kind: "grade", model: g0.res.model, composite: g0.report.composite, grade: g0.report.compositeGrade, ms: g0.res.ms, ok: true });
73
+ localDrafts.push({ n: 0, text: manuscript, report: g0.report });
74
+ setDrafts([...localDrafts]);
75
+ let current = { text: manuscript, report: g0.report };
76
+ let lastModel = g0.res.model;
77
+
78
+ if (current.report.composite >= target) {
79
+ setBest(localDrafts[0]);
80
+ push({ n: 0, kind: "grade", model: "—", ms: 0, ok: true, note: "Target already met." });
81
+ return;
82
+ }
83
+
84
+ for (let i = 1; i <= maxIters; i++) {
85
+ if (abortRef.current?.signal.aborted) break;
86
+
87
+ // Revise — fresh context, random model distinct from last grader.
88
+ const { system: rs, prompt: rp } = buildRevisionPrompt(current.text, current.report, target);
89
+ const rev = await callGeminiResilient(modelPool, lastModel, {
90
+ apiKey,
91
+ prompt: rp,
92
+ system: rs,
93
+ temperature: 0.6,
94
+ signal: abortRef.current?.signal,
95
+ });
96
+ if (!rev.ok || !rev.text.trim()) {
97
+ push({ n: i, kind: "revise", model: rev.model, ms: rev.ms, ok: false, note: rev.error });
98
+ setErr("Revision " + i + " failed: " + (rev.error || "empty output"));
99
+ break;
100
+ }
101
+ const revisedText = rev.text.trim();
102
+ push({ n: i, kind: "revise", model: rev.model, ms: rev.ms, ok: true, note: revisedText.length.toLocaleString() + " chars" });
103
+ lastModel = rev.model;
104
+
105
+ // Grade the new draft — fresh context, random model distinct from reviser.
106
+ const gr = await gradeText(revisedText, rev.model);
107
+ if (!gr.res.ok || !gr.report) {
108
+ push({ n: i, kind: "grade", model: gr.res.model, ms: gr.res.ms, ok: false, note: gr.res.error });
109
+ setErr("Grading of revision " + i + " failed: " + (gr.res.error || "unknown"));
110
+ break;
111
+ }
112
+ push({ n: i, kind: "grade", model: gr.res.model, composite: gr.report.composite, grade: gr.report.compositeGrade, ms: gr.res.ms, ok: true });
113
+ localDrafts.push({ n: i, text: revisedText, report: gr.report });
114
+ setDrafts([...localDrafts]);
115
+ current = { text: revisedText, report: gr.report };
116
+ lastModel = gr.res.model;
117
+
118
+ if (current.report.composite >= target) break;
119
+ }
120
+
121
+ const bestDraft = localDrafts.slice().sort((a, b) => b.report.composite - a.report.composite)[0] || null;
122
+ setBest(bestDraft);
123
+ } finally {
124
+ setRunning(false);
125
+ }
126
+ }
127
+
128
+ function stop() {
129
+ abortRef.current?.abort();
130
+ setRunning(false);
131
+ }
132
+
133
+ const trajectory = drafts.map((d) => d.report.composite);
134
+
135
+ return (
136
+ <div className="space-y-3 text-[13px]">
137
+ <div className="flex flex-wrap items-end gap-3">
138
+ <label className="text-[12px] font-medium text-zinc-600">
139
+ Target score
140
+ <input
141
+ type="number"
142
+ min={1}
143
+ max={100}
144
+ value={target}
145
+ onChange={(e) => setTarget(clampNum(e.target.value, 1, 100, 85))}
146
+ className="ml-2 w-16 rounded-lg border border-zinc-300 px-2 py-1 text-[12px]"
147
+ />
148
+ </label>
149
+ <label className="text-[12px] font-medium text-zinc-600">
150
+ Max iterations
151
+ <input
152
+ type="number"
153
+ min={1}
154
+ max={8}
155
+ value={maxIters}
156
+ onChange={(e) => setMaxIters(clampNum(e.target.value, 1, 8, 4))}
157
+ className="ml-2 w-14 rounded-lg border border-zinc-300 px-2 py-1 text-[12px]"
158
+ />
159
+ </label>
160
+ {!running ? (
161
+ <button
162
+ onClick={run}
163
+ disabled={!canRun}
164
+ className={cx(
165
+ "rounded-lg px-3 py-1.5 text-[13px] font-semibold text-white",
166
+ canRun ? "bg-indigo-600 hover:bg-indigo-500" : "bg-zinc-300",
167
+ )}
168
+ >
169
+ Run recursive revision
170
+ </button>
171
+ ) : (
172
+ <button onClick={stop} className="rounded-lg bg-rose-600 px-3 py-1.5 text-[13px] font-semibold text-white hover:bg-rose-500">
173
+ Stop
174
+ </button>
175
+ )}
176
+ </div>
177
+
178
+ <p className="text-[11px] text-zinc-500">
179
+ Each grade and each revision is an independent Gemini call — <b>fresh context, random model</b> (distinct from the previous
180
+ call). The loop stops when the target is met or iterations are exhausted.
181
+ </p>
182
+
183
+ {err && <p className="rounded-md bg-rose-50 px-2 py-1 text-[12px] text-rose-700">{err}</p>}
184
+
185
+ {trajectory.length > 0 && (
186
+ <div className="rounded-lg border border-zinc-200 bg-white p-2">
187
+ <div className="text-[11px] font-semibold text-zinc-600">
188
+ Score trajectory: {trajectory.map((t) => t.toFixed(1)).join(" → ")}{" "}
189
+ {best && <span className="text-emerald-700">(best {best.report.composite.toFixed(2)} {best.report.compositeGrade})</span>}
190
+ </div>
191
+ </div>
192
+ )}
193
+
194
+ {steps.length > 0 && (
195
+ <div className="space-y-1">
196
+ {steps.map((s, i) => (
197
+ <div key={i} className="flex items-center gap-2 rounded-md border border-zinc-100 bg-zinc-50 px-2 py-1 text-[11px]">
198
+ <span className={cx("rounded px-1.5 py-0.5 font-semibold", s.kind === "grade" ? "bg-teal-100 text-teal-800" : "bg-indigo-100 text-indigo-800")}>
199
+ {s.kind === "grade" ? "GRADE" : "REVISE"} #{s.n}
200
+ </span>
201
+ <span className="font-mono text-zinc-500">{s.model || "—"}</span>
202
+ {typeof s.composite === "number" && (
203
+ <span className="font-mono font-semibold text-zinc-800">
204
+ {s.composite.toFixed(2)} ({s.grade})
205
+ </span>
206
+ )}
207
+ <span className="text-zinc-400">{s.ms} ms</span>
208
+ {s.note && <span className={cx("truncate", s.ok ? "text-zinc-500" : "text-rose-600")}>{s.note}</span>}
209
+ </div>
210
+ ))}
211
+ </div>
212
+ )}
213
+
214
+ {best && (
215
+ <div className="space-y-2">
216
+ <div className="flex flex-wrap items-center gap-2">
217
+ <h4 className="text-[12px] font-bold text-zinc-700">
218
+ Best draft (#{best.n}) — {best.report.composite.toFixed(2)} {best.report.compositeGrade}
219
+ </h4>
220
+ <button onClick={() => copyText(best.text)} className="rounded-lg border border-zinc-300 px-2.5 py-1 text-[11px] font-medium hover:bg-zinc-50">
221
+ Copy manuscript
222
+ </button>
223
+ <button
224
+ onClick={() => download("revised-manuscript-" + nowStamp().replace(/[: ]/g, "-") + ".txt", best.text)}
225
+ className="rounded-lg border border-zinc-300 px-2.5 py-1 text-[11px] font-medium hover:bg-zinc-50"
226
+ >
227
+ Download
228
+ </button>
229
+ <button
230
+ onClick={() => setManuscript(best.text)}
231
+ className="rounded-lg border border-indigo-300 bg-indigo-50 px-2.5 py-1 text-[11px] font-medium text-indigo-700 hover:bg-indigo-100"
232
+ >
233
+ Use as working manuscript
234
+ </button>
235
+ </div>
236
+ <textarea
237
+ readOnly
238
+ value={best.text}
239
+ className="h-48 w-full resize-y rounded-lg border border-zinc-200 bg-white p-2 font-mono text-[11px] text-zinc-700"
240
+ />
241
+ </div>
242
+ )}
243
+ </div>
244
+ );
245
+ }