@xcanwin/manyoyo 5.1.10 → 5.2.5
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 +109 -4
- package/config.example.json +13 -0
- package/lib/agent-resume.js +15 -1
- package/lib/web/frontend/app.css +46 -12
- package/lib/web/frontend/app.html +7 -2
- package/lib/web/frontend/app.js +284 -31
- package/lib/web/frontend/markdown-renderer.js +115 -0
- package/lib/web/frontend/markdown.css +76 -0
- package/lib/web/server.js +296 -7
- package/package.json +2 -1
package/bin/manyoyo.js
CHANGED
|
@@ -56,8 +56,12 @@ let IMAGE_VERSION = IMAGE_VERSION_DEFAULT || `${IMAGE_VERSION_BASE}-common`;
|
|
|
56
56
|
let EXEC_COMMAND = "";
|
|
57
57
|
let EXEC_COMMAND_PREFIX = "";
|
|
58
58
|
let EXEC_COMMAND_SUFFIX = "";
|
|
59
|
+
let FIRST_EXEC_COMMAND = "";
|
|
60
|
+
let FIRST_EXEC_COMMAND_PREFIX = "";
|
|
61
|
+
let FIRST_EXEC_COMMAND_SUFFIX = "";
|
|
59
62
|
let IMAGE_BUILD_ARGS = [];
|
|
60
63
|
let CONTAINER_ENVS = [];
|
|
64
|
+
let FIRST_CONTAINER_ENVS = [];
|
|
61
65
|
let CONTAINER_VOLUMES = [];
|
|
62
66
|
let CONTAINER_PORTS = [];
|
|
63
67
|
const MANYOYO_NAME = detectCommandName();
|
|
@@ -236,6 +240,7 @@ function sanitizeSensitiveData(obj) {
|
|
|
236
240
|
* @property {string} [imageVersion] - 镜像版本
|
|
237
241
|
* @property {Object.<string, string|number|boolean>} [env] - 环境变量映射
|
|
238
242
|
* @property {string[]} [envFile] - 环境文件数组
|
|
243
|
+
* @property {{shellPrefix?:string,shell?:string,shellSuffix?:string,env?:Object.<string,string|number|boolean>,envFile?:string[]}} [first] - 仅首次创建容器执行的一次性命令配置
|
|
239
244
|
* @property {string[]} [volumes] - 挂载卷数组
|
|
240
245
|
* @property {Object.<string, Object>} [plugins] - 可选插件配置映射(如 plugins.playwright)
|
|
241
246
|
* @property {Object.<string, Object>} [runs] - 运行配置映射(-r <name>)
|
|
@@ -436,12 +441,27 @@ function normalizeCliEnvMap(envList) {
|
|
|
436
441
|
return envMap;
|
|
437
442
|
}
|
|
438
443
|
|
|
439
|
-
function
|
|
444
|
+
function normalizeFirstConfig(firstConfig, sourceLabel) {
|
|
445
|
+
if (firstConfig === undefined || firstConfig === null) {
|
|
446
|
+
return {};
|
|
447
|
+
}
|
|
448
|
+
if (typeof firstConfig !== 'object' || Array.isArray(firstConfig)) {
|
|
449
|
+
console.error(`${RED}⚠️ 错误: ${sourceLabel} 的 first 必须是对象(map),例如 {"shell":"init.sh"}${NC}`);
|
|
450
|
+
process.exit(1);
|
|
451
|
+
}
|
|
452
|
+
return firstConfig;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
function addEnvTo(targetEnvs, env) {
|
|
440
456
|
const parsed = parseEnvEntry(env);
|
|
441
|
-
|
|
457
|
+
targetEnvs.push("--env", `${parsed.key}=${parsed.value}`);
|
|
442
458
|
}
|
|
443
459
|
|
|
444
|
-
function
|
|
460
|
+
function addEnv(env) {
|
|
461
|
+
addEnvTo(CONTAINER_ENVS, env);
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
function addEnvFileTo(targetEnvs, envFile) {
|
|
445
465
|
const filePath = String(envFile || '').trim();
|
|
446
466
|
if (!path.isAbsolute(filePath)) {
|
|
447
467
|
console.error(`${RED}⚠️ 错误: --env-file 仅支持绝对路径: ${envFile}${NC}`);
|
|
@@ -472,7 +492,7 @@ function addEnvFile(envFile) {
|
|
|
472
492
|
}
|
|
473
493
|
|
|
474
494
|
if (key) {
|
|
475
|
-
|
|
495
|
+
targetEnvs.push("--env", `${key}=${value}`);
|
|
476
496
|
}
|
|
477
497
|
}
|
|
478
498
|
}
|
|
@@ -482,6 +502,10 @@ function addEnvFile(envFile) {
|
|
|
482
502
|
return {};
|
|
483
503
|
}
|
|
484
504
|
|
|
505
|
+
function addEnvFile(envFile) {
|
|
506
|
+
return addEnvFileTo(CONTAINER_ENVS, envFile);
|
|
507
|
+
}
|
|
508
|
+
|
|
485
509
|
function addVolume(volume) {
|
|
486
510
|
CONTAINER_VOLUMES.push("--volume", volume);
|
|
487
511
|
}
|
|
@@ -1128,6 +1152,8 @@ async function setupCommander() {
|
|
|
1128
1152
|
|
|
1129
1153
|
// Load run config if specified
|
|
1130
1154
|
const runConfig = options.run ? loadRunConfig(options.run, config) : {};
|
|
1155
|
+
const globalFirstConfig = normalizeFirstConfig(config.first, '全局配置');
|
|
1156
|
+
const runFirstConfig = normalizeFirstConfig(runConfig.first, '运行配置');
|
|
1131
1157
|
|
|
1132
1158
|
// Merge configs: command line > run config > global config > defaults
|
|
1133
1159
|
// Override mode (scalar values): use first defined value
|
|
@@ -1158,6 +1184,18 @@ async function setupCommander() {
|
|
|
1158
1184
|
if (mergedShellSuffix) {
|
|
1159
1185
|
EXEC_COMMAND_SUFFIX = normalizeCommandSuffix(mergedShellSuffix);
|
|
1160
1186
|
}
|
|
1187
|
+
const mergedFirstShellPrefix = pickConfigValue(runFirstConfig.shellPrefix, globalFirstConfig.shellPrefix);
|
|
1188
|
+
if (mergedFirstShellPrefix) {
|
|
1189
|
+
FIRST_EXEC_COMMAND_PREFIX = `${mergedFirstShellPrefix} `;
|
|
1190
|
+
}
|
|
1191
|
+
const mergedFirstShell = pickConfigValue(runFirstConfig.shell, globalFirstConfig.shell);
|
|
1192
|
+
if (mergedFirstShell) {
|
|
1193
|
+
FIRST_EXEC_COMMAND = mergedFirstShell;
|
|
1194
|
+
}
|
|
1195
|
+
const mergedFirstShellSuffix = pickConfigValue(runFirstConfig.shellSuffix, globalFirstConfig.shellSuffix);
|
|
1196
|
+
if (mergedFirstShellSuffix) {
|
|
1197
|
+
FIRST_EXEC_COMMAND_SUFFIX = normalizeCommandSuffix(mergedFirstShellSuffix);
|
|
1198
|
+
}
|
|
1161
1199
|
|
|
1162
1200
|
// Basic name validation to reduce injection risk
|
|
1163
1201
|
validateName('containerName', CONTAINER_NAME, SAFE_CONTAINER_NAME_PATTERN);
|
|
@@ -1181,6 +1219,18 @@ async function setupCommander() {
|
|
|
1181
1219
|
};
|
|
1182
1220
|
Object.entries(envMap).forEach(([key, value]) => addEnv(`${key}=${value}`));
|
|
1183
1221
|
|
|
1222
|
+
const firstEnvFileList = [
|
|
1223
|
+
...toArray(globalFirstConfig.envFile),
|
|
1224
|
+
...toArray(runFirstConfig.envFile)
|
|
1225
|
+
].filter(Boolean);
|
|
1226
|
+
firstEnvFileList.forEach(ef => addEnvFileTo(FIRST_CONTAINER_ENVS, ef));
|
|
1227
|
+
|
|
1228
|
+
const firstEnvMap = {
|
|
1229
|
+
...normalizeJsonEnvMap(globalFirstConfig.env, '全局配置 first'),
|
|
1230
|
+
...normalizeJsonEnvMap(runFirstConfig.env, '运行配置 first')
|
|
1231
|
+
};
|
|
1232
|
+
Object.entries(firstEnvMap).forEach(([key, value]) => addEnvTo(FIRST_CONTAINER_ENVS, `${key}=${value}`));
|
|
1233
|
+
|
|
1184
1234
|
const volumeList = mergeArrayConfig(config.volumes, runConfig.volumes, options.volume);
|
|
1185
1235
|
volumeList.forEach(v => addVolume(v));
|
|
1186
1236
|
|
|
@@ -1267,6 +1317,18 @@ async function setupCommander() {
|
|
|
1267
1317
|
prefix: EXEC_COMMAND_PREFIX,
|
|
1268
1318
|
shell: EXEC_COMMAND,
|
|
1269
1319
|
suffix: EXEC_COMMAND_SUFFIX
|
|
1320
|
+
},
|
|
1321
|
+
first: {
|
|
1322
|
+
envFile: firstEnvFileList,
|
|
1323
|
+
env: firstEnvMap,
|
|
1324
|
+
shellPrefix: FIRST_EXEC_COMMAND_PREFIX.trim(),
|
|
1325
|
+
shell: FIRST_EXEC_COMMAND || "",
|
|
1326
|
+
shellSuffix: FIRST_EXEC_COMMAND_SUFFIX || "",
|
|
1327
|
+
exec: {
|
|
1328
|
+
prefix: FIRST_EXEC_COMMAND_PREFIX,
|
|
1329
|
+
shell: FIRST_EXEC_COMMAND,
|
|
1330
|
+
suffix: FIRST_EXEC_COMMAND_SUFFIX
|
|
1331
|
+
}
|
|
1270
1332
|
}
|
|
1271
1333
|
};
|
|
1272
1334
|
// 敏感信息脱敏
|
|
@@ -1300,8 +1362,12 @@ function createRuntimeContext(modeState = {}) {
|
|
|
1300
1362
|
execCommand: EXEC_COMMAND,
|
|
1301
1363
|
execCommandPrefix: EXEC_COMMAND_PREFIX,
|
|
1302
1364
|
execCommandSuffix: EXEC_COMMAND_SUFFIX,
|
|
1365
|
+
firstExecCommand: FIRST_EXEC_COMMAND,
|
|
1366
|
+
firstExecCommandPrefix: FIRST_EXEC_COMMAND_PREFIX,
|
|
1367
|
+
firstExecCommandSuffix: FIRST_EXEC_COMMAND_SUFFIX,
|
|
1303
1368
|
contModeArgs: CONT_MODE_ARGS,
|
|
1304
1369
|
containerEnvs: CONTAINER_ENVS,
|
|
1370
|
+
firstContainerEnvs: FIRST_CONTAINER_ENVS,
|
|
1305
1371
|
containerVolumes: CONTAINER_VOLUMES,
|
|
1306
1372
|
containerPorts: CONTAINER_PORTS,
|
|
1307
1373
|
quiet: QUIET,
|
|
@@ -1379,6 +1445,42 @@ function joinExecCommand(prefix, command, suffix) {
|
|
|
1379
1445
|
return `${prefix || ''}${command || ''}${suffix || ''}`;
|
|
1380
1446
|
}
|
|
1381
1447
|
|
|
1448
|
+
function executeFirstCommand(runtime) {
|
|
1449
|
+
if (!runtime.firstExecCommand || !String(runtime.firstExecCommand).trim()) {
|
|
1450
|
+
return;
|
|
1451
|
+
}
|
|
1452
|
+
|
|
1453
|
+
const firstCommand = joinExecCommand(
|
|
1454
|
+
runtime.firstExecCommandPrefix,
|
|
1455
|
+
runtime.firstExecCommand,
|
|
1456
|
+
runtime.firstExecCommandSuffix
|
|
1457
|
+
);
|
|
1458
|
+
|
|
1459
|
+
if (!(runtime.quiet.cmd || runtime.quiet.full)) {
|
|
1460
|
+
console.log(`${BLUE}----------------------------------------${NC}`);
|
|
1461
|
+
console.log(`⚙️ 首次预执行命令: ${YELLOW}${firstCommand}${NC}`);
|
|
1462
|
+
}
|
|
1463
|
+
|
|
1464
|
+
const firstExecArgs = [
|
|
1465
|
+
'exec',
|
|
1466
|
+
...(runtime.firstContainerEnvs || []),
|
|
1467
|
+
runtime.containerName,
|
|
1468
|
+
'/bin/bash',
|
|
1469
|
+
'-c',
|
|
1470
|
+
firstCommand
|
|
1471
|
+
];
|
|
1472
|
+
const firstExecResult = spawnSync(`${DOCKER_CMD}`, firstExecArgs, { stdio: 'inherit' });
|
|
1473
|
+
if (firstExecResult.error) {
|
|
1474
|
+
throw firstExecResult.error;
|
|
1475
|
+
}
|
|
1476
|
+
if (typeof firstExecResult.status === 'number' && firstExecResult.status !== 0) {
|
|
1477
|
+
throw new Error(`首次预执行命令失败,退出码: ${firstExecResult.status}`);
|
|
1478
|
+
}
|
|
1479
|
+
if (firstExecResult.signal) {
|
|
1480
|
+
throw new Error(`首次预执行命令被信号终止: ${firstExecResult.signal}`);
|
|
1481
|
+
}
|
|
1482
|
+
}
|
|
1483
|
+
|
|
1382
1484
|
/**
|
|
1383
1485
|
* 创建新容器
|
|
1384
1486
|
* @returns {Promise<string>} 默认命令
|
|
@@ -1412,6 +1514,9 @@ async function createNewContainer(runtime) {
|
|
|
1412
1514
|
// Wait for container to be ready
|
|
1413
1515
|
await waitForContainerReady(runtime.containerName);
|
|
1414
1516
|
|
|
1517
|
+
// Run one-time bootstrap command for newly created containers only.
|
|
1518
|
+
executeFirstCommand(runtime);
|
|
1519
|
+
|
|
1415
1520
|
return defaultCommand;
|
|
1416
1521
|
}
|
|
1417
1522
|
|
package/config.example.json
CHANGED
|
@@ -11,6 +11,15 @@
|
|
|
11
11
|
"shellPrefix": "",
|
|
12
12
|
"shell": "",
|
|
13
13
|
"shellSuffix": "",
|
|
14
|
+
"agentPromptCommand": "",
|
|
15
|
+
// 仅首次创建容器时执行一次(创建后、常规 shell 前)
|
|
16
|
+
"first": {
|
|
17
|
+
"shellPrefix": "",
|
|
18
|
+
"shell": "",
|
|
19
|
+
"shellSuffix": "",
|
|
20
|
+
"env": {},
|
|
21
|
+
"envFile": []
|
|
22
|
+
},
|
|
14
23
|
"yolo": "",
|
|
15
24
|
"serverUser": "admin",
|
|
16
25
|
"serverPass": "change-this-password",
|
|
@@ -58,6 +67,10 @@
|
|
|
58
67
|
"containerName": "my-claude-{now}",
|
|
59
68
|
"yolo": "c",
|
|
60
69
|
"shell": "claude",
|
|
70
|
+
"agentPromptCommand": "claude -p {prompt}",
|
|
71
|
+
"first": {
|
|
72
|
+
"shell": "echo first-init"
|
|
73
|
+
},
|
|
61
74
|
"env": {
|
|
62
75
|
"ANTHROPIC_MODEL": "claude-sonnet-4-5"
|
|
63
76
|
},
|
package/lib/agent-resume.js
CHANGED
|
@@ -9,6 +9,13 @@ const AGENT_RESUME_ARG_MAP = {
|
|
|
9
9
|
opencode: '-c'
|
|
10
10
|
};
|
|
11
11
|
|
|
12
|
+
const AGENT_PROMPT_TEMPLATE_MAP = {
|
|
13
|
+
claude: 'claude -p {prompt}',
|
|
14
|
+
gemini: 'gemini -p {prompt}',
|
|
15
|
+
codex: 'codex exec {prompt}',
|
|
16
|
+
opencode: 'opencode run {prompt}'
|
|
17
|
+
};
|
|
18
|
+
|
|
12
19
|
function stripLeadingAssignments(commandText) {
|
|
13
20
|
let rest = String(commandText || '').trim();
|
|
14
21
|
const assignmentPattern = /^(?:[A-Za-z_][A-Za-z0-9_]*=)(?:"(?:\\.|[^"])*"|'(?:\\.|[^'])*'|[^\s]+)(?:\s+|$)/;
|
|
@@ -67,6 +74,11 @@ function resolveAgentResumeArg(commandText) {
|
|
|
67
74
|
return AGENT_RESUME_ARG_MAP[program] || '';
|
|
68
75
|
}
|
|
69
76
|
|
|
77
|
+
function resolveAgentPromptCommandTemplate(commandText) {
|
|
78
|
+
const program = resolveAgentProgram(commandText);
|
|
79
|
+
return AGENT_PROMPT_TEMPLATE_MAP[program] || '';
|
|
80
|
+
}
|
|
81
|
+
|
|
70
82
|
function buildAgentResumeCommand(commandText) {
|
|
71
83
|
const baseCommand = String(commandText || '').trim();
|
|
72
84
|
if (!baseCommand) {
|
|
@@ -80,6 +92,8 @@ function buildAgentResumeCommand(commandText) {
|
|
|
80
92
|
}
|
|
81
93
|
|
|
82
94
|
module.exports = {
|
|
95
|
+
resolveAgentProgram,
|
|
83
96
|
resolveAgentResumeArg,
|
|
84
|
-
buildAgentResumeCommand
|
|
97
|
+
buildAgentResumeCommand,
|
|
98
|
+
resolveAgentPromptCommandTemplate
|
|
85
99
|
};
|
package/lib/web/frontend/app.css
CHANGED
|
@@ -437,20 +437,24 @@ textarea:focus-visible {
|
|
|
437
437
|
box-shadow: inset 3px 0 0 var(--accent), 0 0 0 2px rgba(196, 85, 31, 0.14);
|
|
438
438
|
}
|
|
439
439
|
|
|
440
|
-
.session-item.history
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
.session-item.history-only .session-time {
|
|
447
|
-
color: #b3ab9f;
|
|
440
|
+
.session-item.status-history:not(.active),
|
|
441
|
+
.session-item.status-stopped:not(.active),
|
|
442
|
+
.session-item.status-unknown:not(.active) {
|
|
443
|
+
border-color: rgba(181, 146, 99, 0.22);
|
|
444
|
+
background: rgba(255, 252, 247, 0.72);
|
|
445
|
+
box-shadow: none;
|
|
448
446
|
}
|
|
449
447
|
|
|
450
|
-
.session-item.history
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
448
|
+
.session-item.status-history:not(.active) .session-name,
|
|
449
|
+
.session-item.status-history:not(.active) .session-meta,
|
|
450
|
+
.session-item.status-history:not(.active) .session-time,
|
|
451
|
+
.session-item.status-stopped:not(.active) .session-name,
|
|
452
|
+
.session-item.status-stopped:not(.active) .session-meta,
|
|
453
|
+
.session-item.status-stopped:not(.active) .session-time,
|
|
454
|
+
.session-item.status-unknown:not(.active) .session-name,
|
|
455
|
+
.session-item.status-unknown:not(.active) .session-meta,
|
|
456
|
+
.session-item.status-unknown:not(.active) .session-time {
|
|
457
|
+
opacity: 0.25;
|
|
454
458
|
}
|
|
455
459
|
|
|
456
460
|
.session-name {
|
|
@@ -641,6 +645,7 @@ textarea:focus-visible {
|
|
|
641
645
|
}
|
|
642
646
|
|
|
643
647
|
body.command-mode #modeCommandBtn,
|
|
648
|
+
body.agent-mode #modeAgentBtn,
|
|
644
649
|
body.terminal-mode #modeTerminalBtn {
|
|
645
650
|
color: #ffffff;
|
|
646
651
|
background: var(--accent);
|
|
@@ -722,14 +727,26 @@ body.command-mode #messages {
|
|
|
722
727
|
display: flex;
|
|
723
728
|
}
|
|
724
729
|
|
|
730
|
+
body.agent-mode #messages {
|
|
731
|
+
display: flex;
|
|
732
|
+
}
|
|
733
|
+
|
|
725
734
|
body.command-mode #terminalPanel {
|
|
726
735
|
display: none;
|
|
727
736
|
}
|
|
728
737
|
|
|
738
|
+
body.agent-mode #terminalPanel {
|
|
739
|
+
display: none;
|
|
740
|
+
}
|
|
741
|
+
|
|
729
742
|
body.command-mode .composer {
|
|
730
743
|
display: block;
|
|
731
744
|
}
|
|
732
745
|
|
|
746
|
+
body.agent-mode .composer {
|
|
747
|
+
display: block;
|
|
748
|
+
}
|
|
749
|
+
|
|
733
750
|
body.terminal-mode #messages {
|
|
734
751
|
display: none;
|
|
735
752
|
}
|
|
@@ -834,6 +851,23 @@ body.terminal-mode .composer {
|
|
|
834
851
|
opacity: 0.78;
|
|
835
852
|
}
|
|
836
853
|
|
|
854
|
+
body.agent-mode .msg.origin-command .bubble,
|
|
855
|
+
body.agent-mode .msg.origin-command .msg-meta,
|
|
856
|
+
body.agent-mode .msg.origin-command .msg-exit {
|
|
857
|
+
opacity: 0.25;
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
body.command-mode .msg.origin-agent .bubble,
|
|
861
|
+
body.command-mode .msg.origin-agent .msg-meta,
|
|
862
|
+
body.command-mode .msg.origin-agent .msg-exit {
|
|
863
|
+
opacity: 0.25;
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
body.agent-mode .msg.origin-command .bubble,
|
|
867
|
+
body.command-mode .msg.origin-agent .bubble {
|
|
868
|
+
box-shadow: none;
|
|
869
|
+
}
|
|
870
|
+
|
|
837
871
|
.bubble pre {
|
|
838
872
|
margin: 0;
|
|
839
873
|
white-space: pre-wrap;
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
/>
|
|
9
9
|
<title>MANYOYO Web</title>
|
|
10
10
|
<link rel="stylesheet" href="/app/frontend/app.css" />
|
|
11
|
+
<link rel="stylesheet" href="/app/frontend/markdown.css" />
|
|
11
12
|
<link rel="stylesheet" href="/app/vendor/xterm.css" />
|
|
12
13
|
</head>
|
|
13
14
|
<body>
|
|
@@ -65,7 +66,8 @@
|
|
|
65
66
|
</header>
|
|
66
67
|
<section class="mode-switch" id="modeSwitch">
|
|
67
68
|
<div class="mode-switch-left">
|
|
68
|
-
<button type="button" id="
|
|
69
|
+
<button type="button" id="modeAgentBtn" class="secondary is-active">AGENT 模式</button>
|
|
70
|
+
<button type="button" id="modeCommandBtn" class="secondary">命令模式</button>
|
|
69
71
|
<button type="button" id="modeTerminalBtn" class="secondary">交互终端</button>
|
|
70
72
|
</div>
|
|
71
73
|
<div class="mode-terminal-controls">
|
|
@@ -85,7 +87,7 @@
|
|
|
85
87
|
<button type="submit" id="sendBtn">发送</button>
|
|
86
88
|
</div>
|
|
87
89
|
<div class="composer-foot">
|
|
88
|
-
<span>Enter 发送 · Shift/Alt + Enter 换行</span>
|
|
90
|
+
<span id="composerHint">Enter 发送 · Shift/Alt + Enter 换行</span>
|
|
89
91
|
<span id="sendState" class="send-state">未选择会话</span>
|
|
90
92
|
</div>
|
|
91
93
|
</form>
|
|
@@ -140,6 +142,7 @@
|
|
|
140
142
|
<label>shell<input id="createShell" placeholder="例如 claude / codex" /></label>
|
|
141
143
|
<label>shellSuffix<input id="createShellSuffix" placeholder="例如 --dangerously-skip-permissions" /></label>
|
|
142
144
|
<label>yolo<input id="createYolo" placeholder="例如 c / cx / gm / oc" /></label>
|
|
145
|
+
<label>agentPromptCommand<input id="createAgentPromptCommand" placeholder="例如 codex exec --plain-text {prompt}" /></label>
|
|
143
146
|
</div>
|
|
144
147
|
<label class="text-block">env (KEY=VALUE,每行一项)
|
|
145
148
|
<textarea id="createEnv" placeholder="KEY=value"></textarea>
|
|
@@ -162,6 +165,8 @@
|
|
|
162
165
|
|
|
163
166
|
<script src="/app/vendor/xterm.js"></script>
|
|
164
167
|
<script src="/app/vendor/xterm-addon-fit.js"></script>
|
|
168
|
+
<script src="/app/vendor/marked.min.js"></script>
|
|
169
|
+
<script src="/app/frontend/markdown-renderer.js"></script>
|
|
165
170
|
<script src="/app/frontend/app.js"></script>
|
|
166
171
|
</body>
|
|
167
172
|
</html>
|