@yangdcm/dsh-expert-team 1.3.13 → 1.3.14
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/CHANGELOG.md +36 -0
- package/client.js +66 -5
- package/lib/command.js +31 -7
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,42 @@
|
|
|
3
3
|
本包遵循[语义化版本](https://semver.org/lang/zh-CN/)。dsh 宿主版本线的对应关系写在
|
|
4
4
|
`package.json` 的 `engines.dsh` 与 `dsh.compatibility` 里,插件市场按它判断"这个插件跟你的宿主兼不兼容"。
|
|
5
5
|
|
|
6
|
+
## 1.3.14
|
|
7
|
+
|
|
8
|
+
**性能收尾:同一时刻至多一条重活 + profile 补账**(性能修复 #4)
|
|
9
|
+
|
|
10
|
+
- **真相换了一次**:上一版(1.3.13)把首屏从 3.4 s 打到 9–16 ms ✓,但真机连续采样发现
|
|
11
|
+
**重分节单次 4 805 ms、每 ≥6 s 一次**,而且**重活在飞时 summary 被拖到 772 ms**。
|
|
12
|
+
本轮先补账、再按数据改。
|
|
13
|
+
- **profile 补账(`DSH_EXPERT_TEAM_STATE_PROFILE=1`)**:原先只有 `runs+select / subs / wfLabels / roles / tail`
|
|
14
|
+
五个点,其中 `tail` 把"从角色解析之后到回响应"的**全部**工作都吞进一段(真机上那段约 2 s 无账)。
|
|
15
|
+
现按执行顺序补齐:`people-enrich`(过滤/映射/登记/workflow 元数据/enrich)、`agents`(agents 映射 + 实时投影)、
|
|
16
|
+
`assemble`(违规/schema 校验/告警)、`artifacts`(`RUN.log` 尾 + git)、`tail`(持久化 + 序列化)
|
|
17
|
+
⇒ **账目逐段对齐,不再有"无账的 2 秒"**。
|
|
18
|
+
- **`feed` 也依赖 subs**:原先只有 `want('people')` 才算 subs,于是单独请求 `section=feed` 会**静默返回空 feed**
|
|
19
|
+
—— 典型的"两种零分不清"。现在 `needSubs = want('people') || want('feed')`,该花的一次枚举照花。
|
|
20
|
+
- **新增两道上限(都带如实降级)**:
|
|
21
|
+
- `DSH_EXPERT_TEAM_ARTIFACTS_DEADLINE_MS`(默认 2 500 ms):artifacts 段要读 `RUN.log` 尾、还要跑 `git`,
|
|
22
|
+
是**全链最不可控**的一段。超期限就跳过,并如实记 `artifacts:deadline`(读完日志再超就记 `files:deadline`),
|
|
23
|
+
跳过时**不写**那些键 —— 缺块 ≠ 空数据。
|
|
24
|
+
- `DSH_EXPERT_TEAM_MAX_FEED_AGENTS`(默认 60):feed 按子代理条数封顶,被挡住的条数记 `feed:<n>`。
|
|
25
|
+
- **客户端:重分节改为"只拉当前可见子标签那一块"**(此前无条件每 ≥6 s 拉 `people,feed,artifacts`):
|
|
26
|
+
- `team`(人)→ `people,feed`;`tasks`(事)→ `people,feed`;`info`(料)→ `artifacts`;
|
|
27
|
+
**`board`(盘)→ 不拉任何重分节**(它只渲染 `runs[]`,而 runs 在 `summary` 里就有);
|
|
28
|
+
- 「事」点开任务详情(需要 `files`/`logTail`)时才**一次性**补拉 `artifacts`,不常驻;
|
|
29
|
+
- 映射收敛成**只有两个 canonical 重分节 URL**(`people,feed` / `artifacts`)⇒ `stateHub` 的同 URL 在飞合并
|
|
30
|
+
能把面板、画布、徽章压成**同一条**。
|
|
31
|
+
- **徽章不再与「料」标签并发两条重活**:徽章原先一直自己订阅 `people,feed`(2.5 s 一拍 ⇒ 重活常驻)。现在
|
|
32
|
+
面板/画布开着时由它们**发布**同一份 payload(`publishToLive`,发布时**合并**:缺块 ≠ 空数据),
|
|
33
|
+
徽章只在**无人发布**时才自己轮询,且节奏放宽到 **10 s**(子代理出现时另有 `liveTick()` 主动催一次)。
|
|
34
|
+
- **真机数字的解释(诚实标注口径)**:`4 805 ms ≈ 2 × 2 400 ms` —— 当时画布同时订阅了 `people,feed` 与
|
|
35
|
+
`people,feed,artifacts` 两条**不同 URL** 的重活,服务端在同一事件循环上串行处理 ⇒ 各自看着慢一倍,
|
|
36
|
+
并把 `summary` 拖到 772 ms。本轮把重活收敛成"同一时刻至多一条",这类并发在结构上不再可能。
|
|
37
|
+
- 本机可复现的旁证(真实 run、进程内计时):`snapshotRun` **1.3 ms**、`runLogTail` **0.3 ms**、
|
|
38
|
+
`liveFiles`(git)**0.3 ms 冷 / 0.0 ms 命中缓存** ⇒ artifacts 段**不是**那 2 s 的来源,
|
|
39
|
+
与"并发才是主因"的判断一致。
|
|
40
|
+
- 端到端复测仍归用户(本机装不进运行中的宿主):预期**同一时刻只有一条重活**、
|
|
41
|
+
`summary` 在重活在飞时仍为**十毫秒级**(此前 772 ms)、停留在某标签时后台不再出现不相干分节。
|
|
6
42
|
## 1.3.13
|
|
7
43
|
|
|
8
44
|
**渐进式状态:`/state` 支持 `?section=`,首屏与会话体量解耦**(性能修复 #3)
|
package/client.js
CHANGED
|
@@ -1245,6 +1245,21 @@ window.__ModuleLoader__.load({
|
|
|
1245
1245
|
h('div', { style: { display: 'flex', flexWrap: 'wrap', gap: 6 } }, options))
|
|
1246
1246
|
}
|
|
1247
1247
|
|
|
1248
|
+
// ── 标签 → 重分节映射(性能收尾批次:把"后台一直在拉三块"变成"只拉当前可见的那一块")──
|
|
1249
|
+
// 依据是各标签**实际渲染所用的字段**(读代码得出,不是猜):
|
|
1250
|
+
// `team`(人):agents/members/roles/wfRuns(people)+ 每个成员的实时操作流(feed)
|
|
1251
|
+
// `tasks`(事):依赖图的人员标签来自 people;任务本身在 summary 里(便宜);
|
|
1252
|
+
// 任务详情要 files/logTail(artifacts)⇒ 选中时**一次性**补拉(见下)
|
|
1253
|
+
// `info`(料):违规/覆盖率在 summary 里;实时日志(logTail)需要 artifacts
|
|
1254
|
+
// `board`(盘):只渲染 runs[](summary 里已有)⇒ **不需要任何重分节**
|
|
1255
|
+
// 这条映射是单一真源:订阅与"选中任务补拉"都读它,护栏测试也钉它。
|
|
1256
|
+
function heavySectionsForTab(tb) {
|
|
1257
|
+
if (tb === 'info') return 'artifacts'
|
|
1258
|
+
if (tb === 'tasks') return 'people,feed' // feed 是内存切片(近乎免费),与徽章同 URL ⇒ 合并成一条
|
|
1259
|
+
if (tb === 'board') return ''
|
|
1260
|
+
return 'people,feed' // team(默认)与人相关视图
|
|
1261
|
+
}
|
|
1262
|
+
|
|
1248
1263
|
function Panel(props) {
|
|
1249
1264
|
var sidProp = (props && props.sessionId) || ''
|
|
1250
1265
|
var viewMode = (props && props.mode) === 'view'
|
|
@@ -1373,6 +1388,7 @@ window.__ModuleLoader__.load({
|
|
|
1373
1388
|
function onState(d) {
|
|
1374
1389
|
if (d && d.ok) {
|
|
1375
1390
|
setData(function (prev) { return mergeStatePayload(prev, d) }); setErr(''); reschedule(d)
|
|
1391
|
+
try { publishToLive(d) } catch (e) {}
|
|
1376
1392
|
// N2: keep the composer takeover in sync with pendingDecision
|
|
1377
1393
|
// 批 0-2:把 /state 已经返回的 runId/workspace 一并传出,供横幅拍板时回传给 /decide
|
|
1378
1394
|
try { if (exports._syncPending) exports._syncPending(d.pendingDecision, sessionId, d.runId, d.workspace) } catch (e) {}
|
|
@@ -1407,19 +1423,35 @@ window.__ModuleLoader__.load({
|
|
|
1407
1423
|
}
|
|
1408
1424
|
useEffect(function () {
|
|
1409
1425
|
if (!isOpen && !viewMode) return undefined // panel closed & not canvas → no polling
|
|
1426
|
+
setLivePublisher(true) // 面板/画布开着 ⇒ 接管徽章的数据(见 publishToLive 的注释)
|
|
1410
1427
|
// **双订阅**(性能修复 #3):`summary` 便宜(阶段/进度/计数)⇒ 按 `pollMs` 快拉,
|
|
1411
1428
|
// 首屏立刻有内容;`people,feed,artifacts` 贵(成员解析/事件流/日志尾+git)⇒ 至少 6 秒一次,
|
|
1412
1429
|
// 到达后由 `mergeStatePayload` 合并进同一份 data(**不会**把摘要拍掉的字段抹掉)。
|
|
1413
1430
|
// stateHub 按 URL 各自计时(per-URL due),所以"一快一慢"不会互相拖。
|
|
1414
1431
|
var off = stateHubSubscribe(stateUrl('summary'), dispCfg.pollMs, onState)
|
|
1415
|
-
|
|
1432
|
+
// 重分节**按当前可见子标签**订阅(不再无条件拉 people,feed,artifacts):切标签时旧的 URL
|
|
1433
|
+
// 随卸载退订、新的立即拉一次 ⇒ 后台只保留"你正在看的那一块"。
|
|
1434
|
+
var heavy = heavySectionsForTab(tab)
|
|
1435
|
+
var offDetail = heavy ? stateHubSubscribe(stateUrl(heavy), Math.max(dispCfg.pollMs, 6000), onState) : function () {}
|
|
1416
1436
|
// catch up instantly when the user returns to the tab / window(只补便宜那一份)
|
|
1417
1437
|
var onVis = function () { if (document.visibilityState === 'visible') stateHubFetch(stateUrl('summary'), onState) }
|
|
1418
1438
|
var onFocus = function () { stateHubFetch(stateUrl('summary'), onState) }
|
|
1419
1439
|
document.addEventListener('visibilitychange', onVis)
|
|
1420
1440
|
window.addEventListener('focus', onFocus)
|
|
1421
|
-
return function () {
|
|
1422
|
-
|
|
1441
|
+
return function () {
|
|
1442
|
+
off(); offDetail()
|
|
1443
|
+
setLivePublisher(false)
|
|
1444
|
+
document.removeEventListener('visibilitychange', onVis); window.removeEventListener('focus', onFocus)
|
|
1445
|
+
}
|
|
1446
|
+
}, [sessionId, selRunV, isOpen, viewMode, dispCfg.pollMs, tab])
|
|
1447
|
+
|
|
1448
|
+
// 任务详情(files / logTail)属于 artifacts 分节:**只在真的点开任务时补拉一次**,
|
|
1449
|
+
// 不在后台常驻(否则等于把 artifacts 又变回常驻重分节)。切换选中任务会重新拉一次。
|
|
1450
|
+
useEffect(function () {
|
|
1451
|
+
if (!selTaskV) return
|
|
1452
|
+
if (tab !== 'tasks') return // 任务详情(files/logTail)只在「事」标签渲染
|
|
1453
|
+
try { stateHubFetch(stateUrl('artifacts'), onState) } catch (e) {}
|
|
1454
|
+
}, [selTaskV && selTaskV.id])
|
|
1423
1455
|
|
|
1424
1456
|
// Make the docked panel reserve space (shift the shell frame) instead of
|
|
1425
1457
|
// covering the workspace; clears when closed or floating (md-preview trick).
|
|
@@ -2442,7 +2474,11 @@ window.__ModuleLoader__.load({
|
|
|
2442
2474
|
|
|
2443
2475
|
// ── 共享 state 轮询(HeaderButton / LiveCapsule 复用,单例;无订阅者即停)──
|
|
2444
2476
|
var liveStore = { data: null, sid: '', off: null, subs: new Set() }
|
|
2445
|
-
|
|
2477
|
+
// 徽章/胶囊的基础节奏:它订阅的是 `people,feed`(重分节)。原先 2.5 s 等于**让重活常驻**
|
|
2478
|
+
// (即使没开面板也在拉),实测那正是"重请求在飞时 summary 被拖到 772 ms"的来源之一。
|
|
2479
|
+
// 徽章是环境状态(有没有人在跑/有没有待决策),10 s 的延迟可以接受;
|
|
2480
|
+
// 需要立刻刷新时另有 `liveTick()`(子代理出现时主动催一次),不靠高频轮询。
|
|
2481
|
+
var LIVE_BASE_MS = 10000
|
|
2446
2482
|
function liveUrl(sid) { return '/plugins/dsh-expert-team/state?sessionId=' + encodeURIComponent(sid) + '§ion=people,feed' }
|
|
2447
2483
|
// 手动催一次(子代理刚出现时立刻刷新一次徽章,不必等下一个 tick)
|
|
2448
2484
|
function liveTick() {
|
|
@@ -2461,20 +2497,45 @@ window.__ModuleLoader__.load({
|
|
|
2461
2497
|
var m = (d && d.members) || {}
|
|
2462
2498
|
return Object.keys(m).some(function (k) { var v = m[k]; return v && typeof v === 'object' && (v.activity === 'running' || v.shortStatus === 'running') })
|
|
2463
2499
|
}
|
|
2500
|
+
// ── 面板/画布 → 徽章的**发布**路径(性能收尾批次)────────────────────────────
|
|
2501
|
+
// 为什么需要:徽章订阅的是 `people,feed`(重分节)。若它一直自己轮询,而当前标签是「料」
|
|
2502
|
+
// (重分节 = `artifacts`),同一时刻就有**两条重活并发** —— 真机上那正是单发从 2.4 s 变
|
|
2503
|
+
// 4.8 s 的原因(同一事件循环上串行,各自看着都慢一倍),连带把 9 ms 的 summary 拖到 772 ms。
|
|
2504
|
+
// 现在:面板/画布开着时由它们**发布**同一份 payload(零额外请求);都没开时徽章才自己轮询。
|
|
2505
|
+
var livePublishers = 0
|
|
2506
|
+
function publishToLive(d) {
|
|
2507
|
+
if (!d || typeof d !== 'object') return
|
|
2508
|
+
// 合并而不是替换:面板按标签只发一部分块(缺块 ≠ 空数据),合并后徽章不会因为
|
|
2509
|
+
// 收到一份只有 summary 的负载就把已知的成员/活动抹掉。
|
|
2510
|
+
liveStore.data = Object.assign({}, liveStore.data || {}, d)
|
|
2511
|
+
try { harvestActivity(liveStore.data) } catch (e) {}
|
|
2512
|
+
try { stateHub.busy = teamBusy(liveStore.data) } catch (e) {}
|
|
2513
|
+
liveStore.subs.forEach(function (f) { try { f(liveStore.data) } catch (e) {} })
|
|
2514
|
+
}
|
|
2515
|
+
function setLivePublisher(on) {
|
|
2516
|
+
livePublishers += on ? 1 : -1
|
|
2517
|
+
if (livePublishers < 0) livePublishers = 0
|
|
2518
|
+
notify()
|
|
2519
|
+
}
|
|
2520
|
+
function useLivePublishers() { return useExternal(function () { return livePublishers }) }
|
|
2521
|
+
|
|
2464
2522
|
function useLiveState(sid) {
|
|
2465
2523
|
var st = useState(liveStore.data); var data = st[0], setData = st[1]
|
|
2524
|
+
var pubs = useLivePublishers()
|
|
2466
2525
|
useEffect(function () {
|
|
2467
2526
|
if (!sid) return undefined
|
|
2468
2527
|
liveStore.sid = sid
|
|
2469
2528
|
var fn = function (d) { setData(d) }
|
|
2470
2529
|
liveStore.subs.add(fn)
|
|
2530
|
+
// 有人发布(面板/画布开着)⇒ 徽章**不再另开一条重分节**,靠发布的数据保持新鲜。
|
|
2531
|
+
if (pubs > 0) return function () { liveStore.subs.delete(fn) }
|
|
2471
2532
|
// 经 hub 订阅:与面板/画布共用同一个时钟与在飞守卫(这里**不再**自己 setInterval)
|
|
2472
2533
|
var off = stateHubSubscribe(liveUrl(sid), LIVE_BASE_MS, liveDeliver)
|
|
2473
2534
|
return function () {
|
|
2474
2535
|
liveStore.subs.delete(fn)
|
|
2475
2536
|
off()
|
|
2476
2537
|
}
|
|
2477
|
-
}, [sid])
|
|
2538
|
+
}, [sid, pubs])
|
|
2478
2539
|
return data
|
|
2479
2540
|
}
|
|
2480
2541
|
// 头部徽章文案:让「并排面板」入口自带团队实时状态(与画布标签职责区分)
|
package/lib/command.js
CHANGED
|
@@ -5291,6 +5291,13 @@ export function apply(ctx, config) {
|
|
|
5291
5291
|
const MAX_ROLE_SUBS = Math.max(1, Number((typeof process !== 'undefined' && process.env && process.env.DSH_EXPERT_TEAM_MAX_ROLE_SUBS) || 0) || 60);
|
|
5292
5292
|
// people 分节的软期限:超时后跳过更贵的可选增强(workflow 元数据),同样如实标注。
|
|
5293
5293
|
const PEOPLE_DEADLINE_MS = Math.max(200, Number((typeof process !== 'undefined' && process.env && process.env.DSH_EXPERT_TEAM_PEOPLE_DEADLINE_MS) || 0) || 2500);
|
|
5294
|
+
// artifacts 分节的软期限:它要读 RUN.log 尾、还要跑 git(liveFiles)——后者在大工作区
|
|
5295
|
+
// 里是最不可控的一段。超过就从**请求开始**算起跳过,并**如实进 degraded**(缺块 ≠ 空数据:
|
|
5296
|
+
// 跳过时键不存在,客户端据 degraded 知道"不是没有,是没来得及")。
|
|
5297
|
+
const ARTIFACTS_DEADLINE_MS = Math.max(200, Number((typeof process !== 'undefined' && process.env && process.env.DSH_EXPERT_TEAM_ARTIFACTS_DEADLINE_MS) || 0) || 2500);
|
|
5298
|
+
// feed 分节的硬上限:每 agent 只嵌最近 12 条事件,但 agent 数本身要封顶(重会话里
|
|
5299
|
+
// subs 可能几十上百条),超出的条数**如实进 degraded**。
|
|
5300
|
+
const MAX_FEED_AGENTS = Math.max(1, Number((typeof process !== 'undefined' && process.env && process.env.DSH_EXPERT_TEAM_MAX_FEED_AGENTS) || 0) || 60);
|
|
5294
5301
|
const peopleStartedAt = Date.now();
|
|
5295
5302
|
const degraded = [];
|
|
5296
5303
|
const reg = (await registeredWorkspaces()).filter(Boolean);
|
|
@@ -5346,9 +5353,12 @@ export function apply(ctx, config) {
|
|
|
5346
5353
|
// 只有 people 分节才解析人员:这一步要枚举子会话 durable 清单(重会话里这是整条链上
|
|
5347
5354
|
// 最大的一块)。首屏用 summary 时不付这个成本 —— `agents` 返回空数组,
|
|
5348
5355
|
// 由客户端 `sections` 字段知道自己拿的是"摘要",UI 如实显示"正在加载成员"。
|
|
5349
|
-
|
|
5356
|
+
// `feed` 也必须先有 subs(它按子会话遍历活动缓存)。若只想要 feed 却跳过枚举,
|
|
5357
|
+
// feed 会**静默变空** —— 那正是本仓最忌讳的"两种零分不清"(缺块 ≠ 空数据)。
|
|
5358
|
+
const needSubs = want('people') || want('feed');
|
|
5359
|
+
let subs = needSubs ? await listSubagentStatusBySession(ctx, peopleSid, knownIds) : [];
|
|
5350
5360
|
// 归属会话拿不到人时退回请求会话(否则面板整块空掉),但**如实标注**这不是归属会话的人。
|
|
5351
|
-
if (
|
|
5361
|
+
if (needSubs && !subs.length && peopleSid !== sid) {
|
|
5352
5362
|
const fallback = await listSubagentStatusBySession(ctx, sid, knownIds);
|
|
5353
5363
|
if (fallback.length) { subs = fallback; peopleSid = sid; }
|
|
5354
5364
|
}
|
|
@@ -5463,6 +5473,7 @@ export function apply(ctx, config) {
|
|
|
5463
5473
|
if (want('people')) sel.members = enrichMembers(sel.runId, sel.roles, sel.members, subById, sel.agents);
|
|
5464
5474
|
// cost/model plan: expose each role's planned model so the overlay
|
|
5465
5475
|
// shows the scheme even before dispatch (live model wins once running).
|
|
5476
|
+
mark('people-enrich');
|
|
5466
5477
|
const modelPlan = sel.models || modelPlanFor(sel.roles || []);
|
|
5467
5478
|
for (const role of Object.keys(sel.members)) {
|
|
5468
5479
|
const m = sel.members[role];
|
|
@@ -5514,13 +5525,19 @@ export function apply(ctx, config) {
|
|
|
5514
5525
|
}));
|
|
5515
5526
|
sel.tasksEmpty = true;
|
|
5516
5527
|
}
|
|
5528
|
+
mark('agents');
|
|
5517
5529
|
// Live per-agent activity feed (Qoder-style): last tool events
|
|
5518
5530
|
// per subagent session, keyed by agent id.
|
|
5519
5531
|
// 只在 feed 分节里收集(它按子会话遍历活动缓存;summary 首屏不需要)。
|
|
5532
|
+
// 上限:agent 数封顶 MAX_FEED_AGENTS,被截断的条数如实进 degraded。
|
|
5520
5533
|
const feed = {};
|
|
5521
|
-
if (want('feed'))
|
|
5522
|
-
const
|
|
5523
|
-
if (
|
|
5534
|
+
if (want('feed')) {
|
|
5535
|
+
const feedTargets = subs.slice(0, MAX_FEED_AGENTS);
|
|
5536
|
+
if (subs.length > MAX_FEED_AGENTS) degraded.push('feed:' + (subs.length - MAX_FEED_AGENTS));
|
|
5537
|
+
for (const s of feedTargets) {
|
|
5538
|
+
const arr = ACTIVITY.get(s.id);
|
|
5539
|
+
if (arr && arr.length) feed[s.id] = arr.slice(-12);
|
|
5540
|
+
}
|
|
5524
5541
|
}
|
|
5525
5542
|
sel.feed = feed;
|
|
5526
5543
|
// 用同一批 feed 事件回填 lastEventAt(不额外读日志)
|
|
@@ -5549,13 +5566,20 @@ export function apply(ctx, config) {
|
|
|
5549
5566
|
if (fp.selfBuilt) sel.violations = sel.violations.concat([`非脚手架 run(疑似绕过 /team 手写):缺 ${fp.missing.join('、')}`]);
|
|
5550
5567
|
} catch { /* best-effort */ }
|
|
5551
5568
|
try { sel.warnings = checkKindWarnings(taskList(sel.tasks)); } catch { sel.warnings = []; }
|
|
5569
|
+
mark('assemble');
|
|
5552
5570
|
// Live monitoring: RUN.log feed (what just happened) + git
|
|
5553
5571
|
// changed files (what is being touched right now).
|
|
5554
5572
|
// 只在 artifacts 分节里读(`liveFiles` 要跑 git、`runLogTail` 要读日志尾部)。
|
|
5555
5573
|
if (want('artifacts')) {
|
|
5556
|
-
|
|
5557
|
-
|
|
5574
|
+
const withinArtifacts = () => (Date.now() - peopleStartedAt) < ARTIFACTS_DEADLINE_MS;
|
|
5575
|
+
if (!withinArtifacts()) degraded.push('artifacts:deadline');
|
|
5576
|
+
else {
|
|
5577
|
+
try { sel.logTail = await runLogTail(join(sel.workspace, 'team', sel.runId)); } catch { sel.logTail = ''; }
|
|
5578
|
+
if (!withinArtifacts()) degraded.push('files:deadline');
|
|
5579
|
+
else { try { sel.files = await liveFiles(sel.workspace, sel.runId); } catch { sel.files = []; } }
|
|
5580
|
+
}
|
|
5558
5581
|
}
|
|
5582
|
+
mark('artifacts');
|
|
5559
5583
|
// **GET 不写 run 工件**(2026-09-13 修):这里原先每 ≤5 分钟触发一次
|
|
5560
5584
|
// `autoAggregate`(`Date.now() - lastAggAt > 5*60*1000`),于是浮层每 3 秒的轮询
|
|
5561
5585
|
// 会**周期性改写 `team/METRICS.md` 与 `team/LEARNINGS.md`** —— 而 `LEARNINGS.md`
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yangdcm/dsh-expert-team",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.14",
|
|
4
4
|
"description": "dsh「专家团」bundle:一句自然语言自动组建/持久化一支 12 角色多智能体团队,共享工作区协议 + 阶段门控编排 + 结构化交接 + 质量门禁/自动调度,实现者直接改代码并产出持久工件;带 live 团队浮层(质量门禁/覆盖率/工件预览)。 · Role-based multi-agent expert team for DeepSeek Harness: one sentence in, a staged and gated team delivery out.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|