@xcanwin/manyoyo 5.6.1 → 5.6.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/lib/dev-release.js +132 -0
- package/lib/web/frontend/app.css +8 -24
- package/lib/web/frontend/app.html +4 -3
- package/lib/web/frontend/app.js +25 -16
- package/package.json +2 -1
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
function parseReleaseVersion(version) {
|
|
2
|
+
const match = String(version || '').trim().match(/^(\d+)\.(\d+)\.(\d+)$/);
|
|
3
|
+
if (!match) {
|
|
4
|
+
return null;
|
|
5
|
+
}
|
|
6
|
+
return {
|
|
7
|
+
major: Number(match[1]),
|
|
8
|
+
minor: Number(match[2]),
|
|
9
|
+
patch: Number(match[3])
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function formatReleaseVersion(parts) {
|
|
14
|
+
return `${parts.major}.${parts.minor}.${parts.patch}`;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function compareReleaseVersions(left, right) {
|
|
18
|
+
const a = typeof left === 'string' ? parseReleaseVersion(left) : left;
|
|
19
|
+
const b = typeof right === 'string' ? parseReleaseVersion(right) : right;
|
|
20
|
+
if (!a || !b) {
|
|
21
|
+
return 0;
|
|
22
|
+
}
|
|
23
|
+
if (a.major !== b.major) return a.major - b.major;
|
|
24
|
+
if (a.minor !== b.minor) return a.minor - b.minor;
|
|
25
|
+
return a.patch - b.patch;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function buildVersionSuggestions(version) {
|
|
29
|
+
const parsed = parseReleaseVersion(version);
|
|
30
|
+
if (!parsed) {
|
|
31
|
+
return [];
|
|
32
|
+
}
|
|
33
|
+
return [
|
|
34
|
+
{
|
|
35
|
+
key: 'patch',
|
|
36
|
+
label: '第3段 +1 (patch)',
|
|
37
|
+
version: formatReleaseVersion({
|
|
38
|
+
major: parsed.major,
|
|
39
|
+
minor: parsed.minor,
|
|
40
|
+
patch: parsed.patch + 1
|
|
41
|
+
}),
|
|
42
|
+
recommended: true
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
key: 'minor',
|
|
46
|
+
label: '第2段 +1 (minor)',
|
|
47
|
+
version: formatReleaseVersion({
|
|
48
|
+
major: parsed.major,
|
|
49
|
+
minor: parsed.minor + 1,
|
|
50
|
+
patch: 0
|
|
51
|
+
}),
|
|
52
|
+
recommended: false
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
key: 'major',
|
|
56
|
+
label: '第1段 +1 (major)',
|
|
57
|
+
version: formatReleaseVersion({
|
|
58
|
+
major: parsed.major + 1,
|
|
59
|
+
minor: 0,
|
|
60
|
+
patch: 0
|
|
61
|
+
}),
|
|
62
|
+
recommended: false
|
|
63
|
+
}
|
|
64
|
+
];
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function pickLatestVersionTag(tags) {
|
|
68
|
+
let latest = null;
|
|
69
|
+
for (const rawTag of (tags || [])) {
|
|
70
|
+
const tag = String(rawTag || '').trim();
|
|
71
|
+
if (!tag) {
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
const normalized = tag.startsWith('v') ? tag.slice(1) : tag;
|
|
75
|
+
const parsed = parseReleaseVersion(normalized);
|
|
76
|
+
if (!parsed) {
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
if (!latest || compareReleaseVersions(parsed, latest.parsed) > 0) {
|
|
80
|
+
latest = {
|
|
81
|
+
tag,
|
|
82
|
+
version: normalized,
|
|
83
|
+
parsed
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return latest ? { tag: latest.tag, version: latest.version } : null;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function normalizeCommitMessage(text) {
|
|
91
|
+
const lines = String(text || '').replace(/\r/g, '').split('\n');
|
|
92
|
+
if (!lines.length) {
|
|
93
|
+
return '';
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
let start = 0;
|
|
97
|
+
let end = lines.length;
|
|
98
|
+
|
|
99
|
+
while (start < end && lines[start].trim() === '') {
|
|
100
|
+
start += 1;
|
|
101
|
+
}
|
|
102
|
+
while (end > start && lines[end - 1].trim() === '') {
|
|
103
|
+
end -= 1;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (start < end && lines[start].trim().startsWith('```')) {
|
|
107
|
+
start += 1;
|
|
108
|
+
while (start < end && lines[start].trim() === '') {
|
|
109
|
+
start += 1;
|
|
110
|
+
}
|
|
111
|
+
if (end > start && lines[end - 1].trim() === '```') {
|
|
112
|
+
end -= 1;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
while (start < end && lines[start].trim() === '') {
|
|
117
|
+
start += 1;
|
|
118
|
+
}
|
|
119
|
+
while (end > start && lines[end - 1].trim() === '') {
|
|
120
|
+
end -= 1;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return lines.slice(start, end).join('\n').trim();
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
module.exports = {
|
|
127
|
+
parseReleaseVersion,
|
|
128
|
+
compareReleaseVersions,
|
|
129
|
+
buildVersionSuggestions,
|
|
130
|
+
pickLatestVersionTag,
|
|
131
|
+
normalizeCommitMessage
|
|
132
|
+
};
|
package/lib/web/frontend/app.css
CHANGED
|
@@ -651,21 +651,24 @@ body.mobile-actions-open .header-actions {
|
|
|
651
651
|
|
|
652
652
|
.workspace-shell {
|
|
653
653
|
min-height: 0;
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
654
|
+
height: 100%;
|
|
655
|
+
padding-top: 10px;
|
|
656
|
+
display: block;
|
|
657
|
+
overflow: hidden;
|
|
658
658
|
}
|
|
659
659
|
|
|
660
660
|
.workspace-main {
|
|
661
|
+
height: 100%;
|
|
661
662
|
min-height: 0;
|
|
662
663
|
display: grid;
|
|
663
664
|
grid-template-rows: minmax(0, 1fr) auto;
|
|
664
665
|
gap: 0;
|
|
666
|
+
overflow: hidden;
|
|
665
667
|
}
|
|
666
668
|
|
|
667
669
|
.workspace-pane {
|
|
668
670
|
min-height: 0;
|
|
671
|
+
height: 100%;
|
|
669
672
|
}
|
|
670
673
|
|
|
671
674
|
.workspace-pane[hidden],
|
|
@@ -707,16 +710,6 @@ body.mobile-actions-open .header-actions {
|
|
|
707
710
|
linear-gradient(180deg, rgba(255, 255, 255, 0.88) 0%, rgba(252, 246, 236, 0.88) 100%);
|
|
708
711
|
}
|
|
709
712
|
|
|
710
|
-
.context-panel {
|
|
711
|
-
min-height: 0;
|
|
712
|
-
overflow-y: auto;
|
|
713
|
-
border: 1px solid var(--line);
|
|
714
|
-
border-radius: 16px;
|
|
715
|
-
background:
|
|
716
|
-
linear-gradient(180deg, rgba(255, 255, 255, 0.94) 0%, rgba(251, 244, 232, 0.96) 100%);
|
|
717
|
-
box-shadow: 0 10px 24px rgba(46, 31, 13, 0.08);
|
|
718
|
-
}
|
|
719
|
-
|
|
720
713
|
.inspector-stack {
|
|
721
714
|
display: flex;
|
|
722
715
|
flex-direction: column;
|
|
@@ -1219,15 +1212,6 @@ body.command-mode .msg.origin-agent .bubble {
|
|
|
1219
1212
|
grid-template-columns: minmax(0, 1fr);
|
|
1220
1213
|
}
|
|
1221
1214
|
|
|
1222
|
-
.workspace-shell {
|
|
1223
|
-
grid-template-columns: minmax(0, 1fr);
|
|
1224
|
-
gap: 10px;
|
|
1225
|
-
}
|
|
1226
|
-
|
|
1227
|
-
.context-panel {
|
|
1228
|
-
display: none;
|
|
1229
|
-
}
|
|
1230
|
-
|
|
1231
1215
|
#messages,
|
|
1232
1216
|
#terminalPanel,
|
|
1233
1217
|
.inspector-pane {
|
|
@@ -1284,7 +1268,7 @@ body.command-mode .msg.origin-agent .bubble {
|
|
|
1284
1268
|
|
|
1285
1269
|
.workbench-tabs {
|
|
1286
1270
|
display: grid;
|
|
1287
|
-
grid-template-columns: repeat(
|
|
1271
|
+
grid-template-columns: repeat(5, minmax(0, 1fr));
|
|
1288
1272
|
gap: 6px;
|
|
1289
1273
|
}
|
|
1290
1274
|
|
|
@@ -67,6 +67,7 @@
|
|
|
67
67
|
<div class="workbench-tabs" id="workbenchTabs" aria-label="工作台视图">
|
|
68
68
|
<button type="button" id="viewActivityBtn" class="secondary is-active">活动</button>
|
|
69
69
|
<button type="button" id="viewTerminalBtn" class="secondary">终端</button>
|
|
70
|
+
<button type="button" id="viewDetailBtn" class="secondary">详情</button>
|
|
70
71
|
<button type="button" id="viewConfigBtn" class="secondary">配置</button>
|
|
71
72
|
<button type="button" id="viewCheckBtn" class="secondary">检查</button>
|
|
72
73
|
</div>
|
|
@@ -88,6 +89,9 @@
|
|
|
88
89
|
</div>
|
|
89
90
|
<div id="terminalScreen" aria-label="终端输出区域"></div>
|
|
90
91
|
</section>
|
|
92
|
+
<section id="detailPanel" class="workspace-pane inspector-pane" hidden>
|
|
93
|
+
<div id="detailSummary" class="inspector-stack"></div>
|
|
94
|
+
</section>
|
|
91
95
|
<section id="configPanel" class="workspace-pane inspector-pane" hidden>
|
|
92
96
|
<div id="configSummary" class="inspector-stack"></div>
|
|
93
97
|
</section>
|
|
@@ -112,9 +116,6 @@
|
|
|
112
116
|
</div>
|
|
113
117
|
</form>
|
|
114
118
|
</div>
|
|
115
|
-
<aside class="context-panel" id="contextPanel">
|
|
116
|
-
<div id="contextSummary" class="inspector-stack"></div>
|
|
117
|
-
</aside>
|
|
118
119
|
</section>
|
|
119
120
|
</main>
|
|
120
121
|
<div id="sidebarBackdrop" class="sidebar-backdrop" hidden></div>
|
package/lib/web/frontend/app.js
CHANGED
|
@@ -89,6 +89,7 @@
|
|
|
89
89
|
const headerActions = document.getElementById('headerActions');
|
|
90
90
|
const viewActivityBtn = document.getElementById('viewActivityBtn');
|
|
91
91
|
const viewTerminalBtn = document.getElementById('viewTerminalBtn');
|
|
92
|
+
const viewDetailBtn = document.getElementById('viewDetailBtn');
|
|
92
93
|
const viewConfigBtn = document.getElementById('viewConfigBtn');
|
|
93
94
|
const viewCheckBtn = document.getElementById('viewCheckBtn');
|
|
94
95
|
const mobileSidebarClose = document.getElementById('mobileSidebarClose');
|
|
@@ -129,11 +130,12 @@
|
|
|
129
130
|
const activityAgentBtn = document.getElementById('activityAgentBtn');
|
|
130
131
|
const messagesNode = document.getElementById('messages');
|
|
131
132
|
const terminalPanel = document.getElementById('terminalPanel');
|
|
133
|
+
const detailPanel = document.getElementById('detailPanel');
|
|
132
134
|
const configPanel = document.getElementById('configPanel');
|
|
133
135
|
const checkPanel = document.getElementById('checkPanel');
|
|
136
|
+
const detailSummary = document.getElementById('detailSummary');
|
|
134
137
|
const configSummary = document.getElementById('configSummary');
|
|
135
138
|
const checkSummary = document.getElementById('checkSummary');
|
|
136
|
-
const contextSummary = document.getElementById('contextSummary');
|
|
137
139
|
const terminalScreen = document.getElementById('terminalScreen');
|
|
138
140
|
const composer = document.getElementById('composer');
|
|
139
141
|
const commandInput = document.getElementById('commandInput');
|
|
@@ -186,7 +188,7 @@
|
|
|
186
188
|
if (message && message.mode === 'agent') {
|
|
187
189
|
return 'AGENT 回复';
|
|
188
190
|
}
|
|
189
|
-
return '
|
|
191
|
+
return '命令执行结果';
|
|
190
192
|
}
|
|
191
193
|
return '系统';
|
|
192
194
|
}
|
|
@@ -912,6 +914,7 @@
|
|
|
912
914
|
const VIEW_LABELS = {
|
|
913
915
|
activity: '活动',
|
|
914
916
|
terminal: '终端',
|
|
917
|
+
detail: '详情',
|
|
915
918
|
config: '配置',
|
|
916
919
|
check: '检查'
|
|
917
920
|
};
|
|
@@ -1003,20 +1006,20 @@
|
|
|
1003
1006
|
function renderSessionDetailPanels() {
|
|
1004
1007
|
const detail = state.sessionDetail;
|
|
1005
1008
|
if (!state.active) {
|
|
1006
|
-
renderEmptyInspector(
|
|
1009
|
+
renderEmptyInspector(detailSummary, '详情视图', '选择左侧会话后,这里会显示会话概览、Agent 状态与运行参数。');
|
|
1007
1010
|
renderEmptyInspector(configSummary, '配置视图', '选择会话后可查看当前容器会话的运行参数摘要。');
|
|
1008
1011
|
renderEmptyInspector(checkSummary, '检查视图', '选择会话后可查看当前会话的基础健康检查。');
|
|
1009
1012
|
return;
|
|
1010
1013
|
}
|
|
1011
1014
|
if (state.loadingSessionDetail) {
|
|
1012
|
-
renderEmptyInspector(
|
|
1015
|
+
renderEmptyInspector(detailSummary, '详情视图', '正在加载会话详情...');
|
|
1013
1016
|
renderEmptyInspector(configSummary, '配置视图', '正在加载会话详情...');
|
|
1014
1017
|
renderEmptyInspector(checkSummary, '检查视图', '正在加载会话详情...');
|
|
1015
1018
|
return;
|
|
1016
1019
|
}
|
|
1017
1020
|
if (!detail) {
|
|
1018
1021
|
const message = state.sessionDetailError || '当前会话详情暂时不可用。';
|
|
1019
|
-
renderEmptyInspector(
|
|
1022
|
+
renderEmptyInspector(detailSummary, '详情视图', message);
|
|
1020
1023
|
renderEmptyInspector(configSummary, '配置视图', message);
|
|
1021
1024
|
renderEmptyInspector(checkSummary, '检查视图', message);
|
|
1022
1025
|
return;
|
|
@@ -1026,23 +1029,23 @@
|
|
|
1026
1029
|
const status = sessionStatusInfo(detail.status);
|
|
1027
1030
|
const updatedText = formatDateTime(detail.updatedAt) || '暂无更新';
|
|
1028
1031
|
|
|
1029
|
-
if (
|
|
1030
|
-
|
|
1031
|
-
renderKeyValueCard(
|
|
1032
|
+
if (detailSummary) {
|
|
1033
|
+
detailSummary.innerHTML = '';
|
|
1034
|
+
renderKeyValueCard(detailSummary, '会话概览', [
|
|
1032
1035
|
{ label: '会话', value: detail.name || state.active },
|
|
1033
1036
|
{ label: '状态', value: status.label, tone: status.tone },
|
|
1034
1037
|
{ label: '镜像', value: detail.image || applied.imageName || '—' },
|
|
1035
1038
|
{ label: '最近更新', value: updatedText },
|
|
1036
1039
|
{ label: '消息数', value: String(safeMessageCount(detail.messageCount)) }
|
|
1037
1040
|
]);
|
|
1038
|
-
renderKeyValueCard(
|
|
1041
|
+
renderKeyValueCard(detailSummary, 'Agent 上下文', [
|
|
1039
1042
|
{ label: '已启用', value: detail.agentEnabled ? '是' : '否', tone: detail.agentEnabled ? 'ok' : 'warn' },
|
|
1040
1043
|
{ label: '程序', value: detail.agentProgram || '—' },
|
|
1041
1044
|
{ label: '支持 resume', value: detail.resumeSupported ? '是' : '否', tone: detail.resumeSupported ? 'ok' : 'warn' },
|
|
1042
1045
|
{ label: '最近 resume', value: detail.lastResumeAt ? formatDateTime(detail.lastResumeAt) : '暂无' },
|
|
1043
1046
|
{ label: '最近结果', value: detail.lastResumeOk == null ? '暂无' : (detail.lastResumeOk ? '成功' : '失败'), tone: detail.lastResumeOk == null ? 'info' : (detail.lastResumeOk ? 'ok' : 'danger') }
|
|
1044
1047
|
]);
|
|
1045
|
-
renderKeyValueCard(
|
|
1048
|
+
renderKeyValueCard(detailSummary, '运行参数', [
|
|
1046
1049
|
{ label: 'hostPath', value: applied.hostPath || '—' },
|
|
1047
1050
|
{ label: 'containerPath', value: applied.containerPath || '—' },
|
|
1048
1051
|
{ label: 'imageVersion', value: applied.imageVersion || '—' },
|
|
@@ -1139,6 +1142,7 @@
|
|
|
1139
1142
|
|
|
1140
1143
|
const activityTab = state.activeTab === 'activity';
|
|
1141
1144
|
const terminalTab = state.activeTab === 'terminal';
|
|
1145
|
+
const detailTab = state.activeTab === 'detail';
|
|
1142
1146
|
const configTab = state.activeTab === 'config';
|
|
1143
1147
|
const checkTab = state.activeTab === 'check';
|
|
1144
1148
|
const commandMode = state.mode === 'command';
|
|
@@ -1148,6 +1152,7 @@
|
|
|
1148
1152
|
document.body.classList.toggle('command-mode', commandMode);
|
|
1149
1153
|
document.body.classList.toggle('agent-mode', agentMode);
|
|
1150
1154
|
document.body.classList.toggle('terminal-mode', terminalTab);
|
|
1155
|
+
document.body.classList.toggle('detail-tab', detailTab);
|
|
1151
1156
|
document.body.classList.toggle('config-tab', configTab);
|
|
1152
1157
|
document.body.classList.toggle('check-tab', checkTab);
|
|
1153
1158
|
if (activityCommandBtn) {
|
|
@@ -1160,6 +1165,7 @@
|
|
|
1160
1165
|
}
|
|
1161
1166
|
if (viewActivityBtn) viewActivityBtn.classList.toggle('is-active', activityTab);
|
|
1162
1167
|
if (viewTerminalBtn) viewTerminalBtn.classList.toggle('is-active', terminalTab);
|
|
1168
|
+
if (viewDetailBtn) viewDetailBtn.classList.toggle('is-active', detailTab);
|
|
1163
1169
|
if (viewConfigBtn) viewConfigBtn.classList.toggle('is-active', configTab);
|
|
1164
1170
|
if (viewCheckBtn) viewCheckBtn.classList.toggle('is-active', checkTab);
|
|
1165
1171
|
if (messagesNode) {
|
|
@@ -1168,6 +1174,9 @@
|
|
|
1168
1174
|
if (terminalPanel) {
|
|
1169
1175
|
terminalPanel.hidden = !terminalTab;
|
|
1170
1176
|
}
|
|
1177
|
+
if (detailPanel) {
|
|
1178
|
+
detailPanel.hidden = !detailTab;
|
|
1179
|
+
}
|
|
1171
1180
|
if (configPanel) {
|
|
1172
1181
|
configPanel.hidden = !configTab;
|
|
1173
1182
|
}
|
|
@@ -1654,12 +1663,6 @@
|
|
|
1654
1663
|
|
|
1655
1664
|
row.appendChild(meta);
|
|
1656
1665
|
row.appendChild(bubble);
|
|
1657
|
-
if ((msg.role || '') === 'assistant' && typeof msg.exitCode === 'number') {
|
|
1658
|
-
const exitNode = document.createElement('div');
|
|
1659
|
-
exitNode.className = 'msg-exit';
|
|
1660
|
-
exitNode.textContent = `exit ${msg.exitCode}`;
|
|
1661
|
-
row.appendChild(exitNode);
|
|
1662
|
-
}
|
|
1663
1666
|
return row;
|
|
1664
1667
|
}
|
|
1665
1668
|
|
|
@@ -2179,6 +2182,12 @@
|
|
|
2179
2182
|
});
|
|
2180
2183
|
}
|
|
2181
2184
|
|
|
2185
|
+
if (viewDetailBtn) {
|
|
2186
|
+
viewDetailBtn.addEventListener('click', function () {
|
|
2187
|
+
setActiveTab('detail');
|
|
2188
|
+
});
|
|
2189
|
+
}
|
|
2190
|
+
|
|
2182
2191
|
if (viewConfigBtn) {
|
|
2183
2192
|
viewConfigBtn.addEventListener('click', function () {
|
|
2184
2193
|
setActiveTab('config');
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xcanwin/manyoyo",
|
|
3
|
-
"version": "5.6.
|
|
3
|
+
"version": "5.6.2",
|
|
4
4
|
"imageVersion": "1.9.0-common",
|
|
5
5
|
"playwrightCliVersion": "0.1.1",
|
|
6
6
|
"description": "AI Agent CLI Security Sandbox for Docker and Podman",
|
|
@@ -30,6 +30,7 @@
|
|
|
30
30
|
"my": "bin/manyoyo.js"
|
|
31
31
|
},
|
|
32
32
|
"scripts": {
|
|
33
|
+
"dev:release": "node scripts/dev-release.js",
|
|
33
34
|
"install-link": "npm link",
|
|
34
35
|
"test": "jest --coverage",
|
|
35
36
|
"test:unit": "jest test/",
|