Merge origin/master into feat/website-docs

Conflict resolution notes:
- package.json/run-gates: both sides' new doc-sync gates kept (master's
  scoped-events/readme gates + this branch's website-api/website-yaml);
  js-yaml devDeps deduped (master added them independently).
- pnpm-workspace/knip: website AND python/sdk-runtime entries kept.
- doc-typecheck/verify-type-equiv: master's condensed headers kept, website
  glob retained in both scan scopes.
- vendor/cordis/src/fiber.ts: master's lifecycle-hardening code taken; this
  branch's richer FiberState JSDoc reapplied on top. vendor/README.md logs
  both local modifications (hardening = 6, JSDoc enrichment = 7).
- pnpm-lock: regenerated from master's side (pnpm install).

Post-merge sync the gates forced (the system working as designed):
- verify-website-yaml caught 4 stale plugin names from master's package
  reorg (dsh-stdio-agent -> dsh-stdio-demo, dsh-acp-agent -> dsh-acp-demo);
  8 references fixed across guide/ and develop/.
- gen-website-api picked up master's 6 new services automatically
  (ctx.approval/permission/sandbox/sessionQuery/skills/tasks -> 6 new pages
  + sidebar); api/index.md hub updated to list them.
- AGENTS.md budget ceiling 1370 -> 1400: the website rows (layout line + two
  command lines) and master's own growth collided with the old ceiling; all
  three website rows are load-bearing (new top-level dir, new CI command).
This commit is contained in:
lintianle
2026-07-16 21:36:43 +08:00
1132 changed files with 71533 additions and 19566 deletions

View File

@@ -1,40 +1,16 @@
/**
* Doc-sync gate: verify every ` ```ts type-equiv ` block in the docs is a
* VERBATIM copy of the source type definition it documents.
*
* The core-data-structures docs paste real type definitions so a reader sees
* the exact shape. A paste drifts the moment source changes — this script is
* the drift guard. For each block it extracts the documented symbol's
* declaration from source via the TypeScript compiler API, whitespace-
* normalizes both the source text and the block, and asserts they are equal.
*
* Provenance lives in a central manifest (`scripts/type-equiv.manifest.json`),
* NOT in the doc prose: each entry names `{ doc, symbol, source }`. The script
* enforces a 1:1 correspondence — every type-equiv block in the docs has
* exactly one manifest entry (keyed by doc + declared symbol), and every
* manifest entry resolves to exactly one block. An orphan on either side fails,
* so a block can never be silently unchecked and an entry can never rot.
*
* doc-typecheck.ts recognizes the same ` ```ts type-equiv ` fence and skips it
* (it is not standalone-compilable and is not counted in the opt-out ratio);
* the two scripts share the fence, this one owns the verification.
*
* Run: `tsx scripts/verify-type-equiv.ts`.
* Verify every `ts type-equiv` block against the source symbol named by the
* manifest. Blocks and entries have a one-to-one relationship; comparison
* ignores comments and whitespace but preserves declaration structure.
*/
import { globSync, readFileSync, existsSync } from 'node:fs'
import { resolve } from 'node:path'
import { resolve, sep } from 'node:path'
import ts from 'typescript'
const root = resolve(import.meta.dirname, '..')
/**
* Markdown globs scanned for ` ```ts type-equiv ` blocks — the SAME scope
* doc-typecheck uses. Scanning every doc (not only the docs the manifest names)
* is what makes the 1:1 guarantee real in both directions: a type-equiv block
* added to a doc with NO manifest entry is still discovered here and reported as
* an orphan, instead of being silently skipped.
*/
/** Scan doc-typecheck's full Markdown scope so unmanifested blocks also fail. */
const MARKDOWN_GLOBS = ['README.md', 'docs/**/*.md', 'packages/*/*.md', 'packages/*/*/*.md', 'website/zh-CN/**/*.md']
/** One manifest entry: a documented type-equiv block and its source symbol. */
@@ -58,12 +34,11 @@ interface EquivBlock {
code: string
}
/** Collapse a declaration to its structural form for comparison: drop comments
* (block + line), then collapse all whitespace runs to single spaces. This lets
* a doc block show a CLEAN definition (without source's verbose inline JSDoc)
* while still guaranteeing the field shapes match — drift in a field name or
* type fails; a reworded inline comment does not. Adequate for our own type
* source (no string literal contains `//` or `/* */`); not a general tokenizer. */
/**
* Remove comments and normalize whitespace so prose-only edits do not drift
* structural copies. This is intentionally not a general tokenizer: repo type
* declarations do not contain comment delimiters inside string literals.
*/
function normalize(code: string): string {
return code
.replace(/\/\*[\s\S]*?\*\//g, '')
@@ -72,8 +47,7 @@ function normalize(code: string): string {
.trim()
}
/** Strip a leading `export ` / `export default ` modifier — the doc block shows
* the bare declaration, the source carries the export modifier. */
/** Strip source-only export modifiers. */
function stripExport(code: string): string {
return code.replace(/^export\s+(default\s+)?/, '')
}
@@ -147,7 +121,7 @@ const keyOf = (x: { doc: string; symbol: string }): string => `${x.doc}::${x.sym
// as an orphan rather than silently skipped.
const docSet = new Set<string>()
for (const pattern of MARKDOWN_GLOBS) {
for (const match of globSync(pattern, { cwd: root })) docSet.add(match)
for (const match of globSync(pattern, { cwd: root })) docSet.add(match.split(sep).join('/'))
}
const blocks: EquivBlock[] = [...docSet].sort().flatMap(extractEquivBlocks)