Bladeren bron

build: two-step for packages/vendor build and README

imccyu 2 maanden geleden
bovenliggende
commit
ec9b093cb0

+ 2 - 2
AGENTS.md

@@ -88,7 +88,7 @@ pnpm run typecheck      # tsc -b tsconfig.build.json (declarations) + tsc -p
                     # tsconfig.typecheck.json (tests/examples typecheck too)
                     # tsconfig.typecheck.json (tests/examples typecheck too)
 pnpm run lint           # eslint .
 pnpm run lint           # eslint .
 pnpm run lint:fix       # eslint . --fix
 pnpm run lint:fix       # eslint . --fix
-pnpm run build          # tsc -b tsconfig.build.json && tsdown (JS bundles into lib/)
+pnpm run build          # tsc emits lib/typings, then tsdown bundles runtime lib/index.*
 pnpm run knip           # dead-code / unused-dependency check
 pnpm run knip           # dead-code / unused-dependency check
 pnpm run publint        # package.json publish-correctness check (publishable packages/*)
 pnpm run publint        # package.json publish-correctness check (publishable packages/*)
 pnpm run hygiene        # knip + publint + workspace constraints
 pnpm run hygiene        # knip + publint + workspace constraints
@@ -126,7 +126,7 @@ Dev/test/demo run **unbuilt** via tsx + the `paths` map in the root `tsconfig.js
 ## Conventions
 ## Conventions
 
 
 - **Package naming**: every npm package in this repo is `@deepseek-ai/dsh-<name>` (vendored packages keep their upstream names and are `private: true`).
 - **Package naming**: every npm package in this repo is `@deepseek-ai/dsh-<name>` (vendored packages keep their upstream names and are `private: true`).
-- **ESM everywhere** (`"type": "module"`); imports between workspace packages use package names, never relative paths across package boundaries. In-package imports use explicit `.ts` extensions (allowImportingTsExtensions).
+- **ESM everywhere** (`"type": "module"`); imports between workspace packages use package names, never relative paths across package boundaries. In-package relative imports are extensionless so generated `.d.ts` files stay extensionless; `lib/typings/**/*.js` is a bundler-only intermediate, not a Node ESM entrypoint.
 - **`cordis` is a peerDependency** (+ devDependency) of every harness package, mirroring upstream convention.
 - **`cordis` is a peerDependency** (+ devDependency) of every harness package, mirroring upstream convention.
 - **Registrations are effects**: anything a plugin contributes (adapter, tool, section, agent, event listener) goes through `ctx.effect()` / `ctx.on()` so disposal and HMR work. If you write a registry, `register()` must return the disposer.
 - **Registrations are effects**: anything a plugin contributes (adapter, tool, section, agent, event listener) goes through `ctx.effect()` / `ctx.on()` so disposal and HMR work. If you write a registry, `register()` must return the disposer.
 - **Typed events via declaration merging**: services declare their events in `declare module 'cordis' { interface Events { … } }`, and their ctx key in `interface Context`. Extensible unions use the merge-extensible-map pattern (see `ContentBlockMap`, `MessageSourceMap`).
 - **Typed events via declaration merging**: services declare their events in `declare module 'cordis' { interface Events { … } }`, and their ctx key in `interface Context`. Extensible unions use the merge-extensible-map pattern (see `ContentBlockMap`, `MessageSourceMap`).

+ 3 - 3
docs/cookbook/adding-a-package.md

@@ -7,7 +7,7 @@ The file-by-file checklist for a new `@deepseek-ai/dsh-<name>` package. (Verifie
 ```
 ```
 packages/<name>/
 packages/<name>/
   package.json     # copy from packages/tools, adjust name/description/deps
   package.json     # copy from packages/tools, adjust name/description/deps
-  tsconfig.json    # extends ../../tsconfig.base.json, rootDir src, outDir lib,
+  tsconfig.json    # extends ../../tsconfig.base.json, rootDir src, outDir lib/typings,
                    # references: vendor/cosmokit, vendor/cordis (+ vendor/schemastery
                    # references: vendor/cosmokit, vendor/cordis (+ vendor/schemastery
                    # if you use Config, + ../<dep> for each dsh dependency)
                    # if you use Config, + ../<dep> for each dsh dependency)
   src/index.ts     # service default export or plugin (name/inject/apply/Config)
   src/index.ts     # service default export or plugin (name/inject/apply/Config)
@@ -15,14 +15,14 @@ packages/<name>/
   README.md        # service API, events, extension points, design notes
   README.md        # service API, events, extension points, design notes
 ```
 ```
 
 
-package.json invariants (enforced by `pnpm run constraints` / `scripts/check-workspace-constraints.ts`): `private: true`, `version: 0.0.1`, `type: module`, `cordis` in BOTH peerDependencies and devDependencies (same range). Mirror every dsh peer dependency in devDependencies. `schemastery` goes in `dependencies` (it is a runtime validator), matching agent-loop.
+package.json invariants (enforced by `pnpm run constraints` / `scripts/check-workspace-constraints.ts`): `private: true`, `version: 0.0.1`, `type: module`, `main: "lib/index.js"`, `types: "lib/typings/index.d.ts"`, `exports["."].types: "./lib/typings/index.d.ts"`, `cordis` in BOTH peerDependencies and devDependencies (same range). Mirror every dsh peer dependency in devDependencies. `schemastery` goes in `dependencies` (it is a runtime validator), matching agent-loop. The `files` list is precise: `lib/index.js`, `lib/typings/**/*.d.ts`, and `src`; do not publish `lib/typings` JS/map intermediates or stale root declaration files.
 
 
 ## 2. Register it in the root configs
 ## 2. Register it in the root configs
 
 
 | File | Change |
 | File | Change |
 |---|---|
 |---|---|
 | `tsconfig.base.json` | add `"@deepseek-ai/dsh-<name>": ["./packages/<name>/src"]` to `paths` |
 | `tsconfig.base.json` | add `"@deepseek-ai/dsh-<name>": ["./packages/<name>/src"]` to `paths` |
-| `tsconfig.typecheck.json` | same entry (this file overrides the map wholesale) |
+| `tsconfig.json` | add `{ "path": "./packages/<name>" }` to `references` |
 | `tsconfig.build.json` | add `{ "path": "./packages/<name>" }` to `references` |
 | `tsconfig.build.json` | add `{ "path": "./packages/<name>" }` to `references` |
 | `scripts/publint-all.ts` | add `'packages/<name>'` to the array |
 | `scripts/publint-all.ts` | add `'packages/<name>'` to the array |
 | `knip.json` | only if the package has non-`*.spec.ts` entries (e.g. `*.e2e.ts` → add a per-workspace override like `packages/llm-deepseek`) |
 | `knip.json` | only if the package has non-`*.spec.ts` entries (e.g. `*.e2e.ts` → add a per-workspace override like `packages/llm-deepseek`) |

+ 7 - 7
docs/cookbook/adding-a-vendored-package.md

@@ -12,13 +12,13 @@ vendor/<dir>/
   README.md LICENSE # if upstream ships them
   README.md LICENSE # if upstream ships them
 ```
 ```
 
 
-`tsconfig.json` mirrors the other vendored packages — `rootDir: src`, `outDir: lib`, the strictness relaxations upstream code needs, and a `references` entry for every other vendored package it imports:
+`tsconfig.json` mirrors the other vendored packages — `rootDir: src`, `outDir: lib/typings`, the strictness relaxations upstream code needs, and a `references` entry for every other vendored package it imports:
 
 
 ```jsonc
 ```jsonc
 {
 {
   "extends": "../../tsconfig.base.json",
   "extends": "../../tsconfig.base.json",
   "compilerOptions": {
   "compilerOptions": {
-    "rootDir": "src", "outDir": "lib",
+    "rootDir": "src", "outDir": "lib/typings",
     "noUncheckedIndexedAccess": false, "exactOptionalPropertyTypes": false,
     "noUncheckedIndexedAccess": false, "exactOptionalPropertyTypes": false,
     "noImplicitOverride": false, "noUnusedLocals": false, "noUnusedParameters": false
     "noImplicitOverride": false, "noUnusedLocals": false, "noUnusedParameters": false
   },
   },
@@ -27,19 +27,19 @@ vendor/<dir>/
 }
 }
 ```
 ```
 
 
-`package.json` invariants: `"private": true` (vendored packages are never published), keep upstream's `name`/`version`/`exports`/`type`, and list its cordis deps in `peerDependencies` (matching the upstream manifest). Transitive upstream deps must themselves be vendored or already present — vendoring one package often means vendoring its dependency tree (e.g. `@cordisjs/plugin-http` pulls `@cordisjs/fetch-file`).
+`package.json` invariants: `"private": true` (vendored packages are never published), keep upstream's `name`/`version`/`exports`/`type`, point declaration metadata at `lib/typings`, and list its cordis deps in `peerDependencies` (matching the upstream manifest). Transitive upstream deps must themselves be vendored or already present — vendoring one package often means vendoring its dependency tree (e.g. `@cordisjs/plugin-http` pulls `@cordisjs/fetch-file`).
 
 
 ## 2. Register it in the root configs
 ## 2. Register it in the root configs
 
 
 | File | Change |
 | File | Change |
 |---|---|
 |---|---|
 | `tsconfig.base.json` | add `"<npm-name>": ["./vendor/<dir>/src"]` to `paths` |
 | `tsconfig.base.json` | add `"<npm-name>": ["./vendor/<dir>/src"]` to `paths` |
-| `tsconfig.typecheck.json` | add `"<npm-name>": ["./vendor/<dir>/lib"]` — this file points at built declarations, not src. If the package's `types` entry isn't `lib/index.d.ts`, point at that built file instead (e.g. `logger-console` maps to `./vendor/logger-console/lib/shared`, matching its `"types": "lib/shared.d.ts"`). |
+| `tsconfig.json` | add `{ "path": "./vendor/<dir>" }` to `references` |
 | `tsconfig.build.json` | add `{ "path": "./vendor/<dir>" }` to `references` (before the `packages/*` entries) |
 | `tsconfig.build.json` | add `{ "path": "./vendor/<dir>" }` to `references` (before the `packages/*` entries) |
 | `vendor/README.md` | add a manifest table row (dir, npm name, version, upstream repo, commit SHA) and log any local modifications |
 | `vendor/README.md` | add a manifest table row (dir, npm name, version, upstream repo, commit SHA) and log any local modifications |
 | `scripts/publint-all.ts` | only if the vendored package is itself published from here (vendored deps normally are not — skip) |
 | `scripts/publint-all.ts` | only if the vendored package is itself published from here (vendored deps normally are not — skip) |
 
 
-Covered automatically by globs — no edits needed: root `package.json` workspaces (`vendor/*`), `tsdown.config.ts`, `vitest.config.ts`, `eslint.config.mjs`. A per-package `vendor/<dir>/tsdown.config.ts` is needed ONLY if the build shape diverges from the root default (dual ESM/CJS or multiple entries — see `vendor/schemastery` and `vendor/logger-console`).
+Covered automatically by globs — no edits needed: root `package.json` workspaces (`vendor/*`), `tsdown.config.ts`, `vitest.config.ts`, `eslint.config.mjs`. A per-package `vendor/<dir>/tsdown.config.ts` is needed ONLY if the build shape diverges from the root default (dual ESM/CJS or multiple entries — see `vendor/schemastery` and `vendor/logger-console`); its entry should read the JS emitted under `lib/typings`.
 
 
 ## 3. Mind the manifest guard
 ## 3. Mind the manifest guard
 
 
@@ -49,8 +49,8 @@ Covered automatically by globs — no edits needed: root `package.json` workspac
 
 
 ```sh
 ```sh
 pnpm install        # registers the workspace
 pnpm install        # registers the workspace
-pnpm run typecheck  # the base→lib path split means: run once after a fresh add
+pnpm run typecheck
 pnpm run build && pnpm run test && pnpm run constraints
 pnpm run build && pnpm run test && pnpm run constraints
 ```
 ```
 
 
-Note the `tsconfig` two-map split (called out in [AGENTS.md](../../AGENTS.md) § Secrets/.env): `lint`'s type-aware rules resolve vendored packages through their built `lib/` declarations, so run `pnpm run typecheck` (which builds them) once after adding the package or lint reports unresolved-type errors.
+The source `paths` map is shared by build and root typecheck configs. The important isolation boundary is the project-reference graph: vendored source must be referenced through its own `vendor/<dir>/tsconfig.json`, not pulled into a root strict program.

+ 1 - 1
docs/development.md

@@ -98,7 +98,7 @@ pnpm run verify-md-wrap  # fail on hard-wrapped prose paragraphs in docs/README
 pnpm run doc-sync       # doc-typecheck, event taxonomy, and markdown wrap verification
 pnpm run doc-sync       # doc-typecheck, event taxonomy, and markdown wrap verification
 pnpm run gen-module-graph     # regenerate docs/module-graph.md from package peerDeps
 pnpm run gen-module-graph     # regenerate docs/module-graph.md from package peerDeps
 pnpm run verify-module-graph  # fail if docs/module-graph.md is stale
 pnpm run verify-module-graph  # fail if docs/module-graph.md is stale
-pnpm run build          # build declarations and JS bundles
+pnpm run build          # emit lib/typings intermediates, then bundle lib/index.* runtime files
 pnpm run hygiene        # knip, publint, and workspace constraints
 pnpm run hygiene        # knip, publint, and workspace constraints
 ```
 ```
 
 

+ 1 - 0
package.json

@@ -13,6 +13,7 @@
   ],
   ],
   "scripts": {
   "scripts": {
     "build": "tsc -b tsconfig.build.json && tsdown",
     "build": "tsc -b tsconfig.build.json && tsdown",
+    "clean:build": "rm -rf .typecheck packages/*/lib vendor/*/lib *.tsbuildinfo",
     "typecheck": "tsc -b tsconfig.build.json && tsc -p tsconfig.typecheck.json",
     "typecheck": "tsc -b tsconfig.build.json && tsc -p tsconfig.typecheck.json",
     "lint": "eslint .",
     "lint": "eslint .",
     "lint:fix": "eslint . --fix",
     "lint:fix": "eslint . --fix",

+ 1 - 1
packages/README.md

@@ -60,5 +60,5 @@ Each package has its own `README.md` with purpose, service API, events, extensio
 - **Declaration merging for events and ctx**: services declare their events in `declare module 'cordis' { interface Events { ... } }` and their ctx key in `interface Context`.
 - **Declaration merging for events and ctx**: services declare their events in `declare module 'cordis' { interface Events { ... } }` and their ctx key in `interface Context`.
 - **Waterfall semantics**: `ctx.waterfall` listeners receive `(...args, next)` and MUST call `next()` to delegate; returning without it short-circuits (the veto mechanism).
 - **Waterfall semantics**: `ctx.waterfall` listeners receive `(...args, next)` and MUST call `next()` to delegate; returning without it short-circuits (the veto mechanism).
 - **Extensible unions**: `ContentBlockMap`, `MessageSourceMap`, `FinishReasonMap`, `TurnTriggerMap`, `TurnEndReasonMap`, and `SessionEventMap` use the merge-extensible-map pattern so plugins can add variants via declaration merging.
 - **Extensible unions**: `ContentBlockMap`, `MessageSourceMap`, `FinishReasonMap`, `TurnTriggerMap`, `TurnEndReasonMap`, and `SessionEventMap` use the merge-extensible-map pattern so plugins can add variants via declaration merging.
-- **ESM everywhere**; imports use package names across package boundaries, `.ts` extensions within a package.
+- **ESM everywhere**; imports use package names across package boundaries and extensionless relative specifiers within a package.
 - **Tests**: vitest, colocated under `packages/<name>/tests/*.spec.ts`. Every registry needs an HMR-safety test. Err on the side of more tests.
 - **Tests**: vitest, colocated under `packages/<name>/tests/*.spec.ts`. Every registry needs an HMR-safety test. Err on the side of more tests.

+ 18 - 2
pnpm-lock.yaml

@@ -49,7 +49,7 @@ importers:
         version: 0.3.21
         version: 0.3.21
       tsdown:
       tsdown:
         specifier: ^0.22.2
         specifier: ^0.22.2
-        version: 0.22.2(oxc-resolver@11.20.0)(publint@0.3.21)(tsx@4.22.4)(typescript@6.0.3)
+        version: 0.22.2(oxc-resolver@11.20.0)(publint@0.3.21)(tsx@4.22.4)(typescript@6.0.3)(unrun@0.3.1)
       tsx:
       tsx:
         specifier: ^4.22.4
         specifier: ^4.22.4
         version: 4.22.4
         version: 4.22.4
@@ -2620,6 +2620,16 @@ packages:
   unist-util-visit@5.1.0:
   unist-util-visit@5.1.0:
     resolution: {integrity: sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==}
     resolution: {integrity: sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==}
 
 
+  unrun@0.3.1:
+    resolution: {integrity: sha512-onIck/oNnCaytwths1ZVp1LK2Gq2hPoyFhiHebObuUXqR3S0uHuLLaBK8K6mRRgV7Ptip8AnNvaUsgzwWwBZuA==}
+    engines: {node: ^22.13.0 || >=24.0.0}
+    hasBin: true
+    peerDependencies:
+      synckit: ^0.11.11
+    peerDependenciesMeta:
+      synckit:
+        optional: true
+
   uri-js@4.4.1:
   uri-js@4.4.1:
     resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
     resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
 
 
@@ -4933,7 +4943,7 @@ snapshots:
     optionalDependencies:
     optionalDependencies:
       typescript: 6.0.3
       typescript: 6.0.3
 
 
-  tsdown@0.22.2(oxc-resolver@11.20.0)(publint@0.3.21)(tsx@4.22.4)(typescript@6.0.3):
+  tsdown@0.22.2(oxc-resolver@11.20.0)(publint@0.3.21)(tsx@4.22.4)(typescript@6.0.3)(unrun@0.3.1):
     dependencies:
     dependencies:
       ansis: 4.3.1
       ansis: 4.3.1
       cac: 7.0.0
       cac: 7.0.0
@@ -4954,6 +4964,7 @@ snapshots:
       publint: 0.3.21
       publint: 0.3.21
       tsx: 4.22.4
       tsx: 4.22.4
       typescript: 6.0.3
       typescript: 6.0.3
+      unrun: 0.3.1
     transitivePeerDependencies:
     transitivePeerDependencies:
       - '@ts-macro/tsc'
       - '@ts-macro/tsc'
       - '@typescript/native-preview'
       - '@typescript/native-preview'
@@ -5015,6 +5026,11 @@ snapshots:
       unist-util-is: 6.0.1
       unist-util-is: 6.0.1
       unist-util-visit-parents: 6.0.2
       unist-util-visit-parents: 6.0.2
 
 
+  unrun@0.3.1:
+    dependencies:
+      rolldown: 1.1.1
+    optional: true
+
   uri-js@4.4.1:
   uri-js@4.4.1:
     dependencies:
     dependencies:
       punycode: 2.3.1
       punycode: 2.3.1

+ 5 - 7
tsconfig.base.json

@@ -4,12 +4,12 @@
     "module": "esnext",
     "module": "esnext",
     "moduleResolution": "bundler",
     "moduleResolution": "bundler",
     "declaration": true,
     "declaration": true,
-    "emitDeclarationOnly": true,
+    "sourceMap": true,
+    "declarationMap": true,
     "composite": true,
     "composite": true,
     "incremental": true,
     "incremental": true,
     "skipLibCheck": true,
     "skipLibCheck": true,
     "esModuleInterop": true,
     "esModuleInterop": true,
-    "allowImportingTsExtensions": true,
     "verbatimModuleSyntax": false,
     "verbatimModuleSyntax": false,
     "strict": true,
     "strict": true,
     "noUncheckedIndexedAccess": true,
     "noUncheckedIndexedAccess": true,
@@ -19,11 +19,9 @@
     "noUnusedLocals": true,
     "noUnusedLocals": true,
     "noUnusedParameters": true,
     "noUnusedParameters": true,
     "types": ["node"],
     "types": ["node"],
-    // Source-level resolution for the build graph: without this, a fresh
-    // checkout's first `tsc -b` resolves sibling vendor plugins through their
-    // package.json types (vendor/*/lib/*.d.ts) which don't exist yet — TS2307
-    // until a second run. Derived configs that want lib resolution
-    // (tsconfig.typecheck.json) override this map wholesale.
+    // Source-level resolution for every repo-local graph. Project references,
+    // not declaration path aliases, keep each package/vendor source compiled
+    // under its own tsconfig boundary.
     "paths": {
     "paths": {
       "cordis": ["./vendor/cordis/src"],
       "cordis": ["./vendor/cordis/src"],
       "cosmokit": ["./vendor/cosmokit/src"],
       "cosmokit": ["./vendor/cosmokit/src"],

+ 5 - 5
tsdown.config.ts

@@ -1,10 +1,10 @@
 import { defineConfig } from 'tsdown'
 import { defineConfig } from 'tsdown'
 
 
 /**
 /**
- * JS bundling for all workspace packages (vendor/* + packages/*).
- * Declarations are NOT produced here — `tsc -b tsconfig.build.json` owns
- * .d.ts output (composite project references); hence `dts: false` and
- * `clean: false` (lib/ already holds tsc's declarations).
+ * Runtime bundling for all workspace packages (vendor/* + packages/*).
+ * TypeScript source is compiled first by `tsc -b tsconfig.build.json`; tsdown
+ * reads only the emitted JS under lib/typings and writes lib/index.* runtime
+ * bundles. Declarations are NOT produced here, hence `dts: false`.
  *
  *
  * Per-package shape overrides live in `<package>/tsdown.config.ts`
  * Per-package shape overrides live in `<package>/tsdown.config.ts`
  * (schemastery: dual ESM+CJS; logger-console: extra browser entry).
  * (schemastery: dual ESM+CJS; logger-console: extra browser entry).
@@ -13,7 +13,7 @@ export default defineConfig({
   // Explicit globs: `workspace: true` would also discover examples/* (any
   // Explicit globs: `workspace: true` would also discover examples/* (any
   // package.json), but only vendor/* and packages/* are pnpm workspaces.
   // package.json), but only vendor/* and packages/* are pnpm workspaces.
   workspace: ['vendor/*', 'packages/*'],
   workspace: ['vendor/*', 'packages/*'],
-  entry: ['src/index.ts'],
+  entry: ['lib/typings/index.js'],
   outDir: 'lib',
   outDir: 'lib',
   format: ['esm'],
   format: ['esm'],
   platform: 'node',
   platform: 'node',

+ 6 - 5
vendor/logger-console/tsdown.config.ts

@@ -3,9 +3,10 @@ import { defineConfig } from 'tsdown'
 /**
 /**
  * logger-console ships two entries: the node exporter (index) and the
  * logger-console ships two entries: the node exporter (index) and the
  * browser exporter (browser), selected via package.json `exports`
  * browser exporter (browser), selected via package.json `exports`
- * conditions. They are built as two single-entry passes so the shared
- * base class is inlined into each (matching upstream's published shape)
- * instead of split into a hash-named chunk.
+ * conditions. The entries are JS emitted by tsc under lib/typings and are
+ * bundled as two single-entry passes so the shared base class is inlined into
+ * each (matching upstream's published shape) instead of split into a hash-named
+ * chunk.
  */
  */
 const shared = {
 const shared = {
   outDir: 'lib',
   outDir: 'lib',
@@ -18,6 +19,6 @@ const shared = {
 } as const
 } as const
 
 
 export default defineConfig([
 export default defineConfig([
-  { ...shared, entry: ['src/index.ts'] },
-  { ...shared, entry: ['src/browser.ts'] },
+  { ...shared, entry: ['lib/typings/index.js'] },
+  { ...shared, entry: ['lib/typings/browser.js'] },
 ])
 ])

+ 4 - 4
vendor/schemastery/tsdown.config.ts

@@ -2,12 +2,12 @@ import { defineConfig } from 'tsdown'
 
 
 /**
 /**
  * schemastery has no `"type": "module"` and publishes dual-format output
  * schemastery has no `"type": "module"` and publishes dual-format output
- * (package.json: main → lib/index.cjs, module → lib/index.mjs). Pin the
- * extensions explicitly — the defaults for a CommonJS package would emit
- * .mjs/.js instead.
+ * (package.json: main → lib/index.cjs, module → lib/index.mjs). The entry is
+ * the JS emitted by tsc under lib/typings; pin the bundled extensions
+ * explicitly because the defaults for a CommonJS package would emit .mjs/.js.
  */
  */
 export default defineConfig({
 export default defineConfig({
-  entry: ['src/index.ts'],
+  entry: ['lib/typings/index.js'],
   outDir: 'lib',
   outDir: 'lib',
   format: ['esm', 'cjs'],
   format: ['esm', 'cjs'],
   platform: 'node',
   platform: 'node',