synthos 0.7.2 → 0.8.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 (262) hide show
  1. package/README.md +215 -65
  2. package/default-pages/application.json +1 -0
  3. package/default-pages/json_tools.json +1 -1
  4. package/default-pages/oregon_trail.html +321 -0
  5. package/default-pages/oregon_trail.json +12 -0
  6. package/default-pages/sidebar_page.json +1 -0
  7. package/default-pages/solar_explorer.html +10 -18
  8. package/default-pages/solar_explorer.json +2 -2
  9. package/default-pages/two-panel_page.json +1 -0
  10. package/default-pages/us_map.html +192 -0
  11. package/default-pages/us_map.json +12 -0
  12. package/default-pages/us_map_1850.html +325 -0
  13. package/default-pages/us_map_1850.json +12 -0
  14. package/default-pages/western_cities_1850.html +526 -0
  15. package/default-pages/western_cities_1850.json +12 -0
  16. package/default-themes/{nebula-dawn.css → nebula-dawn.v2.css} +24 -0
  17. package/default-themes/{nebula-dusk.css → nebula-dusk.v2.css} +24 -0
  18. package/dist/agents/a2a/a2aProvider.d.ts +3 -0
  19. package/dist/agents/a2a/a2aProvider.d.ts.map +1 -0
  20. package/dist/agents/a2a/a2aProvider.js +126 -0
  21. package/dist/agents/a2a/a2aProvider.js.map +1 -0
  22. package/dist/agents/discovery.d.ts +30 -0
  23. package/dist/agents/discovery.d.ts.map +1 -0
  24. package/dist/agents/discovery.js +52 -0
  25. package/dist/agents/discovery.js.map +1 -0
  26. package/dist/agents/index.d.ts +7 -0
  27. package/dist/agents/index.d.ts.map +1 -0
  28. package/dist/agents/index.js +19 -0
  29. package/dist/agents/index.js.map +1 -0
  30. package/dist/agents/openclaw/gatewayManager.d.ts +113 -0
  31. package/dist/agents/openclaw/gatewayManager.d.ts.map +1 -0
  32. package/dist/agents/openclaw/gatewayManager.js +470 -0
  33. package/dist/agents/openclaw/gatewayManager.js.map +1 -0
  34. package/dist/agents/openclaw/openclawProvider.d.ts +3 -0
  35. package/dist/agents/openclaw/openclawProvider.d.ts.map +1 -0
  36. package/dist/agents/openclaw/openclawProvider.js +239 -0
  37. package/dist/agents/openclaw/openclawProvider.js.map +1 -0
  38. package/dist/agents/openclaw/sshTunnelManager.d.ts +23 -0
  39. package/dist/agents/openclaw/sshTunnelManager.d.ts.map +1 -0
  40. package/dist/agents/openclaw/sshTunnelManager.js +340 -0
  41. package/dist/agents/openclaw/sshTunnelManager.js.map +1 -0
  42. package/dist/agents/types.d.ts +64 -0
  43. package/dist/agents/types.d.ts.map +1 -0
  44. package/dist/agents/types.js +6 -0
  45. package/dist/agents/types.js.map +1 -0
  46. package/dist/connectors/airtable/connector.json +27 -0
  47. package/dist/connectors/alpha-vantage/connector.json +26 -0
  48. package/dist/connectors/brave-search/connector.json +26 -0
  49. package/dist/connectors/cloudinary/connector.json +27 -0
  50. package/dist/connectors/deepl/connector.json +28 -0
  51. package/dist/connectors/elevenlabs/connector.json +30 -0
  52. package/dist/connectors/giphy/connector.json +27 -0
  53. package/dist/connectors/github/connector.json +29 -0
  54. package/dist/connectors/huggingface/connector.json +27 -0
  55. package/dist/connectors/imgur/connector.json +29 -0
  56. package/dist/connectors/index.d.ts +1 -1
  57. package/dist/connectors/index.d.ts.map +1 -1
  58. package/dist/connectors/instagram/connector.json +43 -0
  59. package/dist/connectors/jira/connector.json +28 -0
  60. package/dist/connectors/mapbox/connector.json +26 -0
  61. package/dist/connectors/nasa/connector.json +27 -0
  62. package/dist/connectors/newsapi/connector.json +27 -0
  63. package/dist/connectors/notion/connector.json +28 -0
  64. package/dist/connectors/open-exchange-rates/connector.json +27 -0
  65. package/dist/connectors/openweathermap/connector.json +26 -0
  66. package/dist/connectors/pexels/connector.json +27 -0
  67. package/dist/connectors/registry.d.ts.map +1 -1
  68. package/dist/connectors/registry.js +42 -96
  69. package/dist/connectors/registry.js.map +1 -1
  70. package/dist/connectors/resend/connector.json +29 -0
  71. package/dist/connectors/rss2json/connector.json +27 -0
  72. package/dist/connectors/sendgrid/connector.json +27 -0
  73. package/dist/connectors/spoonacular/connector.json +28 -0
  74. package/dist/connectors/stability-ai/connector.json +27 -0
  75. package/dist/connectors/twilio/connector.json +28 -0
  76. package/dist/connectors/types.d.ts +23 -0
  77. package/dist/connectors/types.d.ts.map +1 -1
  78. package/dist/connectors/unsplash/connector.json +27 -0
  79. package/dist/connectors/wolfram-alpha/connector.json +26 -0
  80. package/dist/connectors/youtube-data/connector.json +30 -0
  81. package/dist/files.d.ts +1 -0
  82. package/dist/files.d.ts.map +1 -1
  83. package/dist/files.js +16 -1
  84. package/dist/files.js.map +1 -1
  85. package/dist/init.d.ts.map +1 -1
  86. package/dist/init.js +28 -0
  87. package/dist/init.js.map +1 -1
  88. package/dist/migrations.d.ts +3 -2
  89. package/dist/migrations.d.ts.map +1 -1
  90. package/dist/migrations.js +122 -138
  91. package/dist/migrations.js.map +1 -1
  92. package/dist/models/anthropic.d.ts +22 -0
  93. package/dist/models/anthropic.d.ts.map +1 -0
  94. package/dist/models/anthropic.js +76 -0
  95. package/dist/models/anthropic.js.map +1 -0
  96. package/dist/models/chainOfThought.d.ts +12 -0
  97. package/dist/models/chainOfThought.d.ts.map +1 -0
  98. package/dist/models/chainOfThought.js +45 -0
  99. package/dist/models/chainOfThought.js.map +1 -0
  100. package/dist/models/fireworksai.d.ts +30 -0
  101. package/dist/models/fireworksai.d.ts.map +1 -0
  102. package/dist/models/fireworksai.js +133 -0
  103. package/dist/models/fireworksai.js.map +1 -0
  104. package/dist/models/index.d.ts +7 -1
  105. package/dist/models/index.d.ts.map +1 -1
  106. package/dist/models/index.js +19 -1
  107. package/dist/models/index.js.map +1 -1
  108. package/dist/models/logCompletePrompt.d.ts +3 -0
  109. package/dist/models/logCompletePrompt.d.ts.map +1 -0
  110. package/dist/models/logCompletePrompt.js +23 -0
  111. package/dist/models/logCompletePrompt.js.map +1 -0
  112. package/dist/models/openai.d.ts +24 -0
  113. package/dist/models/openai.d.ts.map +1 -0
  114. package/dist/models/openai.js +80 -0
  115. package/dist/models/openai.js.map +1 -0
  116. package/dist/models/providers.d.ts +1 -0
  117. package/dist/models/providers.d.ts.map +1 -1
  118. package/dist/models/providers.js +12 -4
  119. package/dist/models/providers.js.map +1 -1
  120. package/dist/models/types.d.ts +34 -2
  121. package/dist/models/types.d.ts.map +1 -1
  122. package/dist/models/types.js +16 -0
  123. package/dist/models/types.js.map +1 -1
  124. package/dist/models/utils.d.ts +6 -0
  125. package/dist/models/utils.d.ts.map +1 -0
  126. package/dist/models/utils.js +21 -0
  127. package/dist/models/utils.js.map +1 -0
  128. package/dist/scripts.d.ts +2 -1
  129. package/dist/scripts.d.ts.map +1 -1
  130. package/dist/scripts.js +4 -3
  131. package/dist/scripts.js.map +1 -1
  132. package/dist/service/createCompletePrompt.d.ts +1 -1
  133. package/dist/service/createCompletePrompt.d.ts.map +1 -1
  134. package/dist/service/createCompletePrompt.js +9 -6
  135. package/dist/service/createCompletePrompt.js.map +1 -1
  136. package/dist/service/generateImage.d.ts +1 -1
  137. package/dist/service/generateImage.d.ts.map +1 -1
  138. package/dist/service/generateImage.js +3 -3
  139. package/dist/service/generateImage.js.map +1 -1
  140. package/dist/service/server.d.ts.map +1 -1
  141. package/dist/service/server.js +3 -0
  142. package/dist/service/server.js.map +1 -1
  143. package/dist/service/transformPage.d.ts +4 -2
  144. package/dist/service/transformPage.d.ts.map +1 -1
  145. package/dist/service/transformPage.js +74 -6
  146. package/dist/service/transformPage.js.map +1 -1
  147. package/dist/service/useAgentRoutes.d.ts +4 -0
  148. package/dist/service/useAgentRoutes.d.ts.map +1 -0
  149. package/dist/service/useAgentRoutes.js +389 -0
  150. package/dist/service/useAgentRoutes.js.map +1 -0
  151. package/dist/service/useApiRoutes.d.ts.map +1 -1
  152. package/dist/service/useApiRoutes.js +157 -16
  153. package/dist/service/useApiRoutes.js.map +1 -1
  154. package/dist/service/useConnectorRoutes.d.ts.map +1 -1
  155. package/dist/service/useConnectorRoutes.js +14 -3
  156. package/dist/service/useConnectorRoutes.js.map +1 -1
  157. package/dist/service/useGatewayRoutes.d.ts +4 -0
  158. package/dist/service/useGatewayRoutes.d.ts.map +1 -0
  159. package/dist/service/useGatewayRoutes.js +168 -0
  160. package/dist/service/useGatewayRoutes.js.map +1 -0
  161. package/dist/service/usePageRoutes.d.ts.map +1 -1
  162. package/dist/service/usePageRoutes.js +16 -5
  163. package/dist/service/usePageRoutes.js.map +1 -1
  164. package/dist/settings.d.ts +2 -1
  165. package/dist/settings.d.ts.map +1 -1
  166. package/dist/settings.js +4 -8
  167. package/dist/settings.js.map +1 -1
  168. package/dist/themes.d.ts +14 -0
  169. package/dist/themes.d.ts.map +1 -1
  170. package/dist/themes.js +86 -13
  171. package/dist/themes.js.map +1 -1
  172. package/package.json +8 -5
  173. package/page-scripts/helpers-v2.js +101 -0
  174. package/page-scripts/page-v2.js +47 -6
  175. package/required-pages/builder.html +1 -27
  176. package/required-pages/pages.html +745 -22
  177. package/required-pages/settings.html +819 -21
  178. package/required-pages/synthos_apis.html +56 -1
  179. package/src/agents/a2a/a2aProvider.ts +110 -0
  180. package/src/agents/discovery.ts +74 -0
  181. package/src/agents/index.ts +6 -0
  182. package/src/agents/openclaw/gatewayManager.ts +559 -0
  183. package/src/agents/openclaw/openclawProvider.ts +261 -0
  184. package/src/agents/openclaw/sshTunnelManager.ts +385 -0
  185. package/src/agents/types.ts +82 -0
  186. package/src/connectors/airtable/connector.json +27 -0
  187. package/src/connectors/alpha-vantage/connector.json +26 -0
  188. package/src/connectors/brave-search/connector.json +26 -0
  189. package/src/connectors/cloudinary/connector.json +27 -0
  190. package/src/connectors/deepl/connector.json +28 -0
  191. package/src/connectors/elevenlabs/connector.json +30 -0
  192. package/src/connectors/giphy/connector.json +27 -0
  193. package/src/connectors/github/connector.json +29 -0
  194. package/src/connectors/huggingface/connector.json +27 -0
  195. package/src/connectors/imgur/connector.json +29 -0
  196. package/src/connectors/index.ts +2 -0
  197. package/src/connectors/instagram/connector.json +43 -0
  198. package/src/connectors/jira/connector.json +28 -0
  199. package/src/connectors/mapbox/connector.json +26 -0
  200. package/src/connectors/nasa/connector.json +27 -0
  201. package/src/connectors/newsapi/connector.json +27 -0
  202. package/src/connectors/notion/connector.json +28 -0
  203. package/src/connectors/open-exchange-rates/connector.json +27 -0
  204. package/src/connectors/openweathermap/connector.json +26 -0
  205. package/src/connectors/pexels/connector.json +27 -0
  206. package/src/connectors/registry.ts +21 -97
  207. package/src/connectors/resend/connector.json +29 -0
  208. package/src/connectors/rss2json/connector.json +27 -0
  209. package/src/connectors/sendgrid/connector.json +27 -0
  210. package/src/connectors/spoonacular/connector.json +28 -0
  211. package/src/connectors/stability-ai/connector.json +27 -0
  212. package/src/connectors/twilio/connector.json +28 -0
  213. package/src/connectors/types.ts +25 -0
  214. package/src/connectors/unsplash/connector.json +27 -0
  215. package/src/connectors/wolfram-alpha/connector.json +26 -0
  216. package/src/connectors/youtube-data/connector.json +30 -0
  217. package/src/files.ts +14 -0
  218. package/src/init.ts +27 -0
  219. package/src/migrations.ts +121 -138
  220. package/src/models/anthropic.ts +89 -0
  221. package/src/models/chainOfThought.ts +56 -0
  222. package/src/models/fireworksai.ts +136 -0
  223. package/src/models/index.ts +7 -1
  224. package/src/models/logCompletePrompt.ts +25 -0
  225. package/src/models/openai.ts +90 -0
  226. package/src/models/providers.ts +12 -3
  227. package/src/models/types.ts +67 -2
  228. package/src/models/utils.ts +16 -0
  229. package/src/scripts.ts +2 -2
  230. package/src/service/createCompletePrompt.ts +3 -1
  231. package/src/service/generateImage.ts +2 -2
  232. package/src/service/server.ts +4 -0
  233. package/src/service/transformPage.ts +81 -8
  234. package/src/service/useAgentRoutes.ts +423 -0
  235. package/src/service/useApiRoutes.ts +173 -18
  236. package/src/service/useConnectorRoutes.ts +14 -3
  237. package/src/service/usePageRoutes.ts +20 -6
  238. package/src/settings.ts +6 -10
  239. package/src/themes.ts +84 -12
  240. package/tests/anthropic.spec.ts +84 -0
  241. package/tests/chainOfThought.spec.ts +108 -0
  242. package/tests/ensureScripts.spec.ts +82 -0
  243. package/tests/files.spec.ts +233 -0
  244. package/tests/fireworksai.spec.ts +92 -0
  245. package/tests/logCompletePrompt.spec.ts +74 -0
  246. package/tests/migrations.spec.ts +79 -1
  247. package/tests/openai.spec.ts +71 -0
  248. package/tests/pages.spec.ts +226 -1
  249. package/tests/providers.spec.ts +144 -0
  250. package/tests/scripts.spec.ts +209 -0
  251. package/tests/transformPage.spec.ts +517 -0
  252. package/tests/types.spec.ts +23 -0
  253. package/default-pages/app_builder.json +0 -1
  254. package/default-pages/sidebar_builder.json +0 -1
  255. package/default-pages/two-panel_builder.json +0 -1
  256. package/images/home.png +0 -0
  257. package/images/page-management.png +0 -0
  258. package/images/settings.png +0 -0
  259. package/images/synthos-square.png +0 -0
  260. /package/default-pages/{app_builder.html → application.html} +0 -0
  261. /package/default-pages/{sidebar_builder.html → sidebar_page.html} +0 -0
  262. /package/default-pages/{two-panel_builder.html → two-panel_page.html} +0 -0
