@xcanwin/manyoyo 5.5.2 → 5.6.1
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/bin/manyoyo.js +29 -3
- package/lib/agent-resume.js +1 -1
- package/lib/web/frontend/app.css +250 -30
- package/lib/web/frontend/app.html +62 -47
- package/lib/web/frontend/app.js +353 -79
- package/lib/web/server.js +211 -24
- package/package.json +19 -8
package/lib/web/server.js
CHANGED
|
@@ -26,6 +26,8 @@ const WEB_TERMINAL_MIN_ROWS = 12;
|
|
|
26
26
|
const WEB_AGENT_CONTEXT_MAX_MESSAGES = 24;
|
|
27
27
|
const WEB_AGENT_CONTEXT_MAX_CHARS = 6000;
|
|
28
28
|
const WEB_AGENT_CONTEXT_PER_MESSAGE_MAX_CHARS = 600;
|
|
29
|
+
const WEB_AGENT_LAST_MESSAGE_BEGIN_MARKER = '__MANYOYO_LAST_MESSAGE_BEGIN__';
|
|
30
|
+
const WEB_AGENT_LAST_MESSAGE_END_MARKER = '__MANYOYO_LAST_MESSAGE_END__';
|
|
29
31
|
const WEB_AUTH_COOKIE_NAME = 'manyoyo_web_auth';
|
|
30
32
|
const WEB_AUTH_TTL_SECONDS = 12 * 60 * 60;
|
|
31
33
|
const FRONTEND_DIR = path.join(__dirname, 'frontend');
|
|
@@ -84,7 +86,8 @@ try {
|
|
|
84
86
|
XTERM_ADDON_FIT_JS_FILE = null;
|
|
85
87
|
}
|
|
86
88
|
try {
|
|
87
|
-
|
|
89
|
+
const markedPackageDir = path.dirname(require.resolve('marked/package.json'));
|
|
90
|
+
MARKED_MIN_JS_FILE = path.join(markedPackageDir, 'lib', 'marked.umd.js');
|
|
88
91
|
} catch (e) {
|
|
89
92
|
MARKED_MIN_JS_FILE = null;
|
|
90
93
|
}
|
|
@@ -124,7 +127,8 @@ function loadWebSessionHistory(webHistoryDir, containerName) {
|
|
|
124
127
|
resumeSupported: false,
|
|
125
128
|
lastResumeAt: null,
|
|
126
129
|
lastResumeOk: null,
|
|
127
|
-
lastResumeError: ''
|
|
130
|
+
lastResumeError: '',
|
|
131
|
+
applied: null
|
|
128
132
|
};
|
|
129
133
|
}
|
|
130
134
|
|
|
@@ -141,7 +145,10 @@ function loadWebSessionHistory(webHistoryDir, containerName) {
|
|
|
141
145
|
resumeSupported: data.resumeSupported === true,
|
|
142
146
|
lastResumeAt: typeof data.lastResumeAt === 'string' ? data.lastResumeAt : null,
|
|
143
147
|
lastResumeOk: typeof data.lastResumeOk === 'boolean' ? data.lastResumeOk : null,
|
|
144
|
-
lastResumeError: typeof data.lastResumeError === 'string' ? data.lastResumeError : ''
|
|
148
|
+
lastResumeError: typeof data.lastResumeError === 'string' ? data.lastResumeError : '',
|
|
149
|
+
applied: data.applied && typeof data.applied === 'object' && !Array.isArray(data.applied)
|
|
150
|
+
? data.applied
|
|
151
|
+
: null
|
|
145
152
|
};
|
|
146
153
|
} catch (e) {
|
|
147
154
|
return {
|
|
@@ -153,7 +160,8 @@ function loadWebSessionHistory(webHistoryDir, containerName) {
|
|
|
153
160
|
resumeSupported: false,
|
|
154
161
|
lastResumeAt: null,
|
|
155
162
|
lastResumeOk: null,
|
|
156
|
-
lastResumeError: ''
|
|
163
|
+
lastResumeError: '',
|
|
164
|
+
applied: null
|
|
157
165
|
};
|
|
158
166
|
}
|
|
159
167
|
}
|
|
@@ -251,6 +259,9 @@ function normalizeAgentPromptCommandTemplate(value, sourceLabel = 'agentPromptCo
|
|
|
251
259
|
if (!text.includes('{prompt}')) {
|
|
252
260
|
throw new Error(`${sourceLabel} 必须包含 {prompt} 占位符`);
|
|
253
261
|
}
|
|
262
|
+
if (/^codex\s+exec(?:\s|$)/.test(text) && !text.includes('--skip-git-repo-check')) {
|
|
263
|
+
return text.replace(/^codex\s+exec\b/, 'codex exec --skip-git-repo-check');
|
|
264
|
+
}
|
|
254
265
|
return text;
|
|
255
266
|
}
|
|
256
267
|
|
|
@@ -269,6 +280,49 @@ function renderAgentPromptCommand(template, prompt) {
|
|
|
269
280
|
return templateText.replace(/\{prompt\}/g, safePrompt);
|
|
270
281
|
}
|
|
271
282
|
|
|
283
|
+
function buildCodexAgentExecCommand(template, prompt) {
|
|
284
|
+
const templateText = normalizeAgentPromptCommandTemplate(template, 'agentPromptCommand');
|
|
285
|
+
const outputFile = `/tmp/manyoyo-web-agent-last-${Date.now()}-${crypto.randomBytes(6).toString('hex')}.txt`;
|
|
286
|
+
const quotedOutputFile = quoteBashSingleValue(outputFile);
|
|
287
|
+
const codexTemplate = templateText.replace(
|
|
288
|
+
/^((?:(?:[A-Za-z_][A-Za-z0-9_]*=)(?:"(?:\\.|[^"])*"|'(?:\\.|[^'])*'|[^\s]+)\s+)*)codex\s+exec\b/,
|
|
289
|
+
`$1codex exec --output-last-message ${quotedOutputFile}`
|
|
290
|
+
);
|
|
291
|
+
const command = codexTemplate === templateText
|
|
292
|
+
? renderAgentPromptCommand(templateText, prompt)
|
|
293
|
+
: renderAgentPromptCommand(codexTemplate, prompt);
|
|
294
|
+
return [
|
|
295
|
+
`rm -f ${quotedOutputFile}`,
|
|
296
|
+
command,
|
|
297
|
+
'__manyoyo_agent_exit=$?',
|
|
298
|
+
`if [ -f ${quotedOutputFile} ]; then printf '\\n${WEB_AGENT_LAST_MESSAGE_BEGIN_MARKER}\\n'; cat ${quotedOutputFile}; printf '\\n${WEB_AGENT_LAST_MESSAGE_END_MARKER}\\n'; fi`,
|
|
299
|
+
`rm -f ${quotedOutputFile}`,
|
|
300
|
+
'exit $__manyoyo_agent_exit'
|
|
301
|
+
].join('; ');
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
function buildWebAgentExecCommand(template, prompt, agentProgram) {
|
|
305
|
+
if (agentProgram === 'codex') {
|
|
306
|
+
return buildCodexAgentExecCommand(template, prompt);
|
|
307
|
+
}
|
|
308
|
+
return renderAgentPromptCommand(template, prompt);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
function extractLastMessageOutput(text) {
|
|
312
|
+
const raw = String(text || '');
|
|
313
|
+
const pattern = new RegExp(
|
|
314
|
+
`(?:^|\\r?\\n)${WEB_AGENT_LAST_MESSAGE_BEGIN_MARKER}\\r?\\n([\\s\\S]*?)(?:\\r?\\n)${WEB_AGENT_LAST_MESSAGE_END_MARKER}(?:\\r?\\n|$)`,
|
|
315
|
+
'g'
|
|
316
|
+
);
|
|
317
|
+
let lastMatch = null;
|
|
318
|
+
let matched = pattern.exec(raw);
|
|
319
|
+
while (matched) {
|
|
320
|
+
lastMatch = matched[1];
|
|
321
|
+
matched = pattern.exec(raw);
|
|
322
|
+
}
|
|
323
|
+
return String(lastMatch || '').trim();
|
|
324
|
+
}
|
|
325
|
+
|
|
272
326
|
function getAgentRuntimeMeta(history) {
|
|
273
327
|
const sessionHistory = history && typeof history === 'object' ? history : {};
|
|
274
328
|
const template = normalizeAgentPromptCommandTemplate(sessionHistory.agentPromptCommand, 'agentPromptCommand');
|
|
@@ -533,15 +587,51 @@ function normalizeStringArray(value, sourceLabel) {
|
|
|
533
587
|
.filter(Boolean);
|
|
534
588
|
}
|
|
535
589
|
|
|
590
|
+
function expandHomeAliasPath(filePath) {
|
|
591
|
+
const text = String(filePath || '').trim();
|
|
592
|
+
if (!text) {
|
|
593
|
+
return text;
|
|
594
|
+
}
|
|
595
|
+
const homeDir = os.homedir();
|
|
596
|
+
if (text === '~') {
|
|
597
|
+
return homeDir;
|
|
598
|
+
}
|
|
599
|
+
if (text.startsWith('~/')) {
|
|
600
|
+
return path.join(homeDir, text.slice(2));
|
|
601
|
+
}
|
|
602
|
+
if (text === '$HOME') {
|
|
603
|
+
return homeDir;
|
|
604
|
+
}
|
|
605
|
+
if (text.startsWith('$HOME/')) {
|
|
606
|
+
return path.join(homeDir, text.slice('$HOME/'.length));
|
|
607
|
+
}
|
|
608
|
+
return text;
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
function normalizeVolume(volume) {
|
|
612
|
+
const text = String(volume || '').trim();
|
|
613
|
+
if (!text.startsWith('~') && !text.startsWith('$HOME')) {
|
|
614
|
+
return text;
|
|
615
|
+
}
|
|
616
|
+
const separatorIndex = text.indexOf(':');
|
|
617
|
+
if (separatorIndex === -1) {
|
|
618
|
+
return expandHomeAliasPath(text);
|
|
619
|
+
}
|
|
620
|
+
const hostPath = text.slice(0, separatorIndex);
|
|
621
|
+
const rest = text.slice(separatorIndex);
|
|
622
|
+
return `${expandHomeAliasPath(hostPath)}${rest}`;
|
|
623
|
+
}
|
|
624
|
+
|
|
536
625
|
function parseEnvFileToArgs(filePath) {
|
|
537
|
-
|
|
626
|
+
const resolvedPath = expandHomeAliasPath(filePath);
|
|
627
|
+
if (!path.isAbsolute(resolvedPath)) {
|
|
538
628
|
throw new Error(`envFile 仅支持绝对路径: ${filePath}`);
|
|
539
629
|
}
|
|
540
|
-
if (!fs.existsSync(
|
|
541
|
-
throw new Error(`未找到环境文件: ${
|
|
630
|
+
if (!fs.existsSync(resolvedPath)) {
|
|
631
|
+
throw new Error(`未找到环境文件: ${resolvedPath}`);
|
|
542
632
|
}
|
|
543
633
|
|
|
544
|
-
const content = fs.readFileSync(
|
|
634
|
+
const content = fs.readFileSync(resolvedPath, 'utf-8');
|
|
545
635
|
const args = [];
|
|
546
636
|
const lines = content.split('\n');
|
|
547
637
|
|
|
@@ -897,7 +987,7 @@ function buildCreateRuntime(ctx, state, payload) {
|
|
|
897
987
|
: normalizeStringArray(config.volumes, 'config.volumes');
|
|
898
988
|
containerVolumes = [];
|
|
899
989
|
volumeList.forEach(volume => {
|
|
900
|
-
containerVolumes.push('--volume', volume);
|
|
990
|
+
containerVolumes.push('--volume', normalizeVolume(volume));
|
|
901
991
|
});
|
|
902
992
|
}
|
|
903
993
|
|
|
@@ -935,6 +1025,7 @@ function buildCreateRuntime(ctx, state, payload) {
|
|
|
935
1025
|
shellPrefix: shellPrefix || '',
|
|
936
1026
|
shell: shell || '',
|
|
937
1027
|
shellSuffix: shellSuffix || '',
|
|
1028
|
+
defaultCommand: buildDefaultCommand(shellPrefix, shell, shellSuffix) || '/bin/bash',
|
|
938
1029
|
agentEnabled: isAgentPromptCommandEnabled(agentPromptCommand),
|
|
939
1030
|
agentProgram: agentProgram || '',
|
|
940
1031
|
resumeSupported,
|
|
@@ -1056,34 +1147,50 @@ async function execCommandInWebContainer(ctx, containerName, command) {
|
|
|
1056
1147
|
);
|
|
1057
1148
|
|
|
1058
1149
|
const MAX_RAW_OUTPUT_CHARS = 32 * 1024 * 1024;
|
|
1059
|
-
let
|
|
1060
|
-
let
|
|
1150
|
+
let stdoutOutput = '';
|
|
1151
|
+
let stderrOutput = '';
|
|
1152
|
+
let stdoutTruncated = false;
|
|
1153
|
+
let stderrTruncated = false;
|
|
1061
1154
|
|
|
1062
|
-
function appendChunk(chunk) {
|
|
1155
|
+
function appendChunk(chunk, target) {
|
|
1063
1156
|
if (!chunk) return;
|
|
1064
1157
|
const text = chunk.toString('utf-8');
|
|
1065
1158
|
if (!text) return;
|
|
1066
|
-
if (
|
|
1067
|
-
|
|
1159
|
+
if (target.value.length >= MAX_RAW_OUTPUT_CHARS) {
|
|
1160
|
+
target.truncated = true;
|
|
1068
1161
|
return;
|
|
1069
1162
|
}
|
|
1070
|
-
const remain = MAX_RAW_OUTPUT_CHARS -
|
|
1163
|
+
const remain = MAX_RAW_OUTPUT_CHARS - target.value.length;
|
|
1071
1164
|
if (text.length > remain) {
|
|
1072
|
-
|
|
1073
|
-
|
|
1165
|
+
target.value += text.slice(0, remain);
|
|
1166
|
+
target.truncated = true;
|
|
1074
1167
|
return;
|
|
1075
1168
|
}
|
|
1076
|
-
|
|
1169
|
+
target.value += text;
|
|
1077
1170
|
}
|
|
1078
1171
|
|
|
1079
|
-
process.stdout.on('data', appendChunk
|
|
1080
|
-
|
|
1172
|
+
process.stdout.on('data', chunk => appendChunk(chunk, {
|
|
1173
|
+
get value() { return stdoutOutput; },
|
|
1174
|
+
set value(nextValue) { stdoutOutput = nextValue; },
|
|
1175
|
+
get truncated() { return stdoutTruncated; },
|
|
1176
|
+
set truncated(nextValue) { stdoutTruncated = nextValue; }
|
|
1177
|
+
}));
|
|
1178
|
+
process.stderr.on('data', chunk => appendChunk(chunk, {
|
|
1179
|
+
get value() { return stderrOutput; },
|
|
1180
|
+
set value(nextValue) { stderrOutput = nextValue; },
|
|
1181
|
+
get truncated() { return stderrTruncated; },
|
|
1182
|
+
set truncated(nextValue) { stderrTruncated = nextValue; }
|
|
1183
|
+
}));
|
|
1081
1184
|
|
|
1082
1185
|
process.on('error', reject);
|
|
1083
1186
|
process.on('close', code => {
|
|
1084
1187
|
const exitCode = typeof code === 'number' ? code : 1;
|
|
1085
|
-
const
|
|
1086
|
-
const
|
|
1188
|
+
const clippedStdout = stdoutTruncated ? `${stdoutOutput}\n...[stdout-truncated]` : stdoutOutput;
|
|
1189
|
+
const clippedStderr = stderrTruncated ? `${stderrOutput}\n...[stderr-truncated]` : stderrOutput;
|
|
1190
|
+
const clippedRaw = `${clippedStdout}${clippedStdout && clippedStderr ? '\n' : ''}${clippedStderr}`;
|
|
1191
|
+
const extractedLastMessage = extractLastMessageOutput(clippedStdout);
|
|
1192
|
+
const cleanOutputSource = extractedLastMessage || clippedRaw;
|
|
1193
|
+
const output = clipText(stripAnsi(cleanOutputSource).trim() || '(无输出)');
|
|
1087
1194
|
resolve({ exitCode, output });
|
|
1088
1195
|
});
|
|
1089
1196
|
});
|
|
@@ -1169,6 +1276,64 @@ function buildSessionSummary(ctx, state, containerMap, name) {
|
|
|
1169
1276
|
};
|
|
1170
1277
|
}
|
|
1171
1278
|
|
|
1279
|
+
function buildSessionFallbackApplied(ctx, state, name, history, summary) {
|
|
1280
|
+
const snapshot = readWebConfigSnapshot(state.webConfigPath);
|
|
1281
|
+
const defaults = buildConfigDefaults(ctx, snapshot.parseError ? {} : snapshot.parsed);
|
|
1282
|
+
const effectiveAgentPromptCommand = history.agentPromptCommand || defaults.agentPromptCommand || '';
|
|
1283
|
+
const effectiveAgentProgram = history.agentProgram || resolveAgentProgram(effectiveAgentPromptCommand) || '';
|
|
1284
|
+
const effectiveResumeSupported = history.resumeSupported === true
|
|
1285
|
+
|| Boolean(buildAgentResumeCommand(effectiveAgentProgram));
|
|
1286
|
+
const defaultCommand = buildDefaultCommand(
|
|
1287
|
+
defaults.shellPrefix,
|
|
1288
|
+
defaults.shell,
|
|
1289
|
+
defaults.shellSuffix
|
|
1290
|
+
) || buildStaticContainerRuntime(ctx, name).defaultCommand;
|
|
1291
|
+
|
|
1292
|
+
return {
|
|
1293
|
+
containerName: name,
|
|
1294
|
+
hostPath: defaults.hostPath || ctx.hostPath || '',
|
|
1295
|
+
containerPath: defaults.containerPath || ctx.containerPath || '',
|
|
1296
|
+
imageName: defaults.imageName || ctx.imageName || '',
|
|
1297
|
+
imageVersion: defaults.imageVersion || ctx.imageVersion || '',
|
|
1298
|
+
containerMode: defaults.containerMode || '',
|
|
1299
|
+
shellPrefix: defaults.shellPrefix || '',
|
|
1300
|
+
shell: defaults.shell || '',
|
|
1301
|
+
shellSuffix: defaults.shellSuffix || '',
|
|
1302
|
+
defaultCommand,
|
|
1303
|
+
agentEnabled: isAgentPromptCommandEnabled(effectiveAgentPromptCommand),
|
|
1304
|
+
agentProgram: effectiveAgentProgram,
|
|
1305
|
+
resumeSupported: effectiveResumeSupported,
|
|
1306
|
+
yolo: defaults.yolo || '',
|
|
1307
|
+
envCount: Object.keys(defaults.env || {}).length,
|
|
1308
|
+
volumeCount: Array.isArray(defaults.volumes) ? defaults.volumes.length : 0,
|
|
1309
|
+
portCount: Array.isArray(defaults.ports) ? defaults.ports.length : 0,
|
|
1310
|
+
status: summary.status || 'history'
|
|
1311
|
+
};
|
|
1312
|
+
}
|
|
1313
|
+
|
|
1314
|
+
function buildSessionDetail(ctx, state, containerMap, name) {
|
|
1315
|
+
const history = loadWebSessionHistory(state.webHistoryDir, name);
|
|
1316
|
+
const normalizedTemplate = normalizeAgentPromptCommandTemplate(history.agentPromptCommand, 'agentPromptCommand');
|
|
1317
|
+
const summary = buildSessionSummary(ctx, state, containerMap, name);
|
|
1318
|
+
const latestMessage = history.messages.length ? history.messages[history.messages.length - 1] : null;
|
|
1319
|
+
const applied = history.applied && typeof history.applied === 'object' && !Array.isArray(history.applied)
|
|
1320
|
+
? history.applied
|
|
1321
|
+
: buildSessionFallbackApplied(ctx, state, name, history, summary);
|
|
1322
|
+
|
|
1323
|
+
return {
|
|
1324
|
+
...summary,
|
|
1325
|
+
latestRole: latestMessage && latestMessage.role ? String(latestMessage.role) : '',
|
|
1326
|
+
latestTimestamp: latestMessage && latestMessage.timestamp ? latestMessage.timestamp : summary.updatedAt,
|
|
1327
|
+
agentPromptCommand: normalizedTemplate || '',
|
|
1328
|
+
agentProgram: history.agentProgram || summary.agentProgram || '',
|
|
1329
|
+
resumeSupported: history.resumeSupported === true || summary.resumeSupported === true,
|
|
1330
|
+
lastResumeAt: history.lastResumeAt || null,
|
|
1331
|
+
lastResumeOk: typeof history.lastResumeOk === 'boolean' ? history.lastResumeOk : null,
|
|
1332
|
+
lastResumeError: history.lastResumeError || '',
|
|
1333
|
+
applied
|
|
1334
|
+
};
|
|
1335
|
+
}
|
|
1336
|
+
|
|
1172
1337
|
function isSafeStaticAssetName(name) {
|
|
1173
1338
|
return /^[A-Za-z0-9._-]+$/.test(name);
|
|
1174
1339
|
}
|
|
@@ -1584,6 +1749,9 @@ async function handleWebApi(req, res, pathname, ctx, state) {
|
|
|
1584
1749
|
|
|
1585
1750
|
await ensureWebContainer(ctx, state, runtime);
|
|
1586
1751
|
setWebSessionAgentPromptCommand(state.webHistoryDir, runtime.containerName, runtime.agentPromptCommand);
|
|
1752
|
+
patchWebSessionAgentState(state.webHistoryDir, runtime.containerName, {
|
|
1753
|
+
applied: runtime.applied
|
|
1754
|
+
});
|
|
1587
1755
|
sendJson(res, 200, { name: runtime.containerName, applied: runtime.applied });
|
|
1588
1756
|
}
|
|
1589
1757
|
},
|
|
@@ -1599,6 +1767,20 @@ async function handleWebApi(req, res, pathname, ctx, state) {
|
|
|
1599
1767
|
sendJson(res, 200, { name: containerName, messages: history.messages });
|
|
1600
1768
|
}
|
|
1601
1769
|
},
|
|
1770
|
+
{
|
|
1771
|
+
method: 'GET',
|
|
1772
|
+
match: currentPath => currentPath.match(/^\/api\/sessions\/([^/]+)\/detail$/),
|
|
1773
|
+
handler: async match => {
|
|
1774
|
+
const containerName = getValidSessionName(ctx, res, match[1]);
|
|
1775
|
+
if (!containerName) {
|
|
1776
|
+
return;
|
|
1777
|
+
}
|
|
1778
|
+
|
|
1779
|
+
const containerMap = listWebManyoyoContainers(ctx);
|
|
1780
|
+
const detail = buildSessionDetail(ctx, state, containerMap, containerName);
|
|
1781
|
+
sendJson(res, 200, { name: containerName, detail });
|
|
1782
|
+
}
|
|
1783
|
+
},
|
|
1602
1784
|
{
|
|
1603
1785
|
method: 'POST',
|
|
1604
1786
|
match: currentPath => currentPath.match(/^\/api\/sessions\/([^/]+)\/run$/),
|
|
@@ -1645,6 +1827,11 @@ async function handleWebApi(req, res, pathname, ctx, state) {
|
|
|
1645
1827
|
}
|
|
1646
1828
|
|
|
1647
1829
|
const history = loadWebSessionHistory(state.webHistoryDir, containerName);
|
|
1830
|
+
const normalizedTemplate = normalizeAgentPromptCommandTemplate(history.agentPromptCommand, 'agentPromptCommand');
|
|
1831
|
+
if (normalizedTemplate !== history.agentPromptCommand) {
|
|
1832
|
+
history.agentPromptCommand = normalizedTemplate;
|
|
1833
|
+
saveWebSessionHistory(state.webHistoryDir, containerName, history);
|
|
1834
|
+
}
|
|
1648
1835
|
if (!isAgentPromptCommandEnabled(history.agentPromptCommand)) {
|
|
1649
1836
|
sendJson(res, 400, { error: '当前会话未配置 agentPromptCommand' });
|
|
1650
1837
|
return;
|
|
@@ -1669,7 +1856,7 @@ async function handleWebApi(req, res, pathname, ctx, state) {
|
|
|
1669
1856
|
const effectivePrompt = resumeSucceeded
|
|
1670
1857
|
? prompt
|
|
1671
1858
|
: buildAgentPromptWithHistory(history, prompt);
|
|
1672
|
-
const command =
|
|
1859
|
+
const command = buildWebAgentExecCommand(history.agentPromptCommand, effectivePrompt, agentMeta.agentProgram);
|
|
1673
1860
|
const contextMode = resumeSucceeded ? 'resume' : (hasPriorConversation ? 'history-injected' : 'first-turn');
|
|
1674
1861
|
appendWebSessionMessage(state.webHistoryDir, containerName, 'user', prompt, {
|
|
1675
1862
|
mode: 'agent',
|
|
@@ -1995,7 +2182,7 @@ async function startWebServer(options) {
|
|
|
1995
2182
|
const { GREEN, CYAN, YELLOW, NC } = ctx.colors;
|
|
1996
2183
|
const listenHost = formatUrlHost(ctx.serverHost);
|
|
1997
2184
|
console.log(`${GREEN}✅ MANYOYO Web 服务已启动: http://${listenHost}:${listenPort}${NC}`);
|
|
1998
|
-
console.log(`${CYAN}提示: 左侧是 manyoyo
|
|
2185
|
+
console.log(`${CYAN}提示: 左侧是 manyoyo 容器会话列表,中间是活动/终端/配置/检查工作台,右侧显示当前会话上下文。${NC}`);
|
|
1999
2186
|
if (ctx.serverHost === '0.0.0.0') {
|
|
2000
2187
|
console.log(`${CYAN}提示: 当前监听全部网卡,请用本机局域网 IP 访问。${NC}`);
|
|
2001
2188
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xcanwin/manyoyo",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.6.1",
|
|
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",
|
|
@@ -58,25 +58,36 @@
|
|
|
58
58
|
"@playwright/mcp": "0.0.68",
|
|
59
59
|
"@xterm/addon-fit": "^0.11.0",
|
|
60
60
|
"@xterm/xterm": "^6.0.0",
|
|
61
|
-
"commander": "^
|
|
61
|
+
"commander": "^14.0.3",
|
|
62
62
|
"json5": "^2.2.3",
|
|
63
|
-
"marked": "^
|
|
63
|
+
"marked": "^17.0.5",
|
|
64
64
|
"playwright": "1.58.2",
|
|
65
|
-
"ws": "^8.
|
|
65
|
+
"ws": "^8.20.0"
|
|
66
66
|
},
|
|
67
67
|
"devDependencies": {
|
|
68
|
-
"jest": "^30.
|
|
69
|
-
"vitepress": "^
|
|
68
|
+
"jest": "^30.3.0",
|
|
69
|
+
"vitepress": "^1.6.4"
|
|
70
70
|
},
|
|
71
71
|
"overrides": {
|
|
72
|
+
"esbuild": "^0.25.12",
|
|
72
73
|
"glob": "^13.0.6",
|
|
73
74
|
"minimatch": "^10.2.2",
|
|
74
|
-
"test-exclude": "^8.0.0"
|
|
75
|
+
"test-exclude": "^8.0.0",
|
|
76
|
+
"vite": "^6.4.1"
|
|
75
77
|
},
|
|
76
78
|
"jest": {
|
|
77
79
|
"testMatch": [
|
|
78
80
|
"**/test/**/*.test.js"
|
|
79
81
|
],
|
|
80
|
-
"testEnvironment": "node"
|
|
82
|
+
"testEnvironment": "node",
|
|
83
|
+
"modulePathIgnorePatterns": [
|
|
84
|
+
"<rootDir>/temp/"
|
|
85
|
+
],
|
|
86
|
+
"testPathIgnorePatterns": [
|
|
87
|
+
"<rootDir>/temp/"
|
|
88
|
+
],
|
|
89
|
+
"watchPathIgnorePatterns": [
|
|
90
|
+
"<rootDir>/temp/"
|
|
91
|
+
]
|
|
81
92
|
}
|
|
82
93
|
}
|