dsh-session-flow 1.1.0 → 1.3.0
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/lib/client.js +1457 -254
- package/lib/host.js +69 -5
- package/package.json +4 -1
package/lib/host.js
CHANGED
|
@@ -10,10 +10,11 @@
|
|
|
10
10
|
// searchAll { query, workspace? } → 跨会话全文检索(最近 20 会话/总 5s 预算/取消支持)
|
|
11
11
|
// stats → 环境信息(dsh home、索引目录、各工作区缓存状态)
|
|
12
12
|
//
|
|
13
|
-
// 依赖 cordis 服务:webServer(HTTP
|
|
13
|
+
// 依赖 cordis 服务:webServer(HTTP 载体);settings(插件设置命名空间,软依赖)。
|
|
14
14
|
import { existsSync, mkdirSync, readFileSync, readdirSync, rmSync, statSync, writeFile } from 'node:fs'
|
|
15
15
|
import { join } from 'node:path'
|
|
16
16
|
import { deflateRawSync } from 'node:zlib'
|
|
17
|
+
import z from 'schemastery'
|
|
17
18
|
import { decodeFile, listSessionDirs, listWorkspaces, looksLikePath, parseSession, summarizeParsed } from './archive.js'
|
|
18
19
|
import { deriveTimeline } from './timeline.js'
|
|
19
20
|
import {
|
|
@@ -69,17 +70,77 @@ function sendJson(res, status, obj) {
|
|
|
69
70
|
// ── 卡死监控(stall-monitor):健康分类 ─────────────────────────────
|
|
70
71
|
// 「进行中但长时间无输出」≠ 卡死(模型长思考/长工具执行都静默)。
|
|
71
72
|
// 分类只看结构事实:运行中 + 无流式 chunk + 无未闭合工具 + 静默超阈值 → 疑似卡死。
|
|
72
|
-
//
|
|
73
|
+
// 阈值可在设置页配置(settings 命名空间 session-flow / stallThresholdMin,分钟);
|
|
74
|
+
// STALL_THRESHOLD_MS 保留为默认值(verify 引用)。
|
|
73
75
|
export const STALL_THRESHOLD_MS = 3 * 60 * 1000
|
|
74
76
|
export const HEALTH_ACTIVE_WINDOW_MS = 60 * 1000
|
|
75
77
|
|
|
78
|
+
// ── 插件设置(settings 命名空间 'session-flow')────────────────────
|
|
79
|
+
// 默认值必须与 client.js 的 SETTINGS_DEFAULTS 完全一致(无用户设置时行为零变化)。
|
|
80
|
+
export const SETTINGS_DEFAULTS = {
|
|
81
|
+
pianoWindow: 12, // 轮次悬浮条可见行数
|
|
82
|
+
pianoWheelSpeed: 0.012, // 滚轮灵敏度(行/px)
|
|
83
|
+
pianoSnapMs: 170, // 静止吸附延迟(ms)
|
|
84
|
+
livePollMs: 3000, // 实时轮询间隔(ms)
|
|
85
|
+
liveFollowPx: 40, // 实时吸底阈值(px)
|
|
86
|
+
liveHistoryTurns: 3, // 详情页实时模式保留的历史回合数
|
|
87
|
+
stallThresholdMin: 3, // 疑似卡死阈值(分钟)
|
|
88
|
+
railEnhance: true, // 官方轮次导航(TurnNavigatorRail)增强层开关(v0.1.2+)
|
|
89
|
+
railHideOfficial: false, // 完全屏蔽官方轮次导航(只留我们的悬浮条)
|
|
90
|
+
pianoClassicStrip: true, // 经典左侧轮次悬浮条(默认开,与官方 rail 并存;用户裁定 2026-09-05)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/** schemastery schema:settings 服务 resolve 时调用 schema(merged),并需要 toJSON()(describe 用)。 */
|
|
94
|
+
const SETTINGS_SCHEMA = z.object({
|
|
95
|
+
pianoWindow: z.number().step(1).min(6).max(18).default(SETTINGS_DEFAULTS.pianoWindow),
|
|
96
|
+
pianoWheelSpeed: z.number().min(0.005).max(0.03).default(SETTINGS_DEFAULTS.pianoWheelSpeed),
|
|
97
|
+
pianoSnapMs: z.number().step(1).min(100).max(400).default(SETTINGS_DEFAULTS.pianoSnapMs),
|
|
98
|
+
livePollMs: z.number().step(1).min(1500).max(10000).default(SETTINGS_DEFAULTS.livePollMs),
|
|
99
|
+
liveFollowPx: z.number().step(1).min(20).max(120).default(SETTINGS_DEFAULTS.liveFollowPx),
|
|
100
|
+
liveHistoryTurns: z.number().step(1).min(0).max(10).default(SETTINGS_DEFAULTS.liveHistoryTurns),
|
|
101
|
+
stallThresholdMin: z.number().step(1).min(1).max(10).default(SETTINGS_DEFAULTS.stallThresholdMin),
|
|
102
|
+
railEnhance: z.boolean().default(SETTINGS_DEFAULTS.railEnhance),
|
|
103
|
+
railHideOfficial: z.boolean().default(SETTINGS_DEFAULTS.railHideOfficial),
|
|
104
|
+
pianoClassicStrip: z.boolean().default(SETTINGS_DEFAULTS.pianoClassicStrip),
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
/** 解析后的当前设置值(base + user 层);host 侧消费点(卡死阈值)从这里读。 */
|
|
108
|
+
const liveSettings = { ...SETTINGS_DEFAULTS }
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* 注册 settings 命名空间(软依赖:宿主无 settings 服务时跳过,行为回退默认值)。
|
|
112
|
+
* 模式参照 aionui-panel installSettingsSection:ctx.inject(['settings'], ...) +
|
|
113
|
+
* scope.watch 同步当前值。客户端经 settingsScope 直接读写(pet 同款),无需额外路由。
|
|
114
|
+
*/
|
|
115
|
+
function installSettings(ctx) {
|
|
116
|
+
try {
|
|
117
|
+
if (typeof ctx.inject !== 'function') return
|
|
118
|
+
ctx.inject(['settings'], (sctx) => {
|
|
119
|
+
try {
|
|
120
|
+
const scope = sctx.settings.register('session-flow', SETTINGS_SCHEMA, { base: SETTINGS_DEFAULTS })
|
|
121
|
+
const sync = () => {
|
|
122
|
+
const value = scope.get()
|
|
123
|
+
if (value && typeof value === 'object') Object.assign(liveSettings, SETTINGS_DEFAULTS, value)
|
|
124
|
+
}
|
|
125
|
+
sync()
|
|
126
|
+
scope.watch(sync)
|
|
127
|
+
} catch (error) {
|
|
128
|
+
console.error('[dsh-session-flow] settings registration failed:', error)
|
|
129
|
+
}
|
|
130
|
+
})
|
|
131
|
+
} catch (error) {
|
|
132
|
+
console.error('[dsh-session-flow] settings service unavailable:', error)
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
76
136
|
/**
|
|
77
137
|
* 健康分类(纯函数,verify 可测)。
|
|
78
138
|
* @param {{running:boolean,lastEventTime:number|null,openTool:boolean,inflight:boolean}} facts
|
|
79
139
|
* @param {number} now - 调用方时间戳(client 传 Date.now(),避免 host/client 时钟偏差语义混乱)。
|
|
140
|
+
* @param {number} [stallMs] - 卡死阈值(缺省 STALL_THRESHOLD_MS;设置页 stallThresholdMin 下发)。
|
|
80
141
|
* @returns {{kind:'active'|'tool-wait'|'quiet'|'stalled'|'ended'|'unknown', idleMs:number|null}}
|
|
81
142
|
*/
|
|
82
|
-
export function classifyHealth(facts, now) {
|
|
143
|
+
export function classifyHealth(facts, now, stallMs = STALL_THRESHOLD_MS) {
|
|
83
144
|
if (!facts || typeof facts !== 'object') return { kind: 'unknown', idleMs: null }
|
|
84
145
|
const idleMs = typeof facts.lastEventTime === 'number' ? Math.max(0, now - facts.lastEventTime) : null
|
|
85
146
|
if (facts.running !== true) return { kind: 'ended', idleMs }
|
|
@@ -88,7 +149,7 @@ export function classifyHealth(facts, now) {
|
|
|
88
149
|
// 有未闭合工具调用 → 静默是工具在执行(长跑命令正常),不算卡死。
|
|
89
150
|
if (facts.openTool === true) return { kind: 'tool-wait', idleMs }
|
|
90
151
|
if (idleMs === null) return { kind: 'unknown', idleMs }
|
|
91
|
-
if (idleMs >=
|
|
152
|
+
if (idleMs >= stallMs) return { kind: 'stalled', idleMs }
|
|
92
153
|
return { kind: 'quiet', idleMs }
|
|
93
154
|
}
|
|
94
155
|
|
|
@@ -630,6 +691,9 @@ export function apply(ctx) {
|
|
|
630
691
|
return
|
|
631
692
|
}
|
|
632
693
|
|
|
694
|
+
// 插件设置命名空间(软依赖;卡死阈值等 host 侧参数经 liveSettings 下发)。
|
|
695
|
+
installSettings(ctx)
|
|
696
|
+
|
|
633
697
|
webServer.register({
|
|
634
698
|
kind: 'exact',
|
|
635
699
|
path: '/api/session-flow',
|
|
@@ -1040,7 +1104,7 @@ export function apply(ctx) {
|
|
|
1040
1104
|
counts,
|
|
1041
1105
|
timeline,
|
|
1042
1106
|
running,
|
|
1043
|
-
health: { ...healthFacts, ...classifyHealth(healthFacts, now) },
|
|
1107
|
+
health: { ...healthFacts, ...classifyHealth(healthFacts, now, liveSettings.stallThresholdMin * 60000) },
|
|
1044
1108
|
})
|
|
1045
1109
|
}
|
|
1046
1110
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-session-flow",
|
|
3
3
|
"description": "DSH 会话回顾与归档插件:可折叠信息流 + 会话级汇总——总览工作台、折叠时间线、血缘树、双模式摘要、全文检索、ZIP 导出、实时跟踪、会话重命名(官方数据源对齐)、健康监控",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.3.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/host.js",
|
|
7
7
|
"exports": {
|
|
@@ -42,6 +42,9 @@
|
|
|
42
42
|
"platform": "web"
|
|
43
43
|
}
|
|
44
44
|
},
|
|
45
|
+
"dependencies": {
|
|
46
|
+
"schemastery": "^3.18.0"
|
|
47
|
+
},
|
|
45
48
|
"peerDependencies": {
|
|
46
49
|
"react": "^18.2.0",
|
|
47
50
|
"react-dom": "^18.2.0",
|