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

View File

@@ -14,7 +14,13 @@ import { assertNever } from '@deepseek-ai/dsh-llm'
import type {} from '@deepseek-ai/dsh-system-prompt'
import { htmlToMarkdown } from './html.ts'
/** Validate value constraints the schema DSL can't express. */
/**
* Validate value constraints the schema DSL can't express: a non-blank `url`,
* and a positive `timeout_ms` when present. Throws a plain `Error` otherwise.
*
* @param args - the schema-validated `web_fetch` arguments.
* @returns the arguments renamed to the seam's camelCase request fields.
*/
export function parseFetchArgs(args: { url: string; timeout_ms?: number }): { url: string; timeoutMs?: number } {
if (args.url.trim().length === 0) throw new Error('url must be a non-empty string')
if (args.timeout_ms !== undefined && (!Number.isFinite(args.timeout_ms) || args.timeout_ms <= 0)) {
@@ -23,7 +29,13 @@ export function parseFetchArgs(args: { url: string; timeout_ms?: number }): { ur
return { url: args.url, ...args.timeout_ms !== undefined ? { timeoutMs: args.timeout_ms } : {} }
}
/** Render a fetched body to model-facing markdown text. */
/**
* Render a fetched body to model-facing markdown text.
*
* @param body - the decoded body; `html` is converted via
* {@link htmlToMarkdown}, `text` passes through verbatim.
* @returns the text for the tool's output block.
*/
export function renderBody(body: WebFetchBody): string {
switch (body.kind) {
case 'html':
@@ -36,19 +48,35 @@ export function renderBody(body: WebFetchBody): string {
}
}
/** Format a fetch result as one model-facing text block. */
/**
* Format a fetch result as one model-facing text block.
*
* @param result - the seam's fetch outcome.
* @returns a `Fetched <url> (HTTP <status>)` header, the rendered body, and a
* fetch-something-narrower notice when the provider truncated the content.
*/
export function formatFetchOutput(result: WebFetchResult): string {
const header = `Fetched ${result.url} (HTTP ${result.statusCode})`
const footer = result.truncated ? '\n\n(Content truncated. Fetch a more specific URL or section for the full text.)' : ''
return `${header}\n\n${renderBody(result.body)}${footer}`
}
/** Pending-call presentation: a fetch card titled by the URL. */
/**
* Pending-call presentation: a fetch card titled by the URL.
*
* @param args - the raw tool arguments; only `url` feeds the view.
* @returns the generic card view (`kind: 'fetch'`) shown while the call runs.
*/
export function presentFetchCall(args: { url: string; timeout_ms?: number }): GenericCallView {
return { card: 'generic', title: args.url, kind: 'fetch', rawInput: args.url }
}
/** Register the `web_fetch` tool and its system-prompt guidance. */
/**
* Register the `web_fetch` tool and its system-prompt guidance.
*
* @param ctx - context whose `tools` and `systemPrompt` registries receive the
* registrations; both are effect-scoped and unregister on plugin dispose.
*/
export function applyWebFetchTool(ctx: Context): void {
ctx.systemPrompt.section({
name: 'tool:web_fetch',

View File

@@ -44,6 +44,10 @@ function safeFromCodePoint(code: number, fallback: string): string {
* Convert an HTML document to a readable markdown-ish text approximation.
* Best-effort and lossy by design — fidelity is the job of a future heavier
* converter, not this fallback.
*
* @param html - the raw HTML source.
* @returns plain text with markdown headings, list bullets, and links;
* whitespace collapsed to at most one blank line and trimmed.
*/
export function htmlToMarkdown(html: string): string {
let text = html

View File

@@ -33,6 +33,7 @@ export const name = 'tool-web'
/** Services required by the web tool suite. */
export const inject = ['tools', 'web', 'systemPrompt']
/** Plugin config: which web tools to register, and the `web_search` source cap. */
export interface Config {
/** Register `web_search`. Defaults to true. */
search?: boolean

View File

@@ -20,7 +20,13 @@ import type {} from '@deepseek-ai/dsh-system-prompt'
*/
export const WEB_SEARCH_MAX_RESULTS = 8
/** Validate value constraints the schema DSL can't express. */
/**
* Validate value constraints the schema DSL can't express: a non-blank
* `query`. Throws a plain `Error` otherwise.
*
* @param args - the schema-validated `web_search` arguments.
* @returns the accepted arguments, passed through unchanged.
*/
export function parseSearchArgs(args: { query: string }): { query: string } {
if (args.query.trim().length === 0) throw new Error('query must be a non-empty string')
return { query: args.query }
@@ -38,7 +44,14 @@ function sourceLabel(url: string, title: string | undefined): string {
}
}
/** Format a search result as one model-facing text block. */
/**
* Format a search result as one model-facing text block.
*
* @param result - the seam's search outcome.
* @returns the provider answer (when any), a markdown source list with snippet
* and date metadata (or `No results found.`), a refine-the-query note when
* truncated, and a standing cite-your-sources instruction.
*/
export function formatSearchOutput(result: WebSearchResult): string {
const parts: string[] = []
if (result.content !== undefined && result.content.length > 0) parts.push(result.content)
@@ -62,12 +75,24 @@ export function formatSearchOutput(result: WebSearchResult): string {
return parts.join('\n\n')
}
/** Pending-call presentation: a search card titled by the query. */
/**
* Pending-call presentation: a search card titled by the query.
*
* @param args - the raw tool arguments; only `query` feeds the view.
* @returns the generic card view (`kind: 'search'`) shown while the call runs.
*/
export function presentSearchCall(args: { query: string }): GenericCallView {
return { card: 'generic', title: args.query, kind: 'search', rawInput: args.query }
}
/** Register the `web_search` tool and its system-prompt guidance. `maxResults` is the deployment's source cap. */
/**
* Register the `web_search` tool and its system-prompt guidance.
*
* @param ctx - context whose `tools` and `systemPrompt` registries receive the
* registrations; both are effect-scoped and unregister on plugin dispose.
* @param maxResults - the deployment's source cap, sent as every seam
* request's `maxResults`.
*/
export function applyWebSearchTool(ctx: Context, maxResults: number): void {
ctx.systemPrompt.section({
name: 'tool:web_search',