tycono 0.1.96-beta.25 → 0.1.96-beta.27

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.1.96-beta.25",
3
+ "version": "0.1.96-beta.27",
4
4
  "description": "Build an AI company. Watch them work.",
5
5
  "type": "module",
6
6
  "bin": {
package/src/tui/app.tsx CHANGED
@@ -244,7 +244,7 @@ export const App: React.FC = () => {
244
244
  const roles = api.company?.roles ?? [];
245
245
  const statuses = api.execStatus?.statuses ?? {};
246
246
  const orgTree = useMemo(() => buildOrgTree(roles, statuses), [roles, statuses]);
247
- const flatRoleIds = useMemo(() => flattenOrgRoleIds(orgTree), [orgTree]);
247
+ const flatRoleIds = useMemo(() => ['ceo', ...flattenOrgRoleIds(orgTree)], [orgTree]);
248
248
 
249
249
  // Active count
250
250
  const activeCount = Object.values(statuses).filter(
@@ -426,11 +426,11 @@ export const App: React.FC = () => {
426
426
  focusedWaveId={focusedWaveId}
427
427
  portSummary={api.portSummary}
428
428
  onMove={(dir) => {
429
- if (dir === 'up') {
430
- setSelectedRoleIndex(Math.max(0, selectedRoleIndex - 1));
431
- } else {
432
- setSelectedRoleIndex(Math.min(flatRoleIds.length - 1, selectedRoleIndex + 1));
433
- }
429
+ const nextIdx = dir === 'up'
430
+ ? Math.max(0, selectedRoleIndex - 1)
431
+ : Math.min(flatRoleIds.length - 1, selectedRoleIndex + 1);
432
+ setSelectedRoleIndex(nextIdx);
433
+ setSelectedRoleId(flatRoleIds[nextIdx] ?? null);
434
434
  }}
435
435
  onSelect={() => {
436
436
  const roleId = flatRoleIds[selectedRoleIndex] ?? null;
@@ -1,5 +1,6 @@
1
1
  /**
2
2
  * OrgTree — left panel showing organization hierarchy with real-time status
3
+ * CEO is now selectable (index 0 in flatRoles)
3
4
  */
4
5
 
5
6
  import React from 'react';
@@ -12,6 +13,7 @@ interface OrgTreeProps {
12
13
  focused: boolean;
13
14
  selectedIndex: number;
14
15
  flatRoles: string[];
16
+ ceoStatus?: string;
15
17
  }
16
18
 
17
19
  function statusColor(status: string): string {
@@ -46,10 +48,10 @@ function flattenTree(nodes: OrgNode[], prefix: string = '', isLast: boolean[] =
46
48
 
47
49
  let linePrefix = '';
48
50
  for (let j = 0; j < isLast.length; j++) {
49
- linePrefix += isLast[j] ? ' ' : ' ';
51
+ linePrefix += isLast[j] ? ' ' : '\u2502 ';
50
52
  }
51
53
  linePrefix += isLast.length > 0 || i > 0 || nodes.length > 1
52
- ? (last ? '└─ ' : '├─ ')
54
+ ? (last ? '\u2514\u2500 ' : '\u251C\u2500 ')
53
55
  : '';
54
56
 
55
57
  result.push({
@@ -67,14 +69,24 @@ function flattenTree(nodes: OrgNode[], prefix: string = '', isLast: boolean[] =
67
69
  return result;
68
70
  }
69
71
 
70
- export const OrgTree: React.FC<OrgTreeProps> = React.memo(({ tree, focused, selectedIndex, flatRoles }) => {
72
+ export const OrgTree: React.FC<OrgTreeProps> = React.memo(({ tree, focused, selectedIndex, flatRoles, ceoStatus }) => {
71
73
  const entries = flattenTree(tree);
74
+ const isCeoSelected = focused && flatRoles[selectedIndex] === 'ceo';
75
+ const ceoIcon = statusIcon(ceoStatus ?? 'idle');
76
+ const ceoColor = statusColor(ceoStatus ?? 'idle');
72
77
 
73
78
  return (
74
79
  <Box flexDirection="column" paddingX={1}>
75
- <Text bold color={focused ? 'cyan' : 'gray'}>{'── Org Tree ──'}</Text>
80
+ <Text bold color={focused ? 'cyan' : 'gray'}>{'\u2500\u2500 Org Tree \u2500\u2500'}</Text>
76
81
  <Box marginTop={1}>
77
- <Text color="yellow" bold>{'\uD83D\uDC51'} CEO</Text>
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>
78
90
  </Box>
79
91
  {entries.map((entry, i) => {
80
92
  const isSelected = focused && flatRoles[selectedIndex] === entry.roleId;
@@ -119,14 +119,6 @@ export const PanelMode: React.FC<PanelModeProps> = ({
119
119
  ? waves.findIndex(w => w.waveId === focusedWaveId) + 1
120
120
  : 0;
121
121
 
122
- // Count sessions per wave for summary
123
- const waveSessionCounts = new Map<string, number>();
124
- for (const s of activeSessions) {
125
- if (s.waveId) {
126
- waveSessionCounts.set(s.waveId, (waveSessionCounts.get(s.waveId) ?? 0) + 1);
127
- }
128
- }
129
-
130
122
  return (
131
123
  <Box flexDirection="column" flexGrow={1}>
132
124
  {/* Main content: Org Tree left | Detail + Stream right */}
@@ -138,38 +130,8 @@ export const PanelMode: React.FC<PanelModeProps> = ({
138
130
  focused={true}
139
131
  selectedIndex={selectedRoleIndex}
140
132
  flatRoles={flatRoles}
133
+ ceoStatus={activeSessions.some(s => s.roleId === 'ceo' && s.status === 'active') ? 'working' : 'idle'}
141
134
  />
142
-
143
- {/* Resource Summary — below org tree */}
144
- <Box flexDirection="column" paddingX={1} marginTop={1}>
145
- <Text color="gray">{'\u2500'.repeat(24)}</Text>
146
-
147
- {/* Waves */}
148
- {waves.length > 0 && (
149
- <Box flexDirection="column">
150
- {waves.map((w, i) => {
151
- const isFocused = w.waveId === focusedWaveId;
152
- const count = waveSessionCounts.get(w.waveId) ?? 0;
153
- return (
154
- <Box key={w.waveId}>
155
- <Text color={isFocused ? 'green' : 'gray'}>
156
- {isFocused ? '\u25B8' : ' '} W{i + 1}
157
- </Text>
158
- <Text color="gray"> {count > 0 ? `${count} agents` : 'idle'}</Text>
159
- </Box>
160
- );
161
- })}
162
- </Box>
163
- )}
164
-
165
- {/* Port summary */}
166
- {portSummary.totalPorts > 0 && (
167
- <Box marginTop={0}>
168
- <Text color="blue">{portSummary.totalPorts} ports</Text>
169
- <Text color="gray"> allocated</Text>
170
- </Box>
171
- )}
172
- </Box>
173
135
  </Box>
174
136
 
175
137
  {/* Vertical separator — memoized to avoid regenerating on every render */}