dsh-manage-session 0.3.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/src/index.ts CHANGED
@@ -26,15 +26,18 @@ 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
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'
38
+ export { purgeHistory, locateSessionUsage, indexSessionDirs, isSafeChild, dirSize, sessionsRootFor, projCacheRootFor, isSourceMigrateBackupName, backupFilesIn } from './host/history/purge.ts'
37
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'
40
43
  export {
@@ -79,51 +82,26 @@ interface StewardWebRuntime {
79
82
  trustedHosts: readonly string[]
80
83
  }
81
84
 
82
- /** settings 服务面(结构化镜像)。 */
83
- interface SettingsScopeLike {
84
- get(): unknown
85
- 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
86
88
  }
87
- interface SettingsServiceLike {
88
- register(ns: string, schema: unknown, options?: { base?: unknown }): SettingsScopeLike
89
- }
90
- interface SettingsAwareCtx {
91
- inject(deps: readonly string[], fn: (sctx: {
92
- settings: SettingsServiceLike
93
- effect(cleanup: () => (() => void) | void, label?: string): void
94
- }) => 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
95
96
  }
96
97
 
97
- /** 运行时配置 schema(与 src/config.ts 的形状保持一致)。 */
98
- const Config = z.object({
99
- enabled: z.boolean().default(true),
100
- historyFiles: z.boolean().default(true),
101
- 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(),
102
103
  })
103
104
 
104
- /**
105
- * 官方 `installSettingsSection` 的内联等价:通过 settings 服务注册命名空间、
106
- * 以组合入口作为 `base` 层、并保持运行时来源实时(与 toggle / thinking-levels 同范式)。
107
- */
108
- function installSettingsSection<T>(
109
- ctx: Context,
110
- ns: string,
111
- schema: unknown,
112
- entry: T,
113
- hooks: { setSource: (source: () => T) => void; onChange: () => void },
114
- ): void {
115
- ;(ctx as unknown as SettingsAwareCtx).inject(['settings'], (sctx) => {
116
- const scope = sctx.settings.register(ns, schema, { base: entry })
117
- hooks.setSource(() => scope.get() as T)
118
- hooks.onChange()
119
- sctx.effect(() => () => {
120
- hooks.setSource(() => entry)
121
- hooks.onChange()
122
- })
123
- scope.watch(() => hooks.onChange())
124
- })
125
- }
126
-
127
105
  /** 单次请求体的上限(防御无界读取)。 */
128
106
  const MAX_BODY_BYTES = 16 << 20
129
107
 
@@ -245,6 +223,7 @@ export const HEALTH_METHODS = [
245
223
  'session-health-scan',
246
224
  'session-health-session',
247
225
  'session-health-repair',
226
+ 'session-health-source-migrate',
248
227
  ] as const
249
228
 
250
229
  /** 依据开关判定某方法是否启用。 */
@@ -375,6 +354,32 @@ export async function handleMethod(
375
354
  return { ok: true, report, prescriptions: prescribe(report, runtime.dshHome) }
376
355
  }
377
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
+
378
383
  // session-health-repair:出院前的可逆处置 + before/after 对照 + 结果定性
379
384
  const before = reportFor()
380
385
  if (before.level === 'ok') {
@@ -418,14 +423,17 @@ export async function handleMethod(
418
423
  }
419
424
 
420
425
  /**
421
- * 插件主体:注册设置命名空间、装配运行时、挂载 fenced 路由。
422
- * @param ctx - host 插件上下文(webServer / webRuntime / 可选 settings、sessionQuery、sessions、sessionProjections)。
426
+ * 插件主体:装配运行时、挂载 fenced 路由。
427
+ * @param ctx - host 插件上下文(webServer / webRuntime / 可选 sessionQuery、sessions、sessionProjections)。
428
+ * @param config - 组合条目(0.1.7:`.volatile()` 字段为 live ref)。
423
429
  */
424
- export function apply(ctx: Context): void {
425
- let current: () => Required<StewardConfig> = () => DEFAULT_CONFIG
426
- installSettingsSection(ctx, STEWARD_SETTINGS_NAMESPACE, Config, DEFAULT_CONFIG, {
427
- setSource: (source) => { current = () => ({ ...DEFAULT_CONFIG, ...(source() as Partial<StewardConfig>) }) },
428
- onChange: () => {},
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,
429
437
  })
430
438
 
431
439
  const log = (message: string): void => {