@@ -0,0 +1,27 @@
1
+ {
2
+ "id": "pexels",
3
+ "name": "Pexels",
4
+ "category": "Image",
5
+ "description": "Free stock photos and videos. Search a curated library of high-quality, royalty-free images and video clips.",
6
+ "baseUrl": "https://api.pexels.com",
7
+ "authStrategy": "header",
8
+ "authKey": "Authorization",
9
+ "fields": [
10
+ { "name": "apiKey", "label": "API Key", "type": "password" }
11
+ ],
12
+ "hints": [
13
+ "Search photos: GET https://api.pexels.com/v1/search?query={term}&per_page=10 — params: query (required), orientation (landscape|portrait|square), size (large|medium|small), color (red|orange|yellow|green|turquoise|blue|violet|pink|brown|black|gray|white|#hex), page (default:1), per_page (default:15, max:80)",
14
+ "Get a Photo by ID: GET https://api.pexels.com/v1/photos/{id} — params: id (required)",
15
+ "Response (search&get): { photos: [{ id, width, height, src: { original, large, medium, small, tiny }, alt, photographer }] }",
16
+ "Whenever you are doing an API request make sure to show a prominent link to Pexels. You can use a text link (e.g. 'Photos provided by Pexels').",
17
+ "Rate limit: 200 requests/hour, 20,000 requests/month."
18
+ ],
19
+ "onboarding": {
20
+ "url": "https://www.pexels.com/api",
21
+ "steps": [
22
+ "Create an account at pexels.com",
23
+ "Go to pexels.com/api to request API access",
24
+ "Copy your API key from the dashboard"
25
+ ]
26
+ }
27
+ }
@@ -1,98 +1,22 @@
1
- import { ConnectorDefinition } from './types';
1
+ import * as fs from 'fs';
2
+ import * as path from 'path';
3
+ import { ConnectorDefinition, ConnectorJson } from './types';
2
4
 
