@zhongqian97-code/ecode 0.5.30 → 0.5.31
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/dist/index.js +255 -14
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -5700,6 +5700,21 @@ function generateAdminHtml(version2) {
|
|
|
5700
5700
|
to { opacity: 1; transform: translateX(0); }
|
|
5701
5701
|
}
|
|
5702
5702
|
|
|
5703
|
+
/* \u2500\u2500 Skill dropdown \u2500\u2500 */
|
|
5704
|
+
#skill-dropdown .skill-item {
|
|
5705
|
+
padding: 8px 12px;
|
|
5706
|
+
cursor: pointer;
|
|
5707
|
+
border-bottom: 1px solid #30363d;
|
|
5708
|
+
display: flex;
|
|
5709
|
+
gap: 8px;
|
|
5710
|
+
align-items: baseline;
|
|
5711
|
+
}
|
|
5712
|
+
#skill-dropdown .skill-item:last-child { border-bottom: none; }
|
|
5713
|
+
#skill-dropdown .skill-item:hover,
|
|
5714
|
+
#skill-dropdown .skill-item.selected { background: #2d333b; }
|
|
5715
|
+
#skill-dropdown .skill-name { color: #79c0ff; font-weight: 600; font-size: 0.9em; }
|
|
5716
|
+
#skill-dropdown .skill-desc { color: #8b949e; font-size: 0.8em; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 300px; }
|
|
5717
|
+
|
|
5703
5718
|
/* \u2500\u2500 Mobile \u2500\u2500 */
|
|
5704
5719
|
@media (max-width: 600px) {
|
|
5705
5720
|
#hamburger { display: block; }
|
|
@@ -5711,6 +5726,22 @@ function generateAdminHtml(version2) {
|
|
|
5711
5726
|
transition: transform .2s ease;
|
|
5712
5727
|
}
|
|
5713
5728
|
#sidebar.open { transform: translateX(0); }
|
|
5729
|
+
|
|
5730
|
+
/* Fix input bar on mobile */
|
|
5731
|
+
#input-bar {
|
|
5732
|
+
position: fixed;
|
|
5733
|
+
bottom: 0;
|
|
5734
|
+
left: 0;
|
|
5735
|
+
right: 0;
|
|
5736
|
+
bottom: env(safe-area-inset-bottom, 0px);
|
|
5737
|
+
z-index: 40;
|
|
5738
|
+
padding-bottom: calc(10px + env(safe-area-inset-bottom, 0px));
|
|
5739
|
+
}
|
|
5740
|
+
|
|
5741
|
+
/* Add bottom padding to chat so messages don't hide behind fixed input */
|
|
5742
|
+
#messages {
|
|
5743
|
+
padding-bottom: 80px;
|
|
5744
|
+
}
|
|
5714
5745
|
}
|
|
5715
5746
|
</style>
|
|
5716
5747
|
</head>
|
|
@@ -5749,6 +5780,7 @@ function generateAdminHtml(version2) {
|
|
|
5749
5780
|
<div class="empty-chat">\u2190 \u4ECE\u5DE6\u4FA7\u9009\u62E9\u4F1A\u8BDD\uFF0C\u6216\u70B9\u51FB"\u65B0\u5EFA\u4F1A\u8BDD"\u5F00\u59CB</div>
|
|
5750
5781
|
</div>
|
|
5751
5782
|
<div id="ws-status" class="ws-status"></div>
|
|
5783
|
+
<div id="skill-dropdown" style="display:none;position:fixed;bottom:60px;left:14px;right:14px;max-height:200px;overflow-y:auto;background:#1c2128;border:1px solid #30363d;border-radius:6px;z-index:60;"></div>
|
|
5752
5784
|
<div id="input-bar">
|
|
5753
5785
|
<textarea id="msg-input" rows="1" placeholder="\u8F93\u5165\u6D88\u606F\uFF0C\u6309 Enter \u53D1\u9001\uFF08Shift+Enter \u6362\u884C\uFF09\u2026" disabled></textarea>
|
|
5754
5786
|
<button id="send-btn" disabled>\u53D1\u9001</button>
|
|
@@ -5813,6 +5845,8 @@ function generateAdminHtml(version2) {
|
|
|
5813
5845
|
wsRetries: 0,
|
|
5814
5846
|
streamingMsgEl: null, // DOM element currently receiving delta tokens
|
|
5815
5847
|
showTools: true,
|
|
5848
|
+
skills: [], // cached skills from /api/skills
|
|
5849
|
+
skillsLoaded: false,
|
|
5816
5850
|
};
|
|
5817
5851
|
|
|
5818
5852
|
// \u2500\u2500 Toast \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
@@ -6161,6 +6195,70 @@ function generateAdminHtml(version2) {
|
|
|
6161
6195
|
.replace(/>/g, '>');
|
|
6162
6196
|
}
|
|
6163
6197
|
|
|
6198
|
+
// \u2500\u2500 Skill dropdown \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
6199
|
+
var selectedSkillIndex = -1;
|
|
6200
|
+
|
|
6201
|
+
async function loadSkills() {
|
|
6202
|
+
if (state.skillsLoaded) return;
|
|
6203
|
+
try {
|
|
6204
|
+
const data = await apiFetch('/api/skills');
|
|
6205
|
+
state.skills = Array.isArray(data) ? data : [];
|
|
6206
|
+
state.skillsLoaded = true;
|
|
6207
|
+
} catch (e) {
|
|
6208
|
+
state.skills = [];
|
|
6209
|
+
}
|
|
6210
|
+
}
|
|
6211
|
+
|
|
6212
|
+
function showSkillDropdown(query) {
|
|
6213
|
+
const dropdown = document.getElementById('skill-dropdown');
|
|
6214
|
+
if (!dropdown) return;
|
|
6215
|
+
const q = query.toLowerCase();
|
|
6216
|
+
const filtered = state.skills.filter(function(s) {
|
|
6217
|
+
return s.name.toLowerCase().startsWith(q);
|
|
6218
|
+
});
|
|
6219
|
+
if (!filtered.length) {
|
|
6220
|
+
dropdown.style.display = 'none';
|
|
6221
|
+
selectedSkillIndex = -1;
|
|
6222
|
+
return;
|
|
6223
|
+
}
|
|
6224
|
+
selectedSkillIndex = -1;
|
|
6225
|
+
dropdown.innerHTML = filtered.map(function(s, i) {
|
|
6226
|
+
return '<div class="skill-item" data-name="' + escHtml(s.name) + '">' +
|
|
6227
|
+
'<span class="skill-name">/' + escHtml(s.name) + '</span>' +
|
|
6228
|
+
'<span class="skill-desc">' + escHtml(s.description || '') + '</span>' +
|
|
6229
|
+
'</div>';
|
|
6230
|
+
}).join('');
|
|
6231
|
+
dropdown.querySelectorAll('.skill-item').forEach(function(el) {
|
|
6232
|
+
el.addEventListener('click', function() {
|
|
6233
|
+
var name = el.getAttribute('data-name');
|
|
6234
|
+
var inputEl = document.getElementById('msg-input');
|
|
6235
|
+
inputEl.value = '/' + name + ' ';
|
|
6236
|
+
hideSkillDropdown();
|
|
6237
|
+
inputEl.focus();
|
|
6238
|
+
});
|
|
6239
|
+
});
|
|
6240
|
+
dropdown.style.display = 'block';
|
|
6241
|
+
}
|
|
6242
|
+
|
|
6243
|
+
function hideSkillDropdown() {
|
|
6244
|
+
const dropdown = document.getElementById('skill-dropdown');
|
|
6245
|
+
if (dropdown) dropdown.style.display = 'none';
|
|
6246
|
+
selectedSkillIndex = -1;
|
|
6247
|
+
}
|
|
6248
|
+
|
|
6249
|
+
function updateSkillSelection() {
|
|
6250
|
+
const dropdown = document.getElementById('skill-dropdown');
|
|
6251
|
+
if (!dropdown) return;
|
|
6252
|
+
const items = dropdown.querySelectorAll('.skill-item');
|
|
6253
|
+
items.forEach(function(el, i) {
|
|
6254
|
+
if (i === selectedSkillIndex) {
|
|
6255
|
+
el.classList.add('selected');
|
|
6256
|
+
} else {
|
|
6257
|
+
el.classList.remove('selected');
|
|
6258
|
+
}
|
|
6259
|
+
});
|
|
6260
|
+
}
|
|
6261
|
+
|
|
6164
6262
|
// \u2500\u2500 Approval modal \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
6165
6263
|
function showApprovalModal(msg) {
|
|
6166
6264
|
const box = document.getElementById('approval-box');
|
|
@@ -6260,17 +6358,57 @@ function generateAdminHtml(version2) {
|
|
|
6260
6358
|
|
|
6261
6359
|
document.getElementById('send-btn').addEventListener('click', sendMessage);
|
|
6262
6360
|
|
|
6263
|
-
document.getElementById('msg-input').addEventListener('keydown', (e)
|
|
6361
|
+
document.getElementById('msg-input').addEventListener('keydown', function(e) {
|
|
6362
|
+
const dropdown = document.getElementById('skill-dropdown');
|
|
6363
|
+
const dropdownVisible = dropdown && dropdown.style.display !== 'none';
|
|
6364
|
+
if (dropdownVisible) {
|
|
6365
|
+
const items = dropdown.querySelectorAll('.skill-item');
|
|
6366
|
+
if (e.key === 'ArrowDown') {
|
|
6367
|
+
e.preventDefault();
|
|
6368
|
+
selectedSkillIndex = Math.min(selectedSkillIndex + 1, items.length - 1);
|
|
6369
|
+
updateSkillSelection();
|
|
6370
|
+
return;
|
|
6371
|
+
}
|
|
6372
|
+
if (e.key === 'ArrowUp') {
|
|
6373
|
+
e.preventDefault();
|
|
6374
|
+
selectedSkillIndex = Math.max(selectedSkillIndex - 1, -1);
|
|
6375
|
+
updateSkillSelection();
|
|
6376
|
+
return;
|
|
6377
|
+
}
|
|
6378
|
+
if (e.key === 'Enter' && selectedSkillIndex >= 0) {
|
|
6379
|
+
e.preventDefault();
|
|
6380
|
+
const selected = items[selectedSkillIndex];
|
|
6381
|
+
if (selected) {
|
|
6382
|
+
var name = selected.getAttribute('data-name');
|
|
6383
|
+
var inputEl = document.getElementById('msg-input');
|
|
6384
|
+
inputEl.value = '/' + name + ' ';
|
|
6385
|
+
hideSkillDropdown();
|
|
6386
|
+
inputEl.focus();
|
|
6387
|
+
}
|
|
6388
|
+
return;
|
|
6389
|
+
}
|
|
6390
|
+
if (e.key === 'Escape') {
|
|
6391
|
+
e.preventDefault();
|
|
6392
|
+
hideSkillDropdown();
|
|
6393
|
+
return;
|
|
6394
|
+
}
|
|
6395
|
+
}
|
|
6264
6396
|
if (e.key === 'Enter' && !e.shiftKey) {
|
|
6265
6397
|
e.preventDefault();
|
|
6266
6398
|
sendMessage();
|
|
6267
6399
|
}
|
|
6268
6400
|
});
|
|
6269
6401
|
|
|
6270
|
-
// Auto-resize textarea
|
|
6402
|
+
// Auto-resize textarea + slash command dropdown
|
|
6271
6403
|
document.getElementById('msg-input').addEventListener('input', function() {
|
|
6272
6404
|
this.style.height = 'auto';
|
|
6273
6405
|
this.style.height = Math.min(this.scrollHeight, 120) + 'px';
|
|
6406
|
+
const val = this.value;
|
|
6407
|
+
if (val.startsWith('/')) {
|
|
6408
|
+
loadSkills().then(function() { showSkillDropdown(val.slice(1)); });
|
|
6409
|
+
} else {
|
|
6410
|
+
hideSkillDropdown();
|
|
6411
|
+
}
|
|
6274
6412
|
});
|
|
6275
6413
|
|
|
6276
6414
|
// \u2500\u2500 Hamburger (mobile) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
@@ -6382,6 +6520,13 @@ function generateAdminHtml(version2) {
|
|
|
6382
6520
|
});
|
|
6383
6521
|
});
|
|
6384
6522
|
|
|
6523
|
+
// \u2500\u2500 Skill dropdown: hide on outside click \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
6524
|
+
document.addEventListener('click', function(e) {
|
|
6525
|
+
if (!e.target.closest('#skill-dropdown') && !e.target.closest('#msg-input')) {
|
|
6526
|
+
hideSkillDropdown();
|
|
6527
|
+
}
|
|
6528
|
+
});
|
|
6529
|
+
|
|
6385
6530
|
// \u2500\u2500 Mobile keyboard adaptation \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
6386
6531
|
document.getElementById('msg-input').addEventListener('focus', () => {
|
|
6387
6532
|
setTimeout(() => {
|
|
@@ -6389,6 +6534,15 @@ function generateAdminHtml(version2) {
|
|
|
6389
6534
|
}, 300);
|
|
6390
6535
|
});
|
|
6391
6536
|
|
|
6537
|
+
if (window.visualViewport) {
|
|
6538
|
+
window.visualViewport.addEventListener('resize', function() {
|
|
6539
|
+
const bar = document.getElementById('input-bar');
|
|
6540
|
+
if (!bar) return;
|
|
6541
|
+
const offsetBottom = window.innerHeight - window.visualViewport.height - window.visualViewport.offsetTop;
|
|
6542
|
+
bar.style.bottom = Math.max(0, offsetBottom) + 'px';
|
|
6543
|
+
});
|
|
6544
|
+
}
|
|
6545
|
+
|
|
6392
6546
|
// \u2500\u2500 Global error boundary \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
6393
6547
|
window.onerror = function(msg, src, line) {
|
|
6394
6548
|
const wsStatusEl = document.getElementById('ws-status');
|
|
@@ -6664,6 +6818,9 @@ async function chatRoutes(app, opts) {
|
|
|
6664
6818
|
if (typeof body.systemPrompt === "string") {
|
|
6665
6819
|
sessionOpts.systemPrompt = body.systemPrompt;
|
|
6666
6820
|
}
|
|
6821
|
+
if (opts.autoApprove) {
|
|
6822
|
+
sessionOpts.autoApproveNormal = true;
|
|
6823
|
+
}
|
|
6667
6824
|
if (!opts.config.apiKey) {
|
|
6668
6825
|
return reply.code(400).send({
|
|
6669
6826
|
success: false,
|
|
@@ -6828,6 +6985,80 @@ async function systemRoutes(app, opts) {
|
|
|
6828
6985
|
});
|
|
6829
6986
|
}
|
|
6830
6987
|
|
|
6988
|
+
// src/web/routes/skills.ts
|
|
6989
|
+
import { readdir as readdir5, readFile as readFile10 } from "fs/promises";
|
|
6990
|
+
import { join as join15 } from "path";
|
|
6991
|
+
import os2 from "os";
|
|
6992
|
+
var BUILTIN_COMMANDS = [
|
|
6993
|
+
{ name: "clear", description: "Clear conversation history", type: "builtin" },
|
|
6994
|
+
{ name: "interrupt", description: "Interrupt current operation", type: "builtin" },
|
|
6995
|
+
{ name: "help", description: "Show help information", type: "builtin" }
|
|
6996
|
+
];
|
|
6997
|
+
function parseFrontmatter2(content) {
|
|
6998
|
+
const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
|
|
6999
|
+
if (!match) return null;
|
|
7000
|
+
const frontmatter = match[1];
|
|
7001
|
+
const nameMatch = frontmatter.match(/^name:\s*(.+)$/m);
|
|
7002
|
+
if (!nameMatch) return null;
|
|
7003
|
+
const descMatch = frontmatter.match(/^description:\s*(?:>-?|[|>+])?\s*(.+)$/m);
|
|
7004
|
+
if (!descMatch) return null;
|
|
7005
|
+
const name = nameMatch[1].trim();
|
|
7006
|
+
const description = descMatch[1].trim();
|
|
7007
|
+
if (!name || !description) return null;
|
|
7008
|
+
return { name, description };
|
|
7009
|
+
}
|
|
7010
|
+
async function loadAgents() {
|
|
7011
|
+
const agentsDir = join15(os2.homedir(), ".claude", "agents");
|
|
7012
|
+
let files;
|
|
7013
|
+
try {
|
|
7014
|
+
const entries = await readdir5(agentsDir);
|
|
7015
|
+
files = entries.filter((f) => f.endsWith(".md"));
|
|
7016
|
+
} catch {
|
|
7017
|
+
return [];
|
|
7018
|
+
}
|
|
7019
|
+
const items = [];
|
|
7020
|
+
for (const file of files) {
|
|
7021
|
+
try {
|
|
7022
|
+
const content = await readFile10(join15(agentsDir, file), "utf-8");
|
|
7023
|
+
const parsed = parseFrontmatter2(content);
|
|
7024
|
+
if (parsed) {
|
|
7025
|
+
items.push({ ...parsed, type: "agent" });
|
|
7026
|
+
}
|
|
7027
|
+
} catch {
|
|
7028
|
+
}
|
|
7029
|
+
}
|
|
7030
|
+
return items;
|
|
7031
|
+
}
|
|
7032
|
+
async function loadSkills() {
|
|
7033
|
+
const skillsDir = join15(process.cwd(), "skills");
|
|
7034
|
+
let subdirs;
|
|
7035
|
+
try {
|
|
7036
|
+
const entries = await readdir5(skillsDir, { withFileTypes: true });
|
|
7037
|
+
subdirs = entries.filter((e) => e.isDirectory()).map((e) => e.name);
|
|
7038
|
+
} catch {
|
|
7039
|
+
return [];
|
|
7040
|
+
}
|
|
7041
|
+
const items = [];
|
|
7042
|
+
for (const subdir of subdirs) {
|
|
7043
|
+
try {
|
|
7044
|
+
const skillFile = join15(skillsDir, subdir, "SKILL.md");
|
|
7045
|
+
const content = await readFile10(skillFile, "utf-8");
|
|
7046
|
+
const parsed = parseFrontmatter2(content);
|
|
7047
|
+
if (parsed) {
|
|
7048
|
+
items.push({ ...parsed, type: "skill" });
|
|
7049
|
+
}
|
|
7050
|
+
} catch {
|
|
7051
|
+
}
|
|
7052
|
+
}
|
|
7053
|
+
return items;
|
|
7054
|
+
}
|
|
7055
|
+
async function skillsRoutes(app) {
|
|
7056
|
+
app.get("/api/skills", async (_request, _reply) => {
|
|
7057
|
+
const [agents, skills] = await Promise.all([loadAgents(), loadSkills()]);
|
|
7058
|
+
return [...BUILTIN_COMMANDS, ...agents, ...skills];
|
|
7059
|
+
});
|
|
7060
|
+
}
|
|
7061
|
+
|
|
6831
7062
|
// src/web/server.ts
|
|
6832
7063
|
async function buildServer(opts) {
|
|
6833
7064
|
const app = Fastify({ logger: false });
|
|
@@ -6854,8 +7085,9 @@ async function buildServer(opts) {
|
|
|
6854
7085
|
await app.register(sessionsRoutes, { config: opts.config, manager: opts.manager });
|
|
6855
7086
|
await app.register(configRoutes, { config: opts.config, save: saveConfig });
|
|
6856
7087
|
await app.register(automationRoutes, { config: opts.config });
|
|
6857
|
-
await app.register(chatRoutes, { config: opts.config, manager: opts.manager });
|
|
7088
|
+
await app.register(chatRoutes, { config: opts.config, manager: opts.manager, autoApprove: opts.autoApprove });
|
|
6858
7089
|
await app.register(systemRoutes, { version: opts.version });
|
|
7090
|
+
await app.register(skillsRoutes);
|
|
6859
7091
|
await app.register(sessionHubRoutes, { manager: opts.manager });
|
|
6860
7092
|
return app;
|
|
6861
7093
|
}
|
|
@@ -6951,6 +7183,7 @@ var SessionRuntime = class {
|
|
|
6951
7183
|
messages;
|
|
6952
7184
|
config;
|
|
6953
7185
|
model;
|
|
7186
|
+
autoApproveNormal;
|
|
6954
7187
|
abortController = null;
|
|
6955
7188
|
_stopAfterToolRound = false;
|
|
6956
7189
|
_turnCount = 0;
|
|
@@ -6963,6 +7196,7 @@ var SessionRuntime = class {
|
|
|
6963
7196
|
this.config = config2;
|
|
6964
7197
|
this.llm = opts.llm ?? createProvider(resolveActiveProfile(config2));
|
|
6965
7198
|
this.model = config2.model;
|
|
7199
|
+
this.autoApproveNormal = opts.autoApproveNormal ?? false;
|
|
6966
7200
|
const systemContent = opts.systemPrompt ?? (config2.systemPrompt ?? DEFAULT_SYSTEM_PROMPT);
|
|
6967
7201
|
this.messages = systemContent ? [{ role: "system", content: systemContent }] : [];
|
|
6968
7202
|
if (opts.initialMessages) {
|
|
@@ -7101,17 +7335,20 @@ var SessionRuntime = class {
|
|
|
7101
7335
|
const parsed = JSON.parse(args);
|
|
7102
7336
|
const cls = classifyCommand(parsed.command, this.config.dangerousPatterns);
|
|
7103
7337
|
if (cls === "normal" || cls === "danger") {
|
|
7104
|
-
|
|
7105
|
-
|
|
7106
|
-
|
|
7338
|
+
if (cls === "normal" && this.autoApproveNormal) {
|
|
7339
|
+
} else {
|
|
7340
|
+
this._status = "awaiting_confirm";
|
|
7341
|
+
const kind = cls === "danger" ? "danger" : "normal";
|
|
7342
|
+
const prompt = cls === "danger" ? `\u26A0\uFE0F DANGEROUS COMMAND: ${parsed.command}` : `Execute command: ${parsed.command}
|
|
7107
7343
|
Proceed?`;
|
|
7108
|
-
|
|
7109
|
-
|
|
7110
|
-
|
|
7111
|
-
|
|
7112
|
-
|
|
7113
|
-
|
|
7114
|
-
|
|
7344
|
+
const { id: reqId, promise } = this.approvals.request(kind, prompt);
|
|
7345
|
+
this.bus.emit({ type: "approval.requested", requestId: reqId, kind, prompt });
|
|
7346
|
+
const approved = await promise;
|
|
7347
|
+
this._status = "tool_calling";
|
|
7348
|
+
if (!approved) {
|
|
7349
|
+
this._stopAfterToolRound = true;
|
|
7350
|
+
return SKIP_MESSAGE;
|
|
7351
|
+
}
|
|
7115
7352
|
}
|
|
7116
7353
|
}
|
|
7117
7354
|
if (signal.aborted) return SKIP_MESSAGE;
|
|
@@ -7389,6 +7626,7 @@ if (rawArgs[0] === "sessions") {
|
|
|
7389
7626
|
if (rawArgs[0] === "web") {
|
|
7390
7627
|
let webPort = 4310;
|
|
7391
7628
|
let webHost = "127.0.0.1";
|
|
7629
|
+
let webAutoApprove = false;
|
|
7392
7630
|
for (let i = 1; i < rawArgs.length; i++) {
|
|
7393
7631
|
const arg = rawArgs[i];
|
|
7394
7632
|
const next = rawArgs[i + 1];
|
|
@@ -7399,6 +7637,8 @@ if (rawArgs[0] === "web") {
|
|
|
7399
7637
|
} else if (arg === "--host" && next && !next.startsWith("-")) {
|
|
7400
7638
|
webHost = next;
|
|
7401
7639
|
i++;
|
|
7640
|
+
} else if (arg === "--auto") {
|
|
7641
|
+
webAutoApprove = true;
|
|
7402
7642
|
}
|
|
7403
7643
|
}
|
|
7404
7644
|
const token = generateAccessToken();
|
|
@@ -7407,7 +7647,8 @@ if (rawArgs[0] === "web") {
|
|
|
7407
7647
|
config: finalConfig,
|
|
7408
7648
|
manager,
|
|
7409
7649
|
token,
|
|
7410
|
-
version: VERSION
|
|
7650
|
+
version: VERSION,
|
|
7651
|
+
autoApprove: webAutoApprove
|
|
7411
7652
|
});
|
|
7412
7653
|
await server.listen({ port: webPort, host: webHost });
|
|
7413
7654
|
const browserHost = webHost === "0.0.0.0" ? "localhost" : webHost;
|