@xcanwin/manyoyo 5.2.9 → 5.2.15
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/lib/web/frontend/app.css +46 -96
- package/lib/web/frontend/app.html +2 -6
- package/lib/web/frontend/app.js +9 -53
- package/lib/web/server.js +35 -3
- package/package.json +1 -1
package/lib/web/frontend/app.css
CHANGED
|
@@ -104,17 +104,16 @@ body::after {
|
|
|
104
104
|
z-index: 1;
|
|
105
105
|
height: 100vh;
|
|
106
106
|
height: 100dvh;
|
|
107
|
-
padding:
|
|
107
|
+
padding: 0;
|
|
108
108
|
display: grid;
|
|
109
109
|
grid-template-columns: minmax(282px, 334px) minmax(0, 1fr);
|
|
110
|
-
gap:
|
|
110
|
+
gap: 0;
|
|
111
111
|
}
|
|
112
112
|
|
|
113
113
|
.sidebar,
|
|
114
114
|
.main {
|
|
115
|
-
border-radius:
|
|
116
|
-
border:
|
|
117
|
-
box-shadow: var(--shadow-soft);
|
|
115
|
+
border-radius: 0;
|
|
116
|
+
border: none;
|
|
118
117
|
}
|
|
119
118
|
|
|
120
119
|
.sidebar {
|
|
@@ -125,6 +124,7 @@ body::after {
|
|
|
125
124
|
gap: 12px;
|
|
126
125
|
background:
|
|
127
126
|
linear-gradient(165deg, #fffefd 0%, #f8f1e7 100%);
|
|
127
|
+
border-right: 1px solid var(--line);
|
|
128
128
|
animation: panelIn 320ms ease both;
|
|
129
129
|
}
|
|
130
130
|
|
|
@@ -246,12 +246,17 @@ textarea:focus-visible {
|
|
|
246
246
|
}
|
|
247
247
|
|
|
248
248
|
.mobile-session-toggle,
|
|
249
|
-
.mobile-actions-toggle,
|
|
250
249
|
.mobile-sidebar-close,
|
|
251
250
|
.sidebar-backdrop {
|
|
252
251
|
display: none;
|
|
253
252
|
}
|
|
254
253
|
|
|
254
|
+
.mobile-actions-toggle {
|
|
255
|
+
display: inline-flex;
|
|
256
|
+
padding: 8px 12px;
|
|
257
|
+
font-size: 13px;
|
|
258
|
+
}
|
|
259
|
+
|
|
255
260
|
.sidebar-backdrop[hidden] {
|
|
256
261
|
display: none !important;
|
|
257
262
|
}
|
|
@@ -561,6 +566,7 @@ textarea:focus-visible {
|
|
|
561
566
|
}
|
|
562
567
|
|
|
563
568
|
.header {
|
|
569
|
+
position: relative;
|
|
564
570
|
display: flex;
|
|
565
571
|
justify-content: space-between;
|
|
566
572
|
align-items: flex-start;
|
|
@@ -570,6 +576,7 @@ textarea:focus-visible {
|
|
|
570
576
|
}
|
|
571
577
|
|
|
572
578
|
.header-main {
|
|
579
|
+
flex: 1;
|
|
573
580
|
min-width: 0;
|
|
574
581
|
display: flex;
|
|
575
582
|
flex-direction: column;
|
|
@@ -605,10 +612,23 @@ textarea:focus-visible {
|
|
|
605
612
|
}
|
|
606
613
|
|
|
607
614
|
.header-actions {
|
|
608
|
-
display:
|
|
609
|
-
|
|
615
|
+
display: none;
|
|
616
|
+
position: absolute;
|
|
617
|
+
top: calc(100% + 6px);
|
|
618
|
+
right: 8px;
|
|
619
|
+
z-index: 8;
|
|
620
|
+
width: min(240px, calc(100vw - 36px));
|
|
621
|
+
padding: 8px;
|
|
622
|
+
border: 1px solid var(--line);
|
|
623
|
+
border-radius: 10px;
|
|
624
|
+
background: #fffaf2;
|
|
625
|
+
box-shadow: var(--shadow-strong);
|
|
626
|
+
grid-template-columns: 1fr;
|
|
610
627
|
gap: 8px;
|
|
611
|
-
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
body.mobile-actions-open .header-actions {
|
|
631
|
+
display: grid;
|
|
612
632
|
}
|
|
613
633
|
|
|
614
634
|
.mode-switch {
|
|
@@ -652,17 +672,6 @@ body.terminal-mode #modeTerminalBtn {
|
|
|
652
672
|
border-color: var(--accent-strong);
|
|
653
673
|
}
|
|
654
674
|
|
|
655
|
-
.mode-terminal-controls {
|
|
656
|
-
display: none;
|
|
657
|
-
align-items: center;
|
|
658
|
-
gap: 8px;
|
|
659
|
-
min-width: 0;
|
|
660
|
-
}
|
|
661
|
-
|
|
662
|
-
body.terminal-mode .mode-terminal-controls {
|
|
663
|
-
display: inline-flex;
|
|
664
|
-
}
|
|
665
|
-
|
|
666
675
|
#messages {
|
|
667
676
|
min-height: 0;
|
|
668
677
|
overflow-y: auto;
|
|
@@ -682,28 +691,13 @@ body.terminal-mode .mode-terminal-controls {
|
|
|
682
691
|
min-height: 0;
|
|
683
692
|
display: none;
|
|
684
693
|
flex-direction: column;
|
|
685
|
-
|
|
686
|
-
margin: 10px 8px 0;
|
|
687
|
-
padding: 12px;
|
|
688
|
-
border: 1px solid var(--line);
|
|
689
|
-
border-radius: 14px;
|
|
690
|
-
background: rgba(255, 251, 245, 0.9);
|
|
691
|
-
}
|
|
692
|
-
|
|
693
|
-
.terminal-status {
|
|
694
|
-
display: inline-block;
|
|
695
|
-
color: var(--muted);
|
|
696
|
-
font-size: 12px;
|
|
697
|
-
white-space: nowrap;
|
|
694
|
+
margin: 4px 0 0;
|
|
698
695
|
}
|
|
699
696
|
|
|
700
697
|
#terminalScreen {
|
|
701
698
|
flex: 1;
|
|
702
699
|
min-height: 0;
|
|
703
700
|
height: 100%;
|
|
704
|
-
border-radius: 12px;
|
|
705
|
-
border: 1px solid #2a3544;
|
|
706
|
-
box-shadow: inset 0 0 0 1px rgba(255, 209, 102, 0.14);
|
|
707
701
|
overflow: hidden;
|
|
708
702
|
background: var(--terminal-bg);
|
|
709
703
|
}
|
|
@@ -711,18 +705,13 @@ body.terminal-mode .mode-terminal-controls {
|
|
|
711
705
|
#terminalScreen .xterm {
|
|
712
706
|
width: 100%;
|
|
713
707
|
height: 100%;
|
|
714
|
-
padding:
|
|
708
|
+
padding: 4px 6px;
|
|
715
709
|
}
|
|
716
710
|
|
|
717
711
|
#terminalScreen .xterm-screen {
|
|
718
712
|
width: 100%;
|
|
719
713
|
}
|
|
720
714
|
|
|
721
|
-
.terminal-foot {
|
|
722
|
-
color: var(--muted);
|
|
723
|
-
font-size: 12px;
|
|
724
|
-
}
|
|
725
|
-
|
|
726
715
|
body.command-mode #messages {
|
|
727
716
|
display: flex;
|
|
728
717
|
}
|
|
@@ -989,13 +978,14 @@ body.command-mode .msg.origin-agent .bubble {
|
|
|
989
978
|
|
|
990
979
|
.sidebar {
|
|
991
980
|
position: fixed;
|
|
992
|
-
left:
|
|
993
|
-
top:
|
|
994
|
-
bottom:
|
|
981
|
+
left: env(safe-area-inset-left, 0px);
|
|
982
|
+
top: env(safe-area-inset-top, 0px);
|
|
983
|
+
bottom: env(safe-area-inset-bottom, 0px);
|
|
995
984
|
width: min(86vw, 346px);
|
|
996
985
|
max-width: 346px;
|
|
997
986
|
max-height: none;
|
|
998
987
|
background: rgba(255, 252, 246, 0.98);
|
|
988
|
+
border-radius: 0;
|
|
999
989
|
z-index: 40;
|
|
1000
990
|
transform: translateX(calc(-100% - 16px));
|
|
1001
991
|
opacity: 0;
|
|
@@ -1012,14 +1002,15 @@ body.command-mode .msg.origin-agent .bubble {
|
|
|
1012
1002
|
|
|
1013
1003
|
.main {
|
|
1014
1004
|
position: fixed;
|
|
1015
|
-
left:
|
|
1016
|
-
right:
|
|
1017
|
-
top:
|
|
1018
|
-
bottom:
|
|
1005
|
+
left: env(safe-area-inset-left, 0px);
|
|
1006
|
+
right: env(safe-area-inset-right, 0px);
|
|
1007
|
+
top: env(safe-area-inset-top, 0px);
|
|
1008
|
+
bottom: env(safe-area-inset-bottom, 0px);
|
|
1019
1009
|
height: auto;
|
|
1020
1010
|
min-height: auto;
|
|
1021
1011
|
overflow: hidden;
|
|
1022
1012
|
z-index: 1;
|
|
1013
|
+
grid-template-columns: minmax(0, 1fr);
|
|
1023
1014
|
}
|
|
1024
1015
|
|
|
1025
1016
|
#messages,
|
|
@@ -1040,10 +1031,6 @@ body.command-mode .msg.origin-agent .bubble {
|
|
|
1040
1031
|
font-size: 13px;
|
|
1041
1032
|
}
|
|
1042
1033
|
|
|
1043
|
-
.mobile-actions-toggle {
|
|
1044
|
-
display: none;
|
|
1045
|
-
}
|
|
1046
|
-
|
|
1047
1034
|
.sidebar-backdrop {
|
|
1048
1035
|
display: block;
|
|
1049
1036
|
position: fixed;
|
|
@@ -1068,7 +1055,6 @@ body.command-mode .msg.origin-agent .bubble {
|
|
|
1068
1055
|
}
|
|
1069
1056
|
|
|
1070
1057
|
.header {
|
|
1071
|
-
position: relative;
|
|
1072
1058
|
padding: 10px 12px 16px;
|
|
1073
1059
|
}
|
|
1074
1060
|
|
|
@@ -1080,57 +1066,21 @@ body.command-mode .msg.origin-agent .bubble {
|
|
|
1080
1066
|
display: none;
|
|
1081
1067
|
}
|
|
1082
1068
|
|
|
1083
|
-
.header-actions {
|
|
1084
|
-
display: none;
|
|
1085
|
-
position: absolute;
|
|
1086
|
-
top: calc(100% + 6px);
|
|
1087
|
-
right: 8px;
|
|
1088
|
-
z-index: 8;
|
|
1089
|
-
width: min(240px, calc(100vw - 36px));
|
|
1090
|
-
padding: 8px;
|
|
1091
|
-
border: 1px solid var(--line);
|
|
1092
|
-
border-radius: 10px;
|
|
1093
|
-
background: #fffaf2;
|
|
1094
|
-
box-shadow: var(--shadow-strong);
|
|
1095
|
-
grid-template-columns: 1fr;
|
|
1096
|
-
gap: 8px;
|
|
1097
|
-
}
|
|
1098
|
-
|
|
1099
|
-
body.mobile-actions-open .header-actions {
|
|
1100
|
-
display: grid;
|
|
1101
|
-
}
|
|
1102
|
-
|
|
1103
|
-
.mobile-actions-toggle {
|
|
1104
|
-
display: inline-flex;
|
|
1105
|
-
padding: 8px 12px;
|
|
1106
|
-
font-size: 13px;
|
|
1107
|
-
}
|
|
1108
|
-
|
|
1109
1069
|
.mode-switch {
|
|
1110
1070
|
margin: 8px 8px 2px;
|
|
1111
|
-
|
|
1071
|
+
flex-wrap: wrap;
|
|
1112
1072
|
padding: 8px;
|
|
1113
1073
|
gap: 8px;
|
|
1114
1074
|
}
|
|
1115
1075
|
|
|
1116
|
-
.mode-switch-left
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
flex: 0 0 auto;
|
|
1076
|
+
.mode-switch-left {
|
|
1077
|
+
flex: 1 1 auto;
|
|
1078
|
+
min-width: 0;
|
|
1120
1079
|
}
|
|
1121
1080
|
|
|
1122
1081
|
.mode-switch button {
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
.mode-terminal-controls {
|
|
1127
|
-
gap: 6px;
|
|
1128
|
-
}
|
|
1129
|
-
|
|
1130
|
-
.terminal-status {
|
|
1131
|
-
max-width: 5.2em;
|
|
1132
|
-
overflow: hidden;
|
|
1133
|
-
text-overflow: ellipsis;
|
|
1082
|
+
flex: 0 0 auto;
|
|
1083
|
+
min-width: 84px;
|
|
1134
1084
|
}
|
|
1135
1085
|
|
|
1136
1086
|
#commandInput {
|
|
@@ -70,16 +70,12 @@
|
|
|
70
70
|
<button type="button" id="modeCommandBtn" class="secondary">命令模式</button>
|
|
71
71
|
<button type="button" id="modeTerminalBtn" class="secondary">交互终端</button>
|
|
72
72
|
</div>
|
|
73
|
-
|
|
74
|
-
<button type="button" id="terminalConnectBtn">连接终端</button>
|
|
75
|
-
<button type="button" id="terminalDisconnectBtn" class="secondary">断开终端</button>
|
|
76
|
-
<span id="terminalStatus" class="terminal-status">未连接</span>
|
|
77
|
-
</div>
|
|
73
|
+
|
|
78
74
|
</section>
|
|
79
75
|
<section id="messages"></section>
|
|
80
76
|
<section id="terminalPanel" hidden>
|
|
81
77
|
<div id="terminalScreen" aria-label="终端输出区域"></div>
|
|
82
|
-
|
|
78
|
+
|
|
83
79
|
</section>
|
|
84
80
|
<form class="composer" id="composer">
|
|
85
81
|
<div class="composer-inner">
|
package/lib/web/frontend/app.js
CHANGED
|
@@ -118,9 +118,6 @@
|
|
|
118
118
|
const modeTerminalBtn = document.getElementById('modeTerminalBtn');
|
|
119
119
|
const messagesNode = document.getElementById('messages');
|
|
120
120
|
const terminalPanel = document.getElementById('terminalPanel');
|
|
121
|
-
const terminalConnectBtn = document.getElementById('terminalConnectBtn');
|
|
122
|
-
const terminalDisconnectBtn = document.getElementById('terminalDisconnectBtn');
|
|
123
|
-
const terminalStatus = document.getElementById('terminalStatus');
|
|
124
121
|
const terminalScreen = document.getElementById('terminalScreen');
|
|
125
122
|
const composer = document.getElementById('composer');
|
|
126
123
|
const commandInput = document.getElementById('commandInput');
|
|
@@ -565,15 +562,6 @@
|
|
|
565
562
|
state.terminal.term.writeln(text);
|
|
566
563
|
}
|
|
567
564
|
|
|
568
|
-
function renderTerminalIntro() {
|
|
569
|
-
if (!state.terminal.term) return;
|
|
570
|
-
state.terminal.term.reset();
|
|
571
|
-
writeTerminalLine('MANYOYO Interactive Terminal');
|
|
572
|
-
writeTerminalLine(state.active ? ('当前会话: ' + state.active) : '当前会话: 未选择');
|
|
573
|
-
writeTerminalLine('点击“连接终端”后可运行 codex / claude 等交互式 agent。');
|
|
574
|
-
writeTerminalLine('');
|
|
575
|
-
}
|
|
576
|
-
|
|
577
565
|
function resolveFitAddonCtor() {
|
|
578
566
|
if (window.FitAddon && typeof window.FitAddon.FitAddon === 'function') {
|
|
579
567
|
return window.FitAddon.FitAddon;
|
|
@@ -710,7 +698,6 @@
|
|
|
710
698
|
notifyTerminalResize(false);
|
|
711
699
|
});
|
|
712
700
|
state.terminal.terminalReady = true;
|
|
713
|
-
renderTerminalIntro();
|
|
714
701
|
return true;
|
|
715
702
|
}
|
|
716
703
|
|
|
@@ -856,10 +843,6 @@
|
|
|
856
843
|
return MOBILE_LAYOUT_MEDIA.matches;
|
|
857
844
|
}
|
|
858
845
|
|
|
859
|
-
function isMobileCompactLayout() {
|
|
860
|
-
return MOBILE_COMPACT_MEDIA.matches;
|
|
861
|
-
}
|
|
862
|
-
|
|
863
846
|
function setMobileSessionPanel(open) {
|
|
864
847
|
state.mobileSidebarOpen = Boolean(open);
|
|
865
848
|
const mobileLayout = isMobileLayout();
|
|
@@ -885,14 +868,9 @@
|
|
|
885
868
|
|
|
886
869
|
function setMobileActionsMenu(open) {
|
|
887
870
|
state.mobileActionsOpen = Boolean(open);
|
|
888
|
-
|
|
889
|
-
if (!compactLayout) {
|
|
890
|
-
state.mobileActionsOpen = false;
|
|
891
|
-
}
|
|
892
|
-
const shouldOpen = state.mobileActionsOpen && compactLayout;
|
|
893
|
-
document.body.classList.toggle('mobile-actions-open', shouldOpen);
|
|
871
|
+
document.body.classList.toggle('mobile-actions-open', state.mobileActionsOpen);
|
|
894
872
|
if (mobileActionsToggle) {
|
|
895
|
-
mobileActionsToggle.setAttribute('aria-expanded',
|
|
873
|
+
mobileActionsToggle.setAttribute('aria-expanded', state.mobileActionsOpen ? 'true' : 'false');
|
|
896
874
|
}
|
|
897
875
|
}
|
|
898
876
|
|
|
@@ -986,16 +964,6 @@
|
|
|
986
964
|
if (createModal) {
|
|
987
965
|
createModal.hidden = !state.createModalOpen;
|
|
988
966
|
}
|
|
989
|
-
if (terminalConnectBtn) {
|
|
990
|
-
terminalConnectBtn.disabled = !state.active || busy || state.terminal.connecting || state.terminal.connected;
|
|
991
|
-
}
|
|
992
|
-
if (terminalDisconnectBtn) {
|
|
993
|
-
terminalDisconnectBtn.disabled = !(state.terminal.connecting || state.terminal.connected);
|
|
994
|
-
}
|
|
995
|
-
if (terminalStatus) {
|
|
996
|
-
terminalStatus.textContent = state.terminal.status;
|
|
997
|
-
}
|
|
998
|
-
|
|
999
967
|
if (!state.active) {
|
|
1000
968
|
sendState.textContent = '未选择会话';
|
|
1001
969
|
} else if (agentMode && !agentEnabled) {
|
|
@@ -1194,8 +1162,10 @@
|
|
|
1194
1162
|
closeMobileSessionPanel();
|
|
1195
1163
|
}
|
|
1196
1164
|
if (state.mode === 'terminal' && ensureTerminalReady()) {
|
|
1197
|
-
renderTerminalIntro();
|
|
1198
1165
|
scheduleTerminalFit(false);
|
|
1166
|
+
if (!state.terminal.connected && !state.terminal.connecting) {
|
|
1167
|
+
connectTerminal();
|
|
1168
|
+
}
|
|
1199
1169
|
}
|
|
1200
1170
|
renderSessionActiveState();
|
|
1201
1171
|
syncUi();
|
|
@@ -1528,8 +1498,8 @@
|
|
|
1528
1498
|
}
|
|
1529
1499
|
|
|
1530
1500
|
if (state.mode === 'terminal' && ensureTerminalReady() && !state.terminal.connected && !state.terminal.connecting) {
|
|
1531
|
-
renderTerminalIntro();
|
|
1532
1501
|
scheduleTerminalFit(false);
|
|
1502
|
+
connectTerminal();
|
|
1533
1503
|
}
|
|
1534
1504
|
|
|
1535
1505
|
if (opts.reloadMessages) {
|
|
@@ -1879,28 +1849,15 @@
|
|
|
1879
1849
|
renderMessages(state.messages, { forceFullRender: true });
|
|
1880
1850
|
syncUi();
|
|
1881
1851
|
if (ensureTerminalReady()) {
|
|
1882
|
-
if (!state.terminal.connected && !state.terminal.connecting) {
|
|
1883
|
-
renderTerminalIntro();
|
|
1884
|
-
}
|
|
1885
1852
|
scheduleTerminalFit(false);
|
|
1886
1853
|
state.terminal.term.focus();
|
|
1854
|
+
if (!state.terminal.connected && !state.terminal.connecting) {
|
|
1855
|
+
connectTerminal();
|
|
1856
|
+
}
|
|
1887
1857
|
}
|
|
1888
1858
|
});
|
|
1889
1859
|
}
|
|
1890
1860
|
|
|
1891
|
-
if (terminalConnectBtn) {
|
|
1892
|
-
terminalConnectBtn.addEventListener('click', function () {
|
|
1893
|
-
connectTerminal();
|
|
1894
|
-
});
|
|
1895
|
-
}
|
|
1896
|
-
|
|
1897
|
-
if (terminalDisconnectBtn) {
|
|
1898
|
-
terminalDisconnectBtn.addEventListener('click', function () {
|
|
1899
|
-
disconnectTerminal('终端已手动断开');
|
|
1900
|
-
syncUi();
|
|
1901
|
-
});
|
|
1902
|
-
}
|
|
1903
|
-
|
|
1904
1861
|
refreshBtn.addEventListener('click', function () {
|
|
1905
1862
|
closeMobileActionsMenu();
|
|
1906
1863
|
loadSessions(state.active).catch(function (e) { alert(e.message); });
|
|
@@ -1993,7 +1950,6 @@
|
|
|
1993
1950
|
|
|
1994
1951
|
document.addEventListener('click', function (event) {
|
|
1995
1952
|
if (!state.mobileActionsOpen) return;
|
|
1996
|
-
if (!isMobileCompactLayout()) return;
|
|
1997
1953
|
const target = event.target;
|
|
1998
1954
|
if (mobileActionsToggle && mobileActionsToggle.contains(target)) return;
|
|
1999
1955
|
if (headerActions && headerActions.contains(target)) return;
|
package/lib/web/server.js
CHANGED
|
@@ -940,9 +940,36 @@ function buildCreateRuntime(ctx, state, payload) {
|
|
|
940
940
|
};
|
|
941
941
|
}
|
|
942
942
|
|
|
943
|
+
// Estimate container start time from "Up X hours/minutes/seconds" status string.
|
|
944
|
+
// Uses relative time to avoid Podman Machine VM clock drift issues.
|
|
945
|
+
function estimateStartTimeFromStatus(status) {
|
|
946
|
+
if (!status) return null;
|
|
947
|
+
const s = status.trim().toLowerCase();
|
|
948
|
+
if (!s.startsWith('up ')) return null;
|
|
949
|
+
const rest = s.slice(3).trim();
|
|
950
|
+
const now = Date.now();
|
|
951
|
+
|
|
952
|
+
const units = [
|
|
953
|
+
{ re: /^(\d+)\s+week/, ms: 7 * 24 * 3600 * 1000 },
|
|
954
|
+
{ re: /^(\d+)\s+day/, ms: 24 * 3600 * 1000 },
|
|
955
|
+
{ re: /^(\d+)\s+hour/, ms: 3600 * 1000 },
|
|
956
|
+
{ re: /^(\d+)\s+min/, ms: 60 * 1000 },
|
|
957
|
+
{ re: /^(\d+)\s+second/, ms: 1000 },
|
|
958
|
+
];
|
|
959
|
+
for (const { re, ms } of units) {
|
|
960
|
+
const m = rest.match(re);
|
|
961
|
+
if (m) return new Date(now - parseInt(m[1]) * ms).toISOString();
|
|
962
|
+
}
|
|
963
|
+
// "about a minute", "a minute", "about an hour", "an hour", "less than a second"
|
|
964
|
+
if (/\bminute\b/.test(rest)) return new Date(now - 60 * 1000).toISOString();
|
|
965
|
+
if (/\bhour\b/.test(rest)) return new Date(now - 3600 * 1000).toISOString();
|
|
966
|
+
if (/\bsecond\b/.test(rest)) return new Date(now).toISOString();
|
|
967
|
+
return null;
|
|
968
|
+
}
|
|
969
|
+
|
|
943
970
|
function listWebManyoyoContainers(ctx) {
|
|
944
971
|
const output = ctx.dockerExecArgs(
|
|
945
|
-
['ps', '-a', '--
|
|
972
|
+
['ps', '-a', '--format', '{{.Names}}\t{{.Status}}\t{{.Image}}'],
|
|
946
973
|
{ ignoreError: true }
|
|
947
974
|
);
|
|
948
975
|
|
|
@@ -956,10 +983,15 @@ function listWebManyoyoContainers(ctx) {
|
|
|
956
983
|
if (!ctx.isValidContainerName(name)) {
|
|
957
984
|
return;
|
|
958
985
|
}
|
|
986
|
+
const imageName = image || '';
|
|
987
|
+
if (!imageName.includes('manyoyo') && !name.startsWith('manyoyo-') && !name.startsWith('my-')) {
|
|
988
|
+
return;
|
|
989
|
+
}
|
|
959
990
|
map[name] = {
|
|
960
991
|
name,
|
|
961
992
|
status: status || 'unknown',
|
|
962
|
-
image:
|
|
993
|
+
image: imageName,
|
|
994
|
+
createdAt: estimateStartTimeFromStatus(status)
|
|
963
995
|
};
|
|
964
996
|
});
|
|
965
997
|
|
|
@@ -1117,7 +1149,7 @@ function buildSessionSummary(ctx, state, containerMap, name) {
|
|
|
1117
1149
|
const agentMeta = getAgentRuntimeMeta(history);
|
|
1118
1150
|
const latestMessage = history.messages.length ? history.messages[history.messages.length - 1] : null;
|
|
1119
1151
|
const containerInfo = containerMap[name] || {};
|
|
1120
|
-
const updatedAt = history.updatedAt || (latestMessage && latestMessage.timestamp) || null;
|
|
1152
|
+
const updatedAt = history.updatedAt || (latestMessage && latestMessage.timestamp) || containerInfo.createdAt || null;
|
|
1121
1153
|
return {
|
|
1122
1154
|
name,
|
|
1123
1155
|
status: containerInfo.status || 'history',
|