feat: dsh-session-projection seam package (ctx.sessionProjections registry)
This commit is contained in:
@@ -35,6 +35,7 @@ Packages live at `packages/<group>/<pkg>/`; groups are containers, while names r
|
|||||||
| [`cordis/`](cordis/README.md) | Self-referential runtime toolset: inspect the live runtime's plugins and services, mount/unmount model-written plugins ([design](../.agents/notes/implemented/feature/2026-07-08-self-referential-cordis-toolset.md)) | Product — stable surface |
|
| [`cordis/`](cordis/README.md) | Self-referential runtime toolset: inspect the live runtime's plugins and services, mount/unmount model-written plugins ([design](../.agents/notes/implemented/feature/2026-07-08-self-referential-cordis-toolset.md)) | Product — stable surface |
|
||||||
| [`hooks/`](hooks/README.md) | Hook bridges + the shared Claude Code / Codex wire-protocol library | Product — stable surface |
|
| [`hooks/`](hooks/README.md) | Hook bridges + the shared Claude Code / Codex wire-protocol library | Product — stable surface |
|
||||||
| [`session-persistence/`](session-persistence/README.md) | Persistence capability family: the seam + JSONL/SQLite backends | Product — stable surface |
|
| [`session-persistence/`](session-persistence/README.md) | Persistence capability family: the seam + JSONL/SQLite backends | Product — stable surface |
|
||||||
|
| [`session-projection/`](session-projection/README.md) | Session-projection seam: domain host plugins serve whole current values of log-derived per-session state to client carriers | Product — stable surface |
|
||||||
| [`session-query/`](session-query/README.md) | Session retrieval family: logical corpus, bounded reads, lineage, event relationships, semantic filtering, and SQLite full-text search | Product — stable surface |
|
| [`session-query/`](session-query/README.md) | Session retrieval family: logical corpus, bounded reads, lineage, event relationships, semantic filtering, and SQLite full-text search | Product — stable surface |
|
||||||
| [`session-title/`](session-title/README.md) | Log-backed session titles: fallback service, shared LLM policy, and opt-in providers | Product — stable surface |
|
| [`session-title/`](session-title/README.md) | Log-backed session titles: fallback service, shared LLM policy, and opt-in providers | Product — stable surface |
|
||||||
| [`telemetry/`](telemetry/README.md) | Session reporting: capture/redact seam, OTel backend | Product — stable surface |
|
| [`telemetry/`](telemetry/README.md) | Session reporting: capture/redact seam, OTel backend | Product — stable surface |
|
||||||
|
|||||||
@@ -35,6 +35,7 @@
|
|||||||
| [`cordis/`](cordis/README.md) | 自指运行时工具集:检查实时运行时的插件与服务,挂载/卸载模型所写插件([设计](../.agents/notes/implemented/feature/2026-07-08-self-referential-cordis-toolset.md)) | 产品:稳定表面 |
|
| [`cordis/`](cordis/README.md) | 自指运行时工具集:检查实时运行时的插件与服务,挂载/卸载模型所写插件([设计](../.agents/notes/implemented/feature/2026-07-08-self-referential-cordis-toolset.md)) | 产品:稳定表面 |
|
||||||
| [`hooks/`](hooks/README.md) | 钩子桥接 + 共享 Claude Code/Codex 协议格式库 | 产品:稳定表面 |
|
| [`hooks/`](hooks/README.md) | 钩子桥接 + 共享 Claude Code/Codex 协议格式库 | 产品:稳定表面 |
|
||||||
| [`session-persistence/`](session-persistence/README.md) | 持久化能力系列:seam + JSONL/SQLite 后端 | 产品:稳定表面 |
|
| [`session-persistence/`](session-persistence/README.md) | 持久化能力系列:seam + JSONL/SQLite 后端 | 产品:稳定表面 |
|
||||||
|
| [`session-projection/`](session-projection/README.md) | 会话投影缝:域 host 插件向客户端载体供给日志衍生的每会话状态完整当前值 | 产品:稳定表面 |
|
||||||
| [`session-query/`](session-query/README.md) | 会话检索系列:逻辑语料库、有界读取、血缘、事件关系、语义过滤和 SQLite 全文搜索 | 产品:稳定表面 |
|
| [`session-query/`](session-query/README.md) | 会话检索系列:逻辑语料库、有界读取、血缘、事件关系、语义过滤和 SQLite 全文搜索 | 产品:稳定表面 |
|
||||||
| [`session-title/`](session-title/README.md) | 日志支撑的会话标题:回退服务、共享 LLM 策略和选用提供方 | 产品:稳定表面 |
|
| [`session-title/`](session-title/README.md) | 日志支撑的会话标题:回退服务、共享 LLM 策略和选用提供方 | 产品:稳定表面 |
|
||||||
| [`telemetry/`](telemetry/README.md) | 会话上报:捕获/脱敏 seam、OTel 后端 | 产品:稳定表面 |
|
| [`telemetry/`](telemetry/README.md) | 会话上报:捕获/脱敏 seam、OTel 后端 | 产品:稳定表面 |
|
||||||
|
|||||||
7
packages/session-projection/README.md
Normal file
7
packages/session-projection/README.md
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
# session-projection/
|
||||||
|
|
||||||
|
Session-projection capability family: the seam through which domain host plugins serve whole current values of log-derived per-session state to client carriers.
|
||||||
|
|
||||||
|
| Package | ctx key | Role |
|
||||||
|
|---|---|---|
|
||||||
|
| [`session-projection`](session-projection/README.md) | `sessionProjections` | The interface package: the merge-extensible `SessionProjectionMap` type table, the `ProjectionProvider` contract, and the provider registry carriers walk synchronously |
|
||||||
39
packages/session-projection/session-projection/README.md
Normal file
39
packages/session-projection/session-projection/README.md
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
# @deepseek-ai/dsh-session-projection
|
||||||
|
|
||||||
|
Session-projection seam. It owns `ctx.sessionProjections`, the registry through which a domain host plugin serves the whole current value of its log-derived per-session state, and through which a carrier (the api-proxy history tail page today; TUI/ACP/headless consumers later) reads every registered value in one synchronous, seq-consistent cut. Design authority: the [session-projection RFC](../../../.agents/notes/proposed/architecture/2026-07-27-session-projection-and-command-log.md).
|
||||||
|
|
||||||
|
## Service: `SessionProjectionRegistry` (ctx key: `sessionProjections`)
|
||||||
|
|
||||||
|
### Public API
|
||||||
|
|
||||||
|
- `ctx.sessionProjections.register(provider): () => void` Register one domain's provider. Duplicate keys throw; the registration is an effect on the calling fiber, so an unloaded domain plugin's key disappears from subsequent walks (clients read that as capability absence).
|
||||||
|
- `ctx.sessionProjections.entries(): AnyProjectionProvider[]` Snapshot the registered providers in registration order — the carrier walk surface.
|
||||||
|
|
||||||
|
### Key Types
|
||||||
|
|
||||||
|
- `SessionProjectionMap` — the single merge-extensible type table for the whole chain (host provider, wire block, client cell, React hook). Values are wire-JSON whole values; rendering belongs to the slot system, never this layer.
|
||||||
|
- `ProjectionProvider<K>` — `{ key, schema, get(agent) }`. `schema` validates the payload before it leaves the host; `get` returns the current whole value and MUST be synchronous.
|
||||||
|
|
||||||
|
## Contract
|
||||||
|
|
||||||
|
- **Whole-value rule (load-bearing).** A state-carrying log event MUST carry the complete post-change state, never a delta, so the client fold is last-wins by seq. A future domain logging deltas breaks last-wins silently — do not.
|
||||||
|
- **Synchronous `get`.** Carriers read `session.seq` and every provider value with no await between them; that is what makes `asOfSeq` one consistent cut across all keys. An accidentally-async `get` returns a Promise, which fails the carrier-side `schema.parse` loudly.
|
||||||
|
- **Full-log view.** `get` runs against the host's full in-memory log (`agent.session.events`); pagination exists only in the history slice served to clients. A last-wins domain may backscan (first hit from the tail terminates); an expensive fold keeps an incremental cache keyed by observed seq.
|
||||||
|
- **Optional seam.** Domain plugins register under `ctx.inject(['sessionProjections'], …)` so headless assemblies without the registry stay unaffected; carriers use `ctx.get('sessionProjections')` and omit the block entirely when the registry is absent.
|
||||||
|
|
||||||
|
## Role
|
||||||
|
|
||||||
|
This is the interface package of the capability-seam split: domain host plugins (e.g. `dsh-tool-todo`) contribute providers, carriers (`dsh-host-apiproxy`) consume the walk surface, and neither knows the other.
|
||||||
|
|
||||||
|
## Model Experience
|
||||||
|
|
||||||
|
None, as the registry only serves client-facing read models of already-logged session state and touches no prompt, message, schema, stream, or tool result.
|
||||||
|
|
||||||
|
#### KV Cache effect
|
||||||
|
|
||||||
|
None; projections never assemble or send provider requests.
|
||||||
|
|
||||||
|
## Known Limitations and Deferred Work
|
||||||
|
|
||||||
|
- **Every tail page carries every registered key** — there is no per-key opt-out or lazy-key request shape yet; acceptable while values are UI-scale whole states (a todo list, a goal snapshot), revisit if a domain's value grows large.
|
||||||
|
- **Synchronous-`get` discipline is only partially mechanical** — the carrier's `schema.parse` rejects a returned Promise, but a provider that blocks or reads torn non-session state is a review concern; the invariant companion documents why no runtime check exists.
|
||||||
42
packages/session-projection/session-projection/package.json
Normal file
42
packages/session-projection/session-projection/package.json
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
{
|
||||||
|
"name": "@deepseek-ai/dsh-session-projection",
|
||||||
|
"description": "Session-projection seam: the merge-extensible projection type table, the provider contract, and the ctx.sessionProjections registry serving whole current values of log-derived per-session state",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"private": true,
|
||||||
|
"type": "module",
|
||||||
|
"main": "lib/index.js",
|
||||||
|
"types": "lib/types/index.d.ts",
|
||||||
|
"exports": {
|
||||||
|
".": {
|
||||||
|
"types": "./lib/types/index.d.ts",
|
||||||
|
"default": "./lib/index.js"
|
||||||
|
},
|
||||||
|
"./invariant": {
|
||||||
|
"types": "./lib/types/invariant.d.ts",
|
||||||
|
"default": "./lib/invariant.js"
|
||||||
|
},
|
||||||
|
"./src/*": "./src/*",
|
||||||
|
"./package.json": "./package.json"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"lib/index.js",
|
||||||
|
"lib/invariant.js",
|
||||||
|
"lib/types/**/*.d.ts",
|
||||||
|
"lib/types/**/*.d.ts.map",
|
||||||
|
"src"
|
||||||
|
],
|
||||||
|
"license": "BSD-3-Clause",
|
||||||
|
"dependencies": {
|
||||||
|
"zod": "^4.4.3"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@deepseek-ai/dsh-agent": "^0.0.1",
|
||||||
|
"@deepseek-ai/dsh-invariants": "^0.0.1",
|
||||||
|
"cordis": "^4.0.0-rc.7"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@deepseek-ai/dsh-agent": "workspace:^",
|
||||||
|
"@deepseek-ai/dsh-invariants": "workspace:^",
|
||||||
|
"cordis": "^4.0.0-rc.7"
|
||||||
|
}
|
||||||
|
}
|
||||||
112
packages/session-projection/session-projection/src/index.ts
Normal file
112
packages/session-projection/session-projection/src/index.ts
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
/**
|
||||||
|
* Session-projection seam: the merge-extensible `SessionProjectionMap` type
|
||||||
|
* table, the `ProjectionProvider` contract, and the `ctx.sessionProjections`
|
||||||
|
* registry. Domain host plugins contribute whole current values of
|
||||||
|
* log-derived per-session state; carriers (api-proxy history tail page, and
|
||||||
|
* future TUI/ACP consumers) walk the registry synchronously so every key and
|
||||||
|
* the accompanying `asOfSeq` form one consistent cut. Neither side knows the
|
||||||
|
* other (capability-seam three-way split).
|
||||||
|
*
|
||||||
|
* Whole-value rule (load-bearing): a state-carrying log event MUST carry the
|
||||||
|
* complete post-change state, never a delta, so the client-side fold is
|
||||||
|
* last-wins by seq. See the session-projection RFC
|
||||||
|
* (.agents/notes/proposed/architecture/2026-07-27-session-projection-and-command-log.md).
|
||||||
|
*
|
||||||
|
* @module @deepseek-ai/dsh-session-projection
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Context, Service } from 'cordis'
|
||||||
|
import type { ZodType } from 'zod'
|
||||||
|
import type { Agent } from '@deepseek-ai/dsh-agent'
|
||||||
|
|
||||||
|
declare module 'cordis' {
|
||||||
|
interface Context {
|
||||||
|
sessionProjections: SessionProjectionRegistry
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The single projection type table for the whole chain (host provider, wire
|
||||||
|
* block, client cell, React hook). Domain packages merge their key here via
|
||||||
|
* declaration merging; values are wire-JSON whole values. How a value is
|
||||||
|
* rendered is the slot system's business, never this layer's.
|
||||||
|
*/
|
||||||
|
export interface SessionProjectionMap {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* One domain's host-side contribution: the current whole value of its
|
||||||
|
* log-derived per-session state.
|
||||||
|
*/
|
||||||
|
export interface ProjectionProvider<K extends keyof SessionProjectionMap> {
|
||||||
|
/** The projection key this provider owns (its `SessionProjectionMap` entry). */
|
||||||
|
key: K
|
||||||
|
/** Validates the payload before it leaves the host (carriers parse each value through this). */
|
||||||
|
schema: ZodType<SessionProjectionMap[K]>
|
||||||
|
/**
|
||||||
|
* Return the current whole value for one agent's session. MUST be
|
||||||
|
* synchronous — carriers read `session.seq` and every provider value with no
|
||||||
|
* await between them, so an async provider would tear the consistency cut
|
||||||
|
* (an accidentally returned Promise fails the carrier's `schema.parse`
|
||||||
|
* loudly). Runs against the host's full in-memory log
|
||||||
|
* (`agent.session.events`): a last-wins domain may backscan from the tail; a
|
||||||
|
* domain with an expensive fold keeps an incremental cache keyed by observed
|
||||||
|
* seq.
|
||||||
|
* @param agent - the agent whose session state is projected.
|
||||||
|
* @returns the whole current value for this provider's key.
|
||||||
|
*/
|
||||||
|
get(agent: Agent): SessionProjectionMap[K]
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Union-typed view of a registered provider, as seen by carriers walking the table. */
|
||||||
|
export type AnyProjectionProvider = ProjectionProvider<keyof SessionProjectionMap>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* `ctx.sessionProjections`: the projection provider table. Registration is an
|
||||||
|
* effect (disposer rides the calling fiber): an unloaded domain plugin's key
|
||||||
|
* disappears from subsequent walks and clients read it as capability absence.
|
||||||
|
* Duplicate keys throw. Domain plugins register under
|
||||||
|
* `ctx.inject(['sessionProjections'], …)` so headless assemblies without the
|
||||||
|
* registry stay unaffected.
|
||||||
|
*/
|
||||||
|
export class SessionProjectionRegistry extends Service {
|
||||||
|
private readonly providers = new Map<keyof SessionProjectionMap, AnyProjectionProvider>()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create and install the registry as `ctx.sessionProjections`.
|
||||||
|
* @param ctx - Cordis context that owns the service.
|
||||||
|
*/
|
||||||
|
constructor(ctx: Context) {
|
||||||
|
super(ctx, 'sessionProjections')
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register one domain's provider. The registration is an effect on the
|
||||||
|
* calling context's fiber: disposing the fiber (or calling the returned
|
||||||
|
* disposer) removes the key from subsequent walks.
|
||||||
|
* @param provider - key, boundary schema, and synchronous whole-value read.
|
||||||
|
* @returns the exact disposer that unregisters this provider.
|
||||||
|
*/
|
||||||
|
register<K extends keyof SessionProjectionMap>(provider: ProjectionProvider<K>): () => void {
|
||||||
|
const dispose = this.ctx.effect(function* (this: SessionProjectionRegistry) {
|
||||||
|
if (this.providers.has(provider.key)) {
|
||||||
|
throw new Error(`session projection key ${JSON.stringify(provider.key)} is already registered`)
|
||||||
|
}
|
||||||
|
this.providers.set(provider.key, provider)
|
||||||
|
yield () => {
|
||||||
|
this.providers.delete(provider.key)
|
||||||
|
}
|
||||||
|
}.bind(this), 'sessionProjections.register()')
|
||||||
|
return () => void dispose()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Snapshot the registered providers in registration order — the carrier
|
||||||
|
* walk surface. Each provider carries its own `key` and `schema`.
|
||||||
|
* @returns the providers registered at this moment.
|
||||||
|
*/
|
||||||
|
entries(): AnyProjectionProvider[] {
|
||||||
|
return [...this.providers.values()]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SessionProjectionRegistry
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
/**
|
||||||
|
* Package-owned invariant companion for `@deepseek-ai/dsh-session-projection`.
|
||||||
|
* @module @deepseek-ai/dsh-session-projection/invariant
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* jscpd:ignore-start */
|
||||||
|
import type { Context } from 'cordis'
|
||||||
|
import type { InvariantInstaller } from '@deepseek-ai/dsh-invariants'
|
||||||
|
|
||||||
|
const PACKAGE_NAME = '@deepseek-ai/dsh-session-projection'
|
||||||
|
|
||||||
|
/** Cordis companion plugin name. */
|
||||||
|
export const name = 'session-projection-invariant'
|
||||||
|
/** Service required before the companion can reserve package ownership. */
|
||||||
|
export const inject = ['invariants']
|
||||||
|
|
||||||
|
/**
|
||||||
|
* No runtime invariant: the registry's own contracts (duplicate-key rejection,
|
||||||
|
* effect-tied removal) are enforced synchronously at the register() boundary,
|
||||||
|
* and the served-block relation — every served key has a live registration —
|
||||||
|
* lives on each carrier's wire path, which emits no cordis event this
|
||||||
|
* companion could observe; carrier specs assert it instead. Synchronous-`get`
|
||||||
|
* discipline is enforced as far as practical by the carrier's `schema.parse`
|
||||||
|
* (a Promise value fails loudly).
|
||||||
|
*/
|
||||||
|
const install: InvariantInstaller = () => {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register this package's invariant companion.
|
||||||
|
* @param ctx - Cordis context carrying the invariant service.
|
||||||
|
* @returns the installed registration's disposer after setup succeeds.
|
||||||
|
*/
|
||||||
|
export const apply = (ctx: Context): Promise<() => void> =>
|
||||||
|
Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install))
|
||||||
|
/* jscpd:ignore-end */
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
/**
|
||||||
|
* SessionProjectionRegistry behavior: registration surfaces through entries(),
|
||||||
|
* duplicate keys fail loud, and both the returned disposer and the owning
|
||||||
|
* fiber's disposal remove the key (HMR safety).
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { describe, expect, it } from 'vitest'
|
||||||
|
import { Context } from 'cordis'
|
||||||
|
import { z } from 'zod'
|
||||||
|
import type { Agent } from '@deepseek-ai/dsh-agent'
|
||||||
|
import SessionProjectionRegistry from '@deepseek-ai/dsh-session-projection'
|
||||||
|
import type { ProjectionProvider } from '@deepseek-ai/dsh-session-projection'
|
||||||
|
|
||||||
|
declare module '@deepseek-ai/dsh-session-projection' {
|
||||||
|
interface SessionProjectionMap {
|
||||||
|
'test/alpha': { value: string }
|
||||||
|
'test/beta': number
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const alphaProvider = (value: string): ProjectionProvider<'test/alpha'> => ({
|
||||||
|
key: 'test/alpha',
|
||||||
|
schema: z.object({ value: z.string() }),
|
||||||
|
get: () => ({ value }),
|
||||||
|
})
|
||||||
|
|
||||||
|
async function harness(): Promise<Context> {
|
||||||
|
const ctx = new Context()
|
||||||
|
await ctx.plugin(SessionProjectionRegistry)
|
||||||
|
return ctx
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('SessionProjectionRegistry', () => {
|
||||||
|
it('registers a provider, walks it via entries(), and serves get()', async () => {
|
||||||
|
const ctx = await harness()
|
||||||
|
ctx.sessionProjections.register(alphaProvider('a'))
|
||||||
|
const entries = ctx.sessionProjections.entries()
|
||||||
|
expect(entries.map(entry => entry.key)).toEqual(['test/alpha'])
|
||||||
|
const provider = entries[0] as ProjectionProvider<'test/alpha'>
|
||||||
|
expect(provider.get({} as Agent)).toEqual({ value: 'a' })
|
||||||
|
expect(provider.schema.parse({ value: 'a' })).toEqual({ value: 'a' })
|
||||||
|
})
|
||||||
|
|
||||||
|
it('preserves registration order across keys', async () => {
|
||||||
|
const ctx = await harness()
|
||||||
|
ctx.sessionProjections.register(alphaProvider('a'))
|
||||||
|
ctx.sessionProjections.register({
|
||||||
|
key: 'test/beta',
|
||||||
|
schema: z.number(),
|
||||||
|
get: () => 1,
|
||||||
|
})
|
||||||
|
expect(ctx.sessionProjections.entries().map(entry => entry.key)).toEqual(['test/alpha', 'test/beta'])
|
||||||
|
})
|
||||||
|
|
||||||
|
it('throws on a duplicate key and keeps the first registration', async () => {
|
||||||
|
const ctx = await harness()
|
||||||
|
ctx.sessionProjections.register(alphaProvider('first'))
|
||||||
|
expect(() => ctx.sessionProjections.register(alphaProvider('second')))
|
||||||
|
.toThrow(/"test\/alpha" is already registered/)
|
||||||
|
const entries = ctx.sessionProjections.entries()
|
||||||
|
expect(entries).toHaveLength(1)
|
||||||
|
expect((entries[0] as ProjectionProvider<'test/alpha'>).get({} as Agent)).toEqual({ value: 'first' })
|
||||||
|
})
|
||||||
|
|
||||||
|
it('register() returns a disposer that removes the key and frees it for re-registration', async () => {
|
||||||
|
const ctx = await harness()
|
||||||
|
const dispose = ctx.sessionProjections.register(alphaProvider('a'))
|
||||||
|
dispose()
|
||||||
|
expect(ctx.sessionProjections.entries()).toEqual([])
|
||||||
|
ctx.sessionProjections.register(alphaProvider('again'))
|
||||||
|
expect(ctx.sessionProjections.entries()).toHaveLength(1)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('removes a registration when its owning fiber unloads (HMR safety)', async () => {
|
||||||
|
const ctx = await harness()
|
||||||
|
const fiber = await ctx.plugin(Object.assign((inner: Context) => {
|
||||||
|
inner.sessionProjections.register(alphaProvider('scoped'))
|
||||||
|
}, { inject: ['sessionProjections'] }))
|
||||||
|
expect(ctx.sessionProjections.entries()).toHaveLength(1)
|
||||||
|
await fiber.dispose()
|
||||||
|
expect(ctx.sessionProjections.entries()).toEqual([])
|
||||||
|
})
|
||||||
|
})
|
||||||
24
packages/session-projection/session-projection/tsconfig.json
Normal file
24
packages/session-projection/session-projection/tsconfig.json
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"extends": "../../../tsconfig.base.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"rootDir": "src",
|
||||||
|
"outDir": "lib/types"
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"src"
|
||||||
|
],
|
||||||
|
"references": [
|
||||||
|
{
|
||||||
|
"path": "../../../vendor/cosmokit"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "../../../vendor/cordis"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "../../core/agent"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "../../support/invariants"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
16
pnpm-lock.yaml
generated
16
pnpm-lock.yaml
generated
@@ -3326,6 +3326,22 @@ importers:
|
|||||||
specifier: ^4.0.0-rc.7
|
specifier: ^4.0.0-rc.7
|
||||||
version: 4.0.0-rc.7(@cordisjs/plugin-include@1.0.4)(@cordisjs/plugin-loader@1.0.0-rc.5)
|
version: 4.0.0-rc.7(@cordisjs/plugin-include@1.0.4)(@cordisjs/plugin-loader@1.0.0-rc.5)
|
||||||
|
|
||||||
|
packages/session-projection/session-projection:
|
||||||
|
dependencies:
|
||||||
|
zod:
|
||||||
|
specifier: ^4.4.3
|
||||||
|
version: 4.4.3
|
||||||
|
devDependencies:
|
||||||
|
'@deepseek-ai/dsh-agent':
|
||||||
|
specifier: workspace:^
|
||||||
|
version: link:../../core/agent
|
||||||
|
'@deepseek-ai/dsh-invariants':
|
||||||
|
specifier: workspace:^
|
||||||
|
version: link:../../support/invariants
|
||||||
|
cordis:
|
||||||
|
specifier: ^4.0.0-rc.7
|
||||||
|
version: 4.0.0-rc.7(@cordisjs/plugin-include@1.0.4)(@cordisjs/plugin-loader@1.0.0-rc.5)
|
||||||
|
|
||||||
packages/session-query/session-query:
|
packages/session-query/session-query:
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@deepseek-ai/dsh-brand':
|
'@deepseek-ai/dsh-brand':
|
||||||
|
|||||||
@@ -85,6 +85,7 @@ const SENTENCE_MODEL_EXPERIENCE: Readonly<Record<string, SentenceContract>> = {
|
|||||||
'packages/sdk/helper': { kind: 'none', reason: 'The project domain edits files and registers no live agent or model surface.' },
|
'packages/sdk/helper': { kind: 'none', reason: 'The project domain edits files and registers no live agent or model surface.' },
|
||||||
'packages/sdk/scripts': { kind: 'indirect', reason: 'The launcher delegates model context to the loaded project plugin tree.' },
|
'packages/sdk/scripts': { kind: 'indirect', reason: 'The launcher delegates model context to the loaded project plugin tree.' },
|
||||||
'packages/sdk/telemetry': { kind: 'none', reason: 'The launcher-side reporter sends developer-cycle telemetry and registers no live agent or model surface.' },
|
'packages/sdk/telemetry': { kind: 'none', reason: 'The launcher-side reporter sends developer-cycle telemetry and registers no live agent or model surface.' },
|
||||||
|
'packages/session-projection/session-projection': { kind: 'none', reason: 'The projection registry serves client-facing read models of already-logged session state and registers no model surface.' },
|
||||||
'packages/session-query/session-query': { kind: 'none', reason: 'The trusted query service exposes cloned records only to callers and registers no model surface.' },
|
'packages/session-query/session-query': { kind: 'none', reason: 'The trusted query service exposes cloned records only to callers and registers no model surface.' },
|
||||||
'packages/session-query/session-query-sqlite': { kind: 'none', reason: 'The search backend returns hits only to callers and registers no model surface.' },
|
'packages/session-query/session-query-sqlite': { kind: 'none', reason: 'The search backend returns hits only to callers and registers no model surface.' },
|
||||||
'packages/telemetry/session-telemetry': { kind: 'none', reason: 'The seam observes the session stream and hands redacted copies outward; it registers no model surface.' },
|
'packages/telemetry/session-telemetry': { kind: 'none', reason: 'The seam observes the session stream and hands redacted copies outward; it registers no model surface.' },
|
||||||
|
|||||||
@@ -74,6 +74,7 @@
|
|||||||
"./packages/sandbox/*/src/invariant.ts",
|
"./packages/sandbox/*/src/invariant.ts",
|
||||||
"./packages/hooks/*/src/invariant.ts",
|
"./packages/hooks/*/src/invariant.ts",
|
||||||
"./packages/session-persistence/*/src/invariant.ts",
|
"./packages/session-persistence/*/src/invariant.ts",
|
||||||
|
"./packages/session-projection/*/src/invariant.ts",
|
||||||
"./packages/session-query/*/src/invariant.ts",
|
"./packages/session-query/*/src/invariant.ts",
|
||||||
"./packages/telemetry/*/src/invariant.ts",
|
"./packages/telemetry/*/src/invariant.ts",
|
||||||
"./packages/acp/*/src/invariant.ts",
|
"./packages/acp/*/src/invariant.ts",
|
||||||
@@ -153,6 +154,7 @@
|
|||||||
"./packages/sandbox/*/src",
|
"./packages/sandbox/*/src",
|
||||||
"./packages/hooks/*/src",
|
"./packages/hooks/*/src",
|
||||||
"./packages/session-persistence/*/src",
|
"./packages/session-persistence/*/src",
|
||||||
|
"./packages/session-projection/*/src",
|
||||||
"./packages/session-query/*/src",
|
"./packages/session-query/*/src",
|
||||||
"./packages/session-title/*/src",
|
"./packages/session-title/*/src",
|
||||||
"./packages/telemetry/*/src",
|
"./packages/telemetry/*/src",
|
||||||
|
|||||||
@@ -55,6 +55,7 @@
|
|||||||
{ "path": "./packages/session-persistence/session-checkpoint-policy" },
|
{ "path": "./packages/session-persistence/session-checkpoint-policy" },
|
||||||
{ "path": "./packages/session-persistence/session-persistence-jsonl" },
|
{ "path": "./packages/session-persistence/session-persistence-jsonl" },
|
||||||
{ "path": "./packages/session-persistence/session-persistence-sqlite" },
|
{ "path": "./packages/session-persistence/session-persistence-sqlite" },
|
||||||
|
{ "path": "./packages/session-projection/session-projection" },
|
||||||
{ "path": "./packages/session-query/session-query" },
|
{ "path": "./packages/session-query/session-query" },
|
||||||
{ "path": "./packages/session-query/session-query-sqlite" },
|
{ "path": "./packages/session-query/session-query-sqlite" },
|
||||||
{ "path": "./packages/session-query/tool-session-query" },
|
{ "path": "./packages/session-query/tool-session-query" },
|
||||||
|
|||||||
Reference in New Issue
Block a user