Gate JSDoc completeness on every package export

New doc-sync gate verify-export-jsdoc walks every module-level exported
name under packages/*/*/src and requires description prose everywhere,
plus @param per parameter and @returns on non-void annotated returns for
function-like exports, public class methods, properties, and accessors.
The parsing + check helpers move out of gen-cordis-catalog.ts into a
shared scripts/jsdoc.ts so 'documented' means one thing on both gated
surfaces.

Deliberate exemptions (documented in the RFC): heritage-declared class
members (the seam declaration is the doc's one home — the one checker
query in an otherwise pure-AST walk), cordis plugin-protocol slots
(name/inject/reusable/Config/apply, top-level and static), constructors,
overload implementations, declare-module augmentation bodies, and
re-export statements (checked at the defining module).

The 203 under-documented exports the gate found at adoption are filled
in this change, so the gate lands green; generated catalogs/graphs are
regenerated for the shifted line pointers.

RFC: docs/rfc/implemented/process/2026-07-06-export-surface-jsdoc-gate.md
This commit is contained in:
Tianyi Cui
2026-07-06 22:09:30 +08:00
parent 1c999804d8
commit cd9737d569
92 changed files with 1802 additions and 289 deletions
+9 -1
View File
@@ -21,14 +21,22 @@ import { toPiContext, toStreamChunks } from './convert.ts'
/** Reasoning levels surfaced by this adapter (DeepSeek wire: high|max). */
export type PiAiReasoning = 'off' | 'high' | 'xhigh'
/** Constructor options for {@link PiAiAdapter}; the plugin's `apply` resolves them from Config + environment. */
export interface PiAiAdapterOptions {
/** Bearer token pi-ai sends on every request. */
apiKey: string
/** Endpoint base; `/chat/completions` is appended. */
baseURL: string
/** Thinking level applied to every request ('off' disables thinking). */
reasoning?: PiAiReasoning | undefined
}
/** Build the inline pi-ai model descriptor for one DeepSeek model name. */
/**
* Build the inline pi-ai model descriptor for one DeepSeek model name.
* @param modelId - harness model name; sent verbatim on the wire.
* @param options - adapter options; only `baseURL` is read here (key and reasoning apply per request, not per descriptor).
* @returns a descriptor with every DeepSeek compat flag explicit — pi-ai's URL-based auto-detection is never relied on.
*/
export function buildModel(modelId: string, options: PiAiAdapterOptions): Model<'openai-completions'> {
return {
id: modelId,
+15 -2
View File
@@ -55,6 +55,8 @@ function parseArguments(raw: string): Record<string, unknown> {
* NAME (pi-ai's `toolName`), which the harness doesn't carry on the result
* block — it is recovered from the preceding assistant tool-call with the
* same id.
* @param options - the harness request; `options.system` maps to pi-ai's single `systemPrompt` slot.
* @returns the pi-ai context; `tools` is omitted entirely when the request declares none.
*/
export function toPiContext(options: GenerateOptions): PiContext {
const toolNames = new Map<CallId, string>()
@@ -159,7 +161,11 @@ function emptyPiUsage(): PiUsage {
}
}
/** Map pi-ai usage (reasoning folded into output by pi-ai). */
/**
* Map pi-ai usage (reasoning folded into output by pi-ai).
* @param usage - cumulative usage from the terminal pi-ai event.
* @returns harness counts; cache fields appear only when non-zero (pi-ai reports zeros, not absence).
*/
export function mapUsage(usage: PiUsage): TokenUsage {
return {
inputTokens: usage.input,
@@ -177,7 +183,11 @@ function classifyPiAiError(message: string): string {
return 'PI_AI_ERROR'
}
/** Map a terminal pi-ai event to the harness finish reason. */
/**
* Map a terminal pi-ai event to the harness finish reason.
* @param message - the assistant message carried by the `done` or `error` event.
* @returns the harness reason; `error` yields `{kind: 'error'}` with a code classified from the error text.
*/
export function mapStopReason(message: AssistantMessage): FinishReason {
switch (message.stopReason) {
case 'stop': return { kind: 'stop' }
@@ -195,6 +205,9 @@ export function mapStopReason(message: AssistantMessage): FinishReason {
* Translate the pi-ai event stream into StreamChunks. pi-ai never throws
* mid-stream — failures arrive as `error` events, which become error/aborted
* `finish` chunks (the harness protocol's other error-delivery style).
* @param events - one assistant turn's pi-ai event stream.
* @returns the harness chunks, ending with `usage` then `finish`; throws
* `LlmError` (`STREAM_CLOSED`) if the source ends without a terminal event.
*/
export async function* toStreamChunks(events: AsyncIterable<AssistantMessageEvent>): AsyncGenerator<StreamChunk> {
// pi-ai contentIndex ↔ our block index map 1:1 (both count blocks from 0
+5
View File
@@ -29,6 +29,11 @@ export { mapStopReason, mapUsage, toPiContext, toStreamChunks } from './convert.
export const name = 'llm-pi-ai'
export const inject = ['llm']
/**
* Plugin config, validated by the same-named schemastery schema. Every field
* is optional in yml: credentials/endpoint fall back to the environment (a
* missing API key fails plugin load, not the first call).
*/
export interface Config {
/** API key; falls back to $DEEPSEEK_API_KEY. Required one way or the other. */
apiKey?: string