synthos 0.10.1 → 0.11.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 (311) hide show
  1. package/README.md +5 -5
  2. package/default-pages/elevenlabs_effects_studio/chat-history.json +1 -0
  3. package/default-pages/elevenlabs_effects_studio/page.html +1345 -1363
  4. package/default-pages/elevenlabs_effects_studio/page.json +13 -11
  5. package/default-pages/elevenlabs_voice_studio/chat-history.json +1 -0
  6. package/default-pages/elevenlabs_voice_studio/page.html +782 -801
  7. package/default-pages/elevenlabs_voice_studio/page.json +13 -11
  8. package/default-pages/json_tools/chat-history.json +1 -0
  9. package/default-pages/json_tools/page.html +70 -90
  10. package/default-pages/json_tools/page.json +12 -10
  11. package/default-pages/my_notes/chat-history.json +1 -0
  12. package/default-pages/my_notes/page.html +115 -131
  13. package/default-pages/my_notes/page.json +14 -12
  14. package/default-pages/neon_asteroids/chat-history.json +1 -0
  15. package/default-pages/neon_asteroids/page.html +1777 -1803
  16. package/default-pages/neon_asteroids/page.json +14 -12
  17. package/default-pages/oregon_trail/chat-history.json +1 -0
  18. package/default-pages/oregon_trail/page.html +290 -307
  19. package/default-pages/oregon_trail/page.json +14 -12
  20. package/default-pages/solar_explorer/chat-history.json +1 -0
  21. package/default-pages/solar_explorer/page.html +1929 -1951
  22. package/default-pages/solar_explorer/page.json +14 -12
  23. package/default-pages/solar_tutorial/chat-history.json +1 -0
  24. package/default-pages/solar_tutorial/page.html +464 -478
  25. package/default-pages/solar_tutorial/page.json +12 -10
  26. package/default-pages/us_map/chat-history.json +1 -0
  27. package/default-pages/us_map/page.html +170 -193
  28. package/default-pages/us_map/page.json +14 -12
  29. package/default-pages/us_map/page.light.png +0 -0
  30. package/default-pages/us_map_1850/chat-history.json +1 -0
  31. package/default-pages/us_map_1850/page.html +302 -326
  32. package/default-pages/us_map_1850/page.json +14 -12
  33. package/default-pages/western_cities_1850/chat-history.json +1 -0
  34. package/default-pages/western_cities_1850/page.html +503 -527
  35. package/default-pages/western_cities_1850/page.json +14 -12
  36. package/default-themes/aurora-dawn.v3.css +15 -14
  37. package/default-themes/aurora-dusk.v3.css +26 -26
  38. package/default-themes/cosmos-dawn.v3.css +15 -14
  39. package/default-themes/cosmos-dusk.v3.css +26 -26
  40. package/default-themes/elemental-dawn.v3.css +200 -0
  41. package/default-themes/nebula-dawn.v3.css +15 -14
  42. package/default-themes/nebula-dusk.v3.css +24 -24
  43. package/default-themes/solar-flare-dawn.v3.css +15 -14
  44. package/default-themes/solar-flare-dusk.v3.css +26 -26
  45. package/dist/builders/anthropic.d.ts +26 -2
  46. package/dist/builders/anthropic.d.ts.map +1 -1
  47. package/dist/builders/anthropic.js +132 -31
  48. package/dist/builders/anthropic.js.map +1 -1
  49. package/dist/builders/claudecode.d.ts +13 -0
  50. package/dist/builders/claudecode.d.ts.map +1 -0
  51. package/dist/builders/claudecode.js +253 -0
  52. package/dist/builders/claudecode.js.map +1 -0
  53. package/dist/builders/index.d.ts +2 -1
  54. package/dist/builders/index.d.ts.map +1 -1
  55. package/dist/builders/index.js +8 -1
  56. package/dist/builders/index.js.map +1 -1
  57. package/dist/builders/openai.js +2 -1
  58. package/dist/builders/openai.js.map +1 -1
  59. package/dist/builders/types.d.ts +31 -7
  60. package/dist/builders/types.d.ts.map +1 -1
  61. package/dist/builders/types.js +60 -28
  62. package/dist/builders/types.js.map +1 -1
  63. package/dist/connectors/types.d.ts +8 -0
  64. package/dist/connectors/types.d.ts.map +1 -1
  65. package/dist/init.d.ts.map +1 -1
  66. package/dist/init.js +13 -6
  67. package/dist/init.js.map +1 -1
  68. package/dist/migrations.d.ts.map +1 -1
  69. package/dist/migrations.js +161 -14
  70. package/dist/migrations.js.map +1 -1
  71. package/dist/models/anthropic.d.ts +1 -0
  72. package/dist/models/anthropic.d.ts.map +1 -1
  73. package/dist/models/anthropic.js +129 -29
  74. package/dist/models/anthropic.js.map +1 -1
  75. package/dist/models/chainOfThought.d.ts.map +1 -1
  76. package/dist/models/chainOfThought.js +32 -19
  77. package/dist/models/chainOfThought.js.map +1 -1
  78. package/dist/models/index.d.ts +2 -2
  79. package/dist/models/index.d.ts.map +1 -1
  80. package/dist/models/index.js +2 -1
  81. package/dist/models/index.js.map +1 -1
  82. package/dist/models/providers.d.ts +1 -0
  83. package/dist/models/providers.d.ts.map +1 -1
  84. package/dist/models/providers.js +12 -4
  85. package/dist/models/providers.js.map +1 -1
  86. package/dist/models/types.d.ts +15 -1
  87. package/dist/models/types.d.ts.map +1 -1
  88. package/dist/models/types.js.map +1 -1
  89. package/dist/pages.d.ts +57 -8
  90. package/dist/pages.d.ts.map +1 -1
  91. package/dist/pages.js +258 -45
  92. package/dist/pages.js.map +1 -1
  93. package/dist/service/createCompletePrompt.d.ts.map +1 -1
  94. package/dist/service/createCompletePrompt.js +5 -0
  95. package/dist/service/createCompletePrompt.js.map +1 -1
  96. package/dist/service/mediaCache.d.ts +36 -0
  97. package/dist/service/mediaCache.d.ts.map +1 -0
  98. package/dist/service/mediaCache.js +182 -0
  99. package/dist/service/mediaCache.js.map +1 -0
  100. package/dist/service/pageValidator.d.ts +25 -0
  101. package/dist/service/pageValidator.d.ts.map +1 -0
  102. package/dist/service/pageValidator.js +315 -0
  103. package/dist/service/pageValidator.js.map +1 -0
  104. package/dist/service/server.d.ts.map +1 -1
  105. package/dist/service/server.js +4 -0
  106. package/dist/service/server.js.map +1 -1
  107. package/dist/service/sharedTableSchema.d.ts +73 -0
  108. package/dist/service/sharedTableSchema.d.ts.map +1 -0
  109. package/dist/service/sharedTableSchema.js +206 -0
  110. package/dist/service/sharedTableSchema.js.map +1 -0
  111. package/dist/service/transformPage.d.ts +49 -11
  112. package/dist/service/transformPage.d.ts.map +1 -1
  113. package/dist/service/transformPage.js +354 -241
  114. package/dist/service/transformPage.js.map +1 -1
  115. package/dist/service/useApiRoutes.d.ts.map +1 -1
  116. package/dist/service/useApiRoutes.js +288 -34
  117. package/dist/service/useApiRoutes.js.map +1 -1
  118. package/dist/service/useConnectorRoutes.d.ts.map +1 -1
  119. package/dist/service/useConnectorRoutes.js +170 -32
  120. package/dist/service/useConnectorRoutes.js.map +1 -1
  121. package/dist/service/useDataRoutes.d.ts.map +1 -1
  122. package/dist/service/useDataRoutes.js +59 -2
  123. package/dist/service/useDataRoutes.js.map +1 -1
  124. package/dist/service/useExtractRoutes.d.ts +4 -0
  125. package/dist/service/useExtractRoutes.d.ts.map +1 -0
  126. package/dist/service/useExtractRoutes.js +304 -0
  127. package/dist/service/useExtractRoutes.js.map +1 -0
  128. package/dist/service/usePageRoutes.d.ts +17 -0
  129. package/dist/service/usePageRoutes.d.ts.map +1 -1
  130. package/dist/service/usePageRoutes.js +1385 -483
  131. package/dist/service/usePageRoutes.js.map +1 -1
  132. package/dist/service/useSharedDataRoutes.d.ts.map +1 -1
  133. package/dist/service/useSharedDataRoutes.js +54 -2
  134. package/dist/service/useSharedDataRoutes.js.map +1 -1
  135. package/dist/settings.d.ts +27 -0
  136. package/dist/settings.d.ts.map +1 -1
  137. package/dist/settings.js +40 -1
  138. package/dist/settings.js.map +1 -1
  139. package/dist/themes.d.ts +0 -5
  140. package/dist/themes.d.ts.map +1 -1
  141. package/dist/themes.js +3 -95
  142. package/dist/themes.js.map +1 -1
  143. package/migration-rules/v2-to-v3.md +277 -119
  144. package/package.json +5 -1
  145. package/{default-pages/application → required-pages/_shell}/page.html +56 -42
  146. package/required-pages/_shell/page.json +14 -0
  147. package/required-pages/_starters/page.html +534 -0
  148. package/required-pages/_starters/page.json +12 -0
  149. package/required-pages/builder/page.html +353 -43
  150. package/required-pages/builder/page.json +12 -10
  151. package/required-pages/pages/page.html +697 -924
  152. package/required-pages/pages/page.json +12 -10
  153. package/required-pages/settings/page.html +1879 -1753
  154. package/required-pages/settings/page.json +12 -10
  155. package/required-pages/synthos_apis/page.html +834 -845
  156. package/required-pages/synthos_apis/page.json +12 -10
  157. package/required-pages/synthos_scripts/page.html +74 -88
  158. package/required-pages/synthos_scripts/page.json +12 -10
  159. package/scripts/append-instructions.py +90 -0
  160. package/scripts/audit-instructions.py +76 -0
  161. package/scripts/cleanup-shell-markup.mjs +112 -0
  162. package/service-connectors/buffer/connector.json +46 -0
  163. package/service-connectors/canva/connector.json +67 -0
  164. package/service-connectors/elevenlabs/connector.json +1 -1
  165. package/src/builders/anthropic.ts +150 -25
  166. package/src/builders/claudecode.ts +310 -0
  167. package/src/builders/index.ts +7 -1
  168. package/src/builders/openai.ts +2 -1
  169. package/src/builders/types.ts +93 -32
  170. package/src/connectors/types.ts +8 -0
  171. package/src/init.ts +13 -7
  172. package/src/migrations.ts +187 -16
  173. package/src/models/anthropic.ts +140 -30
  174. package/src/models/chainOfThought.ts +33 -18
  175. package/src/models/index.ts +2 -2
  176. package/src/models/providers.ts +10 -1
  177. package/src/models/types.ts +21 -1
  178. package/src/pages.ts +271 -35
  179. package/src/service/createCompletePrompt.ts +6 -0
  180. package/src/service/mediaCache.ts +206 -0
  181. package/src/service/pageValidator.ts +337 -0
  182. package/src/service/server.ts +4 -0
  183. package/src/service/sharedTableSchema.ts +236 -0
  184. package/src/service/transformPage.ts +370 -260
  185. package/src/service/useApiRoutes.ts +282 -32
  186. package/src/service/useConnectorRoutes.ts +189 -34
  187. package/src/service/useDataRoutes.ts +198 -116
  188. package/src/service/useExtractRoutes.ts +331 -0
  189. package/src/service/usePageRoutes.ts +1411 -394
  190. package/src/service/useSharedDataRoutes.ts +184 -109
  191. package/src/settings.ts +65 -0
  192. package/src/themes.ts +78 -180
  193. package/starters/blank_starter/chat-history.json +1 -0
  194. package/starters/blank_starter/page.dark.png +0 -0
  195. package/starters/blank_starter/page.html +47 -0
  196. package/starters/blank_starter/page.json +13 -0
  197. package/starters/blank_starter/page.light.png +0 -0
  198. package/starters/calculator_starter/chat-history.json +1 -0
  199. package/starters/calculator_starter/page.dark.png +0 -0
  200. package/starters/calculator_starter/page.html +232 -0
  201. package/starters/calculator_starter/page.json +13 -0
  202. package/starters/calculator_starter/page.light.png +0 -0
  203. package/starters/calendar_starter/chat-history.json +1 -0
  204. package/starters/calendar_starter/page.dark.png +0 -0
  205. package/starters/calendar_starter/page.html +495 -0
  206. package/starters/calendar_starter/page.json +13 -0
  207. package/starters/calendar_starter/page.light.png +0 -0
  208. package/starters/chat_starter/chat-history.json +1 -0
  209. package/starters/chat_starter/page.dark.png +0 -0
  210. package/starters/chat_starter/page.html +351 -0
  211. package/starters/chat_starter/page.json +13 -0
  212. package/starters/chat_starter/page.light.png +0 -0
  213. package/starters/checklist_starter/chat-history.json +1 -0
  214. package/starters/checklist_starter/page.dark.png +0 -0
  215. package/starters/checklist_starter/page.html +437 -0
  216. package/starters/checklist_starter/page.json +13 -0
  217. package/starters/checklist_starter/page.light.png +0 -0
  218. package/starters/dashboard_starter/chat-history.json +1 -0
  219. package/starters/dashboard_starter/page.dark.png +0 -0
  220. package/starters/dashboard_starter/page.html +195 -0
  221. package/starters/dashboard_starter/page.json +13 -0
  222. package/starters/dashboard_starter/page.light.png +0 -0
  223. package/starters/form_starter/chat-history.json +1 -0
  224. package/starters/form_starter/page.dark.png +0 -0
  225. package/starters/form_starter/page.html +313 -0
  226. package/starters/form_starter/page.json +13 -0
  227. package/starters/form_starter/page.light.png +0 -0
  228. package/starters/gallery_starter/chat-history.json +1 -0
  229. package/starters/gallery_starter/page.dark.png +0 -0
  230. package/starters/gallery_starter/page.html +418 -0
  231. package/starters/gallery_starter/page.json +13 -0
  232. package/starters/gallery_starter/page.light.png +0 -0
  233. package/starters/generator_starter/chat-history.json +1 -0
  234. package/starters/generator_starter/page.dark.png +0 -0
  235. package/starters/generator_starter/page.html +261 -0
  236. package/starters/generator_starter/page.json +13 -0
  237. package/starters/generator_starter/page.light.png +0 -0
  238. package/starters/index.html +538 -0
  239. package/starters/kanban_starter/chat-history.json +1 -0
  240. package/starters/kanban_starter/page.dark.png +0 -0
  241. package/starters/kanban_starter/page.html +432 -0
  242. package/starters/kanban_starter/page.json +13 -0
  243. package/starters/kanban_starter/page.light.png +0 -0
  244. package/starters/presentation_builder/chat-history.json +1 -0
  245. package/starters/presentation_builder/page.dark.png +0 -0
  246. package/starters/presentation_builder/page.html +970 -0
  247. package/starters/presentation_builder/page.json +15 -0
  248. package/starters/presentation_builder/page.light.png +0 -0
  249. package/starters/presentation_builder/presentation_voice/voice_config.json +9 -0
  250. package/starters/pulse_starter/chat-history.json +1 -0
  251. package/starters/pulse_starter/page.dark.png +0 -0
  252. package/starters/pulse_starter/page.html +698 -0
  253. package/starters/pulse_starter/page.json +13 -0
  254. package/starters/pulse_starter/page.light.png +0 -0
  255. package/starters/quiz_starter/chat-history.json +1 -0
  256. package/starters/quiz_starter/page.dark.png +0 -0
  257. package/starters/quiz_starter/page.html +292 -0
  258. package/starters/quiz_starter/page.json +13 -0
  259. package/starters/quiz_starter/page.light.png +0 -0
  260. package/starters/reference_starter/chat-history.json +1 -0
  261. package/starters/reference_starter/page.dark.png +0 -0
  262. package/starters/reference_starter/page.html +250 -0
  263. package/starters/reference_starter/page.json +13 -0
  264. package/starters/reference_starter/page.light.png +0 -0
  265. package/starters/retro_game_starter/chat-history.json +1 -0
  266. package/starters/retro_game_starter/page.dark.png +0 -0
  267. package/{default-pages → starters}/retro_game_starter/page.html +1281 -1308
  268. package/starters/retro_game_starter/page.json +15 -0
  269. package/starters/retro_game_starter/page.light.png +0 -0
  270. package/starters/roster_starter/chat-history.json +1 -0
  271. package/starters/roster_starter/page.dark.png +0 -0
  272. package/starters/roster_starter/page.html +600 -0
  273. package/starters/roster_starter/page.json +13 -0
  274. package/starters/roster_starter/page.light.png +0 -0
  275. package/starters/server.js +182 -0
  276. package/starters/start.cmd +1 -0
  277. package/starters/timeline_starter/chat-history.json +1 -0
  278. package/starters/timeline_starter/page.dark.png +0 -0
  279. package/starters/timeline_starter/page.html +446 -0
  280. package/starters/timeline_starter/page.json +13 -0
  281. package/starters/timeline_starter/page.light.png +0 -0
  282. package/starters/tutorial_starter/chat-history.json +1 -0
  283. package/starters/tutorial_starter/page.dark.png +0 -0
  284. package/starters/tutorial_starter/page.html +283 -0
  285. package/starters/tutorial_starter/page.json +13 -0
  286. package/starters/tutorial_starter/page.light.png +0 -0
  287. package/static-files/agent.v3.js +122 -0
  288. package/static-files/connector.v3.js +48 -0
  289. package/static-files/extract.v3.js +188 -0
  290. package/static-files/helpers.v3.js +50 -6
  291. package/static-files/page-bridge.js +114 -0
  292. package/static-files/page.v3.js +1292 -1290
  293. package/static-files/script.v3.js +32 -0
  294. package/static-files/server.v3.js +89 -0
  295. package/static-files/shell-bridge.v3.js +174 -0
  296. package/static-files/shell-modals.v3.js +521 -0
  297. package/static-files/{shell.css → shell.v3.css} +271 -22
  298. package/static-files/shell.v3.js +1865 -0
  299. package/static-files/storage.v3.js +176 -0
  300. package/tests/anthropic.spec.ts +42 -7
  301. package/tests/builders.spec.ts +70 -2
  302. package/tests/pageValidator.spec.ts +548 -0
  303. package/tests/profiles.spec.ts +122 -0
  304. package/tests/sharedTableSchema.spec.ts +242 -0
  305. package/tests/transformPage.spec.ts +62 -81
  306. package/default-pages/application/page.json +0 -10
  307. package/default-pages/retro_game_starter/page.json +0 -12
  308. package/default-pages/sidebar_page/page.html +0 -51
  309. package/default-pages/sidebar_page/page.json +0 -10
  310. package/default-pages/two-panel_page/page.html +0 -68
  311. package/default-pages/two-panel_page/page.json +0 -10
