@wendongfly/myhi 1.3.151 → 1.3.153

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
@@ -2608,6 +2608,11 @@
2608
2608
 
2609
2609
  // ── 输入处理 ──────────────────────────────────
2610
2610
  window.sendCommand = sendCommand;
2611
+ // 服务端本地处理的 slash 命令(agent.js 拦截后只回一条 system/info、不 spawn claude、
2612
+ // 永远等不到 result)—— 这些不能进 thinking/working 态,否则没人把它清回来:
2613
+ // 切模型后输入框永远「运行中」(1.3.152 用户实测)。
2614
+ const LOCAL_SLASH_RE = /^\/(clear|rename|model\s|resume\s|plan(\s|$))/;
2615
+
2611
2616
  function sendCommand() {
2612
2617
  const text = cmdInput.value.trim();
2613
2618
  if (!text && !_pendingImage && !_pendingFile) return;
@@ -2643,7 +2648,8 @@
2643
2648
  ? `用户上传了一个临时文件用于本次分析(不在项目文件树里),路径是 ${filePath}(原文件名 ${fileName}),请用合适的工具(如 Read)读取并分析它。用户的要求是:${userText || '分析这个文件'}`
2644
2649
  : text;
2645
2650
  socket.emit('agent:query', { prompt });
2646
- showThinking();
2651
+ // 本地 slash(/model /clear /plan /resume /rename)只回一条 info、无 result,不进 thinking 态
2652
+ if (!LOCAL_SLASH_RE.test(text)) showThinking();
2647
2653
  } else {
2648
2654
  const attach = imgPath || filePath;
2649
2655
  const input = attach
@@ -3402,7 +3408,7 @@
3402
3408
  // 用【别名】而非硬编码全名:/model sonnet 永远指向该家族最新版,claude 升级不用改这里。
3403
3409
  // 精确版本/冷门模型用面板底部「自定义模型」输入框指定全名(如 claude-sonnet-4-6)。
3404
3410
  const MODELS = [
3405
- { id: 'default', label: '默认', desc: '恢复 Claude 默认模型(跟随账户/订阅设置)' },
3411
+ { id: 'default', label: '默认', desc: '跟随账户/订阅设置' },
3406
3412
  { id: 'sonnet', label: 'Sonnet', desc: '速度+智能平衡 · 跟随最新版' },
3407
3413
  { id: 'opus', label: 'Opus', desc: '最强推理 · agentic coding · 跟随最新版' },
3408
3414
  { id: 'haiku', label: 'Haiku', desc: '最快最便宜 · 跟随最新版' },
@@ -4323,7 +4329,8 @@
4323
4329
  if (!isController && canTakeControl()) socket.emit('take-control', { sessionId: SESSION_ID });
4324
4330
  socket.emit('agent:query', { prompt: prompt_text });
4325
4331
  addInputMessage(prompt_text);
4326
- showThinking();
4332
+ // 本地 slash(/plan /resume /rename)只回一条 info、无 result,不进 thinking 态
4333
+ if (!LOCAL_SLASH_RE.test(prompt_text)) showThinking();
4327
4334
  };
4328
4335
  // Enter 键提交
4329
4336
  document.getElementById('slash-input')?.addEventListener('keydown', (e) => {
package/dist/grid.html CHANGED
@@ -312,8 +312,7 @@
312
312
  // ── 新建任务(和首页「新建终端会话」一致:预设 + 名称 + 命令 + 目录 + 最近目录)──
313
313
  const socket = io();
314
314
  const NT_PRESETS = [
315
- { icon:'🤖', label:'Claude', title:'claude', type:'agent', cmd:'' },
316
- { icon:'✨', label:'Gemini', title:'gemini', type:'pty', cmd:'gemini' },
315
+ { icon:'🤖', label:'默认', title:'claude', type:'agent', cmd:'' },
317
316
  { icon:'🐚', label:'Shell', title:'shell', type:'pty', cmd:'' },
318
317
  ];
319
318
  let _ntPreset = 0;
package/dist/index.html CHANGED
@@ -548,9 +548,10 @@
548
548
  <input id="inp-cmd" type="text" placeholder="留空仅打开 shell" autocomplete="off" spellcheck="false" style="font-family:'SF Mono',Consolas,monospace;font-size:0.85rem">
549
549
  </div>
550
550
  <div class="field">
551
- <label>工作目录 <span style="font-weight:400;text-transform:none">(可选)</span></label>
551
+ <label>工作目录 <span style="font-weight:400;text-transform:none">(可选,默认按任务名建在根目录下)</span></label>
552
552
  <div style="display:flex;gap:0.5rem">
553
- <input id="inp-cwd" type="text" placeholder="留空使用默认目录" autocomplete="off" spellcheck="false" style="flex:1">
553
+ <input id="inp-cwd" type="text" placeholder="输入任务名后自动填充,可改可另选" autocomplete="off" spellcheck="false" style="flex:1">
554
+ <button onclick="pinTaskRoot(this)" title="把当前目录的上级记为默认根目录(新建任务时自动拼 任务名)" style="flex-shrink:0;background:var(--bg);border:1px solid var(--border);border-radius:8px;padding:0 0.75rem;color:var(--text);font-size:0.95rem;cursor:pointer">📌</button>
554
555
  <button onclick="openDirPicker()" style="flex-shrink:0;background:var(--bg);border:1px solid var(--border);border-radius:8px;padding:0 0.75rem;color:var(--text);font-size:1.1rem;cursor:pointer">📁</button>
555
556
  </div>
556
557
  <div id="recent-dirs" style="display:flex;flex-wrap:wrap;gap:0.35rem;margin-top:0.4rem"></div>
@@ -649,7 +650,7 @@
649
650
  const H = 'style="font-size:0.9rem;font-weight:700;margin-bottom:0.5rem;color:var(--text)"';
650
651
  const T = 'style="font-size:0.82rem;color:var(--text2);line-height:1.6"';
651
652
  let html = '<div style="padding:1.5rem">';
652
- html += '<h3 style="margin:0 0 1.2rem;font-size:1.1rem;color:#fff;text-align:center">Claude 用量</h3>';
653
+ html += '<h3 style="margin:0 0 1.2rem;font-size:1.1rem;color:#fff;text-align:center">用量</h3>';
653
654
  if (data.rateLimit) {
654
655
  const rl = data.rateLimit;
655
656
  const resetTime = new Date(rl.resetsAt * 1000);
@@ -1183,9 +1184,8 @@
1183
1184
  // ── Presets ───────────────────────────────────────────────────
1184
1185
  const PRESETS = [
1185
1186
  // Agent 模式
1186
- { icon: '🤖', label: 'Claude', title: 'claude', type: 'agent', cmd: 'claude' },
1187
+ { icon: '🤖', label: '默认', title: 'claude', type: 'agent', cmd: 'claude' },
1187
1188
  // PTY 模式(终端)
1188
- { icon: '✨', label: 'Gemini', title: 'gemini', type: 'pty', cmd: 'gemini' },
1189
1189
  { icon: '🐚', label: 'Shell', title: 'shell', type: 'pty', cmd: '' },
1190
1190
  ];
1191
1191
 
@@ -1206,7 +1206,7 @@
1206
1206
  document.querySelectorAll('.chip').forEach((c, j) =>
1207
1207
  c.classList.toggle('selected', j === i));
1208
1208
  const p = PRESETS[i];
1209
- // 不再自动把名称填成 claude/gemini/shell —— 名称必填、留给用户输入任务名
1209
+ // 不再自动把名称填成 claude/shell —— 名称必填、留给用户输入任务名
1210
1210
  document.getElementById('inp-cmd').value = p.cmd || '';
1211
1211
  }
1212
1212
 
@@ -1216,6 +1216,9 @@
1216
1216
  document.getElementById('sheet').classList.add('open');
1217
1217
  // Default to first preset
1218
1218
  selectPreset(0);
1219
+ // 重置目录接管状态:按当前任务名重新算默认目录(title 已被上次创建清空 → 目录清空)
1220
+ _cwdTouched = false;
1221
+ syncCwdToTitle();
1219
1222
  setTimeout(() => document.getElementById('inp-title').focus(), 300);
1220
1223
  }
1221
1224
  function closeSheet() {
@@ -1225,6 +1228,52 @@
1225
1228
  document.querySelectorAll('.chip').forEach(c => c.classList.remove('selected'));
1226
1229
  }
1227
1230
 
1231
+ // ── 工作目录默认跟随任务名 ─────────────────────────────────
1232
+ // 任务名 → <根目录>/<任务名>,如 EPS3 → D:\project\EPS3(服务端会自动 mkdir)。
1233
+ // 手改目录 / 📁 选择 / 点最近目录 = 用户接管,本次弹窗内不再自动覆盖;📌 把当前目录
1234
+ // 的上级记为根目录(localStorage 持久)。
1235
+ const ROOT_KEY = 'myhi_newtask_root';
1236
+ const IS_WIN = /Win/i.test(navigator.platform || '');
1237
+ const ROOT_DEFAULT = IS_WIN ? 'D:\\project' : '';
1238
+ let _cwdTouched = false;
1239
+
1240
+ function taskRoot() {
1241
+ try { const v = localStorage.getItem(ROOT_KEY); if (v) return v; } catch {}
1242
+ return ROOT_DEFAULT;
1243
+ }
1244
+ function sanitizeTaskName(name) {
1245
+ // 与服务端 taskCwdFromTitle 同款清洗:Windows 目录非法字符 → '_',掐头尾点和空白
1246
+ return String(name || '').trim().replace(/[\\/:*?"<>|]+/g, '_').replace(/^\.+/, '').trim().slice(0, 80);
1247
+ }
1248
+ function defaultTaskDir(name) {
1249
+ const n = sanitizeTaskName(name);
1250
+ if (!n) return '';
1251
+ const root = taskRoot();
1252
+ if (!root) return ''; // 非 Windows 且没设过根:不猜,留空自选
1253
+ const sep = root.includes('\\') ? '\\' : '/';
1254
+ return root.replace(/[\\/]+$/, '') + sep + n;
1255
+ }
1256
+ function syncCwdToTitle() {
1257
+ if (_cwdTouched) return;
1258
+ document.getElementById('inp-cwd').value = defaultTaskDir(document.getElementById('inp-title').value);
1259
+ }
1260
+ function pinTaskRoot(btn) {
1261
+ const cur = document.getElementById('inp-cwd').value.trim();
1262
+ if (!cur) { alert('请先填写或选择一个目录,再点 📌 把它的上级记为默认根目录'); return; }
1263
+ const m = cur.replace(/[\\/]+$/, '');
1264
+ const idx = Math.max(m.lastIndexOf('\\'), m.lastIndexOf('/'));
1265
+ const root = idx > 2 ? m.slice(0, idx) : m;
1266
+ try { localStorage.setItem(ROOT_KEY, root); } catch {}
1267
+ _cwdTouched = false;
1268
+ syncCwdToTitle();
1269
+ const old = btn.textContent;
1270
+ btn.textContent = '已记住';
1271
+ setTimeout(() => { btn.textContent = old; }, 1200);
1272
+ }
1273
+
1274
+ document.getElementById('inp-title').addEventListener('input', syncCwdToTitle);
1275
+ document.getElementById('inp-cwd').addEventListener('input', () => { _cwdTouched = true; });
1276
+
1228
1277
  document.getElementById('inp-title').addEventListener('keydown', e => {
1229
1278
  if (e.key === 'Enter') createSession();
1230
1279
  });
@@ -1296,7 +1345,7 @@
1296
1345
  btn.textContent = short;
1297
1346
  btn.title = path;
1298
1347
  btn.style.cssText = 'background:var(--bg);color:var(--accent);border:1px solid var(--border);border-radius:6px;padding:0.2rem 0.5rem;font-size:0.72rem;cursor:pointer;font-family:"SF Mono",Consolas,monospace;max-width:140px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap';
1299
- btn.onclick = () => { document.getElementById('inp-cwd').value = path; };
1348
+ btn.onclick = () => { document.getElementById('inp-cwd').value = path; _cwdTouched = true; };
1300
1349
  container.appendChild(btn);
1301
1350
  });
1302
1351
  }
@@ -1315,6 +1364,7 @@
1315
1364
  }
1316
1365
  function selectDir() {
1317
1366
  document.getElementById('inp-cwd').value = _dirCurrent;
1367
+ _cwdTouched = true; // 用户明确选了目录:接管,不再自动跟随任务名
1318
1368
  recordDir(_dirCurrent);
1319
1369
  closeDirPicker();
1320
1370
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wendongfly/myhi",
3
- "version": "1.3.151",
3
+ "version": "1.3.153",
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",