Merge remote-tracking branch 'origin/master' into jsonl-packed-chunk-rows

Conflicts: the four generated catalog docs (regenerated over merged sources),
session index.ts exports (keep chunk-rows exports + master's SessionSurface
re-export), stdio/acp demo config schema and persistence wiring (thread
packChunks through master's DEFAULT_PERSISTENCE_ROOT/UI shape), stdio README
config table, and the jsonl spec import line. The packed-chunk fixture also
gains the provenance field master made required on assistant/message.
This commit is contained in:
kingwl
2026-07-20 15:24:58 +08:00
1331 changed files with 74129 additions and 16289 deletions

View File

@@ -1,7 +1,8 @@
/**
* JSONL durable session-persistence backend. It stores a header and contiguous
* events in one append-only file per session, and delegates orchestration to
* {@link PersistenceCoordinator}.
* {@link PersistenceCoordinator}. Its side-effect-free locator returns the
* absolute per-session log target before materialization.
* @module @deepseek-ai/dsh-session-persistence-jsonl
*/
@@ -12,7 +13,7 @@ import { dirname, resolve } from 'node:path'
import { randomBytes } from 'node:crypto'
import {
SessionPersistence, PersistenceCoordinator,
type PersistenceBackend, type StoredPrefix,
type PersistenceBackend, type SessionLocation, type StoredPrefix,
} from '@deepseek-ai/dsh-session-persistence'
import type { SessionEvent, SessionId, SessionHeader } from '@deepseek-ai/dsh-session'
import {
@@ -67,6 +68,9 @@ export class SessionPersistenceJsonl extends SessionPersistence implements Persi
private packChunks: boolean
private coordinator: PersistenceCoordinator<number>
/** Runtime host platform used to decide whether directory sync is supported. */
readonly internals: { platform: NodeJS.Platform } = { platform: process.platform }
constructor(ctx: Context, public config: Config) {
super(ctx)
// Resolve once so later process.cwd() changes cannot split one backend across roots.
@@ -82,6 +86,11 @@ export class SessionPersistenceJsonl extends SessionPersistence implements Persi
/* jscpd:ignore-start */
// --- SessionPersistence service surface (delegated to the coordinator) ---
/** Resolve the absolute target path without touching the filesystem. */
locate(meta: SessionHeader): SessionLocation {
return { kind: 'jsonl', path: logPath(this.root, meta.cwd, meta.id) }
}
create(meta: SessionHeader): Promise<void> {
return this.coordinator.create(meta)
}
@@ -216,11 +225,18 @@ export class SessionPersistenceJsonl extends SessionPersistence implements Persi
}
}
/** fsync a directory so a just-created or published entry inside it is crash-durable. */
/** fsync a directory when the host exposes that durability primitive. */
private async syncDir(dir: string): Promise<void> {
const handle = await open(dir, 'r')
try {
await handle.sync()
try {
await handle.sync()
} catch (error: unknown) {
const code = (error as NodeJS.ErrnoException | null)?.code
// Node opens directories on Windows but its fsync binding rejects them.
// File-content fsync remains mandatory; only this unsupported primitive is skipped.
if (this.internals.platform !== 'win32' || code !== 'EPERM') throw error
}
} finally {
await handle.close()
}