@@ -0,0 +1,698 @@
1
+ <!DOCTYPE html><html lang="en"><head>
2
+ <meta charset="UTF-8">
3
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
4
+ <title>SynthOS - Pulse Starter</title>
5
+ <script id="theme-info" src="/api/theme-info.js" data-locked="true"></script>
6
+ <link id="theme-css" rel="stylesheet" href="/api/theme.css" data-locked="true">
7
+ <style>
8
+ html, body { height: 100%; }
9
+ body { margin: 0; }
10
+ .viewer-panel { height: 100%; }
11
+ .pulse-app {
12
+ display: flex;
13
+ flex-direction: column;
14
+ height: 100%;
15
+ min-height: 100%;
16
+ box-sizing: border-box;
17
+ }
18
+ .pulse-header {
19
+ display: flex;
20
+ justify-content: space-between;
21
+ align-items: center;
22
+ padding: 14px 24px;
23
+ border-bottom: 1px solid var(--bodyDivider, #edebe9);
24
+ background: var(--defaultStateBackground, #faf9f8);
25
+ gap: 12px;
26
+ flex: 0 0 auto;
27
+ }
28
+ .pulse-header h1 {
29
+ margin: 0;
30
+ font-size: 18px;
31
+ font-weight: 700;
32
+ color: var(--bodyText, #333333);
33
+ }
34
+ .pulse-header .subtitle {
35
+ margin: 2px 0 0;
36
+ font-size: 12px;
37
+ color: var(--bodySubtext, #605e5c);
38
+ }
39
+ .pulse-actions { display: flex; gap: 8px; align-items: center; }
40
+
41
+ .data-strip {
42
+ display: flex;
43
+ align-items: center;
44
+ gap: 10px;
45
+ padding: 10px 24px;
46
+ border-bottom: 1px solid var(--bodyDivider, #edebe9);
47
+ background: var(--bodyBackground, #ffffff);
48
+ flex: 0 0 auto;
49
+ flex-wrap: wrap;
50
+ }
51
+ .data-strip-label {
52
+ font-size: 11px;
53
+ font-weight: 600;
54
+ text-transform: uppercase;
55
+ letter-spacing: 0.04em;
56
+ color: var(--bodySubtext, #605e5c);
57
+ }
58
+ .data-chips {
59
+ display: flex;
60
+ gap: 6px;
61
+ flex-wrap: wrap;
62
+ flex: 1 1 auto;
63
+ }
64
+ .data-chip {
65
+ display: inline-flex;
66
+ align-items: center;
67
+ gap: 6px;
68
+ padding: 4px 10px;
69
+ border-radius: 999px;
70
+ background: color-mix(in srgb, var(--themePrimary, #0078d4) 12%, transparent);
71
+ color: var(--themePrimary, #0078d4);
72
+ font-size: 12px;
73
+ font-weight: 500;
74
+ }
75
+ .data-chip .count {
76
+ font-size: 11px;
77
+ opacity: 0.75;
78
+ }
79
+ .data-strip-link {
80
+ font-size: 12px;
81
+ color: var(--themePrimary, #0078d4);
82
+ text-decoration: none;
83
+ cursor: pointer;
84
+ }
85
+ .data-strip-link:hover { text-decoration: underline; }
86
+
87
+ .transcript {
88
+ flex: 1 1 auto;
89
+ min-height: 0;
90
+ overflow-y: auto;
91
+ padding: 20px 24px;
92
+ display: flex;
93
+ flex-direction: column;
94
+ gap: 18px;
95
+ background: var(--bodyBackground, #ffffff);
96
+ }
97
+ .empty-state {
98
+ margin: auto;
99
+ text-align: center;
100
+ color: var(--bodySubtext, #605e5c);
101
+ font-size: 13px;
102
+ max-width: 540px;
103
+ line-height: 1.5;
104
+ }
105
+ .empty-state strong {
106
+ display: block;
107
+ font-size: 15px;
108
+ color: var(--bodyText, #333333);
109
+ margin-bottom: 6px;
110
+ }
111
+ .empty-state p { margin: 0 0 14px; }
112
+ .suggestion-grid {
113
+ display: grid;
114
+ grid-template-columns: repeat(2, minmax(0, 1fr));
115
+ gap: 8px;
116
+ margin-top: 10px;
117
+ }
118
+ .suggestion-chip {
119
+ border: 1px solid var(--bodyDivider, #edebe9);
120
+ background: var(--defaultStateBackground, #faf9f8);
121
+ color: var(--bodyText, #333333);
122
+ border-radius: 10px;
123
+ padding: 10px 12px;
124
+ font: inherit;
125
+ font-size: 12px;
126
+ line-height: 1.35;
127
+ text-align: left;
128
+ cursor: pointer;
129
+ transition: border-color .12s ease, background .12s ease;
130
+ }
131
+ .suggestion-chip:hover {
132
+ border-color: var(--themePrimary, #0078d4);
133
+ background: var(--bodyBackgroundHovered, #f3f2f1);
134
+ }
135
+
136
+ .turn { display: flex; flex-direction: column; gap: 8px; }
137
+ .prompt-bubble {
138
+ align-self: flex-end;
139
+ max-width: min(560px, 78%);
140
+ padding: 10px 14px;
141
+ border-radius: 14px 14px 4px 14px;
142
+ background: var(--themePrimary, #0078d4);
143
+ color: #ffffff;
144
+ font-size: 14px;
145
+ line-height: 1.45;
146
+ white-space: pre-wrap;
147
+ word-wrap: break-word;
148
+ }
149
+
150
+ .result-card {
151
+ border: 1px solid var(--bodyDivider, #edebe9);
152
+ border-radius: 12px;
153
+ background: var(--defaultStateBackground, #faf9f8);
154
+ overflow: hidden;
155
+ box-sizing: border-box;
156
+ }
157
+ .result-header {
158
+ display: flex;
159
+ align-items: center;
160
+ gap: 10px;
161
+ padding: 12px 14px;
162
+ border-bottom: 1px solid var(--bodyDivider, #edebe9);
163
+ background: var(--bodyBackground, #ffffff);
164
+ }
165
+ .result-icon {
166
+ display: inline-flex;
167
+ align-items: center;
168
+ justify-content: center;
169
+ width: 24px;
170
+ height: 24px;
171
+ border-radius: 6px;
172
+ background: color-mix(in srgb, var(--themePrimary, #0078d4) 16%, transparent);
173
+ color: var(--themePrimary, #0078d4);
174
+ font-size: 13px;
175
+ font-weight: 700;
176
+ flex: 0 0 auto;
177
+ }
178
+ .result-summary {
179
+ flex: 1 1 auto;
180
+ font-size: 13px;
181
+ color: var(--bodyText, #333333);
182
+ line-height: 1.4;
183
+ }
184
+ .result-summary .grounding {
185
+ display: block;
186
+ margin-top: 2px;
187
+ font-size: 11px;
188
+ color: var(--bodySubtext, #605e5c);
189
+ }
190
+ .result-body { padding: 8px 6px; }
191
+
192
+ /* List shape */
193
+ .result-list { display: flex; flex-direction: column; }
194
+ .result-row {
195
+ display: flex;
196
+ justify-content: space-between;
197
+ align-items: center;
198
+ gap: 10px;
199
+ padding: 10px 12px;
200
+ border-radius: 8px;
201
+ }
202
+ .result-row + .result-row {
203
+ border-top: 1px solid var(--bodyDivider, #edebe9);
204
+ border-radius: 0;
205
+ }
206
+ .result-row:hover { background: var(--bodyBackgroundHovered, #f3f2f1); }
207
+ .row-content {
208
+ flex: 1 1 auto;
209
+ font-size: 13px;
210
+ color: var(--bodyText, #333333);
211
+ line-height: 1.4;
212
+ }
213
+ .row-content .row-meta {
214
+ display: block;
215
+ margin-top: 2px;
216
+ font-size: 11px;
217
+ color: var(--bodySubtext, #605e5c);
218
+ }
219
+ .row-actions {
220
+ display: flex;
221
+ gap: 4px;
222
+ flex: 0 0 auto;
223
+ }
224
+ .row-action {
225
+ border: 1px solid transparent;
226
+ background: transparent;
227
+ color: var(--themePrimary, #0078d4);
228
+ font: inherit;
229
+ font-size: 12px;
230
+ padding: 4px 8px;
231
+ border-radius: 6px;
232
+ cursor: pointer;
233
+ }
234
+ .row-action:hover {
235
+ background: color-mix(in srgb, var(--themePrimary, #0078d4) 10%, transparent);
236
+ }
237
+
238
+ /* Draft shape */
239
+ .result-draft {
240
+ padding: 4px 8px 6px;
241
+ }
242
+ .draft-meta {
243
+ font-size: 11px;
244
+ color: var(--bodySubtext, #605e5c);
245
+ padding: 4px 6px;
246
+ }
247
+ .draft-meta strong { color: var(--bodyText, #333333); font-weight: 600; }
248
+ .draft-body {
249
+ margin-top: 4px;
250
+ padding: 10px 12px;
251
+ background: var(--bodyBackground, #ffffff);
252
+ border: 1px solid var(--bodyDivider, #edebe9);
253
+ border-radius: 8px;
254
+ font-size: 13px;
255
+ line-height: 1.5;
256
+ color: var(--bodyText, #333333);
257
+ white-space: pre-wrap;
258
+ }
259
+
260
+ /* Batch shape */
261
+ .result-batch {
262
+ padding: 8px 12px 4px;
263
+ font-size: 13px;
264
+ color: var(--bodyText, #333333);
265
+ line-height: 1.5;
266
+ }
267
+ .batch-list {
268
+ margin: 6px 0 4px;
269
+ padding-left: 18px;
270
+ }
271
+ .batch-list li { margin: 2px 0; color: var(--bodySubtext, #605e5c); font-size: 12px; }
272
+
273
+ .result-footer {
274
+ display: flex;
275
+ justify-content: flex-end;
276
+ gap: 6px;
277
+ padding: 10px 12px;
278
+ border-top: 1px solid var(--bodyDivider, #edebe9);
279
+ background: var(--bodyBackground, #ffffff);
280
+ }
281
+ .footer-action {
282
+ border: 1px solid var(--bodyDivider, #edebe9);
283
+ background: var(--bodyBackground, #ffffff);
284
+ color: var(--bodyText, #333333);
285
+ font: inherit;
286
+ font-size: 12px;
287
+ padding: 6px 12px;
288
+ border-radius: 6px;
289
+ cursor: pointer;
290
+ }
291
+ .footer-action:hover { background: var(--bodyBackgroundHovered, #f3f2f1); }
292
+ .footer-action.primary {
293
+ background: var(--themePrimary, #0078d4);
294
+ color: #ffffff;
295
+ border-color: var(--themePrimary, #0078d4);
296
+ }
297
+ .footer-action.primary:hover {
298
+ background: var(--themeDarkAlt, #106ebe);
299
+ border-color: var(--themeDarkAlt, #106ebe);
300
+ }
301
+
302
+ .thinking {
303
+ display: inline-flex;
304
+ gap: 4px;
305
+ padding: 6px 10px;
306
+ border-radius: 999px;
307
+ background: var(--defaultStateBackground, #faf9f8);
308
+ border: 1px solid var(--bodyDivider, #edebe9);
309
+ color: var(--bodySubtext, #605e5c);
310
+ font-size: 12px;
311
+ }
312
+ .thinking span {
313
+ width: 5px;
314
+ height: 5px;
315
+ border-radius: 50%;
316
+ background: var(--bodySubtext, #605e5c);
317
+ opacity: 0.5;
318
+ align-self: center;
319
+ animation: tdot 1.2s infinite ease-in-out;
320
+ }
321
+ .thinking span:nth-child(2) { animation-delay: 0.2s; }
322
+ .thinking span:nth-child(3) { animation-delay: 0.4s; }
323
+ @keyframes tdot { 0%,80%,100% { transform: scale(0.7); opacity: 0.4; } 40% { transform: scale(1); opacity: 0.9; } }
324
+
325
+ .composer {
326
+ flex: 0 0 auto;
327
+ padding: 12px 16px 16px;
328
+ border-top: 1px solid var(--bodyDivider, #edebe9);
329
+ background: var(--defaultStateBackground, #faf9f8);
330
+ }
331
+ .composer-row {
332
+ display: flex;
333
+ gap: 8px;
334
+ align-items: flex-end;
335
+ background: var(--bodyBackground, #ffffff);
336
+ border: 1px solid var(--inputBorder, #d2d0ce);
337
+ border-radius: 10px;
338
+ padding: 8px 8px 8px 12px;
339
+ }
340
+ .composer-row:focus-within { border-color: var(--themePrimary, #0078d4); }
341
+ .composer textarea {
342
+ flex: 1 1 auto;
343
+ border: none;
344
+ outline: none;
345
+ resize: none;
346
+ background: transparent;
347
+ color: var(--bodyText, #333333);
348
+ font: inherit;
349
+ font-size: 14px;
350
+ line-height: 1.4;
351
+ max-height: 160px;
352
+ min-height: 22px;
353
+ padding: 4px 0;
354
+ }
355
+ .composer-hint {
356
+ margin-top: 6px;
357
+ font-size: 11px;
358
+ color: var(--bodySubtext, #605e5c);
359
+ text-align: right;
360
+ }
361
+ </style>
362
+ </head>
363
+ <body>
364
+ <div class="viewer-panel" id="viewerPanel" style="padding: 0;">
365
+ <div class="pulse-app">
366
+ <div class="pulse-header">
367
+ <div>
368
+ <h1>[Pulse Console Title]</h1>
369
+ <div class="subtitle">[One-line description of what this console answers]</div>
370
+ </div>
371
+ <div class="pulse-actions">
372
+ <button class="flm-button" id="clearBtn" data-icon="Delete">Clear</button>
373
+ </div>
374
+ </div>
375
+
376
+ <div class="data-strip" id="dataStrip">
377
+ <span class="data-strip-label">Connected</span>
378
+ <div class="data-chips" id="dataChips">
379
+ <!-- Replace with real tables. Each chip names a synthos.shared.data table the console can query. -->
380
+ <span class="data-chip" data-table="[table_a]">[Table A] <span class="count">· 0 rows</span></span>
381
+ <span class="data-chip" data-table="[table_b]">[Table B] <span class="count">· 0 rows</span></span>
382
+ </div>
383
+ <a class="data-strip-link" id="connectLink" href="#">Connect a table</a>
384
+ </div>
385
+
386
+ <div class="transcript" id="transcript">
387
+ <div class="empty-state" id="emptyState">
388
+ <strong>Ask anything about your data</strong>
389
+ <p>Pulse reads your shared data tables and turns natural-language questions into filtered lists, drafted messages, and proposed actions.</p>
390
+ <div class="suggestion-grid" id="suggestionGrid">
391
+ <button class="suggestion-chip" data-prompt="[Suggested prompt 1 — e.g. 'Which customers haven't ordered in 60 days?']">[Suggested prompt 1]</button>
392
+ <button class="suggestion-chip" data-prompt="[Suggested prompt 2 — e.g. 'Outstanding receivables this month?']">[Suggested prompt 2]</button>
393
+ <button class="suggestion-chip" data-prompt="[Suggested prompt 3 — e.g. 'Draft a follow-up email to leads from last week.']">[Suggested prompt 3]</button>
394
+ <button class="suggestion-chip" data-prompt="[Suggested prompt 4 — e.g. 'Mark all Q3 invoices past 30 days as late.']">[Suggested prompt 4]</button>
395
+ </div>
396
+ </div>
397
+ </div>
398
+
399
+ <div class="composer">
400
+ <div class="composer-row">
401
+ <textarea id="composerInput" rows="1" placeholder="[Ask about your data — e.g. 'who hasn't ordered in 60 days?']"></textarea>
402
+ <button class="flm-button flm-button--primary" id="sendBtn" data-icon="Send">Ask</button>
403
+ </div>
404
+ <div class="composer-hint">Enter to ask · Shift+Enter for newline</div>
405
+ </div>
406
+ </div>
407
+ </div>
408
+
409
+ <div id="instructions" style="display: none;" data-locked="true">Pulse archetype — a natural-language ops console grounded in synthos.shared.data tables. Header + connected-tables strip + transcript (prompt → result card) + composer. Each turn renders a user prompt bubble (right-aligned, themePrimary fill) and a result card. The result card supports three shapes the chat agent should pick between based on the user's question: (1) list — a filtered list of rows with row-level action chips (Email/Note/Mark/etc.); (2) draft — a generated message ready to send/edit/copy; (3) batch — a proposed multi-row action with a Confirm button. The result card has a header (icon + summary line + grounding caption naming which tables were read) and a footer with primary/secondary actions. Replace the placeholder data chips with the user's actual tables, replace the four suggestion chips with prompts the user would actually ask, and wire runQuery() to a real LLM tool-use loop that reads from synthos.shared.data.list("table") and emits one of the three result shapes. Persist turns as { id, prompt, result, createdAt } via synthos.shared.data so users can scroll back through past queries. Keep the transcript flex:1 + min-height:0 + overflow-y:auto and composer flex:0 0 auto so the composer stays pinned. Auto-scroll only when isPinnedToBottom() is true so users can scroll up to read history without being yanked. Use theme tokens (avoid the natural pallet) unless the user requests an alternative color.</div>
410
+ <div id="thoughts" style="display: none;" data-locked="true"></div>
411
+
412
+ <script>
413
+ (function () {
414
+ var transcript = document.getElementById('transcript');
415
+ var emptyState = document.getElementById('emptyState');
416
+ var input = document.getElementById('composerInput');
417
+ var sendBtn = document.getElementById('sendBtn');
418
+ var clearBtn = document.getElementById('clearBtn');
419
+ var suggestionGrid = document.getElementById('suggestionGrid');
420
+
421
+ var turns = [];
422
+ var pendingThinking = false;
423
+
424
+ function escapeHtml(s) {
425
+ return String(s).replace(/[&<>"']/g, function (c) {
426
+ return ({ '&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;' })[c];
427
+ });
428
+ }
429
+
430
+ function isPinnedToBottom() {
431
+ var threshold = 80;
432
+ return transcript.scrollHeight - transcript.scrollTop - transcript.clientHeight <= threshold;
433
+ }
434
+ function scrollToBottom() {
435
+ transcript.scrollTop = transcript.scrollHeight;
436
+ }
437
+
438
+ function renderResultCard(result) {
439
+ var card = document.createElement('div');
440
+ card.className = 'result-card';
441
+
442
+ var header = document.createElement('div');
443
+ header.className = 'result-header';
444
+ header.innerHTML =
445
+ '<span class="result-icon">' + escapeHtml(result.icon || '⊙') + '</span>' +
446
+ '<div class="result-summary">' + escapeHtml(result.summary || '') +
447
+ (result.grounding ? '<span class="grounding">Read from: ' + escapeHtml(result.grounding) + '</span>' : '') +
448
+ '</div>';
449
+ card.appendChild(header);
450
+
451
+ var body = document.createElement('div');
452
+ body.className = 'result-body';
453
+
454
+ if (result.shape === 'list') {
455
+ var list = document.createElement('div');
456
+ list.className = 'result-list';
457
+ (result.rows || []).forEach(function (row) {
458
+ var rowEl = document.createElement('div');
459
+ rowEl.className = 'result-row';
460
+ var actionsHtml = (row.actions || []).map(function (a) {
461
+ return '<button class="row-action" data-action="' + escapeHtml(a) + '">' + escapeHtml(a) + '</button>';
462
+ }).join('');
463
+ rowEl.innerHTML =
464
+ '<div class="row-content">' + escapeHtml(row.title) +
465
+ (row.meta ? '<span class="row-meta">' + escapeHtml(row.meta) + '</span>' : '') +
466
+ '</div>' +
467
+ '<div class="row-actions">' + actionsHtml + '</div>';
468
+ list.appendChild(rowEl);
469
+ });
470
+ body.appendChild(list);
471
+ } else if (result.shape === 'draft') {
472
+ var draft = document.createElement('div');
473
+ draft.className = 'result-draft';
474
+ draft.innerHTML =
475
+ '<div class="draft-meta"><strong>To:</strong> ' + escapeHtml(result.to || '') +
476
+ ' <strong>Subject:</strong> ' + escapeHtml(result.subject || '') + '</div>' +
477
+ '<div class="draft-body">' + escapeHtml(result.draft || '') + '</div>';
478
+ body.appendChild(draft);
479
+ } else if (result.shape === 'batch') {
480
+ var batch = document.createElement('div');
481
+ batch.className = 'result-batch';
482
+ var itemsHtml = (result.items || []).map(function (i) {
483
+ return '<li>' + escapeHtml(i) + '</li>';
484
+ }).join('');
485
+ batch.innerHTML =
486
+ '<div>' + escapeHtml(result.action || '') + '</div>' +
487
+ '<ul class="batch-list">' + itemsHtml + '</ul>';
488
+ body.appendChild(batch);
489
+ }
490
+
491
+ card.appendChild(body);
492
+
493
+ if (result.footerActions && result.footerActions.length) {
494
+ var footer = document.createElement('div');
495
+ footer.className = 'result-footer';
496
+ footer.innerHTML = result.footerActions.map(function (a) {
497
+ var cls = a.primary ? 'footer-action primary' : 'footer-action';
498
+ return '<button class="' + cls + '" data-action="' + escapeHtml(a.label) + '">' + escapeHtml(a.label) + '</button>';
499
+ }).join('');
500
+ card.appendChild(footer);
501
+ }
502
+
503
+ return card;
504
+ }
505
+
506
+ function renderTurn(turn) {
507
+ var wrap = document.createElement('div');
508
+ wrap.className = 'turn';
509
+ wrap.setAttribute('data-id', turn.id);
510
+ if (turn.prompt) {
511
+ var bubble = document.createElement('div');
512
+ bubble.className = 'prompt-bubble';
513
+ bubble.textContent = turn.prompt;
514
+ wrap.appendChild(bubble);
515
+ }
516
+ if (turn.result) {
517
+ wrap.appendChild(renderResultCard(turn.result));
518
+ }
519
+ return wrap;
520
+ }
521
+
522
+ function renderAll() {
523
+ transcript.innerHTML = '';
524
+ if (!turns.length) {
525
+ transcript.appendChild(emptyState);
526
+ return;
527
+ }
528
+ turns.forEach(function (t) { transcript.appendChild(renderTurn(t)); });
529
+ scrollToBottom();
530
+ }
531
+
532
+ function appendTurn(turn) {
533
+ if (emptyState.parentNode === transcript) {
534
+ transcript.removeChild(emptyState);
535
+ }
536
+ var pinned = isPinnedToBottom();
537
+ turns.push(turn);
538
+ transcript.appendChild(renderTurn(turn));
539
+ if (pinned) scrollToBottom();
540
+ // synthos.shared.data.save('pulse_turns', turn);
541
+ }
542
+
543
+ function showThinking() {
544
+ if (pendingThinking) return;
545
+ pendingThinking = true;
546
+ var row = document.createElement('div');
547
+ row.id = 'thinkingRow';
548
+ row.innerHTML = '<div class="thinking">Reading your tables<span></span><span></span><span></span></div>';
549
+ transcript.appendChild(row);
550
+ scrollToBottom();
551
+ }
552
+ function hideThinking() {
553
+ pendingThinking = false;
554
+ var row = document.getElementById('thinkingRow');
555
+ if (row) row.parentNode.removeChild(row);
556
+ }
557
+
558
+ function autoSize() {
559
+ input.style.height = 'auto';
560
+ input.style.height = Math.min(input.scrollHeight, 160) + 'px';
561
+ }
562
+
563
+ function ask() {
564
+ var text = (input.value || '').trim();
565
+ if (!text) return;
566
+ var turnId = 't_' + Math.random().toString(36).slice(2, 9);
567
+ appendTurn({ id: turnId, prompt: text, result: null, createdAt: new Date().toISOString() });
568
+ input.value = '';
569
+ autoSize();
570
+ runQuery(turnId, text);
571
+ }
572
+
573
+ // Stub: pick one of three result shapes by keyword and emit a sample result.
574
+ // Replace this with a real tool-use loop that reads from synthos.shared.data.list("table"),
575
+ // reasons over the rows, and emits { shape: 'list'|'draft'|'batch', ... } per the user's question.
576
+ function runQuery(turnId, prompt) {
577
+ showThinking();
578
+ setTimeout(function () {
579
+ hideThinking();
580
+ var lower = prompt.toLowerCase();
581
+ var result;
582
+ if (/(draft|email|message|reply|reach out|follow[- ]?up)/.test(lower)) {
583
+ result = {
584
+ shape: 'draft',
585
+ icon: '✉',
586
+ summary: 'Drafted a message based on your prompt.',
587
+ grounding: '[table_a]',
588
+ to: '[recipient placeholder]',
589
+ subject: '[Subject line generated from prompt]',
590
+ draft: '[Drafted message body — replace this stub with a real synthos.generate.completion call grounded in the matching rows.]',
591
+ footerActions: [
592
+ { label: 'Copy' },
593
+ { label: 'Edit' },
594
+ { label: 'Send', primary: true }
595
+ ]
596
+ };
597
+ } else if (/(mark all|move all|update all|send to all|batch|every)/.test(lower)) {
598
+ result = {
599
+ shape: 'batch',
600
+ icon: '⚡',
601
+ summary: 'Proposed a batch action — review before confirming.',
602
+ grounding: '[table_b]',
603
+ action: '[Action description — what will happen if confirmed.]',
604
+ items: [
605
+ '[Item 1 that will be affected]',
606
+ '[Item 2 that will be affected]',
607
+ '[Item 3 that will be affected]'
608
+ ],
609
+ footerActions: [
610
+ { label: 'Cancel' },
611
+ { label: 'Confirm', primary: true }
612
+ ]
613
+ };
614
+ } else {
615
+ result = {
616
+ shape: 'list',
617
+ icon: '⊙',
618
+ summary: 'Found [N] rows matching your question.',
619
+ grounding: '[table_a]',
620
+ rows: [
621
+ { title: '[Row 1 primary text]', meta: '[Row 1 meta — date / status / value]', actions: ['Email', 'Note', 'Mark'] },
622
+ { title: '[Row 2 primary text]', meta: '[Row 2 meta — date / status / value]', actions: ['Email', 'Note', 'Mark'] },
623
+ { title: '[Row 3 primary text]', meta: '[Row 3 meta — date / status / value]', actions: ['Email', 'Note', 'Mark'] }
624
+ ],
625
+ footerActions: [
626
+ { label: 'Refine' },
627
+ { label: 'Export' }
628
+ ]
629
+ };
630
+ }
631
+ var turn = turns.filter(function (t) { return t.id === turnId; })[0];
632
+ if (turn) {
633
+ turn.result = result;
634
+ // Re-render just this turn's card by appending under the existing prompt bubble
635
+ var wrap = transcript.querySelector('[data-id="' + turnId + '"]');
636
+ if (wrap) wrap.appendChild(renderResultCard(result));
637
+ if (isPinnedToBottom()) scrollToBottom();
638
+ // synthos.shared.data.save('pulse_turns', turn);
639
+ }
640
+ }, 700);
641
+
642
+ // Real wiring (uncomment + adapt):
643
+ // Promise.all([
644
+ // synthos.shared.data.list('[table_a]'),
645
+ // synthos.shared.data.list('[table_b]')
646
+ // ]).then(function (tables) {
647
+ // return synthos.generate.completion({
648
+ // system: 'You are an ops console. Answer the user\'s question grounded in the supplied tables. ' +
649
+ // 'Respond as JSON: { shape: "list"|"draft"|"batch", ... }',
650
+ // messages: [{ role: 'user', content: prompt }],
651
+ // context: { tables: tables }
652
+ // });
653
+ // }).then(function (raw) {
654
+ // var result = JSON.parse(raw);
655
+ // /* attach result to turn + render */
656
+ // });
657
+ }
658
+
659
+ // Suggestion chips populate the composer (single-click; no auto-send so the user can edit).
660
+ suggestionGrid.addEventListener('click', function (e) {
661
+ var chip = e.target.closest('.suggestion-chip');
662
+ if (!chip) return;
663
+ input.value = chip.getAttribute('data-prompt') || chip.textContent;
664
+ autoSize();
665
+ input.focus();
666
+ });
667
+
668
+ input.addEventListener('input', autoSize);
669
+ input.addEventListener('keydown', function (e) {
670
+ if (e.key === 'Enter' && !e.shiftKey) {
671
+ e.preventDefault();
672
+ ask();
673
+ }
674
+ });
675
+ sendBtn.addEventListener('click', ask);
676
+
677
+ clearBtn.addEventListener('click', function () {
678
+ if (!turns.length) return;
679
+ if (!confirm('Clear all queries?')) return;
680
+ // Remove persisted turns: turns.forEach(function (t) { synthos.shared.data.remove('pulse_turns', t.id); });
681
+ turns = [];
682
+ renderAll();
683
+ });
684
+
685
+ // Load persisted turns (uncomment to enable):
686
+ // synthos.shared.data.list('pulse_turns').then(function (rows) {
687
+ // if (rows && rows.length) {
688
+ // turns = rows.slice().sort(function (a, b) {
689
+ // return (a.createdAt || '').localeCompare(b.createdAt || '');
690
+ // });
691
+ // renderAll();
692
+ // }
693
+ // });
694
+
695
+ renderAll();
696
+ })();
697
+ </script>
698
+ </body></html>