@wendongfly/myhi 1.3.30 → 1.3.32

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.
Files changed (2) hide show
  1. package/dist/chat.html +138 -7
  2. package/package.json +1 -1
package/dist/chat.html CHANGED
@@ -327,7 +327,7 @@
327
327
  </div>
328
328
  <div id="sk-claude-agent" style="display:none">
329
329
  <button class="sk sk-claude" onclick="openModelSheet()">模型</button>
330
- <button class="sk sk-claude" onclick="doSlashCmd('/plan')">计划</button>
330
+ <button class="sk sk-claude" id="btn-plan" onclick="togglePlanMode()">计划</button>
331
331
  <button class="sk sk-claude" onclick="doSlashCmd('/compact')">压缩</button>
332
332
  <button class="sk sk-claude" onclick="openResumeSheet()">恢复</button>
333
333
  <button class="sk sk-claude" onclick="doClear()">清除</button>
@@ -452,6 +452,33 @@
452
452
  </div>
453
453
  </div>
454
454
 
455
+ <!-- 自定义 Slash Commands 弹窗 -->
456
+ <div id="cmd-sheet" class="action-sheet">
457
+ <div class="action-sheet-backdrop" onclick="closeCmdSheet()"></div>
458
+ <div class="action-sheet-box" style="max-height:75vh;display:flex;flex-direction:column">
459
+ <div class="action-sheet-title">自定义命令</div>
460
+ <div style="padding:0.3rem 0.2rem">
461
+ <input id="cmd-filter" class="slash-inp" placeholder="搜索命令..." autocomplete="off">
462
+ </div>
463
+ <div id="cmd-sheet-list" style="flex:1;overflow-y:auto;padding:0.3rem 0;scrollbar-width:thin"></div>
464
+ <button class="action-sheet-cancel" onclick="closeCmdSheet()">取消</button>
465
+ </div>
466
+ </div>
467
+
468
+ <!-- 运行自定义命令 (输入参数) 弹窗 -->
469
+ <div id="skill-run-sheet" class="action-sheet">
470
+ <div class="action-sheet-backdrop" onclick="closeSkillRunSheet()"></div>
471
+ <div class="action-sheet-box" style="max-height:60vh;display:flex;flex-direction:column">
472
+ <div class="action-sheet-title" id="skill-run-title">/命令</div>
473
+ <div id="skill-run-desc" style="padding:0.3rem 0.5rem;font-size:0.78rem;color:#8b949e;line-height:1.5;white-space:pre-wrap"></div>
474
+ <div style="padding:0.3rem 0.2rem">
475
+ <textarea id="skill-run-input" class="slash-inp" placeholder="补充要求(可选),如项目范围、额外约束等" rows="3" style="resize:vertical"></textarea>
476
+ </div>
477
+ <button class="action-sheet-cancel" style="background:#7c3aed;color:#fff;font-weight:600;margin-bottom:0.4rem" onclick="submitSkillRun()">执行</button>
478
+ <button class="action-sheet-cancel" onclick="closeSkillRunSheet()">取消</button>
479
+ </div>
480
+ </div>
481
+
455
482
  <!-- AskUserQuestion 弹窗 -->
456
483
  <div id="ask-sheet" class="action-sheet">
457
484
  <div class="action-sheet-backdrop" onclick="closeAskSheet()"></div>
@@ -1185,6 +1212,7 @@
1185
1212
 
1186
1213
  claudeSession = isClaudeSession(session) || session.mode === 'agent';
1187
1214
  updateShortcutBar();
1215
+ updatePlanButton();
1188
1216
 
1189
1217
  // 更新输入框占位符
1190
1218
  cmdInput.placeholder = session.mode === 'agent' ? '输入消息...' : '输入命令...';
@@ -1235,6 +1263,14 @@
1235
1263
  setWorkState('idle');
1236
1264
  } else if (msg.subtype === 'info' && msg.message) {
1237
1265
  addStatusMessage(msg.message);
1266
+ // 同步计划模式状态到按钮
1267
+ if (msg.message.includes('进入计划模式')) {
1268
+ if (currentSession) currentSession.permissionMode = 'plan';
1269
+ updatePlanButton();
1270
+ } else if (msg.message.includes('退出计划模式')) {
1271
+ if (currentSession) currentSession.permissionMode = 'bypassPermissions';
1272
+ updatePlanButton();
1273
+ }
1238
1274
  }
