tycono 0.1.96-beta.26 → 0.1.96-beta.28

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.26",
3
+ "version": "0.1.96-beta.28",
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(
@@ -364,17 +364,16 @@ export const App: React.FC = () => {
364
364
  }
365
365
  }, [execute, addSystemMessage, addSystemLines, focusedWaveId, focusedWaveIndex, derivedWaveStatus, api.sessions.length, activeCount, waves, api.activeSessions, api.portSummary]);
366
366
 
367
- // Global key handler: Tab to toggle mode, Ctrl+C handling
367
+ // Global key handler: Tab to toggle mode, Ctrl+C always exits
368
368
  useInput((input, key) => {
369
- if (mode === 'command' && key.tab) {
370
- setMode('panel');
371
- return;
372
- }
373
- // Ctrl+C in command mode: exit
374
369
  if (key.ctrl && input === 'c') {
375
370
  exit();
371
+ return;
376
372
  }
377
- }, { isActive: mode === 'command' });
373
+ if (mode === 'command' && key.tab) {
374
+ setMode('panel');
375
+ }
376
+ });
378
377
 
379
378
  // Loading state
380
379
  if (view === 'loading') {
@@ -426,11 +425,11 @@ export const App: React.FC = () => {
426
425
  focusedWaveId={focusedWaveId}
427
426
  portSummary={api.portSummary}
428
427
  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
- }
428
+ const nextIdx = dir === 'up'
429
+ ? Math.max(0, selectedRoleIndex - 1)
430
+ : Math.min(flatRoleIds.length - 1, selectedRoleIndex + 1);
431
+ setSelectedRoleIndex(nextIdx);
432
+ setSelectedRoleId(flatRoleIds[nextIdx] ?? null);
434
433
  }}
435
434
  onSelect={() => {
436
435
  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;
@@ -130,6 +130,7 @@ export const PanelMode: React.FC<PanelModeProps> = ({
130
130
  focused={true}
131
131
  selectedIndex={selectedRoleIndex}
132
132
  flatRoles={flatRoles}
133
+ ceoStatus={activeSessions.some(s => s.roleId === 'ceo' && s.status === 'active') ? 'working' : 'idle'}
133
134
  />
134
135
  </Box>
135
136