3
- export const CONNECTOR_REGISTRY: ConnectorDefinition[] = [
4
- {
5
- id: 'brave-search',
6
- name: 'Brave Search',
7
- category: 'Search',
8
- description: 'Web search powered by the Brave Search API. Provides real-time search results from the web.',
9
- baseUrl: 'https://api.search.brave.com',
10
- authStrategy: 'header',
11
- authKey: 'X-Subscription-Token',
12
- fields: [
13
- { name: 'apiKey', label: 'API Key', type: 'password' }
14
- ],
15
- hints: [
16
- 'Endpoint: GET /res/v1/web/search',
17
- 'Query params: q (required), count (1-20, default 10), country, freshness',
18
- 'Response: { web: { results: [{ title, url, description }] } }',
19
- 'Note: synthos.search.web() is a convenience wrapper prefer it over raw connector calls for basic web search.'
20
- ].join('\n')
21
- },
22
- {
23
- id: 'elevenlabs',
24
- name: 'ElevenLabs',
25
- category: 'Audio',
26
- description: 'AI-powered text-to-speech and voice synthesis. Generate natural-sounding audio from text.',
27
- baseUrl: 'https://api.elevenlabs.io',
28
- authStrategy: 'header',
29
- authKey: 'xi-api-key',
30
- fields: [
31
- { name: 'apiKey', label: 'API Key', type: 'password' }
32
- ],
33
- hints: [
34
- 'List voices: GET /v1/voices → { voices: [{ voice_id, name, category }] }',
35
- 'Text-to-speech: POST /v1/text-to-speech/{voice_id}?output_format=mp3_44100_128',
36
- ' Request headers: Accept: audio/mpeg, Content-Type: application/json',
37
- ' Request body: { text: string, model_id: "eleven_multilingual_v2" }',
38
- ' Response: raw audio/mpeg binary — use resp.arrayBuffer() then new Blob([buf], {type:"audio/mpeg"}) and URL.createObjectURL() to play',
39
- ' IMPORTANT: The proxy returns raw binary, NOT JSON. Call fetch("/api/connectors", ...) directly instead of synthos.connectors.call() for TTS, since the helper parses JSON.',
40
- 'Default voice: "Rachel" (voice_id: 21m00Tcm4TlvDq8ikWAM) is a good general-purpose voice.',
41
- 'Max text length: 5000 characters per request.'
42
- ].join('\n')
43
- },
44
- {
45
- id: 'stability-ai',
46
- name: 'Stability AI',
47
- category: 'Image',
48
- description: 'AI image generation powered by Stable Diffusion. Create images from text prompts.',
49
- baseUrl: 'https://api.stability.ai',
50
- authStrategy: 'bearer',
51
- authKey: 'Authorization',
52
- fields: [
53
- { name: 'apiKey', label: 'API Key', type: 'password' }
54
- ],
55
- hints: [
56
- 'Text-to-image: POST /v1/generation/stable-diffusion-xl-1024-v1-0/text-to-image',
57
- ' Request headers: Content-Type: application/json, Accept: application/json',
58
- ' Request body: { text_prompts: [{ text: string, weight: 1 }], cfg_scale: 7, steps: 30, width: 1024, height: 1024 }',
59
- ' Response: { artifacts: [{ base64: string, finishReason: string }] }',
60
- ' Display with: <img src="data:image/png;base64,{base64}">'
61
- ].join('\n')
62
- },
63
- {
64
- id: 'instagram',
65
- name: 'Instagram',
66
- category: 'Social',
67
- description: 'Post photos and videos to Instagram via the Instagram Graph API.',
68
- baseUrl: 'https://graph.facebook.com/v21.0',
69
- authStrategy: 'oauth2',
70
- authKey: 'access_token',
71
- authorizationUrl: 'https://www.facebook.com/v21.0/dialog/oauth',
72
- tokenUrl: 'https://graph.facebook.com/v21.0/oauth/access_token',
73
- scopes: [
74
- 'instagram_basic',
75
- 'instagram_content_publish',
76
- 'pages_show_list',
77
- 'pages_read_engagement'
78
- ],
79
- fields: [
80
- { name: 'clientId', label: 'App ID', type: 'text' },
81
- { name: 'clientSecret', label: 'App Secret', type: 'password' }
82
- ],
83
- hints: [
84
- 'Publishing flow (two-step):',
85
- ' 1. Create media container: POST /{ig-user-id}/media',
86
- ' Body (photo): { image_url, caption }',
87
- ' Body (reel/video): { video_url, caption, media_type: "REELS" }',
88
- ' Response: { id: "<container-id>" }',
89
- ' 2. Publish container: POST /{ig-user-id}/media_publish',
90
- ' Body: { creation_id: "<container-id>" }',
91
- ' Response: { id: "<media-id>" }',
92
- 'IMPORTANT: Do NOT include access_token in body or query params — the proxy attaches it automatically.',
93
- 'IMPORTANT: Images must be publicly accessible URLs. Use a hosting service or the data API to serve local images.',
94
- 'Rate limit: 25 posts per 24-hour period.',
95
- 'Requires a Business or Creator Instagram account linked to a Facebook Page.'
96
- ].join('\n')
97
- }
98
- ];
5
+ const connectorsDir = __dirname;
6
+
7
+ function loadConnectorJson(dir: string): ConnectorDefinition | null {
8
+ const file = path.join(dir, 'connector.json');
9
+ if (!fs.existsSync(file)) return null;
10
+ const raw: ConnectorJson = JSON.parse(fs.readFileSync(file, 'utf-8'));
11
+ return {
12
+ ...raw,
13
+ hints: raw.hints ? raw.hints.join('\n') : undefined
14
+ };
15
+ }
16
+
17
+ export const CONNECTOR_REGISTRY: ConnectorDefinition[] = fs
18
+ .readdirSync(connectorsDir, { withFileTypes: true })
19
+ .filter(d => d.isDirectory())
20
+ .map(d => loadConnectorJson(path.join(connectorsDir, d.name)))
21
+ .filter((d): d is ConnectorDefinition => d !== null)
22
+ .sort((a, b) => a.name.localeCompare(b.name));
@@ -0,0 +1,29 @@
1
+ {
2
+ "id": "resend",
3
+ "name": "Resend",
4
+ "category": "Communication",
5
+ "description": "Modern email delivery API. Send transactional emails with a clean, developer-friendly interface.",
6
+ "baseUrl": "https://api.resend.com",
7
+ "authStrategy": "bearer",
8
+ "authKey": "Authorization",
9
+ "fields": [
10
+ { "name": "apiKey", "label": "API Key", "type": "password" }
11
+ ],
12
+ "hints": [
13
+ "Send email: POST /emails",
14
+ " Body: { from: \"you@yourdomain.com\", to: [\"recipient@example.com\"], subject: \"...\", html: \"<p>Hello</p>\" }",
15
+ " Response: { id: \"email-id\" }",
16
+ "Get email: GET /emails/{id}",
17
+ " Response: { id, from, to, subject, created_at, last_event }",
18
+ "IMPORTANT: 'from' must use a verified domain. Use 'onboarding@resend.dev' for testing.",
19
+ "Free tier: 100 emails/day, 3,000 emails/month."
20
+ ],
21
+ "onboarding": {
22
+ "url": "https://resend.com/signup",
23
+ "steps": [
24
+ "Create an account at resend.com",
25
+ "Go to API Keys in the dashboard",
26
+ "Create a new API key and copy it"
27
+ ]
28
+ }
29
+ }
@@ -0,0 +1,27 @@
1
+ {
2
+ "id": "rss2json",
3
+ "name": "RSS/Atom Feed",
4
+ "category": "News",
5
+ "description": "Convert any RSS or Atom feed into JSON. Fetch and parse blog posts, podcasts, and news feeds from any source.",
6
+ "baseUrl": "https://api.rss2json.com",
7
+ "authStrategy": "query",
8
+ "authKey": "api_key",
9
+ "fields": [
10
+ { "name": "apiKey", "label": "API Key", "type": "password" }
11
+ ],
12
+ "hints": [
13
+ "Parse feed: GET /v1/api.json?rss_url={encoded_feed_url}",
14
+ "Response: { status: \"ok\", feed: { title, link, description }, items: [{ title, link, pubDate, description, content, thumbnail }] }",
15
+ "The rss_url param must be URL-encoded.",
16
+ "Free tier: 10,000 requests/day, up to 10 items per feed.",
17
+ "Paid plans return more items and support count, order_by, order_dir params."
18
+ ],
19
+ "onboarding": {
20
+ "url": "https://rss2json.com/",
21
+ "steps": [
22
+ "Create a free account at rss2json.com",
23
+ "Your API key is shown on the dashboard after sign-up",
24
+ "Copy the API key"
25
+ ]
26
+ }
27
+ }
@@ -0,0 +1,27 @@
1
+ {
2
+ "id": "sendgrid",
3
+ "name": "SendGrid",
4
+ "category": "Communication",
5
+ "description": "Email delivery service. Send transactional and marketing emails at scale via API.",
6
+ "baseUrl": "https://api.sendgrid.com",
7
+ "authStrategy": "bearer",
8
+ "authKey": "Authorization",
9
+ "fields": [
10
+ { "name": "apiKey", "label": "API Key", "type": "password" }
11
+ ],
12
+ "hints": [
13
+ "Send email: POST /v3/mail/send",
14
+ " Body: { personalizations: [{ to: [{ email }] }], from: { email }, subject: \"...\", content: [{ type: \"text/plain\", value: \"...\" }] }",
15
+ " Returns 202 Accepted (no body) on success.",
16
+ "List templates: GET /v3/templates?generations=dynamic",
17
+ "Free tier: 100 emails/day."
18
+ ],
19
+ "onboarding": {
20
+ "url": "https://signup.sendgrid.com/",
21
+ "steps": [
22
+ "Create an account at sendgrid.com",
23
+ "Go to Settings > API Keys",
24
+ "Create a new API key with appropriate permissions and copy it"
25
+ ]
26
+ }
27
+ }
@@ -0,0 +1,28 @@
1
+ {
2
+ "id": "spoonacular",
3
+ "name": "Spoonacular",
4
+ "category": "Food",
5
+ "description": "Food and recipe API. Search recipes, get nutritional data, meal planning, and ingredient information.",
6
+ "baseUrl": "https://api.spoonacular.com",
7
+ "authStrategy": "header",
8
+ "authKey": "x-api-key",
9
+ "fields": [
10
+ { "name": "apiKey", "label": "API Key", "type": "password" }
11
+ ],
12
+ "hints": [
13
+ "Search recipes: GET /recipes/complexSearch?query={term}&number=10",
14
+ "Get recipe: GET /recipes/{id}/information",
15
+ "Random recipes: GET /recipes/random?number=5",
16
+ "Nutritional info: GET /recipes/{id}/nutritionWidget.json",
17
+ "Response (search): { results: [{ id, title, image }], totalResults }",
18
+ "Free tier: 150 requests/day."
19
+ ],
20
+ "onboarding": {
21
+ "url": "https://spoonacular.com/food-api/console#Dashboard",
22
+ "steps": [
23
+ "Create an account at spoonacular.com/food-api",
24
+ "Go to your Dashboard / Profile",
25
+ "Copy your API key"
26
+ ]
27
+ }
28
+ }
@@ -0,0 +1,27 @@
1
+ {
2
+ "id": "stability-ai",
3
+ "name": "Stability AI",
4
+ "category": "Image",
5
+ "description": "AI image generation powered by Stable Diffusion. Create images from text prompts.",
6
+ "baseUrl": "https://api.stability.ai",
7
+ "authStrategy": "bearer",
8
+ "authKey": "Authorization",
9
+ "fields": [
10
+ { "name": "apiKey", "label": "API Key", "type": "password" }
11
+ ],
12
+ "hints": [
13
+ "Text-to-image: POST /v1/generation/stable-diffusion-xl-1024-v1-0/text-to-image",
14
+ " Request headers: Content-Type: application/json, Accept: application/json",
15
+ " Request body: { text_prompts: [{ text: string, weight: 1 }], cfg_scale: 7, steps: 30, width: 1024, height: 1024 }",
16
+ " Response: { artifacts: [{ base64: string, finishReason: string }] }",
17
+ " Display with: <img src=\"data:image/png;base64,{base64}\">"
18
+ ],
19
+ "onboarding": {
20
+ "url": "https://platform.stability.ai/",
21
+ "steps": [
22
+ "Create an account at platform.stability.ai",
23
+ "Go to Account > API Keys",
24
+ "Create and copy your API key"
25
+ ]
26
+ }
27
+ }
@@ -0,0 +1,28 @@
1
+ {
2
+ "id": "twilio",
3
+ "name": "Twilio",
4
+ "category": "Communication",
5
+ "description": "SMS, voice, and messaging APIs. Send text messages, make calls, and build communication workflows.",
6
+ "baseUrl": "https://api.twilio.com",
7
+ "authStrategy": "header",
8
+ "authKey": "Authorization",
9
+ "fields": [
10
+ { "name": "apiKey", "label": "Auth Token (Base64 SID:Token)", "type": "password" }
11
+ ],
12
+ "hints": [
13
+ "Send SMS: POST /2010-04-01/Accounts/{AccountSid}/Messages.json",
14
+ " Body (form-encoded): To=+1234567890&From=+0987654321&Body=Hello",
15
+ " IMPORTANT: Twilio uses Basic auth. Save your key as 'Basic base64(AccountSID:AuthToken)'.",
16
+ " Content-Type must be application/x-www-form-urlencoded for SMS.",
17
+ "List messages: GET /2010-04-01/Accounts/{AccountSid}/Messages.json",
18
+ "Free trial: requires verified phone numbers."
19
+ ],
20
+ "onboarding": {
21
+ "url": "https://www.twilio.com/try-twilio",
22
+ "steps": [
23
+ "Create a Twilio account at twilio.com/try-twilio",
24
+ "Find your Account SID and Auth Token on the Console dashboard",
25
+ "Base64-encode 'AccountSID:AuthToken' and paste as your key"
26
+ ]
27
+ }
28
+ }
@@ -6,6 +6,11 @@ export interface ConnectorField {
6
6
  type: 'password' | 'text';
7
7
  }
