refactor(web): consume owner remote events directly

This commit is contained in:
imccyu
2026-08-11 16:50:03 +08:00
parent 80f1a064f5
commit e0bbe42242
75 changed files with 353 additions and 350 deletions

View File

@@ -17,7 +17,7 @@ import { dirname, isAbsolute, join, resolve } from 'node:path'
import { writeFileAtomic } from '@deepseek-ai/dsh-atomic-write'
import { expandHomePath } from '@deepseek-ai/dsh-paths'
import { METADATA_FILE, renderPresetMetadata } from './metadata.ts'
import { PRESET_ID, type AgentPreset, type PresetRoot } from './types.ts'
import { PRESET_ID, type AgentPreset, type PresetRoot } from './preset.ts'
/** A preset id that cannot be used as a directory name under a root. */
export class InvalidPresetIdError extends Error {

View File

@@ -20,7 +20,7 @@ import { load } from 'js-yaml'
import { entryListSchema } from '@deepseek-ai/cordis-plugin-include'
import { expandHomePath } from '@deepseek-ai/dsh-paths'
import { readPresetMetadata } from './metadata.ts'
import { PRESET_ID, type AgentPreset, type PresetRoot } from './types.ts'
import { PRESET_ID, type AgentPreset, type PresetRoot } from './preset.ts'
/** The composition file that makes a directory a preset. */
export const COMPOSITION_FILE = 'agent.cordis.yml'

View File

@@ -32,7 +32,8 @@ import { discoverPresets } from './discovery.ts'
import { copyComposition, deleteComposition, readComposition } from './authoring.ts'
import { mountPreset, serviceForAgent, standingMountFor } from './mount.ts'
import { PresetExistsError } from './authoring.ts'
import { PresetMountError, UnknownPresetError, type AgentPreset, type Config } from './types.ts'
import { PresetMountError, UnknownPresetError, type AgentPreset, type Config } from './preset.ts'
import type {} from './types.ts'
/** Settings namespace carrying the user's chosen default preset. */
export const SETTINGS_NAMESPACE = 'agent-presets'
@@ -61,8 +62,8 @@ export {
PresetNotWritableError, readComposition, writableRoot,
} from './authoring.ts'
export { resolveSessionPreset, type PresetBearingSession } from './session.ts'
export { PresetMountError, UnknownPresetError } from './types.ts'
export type { AgentPreset, Config, PresetRoot, PresetTrust } from './types.ts'
export { PresetMountError, UnknownPresetError } from './preset.ts'
export type { AgentPreset, Config, PresetRoot, PresetTrust } from './preset.ts'
declare module '@deepseek-ai/cordis' {
interface Context {
@@ -154,6 +155,13 @@ export class AgentPresets extends Service {
+ '(join through AgentPresets.mount() or composeFrom() in the agent factory setup)',
)
})
// The durable record is the commit point. Its public notification carries
// only the stable identity needed by clients, never the live Session.
ctx.on('session/event', (session, event) => {
if (event.type !== 'agent-preset/selected') return
ctx.emit('agent-preset/selected', session.id, event.data.agentPreset)
})
}
/**

View File

@@ -20,7 +20,7 @@ import { Context, type Fiber } from '@deepseek-ai/cordis'
import { Include } from '@deepseek-ai/cordis-plugin-include'
import type { EntryTree } from '@deepseek-ai/cordis-plugin-loader'
import { scopeOf, scopeParentOf, type ScopeKey } from '@deepseek-ai/dsh-scope'
import { PresetMountError, type AgentPreset } from './types.ts'
import { PresetMountError, type AgentPreset } from './preset.ts'
/** What one mounted subtree publishes about itself for the audit to read. */
interface MountedTree {

View File

@@ -0,0 +1,88 @@
/** Agent-preset vocabulary shared by discovery, mounting, and consumers. */
/**
* Where a preset's composition came from. A `system` preset ships with the
* deployment; a `user` preset was authored locally, by a person or by an
* agent, and therefore carries the same trust as shell access.
*/
export type PresetTrust = 'system' | 'user'
/**
* Ids a preset directory may use.
*
* The id becomes a path segment, so this is a containment boundary rather than
* a style rule: `..`, a separator, or an absolute-looking name would place the
* composition outside the root the deployment authorised. Discovery shares it:
* a directory whose name no copy could ever claim is not a preset slot.
*/
export const PRESET_ID = /^[a-z0-9][a-z0-9-]*$/
/** One preset directory that carries a mountable agent composition. */
export interface AgentPreset {
/** Stable identifier; the preset directory's name. */
readonly id: string
/** Trust recorded from the root this preset was discovered under. */
readonly trust: PresetTrust
/** Absolute path of the preset's agent composition file. */
readonly path: string
/** Display name from the preset's own metadata; absent falls back to {@link id}. */
readonly name?: string
/** One sentence on what this preset is for, when it published one. */
readonly description?: string
/** Declared position within its group; absent sorts after those that declare one. */
readonly order?: number
/**
* Why this preset cannot compose a session, absent when it can. A broken
* preset stays on the roster — hiding it would leave its directory blocking
* the id with nothing to see or delete — but every mounting path refuses it
* up front with this reason instead of failing deep inside the loader.
*/
readonly broken?: string
}
/** One directory scanned for preset subdirectories. */
export interface PresetRoot {
/** Directory holding one subdirectory per preset; a leading `~` expands. */
path: string
/** Trust recorded on every preset discovered under this root. */
trust: PresetTrust
}
/** Plugin config: which preset is the default, and where presets live. */
export interface Config {
/** Preset id mounted when a caller names none. Missing at mount time fails loud. */
default: string
/** Scanned roots in precedence order; an earlier root wins a duplicate id. */
roots: PresetRoot[]
}
/**
* No configured root supplies the requested preset.
*
* Separate from a mount failure because the two mean different things to a
* caller: an unknown id is a bad request, while an unusable composition is a
* broken preset the deployment must fix.
*/
export class UnknownPresetError extends Error {
constructor(
/** The id that was requested. */
readonly presetId: string,
/** Ids the roster does supply, for the caller to offer instead. */
readonly available: readonly string[],
) {
super(`agent-presets: preset "${presetId}" not found (available: ${available.join(', ') || 'none'})`)
}
}
/** A preset exists but its composition cannot be installed. */
export class PresetMountError extends Error {
constructor(
/** The preset whose composition failed. */
readonly presetId: string,
/** Why it failed, without this package's own message prefix. */
readonly reason: string,
options?: ErrorOptions,
) {
super(`agent-presets: preset "${presetId}" failed to mount: ${reason}`, options)
}
}

View File

@@ -1,88 +1,17 @@
/** Agent-preset vocabulary shared by discovery, mounting, and consumers. @module @deepseek-ai/dsh-agent-presets/types */
/** Client-safe event declarations owned by the agent-preset domain. */
import type { SessionId } from '@deepseek-ai/dsh-session/types'
/**
* Where a preset's composition came from. A `system` preset ships with the
* deployment; a `user` preset was authored locally, by a person or by an
* agent, and therefore carries the same trust as shell access.
*/
export type PresetTrust = 'system' | 'user'
/**
* Ids a preset directory may use.
*
* The id becomes a path segment, so this is a containment boundary rather than
* a style rule: `..`, a separator, or an absolute-looking name would place the
* composition outside the root the deployment authorised. Discovery shares it:
* a directory whose name no copy could ever claim is not a preset slot.
*/
export const PRESET_ID = /^[a-z0-9][a-z0-9-]*$/
/** One preset directory that carries a mountable agent composition. */
export interface AgentPreset {
/** Stable identifier; the preset directory's name. */
readonly id: string
/** Trust recorded from the root this preset was discovered under. */
readonly trust: PresetTrust
/** Absolute path of the preset's agent composition file. */
readonly path: string
/** Display name from the preset's own metadata; absent falls back to {@link id}. */
readonly name?: string
/** One sentence on what this preset is for, when it published one. */
readonly description?: string
/** Declared position within its group; absent sorts after those that declare one. */
readonly order?: number
/**
* Why this preset cannot compose a session, absent when it can. A broken
* preset stays on the roster — hiding it would leave its directory blocking
* the id with nothing to see or delete — but every mounting path refuses it
* up front with this reason instead of failing deep inside the loader.
*/
readonly broken?: string
}
/** One directory scanned for preset subdirectories. */
export interface PresetRoot {
/** Directory holding one subdirectory per preset; a leading `~` expands. */
path: string
/** Trust recorded on every preset discovered under this root. */
trust: PresetTrust
}
/** Plugin config: which preset is the default, and where presets live. */
export interface Config {
/** Preset id mounted when a caller names none. Missing at mount time fails loud. */
default: string
/** Scanned roots in precedence order; an earlier root wins a duplicate id. */
roots: PresetRoot[]
}
/**
* No configured root supplies the requested preset.
*
* Separate from a mount failure because the two mean different things to a
* caller: an unknown id is a bad request, while an unusable composition is a
* broken preset the deployment must fix.
*/
export class UnknownPresetError extends Error {
constructor(
/** The id that was requested. */
readonly presetId: string,
/** Ids the roster does supply, for the caller to offer instead. */
readonly available: readonly string[],
) {
super(`agent-presets: preset "${presetId}" not found (available: ${available.join(', ') || 'none'})`)
declare module '@deepseek-ai/cordis' {
interface Events {
/**
* One session committed a different agent preset to its durable log.
* Consumers invalidate only state derived from that session's composition.
* @mode emit
* @param sessionId - the session whose composition changed.
* @param agentPreset - the preset recorded by the committed selection.
*/
'agent-preset/selected'(sessionId: SessionId, agentPreset: string): void
}
}
/** A preset exists but its composition cannot be installed. */
export class PresetMountError extends Error {
constructor(
/** The preset whose composition failed. */
readonly presetId: string,
/** Why it failed, without this package's own message prefix. */
readonly reason: string,
options?: ErrorOptions,
) {
super(`agent-presets: preset "${presetId}" failed to mount: ${reason}`, options)
}
}
export {}