tycono 0.3.17 → 0.3.19

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.17",
3
+ "version": "0.3.19",
4
4
  "description": "Build an AI company. Watch them work.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -95,7 +95,6 @@ class WaveMultiplexer {
95
95
  const allEvents: { event: ActivityEvent; sessionId: string }[] = [];
96
96
  for (const exec of recentSessions) {
97
97
  const events = ActivityStream.readFrom(exec.sessionId, 0);
98
- // Take last N events per session
99
98
  const recent = events.slice(-50);
100
99
  for (const event of recent) {
101
100
  allEvents.push({ event, sessionId: exec.sessionId });
@@ -159,7 +158,7 @@ class WaveMultiplexer {
159
158
  });
160
159
 
161
160
  const events = ActivityStream.readFrom(execution.sessionId, 0);
162
- const recentEvents = events.slice(-50); // Cap replay per session
161
+ const recentEvents = events.slice(-50);
163
162
  for (const event of recentEvents) {
164
163
  const key = `${event.roleId}:${event.seq}`;
165
164
  if (client.sentEvents.has(key)) continue;
@@ -306,15 +306,25 @@ export const CommandMode: React.FC<CommandModeProps> = ({
306
306
  const [quickBarIndex, setQuickBarIndex] = useState(0);
307
307
  const [acIndex, setAcIndex] = useState(0);
308
308
 
309
- // Convert events to stream lines (collapse consecutive thinking from same role)
309
+ // Convert events to stream lines (collapse duplicates from session reuse)
310
310
  const eventLines: StreamLine[] = [];
311
+ const seenDone = new Set<string>(); // dedup msg:done per role
311
312
  for (let i = 0; i < events.length; i++) {
312
313
  const event = events[i];
313
- // Skip thinking events if next event from same role is also thinking
314
+ // Skip consecutive thinking from same role
314
315
  if (event.type === 'thinking' && i + 1 < events.length) {
315
316
  const next = events[i + 1];
316
317
  if (next.type === 'thinking' && next.roleId === event.roleId) continue;
317
318
  }
319
+ // Dedup msg:done — only show last one per role (session reuse causes duplicates)
320
+ if (event.type === 'msg:done') {
321
+ const key = `${event.roleId}:done`;
322
+ if (seenDone.has(key)) continue;
323
+ // Check if there's a later msg:done from same role — skip this one
324
+ const hasLater = events.slice(i + 1).some(e => e.type === 'msg:done' && e.roleId === event.roleId);
325
+ if (hasLater) continue;
326
+ seenDone.add(key);
327
+ }
318
328
  const line = summarizeEvent(event, allRoleIds);
319
329
  if (line) eventLines.push(line);
320
330
  }
@@ -216,7 +216,12 @@ const PanelModeInner: React.FC<PanelModeProps> = ({
216
216
  if (activeRoleId) rightContentLines.push(`\u25B8 ${activeRoleId}`);
217
217
  const maxEv = Math.max(5, contentHeight - 3);
218
218
  const filtered = activeRoleId ? events.filter(e => e.roleId === activeRoleId) : events;
219
- const visible = filtered.slice(-maxEv);
219
+ // Dedup msg:done — only show last one per role (session reuse causes duplicates)
220
+ const deduped = filtered.filter((ev, i) => {
221
+ if (ev.type !== 'msg:done') return true;
222
+ return !filtered.slice(i + 1).some(e => e.type === 'msg:done' && e.roleId === ev.roleId);
223
+ });
224
+ const visible = deduped.slice(-maxEv);
220
225
  for (const ev of visible) {
221
226
  const line = eventLine(ev);
222
227
  if (!line) continue;