1239
1275
  break;
1240
1276
  case 'assistant':
@@ -2020,6 +2056,35 @@
2020
2056
  let _slashCmd = null;
2021
2057
  const _slashTitles = { '/plan': '计划模式', '/compact': '压缩上下文', '/rename': '重命名会话' };
2022
2058
  const _slashHints = { '/plan': '输入计划描述...', '/compact': '输入压缩提示...', '/rename': '输入新名称...' };
2059
+ // 根据当前权限模式更新 "计划" 按钮 UI
2060
+ function updatePlanButton() {
2061
+ const btn = document.getElementById('btn-plan');
2062
+ if (!btn) return;
2063
+ const isPlan = currentSession?.permissionMode === 'plan';
2064
+ btn.textContent = isPlan ? '退出计划' : '计划';
2065
+ btn.style.color = isPlan ? '#f0883e' : '';
2066
+ btn.style.fontWeight = isPlan ? '600' : '';
2067
+ }
2068
+ window.togglePlanMode = function() {
2069
+ const isPlan = currentSession?.permissionMode === 'plan';
2070
+ if (!isController && canTakeControl()) socket.emit('take-control', { sessionId: SESSION_ID });
2071
+ if (isPlan) {
2072
+ // 直接切回 bypassPermissions,不走 /plan 命令(因为那要等 agent 响应)
2073
+ socket.emit('set-mode', { sessionId: SESSION_ID, mode: 'bypassPermissions' });
2074
+ if (currentSession) currentSession.permissionMode = 'bypassPermissions';
2075
+ updatePlanButton();
2076
+ addStatusMessage('已退出计划模式,恢复到自动执行');
2077
+ } else {
2078
+ // 进入计划:弹窗输入计划描述
2079
+ doSlashCmd('/plan');
2080
+ }
2081
+ };
2082
+ socket.on('mode-changed', ({ sessionId, mode }) => {
2083
+ if (sessionId !== SESSION_ID) return;
2084
+ if (currentSession) currentSession.permissionMode = mode;
2085
+ updatePlanButton();
2086
+ });
2087
+
2023
2088
  window.doSlashCmd = function(cmd) {
2024
2089
  _slashCmd = cmd;
2025
2090
  document.getElementById('slash-title').textContent = _slashTitles[cmd] || cmd;
@@ -2067,24 +2132,90 @@
2067
2132
  });
2068
2133
 
2069
2134
  // ── 动态加载 Skill 按钮 ──────────────────────────
2135
+ let _customSkills = [];
2070
2136
  async function loadSkills() {
2071
2137
  try {
2072
2138
  const resp = await fetch(`/api/skills?sessionId=${SESSION_ID}`);
2073
2139
  const data = await resp.json();
2074
2140
  const container = document.getElementById('sk-custom-skills');
2075
- if (!data.skills || !data.skills.length) { container.innerHTML = ''; return; }
2076
- container.innerHTML = data.skills.map(s =>
2077
- `<button class="sk sk-claude" onclick="runSkill('${escHtml(s.name)}')" title="${escHtml(s.desc)}" style="color:#9d5cf5">/${escHtml(s.name)}</button>`
2078
- ).join('');
2141
+ _customSkills = data.skills || [];
2142
+ if (!_customSkills.length) { container.innerHTML = ''; return; }
2143
+ // ≤3 个:直接显示按钮;>3 个:显示 "/命令 (N)" 入口
2144
+ if (_customSkills.length <= 3) {
2145
+ container.innerHTML = _customSkills.map(s =>
2146
+ `<button class="sk sk-claude" onclick="runSkill('${escHtml(s.name)}')" title="${escHtml(s.desc)}" style="color:#9d5cf5">/${escHtml(s.name)}</button>`
2147
+ ).join('');
2148
+ } else {
2149
+ container.innerHTML = `<button class="sk sk-claude" onclick="openCmdSheet()" style="color:#9d5cf5">/命令 (${_customSkills.length})</button>`;
2150
+ }
2079
2151
  } catch {}
2080
2152
  }
