@wendongfly/myhi 1.3.100 → 1.3.102
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 +139 -2
- package/dist/index.js +1 -1
- package/dist/index.min.js +2 -2
- package/package.json +1 -1
package/dist/chat.html
CHANGED
|
@@ -382,7 +382,6 @@
|
|
|
382
382
|
<button class="sk sk-claude" onclick="openResumeSheet()">恢复</button>
|
|
383
383
|
<button class="sk sk-claude" onclick="doCompact()">压缩</button>
|
|
384
384
|
<button class="sk sk-claude" data-cmd="/clear">清除</button>
|
|
385
|
-
<button class="sk sk-claude" onclick="doRename()">命名</button>
|
|
386
385
|
<button class="sk sk-claude" onclick="openGitSheet()" style="color:var(--green)">提交</button>
|
|
387
386
|
<button class="sk" data-send="ctrl-c">Ctrl+C</button>
|
|
388
387
|
<button class="sk" data-send="esc">Esc</button>
|
|
@@ -393,7 +392,7 @@
|
|
|
393
392
|
<button class="sk sk-claude" onclick="doSlashCmd('/compact')">压缩</button>
|
|
394
393
|
<button class="sk sk-claude" onclick="openResumeSheet()">恢复</button>
|
|
395
394
|
<button class="sk sk-claude" onclick="doClear()">清除</button>
|
|
396
|
-
<button class="sk sk-claude" onclick="
|
|
395
|
+
<button class="sk sk-claude" onclick="openSecretsSheet()" style="color:var(--blue2)">🔑 密钥</button>
|
|
397
396
|
<button class="sk sk-claude" onclick="openGitSheet()" style="color:var(--green)">提交</button>
|
|
398
397
|
<button class="sk sk-claude" onclick="showMemory()">记忆</button>
|
|
399
398
|
<button class="sk sk-claude" onclick="openVaSheet()" style="color:var(--blue2)">语音</button>
|
|
@@ -534,6 +533,39 @@
|
|
|
534
533
|
</div>
|
|
535
534
|
</div>
|
|
536
535
|
|
|
536
|
+
<!-- 项目密钥(会话级,绑定本会话 cwd) -->
|
|
537
|
+
<div id="secrets-sheet" class="action-sheet">
|
|
538
|
+
<div class="action-sheet-backdrop" onclick="closeSecretsSheet()"></div>
|
|
539
|
+
<div class="action-sheet-box" style="max-height:82vh;display:flex;flex-direction:column">
|
|
540
|
+
<div class="action-sheet-title">项目密钥 · 本会话</div>
|
|
541
|
+
<div style="font-size:0.68rem;color:var(--muted);padding:0 0.2rem 0.4rem;line-height:1.5">
|
|
542
|
+
只注入到<b>本项目 (cwd) 的会话</b>,命令里用 <code>$名字</code> 引用(证书类型用 <code>$MYHI_SECRET_名字</code>)。密钥值不进聊天。新增后需 <b>清除/重开会话</b>才注入进环境变量。
|
|
543
|
+
<a onclick="toggleBulkSecrets()" id="sec-bulk-toggle" style="color:var(--blue2);cursor:pointer;white-space:nowrap">批量编辑 ⇄</a>
|
|
544
|
+
</div>
|
|
545
|
+
<!-- 列表模式 -->
|
|
546
|
+
<div id="sec-mode-list" style="flex:1;display:flex;flex-direction:column;min-height:0">
|
|
547
|
+
<div id="sec-sheet-list" style="flex:1;overflow-y:auto;padding:0.2rem 0;font-size:0.8rem;scrollbar-width:thin"></div>
|
|
548
|
+
<div style="padding:0.3rem 0.2rem;display:flex;flex-direction:column;gap:0.4rem;border-top:1px solid var(--surface2)">
|
|
549
|
+
<div style="display:flex;gap:0.4rem">
|
|
550
|
+
<input id="sec-sheet-name" class="slash-inp" placeholder="名字 如 GITLAB_PAT" autocomplete="off" style="flex:1">
|
|
551
|
+
<select id="sec-sheet-type" class="slash-inp" style="max-width:88px"><option value="env">变量</option><option value="file">文件</option></select>
|
|
552
|
+
</div>
|
|
553
|
+
<input id="sec-sheet-value" class="slash-inp" type="password" placeholder="密钥值 / 证书内容(点上方某项可载入其名改值)" autocomplete="off">
|
|
554
|
+
</div>
|
|
555
|
+
<button class="action-sheet-cancel" style="background:var(--blue2);color:#fff;font-weight:600;margin:0.4rem 0" onclick="addProjectSecret()">保存密钥</button>
|
|
556
|
+
</div>
|
|
557
|
+
<!-- 批量模式:像编辑 .env 一样总览+批量增改 -->
|
|
558
|
+
<div id="sec-mode-bulk" style="display:none;flex:1;flex-direction:column;min-height:0">
|
|
559
|
+
<div style="font-size:0.66rem;color:var(--muted);padding:0 0.2rem 0.3rem;line-height:1.5">
|
|
560
|
+
每行 <code>NAME=值</code>;值留空=保留旧值不改;<code>#</code> 开头忽略。已有变量已列出(值隐藏,填上即改)。<b>此处不删变量</b>(删用列表模式);仅按「变量」型保存。
|
|
561
|
+
</div>
|
|
562
|
+
<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>
|
|
563
|
+
<button class="action-sheet-cancel" style="background:var(--blue2);color:#fff;font-weight:600;margin:0.4rem 0" onclick="saveBulkSecrets()">批量保存</button>
|
|
564
|
+
</div>
|
|
565
|
+
<button class="action-sheet-cancel" onclick="closeSecretsSheet()">关闭</button>
|
|
566
|
+
</div>
|
|
567
|
+
</div>
|
|
568
|
+
|
|
537
569
|
<div id="memory-sheet" class="action-sheet">
|
|
538
570
|
<div class="action-sheet-backdrop" onclick="closeMemorySheet()"></div>
|
|
539
571
|
<div class="action-sheet-box" style="max-height:80vh;display:flex;flex-direction:column">
|
|
@@ -2806,6 +2838,111 @@
|
|
|
2806
2838
|
}
|
|
2807
2839
|
};
|
|
2808
2840
|
|
|
2841
|
+
// ── 项目密钥(会话级,绑定本会话 cwd;普通登录即可,非 admin)─────────
|
|
2842
|
+
let _lastProjSecrets = { project: [], global: [] };
|
|
2843
|
+
function setSecretsMode(mode) {
|
|
2844
|
+
const bulk = mode === 'bulk';
|
|
2845
|
+
document.getElementById('sec-mode-list').style.display = bulk ? 'none' : 'flex';
|
|
2846
|
+
document.getElementById('sec-mode-bulk').style.display = bulk ? 'flex' : 'none';
|
|
2847
|
+
document.getElementById('sec-bulk-toggle').textContent = bulk ? '列表编辑 ⇄' : '批量编辑 ⇄';
|
|
2848
|
+
}
|
|
2849
|
+
window.openSecretsSheet = function() {
|
|
2850
|
+
document.getElementById('secrets-sheet').classList.add('open');
|
|
2851
|
+
setSecretsMode('list');
|
|
2852
|
+
loadProjectSecrets();
|
|
2853
|
+
};
|
|
2854
|
+
window.toggleBulkSecrets = function() {
|
|
2855
|
+
const goingBulk = document.getElementById('sec-mode-bulk').style.display === 'none';
|
|
2856
|
+
if (goingBulk) {
|
|
2857
|
+
// 用已有变量名预填(值隐藏),让用户看到全貌、填值即改
|
|
2858
|
+
const names = (_lastProjSecrets.project || []).map(s => `${s.name}=`).join('\n');
|
|
2859
|
+
const ta = document.getElementById('sec-bulk-text');
|
|
2860
|
+
ta.value = names + (names ? '\n' : '');
|
|
2861
|
+
ta.placeholder = 'MINIMAX_BASE_URL=https://api.minimaxi.com\nMINIMAX_API_KEY=你的key\nPORTAL_USER=账号\nPORTAL_PASS=密码';
|
|
2862
|
+
}
|
|
2863
|
+
setSecretsMode(goingBulk ? 'bulk' : 'list');
|
|
2864
|
+
};
|
|
2865
|
+
window.saveBulkSecrets = async function() {
|
|
2866
|
+
const text = document.getElementById('sec-bulk-text').value;
|
|
2867
|
+
try {
|
|
2868
|
+
const r = await fetch(`/api/session/${SESSION_ID}/secrets/bulk`, {
|
|
2869
|
+
method: 'POST', headers: { 'Content-Type': 'application/json' },
|
|
2870
|
+
body: JSON.stringify({ text }),
|
|
2871
|
+
});
|
|
2872
|
+
const d = await r.json();
|
|
2873
|
+
if (d.ok) {
|
|
2874
|
+
addStatusMessage(`批量保存:更新 ${d.count} 项${d.errors && d.errors.length ? ',跳过 ' + d.errors.length + ' 行' : ''}。清除/重开会话后生效`);
|
|
2875
|
+
setSecretsMode('list');
|
|
2876
|
+
loadProjectSecrets();
|
|
2877
|
+
} else { addStatusMessage(d.error || '批量保存失败'); }
|
|
2878
|
+
} catch { addStatusMessage('连接失败'); }
|
|
2879
|
+
};
|
|
2880
|
+
window.editProjectSecret = function(name, type) {
|
|
2881
|
+
document.getElementById('sec-sheet-name').value = name;
|
|
2882
|
+
document.getElementById('sec-sheet-type').value = type || 'env';
|
|
2883
|
+
const v = document.getElementById('sec-sheet-value');
|
|
2884
|
+
v.value = ''; v.focus();
|
|
2885
|
+
addStatusMessage('改「' + name + '」的值:填新值后点「保存密钥」');
|
|
2886
|
+
};
|
|
2887
|
+
window.closeSecretsSheet = function() {
|
|
2888
|
+
document.getElementById('secrets-sheet').classList.remove('open');
|
|
2889
|
+
};
|
|
2890
|
+
async function loadProjectSecrets() {
|
|
2891
|
+
const box = document.getElementById('sec-sheet-list');
|
|
2892
|
+
box.innerHTML = '<div style="text-align:center;color:var(--muted);padding:1rem 0">加载中...</div>';
|
|
2893
|
+
try {
|
|
2894
|
+
const r = await fetch(`/api/session/${SESSION_ID}/secrets`);
|
|
2895
|
+
if (!r.ok) { box.innerHTML = '<div style="color:var(--muted);padding:0.5rem">读取失败</div>'; return; }
|
|
2896
|
+
const d = await r.json();
|
|
2897
|
+
_lastProjSecrets = d;
|
|
2898
|
+
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)">
|
|
2899
|
+
<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>
|
|
2900
|
+
<span style="color:var(--muted);font-size:0.7rem">${s.type === 'file' ? '📄' : '🔑'}</span>
|
|
2901
|
+
<span style="flex:1;font-family:monospace;color:var(--muted);font-size:0.72rem">${escHtml(s.preview)}</span>
|
|
2902
|
+
${isGlobal ? '<span style="color:var(--muted);font-size:0.68rem">全局·只读</span>'
|
|
2903
|
+
: `<button class="sk sk-claude" style="padding:0.05rem 0.5rem" onclick="delProjectSecret('${escHtml(s.name)}')">删</button>`}
|
|
2904
|
+
</div>`;
|
|
2905
|
+
let html = '';
|
|
2906
|
+
if (d.project && d.project.length) {
|
|
2907
|
+
html += '<div style="color:var(--muted);font-size:0.7rem;margin:0.2rem 0">本项目</div>' + d.project.map(s => row(s, false)).join('');
|
|
2908
|
+
} else {
|
|
2909
|
+
html += '<div style="color:var(--muted);font-size:0.75rem;padding:0.3rem">(本项目暂无密钥)</div>';
|
|
2910
|
+
}
|
|
2911
|
+
if (d.global && d.global.length) {
|
|
2912
|
+
html += '<div style="color:var(--muted);font-size:0.7rem;margin:0.5rem 0 0.2rem">继承自全局</div>' + d.global.map(s => row(s, true)).join('');
|
|
2913
|
+
}
|
|
2914
|
+
box.innerHTML = html;
|
|
2915
|
+
} catch { box.innerHTML = '<div style="color:var(--muted);padding:0.5rem">连接失败</div>'; }
|
|
2916
|
+
}
|
|
2917
|
+
window.addProjectSecret = async function() {
|
|
2918
|
+
const name = document.getElementById('sec-sheet-name').value.trim();
|
|
2919
|
+
const value = document.getElementById('sec-sheet-value').value;
|
|
2920
|
+
const type = document.getElementById('sec-sheet-type').value;
|
|
2921
|
+
if (!name || !value) { addStatusMessage('密钥名和值都要填'); return; }
|
|
2922
|
+
try {
|
|
2923
|
+
const r = await fetch(`/api/session/${SESSION_ID}/secrets`, {
|
|
2924
|
+
method: 'POST', headers: { 'Content-Type': 'application/json' },
|
|
2925
|
+
body: JSON.stringify({ name, value, type }),
|
|
2926
|
+
});
|
|
2927
|
+
const d = await r.json();
|
|
2928
|
+
if (d.ok) {
|
|
2929
|
+
document.getElementById('sec-sheet-name').value = '';
|
|
2930
|
+
document.getElementById('sec-sheet-value').value = '';
|
|
2931
|
+
addStatusMessage('项目密钥已保存,清除/重开会话后可用 $' + name + ' 引用');
|
|
2932
|
+
loadProjectSecrets();
|
|
2933
|
+
} else { addStatusMessage(d.error || '保存失败'); }
|
|
2934
|
+
} catch { addStatusMessage('连接失败'); }
|
|
2935
|
+
};
|
|
2936
|
+
window.delProjectSecret = async function(name) {
|
|
2937
|
+
try {
|
|
2938
|
+
await fetch(`/api/session/${SESSION_ID}/secrets`, {
|
|
2939
|
+
method: 'DELETE', headers: { 'Content-Type': 'application/json' },
|
|
2940
|
+
body: JSON.stringify({ name }),
|
|
2941
|
+
});
|
|
2942
|
+
loadProjectSecrets();
|
|
2943
|
+
} catch {}
|
|
2944
|
+
};
|
|
2945
|
+
|
|
2809
2946
|
// ── 会话命名 ──────────────────────────────────
|
|
2810
2947
|
let _slashCmd = null;
|
|
2811
2948
|
const _slashTitles = { '/plan': '计划模式', '/compact': '压缩上下文', '/rename': '重命名会话' };
|