tycono 0.3.14-beta.1 → 0.3.14-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,16 +1,21 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* presets.ts — Preset API routes
|
|
3
3
|
*
|
|
4
|
-
* GET
|
|
5
|
-
* GET
|
|
4
|
+
* GET /api/presets — list all preset summaries
|
|
5
|
+
* GET /api/presets/:id — get full preset detail
|
|
6
|
+
* POST /api/presets/install — install preset from data
|
|
7
|
+
* DELETE /api/presets/:id — remove installed preset
|
|
6
8
|
*/
|
|
7
9
|
import { Router } from 'express';
|
|
10
|
+
import fs from 'node:fs';
|
|
11
|
+
import path from 'node:path';
|
|
12
|
+
import YAML from 'yaml';
|
|
8
13
|
import { COMPANY_ROOT } from '../services/file-reader.js';
|
|
9
|
-
import { getPresetSummaries, getPresetById } from '../services/preset-loader.js';
|
|
14
|
+
import { getPresetSummaries, getPresetById, loadPresets } from '../services/preset-loader.js';
|
|
10
15
|
|
|
11
16
|
export const presetsRouter = Router();
|
|
12
17
|
|
|
13
|
-
/** GET /api/presets — list preset summaries
|
|
18
|
+
/** GET /api/presets — list preset summaries */
|
|
14
19
|
presetsRouter.get('/', (_req, res) => {
|
|
15
20
|
try {
|
|
16
21
|
const summaries = getPresetSummaries(COMPANY_ROOT);
|
|
@@ -33,3 +38,86 @@ presetsRouter.get('/:id', (req, res) => {
|
|
|
33
38
|
res.status(500).json({ error: 'Failed to load preset' });
|
|
34
39
|
}
|
|
35
40
|
});
|
|
41
|
+
|
|
42
|
+
/** POST /api/presets/install — install a preset from provided data */
|
|
43
|
+
presetsRouter.post('/install', (req, res) => {
|
|
44
|
+
try {
|
|
45
|
+
const { id, preset } = req.body as { id: string; preset: Record<string, unknown> };
|
|
46
|
+
if (!id || !preset) {
|
|
47
|
+
res.status(400).json({ error: 'id and preset are required' });
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Validate preset has required fields
|
|
52
|
+
if (!preset.name || !preset.roles || !Array.isArray(preset.roles)) {
|
|
53
|
+
res.status(400).json({ error: 'preset must have name and roles array' });
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Check for conflict with existing preset
|
|
58
|
+
const existing = getPresetById(COMPANY_ROOT, id);
|
|
59
|
+
if (existing && !existing.isDefault) {
|
|
60
|
+
res.status(409).json({ error: `Preset already installed: ${id}` });
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Create preset directory and write preset.yaml
|
|
65
|
+
const presetDir = path.join(COMPANY_ROOT, 'company', 'presets', id);
|
|
66
|
+
fs.mkdirSync(presetDir, { recursive: true });
|
|
67
|
+
|
|
68
|
+
// Write preset.yaml
|
|
69
|
+
const yamlContent = YAML.stringify(preset);
|
|
70
|
+
fs.writeFileSync(path.join(presetDir, 'preset.yaml'), yamlContent);
|
|
71
|
+
|
|
72
|
+
// Create subdirectories for roles/knowledge/skills
|
|
73
|
+
fs.mkdirSync(path.join(presetDir, 'roles'), { recursive: true });
|
|
74
|
+
fs.mkdirSync(path.join(presetDir, 'knowledge'), { recursive: true });
|
|
75
|
+
fs.mkdirSync(path.join(presetDir, 'skills'), { recursive: true });
|
|
76
|
+
|
|
77
|
+
// Write knowledge docs if provided
|
|
78
|
+
const knowledge = req.body.knowledge as Array<{ filename: string; content: string }> | undefined;
|
|
79
|
+
if (knowledge) {
|
|
80
|
+
for (const doc of knowledge) {
|
|
81
|
+
fs.writeFileSync(path.join(presetDir, 'knowledge', doc.filename), doc.content);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Write role yamls if provided
|
|
86
|
+
const roleDefinitions = req.body.roleDefinitions as Array<{ id: string; yaml: string }> | undefined;
|
|
87
|
+
if (roleDefinitions) {
|
|
88
|
+
for (const role of roleDefinitions) {
|
|
89
|
+
const roleDir = path.join(presetDir, 'roles', role.id);
|
|
90
|
+
fs.mkdirSync(roleDir, { recursive: true });
|
|
91
|
+
fs.writeFileSync(path.join(roleDir, 'role.yaml'), role.yaml);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
res.json({ ok: true, id, path: `company/presets/${id}` });
|
|
96
|
+
} catch (err) {
|
|
97
|
+
res.status(500).json({ error: `Install failed: ${err instanceof Error ? err.message : 'unknown'}` });
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
/** DELETE /api/presets/:id — remove installed preset */
|
|
102
|
+
presetsRouter.delete('/:id', (req, res) => {
|
|
103
|
+
try {
|
|
104
|
+
const { id } = req.params;
|
|
105
|
+
if (id === 'default' || id === '_default') {
|
|
106
|
+
res.status(400).json({ error: 'Cannot remove default preset' });
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const presetDir = path.join(COMPANY_ROOT, 'company', 'presets', id);
|
|
111
|
+
if (!fs.existsSync(presetDir)) {
|
|
112
|
+
res.status(404).json({ error: `Preset not found: ${id}` });
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Remove preset directory recursively
|
|
117
|
+
fs.rmSync(presetDir, { recursive: true, force: true });
|
|
118
|
+
|
|
119
|
+
res.json({ ok: true, id });
|
|
120
|
+
} catch (err) {
|
|
121
|
+
res.status(500).json({ error: `Remove failed: ${err instanceof Error ? err.message : 'unknown'}` });
|
|
122
|
+
}
|
|
123
|
+
});
|
|
@@ -724,8 +724,8 @@ Your job: monitor progress, course-correct if needed, wait for completion, then
|
|
|
724
724
|
console.log(`[ExecMgr] Supervision recovery: ${deadExecution.roleId} died with ${runningChildren.length} running children. Restarting.`);
|
|
725
725
|
|
|
726
726
|
// Propagate waveId from the dead session
|
|
727
|
-
const
|
|
728
|
-
const waveId =
|
|
727
|
+
const deadSes = getSession(deadExecution.sessionId);
|
|
728
|
+
const waveId = deadSes?.waveId;
|
|
729
729
|
|
|
730
730
|
// Create new session for recovery
|
|
731
731
|
const newSession = createSession(deadExecution.roleId, {
|