2081
- window.runSkill = function(name) {
2153
+ window.runSkill = function(name, skipPrompt) {
2154
+ // 直接运行(从弹窗确认后调用 skipPrompt=true)
2155
+ if (skipPrompt) {
2156
+ if (!isController && canTakeControl()) socket.emit('take-control', { sessionId: SESSION_ID });
2157
+ const cmd = '/' + name;
2158
+ socket.emit('agent:query', { prompt: cmd });
2159
+ addInputMessage(cmd);
2160
+ showThinking();
2161
+ return;
2162
+ }
2163
+ // 先弹窗让用户补充要求
2164
+ const skill = _customSkills.find(s => s.name === name);
2165
+ openSkillRunSheet(name, skill?.desc);
2166
+ };
2167
+ let _pendingSkillName = null;
2168
+ window.openSkillRunSheet = function(name, desc) {
2169
+ _pendingSkillName = name;
2170
+ const sheet = document.getElementById('skill-run-sheet');
2171
+ document.getElementById('skill-run-title').textContent = `/${name}`;
2172
+ document.getElementById('skill-run-desc').textContent = desc || '';
2173
+ document.getElementById('skill-run-input').value = '';
2174
+ sheet.classList.add('open');
2175
+ setTimeout(() => document.getElementById('skill-run-input').focus(), 100);
2176
+ };
2177
+ window.closeSkillRunSheet = function() {
2178
+ document.getElementById('skill-run-sheet').classList.remove('open');
2179
+ _pendingSkillName = null;
2180
+ };
2181
+ window.submitSkillRun = function() {
2182
+ if (!_pendingSkillName) return;
2183
+ const args = document.getElementById('skill-run-input').value.trim();
2184
+ const name = _pendingSkillName;
2185
+ closeSkillRunSheet();
2082
2186
  if (!isController && canTakeControl()) socket.emit('take-control', { sessionId: SESSION_ID });
2083
- const cmd = '/' + name;
2187
+ const cmd = args ? `/${name} ${args}` : `/${name}`;
2084
2188
  socket.emit('agent:query', { prompt: cmd });
2085
2189
  addInputMessage(cmd);
2086
2190
  showThinking();
2087
2191
  };
2192
+ window.openCmdSheet = function() {
2193
+ const sheet = document.getElementById('cmd-sheet');
2194
+ const listEl = document.getElementById('cmd-sheet-list');
2195
+ const filterInp = document.getElementById('cmd-filter');
2196
+ filterInp.value = '';
2197
+ const render = (keyword = '') => {
2198
+ const kw = keyword.toLowerCase();
2199
+ const filtered = _customSkills.filter(s =>
2200
+ !kw || s.name.toLowerCase().includes(kw) || (s.desc || '').toLowerCase().includes(kw));
2201
+ listEl.innerHTML = filtered.length
2202
+ ? filtered.map(s => `<div class="action-sheet-item" onclick="runSkillAndClose('${escHtml(s.name)}')">
2203
+ <div><div style="color:#d2a8ff">/${escHtml(s.name)}</div>${s.desc ? `<div class="desc">${escHtml(s.desc)}</div>` : ''}</div>
2204
+ </div>`).join('')
2205
+ : '<div style="text-align:center;color:#8b949e;padding:1.5rem 0;font-size:0.82rem">无匹配命令</div>';
2206
+ };
2207
+ render();
2208
+ filterInp.oninput = (e) => render(e.target.value);
2209
+ sheet.classList.add('open');
2210
+ setTimeout(() => filterInp.focus(), 100);
2211
+ };
2212
+ window.closeCmdSheet = function() {
2213
+ document.getElementById('cmd-sheet').classList.remove('open');
2214
+ };
2215
+ window.runSkillAndClose = function(name) {
2216
+ closeCmdSheet();
2217
+ runSkill(name);
2218
+ };
2088
2219
  // 加入会话后加载 skill
2089
2220
  socket.on('joined', () => { if (currentSession?.mode === 'agent') loadSkills(); });
2090
2221
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wendongfly/myhi",
3
- "version": "1.3.30",
3
+ "version": "1.3.32",
4
4
  "description": "Web-based terminal sharing with chat UI — control your terminal from phone via LAN/Tailscale",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",