@dmsdc-ai/aigentry-telepty 0.1.61 → 0.1.62

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/tui.js +50 -2
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dmsdc-ai/aigentry-telepty",
3
- "version": "0.1.61",
3
+ "version": "0.1.62",
4
4
  "main": "daemon.js",
5
5
  "bin": {
6
6
  "aigentry-telepty": "install.js",
package/tui.js CHANGED
@@ -23,6 +23,7 @@ class TuiDashboard {
23
23
  this.pollTimer = null;
24
24
  this.busWs = null;
25
25
  this.busLog = [];
26
+ this.sessionTasks = {}; // { sessionId: { summary, state, updatedAt } }
26
27
  this.setupScreen();
27
28
  this.startPolling();
28
29
  this.connectBus();
@@ -248,6 +249,35 @@ class TuiDashboard {
248
249
  this.screen.render();
249
250
  }
250
251
 
252
+ // ── Task extraction from bus events ─────────────────────────
253
+
254
+ parseTaskInfo(content) {
255
+ if (!content || typeof content !== 'string') return null;
256
+ const firstLine = content.split('\n')[0].trim();
257
+ // Extract [tag] patterns: [P0 착수], [완료 보고], [telepty 관점], etc.
258
+ const tagMatch = firstLine.match(/\[([^\]]{2,30})\]/);
259
+ const tag = tagMatch ? tagMatch[1] : null;
260
+ // Detect state from keywords
261
+ let state = 'working';
262
+ if (/완료|complete|done|finish/i.test(firstLine)) state = 'done';
263
+ else if (/토론|deliberat|discuss|synthesis|합의/i.test(firstLine)) state = 'discussing';
264
+ else if (/동의|반대|vote|찬성/i.test(firstLine)) state = 'voting';
265
+ else if (/대기|standby|waiting|idle/i.test(firstLine)) state = 'idle';
266
+ // Build summary (tag or truncated first line)
267
+ const summary = tag || firstLine.replace(/\[.*?\]/g, '').trim().slice(0, 30);
268
+ return { summary, state };
269
+ }
270
+
271
+ updateSessionTask(sessionId, content) {
272
+ const info = this.parseTaskInfo(content);
273
+ if (!info || !info.summary) return;
274
+ this.sessionTasks[sessionId] = {
275
+ summary: info.summary,
276
+ state: info.state,
277
+ updatedAt: Date.now()
278
+ };
279
+ }
280
+
251
281
  // ── Event Bus ────────────────────────────────────────────────
252
282
 
253
283
  connectBus() {
@@ -263,16 +293,20 @@ class TuiDashboard {
263
293
  let line = `${ts} `;
264
294
  if (msg.type === 'inject_written') {
265
295
  line += `{cyan-fg}inject{/} -> ${msg.target || '?'}`;
296
+ // Track task from inject content
297
+ if (msg.target) this.updateSessionTask(msg.target, msg.content || msg.prompt);
266
298
  } else if (msg.type === 'injection') {
267
299
  line += `{cyan-fg}broadcast{/} -> ${msg.target_agent || 'all'}`;
268
300
  } else if (msg.type === 'message_routed') {
269
301
  line += `{yellow-fg}${msg.from || '?'}{/} -> {green-fg}${msg.to || '?'}{/}`;
302
+ if (msg.from) this.updateSessionTask(msg.from, msg.content || msg.prompt);
270
303
  } else {
271
304
  line += `{white-fg}${msg.type || 'event'}{/}`;
272
305
  }
273
306
  this.busLog.push(line);
274
307
  if (this.busLog.length > 100) this.busLog.shift();
275
308
  this.renderBusLog();
309
+ this.renderSessionList(); // refresh task info
276
310
  } catch { /* ignore malformed */ }
277
311
  });
278
312
  this.busWs.on('close', () => {
@@ -428,9 +462,20 @@ class TuiDashboard {
428
462
  getStatusInfo(session) {
429
463
  const idle = session.idleSeconds;
430
464
  const clients = session.active_clients || 0;
431
-
465
+ const task = this.sessionTasks[session.id];
466
+ // Task-aware state (bus events override idle heuristic)
432
467
  if (clients === 0) return { icon: '{red-fg}✕{/}', label: '{red-fg}dead{/}' };
433
468
  if (idle !== null && idle > STALE_THRESHOLD) return { icon: '{yellow-fg}○{/}', label: '{yellow-fg}stale{/}' };
469
+ if (task && (Date.now() - task.updatedAt) < 300000) { // 5min freshness
470
+ const stateMap = {
471
+ done: { icon: '{green-fg}✓{/}', label: '{green-fg}done{/}' },
472
+ discussing: { icon: '{magenta-fg}◉{/}', label: '{magenta-fg}discuss{/}' },
473
+ voting: { icon: '{magenta-fg}◎{/}', label: '{magenta-fg}vote{/}' },
474
+ working: { icon: '{cyan-fg}●{/}', label: '{cyan-fg}working{/}' },
475
+ idle: { icon: '{green-fg}●{/}', label: '{white-fg}idle{/}' }
476
+ };
477
+ return stateMap[task.state] || stateMap.working;
478
+ }
434
479
  if (idle !== null && idle < 10) return { icon: '{green-fg}●{/}', label: '{green-fg}busy{/}' };
435
480
  return { icon: '{green-fg}●{/}', label: '{white-fg}idle{/}' };
436
481
  }
@@ -439,7 +484,10 @@ class TuiDashboard {
439
484
  const items = this.sessions.map((s) => {
440
485
  const { icon, label } = this.getStatusInfo(s);
441
486
  const shortId = s.id.replace(/^aigentry-/, '').replace(/-claude$/, '');
442
- return ` ${icon} ${shortId.padEnd(24)} ${label} {gray-fg}C:${s.active_clients}{/}`;
487
+ const task = this.sessionTasks[s.id];
488
+ const taskStr = (task && (Date.now() - task.updatedAt) < 300000)
489
+ ? ` {gray-fg}${task.summary.slice(0, 20)}{/}` : '';
490
+ return ` ${icon} ${shortId.padEnd(20)} ${label.padEnd(18)}${taskStr}`;
443
491
  });
444
492
 
445
493
  this.sessionList.setItems(items);