tycono 0.3.14-beta.2 → 0.3.14-beta.20
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 +1 -1
- package/src/api/src/create-server.ts +2 -0
- package/src/api/src/services/execution-manager.ts +2 -1
- package/src/api/src/services/supervisor-heartbeat.ts +4 -1
- package/src/tui/app.tsx +4 -2
- package/src/tui/components/OrgTree.tsx +15 -82
- package/src/tui/components/PanelMode.tsx +210 -473
- package/src/tui/components/StreamView.tsx +45 -113
- package/src/web/dist/assets/index-C6r_vHBI.js +138 -0
- package/src/web/dist/assets/{index-uwS0YSTU.js → index-Czp8wshq.js} +1 -1
- package/src/web/dist/assets/index-DVKWFwwK.css +1 -0
- package/src/web/dist/assets/{preview-app-CAohaHWp.js → preview-app-CMGFfqT-.js} +1 -1
- package/src/web/dist/index.html +2 -2
- package/src/web/dist/assets/index-A3-TBmWZ.js +0 -138
- package/src/web/dist/assets/index-D1RTvnx7.css +0 -1
package/package.json
CHANGED
|
@@ -33,6 +33,7 @@ import { questsRouter } from './routes/quests.js';
|
|
|
33
33
|
import { coinsRouter } from './routes/coins.js';
|
|
34
34
|
import { activeSessionsRouter } from './routes/active-sessions.js';
|
|
35
35
|
import { supervisionRouter } from './routes/supervision.js';
|
|
36
|
+
import { presetsRouter } from './routes/presets.js';
|
|
36
37
|
import { importKnowledge } from './services/knowledge-importer.js';
|
|
37
38
|
import { AnthropicProvider, type LLMProvider } from './engine/llm-adapter.js';
|
|
38
39
|
import { readConfig } from './services/company-config.js';
|
|
@@ -212,6 +213,7 @@ export function createExpressApp(): express.Application {
|
|
|
212
213
|
app.use('/api/coins', coinsRouter);
|
|
213
214
|
app.use('/api/active-sessions', activeSessionsRouter);
|
|
214
215
|
app.use('/api/supervision', supervisionRouter);
|
|
216
|
+
app.use('/api/presets', presetsRouter);
|
|
215
217
|
|
|
216
218
|
app.get('/api/health', (_req, res) => {
|
|
217
219
|
res.json({ status: 'ok', companyRoot: COMPANY_ROOT });
|
|
@@ -180,7 +180,7 @@ class ExecutionManager {
|
|
|
180
180
|
|
|
181
181
|
this.executions.set(execId, execution);
|
|
182
182
|
|
|
183
|
-
this.initializeAndRunExecution(execution, params, orgTree);
|
|
183
|
+
this.initializeAndRunExecution(execution, params, orgTree, presetId);
|
|
184
184
|
|
|
185
185
|
return execution;
|
|
186
186
|
}
|
|
@@ -189,6 +189,7 @@ class ExecutionManager {
|
|
|
189
189
|
execution: Execution,
|
|
190
190
|
params: StartExecutionParams,
|
|
191
191
|
orgTree: ReturnType<typeof buildOrgTree>,
|
|
192
|
+
presetId?: string,
|
|
192
193
|
): Promise<void> {
|
|
193
194
|
try {
|
|
194
195
|
const ports = await portRegistry.allocate(execution.sessionId || execution.id, params.roleId, params.task);
|
|
@@ -172,13 +172,15 @@ class SupervisorHeartbeat {
|
|
|
172
172
|
const waveSessions = listSessions().filter(s => s.waveId === waveId);
|
|
173
173
|
const ceoSession = waveSessions.find(s => s.roleId === 'ceo') ?? null;
|
|
174
174
|
|
|
175
|
-
// Read original directive from wave artifact file
|
|
175
|
+
// Read original directive + preset from wave artifact file
|
|
176
176
|
let originalDirective = '';
|
|
177
|
+
let originalPreset: string | undefined;
|
|
177
178
|
try {
|
|
178
179
|
const waveFile = path.join(COMPANY_ROOT, 'operations', 'waves', `${waveId}.json`);
|
|
179
180
|
if (fs.existsSync(waveFile)) {
|
|
180
181
|
const waveData = JSON.parse(fs.readFileSync(waveFile, 'utf-8'));
|
|
181
182
|
originalDirective = waveData.directive ?? '';
|
|
183
|
+
originalPreset = waveData.preset;
|
|
182
184
|
}
|
|
183
185
|
} catch { /* ignore */ }
|
|
184
186
|
|
|
@@ -188,6 +190,7 @@ class SupervisorHeartbeat {
|
|
|
188
190
|
waveId,
|
|
189
191
|
directive: originalDirective || text,
|
|
190
192
|
continuous: false,
|
|
193
|
+
preset: originalPreset,
|
|
191
194
|
supervisorSessionId: ceoSession?.id ?? null,
|
|
192
195
|
executionId: null,
|
|
193
196
|
status: 'stopped',
|
package/src/tui/app.tsx
CHANGED
|
@@ -630,6 +630,8 @@ export const App: React.FC = () => {
|
|
|
630
630
|
return;
|
|
631
631
|
}
|
|
632
632
|
if (mode === 'command' && key.tab) {
|
|
633
|
+
// Clear terminal before Panel Mode (removes Command Mode scrollback)
|
|
634
|
+
process.stdout.write('\x1b[2J\x1b[H');
|
|
633
635
|
setMode('panel');
|
|
634
636
|
}
|
|
635
637
|
});
|
|
@@ -669,8 +671,8 @@ export const App: React.FC = () => {
|
|
|
669
671
|
// Panel Mode: fullscreen (intentional — like vim for inspection)
|
|
670
672
|
if (mode === 'panel') {
|
|
671
673
|
return (
|
|
672
|
-
<Box flexDirection="column"
|
|
673
|
-
<Box
|
|
674
|
+
<Box flexDirection="column">
|
|
675
|
+
<Box flexDirection="column">
|
|
674
676
|
<PanelMode
|
|
675
677
|
tree={orgTree}
|
|
676
678
|
flatRoles={flatRoleIds}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* OrgTree — left panel showing organization hierarchy
|
|
3
|
-
*
|
|
2
|
+
* OrgTree — left panel showing organization hierarchy
|
|
3
|
+
* Simplified to single Text render to prevent yoga OOM on wide terminals
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import React from 'react';
|
|
@@ -16,103 +16,36 @@ interface OrgTreeProps {
|
|
|
16
16
|
ceoStatus?: string;
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
function
|
|
20
|
-
|
|
21
|
-
case 'working':
|
|
22
|
-
case 'streaming':
|
|
23
|
-
return 'green';
|
|
24
|
-
case 'done':
|
|
25
|
-
return 'gray';
|
|
26
|
-
case 'error':
|
|
27
|
-
return 'red';
|
|
28
|
-
case 'awaiting_input':
|
|
29
|
-
return 'yellow';
|
|
30
|
-
default:
|
|
31
|
-
return 'gray';
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
interface FlatEntry {
|
|
36
|
-
roleId: string;
|
|
37
|
-
level: string;
|
|
38
|
-
status: string;
|
|
39
|
-
prefix: string;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
function flattenTree(nodes: OrgNode[], prefix: string = '', isLast: boolean[] = []): FlatEntry[] {
|
|
43
|
-
const result: FlatEntry[] = [];
|
|
44
|
-
|
|
19
|
+
function flattenTree(nodes: OrgNode[], isLast: boolean[] = []): Array<{ roleId: string; status: string; line: string }> {
|
|
20
|
+
const result: Array<{ roleId: string; status: string; line: string }> = [];
|
|
45
21
|
for (let i = 0; i < nodes.length; i++) {
|
|
46
22
|
const node = nodes[i];
|
|
47
23
|
const last = i === nodes.length - 1;
|
|
48
|
-
|
|
49
|
-
let linePrefix = '';
|
|
24
|
+
let prefix = '';
|
|
50
25
|
for (let j = 0; j < isLast.length; j++) {
|
|
51
|
-
|
|
26
|
+
prefix += isLast[j] ? ' ' : '\u2502 ';
|
|
52
27
|
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
result.push({
|
|
58
|
-
roleId: node.role.id,
|
|
59
|
-
level: node.role.level,
|
|
60
|
-
status: node.status,
|
|
61
|
-
prefix: linePrefix,
|
|
62
|
-
});
|
|
63
|
-
|
|
28
|
+
prefix += last ? '\u2514\u2500 ' : '\u251C\u2500 ';
|
|
29
|
+
const icon = statusIcon(node.status);
|
|
30
|
+
result.push({ roleId: node.role.id, status: node.status, line: `${prefix}${icon} ${node.role.id}` });
|
|
64
31
|
if (node.children.length > 0) {
|
|
65
|
-
result.push(...flattenTree(node.children,
|
|
32
|
+
result.push(...flattenTree(node.children, [...isLast, last]));
|
|
66
33
|
}
|
|
67
34
|
}
|
|
68
|
-
|
|
69
35
|
return result;
|
|
70
36
|
}
|
|
71
37
|
|
|
72
38
|
export const OrgTree: React.FC<OrgTreeProps> = React.memo(({ tree, focused, selectedIndex, flatRoles, ceoStatus }) => {
|
|
73
|
-
const entries = flattenTree(tree);
|
|
74
|
-
const isCeoSelected = focused && flatRoles[selectedIndex] === 'ceo';
|
|
75
39
|
const ceoIcon = statusIcon(ceoStatus ?? 'idle');
|
|
76
|
-
const
|
|
40
|
+
const entries = flattenTree(tree);
|
|
41
|
+
|
|
42
|
+
// Render entire tree as single Text block (1 yoga node instead of 50+)
|
|
43
|
+
const lines = [`${ceoIcon} CEO`, ...entries.map(e => e.line)];
|
|
77
44
|
|
|
78
45
|
return (
|
|
79
46
|
<Box flexDirection="column" paddingX={1}>
|
|
80
47
|
<Text bold color={focused ? 'cyan' : 'gray'}>{'\u2500\u2500 Org Tree \u2500\u2500'}</Text>
|
|
81
|
-
<
|
|
82
|
-
<Text color={ceoColor} bold={ceoStatus === 'working'}>{ceoIcon} </Text>
|
|
83
|
-
<Text
|
|
84
|
-
color={isCeoSelected ? 'cyan' : 'yellow'}
|
|
85
|
-
bold={isCeoSelected}
|
|
86
|
-
inverse={isCeoSelected}
|
|
87
|
-
>
|
|
88
|
-
CEO
|
|
89
|
-
</Text>
|
|
90
|
-
</Box>
|
|
91
|
-
{entries.map((entry, i) => {
|
|
92
|
-
const isSelected = focused && flatRoles[selectedIndex] === entry.roleId;
|
|
93
|
-
const icon = statusIcon(entry.status);
|
|
94
|
-
const color = statusColor(entry.status);
|
|
95
|
-
|
|
96
|
-
return (
|
|
97
|
-
<Box key={entry.roleId + '-' + i}>
|
|
98
|
-
<Text color="gray">{entry.prefix}</Text>
|
|
99
|
-
<Text
|
|
100
|
-
color={color}
|
|
101
|
-
bold={entry.status === 'working'}
|
|
102
|
-
>
|
|
103
|
-
{icon}
|
|
104
|
-
</Text>
|
|
105
|
-
<Text> </Text>
|
|
106
|
-
<Text
|
|
107
|
-
color={isSelected ? 'cyan' : 'white'}
|
|
108
|
-
bold={isSelected}
|
|
109
|
-
inverse={isSelected}
|
|
110
|
-
>
|
|
111
|
-
{entry.roleId}
|
|
112
|
-
</Text>
|
|
113
|
-
</Box>
|
|
114
|
-
);
|
|
115
|
-
})}
|
|
48
|
+
<Text color="white">{'\n' + lines.join('\n')}</Text>
|
|
116
49
|
</Box>
|
|
117
50
|
);
|
|
118
51
|
});
|