@wendongfly/myhi 1.3.114 → 1.3.115
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 +39 -1
- package/dist/grid.html +48 -1
- package/dist/index.js +1 -1
- package/dist/index.min.js +133 -133
- package/package.json +1 -1
package/dist/chat.html
CHANGED
|
@@ -449,6 +449,12 @@
|
|
|
449
449
|
<button class="fp-btn" onclick="fpExitSync()">退出同步</button>
|
|
450
450
|
</div>
|
|
451
451
|
<div class="fp-path" id="fp-path"></div>
|
|
452
|
+
<div id="fp-tools" style="display:flex;gap:0.4rem;align-items:center;padding:0.3rem 0.75rem;flex-wrap:wrap">
|
|
453
|
+
<button class="fp-btn" onclick="fpOpenFolder()" title="在服务端机器打开系统文件夹(你就坐在跑 myhi 的机器时有效)">📂 打开文件夹</button>
|
|
454
|
+
<button class="fp-btn" onclick="fpOpenEditor()" title="用 VS Code 打开项目(本机、装了 code 命令时有效)">VS Code</button>
|
|
455
|
+
<span style="flex:1"></span>
|
|
456
|
+
<button class="fp-btn" id="fp-sort-btn" onclick="fpToggleSort()" title="切换排序">排序: 名称</button>
|
|
457
|
+
</div>
|
|
452
458
|
<div class="fp-list" id="fp-list"></div>
|
|
453
459
|
<div class="fp-diff-actions" id="fp-diff-actions" style="display:none">
|
|
454
460
|
<button class="fp-btn fp-btn-primary" onclick="fpSyncToLocal()">下载到本地</button>
|
|
@@ -1583,6 +1589,13 @@
|
|
|
1583
1589
|
cancelBtn.classList.toggle('show', busy);
|
|
1584
1590
|
sendBtn.style.display = busy ? 'none' : '';
|
|
1585
1591
|
}
|
|
1592
|
+
_postStatus(state);
|
|
1593
|
+
}
|
|
1594
|
+
// 内嵌分屏(iframe)时把状态上报给外层 grid,更新窗格状态灯
|
|
1595
|
+
function _postStatus(state) {
|
|
1596
|
+
if (window.parent && window.parent !== window) {
|
|
1597
|
+
try { window.parent.postMessage({ type: 'myhi-status', sessionId: SESSION_ID, state }, '*'); } catch {}
|
|
1598
|
+
}
|
|
1586
1599
|
}
|
|
1587
1600
|
|
|
1588
1601
|
function updateShortcutBar() {
|
|
@@ -2196,6 +2209,27 @@
|
|
|
2196
2209
|
|
|
2197
2210
|
// ── 文件管理 ──────────────────────────────────
|
|
2198
2211
|
let fpCurrentPath = '';
|
|
2212
|
+
let fpSort = 'name'; // name | recent
|
|
2213
|
+
window.fpToggleSort = function() {
|
|
2214
|
+
fpSort = fpSort === 'name' ? 'recent' : 'name';
|
|
2215
|
+
const b = document.getElementById('fp-sort-btn');
|
|
2216
|
+
if (b) b.textContent = '排序: ' + (fpSort === 'recent' ? '最近修改' : '名称');
|
|
2217
|
+
fpLoadFiles();
|
|
2218
|
+
};
|
|
2219
|
+
window.fpOpenFolder = async function() {
|
|
2220
|
+
try {
|
|
2221
|
+
const r = await fetch(`/api/session/${SESSION_ID}/open-folder`, { method: 'POST' });
|
|
2222
|
+
const d = await r.json();
|
|
2223
|
+
addStatusMessage(d.ok ? '已在服务端机器打开文件夹(远程访问则看不到,用下方列表浏览/下载)' : ('打开失败: ' + (d.error || '')));
|
|
2224
|
+
} catch (e) { addStatusMessage('打开出错: ' + e.message); }
|
|
2225
|
+
};
|
|
2226
|
+
window.fpOpenEditor = async function() {
|
|
2227
|
+
try {
|
|
2228
|
+
const r = await fetch(`/api/session/${SESSION_ID}/open-editor`, { method: 'POST' });
|
|
2229
|
+
const d = await r.json();
|
|
2230
|
+
addStatusMessage(d.ok ? '已尝试用 VS Code 打开(需服务端装了 code 命令且你在本机)' : ('打开失败: ' + (d.error || '')));
|
|
2231
|
+
} catch (e) { addStatusMessage('打开出错: ' + e.message); }
|
|
2232
|
+
};
|
|
2199
2233
|
window.openFilePanel = function() {
|
|
2200
2234
|
fpCurrentPath = '';
|
|
2201
2235
|
fpLoadFiles();
|
|
@@ -2223,7 +2257,10 @@
|
|
|
2223
2257
|
if (data.parent != null) {
|
|
2224
2258
|
html += `<div class="fp-item" onclick="fpNav('${escHtml(data.parent)}')"><span class="fp-icon">📁</span><span class="fp-name">..</span></div>`;
|
|
2225
2259
|
}
|
|
2226
|
-
|
|
2260
|
+
const entries = (data.entries || []).slice();
|
|
2261
|
+
if (fpSort === 'recent') entries.sort((a, b) => (b.mtime || 0) - (a.mtime || 0)); // 最近修改在前,看 AI 刚生成啥
|
|
2262
|
+
else entries.sort((a, b) => (Number(b.isDir) - Number(a.isDir)) || a.name.localeCompare(b.name));
|
|
2263
|
+
for (const e of entries) {
|
|
2227
2264
|
const rel = fpCurrentPath ? fpCurrentPath + '/' + e.name : e.name;
|
|
2228
2265
|
if (e.isDir) {
|
|
2229
2266
|
html += `<div class="fp-item" onclick="fpNav('${escHtml(rel)}')"><span class="fp-icon">📁</span><span class="fp-name">${escHtml(e.name)}</span></div>`;
|
|
@@ -2740,6 +2777,7 @@
|
|
|
2740
2777
|
}
|
|
2741
2778
|
if (!_askQuestions.length) return;
|
|
2742
2779
|
_renderAskSheet();
|
|
2780
|
+
_postStatus('waiting'); // 通知外层 grid:本格在等你回答
|
|
2743
2781
|
};
|
|
2744
2782
|
|
|
2745
2783
|
function _renderAskSheet() {
|
package/dist/grid.html
CHANGED
|
@@ -47,6 +47,12 @@
|
|
|
47
47
|
.pane-head select { flex:1; min-width:0; background:var(--bg); color:var(--text); border:1px solid var(--border); border-radius:6px; padding:0.28rem 0.4rem; font-size:0.78rem; }
|
|
48
48
|
.pane-head .pane-picker { flex:1; min-width:0; display:flex; align-items:center; justify-content:space-between; gap:0.3rem; text-align:left; }
|
|
49
49
|
#tp-list [data-id]:hover { background:var(--surface2) !important; }
|
|
50
|
+
/* 窗格状态灯 */
|
|
51
|
+
.pane-dot { width:9px; height:9px; border-radius:50%; background:var(--dim); flex-shrink:0; }
|
|
52
|
+
.pane-dot.pulse { animation:panepulse 1.1s ease-in-out infinite; }
|
|
53
|
+
@keyframes panepulse { 0%,100%{opacity:1} 50%{opacity:0.3} }
|
|
54
|
+
.pane-head.flash { animation:paneflash 1s ease-in-out 3; }
|
|
55
|
+
@keyframes paneflash { 0%,100%{background:var(--surface2)} 50%{background:var(--blue2)} }
|
|
50
56
|
.pane-head button { background:var(--bg); border:1px solid var(--border); color:var(--muted); border-radius:6px; padding:0.2rem 0.45rem; font-size:0.8rem; cursor:pointer; line-height:1; }
|
|
51
57
|
.pane-head button:hover { color:var(--text); border-color:var(--blue2); }
|
|
52
58
|
.pane-body { flex:1; min-height:0; position:relative; }
|
|
@@ -67,6 +73,7 @@
|
|
|
67
73
|
<button data-lo="3">3列</button>
|
|
68
74
|
</div>
|
|
69
75
|
<span class="spacer"></span>
|
|
76
|
+
<button class="bar-btn" id="notify-btn" onclick="toggleNotify()" title="任务完成/待回答时桌面通知+提示音(默认关)">🔔 关</button>
|
|
70
77
|
<button class="bar-btn" onclick="refreshSessions(true)" title="刷新任务列表">↻</button>
|
|
71
78
|
<button class="bar-btn" onclick="addPane('')" title="加一个空窗格,从下拉选已有任务">+ 窗格</button>
|
|
72
79
|
<button class="bar-btn" style="border-color:var(--green);color:var(--green)" onclick="openNewTask()" title="新建任务(和首页一致:预设/名称/命令/目录)">🆕 新建任务</button>
|
|
@@ -174,10 +181,12 @@
|
|
|
174
181
|
function addPane(sid, skipSave) {
|
|
175
182
|
const pane = document.createElement('div'); pane.className = 'pane'; pane._sid = sid || '';
|
|
176
183
|
const head = document.createElement('div'); head.className = 'pane-head';
|
|
184
|
+
const dot = document.createElement('span'); dot.className = 'pane-dot'; dot.title = '任务状态';
|
|
177
185
|
const picker = document.createElement('button'); picker.className = 'pane-picker';
|
|
178
186
|
const full = document.createElement('button'); full.textContent='↗'; full.title='在新标签页打开';
|
|
179
187
|
const close = document.createElement('button'); close.textContent='✕'; close.title='关闭此格'; close.style.color='var(--red)';
|
|
180
|
-
head.appendChild(picker); head.appendChild(full); head.appendChild(close);
|
|
188
|
+
head.appendChild(dot); head.appendChild(picker); head.appendChild(full); head.appendChild(close);
|
|
189
|
+
pane._dot = dot; pane._head = head;
|
|
181
190
|
const body = document.createElement('div'); body.className = 'pane-body';
|
|
182
191
|
const empty = document.createElement('div'); empty.className='pane-empty'; empty.textContent='点上方「选择任务」挑一个(可搜索/分组/按标签)'; body.appendChild(empty);
|
|
183
192
|
pane.appendChild(head); pane.appendChild(body);
|
|
@@ -350,6 +359,44 @@
|
|
|
350
359
|
document.getElementById('nt-cwd').value = b.dataset.dir;
|
|
351
360
|
});
|
|
352
361
|
|
|
362
|
+
// ── 窗格状态灯 + 完成/待回答高亮 + 通知(内嵌会话页 postMessage 上报)──
|
|
363
|
+
let _notify = localStorage.getItem('myhi_grid_notify') === '1';
|
|
364
|
+
function syncNotifyBtn(){ const b=document.getElementById('notify-btn'); if(b) b.textContent='🔔 '+(_notify?'开':'关'); }
|
|
365
|
+
window.toggleNotify = function(){
|
|
366
|
+
_notify = !_notify;
|
|
367
|
+
if (_notify && 'Notification' in window && Notification.permission==='default') Notification.requestPermission();
|
|
368
|
+
localStorage.setItem('myhi_grid_notify', _notify?'1':'0');
|
|
369
|
+
syncNotifyBtn();
|
|
370
|
+
};
|
|
371
|
+
syncNotifyBtn();
|
|
372
|
+
function paneTitle(pane){ const s = pane._sid ? sessById(pane._sid) : null; return s ? sName(s) : '任务'; }
|
|
373
|
+
function beep(){ try { const c=new (window.AudioContext||window.webkitAudioContext)(); const o=c.createOscillator(), g=c.createGain(); o.connect(g); g.connect(c.destination); o.frequency.value=660; g.gain.value=0.06; o.start(); setTimeout(()=>{o.stop();c.close();},180);} catch {} }
|
|
374
|
+
function fireNotify(pane,label){
|
|
375
|
+
if(!_notify) return;
|
|
376
|
+
try { if('Notification' in window && Notification.permission==='granted') new Notification('myhi · '+label,{body:paneTitle(pane)}); } catch {}
|
|
377
|
+
beep();
|
|
378
|
+
}
|
|
379
|
+
function setPaneStatus(pane,state){
|
|
380
|
+
const prev=pane._state; pane._state=state;
|
|
381
|
+
if(pane._dot){
|
|
382
|
+
const c={idle:'var(--green)',working:'var(--blue)',thinking:'var(--blue)',waiting:'#d29922'}[state]||'var(--dim)';
|
|
383
|
+
pane._dot.style.background=c;
|
|
384
|
+
pane._dot.classList.toggle('pulse', state==='working'||state==='thinking');
|
|
385
|
+
pane._dot.title={idle:'空闲/已完成',working:'执行中',thinking:'执行中',waiting:'等你回答'}[state]||'状态';
|
|
386
|
+
}
|
|
387
|
+
const justDone=(prev==='working'||prev==='thinking')&&state==='idle';
|
|
388
|
+
if(justDone||state==='waiting'){
|
|
389
|
+
if(pane._head){ pane._head.classList.remove('flash'); void pane._head.offsetWidth; pane._head.classList.add('flash'); setTimeout(()=>pane._head&&pane._head.classList.remove('flash'),3200); }
|
|
390
|
+
fireNotify(pane, state==='waiting'?'待回答':'已完成');
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
window.addEventListener('message',(e)=>{
|
|
394
|
+
const m=e.data;
|
|
395
|
+
if(!m||m.type!=='myhi-status') return;
|
|
396
|
+
const pane=paneEls.find(p=>p._sid&&p._sid===m.sessionId);
|
|
397
|
+
if(pane) setPaneStatus(pane,m.state);
|
|
398
|
+
});
|
|
399
|
+
|
|
353
400
|
// ── 初始化 ──
|
|
354
401
|
(async function init() {
|
|
355
402
|
await refreshSessions(false);
|