synthos 0.8.0 → 0.9.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 (359) hide show
  1. package/README.md +1 -1
  2. package/default-pages/application/page.html +42 -0
  3. package/default-pages/application/page.json +10 -0
  4. package/default-pages/elevenlabs_effects_studio/page.html +1363 -0
  5. package/default-pages/elevenlabs_effects_studio/page.json +11 -0
  6. package/default-pages/elevenlabs_voice_studio/page.html +801 -0
  7. package/default-pages/elevenlabs_voice_studio/page.json +11 -0
  8. package/default-pages/{json_tools.html → json_tools/page.html} +13 -11
  9. package/default-pages/json_tools/page.json +10 -0
  10. package/default-pages/my_notes/notes/a1b2c3d4-e5f6-7890-abcd-ef1234567890.json +5 -0
  11. package/default-pages/my_notes/page.html +132 -0
  12. package/default-pages/{my_notes.json → my_notes/page.json} +2 -2
  13. package/default-pages/neon_asteroids/files/Ambient_Space.mp3 +0 -0
  14. package/default-pages/neon_asteroids/files/Ambient_Space2.mp3 +0 -0
  15. package/default-pages/neon_asteroids/files/Ambient_Space3.mp3 +0 -0
  16. package/default-pages/neon_asteroids/files/Asteroid_Explosion.mp3 +0 -0
  17. package/default-pages/neon_asteroids/files/Hyperspace_Jump.mp3 +0 -0
  18. package/default-pages/neon_asteroids/files/Laser_Fire.mp3 +0 -0
  19. package/default-pages/neon_asteroids/files/Menu_Navigate.mp3 +0 -0
  20. package/default-pages/neon_asteroids/files/Power_Up_Collect.mp3 +0 -0
  21. package/default-pages/neon_asteroids/files/Saucer_Alert.mp3 +0 -0
  22. package/default-pages/neon_asteroids/files/Ship_Thrust.mp3 +0 -0
  23. package/default-pages/neon_asteroids/files/effects.json +74 -0
  24. package/default-pages/neon_asteroids/page.html +1822 -0
  25. package/default-pages/{neon_asteroids.json → neon_asteroids/page.json} +3 -3
  26. package/default-pages/{oregon_trail.html → oregon_trail/page.html} +14 -12
  27. package/default-pages/{oregon_trail.json → oregon_trail/page.json} +2 -2
  28. package/default-pages/retro_game_starter/page.html +1308 -0
  29. package/default-pages/retro_game_starter/page.json +12 -0
  30. package/default-pages/{sidebar_page.html → sidebar_page/page.html} +12 -10
  31. package/default-pages/sidebar_page/page.json +10 -0
  32. package/default-pages/{solar_explorer.html → solar_explorer/page.html} +14 -11
  33. package/default-pages/{solar_explorer.json → solar_explorer/page.json} +2 -2
  34. package/default-pages/{solar_tutorial.html → solar_tutorial/page.html} +12 -10
  35. package/default-pages/solar_tutorial/page.json +10 -0
  36. package/default-pages/{two-panel_page.html → two-panel_page/page.html} +13 -11
  37. package/default-pages/two-panel_page/page.json +10 -0
  38. package/default-pages/{us_map.html → us_map/page.html} +193 -192
  39. package/default-pages/{us_map.json → us_map/page.json} +12 -12
  40. package/default-pages/{us_map_1850.html → us_map_1850/page.html} +326 -325
  41. package/default-pages/{us_map_1850.json → us_map_1850/page.json} +12 -12
  42. package/default-pages/{western_cities_1850.html → western_cities_1850/page.html} +527 -526
  43. package/default-pages/{western_cities_1850.json → western_cities_1850/page.json} +12 -12
  44. package/default-themes/aurora-dawn.json +19 -0
  45. package/default-themes/aurora-dawn.v3.css +198 -0
  46. package/default-themes/aurora-dusk.json +19 -0
  47. package/default-themes/aurora-dusk.v3.css +200 -0
  48. package/default-themes/cosmos-dawn.json +19 -0
  49. package/default-themes/cosmos-dawn.v3.css +198 -0
  50. package/default-themes/cosmos-dusk.json +19 -0
  51. package/default-themes/cosmos-dusk.v3.css +200 -0
  52. package/default-themes/high-contrast-dark.json +19 -0
  53. package/default-themes/high-contrast-dark.v3.css +200 -0
  54. package/default-themes/high-contrast-light.json +19 -0
  55. package/default-themes/high-contrast-light.v3.css +198 -0
  56. package/default-themes/nebula-dawn.v2.css +110 -0
  57. package/default-themes/nebula-dawn.v3.css +199 -0
  58. package/default-themes/nebula-dusk.v2.css +104 -0
  59. package/default-themes/nebula-dusk.v3.css +201 -0
  60. package/default-themes/solar-flare-dawn.json +19 -0
  61. package/default-themes/solar-flare-dawn.v3.css +198 -0
  62. package/default-themes/solar-flare-dusk.json +19 -0
  63. package/default-themes/solar-flare-dusk.v3.css +200 -0
  64. package/dist/agents/index.d.ts +1 -1
  65. package/dist/agents/index.d.ts.map +1 -1
  66. package/dist/agents/index.js +2 -1
  67. package/dist/agents/index.js.map +1 -1
  68. package/dist/agents/openclaw/gatewayManager.d.ts +4 -0
  69. package/dist/agents/openclaw/gatewayManager.d.ts.map +1 -1
  70. package/dist/agents/openclaw/gatewayManager.js +27 -11
  71. package/dist/agents/openclaw/gatewayManager.js.map +1 -1
  72. package/dist/agents/openclaw/openclawProvider.d.ts.map +1 -1
  73. package/dist/agents/openclaw/openclawProvider.js +2 -4
  74. package/dist/agents/openclaw/openclawProvider.js.map +1 -1
  75. package/dist/agents/openclaw/sshTunnelManager.d.ts +2 -0
  76. package/dist/agents/openclaw/sshTunnelManager.d.ts.map +1 -1
  77. package/dist/agents/openclaw/sshTunnelManager.js +31 -12
  78. package/dist/agents/openclaw/sshTunnelManager.js.map +1 -1
  79. package/dist/builders/anthropic.d.ts +31 -0
  80. package/dist/builders/anthropic.d.ts.map +1 -0
  81. package/dist/builders/anthropic.js +227 -0
  82. package/dist/builders/anthropic.js.map +1 -0
  83. package/dist/builders/fireworksai.d.ts +9 -0
  84. package/dist/builders/fireworksai.d.ts.map +1 -0
  85. package/dist/builders/fireworksai.js +57 -0
  86. package/dist/builders/fireworksai.js.map +1 -0
  87. package/dist/builders/index.d.ts +13 -0
  88. package/dist/builders/index.d.ts.map +1 -0
  89. package/dist/builders/index.js +31 -0
  90. package/dist/builders/index.js.map +1 -0
  91. package/dist/builders/openai.d.ts +8 -0
  92. package/dist/builders/openai.d.ts.map +1 -0
  93. package/dist/builders/openai.js +87 -0
  94. package/dist/builders/openai.js.map +1 -0
  95. package/dist/builders/types.d.ts +54 -0
  96. package/dist/builders/types.d.ts.map +1 -0
  97. package/dist/builders/types.js +211 -0
  98. package/dist/builders/types.js.map +1 -0
  99. package/dist/connectors/index.d.ts.map +1 -1
  100. package/dist/connectors/index.js +3 -2
  101. package/dist/connectors/index.js.map +1 -1
  102. package/dist/connectors/registry.d.ts +2 -1
  103. package/dist/connectors/registry.d.ts.map +1 -1
  104. package/dist/connectors/registry.js +31 -8
  105. package/dist/connectors/registry.js.map +1 -1
  106. package/dist/customizer/Customizer.d.ts +57 -0
  107. package/dist/customizer/Customizer.d.ts.map +1 -0
  108. package/dist/customizer/Customizer.js +124 -0
  109. package/dist/customizer/Customizer.js.map +1 -0
  110. package/dist/customizer/index.d.ts.map +1 -0
  111. package/dist/customizer/index.js +9 -0
  112. package/dist/customizer/index.js.map +1 -0
  113. package/dist/files.d.ts +16 -0
  114. package/dist/files.d.ts.map +1 -1
  115. package/dist/files.js +60 -1
  116. package/dist/files.js.map +1 -1
  117. package/dist/index.d.ts.map +1 -1
  118. package/dist/index.js +1 -0
  119. package/dist/index.js.map +1 -1
  120. package/dist/init.d.ts +10 -6
  121. package/dist/init.d.ts.map +1 -1
  122. package/dist/init.js +96 -113
  123. package/dist/init.js.map +1 -1
  124. package/dist/migrations.d.ts.map +1 -1
  125. package/dist/migrations.js +23 -10
  126. package/dist/migrations.js.map +1 -1
  127. package/dist/models/anthropic.d.ts +4 -2
  128. package/dist/models/anthropic.d.ts.map +1 -1
  129. package/dist/models/anthropic.js +33 -6
  130. package/dist/models/anthropic.js.map +1 -1
  131. package/dist/models/fireworksai.d.ts.map +1 -1
  132. package/dist/models/fireworksai.js +9 -1
  133. package/dist/models/fireworksai.js.map +1 -1
  134. package/dist/models/index.d.ts +1 -1
  135. package/dist/models/index.d.ts.map +1 -1
  136. package/dist/models/index.js +2 -1
  137. package/dist/models/index.js.map +1 -1
  138. package/dist/models/openai.d.ts +1 -1
  139. package/dist/models/openai.d.ts.map +1 -1
  140. package/dist/models/openai.js +24 -3
  141. package/dist/models/openai.js.map +1 -1
  142. package/dist/models/types.d.ts +20 -1
  143. package/dist/models/types.d.ts.map +1 -1
  144. package/dist/models/types.js +6 -1
  145. package/dist/models/types.js.map +1 -1
  146. package/dist/pages.d.ts +30 -7
  147. package/dist/pages.d.ts.map +1 -1
  148. package/dist/pages.js +177 -55
  149. package/dist/pages.js.map +1 -1
  150. package/dist/service/server.d.ts.map +1 -1
  151. package/dist/service/server.js +37 -8
  152. package/dist/service/server.js.map +1 -1
  153. package/dist/service/transformPage.d.ts +47 -20
  154. package/dist/service/transformPage.d.ts.map +1 -1
  155. package/dist/service/transformPage.js +514 -293
  156. package/dist/service/transformPage.js.map +1 -1
  157. package/dist/service/useAgentRoutes.d.ts +2 -1
  158. package/dist/service/useAgentRoutes.d.ts.map +1 -1
  159. package/dist/service/useAgentRoutes.js +5 -2
  160. package/dist/service/useAgentRoutes.js.map +1 -1
  161. package/dist/service/useApiRoutes.d.ts.map +1 -1
  162. package/dist/service/useApiRoutes.js +237 -136
  163. package/dist/service/useApiRoutes.js.map +1 -1
  164. package/dist/service/useConnectorRoutes.js +6 -6
  165. package/dist/service/useConnectorRoutes.js.map +1 -1
  166. package/dist/service/useFileRoutes.d.ts +4 -0
  167. package/dist/service/useFileRoutes.d.ts.map +1 -0
  168. package/dist/service/useFileRoutes.js +122 -0
  169. package/dist/service/useFileRoutes.js.map +1 -0
  170. package/dist/service/usePageRoutes.d.ts.map +1 -1
  171. package/dist/service/usePageRoutes.js +648 -67
  172. package/dist/service/usePageRoutes.js.map +1 -1
  173. package/dist/service/useSharedDataRoutes.d.ts +4 -0
  174. package/dist/service/useSharedDataRoutes.d.ts.map +1 -0
  175. package/dist/service/useSharedDataRoutes.js +104 -0
  176. package/dist/service/useSharedDataRoutes.js.map +1 -0
  177. package/dist/service/useSharedFileRoutes.d.ts +4 -0
  178. package/dist/service/useSharedFileRoutes.d.ts.map +1 -0
  179. package/dist/service/useSharedFileRoutes.js +121 -0
  180. package/dist/service/useSharedFileRoutes.js.map +1 -0
  181. package/dist/settings.d.ts +1 -0
  182. package/dist/settings.d.ts.map +1 -1
  183. package/dist/settings.js +1 -0
  184. package/dist/settings.js.map +1 -1
  185. package/dist/synthos-cli.d.ts.map +1 -1
  186. package/dist/synthos-cli.js +4 -3
  187. package/dist/synthos-cli.js.map +1 -1
  188. package/dist/themes.d.ts +1 -0
  189. package/dist/themes.d.ts.map +1 -1
  190. package/dist/themes.js +28 -15
  191. package/dist/themes.js.map +1 -1
  192. package/migration-rules/v1-to-v2.md +193 -0
  193. package/migration-rules/v2-to-v3.md +481 -0
  194. package/package.json +11 -10
  195. package/required-pages/builder/page.html +43 -0
  196. package/required-pages/builder/page.json +10 -0
  197. package/required-pages/{pages.html → pages/page.html} +238 -233
  198. package/required-pages/pages/page.json +10 -0
  199. package/required-pages/{settings.html → settings/page.html} +389 -275
  200. package/required-pages/settings/page.json +10 -0
  201. package/required-pages/synthos_apis/page.html +846 -0
  202. package/required-pages/synthos_apis/page.json +10 -0
  203. package/required-pages/{synthos_scripts.html → synthos_scripts/page.html} +13 -11
  204. package/required-pages/synthos_scripts/page.json +10 -0
  205. package/src/agents/index.ts +1 -1
  206. package/src/agents/openclaw/gatewayManager.ts +22 -11
  207. package/src/agents/openclaw/openclawProvider.ts +2 -4
  208. package/src/agents/openclaw/sshTunnelManager.ts +19 -11
  209. package/src/builders/anthropic.ts +283 -0
  210. package/src/builders/fireworksai.ts +59 -0
  211. package/src/builders/index.ts +33 -0
  212. package/src/builders/openai.ts +89 -0
  213. package/src/builders/types.ts +261 -0
  214. package/src/connectors/index.ts +1 -1
  215. package/src/connectors/registry.ts +28 -8
  216. package/src/customizer/Customizer.ts +151 -0
  217. package/src/customizer/index.ts +5 -0
  218. package/src/files.ts +57 -0
  219. package/src/index.ts +2 -1
  220. package/src/init.ts +137 -123
  221. package/src/migrations.ts +30 -10
  222. package/src/models/anthropic.ts +40 -10
  223. package/src/models/fireworksai.ts +9 -2
  224. package/src/models/index.ts +1 -1
  225. package/src/models/openai.ts +26 -6
  226. package/src/models/types.ts +31 -1
  227. package/src/pages.ts +176 -54
  228. package/src/service/server.ts +36 -9
  229. package/src/service/transformPage.ts +557 -326
  230. package/src/service/useAgentRoutes.ts +7 -2
  231. package/src/service/useApiRoutes.ts +150 -41
  232. package/src/service/useConnectorRoutes.ts +7 -7
  233. package/src/service/useFileRoutes.ts +127 -0
  234. package/src/service/usePageRoutes.ts +720 -73
  235. package/src/service/useSharedDataRoutes.ts +106 -0
  236. package/src/service/useSharedFileRoutes.ts +126 -0
  237. package/src/settings.ts +2 -0
  238. package/src/synthos-cli.ts +4 -3
  239. package/src/themes.ts +25 -14
  240. package/static-files/favicon.svg +12 -0
  241. package/static-files/fluentlm-instructions.llmd +868 -0
  242. package/static-files/fluentlm-instructions.md +1595 -0
  243. package/static-files/fluentlm.css +4844 -0
  244. package/static-files/fluentlm.js +3602 -0
  245. package/static-files/fluentlm.min.css +1 -0
  246. package/static-files/fluentlm.min.js +1 -0
  247. package/{page-scripts/helpers-v2.js → static-files/helpers.v3.js} +82 -0
  248. package/static-files/page.v3.js +1290 -0
  249. package/static-files/recommended-frameworks.llmd +81 -0
  250. package/static-files/recommended-frameworks.md +137 -0
  251. package/static-files/retro-game.js +877 -0
  252. package/static-files/shell.css +797 -0
  253. package/static-files/theme-dark.css +169 -0
  254. package/static-files/theme-light.css +169 -0
  255. package/tests/builders.spec.ts +139 -0
  256. package/tests/pages.spec.ts +8 -8
  257. package/tests/transformPage.spec.ts +299 -360
  258. package/default-pages/application.html +0 -40
  259. package/default-pages/application.json +0 -1
  260. package/default-pages/json_tools.json +0 -1
  261. package/default-pages/my_notes.html +0 -33
  262. package/default-pages/neon_asteroids.html +0 -77
  263. package/default-pages/sidebar_page.json +0 -1
  264. package/default-pages/solar_tutorial.json +0 -1
  265. package/default-pages/two-panel_page.json +0 -1
  266. package/dist/agents/a2a/a2aProvider.d.ts +0 -3
  267. package/dist/agents/discovery.d.ts +0 -30
  268. package/dist/agents/openclaw/openclawProvider.d.ts +0 -3
  269. package/dist/agents/types.d.ts +0 -64
  270. package/dist/connectors/index.d.ts +0 -3
  271. package/dist/connectors/types.d.ts +0 -84
  272. package/dist/index.d.ts +0 -7
  273. package/dist/migrations.d.ts +0 -12
  274. package/dist/models/chainOfThought.d.ts +0 -12
  275. package/dist/models/fireworksai.d.ts +0 -30
  276. package/dist/models/logCompletePrompt.d.ts +0 -3
  277. package/dist/models/providers.d.ts +0 -8
  278. package/dist/models/utils.d.ts +0 -6
  279. package/dist/scripts.d.ts +0 -15
  280. package/dist/service/createCompletePrompt.d.ts +0 -5
  281. package/dist/service/debugLog.d.ts +0 -11
  282. package/dist/service/generateImage.d.ts +0 -32
  283. package/dist/service/index.d.ts +0 -8
  284. package/dist/service/modelInstructions.d.ts +0 -7
  285. package/dist/service/requiresSettings.d.ts +0 -3
  286. package/dist/service/server.d.ts +0 -4
  287. package/dist/service/useApiRoutes.d.ts +0 -4
  288. package/dist/service/useConnectorRoutes.d.ts +0 -4
  289. package/dist/service/useDataRoutes.d.ts +0 -4
  290. package/dist/service/useGatewayRoutes.d.ts +0 -4
  291. package/dist/service/useGatewayRoutes.d.ts.map +0 -1
  292. package/dist/service/useGatewayRoutes.js +0 -168
  293. package/dist/service/useGatewayRoutes.js.map +0 -1
  294. package/dist/service/usePageRoutes.d.ts +0 -5
  295. package/dist/synthos-cli.d.ts +0 -2
  296. package/page-scripts/page-v2.js +0 -656
  297. package/required-pages/builder.html +0 -48
  298. package/required-pages/builder.json +0 -1
  299. package/required-pages/pages.json +0 -1
  300. package/required-pages/settings.json +0 -1
  301. package/required-pages/synthos_apis.html +0 -327
  302. package/required-pages/synthos_apis.json +0 -1
  303. package/required-pages/synthos_scripts.json +0 -1
  304. package/src/connectors/airtable/connector.json +0 -27
  305. package/src/connectors/alpha-vantage/connector.json +0 -26
  306. package/src/connectors/brave-search/connector.json +0 -26
  307. package/src/connectors/cloudinary/connector.json +0 -27
  308. package/src/connectors/deepl/connector.json +0 -28
  309. package/src/connectors/elevenlabs/connector.json +0 -30
  310. package/src/connectors/giphy/connector.json +0 -27
  311. package/src/connectors/github/connector.json +0 -29
  312. package/src/connectors/huggingface/connector.json +0 -27
  313. package/src/connectors/imgur/connector.json +0 -29
  314. package/src/connectors/instagram/connector.json +0 -43
  315. package/src/connectors/jira/connector.json +0 -28
  316. package/src/connectors/mapbox/connector.json +0 -26
  317. package/src/connectors/nasa/connector.json +0 -27
  318. package/src/connectors/newsapi/connector.json +0 -27
  319. package/src/connectors/notion/connector.json +0 -28
  320. package/src/connectors/open-exchange-rates/connector.json +0 -27
  321. package/src/connectors/openweathermap/connector.json +0 -26
  322. package/src/connectors/pexels/connector.json +0 -27
  323. package/src/connectors/resend/connector.json +0 -29
  324. package/src/connectors/rss2json/connector.json +0 -27
  325. package/src/connectors/sendgrid/connector.json +0 -27
  326. package/src/connectors/spoonacular/connector.json +0 -28
  327. package/src/connectors/stability-ai/connector.json +0 -27
  328. package/src/connectors/twilio/connector.json +0 -28
  329. package/src/connectors/unsplash/connector.json +0 -27
  330. package/src/connectors/wolfram-alpha/connector.json +0 -26
  331. package/src/connectors/youtube-data/connector.json +0 -30
  332. /package/{dist/connectors → service-connectors}/airtable/connector.json +0 -0
  333. /package/{dist/connectors → service-connectors}/alpha-vantage/connector.json +0 -0
  334. /package/{dist/connectors → service-connectors}/brave-search/connector.json +0 -0
  335. /package/{dist/connectors → service-connectors}/cloudinary/connector.json +0 -0
  336. /package/{dist/connectors → service-connectors}/deepl/connector.json +0 -0
  337. /package/{dist/connectors → service-connectors}/elevenlabs/connector.json +0 -0
  338. /package/{dist/connectors → service-connectors}/giphy/connector.json +0 -0
  339. /package/{dist/connectors → service-connectors}/github/connector.json +0 -0
  340. /package/{dist/connectors → service-connectors}/huggingface/connector.json +0 -0
  341. /package/{dist/connectors → service-connectors}/imgur/connector.json +0 -0
  342. /package/{dist/connectors → service-connectors}/instagram/connector.json +0 -0
  343. /package/{dist/connectors → service-connectors}/jira/connector.json +0 -0
  344. /package/{dist/connectors → service-connectors}/mapbox/connector.json +0 -0
  345. /package/{dist/connectors → service-connectors}/nasa/connector.json +0 -0
  346. /package/{dist/connectors → service-connectors}/newsapi/connector.json +0 -0
  347. /package/{dist/connectors → service-connectors}/notion/connector.json +0 -0
  348. /package/{dist/connectors → service-connectors}/open-exchange-rates/connector.json +0 -0
  349. /package/{dist/connectors → service-connectors}/openweathermap/connector.json +0 -0
  350. /package/{dist/connectors → service-connectors}/pexels/connector.json +0 -0
  351. /package/{dist/connectors → service-connectors}/resend/connector.json +0 -0
  352. /package/{dist/connectors → service-connectors}/rss2json/connector.json +0 -0
  353. /package/{dist/connectors → service-connectors}/sendgrid/connector.json +0 -0
  354. /package/{dist/connectors → service-connectors}/spoonacular/connector.json +0 -0
  355. /package/{dist/connectors → service-connectors}/stability-ai/connector.json +0 -0
  356. /package/{dist/connectors → service-connectors}/twilio/connector.json +0 -0
  357. /package/{dist/connectors → service-connectors}/unsplash/connector.json +0 -0
  358. /package/{dist/connectors → service-connectors}/wolfram-alpha/connector.json +0 -0
  359. /package/{dist/connectors → service-connectors}/youtube-data/connector.json +0 -0
