tycono 0.1.96-beta.28 → 0.1.96-beta.29

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.28",
3
+ "version": "0.1.96-beta.29",
4
4
  "description": "Build an AI company. Watch them work.",
5
5
  "type": "module",
6
6
  "bin": {
package/src/tui/api.ts CHANGED
@@ -180,6 +180,14 @@ export async function fetchActiveSessions(): Promise<ActiveSessionsResponse> {
180
180
  return fetchJson<ActiveSessionsResponse>('/api/active-sessions');
181
181
  }
182
182
 
183
+ export async function killSession(sessionId: string): Promise<{ ok: boolean }> {
184
+ return fetchJson<{ ok: boolean }>(`/api/active-sessions/${sessionId}`, { method: 'DELETE' });
185
+ }
186
+
187
+ export async function cleanupSessions(): Promise<{ cleaned: number; remaining: number }> {
188
+ return fetchJson<{ cleaned: number; remaining: number }>('/api/active-sessions/cleanup', { method: 'POST' });
189
+ }
190
+
183
191
  /* ─── Setup API calls ─── */
184
192
 
185
193
  export interface TeamTemplate {
package/src/tui/app.tsx CHANGED
@@ -326,6 +326,28 @@ export const App: React.FC = () => {
326
326
  addSystemLines(lines);
327
327
  break;
328
328
  }
329
+ case 'sessions': {
330
+ if (api.activeSessions.length === 0) {
331
+ addSystemMessage('No active sessions.', 'gray');
332
+ } else {
333
+ addSystemMessage(`Sessions (${api.activeSessions.length}):`, 'cyan');
334
+ for (const s of api.activeSessions) {
335
+ const alive = s.alive === false ? ' DEAD' : s.pid ? ` PID:${s.pid}` : '';
336
+ const wave = s.waveId ? ` wave=${String(s.waveId).replace('wave-', 'W')}` : '';
337
+ addSystemMessage(
338
+ ` ${s.sessionId.slice(0, 25).padEnd(26)} ${s.roleId.padEnd(12)} API:${s.ports.api} ${s.status}${alive}${wave}`,
339
+ s.alive === false ? 'red' : s.status === 'active' ? 'green' : 'gray'
340
+ );
341
+ }
342
+ addSystemMessage(' /kill <sessionId> to stop | /cleanup to remove dead', 'gray');
343
+ }
344
+ break;
345
+ }
346
+ case 'cleanup': {
347
+ addSystemMessage(result.message, 'yellow');
348
+ api.refresh();
349
+ break;
350
+ }
329
351
  case 'error':
330
352
  addSystemMessage(result.message, 'red');
331
353
  break;
@@ -337,6 +359,9 @@ export const App: React.FC = () => {
337
359
  addSystemMessage(' /focus <n> Switch to wave n', 'white');
338
360
  addSystemMessage(' /agents Agent tree + resources', 'white');
339
361
  addSystemMessage(' /ports Port allocations', 'white');
362
+ addSystemMessage(' /sessions All sessions (kill/cleanup)', 'white');
363
+ addSystemMessage(' /kill <id> Kill a session', 'white');
364
+ addSystemMessage(' /cleanup Remove dead sessions', 'white');
340
365
  addSystemMessage(' /status Show current status', 'white');
341
366
  addSystemMessage(' /assign <role> <task> Assign task to role', 'white');
342
367
  addSystemMessage(' /roles Org tree (Panel Mode)', 'white');
@@ -16,7 +16,7 @@
16
16
  */
17
17
 
18
18
  import { useCallback } from 'react';
19
- import { dispatchWave, sendDirective, fetchJson } from '../api';
19
+ import { dispatchWave, sendDirective, fetchJson, killSession, cleanupSessions } from '../api';
20
20
 
21
21
  export interface WaveInfo {
22
22
  waveId: string;
@@ -25,7 +25,7 @@ export interface WaveInfo {
25
25
  }
26
26
 
27
27
  export interface CommandResult {
28
- type: 'success' | 'error' | 'info' | 'wave_started' | 'directive_sent' | 'stopped' | 'quit' | 'help' | 'panel' | 'waves_list' | 'focus_changed' | 'agents' | 'ports';
28
+ type: 'success' | 'error' | 'info' | 'wave_started' | 'directive_sent' | 'stopped' | 'quit' | 'help' | 'panel' | 'waves_list' | 'focus_changed' | 'agents' | 'ports' | 'sessions' | 'cleanup';
29
29
  message: string;
30
30
  waveId?: string;
31
31
  }
@@ -99,6 +99,30 @@ export function useCommand(options: UseCommandOptions) {
99
99
  case 'ports':
100
100
  return { type: 'ports', message: '__ports__' };
101
101
 
102
+ case 'sessions':
103
+ return { type: 'sessions', message: '__sessions__' };
104
+
105
+ case 'kill': {
106
+ if (!args) {
107
+ return { type: 'error', message: 'Usage: /kill <sessionId>' };
108
+ }
109
+ try {
110
+ await killSession(args);
111
+ return { type: 'success', message: `Session ${args} killed` };
112
+ } catch (err) {
113
+ return { type: 'error', message: `Kill failed: ${err instanceof Error ? err.message : 'unknown'}` };
114
+ }
115
+ }
116
+
117
+ case 'cleanup': {
118
+ try {
119
+ const result = await cleanupSessions();
120
+ return { type: 'cleanup', message: `Cleaned ${result.cleaned} dead sessions. ${result.remaining} remaining.` };
121
+ } catch (err) {
122
+ return { type: 'error', message: `Cleanup failed: ${err instanceof Error ? err.message : 'unknown'}` };
123
+ }
124
+ }
125
+
102
126
  case 'status':
103
127
  return { type: 'info', message: '__status__' };
104
128