dsh-manage-session 0.2.3 → 0.4.8
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.ja.md +19 -0
- package/CHANGELOG.ko.md +18 -0
- package/CHANGELOG.md +40 -0
- package/README.en.md +14 -0
- package/README.ja.md +14 -0
- package/README.ko.md +14 -0
- package/README.md +14 -0
- package/dsh.plugin.json +4 -4
- package/lib/client.js +179 -36
- package/lib/index.d.ts +288 -16
- package/lib/index.js +1003 -384
- package/package.json +125 -121
- package/screenshots.json +5 -1
- package/src/client/card.tsx +150 -153
- package/src/client/health-panel.tsx +56 -1
- package/src/client/host-api.ts +19 -1
- package/src/client/index.ts +337 -234
- package/src/client/locales.ts +22 -2
- package/src/host/health/cache.ts +1 -1
- package/src/host/health/decode.ts +19 -1
- package/src/host/health/gates.ts +94 -3
- package/src/host/health/generation.ts +216 -0
- package/src/host/health/repair.ts +28 -7
- package/src/host/health/scan.ts +84 -27
- package/src/host/health/source-kind.ts +350 -0
- package/src/host/history/archive.ts +4 -1
- package/src/host/history/purge.ts +51 -4
- package/src/index.ts +83 -55
package/src/index.ts
CHANGED
|
@@ -26,20 +26,40 @@ import { purgeHistory } from './host/history/purge.ts'
|
|
|
26
26
|
import { buildProjectionOwnerIndex, createAttributor, defaultProfileNodeModules } from './host/health/attribution.ts'
|
|
27
27
|
import { HealthCache } from './host/health/cache.ts'
|
|
28
28
|
import { buildSessionReport, type SessionHealthReport } from './host/health/gates.ts'
|
|
29
|
+
import { decodeSessionLogFile } from './host/health/decode.ts'
|
|
29
30
|
import { assessRepair, prescribe, quarantineProjectionCache } from './host/health/repair.ts'
|
|
30
|
-
import { countCorpus,
|
|
31
|
+
import { countCorpus, findSession, scanSessions } from './host/health/scan.ts'
|
|
32
|
+
import { gateSourceKind, migrateSessionSourceKind, readSourceKindFacts } from './host/health/source-kind.ts'
|
|
31
33
|
|
|
32
34
|
export { DEFAULT_CONFIG, STEWARD_API_PREFIX, STEWARD_SETTINGS_NAMESPACE } from './config.ts'
|
|
33
35
|
export type { StewardConfig } from './config.ts'
|
|
34
36
|
export { readArchiveSet, pruneArchiveFile, editWorkspaceDocument } from './host/history/archive-source.ts'
|
|
35
37
|
export { listHistory, pruneHistory } from './host/history/archive.ts'
|
|
36
|
-
export { purgeHistory, locateSessionUsage, indexSessionDirs, isSafeChild, dirSize, sessionsRootFor, projCacheRootFor } from './host/history/purge.ts'
|
|
37
|
-
export { buildSessionReport, gateColdRead, gateLogIntegrity, gateLosslessJson, gateProjectionCache, readProjectionCache, readTailFacts } from './host/health/gates.ts'
|
|
38
|
+
export { purgeHistory, locateSessionUsage, indexSessionDirs, isSafeChild, dirSize, sessionsRootFor, projCacheRootFor, isSourceMigrateBackupName, backupFilesIn } from './host/history/purge.ts'
|
|
39
|
+
export { buildSessionReport, gateColdRead, gateGeneration, gateLogIntegrity, gateLosslessJson, gateProjectionCache, readProjectionCache, readTailFacts } from './host/health/gates.ts'
|
|
40
|
+
export { gateSourceKind, migrateSessionSourceKind, migrateLegacySource, readSourceKindFacts, SOURCE_MIGRATE_BACKUP_SUFFIX, V4_HOST_MIN } from './host/health/source-kind.ts'
|
|
38
41
|
export { firstLosslessViolation, isLossless } from './host/health/lossless.ts'
|
|
39
42
|
export { decodeSessionLogBytes, decodeSessionLogFile, scanZstdFrames } from './host/health/decode.ts'
|
|
43
|
+
export {
|
|
44
|
+
classifyGenerationFilename,
|
|
45
|
+
generationLogFilename,
|
|
46
|
+
isMigrationStagingFilename,
|
|
47
|
+
latestArtifactMtime,
|
|
48
|
+
parseGenerationLogFilename,
|
|
49
|
+
readSessionGenerations,
|
|
50
|
+
sessionPriority,
|
|
51
|
+
} from './host/health/generation.ts'
|
|
52
|
+
export type {
|
|
53
|
+
GenerationArtifact,
|
|
54
|
+
LogArtifact,
|
|
55
|
+
LogCompression,
|
|
56
|
+
SessionGenerations,
|
|
57
|
+
SessionPriority,
|
|
58
|
+
} from './host/health/generation.ts'
|
|
40
59
|
export { buildProjectionOwnerIndex, createAttributor } from './host/health/attribution.ts'
|
|
41
60
|
export { prescribe, quarantineProjectionCache } from './host/health/repair.ts'
|
|
42
|
-
export { countCorpus, discoverSessions, findSessionLog, scanSessions } from './host/health/scan.ts'
|
|
61
|
+
export { countCorpus, discoverSessions, findSession, findSessionLog, scanSessions } from './host/health/scan.ts'
|
|
62
|
+
export type { DiscoveredSession } from './host/health/scan.ts'
|
|
43
63
|
export { HealthCache } from './host/health/cache.ts'
|
|
44
64
|
export type { HealthCacheEntry } from './host/health/cache.ts'
|
|
45
65
|
export { assessRepair } from './host/health/repair.ts'
|
|
@@ -62,51 +82,26 @@ interface StewardWebRuntime {
|
|
|
62
82
|
trustedHosts: readonly string[]
|
|
63
83
|
}
|
|
64
84
|
|
|
65
|
-
/**
|
|
66
|
-
interface
|
|
67
|
-
get():
|
|
68
|
-
watch(callback: () => void): () => void
|
|
85
|
+
/** Live reference the 0.1.7 loader hands `apply` for `.volatile()` config fields. */
|
|
86
|
+
interface VolatileRef<T> {
|
|
87
|
+
get(): T
|
|
69
88
|
}
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
}) => void): void
|
|
89
|
+
|
|
90
|
+
/** Resolve one possibly-volatile field: a live ref on 0.1.7+, a plain value otherwise. */
|
|
91
|
+
function readVolatileValue<T>(value: T | VolatileRef<T> | undefined): T | undefined {
|
|
92
|
+
if (value !== null && typeof value === 'object' && typeof (value as VolatileRef<T>).get === 'function') {
|
|
93
|
+
return (value as VolatileRef<T>).get()
|
|
94
|
+
}
|
|
95
|
+
return value as T | undefined
|
|
78
96
|
}
|
|
79
97
|
|
|
80
|
-
/** 运行时配置 schema(与 src/config.ts 的形状保持一致)。 */
|
|
81
|
-
const Config = z.object({
|
|
82
|
-
enabled: z.boolean().default(true),
|
|
83
|
-
historyFiles: z.boolean().default(true),
|
|
84
|
-
healthCheck: z.boolean().default(true),
|
|
98
|
+
/** 运行时配置 schema(与 src/config.ts 的形状保持一致)。0.1.7:volatile 字段即设置表单。 */
|
|
99
|
+
export const Config = z.object({
|
|
100
|
+
enabled: z.boolean().default(true).volatile(),
|
|
101
|
+
historyFiles: z.boolean().default(true).volatile(),
|
|
102
|
+
healthCheck: z.boolean().default(true).volatile(),
|
|
85
103
|
})
|
|
86
104
|
|
|
87
|
-
/**
|
|
88
|
-
* 官方 `installSettingsSection` 的内联等价:通过 settings 服务注册命名空间、
|
|
89
|
-
* 以组合入口作为 `base` 层、并保持运行时来源实时(与 toggle / thinking-levels 同范式)。
|
|
90
|
-
*/
|
|
91
|
-
function installSettingsSection<T>(
|
|
92
|
-
ctx: Context,
|
|
93
|
-
ns: string,
|
|
94
|
-
schema: unknown,
|
|
95
|
-
entry: T,
|
|
96
|
-
hooks: { setSource: (source: () => T) => void; onChange: () => void },
|
|
97
|
-
): void {
|
|
98
|
-
;(ctx as unknown as SettingsAwareCtx).inject(['settings'], (sctx) => {
|
|
99
|
-
const scope = sctx.settings.register(ns, schema, { base: entry })
|
|
100
|
-
hooks.setSource(() => scope.get() as T)
|
|
101
|
-
hooks.onChange()
|
|
102
|
-
sctx.effect(() => () => {
|
|
103
|
-
hooks.setSource(() => entry)
|
|
104
|
-
hooks.onChange()
|
|
105
|
-
})
|
|
106
|
-
scope.watch(() => hooks.onChange())
|
|
107
|
-
})
|
|
108
|
-
}
|
|
109
|
-
|
|
110
105
|
/** 单次请求体的上限(防御无界读取)。 */
|
|
111
106
|
const MAX_BODY_BYTES = 16 << 20
|
|
112
107
|
|
|
@@ -228,6 +223,7 @@ export const HEALTH_METHODS = [
|
|
|
228
223
|
'session-health-scan',
|
|
229
224
|
'session-health-session',
|
|
230
225
|
'session-health-repair',
|
|
226
|
+
'session-health-source-migrate',
|
|
231
227
|
] as const
|
|
232
228
|
|
|
233
229
|
/** 依据开关判定某方法是否启用。 */
|
|
@@ -335,14 +331,17 @@ export async function handleMethod(
|
|
|
335
331
|
const request = (payload ?? {}) as { sessionId?: unknown }
|
|
336
332
|
const sessionId = asSessionId(request.sessionId)
|
|
337
333
|
if (sessionId === undefined) return { ok: false, error: '缺少合法的 sessionId' }
|
|
338
|
-
|
|
339
|
-
|
|
334
|
+
// 按代次定位:会话存在但尚未发布当前代时 logPath 为 undefined,此时仍要出报告
|
|
335
|
+
// (generation / log-integrity 两门如实报出),不能笼统回「未找到会话日志」。
|
|
336
|
+
const session = findSession(sessionId, runtime.dshHome)
|
|
337
|
+
if (session === undefined) return { ok: false, error: `未找到会话日志:${sessionId}` }
|
|
340
338
|
|
|
341
339
|
const projectionState = runtime.projectionStateFor(sessionId)
|
|
342
340
|
const reportFor = (): SessionHealthReport => buildSessionReport({
|
|
343
341
|
sessionId,
|
|
344
342
|
dshHome: runtime.dshHome,
|
|
345
|
-
logPath,
|
|
343
|
+
...(session.logPath === undefined ? {} : { logPath: session.logPath }),
|
|
344
|
+
generations: session.generations,
|
|
346
345
|
...(projectionState === undefined ? {} : { projectionState }),
|
|
347
346
|
attribute: runtime.attribute,
|
|
348
347
|
})
|
|
@@ -355,6 +354,32 @@ export async function handleMethod(
|
|
|
355
354
|
return { ok: true, report, prescriptions: prescribe(report, runtime.dshHome) }
|
|
356
355
|
}
|
|
357
356
|
|
|
357
|
+
// session-health-source-migrate:把 v4 日志里的旧署名行(kind:'plugin' + plugin 字段)
|
|
358
|
+
// 转换为 producer-owned kind。这是「禁止改写会话日志」红线的唯一显式例外:
|
|
359
|
+
// 只动 source 署名字段、先整文件备份、v3 及更早版本线拒绝执行(见 source-kind.ts 的版本依赖表)。
|
|
360
|
+
if (method === 'session-health-source-migrate') {
|
|
361
|
+
if (session.logPath === undefined) {
|
|
362
|
+
return { ok: false, error: '会话尚未发布当前代日志,无从转换(先用会话代次工具发布)' }
|
|
363
|
+
}
|
|
364
|
+
const log = decodeSessionLogFile(session.logPath)
|
|
365
|
+
const outcome = migrateSessionSourceKind(sessionId, session.logPath, log, runtime.dshHome)
|
|
366
|
+
// 转换后重出报告:source-kind 门应转 ok;失败时报告原样(便于面板对照)。
|
|
367
|
+
const after = buildSessionReport({
|
|
368
|
+
sessionId,
|
|
369
|
+
dshHome: runtime.dshHome,
|
|
370
|
+
logPath: session.logPath,
|
|
371
|
+
generations: session.generations,
|
|
372
|
+
...(projectionState === undefined ? {} : { projectionState }),
|
|
373
|
+
attribute: runtime.attribute,
|
|
374
|
+
})
|
|
375
|
+
runtime.cache?.patch(after)
|
|
376
|
+
runtime.log(
|
|
377
|
+
`source-kind migrate ${sessionId}: ok=${outcome.ok} changed=${outcome.changedRows ?? 0}` +
|
|
378
|
+
(outcome.error === undefined ? '' : ` error=${outcome.error}`),
|
|
379
|
+
)
|
|
380
|
+
return { ok: outcome.ok, outcome, after, report: after, error: outcome.error }
|
|
381
|
+
}
|
|
382
|
+
|
|
358
383
|
// session-health-repair:出院前的可逆处置 + before/after 对照 + 结果定性
|
|
359
384
|
const before = reportFor()
|
|
360
385
|
if (before.level === 'ok') {
|
|
@@ -371,7 +396,7 @@ export async function handleMethod(
|
|
|
371
396
|
verdict: clean.verdict,
|
|
372
397
|
explanation: clean.explanation,
|
|
373
398
|
residual: clean.residual,
|
|
374
|
-
prescriptions: ['#
|
|
399
|
+
prescriptions: ['# 全部检查通过:无需处置'],
|
|
375
400
|
}
|
|
376
401
|
}
|
|
377
402
|
const repair = quarantineProjectionCache(sessionId, runtime.dshHome)
|
|
@@ -398,14 +423,17 @@ export async function handleMethod(
|
|
|
398
423
|
}
|
|
399
424
|
|
|
400
425
|
/**
|
|
401
|
-
*
|
|
402
|
-
* @param ctx - host 插件上下文(webServer / webRuntime / 可选
|
|
426
|
+
* 插件主体:装配运行时、挂载 fenced 路由。
|
|
427
|
+
* @param ctx - host 插件上下文(webServer / webRuntime / 可选 sessionQuery、sessions、sessionProjections)。
|
|
428
|
+
* @param config - 组合条目(0.1.7:`.volatile()` 字段为 live ref)。
|
|
403
429
|
*/
|
|
404
|
-
export function apply(ctx: Context): void {
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
430
|
+
export function apply(ctx: Context, config: Partial<StewardConfig> = {}): void {
|
|
431
|
+
// 0.1.7:volatile 字段每次读取解引出最新快照(开关即时生效),不再有任何
|
|
432
|
+
// settings 注册调用。
|
|
433
|
+
const current = (): Required<StewardConfig> => ({
|
|
434
|
+
enabled: readVolatileValue(config.enabled) ?? DEFAULT_CONFIG.enabled,
|
|
435
|
+
historyFiles: readVolatileValue(config.historyFiles) ?? DEFAULT_CONFIG.historyFiles,
|
|
436
|
+
healthCheck: readVolatileValue(config.healthCheck) ?? DEFAULT_CONFIG.healthCheck,
|
|
409
437
|
})
|
|
410
438
|
|
|
411
439
|
const log = (message: string): void => {
|