8
8
 
9
+ export interface ConnectorOnboarding {
10
+ url: string;
11
+ steps: string[];
12
+ }
13
+
9
14
  export interface ConnectorDefinition {
10
15
  id: string;
11
16
  name: string;
@@ -17,6 +22,8 @@ export interface ConnectorDefinition {
17
22
  fields: ConnectorField[];
18
23
  /** Usage hints shown to the LLM — recommended endpoints, default settings, gotchas. */
19
24
  hints?: string;
25
+ /** Onboarding instructions — signup URL and steps to get an API key. */
26
+ onboarding?: ConnectorOnboarding;
20
27
  /** OAuth2: Authorization endpoint URL. */
21
28
  authorizationUrl?: string;
22
29
  /** OAuth2: Token exchange endpoint URL. */
@@ -25,6 +32,22 @@ export interface ConnectorDefinition {
25
32
  scopes?: string[];
26
33
  }
27
34
 
35
+ export interface ConnectorJson {
36
+ id: string;
37
+ name: string;
38
+ category: string;
39
+ description: string;
40
+ baseUrl: string;
41
+ authStrategy: AuthStrategy;
42
+ authKey: string;
43
+ fields: ConnectorField[];
44
+ hints?: string[];
45
+ onboarding?: ConnectorOnboarding;
46
+ authorizationUrl?: string;
47
+ tokenUrl?: string;
48
+ scopes?: string[];
49
+ }
50
+
28
51
  export interface ConnectorConfig {
29
52
  apiKey: string;
30
53
  enabled: boolean;
@@ -46,7 +69,9 @@ export interface ConnectorSummary {
46
69
  id: string;
47
70
  name: string;
48
71
  category: string;
72
+ description: string;
49
73
  configured: boolean;
74
+ enabled: boolean;
50
75
  }
51
76
 
52
77
  export interface ConnectorDetail extends ConnectorDefinition {
@@ -0,0 +1,27 @@
1
+ {
2
+ "id": "unsplash",
3
+ "name": "Unsplash",
4
+ "category": "Image",
5
+ "description": "Access a vast library of free high-resolution photos. Search, browse, and download professional photography.",
6
+ "baseUrl": "https://api.unsplash.com",
7
+ "authStrategy": "header",
8
+ "authKey": "Authorization",
9
+ "fields": [
10
+ { "name": "apiKey", "label": "Access Key", "type": "password" }
11
+ ],
12
+ "hints": [
13
+ "Search photos: GET /search/photos?query={term}&per_page=10",
14
+ "Random photo: GET /photos/random?query={term}",
15
+ "Response: { results: [{ urls: { regular, small, thumb }, description, user: { name } }] }",
16
+ "IMPORTANT: Save your key as 'Client-ID YOUR_ACCESS_KEY' (the proxy sends raw header value).",
17
+ "Free tier: 50 requests/hour."
18
+ ],
19
+ "onboarding": {
20
+ "url": "https://unsplash.com/developers",
21
+ "steps": [
22
+ "Create a developer account at unsplash.com/developers",
23
+ "Register a new application",
24
+ "Copy your Access Key from the app settings"
25
+ ]
26
+ }
27
+ }
@@ -0,0 +1,26 @@
1
+ {
2
+ "id": "wolfram-alpha",
3
+ "name": "Wolfram Alpha",
4
+ "category": "Science",
5
+ "description": "Computational intelligence engine. Get answers to factual queries, math, science, and data analysis.",
6
+ "baseUrl": "https://api.wolframalpha.com",
7
+ "authStrategy": "query",
8
+ "authKey": "appid",
9
+ "fields": [
10
+ { "name": "apiKey", "label": "App ID", "type": "password" }
11
+ ],
12
+ "hints": [
13
+ "Short answer: GET /v1/result?i={query} — returns plain text",
14
+ "Full results: GET /v2/query?input={query}&output=json",
15
+ "Response (v2): { queryresult: { pods: [{ title, subpods: [{ plaintext, img: { src } }] }] } }",
16
+ "Free tier: 2,000 queries/month."
17
+ ],
18
+ "onboarding": {
19
+ "url": "https://developer.wolframalpha.com/portal/myapps/",
20
+ "steps": [
21
+ "Create a Wolfram ID at developer.wolframalpha.com",
22
+ "Go to My Apps and create a new app",
23
+ "Copy the AppID from your app settings"
24
+ ]
25
+ }
26
+ }
@@ -0,0 +1,30 @@
1
+ {
2
+ "id": "youtube-data",
3
+ "name": "YouTube Data",
4
+ "category": "Media",
5
+ "description": "Search YouTube videos, retrieve channel info, playlists, and video metadata via the YouTube Data API v3.",
6
+ "baseUrl": "https://www.googleapis.com/youtube/v3",
7
+ "authStrategy": "query",
8
+ "authKey": "key",
9
+ "fields": [
10
+ { "name": "apiKey", "label": "API Key", "type": "password" }
11
+ ],
12
+ "hints": [
13
+ "Search videos: GET /search?part=snippet&q={query}&type=video&maxResults=10",
14
+ "Get video details: GET /videos?part=snippet,statistics&id={videoId}",
15
+ "Get channel: GET /channels?part=snippet,statistics&id={channelId}",
16
+ "Get playlist items: GET /playlistItems?part=snippet&playlistId={playlistId}&maxResults=10",
17
+ "Response (search): { items: [{ id: { videoId }, snippet: { title, description, thumbnails, channelTitle } }] }",
18
+ "Embed video: <iframe src=\"https://www.youtube.com/embed/{videoId}\"></iframe>",
19
+ "Free quota: 10,000 units/day. Search costs 100 units, most reads cost 1-3 units."
20
+ ],
21
+ "onboarding": {
22
+ "url": "https://console.cloud.google.com/apis/library/youtube.googleapis.com",
23
+ "steps": [
24
+ "Go to the Google Cloud Console and create or select a project",
25
+ "Enable the YouTube Data API v3",
26
+ "Go to Credentials and create an API key",
27
+ "Copy the API key"
28
+ ]
29
+ }
30
+ }
package/src/files.ts CHANGED
@@ -55,6 +55,20 @@ export async function deleteFile(path: string): Promise<void> {
55
55
  await fs.unlink(path);
56
56
  }
57
57
 
58
+ export async function copyFolderRecursive(srcFolder: string, destFolder: string): Promise<void> {
59
+ await ensureFolderExists(destFolder);
60
+ const entries = await fs.readdir(srcFolder, { withFileTypes: true });
61
+ for (const entry of entries) {
62
+ const srcPath = path.join(srcFolder, entry.name);
63
+ const destPath = path.join(destFolder, entry.name);
64
+ if (entry.isDirectory()) {
65
+ await copyFolderRecursive(srcPath, destPath);
66
+ } else {
67
+ await fs.copyFile(srcPath, destPath);
68
+ }
69
+ }
70
+ }
71
+
58
72
  export async function deleteFolder(dirPath: string): Promise<void> {
59
73
  await fs.rm(dirPath, { recursive: true });
60
74
  }
package/src/init.ts CHANGED
@@ -3,6 +3,7 @@ import path from "path";
3
3
  import { checkIfExists, copyFile, copyFiles, deleteFile, ensureFolderExists, listFiles, saveFile } from "./files";
4
4
  import { PAGE_VERSION } from "./pages";
5
5
  import { DefaultSettings } from "./settings";
6
+ import { getOutdatedThemes, parseThemeFilename } from "./themes";
6
7
 
7
8
  export interface SynthOSConfig {
8
9
  pagesFolder: string;
@@ -112,6 +113,30 @@ async function repairMissingFolders(config: SynthOSConfig): Promise<void> {
112
113
  console.log(`Restoring default themes to .synthos folder...`);
113
114
  await ensureFolderExists(themesFolder);
114
115
  await copyFiles(config.defaultThemesFolder, themesFolder);
116
+ } else {
117
+ // Upgrade outdated themes — copy newer versioned CSS from defaults
118
+ const outdated = await getOutdatedThemes(config);
119
+ if (outdated.length > 0) {
120
+ console.log(`Upgrading ${outdated.length} theme(s): ${outdated.join(', ')}...`);
121
+ const defaultFiles = await listFiles(config.defaultThemesFolder);
122
+ for (const themeName of outdated) {
123
+ // Remove old versioned CSS files for this theme
124
+ const localFiles = await listFiles(themesFolder);
125
+ for (const f of localFiles) {
126
+ const parsed = parseThemeFilename(f);
127
+ if (parsed && parsed.name === themeName) {
128
+ await deleteFile(path.join(themesFolder, f));
129
+ }
130
+ }
131
+ // Copy the new versioned CSS from defaults
132
+ for (const f of defaultFiles) {
133
+ const parsed = parseThemeFilename(f);
134
+ if (parsed && parsed.name === themeName) {
135
+ await copyFile(path.join(config.defaultThemesFolder, f), themesFolder);
136
+ }
137
+ }
138
+ }
139
+ }
115
140
  }
116
141
 
117
142
  // Ensure pages/ subfolder exists
@@ -164,6 +189,7 @@ async function migrateFlatPages(pagesFolder: string): Promise<void> {
164
189
  title,
165
190
  categories: [category],
166
191
  pinned: false,
192
+ showInAll: true,
167
193
  createdDate: now,
168
194
  lastModified: now,
169
195
  pageVersion: 1,
@@ -201,6 +227,7 @@ async function copyDefaultPages(srcFolder: string, destFolder: string): Promise<
201
227
  title: typeof metadata.title === 'string' ? metadata.title : '',
202
228
  categories: Array.isArray(metadata.categories) ? metadata.categories : [],
203
229
  pinned: typeof metadata.pinned === 'boolean' ? metadata.pinned : false,
230
+ showInAll: typeof metadata.showInAll === 'boolean' ? metadata.showInAll : true,
204
231
  createdDate: now,
205
232
  lastModified: now,
206
233
  pageVersion: typeof metadata.pageVersion === 'number' ? metadata.pageVersion