@xcanwin/manyoyo 7.0.6 → 7.0.8
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/capacity.js +92 -0
- package/lib/json5-text-edit.js +62 -1
- package/lib/web/frontend/shadcn.html +121 -63
- package/lib/web/server.js +85 -4
- package/manyoyo.example.json +7 -1
- package/package.json +1 -1
package/lib/web/server.js
CHANGED
|
@@ -9,8 +9,9 @@ const http = require('http');
|
|
|
9
9
|
const WebSocket = require('ws');
|
|
10
10
|
const JSON5 = require('json5');
|
|
11
11
|
const { buildContainerRunArgs } = require('../container-run');
|
|
12
|
+
const { estimateContainerCapacity } = require('../capacity');
|
|
12
13
|
const { extractAgentMessageFromCodexJsonl } = require('../codex-output');
|
|
13
|
-
const { findValueRangeByPath, applyTextReplacements } = require('../json5-text-edit');
|
|
14
|
+
const { findValueRangeByPath, applyTextReplacements, upsertValueByPath } = require('../json5-text-edit');
|
|
14
15
|
const { resolveRuntimeConfig } = require('../runtime-resolver');
|
|
15
16
|
const {
|
|
16
17
|
parseEnvEntry,
|
|
@@ -4505,6 +4506,83 @@ async function handleWebApi(req, res, pathname, ctx, state) {
|
|
|
4505
4506
|
});
|
|
4506
4507
|
}
|
|
4507
4508
|
},
|
|
4509
|
+
{
|
|
4510
|
+
method: 'GET',
|
|
4511
|
+
match: currentPath => currentPath === '/api/system/capacity' ? [] : null,
|
|
4512
|
+
handler: async () => {
|
|
4513
|
+
const containerMap = listWebManyoyoContainers(ctx);
|
|
4514
|
+
const diskPath = path.dirname(path.resolve(state.webConfigPath));
|
|
4515
|
+
const report = estimateContainerCapacity({
|
|
4516
|
+
runtimeCommand: ctx.dockerCmd || 'docker',
|
|
4517
|
+
imageName: ctx.imageName,
|
|
4518
|
+
imageVersion: ctx.imageVersion,
|
|
4519
|
+
containerNames: Object.keys(containerMap),
|
|
4520
|
+
diskPath,
|
|
4521
|
+
runCommand: (command, args) => ctx.dockerExecArgs(args, { ignoreError: false }),
|
|
4522
|
+
statfs: statPath => fs.statfsSync(statPath)
|
|
4523
|
+
});
|
|
4524
|
+
sendJson(res, 200, report);
|
|
4525
|
+
}
|
|
4526
|
+
},
|
|
4527
|
+
{
|
|
4528
|
+
method: 'GET',
|
|
4529
|
+
match: currentPath => currentPath === '/api/system/quick-chat-config' ? [] : null,
|
|
4530
|
+
handler: async () => {
|
|
4531
|
+
const snapshot = readWebConfigSnapshot(state.webConfigPath);
|
|
4532
|
+
const serve = snapshot.parsed && typeof snapshot.parsed.serve === 'object' && snapshot.parsed.serve !== null
|
|
4533
|
+
? snapshot.parsed.serve
|
|
4534
|
+
: {};
|
|
4535
|
+
const quickChat = serve.quickChat && typeof serve.quickChat === 'object' ? serve.quickChat : {};
|
|
4536
|
+
sendJson(res, 200, {
|
|
4537
|
+
path: typeof quickChat.path === 'string' && quickChat.path.trim() ? quickChat.path : null,
|
|
4538
|
+
run: typeof quickChat.run === 'string' && quickChat.run.trim() ? quickChat.run : null
|
|
4539
|
+
});
|
|
4540
|
+
}
|
|
4541
|
+
},
|
|
4542
|
+
{
|
|
4543
|
+
method: 'PUT',
|
|
4544
|
+
match: currentPath => currentPath === '/api/system/quick-chat-config' ? [] : null,
|
|
4545
|
+
handler: async () => {
|
|
4546
|
+
const payload = await readJsonBody(req);
|
|
4547
|
+
const quickChatPath = typeof payload.path === 'string' ? payload.path.trim() : '';
|
|
4548
|
+
const quickChatRun = typeof payload.run === 'string' ? payload.run.trim() : '';
|
|
4549
|
+
if (!quickChatPath) {
|
|
4550
|
+
sendJson(res, 400, { error: 'path 不能为空' });
|
|
4551
|
+
return;
|
|
4552
|
+
}
|
|
4553
|
+
if (!quickChatRun) {
|
|
4554
|
+
sendJson(res, 400, { error: 'run 不能为空' });
|
|
4555
|
+
return;
|
|
4556
|
+
}
|
|
4557
|
+
const resolvedPath = expandHomeAliasPath(quickChatPath);
|
|
4558
|
+
const homeDir = process.env.HOME || os.homedir() || '/home';
|
|
4559
|
+
if (resolvedPath === '/' || resolvedPath === homeDir) {
|
|
4560
|
+
sendJson(res, 400, { error: 'path 不能是根目录或 home 目录本身' });
|
|
4561
|
+
return;
|
|
4562
|
+
}
|
|
4563
|
+
|
|
4564
|
+
const snapshot = readWebConfigSnapshot(state.webConfigPath);
|
|
4565
|
+
if (snapshot.parseError) {
|
|
4566
|
+
sendJson(res, 400, { error: '当前配置解析失败,无法写入', detail: snapshot.parseError });
|
|
4567
|
+
return;
|
|
4568
|
+
}
|
|
4569
|
+
|
|
4570
|
+
let nextRaw;
|
|
4571
|
+
try {
|
|
4572
|
+
nextRaw = upsertValueByPath(snapshot.raw, ['serve', 'quickChat', 'path'], JSON.stringify(quickChatPath));
|
|
4573
|
+
nextRaw = upsertValueByPath(nextRaw, ['serve', 'quickChat', 'run'], JSON.stringify(quickChatRun));
|
|
4574
|
+
} catch (e) {
|
|
4575
|
+
sendJson(res, 400, { error: '配置写入失败', detail: e.message || '' });
|
|
4576
|
+
return;
|
|
4577
|
+
}
|
|
4578
|
+
|
|
4579
|
+
const savePath = path.resolve(state.webConfigPath);
|
|
4580
|
+
fs.mkdirSync(path.dirname(savePath), { recursive: true });
|
|
4581
|
+
fs.writeFileSync(savePath, nextRaw, 'utf-8');
|
|
4582
|
+
|
|
4583
|
+
sendJson(res, 200, { saved: true, path: quickChatPath, run: quickChatRun });
|
|
4584
|
+
}
|
|
4585
|
+
},
|
|
4508
4586
|
{
|
|
4509
4587
|
method: 'GET',
|
|
4510
4588
|
match: currentPath => currentPath === '/api/sessions' ? [] : null,
|
|
@@ -5044,14 +5122,17 @@ async function handleWebApi(req, res, pathname, ctx, state) {
|
|
|
5044
5122
|
}
|
|
5045
5123
|
|
|
5046
5124
|
await ensureWebContainer(ctx, state, sessionRef.containerName, sessionRef);
|
|
5047
|
-
appendWebSessionMessage(state.webHistoryDir, sessionRef, 'user', command);
|
|
5125
|
+
appendWebSessionMessage(state.webHistoryDir, sessionRef, 'user', command, { mode: 'command' });
|
|
5048
5126
|
const result = await execCommandInWebContainer(ctx, sessionRef.containerName, command);
|
|
5127
|
+
// role 用 'system'、带 mode: 'command',与前端实时发送时的约定对齐(workspace-panel.tsx
|
|
5128
|
+
// handleSend 的 command 分支)——命令输出本来就不该走 assistant 的气泡样式和 markdown 渲染,
|
|
5129
|
+
// 之前这里存的是 'assistant' 且没带 mode,历史记录重新加载后气泡样式和渲染方式会跟实时时不一致
|
|
5049
5130
|
appendWebSessionMessage(
|
|
5050
5131
|
state.webHistoryDir,
|
|
5051
5132
|
sessionRef,
|
|
5052
|
-
'
|
|
5133
|
+
'system',
|
|
5053
5134
|
result.output,
|
|
5054
|
-
{ exitCode: result.exitCode }
|
|
5135
|
+
{ exitCode: result.exitCode, mode: 'command' }
|
|
5055
5136
|
);
|
|
5056
5137
|
sendJson(res, 200, { exitCode: result.exitCode, output: result.output });
|
|
5057
5138
|
}
|
package/manyoyo.example.json
CHANGED
|
@@ -47,8 +47,14 @@
|
|
|
47
47
|
// serve 命令专属配置(覆盖型:runs.<name>.serve > 全局配置)
|
|
48
48
|
// 不设置 serve 字段(或不设置 title 字段)时,网页 <title> 按当前会话 Agent 名动态显示
|
|
49
49
|
// 一旦设置 title,则固定显示该值(不再随会话变化),留空字符串 "" 即固定显示为空
|
|
50
|
+
// quickChat 是网页端"快捷对话"按钮的配置:path 为工作根目录(每次点击按时间戳建子目录),
|
|
51
|
+
// run 为使用哪个 runs.<name> 配置;也可以在网页「系统设置 > 快捷对话」里填写,效果一样
|
|
50
52
|
// "serve": {
|
|
51
|
-
// "title": "My MANYOYO"
|
|
53
|
+
// "title": "My MANYOYO",
|
|
54
|
+
// "quickChat": {
|
|
55
|
+
// "path": "~/.manyoyo/workpath/",
|
|
56
|
+
// "run": "claude"
|
|
57
|
+
// }
|
|
52
58
|
// },
|
|
53
59
|
|
|
54
60
|
// 可选插件(manyoyo playwright / manyoyo plugin playwright)
|