@wendongfly/myhi 1.3.101 → 1.3.103
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/chat.html +106 -11
- package/dist/index.js +1 -1
- package/dist/index.min.js +2 -2
- package/package.json +1 -1
package/dist/chat.html
CHANGED
|
@@ -352,6 +352,7 @@
|
|
|
352
352
|
<button class="tb-btn" id="btn-photo" onclick="openCamera()" title="拍照">
|
|
353
353
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M23 19a2 2 0 01-2 2H3a2 2 0 01-2-2V8a2 2 0 012-2h4l2-3h6l2 3h4a2 2 0 012 2z"/><circle cx="12" cy="13" r="4"/></svg>
|
|
354
354
|
</button>
|
|
355
|
+
<span id="enter-hint" style="display:none;font-size:0.68rem;color:var(--muted);white-space:nowrap;align-self:center;margin-left:0.15rem"></span>
|
|
355
356
|
<div class="spacer"></div>
|
|
356
357
|
<button class="tb-btn" id="voice-btn" onclick="openVaSheet()" title="语音输入 / 需求助手">
|
|
357
358
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M12 1a3 3 0 00-3 3v8a3 3 0 006 0V4a3 3 0 00-3-3z"/><path d="M19 10v2a7 7 0 01-14 0v-2"/><line x1="12" y1="19" x2="12" y2="23"/><line x1="8" y1="23" x2="16" y2="23"/></svg>
|
|
@@ -453,6 +454,18 @@
|
|
|
453
454
|
<label class="setting-toggle"><span>显示思考过程</span><input type="checkbox" id="set-thinking" checked></label>
|
|
454
455
|
<label class="setting-toggle"><span>工具调用默认折叠</span><input type="checkbox" id="set-collapse" checked></label>
|
|
455
456
|
</div>
|
|
457
|
+
<div class="setting-group">
|
|
458
|
+
<h4>输入</h4>
|
|
459
|
+
<div style="font-size:0.8rem;color:var(--text2);margin:0.1rem 0 0.35rem">回车键</div>
|
|
460
|
+
<div id="seg-enter" class="seg-row">
|
|
461
|
+
<button class="seg" data-enter="auto">自动</button>
|
|
462
|
+
<button class="seg" data-enter="send">发送</button>
|
|
463
|
+
<button class="seg" data-enter="newline">换行</button>
|
|
464
|
+
</div>
|
|
465
|
+
<div style="font-size:0.72rem;color:var(--muted);margin-top:0.35rem;line-height:1.5">
|
|
466
|
+
自动:电脑回车发送 / Shift+回车换行;手机回车换行、用按钮发送。<br>发送:回车总是发送(换行用 Shift+回车)。换行:回车总是换行(发送用 Ctrl/⌘+回车 或按钮)。
|
|
467
|
+
</div>
|
|
468
|
+
</div>
|
|
456
469
|
<div class="setting-group">
|
|
457
470
|
<h4>语音识别 (ASR)</h4>
|
|
458
471
|
<div style="font-size:0.72rem;color:var(--muted);margin-bottom:0.35rem">SenseVoice 或兼容服务的地址,留空表示禁用语音</div>
|
|
@@ -540,16 +553,28 @@
|
|
|
540
553
|
<div class="action-sheet-title">项目密钥 · 本会话</div>
|
|
541
554
|
<div style="font-size:0.68rem;color:var(--muted);padding:0 0.2rem 0.4rem;line-height:1.5">
|
|
542
555
|
只注入到<b>本项目 (cwd) 的会话</b>,命令里用 <code>$名字</code> 引用(证书类型用 <code>$MYHI_SECRET_名字</code>)。密钥值不进聊天。新增后需 <b>清除/重开会话</b>才注入进环境变量。
|
|
556
|
+
<a onclick="toggleBulkSecrets()" id="sec-bulk-toggle" style="color:var(--blue2);cursor:pointer;white-space:nowrap">批量编辑 ⇄</a>
|
|
543
557
|
</div>
|
|
544
|
-
|
|
545
|
-
<div style="
|
|
546
|
-
<div style="
|
|
547
|
-
|
|
548
|
-
<
|
|
558
|
+
<!-- 列表模式 -->
|
|
559
|
+
<div id="sec-mode-list" style="flex:1;display:flex;flex-direction:column;min-height:0">
|
|
560
|
+
<div id="sec-sheet-list" style="flex:1;overflow-y:auto;padding:0.2rem 0;font-size:0.8rem;scrollbar-width:thin"></div>
|
|
561
|
+
<div style="padding:0.3rem 0.2rem;display:flex;flex-direction:column;gap:0.4rem;border-top:1px solid var(--surface2)">
|
|
562
|
+
<div style="display:flex;gap:0.4rem">
|
|
563
|
+
<input id="sec-sheet-name" class="slash-inp" placeholder="名字 如 GITLAB_PAT" autocomplete="off" style="flex:1">
|
|
564
|
+
<select id="sec-sheet-type" class="slash-inp" style="max-width:88px"><option value="env">变量</option><option value="file">文件</option></select>
|
|
565
|
+
</div>
|
|
566
|
+
<input id="sec-sheet-value" class="slash-inp" type="password" placeholder="密钥值 / 证书内容(点上方某项可载入其名改值)" autocomplete="off">
|
|
567
|
+
</div>
|
|
568
|
+
<button class="action-sheet-cancel" style="background:var(--blue2);color:#fff;font-weight:600;margin:0.4rem 0" onclick="addProjectSecret()">保存密钥</button>
|
|
569
|
+
</div>
|
|
570
|
+
<!-- 批量模式:像编辑 .env 一样总览+批量增改 -->
|
|
571
|
+
<div id="sec-mode-bulk" style="display:none;flex:1;flex-direction:column;min-height:0">
|
|
572
|
+
<div style="font-size:0.66rem;color:var(--muted);padding:0 0.2rem 0.3rem;line-height:1.5">
|
|
573
|
+
每行 <code>NAME=值</code>;值留空=保留旧值不改;<code>#</code> 开头忽略。已有变量已列出(值隐藏,填上即改)。<b>此处不删变量</b>(删用列表模式);仅按「变量」型保存。
|
|
549
574
|
</div>
|
|
550
|
-
<
|
|
575
|
+
<textarea id="sec-bulk-text" spellcheck="false" style="flex:1;min-height:9rem;width:100%;box-sizing:border-box;font-family:monospace;font-size:0.78rem;background:var(--surface2);color:var(--text);border:1px solid var(--border);border-radius:8px;padding:0.5rem;resize:vertical"></textarea>
|
|
576
|
+
<button class="action-sheet-cancel" style="background:var(--blue2);color:#fff;font-weight:600;margin:0.4rem 0" onclick="saveBulkSecrets()">批量保存</button>
|
|
551
577
|
</div>
|
|
552
|
-
<button class="action-sheet-cancel" style="background:var(--blue2);color:#fff;font-weight:600;margin-bottom:0.4rem" onclick="addProjectSecret()">保存密钥</button>
|
|
553
578
|
<button class="action-sheet-cancel" onclick="closeSecretsSheet()">关闭</button>
|
|
554
579
|
</div>
|
|
555
580
|
</div>
|
|
@@ -796,7 +821,7 @@
|
|
|
796
821
|
let workState = 'idle';
|
|
797
822
|
|
|
798
823
|
// 设置
|
|
799
|
-
const DEFAULT_SETTINGS = { parseOutput: true, showThinking: true, collapseTools: true };
|
|
824
|
+
const DEFAULT_SETTINGS = { parseOutput: true, showThinking: true, collapseTools: true, enterMode: 'auto' };
|
|
800
825
|
let settings = loadSettings();
|
|
801
826
|
|
|
802
827
|
function loadSettings() { try { return { ...DEFAULT_SETTINGS, ...JSON.parse(localStorage.getItem('myhi_chat_settings')) }; } catch { return { ...DEFAULT_SETTINGS }; } }
|
|
@@ -825,6 +850,24 @@
|
|
|
825
850
|
}
|
|
826
851
|
document.querySelectorAll('#seg-theme .seg').forEach(b => b.addEventListener('click', () => applyTheme(b.dataset.theme)));
|
|
827
852
|
document.querySelectorAll('#seg-font .seg').forEach(b => b.addEventListener('click', () => applyFont(b.dataset.font)));
|
|
853
|
+
// 回车键行为(自动/发送/换行)——存 settings.enterMode,keydown 处理器读取
|
|
854
|
+
function updateEnterHint() {
|
|
855
|
+
const el = document.getElementById('enter-hint');
|
|
856
|
+
if (!el) return;
|
|
857
|
+
if (window.matchMedia('(pointer: coarse)').matches) { el.style.display = 'none'; return; } // 手机不显示
|
|
858
|
+
const mode = settings.enterMode || 'auto';
|
|
859
|
+
el.textContent = mode === 'newline' ? 'Enter 换行 · Ctrl+Enter 发送' : 'Enter 发送 · Shift+Enter 换行';
|
|
860
|
+
el.style.display = '';
|
|
861
|
+
}
|
|
862
|
+
function syncEnterModeUI() {
|
|
863
|
+
const m = settings.enterMode || 'auto';
|
|
864
|
+
document.querySelectorAll('#seg-enter .seg').forEach(b => b.classList.toggle('active', b.dataset.enter === m));
|
|
865
|
+
updateEnterHint();
|
|
866
|
+
}
|
|
867
|
+
document.querySelectorAll('#seg-enter .seg').forEach(b => b.addEventListener('click', () => {
|
|
868
|
+
settings.enterMode = b.dataset.enter; saveSettings(); syncEnterModeUI();
|
|
869
|
+
}));
|
|
870
|
+
updateEnterHint();
|
|
828
871
|
|
|
829
872
|
// 输出累积
|
|
830
873
|
let outputBuffer = '';
|
|
@@ -2023,8 +2066,17 @@
|
|
|
2023
2066
|
}
|
|
2024
2067
|
return;
|
|
2025
2068
|
}
|
|
2026
|
-
if (e.key === 'Enter'
|
|
2027
|
-
|
|
2069
|
+
if (e.key === 'Enter') {
|
|
2070
|
+
if (e.isComposing || e.keyCode === 229) return; // 中文/日文输入法选词中,绝不发送
|
|
2071
|
+
if (e.ctrlKey || e.metaKey) { e.preventDefault(); sendCommand(); return; } // Ctrl/⌘+回车 始终发送
|
|
2072
|
+
const mode = settings.enterMode || 'auto';
|
|
2073
|
+
const sendOnEnter = mode === 'send' ? !e.shiftKey
|
|
2074
|
+
: mode === 'newline' ? false
|
|
2075
|
+
: (!e.shiftKey && !window.matchMedia('(pointer: coarse)').matches); // 自动:桌面(细指针)发送、触屏换行
|
|
2076
|
+
if (sendOnEnter) { e.preventDefault(); sendCommand(); }
|
|
2077
|
+
return; // 不发送时交给 textarea 默认插入换行
|
|
2078
|
+
}
|
|
2079
|
+
if (e.key === 'ArrowUp' && !cmdInput.value) { if (historyIdx < cmdHistory.length - 1) { historyIdx++; cmdInput.value = cmdHistory[historyIdx]; } e.preventDefault(); }
|
|
2028
2080
|
else if (e.key === 'ArrowDown' && !cmdInput.value) { if (historyIdx > 0) { historyIdx--; cmdInput.value = cmdHistory[historyIdx]; } else if (historyIdx === 0) { historyIdx = -1; cmdInput.value = ''; } e.preventDefault(); }
|
|
2029
2081
|
});
|
|
2030
2082
|
|
|
@@ -2393,6 +2445,7 @@
|
|
|
2393
2445
|
document.getElementById('set-parse').checked = settings.parseOutput;
|
|
2394
2446
|
document.getElementById('set-thinking').checked = settings.showThinking;
|
|
2395
2447
|
document.getElementById('set-collapse').checked = settings.collapseTools;
|
|
2448
|
+
syncEnterModeUI();
|
|
2396
2449
|
// 从服务端加载 ASR URL
|
|
2397
2450
|
fetch('/api/server-config').then(r => r.json()).then(d => {
|
|
2398
2451
|
document.getElementById('set-asr-url').value = d.asrUrl || '';
|
|
@@ -2827,10 +2880,51 @@
|
|
|
2827
2880
|
};
|
|
2828
2881
|
|
|
2829
2882
|
// ── 项目密钥(会话级,绑定本会话 cwd;普通登录即可,非 admin)─────────
|
|
2883
|
+
let _lastProjSecrets = { project: [], global: [] };
|
|
2884
|
+
function setSecretsMode(mode) {
|
|
2885
|
+
const bulk = mode === 'bulk';
|
|
2886
|
+
document.getElementById('sec-mode-list').style.display = bulk ? 'none' : 'flex';
|
|
2887
|
+
document.getElementById('sec-mode-bulk').style.display = bulk ? 'flex' : 'none';
|
|
2888
|
+
document.getElementById('sec-bulk-toggle').textContent = bulk ? '列表编辑 ⇄' : '批量编辑 ⇄';
|
|
2889
|
+
}
|
|
2830
2890
|
window.openSecretsSheet = function() {
|
|
2831
2891
|
document.getElementById('secrets-sheet').classList.add('open');
|
|
2892
|
+
setSecretsMode('list');
|
|
2832
2893
|
loadProjectSecrets();
|
|
2833
2894
|
};
|
|
2895
|
+
window.toggleBulkSecrets = function() {
|
|
2896
|
+
const goingBulk = document.getElementById('sec-mode-bulk').style.display === 'none';
|
|
2897
|
+
if (goingBulk) {
|
|
2898
|
+
// 用已有变量名预填(值隐藏),让用户看到全貌、填值即改
|
|
2899
|
+
const names = (_lastProjSecrets.project || []).map(s => `${s.name}=`).join('\n');
|
|
2900
|
+
const ta = document.getElementById('sec-bulk-text');
|
|
2901
|
+
ta.value = names + (names ? '\n' : '');
|
|
2902
|
+
ta.placeholder = 'MINIMAX_BASE_URL=https://api.minimaxi.com\nMINIMAX_API_KEY=你的key\nPORTAL_USER=账号\nPORTAL_PASS=密码';
|
|
2903
|
+
}
|
|
2904
|
+
setSecretsMode(goingBulk ? 'bulk' : 'list');
|
|
2905
|
+
};
|
|
2906
|
+
window.saveBulkSecrets = async function() {
|
|
2907
|
+
const text = document.getElementById('sec-bulk-text').value;
|
|
2908
|
+
try {
|
|
2909
|
+
const r = await fetch(`/api/session/${SESSION_ID}/secrets/bulk`, {
|
|
2910
|
+
method: 'POST', headers: { 'Content-Type': 'application/json' },
|
|
2911
|
+
body: JSON.stringify({ text }),
|
|
2912
|
+
});
|
|
2913
|
+
const d = await r.json();
|
|
2914
|
+
if (d.ok) {
|
|
2915
|
+
addStatusMessage(`批量保存:更新 ${d.count} 项${d.errors && d.errors.length ? ',跳过 ' + d.errors.length + ' 行' : ''}。清除/重开会话后生效`);
|
|
2916
|
+
setSecretsMode('list');
|
|
2917
|
+
loadProjectSecrets();
|
|
2918
|
+
} else { addStatusMessage(d.error || '批量保存失败'); }
|
|
2919
|
+
} catch { addStatusMessage('连接失败'); }
|
|
2920
|
+
};
|
|
2921
|
+
window.editProjectSecret = function(name, type) {
|
|
2922
|
+
document.getElementById('sec-sheet-name').value = name;
|
|
2923
|
+
document.getElementById('sec-sheet-type').value = type || 'env';
|
|
2924
|
+
const v = document.getElementById('sec-sheet-value');
|
|
2925
|
+
v.value = ''; v.focus();
|
|
2926
|
+
addStatusMessage('改「' + name + '」的值:填新值后点「保存密钥」');
|
|
2927
|
+
};
|
|
2834
2928
|
window.closeSecretsSheet = function() {
|
|
2835
2929
|
document.getElementById('secrets-sheet').classList.remove('open');
|
|
2836
2930
|
};
|
|
@@ -2841,8 +2935,9 @@
|
|
|
2841
2935
|
const r = await fetch(`/api/session/${SESSION_ID}/secrets`);
|
|
2842
2936
|
if (!r.ok) { box.innerHTML = '<div style="color:var(--muted);padding:0.5rem">读取失败</div>'; return; }
|
|
2843
2937
|
const d = await r.json();
|
|
2938
|
+
_lastProjSecrets = d;
|
|
2844
2939
|
const row = (s, isGlobal) => `<div style="display:flex;align-items:center;gap:0.5rem;padding:0.3rem 0.2rem;border-bottom:1px solid var(--surface2)">
|
|
2845
|
-
<span style="font-family:monospace;color
|
|
2940
|
+
<span style="font-family:monospace;color:${isGlobal ? 'var(--text)' : 'var(--blue2)'}${isGlobal ? '' : ';cursor:pointer'}" ${isGlobal ? '' : `onclick="editProjectSecret('${escHtml(s.name)}','${s.type || 'env'}')" title="点我改这个变量的值"`}>${escHtml(s.name)}</span>
|
|
2846
2941
|
<span style="color:var(--muted);font-size:0.7rem">${s.type === 'file' ? '📄' : '🔑'}</span>
|
|
2847
2942
|
<span style="flex:1;font-family:monospace;color:var(--muted);font-size:0.72rem">${escHtml(s.preview)}</span>
|
|
2848
2943
|
${isGlobal ? '<span style="color:var(--muted);font-size:0.68rem">全局·只读</span>'
|