tycono-server 0.1.0-beta.1 → 0.1.0-beta.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tycono-server",
3
- "version": "0.1.0-beta.1",
3
+ "version": "0.1.0-beta.2",
4
4
  "description": "Tycono AI team orchestration server. Dispatch, supervise, and observe AI agents working as a team.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -9,6 +9,7 @@
9
9
  */
10
10
  import fs from 'node:fs';
11
11
  import path from 'node:path';
12
+ import { execSync } from 'node:child_process';
12
13
  import YAML from 'yaml';
13
14
  import type { PresetDefinition, LoadedPreset, PresetSummary } from '../../../shared/types.js';
14
15
 
@@ -123,6 +124,19 @@ export function loadPresets(companyRoot: string): LoadedPreset[] {
123
124
  }
124
125
  }
125
126
 
127
+ // 3. Bundled presets (shipped with tycono-server, fallback if not in user's project)
128
+ const bundledPresetsDir = path.resolve(__dirname, '../../../../presets');
129
+ if (fs.existsSync(bundledPresetsDir)) {
130
+ const loadedIds = new Set(presets.map(p => p.definition.id));
131
+ const entries = fs.readdirSync(bundledPresetsDir, { withFileTypes: true });
132
+ for (const entry of entries) {
133
+ if (!entry.isDirectory()) continue;
134
+ if (loadedIds.has(entry.name)) continue; // user's preset takes priority
135
+ const preset = loadPresetFromDir(path.join(bundledPresetsDir, entry.name));
136
+ if (preset) presets.push(preset);
137
+ }
138
+ }
139
+
126
140
  return presets;
127
141
  }
128
142
 
@@ -142,8 +156,58 @@ export function getPresetSummaries(companyRoot: string): PresetSummary[] {
142
156
 
143
157
  /**
144
158
  * Find a specific preset by ID.
159
+ * Falls back to remote download from tycono.ai if not found locally.
145
160
  */
146
161
  export function getPresetById(companyRoot: string, presetId: string): LoadedPreset | null {
147
162
  const presets = loadPresets(companyRoot);
148
- return presets.find(p => p.definition.id === presetId) ?? null;
163
+ const local = presets.find(p => p.definition.id === presetId);
164
+ if (local) return local;
165
+
166
+ // Try downloading from tycono.ai preset registry
167
+ const downloaded = downloadPreset(companyRoot, presetId);
168
+ return downloaded;
169
+ }
170
+
171
+ /**
172
+ * Download a preset from the remote registry (tycono.ai).
173
+ * Saves to knowledge/presets/{id}/ for future use.
174
+ */
175
+ function downloadPreset(companyRoot: string, presetId: string): LoadedPreset | null {
176
+ const REGISTRY_URL = process.env.TYCONO_PRESET_REGISTRY || 'https://tycono.ai/api/presets';
177
+
178
+ try {
179
+ // Synchronous HTTP request (preset download is a blocking init step)
180
+ const response = execSync(
181
+ `curl -s --max-time 10 "${REGISTRY_URL}/${presetId}/download"`,
182
+ { encoding: 'utf-8' },
183
+ );
184
+
185
+ const data = JSON.parse(response);
186
+ if (!data.preset || !data.files) return null;
187
+
188
+ // Save to local presets directory
189
+ const targetDir = path.join(companyRoot, PRESETS_DIR, presetId);
190
+ fs.mkdirSync(targetDir, { recursive: true });
191
+
192
+ // Write preset.yaml
193
+ fs.writeFileSync(
194
+ path.join(targetDir, 'preset.yaml'),
195
+ YAML.stringify(data.preset),
196
+ );
197
+
198
+ // Write knowledge files
199
+ if (data.files && typeof data.files === 'object') {
200
+ for (const [filePath, content] of Object.entries(data.files)) {
201
+ const fullPath = path.join(targetDir, filePath);
202
+ fs.mkdirSync(path.dirname(fullPath), { recursive: true });
203
+ fs.writeFileSync(fullPath, content as string);
204
+ }
205
+ }
206
+
207
+ console.log(`[Preset] Downloaded "${presetId}" from ${REGISTRY_URL}`);
208
+ return loadPresetFromDir(targetDir);
209
+ } catch (err) {
210
+ console.warn(`[Preset] Failed to download "${presetId}": ${(err as Error).message}`);
211
+ return null;
212
+ }
149
213
  }