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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tycono",
3
- "version": "0.3.14-beta.2",
3
+ "version": "0.3.14-beta.20",
4
4
  "description": "Build an AI company. Watch them work.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -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" height={termHeight}>
673
- <Box flexGrow={1} flexDirection="column">
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 with real-time status
3
- * CEO is now selectable (index 0 in flatRoles)
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 statusColor(status: string): string {
20
- switch (status) {
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
- linePrefix += isLast[j] ? ' ' : '\u2502 ';
26
+ prefix += isLast[j] ? ' ' : '\u2502 ';
52
27
  }
53
- linePrefix += isLast.length > 0 || i > 0 || nodes.length > 1
54
- ? (last ? '\u2514\u2500 ' : '\u251C\u2500 ')
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, '', [...isLast, last]));
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 ceoColor = statusColor(ceoStatus ?? 'idle');
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
- <Box marginTop={1}>
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
  });