tycono 0.1.107-beta.0 → 0.1.107-beta.2
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/tui/api.ts +13 -0
- package/src/tui/app.tsx +40 -5
- package/src/tui/hooks/useApi.ts +23 -3
package/package.json
CHANGED
package/src/tui/api.ts
CHANGED
|
@@ -159,6 +159,19 @@ export async function fetchActiveWaves(): Promise<{ waves: Array<{ waveId: strin
|
|
|
159
159
|
return fetchJson('/api/waves/active');
|
|
160
160
|
}
|
|
161
161
|
|
|
162
|
+
export interface PastWaveInfo {
|
|
163
|
+
id: string;
|
|
164
|
+
directive: string;
|
|
165
|
+
rolesCount: number;
|
|
166
|
+
startedAt: string;
|
|
167
|
+
sessionIds?: string[];
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
export async function fetchPastWaves(limit = 20): Promise<PastWaveInfo[]> {
|
|
171
|
+
const all = await fetchJson<PastWaveInfo[]>('/api/operations/waves');
|
|
172
|
+
return all.slice(0, limit);
|
|
173
|
+
}
|
|
174
|
+
|
|
162
175
|
/* ─── Active Sessions (port/worktree visibility) ─── */
|
|
163
176
|
|
|
164
177
|
export interface ActiveSessionInfo {
|
package/src/tui/app.tsx
CHANGED
|
@@ -263,17 +263,53 @@ export const App: React.FC = () => {
|
|
|
263
263
|
if (view !== 'dashboard' || autoWaveCreated.current) return;
|
|
264
264
|
|
|
265
265
|
if (api.activeWaves.length > 0) {
|
|
266
|
-
// Attach to existing waves from API
|
|
266
|
+
// Attach to existing active waves from API
|
|
267
267
|
const apiWaves: WaveInfo[] = api.activeWaves.map(w => ({
|
|
268
268
|
waveId: w.waveId,
|
|
269
269
|
directive: w.directive ?? '',
|
|
270
270
|
startedAt: w.startedAt ?? Date.now(),
|
|
271
271
|
}));
|
|
272
|
-
|
|
272
|
+
|
|
273
|
+
// Also append past waves (completed) that aren't already in active list
|
|
274
|
+
const activeIds = new Set(apiWaves.map(w => w.waveId));
|
|
275
|
+
const pastEntries: WaveInfo[] = api.pastWaves
|
|
276
|
+
.filter(pw => !activeIds.has(pw.id))
|
|
277
|
+
.slice(0, 10)
|
|
278
|
+
.map(pw => ({
|
|
279
|
+
waveId: pw.id,
|
|
280
|
+
directive: pw.directive || '',
|
|
281
|
+
startedAt: pw.startedAt ? new Date(pw.startedAt).getTime() : 0,
|
|
282
|
+
}));
|
|
283
|
+
|
|
284
|
+
const allWaves = [...pastEntries, ...apiWaves];
|
|
285
|
+
setWaves(allWaves);
|
|
273
286
|
setFocusedWaveId(apiWaves[apiWaves.length - 1].waveId);
|
|
274
287
|
autoWaveCreated.current = true;
|
|
288
|
+
} else if (api.loaded && api.pastWaves.length > 0) {
|
|
289
|
+
// No active waves, but past waves exist — load them + create a new one
|
|
290
|
+
autoWaveCreated.current = true;
|
|
291
|
+
const pastEntries: WaveInfo[] = api.pastWaves.slice(0, 10).map(pw => ({
|
|
292
|
+
waveId: pw.id,
|
|
293
|
+
directive: pw.directive || '',
|
|
294
|
+
startedAt: pw.startedAt ? new Date(pw.startedAt).getTime() : 0,
|
|
295
|
+
}));
|
|
296
|
+
|
|
297
|
+
dispatchWave().then(result => {
|
|
298
|
+
const newWave: WaveInfo = {
|
|
299
|
+
waveId: result.waveId,
|
|
300
|
+
directive: '',
|
|
301
|
+
startedAt: Date.now(),
|
|
302
|
+
};
|
|
303
|
+
setWaves([...pastEntries, newWave]);
|
|
304
|
+
setFocusedWaveId(result.waveId);
|
|
305
|
+
}).catch(() => {
|
|
306
|
+
// Even if new wave fails, show past waves
|
|
307
|
+
setWaves(pastEntries);
|
|
308
|
+
setFocusedWaveId(pastEntries[pastEntries.length - 1]?.waveId ?? null);
|
|
309
|
+
autoWaveCreated.current = true;
|
|
310
|
+
});
|
|
275
311
|
} else if (api.loaded) {
|
|
276
|
-
//
|
|
312
|
+
// No active waves, no past waves — fresh start
|
|
277
313
|
autoWaveCreated.current = true;
|
|
278
314
|
dispatchWave().then(result => {
|
|
279
315
|
const newWave: WaveInfo = {
|
|
@@ -284,11 +320,10 @@ export const App: React.FC = () => {
|
|
|
284
320
|
setWaves([newWave]);
|
|
285
321
|
setFocusedWaveId(result.waveId);
|
|
286
322
|
}).catch(() => {
|
|
287
|
-
// If empty wave creation fails, still proceed — user can /new
|
|
288
323
|
autoWaveCreated.current = true;
|
|
289
324
|
});
|
|
290
325
|
}
|
|
291
|
-
}, [view, api.activeWaves, api.loaded]);
|
|
326
|
+
}, [view, api.activeWaves, api.pastWaves, api.loaded]);
|
|
292
327
|
|
|
293
328
|
// SSE subscription to focused wave
|
|
294
329
|
const sse = useSSE(focusedWaveId);
|
package/src/tui/hooks/useApi.ts
CHANGED
|
@@ -10,11 +10,13 @@ import {
|
|
|
10
10
|
fetchActiveWaves,
|
|
11
11
|
fetchActiveSessions,
|
|
12
12
|
fetchKnowledgeDocs,
|
|
13
|
+
fetchPastWaves,
|
|
13
14
|
type CompanyInfo,
|
|
14
15
|
type SessionInfo,
|
|
15
16
|
type ExecStatus,
|
|
16
17
|
type ActiveSessionInfo,
|
|
17
18
|
type KnowledgeDoc,
|
|
19
|
+
type PastWaveInfo,
|
|
18
20
|
} from '../api';
|
|
19
21
|
|
|
20
22
|
const POLL_INTERVAL = 5000; // 5 seconds (reduce re-renders)
|
|
@@ -31,6 +33,7 @@ export interface ApiState {
|
|
|
31
33
|
sessions: SessionInfo[];
|
|
32
34
|
execStatus: ExecStatus | null;
|
|
33
35
|
activeWaves: ActiveWaveInfo[];
|
|
36
|
+
pastWaves: PastWaveInfo[];
|
|
34
37
|
activeSessions: ActiveSessionInfo[];
|
|
35
38
|
portSummary: { active: number; totalPorts: number };
|
|
36
39
|
knowledgeDocs: KnowledgeDoc[];
|
|
@@ -44,6 +47,8 @@ export function useApi(): ApiState {
|
|
|
44
47
|
const [sessions, setSessions] = useState<SessionInfo[]>([]);
|
|
45
48
|
const [execStatus, setExecStatus] = useState<ExecStatus | null>(null);
|
|
46
49
|
const [activeWaves, setActiveWaves] = useState<ActiveWaveInfo[]>([]);
|
|
50
|
+
const [pastWaves, setPastWaves] = useState<PastWaveInfo[]>([]);
|
|
51
|
+
const pastWavesLoadedRef = useRef(false);
|
|
47
52
|
const [activeSessions, setActiveSessions] = useState<ActiveSessionInfo[]>([]);
|
|
48
53
|
const [portSummary, setPortSummary] = useState<{ active: number; totalPorts: number }>({ active: 0, totalPorts: 0 });
|
|
49
54
|
const [knowledgeDocs, setKnowledgeDocs] = useState<KnowledgeDoc[]>([]);
|
|
@@ -54,13 +59,22 @@ export function useApi(): ApiState {
|
|
|
54
59
|
|
|
55
60
|
const refresh = useCallback(async () => {
|
|
56
61
|
try {
|
|
57
|
-
const
|
|
62
|
+
const promises: [
|
|
63
|
+
Promise<CompanyInfo | null>,
|
|
64
|
+
Promise<SessionInfo[]>,
|
|
65
|
+
Promise<ExecStatus | null>,
|
|
66
|
+
Promise<{ waves: Array<{ waveId: string; sessionIds: string[] }> }>,
|
|
67
|
+
Promise<{ sessions: ActiveSessionInfo[]; summary: { active: number; totalPorts: number } }>,
|
|
68
|
+
Promise<PastWaveInfo[]>,
|
|
69
|
+
] = [
|
|
58
70
|
fetchCompany().catch(() => null),
|
|
59
71
|
fetchSessions().catch(() => []),
|
|
60
72
|
fetchExecStatus().catch(() => null),
|
|
61
73
|
fetchActiveWaves().catch(() => ({ waves: [] })),
|
|
62
74
|
fetchActiveSessions().catch(() => ({ sessions: [], summary: { active: 0, totalPorts: 0 } })),
|
|
63
|
-
|
|
75
|
+
!pastWavesLoadedRef.current ? fetchPastWaves(20).catch(() => []) : Promise.resolve([]),
|
|
76
|
+
];
|
|
77
|
+
const [comp, sess, exec, waves, activeSess, pastWavesResult] = await Promise.all(promises);
|
|
64
78
|
|
|
65
79
|
if (!mountedRef.current) return;
|
|
66
80
|
|
|
@@ -80,6 +94,12 @@ export function useApi(): ApiState {
|
|
|
80
94
|
setActiveSessions(activeSess.sessions ?? []);
|
|
81
95
|
setPortSummary(activeSess.summary ?? { active: 0, totalPorts: 0 });
|
|
82
96
|
|
|
97
|
+
// Past waves (load once, included in Promise.all)
|
|
98
|
+
if (!pastWavesLoadedRef.current && pastWavesResult.length > 0) {
|
|
99
|
+
pastWavesLoadedRef.current = true;
|
|
100
|
+
setPastWaves(pastWavesResult);
|
|
101
|
+
}
|
|
102
|
+
|
|
83
103
|
// KB docs (load once, not every poll)
|
|
84
104
|
if (!kbLoadedRef.current) {
|
|
85
105
|
kbLoadedRef.current = true;
|
|
@@ -108,5 +128,5 @@ export function useApi(): ApiState {
|
|
|
108
128
|
};
|
|
109
129
|
}, [refresh]);
|
|
110
130
|
|
|
111
|
-
return { company, sessions, execStatus, activeWaves, activeSessions, portSummary, knowledgeDocs, error, loaded, refresh };
|
|
131
|
+
return { company, sessions, execStatus, activeWaves, pastWaves, activeSessions, portSummary, knowledgeDocs, error, loaded, refresh };
|
|
112
132
|
}
|