Trim redundant source comments

This commit is contained in:
Turtle
2026-07-25 13:02:37 +08:00
parent f7b36bd36d
commit fac6c35e9a
83 changed files with 219 additions and 748 deletions

View File

@@ -161,11 +161,7 @@ function deepFreeze(value: unknown): void {
}
}
// ---- defineStore shell (slot terminal design §4) ----
// The type authority is ui-slots' store family (create(scopeKey?) and
// clearPersisted() included); this module houses only the engine-backed
// implementation. The one engine-side widening left: instances expose the
// raw engine store for framework/test surfaces.
// ui-slots owns the contract; this module supplies the engine implementation.
/** A live engine instance: the contract instance plus the raw engine store. */
export interface EngineStoreInstance<T, A extends ActionsDecl<T>> extends StoreInstance<T, A> {

View File

@@ -1,12 +1,7 @@
/**
* Browser half: the whole runtime contract surface (api-contracts v3 §4) —
* SlotsService (declaration ledger + renderer seam + store axis, built-in
* 'root'), SessionsService (list store + current selection + scope tree +
* object layer), and the cordis Context/Events merges. apply mounts
* ctx.slots + ctx.sessions and wires the connection stream loop into the
* object layer. A static-arrival entry: the web shell bundles this module
* and mounts it through the host graph (module loading lives in
* @deepseek-ai/dsh-client-modules, entry governance in the vendored Loader).
* Browser runtime services for slots, sessions, and connection-stream
* delivery. The web shell mounts this static client entry through the host
* plugin graph.
*/
import type { Context } from 'cordis'
import type { ConnectionHandle, SessionId } from '@deepseek-ai/dsh-client-connection/client'
@@ -17,15 +12,11 @@ import type { SessionListState } from './sessions/service.ts'
import type { ConversationSnapshot, RunningToolCall, ToolResultNode } from './sessions/conversation.ts'
export { SlotsService } from './slots.ts'
// RootOwnerProps rides the 'root' SlotMap row (both migrated here from
// ui-layout: the framework slot is declared by the framework package).
export type { RootOwnerProps } from './slots.ts'
export { SessionsService, scopeOf } from './sessions/service.ts'
export type { Session } from './sessions/session.ts'
export type { SessionBinding, SessionListState, SessionSummary } from './sessions/service.ts'
// The snapshot-store engine lives here since the store migration (the data
// layer owns its substrate; web-react is React glue only). The './client'
// main export is the single serving door — no store subpath.
// Runtime owns the snapshot store; web-react only binds it to React.
export { createSnapshotStore, defineStore, shallowEqual } from './contract/store.ts'
export type {
EngineStoreHandle, EngineStoreInstance, ObservableSnapshot, SnapshotStore,
@@ -35,21 +26,11 @@ export type {
RunningToolCall, SteeringMessageNode,
ToolResultNode, UnknownSurfaceNode, UserMessageNode,
} from './sessions/conversation.ts'
// PendingWait is a value export: tests construct fixture waits directly.
export { PendingWait } from './sessions/pending.ts'
export type { PendingInteraction, PendingKind, PendingPayloads } from './sessions/pending.ts'
export type { SessionId } from '@deepseek-ai/dsh-client-connection/client'
// ---- Narrowed aliases (the single narrowing point of the slot type chain:
// ui-slots/web-react stay generic and dependency-inverted; the client-tree
// concrete types live here, where their subjects live) ----
/**
* The client cordis context face: the base Context plus the service keys
* this package's declaration merge contributes (slots/sessions/loader) and
* every later plugin's merge. A plain alias — the merges land on Context
* itself inside the client program; the name marks intent at consumer seams.
*/
/** Client-side Cordis context after declaration merging. */
export type ClientContext = Context
/** The conversation-snapshot selector hook (ConvViewProps/ToolRowProps take this). */
@@ -69,14 +50,12 @@ declare module '@deepseek-ai/dsh-client-ui-slots' {
* every session-scope slot component receives these from the framework.
*/
interface SessionStandardProps {
/** Selector hook over this session's conversation snapshot. */
useSession: SnapshotSelectorHook<ConversationSnapshot>
/** The framework-resolved session id (owners never pass it). */
sessionId: SessionId
}
/** Global standard kit, real members: the session-list hook every slot component receives. */
/** Props injected into every global slot component. */
interface GlobalStandardProps {
/** Selector hook over the session list snapshot (`current` included — the arbitrated selection seat). */
useSessions: SnapshotSelectorHook<SessionListState>
}
}
@@ -99,9 +78,8 @@ declare module 'cordis' {
/** Required services: the wire handle mounted by the connection plugin. */
export const inject = ['connection']
/**
* Client plugin body: mount slots + sessions, start the stream loop.
* @param ctx - client cordis context.
/** Mounts the browser runtime services and connection stream.
* @param ctx - Client Cordis context.
*/
export function apply(ctx: Context): void {
ctx.plugin(SlotsService)

View File

@@ -24,10 +24,10 @@ export interface CallIndexEntry {
callView: ToolCallView | null
}
/** Non-surface-eligible sentinel event (safely skipped by surfaceOpOf's undefined branch).
* 'noop/padding' is not a real event type on purpose: a genuine type with fake data would
* surface as garbage the day anyone adds handling for it (design §D.1; the cast is the one
* place a synthetic event enters the window). */
/** Non-surface sentinel used to preserve paged-window sequence offsets.
* `noop/padding` is deliberately not a real event type, so it cannot acquire
* surface behavior; this cast is the only synthetic event entry point.
*/
function paddingEvent(seq: number): SessionEvent {
return { type: 'noop/padding', seq, time: 0, data: {} } as unknown as SessionEvent
}

View File

@@ -291,8 +291,7 @@ export class SessionsService {
fiber,
ctx,
binding: { sessionId: id, session, ctx },
// Bare source form (store migration): the Session object IS the
// observable; the React side binds the useSession hook per cell.
// Session is the observable; React binds a selector hook at its own seam.
cell: { sessionId: id, session },
}
this.scopes.set(id, record)

View File

@@ -1,7 +1,4 @@
// Session: wraps every contract call that needs a sessionId + all conversation state for this
// session (design §A.2/§A.9/§D.2/§D.3). Instances are resident (ruling 2): never destroyed once
// created, they keep consuming mux frames in the background; React connects directly via
// subscribe/getSnapshot.
// Sessions remain resident after creation so they continue consuming mux frames off-screen.
import type { ContentBlock } from '@deepseek-ai/dsh-llm/types'
import type { SessionEvent } from '@deepseek-ai/dsh-session/types'
@@ -22,14 +19,12 @@ import { FoldAdapter } from './fold-adapter.ts'
import { Notifier } from './notifier.ts'
import { PartialAccumulator } from './partial.ts'
/** Messages per page (F.4 ledger: promote to Config at graduation; every call site references this constant). */
/** Messages requested per history page. */
export const PAGE_MESSAGES = 50
/**
* Per-session state owner: event window + fold + partial, snapshot out via
* subscribe/getSnapshot (see the web client architecture RFC). Bare source
* only (store migration): the React machinery binds the per-cell useSession
* hook at its own seam — no selector hook member lives on the data layer.
* Owns a session's event window, derived conversation state, and observable
* snapshot. React bindings remain outside this data layer.
*/
export class Session implements ObservableSnapshot<ConversationSnapshot> {
// ---- Window and derived state (all private; the snapshot is the only read surface) ----
@@ -54,8 +49,7 @@ export class Session implements ObservableSnapshot<ConversationSnapshot> {
* Derived from window events (turn/end sweep) — rebuilt by rebuildDerivedFromWindow like partial/openCalls. */
private frozenNodes: ConversationNode[] = []
private pending = new Map<string, PendingInteraction>()
// Revision counters + caches backing the snapshot's reference-stability contract (§A.9.4/§C.2,
// audit S5): buildSnapshot reuses the previous array when the revision is unchanged, so
// Revision counters preserve array identity when derived content is unchanged, so
// React.memo children survive unrelated snapshot swaps (chunk storms must not re-render every
// tool card and pending card). Mutation sites bump the matching revision. partial needs no
// counter — PartialAccumulator.toPartial already returns a cached reference when unchanged.
@@ -69,9 +63,9 @@ export class Session implements ObservableSnapshot<ConversationSnapshot> {
private removed = false
private promptError: PromptError | null = null
private lastAgentError: string | null = null
/** Buffer for live events arriving while open/resync is in flight (stitched by seq once history lands, §D.3). */
/** Live events buffered during open/resync and stitched by sequence once history lands. */
private liveBuffer: { event: SessionEvent; view: ToolEventView | undefined }[] = []
/** Gap-repair (resync-lite) in flight: acceptLiveEvent detours to liveBuffer until the tail page lands (audit S3). */
/** Gap repair in flight; live events detour to the buffer until the tail page lands. */
private stitching = false
/** subscribed.lastSeq baseline (gap detection; null when no subscribed frame arrived — degrade to the liveBuffer dedup path). */
private subscribedLastSeq: number | null = null
@@ -292,8 +286,7 @@ export class Session implements ObservableSnapshot<ConversationSnapshot> {
this.notifier.markDirty()
}
/** Instance-eviction hook, reserved no-op (design §F.6): resident instances are never destroyed
* in v1; an eviction policy lands here (unsubscribe, drop buffers) without touching call sites. */
/** No-op because session instances remain resident. */
dispose(): void {}
// ---- 私有 ----

View File

@@ -1,11 +1,4 @@
/**
* Runtime plugin, node half. The implementation lives entirely in the client
* half (src/client/ — SlotsService, SessionsService + object layer, and the
* shell-held ClientLoader under ./loader); consumers import the /client or
* /loader subpaths. The empty apply exists so the plugin appears in the host
* Loader (lifecycle governance + dshClient discovery). Contract:
* api-contracts v3 section 4.
*/
/** Host loader entry for the browser runtime exported from `./client` and `./loader`. */
/** Host plugin body — no host-side behavior for the runtime plugin. */
export function apply(_ctx: unknown): void {}

View File

@@ -187,8 +187,7 @@ describe('cell (render-layer session kit)', () => {
const cell = b.svc.cell('s1')
expect(cell).toBeDefined()
expect(cell?.sessionId).toBe('s1')
// Bare-source form (store migration): the cell carries the Session
// observable itself; hook binding happens in the React machinery.
// Hook binding happens in React; the cell carries the observable itself.
expect(cell?.session).toBe(b.svc.manager.get(sid('s1')))
expect(b.svc.cell('s1')).toBe(cell)
expect(b.svc.cell('ghost')).toBeUndefined()