@wendongfly/myhi 1.3.31 → 1.3.33

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 +132 -10
  2. package/package.json +1 -1
package/dist/chat.html CHANGED
@@ -62,6 +62,14 @@
62
62
  .msg-assistant .content pre code { background: none; padding: 0; }
63
63
  .msg-assistant .content ul, .msg-assistant .content ol { padding-left: 1.5rem; margin: 0.3rem 0; }
64
64
  .msg-assistant .content strong { color: #fff; }
65
+ .msg-assistant .content a { color: #58a6ff; text-decoration: none; word-break: break-all; }
66
+ .msg-assistant .content a:hover { text-decoration: underline; }
67
+ .md-table { border-collapse: collapse; margin: 0.5rem 0; font-size: 0.82rem; width: 100%; display: block; overflow-x: auto; white-space: nowrap; }
68
+ .md-table thead { background: #161b22; }
69
+ .md-table th, .md-table td { border: 1px solid #30363d; padding: 0.4rem 0.7rem; text-align: left; }
70
+ .md-table th { color: #fff; font-weight: 600; }
71
+ .md-table tbody tr:nth-child(even) { background: #0d1117; }
72
+ .md-table tbody tr:hover { background: #1c2128; }
65
73
 
66
74
  /* 工具调用组 */
67
75
  .msg-tool-group { border-left: 3px solid #58a6ff; margin-left: 0.3rem; padding-left: 0.6rem; margin-bottom: 0.3rem; }
@@ -327,7 +335,7 @@
327
335
  </div>
328
336
  <div id="sk-claude-agent" style="display:none">
329
337
  <button class="sk sk-claude" onclick="openModelSheet()">模型</button>
330
- <button class="sk sk-claude" onclick="doSlashCmd('/plan')">计划</button>
338
+ <button class="sk sk-claude" id="btn-plan" onclick="togglePlanMode()">计划</button>
331
339
  <button class="sk sk-claude" onclick="doSlashCmd('/compact')">压缩</button>
332
340
  <button class="sk sk-claude" onclick="openResumeSheet()">恢复</button>
333
341
  <button class="sk sk-claude" onclick="doClear()">清除</button>
@@ -465,6 +473,20 @@
465
473
  </div>
466
474
  </div>
467
475
 
476
+ <!-- 运行自定义命令 (输入参数) 弹窗 -->
477
+ <div id="skill-run-sheet" class="action-sheet">
478
+ <div class="action-sheet-backdrop" onclick="closeSkillRunSheet()"></div>
479
+ <div class="action-sheet-box" style="max-height:60vh;display:flex;flex-direction:column">
480
+ <div class="action-sheet-title" id="skill-run-title">/命令</div>
481
+ <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>
482
+ <div style="padding:0.3rem 0.2rem">
483
+ <textarea id="skill-run-input" class="slash-inp" placeholder="补充要求(可选),如项目范围、额外约束等" rows="3" style="resize:vertical"></textarea>
484
+ </div>
485
+ <button class="action-sheet-cancel" style="background:#7c3aed;color:#fff;font-weight:600;margin-bottom:0.4rem" onclick="submitSkillRun()">执行</button>
486
+ <button class="action-sheet-cancel" onclick="closeSkillRunSheet()">取消</button>
487
+ </div>
488
+ </div>
489
+
468
490
  <!-- AskUserQuestion 弹窗 -->
469
491
  <div id="ask-sheet" class="action-sheet">
470
492
  <div class="action-sheet-backdrop" onclick="closeAskSheet()"></div>
@@ -664,7 +686,21 @@
664
686
  let html = '';
665
687
  let inCode = false, codeLang = '', codeLines = [];
666
688
 
667
- for (const line of lines) {
689
+ // 行内格式化辅助函数
690
+ const fmtInline = (s) => s
691
+ .replace(/\*\*(.+?)\*\*/g, '<strong>$1</strong>')
692
+ .replace(/\*(.+?)\*/g, '<em>$1</em>')
693
+ .replace(/`([^`]+)`/g, '<code>$1</code>')
694
+ .replace(/\[([^\]]+)\]\((https?:\/\/[^)]+)\)/g, '<a href="$2" target="_blank" rel="noopener">$1</a>');
695
+
696
+ // 表格检测:| ... | 后跟 |---|---| 分隔行
697
+ const isTableRow = (s) => /^\s*\|(.+)\|\s*$/.test(s);
698
+ const isTableSep = (s) => /^\s*\|?\s*:?-+:?\s*(\|\s*:?-+:?\s*)+\|?\s*$/.test(s);
699
+ const splitCells = (s) => s.trim().replace(/^\||\|$/g, '').split('|').map(c => c.trim());
700
+
701
+ for (let i = 0; i < lines.length; i++) {
702
+ const line = lines[i];
703
+
668
704
  if (!inCode && /^```(\w*)/.test(line)) {
669
705
  inCode = true; codeLang = line.match(/^```(\w*)/)[1]; codeLines = [];
670
706
  continue;
@@ -675,15 +711,31 @@
675
711
  }
676
712
  if (inCode) { codeLines.push(line); continue; }
677
713
 
714
+ // 表格
715
+ if (isTableRow(line) && i + 1 < lines.length && isTableSep(lines[i + 1])) {
716
+ const header = splitCells(line);
717
+ let tableHtml = '<table class="md-table"><thead><tr>' +
718
+ header.map(c => `<th>${fmtInline(escHtml(c))}</th>`).join('') +
719
+ '</tr></thead><tbody>';
720
+ i += 2; // 跳过表头和分隔行
721
+ while (i < lines.length && isTableRow(lines[i])) {
722
+ const cells = splitCells(lines[i]);
723
+ tableHtml += '<tr>' + cells.map(c => `<td>${fmtInline(escHtml(c))}</td>`).join('') + '</tr>';
724
+ i++;
725
+ }
726
+ tableHtml += '</tbody></table>';
727
+ html += tableHtml;
728
+ i--; // 回退一步让外层 for 循环正确递增
729
+ continue;
730
+ }
731
+
678
732
  let l = escHtml(line);
679
733
  // 标题
680
- if (/^### /.test(l)) { html += `<h4>${l.slice(4)}</h4>`; continue; }
681
- if (/^## /.test(l)) { html += `<h3>${l.slice(3)}</h3>`; continue; }
682
- if (/^# /.test(l)) { html += `<h2>${l.slice(2)}</h2>`; continue; }
734
+ if (/^### /.test(l)) { html += `<h4>${fmtInline(l.slice(4))}</h4>`; continue; }
735
+ if (/^## /.test(l)) { html += `<h3>${fmtInline(l.slice(3))}</h3>`; continue; }
736
+ if (/^# /.test(l)) { html += `<h2>${fmtInline(l.slice(2))}</h2>`; continue; }
683
737
  // 行内格式
684
- l = l.replace(/\*\*(.+?)\*\*/g, '<strong>$1</strong>');
685
- l = l.replace(/\*(.+?)\*/g, '<em>$1</em>');
686
- l = l.replace(/`([^`]+)`/g, '<code>$1</code>');
738
+ l = fmtInline(l);
687
739
  // 列表
688
740
  if (/^- /.test(l)) { html += `<li>${l.slice(2)}</li>`; continue; }
689
741
  if (/^\d+\. /.test(l)) { html += `<li>${l.replace(/^\d+\.\s*/, '')}</li>`; continue; }
@@ -1198,6 +1250,7 @@
1198
1250
 
1199
1251
  claudeSession = isClaudeSession(session) || session.mode === 'agent';
1200
1252
  updateShortcutBar();
1253
+ updatePlanButton();
1201
1254
 
1202
1255
  // 更新输入框占位符
1203
1256
  cmdInput.placeholder = session.mode === 'agent' ? '输入消息...' : '输入命令...';
@@ -1248,6 +1301,14 @@
1248
1301
  setWorkState('idle');
1249
1302
  } else if (msg.subtype === 'info' && msg.message) {
1250
1303
  addStatusMessage(msg.message);
1304
+ // 同步计划模式状态到按钮
1305
+ if (msg.message.includes('进入计划模式')) {
1306
+ if (currentSession) currentSession.permissionMode = 'plan';
1307
+ updatePlanButton();
1308
+ } else if (msg.message.includes('退出计划模式')) {
1309
+ if (currentSession) currentSession.permissionMode = 'bypassPermissions';
1310
+ updatePlanButton();
1311
+ }
1251
1312
  }
1252
1313
  break;
1253
1314
  case 'assistant':
@@ -2033,6 +2094,35 @@
2033
2094
  let _slashCmd = null;
2034
2095
  const _slashTitles = { '/plan': '计划模式', '/compact': '压缩上下文', '/rename': '重命名会话' };
2035
2096
  const _slashHints = { '/plan': '输入计划描述...', '/compact': '输入压缩提示...', '/rename': '输入新名称...' };
2097
+ // 根据当前权限模式更新 "计划" 按钮 UI
2098
+ function updatePlanButton() {
2099
+ const btn = document.getElementById('btn-plan');
2100
+ if (!btn) return;
2101
+ const isPlan = currentSession?.permissionMode === 'plan';
2102
+ btn.textContent = isPlan ? '退出计划' : '计划';
2103
+ btn.style.color = isPlan ? '#f0883e' : '';
2104
+ btn.style.fontWeight = isPlan ? '600' : '';
2105
+ }
2106
+ window.togglePlanMode = function() {
2107
+ const isPlan = currentSession?.permissionMode === 'plan';
2108
+ if (!isController && canTakeControl()) socket.emit('take-control', { sessionId: SESSION_ID });
2109
+ if (isPlan) {
2110
+ // 直接切回 bypassPermissions,不走 /plan 命令(因为那要等 agent 响应)
2111
+ socket.emit('set-mode', { sessionId: SESSION_ID, mode: 'bypassPermissions' });
2112
+ if (currentSession) currentSession.permissionMode = 'bypassPermissions';
2113
+ updatePlanButton();
2114
+ addStatusMessage('已退出计划模式,恢复到自动执行');
2115
+ } else {
2116
+ // 进入计划:弹窗输入计划描述
2117
+ doSlashCmd('/plan');
2118
+ }
2119
+ };
2120
+ socket.on('mode-changed', ({ sessionId, mode }) => {
2121
+ if (sessionId !== SESSION_ID) return;
2122
+ if (currentSession) currentSession.permissionMode = mode;
2123
+ updatePlanButton();
2124
+ });
2125
+
2036
2126
  window.doSlashCmd = function(cmd) {
2037
2127
  _slashCmd = cmd;
2038
2128
  document.getElementById('slash-title').textContent = _slashTitles[cmd] || cmd;
@@ -2098,9 +2188,41 @@
2098
2188
  }
2099
2189
  } catch {}
2100
2190
  }
2101
- window.runSkill = function(name) {
2191
+ window.runSkill = function(name, skipPrompt) {
2192
+ // 直接运行(从弹窗确认后调用 skipPrompt=true)
2193
+ if (skipPrompt) {
2194
+ if (!isController && canTakeControl()) socket.emit('take-control', { sessionId: SESSION_ID });
2195
+ const cmd = '/' + name;
2196
+ socket.emit('agent:query', { prompt: cmd });
2197
+ addInputMessage(cmd);
2198
+ showThinking();
2199
+ return;
2200
+ }
2201
+ // 先弹窗让用户补充要求
2202
+ const skill = _customSkills.find(s => s.name === name);
2203
+ openSkillRunSheet(name, skill?.desc);
2204
+ };
2205
+ let _pendingSkillName = null;
2206
+ window.openSkillRunSheet = function(name, desc) {
2207
+ _pendingSkillName = name;
2208
+ const sheet = document.getElementById('skill-run-sheet');
2209
+ document.getElementById('skill-run-title').textContent = `/${name}`;
2210
+ document.getElementById('skill-run-desc').textContent = desc || '';
2211
+ document.getElementById('skill-run-input').value = '';
2212
+ sheet.classList.add('open');
2213
+ setTimeout(() => document.getElementById('skill-run-input').focus(), 100);
2214
+ };
2215
+ window.closeSkillRunSheet = function() {
2216
+ document.getElementById('skill-run-sheet').classList.remove('open');
2217
+ _pendingSkillName = null;
2218
+ };
2219
+ window.submitSkillRun = function() {
2220
+ if (!_pendingSkillName) return;
2221
+ const args = document.getElementById('skill-run-input').value.trim();
2222
+ const name = _pendingSkillName;
2223
+ closeSkillRunSheet();
2102
2224
  if (!isController && canTakeControl()) socket.emit('take-control', { sessionId: SESSION_ID });
2103
- const cmd = '/' + name;
2225
+ const cmd = args ? `/${name} ${args}` : `/${name}`;
2104
2226
  socket.emit('agent:query', { prompt: cmd });
2105
2227
  addInputMessage(cmd);
2106
2228
  showThinking();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wendongfly/myhi",
3
- "version": "1.3.31",
3
+ "version": "1.3.33",
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",