@wendongfly/myhi 1.3.101 → 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 CHANGED
@@ -540,16 +540,28 @@
540
540
  <div class="action-sheet-title">项目密钥 · 本会话</div>
541
541
  <div style="font-size:0.68rem;color:var(--muted);padding:0 0.2rem 0.4rem;line-height:1.5">
542
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>
543
544
  </div>
544
- <div id="sec-sheet-list" style="flex:1;overflow-y:auto;padding:0.2rem 0;font-size:0.8rem;scrollbar-width:thin"></div>
545
- <div style="padding:0.3rem 0.2rem;display:flex;flex-direction:column;gap:0.4rem;border-top:1px solid var(--surface2)">
546
- <div style="display:flex;gap:0.4rem">
547
- <input id="sec-sheet-name" class="slash-inp" placeholder="名字 如 GITLAB_PAT" autocomplete="off" style="flex:1">
548
- <select id="sec-sheet-type" class="slash-inp" style="max-width:88px"><option value="env">变量</option><option value="file">文件</option></select>
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>(删用列表模式);仅按「变量」型保存。
549
561
  </div>
550
- <input id="sec-sheet-value" class="slash-inp" type="password" placeholder="密钥值 / 证书内容" autocomplete="off">
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>
551
564
  </div>
552
- <button class="action-sheet-cancel" style="background:var(--blue2);color:#fff;font-weight:600;margin-bottom:0.4rem" onclick="addProjectSecret()">保存密钥</button>
553
565
  <button class="action-sheet-cancel" onclick="closeSecretsSheet()">关闭</button>
554
566
  </div>
555
567
  </div>
@@ -2827,10 +2839,51 @@
2827
2839
  };
2828
2840
 
2829
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
+ }
2830
2849
  window.openSecretsSheet = function() {
2831
2850
  document.getElementById('secrets-sheet').classList.add('open');
2851
+ setSecretsMode('list');
2832
2852
  loadProjectSecrets();
2833
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
+ };
2834
2887
  window.closeSecretsSheet = function() {
2835
2888
  document.getElementById('secrets-sheet').classList.remove('open');
2836
2889
  };
@@ -2841,8 +2894,9 @@
2841
2894
  const r = await fetch(`/api/session/${SESSION_ID}/secrets`);
2842
2895
  if (!r.ok) { box.innerHTML = '<div style="color:var(--muted);padding:0.5rem">读取失败</div>'; return; }
2843
2896
  const d = await r.json();
2897
+ _lastProjSecrets = d;
2844
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)">
2845
- <span style="font-family:monospace;color:var(--text)">${escHtml(s.name)}</span>
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>
2846
2900
  <span style="color:var(--muted);font-size:0.7rem">${s.type === 'file' ? '📄' : '🔑'}</span>
2847
2901
  <span style="flex:1;font-family:monospace;color:var(--muted);font-size:0.72rem">${escHtml(s.preview)}</span>
2848
2902
  ${isGlobal ? '<span style="color:var(--muted);font-size:0.68rem">全局·只读</span>'