@wendongfly/myhi 1.3.203 → 1.3.205
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 +151 -36
- package/dist/chat.html.gz +0 -0
- package/dist/index.html +7 -3
- package/dist/index.html.gz +0 -0
- package/dist/index.js +9 -9
- package/dist/index.min.js +160 -154
- package/package.json +1 -1
package/dist/chat.html
CHANGED
|
@@ -406,7 +406,26 @@
|
|
|
406
406
|
.fp-header h3 { flex: 1; font-size: 0.9rem; margin: 0; color: var(--text); }
|
|
407
407
|
.fp-btn { background: var(--surface2); color: var(--text); border: 1px solid var(--border); border-radius: 6px; padding: 0.3rem 0.6rem; font-size: 0.75rem; cursor: pointer; }
|
|
408
408
|
.fp-btn:active { background: var(--border); }
|
|
409
|
-
.fp-path { padding: 0.4rem 0.75rem; font-size: 0.
|
|
409
|
+
.fp-path { padding: 0.4rem 0.75rem; font-size: 0.74rem; color: var(--muted); border-bottom: 1px solid var(--surface2); word-break: break-all; flex-shrink: 0; line-height: 1.6; }
|
|
410
|
+
.fp-path .crumb { color: var(--blue); cursor: pointer; }
|
|
411
|
+
.fp-path .crumb:hover { text-decoration: underline; }
|
|
412
|
+
.fp-path .crumb.cur { color: var(--text); cursor: default; text-decoration: none; font-weight: 600; }
|
|
413
|
+
.fp-path .sep { margin: 0 0.25rem; color: var(--muted); }
|
|
414
|
+
.fp-x { padding: 0.25rem 0.55rem; }
|
|
415
|
+
#fp-tools { display: flex; gap: 0.4rem; align-items: center; padding: 0.35rem 0.75rem; border-bottom: 1px solid var(--surface2); flex-shrink: 0; }
|
|
416
|
+
#fp-sel-bar { display: none; align-items: center; gap: 0.3rem; padding: 0.45rem 0.6rem; background: var(--surface2); font-size: 0.76rem; border-top: 1px solid var(--border); flex-shrink: 0; }
|
|
417
|
+
#fp-sel-bar .fp-btn { padding: 0.3rem 0.45rem; white-space: nowrap; }
|
|
418
|
+
.fp-item .fp-more { color: var(--muted); padding: 0 0.45rem; font-size: 1rem; line-height: 1; letter-spacing: 1px; flex-shrink: 0; align-self: flex-start; border-radius: 6px; cursor: pointer; }
|
|
419
|
+
.fp-item .fp-more:hover { background: var(--surface2); color: var(--text); }
|
|
420
|
+
/* 行 / 工具 ⋯ 菜单:电脑上是贴着鼠标的小菜单,手机上是底部抽屉 */
|
|
421
|
+
#fp-menu-ov { position: fixed; inset: 0; z-index: 90; }
|
|
422
|
+
#fp-menu { position: fixed; z-index: 91; background: var(--surface); border: 1px solid var(--border); border-radius: 10px; box-shadow: 0 8px 24px rgba(0,0,0,0.3); padding: 0.3rem 0; min-width: 12rem; max-width: 18rem; }
|
|
423
|
+
#fp-menu.sheet { left: 0 !important; right: 0; bottom: 0; top: auto !important; max-width: none; border-radius: 16px 16px 0 0; padding-bottom: max(0.6rem, env(safe-area-inset-bottom)); }
|
|
424
|
+
#fp-menu .mh { padding: 0.4rem 0.9rem 0.3rem; font-size: 0.7rem; color: var(--muted); word-break: break-all; border-bottom: 1px solid var(--surface2); }
|
|
425
|
+
#fp-menu button { display: block; width: 100%; text-align: left; background: none; border: none; color: var(--text); font-size: 0.84rem; padding: 0.55rem 0.9rem; cursor: pointer; }
|
|
426
|
+
#fp-menu.sheet button { padding: 0.8rem 1.1rem; font-size: 0.9rem; }
|
|
427
|
+
#fp-menu button:hover { background: var(--surface2); }
|
|
428
|
+
#fp-menu button small { color: var(--muted); font-size: 0.7rem; margin-left: 0.3rem; }
|
|
410
429
|
.fp-list { flex: 1; overflow-y: auto; padding: 0.25rem 0; }
|
|
411
430
|
.fp-item { display: flex; align-items: center; padding: 0.5rem 0.75rem; gap: 0.5rem; cursor: pointer; font-size: 0.82rem; color: var(--text); }
|
|
412
431
|
.fp-item:active { background: var(--surface2); }
|
|
@@ -419,12 +438,15 @@
|
|
|
419
438
|
#fp-multi-btn.on { border-color: var(--purple); color: var(--purple); }
|
|
420
439
|
.fp-item .fp-dl { color: var(--blue); font-size: 0.78rem; text-decoration: none; padding: 0.2rem 0.3rem; flex-shrink: 0; align-self: flex-start; }
|
|
421
440
|
.fp-empty { text-align: center; color: var(--muted); padding: 2rem 0.75rem; font-size: 0.85rem; }
|
|
441
|
+
/* 拖拽上传区:平时不占位置,电脑上把文件拖进抽屉时才出现(手机没法拖拽) */
|
|
422
442
|
.fp-drop-zone {
|
|
443
|
+
display: none;
|
|
423
444
|
margin: 0.5rem 0.75rem; padding: 1.5rem; border: 2px dashed var(--border); border-radius: 8px;
|
|
424
445
|
text-align: center; color: var(--muted); font-size: 0.8rem; flex-shrink: 0;
|
|
425
446
|
transition: border-color 0.2s, background 0.2s;
|
|
426
447
|
}
|
|
427
448
|
.fp-drop-zone.dragover { border-color: var(--blue); background: rgba(88,166,255,0.08); }
|
|
449
|
+
#file-panel.dragging .fp-drop-zone { display: block; border-color: var(--blue); background: rgba(88,166,255,0.08); color: var(--blue); }
|
|
428
450
|
.fp-progress { padding: 0.4rem 0.75rem; font-size: 0.75rem; color: var(--yellow); flex-shrink: 0; display: none; }
|
|
429
451
|
.fp-sync-bar { display: flex; gap: 0.4rem; padding: 0.5rem 0.75rem; border-bottom: 1px solid var(--surface2); flex-shrink: 0; align-items: center; flex-wrap: wrap; }
|
|
430
452
|
.fp-sync-bar .fp-btn { font-size: 0.7rem; padding: 0.25rem 0.5rem; }
|
|
@@ -826,10 +848,8 @@
|
|
|
826
848
|
<div id="file-panel-backdrop" onclick="closeFilePanel()"></div>
|
|
827
849
|
<div id="file-panel">
|
|
828
850
|
<div class="fp-header">
|
|
829
|
-
<h3 id="fp-title"
|
|
830
|
-
<button class="fp-btn" onclick="
|
|
831
|
-
<button class="fp-btn" onclick="fpStartSync()">同步</button>
|
|
832
|
-
<button class="fp-btn" onclick="closeFilePanel()">关闭</button>
|
|
851
|
+
<h3 id="fp-title">文件</h3>
|
|
852
|
+
<button class="fp-btn fp-x" onclick="closeFilePanel()" title="关闭">✕</button>
|
|
833
853
|
</div>
|
|
834
854
|
<div class="fp-sync-bar" id="fp-sync-bar" style="display:none">
|
|
835
855
|
<span class="sync-dir" id="fp-sync-dir"></span>
|
|
@@ -837,26 +857,29 @@
|
|
|
837
857
|
<button class="fp-btn" onclick="fpExitSync()">退出同步</button>
|
|
838
858
|
</div>
|
|
839
859
|
<div class="fp-path" id="fp-path"></div>
|
|
840
|
-
|
|
841
|
-
|
|
860
|
+
<!-- 工具栏只留常用的两个;同步 / 排序 / 本机打开文件夹收进 ⋯ -->
|
|
861
|
+
<div id="fp-tools">
|
|
862
|
+
<button class="fp-btn" onclick="fpUploadClick()" title="上传文件到当前目录(电脑上也可以直接把文件拖进来)">⬆ 上传</button>
|
|
863
|
+
<button class="fp-btn" id="fp-multi-btn" onclick="fpToggleMulti()" title="勾选多个文件 / 文件夹:打包下载,或一次引用给 AI">☑ 选择</button>
|
|
842
864
|
<span style="flex:1"></span>
|
|
843
|
-
<button class="fp-btn"
|
|
844
|
-
<button class="fp-btn" id="fp-sort-btn" onclick="fpToggleSort()" title="切换排序">排序: 名称</button>
|
|
865
|
+
<button class="fp-btn" onclick="fpToolsMenu(event)" title="更多:同步到本地、排序、在本机打开文件夹">⋯</button>
|
|
845
866
|
</div>
|
|
846
|
-
<div
|
|
847
|
-
|
|
867
|
+
<div class="fp-list" id="fp-list"></div>
|
|
868
|
+
<!-- 选择模式的操作栏放底部:手指够得着 -->
|
|
869
|
+
<div id="fp-sel-bar">
|
|
870
|
+
<span id="fp-sel-count" style="color:var(--muted);white-space:nowrap">已选0</span>
|
|
848
871
|
<span style="flex:1"></span>
|
|
849
872
|
<button class="fp-btn" onclick="fpSelAll()">全选</button>
|
|
873
|
+
<button class="fp-btn" id="fp-sel-ref" onclick="fpReferSelected()" disabled title="把选中的文件路径一起插进消息框,让 AI 读这些文件">@ 引用</button>
|
|
850
874
|
<button class="fp-btn fp-btn-primary" id="fp-sel-dl" onclick="fpZipSelected()" disabled>⬇ 打包下载</button>
|
|
851
|
-
<button class="fp-btn" onclick="fpToggleMulti(false)"
|
|
875
|
+
<button class="fp-btn" onclick="fpToggleMulti(false)" title="取消选择">✕</button>
|
|
852
876
|
</div>
|
|
853
|
-
<div class="fp-list" id="fp-list"></div>
|
|
854
877
|
<div class="fp-diff-actions" id="fp-diff-actions" style="display:none">
|
|
855
878
|
<button class="fp-btn fp-btn-primary" onclick="fpSyncToLocal()">下载到本地</button>
|
|
856
879
|
<button class="fp-btn fp-btn-warn" onclick="fpSyncToServer()">上传到服务器</button>
|
|
857
880
|
</div>
|
|
858
881
|
<div class="fp-progress" id="fp-progress"></div>
|
|
859
|
-
<div class="fp-drop-zone" id="fp-drop"
|
|
882
|
+
<div class="fp-drop-zone" id="fp-drop">松开鼠标,上传到当前目录</div>
|
|
860
883
|
<input type="file" id="fp-file-input" multiple style="display:none">
|
|
861
884
|
</div>
|
|
862
885
|
|
|
@@ -4134,7 +4157,7 @@
|
|
|
4134
4157
|
const r = await fetch(`/api/files/${SESSION_ID}?path=${encodeURIComponent(fpCurrentPath)}`);
|
|
4135
4158
|
const data = await r.json();
|
|
4136
4159
|
if (!data.ok) { list.innerHTML = `<div class="fp-empty">${escHtml(data.error)}</div>`; return; }
|
|
4137
|
-
|
|
4160
|
+
fpRenderCrumbs(data.cwd, data.path || '');
|
|
4138
4161
|
if (!data.entries.length && data.parent == null) {
|
|
4139
4162
|
list.innerHTML = '<div class="fp-empty">空目录</div>';
|
|
4140
4163
|
return;
|
|
@@ -4156,19 +4179,15 @@
|
|
|
4156
4179
|
html += `<div class="fp-item${on ? ' sel' : ''}" onclick="fpToggleSel('${escAttr(rel)}')"><input type="checkbox" class="fp-chk" ${on ? 'checked' : ''} tabindex="-1" style="pointer-events:none"><span class="fp-icon">${e.isDir ? '📁' : '📄'}</span><span class="fp-name" title="${escAttr(rel)}">${escHtml(e.name)}</span>${e.isDir ? '' : `<span class="fp-size">${fpFormatSize(e.size)}</span>`}</div>`;
|
|
4157
4180
|
continue;
|
|
4158
4181
|
}
|
|
4159
|
-
|
|
4160
|
-
|
|
4161
|
-
|
|
4162
|
-
|
|
4163
|
-
|
|
4164
|
-
|
|
4165
|
-
|
|
4166
|
-
|
|
4167
|
-
|
|
4168
|
-
${editable ? `<span class="fp-dl" onclick="event.stopPropagation();openFileEditor('${escAttr(rel)}')" title="在线编辑">✏️</span>` : ''}
|
|
4169
|
-
<a class="fp-dl" href="/api/files/${SESSION_ID}/download?path=${encodeURIComponent(rel)}" download title="下载" onclick="event.stopPropagation()">⬇</a>
|
|
4170
|
-
</div>`;
|
|
4171
|
-
}
|
|
4182
|
+
// 点整行 = 打开(文件夹进入 / 文件预览或编辑);其余操作都在行尾 ⋯(电脑上右键也行)
|
|
4183
|
+
const kind = e.isDir ? 'd' : isEditableFile(e.name) ? 'e' : 'f';
|
|
4184
|
+
const a = `'${escAttr(rel)}','${kind}'`;
|
|
4185
|
+
html += `<div class="fp-item" onclick="fpOpen(${a})" oncontextmenu="fpItemMenu(event,${a})" title="${kind === 'f' ? '点击查看可用操作' : '点击打开'}">
|
|
4186
|
+
<span class="fp-icon">${e.isDir ? '📁' : kind === 'e' ? '📝' : '📄'}</span>
|
|
4187
|
+
<span class="fp-name">${escHtml(e.name)}</span>
|
|
4188
|
+
${e.isDir ? '' : `<span class="fp-size">${fpFormatSize(e.size)}</span>`}
|
|
4189
|
+
<span class="fp-more" onclick="event.stopPropagation();fpItemMenu(event,${a})" title="更多操作">⋯</span>
|
|
4190
|
+
</div>`;
|
|
4172
4191
|
}
|
|
4173
4192
|
list.innerHTML = html;
|
|
4174
4193
|
} catch (e) {
|
|
@@ -4186,8 +4205,9 @@
|
|
|
4186
4205
|
bar.style.display = fpSel ? 'flex' : 'none';
|
|
4187
4206
|
document.getElementById('fp-multi-btn').classList.toggle('on', !!fpSel);
|
|
4188
4207
|
if (!fpSel) return;
|
|
4189
|
-
document.getElementById('fp-sel-count').textContent =
|
|
4208
|
+
document.getElementById('fp-sel-count').textContent = `已选${fpSel.size}`;
|
|
4190
4209
|
document.getElementById('fp-sel-dl').disabled = !fpSel.size;
|
|
4210
|
+
document.getElementById('fp-sel-ref').disabled = !fpSel.size;
|
|
4191
4211
|
}
|
|
4192
4212
|
window.fpToggleMulti = function(on) {
|
|
4193
4213
|
fpSel = (on ?? !fpSel) ? new Set() : null;
|
|
@@ -4205,6 +4225,86 @@
|
|
|
4205
4225
|
fpSyncSelBar(); fpLoadFiles();
|
|
4206
4226
|
};
|
|
4207
4227
|
window.fpZipSelected = function() { if (fpSel?.size) fpZip([...fpSel]); };
|
|
4228
|
+
// 选中的一次引用给 AI:路径用空格连起来插进消息框
|
|
4229
|
+
window.fpReferSelected = function() {
|
|
4230
|
+
if (!fpSel?.size) return;
|
|
4231
|
+
const list = [...fpSel];
|
|
4232
|
+
fpToggleMulti(false);
|
|
4233
|
+
fpRefer(list.join(' '));
|
|
4234
|
+
};
|
|
4235
|
+
|
|
4236
|
+
// 面包屑:项目名 › 子目录 › …,点哪级回哪级
|
|
4237
|
+
function fpRenderCrumbs(cwd, path) {
|
|
4238
|
+
const el = document.getElementById('fp-path');
|
|
4239
|
+
const root = String(cwd || '').replace(/[\\/]+$/, '').split(/[\\/]/).pop() || '项目';
|
|
4240
|
+
const segs = path ? path.split('/') : [];
|
|
4241
|
+
const parts = [{ name: root, rel: '' }, ...segs.map((n, i) => ({ name: n, rel: segs.slice(0, i + 1).join('/') }))];
|
|
4242
|
+
el.innerHTML = parts.map((p, i) => i === parts.length - 1
|
|
4243
|
+
? `<span class="crumb cur">${escHtml(p.name)}</span>`
|
|
4244
|
+
: `<span class="crumb" onclick="fpNav('${escAttr(p.rel)}')">${escHtml(p.name)}</span><span class="sep">›</span>`).join('');
|
|
4245
|
+
el.title = String(cwd || '') + (path ? '/' + path : '');
|
|
4246
|
+
}
|
|
4247
|
+
|
|
4248
|
+
// 点整行:文件夹进入;能在线看 / 改的打开(html / md 默认预览);其他文件(图片、压缩包…)弹出操作菜单
|
|
4249
|
+
window.fpOpen = function(rel, kind) {
|
|
4250
|
+
if (fpSel) return fpToggleSel(rel);
|
|
4251
|
+
if (kind === 'd') return fpNav(rel);
|
|
4252
|
+
if (kind === 'e') return openFileEditor(rel);
|
|
4253
|
+
fpItemMenu(null, rel, kind);
|
|
4254
|
+
};
|
|
4255
|
+
window.fpCopyPath = function(rel) {
|
|
4256
|
+
const t = typeof feditAbs === 'function' ? feditAbs(rel) : rel;
|
|
4257
|
+
const ok = () => addStatusMessage('已复制路径:' + t);
|
|
4258
|
+
(navigator.clipboard?.writeText(t) || Promise.reject()).then(ok, () => {
|
|
4259
|
+
const x = document.createElement('textarea'); x.value = t; document.body.appendChild(x); x.select();
|
|
4260
|
+
try { document.execCommand('copy'); ok(); } catch {} x.remove();
|
|
4261
|
+
});
|
|
4262
|
+
};
|
|
4263
|
+
function fpDownload(rel) {
|
|
4264
|
+
const a = document.createElement('a');
|
|
4265
|
+
a.href = `/api/files/${SESSION_ID}/download?path=${encodeURIComponent(rel)}`; a.download = '';
|
|
4266
|
+
document.body.appendChild(a); a.click(); a.remove();
|
|
4267
|
+
}
|
|
4268
|
+
|
|
4269
|
+
// 通用小菜单:电脑(鼠标)贴着点击位置弹,手机从底部弹
|
|
4270
|
+
function fpMenu(ev, title, items) {
|
|
4271
|
+
document.getElementById('fp-menu-ov')?.remove(); document.getElementById('fp-menu')?.remove();
|
|
4272
|
+
const ov = document.createElement('div'); ov.id = 'fp-menu-ov';
|
|
4273
|
+
const m = document.createElement('div'); m.id = 'fp-menu';
|
|
4274
|
+
const sheet = !ev || !matchMedia('(pointer: fine)').matches;
|
|
4275
|
+
if (sheet) { m.classList.add('sheet'); ov.style.background = 'rgba(0,0,0,0.45)'; }
|
|
4276
|
+
m.innerHTML = (title ? `<div class="mh">${escHtml(title)}</div>` : '') +
|
|
4277
|
+
items.map((it, i) => `<button data-i="${i}">${it[0]}${it[2] ? `<small>${escHtml(it[2])}</small>` : ''}</button>`).join('');
|
|
4278
|
+
const close = () => { ov.remove(); m.remove(); };
|
|
4279
|
+
ov.onclick = close; ov.oncontextmenu = (e) => { e.preventDefault(); close(); };
|
|
4280
|
+
m.onclick = (e) => { const b = e.target.closest('button[data-i]'); if (!b) return; close(); items[+b.dataset.i][1](); };
|
|
4281
|
+
document.body.appendChild(ov); document.body.appendChild(m);
|
|
4282
|
+
if (!sheet) {
|
|
4283
|
+
const r = m.getBoundingClientRect();
|
|
4284
|
+
m.style.left = Math.max(8, Math.min(ev.clientX, innerWidth - r.width - 8)) + 'px';
|
|
4285
|
+
m.style.top = Math.max(8, Math.min(ev.clientY, innerHeight - r.height - 8)) + 'px';
|
|
4286
|
+
}
|
|
4287
|
+
}
|
|
4288
|
+
window.fpItemMenu = function(ev, rel, kind) {
|
|
4289
|
+
if (ev) { ev.preventDefault(); ev.stopPropagation(); }
|
|
4290
|
+
if (fpSel) return;
|
|
4291
|
+
const items = [];
|
|
4292
|
+
if (kind === 'd') items.push(['📂 打开', () => fpNav(rel)], ['⬇ 打包下载', () => fpZip([rel]), 'zip']);
|
|
4293
|
+
else {
|
|
4294
|
+
if (kind === 'e') items.push([/\.(html?|md|markdown)$/i.test(rel) ? '👁 查看 / 编辑' : '✏️ 编辑', () => openFileEditor(rel)]);
|
|
4295
|
+
items.push(['⬇ 下载', () => fpDownload(rel)]);
|
|
4296
|
+
}
|
|
4297
|
+
items.push(['@ 引用到消息', () => fpRefer(kind === 'd' ? rel + '/' : rel), '让 AI 读它'], ['📋 复制路径', () => fpCopyPath(rel)]);
|
|
4298
|
+
fpMenu(ev, rel, items);
|
|
4299
|
+
};
|
|
4300
|
+
window.fpToolsMenu = function(ev) {
|
|
4301
|
+
const items = [
|
|
4302
|
+
['🔄 同步到本地文件夹', () => fpStartSync(), 'Chrome / Edge'],
|
|
4303
|
+
[fpSort === 'recent' ? '🔤 按名称排序' : '🕘 按最近修改排序', () => fpToggleSort()],
|
|
4304
|
+
];
|
|
4305
|
+
if (!document.body.classList.contains('no-desktop')) items.push(['📂 在这台电脑上打开文件夹', () => fpOpenFolder(), '远程访问无效']);
|
|
4306
|
+
fpMenu(ev, '', items);
|
|
4307
|
+
};
|
|
4208
4308
|
window.fpZip = async function(paths) {
|
|
4209
4309
|
const prog = document.getElementById('fp-progress');
|
|
4210
4310
|
prog.textContent = '正在统计要打包的文件…'; prog.style.display = 'block';
|
|
@@ -4285,13 +4385,16 @@
|
|
|
4285
4385
|
setTimeout(() => { progress.style.display = 'none'; }, 3000);
|
|
4286
4386
|
}
|
|
4287
4387
|
|
|
4288
|
-
//
|
|
4289
|
-
const
|
|
4290
|
-
|
|
4291
|
-
|
|
4292
|
-
|
|
4293
|
-
|
|
4294
|
-
|
|
4388
|
+
// 拖拽上传:把文件拖到抽屉任意位置,出现提示区,松开即上传到当前目录
|
|
4389
|
+
const fpPanel = document.getElementById('file-panel');
|
|
4390
|
+
let fpDragDepth = 0;
|
|
4391
|
+
const isFileDrag = (e) => [...(e.dataTransfer?.types || [])].includes('Files');
|
|
4392
|
+
fpPanel.addEventListener('dragenter', (e) => { if (!isFileDrag(e) || syncMode) return; e.preventDefault(); fpDragDepth++; fpPanel.classList.add('dragging'); });
|
|
4393
|
+
fpPanel.addEventListener('dragover', (e) => { if (isFileDrag(e) && !syncMode) e.preventDefault(); });
|
|
4394
|
+
fpPanel.addEventListener('dragleave', () => { if (--fpDragDepth <= 0) { fpDragDepth = 0; fpPanel.classList.remove('dragging'); } });
|
|
4395
|
+
fpPanel.addEventListener('drop', (e) => {
|
|
4396
|
+
if (!isFileDrag(e) || syncMode) return;
|
|
4397
|
+
e.preventDefault(); fpDragDepth = 0; fpPanel.classList.remove('dragging');
|
|
4295
4398
|
if (e.dataTransfer.files.length) fpUploadFiles(e.dataTransfer.files);
|
|
4296
4399
|
});
|
|
4297
4400
|
|
|
@@ -4803,6 +4906,18 @@
|
|
|
4803
4906
|
window.goHome = goHome;
|
|
4804
4907
|
window.goBack = function() { goHome(); };
|
|
4805
4908
|
|
|
4909
|
+
// ── 电脑宽屏回工作台 ──────────────────────────────────────────
|
|
4910
|
+
// 工作台窗口拉窄(< 1024px,比如两个窗口并排、拖到半屏)会跳到单独会话页;以前再拉宽也回不去,
|
|
4911
|
+
// 一直停在没有左侧任务栏的页面。现在:电脑(鼠标)上单独打开的会话页,宽度够了就回工作台、仍选中这个任务。
|
|
4912
|
+
// 分屏(embed=1)、工作台右侧(embed=ws)里嵌的会话页不动
|
|
4913
|
+
{
|
|
4914
|
+
const wide = matchMedia('(min-width: 1024px) and (pointer: fine)');
|
|
4915
|
+
const standalone = !new URLSearchParams(location.search).get('embed') && window.top === window;
|
|
4916
|
+
const back = () => { if (standalone && wide.matches) location.replace('/?s=' + encodeURIComponent(SESSION_ID)); };
|
|
4917
|
+
wide.addEventListener('change', back);
|
|
4918
|
+
back();
|
|
4919
|
+
}
|
|
4920
|
+
|
|
4806
4921
|
// ── 手机精简布局:⋯ 更多菜单 / 技能按钮 / 未读标记 / 其他任务提醒 ──────────
|
|
4807
4922
|
const IS_M = document.documentElement.classList.contains('m');
|
|
4808
4923
|
// 技能按钮:手机上快捷栏不平铺技能,点「技能」直接出可运行列表(底部有「管理技能」)
|
package/dist/chat.html.gz
CHANGED
|
Binary file
|
package/dist/index.html
CHANGED
|
@@ -1982,14 +1982,16 @@
|
|
|
1982
1982
|
what.innerHTML = `<b>包里会有</b>
|
|
1983
1983
|
<div class="mig-row"><span>📁</span><div>项目文件 <b>${p.files}</b> 个,共 <b>${fmtSize(p.bytes)}</b><br><small>${esc(p.cwd)}</small>${p.truncated ? '<div class="mig-warn">文件太多,只打包了前 20 万个</div>' : ''}</div></div>
|
|
1984
1984
|
${skipped ? `<div class="mig-row"><span>⏭</span><div>不打包(可重新生成,到新电脑再装):${skipped}</div></div>` : ''}
|
|
1985
|
-
<div class="mig-row"><span>💬</span><label style="cursor:pointer"><input type="checkbox" id="mig-conv" ${p.hasConv ? 'checked' : 'disabled'}> 带上 AI 对话记录${p.hasConv ? `(${fmtSize(p.convBytes)})` : ''}<br><small>${p.hasConv ? '带上后在新电脑上可以<b>接着聊</b>,AI
|
|
1985
|
+
<div class="mig-row"><span>💬</span><label style="cursor:pointer"><input type="checkbox" id="mig-conv" ${p.hasConv ? 'checked' : 'disabled'}> 带上 AI 对话记录${p.hasConv ? `(${fmtSize(p.convBytes)})` : ''}<br><small>${p.hasConv ? '带上后在新电脑上可以<b>接着聊</b>,AI 记得之前做过什么;对话里的项目路径会自动改成新位置。' : '这个任务还没有对话记录。'}</small></label></div>
|
|
1986
|
+
<div class="mig-row"><span>🧠</span><label style="cursor:pointer"><input type="checkbox" id="mig-mem" ${p.memFiles ? 'checked' : 'disabled'}> 带上项目记忆${p.memFiles ? `(${p.memFiles} 个文件)` : ''}<br><small>${p.memFiles ? 'AI 在这个项目里记下的约定、经验(记忆功能),和对话记录分开选:只要记忆、不要冗长聊天记录也行。记忆里写到的旧路径会改成新位置。' : '这个项目还没有 AI 记忆。'}</small></label></div>
|
|
1986
1987
|
${p.guard ? `<div class="mig-row"><span>🛡</span><div>隐私护栏配置(${p.guard.enabled ? '已开启' : '未开启'},主体词典 ${p.guard.entities} 个)和假名映射表一起带走,新电脑上继续脱敏</div></div>` : ''}
|
|
1987
1988
|
${p.secrets.length ? `<div class="mig-row"><span>🔑</span><div><b>密钥不会带走</b>(${p.secrets.map(esc).join('、')})<br><small>为了安全,密钥只留在这台电脑。到新电脑后在任务会话页「🔑 密钥」里重新录入。</small></div></div>` : ''}
|
|
1988
1989
|
${p.busy ? '<div class="mig-row mig-warn"><span>⚠️</span><div>AI 正在执行,建议等这一轮结束再导出,否则最后一轮对话可能不完整。</div></div>' : ''}`;
|
|
1989
1990
|
const btn = box.querySelector('#mig-dl'); btn.disabled = false;
|
|
1990
1991
|
btn.onclick = () => {
|
|
1991
1992
|
const conv = box.querySelector('#mig-conv')?.checked ? '1' : '0';
|
|
1992
|
-
const
|
|
1993
|
+
const mem = box.querySelector('#mig-mem')?.checked ? '1' : '0';
|
|
1994
|
+
const a = document.createElement('a'); a.href = '/api/migrate/' + encodeURIComponent(id) + '/export?conv=' + conv + '&mem=' + mem; a.download = '';
|
|
1993
1995
|
document.body.appendChild(a); a.click(); a.remove();
|
|
1994
1996
|
btn.textContent = '✓ 已开始下载'; btn.disabled = true;
|
|
1995
1997
|
btn.insertAdjacentHTML('afterend', '<div class="mig-dim" style="margin-top:0.4rem">文件大时浏览器会在后台下载,留意下载栏 / 通知。下载完成后按上面第 2、3 步操作。</div>');
|
|
@@ -2032,6 +2034,7 @@
|
|
|
2032
2034
|
<div class="mig-row"><span>📝</span><div>任务:<b>${esc(m.title || '')}</b><br><small>来自「${esc(m.from || '另一台 myhi')}」,${esc(new Date(m.exportedAt).toLocaleString())} 导出</small></div></div>
|
|
2033
2035
|
<div class="mig-row"><span>📁</span><div>项目文件 ${m.files} 个,共 ${fmtSize(m.bytes || 0)}<br><small>原位置:${esc(m.cwd || '')}</small></div></div>
|
|
2034
2036
|
<div class="mig-row"><span>💬</span><div>${m.conv ? 'AI 对话记录:有 —— 导入后可以<b>接着聊</b>' : 'AI 对话记录:没带 —— 导入后是一个新对话(项目文件都在)'}</div></div>
|
|
2037
|
+
<div class="mig-row"><span>🧠</span><div>${m.memory ? `项目记忆:${m.memory.count} 个文件 —— AI 记下的项目约定和经验一起导入;这台电脑上已有同名记忆时保留这台的,记忆索引会合并` : '项目记忆:没带'}</div></div>
|
|
2035
2038
|
${skipped ? `<div class="mig-row"><span>⏭</span><div>原电脑上没打包:${skipped}<br><small>依赖 / 构建产物需要在这台电脑重新安装或生成(例如 npm install);可以导入后直接让 AI 帮你装。</small></div></div>` : ''}
|
|
2036
2039
|
${m.guard ? `<div class="mig-row"><span>🛡</span><div>隐私护栏配置一起导入(主体词典 ${m.guard.entities} 个)</div></div>` : ''}
|
|
2037
2040
|
${(m.secrets || []).length ? `<div class="mig-row mig-warn"><span>🔑</span><div>需要重新录入的密钥:${m.secrets.map(esc).join('、')}<br><small>导入后在任务会话页「🔑 密钥」里填。</small></div></div>` : ''}
|
|
@@ -2050,7 +2053,8 @@
|
|
|
2050
2053
|
catch (e) { d = { ok: false, error: e.message }; }
|
|
2051
2054
|
if (!d.ok) { btn.disabled = false; btn.textContent = '导入为新任务'; res.innerHTML = '<div class="mig-warn" style="margin-top:0.4rem">' + esc(d.error) + '</div>'; return; }
|
|
2052
2055
|
btn.textContent = '✓ 导入完成';
|
|
2053
|
-
|
|
2056
|
+
const mm = d.memory && (d.memory.written || d.memory.kept) ? `项目记忆导入 ${d.memory.written} 个${d.memory.kept ? `(${d.memory.kept} 个这台电脑上已有,保留了这台的)` : ''}。` : '';
|
|
2057
|
+
res.innerHTML = `<div style="margin-top:0.5rem">任务已导入到 <code>${esc(cwd)}</code>。${d.conv ? '打开后直接发消息就能接着聊。' : ''}${mm}${(d.secrets || []).length ? `<div class="mig-warn">别忘了在会话页「🔑 密钥」里重新录入:${d.secrets.map(esc).join('、')}</div>` : ''}</div>
|
|
2054
2058
|
<button class="mig-btn" id="mig-open">打开这个任务</button>`;
|
|
2055
2059
|
res.querySelector('#mig-open').onclick = () => { document.getElementById('mig-ov')?.remove(); openSession(d.id); };
|
|
2056
2060
|
try { socket.emit('list'); } catch {}
|
package/dist/index.html.gz
CHANGED
|
Binary file
|