loadtoagent 1.0.0 → 1.1.0
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/main.js +50 -1
- package/package.json +4 -2
- package/preload.js +5 -0
- package/renderer/app-bootstrap.js +11 -1
- package/renderer/app-dashboard.js +7 -3
- package/renderer/app-drawer-content.js +68 -55
- package/renderer/app-drawer.js +13 -7
- package/renderer/app-events-filters.js +5 -1
- package/renderer/app-events-navigation.js +1 -1
- package/renderer/app-events-sessions.js +21 -1
- package/renderer/app-graph-model.js +47 -1
- package/renderer/app-graph-orchestration.js +9 -8
- package/renderer/app-graph-view.js +6 -5
- package/renderer/app-tmux-render.js +75 -2
- package/renderer/app.js +2 -1
- package/renderer/i18n-messages.js +1 -0
- package/renderer/index.html +18 -17
- package/renderer/styles-agent-map.css +44 -1
- package/renderer/styles-collaboration.css +18 -88
- package/renderer/styles-components.css +40 -5
- package/renderer/styles-overlays.css +5 -0
- package/renderer/styles-responsive-runtime.css +9 -0
- package/renderer/styles-responsive-workflows.css +0 -14
- package/renderer/styles-tmux.css +154 -0
- package/renderer/terminal-workbench.js +11 -1
- package/renderer/terminal.js +9 -3
- package/src/attentionNotifier.js +67 -0
- package/src/processMonitor.js +1 -1
- package/src/tmuxMonitor.js +2 -2
package/renderer/styles-tmux.css
CHANGED
|
@@ -390,6 +390,160 @@
|
|
|
390
390
|
background: linear-gradient(90deg,#52d7aa,var(--provider));
|
|
391
391
|
}
|
|
392
392
|
|
|
393
|
+
.tmux-subagents {
|
|
394
|
+
border-top: 1px solid #1c2731;
|
|
395
|
+
background: rgba(8,14,20,.74);
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
.tmux-subagents-toggle {
|
|
399
|
+
display: flex;
|
|
400
|
+
align-items: center;
|
|
401
|
+
justify-content: space-between;
|
|
402
|
+
gap: 12px;
|
|
403
|
+
width: 100%;
|
|
404
|
+
padding: 10px 14px;
|
|
405
|
+
border: 0;
|
|
406
|
+
background: transparent;
|
|
407
|
+
color: #cbd7e1;
|
|
408
|
+
text-align: left;
|
|
409
|
+
cursor: pointer;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
.tmux-subagents-toggle:hover,
|
|
413
|
+
.tmux-subagents-toggle:focus-visible {
|
|
414
|
+
background: rgba(83,218,177,.055);
|
|
415
|
+
color: #edf8f4;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
.tmux-subagents-toggle span,
|
|
419
|
+
.tmux-subagents-toggle b,
|
|
420
|
+
.tmux-subagents-toggle small {
|
|
421
|
+
display: block;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
.tmux-subagents-toggle b {
|
|
425
|
+
font-size: 11px;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
.tmux-subagents-toggle small {
|
|
429
|
+
margin-top: 3px;
|
|
430
|
+
color: #718395;
|
|
431
|
+
font-size: 9px;
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
.tmux-subagents-toggle>i {
|
|
435
|
+
color: #72deb8;
|
|
436
|
+
font-style: normal;
|
|
437
|
+
transition: transform var(--motion-fast) ease;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
.tmux-subagents.expanded .tmux-subagents-toggle>i {
|
|
441
|
+
transform: rotate(180deg);
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
.tmux-subagent-list {
|
|
445
|
+
display: grid;
|
|
446
|
+
gap: 6px;
|
|
447
|
+
padding: 0 10px 10px;
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
.tmux-subagent-row {
|
|
451
|
+
display: grid;
|
|
452
|
+
grid-template-columns: 28px minmax(0,1fr) auto;
|
|
453
|
+
align-items: center;
|
|
454
|
+
gap: 8px;
|
|
455
|
+
margin-left: calc(var(--tmux-subagent-depth,0) * 12px);
|
|
456
|
+
padding: 8px;
|
|
457
|
+
border: 1px solid color-mix(in srgb,var(--provider) 18%,#26323d);
|
|
458
|
+
border-radius: 9px;
|
|
459
|
+
background: color-mix(in srgb,var(--provider) 4%,#0b1219);
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
.tmux-subagent-row.work-working {
|
|
463
|
+
border-color: color-mix(in srgb,var(--provider) 38%,#315148);
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
.tmux-subagent-row.work-attention {
|
|
467
|
+
border-color: rgba(235,119,119,.42);
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
.tmux-subagent-row>.provider-mark {
|
|
471
|
+
width: 27px;
|
|
472
|
+
height: 27px;
|
|
473
|
+
font-size: 9px;
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
.tmux-subagent-copy,
|
|
477
|
+
.tmux-subagent-copy>span {
|
|
478
|
+
min-width: 0;
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
.tmux-subagent-copy>span {
|
|
482
|
+
display: flex;
|
|
483
|
+
align-items: center;
|
|
484
|
+
gap: 6px;
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
.tmux-subagent-copy b,
|
|
488
|
+
.tmux-subagent-copy strong,
|
|
489
|
+
.tmux-subagent-copy em {
|
|
490
|
+
overflow: hidden;
|
|
491
|
+
text-overflow: ellipsis;
|
|
492
|
+
white-space: nowrap;
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
.tmux-subagent-copy b {
|
|
496
|
+
color: #dce6ee;
|
|
497
|
+
font-size: 10px;
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
.tmux-subagent-copy i {
|
|
501
|
+
padding: 2px 5px;
|
|
502
|
+
border-radius: 999px;
|
|
503
|
+
background: #17262a;
|
|
504
|
+
color: #77dcb9;
|
|
505
|
+
font-size: 8px;
|
|
506
|
+
font-style: normal;
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
.tmux-subagent-copy small {
|
|
510
|
+
color: #647588;
|
|
511
|
+
font-size: 8px;
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
.tmux-subagent-copy strong,
|
|
515
|
+
.tmux-subagent-copy em {
|
|
516
|
+
display: block;
|
|
517
|
+
margin-top: 3px;
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
.tmux-subagent-copy strong {
|
|
521
|
+
color: #b9c7d3;
|
|
522
|
+
font-size: 10px;
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
.tmux-subagent-copy em {
|
|
526
|
+
color: #718294;
|
|
527
|
+
font-size: 9px;
|
|
528
|
+
font-style: normal;
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
.tmux-subagent-row>button {
|
|
532
|
+
min-height: 27px;
|
|
533
|
+
padding: 0 7px;
|
|
534
|
+
border: 1px solid #294139;
|
|
535
|
+
border-radius: 7px;
|
|
536
|
+
background: #10211f;
|
|
537
|
+
color: #72deb8;
|
|
538
|
+
font-size: 9px;
|
|
539
|
+
cursor: pointer;
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
.tmux-subagent-row>button:hover {
|
|
543
|
+
border-color: #3e6b5d;
|
|
544
|
+
background: #142a26;
|
|
545
|
+
}
|
|
546
|
+
|
|
393
547
|
.tmux-pane-node footer button {
|
|
394
548
|
height: 27px;
|
|
395
549
|
padding: 0 8px;
|
|
@@ -455,7 +455,17 @@ window.LoadToAgentTerminalWorkbench = function createModule(context) {
|
|
|
455
455
|
if (!operation) return;
|
|
456
456
|
const result = await guarded(operation, message);
|
|
457
457
|
if (result) {
|
|
458
|
-
if (action.startsWith('kill-'))
|
|
458
|
+
if (action.startsWith('kill-')) {
|
|
459
|
+
stopCapture();
|
|
460
|
+
state.captureGeneration += 1;
|
|
461
|
+
state.selectedTmux = null;
|
|
462
|
+
state.remoteCapture = '';
|
|
463
|
+
state.remoteViewportAnchor = null;
|
|
464
|
+
state.remoteViewportAtBottom = false;
|
|
465
|
+
if (state.remoteTerminal) state.remoteTerminal.terminal.reset();
|
|
466
|
+
renderAll();
|
|
467
|
+
await showSelection();
|
|
468
|
+
}
|
|
459
469
|
setTimeout(refreshSnapshot, 300);
|
|
460
470
|
}
|
|
461
471
|
}
|
package/renderer/terminal.js
CHANGED
|
@@ -406,15 +406,21 @@
|
|
|
406
406
|
}
|
|
407
407
|
|
|
408
408
|
async function activate(snapshot, workspaces, mode = 'general') {
|
|
409
|
+
const nextMode = mode === 'tmux' ? 'tmux' : 'general';
|
|
410
|
+
const enteringMode = !state.active || state.mode !== nextMode;
|
|
409
411
|
state.active = true;
|
|
410
|
-
state.mode =
|
|
412
|
+
state.mode = nextMode;
|
|
411
413
|
moveWorkbench(state.mode);
|
|
412
414
|
if (state.mode === 'general') state.selectedTmux = null;
|
|
413
415
|
if (state.selectedId && !modeSessions().some(item => item.id === state.selectedId)) state.selectedId = null;
|
|
414
416
|
updateSnapshot(snapshot, workspaces);
|
|
415
|
-
if (!state.initialized)
|
|
417
|
+
if (!state.initialized) {
|
|
418
|
+
state.active = false;
|
|
419
|
+
return;
|
|
420
|
+
}
|
|
416
421
|
await refreshSessions();
|
|
417
|
-
if (!state.
|
|
422
|
+
if (!state.active || state.mode !== nextMode) return;
|
|
423
|
+
if (enteringMode && !state.selectedId && !state.selectedTmux) {
|
|
418
424
|
const visible = modeSessions();
|
|
419
425
|
if (visible.length) state.selectedId = visible[0].id;
|
|
420
426
|
else if (state.mode === 'tmux') state.selectedTmux = tmuxRows()[0] || null;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
class AttentionNotifier {
|
|
4
|
+
constructor(options = {}) {
|
|
5
|
+
this.Notification = options.Notification;
|
|
6
|
+
this.isSupported = options.isSupported || (() => Boolean(this.Notification));
|
|
7
|
+
this.copy = options.copy || (() => ({ title: '내 확인이 필요합니다', body: '응답이나 선택을 기다리는 AI 세션이 있습니다.' }));
|
|
8
|
+
this.onOpen = options.onOpen || (() => {});
|
|
9
|
+
this.onFallback = options.onFallback || (() => {});
|
|
10
|
+
this.waitingIds = null;
|
|
11
|
+
this.notifications = new Set();
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
sync(snapshot) {
|
|
15
|
+
const waiting = (snapshot && Array.isArray(snapshot.sessions) ? snapshot.sessions : [])
|
|
16
|
+
.filter(session => session && session.id && session.status === 'waiting');
|
|
17
|
+
const nextIds = new Set(waiting.map(session => String(session.id)));
|
|
18
|
+
|
|
19
|
+
if (this.waitingIds === null) {
|
|
20
|
+
this.waitingIds = nextIds;
|
|
21
|
+
return [];
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const newlyWaiting = waiting.filter(session => !this.waitingIds.has(String(session.id)));
|
|
25
|
+
this.waitingIds = nextIds;
|
|
26
|
+
newlyWaiting.forEach(session => this.notify(session));
|
|
27
|
+
return newlyWaiting.map(session => String(session.id));
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
notify(session) {
|
|
31
|
+
let supported = false;
|
|
32
|
+
try {
|
|
33
|
+
supported = Boolean(this.Notification && this.isSupported());
|
|
34
|
+
} catch (_supportProbeFailure) {
|
|
35
|
+
supported = false;
|
|
36
|
+
}
|
|
37
|
+
if (!supported) {
|
|
38
|
+
this.onFallback(session);
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
try {
|
|
42
|
+
const copy = this.copy(session) || {};
|
|
43
|
+
const notification = new this.Notification({
|
|
44
|
+
title: String(copy.title || '내 확인이 필요합니다'),
|
|
45
|
+
body: String(copy.body || session.title || 'AI 세션이 응답을 기다리고 있습니다.'),
|
|
46
|
+
silent: false,
|
|
47
|
+
});
|
|
48
|
+
this.notifications.add(notification);
|
|
49
|
+
notification.once('click', () => this.onOpen(session));
|
|
50
|
+
notification.once('close', () => this.notifications.delete(notification));
|
|
51
|
+
notification.show();
|
|
52
|
+
return notification;
|
|
53
|
+
} catch (_notificationFailure) {
|
|
54
|
+
this.onFallback(session);
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
dispose() {
|
|
60
|
+
for (const notification of this.notifications) {
|
|
61
|
+
try { notification.close(); } catch {}
|
|
62
|
+
}
|
|
63
|
+
this.notifications.clear();
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
module.exports = { AttentionNotifier };
|
package/src/processMonitor.js
CHANGED
|
@@ -298,7 +298,7 @@ function applyRuntimePresence(agentSessions, tmuxSnapshot, processSnapshot, now
|
|
|
298
298
|
for (const pane of window.panes || []) {
|
|
299
299
|
const agent = pane.agent;
|
|
300
300
|
const linked = agent && agent.linkedSessionId && byId.get(agent.linkedSessionId);
|
|
301
|
-
if (!linked) continue;
|
|
301
|
+
if (!linked || pane.dead) continue;
|
|
302
302
|
usedSessionIds.add(linked.id);
|
|
303
303
|
markRuntime(linked, {
|
|
304
304
|
id: `tmux:${distro.name}:${pane.nativeId}`,
|
package/src/tmuxMonitor.js
CHANGED
|
@@ -271,8 +271,8 @@ function linkAgentSessions(snapshot, agentSessions, now = Date.now()) {
|
|
|
271
271
|
for (const pane of window.panes || []) {
|
|
272
272
|
paneCount += 1;
|
|
273
273
|
if (!pane.agentProcess) continue;
|
|
274
|
-
aiPaneCount += 1;
|
|
275
|
-
const ranked = (agentSessions || [])
|
|
274
|
+
if (!pane.dead) aiPaneCount += 1;
|
|
275
|
+
const ranked = pane.dead ? [] : (agentSessions || [])
|
|
276
276
|
.filter(session => !usedSessionIds.has(session.id))
|
|
277
277
|
.map(session => ({ session, score: linkScore(session, pane, distro, pane.agentProcess, now) }))
|
|
278
278
|
.filter(item => item.score >= 1_000)
|