@@ -1,656 +0,0 @@
1
- (function() {
2
- if (window.__synthOSChatPanel) return;
3
- window.__synthOSChatPanel = true;
4
-
5
- // 0. First-run greeting — replace default greeting when ?firstRun=true
6
- (function() {
7
- var params = new URLSearchParams(window.location.search);
8
- if (params.get('firstRun') !== 'true') return;
9
- var greeting = document.getElementById('defaultGreeting');
10
- if (!greeting) return;
11
- greeting.innerHTML =
12
- '<p><strong>Welcome to SynthOS!</strong></p>' +
13
- '<p>You\'re all set up and ready to start creating. This is the <strong>Builder</strong> — your main workspace. Just type what you want to build into the chat and SynthOS will generate it for you as a live, interactive page.</p>' +
14
- '<p>You can create just about anything: dashboards, tools, games, visualizations, forms, calculators — if it can be expressed as a web page, you can build it here through conversation.</p>' +
15
- '<p><strong>How pages work:</strong></p>' +
16
- '<ul>' +
17
- '<li>Each creation lives on its own <strong>page</strong>. When you save, it gets a name and becomes part of your collection.</li>' +
18
- '<li>The <strong>Pages</strong> button (in the link bar above) takes you to the <strong>Pages Gallery</strong> where you can browse, open, and manage all your saved creations.</li>' +
19
- '</ul>' +
20
- '<p><strong>Key actions:</strong></p>' +
21
- '<ul>' +
22
- '<li><strong>Save</strong> — saves your current page. You\'ll be prompted for a name the first time. <em>Save often!</em> Your work only persists when you save it.</li>' +
23
- '<li><strong>Reset</strong> — clears the current page back to a blank slate. Useful when you want to start fresh on something new.</li>' +
24
- '</ul>' +
25
- '<p>When you\'re ready, we recommend trying the <a href="/solar_tutorial">Solar Tutorial</a> — it\'s a guided walkthrough that will show you the basics of creating with SynthOS step by step.</p>' +
26
- '<p>Have fun building!</p>';
27
- })();
28
-
29
- // 1. Themed tooltips for chat panel controls
30
- (function() {
31
- var style = document.createElement('style');
32
- style.textContent =
33
- '.synthos-tooltip {' +
34
- 'position: fixed;' +
35
- 'padding: 6px 10px;' +
36
- 'background: var(--bg-tertiary, #0f0f23);' +
37
- 'color: var(--text-secondary, #b794f6);' +
38
- 'border: 1px solid var(--border-color, rgba(138,43,226,0.3));' +
39
- 'border-radius: 6px;' +
40
- 'font-size: 12px;' +
41
- 'max-width: 150px;' +
42
- 'text-align: center;' +
43
- 'pointer-events: none;' +
44
- 'z-index: 10000;' +
45
- 'box-shadow: 0 2px 8px rgba(0,0,0,0.3);' +
46
- 'opacity: 0;' +
47
- 'transition: opacity 0.15s;' +
48
- '}' +
49
- '.synthos-tooltip.visible { opacity: 1; }';
50
- document.head.appendChild(style);
51
-
52
- var tip = document.createElement('div');
53
- tip.className = 'synthos-tooltip';
54
- document.body.appendChild(tip);
55
-
56
- function show(el) {
57
- tip.textContent = el.getAttribute('data-tooltip');
58
- tip.style.display = 'block';
59
- tip.classList.remove('visible');
60
- var r = el.getBoundingClientRect();
61
- var tw = tip.offsetWidth;
62
- var left = r.left + (r.width / 2) - (tw / 2);
63
- if (left < 4) left = 4;
64
- if (left + tw > window.innerWidth - 4) left = window.innerWidth - tw - 4;
65
- tip.style.left = left + 'px';
66
- tip.style.top = (r.top - tip.offsetHeight - 6) + 'px';
67
- void tip.offsetWidth;
68
- tip.classList.add('visible');
69
- }
70
-
71
- function hide() {
72
- tip.classList.remove('visible');
73
- tip.style.display = 'none';
74
- }
75
- hide();
76
-
77
- function attach(el, text) {
78
- el.setAttribute('data-tooltip', text);
79
- el.addEventListener('mouseenter', function() { show(el); });
80
- el.addEventListener('mouseleave', hide);
81
- }
82
-
83
- // Pages link is never renamed
84
- var pagesLink = document.getElementById('pagesLink');
85
- if (pagesLink) attach(pagesLink, 'Browse all pages');
86
-
87
- // Save and Reset tooltips deferred — locked-mode renames them on DOMContentLoaded
88
- document.addEventListener('DOMContentLoaded', function() {
89
- setTimeout(function() {
90
- var s = document.getElementById('saveLink');
91
- if (s) attach(s, s.textContent.trim() === 'Copy' ? 'Copy page as a new name' : 'Save page as a new name');
92
- var r = document.getElementById('resetLink');
93
- if (r) attach(r, r.textContent.trim() === 'Reload' ? 'Reload this page' : 'Reset page to default');
94
- }, 0);
95
- });
96
-
97
- window.__synthOSTooltip = attach;
98
- })();
99
-
100
- // 1. Initial focus
101
- var chatInput = document.getElementById('chatInput');
102
- if (chatInput) chatInput.focus();
103
-
104
- // 2. Form submit handler — show overlay + disable inputs
105
- var chatForm = document.getElementById('chatForm');
106
- if (chatForm) {
107
- chatForm.addEventListener('submit', function() {
108
- var overlay = document.getElementById('loadingOverlay');
109
- if (overlay) overlay.style.display = 'flex';
110
- chatForm.action = window.location.pathname;
111
- setTimeout(function() {
112
- var ci = document.getElementById('chatInput');
113
- if (ci) ci.disabled = true;
114
- var sb = document.querySelector('.chat-submit');
115
- if (sb) sb.disabled = true;
116
- document.querySelectorAll('.link-group a').forEach(function(a) {
117
- a.style.pointerEvents = 'none';
118
- a.style.opacity = '0.5';
119
- });
120
- }, 50);
121
- });
122
- }
123
-
124
- // 3. Save link handler — themed modal with title, categories, greeting
125
- (function() {
126
- var saveLink = document.getElementById('saveLink');
127
- if (!saveLink) return;
128
-
129
- // Detect if current page is a Builders or System page (start with blank fields)
130
- var isBuilder = window.pageInfo && Array.isArray(window.pageInfo.categories) &&
131
- (window.pageInfo.categories.indexOf('Builders') !== -1 ||
132
- window.pageInfo.categories.indexOf('System') !== -1);
133
-
134
- // Original title for change detection
135
- var originalTitle = (window.pageInfo && window.pageInfo.title) ? window.pageInfo.title : '';
136
-
137
- // --- Create save modal ---
138
- var modal = document.createElement('div');
139
- modal.id = 'saveModal';
140
- modal.className = 'modal-overlay';
141
- modal.innerHTML =
142
- '<div class="modal-content" style="max-width:480px;">' +
143
- '<div class="modal-header">' +
144
- '<span>Save Page</span>' +
145
- '<button type="button" class="brainstorm-close-btn" id="saveCloseBtn">&times;</button>' +
146
- '</div>' +
147
- '<div class="modal-body" style="display:flex;flex-direction:column;gap:12px;padding:16px 20px;">' +
148
- '<div>' +
149
- '<label style="display:block;margin-bottom:4px;font-size:13px;color:var(--text-secondary);">Display Title <span style="color:var(--accent-primary);">*</span></label>' +
150
- '<input type="text" id="saveTitleInput" class="brainstorm-input" placeholder="Enter a display title..." style="width:100%;box-sizing:border-box;">' +
151
- '<div id="saveTitleError" style="color:#ff6b6b;font-size:12px;margin-top:4px;display:none;">Title is required</div>' +
152
- '</div>' +
153
- '<div>' +
154
- '<label style="display:block;margin-bottom:4px;font-size:13px;color:var(--text-secondary);">Categories <span style="color:var(--accent-primary);">*</span></label>' +
155
- '<input type="text" id="saveCategoriesInput" class="brainstorm-input" placeholder="e.g. Tool, Game, Utility" style="width:100%;box-sizing:border-box;">' +
156
- '<div id="saveCategoriesError" style="color:#ff6b6b;font-size:12px;margin-top:4px;display:none;">At least one category is required</div>' +
157
- '</div>' +
158
- '<div>' +
159
- '<label style="display:block;margin-bottom:4px;font-size:13px;color:var(--text-secondary);">Greeting <span style="font-size:11px;opacity:0.7;">(optional)</span></label>' +
160
- '<input type="text" id="saveGreetingInput" class="brainstorm-input" placeholder="Available when title changes" style="width:100%;box-sizing:border-box;" disabled>' +
161
- '<div style="font-size:11px;color:var(--text-secondary);margin-top:4px;opacity:0.7;" id="saveGreetingHint">Change the title to enable a custom greeting.</div>' +
162
- '</div>' +
163
- '</div>' +
164
- '<div class="modal-footer" style="display:flex;justify-content:flex-end;gap:8px;padding:12px 20px;">' +
165
- '<button type="button" class="brainstorm-send-btn" id="saveCancelBtn" style="background:transparent;border:1px solid var(--border-color);color:var(--text-secondary);">Cancel</button>' +
166
- '<button type="button" class="brainstorm-send-btn" id="saveConfirmBtn">Save</button>' +
167
- '</div>' +
168
- '</div>';
169
- document.body.appendChild(modal);
170
-
171
- // --- Create error modal ---
172
- var errorModal = document.createElement('div');
173
- errorModal.id = 'errorModal';
174
- errorModal.className = 'modal-overlay';
175
- errorModal.innerHTML =
176
- '<div class="modal-content" style="max-width:400px;">' +
177
- '<div class="modal-header">' +
178
- '<span>Error</span>' +
179
- '<button type="button" class="brainstorm-close-btn" id="errorCloseBtn">&times;</button>' +
180
- '</div>' +
181
- '<div class="modal-body" style="padding:16px 20px;">' +
182
- '<p id="errorMessage" style="margin:0;color:var(--text-primary);"></p>' +
183
- '</div>' +
184
- '<div class="modal-footer" style="display:flex;justify-content:flex-end;padding:12px 20px;">' +
185
- '<button type="button" class="brainstorm-send-btn" id="errorOkBtn">OK</button>' +
186
- '</div>' +
187
- '</div>';
188
- document.body.appendChild(errorModal);
189
-
190
- // --- Element references ---
191
- var titleInput = document.getElementById('saveTitleInput');
192
- var categoriesInput = document.getElementById('saveCategoriesInput');
193
- var greetingInput = document.getElementById('saveGreetingInput');
194
- var greetingHint = document.getElementById('saveGreetingHint');
195
- var titleError = document.getElementById('saveTitleError');
196
- var categoriesError = document.getElementById('saveCategoriesError');
197
-
198
- // --- Greeting enable/disable based on title change ---
199
- titleInput.addEventListener('input', function() {
200
- var changed = titleInput.value.trim() !== originalTitle;
201
- greetingInput.disabled = !changed;
202
- if (changed) {
203
- greetingInput.placeholder = 'Enter a custom greeting...';
204
- greetingHint.textContent = 'Replaces the initial Synthos greeting and removes chat history.';
205
- } else {
206
- greetingInput.placeholder = 'Available when title changes';
207
- greetingInput.value = '';
208
- greetingHint.textContent = 'Change the title to enable a custom greeting.';
209
- }
210
- });
211
-
212
- // --- Open modal ---
213
- function openSaveModal() {
214
- // Pre-fill fields (blank for Builder pages)
215
- titleInput.value = isBuilder ? '' : originalTitle;
216
- categoriesInput.value = isBuilder ? '' : (
217
- (window.pageInfo && Array.isArray(window.pageInfo.categories))
218
- ? window.pageInfo.categories.join(', ')
219
- : ''
220
- );
221
- greetingInput.value = '';
222
- greetingInput.disabled = true;
223
- greetingInput.placeholder = 'Available when title changes';
224
- greetingHint.textContent = 'Change the title to enable a custom greeting.';
225
- titleError.style.display = 'none';
226
- categoriesError.style.display = 'none';
227
- modal.classList.add('show');
228
- titleInput.focus();
229
- }
230
-
231
- function closeSaveModal() {
232
- modal.classList.remove('show');
233
- }
234
-
235
- function showError(msg) {
236
- document.getElementById('errorMessage').textContent = msg;
237
- errorModal.classList.add('show');
238
- }
239
-
240
- function closeError() {
241
- errorModal.classList.remove('show');
242
- }
243
-
244
- // --- Submit ---
245
- function submitSave() {
246
- var title = titleInput.value.trim();
247
- var cats = categoriesInput.value.trim();
248
- var greeting = greetingInput.value.trim();
249
- var valid = true;
250
-
251
- // Validate
252
- if (!title) {
253
- titleError.style.display = 'block';
254
- valid = false;
255
- } else {
256
- titleError.style.display = 'none';
257
- }
258
- if (!cats) {
259
- categoriesError.style.display = 'block';
260
- valid = false;
261
- } else {
262
- categoriesError.style.display = 'none';
263
- }
264
- if (!valid) return;
265
-
266
- // Parse categories
267
- var categories = cats.split(',').map(function(c) { return c.trim(); }).filter(Boolean);
268
-
269
- // Disable button during save
270
- var confirmBtn = document.getElementById('saveConfirmBtn');
271
- confirmBtn.disabled = true;
272
- confirmBtn.textContent = 'Saving...';
273
-
274
- var body = { title: title, categories: categories };
275
- if (greeting && !greetingInput.disabled) {
276
- body.greeting = greeting;
277
- }
278
-
279
- fetch(window.location.pathname + '/save', {
280
- method: 'POST',
281
- headers: { 'Content-Type': 'application/json' },
282
- body: JSON.stringify(body)
283
- })
284
- .then(function(res) {
285
- return res.json().then(function(data) {
286
- return { ok: res.ok, data: data };
287
- });
288
- })
289
- .then(function(result) {
290
- if (result.ok && result.data.redirect) {
291
- window.location.href = result.data.redirect;
292
- } else {
293
- closeSaveModal();
294
- showError(result.data.error || 'An unknown error occurred');
295
- confirmBtn.disabled = false;
296
- confirmBtn.textContent = 'Save';
297
- }
298
- })
299
- .catch(function(err) {
300
- closeSaveModal();
301
- showError('Network error: ' + err.message);
302
- confirmBtn.disabled = false;
303
- confirmBtn.textContent = 'Save';
304
- });
305
- }
306
-
307
- // --- Event listeners ---
308
- saveLink.addEventListener('click', openSaveModal);
309
- document.getElementById('saveCloseBtn').addEventListener('click', closeSaveModal);
310
- document.getElementById('saveCancelBtn').addEventListener('click', closeSaveModal);
311
- document.getElementById('saveConfirmBtn').addEventListener('click', submitSave);
312
- document.getElementById('errorCloseBtn').addEventListener('click', closeError);
313
- document.getElementById('errorOkBtn').addEventListener('click', closeError);
314
-
315
- var saveModalMouseDownTarget = null;
316
- modal.addEventListener('mousedown', function(e) { saveModalMouseDownTarget = e.target; });
317
- modal.addEventListener('click', function(e) {
318
- if (e.target === modal && saveModalMouseDownTarget === modal) closeSaveModal();
319
- saveModalMouseDownTarget = null;
320
- });
321
- var errorModalMouseDownTarget = null;
322
- errorModal.addEventListener('mousedown', function(e) { errorModalMouseDownTarget = e.target; });
323
- errorModal.addEventListener('click', function(e) {
324
- if (e.target === errorModal && errorModalMouseDownTarget === errorModal) closeError();
325
- errorModalMouseDownTarget = null;
326
- });
327
-
328
- document.addEventListener('keydown', function(e) {
329
- if (e.key === 'Escape') {
330
- if (modal.classList.contains('show')) closeSaveModal();
331
- if (errorModal.classList.contains('show')) closeError();
332
- }
333
- });
334
-
335
- // Enter key in title/categories inputs triggers save
336
- titleInput.addEventListener('keydown', function(e) {
337
- if (e.key === 'Enter') { e.preventDefault(); submitSave(); }
338
- });
339
- categoriesInput.addEventListener('keydown', function(e) {
340
- if (e.key === 'Enter') { e.preventDefault(); submitSave(); }
341
- });
342
- })();
343
-
344
- // 4. Reset link handler
345
- var resetLink = document.getElementById('resetLink');
346
- if (resetLink) {
347
- resetLink.addEventListener('click', function() {
348
- window.location.href = window.location.pathname + '/reset';
349
- });
350
- }
351
-
352
- // 5. Chat scroll to bottom
353
- var chatMessages = document.getElementById('chatMessages');
354
- if (chatMessages) {
355
- chatMessages.scrollTo({
356
- top: chatMessages.scrollHeight,
357
- behavior: 'smooth'
358
- });
359
- }
360
-
361
- // 6. Chat toggle button — create (if not already in markup), persist in localStorage
362
- (function() {
363
- var btn = document.querySelector('.chat-toggle');
364
- if (!btn) {
365
- btn = document.createElement('button');
366
- btn.className = 'chat-toggle';
367
- btn.setAttribute('aria-label', 'Toggle chat panel');
368
- var dots = document.createElement('span');
369
- dots.className = 'chat-toggle-dots';
370
- for (var i = 0; i < 3; i++) {
371
- var dot = document.createElement('span');
372
- dot.className = 'chat-toggle-dot';
373
- dots.appendChild(dot);
374
- }
375
- btn.appendChild(dots);
376
- document.body.appendChild(btn);
377
- }
378
-
379
- var STORAGE_KEY = 'synthos-chat-collapsed';
380
-
381
- if (localStorage.getItem(STORAGE_KEY) === 'true') {
382
- document.body.classList.add('chat-collapsed');
383
- }
384
-
385
- btn.addEventListener('click', function() {
386
- document.body.classList.toggle('chat-collapsed');
387
- localStorage.setItem(STORAGE_KEY, document.body.classList.contains('chat-collapsed'));
388
- });
389
- })();
390
-
391
- // 7. Focus management — prevent viewer content from stealing keystrokes
392
- (function() {
393
- var ci = document.getElementById('chatInput');
394
- var vp = document.getElementById('viewerPanel');
395
- if (!ci || !vp) return;
396
-
397
- ci.addEventListener('mousedown', function(e) {
398
- e.stopPropagation();
399
- });
400
-
401
- ['keydown', 'keyup', 'keypress'].forEach(function(type) {
402
- document.addEventListener(type, function(e) {
403
- if (document.activeElement === ci) {
404
- e.stopImmediatePropagation();
405
- }
406
- }, true);
407
- });
408
-
409
- vp.setAttribute('tabindex', '-1');
410
- ci.addEventListener('blur', function() {
411
- vp.focus();
412
- });
413
- })();
414
-
415
- // 8. Brainstorm — dynamic brainstorming UI (available on every v2 page)
416
- (function() {
417
- var chatInput = document.getElementById('chatInput');
418
- if (!chatInput) return;
419
-
420
- // --- Wrap chatInput in .chat-input-wrapper if not already wrapped ---
421
- if (!chatInput.parentElement || !chatInput.parentElement.classList.contains('chat-input-wrapper')) {
422
- var wrapper = document.createElement('div');
423
- wrapper.className = 'chat-input-wrapper';
424
- chatInput.parentNode.insertBefore(wrapper, chatInput);
425
- wrapper.appendChild(chatInput);
426
- }
427
-
428
- // --- Create brainstorm icon button ---
429
- var brainstormBtn = document.createElement('button');
430
- brainstormBtn.type = 'button';
431
- brainstormBtn.className = 'brainstorm-icon-btn';
432
- if (window.__synthOSTooltip) window.__synthOSTooltip(brainstormBtn, 'Brainstorm ideas');
433
- brainstormBtn.innerHTML = '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">' +
434
- '<circle cx="12" cy="12" r="3"></circle>' +
435
- '<path d="M12 1v2M12 21v2M4.22 4.22l1.42 1.42M18.36 18.36l1.42 1.42M1 12h2M21 12h2M4.22 19.78l1.42-1.42M18.36 5.64l1.42-1.42"></path>' +
436
- '</svg>';
437
- chatInput.parentElement.appendChild(brainstormBtn);
438
-
439
- // --- Create brainstorm modal ---
440
- var modal = document.createElement('div');
441
- modal.id = 'brainstormModal';
442
- modal.className = 'modal-overlay brainstorm-modal';
443
- modal.innerHTML =
444
- '<div class="modal-content">' +
445
- '<div class="modal-header">' +
446
- '<span>Brainstorm</span>' +
447
- '<button type="button" class="brainstorm-close-btn" id="brainstormCloseBtn">&times;</button>' +
448
- '</div>' +
449
- '<div class="brainstorm-messages" id="brainstormMessages"></div>' +
450
- '<div class="brainstorm-input-row">' +
451
- '<input type="text" class="brainstorm-input" id="brainstormInput" placeholder="What\'s on your mind...">' +
452
- '<button type="button" class="brainstorm-send-btn" id="brainstormSendBtn">Send</button>' +
453
- '</div>' +
454
- '</div>';
455
- document.body.appendChild(modal);
456
-
457
- // --- State ---
458
- var brainstormHistory = [];
459
-
460
- // --- Helpers ---
461
- function openBrainstorm() {
462
- modal.classList.add('show');
463
- // Grab text from chat input as initial topic
464
- var topic = chatInput.value.trim();
465
- if (topic) {
466
- chatInput.value = '';
467
- sendBrainstormText(topic, true);
468
- } else {
469
- // No topic — send context-only opener so LLM starts the brainstorm
470
- sendBrainstormText('', true);
471
- }
472
- }
473
-
474
- function closeBrainstorm() {
475
- modal.classList.remove('show');
476
- brainstormHistory = [];
477
- document.getElementById('brainstormMessages').innerHTML = '';
478
- }
479
-
480
- function scrollBrainstormToBottom() {
481
- var el = document.getElementById('brainstormMessages');
482
- el.scrollTo({ top: el.scrollHeight, behavior: 'smooth' });
483
- }
484
-
485
- function escapeHtml(str) {
486
- var div = document.createElement('div');
487
- div.appendChild(document.createTextNode(str));
488
- return div.innerHTML;
489
- }
490
-
491
- function appendBrainstormMessage(role, text, prompt, suggestions, isOpener) {
492
- var div = document.createElement('div');
493
- div.className = 'brainstorm-message ' + (role === 'user' ? 'brainstorm-user' : 'brainstorm-assistant');
494
- if (role === 'assistant') {
495
- var html;
496
- if (typeof marked !== 'undefined') {
497
- html = marked.parse(text);
498
- } else {
499
- html = escapeHtml(text);
500
- }
501
- div.innerHTML = '<strong>SynthOS:</strong> ' + html;
502
- // Clickable suggestion chips
503
- if (suggestions && suggestions.length > 0) {
504
- var chips = document.createElement('div');
505
- chips.className = 'brainstorm-suggestions';
506
- suggestions.forEach(function(s) {
507
- var chip = document.createElement('button');
508
- chip.type = 'button';
509
- chip.className = 'brainstorm-suggestion-chip';
510
- chip.textContent = s;
511
- chip.addEventListener('click', function() {
512
- submitSuggestion(s);
513
- });
514
- chips.appendChild(chip);
515
- });
516
- div.appendChild(chips);
517
- }
518
- // "Build It" button — skip on the opener response
519
- if (prompt && !isOpener) {
520
- var btnRow = document.createElement('div');
521
- btnRow.className = 'brainstorm-build-row';
522
- var buildBtn = document.createElement('button');
523
- buildBtn.type = 'button';
524
- buildBtn.className = 'brainstorm-build-btn';
525
- buildBtn.textContent = 'Build It';
526
- buildBtn.setAttribute('data-prompt', prompt);
527
- buildBtn.addEventListener('click', function() {
528
- chatInput.value = this.getAttribute('data-prompt');
529
- closeBrainstorm();
530
- chatInput.focus();
531
- });
532
- btnRow.appendChild(buildBtn);
533
- div.appendChild(btnRow);
534
- }
535
- } else {
536
- div.textContent = text;
537
- }
538
- document.getElementById('brainstormMessages').appendChild(div);
539
- scrollBrainstormToBottom();
540
- }
541
-
542
- function submitSuggestion(text) {
543
- // Disable old suggestion chips so they can't be double-clicked
544
- var oldChips = document.querySelectorAll('#brainstormMessages .brainstorm-suggestion-chip');
545
- for (var i = 0; i < oldChips.length; i++) {
546
- oldChips[i].disabled = true;
547
- }
548
- sendBrainstormText(text, false);
549
- }
550
-
551
- function getBrainstormContext() {
552
- var chatEl = document.getElementById('chatMessages');
553
- if (!chatEl) return '<CHAT_HISTORY>\n';
554
- var msgs = chatEl.querySelectorAll('.chat-message');
555
- var lines = [];
556
- var started = false;
557
- for (var i = 0; i < msgs.length; i++) {
558
- var text = msgs[i].innerText;
559
- if (!started && /^User:/i.test(text.trim())) started = true;
560
- if (started) lines.push(text);
561
- }
562
- return '<CHAT_HISTORY>\n' + lines.join('\n');
563
- }
564
-
565
- // Send from the input field
566
- function sendBrainstormMessage() {
567
- var input = document.getElementById('brainstormInput');
568
- var text = input.value.trim();
569
- if (!text) return;
570
- input.value = '';
571
- sendBrainstormText(text, false);
572
- }
573
-
574
- // Core fetch — isOpener=true means this is the initial call when brainstorm opens
575
- function sendBrainstormText(text, isOpener) {
576
- var input = document.getElementById('brainstormInput');
577
- var userMsg = text || (isOpener ? 'Look at the conversation so far and suggest what we could build or improve.' : '');
578
- if (!userMsg) return;
579
-
580
- // Show user message in chat (skip for auto-generated opener)
581
- if (text) {
582
- appendBrainstormMessage('user', text);
583
- }
584
- brainstormHistory.push({ role: 'user', content: userMsg });
585
-
586
- var thinking = document.createElement('div');
587
- thinking.className = 'brainstorm-thinking';
588
- thinking.id = 'brainstormThinking';
589
- thinking.textContent = 'Thinking...';
590
- document.getElementById('brainstormMessages').appendChild(thinking);
591
- scrollBrainstormToBottom();
592
-
593
- input.disabled = true;
594
- document.getElementById('brainstormSendBtn').disabled = true;
595
-
596
- fetch('/api/brainstorm', {
597
- method: 'POST',
598
- headers: { 'Content-Type': 'application/json' },
599
- body: JSON.stringify({
600
- context: getBrainstormContext(),
601
- messages: brainstormHistory
602
- })
603
- })
604
- .then(function(res) {
605
- if (!res.ok) throw new Error('Brainstorm request failed');
606
- return res.json();
607
- })
608
- .then(function(data) {
609
- var thinkingEl = document.getElementById('brainstormThinking');
610
- if (thinkingEl) thinkingEl.remove();
611
-
612
- var response = data.response || 'Sorry, I didn\'t get a response.';
613
- var prompt = data.prompt || '';
614
- var suggestions = Array.isArray(data.suggestions) ? data.suggestions : [];
615
- appendBrainstormMessage('assistant', response, prompt, suggestions, isOpener);
616
- brainstormHistory.push({
617
- role: 'assistant',
618
- content: response + '\n\n[Suggested prompt: ' + prompt + ']'
619
- });
620
- })
621
- .catch(function(err) {
622
- var thinkingEl = document.getElementById('brainstormThinking');
623
- if (thinkingEl) thinkingEl.remove();
624
- appendBrainstormMessage('assistant', 'Something went wrong: ' + err.message);
625
- })
626
- .finally(function() {
627
- input.disabled = false;
628
- document.getElementById('brainstormSendBtn').disabled = false;
629
- input.focus();
630
- });
631
- }
632
-
633
- // --- Event listeners ---
634
- brainstormBtn.addEventListener('click', openBrainstorm);
635
- document.getElementById('brainstormCloseBtn').addEventListener('click', closeBrainstorm);
636
-
637
- var brainstormMouseDownTarget = null;
638
- modal.addEventListener('mousedown', function(e) { brainstormMouseDownTarget = e.target; });
639
- modal.addEventListener('click', function(e) {
640
- if (e.target === modal && brainstormMouseDownTarget === modal) closeBrainstorm();
641
- brainstormMouseDownTarget = null;
642
- });
643
-
644
- document.addEventListener('keydown', function(e) {
645
- if (e.key === 'Escape' && modal.classList.contains('show')) closeBrainstorm();
646
- });
647
-
648
- document.getElementById('brainstormSendBtn').addEventListener('click', sendBrainstormMessage);
649
- document.getElementById('brainstormInput').addEventListener('keydown', function(e) {
650
- if (e.key === 'Enter' && !e.shiftKey) {
651
- e.preventDefault();
652
- sendBrainstormMessage();
653
- }
654
- });
655
- })();
656
- })();