Merge pull request #181 from deepseek-harness/worktree-node-22-18-compat
build: lower the Node engines floor to 22.19
This commit is contained in:
@@ -95,13 +95,13 @@ jobs:
|
||||
|
||||
node-compat:
|
||||
runs-on: ubuntu-latest
|
||||
name: node 26
|
||||
name: node ${{ matrix.node }}
|
||||
env:
|
||||
DSH_GATE_CONCURRENCY: '2'
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
node: [26]
|
||||
node: ['22.19', 24, 26]
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
|
||||
@@ -49,6 +49,7 @@ permissions:
|
||||
jobs:
|
||||
e2e:
|
||||
runs-on: ubuntu-latest
|
||||
name: e2e
|
||||
# Run on every trusted event. Skip untrusted PRs (forks + Dependabot) where
|
||||
# the secret is withheld — they would otherwise hard-fail the preflight.
|
||||
if: >-
|
||||
|
||||
@@ -34,7 +34,7 @@ Per-package map: the group READMEs, indexed from [packages/README.md](packages/R
|
||||
## Commands
|
||||
|
||||
```sh
|
||||
pnpm install # pnpm workspaces, node >= 24
|
||||
pnpm install # pnpm workspaces, node ^22.19 || >=24
|
||||
pnpm run test # vitest unit tests
|
||||
pnpm run test:coverage # THE gating test run: per-file 100% coverage on packages/*/*/src
|
||||
pnpm run test:e2e # real-API tests; self-skip without DEEPSEEK_API_KEY
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@ Every fact has exactly one home — the tier whose job it is — and every other
|
||||
| [postmortem/](postmortem/README.md) | Incident stories — the only tier where war-story narrative belongs | — |
|
||||
| [cookbook/](cookbook/adding-a-package.md) | Step-by-step how-tos with numbered verify steps | Design rationale (→ the RFC each guide links) |
|
||||
| Package README | The per-package contract: config, semantics, limitations, extension points | JSDoc restatement, generated-catalog restatement (event/tool tables), other packages' concerns |
|
||||
| [development.md](development.md) | Human-facing setup and daily workflow; a bilingual pair under the [i18n contract](i18n/README.md) | Gate-by-gate enumerations that drift from `package.json` scripts |
|
||||
| [development.md](development.md) | First-stop contributor onboarding: local setup, daily workflow, and CI shape at summary level; a bilingual pair under the [i18n contract](i18n/README.md) | Runtime/version rationale (→ RFCs), gate-by-gate enumerations that drift from `package.json` scripts |
|
||||
| Generated catalogs: [cordis events](cordis-catalog/events.md), [cordis services](cordis-catalog/services.md), [tool-catalog](tool-catalog.md), [config-catalog](config-catalog.md), [persistence-catalog](persistence-catalog.md), [module-graph.md](module-graph.md) | Exhaustive enumerations regenerated from source, freshness-gated | Hand edits of any kind |
|
||||
| Skills (`.agents/skills/`) | Workflows: how to carry out a recurring task against the contracts | The contracts themselves (→ docs) |
|
||||
|
||||
|
||||
@@ -91,4 +91,4 @@ Selection never depends on registration, config, or HMR order: a capability has
|
||||
|
||||
## The service
|
||||
|
||||
`WebService` (`ctx.web`, defined in [`packages/web/web/src/index.ts`](../../packages/web/web/src/index.ts)) is a provider registry plus a provider-selecting execution surface, close to `LlmService`'s shape: `registerSearchProvider`/`registerFetchProvider` (duplicate ids throw `WEB_DUPLICATE_PROVIDER`, return disposers) and `search`/`fetch` (resolve the provider at call time, throw a structured `WebError` when the capability cannot run). Providers issue requests with the platform-native `fetch` (Node 24), mirroring `dsh-llm-deepseek`; the `dsh-web-fetch-local` provider owns safe retrieval (http/https-only, credential rejection, byte/char/timeout/redirect caps, same-origin-only redirects with per-hop re-validation, charset decoding) while `dsh-tool-web` owns presentation (HTML→markdown). SSRF / private-network blocking is deferred (see the RFC) — until it lands, `web_fetch` must not be enabled where it can reach sensitive internal targets.
|
||||
`WebService` (`ctx.web`, defined in [`packages/web/web/src/index.ts`](../../packages/web/web/src/index.ts)) is a provider registry plus a provider-selecting execution surface, close to `LlmService`'s shape: `registerSearchProvider`/`registerFetchProvider` (duplicate ids throw `WEB_DUPLICATE_PROVIDER`, return disposers) and `search`/`fetch` (resolve the provider at call time, throw a structured `WebError` when the capability cannot run). Providers issue requests with platform-native `fetch` at the repo's Node floor, mirroring `dsh-llm-deepseek`; the `dsh-web-fetch-local` provider owns safe retrieval (http/https-only, credential rejection, byte/char/timeout/redirect caps, same-origin-only redirects with per-hop re-validation, charset decoding) while `dsh-tool-web` owns presentation (HTML→markdown). SSRF / private-network blocking is deferred (see the RFC) — until it lands, `web_fetch` must not be enabled where it can reach sensitive internal targets.
|
||||
@@ -2,5 +2,5 @@
|
||||
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write
|
||||
development.md: 9f63dafdaa533d6340440ab7b7cb2b793ff1d10c
|
||||
development.zh.md: cabfc2dc10a63bc15bdea0bf740044e61acd4480
|
||||
development.md: bd6f6b561480419abea7a42a44b4078e2c59b1cb
|
||||
development.zh.md: 54bf19765d2b4dc419e6b71684dbcfcd28230541
|
||||
+4
-4
@@ -2,11 +2,11 @@
|
||||
|
||||
English | [中文](development.zh.md)
|
||||
|
||||
This guide covers the local setup needed to work on DeepSeek Harness and understand the local hooks, daily checks, and CI gates.
|
||||
This onboarding guide helps project contributors get started with the local environment, daily workflow, and CI flow; see the RFCs for design rationale and technical trade-offs.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Node.js 24 or newer. The repo declares `node >=24`; CI runs the matrix on Node 24 and 26.
|
||||
- Node.js supports 22.19+ and 24+. CI covers 22.19, 24, and 26; see the [Node engine floor RFC](rfc/implemented/process/2026-07-06-node-engine-floor.md).
|
||||
- Corepack-enabled pnpm. The repo pins `pnpm@11.7.0` in `package.json`; run `corepack enable` if `pnpm --version` does not resolve through Corepack.
|
||||
- Git.
|
||||
- Optional: a DeepSeek API key for the REPL/ACP agent demos and real-API e2e tests.
|
||||
@@ -63,11 +63,11 @@ lefthook is configured in `lefthook.yml` as an early local checkpoint before rev
|
||||
|
||||
The vendor manifest guard checks that changes under `vendor/*/src` are staged with the matching `vendor/README.md` manifest update. See `vendor/README.md` before editing vendored code.
|
||||
|
||||
These hooks do not exactly mirror CI. Notably, `pre-push` runs unit tests without coverage, while CI runs `pnpm run test:coverage`; CI also runs echo-agent and built-bin smoke tests and exercises the matrix on Node 24 and 26.
|
||||
These hooks do not exactly mirror CI. Notably, `pre-push` runs unit tests without coverage, while CI runs `pnpm run test:coverage`; CI also runs echo-agent and built-bin smoke tests and exercises the compatibility matrix on Node 22.19, 24, and 26.
|
||||
|
||||
## CI gates
|
||||
|
||||
The keyless GitHub workflow has six jobs: five Node 24 lanes run static gates, lint, coverage, snapshot replay, and artifact gates separately, and the Node 26 compatibility job runs `pnpm run check:node-compat`. The lane schedulers fan out independent gates from `package.json`: constraints, typecheck, lint, coverage, snapshot replay, `doc-sync` members, module-graph freshness, `knip`, and the echo-agent smoke test.
|
||||
The keyless GitHub workflow has eight jobs: five Node 24 lanes run static gates, lint, coverage, snapshot replay, and artifact gates separately, and three compatibility jobs run `pnpm run check:node-compat` on Node 22.19, 24, and 26. The lane schedulers fan out independent gates from `package.json`: constraints, typecheck, lint, coverage, snapshot replay, `doc-sync` members, module-graph freshness, `knip`, and the echo-agent smoke test.
|
||||
|
||||
`pnpm run build` feeds the artifact lane, and `publint`, `verify-node-next-types`, and built-bin smoke tests wait for build output. The separate real-API workflow runs `pnpm run test:e2e` with a secret and `DSH_E2E_MAX_WORKERS=14`.
|
||||
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
|
||||
[English](development.md) | 中文
|
||||
|
||||
本指南覆盖参与 DeepSeek Harness 开发所需的本地环境搭建,并帮助你理解本地钩子、日常检查与 CI 门禁。
|
||||
本文面向参与项目开发的贡献者,帮助你上手本地环境、日常工作流和 CI 流程。相关设计考量和技术取舍参见 RFC,不在这里展开。
|
||||
|
||||
## 前置条件
|
||||
|
||||
- Node.js 24 或更新版本。仓库声明 `node >=24`;CI 在 Node 24 和 26 上跑矩阵。
|
||||
- Node.js 支持 22.19+ 和 24+。CI 覆盖 22.19、24、26;见 [Node engine floor RFC](rfc/implemented/process/2026-07-06-node-engine-floor.md)。
|
||||
- 启用了 Corepack 的 pnpm。仓库在 `package.json` 中钉住 `pnpm@11.7.0`;如果 `pnpm --version` 无法通过 Corepack 解析,先运行 `corepack enable`。
|
||||
- Git。
|
||||
- 可选:一个 DeepSeek API key,用于 REPL/ACP agent(智能体)演示和真实 API 的 e2e 测试。
|
||||
@@ -63,11 +63,11 @@ lefthook 在 `lefthook.yml` 中配置,作为评审前的本地早期检查点
|
||||
|
||||
vendor manifest 守卫检查 `vendor/*/src` 下的改动是否连同对应的 `vendor/README.md` manifest 更新一起暂存。编辑 vendor 代码前先看 `vendor/README.md`。
|
||||
|
||||
这些钩子并不与 CI 完全一致。特别是:`pre-push` 跑不带覆盖率的单元测试,而 CI 跑 `pnpm run test:coverage`;CI 还会跑 echo-agent 和 built-bin 冒烟测试,并在 Node 24 和 26 上跑矩阵。
|
||||
这些钩子并不与 CI 完全一致。特别是:`pre-push` 跑不带覆盖率的单元测试,而 CI 跑 `pnpm run test:coverage`;CI 还会跑 echo-agent 和 built-bin 冒烟测试,并在 Node 22.19、24 和 26 上跑兼容性矩阵。
|
||||
|
||||
## CI 门禁
|
||||
|
||||
keyless GitHub 工作流有六个 job:五个 Node 24 lane 分别运行 static gates、lint、coverage、snapshot replay 和 artifact gates,Node 26 兼容性 job 运行 `pnpm run check:node-compat`。各 lane 调度器并发运行来自 `package.json` 的独立门禁:constraints、typecheck、lint、coverage、snapshot replay、`doc-sync` 成员、module graph 新鲜度、`knip` 和 echo-agent 冒烟测试。
|
||||
keyless GitHub 工作流有八个 job:五个 Node 24 lane 分别运行 static gates、lint、coverage、snapshot replay 和 artifact gates,三个兼容性 job 在 Node 22.19、24 和 26 上运行 `pnpm run check:node-compat`。各 lane 调度器并发运行来自 `package.json` 的独立门禁:constraints、typecheck、lint、coverage、snapshot replay、`doc-sync` 成员、module graph 新鲜度、`knip` 和 echo-agent 冒烟测试。
|
||||
|
||||
`pnpm run build` 供给 artifact lane,`publint`、`verify-node-next-types` 和 built-bin 冒烟测试等待 build 输出。单独的真实 API 工作流带密钥运行 `pnpm run test:e2e`,并设置 `DSH_E2E_MAX_WORKERS=14`。
|
||||
|
||||
|
||||
@@ -146,6 +146,7 @@ Generated by `pnpm run gen-rfc-index` from the RFC tree — never edit by hand;
|
||||
| [One gated in-file format for RFCs](implemented/process/2026-07-05-uniform-rfc-format.md) | 2026-07-05 |
|
||||
| [Export-surface JSDoc gate](implemented/process/2026-07-06-export-surface-jsdoc-gate.md) | 2026-07-06 |
|
||||
| [Generated plugin config catalog](implemented/process/2026-07-06-generated-config-catalog.md) | 2026-07-06 |
|
||||
| [Raise the Node LTS engine floor to 22.19](implemented/process/2026-07-06-node-engine-floor.md) | 2026-07-06 |
|
||||
| [Parallel GitHub CI gates](implemented/process/2026-07-06-parallel-github-ci-gates.md) | 2026-07-06 |
|
||||
| [Parallel pre-push gates](implemented/process/2026-07-06-parallel-pre-push-gates.md) | 2026-07-06 |
|
||||
|
||||
|
||||
@@ -66,7 +66,7 @@ flowchart LR
|
||||
|
||||
`@deepseek-ai/dsh-web` depends only on Cordis and low-level harness support. It declares `ctx.web`, provider interfaces, request/result types, the provider status type, and error codes. It does not import tool, agent, session, LLM, or provider packages.
|
||||
|
||||
Provider packages depend on `@deepseek-ai/dsh-web` and Cordis. They own credentials, endpoint config, provider-specific request mapping, provider-specific response parsing, and provider-specific error translation into `WebError`. They issue network requests with the platform-native `fetch` (Node 24), mirroring `@deepseek-ai/dsh-llm-deepseek`'s adapter, NOT a cordis HTTP-client service (`ctx.http`/`@cordisjs/plugin-http`) — even where a Perplexity provider's request is shaped like an OpenAI-compatible chat completion, that wire shape is a provider-private detail and does not make the provider depend on `ctx.llm`. A provider does NOT own the `ctx.web` key (two search providers cannot both own it): like `dsh-llm-deepseek`, each provider package is a function/namespace plugin (`inject: ['web']`) whose `apply` constructs the backend and calls `ctx.web.registerSearchProvider` / `registerFetchProvider`. `@deepseek-ai/dsh-web` is the `export default` service that owns the key.
|
||||
Provider packages depend on `@deepseek-ai/dsh-web` and Cordis. They own credentials, endpoint config, provider-specific request mapping, provider-specific response parsing, and provider-specific error translation into `WebError`. They issue network requests with platform-native `fetch` at the repo's Node floor, mirroring `@deepseek-ai/dsh-llm-deepseek`'s adapter, NOT a cordis HTTP-client service (`ctx.http`/`@cordisjs/plugin-http`) — even where a Perplexity provider's request is shaped like an OpenAI-compatible chat completion, that wire shape is a provider-private detail and does not make the provider depend on `ctx.llm`. A provider does NOT own the `ctx.web` key (two search providers cannot both own it): like `dsh-llm-deepseek`, each provider package is a function/namespace plugin (`inject: ['web']`) whose `apply` constructs the backend and calls `ctx.web.registerSearchProvider` / `registerFetchProvider`. `@deepseek-ai/dsh-web` is the `export default` service that owns the key.
|
||||
|
||||
`@deepseek-ai/dsh-tool-web` depends on `@deepseek-ai/dsh-web`, `@deepseek-ai/dsh-tools`, `@deepseek-ai/dsh-system-prompt`, and Cordis. It never imports concrete provider packages.
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ Every AGENTS.md promise gets a command that exits non-zero, wired into git hooks
|
||||
- ESLint strict-type-checked + @stylistic (the house style, enforced); vendored code excluded.
|
||||
- Per-file 100% coverage on `packages/*/src` (v8); unreachable defensive guards carry `/* v8 ignore */ ` with stated reasons instead of deletion.
|
||||
- knip (dead code/deps), publint (package correctness), workspace constraints (workspace rules: private, cordis peer+dev, uniform version, ESM), and a NodeNext consumer typecheck for built package declarations.
|
||||
- lefthook pre-commit (lint staged, typecheck, vendor-manifest guard) and pre-push (tests, hygiene); CI runs the full matrix on node 24/26 plus a demo smoke test driving the echo-agent end to end.
|
||||
- lefthook pre-commit (lint staged, typecheck, vendor-manifest guard) and pre-push (tests, hygiene); CI runs the full matrix on node 22.19/24/26 plus a demo smoke test driving the echo-agent end to end.
|
||||
|
||||
## Consequences
|
||||
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
# RFC: Raise the Node LTS engine floor to 22.19
|
||||
|
||||
Status: implemented
|
||||
|
||||
## Problem
|
||||
|
||||
The Node 22 branch of the root `engines.node` range is a contract for the installed workspace, not only for the runtime APIs the harness source calls directly. It must be no lower than package `engines.node` declarations for dependencies the workspace installs on that branch; otherwise `pnpm install --engine-strict` fails at an advertised LTS version, and non-strict installs run outside a dependency's supported runtime.
|
||||
|
||||
## Decision
|
||||
|
||||
Set `engines.node` to `^22.19.0 || >=24.0.0` and test the keyless CI compatibility matrix on `['22.19', 24, 26]`. The real-API e2e workflow stays on Node 24 because it exercises API integration rather than the runtime floor.
|
||||
|
||||
Two Node features gate the source runtime:
|
||||
|
||||
- **`node:sqlite`** — `packages/session-persistence/session-persistence-sqlite` does a top-level `import { DatabaseSync } from 'node:sqlite'`. The module dropped its `--experimental-sqlite` flag requirement at **22.13** (LTS) and **23.4** (Current); before those, importing it throws at load.
|
||||
- **Native TypeScript type-stripping** — the `packages/ui/stdio-agent/tests/built-bin.e2e.ts` smoke boots the published `lib/bin.js` under plain `node` (no tsx) and loads the example's `.ts` plugins (`mock-llm.ts`, `echo-tool.ts`). Type-stripping is the default from **22.18** (LTS) and **23.6** (Current); before those it needs `--experimental-strip-types`.
|
||||
|
||||
Those source features clear on the 22.x line at **22.18**, but the installed Pi adapter dependency raises the advertised LTS floor. `@deepseek-ai/dsh-llm-pi-ai` depends on `@earendil-works/pi-ai@0.79.3`, whose package declares `engines.node >=22.19.0`, so the LTS floor is **22.19**. The 24.x branch remains `>=24.0.0`. The disjoint range excludes Node 23 entirely: Node 23.0–23.5 still has at least one flagged source feature, and the 23 line is non-LTS/EOL, so advertising `>=23.6` would add a dead release line and a CI leg no deployment should use.
|
||||
|
||||
`@types/node` remains pinned to the 22.x line (`^22.20.0`) to match the LTS support line: reaching for a Node 23+/24+/25+ API fails `tsc` on every machine and in the typecheck gate, rather than compiling clean and surviving to a runtime failure only a floor matrix leg could catch. The whole tree typechecks clean against the Node 22 type surface today, so the pin costs nothing.
|
||||
|
||||
## Consequences
|
||||
|
||||
- The advertised LTS branch no longer undercuts the Pi adapter dependency floor.
|
||||
- CI proves the Node 22 LTS floor directly with Node 22.19, keeps the Node 24 branch on `node: 24`, and keeps Node 26 for the next even line.
|
||||
- The built-bin smoke needs no version-conditional flag: at 22.19 type-stripping is already the default, so the test stays the plain `node lib/bin.js` path it documents.
|
||||
- A future dependency or source API that raises the runtime floor must move `engines.node`, the compatibility matrix, and this RFC in the same change.
|
||||
|
||||
## Alternatives considered
|
||||
|
||||
- **Keep `^22.18.0 || >=24.0.0`.** Rejected: it advertises an LTS version lower than the Pi adapter dependency floor. `@earendil-works/pi-ai@0.79.3` requires `>=22.19.0`.
|
||||
- **Downgrade or pin `@earendil-works/pi-ai` to preserve the 22.18 advertised range.** Rejected: the current Pi adapter dependency is part of the intended workspace, and 22.19 is still inside the Node 22 LTS line.
|
||||
- **Floor `>=22.13` (the `node:sqlite` boundary) plus `--experimental-strip-types` in the built-bin smoke on 22.13–22.17.** Rejected: it adds a version-conditional test flag for one narrow range and dresses up an experimental-flag dependency as first-class support. The Pi adapter dependency already requires a higher LTS floor.
|
||||
- **Open-ended `>=22.19`.** Rejected: it advertises support for Node 23.0–23.5, where `node:sqlite` (until 23.4) or type-stripping (until 23.6) is still flagged.
|
||||
- **Include Node 23.6+ (`^22.19.0 || >=23.6.0`).** Rejected: 23.6+ does run both source features unflagged, but Node 23 is end-of-life; advertising a dead release line adds a range term and a CI leg for a runtime no deployment should use.
|
||||
- **Matrix `[22, 24, 26]` instead of pinning `22.19`.** Rejected: floating major-version entries drift upward over time and silently stop exercising the declared LTS floor.
|
||||
- **Keep `@types/node` ahead of the floor (`^25`).** Rejected: types ahead of the runtime floor let a Node 24/25-only API compile clean and fail only at runtime on 22.x. Pinning `@types/node` to the 22.x line turns that into a compile error everywhere.
|
||||
@@ -54,7 +54,7 @@ The repo secret is named `DEEPSEEK_API_KEY_EXTERNAL`; it is mapped to the `DEEPS
|
||||
|
||||
### Scope, runtime shape
|
||||
|
||||
Run **only** `test:e2e`. The keyless gates (typecheck/lint/coverage/snapshot/build/hygiene) already run in ci.yml on every push and PR; repeating them here would duplicate signal and slow the real-API job. No build step — e2e tests run unbuilt via tsx + the tsconfig paths map. Single Node 24 (the `engines` floor): these tests exercise *API integration*, not node-version compat, which ci.yml's Node 24/26 jobs already own; a second Node version would double real-API calls for no added signal. `vitest.e2e.config.ts` runs files through a bounded worker pool (`DSH_E2E_MAX_WORKERS`, default `4`, CI value `14`) so CI and local with-key runs parallelize independent files while retaining a one-line serial escape hatch for quota investigations. `timeout-minutes: 45` bounds a wedged run given 120s/test and `retry: 2`. `cancel-in-progress` is enabled only for `pull_request` runs — a superseded PR run is on a stale commit and worth cancelling, whereas a push/schedule run is already producing the post-merge/nightly signal and is never cancelled.
|
||||
Run **only** `test:e2e`. The keyless gates (typecheck/lint/coverage/snapshot/build/hygiene) already run in ci.yml on every push and PR; repeating them here would duplicate signal and slow the real-API job. No build step — e2e tests run unbuilt via tsx + the tsconfig paths map. Single Node 24 (the primary line): these tests exercise API integration, not node-version compatibility, which ci.yml's Node 22.19/24/26 matrix owns. `vitest.e2e.config.ts` runs files through a bounded worker pool (`DSH_E2E_MAX_WORKERS`, default `4`, CI value `14`) so CI and local with-key runs parallelize independent files while retaining a one-line serial escape hatch for quota investigations. `timeout-minutes: 45` bounds a wedged run given 120s/test and `retry: 2`. `cancel-in-progress` is enabled only for `pull_request` runs — a superseded PR run is on a stale commit and worth cancelling, whereas a push/schedule run is already producing the post-merge/nightly signal and is never cancelled.
|
||||
|
||||
## Security
|
||||
|
||||
|
||||
+2
-2
@@ -5,7 +5,7 @@
|
||||
"type": "module",
|
||||
"packageManager": "pnpm@11.7.0",
|
||||
"engines": {
|
||||
"node": ">=24"
|
||||
"node": "^22.19.0 || >=24.0.0"
|
||||
},
|
||||
"workspaces": [
|
||||
"vendor/*",
|
||||
@@ -71,7 +71,7 @@
|
||||
"@stylistic/eslint-plugin": "^5.10.0",
|
||||
"@types/jsdom": "^28.0.3",
|
||||
"@types/mdast": "^4.0.4",
|
||||
"@types/node": "^25.3.5",
|
||||
"@types/node": "^22.20.0",
|
||||
"@vitest/coverage-v8": "^4.1.8",
|
||||
"eslint": "^10.4.1",
|
||||
"fast-check": "^4.8.0",
|
||||
|
||||
@@ -8,7 +8,7 @@ A SQLite durable session-persistence backend — a second `SessionPersistence` i
|
||||
|
||||
Each `SessionEvent` maps 1:1 onto a row in an `events` table `(session_id, seq, type, time, data, source_event_seqs, surface_op)` — `data` is the event payload as JSON text, so the row shape is the event verbatim (including `assistant/chunk`, keeping `seq` contiguous). The two `TEXT` columns `source_event_seqs` and `surface_op` are nullable; they store the event's optional surface-metadata fields (see [session surface](../../../docs/rfc/implemented/architecture/2026-06-18-session-surface.md)). Out-of-log metadata (`SessionHeader`) lives in a `sessions` row. A `sessions` row is written only by the first `append` — its existence is the lazy-materialization signal (`list` reports exactly the sessions that have a row), so no separate column is needed.
|
||||
|
||||
The repo targets Node ≥ 24 (the root `engines` field), which includes the stable `node:sqlite` module. The database opens with `foreign_keys = ON` (so `ON DELETE CASCADE` drops a session's events with its row) and the configured `journal_mode` (default `wal`; pick a rollback-journal mode like `delete` on filesystems where WAL's shared-memory files do not work, e.g. network mounts). The table-layout version is stored in `PRAGMA user_version` and checked on open: a fresh database is stamped with the current `SCHEMA_VERSION`; a database written by any other, incompatible build (a non-current `user_version`, older or newer) is rejected rather than opened against an unknown layout — there is no migration (unreleased software).
|
||||
The repo's `engines.node` is `^22.19.0 || >=24.0.0` (Node 22.19+ or 24+), matching the LTS floor required by the installed Pi adapter dependency; `node:sqlite` itself ships without the `--experimental-sqlite` flag from Node 22.13 (LTS) and 23.4 / 24 (Current) on. The range deliberately excludes Node 23 because that line is non-LTS/EOL and still has flagged runtime features before 23.6. The database opens with `foreign_keys = ON` (so `ON DELETE CASCADE` drops a session's events with its row) and the configured `journal_mode` (default `wal`; pick a rollback-journal mode like `delete` on filesystems where WAL's shared-memory files do not work, e.g. network mounts). The table-layout version is stored in `PRAGMA user_version` and checked on open: a fresh database is stamped with the current `SCHEMA_VERSION`; a database written by any other, incompatible build (a non-current `user_version`, older or newer) is rejected rather than opened against an unknown layout — there is no migration (unreleased software).
|
||||
|
||||
## Contract semantics over rows
|
||||
|
||||
|
||||
@@ -76,9 +76,10 @@ async function makeConsumer(welcome: string, disabledBrokenEntry = false): Promi
|
||||
await mkdir(dirname(target), { recursive: true })
|
||||
await symlink(abs, target)
|
||||
}
|
||||
// The example's mock model + echo tool are example-local TS plugins (Node 24+
|
||||
// strips types natively, so plain `node` loads them); they import the workspace
|
||||
// packages the symlinked node_modules now provides.
|
||||
// The example's mock model + echo tool are example-local TS plugins (Node
|
||||
// 22.19+ — the engines floor — strips types natively, so plain `node` loads
|
||||
// them); they import the workspace packages the symlinked node_modules now
|
||||
// provides.
|
||||
await cp(join(repoRoot, 'examples/echo-agent/src'), join(dir, 'src'), { recursive: true })
|
||||
await writeFile(join(dir, 'cordis.yml'), [
|
||||
'- id: mock-llm',
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* `LocalFetchProvider`: a `WebFetchProvider` that retrieves a concrete public
|
||||
* HTTP(S) URL with the platform-native `fetch` (Node 24) and returns a status
|
||||
* HTTP(S) URL with platform-native `fetch` at the repo's Node floor and returns a status
|
||||
* code plus bounded decoded content. It owns SAFE RESOURCE RETRIEVAL — URL
|
||||
* validation, redirect policy, timeout, abort, byte caps, charset decoding,
|
||||
* content-type classification, binary rejection — but NOT presentation
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
* `web_search_tool_result` block (native search did not trigger), it throws
|
||||
* `WEB_PROVIDER_ERROR` rather than degrading to prose-scraping.
|
||||
*
|
||||
* Network requests use platform-native `fetch` (Node 24), mirroring
|
||||
* Network requests use platform-native `fetch` at the repo's Node floor, mirroring
|
||||
* `@deepseek-ai/dsh-llm-deepseek`'s adapter — not a cordis HTTP-client service.
|
||||
* The Anthropic wire shape is a provider-private detail and does NOT make this
|
||||
* provider depend on `ctx.llm`.
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* `title`, the first highlight as `snippet`, and `publishedDate` as
|
||||
* `publishedAt`.
|
||||
*
|
||||
* Network requests use platform-native `fetch` (Node 24), mirroring
|
||||
* Network requests use platform-native `fetch` at the repo's Node floor, mirroring
|
||||
* `@deepseek-ai/dsh-llm-deepseek`'s adapter — not a cordis HTTP-client service.
|
||||
*
|
||||
* @module @deepseek-ai/dsh-web-search-exa/provider
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* structured `search_results[]` for `sources[]`, falling back to the URL-only
|
||||
* `citations[]` when `search_results` is absent.
|
||||
*
|
||||
* Network requests use platform-native `fetch` (Node 24), mirroring
|
||||
* Network requests use platform-native `fetch` at the repo's Node floor, mirroring
|
||||
* `@deepseek-ai/dsh-llm-deepseek`'s adapter. The OpenAI-compatible request shape
|
||||
* is a provider-private detail and does NOT make this provider depend on
|
||||
* `ctx.llm`.
|
||||
|
||||
Generated
+27
-15
@@ -21,8 +21,8 @@ importers:
|
||||
specifier: ^4.0.4
|
||||
version: 4.0.4
|
||||
'@types/node':
|
||||
specifier: ^25.3.5
|
||||
version: 25.9.3
|
||||
specifier: ^22.20.0
|
||||
version: 22.20.0
|
||||
'@vitest/coverage-v8':
|
||||
specifier: ^4.1.8
|
||||
version: 4.1.8(vitest@4.1.8)
|
||||
@@ -70,10 +70,10 @@ importers:
|
||||
version: 8.61.0(eslint@10.5.0(jiti@2.7.0))(typescript@6.0.3)
|
||||
vite-tsconfig-paths:
|
||||
specifier: ^6.1.1
|
||||
version: 6.1.1(typescript@6.0.3)(vite@8.0.16(@types/node@25.9.3)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0))
|
||||
version: 6.1.1(typescript@6.0.3)(vite@8.0.16(@types/node@22.20.0)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0))
|
||||
vitest:
|
||||
specifier: ^4.1.8
|
||||
version: 4.1.8(@types/node@25.9.3)(@vitest/coverage-v8@4.1.8)(jsdom@29.1.1)(vite@8.0.16(@types/node@25.9.3)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0))
|
||||
version: 4.1.8(@types/node@22.20.0)(@vitest/coverage-v8@4.1.8)(jsdom@29.1.1)(vite@8.0.16(@types/node@22.20.0)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0))
|
||||
|
||||
packages/bash/bash:
|
||||
devDependencies:
|
||||
@@ -2354,6 +2354,9 @@ packages:
|
||||
'@types/ms@2.1.0':
|
||||
resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==}
|
||||
|
||||
'@types/node@22.20.0':
|
||||
resolution: {integrity: sha512-QWlFW2wf3nTjC13/DqRnBpR4ZO36VJH/JVBkA/vcnmbTBNQIlnObqyqZE1tUR7+Ni23Lda8R1BxMfbXRpCUx5g==}
|
||||
|
||||
'@types/node@25.9.3':
|
||||
resolution: {integrity: sha512-603BddQMv3pUcr4U2dhujk83N2tTDVr/34wII2B6bJy6g+8WD6yUb11jszNs0gdi4PesVWl7ABt8nYMVpnLUcg==}
|
||||
|
||||
@@ -3820,6 +3823,9 @@ packages:
|
||||
unconfig-core@7.5.0:
|
||||
resolution: {integrity: sha512-Su3FauozOGP44ZmKdHy2oE6LPjk51M/TRRjHv2HNCWiDvfvCoxC2lno6jevMA91MYAdCdwP05QnWdWpSbncX/w==}
|
||||
|
||||
undici-types@6.21.0:
|
||||
resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==}
|
||||
|
||||
undici-types@7.24.6:
|
||||
resolution: {integrity: sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==}
|
||||
|
||||
@@ -5089,6 +5095,10 @@ snapshots:
|
||||
|
||||
'@types/ms@2.1.0': {}
|
||||
|
||||
'@types/node@22.20.0':
|
||||
dependencies:
|
||||
undici-types: 6.21.0
|
||||
|
||||
'@types/node@25.9.3':
|
||||
dependencies:
|
||||
undici-types: 7.24.6
|
||||
@@ -5212,7 +5222,7 @@ snapshots:
|
||||
obug: 2.1.3
|
||||
std-env: 4.1.0
|
||||
tinyrainbow: 3.1.0
|
||||
vitest: 4.1.8(@types/node@25.9.3)(@vitest/coverage-v8@4.1.8)(jsdom@29.1.1)(vite@8.0.16(@types/node@25.9.3)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0))
|
||||
vitest: 4.1.8(@types/node@22.20.0)(@vitest/coverage-v8@4.1.8)(jsdom@29.1.1)(vite@8.0.16(@types/node@22.20.0)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0))
|
||||
|
||||
'@vitest/expect@4.1.8':
|
||||
dependencies:
|
||||
@@ -5223,13 +5233,13 @@ snapshots:
|
||||
chai: 6.2.2
|
||||
tinyrainbow: 3.1.0
|
||||
|
||||
'@vitest/mocker@4.1.8(vite@8.0.16(@types/node@25.9.3)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0))':
|
||||
'@vitest/mocker@4.1.8(vite@8.0.16(@types/node@22.20.0)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0))':
|
||||
dependencies:
|
||||
'@vitest/spy': 4.1.8
|
||||
estree-walker: 3.0.3
|
||||
magic-string: 0.30.21
|
||||
optionalDependencies:
|
||||
vite: 8.0.16(@types/node@25.9.3)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0)
|
||||
vite: 8.0.16(@types/node@22.20.0)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0)
|
||||
|
||||
'@vitest/pretty-format@4.1.8':
|
||||
dependencies:
|
||||
@@ -6825,6 +6835,8 @@ snapshots:
|
||||
'@quansync/fs': 1.0.0
|
||||
quansync: 1.0.0
|
||||
|
||||
undici-types@6.21.0: {}
|
||||
|
||||
undici-types@7.24.6: {}
|
||||
|
||||
undici@7.28.0: {}
|
||||
@@ -6854,17 +6866,17 @@ snapshots:
|
||||
|
||||
uuid@14.0.1: {}
|
||||
|
||||
vite-tsconfig-paths@6.1.1(typescript@6.0.3)(vite@8.0.16(@types/node@25.9.3)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0)):
|
||||
vite-tsconfig-paths@6.1.1(typescript@6.0.3)(vite@8.0.16(@types/node@22.20.0)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0)):
|
||||
dependencies:
|
||||
debug: 4.4.3
|
||||
globrex: 0.1.2
|
||||
tsconfck: 3.1.6(typescript@6.0.3)
|
||||
vite: 8.0.16(@types/node@25.9.3)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0)
|
||||
vite: 8.0.16(@types/node@22.20.0)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
- typescript
|
||||
|
||||
vite@8.0.16(@types/node@25.9.3)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0):
|
||||
vite@8.0.16(@types/node@22.20.0)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0):
|
||||
dependencies:
|
||||
lightningcss: 1.32.0
|
||||
picomatch: 4.0.4
|
||||
@@ -6872,17 +6884,17 @@ snapshots:
|
||||
rolldown: 1.0.3
|
||||
tinyglobby: 0.2.17
|
||||
optionalDependencies:
|
||||
'@types/node': 25.9.3
|
||||
'@types/node': 22.20.0
|
||||
esbuild: 0.28.1
|
||||
fsevents: 2.3.3
|
||||
jiti: 2.7.0
|
||||
tsx: 4.22.4
|
||||
yaml: 2.9.0
|
||||
|
||||
vitest@4.1.8(@types/node@25.9.3)(@vitest/coverage-v8@4.1.8)(jsdom@29.1.1)(vite@8.0.16(@types/node@25.9.3)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0)):
|
||||
vitest@4.1.8(@types/node@22.20.0)(@vitest/coverage-v8@4.1.8)(jsdom@29.1.1)(vite@8.0.16(@types/node@22.20.0)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0)):
|
||||
dependencies:
|
||||
'@vitest/expect': 4.1.8
|
||||
'@vitest/mocker': 4.1.8(vite@8.0.16(@types/node@25.9.3)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0))
|
||||
'@vitest/mocker': 4.1.8(vite@8.0.16(@types/node@22.20.0)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0))
|
||||
'@vitest/pretty-format': 4.1.8
|
||||
'@vitest/runner': 4.1.8
|
||||
'@vitest/snapshot': 4.1.8
|
||||
@@ -6899,10 +6911,10 @@ snapshots:
|
||||
tinyexec: 1.2.4
|
||||
tinyglobby: 0.2.17
|
||||
tinyrainbow: 3.1.0
|
||||
vite: 8.0.16(@types/node@25.9.3)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0)
|
||||
vite: 8.0.16(@types/node@22.20.0)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0)
|
||||
why-is-node-running: 2.3.0
|
||||
optionalDependencies:
|
||||
'@types/node': 25.9.3
|
||||
'@types/node': 22.20.0
|
||||
'@vitest/coverage-v8': 4.1.8(vitest@4.1.8)
|
||||
jsdom: 29.1.1
|
||||
transitivePeerDependencies:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"AGENTS.md": 1690,
|
||||
"AGENTS.md": 1691,
|
||||
"docs/AGENTS.md": 1315,
|
||||
"docs/architecture.md": 1630,
|
||||
"docs/cordis-primer.md": 550,
|
||||
|
||||
@@ -25,9 +25,8 @@
|
||||
*/
|
||||
|
||||
import { execFileSync } from 'node:child_process'
|
||||
import { mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'
|
||||
import { globSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'
|
||||
import { join, relative, resolve } from 'node:path'
|
||||
import { glob } from 'node:fs/promises'
|
||||
import ts from 'typescript'
|
||||
|
||||
const root = resolve(import.meta.dirname, '..')
|
||||
@@ -139,7 +138,7 @@ const markdownGlobs = ['README.md', 'docs/**/*.md', 'packages/*/*.md', 'packages
|
||||
|
||||
const files: string[] = []
|
||||
for (const pattern of markdownGlobs) {
|
||||
for await (const match of glob(pattern, { cwd: root })) files.push(resolve(root, match))
|
||||
for (const match of globSync(pattern, { cwd: root })) files.push(resolve(root, match))
|
||||
}
|
||||
files.sort()
|
||||
|
||||
|
||||
@@ -26,9 +26,8 @@
|
||||
* Run: `tsx scripts/verify-doc-refs.ts`.
|
||||
*/
|
||||
|
||||
import { existsSync, readFileSync } from 'node:fs'
|
||||
import { existsSync, globSync, readFileSync } from 'node:fs'
|
||||
import { relative, resolve } from 'node:path'
|
||||
import { glob } from 'node:fs/promises'
|
||||
|
||||
const root = resolve(import.meta.dirname, '..')
|
||||
|
||||
@@ -77,7 +76,7 @@ function findViolations(absPath: string): Violation[] {
|
||||
const all: Violation[] = []
|
||||
let checked = 0
|
||||
for (const pattern of PATTERNS) {
|
||||
for await (const match of glob(pattern, { cwd: root })) {
|
||||
for (const match of globSync(pattern, { cwd: root })) {
|
||||
if (isExcluded(match)) continue
|
||||
checked++
|
||||
all.push(...findViolations(resolve(root, match)))
|
||||
|
||||
@@ -32,9 +32,8 @@
|
||||
* Run: `tsx scripts/verify-md-links.ts`.
|
||||
*/
|
||||
|
||||
import { existsSync, readFileSync, realpathSync } from 'node:fs'
|
||||
import { existsSync, globSync, readFileSync, realpathSync } from 'node:fs'
|
||||
import { dirname, relative, resolve } from 'node:path'
|
||||
import { glob } from 'node:fs/promises'
|
||||
import { fromMarkdown } from 'mdast-util-from-markdown'
|
||||
import { gfmFromMarkdown } from 'mdast-util-gfm'
|
||||
import { gfm } from 'micromark-extension-gfm'
|
||||
@@ -134,7 +133,7 @@ const seen = new Set<string>()
|
||||
const all: Violation[] = []
|
||||
let checked = 0
|
||||
for (const pattern of PATTERNS) {
|
||||
for await (const match of glob(pattern, { cwd: root })) {
|
||||
for (const match of globSync(pattern, { cwd: root })) {
|
||||
const abs = resolve(root, match)
|
||||
// CLAUDE.md symlinks resolve onto AGENTS.md; dedupe by real path so a file
|
||||
// matched twice (or via symlink) is checked once.
|
||||
|
||||
@@ -25,9 +25,8 @@
|
||||
* Run: `tsx scripts/verify-md-wrap.ts`.
|
||||
*/
|
||||
|
||||
import { readFileSync, realpathSync } from 'node:fs'
|
||||
import { globSync, readFileSync, realpathSync } from 'node:fs'
|
||||
import { relative, resolve } from 'node:path'
|
||||
import { glob } from 'node:fs/promises'
|
||||
import { fromMarkdown } from 'mdast-util-from-markdown'
|
||||
import { gfmFromMarkdown } from 'mdast-util-gfm'
|
||||
import { gfm } from 'micromark-extension-gfm'
|
||||
@@ -76,7 +75,7 @@ const seen = new Set<string>()
|
||||
const all: Violation[] = []
|
||||
let checked = 0
|
||||
for (const pattern of PATTERNS) {
|
||||
for await (const match of glob(pattern, { cwd: root })) {
|
||||
for (const match of globSync(pattern, { cwd: root })) {
|
||||
const abs = resolve(root, match)
|
||||
// CLAUDE.md symlinks resolve onto AGENTS.md; dedupe by real path so a file
|
||||
// matched twice (or via symlink) is checked once.
|
||||
|
||||
@@ -12,9 +12,8 @@
|
||||
* Run: `tsx scripts/verify-mermaid.ts`.
|
||||
*/
|
||||
|
||||
import { readFileSync, realpathSync } from 'node:fs'
|
||||
import { globSync, readFileSync, realpathSync } from 'node:fs'
|
||||
import { resolve } from 'node:path'
|
||||
import { glob } from 'node:fs/promises'
|
||||
import { fromMarkdown } from 'mdast-util-from-markdown'
|
||||
import { gfmFromMarkdown } from 'mdast-util-gfm'
|
||||
import { gfm } from 'micromark-extension-gfm'
|
||||
@@ -72,7 +71,7 @@ const blocks: Block[] = []
|
||||
const seen = new Set<string>()
|
||||
let checkedFiles = 0
|
||||
for (const pattern of PATTERNS) {
|
||||
for await (const match of glob(pattern, { cwd: root })) {
|
||||
for (const match of globSync(pattern, { cwd: root })) {
|
||||
const real = realpathSync(resolve(root, match))
|
||||
if (seen.has(real)) continue
|
||||
seen.add(real)
|
||||
|
||||
@@ -39,9 +39,8 @@
|
||||
* Run: `tsx scripts/verify-package-paths.ts`.
|
||||
*/
|
||||
|
||||
import { existsSync, readdirSync, readFileSync, realpathSync } from 'node:fs'
|
||||
import { existsSync, globSync, readdirSync, readFileSync, realpathSync } from 'node:fs'
|
||||
import { relative, resolve } from 'node:path'
|
||||
import { glob } from 'node:fs/promises'
|
||||
|
||||
const root = resolve(import.meta.dirname, '..')
|
||||
|
||||
@@ -144,7 +143,7 @@ const all: Violation[] = []
|
||||
let checked = 0
|
||||
const seen = new Set<string>()
|
||||
for (const pattern of PATTERNS) {
|
||||
for await (const match of glob(pattern, { cwd: root })) {
|
||||
for (const match of globSync(pattern, { cwd: root })) {
|
||||
if (isExcluded(match)) continue
|
||||
// Dedup by real path: the root/packages CLAUDE.md are symlinks to AGENTS.md.
|
||||
const real = realpathSync(resolve(root, match))
|
||||
|
||||
@@ -44,9 +44,8 @@
|
||||
*/
|
||||
|
||||
import { createHash } from 'node:crypto'
|
||||
import { existsSync, readFileSync, writeFileSync } from 'node:fs'
|
||||
import { existsSync, globSync, readFileSync, writeFileSync } from 'node:fs'
|
||||
import { basename, join, resolve } from 'node:path'
|
||||
import { glob } from 'node:fs/promises'
|
||||
import { fromMarkdown } from 'mdast-util-from-markdown'
|
||||
import { gfmFromMarkdown } from 'mdast-util-gfm'
|
||||
import { gfm } from 'micromark-extension-gfm'
|
||||
@@ -211,7 +210,7 @@ function parse(content: string): Nodes {
|
||||
// Enumerate the scope once.
|
||||
const files = new Set<string>()
|
||||
for (const pattern of SCOPE_PATTERNS) {
|
||||
for await (const match of glob(pattern, { cwd: root })) files.add(match)
|
||||
for (const match of globSync(pattern, { cwd: root })) files.add(match)
|
||||
}
|
||||
const translations = [...files].filter(f => f.endsWith('.zh.md')).sort()
|
||||
const metas = [...files].filter(f => f.endsWith('.i18n.yaml')).sort()
|
||||
|
||||
@@ -22,9 +22,8 @@
|
||||
* Run: `tsx scripts/verify-type-equiv.ts`.
|
||||
*/
|
||||
|
||||
import { readFileSync, existsSync } from 'node:fs'
|
||||
import { globSync, readFileSync, existsSync } from 'node:fs'
|
||||
import { resolve } from 'node:path'
|
||||
import { glob } from 'node:fs/promises'
|
||||
import ts from 'typescript'
|
||||
|
||||
const root = resolve(import.meta.dirname, '..')
|
||||
@@ -148,7 +147,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 await (const match of glob(pattern, { cwd: root })) docSet.add(match)
|
||||
for (const match of globSync(pattern, { cwd: root })) docSet.add(match)
|
||||
}
|
||||
const blocks: EquivBlock[] = [...docSet].sort().flatMap(extractEquivBlocks)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user