@xcanwin/manyoyo 5.8.0 → 5.8.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/web/frontend/app.css +69 -0
- package/lib/web/frontend/app.html +40 -15
- package/lib/web/frontend/app.js +179 -125
- package/lib/web/server.js +1 -1
- package/package.json +1 -1
- package/lib/web/frontend/path-picker-utils.js +0 -57
package/lib/web/frontend/app.css
CHANGED
|
@@ -407,6 +407,75 @@ textarea:focus-visible {
|
|
|
407
407
|
width: min(760px, calc(100vw - 24px));
|
|
408
408
|
}
|
|
409
409
|
|
|
410
|
+
.agent-template-primary .text-block {
|
|
411
|
+
margin-top: 0;
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
.agent-template-primary .text-block + .text-block,
|
|
415
|
+
#agentTemplateOverrideGroup {
|
|
416
|
+
margin-top: 12px;
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
.agent-template-primary select,
|
|
420
|
+
.agent-template-primary textarea {
|
|
421
|
+
border: 1px solid var(--line);
|
|
422
|
+
border-radius: 10px;
|
|
423
|
+
padding: 9px 11px;
|
|
424
|
+
background: var(--panel-strong);
|
|
425
|
+
color: var(--text);
|
|
426
|
+
font-size: 13px;
|
|
427
|
+
font-family: var(--font-ui);
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
.agent-template-primary textarea {
|
|
431
|
+
min-height: 92px;
|
|
432
|
+
font-family: var(--font-mono);
|
|
433
|
+
resize: vertical;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
.agent-template-section {
|
|
437
|
+
padding: 12px;
|
|
438
|
+
border: 1px solid var(--line);
|
|
439
|
+
border-radius: 12px;
|
|
440
|
+
background: rgba(255, 253, 250, 0.92);
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
.agent-template-section + .agent-template-section {
|
|
444
|
+
margin-top: 12px;
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
.agent-template-section-title {
|
|
448
|
+
margin-bottom: 8px;
|
|
449
|
+
font-size: 12px;
|
|
450
|
+
font-weight: 700;
|
|
451
|
+
color: var(--text);
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
.agent-template-section .text-block {
|
|
455
|
+
margin-top: 0;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
.agent-template-section .text-block + .text-block {
|
|
459
|
+
margin-top: 10px;
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
.agent-template-section select,
|
|
463
|
+
.agent-template-section textarea {
|
|
464
|
+
border: 1px solid var(--line);
|
|
465
|
+
border-radius: 10px;
|
|
466
|
+
padding: 9px 11px;
|
|
467
|
+
background: var(--panel-strong);
|
|
468
|
+
color: var(--text);
|
|
469
|
+
font-size: 13px;
|
|
470
|
+
font-family: var(--font-ui);
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
.agent-template-section textarea {
|
|
474
|
+
min-height: 92px;
|
|
475
|
+
font-family: var(--font-mono);
|
|
476
|
+
resize: vertical;
|
|
477
|
+
}
|
|
478
|
+
|
|
410
479
|
.session-head {
|
|
411
480
|
display: flex;
|
|
412
481
|
justify-content: space-between;
|
|
@@ -165,12 +165,7 @@
|
|
|
165
165
|
</div>
|
|
166
166
|
</label>
|
|
167
167
|
<label>containerName<input id="createContainerName" placeholder="my-dev 或 my-{now}" /></label>
|
|
168
|
-
<label>containerPath
|
|
169
|
-
<div class="field-inline">
|
|
170
|
-
<input id="createContainerPath" placeholder="/workspace" />
|
|
171
|
-
<button type="button" id="pickContainerPathBtn" class="secondary field-picker-btn">选择</button>
|
|
172
|
-
</div>
|
|
173
|
-
</label>
|
|
168
|
+
<label>containerPath<input id="createContainerPath" placeholder="/workspace" /></label>
|
|
174
169
|
<label>imageName<input id="createImageName" placeholder="localhost/xcanwin/manyoyo" /></label>
|
|
175
170
|
<label>imageVersion<input id="createImageVersion" placeholder="1.7.4-common" /></label>
|
|
176
171
|
<label>containerMode
|
|
@@ -184,7 +179,15 @@
|
|
|
184
179
|
<label>shellPrefix<input id="createShellPrefix" placeholder="例如 IS_SANDBOX=1" /></label>
|
|
185
180
|
<label>shell<input id="createShell" placeholder="例如 claude / codex" /></label>
|
|
186
181
|
<label>shellSuffix<input id="createShellSuffix" placeholder="例如 --dangerously-skip-permissions" /></label>
|
|
187
|
-
<label>
|
|
182
|
+
<label>CLI
|
|
183
|
+
<select id="createYolo">
|
|
184
|
+
<option value="">(不使用)</option>
|
|
185
|
+
<option value="claude">claude</option>
|
|
186
|
+
<option value="codex">codex</option>
|
|
187
|
+
<option value="gemini">gemini</option>
|
|
188
|
+
<option value="opencode">opencode</option>
|
|
189
|
+
</select>
|
|
190
|
+
</label>
|
|
188
191
|
<label>agentPromptCommand<input id="createAgentPromptCommand" placeholder="例如 codex exec --plain-text {prompt}" /></label>
|
|
189
192
|
</div>
|
|
190
193
|
<label class="text-block">env (KEY=VALUE,每行一项)
|
|
@@ -231,15 +234,38 @@
|
|
|
231
234
|
<button type="button" id="agentTemplateCancelBtn" class="secondary">关闭</button>
|
|
232
235
|
</header>
|
|
233
236
|
<div class="modal-body">
|
|
234
|
-
<div id="
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
237
|
+
<div id="agentTemplatePrimary" class="agent-template-primary">
|
|
238
|
+
<label class="text-block">CLI
|
|
239
|
+
<select id="containerCliSelect">
|
|
240
|
+
<option value="custom">自定义</option>
|
|
241
|
+
<option value="claude">claude</option>
|
|
242
|
+
<option value="codex">codex</option>
|
|
243
|
+
<option value="gemini">gemini</option>
|
|
244
|
+
<option value="opencode">opencode</option>
|
|
245
|
+
</select>
|
|
246
|
+
</label>
|
|
247
|
+
<label class="text-block">高级编辑 agentPromptCommand
|
|
248
|
+
<textarea id="containerAgentPromptEditor" placeholder="例如 codex exec --skip-git-repo-check {prompt}"></textarea>
|
|
241
249
|
</label>
|
|
242
250
|
</div>
|
|
251
|
+
<div id="agentTemplateOverrideGroup">
|
|
252
|
+
<section class="agent-template-section">
|
|
253
|
+
<div class="agent-template-section-title">当前 AGENT 覆盖</div>
|
|
254
|
+
<label class="text-block">CLI
|
|
255
|
+
<select id="agentCliSelect">
|
|
256
|
+
<option value="">继承容器默认</option>
|
|
257
|
+
<option value="custom">自定义</option>
|
|
258
|
+
<option value="claude">claude</option>
|
|
259
|
+
<option value="codex">codex</option>
|
|
260
|
+
<option value="gemini">gemini</option>
|
|
261
|
+
<option value="opencode">opencode</option>
|
|
262
|
+
</select>
|
|
263
|
+
</label>
|
|
264
|
+
<label class="text-block">高级编辑 agentPromptCommand
|
|
265
|
+
<textarea id="agentPromptOverrideEditor" placeholder="留空则继承容器默认模板"></textarea>
|
|
266
|
+
</label>
|
|
267
|
+
</section>
|
|
268
|
+
</div>
|
|
243
269
|
<div id="agentTemplateError" class="modal-error" hidden></div>
|
|
244
270
|
</div>
|
|
245
271
|
<footer class="modal-footer">
|
|
@@ -254,7 +280,6 @@
|
|
|
254
280
|
<script src="/app/vendor/xterm-addon-fit.js"></script>
|
|
255
281
|
<script src="/app/vendor/marked.min.js"></script>
|
|
256
282
|
<script src="/app/frontend/markdown-renderer.js"></script>
|
|
257
|
-
<script src="/app/frontend/path-picker-utils.js"></script>
|
|
258
283
|
<script src="/app/frontend/app.js"></script>
|
|
259
284
|
</body>
|
|
260
285
|
</html>
|
package/lib/web/frontend/app.js
CHANGED
|
@@ -62,7 +62,6 @@
|
|
|
62
62
|
sessionDetailRequestId: 0,
|
|
63
63
|
agentTemplateError: '',
|
|
64
64
|
createAgentPromptAuto: false,
|
|
65
|
-
createContainerPathBase: '',
|
|
66
65
|
createDefaults: null,
|
|
67
66
|
createRuns: {},
|
|
68
67
|
sessionNodeMap: new Map(),
|
|
@@ -80,8 +79,6 @@
|
|
|
80
79
|
title: '',
|
|
81
80
|
tip: '',
|
|
82
81
|
currentPath: '',
|
|
83
|
-
basePath: '',
|
|
84
|
-
baseContainerPath: '',
|
|
85
82
|
entries: [],
|
|
86
83
|
error: ''
|
|
87
84
|
},
|
|
@@ -145,7 +142,6 @@
|
|
|
145
142
|
const createHostPath = document.getElementById('createHostPath');
|
|
146
143
|
const createContainerPath = document.getElementById('createContainerPath');
|
|
147
144
|
const pickHostPathBtn = document.getElementById('pickHostPathBtn');
|
|
148
|
-
const pickContainerPathBtn = document.getElementById('pickContainerPathBtn');
|
|
149
145
|
const createImageName = document.getElementById('createImageName');
|
|
150
146
|
const createImageVersion = document.getElementById('createImageVersion');
|
|
151
147
|
const createContainerMode = document.getElementById('createContainerMode');
|
|
@@ -188,9 +184,11 @@
|
|
|
188
184
|
const sendBtn = document.getElementById('sendBtn');
|
|
189
185
|
const stopBtn = document.getElementById('stopBtn');
|
|
190
186
|
const agentTemplateModal = document.getElementById('agentTemplateModal');
|
|
191
|
-
const
|
|
187
|
+
const agentTemplatePrimary = document.getElementById('agentTemplatePrimary');
|
|
188
|
+
const containerCliSelect = document.getElementById('containerCliSelect');
|
|
192
189
|
const containerAgentPromptEditor = document.getElementById('containerAgentPromptEditor');
|
|
193
190
|
const agentTemplateOverrideGroup = document.getElementById('agentTemplateOverrideGroup');
|
|
191
|
+
const agentCliSelect = document.getElementById('agentCliSelect');
|
|
194
192
|
const agentPromptOverrideEditor = document.getElementById('agentPromptOverrideEditor');
|
|
195
193
|
const agentTemplateError = document.getElementById('agentTemplateError');
|
|
196
194
|
const agentTemplateCancelBtn = document.getElementById('agentTemplateCancelBtn');
|
|
@@ -230,16 +228,18 @@
|
|
|
230
228
|
const GEMINI_YOLO_FLAG = '--yolo';
|
|
231
229
|
const CODEX_DANGEROUS_FLAG = '--dangerously-bypass-approvals-and-sandbox';
|
|
232
230
|
const OPENCODE_PERMISSION_KEY = 'OPENCODE_PERMISSION=';
|
|
231
|
+
const AGENT_TEMPLATE_CLI_COMMAND_MAP = {
|
|
232
|
+
claude: YOLO_COMMAND_MAP.claude,
|
|
233
|
+
codex: YOLO_COMMAND_MAP.codex,
|
|
234
|
+
gemini: YOLO_COMMAND_MAP.gemini,
|
|
235
|
+
opencode: YOLO_COMMAND_MAP.opencode
|
|
236
|
+
};
|
|
233
237
|
const SIDEBAR_TREE_STORAGE_KEY = 'manyoyo.web.sidebarTree.v1';
|
|
234
238
|
const markdownRenderer = window.ManyoyoMarkdown
|
|
235
239
|
&& typeof window.ManyoyoMarkdown.shouldRenderMessage === 'function'
|
|
236
240
|
&& typeof window.ManyoyoMarkdown.render === 'function'
|
|
237
241
|
? window.ManyoyoMarkdown
|
|
238
242
|
: null;
|
|
239
|
-
const pathPickerUtils = window.ManyoyoPathPickerUtils && typeof window.ManyoyoPathPickerUtils === 'object'
|
|
240
|
-
? window.ManyoyoPathPickerUtils
|
|
241
|
-
: {};
|
|
242
|
-
|
|
243
243
|
function normalizeBooleanMap(source) {
|
|
244
244
|
const result = {};
|
|
245
245
|
if (!source || typeof source !== 'object' || Array.isArray(source)) {
|
|
@@ -696,41 +696,6 @@
|
|
|
696
696
|
return false;
|
|
697
697
|
}
|
|
698
698
|
|
|
699
|
-
function normalizeSlashPath(value) {
|
|
700
|
-
if (typeof pathPickerUtils.normalizeSlashPath === 'function') {
|
|
701
|
-
return pathPickerUtils.normalizeSlashPath(value);
|
|
702
|
-
}
|
|
703
|
-
return String(value || '').replace(/\\/g, '/');
|
|
704
|
-
}
|
|
705
|
-
|
|
706
|
-
function isChildPath(basePath, targetPath) {
|
|
707
|
-
if (typeof pathPickerUtils.isChildPath === 'function') {
|
|
708
|
-
return pathPickerUtils.isChildPath(basePath, targetPath);
|
|
709
|
-
}
|
|
710
|
-
const normalizedBase = normalizeSlashPath(basePath).replace(/\/+$/, '');
|
|
711
|
-
const normalizedTarget = normalizeSlashPath(targetPath).replace(/\/+$/, '');
|
|
712
|
-
if (!normalizedBase) {
|
|
713
|
-
return false;
|
|
714
|
-
}
|
|
715
|
-
return normalizedTarget === normalizedBase || normalizedTarget.startsWith(normalizedBase + '/');
|
|
716
|
-
}
|
|
717
|
-
|
|
718
|
-
function buildContainerPathFromHostSelection(baseHostPath, baseContainerPath, selectedHostPath) {
|
|
719
|
-
if (typeof pathPickerUtils.buildContainerPathFromHostSelection === 'function') {
|
|
720
|
-
return pathPickerUtils.buildContainerPathFromHostSelection(baseHostPath, baseContainerPath, selectedHostPath);
|
|
721
|
-
}
|
|
722
|
-
const normalizedBaseHost = normalizeSlashPath(baseHostPath).replace(/\/+$/, '');
|
|
723
|
-
const normalizedContainer = normalizeSlashPath(baseContainerPath).replace(/\/+$/, '') || '/workspace';
|
|
724
|
-
const normalizedSelected = normalizeSlashPath(selectedHostPath).replace(/\/+$/, '');
|
|
725
|
-
if (!normalizedBaseHost || !isChildPath(normalizedBaseHost, normalizedSelected)) {
|
|
726
|
-
return normalizedContainer;
|
|
727
|
-
}
|
|
728
|
-
const relative = normalizedSelected === normalizedBaseHost
|
|
729
|
-
? ''
|
|
730
|
-
: normalizedSelected.slice(normalizedBaseHost.length + 1);
|
|
731
|
-
return relative ? `${normalizedContainer}/${relative}`.replace(/\/+/g, '/') : normalizedContainer;
|
|
732
|
-
}
|
|
733
|
-
|
|
734
699
|
function setModalVisible(modalNode, visible) {
|
|
735
700
|
if (!modalNode) return;
|
|
736
701
|
modalNode.hidden = !visible;
|
|
@@ -829,6 +794,26 @@
|
|
|
829
794
|
return YOLO_COMMAND_MAP[key] || '';
|
|
830
795
|
}
|
|
831
796
|
|
|
797
|
+
function normalizeCreateYoloValue(yolo) {
|
|
798
|
+
const key = String(yolo || '').trim().toLowerCase();
|
|
799
|
+
if (!key) {
|
|
800
|
+
return '';
|
|
801
|
+
}
|
|
802
|
+
if (key === 'claude' || key === 'cc' || key === 'c') {
|
|
803
|
+
return 'claude';
|
|
804
|
+
}
|
|
805
|
+
if (key === 'codex' || key === 'cx') {
|
|
806
|
+
return 'codex';
|
|
807
|
+
}
|
|
808
|
+
if (key === 'gemini' || key === 'gm' || key === 'g') {
|
|
809
|
+
return 'gemini';
|
|
810
|
+
}
|
|
811
|
+
if (key === 'opencode' || key === 'oc') {
|
|
812
|
+
return 'opencode';
|
|
813
|
+
}
|
|
814
|
+
return '';
|
|
815
|
+
}
|
|
816
|
+
|
|
832
817
|
function stripLeadingAssignments(commandText) {
|
|
833
818
|
let rest = String(commandText || '').trim();
|
|
834
819
|
const assignmentPattern = /^(?:[A-Za-z_][A-Za-z0-9_]*=)(?:"(?:\\.|[^"])*"|'(?:\\.|[^'])*'|[^\s]+)(?:\s+|$)/;
|
|
@@ -919,7 +904,6 @@
|
|
|
919
904
|
createContainerName.value = value.containerName || '';
|
|
920
905
|
createHostPath.value = value.hostPath || '';
|
|
921
906
|
createContainerPath.value = value.containerPath || '';
|
|
922
|
-
state.createContainerPathBase = String(value.containerPath || '').trim();
|
|
923
907
|
createImageName.value = value.imageName || '';
|
|
924
908
|
createImageVersion.value = value.imageVersion || '';
|
|
925
909
|
createContainerMode.value = value.containerMode || '';
|
|
@@ -928,7 +912,7 @@
|
|
|
928
912
|
createShellSuffix.value = value.shellSuffix || '';
|
|
929
913
|
createAgentPromptCommand.value = value.agentPromptCommand || '';
|
|
930
914
|
state.createAgentPromptAuto = false;
|
|
931
|
-
createYolo.value = value.yolo
|
|
915
|
+
createYolo.value = normalizeCreateYoloValue(value.yolo);
|
|
932
916
|
// 敏感 env 与继承数组由服务端在创建时合并,前端表单默认不回显,避免泄露或重复提交。
|
|
933
917
|
createEnv.value = '';
|
|
934
918
|
createEnvFile.value = '';
|
|
@@ -1106,28 +1090,101 @@
|
|
|
1106
1090
|
agentTemplateError.textContent = state.agentTemplateError;
|
|
1107
1091
|
}
|
|
1108
1092
|
|
|
1093
|
+
function inferTemplateCliValue(templateText, options) {
|
|
1094
|
+
const text = String(templateText || '').trim();
|
|
1095
|
+
const opts = options && typeof options === 'object' ? options : {};
|
|
1096
|
+
if (!text) {
|
|
1097
|
+
return opts.allowEmpty ? '' : 'custom';
|
|
1098
|
+
}
|
|
1099
|
+
const program = resolveAgentProgram(text);
|
|
1100
|
+
return AGENT_PROMPT_TEMPLATE_MAP[program] ? program : 'custom';
|
|
1101
|
+
}
|
|
1102
|
+
|
|
1103
|
+
function buildTemplateFromCliValue(cliValue) {
|
|
1104
|
+
const cli = String(cliValue || '').trim().toLowerCase();
|
|
1105
|
+
if (!cli || cli === 'custom') {
|
|
1106
|
+
return '';
|
|
1107
|
+
}
|
|
1108
|
+
const baseCommand = AGENT_TEMPLATE_CLI_COMMAND_MAP[cli] || '';
|
|
1109
|
+
if (!baseCommand) {
|
|
1110
|
+
return '';
|
|
1111
|
+
}
|
|
1112
|
+
return resolveAgentPromptTemplate(baseCommand);
|
|
1113
|
+
}
|
|
1114
|
+
|
|
1115
|
+
function syncAgentTemplateSelectFromEditor(selectNode, editorNode, options) {
|
|
1116
|
+
if (!selectNode || !editorNode) {
|
|
1117
|
+
return;
|
|
1118
|
+
}
|
|
1119
|
+
const value = inferTemplateCliValue(editorNode.value, options);
|
|
1120
|
+
selectNode.value = value;
|
|
1121
|
+
}
|
|
1122
|
+
|
|
1123
|
+
function getInheritedContainerTemplateText() {
|
|
1124
|
+
if (containerAgentPromptEditor) {
|
|
1125
|
+
const editorText = String(containerAgentPromptEditor.value || '').trim();
|
|
1126
|
+
if (editorText) {
|
|
1127
|
+
return editorText;
|
|
1128
|
+
}
|
|
1129
|
+
}
|
|
1130
|
+
if (state.sessionDetail && typeof state.sessionDetail.containerAgentPromptCommand === 'string') {
|
|
1131
|
+
const containerText = String(state.sessionDetail.containerAgentPromptCommand || '').trim();
|
|
1132
|
+
if (containerText) {
|
|
1133
|
+
return containerText;
|
|
1134
|
+
}
|
|
1135
|
+
}
|
|
1136
|
+
if (state.sessionDetail && typeof state.sessionDetail.agentPromptCommand === 'string') {
|
|
1137
|
+
const effectiveText = String(state.sessionDetail.agentPromptCommand || '').trim();
|
|
1138
|
+
if (effectiveText) {
|
|
1139
|
+
return effectiveText;
|
|
1140
|
+
}
|
|
1141
|
+
}
|
|
1142
|
+
return '';
|
|
1143
|
+
}
|
|
1144
|
+
|
|
1145
|
+
function applyAgentTemplateCliSelection(selectNode, editorNode, options) {
|
|
1146
|
+
if (!selectNode || !editorNode) {
|
|
1147
|
+
return;
|
|
1148
|
+
}
|
|
1149
|
+
const opts = options && typeof options === 'object' ? options : {};
|
|
1150
|
+
const cliValue = String(selectNode.value || '').trim();
|
|
1151
|
+
if (!cliValue && opts.allowEmpty === true) {
|
|
1152
|
+
editorNode.value = getInheritedContainerTemplateText();
|
|
1153
|
+
showAgentTemplateError('');
|
|
1154
|
+
return;
|
|
1155
|
+
}
|
|
1156
|
+
if (cliValue === 'custom') {
|
|
1157
|
+
showAgentTemplateError('');
|
|
1158
|
+
return;
|
|
1159
|
+
}
|
|
1160
|
+
const nextTemplate = buildTemplateFromCliValue(cliValue);
|
|
1161
|
+
if (nextTemplate) {
|
|
1162
|
+
editorNode.value = nextTemplate;
|
|
1163
|
+
}
|
|
1164
|
+
showAgentTemplateError('');
|
|
1165
|
+
}
|
|
1166
|
+
|
|
1109
1167
|
function fillAgentTemplateForm(detail) {
|
|
1110
1168
|
const currentDetail = detail && typeof detail === 'object' ? detail : {};
|
|
1169
|
+
const overrideEditable = isActiveAgentOverrideEditable();
|
|
1170
|
+
const containerTemplateText = String(
|
|
1171
|
+
currentDetail.containerAgentPromptCommand || currentDetail.agentPromptCommand || ''
|
|
1172
|
+
).trim();
|
|
1111
1173
|
if (containerAgentPromptEditor) {
|
|
1112
|
-
containerAgentPromptEditor.value =
|
|
1174
|
+
containerAgentPromptEditor.value = containerTemplateText;
|
|
1113
1175
|
}
|
|
1114
1176
|
if (agentPromptOverrideEditor) {
|
|
1115
|
-
agentPromptOverrideEditor.value = currentDetail.agentPromptCommandOverride ||
|
|
1177
|
+
agentPromptOverrideEditor.value = currentDetail.agentPromptCommandOverride || containerTemplateText;
|
|
1178
|
+
}
|
|
1179
|
+
syncAgentTemplateSelectFromEditor(containerCliSelect, containerAgentPromptEditor);
|
|
1180
|
+
if (agentCliSelect) {
|
|
1181
|
+
agentCliSelect.value = currentDetail.agentPromptCommandOverride ? inferTemplateCliValue(currentDetail.agentPromptCommandOverride, { allowEmpty: true }) : '';
|
|
1182
|
+
}
|
|
1183
|
+
if (agentTemplatePrimary) {
|
|
1184
|
+
agentTemplatePrimary.hidden = overrideEditable;
|
|
1116
1185
|
}
|
|
1117
1186
|
if (agentTemplateOverrideGroup) {
|
|
1118
|
-
agentTemplateOverrideGroup.hidden = !
|
|
1119
|
-
}
|
|
1120
|
-
if (agentTemplateTip) {
|
|
1121
|
-
const sessionName = currentDetail.agentName || state.active || '当前会话';
|
|
1122
|
-
const sourceMap = {
|
|
1123
|
-
agent: '当前 AGENT 覆盖',
|
|
1124
|
-
container: '容器默认模板',
|
|
1125
|
-
inferred: '从容器启动命令推导',
|
|
1126
|
-
none: '未配置'
|
|
1127
|
-
};
|
|
1128
|
-
const sourceLabel = sourceMap[currentDetail.agentPromptSource] || '未配置';
|
|
1129
|
-
const effectiveTemplate = currentDetail.agentPromptCommand || '—';
|
|
1130
|
-
agentTemplateTip.textContent = `${sessionName} · 当前生效来源:${sourceLabel} · 生效模板:${effectiveTemplate}`;
|
|
1187
|
+
agentTemplateOverrideGroup.hidden = !overrideEditable;
|
|
1131
1188
|
}
|
|
1132
1189
|
showAgentTemplateError('');
|
|
1133
1190
|
}
|
|
@@ -1155,7 +1212,11 @@
|
|
|
1155
1212
|
state.agentTemplateModalOpen = true;
|
|
1156
1213
|
fillAgentTemplateForm(detail);
|
|
1157
1214
|
syncUi();
|
|
1158
|
-
if (
|
|
1215
|
+
if (isActiveAgentOverrideEditable() && agentCliSelect) {
|
|
1216
|
+
agentCliSelect.focus();
|
|
1217
|
+
} else if (containerCliSelect) {
|
|
1218
|
+
containerCliSelect.focus();
|
|
1219
|
+
} else if (containerAgentPromptEditor) {
|
|
1159
1220
|
containerAgentPromptEditor.focus();
|
|
1160
1221
|
}
|
|
1161
1222
|
}
|
|
@@ -1177,11 +1238,15 @@
|
|
|
1177
1238
|
showAgentTemplateError('');
|
|
1178
1239
|
syncUi();
|
|
1179
1240
|
try {
|
|
1180
|
-
const payload = {
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1241
|
+
const payload = {};
|
|
1242
|
+
if (isActiveAgentOverrideEditable()) {
|
|
1243
|
+
if (agentCliSelect && String(agentCliSelect.value || '').trim() === '') {
|
|
1244
|
+
payload.agentPromptCommandOverride = '';
|
|
1245
|
+
} else if (agentPromptOverrideEditor) {
|
|
1246
|
+
payload.agentPromptCommandOverride = String(agentPromptOverrideEditor.value || '').trim();
|
|
1247
|
+
}
|
|
1248
|
+
} else if (containerAgentPromptEditor) {
|
|
1249
|
+
payload.containerAgentPromptCommand = String(containerAgentPromptEditor.value || '').trim();
|
|
1185
1250
|
}
|
|
1186
1251
|
const data = await api('/api/sessions/' + encodeURIComponent(state.active) + '/agent-template', {
|
|
1187
1252
|
method: 'PUT',
|
|
@@ -2020,6 +2085,18 @@
|
|
|
2020
2085
|
if (agentTemplateCancelBtn) {
|
|
2021
2086
|
agentTemplateCancelBtn.disabled = state.agentTemplateSaving;
|
|
2022
2087
|
}
|
|
2088
|
+
if (containerCliSelect) {
|
|
2089
|
+
containerCliSelect.disabled = state.agentTemplateSaving || isActiveAgentOverrideEditable();
|
|
2090
|
+
}
|
|
2091
|
+
if (containerAgentPromptEditor) {
|
|
2092
|
+
containerAgentPromptEditor.disabled = state.agentTemplateSaving || isActiveAgentOverrideEditable();
|
|
2093
|
+
}
|
|
2094
|
+
if (agentCliSelect) {
|
|
2095
|
+
agentCliSelect.disabled = state.agentTemplateSaving || !isActiveAgentOverrideEditable();
|
|
2096
|
+
}
|
|
2097
|
+
if (agentPromptOverrideEditor) {
|
|
2098
|
+
agentPromptOverrideEditor.disabled = state.agentTemplateSaving || !isActiveAgentOverrideEditable();
|
|
2099
|
+
}
|
|
2023
2100
|
document.body.classList.toggle(
|
|
2024
2101
|
'modal-open',
|
|
2025
2102
|
state.configModalOpen || state.createModalOpen || state.directoryPicker.open || state.agentTemplateModalOpen
|
|
@@ -2290,12 +2367,8 @@
|
|
|
2290
2367
|
try {
|
|
2291
2368
|
const params = new URLSearchParams();
|
|
2292
2369
|
params.set('path', picker.currentPath || '/');
|
|
2293
|
-
if (picker.basePath) {
|
|
2294
|
-
params.set('basePath', picker.basePath);
|
|
2295
|
-
}
|
|
2296
2370
|
const data = await api('/api/fs/directories?' + params.toString());
|
|
2297
2371
|
picker.currentPath = data.currentPath || picker.currentPath;
|
|
2298
|
-
picker.basePath = data.basePath || picker.basePath || '';
|
|
2299
2372
|
picker.parentPath = data.parentPath || '';
|
|
2300
2373
|
picker.entries = Array.isArray(data.entries) ? data.entries : [];
|
|
2301
2374
|
} catch (e) {
|
|
@@ -2314,8 +2387,6 @@
|
|
|
2314
2387
|
state.directoryPicker.title = '';
|
|
2315
2388
|
state.directoryPicker.tip = '';
|
|
2316
2389
|
state.directoryPicker.currentPath = '';
|
|
2317
|
-
state.directoryPicker.basePath = '';
|
|
2318
|
-
state.directoryPicker.baseContainerPath = '';
|
|
2319
2390
|
state.directoryPicker.parentPath = '';
|
|
2320
2391
|
state.directoryPicker.entries = [];
|
|
2321
2392
|
state.directoryPicker.error = '';
|
|
@@ -2327,54 +2398,22 @@
|
|
|
2327
2398
|
if (!picker.currentPath) {
|
|
2328
2399
|
return;
|
|
2329
2400
|
}
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
if (!(createContainerPath.value || '').trim()) {
|
|
2333
|
-
createContainerPath.value = '/workspace';
|
|
2334
|
-
state.createContainerPathBase = '/workspace';
|
|
2335
|
-
}
|
|
2336
|
-
} else if (picker.mode === 'container') {
|
|
2337
|
-
const mapped = buildContainerPathFromHostSelection(
|
|
2338
|
-
picker.basePath,
|
|
2339
|
-
picker.baseContainerPath || '/workspace',
|
|
2340
|
-
picker.currentPath
|
|
2341
|
-
);
|
|
2342
|
-
createContainerPath.value = mapped;
|
|
2343
|
-
}
|
|
2401
|
+
createHostPath.value = picker.currentPath;
|
|
2402
|
+
createContainerPath.value = picker.currentPath;
|
|
2344
2403
|
closeDirectoryPicker();
|
|
2345
2404
|
}
|
|
2346
2405
|
|
|
2347
|
-
function openDirectoryPicker(
|
|
2406
|
+
function openDirectoryPicker() {
|
|
2348
2407
|
const picker = state.directoryPicker;
|
|
2349
2408
|
picker.open = true;
|
|
2350
2409
|
picker.loading = false;
|
|
2351
2410
|
picker.error = '';
|
|
2352
2411
|
picker.entries = [];
|
|
2353
2412
|
picker.parentPath = '';
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
picker.open = false;
|
|
2359
|
-
renderDirectoryPicker();
|
|
2360
|
-
return;
|
|
2361
|
-
}
|
|
2362
|
-
picker.mode = 'container';
|
|
2363
|
-
picker.title = '选择 containerPath 对应目录';
|
|
2364
|
-
picker.tip = '从 hostPath 下选择子目录,结果会映射到容器路径。';
|
|
2365
|
-
picker.basePath = baseHostPath;
|
|
2366
|
-
picker.baseContainerPath = typeof pathPickerUtils.resolveContainerPickerBase === 'function'
|
|
2367
|
-
? pathPickerUtils.resolveContainerPickerBase(state.createContainerPathBase, createContainerPath.value)
|
|
2368
|
-
: (String(state.createContainerPathBase || '').trim() || String(createContainerPath.value || '').trim() || '/workspace');
|
|
2369
|
-
picker.currentPath = baseHostPath;
|
|
2370
|
-
} else {
|
|
2371
|
-
picker.mode = 'host';
|
|
2372
|
-
picker.title = '选择 hostPath';
|
|
2373
|
-
picker.tip = '浏览宿主机目录,选中后会回填 create 表单。';
|
|
2374
|
-
picker.basePath = '';
|
|
2375
|
-
picker.baseContainerPath = '';
|
|
2376
|
-
picker.currentPath = (createHostPath.value || '').trim() || '/';
|
|
2377
|
-
}
|
|
2413
|
+
picker.mode = 'host';
|
|
2414
|
+
picker.title = '选择 hostPath';
|
|
2415
|
+
picker.tip = '浏览宿主机目录,选中后会回填 create 表单。';
|
|
2416
|
+
picker.currentPath = (createHostPath.value || '').trim() || '/';
|
|
2378
2417
|
renderDirectoryPicker();
|
|
2379
2418
|
loadDirectoryPicker(picker.currentPath);
|
|
2380
2419
|
}
|
|
@@ -3538,13 +3577,7 @@
|
|
|
3538
3577
|
|
|
3539
3578
|
if (pickHostPathBtn) {
|
|
3540
3579
|
pickHostPathBtn.addEventListener('click', function () {
|
|
3541
|
-
openDirectoryPicker(
|
|
3542
|
-
});
|
|
3543
|
-
}
|
|
3544
|
-
|
|
3545
|
-
if (pickContainerPathBtn) {
|
|
3546
|
-
pickContainerPathBtn.addEventListener('click', function () {
|
|
3547
|
-
openDirectoryPicker('container');
|
|
3580
|
+
openDirectoryPicker();
|
|
3548
3581
|
});
|
|
3549
3582
|
}
|
|
3550
3583
|
|
|
@@ -3568,6 +3601,30 @@
|
|
|
3568
3601
|
});
|
|
3569
3602
|
}
|
|
3570
3603
|
|
|
3604
|
+
if (containerCliSelect) {
|
|
3605
|
+
containerCliSelect.addEventListener('change', function () {
|
|
3606
|
+
applyAgentTemplateCliSelection(containerCliSelect, containerAgentPromptEditor);
|
|
3607
|
+
});
|
|
3608
|
+
}
|
|
3609
|
+
|
|
3610
|
+
if (agentCliSelect) {
|
|
3611
|
+
agentCliSelect.addEventListener('change', function () {
|
|
3612
|
+
applyAgentTemplateCliSelection(agentCliSelect, agentPromptOverrideEditor, { allowEmpty: true });
|
|
3613
|
+
});
|
|
3614
|
+
}
|
|
3615
|
+
|
|
3616
|
+
if (containerAgentPromptEditor) {
|
|
3617
|
+
containerAgentPromptEditor.addEventListener('input', function () {
|
|
3618
|
+
syncAgentTemplateSelectFromEditor(containerCliSelect, containerAgentPromptEditor);
|
|
3619
|
+
});
|
|
3620
|
+
}
|
|
3621
|
+
|
|
3622
|
+
if (agentPromptOverrideEditor) {
|
|
3623
|
+
agentPromptOverrideEditor.addEventListener('input', function () {
|
|
3624
|
+
syncAgentTemplateSelectFromEditor(agentCliSelect, agentPromptOverrideEditor, { allowEmpty: true });
|
|
3625
|
+
});
|
|
3626
|
+
}
|
|
3627
|
+
|
|
3571
3628
|
if (agentTemplateCancelBtn) {
|
|
3572
3629
|
agentTemplateCancelBtn.addEventListener('click', function () {
|
|
3573
3630
|
closeAgentTemplateModal();
|
|
@@ -3599,6 +3656,9 @@
|
|
|
3599
3656
|
inputNode.addEventListener('input', function () {
|
|
3600
3657
|
updateCreateAgentPromptCommandFromCommand();
|
|
3601
3658
|
});
|
|
3659
|
+
inputNode.addEventListener('change', function () {
|
|
3660
|
+
updateCreateAgentPromptCommandFromCommand();
|
|
3661
|
+
});
|
|
3602
3662
|
});
|
|
3603
3663
|
|
|
3604
3664
|
if (createAgentPromptCommand) {
|
|
@@ -3614,12 +3674,6 @@
|
|
|
3614
3674
|
});
|
|
3615
3675
|
}
|
|
3616
3676
|
|
|
3617
|
-
if (createContainerPath) {
|
|
3618
|
-
createContainerPath.addEventListener('input', function () {
|
|
3619
|
-
state.createContainerPathBase = String(createContainerPath.value || '').trim();
|
|
3620
|
-
});
|
|
3621
|
-
}
|
|
3622
|
-
|
|
3623
3677
|
if (createForm) {
|
|
3624
3678
|
createForm.addEventListener('submit', async function (event) {
|
|
3625
3679
|
event.preventDefault();
|
package/lib/web/server.js
CHANGED
|
@@ -3767,7 +3767,7 @@ async function startWebServer(options) {
|
|
|
3767
3767
|
const appFrontendMatch = pathname.match(/^\/app\/frontend\/([A-Za-z0-9._-]+)$/);
|
|
3768
3768
|
if (req.method === 'GET' && appFrontendMatch) {
|
|
3769
3769
|
const assetName = appFrontendMatch[1];
|
|
3770
|
-
if (!(assetName === 'app.css' || assetName === 'app.js' || assetName === 'markdown.css' || assetName === 'markdown-renderer.js'
|
|
3770
|
+
if (!(assetName === 'app.css' || assetName === 'app.js' || assetName === 'markdown.css' || assetName === 'markdown-renderer.js')) {
|
|
3771
3771
|
sendHtml(res, 404, '<h1>404 Not Found</h1>');
|
|
3772
3772
|
return;
|
|
3773
3773
|
}
|
package/package.json
CHANGED
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
(function (root, factory) {
|
|
2
|
-
const api = factory();
|
|
3
|
-
if (typeof module === 'object' && module.exports) {
|
|
4
|
-
module.exports = api;
|
|
5
|
-
}
|
|
6
|
-
if (root && typeof root === 'object') {
|
|
7
|
-
root.ManyoyoPathPickerUtils = api;
|
|
8
|
-
}
|
|
9
|
-
}(typeof globalThis !== 'undefined' ? globalThis : this, function () {
|
|
10
|
-
function normalizeSlashPath(value) {
|
|
11
|
-
return String(value || '').replace(/\\/g, '/');
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
function isChildPath(basePath, targetPath) {
|
|
15
|
-
const normalizedBase = normalizeSlashPath(basePath).replace(/\/+$/, '');
|
|
16
|
-
const normalizedTarget = normalizeSlashPath(targetPath).replace(/\/+$/, '');
|
|
17
|
-
if (!normalizedBase) {
|
|
18
|
-
return false;
|
|
19
|
-
}
|
|
20
|
-
return normalizedTarget === normalizedBase || normalizedTarget.startsWith(normalizedBase + '/');
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
function resolveContainerPickerBase(baseContainerPath, currentContainerPath) {
|
|
24
|
-
return String(baseContainerPath || '').trim()
|
|
25
|
-
|| String(currentContainerPath || '').trim()
|
|
26
|
-
|| '/workspace';
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
function buildContainerPathFromHostSelection(baseHostPath, baseContainerPath, selectedHostPath) {
|
|
30
|
-
const normalizedBaseHost = normalizeSlashPath(baseHostPath).replace(/\/+$/, '');
|
|
31
|
-
const normalizedContainer = normalizeSlashPath(baseContainerPath).replace(/\/+$/, '') || '/workspace';
|
|
32
|
-
const normalizedSelected = normalizeSlashPath(selectedHostPath).replace(/\/+$/, '');
|
|
33
|
-
if (!normalizedBaseHost || !isChildPath(normalizedBaseHost, normalizedSelected)) {
|
|
34
|
-
return normalizedContainer;
|
|
35
|
-
}
|
|
36
|
-
const relative = normalizedSelected === normalizedBaseHost
|
|
37
|
-
? ''
|
|
38
|
-
: normalizedSelected.slice(normalizedBaseHost.length + 1);
|
|
39
|
-
return relative ? `${normalizedContainer}/${relative}`.replace(/\/+/g, '/') : normalizedContainer;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
function applyContainerPathSelection(baseHostPath, baseContainerPath, currentContainerPath, selectedHostPath) {
|
|
43
|
-
return buildContainerPathFromHostSelection(
|
|
44
|
-
baseHostPath,
|
|
45
|
-
resolveContainerPickerBase(baseContainerPath, currentContainerPath),
|
|
46
|
-
selectedHostPath
|
|
47
|
-
);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
return {
|
|
51
|
-
normalizeSlashPath,
|
|
52
|
-
isChildPath,
|
|
53
|
-
resolveContainerPickerBase,
|
|
54
|
-
buildContainerPathFromHostSelection,
|
|
55
|
-
applyContainerPathSelection
|
|
56
|
-
};
|
|
57
|
-
}));
|