chore(storage,workspace): gates — coverage, catalogs, bilingual note

- Per-file 100% coverage across the five new packages (invariant
  companion suites, failure-injection negatives, lifecycle and
  malformed-medium branches).
- Canonical README Model Experience / Known Limitations sections; new
  storage/ and workspace/ group READMEs; packages/README.md rows (budget
  ceiling raised 760 → 790 for the two new groups).
- Cordis catalog/type-link registrations, service-role classification,
  and regenerated catalogs/graphs for the new services and events.
- Agent Note: English body + i18n pairing record; design-sketch fences
  opted out of doc-typecheck as ignore-check.
- Two exactOptionalPropertyTypes/discriminant fixes in new tests.

doc-sync (24 gates), typecheck, hygiene, and the five-package suite
(92 tests) all pass.
This commit is contained in:
imccyu
2026-07-24 22:49:57 +08:00
parent 80b3b6d917
commit 0559e0207e
33 changed files with 1333 additions and 58 deletions

View File

@@ -642,6 +642,20 @@ export const SERVICE_API: readonly ServiceApiEntry[] = [
},
],
},
{
key: 'storage',
summary: 'The storage hub service.',
methods: [
{
signature: 'mount<K extends keyof StorageForms>(form: K, facility: StorageForms[K]): () => void',
jsDoc: '/**\n * Mount a data-form facility on the hub. Mounting is an effect: the\n * returned disposer unmounts the form.\n * @param form - Form key declared in {@link StorageForms}.\n * @param facility - The facility instance to expose.\n * @returns the disposer that unmounts the form.\n */',
},
{
signature: 'form<K extends keyof StorageForms>(form: K): StorageForms[K]',
jsDoc: '/**\n * Resolve a mounted data form.\n * @param form - Form key declared in {@link StorageForms}.\n * @returns the mounted facility.\n */',
},
],
},
{
key: 'subagents',
summary: 'Named provider registry and capability-checked start surface.',
@@ -846,6 +860,28 @@ export const SERVICE_API: readonly ServiceApiEntry[] = [
},
],
},
{
key: 'workspace',
summary: 'The workspace registry service.',
methods: [
{
signature: 'async create(path: string, title?: string): Promise<Workspace>',
jsDoc: '/**\n * Create a workspace over an existing directory. The path is canonicalized\n * through `fs.realpath` first — a nonexistent path rejects with the\n * original `ENOENT`, a path resolving to anything but a directory rejects,\n * and a canonical path already owned by another workspace (including a\n * symlink resolving to it) rejects.\n * @param path - Directory the workspace points at; canonicalized before storing.\n * @param title - Display title; defaults to `basename` of the canonical path.\n * @returns the created workspace after durability.\n */',
},
{
signature: 'get(id: WorkspaceId): Workspace | undefined',
jsDoc: '/**\n * Look up a workspace by id.\n * @param id - The workspace id.\n * @returns the workspace, or `undefined` when unknown.\n */',
},
{
signature: 'list(): Workspace[]',
jsDoc: '/**\n * Snapshot of all workspaces, in load-then-creation order.\n * @returns a fresh array of the cached entities.\n */',
},
{
signature: 'async resolveByPath(path: string): Promise<Workspace | undefined>',
jsDoc: '/**\n * Resolve a workspace by directory path, through the same `fs.realpath`\n * canon as {@link create} (hence async). A path that does not exist rejects\n * with the original error — a missing directory has no canonical form to\n * compare (a workspace whose recorded directory vanished is only reachable\n * by id; see `Workspace.status`).\n * @param path - Directory path in any spelling (symlinks, `..`, trailing slash).\n * @returns the owning workspace, or `undefined` when none matches.\n */',
},
],
},
]
/** Every harness event, sorted by name. */
@@ -997,6 +1033,13 @@ export const EVENT_API: readonly EventApiEntry[] = [
jsDoc: '/**\n * A command was registered or unregistered. This is an unfiltered registry\n * notification because a global or scoped change may affect any UI view.\n * Observer failures are contained and cannot veto the registry mutation.\n * @mode emit\n */',
summary: 'A command was registered or unregistered.',
},
{
name: 'domain/changed',
mode: 'emit',
signature: '\'domain/changed\'(change: DomainChanged): void',
jsDoc: '/**\n * A domain record or the global singleton changed, emitted once per write\n * strictly after the backend acknowledged durability. Events of one\n * domain arrive in its write-chain order.\n * @param change - domain, table (`\'\'` for global), key (`\'\'` for global),\n * operation discriminant, and on `put` the new snapshot.\n * @mode emit\n */',
summary: 'A domain record or the global singleton changed, emitted once per write strictly after the backend acknowledged durability.',
},
{
name: 'fs/edit-intent',
mode: 'waterfall',
@@ -1999,6 +2042,10 @@ export const TYPE_API: readonly TypeApiEntry[] = [
name: 'SpillSource',
declaration: 'export interface SpillSource {\n toolName: string;\n callId: CallId;\n label: string;\n}',
},
{
name: 'StorageForms',
declaration: 'export interface StorageForms {\n}',
},
{
name: 'StreamChunk',
declaration: 'export type StreamChunk = {\n type: \'block-start\';\n index: number;\n blockType: ContentBlockType;\n} | {\n type: \'text-delta\';\n index: number;\n text: string;\n} | {\n type: \'reasoning-delta\';\n index: number;\n text: string;\n} | {\n type: \'tool-call-delta\';\n index: number;\n id: CallId;\n name?: string;\n argumentsDelta: string;\n} | {\n type: \'block-end\';\n index: number;\n block: ContentBlock;\n} | {\n type: \'usage\';\n usage: TokenUsage;\n} | {\n type: \'finish\';\n reason: FinishReason;\n replayState?: unknown;\n};',
@@ -2335,6 +2382,10 @@ export const TYPE_API: readonly TypeApiEntry[] = [
name: 'WorkflowStopReason',
declaration: 'export type WorkflowStopReason = \'completed\' | \'cancelled\' | \'error\';',
},
{
name: 'Workspace',
declaration: 'export interface Workspace {\n readonly id: WorkspaceId;\n readonly path: string;\n readonly title: string;\n readonly sessionIds: readonly SessionId[];\n setTitle(title: string): Promise<void>;\n attachSession(sessionId: SessionId): Promise<void>;\n detachSession(sessionId: SessionId): Promise<void>;\n status(): Promise<\'ok\' | \'missing-dir\'>;\n}',
},
]
/** The inherited `ctx` surface (cordis core + loader/hmr/timer), in curated order. */