@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.
@@ -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
+ };
@@ -651,21 +651,24 @@ body.mobile-actions-open .header-actions {
651
651
 
652
652
  .workspace-shell {
653
653
  min-height: 0;
654
- margin-top: 10px;
655
- display: grid;
656
- grid-template-columns: minmax(0, 1fr) 320px;
657
- gap: 14px;
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(4, minmax(0, 1fr));
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>
@@ -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(contextSummary, '当前上下文', '选择左侧会话后,这里会显示容器状态、配置摘要与 Agent 信息。');
1009
+ renderEmptyInspector(detailSummary, '详情视图', '选择左侧会话后,这里会显示会话概览、Agent 状态与运行参数。');
1007
1010
  renderEmptyInspector(configSummary, '配置视图', '选择会话后可查看当前容器会话的运行参数摘要。');
1008
1011
  renderEmptyInspector(checkSummary, '检查视图', '选择会话后可查看当前会话的基础健康检查。');
1009
1012
  return;
1010
1013
  }
1011
1014
  if (state.loadingSessionDetail) {
1012
- renderEmptyInspector(contextSummary, '当前上下文', '正在加载会话详情...');
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(contextSummary, '当前上下文', message);
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 (contextSummary) {
1030
- contextSummary.innerHTML = '';
1031
- renderKeyValueCard(contextSummary, '会话概览', [
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(contextSummary, 'Agent 上下文', [
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(contextSummary, '运行参数', [
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.1",
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/",