synthos 0.5.0 → 0.7.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 +33 -1
- package/default-pages/app_builder.html +40 -0
- package/default-pages/app_builder.json +1 -0
- package/default-pages/json_tools.html +89 -159
- package/default-pages/json_tools.json +1 -0
- package/default-pages/my_notes.html +33 -0
- package/default-pages/my_notes.json +12 -0
- package/default-pages/neon_asteroids.html +77 -0
- package/default-pages/neon_asteroids.json +12 -0
- package/default-pages/sidebar_builder.html +49 -0
- package/default-pages/sidebar_builder.json +1 -0
- package/default-pages/solar_explorer.html +1956 -0
- package/default-pages/solar_explorer.json +12 -0
- package/default-pages/solar_tutorial.html +476 -0
- package/default-pages/solar_tutorial.json +1 -0
- package/default-pages/two-panel_builder.html +66 -0
- package/default-pages/two-panel_builder.json +1 -0
- package/dist/connectors/index.d.ts +3 -0
- package/dist/connectors/index.d.ts.map +1 -0
- package/dist/connectors/index.js +6 -0
- package/dist/connectors/index.js.map +1 -0
- package/dist/connectors/registry.d.ts +3 -0
- package/dist/connectors/registry.d.ts.map +1 -0
- package/dist/connectors/registry.js +100 -0
- package/dist/connectors/registry.js.map +1 -0
- package/dist/connectors/types.d.ts +61 -0
- package/dist/connectors/types.d.ts.map +1 -0
- package/dist/connectors/types.js +3 -0
- package/dist/connectors/types.js.map +1 -0
- package/dist/files.d.ts +2 -0
- package/dist/files.d.ts.map +1 -1
- package/dist/files.js +12 -1
- package/dist/files.js.map +1 -1
- package/dist/init.d.ts +8 -1
- package/dist/init.d.ts.map +1 -1
- package/dist/init.js +155 -3
- package/dist/init.js.map +1 -1
- package/dist/migrations.d.ts +11 -0
- package/dist/migrations.d.ts.map +1 -0
- package/dist/migrations.js +281 -0
- package/dist/migrations.js.map +1 -0
- package/dist/models/index.d.ts +3 -0
- package/dist/models/index.d.ts.map +1 -0
- package/dist/models/index.js +10 -0
- package/dist/models/index.js.map +1 -0
- package/dist/models/providers.d.ts +7 -0
- package/dist/models/providers.d.ts.map +1 -0
- package/dist/models/providers.js +33 -0
- package/dist/models/providers.js.map +1 -0
- package/dist/models/types.d.ts +21 -0
- package/dist/models/types.d.ts.map +1 -0
- package/dist/models/types.js +3 -0
- package/dist/models/types.js.map +1 -0
- package/dist/pages.d.ts +21 -2
- package/dist/pages.d.ts.map +1 -1
- package/dist/pages.js +202 -23
- package/dist/pages.js.map +1 -1
- package/dist/scripts.js +2 -2
- package/dist/scripts.js.map +1 -1
- package/dist/service/createCompletePrompt.d.ts +3 -2
- package/dist/service/createCompletePrompt.d.ts.map +1 -1
- package/dist/service/createCompletePrompt.js +11 -16
- package/dist/service/createCompletePrompt.js.map +1 -1
- package/dist/service/debugLog.d.ts +11 -0
- package/dist/service/debugLog.d.ts.map +1 -0
- package/dist/service/debugLog.js +26 -0
- package/dist/service/debugLog.js.map +1 -0
- package/dist/service/modelInstructions.d.ts +7 -0
- package/dist/service/modelInstructions.d.ts.map +1 -0
- package/dist/service/modelInstructions.js +16 -0
- package/dist/service/modelInstructions.js.map +1 -0
- package/dist/service/requiresSettings.d.ts +2 -2
- package/dist/service/requiresSettings.d.ts.map +1 -1
- package/dist/service/requiresSettings.js.map +1 -1
- package/dist/service/server.d.ts.map +1 -1
- package/dist/service/server.js +15 -0
- package/dist/service/server.js.map +1 -1
- package/dist/service/transformPage.d.ts +81 -2
- package/dist/service/transformPage.d.ts.map +1 -1
- package/dist/service/transformPage.js +672 -82
- package/dist/service/transformPage.js.map +1 -1
- package/dist/service/useApiRoutes.d.ts.map +1 -1
- package/dist/service/useApiRoutes.js +579 -13
- package/dist/service/useApiRoutes.js.map +1 -1
- package/dist/service/useConnectorRoutes.d.ts +4 -0
- package/dist/service/useConnectorRoutes.d.ts.map +1 -0
- package/dist/service/useConnectorRoutes.js +389 -0
- package/dist/service/useConnectorRoutes.js.map +1 -0
- package/dist/service/useDataRoutes.d.ts.map +1 -1
- package/dist/service/useDataRoutes.js +83 -70
- package/dist/service/useDataRoutes.js.map +1 -1
- package/dist/service/usePageRoutes.d.ts.map +1 -1
- package/dist/service/usePageRoutes.js +243 -38
- package/dist/service/usePageRoutes.js.map +1 -1
- package/dist/settings.d.ts +33 -4
- package/dist/settings.d.ts.map +1 -1
- package/dist/settings.js +108 -15
- package/dist/settings.js.map +1 -1
- package/dist/synthos-cli.d.ts.map +1 -1
- package/dist/synthos-cli.js +11 -1
- package/dist/synthos-cli.js.map +1 -1
- package/dist/themes.d.ts +9 -0
- package/dist/themes.d.ts.map +1 -0
- package/dist/themes.js +64 -0
- package/dist/themes.js.map +1 -0
- package/package.json +5 -3
- package/required-pages/builder.html +74 -0
- package/required-pages/builder.json +1 -0
- package/required-pages/pages.html +169 -126
- package/required-pages/pages.json +1 -0
- package/required-pages/settings.html +812 -156
- package/required-pages/settings.json +1 -0
- package/required-pages/synthos_apis.html +272 -0
- package/required-pages/synthos_apis.json +1 -0
- package/required-pages/synthos_scripts.html +87 -0
- package/required-pages/synthos_scripts.json +1 -0
- package/src/connectors/index.ts +12 -0
- package/src/connectors/registry.ts +98 -0
- package/src/connectors/types.ts +68 -0
- package/src/files.ts +11 -0
- package/src/init.ts +151 -5
- package/src/migrations.ts +266 -0
- package/src/models/index.ts +2 -0
- package/src/models/providers.ts +33 -0
- package/src/models/types.ts +23 -0
- package/src/pages.ts +234 -26
- package/src/scripts.ts +2 -2
- package/src/service/createCompletePrompt.ts +14 -18
- package/src/service/debugLog.ts +17 -0
- package/src/service/modelInstructions.ts +14 -0
- package/src/service/requiresSettings.ts +3 -3
- package/src/service/server.ts +19 -2
- package/src/service/transformPage.ts +709 -88
- package/src/service/useApiRoutes.ts +632 -16
- package/src/service/useConnectorRoutes.ts +427 -0
- package/src/service/useDataRoutes.ts +87 -71
- package/src/service/usePageRoutes.ts +237 -44
- package/src/settings.ts +143 -20
- package/src/synthos-cli.ts +11 -1
- package/src/themes.ts +71 -0
- package/default-pages/[application].html +0 -95
- package/default-pages/[markdown].html +0 -271
- package/default-pages/[sidebar].html +0 -114
- package/default-pages/[split-application].html +0 -118
- package/default-pages/solar_system.html +0 -432
- package/default-pages/space_invaders.html +0 -617
- package/required-pages/apis.html +0 -362
- package/required-pages/home.html +0 -126
- package/required-pages/scripts.html +0 -350
package/src/pages.ts
CHANGED
|
@@ -1,41 +1,174 @@
|
|
|
1
|
-
import {checkIfExists, listFiles, loadFile, saveFile} from './files';
|
|
1
|
+
import {checkIfExists, deleteFile, deleteFolder, ensureFolderExists, listFiles, listFolders, loadFile, saveFile} from './files';
|
|
2
2
|
import path from 'path';
|
|
3
3
|
|
|
4
4
|
// Page State Cache
|
|
5
5
|
const _pages: { [name: string]: string } = {};
|
|
6
6
|
|
|
7
|
-
export
|
|
8
|
-
// Load all pages from primary pages folder
|
|
9
|
-
const all = (await listFiles(pagesFolder)).filter(file => file.endsWith('.html'));
|
|
7
|
+
export const REQUIRED_PAGES = ['builder', 'pages', 'settings', 'apis', 'scripts'];
|
|
10
8
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
9
|
+
export const PAGE_VERSION = 2;
|
|
10
|
+
|
|
11
|
+
export interface PageInfo {
|
|
12
|
+
name: string;
|
|
13
|
+
title: string;
|
|
14
|
+
categories: string[];
|
|
15
|
+
pinned: boolean;
|
|
16
|
+
showInAll: boolean; // true = visible in "All" filter, false = only in category filters
|
|
17
|
+
createdDate: string; // ISO 8601, empty string if unknown
|
|
18
|
+
lastModified: string; // ISO 8601, empty string if unknown
|
|
19
|
+
pageVersion: number; // integer, 0 = pre-versioning
|
|
20
|
+
mode: 'unlocked' | 'locked';
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export type PageMetadata = Omit<PageInfo, 'name'>;
|
|
24
|
+
|
|
25
|
+
export async function loadPageMetadata(pagesFolder: string, name: string, fallbackFolder?: string): Promise<PageMetadata | undefined> {
|
|
26
|
+
// 1. Try user override: .synthos/pages/<name>/page.json
|
|
27
|
+
const metadataPath = path.join(pagesFolder, 'pages', name, 'page.json');
|
|
28
|
+
if (await checkIfExists(metadataPath)) {
|
|
29
|
+
try {
|
|
30
|
+
const raw = await loadFile(metadataPath);
|
|
31
|
+
const parsed = JSON.parse(raw);
|
|
32
|
+
return parseMetadata(parsed);
|
|
33
|
+
} catch {
|
|
34
|
+
// fall through
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// 2. Try fallback: fallbackFolder/<name>.json
|
|
39
|
+
if (fallbackFolder) {
|
|
40
|
+
const fallbackPath = path.join(fallbackFolder, `${name}.json`);
|
|
41
|
+
if (await checkIfExists(fallbackPath)) {
|
|
42
|
+
try {
|
|
43
|
+
const raw = await loadFile(fallbackPath);
|
|
44
|
+
const parsed = JSON.parse(raw);
|
|
45
|
+
return parseMetadata(parsed);
|
|
46
|
+
} catch {
|
|
47
|
+
// fall through
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return undefined;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function parseMetadata(parsed: Record<string, unknown>): PageMetadata {
|
|
56
|
+
return {
|
|
57
|
+
title: typeof parsed.title === 'string' ? parsed.title : '',
|
|
58
|
+
categories: Array.isArray(parsed.categories) ? parsed.categories : [],
|
|
59
|
+
pinned: typeof parsed.pinned === 'boolean' ? parsed.pinned : false,
|
|
60
|
+
showInAll: typeof parsed.showInAll === 'boolean' ? parsed.showInAll : true,
|
|
61
|
+
createdDate: typeof parsed.createdDate === 'string' ? parsed.createdDate : '',
|
|
62
|
+
lastModified: typeof parsed.lastModified === 'string' ? parsed.lastModified : '',
|
|
63
|
+
pageVersion: typeof parsed.pageVersion === 'number' ? parsed.pageVersion
|
|
64
|
+
: typeof parsed.uxVersion === 'number' ? parsed.uxVersion : 0,
|
|
65
|
+
mode: parsed.mode === 'locked' ? 'locked' : 'unlocked',
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export async function savePageMetadata(pagesFolder: string, name: string, metadata: PageMetadata): Promise<void> {
|
|
70
|
+
const pageFolder = path.join(pagesFolder, 'pages', name);
|
|
71
|
+
await ensureFolderExists(pageFolder);
|
|
72
|
+
await saveFile(path.join(pageFolder, 'page.json'), JSON.stringify(metadata, null, 4));
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const DEFAULT_METADATA: PageMetadata = {
|
|
76
|
+
title: '',
|
|
77
|
+
categories: [],
|
|
78
|
+
pinned: false,
|
|
79
|
+
showInAll: true,
|
|
80
|
+
createdDate: '',
|
|
81
|
+
lastModified: '',
|
|
82
|
+
pageVersion: 0,
|
|
83
|
+
mode: 'unlocked',
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
export async function listPages(pagesFolder: string, fallbackPagesFolder: string): Promise<PageInfo[]> {
|
|
87
|
+
const pageMap = new Map<string, PageInfo>();
|
|
88
|
+
|
|
89
|
+
// Folder-based pages under pages/ subdirectory
|
|
90
|
+
const pagesSubdir = path.join(pagesFolder, 'pages');
|
|
91
|
+
if (await checkIfExists(pagesSubdir)) {
|
|
92
|
+
const folders = await listFolders(pagesSubdir);
|
|
93
|
+
for (const folder of folders) {
|
|
94
|
+
if (await checkIfExists(path.join(pagesSubdir, folder, 'page.html'))) {
|
|
95
|
+
const metadata = await loadPageMetadata(pagesFolder, folder);
|
|
96
|
+
pageMap.set(folder, {
|
|
97
|
+
name: folder,
|
|
98
|
+
...(metadata ?? DEFAULT_METADATA),
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Legacy flat .html files in root (v1 pages)
|
|
105
|
+
const flatFiles = (await listFiles(pagesFolder)).filter(file => file.endsWith('.html'));
|
|
106
|
+
for (const file of flatFiles) {
|
|
107
|
+
const name = file.replace(/\.html$/, '');
|
|
108
|
+
if (!pageMap.has(name)) {
|
|
109
|
+
// Derive title: strip brackets, replace underscores with spaces, title-case
|
|
110
|
+
const stripped = name.replace(/^\[/, '').replace(/\]$/, '');
|
|
111
|
+
const title = stripped
|
|
112
|
+
.replace(/_/g, ' ')
|
|
113
|
+
.replace(/\b\w/g, c => c.toUpperCase());
|
|
114
|
+
// Assign category: bracketed names → "Builder", otherwise → "Page"
|
|
115
|
+
const hasBrackets = name.startsWith('[') && name.endsWith(']');
|
|
116
|
+
const categories = hasBrackets ? ['Builder'] : ['Page'];
|
|
117
|
+
pageMap.set(name, {
|
|
118
|
+
name,
|
|
119
|
+
title,
|
|
120
|
+
categories,
|
|
121
|
+
pinned: false,
|
|
122
|
+
showInAll: true,
|
|
123
|
+
createdDate: '',
|
|
124
|
+
lastModified: '',
|
|
125
|
+
pageVersion: 1,
|
|
126
|
+
mode: 'unlocked',
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Add pages from fallback (required) pages folder
|
|
132
|
+
const fallbackFiles = (await listFiles(fallbackPagesFolder)).filter(file => file.endsWith('.html'));
|
|
133
|
+
for (const file of fallbackFiles) {
|
|
134
|
+
const name = file.replace(/\.html$/, '');
|
|
135
|
+
if (!pageMap.has(name)) {
|
|
136
|
+
// System page not yet in map — check for user override, then fallback .json
|
|
137
|
+
const metadata = await loadPageMetadata(pagesFolder, name, fallbackPagesFolder);
|
|
138
|
+
pageMap.set(name, {
|
|
139
|
+
name,
|
|
140
|
+
title: metadata?.title ?? '',
|
|
141
|
+
categories: metadata?.categories ?? ['System'],
|
|
142
|
+
pinned: metadata?.pinned ?? true,
|
|
143
|
+
showInAll: metadata?.showInAll ?? true,
|
|
144
|
+
createdDate: metadata?.createdDate ?? '',
|
|
145
|
+
lastModified: metadata?.lastModified ?? '',
|
|
146
|
+
pageVersion: metadata?.pageVersion ?? 0,
|
|
147
|
+
mode: metadata?.mode ?? 'unlocked',
|
|
148
|
+
});
|
|
15
149
|
}
|
|
16
|
-
}
|
|
150
|
+
}
|
|
17
151
|
|
|
18
|
-
//
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
// Move [templates] to end of array
|
|
22
|
-
const pages = sorted.filter(page => !page.startsWith('['));
|
|
23
|
-
const templates = sorted.filter(page => page.startsWith('['));
|
|
24
|
-
pages.push(...templates);
|
|
152
|
+
// Sort alphabetically
|
|
153
|
+
const entries = Array.from(pageMap.values());
|
|
154
|
+
entries.sort((a, b) => a.name.localeCompare(b.name));
|
|
25
155
|
|
|
26
|
-
return
|
|
156
|
+
return entries;
|
|
27
157
|
}
|
|
28
158
|
|
|
29
159
|
export async function loadPageState(pagesFolder: string, name: string, reset: boolean): Promise<string|undefined> {
|
|
30
160
|
if (!_pages[name] || reset) {
|
|
31
|
-
//
|
|
32
|
-
const
|
|
33
|
-
|
|
161
|
+
// Try folder-based path under pages/ first, then fall back to flat file
|
|
162
|
+
const folderPath = path.join(pagesFolder, 'pages', name, 'page.html');
|
|
163
|
+
const flatPath = path.join(pagesFolder, `${name}.html`);
|
|
164
|
+
|
|
165
|
+
if (await checkIfExists(folderPath)) {
|
|
166
|
+
_pages[name] = await loadFile(folderPath);
|
|
167
|
+
} else if (await checkIfExists(flatPath)) {
|
|
168
|
+
_pages[name] = await loadFile(flatPath);
|
|
169
|
+
} else {
|
|
34
170
|
return undefined;
|
|
35
171
|
}
|
|
36
|
-
|
|
37
|
-
// Load file
|
|
38
|
-
_pages[name] = await loadFile(filename);
|
|
39
172
|
}
|
|
40
173
|
|
|
41
174
|
return _pages[name];
|
|
@@ -45,11 +178,86 @@ export function normalizePageName(name: string|undefined): string|undefined {
|
|
|
45
178
|
return typeof name == 'string' && name.length > 0 ? name.replace(/[^a-z0-9\-_\[\]\(\)\{\}@#\$%&]/gi, '_').toLowerCase() : undefined;
|
|
46
179
|
}
|
|
47
180
|
|
|
48
|
-
export async function savePageState(pagesFolder: string, name: string, content: string): Promise<void> {
|
|
181
|
+
export async function savePageState(pagesFolder: string, name: string, content: string, title?: string, categories?: string[]): Promise<void> {
|
|
49
182
|
_pages[name] = content;
|
|
50
|
-
|
|
183
|
+
const pageFolder = path.join(pagesFolder, 'pages', name);
|
|
184
|
+
await ensureFolderExists(pageFolder);
|
|
185
|
+
await saveFile(path.join(pageFolder, 'page.html'), content);
|
|
186
|
+
|
|
187
|
+
// Create page.json with full metadata if it doesn't exist
|
|
188
|
+
const metadataPath = path.join(pageFolder, 'page.json');
|
|
189
|
+
if (!(await checkIfExists(metadataPath))) {
|
|
190
|
+
const now = new Date().toISOString();
|
|
191
|
+
const metadata: PageMetadata = {
|
|
192
|
+
title: title ?? '',
|
|
193
|
+
categories: categories ?? [],
|
|
194
|
+
pinned: false,
|
|
195
|
+
showInAll: true,
|
|
196
|
+
createdDate: now,
|
|
197
|
+
lastModified: now,
|
|
198
|
+
pageVersion: PAGE_VERSION,
|
|
199
|
+
mode: 'unlocked',
|
|
200
|
+
};
|
|
201
|
+
await saveFile(metadataPath, JSON.stringify(metadata, null, 4));
|
|
202
|
+
}
|
|
51
203
|
}
|
|
52
204
|
|
|
53
205
|
export function updatePageState(name: string, content: string): void {
|
|
54
206
|
_pages[name] = content;
|
|
55
|
-
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
export async function deletePage(pagesFolder: string, name: string): Promise<void> {
|
|
210
|
+
// Delete folder-based page: <pagesFolder>/pages/<name>/
|
|
211
|
+
const folderPath = path.join(pagesFolder, 'pages', name);
|
|
212
|
+
if (await checkIfExists(folderPath)) {
|
|
213
|
+
await deleteFolder(folderPath);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// Delete legacy flat file: <pagesFolder>/<name>.html
|
|
217
|
+
const flatPath = path.join(pagesFolder, `${name}.html`);
|
|
218
|
+
if (await checkIfExists(flatPath)) {
|
|
219
|
+
await deleteFile(flatPath);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// Clear in-memory cache
|
|
223
|
+
delete _pages[name];
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
export async function copyPage(
|
|
227
|
+
pagesFolder: string,
|
|
228
|
+
sourceName: string,
|
|
229
|
+
targetName: string,
|
|
230
|
+
title: string,
|
|
231
|
+
categories: string[],
|
|
232
|
+
requiredPagesFolder: string
|
|
233
|
+
): Promise<void> {
|
|
234
|
+
// Load source HTML from user folder, then try required folder as fallback
|
|
235
|
+
let html = await loadPageState(pagesFolder, sourceName, true);
|
|
236
|
+
if (!html) {
|
|
237
|
+
const requiredPath = path.join(requiredPagesFolder, `${sourceName}.html`);
|
|
238
|
+
if (await checkIfExists(requiredPath)) {
|
|
239
|
+
html = await loadFile(requiredPath);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
if (!html) {
|
|
244
|
+
throw new Error(`Source page "${sourceName}" not found`);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// Save HTML to target (creates folder + page.html + page.json)
|
|
248
|
+
await savePageState(pagesFolder, targetName, html, title);
|
|
249
|
+
|
|
250
|
+
// Overwrite the generated metadata with provided title + categories
|
|
251
|
+
const now = new Date().toISOString();
|
|
252
|
+
const metadata: PageMetadata = {
|
|
253
|
+
title,
|
|
254
|
+
categories,
|
|
255
|
+
pinned: false,
|
|
256
|
+
showInAll: true,
|
|
257
|
+
createdDate: now,
|
|
258
|
+
lastModified: now,
|
|
259
|
+
pageVersion: PAGE_VERSION,
|
|
260
|
+
mode: 'unlocked',
|
|
261
|
+
};
|
|
262
|
+
await savePageMetadata(pagesFolder, targetName, metadata);
|
|
263
|
+
}
|
package/src/scripts.ts
CHANGED
|
@@ -17,7 +17,7 @@ export interface ExecuteScriptResponse {
|
|
|
17
17
|
export async function listScripts(pagesFolder: string): Promise<string> {
|
|
18
18
|
if (!scriptsList) {
|
|
19
19
|
let list: string[] = [];
|
|
20
|
-
const folder = path.join(pagesFolder, 'scripts');
|
|
20
|
+
const folder = path.join(pagesFolder, 'pages', 'scripts', 'scripts');
|
|
21
21
|
if (await checkIfExists(folder)) {
|
|
22
22
|
const files = (await listFiles(folder)).filter(f => f.endsWith('.json'));
|
|
23
23
|
for (const file of files) {
|
|
@@ -52,7 +52,7 @@ export async function executeScript(args: ExecuteScriptArgs): Promise<AgentCompl
|
|
|
52
52
|
const { pagesFolder, scriptId, variables } = args;
|
|
53
53
|
|
|
54
54
|
// Load the script
|
|
55
|
-
const script = await loadFile(path.join(pagesFolder,
|
|
55
|
+
const script = await loadFile(path.join(pagesFolder, 'pages', 'scripts', 'scripts', `${scriptId}.json`));
|
|
56
56
|
if (!script) {
|
|
57
57
|
return { completed: false, error: new Error(`Script not found: ${scriptId}`) };
|
|
58
58
|
}
|
|
@@ -1,41 +1,37 @@
|
|
|
1
1
|
import {anthropic, completePrompt, logCompletePrompt, openai} from 'agentm-core';
|
|
2
|
-
import { loadSettings } from '../settings';
|
|
2
|
+
import { getModelEntry, loadSettings } from '../settings';
|
|
3
|
+
import { PROVIDERS } from '../models';
|
|
3
4
|
|
|
4
|
-
export
|
|
5
|
-
'claude-opus-4-5',
|
|
6
|
-
'Claude Sonnet 4.5',
|
|
7
|
-
'Claude Haiku 4.5',
|
|
8
|
-
'GPT-5.2',
|
|
9
|
-
'GPT-5 mini',
|
|
10
|
-
'GPT-5 nano'
|
|
11
|
-
];
|
|
12
|
-
|
|
13
|
-
export async function createCompletePrompt(pagesFolder: string, model?: string): Promise<completePrompt> {
|
|
5
|
+
export async function createCompletePrompt(pagesFolder: string, use: 'builder' | 'chat', modelOverride?: string): Promise<completePrompt> {
|
|
14
6
|
// Get configuration settings
|
|
15
7
|
const settings = await loadSettings(pagesFolder);
|
|
16
|
-
|
|
17
|
-
|
|
8
|
+
const entry = getModelEntry(settings, use);
|
|
9
|
+
|
|
10
|
+
if (!entry.configuration.apiKey) {
|
|
11
|
+
throw new Error('API key not configured');
|
|
18
12
|
}
|
|
19
13
|
|
|
20
14
|
// Validate model
|
|
21
|
-
model =
|
|
15
|
+
const model = modelOverride || entry.configuration.model;
|
|
22
16
|
if (!model) {
|
|
23
17
|
throw new Error('Model not configured');
|
|
24
18
|
}
|
|
25
19
|
|
|
26
20
|
// Create completion functions
|
|
27
21
|
let modelInstance: completePrompt;
|
|
28
|
-
const apiKey =
|
|
29
|
-
if (
|
|
22
|
+
const apiKey = entry.configuration.apiKey;
|
|
23
|
+
if (entry.provider === 'Anthropic') {
|
|
30
24
|
modelInstance = anthropic({apiKey, model});
|
|
31
25
|
} else {
|
|
32
26
|
modelInstance = openai({apiKey, model});
|
|
33
27
|
}
|
|
34
28
|
|
|
35
29
|
// Return new model instance
|
|
36
|
-
if (
|
|
30
|
+
if (entry.logCompletions) {
|
|
37
31
|
return logCompletePrompt(modelInstance, true);
|
|
38
32
|
} else {
|
|
39
33
|
return modelInstance;
|
|
40
34
|
}
|
|
41
|
-
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export { PROVIDERS };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// ANSI color helpers — no external dependency
|
|
2
|
+
export const reset = '\x1b[0m';
|
|
3
|
+
export const cyan = (s: string): string => `\x1b[36m${s}${reset}`;
|
|
4
|
+
export const yellow = (s: string): string => `\x1b[33m${s}${reset}`;
|
|
5
|
+
export const green = (s: string): string => `\x1b[32m${s}${reset}`;
|
|
6
|
+
export const red = (s: string): string => `\x1b[31m${s}${reset}`;
|
|
7
|
+
export const dim = (s: string): string => `\x1b[2m${s}${reset}`;
|
|
8
|
+
|
|
9
|
+
/** Format milliseconds as `X.XXXs` */
|
|
10
|
+
export function formatTime(ms: number): string {
|
|
11
|
+
return `${(ms / 1000).toFixed(3)}s`;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/** Rough token estimate based on chars / 4 heuristic */
|
|
15
|
+
export function estimateTokens(chars: number): number {
|
|
16
|
+
return Math.ceil(chars / 4);
|
|
17
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { ProviderName } from '../models';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Returns provider-specific prompt instructions for how the model should
|
|
5
|
+
* format its change-list response.
|
|
6
|
+
*/
|
|
7
|
+
export function getModelInstructions(provider: ProviderName): string {
|
|
8
|
+
if (provider === 'Anthropic') {
|
|
9
|
+
return `Return ONLY the JSON array of change operations. Do not wrap it in markdown code fences or add any other text.`;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// OpenAI and other providers
|
|
13
|
+
return `Return ONLY the JSON array of change operations. Do not wrap it in markdown code fences or add any other text.`;
|
|
14
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { hasConfiguredSettings, loadSettings,
|
|
1
|
+
import { hasConfiguredSettings, loadSettings, SettingsV2 } from "../settings";
|
|
2
2
|
|
|
3
3
|
|
|
4
|
-
export async function requiresSettings(res: any, folder: string, cb: (settings:
|
|
4
|
+
export async function requiresSettings(res: any, folder: string, cb: (settings: SettingsV2) => Promise<void>) {
|
|
5
5
|
try {
|
|
6
6
|
// Ensure settings configured
|
|
7
7
|
const isConfigured = await hasConfiguredSettings(folder);
|
|
@@ -19,4 +19,4 @@ export async function requiresSettings(res: any, folder: string, cb: (settings:
|
|
|
19
19
|
console.error(err);
|
|
20
20
|
res.status(500).send((err as Error).message);
|
|
21
21
|
}
|
|
22
|
-
}
|
|
22
|
+
}
|
package/src/service/server.ts
CHANGED
|
@@ -3,10 +3,24 @@ import { usePageRoutes } from './usePageRoutes';
|
|
|
3
3
|
import { useApiRoutes } from './useApiRoutes';
|
|
4
4
|
import { SynthOSConfig } from '../init';
|
|
5
5
|
import { useDataRoutes } from './useDataRoutes';
|
|
6
|
+
import { useConnectorRoutes } from './useConnectorRoutes';
|
|
7
|
+
import { cyan, yellow, formatTime } from './debugLog';
|
|
6
8
|
|
|
7
9
|
export function server(config: SynthOSConfig): Application {
|
|
8
10
|
const app = express();
|
|
9
|
-
|
|
11
|
+
|
|
12
|
+
// Debug request-logging middleware
|
|
13
|
+
if (config.debug) {
|
|
14
|
+
app.use((req, res, next) => {
|
|
15
|
+
const start = Date.now();
|
|
16
|
+
res.on('finish', () => {
|
|
17
|
+
const ms = Date.now() - start;
|
|
18
|
+
console.log(`${cyan(req.method + ' ' + req.originalUrl)} → ${res.statusCode} ${yellow('(' + formatTime(ms) + ')')}`);
|
|
19
|
+
});
|
|
20
|
+
next();
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
|
|
10
24
|
// Middleware to parse URL-encoded data (form data)
|
|
11
25
|
app.use(express.urlencoded({ extended: true }));
|
|
12
26
|
|
|
@@ -19,8 +33,11 @@ export function server(config: SynthOSConfig): Application {
|
|
|
19
33
|
// API routes
|
|
20
34
|
useApiRoutes(config, app);
|
|
21
35
|
|
|
36
|
+
// Connector routes
|
|
37
|
+
useConnectorRoutes(config, app);
|
|
38
|
+
|
|
22
39
|
// Data routes
|
|
23
40
|
useDataRoutes(config, app);
|
|
24
|
-
|
|
41
|
+
|
|
25
42
|
return app;
|
|
26
43
|
}
|