synthos 0.8.0 → 0.10.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.
- package/README.md +1 -1
- package/default-pages/application/page.html +42 -0
- package/default-pages/application/page.json +10 -0
- package/default-pages/elevenlabs_effects_studio/page.html +1363 -0
- package/default-pages/elevenlabs_effects_studio/page.json +11 -0
- package/default-pages/elevenlabs_voice_studio/page.html +801 -0
- package/default-pages/elevenlabs_voice_studio/page.json +11 -0
- package/default-pages/{json_tools.html → json_tools/page.html} +13 -11
- package/default-pages/json_tools/page.json +10 -0
- package/default-pages/my_notes/notes/a1b2c3d4-e5f6-7890-abcd-ef1234567890.json +5 -0
- package/default-pages/my_notes/page.html +132 -0
- package/default-pages/{my_notes.json → my_notes/page.json} +2 -2
- package/default-pages/neon_asteroids/files/Ambient_Space.mp3 +0 -0
- package/default-pages/neon_asteroids/files/Ambient_Space2.mp3 +0 -0
- package/default-pages/neon_asteroids/files/Ambient_Space3.mp3 +0 -0
- package/default-pages/neon_asteroids/files/Asteroid_Explosion.mp3 +0 -0
- package/default-pages/neon_asteroids/files/Hyperspace_Jump.mp3 +0 -0
- package/default-pages/neon_asteroids/files/Laser_Fire.mp3 +0 -0
- package/default-pages/neon_asteroids/files/Menu_Navigate.mp3 +0 -0
- package/default-pages/neon_asteroids/files/Power_Up_Collect.mp3 +0 -0
- package/default-pages/neon_asteroids/files/Saucer_Alert.mp3 +0 -0
- package/default-pages/neon_asteroids/files/Ship_Thrust.mp3 +0 -0
- package/default-pages/neon_asteroids/files/effects.json +74 -0
- package/default-pages/neon_asteroids/page.html +1803 -0
- package/default-pages/{neon_asteroids.json → neon_asteroids/page.json} +3 -3
- package/default-pages/{oregon_trail.html → oregon_trail/page.html} +16 -30
- package/default-pages/{oregon_trail.json → oregon_trail/page.json} +2 -2
- package/default-pages/retro_game_starter/page.html +1308 -0
- package/default-pages/retro_game_starter/page.json +12 -0
- package/default-pages/{sidebar_page.html → sidebar_page/page.html} +12 -10
- package/default-pages/sidebar_page/page.json +10 -0
- package/default-pages/{solar_explorer.html → solar_explorer/page.html} +15 -12
- package/default-pages/{solar_explorer.json → solar_explorer/page.json} +2 -2
- package/default-pages/{solar_tutorial.html → solar_tutorial/page.html} +12 -10
- package/default-pages/solar_tutorial/page.json +10 -0
- package/default-pages/{two-panel_page.html → two-panel_page/page.html} +13 -11
- package/default-pages/two-panel_page/page.json +10 -0
- package/default-pages/{us_map.html → us_map/page.html} +193 -192
- package/default-pages/{us_map.json → us_map/page.json} +12 -12
- package/default-pages/{us_map_1850.html → us_map_1850/page.html} +326 -325
- package/default-pages/{us_map_1850.json → us_map_1850/page.json} +12 -12
- package/default-pages/{western_cities_1850.html → western_cities_1850/page.html} +527 -526
- package/default-pages/{western_cities_1850.json → western_cities_1850/page.json} +12 -12
- package/default-themes/aurora-dawn.json +19 -0
- package/default-themes/aurora-dawn.v3.css +198 -0
- package/default-themes/aurora-dusk.json +19 -0
- package/default-themes/aurora-dusk.v3.css +200 -0
- package/default-themes/cosmos-dawn.json +19 -0
- package/default-themes/cosmos-dawn.v3.css +198 -0
- package/default-themes/cosmos-dusk.json +19 -0
- package/default-themes/cosmos-dusk.v3.css +200 -0
- package/default-themes/high-contrast-dark.json +19 -0
- package/default-themes/high-contrast-dark.v3.css +200 -0
- package/default-themes/high-contrast-light.json +19 -0
- package/default-themes/high-contrast-light.v3.css +198 -0
- package/default-themes/nebula-dawn.v2.css +110 -0
- package/default-themes/nebula-dawn.v3.css +199 -0
- package/default-themes/nebula-dusk.v2.css +104 -0
- package/default-themes/nebula-dusk.v3.css +201 -0
- package/default-themes/solar-flare-dawn.json +19 -0
- package/default-themes/solar-flare-dawn.v3.css +198 -0
- package/default-themes/solar-flare-dusk.json +19 -0
- package/default-themes/solar-flare-dusk.v3.css +200 -0
- package/dist/agents/index.d.ts +1 -1
- package/dist/agents/index.d.ts.map +1 -1
- package/dist/agents/index.js +2 -1
- package/dist/agents/index.js.map +1 -1
- package/dist/agents/openclaw/gatewayManager.d.ts +4 -0
- package/dist/agents/openclaw/gatewayManager.d.ts.map +1 -1
- package/dist/agents/openclaw/gatewayManager.js +27 -11
- package/dist/agents/openclaw/gatewayManager.js.map +1 -1
- package/dist/agents/openclaw/openclawProvider.d.ts.map +1 -1
- package/dist/agents/openclaw/openclawProvider.js +2 -4
- package/dist/agents/openclaw/openclawProvider.js.map +1 -1
- package/dist/agents/openclaw/sshTunnelManager.d.ts +2 -0
- package/dist/agents/openclaw/sshTunnelManager.d.ts.map +1 -1
- package/dist/agents/openclaw/sshTunnelManager.js +31 -12
- package/dist/agents/openclaw/sshTunnelManager.js.map +1 -1
- package/dist/builders/anthropic.d.ts +31 -0
- package/dist/builders/anthropic.d.ts.map +1 -0
- package/dist/builders/anthropic.js +227 -0
- package/dist/builders/anthropic.js.map +1 -0
- package/dist/builders/fireworksai.d.ts +9 -0
- package/dist/builders/fireworksai.d.ts.map +1 -0
- package/dist/builders/fireworksai.js +57 -0
- package/dist/builders/fireworksai.js.map +1 -0
- package/dist/builders/index.d.ts +13 -0
- package/dist/builders/index.d.ts.map +1 -0
- package/dist/builders/index.js +31 -0
- package/dist/builders/index.js.map +1 -0
- package/dist/builders/openai.d.ts +8 -0
- package/dist/builders/openai.d.ts.map +1 -0
- package/dist/builders/openai.js +87 -0
- package/dist/builders/openai.js.map +1 -0
- package/dist/builders/types.d.ts +54 -0
- package/dist/builders/types.d.ts.map +1 -0
- package/dist/builders/types.js +211 -0
- package/dist/builders/types.js.map +1 -0
- package/dist/connectors/index.d.ts +1 -1
- package/dist/connectors/index.d.ts.map +1 -1
- package/dist/connectors/index.js +3 -2
- package/dist/connectors/index.js.map +1 -1
- package/dist/connectors/registry.d.ts +2 -1
- package/dist/connectors/registry.d.ts.map +1 -1
- package/dist/connectors/registry.js +31 -8
- package/dist/connectors/registry.js.map +1 -1
- package/dist/customizer/Customizer.d.ts +62 -0
- package/dist/customizer/Customizer.d.ts.map +1 -0
- package/dist/customizer/Customizer.js +134 -0
- package/dist/customizer/Customizer.js.map +1 -0
- package/dist/customizer/index.d.ts +4 -0
- package/dist/customizer/index.d.ts.map +1 -0
- package/dist/customizer/index.js +9 -0
- package/dist/customizer/index.js.map +1 -0
- package/dist/files.d.ts +16 -0
- package/dist/files.d.ts.map +1 -1
- package/dist/files.js +60 -1
- package/dist/files.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/init.d.ts +12 -6
- package/dist/init.d.ts.map +1 -1
- package/dist/init.js +150 -133
- package/dist/init.js.map +1 -1
- package/dist/migrations.d.ts.map +1 -1
- package/dist/migrations.js +23 -10
- package/dist/migrations.js.map +1 -1
- package/dist/models/anthropic.d.ts +4 -2
- package/dist/models/anthropic.d.ts.map +1 -1
- package/dist/models/anthropic.js +33 -6
- package/dist/models/anthropic.js.map +1 -1
- package/dist/models/fireworksai.d.ts.map +1 -1
- package/dist/models/fireworksai.js +9 -1
- package/dist/models/fireworksai.js.map +1 -1
- package/dist/models/index.d.ts +1 -1
- package/dist/models/index.d.ts.map +1 -1
- package/dist/models/index.js +2 -1
- package/dist/models/index.js.map +1 -1
- package/dist/models/openai.d.ts +1 -1
- package/dist/models/openai.d.ts.map +1 -1
- package/dist/models/openai.js +24 -3
- package/dist/models/openai.js.map +1 -1
- package/dist/models/types.d.ts +20 -1
- package/dist/models/types.d.ts.map +1 -1
- package/dist/models/types.js +6 -1
- package/dist/models/types.js.map +1 -1
- package/dist/pages.d.ts +34 -10
- package/dist/pages.d.ts.map +1 -1
- package/dist/pages.js +229 -79
- package/dist/pages.js.map +1 -1
- package/dist/service/createCompletePrompt.d.ts +2 -1
- package/dist/service/createCompletePrompt.d.ts.map +1 -1
- package/dist/service/createCompletePrompt.js +2 -2
- package/dist/service/createCompletePrompt.js.map +1 -1
- package/dist/service/requiresSettings.d.ts +2 -1
- package/dist/service/requiresSettings.d.ts.map +1 -1
- package/dist/service/requiresSettings.js +3 -3
- package/dist/service/requiresSettings.js.map +1 -1
- package/dist/service/server.d.ts +2 -1
- package/dist/service/server.d.ts.map +1 -1
- package/dist/service/server.js +37 -8
- package/dist/service/server.js.map +1 -1
- package/dist/service/transformPage.d.ts +47 -20
- package/dist/service/transformPage.d.ts.map +1 -1
- package/dist/service/transformPage.js +514 -293
- package/dist/service/transformPage.js.map +1 -1
- package/dist/service/useAgentRoutes.d.ts +2 -1
- package/dist/service/useAgentRoutes.d.ts.map +1 -1
- package/dist/service/useAgentRoutes.js +17 -14
- package/dist/service/useAgentRoutes.js.map +1 -1
- package/dist/service/useApiRoutes.d.ts +2 -1
- package/dist/service/useApiRoutes.d.ts.map +1 -1
- package/dist/service/useApiRoutes.js +287 -172
- package/dist/service/useApiRoutes.js.map +1 -1
- package/dist/service/useConnectorRoutes.js +17 -17
- package/dist/service/useConnectorRoutes.js.map +1 -1
- package/dist/service/useDataRoutes.d.ts.map +1 -1
- package/dist/service/useDataRoutes.js +13 -10
- package/dist/service/useDataRoutes.js.map +1 -1
- package/dist/service/useFileRoutes.d.ts +4 -0
- package/dist/service/useFileRoutes.d.ts.map +1 -0
- package/dist/service/useFileRoutes.js +122 -0
- package/dist/service/useFileRoutes.js.map +1 -0
- package/dist/service/usePageRoutes.d.ts +2 -1
- package/dist/service/usePageRoutes.d.ts.map +1 -1
- package/dist/service/usePageRoutes.js +671 -74
- package/dist/service/usePageRoutes.js.map +1 -1
- package/dist/service/useSharedDataRoutes.d.ts +4 -0
- package/dist/service/useSharedDataRoutes.d.ts.map +1 -0
- package/dist/service/useSharedDataRoutes.js +107 -0
- package/dist/service/useSharedDataRoutes.js.map +1 -0
- package/dist/service/useSharedFileRoutes.d.ts +4 -0
- package/dist/service/useSharedFileRoutes.d.ts.map +1 -0
- package/dist/service/useSharedFileRoutes.js +121 -0
- package/dist/service/useSharedFileRoutes.js.map +1 -0
- package/dist/settings.d.ts +5 -3
- package/dist/settings.d.ts.map +1 -1
- package/dist/settings.js +12 -10
- package/dist/settings.js.map +1 -1
- package/dist/storage/FsStorageProvider.d.ts +25 -0
- package/dist/storage/FsStorageProvider.d.ts.map +1 -0
- package/dist/storage/FsStorageProvider.js +103 -0
- package/dist/storage/FsStorageProvider.js.map +1 -0
- package/dist/storage/StorageProvider.d.ts +31 -0
- package/dist/storage/StorageProvider.d.ts.map +1 -0
- package/dist/storage/StorageProvider.js +3 -0
- package/dist/storage/StorageProvider.js.map +1 -0
- package/dist/storage/index.d.ts +3 -0
- package/dist/storage/index.d.ts.map +1 -0
- package/dist/storage/index.js +6 -0
- package/dist/storage/index.js.map +1 -0
- package/dist/synthos-cli.d.ts.map +1 -1
- package/dist/synthos-cli.js +4 -3
- package/dist/synthos-cli.js.map +1 -1
- package/dist/themes.d.ts +1 -0
- package/dist/themes.d.ts.map +1 -1
- package/dist/themes.js +65 -28
- package/dist/themes.js.map +1 -1
- package/migration-rules/v1-to-v2.md +193 -0
- package/migration-rules/v2-to-v3.md +481 -0
- package/package.json +11 -10
- package/required-pages/builder/page.html +43 -0
- package/required-pages/builder/page.json +10 -0
- package/required-pages/{pages.html → pages/page.html} +238 -233
- package/required-pages/pages/page.json +10 -0
- package/required-pages/{settings.html → settings/page.html} +389 -275
- package/required-pages/settings/page.json +10 -0
- package/required-pages/synthos_apis/page.html +846 -0
- package/required-pages/synthos_apis/page.json +10 -0
- package/required-pages/{synthos_scripts.html → synthos_scripts/page.html} +13 -11
- package/required-pages/synthos_scripts/page.json +10 -0
- package/src/agents/index.ts +1 -1
- package/src/agents/openclaw/gatewayManager.ts +22 -11
- package/src/agents/openclaw/openclawProvider.ts +2 -4
- package/src/agents/openclaw/sshTunnelManager.ts +19 -11
- package/src/builders/anthropic.ts +283 -0
- package/src/builders/fireworksai.ts +59 -0
- package/src/builders/index.ts +33 -0
- package/src/builders/openai.ts +89 -0
- package/src/builders/types.ts +261 -0
- package/src/connectors/index.ts +1 -1
- package/src/connectors/registry.ts +28 -8
- package/src/customizer/Customizer.ts +163 -0
- package/src/customizer/index.ts +5 -0
- package/src/files.ts +57 -0
- package/src/index.ts +3 -1
- package/src/init.ts +195 -145
- package/src/migrations.ts +30 -10
- package/src/models/anthropic.ts +40 -10
- package/src/models/fireworksai.ts +9 -2
- package/src/models/index.ts +1 -1
- package/src/models/openai.ts +26 -6
- package/src/models/types.ts +31 -1
- package/src/pages.ts +230 -77
- package/src/service/createCompletePrompt.ts +3 -2
- package/src/service/requiresSettings.ts +4 -3
- package/src/service/server.ts +36 -9
- package/src/service/transformPage.ts +557 -326
- package/src/service/useAgentRoutes.ts +19 -14
- package/src/service/useApiRoutes.ts +208 -84
- package/src/service/useConnectorRoutes.ts +18 -18
- package/src/service/useDataRoutes.ts +13 -10
- package/src/service/useFileRoutes.ts +128 -0
- package/src/service/usePageRoutes.ts +730 -81
- package/src/service/useSharedDataRoutes.ts +109 -0
- package/src/service/useSharedFileRoutes.ts +127 -0
- package/src/settings.ts +14 -10
- package/src/storage/FsStorageProvider.ts +87 -0
- package/src/storage/StorageProvider.ts +34 -0
- package/src/storage/index.ts +2 -0
- package/src/synthos-cli.ts +4 -3
- package/src/themes.ts +64 -27
- package/static-files/favicon.svg +12 -0
- package/static-files/fluentlm-instructions.llmd +868 -0
- package/static-files/fluentlm-instructions.md +1595 -0
- package/static-files/fluentlm.css +4844 -0
- package/static-files/fluentlm.js +3602 -0
- package/static-files/fluentlm.min.css +1 -0
- package/static-files/fluentlm.min.js +1 -0
- package/{page-scripts/helpers-v2.js → static-files/helpers.v3.js} +82 -0
- package/static-files/page.v3.js +1290 -0
- package/static-files/recommended-frameworks.llmd +81 -0
- package/static-files/recommended-frameworks.md +137 -0
- package/static-files/retro-game.js +877 -0
- package/static-files/shell.css +797 -0
- package/static-files/theme-dark.css +169 -0
- package/static-files/theme-light.css +169 -0
- package/tests/builders.spec.ts +139 -0
- package/tests/pages.spec.ts +54 -84
- package/tests/transformPage.spec.ts +299 -360
- package/default-pages/application.html +0 -40
- package/default-pages/application.json +0 -1
- package/default-pages/json_tools.json +0 -1
- package/default-pages/my_notes.html +0 -33
- package/default-pages/neon_asteroids.html +0 -77
- package/default-pages/sidebar_page.json +0 -1
- package/default-pages/solar_tutorial.json +0 -1
- package/default-pages/two-panel_page.json +0 -1
- package/dist/service/useGatewayRoutes.d.ts +0 -4
- package/dist/service/useGatewayRoutes.d.ts.map +0 -1
- package/dist/service/useGatewayRoutes.js +0 -168
- package/dist/service/useGatewayRoutes.js.map +0 -1
- package/page-scripts/page-v2.js +0 -656
- package/required-pages/builder.html +0 -48
- package/required-pages/builder.json +0 -1
- package/required-pages/pages.json +0 -1
- package/required-pages/settings.json +0 -1
- package/required-pages/synthos_apis.html +0 -327
- package/required-pages/synthos_apis.json +0 -1
- package/required-pages/synthos_scripts.json +0 -1
- package/src/connectors/airtable/connector.json +0 -27
- package/src/connectors/alpha-vantage/connector.json +0 -26
- package/src/connectors/brave-search/connector.json +0 -26
- package/src/connectors/cloudinary/connector.json +0 -27
- package/src/connectors/deepl/connector.json +0 -28
- package/src/connectors/elevenlabs/connector.json +0 -30
- package/src/connectors/giphy/connector.json +0 -27
- package/src/connectors/github/connector.json +0 -29
- package/src/connectors/huggingface/connector.json +0 -27
- package/src/connectors/imgur/connector.json +0 -29
- package/src/connectors/instagram/connector.json +0 -43
- package/src/connectors/jira/connector.json +0 -28
- package/src/connectors/mapbox/connector.json +0 -26
- package/src/connectors/nasa/connector.json +0 -27
- package/src/connectors/newsapi/connector.json +0 -27
- package/src/connectors/notion/connector.json +0 -28
- package/src/connectors/open-exchange-rates/connector.json +0 -27
- package/src/connectors/openweathermap/connector.json +0 -26
- package/src/connectors/pexels/connector.json +0 -27
- package/src/connectors/resend/connector.json +0 -29
- package/src/connectors/rss2json/connector.json +0 -27
- package/src/connectors/sendgrid/connector.json +0 -27
- package/src/connectors/spoonacular/connector.json +0 -28
- package/src/connectors/stability-ai/connector.json +0 -27
- package/src/connectors/twilio/connector.json +0 -28
- package/src/connectors/unsplash/connector.json +0 -27
- package/src/connectors/wolfram-alpha/connector.json +0 -26
- package/src/connectors/youtube-data/connector.json +0 -30
- /package/{dist/connectors → service-connectors}/airtable/connector.json +0 -0
- /package/{dist/connectors → service-connectors}/alpha-vantage/connector.json +0 -0
- /package/{dist/connectors → service-connectors}/brave-search/connector.json +0 -0
- /package/{dist/connectors → service-connectors}/cloudinary/connector.json +0 -0
- /package/{dist/connectors → service-connectors}/deepl/connector.json +0 -0
- /package/{dist/connectors → service-connectors}/elevenlabs/connector.json +0 -0
- /package/{dist/connectors → service-connectors}/giphy/connector.json +0 -0
- /package/{dist/connectors → service-connectors}/github/connector.json +0 -0
- /package/{dist/connectors → service-connectors}/huggingface/connector.json +0 -0
- /package/{dist/connectors → service-connectors}/imgur/connector.json +0 -0
- /package/{dist/connectors → service-connectors}/instagram/connector.json +0 -0
- /package/{dist/connectors → service-connectors}/jira/connector.json +0 -0
- /package/{dist/connectors → service-connectors}/mapbox/connector.json +0 -0
- /package/{dist/connectors → service-connectors}/nasa/connector.json +0 -0
- /package/{dist/connectors → service-connectors}/newsapi/connector.json +0 -0
- /package/{dist/connectors → service-connectors}/notion/connector.json +0 -0
- /package/{dist/connectors → service-connectors}/open-exchange-rates/connector.json +0 -0
- /package/{dist/connectors → service-connectors}/openweathermap/connector.json +0 -0
- /package/{dist/connectors → service-connectors}/pexels/connector.json +0 -0
- /package/{dist/connectors → service-connectors}/resend/connector.json +0 -0
- /package/{dist/connectors → service-connectors}/rss2json/connector.json +0 -0
- /package/{dist/connectors → service-connectors}/sendgrid/connector.json +0 -0
- /package/{dist/connectors → service-connectors}/spoonacular/connector.json +0 -0
- /package/{dist/connectors → service-connectors}/stability-ai/connector.json +0 -0
- /package/{dist/connectors → service-connectors}/twilio/connector.json +0 -0
- /package/{dist/connectors → service-connectors}/unsplash/connector.json +0 -0
- /package/{dist/connectors → service-connectors}/wolfram-alpha/connector.json +0 -0
- /package/{dist/connectors → service-connectors}/youtube-data/connector.json +0 -0
package/src/files.ts
CHANGED
|
@@ -72,3 +72,60 @@ export async function copyFolderRecursive(srcFolder: string, destFolder: string)
|
|
|
72
72
|
export async function deleteFolder(dirPath: string): Promise<void> {
|
|
73
73
|
await fs.rm(dirPath, { recursive: true });
|
|
74
74
|
}
|
|
75
|
+
|
|
76
|
+
// --- Multi-folder helpers ---
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Search folders in order, return the full path to the first existing match
|
|
80
|
+
* for the given filename.
|
|
81
|
+
*/
|
|
82
|
+
export async function findFileInFolders(folders: string[], filename: string): Promise<string | undefined> {
|
|
83
|
+
for (const folder of folders) {
|
|
84
|
+
const candidate = path.join(folder, filename);
|
|
85
|
+
if (await checkIfExists(candidate)) {
|
|
86
|
+
return candidate;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return undefined;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Merge file listings from multiple folders. First folder takes priority on
|
|
94
|
+
* name collisions (earlier occurrence wins).
|
|
95
|
+
*/
|
|
96
|
+
export async function listFilesFromFolders(folders: string[]): Promise<string[]> {
|
|
97
|
+
const seen = new Set<string>();
|
|
98
|
+
const result: string[] = [];
|
|
99
|
+
for (const folder of folders) {
|
|
100
|
+
if (!await checkIfExists(folder)) continue;
|
|
101
|
+
const files = await listFiles(folder);
|
|
102
|
+
for (const f of files) {
|
|
103
|
+
if (!seen.has(f)) {
|
|
104
|
+
seen.add(f);
|
|
105
|
+
result.push(f);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return result;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Copy files from multiple source folders into a single destination.
|
|
114
|
+
* First folder takes priority on duplicate filenames (copy is skipped
|
|
115
|
+
* if the file already exists in dest from an earlier folder).
|
|
116
|
+
*/
|
|
117
|
+
export async function copyFilesFromFolders(folders: string[], destFolder: string): Promise<void> {
|
|
118
|
+
await ensureFolderExists(destFolder);
|
|
119
|
+
const copied = new Set<string>();
|
|
120
|
+
for (const folder of folders) {
|
|
121
|
+
if (!await checkIfExists(folder)) continue;
|
|
122
|
+
const files = await fs.readdir(folder);
|
|
123
|
+
for (const file of files) {
|
|
124
|
+
if (copied.has(file)) continue;
|
|
125
|
+
copied.add(file);
|
|
126
|
+
const srcPath = path.join(folder, file);
|
|
127
|
+
const destPath = path.join(destFolder, file);
|
|
128
|
+
await fs.copyFile(srcPath, destPath);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
package/src/index.ts
CHANGED
package/src/init.ts
CHANGED
|
@@ -1,159 +1,165 @@
|
|
|
1
1
|
import * as fs from 'fs/promises';
|
|
2
2
|
import path from "path";
|
|
3
|
-
import { checkIfExists,
|
|
4
|
-
import { PAGE_VERSION } from "./pages";
|
|
3
|
+
import { checkIfExists, findFileInFolders, listFolders } from "./files";
|
|
4
|
+
import { PAGE_VERSION, getRequiredPages } from "./pages";
|
|
5
5
|
import { DefaultSettings } from "./settings";
|
|
6
|
-
import {
|
|
6
|
+
import { Customizer } from './customizer';
|
|
7
|
+
import { StorageProvider, FsStorageProvider } from './storage';
|
|
7
8
|
|
|
8
9
|
export interface SynthOSConfig {
|
|
10
|
+
localFolder: string;
|
|
9
11
|
pagesFolder: string;
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
requiredPagesFolders: string[];
|
|
13
|
+
defaultPagesFolders: string[];
|
|
14
|
+
defaultScriptsFolders: string[];
|
|
15
|
+
defaultThemesFolders: string[];
|
|
16
|
+
staticFilesFolders: string[];
|
|
17
|
+
serviceConnectorsFolders: string[];
|
|
18
|
+
requiredPages: string[];
|
|
19
|
+
storageProvider: StorageProvider;
|
|
15
20
|
debug: boolean;
|
|
16
21
|
debugPageUpdates: boolean;
|
|
17
22
|
}
|
|
18
23
|
|
|
19
|
-
|
|
24
|
+
/**
|
|
25
|
+
* Resolve a folder array from a Customizer getter: replace the `'default'`
|
|
26
|
+
* sentinel with the built-in SynthOS path.
|
|
27
|
+
*/
|
|
28
|
+
function resolveFolders(folders: string[], builtInPath: string): string[] {
|
|
29
|
+
return folders.map(f => f === 'default' ? builtInPath : f);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export async function createConfig(
|
|
33
|
+
pagesFolder = '.synthos',
|
|
34
|
+
options?: { debug?: boolean; debugPageUpdates?: boolean },
|
|
35
|
+
customizer?: Customizer
|
|
36
|
+
): Promise<SynthOSConfig> {
|
|
37
|
+
const requiredPagesFolders = resolveFolders(
|
|
38
|
+
customizer?.requiredPagesFolders ?? ['default'],
|
|
39
|
+
path.join(__dirname, '../required-pages')
|
|
40
|
+
);
|
|
41
|
+
const requiredPages = await getRequiredPages(requiredPagesFolders);
|
|
20
42
|
return {
|
|
43
|
+
localFolder: pagesFolder,
|
|
21
44
|
pagesFolder: path.join(process.cwd(), pagesFolder),
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
45
|
+
requiredPagesFolders,
|
|
46
|
+
defaultPagesFolders: resolveFolders(
|
|
47
|
+
customizer?.defaultPagesFolders ?? ['default'],
|
|
48
|
+
path.join(__dirname, '../default-pages')
|
|
49
|
+
),
|
|
50
|
+
defaultScriptsFolders: resolveFolders(
|
|
51
|
+
customizer?.defaultScriptsFolders ?? ['default'],
|
|
52
|
+
path.join(__dirname, '../default-scripts')
|
|
53
|
+
),
|
|
54
|
+
defaultThemesFolders: resolveFolders(
|
|
55
|
+
customizer?.defaultThemesFolders ?? ['default'],
|
|
56
|
+
path.join(__dirname, '../default-themes')
|
|
57
|
+
),
|
|
58
|
+
staticFilesFolders: resolveFolders(
|
|
59
|
+
customizer?.staticFilesFolders ?? ['default'],
|
|
60
|
+
path.join(__dirname, '../static-files')
|
|
61
|
+
),
|
|
62
|
+
serviceConnectorsFolders: resolveFolders(
|
|
63
|
+
customizer?.serviceConnectorsFolders ?? ['default'],
|
|
64
|
+
path.join(__dirname, '../service-connectors')
|
|
65
|
+
),
|
|
66
|
+
requiredPages,
|
|
67
|
+
storageProvider: customizer?.storageProvider ?? new FsStorageProvider(),
|
|
27
68
|
debug: options?.debug ?? false,
|
|
28
69
|
debugPageUpdates: options?.debugPageUpdates ?? false
|
|
29
70
|
};
|
|
30
71
|
}
|
|
31
72
|
|
|
32
73
|
export async function init(config: SynthOSConfig, includeDefaultPages: boolean = true): Promise<boolean> {
|
|
74
|
+
const sp = config.storageProvider;
|
|
75
|
+
|
|
33
76
|
// Check for existing folder
|
|
34
|
-
if (await checkIfExists(config.pagesFolder)) {
|
|
77
|
+
if (await sp.checkIfExists(config.pagesFolder)) {
|
|
35
78
|
await repairMissingFolders(config);
|
|
36
79
|
return false;
|
|
37
80
|
}
|
|
38
81
|
|
|
39
|
-
console.log(`Initializing .
|
|
82
|
+
console.log(`Initializing ${config.localFolder} folder...`);
|
|
40
83
|
|
|
41
84
|
// Create pages folder
|
|
42
|
-
await ensureFolderExists(config.pagesFolder);
|
|
85
|
+
await sp.ensureFolderExists(config.pagesFolder);
|
|
43
86
|
|
|
44
87
|
// Create mandatory files
|
|
45
|
-
await saveFile(path.join(config.pagesFolder, '.gitignore'), 'settings.json\n');
|
|
46
|
-
await saveFile(path.join(config.pagesFolder, 'settings.json'), JSON.stringify(DefaultSettings, null, 4));
|
|
47
|
-
await saveFile(path.join(config.pagesFolder, 'settings.json.example'), JSON.stringify(DefaultSettings, null, 4));
|
|
88
|
+
await sp.saveFile(path.join(config.pagesFolder, '.gitignore'), 'settings.json\n');
|
|
89
|
+
await sp.saveFile(path.join(config.pagesFolder, 'settings.json'), JSON.stringify(DefaultSettings, null, 4));
|
|
90
|
+
await sp.saveFile(path.join(config.pagesFolder, 'settings.json.example'), JSON.stringify(DefaultSettings, null, 4));
|
|
48
91
|
|
|
49
92
|
// Setup default scripts
|
|
50
|
-
console.log(`Copying default scripts to .
|
|
93
|
+
console.log(`Copying default scripts to ${config.localFolder} folder...`);
|
|
51
94
|
const scriptsFolder = path.join(config.pagesFolder, 'scripts');
|
|
52
|
-
await ensureFolderExists(scriptsFolder);
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
await
|
|
70
|
-
|
|
71
|
-
// Setup default themes
|
|
72
|
-
console.log(`Copying default themes to .synthos folder...`);
|
|
73
|
-
const themesFolder = path.join(config.pagesFolder, 'themes');
|
|
74
|
-
await ensureFolderExists(themesFolder);
|
|
75
|
-
await copyFiles(config.defaultThemesFolder, themesFolder);
|
|
95
|
+
await sp.ensureFolderExists(scriptsFolder);
|
|
96
|
+
const scriptFilename = ({
|
|
97
|
+
win32: 'windows-terminal.json',
|
|
98
|
+
darwin: 'mac-terminal.json',
|
|
99
|
+
android: 'android-terminal.json',
|
|
100
|
+
} as Record<string, string>)[process.platform] ?? 'linux-terminal.json';
|
|
101
|
+
const scriptSrc = await findFileInFolders(config.defaultScriptsFolders, scriptFilename);
|
|
102
|
+
if (scriptSrc) {
|
|
103
|
+
// Read from package (local fs), write to user storage (provider)
|
|
104
|
+
const data = await fs.readFile(scriptSrc);
|
|
105
|
+
await sp.saveBuffer(path.join(scriptsFolder, path.basename(scriptSrc)), data);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
await sp.saveFile(path.join(scriptsFolder, 'example.sh'), `#!/bin/bash\n\n# This is an example script\n\n# You can run this script using the following command:\n# sh ${config.localFolder}/scripts/example.sh\n\n# This script will print "Hello, World!" to the console\n\necho "Hello, World!"\n`);
|
|
109
|
+
|
|
110
|
+
// Create empty themes folder — default themes are served directly from
|
|
111
|
+
// defaultThemesFolders; users can add custom themes here.
|
|
112
|
+
await sp.ensureFolderExists(path.join(config.pagesFolder, 'themes'));
|
|
76
113
|
|
|
77
114
|
// Copy pages
|
|
78
115
|
if (includeDefaultPages) {
|
|
79
|
-
console.log(`Copying default pages to .
|
|
80
|
-
await copyDefaultPages(config
|
|
116
|
+
console.log(`Copying default pages to ${config.localFolder} folder...`);
|
|
117
|
+
await copyDefaultPages(config, config.defaultPagesFolders);
|
|
81
118
|
}
|
|
82
119
|
|
|
83
120
|
return true;
|
|
84
121
|
}
|
|
85
122
|
|
|
86
123
|
async function repairMissingFolders(config: SynthOSConfig): Promise<void> {
|
|
124
|
+
const sp = config.storageProvider;
|
|
125
|
+
|
|
87
126
|
// Rebuild scripts folder from defaults if missing
|
|
88
127
|
const scriptsFolder = path.join(config.pagesFolder, 'scripts');
|
|
89
|
-
if (!await checkIfExists(scriptsFolder)) {
|
|
90
|
-
console.log(`Restoring default scripts to .
|
|
91
|
-
await ensureFolderExists(scriptsFolder);
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
break;
|
|
102
|
-
case 'linux':
|
|
103
|
-
default:
|
|
104
|
-
await copyFile(path.join(config.defaultScriptsFolder, 'linux-terminal.json'), scriptsFolder);
|
|
105
|
-
break;
|
|
128
|
+
if (!await sp.checkIfExists(scriptsFolder)) {
|
|
129
|
+
console.log(`Restoring default scripts to ${config.localFolder} folder...`);
|
|
130
|
+
await sp.ensureFolderExists(scriptsFolder);
|
|
131
|
+
const scriptFilename = ({
|
|
132
|
+
win32: 'windows-terminal.json',
|
|
133
|
+
darwin: 'mac-terminal.json',
|
|
134
|
+
android: 'android-terminal.json',
|
|
135
|
+
} as Record<string, string>)[process.platform] ?? 'linux-terminal.json';
|
|
136
|
+
const scriptSrc = await findFileInFolders(config.defaultScriptsFolders, scriptFilename);
|
|
137
|
+
if (scriptSrc) {
|
|
138
|
+
const data = await fs.readFile(scriptSrc);
|
|
139
|
+
await sp.saveBuffer(path.join(scriptsFolder, path.basename(scriptSrc)), data);
|
|
106
140
|
}
|
|
107
|
-
await saveFile(path.join(scriptsFolder, 'example.sh'),
|
|
141
|
+
await sp.saveFile(path.join(scriptsFolder, 'example.sh'), `#!/bin/bash\n\n# This is an example script\n\n# You can run this script using the following command:\n# sh ${config.localFolder}/scripts/example.sh\n\n# This script will print "Hello, World!" to the console\n\necho "Hello, World!"\n`);
|
|
108
142
|
}
|
|
109
143
|
|
|
110
|
-
//
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
console.log(`Restoring default themes to .synthos folder...`);
|
|
114
|
-
await ensureFolderExists(themesFolder);
|
|
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
|
-
}
|
|
140
|
-
}
|
|
144
|
+
// Ensure themes folder exists — default themes are served directly from
|
|
145
|
+
// defaultThemesFolders; this folder is for user-added custom themes only.
|
|
146
|
+
await sp.ensureFolderExists(path.join(config.pagesFolder, 'themes'));
|
|
141
147
|
|
|
142
148
|
// Ensure pages/ subfolder exists
|
|
143
149
|
const pagesSubdir = path.join(config.pagesFolder, 'pages');
|
|
144
|
-
if (!await checkIfExists(pagesSubdir)) {
|
|
150
|
+
if (!await sp.checkIfExists(pagesSubdir)) {
|
|
145
151
|
// No pages folder and no flat files — rebuild from defaults
|
|
146
|
-
const htmlFiles = (await listFiles(config.pagesFolder)).filter(f => f.endsWith('.html'));
|
|
152
|
+
const htmlFiles = (await sp.listFiles(config.pagesFolder)).filter(f => f.endsWith('.html'));
|
|
147
153
|
if (htmlFiles.length === 0) {
|
|
148
|
-
console.log(`Restoring default pages to .
|
|
149
|
-
await copyDefaultPages(config
|
|
154
|
+
console.log(`Restoring default pages to ${config.localFolder}/pages/ folder...`);
|
|
155
|
+
await copyDefaultPages(config, config.defaultPagesFolders);
|
|
150
156
|
} else {
|
|
151
|
-
await ensureFolderExists(pagesSubdir);
|
|
157
|
+
await sp.ensureFolderExists(pagesSubdir);
|
|
152
158
|
}
|
|
153
159
|
}
|
|
154
160
|
|
|
155
161
|
// Migrate any stray flat .html files from root into pages/<name>/
|
|
156
|
-
await migrateFlatPages(config
|
|
162
|
+
await migrateFlatPages(config);
|
|
157
163
|
}
|
|
158
164
|
|
|
159
165
|
function toTitleCase(name: string): string {
|
|
@@ -164,13 +170,15 @@ function toTitleCase(name: string): string {
|
|
|
164
170
|
.replace(/\b\w/g, c => c.toUpperCase());
|
|
165
171
|
}
|
|
166
172
|
|
|
167
|
-
async function migrateFlatPages(
|
|
173
|
+
async function migrateFlatPages(config: SynthOSConfig): Promise<void> {
|
|
174
|
+
const sp = config.storageProvider;
|
|
175
|
+
const pagesFolder = config.pagesFolder;
|
|
168
176
|
const pagesSubdir = path.join(pagesFolder, 'pages');
|
|
169
|
-
const htmlFiles = (await listFiles(pagesFolder)).filter(f => f.endsWith('.html'));
|
|
177
|
+
const htmlFiles = (await sp.listFiles(pagesFolder)).filter(f => f.endsWith('.html'));
|
|
170
178
|
if (htmlFiles.length === 0) return;
|
|
171
179
|
|
|
172
|
-
console.log(`Migrating ${htmlFiles.length} page(s) to .
|
|
173
|
-
await ensureFolderExists(pagesSubdir);
|
|
180
|
+
console.log(`Migrating ${htmlFiles.length} page(s) to ${config.localFolder}/pages/ folder...`);
|
|
181
|
+
await sp.ensureFolderExists(pagesSubdir);
|
|
174
182
|
const now = new Date().toISOString();
|
|
175
183
|
|
|
176
184
|
for (const file of htmlFiles) {
|
|
@@ -178,12 +186,11 @@ async function migrateFlatPages(pagesFolder: string): Promise<void> {
|
|
|
178
186
|
const category = pageName.startsWith('[') ? 'Builder' : 'Pages';
|
|
179
187
|
const title = toTitleCase(pageName);
|
|
180
188
|
const pageFolder = path.join(pagesSubdir, pageName);
|
|
181
|
-
await ensureFolderExists(pageFolder);
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
await saveFile(
|
|
189
|
+
await sp.ensureFolderExists(pageFolder);
|
|
190
|
+
// Both source and destination are user storage
|
|
191
|
+
const content = await sp.loadFile(path.join(pagesFolder, file));
|
|
192
|
+
await sp.saveFile(path.join(pageFolder, 'page.html'), content);
|
|
193
|
+
await sp.saveFile(
|
|
187
194
|
path.join(pageFolder, 'page.json'),
|
|
188
195
|
JSON.stringify({
|
|
189
196
|
title,
|
|
@@ -196,44 +203,87 @@ async function migrateFlatPages(pagesFolder: string): Promise<void> {
|
|
|
196
203
|
mode: 'unlocked',
|
|
197
204
|
}, null, 4)
|
|
198
205
|
);
|
|
199
|
-
await deleteFile(path.join(pagesFolder, file));
|
|
206
|
+
await sp.deleteFile(path.join(pagesFolder, file));
|
|
200
207
|
}
|
|
201
208
|
}
|
|
202
209
|
|
|
203
|
-
async function copyDefaultPages(
|
|
204
|
-
const
|
|
205
|
-
|
|
206
|
-
|
|
210
|
+
async function copyDefaultPages(config: SynthOSConfig, srcFolders: string[]): Promise<void> {
|
|
211
|
+
const sp = config.storageProvider;
|
|
212
|
+
const pagesDir = path.join(config.pagesFolder, 'pages');
|
|
213
|
+
await sp.ensureFolderExists(pagesDir);
|
|
207
214
|
const now = new Date().toISOString();
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
await
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
215
|
+
const seen = new Set<string>();
|
|
216
|
+
|
|
217
|
+
for (const srcFolder of srcFolders) {
|
|
218
|
+
if (!await checkIfExists(srcFolder)) continue; // source is always local fs
|
|
219
|
+
const dirs = await listFolders(srcFolder); // source is always local fs
|
|
220
|
+
for (const dir of dirs) {
|
|
221
|
+
const srcPageDir = path.join(srcFolder, dir);
|
|
222
|
+
if (!await checkIfExists(path.join(srcPageDir, 'page.html'))) continue;
|
|
223
|
+
if (seen.has(dir)) continue; // first folder wins
|
|
224
|
+
seen.add(dir);
|
|
225
|
+
|
|
226
|
+
const pageFolder = path.join(pagesDir, dir);
|
|
227
|
+
await sp.ensureFolderExists(pageFolder);
|
|
228
|
+
|
|
229
|
+
// Read from local fs, write via provider
|
|
230
|
+
const htmlData = await fs.readFile(path.join(srcPageDir, 'page.html'));
|
|
231
|
+
await sp.saveBuffer(path.join(pageFolder, 'page.html'), htmlData);
|
|
232
|
+
|
|
233
|
+
// Read companion page.json metadata from source folder, fall back to defaults
|
|
234
|
+
let metadata: Record<string, unknown> = {};
|
|
235
|
+
const jsonPath = path.join(srcPageDir, 'page.json');
|
|
236
|
+
if (await checkIfExists(jsonPath)) {
|
|
237
|
+
try {
|
|
238
|
+
const raw = await fs.readFile(jsonPath, 'utf-8');
|
|
239
|
+
metadata = JSON.parse(raw);
|
|
240
|
+
} catch {
|
|
241
|
+
// use defaults
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
const fullMetadata = {
|
|
245
|
+
title: typeof metadata.title === 'string' ? metadata.title : '',
|
|
246
|
+
categories: Array.isArray(metadata.categories) ? metadata.categories : [],
|
|
247
|
+
pinned: typeof metadata.pinned === 'boolean' ? metadata.pinned : false,
|
|
248
|
+
showInAll: typeof metadata.showInAll === 'boolean' ? metadata.showInAll : true,
|
|
249
|
+
createdDate: now,
|
|
250
|
+
lastModified: now,
|
|
251
|
+
pageVersion: typeof metadata.pageVersion === 'number' ? metadata.pageVersion
|
|
252
|
+
: typeof metadata.uxVersion === 'number' ? metadata.uxVersion : PAGE_VERSION,
|
|
253
|
+
mode: metadata.mode === 'locked' ? 'locked' : 'unlocked',
|
|
254
|
+
};
|
|
255
|
+
await sp.saveFile(path.join(pageFolder, 'page.json'), JSON.stringify(fullMetadata, null, 4));
|
|
256
|
+
|
|
257
|
+
// Copy data subfolders (anything that isn't page.html/page.json)
|
|
258
|
+
// Read from local fs, write via provider using cross-provider copy
|
|
259
|
+
const subEntries = await fs.readdir(srcPageDir, { withFileTypes: true });
|
|
260
|
+
for (const entry of subEntries) {
|
|
261
|
+
if (!entry.isDirectory()) continue;
|
|
262
|
+
await crossProviderCopyFolder(
|
|
263
|
+
path.join(srcPageDir, entry.name),
|
|
264
|
+
path.join(pageFolder, entry.name),
|
|
265
|
+
sp
|
|
266
|
+
);
|
|
224
267
|
}
|
|
225
268
|
}
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* Copy a folder from local filesystem to the storage provider.
|
|
274
|
+
* Reads from local fs, writes via provider.
|
|
275
|
+
*/
|
|
276
|
+
async function crossProviderCopyFolder(srcFolder: string, destFolder: string, sp: StorageProvider): Promise<void> {
|
|
277
|
+
await sp.ensureFolderExists(destFolder);
|
|
278
|
+
const entries = await fs.readdir(srcFolder, { withFileTypes: true });
|
|
279
|
+
for (const entry of entries) {
|
|
280
|
+
const srcPath = path.join(srcFolder, entry.name);
|
|
281
|
+
const destPath = path.join(destFolder, entry.name);
|
|
282
|
+
if (entry.isDirectory()) {
|
|
283
|
+
await crossProviderCopyFolder(srcPath, destPath, sp);
|
|
284
|
+
} else {
|
|
285
|
+
const data = await fs.readFile(srcPath);
|
|
286
|
+
await sp.saveBuffer(destPath, data);
|
|
287
|
+
}
|
|
238
288
|
}
|
|
239
289
|
}
|
package/src/migrations.ts
CHANGED
|
@@ -10,6 +10,7 @@ import { deduplicateInlineScripts } from './service/transformPage';
|
|
|
10
10
|
*/
|
|
11
11
|
const migrations: Record<number, (html: string, completePrompt: completePrompt) => Promise<string>> = {
|
|
12
12
|
1: migrateV1toV2,
|
|
13
|
+
2: migrateV2toV3,
|
|
13
14
|
};
|
|
14
15
|
|
|
15
16
|
/**
|
|
@@ -36,7 +37,6 @@ const SHARED_CSS_SELECTORS = [
|
|
|
36
37
|
'.chat-panel', '.chat-header', '.chat-messages',
|
|
37
38
|
'.chat-message', '.chat-message p', '.chat-message p strong', '.chat-message p code',
|
|
38
39
|
'.chat-message strong', '.chat-message pre', '.chat-message code', '.chat-message a',
|
|
39
|
-
'.link-group', '.link-group a', '.link-group a:hover',
|
|
40
40
|
'form',
|
|
41
41
|
'.chat-input', '.chat-input:focus', '.chat-input::placeholder', '.chat-input:disabled',
|
|
42
42
|
'.chat-submit', '.chat-submit:hover', '.chat-submit:active', '.chat-submit:disabled',
|
|
@@ -80,14 +80,8 @@ const DEFAULT_CHAT_PANEL = `
|
|
|
80
80
|
<div class="chat-messages" id="chatMessages">
|
|
81
81
|
<div class="chat-message"><p>Welcome! How can I help you?</p></div>
|
|
82
82
|
</div>
|
|
83
|
-
<div class="link-group">
|
|
84
|
-
<a href="#" id="saveLink">Save</a>
|
|
85
|
-
<a href="/pages" id="pagesLink">Pages</a>
|
|
86
|
-
<a href="#" id="resetLink">Reset</a>
|
|
87
|
-
</div>
|
|
88
83
|
<form action="/" method="POST" id="chatForm">
|
|
89
|
-
<
|
|
90
|
-
<button type="submit" class="chat-submit">Send</button>
|
|
84
|
+
<textarea class="chat-input" id="chatInput" name="message" rows="2" placeholder="Type a message..."></textarea>
|
|
91
85
|
</form>
|
|
92
86
|
</div>`;
|
|
93
87
|
|
|
@@ -125,6 +119,33 @@ async function migrateV1toV2(html: string, completePrompt: completePrompt): Prom
|
|
|
125
119
|
return migrated;
|
|
126
120
|
}
|
|
127
121
|
|
|
122
|
+
/**
|
|
123
|
+
* v2 -> v3: Cheerio-based migration (no LLM).
|
|
124
|
+
* - Removes .link-group div
|
|
125
|
+
* - Converts chat <input> to <textarea>
|
|
126
|
+
* - Removes .chat-submit button (v3 creates it dynamically)
|
|
127
|
+
*/
|
|
128
|
+
async function migrateV2toV3(html: string, _completePrompt: completePrompt): Promise<string> {
|
|
129
|
+
const $ = cheerio.load(html, { decodeEntities: false });
|
|
130
|
+
|
|
131
|
+
// 1. Remove .link-group div and its children
|
|
132
|
+
$('.link-group').remove();
|
|
133
|
+
|
|
134
|
+
// 2. Replace <input type="text" id="chatInput" ...> with <textarea>
|
|
135
|
+
const chatInput = $('input#chatInput, input.chat-input');
|
|
136
|
+
if (chatInput.length > 0) {
|
|
137
|
+
chatInput.replaceWith(
|
|
138
|
+
'<textarea class="chat-input" id="chatInput" name="message" rows="2" placeholder="Type a message..."></textarea>'
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// 3. Remove .chat-submit button inside #chatForm (or anywhere)
|
|
143
|
+
$('button.chat-submit').remove();
|
|
144
|
+
|
|
145
|
+
// Run through postProcessV2 to ensure structural integrity
|
|
146
|
+
return postProcessV2($.html());
|
|
147
|
+
}
|
|
148
|
+
|
|
128
149
|
/**
|
|
129
150
|
* Cheerio-based post-processing to verify the LLM output meets v2 requirements.
|
|
130
151
|
* Uses the original HTML as a fallback source for critical elements.
|
|
@@ -146,8 +167,7 @@ export function postProcessV2(html: string, originalHtml?: string): string {
|
|
|
146
167
|
// Append default form
|
|
147
168
|
$('.chat-panel').append(`
|
|
148
169
|
<form action="/" method="POST" id="chatForm">
|
|
149
|
-
<
|
|
150
|
-
<button type="submit" class="chat-submit">Send</button>
|
|
170
|
+
<textarea class="chat-input" id="chatInput" name="message" rows="2" placeholder="Type a message..."></textarea>
|
|
151
171
|
</form>`);
|
|
152
172
|
}
|
|
153
173
|
} else {
|