mingdao-harness 0.2.4 → 0.2.6
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/docs/EVALUATION-ROUND2.md +58 -0
- package/docs/ROADMAP-NEXT.md +5 -5
- package/package.json +2 -2
- package/src/agent.js +74 -36
- package/src/atomic-write.js +8 -2
- package/src/audit.js +2 -2
- package/src/batch.js +7 -7
- package/src/cachestats.js +9 -9
- package/src/cli.js +42 -688
- package/src/commands/desktop.js +1 -1
- package/src/commands/key.js +1 -1
- package/src/commands/repl.js +711 -0
- package/src/commands/schedule.js +7 -7
- package/src/commands/skill.js +18 -16
- package/src/commands/sync.js +5 -5
- package/src/commands/update.js +7 -6
- package/src/commands/workspace.js +2 -2
- package/src/compact.js +6 -6
- package/src/config.js +7 -4
- package/src/context.js +37 -21
- package/src/cost-guard.js +14 -6
- package/src/credentials.js +6 -0
- package/src/hooks.js +11 -11
- package/src/mcp-presets.js +5 -5
- package/src/mcp.js +19 -19
- package/src/memory.js +16 -16
- package/src/model-discovery.js +16 -15
- package/src/models.js +4 -4
- package/src/notify.js +2 -2
- package/src/permissions.js +7 -3
- package/src/pricing.js +35 -1
- package/src/prompts.js +1 -1
- package/src/providers/index.js +7 -7
- package/src/providers/openai-compatible.js +13 -11
- package/src/routing.js +8 -8
- package/src/schedule.js +30 -30
- package/src/session-index.js +5 -1
- package/src/session.js +11 -2
- package/src/skill-lib.js +62 -3
- package/src/skill-registry.js +10 -9
- package/src/skills.js +14 -12
- package/src/sync-server.js +86 -3
- package/src/sync.js +53 -20
- package/src/tasks/worker.js +126 -0
- package/src/tasks.js +14 -14
- package/src/titles.js +5 -5
- package/src/tokenizer.js +23 -5
- package/src/tools/bash.js +12 -12
- package/src/tools/fs-tools.js +66 -9
- package/src/tools/index.js +7 -7
- package/src/ui.js +83 -6
- package/src/update.js +8 -8
- package/src/web/app.js +16 -5
- package/src/web/attachments.js +1 -1
- package/src/web/index.html +21 -1
- package/src/web/routes/api.js +38 -786
- package/src/web/routes/domains/config.js +280 -0
- package/src/web/routes/domains/misc.js +129 -0
- package/src/web/routes/domains/schedule.js +127 -0
- package/src/web/routes/domains/sessions.js +105 -0
- package/src/web/routes/domains/skills.js +79 -0
- package/src/web/routes/domains/sync.js +101 -0
- package/src/web/routes/domains/workspace.js +119 -0
- package/src/web/server.js +73 -31
- package/src/web/web-io.js +54 -12
- package/src/workspace.js +14 -14
package/src/update.js
CHANGED
|
@@ -12,7 +12,7 @@ import { fileURLToPath } from 'node:url';
|
|
|
12
12
|
import { mingdaoHome, ensureHome } from './config.js';
|
|
13
13
|
import { atomicWriteFileSync } from './atomic-write.js';
|
|
14
14
|
|
|
15
|
-
function git(args, cwd) {
|
|
15
|
+
function git(/** @type {any} */ args, /** @type {any} */ cwd) {
|
|
16
16
|
const r = spawnSync('git', args, { cwd, encoding: 'utf8', timeout: 120000 });
|
|
17
17
|
return {
|
|
18
18
|
ok: r.status === 0 && !r.error,
|
|
@@ -36,11 +36,11 @@ export function findRepoRoot() {
|
|
|
36
36
|
return null;
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
function resolveRepo(override) {
|
|
39
|
+
function resolveRepo(/** @type {any} */ override) {
|
|
40
40
|
return override || findRepoRoot();
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
-
function versionAt(repo, ref = 'HEAD') {
|
|
43
|
+
function versionAt(/** @type {any} */ repo, ref = 'HEAD') {
|
|
44
44
|
const r = git(['show', `${ref}:package.json`], repo);
|
|
45
45
|
if (!r.ok) return null;
|
|
46
46
|
try {
|
|
@@ -50,7 +50,7 @@ function versionAt(repo, ref = 'HEAD') {
|
|
|
50
50
|
}
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
function compareVersions(a, b) {
|
|
53
|
+
function compareVersions(/** @type {any} */ a, /** @type {any} */ b) {
|
|
54
54
|
const pa = String(a).split('.').map((n) => parseInt(n, 10) || 0);
|
|
55
55
|
const pb = String(b).split('.').map((n) => parseInt(n, 10) || 0);
|
|
56
56
|
for (let i = 0; i < 3; i++) {
|
|
@@ -71,7 +71,7 @@ function readState() {
|
|
|
71
71
|
return null;
|
|
72
72
|
}
|
|
73
73
|
}
|
|
74
|
-
function writeState(s) {
|
|
74
|
+
function writeState(/** @type {any} */ s) {
|
|
75
75
|
ensureHome();
|
|
76
76
|
atomicWriteFileSync(stateFile(), JSON.stringify(s, null, 2) + '\n', { mode: 0o600 }); // 质检 H4:更新状态原子写
|
|
77
77
|
}
|
|
@@ -79,20 +79,20 @@ function writeState(s) {
|
|
|
79
79
|
// 直接向远端指定分支要版本(评估 D6):fetch 到 FETCH_HEAD 再读 package.json,
|
|
80
80
|
// 不依赖本地 refs 落盘——部分 Windows git 环境存在「fetch 成功但 refs 不更新」的异常,
|
|
81
81
|
// 按本地 refs 判断会误报「已是最新」。ls-remote 思路的等价实现。
|
|
82
|
-
function remoteVersion(repo, remote, branch) {
|
|
82
|
+
function remoteVersion(/** @type {any} */ repo, /** @type {any} */ remote, /** @type {any} */ branch) {
|
|
83
83
|
const r = git(['fetch', '--quiet', remote, branch], repo);
|
|
84
84
|
if (!r.ok) return null;
|
|
85
85
|
return versionAt(repo, 'FETCH_HEAD');
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
-
function listRemotes(repo) {
|
|
88
|
+
function listRemotes(/** @type {any} */ repo) {
|
|
89
89
|
const r = git(['remote'], repo);
|
|
90
90
|
if (!r.ok) return [];
|
|
91
91
|
return r.out.split('\n').filter(Boolean);
|
|
92
92
|
}
|
|
93
93
|
|
|
94
94
|
// 各远端(main/master 任一存在)中版本号最大的(多镜像部署:github/gitee/gitcode 谁新跟谁)
|
|
95
|
-
function newestRemote(repo) {
|
|
95
|
+
function newestRemote(/** @type {any} */ repo) {
|
|
96
96
|
let latest = '';
|
|
97
97
|
let ref = '';
|
|
98
98
|
for (const remote of listRemotes(repo)) {
|
package/src/web/app.js
CHANGED
|
@@ -427,7 +427,7 @@ function renderWorkStatus(){
|
|
|
427
427
|
}
|
|
428
428
|
el.style.display=html?'flex':'none';
|
|
429
429
|
el.innerHTML=html;
|
|
430
|
-
const bg=el.querySelector('.ws-bg'); if(bg) bg.onclick=()=>{ const tp=$('#tasksPanel'); tp.style.display = tp.style.display==='none'?'flex':'none'; if(tp.style.display==='flex'){ $('#trajPanel').style.display='none'; $('#subPanel').style.display='none'; updateTasksPanel(); } };
|
|
430
|
+
const bg=el.querySelector('.ws-bg'); if(bg) bg.onclick=()=>{ const tp=$('#tasksPanel'); tp.style.display = tp.style.display==='none'?'flex':'none'; if(tp.style.display==='flex'){ $('#trajPanel').style.display='none'; $('#subPanel').style.display='none'; updateTasksPanel(); } syncPanelLayout(); };
|
|
431
431
|
}
|
|
432
432
|
// 顶部常驻活动条(静默完美解决层):生成期间始终可见,滚动不影响
|
|
433
433
|
function renderLiveBar(){
|
|
@@ -483,6 +483,15 @@ function openTraj(msg){
|
|
|
483
483
|
$('#trajPanel').style.display='flex';
|
|
484
484
|
$('#tasksPanel').style.display='none'; // 仅任务面板(右侧)与轨迹互斥;子代理面板可与轨迹同显
|
|
485
485
|
$('#trajRailBtn').classList.add('on');
|
|
486
|
+
syncPanelLayout();
|
|
487
|
+
}
|
|
488
|
+
// 面板布局同步(2026-09-02):轨迹/子代理/任务面板打开时以 body class 推开内容区,
|
|
489
|
+
// 聊天文本与附件行不再被固定面板遮挡;面板宽度随屏宽自动收窄(CSS 媒体查询)。
|
|
490
|
+
function syncPanelLayout(){
|
|
491
|
+
const open=(id)=>document.getElementById(id)?.style.display==='flex';
|
|
492
|
+
document.body.classList.toggle('traj-open', open('trajPanel'));
|
|
493
|
+
document.body.classList.toggle('sub-open', open('subPanel'));
|
|
494
|
+
document.body.classList.toggle('tasks-open', open('tasksPanel'));
|
|
486
495
|
}
|
|
487
496
|
function resultText(r){
|
|
488
497
|
if(r==null||r===undefined) return '';
|
|
@@ -492,13 +501,14 @@ function resultText(r){
|
|
|
492
501
|
return JSON.stringify(r);
|
|
493
502
|
}
|
|
494
503
|
function truncText(t,n){ t=String(t||''); return t.length>n?t.slice(0,n)+'\n…(截断,共 '+t.length+' 字)':t; }
|
|
495
|
-
$('#tjClose').onclick=()=>{ $('#trajPanel').style.display='none'; $('#trajRailBtn').classList.remove('on'); };
|
|
504
|
+
$('#tjClose').onclick=()=>{ $('#trajPanel').style.display='none'; $('#trajRailBtn').classList.remove('on'); syncPanelLayout(); };
|
|
496
505
|
$('#trajRailBtn').onclick=()=>{
|
|
497
506
|
const p=$('#trajPanel');
|
|
498
507
|
const willShow=p.style.display==='none';
|
|
499
508
|
if(willShow){ const m=lastMsgWithTraj(); if(!m){ uiAlert('本轮还没有可展示的轨迹(先发起一个任务)'); return; } openTraj(m); }
|
|
500
509
|
else p.style.display='none';
|
|
501
510
|
$('#trajRailBtn').classList.toggle('on', willShow);
|
|
511
|
+
syncPanelLayout();
|
|
502
512
|
};
|
|
503
513
|
function lastMsgWithTraj(){
|
|
504
514
|
const msgs=[...document.querySelectorAll('#chat .msg-ai')].reverse();
|
|
@@ -528,9 +538,10 @@ const toggleSubPanel=()=>{
|
|
|
528
538
|
p.style.display=willShow?'flex':'none';
|
|
529
539
|
$('#subRailBtn').classList.toggle('on', willShow);
|
|
530
540
|
if(willShow){ $('#tasksPanel').style.display='none'; renderSubPanel(); } // 轨迹(左侧)可与子代理(右侧)同显
|
|
541
|
+
syncPanelLayout();
|
|
531
542
|
};
|
|
532
543
|
$('#subRailBtn').onclick=toggleSubPanel;
|
|
533
|
-
$('#sbClose').onclick=()=>{ $('#subPanel').style.display='none'; $('#subRailBtn').classList.remove('on'); };
|
|
544
|
+
$('#sbClose').onclick=()=>{ $('#subPanel').style.display='none'; $('#subRailBtn').classList.remove('on'); syncPanelLayout(); };
|
|
534
545
|
// —— 任务面板(多会话并行) ——
|
|
535
546
|
function setBtn(){
|
|
536
547
|
sendBtn.textContent = generating ? '■ 停止' : '发送';
|
|
@@ -597,8 +608,8 @@ async function refreshStatusBar(){
|
|
|
597
608
|
$('#statusBar').textContent = s.turns+' 轮 · '+s.steps+' 步 | LLM '+fmtDur(s.llmMs)+' · 工具调用 '+fmtDur(s.toolMs)+' | 首 token 平均 '+ft+' · '+tps+' | 缓存命中 '+rate+' | 输入 '+fmtTok(s.prompt)+' tok · 输出 '+fmtTok(s.completion)+' tok';
|
|
598
609
|
}
|
|
599
610
|
refreshStatusBar(); setInterval(refreshStatusBar, 15000);
|
|
600
|
-
$('#tasksBtn').onclick=()=>{ const p=$('#tasksPanel'); p.style.display = p.style.display==='none'?'flex':'none'; if(p.style.display==='flex'){ $('#subPanel').style.display='none'; $('#trajPanel').style.display='none'; $('#trajRailBtn').classList.remove('on'); $('#subRailBtn').classList.remove('on'); updateTasksPanel(); } };
|
|
601
|
-
$('#tpClose').onclick=()=>{ $('#tasksPanel').style.display='none'; };
|
|
611
|
+
$('#tasksBtn').onclick=()=>{ const p=$('#tasksPanel'); p.style.display = p.style.display==='none'?'flex':'none'; if(p.style.display==='flex'){ $('#subPanel').style.display='none'; $('#trajPanel').style.display='none'; $('#trajRailBtn').classList.remove('on'); $('#subRailBtn').classList.remove('on'); updateTasksPanel(); } syncPanelLayout(); };
|
|
612
|
+
$('#tpClose').onclick=()=>{ $('#tasksPanel').style.display='none'; syncPanelLayout(); };
|
|
602
613
|
|
|
603
614
|
async function refreshSessions(q){ const u=q?'/api/sessions?q='+encodeURIComponent(q):'/api/sessions'; const r=await fetch(u).catch(()=>null); if(!r)return; const j=await r.json(); const sel=$('#sessions'); sel.innerHTML='<option value="">历史会话</option>'; for(const s of j.sessions){ const o=document.createElement('option'); o.value=s.file; o.textContent=s.label; sel.appendChild(o); } if(currentSession&&!q) sel.value=currentSession; }
|
|
604
615
|
let searchTimer=null;
|
package/src/web/attachments.js
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
const MAX_IMAGE_DATAURL = 7 * 1024 * 1024; // base64 膨胀 1.33 倍,对应约 5MB 原图
|
|
8
8
|
const MAX_TEXT = 200 * 1024;
|
|
9
9
|
|
|
10
|
-
export function buildUserContent(message, attachments, visionSupported) {
|
|
10
|
+
export function buildUserContent(/** @type {any} */ message, /** @type {any} */ attachments, /** @type {any} */ visionSupported) {
|
|
11
11
|
const text = String(message ?? '').trim();
|
|
12
12
|
const list = Array.isArray(attachments) ? attachments.slice(0, 4) : [];
|
|
13
13
|
const imageParts = [];
|
package/src/web/index.html
CHANGED
|
@@ -25,7 +25,27 @@
|
|
|
25
25
|
*::-webkit-scrollbar-thumb:hover{background:#545557;border:2px solid transparent;background-clip:content-box}
|
|
26
26
|
*::-webkit-scrollbar-track{background:transparent}
|
|
27
27
|
html,body{height:100%}
|
|
28
|
-
body{margin:0;background:var(--bg);color:var(--text);font:15px/1.65 -apple-system,"Segoe UI","PingFang SC","Microsoft YaHei",sans-serif;display:flex;flex-direction:column;overflow-x:hidden}
|
|
28
|
+
body{margin:0;background:var(--bg);color:var(--text);font:15px/1.65 -apple-system,"Segoe UI","PingFang SC","Microsoft YaHei",sans-serif;display:flex;flex-direction:column;overflow-x:hidden;transition:padding .16s ease}
|
|
29
|
+
/* 面板推开布局(2026-09-02):轨迹/子代理/任务面板打开时推开内容区,聊天文本与附件行不被遮挡;
|
|
30
|
+
面板宽度随屏宽自动收窄,保证聊天区始终可读(≤560px 退化为全宽面板) */
|
|
31
|
+
body.traj-open{padding-left:294px}
|
|
32
|
+
body.sub-open{padding-right:320px}
|
|
33
|
+
body.tasks-open{padding-right:280px}
|
|
34
|
+
@media (max-width:1200px){
|
|
35
|
+
#trajPanel{width:210px}body.traj-open{padding-left:252px}
|
|
36
|
+
#subPanel{width:270px}body.sub-open{padding-right:270px}
|
|
37
|
+
#tasksPanel{width:230px}body.tasks-open{padding-right:230px}
|
|
38
|
+
}
|
|
39
|
+
@media (max-width:860px){
|
|
40
|
+
#trajPanel{width:160px}body.traj-open{padding-left:202px}
|
|
41
|
+
#subPanel{width:190px}body.sub-open{padding-right:190px}
|
|
42
|
+
#tasksPanel{width:190px}body.tasks-open{padding-right:190px}
|
|
43
|
+
}
|
|
44
|
+
@media (max-width:560px){
|
|
45
|
+
body.traj-open,body.sub-open,body.tasks-open{padding:0}
|
|
46
|
+
#trajPanel{width:calc(100vw - 42px);left:42px}
|
|
47
|
+
#subPanel,#tasksPanel{width:100vw}
|
|
48
|
+
}
|
|
29
49
|
header{min-height:52px;display:flex;align-items:center;gap:10px;padding:8px 12px;border-bottom:1px solid var(--border);background:var(--bg2);flex:none;flex-wrap:nowrap;white-space:nowrap;overflow-x:auto}
|
|
30
50
|
header .logo{font-weight:700;font-size:16px;color:var(--accent);letter-spacing:.5px;flex:none}
|
|
31
51
|
header .logo span{color:var(--text)}
|