2026-06-11 10:52:45 +08:00
{
"name" : "@deepseek-ai/dsh-root" ,
"version" : "0.0.1" ,
"private" : true ,
"type" : "module" ,
2026-06-16 14:55:37 +08:00
"packageManager" : "pnpm@11.7.0" ,
2026-06-11 10:52:45 +08:00
"engines" : {
2026-07-07 17:39:04 +08:00
"node" : "^22.19.0 || >=24.0.0"
2026-06-11 10:52:45 +08:00
} ,
"workspaces" : [
"vendor/*" ,
2026-07-13 15:38:47 +08:00
"packages/*/*" ,
"website"
2026-06-11 10:52:45 +08:00
] ,
"scripts" : {
Replace dumble with tsdown for JS bundling
dumble (0.2.x, ~530 dl/wk, single-maintainer) was a bus-factor risk as
the load-bearing bundler. tsdown (rolldown-based, ~2.5M dl/wk, actively
maintained) replaces it while output stays list-identical, verified by
snapshot diff: 17 JS bundles, externals preserved, schemastery dual
.mjs/.cjs and logger-console node+browser entries intact.
Root tsdown.config.ts uses workspace globs ['vendor/*', 'packages/*']
(explicit, so examples/* stays excluded); two per-package overrides in
vendor/ cover the special shapes and are logged in vendor/README.md as
ours (not upstream sync surface). scripts/build.ts (dumble
orchestration) is deleted; yarn build = tsc -b && tsdown. tsc -b keeps
owning declarations (dts: false, clean: false).
Rationale recorded in ADR 0008 (also covers the direct-esbuild and
pkgroll alternatives).
Gates: lint, typecheck, 134 tests, hygiene (knip/publint/constraints),
demo smoke all green.
2026-06-11 22:08:10 +08:00
"build" : "tsc -b tsconfig.build.json && tsdown" ,
2026-06-22 00:51:41 +08:00
"clean:build" : "rm -rf .typecheck packages/*/*/lib vendor/*/lib *.tsbuildinfo" ,
2026-06-17 23:41:18 +08:00
"typecheck" : "tsc -b tsconfig.json" ,
Add ESLint: typescript-eslint strict-type-checked + stylistic formatting
Flat config with two layers. Correctness (type-checked): the headline
rules for this codebase are no-floating-promises / no-misused-promises
(a lost promise in the agent loop is our primary bug class),
switch-exhaustiveness-check (we switch over merge-extensible unions
everywhere), no-unnecessary-condition, require-await, and
no-explicit-any. Style (@stylistic): 2-space, no semicolons, single
quotes, trailing commas, max-len 140 — the existing house style, now
enforced instead of drifting between agents. vendor/ is excluded
(vendored source keeps upstream style); tests relax the rules that
fight test ergonomics (non-null assertions after expects, async mock
signatures, non-Error throws).
Code adjusted to pass: registry disposers wrap ctx.effect's
promise-returning disposer behind a sync () => void (our public API),
BlockAssembler gains an invariant-checking mustGet instead of non-null
assertions, lastTurnNumber uses findLast, waterfall tails return
Promise.resolve instead of async-without-await arrows, and the two
deliberate suppressions (non-exhaustive derivation switch, unbound
execute pass-through) carry justification comments.
yarn lint / yarn lint:fix added.
2026-06-11 14:17:58 +08:00
"lint" : "eslint ." ,
"lint:fix" : "eslint . --fix" ,
2026-07-14 00:24:04 +08:00
"duplication" : "jscpd --config .jscpd.json packages scripts" ,
2026-06-11 10:52:45 +08:00
"test" : "vitest run" ,
Enforce 100% per-file test coverage on packages/*/src
vitest coverage (v8 provider) with per-file 100% thresholds for
statements, branches, functions, and lines. Scope: our runtime source
only — types-only files, vendor/ (upstream code), and examples/
(exercised by the demo smoke test) are excluded. yarn test:coverage
runs the gate.
59 tests added to close every gap: llm generate-waterfall and adapter
disposal; assembler edge protocol (duplicate block-start, stragglers
after block-end, id fallback, usage omission, invariant violation);
the whole Inbox surface incl. the wakeup-overwrite race; LoopAgent
disposed-state throws and double-stop idempotence; config-driven agent
creation; loop backstop catches (throwing turn-start/turn-end
listeners, non-Error throws, non-JSON tool arguments); system-prompt
dynamic sections and disposer paths; tools errorMessage fallbacks and
the full schema-DSL emission matrix. Genuinely unreachable defensive
guards carry /* v8 ignore */ comments with stated reasons rather than
deletion (132 tests total).
2026-06-11 14:58:36 +08:00
"test:coverage" : "vitest run --coverage" ,
2026-06-13 00:28:29 +08:00
"test:e2e" : "vitest run --config vitest.e2e.config.ts" ,
feat(acp-example): snapshot harness, normalizers, wiring, and handshake scenario
Adds the snapshot-test harness and the keyless replay pipeline end-to-end.
- snapshot-harness.ts: boots the real acp-agent subprocess via the cordis
Loader (preserving TSX_TSCONFIG_PATH so unbuilt dsh-* imports resolve from a
temp cwd), tees raw stdout into an SDK ClientSideConnection, interprets a
per-scenario input.json DSL (initialize / newSession capturing the random
sessionId / prompt / cancel), closes stdin to trigger graceful shutdown, and
harvests the persisted session.jsonl. Failure-safe: a finally block SIGKILLs
a live child, awaits its exit, and removes both temp dirs even on a thrown
step or harvest. Raw bytes are buffered and decoded once (no multibyte split).
- snapshot-normalize.ts (+ spec): two pure normalizers (stdout frames + session
JSONL) scrub cwd, session ids / UUIDs, and JSON-RPC ids, and zero time /
createdAt — but keep `seq` (deterministic by contract). normalizeStdout throws
on a non-JSON line (the stdout-purity check).
- start.ts: selects cordis.snapshot.yml (replay, providerless) or
cordis.snapshot-record.yml (record, real adapter) from DSH_SNAPSHOT, skips
.env in replay, and disposes the ctx on stdin end so persistence flushes
before exit (harvest-after-flush, not on the prompt response).
- acp.snapshot.ts: asserts the normalized stdout golden (and, for model
scenarios, the re-persisted JSONL golden) via toMatchFileSnapshot; record mode
writes the harvested log back to the scenario fixture; an orphan-fixture guard
fails on an unregistered scenario dir.
- handshake scenario: initialize + session/new (no model call; a header-only
session.jsonl, since session/new persists no events).
- vitest.snapshot.config.ts, test:snapshot / test:snapshot:record scripts, a
pre-push snapshot job, and the knip entry.
Incorporates Codex review: record-fixture writeback, failure-safe teardown,
seq-not-scrubbed, harvest-after-flush. Per docs/rfc/implemented/2026-06-19.
2026-06-19 03:36:12 +08:00
"test:snapshot" : "vitest run --config vitest.snapshot.config.ts" ,
"test:snapshot:record" : "DSH_SNAPSHOT=record vitest run --config vitest.snapshot.config.ts --update" ,
2026-07-10 00:48:27 +08:00
"test:snapshot:refresh" : "DSH_SNAPSHOT=refresh vitest run --config vitest.snapshot.config.ts" ,
2026-07-06 01:47:13 +08:00
"check:ci" : "tsx scripts/run-gates.ts ci-primary" ,
2026-07-06 02:22:22 +08:00
"check:ci:static" : "tsx scripts/run-gates.ts ci-static" ,
2026-07-06 02:39:26 +08:00
"check:ci:lint" : "tsx scripts/run-gates.ts ci-lint" ,
2026-07-06 02:22:22 +08:00
"check:ci:coverage" : "tsx scripts/run-gates.ts ci-coverage" ,
"check:ci:snapshot" : "tsx scripts/run-gates.ts ci-snapshot" ,
"check:ci:artifacts" : "tsx scripts/run-gates.ts ci-artifacts" ,
2026-07-06 01:47:13 +08:00
"check:node-compat" : "tsx scripts/run-gates.ts node-compat" ,
"check:pre-push" : "tsx scripts/run-gates.ts pre-push" ,
2026-06-20 22:33:27 +08:00
"knip" : "knip --treat-config-hints-as-errors" ,
2026-06-11 15:04:50 +08:00
"publint" : "tsx scripts/publint-all.ts" ,
2026-06-14 00:47:38 +08:00
"doc-typecheck" : "tsx scripts/doc-typecheck.ts" ,
feat: enforce merge-commit policy and markdown wrap convention
- AGENTS.md: require merging PRs with a merge commit (gh pr merge
--merge), never squash/rebase — the per-PR commit history (review-fix
and regression-test commits) is intentional record.
- Add scripts/verify-md-wrap.ts: a doc-sync gate that fails on
hard-wrapped prose paragraphs (one physical line per paragraph), with
smart exemptions for fenced code, tables, lists, blockquotes, headings,
HTML comments, hrs, and reference defs. Scope covers README.md,
docs/**/*.md, packages/*/README.md, plus AGENTS.md / packages/AGENTS.md
(the files doc-sync did not previously cover). Folded into doc-sync so
it rides the existing pre-push and CI gates.
- Sync AGENTS.md and docs/development.md doc-sync descriptions and
command lists to include verify-md-wrap.
2026-06-16 22:14:25 +08:00
"verify-md-wrap" : "tsx scripts/verify-md-wrap.ts" ,
2026-06-18 02:18:24 +08:00
"verify-md-links" : "tsx scripts/verify-md-links.ts" ,
2026-06-20 22:29:45 +08:00
"verify-doc-refs" : "tsx scripts/verify-doc-refs.ts" ,
2026-06-20 23:12:14 +08:00
"verify-package-paths" : "tsx scripts/verify-package-paths.ts" ,
2026-07-12 02:12:36 +08:00
"verify-package-readme-model-experience" : "tsx scripts/verify-package-readme-model-experience.ts" ,
2026-07-03 01:32:01 +08:00
"verify-mermaid" : "tsx scripts/verify-mermaid.ts" ,
2026-07-19 22:50:49 +08:00
"verify-agent-note-classification" : "tsx scripts/verify-agent-note-classification.ts" ,
"verify-agent-note-format" : "tsx scripts/verify-agent-note-format.ts" ,
2026-06-20 16:24:37 +08:00
"verify-type-equiv" : "tsx scripts/verify-type-equiv.ts" ,
2026-07-14 23:09:01 +08:00
"verify-translation-prompt" : "tsx scripts/verify-translation-prompt.ts" ,
docs: bilingual docs contract, translation skill, and pairing gate
Establish EN->ZH bilingual documentation for the README and docs tree:
- docs/i18n/README.md — the pairing contract: sibling foo.md <-> foo.zh.md,
English canonical, blob-hash source fingerprints, language switchers,
scope/exclusions, and a manifest-driven rollout ratchet.
- docs/i18n/translation-rules.md — how to translate: faithfulness, structure
preservation, terminology discipline over docs/i18n/terminology.md, and
typography rules grounded in MDN/K8s/Vue/clreq conventions.
- .agents/skills/dsh-translate-docs — the committed agent workflow, following
the dsh-code-review pattern of deferring to docs as sources of truth.
- scripts/verify-translation-pairing.ts + manifest — a doc-sync gate: required
pairs exist; every existing .zh.md is fresh (fingerprint = current source
blob), switcher-linked, structure-matched, and non-orphaned; excluded
(generated) docs stay unpaired. --list prints the translation work list.
- RFC (implemented/process) recording the decision and the alternatives.
- Dogfood: README.zh.md and the two i18n docs translated under their own rules.
Gates: doc-sync green including the new gate; red/green proven for stale
fingerprint, orphan, and excluded-file violations.
2026-07-02 23:12:25 -07:00
"verify-translation-pairing" : "tsx scripts/verify-translation-pairing.ts" ,
feat(doc-standards): documentation tiers, budgets, and the ceiling gate
Standing docs accrete a paragraph per PR with nothing pushing back; the
root AGENTS.md reached 8,130 words in 50 commits with the same rule
stated two and three times. This encodes the counter-pressure:
- docs/AGENTS.md becomes the documentation standard: the tier taxonomy
(one home per fact), target word budgets, and the slop checklist.
- verify-doc-budgets joins doc-sync: word ceilings for the six
accretion-prone standing docs, manifest-driven, frozen at current
sizes and ratcheted down as each doc is brought to target.
- .agents/skills/dsh-doc-standards: the thin placement/audit/red-gate
workflow over the standard, mirroring the dsh-translate-docs split.
- RFC (implemented/process) records the decision, alternatives, and
the first audit cycle's deferred work list.
The gate's first catch was the standard itself (1,057 > 1,000); it
ships condensed to 984 words rather than with a raised ceiling.
2026-07-04 13:53:43 +08:00
"verify-doc-budgets" : "tsx scripts/verify-doc-budgets.ts" ,
2026-07-13 15:38:47 +08:00
"docs:dev" : "pnpm --filter @deepseek-ai/website run dev" ,
"docs:build" : "pnpm --filter @deepseek-ai/website run build" ,
"docs:preview" : "pnpm --filter @deepseek-ai/website run preview" ,
"docs:check" : "pnpm exec vitest run scripts/project-doc-site.spec.ts && pnpm run docs:build" ,
2026-07-18 21:35:06 +08:00
"website:dev" : "pnpm run docs:dev" ,
"website:build" : "pnpm run docs:build" ,
2026-07-14 00:22:52 +08:00
"verify-package-readme-limitations" : "tsx scripts/verify-package-readme-limitations.ts" ,
2026-06-22 06:11:00 +08:00
"verify-node-next-types" : "tsx scripts/verify-node-next-types.ts" ,
2026-07-13 16:34:09 +08:00
"verify-runtime-closure" : "tsx scripts/verify-runtime-closure.ts" ,
2026-07-14 21:25:58 +08:00
"verify-cordis-config" : "tsx scripts/verify-cordis-config.ts" ,
2026-06-20 19:47:09 +08:00
"gen-cordis-catalog" : "tsx scripts/gen-cordis-catalog.ts" ,
"verify-cordis-catalog" : "tsx scripts/gen-cordis-catalog.ts --check" ,
2026-07-08 11:47:51 +08:00
"gen-cordis-api" : "tsx scripts/gen-cordis-api.ts" ,
"verify-cordis-api" : "tsx scripts/gen-cordis-api.ts --check" ,
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
2026-07-06 22:09:30 +08:00
"verify-export-jsdoc" : "tsx scripts/verify-export-jsdoc.ts" ,
feat(docs): generate a tool-schema catalog by booting the tool plugins
Add docs/tool-catalog/tools.md, a generated reference of every model-facing
tool a shipped `packages/*/tool-*` plugin contributes (name, description,
JSON-Schema parameters) — the third generated catalog alongside the cordis
events/services and core-data-structures catalogs.
Unlike the cordis catalog (a pure source-AST pass), this generator BOOTS each
tool plugin on a real cordis Context and reads `ctx.tools.schemas()`, because a
tool schema is not statically knowable: `todo_write` builds its enum with a
runtime spread, descriptions are string-concatenated, `subagent`'s name is
config-driven, and MCP tools register raw JSON Schema without `defineTool`. A
completeness guard globs the on-disk `tool-*` packages and fails if any is
absent from the boot manifest, restoring the "nothing silently omitted"
property booting would otherwise lose. `verify-tool-catalog` runs inside
`doc-sync`, so the artifact cannot drift.
The boot-over-AST decision and the discovered-inventory / hand-written-recipe
split are recorded in a process RFC.
2026-07-02 02:20:24 +08:00
"gen-tool-catalog" : "tsx scripts/gen-tool-catalog.ts" ,
"verify-tool-catalog" : "tsx scripts/gen-tool-catalog.ts --check" ,
feat: generated plugin config catalog (docs/config-catalog.md)
scripts/gen-config-catalog.ts walks every packages/<group>/<pkg> entry with
the TypeScript compiler API and emits docs/config-catalog.md: per loadable
plugin, the verbatim config declaration (JSDoc included) its apply/constructor
receives in a ts config-catalog fence, the inject requirements, resolved links
for every referenced type (package-local types pasted transitively, other
plugins' config types as intra-page anchors, LINK_MAP names to
core-data-structures, workspace types to source), and terse classification
lists for config-free plugins, abstract seams, and libraries — classification
is total, so a new package cannot go undocumented.
The walk enforces per-field JSDoc prose on every pasted declaration and
statically cross-checks the schemastery schema (z.object keys, z.intersect
composition across packages): every schema-validated key must be a declared
member of the config type. One violation existed repo-wide — the agents[].id
field in dsh-agent-loop — fixed by adding its JSDoc (which shifts the
cordis-catalog services page's source pointers; regenerated).
verify-config-catalog (--check) joins doc-sync; doc-typecheck learns the
ts config-catalog fence; gen-cordis-catalog exports its JSDoc/pointer helpers
and LINK_MAP for reuse. Negative-path spec in
packages/core/agent-core/tests/gen-config-catalog.spec.ts mirrors the
gen-cordis-catalog spec. Decision record:
docs/rfc/implemented/process/2026-07-06-generated-config-catalog.md (includes
the deliberate acceptance of README ## Config overlap).
2026-07-06 21:57:17 +08:00
"gen-config-catalog" : "tsx scripts/gen-config-catalog.ts" ,
"verify-config-catalog" : "tsx scripts/gen-config-catalog.ts --check" ,
2026-07-03 01:13:52 +08:00
"gen-doc-graphs" : "tsx scripts/gen-doc-graphs.ts" ,
"verify-doc-graphs" : "tsx scripts/gen-doc-graphs.ts --check" ,
Add generated persistence log event catalog with freshness + completeness gates
docs/persistence-catalog/log-events.md enumerates every SessionEventMap
member — the owning dsh-session vocabulary plus the dsh-compact and
dsh-hook-protocol declaration merges — with payload, surface/log-only badge,
JSDoc prose, and declaration site. scripts/gen-persistence-catalog.ts is a
pure AST pass in the gen-cordis-catalog mold: verify-persistence-catalog
(--check) joins doc-sync, so a stale committed catalog fails pre-push and CI.
The walk enforces JSDoc completeness (every member needs description prose;
@mode is rejected as a category error — log events do not dispatch on the
cordis bus), derives the surface badge from the SurfaceEventType union with a
stale-member cross-check, and hard-errors on duplicate declarations. Payloads
render through the TypeScript printer so newline-separated multi-line type
literals still emit valid one-line fragments.
Documented the five previously JSDoc-less core events (turn/step boundaries,
tool/call), removed the two stray @mode tags on the hook/* merges, and
replaced the hand-restated event enumerations (session.md hook/* table,
compact README table, hook-protocol README bullets, session README name-list
— whose merge note had already drifted) with links to the catalog. RFC:
docs/rfc/implemented/process/2026-07-04-persistence-log-catalog.md.
2026-07-04 22:58:28 +08:00
"gen-persistence-catalog" : "tsx scripts/gen-persistence-catalog.ts" ,
"verify-persistence-catalog" : "tsx scripts/gen-persistence-catalog.ts --check" ,
2026-06-16 21:00:24 +08:00
"gen-module-graph" : "tsx scripts/gen-module-graph.ts" ,
2026-07-14 23:14:51 +08:00
"gen-scoped-events" : "tsx scripts/gen-scoped-events.ts" ,
"verify-scoped-events" : "tsx scripts/gen-scoped-events.ts --check" ,
2026-06-16 21:00:24 +08:00
"verify-module-graph" : "tsx scripts/gen-module-graph.ts --check" ,
2026-06-16 14:55:37 +08:00
"constraints" : "tsx scripts/check-workspace-constraints.ts" ,
2026-07-20 10:21:36 +08:00
"doc-sync" : "pnpm run doc-typecheck && pnpm run verify-cordis-catalog && pnpm run verify-cordis-api && pnpm run verify-export-jsdoc && pnpm run verify-tool-catalog && pnpm run verify-config-catalog && pnpm run verify-persistence-catalog && pnpm run verify-doc-graphs && pnpm run verify-scoped-events && pnpm run verify-md-wrap && pnpm run verify-md-links && pnpm run verify-doc-refs && pnpm run verify-package-paths && pnpm run verify-package-readme-model-experience && pnpm run verify-mermaid && pnpm run verify-agent-note-classification && pnpm run verify-agent-note-format && pnpm run verify-type-equiv && pnpm run verify-translation-prompt && pnpm run verify-translation-pairing && pnpm run verify-doc-budgets && pnpm run verify-package-readme-limitations && pnpm run docs:check" ,
2026-07-14 21:25:58 +08:00
"hygiene" : "pnpm run knip && pnpm run publint && pnpm run constraints && pnpm run verify-cordis-config && pnpm run verify-node-next-types && pnpm run verify-runtime-closure" ,
2026-07-15 15:57:57 +08:00
"demo:echo" : "node --expose-internals --import tsx packages/examples/stdio-demo/src/bin.ts examples/echo-agent/cordis.yml" ,
2026-07-19 13:13:14 +08:00
"demo:repl" : "node --expose-internals --import tsx packages/examples/stdio-demo/src/bin.ts examples/repl-agent/cordis.yml" ,
2026-07-16 16:12:27 +08:00
"demo:headless" : "node --expose-internals --import tsx packages/examples/cli-demo/src/bin.ts --config examples/headless-agent/cordis.yml" ,
2026-07-19 01:09:20 +08:00
"demo:tui" : "node --expose-internals --import tsx packages/examples/stdio-demo/src/bin.ts examples/tui-agent/cordis.yml" ,
2026-07-09 12:16:37 +08:00
"demo:code-mode" : "node scripts/demo-code-mode.mjs" ,
2026-07-15 15:57:57 +08:00
"demo:cordis" : "node --expose-internals --import tsx packages/examples/stdio-demo/src/bin.ts examples/cordis-agent/cordis.yml" ,
"demo:acp" : "node --import tsx packages/examples/acp-demo/src/bin.ts --config examples/acp-agent/cordis.yml" ,
2026-06-17 21:26:44 +08:00
"postinstall" : "node scripts/install-lefthook.mjs"
2026-06-11 10:52:45 +08:00
} ,
"devDependencies" : {
2026-06-16 11:10:25 +08:00
"@agentclientprotocol/sdk" : "0.25.1" ,
Add ESLint: typescript-eslint strict-type-checked + stylistic formatting
Flat config with two layers. Correctness (type-checked): the headline
rules for this codebase are no-floating-promises / no-misused-promises
(a lost promise in the agent loop is our primary bug class),
switch-exhaustiveness-check (we switch over merge-extensible unions
everywhere), no-unnecessary-condition, require-await, and
no-explicit-any. Style (@stylistic): 2-space, no semicolons, single
quotes, trailing commas, max-len 140 — the existing house style, now
enforced instead of drifting between agents. vendor/ is excluded
(vendored source keeps upstream style); tests relax the rules that
fight test ergonomics (non-null assertions after expects, async mock
signatures, non-Error throws).
Code adjusted to pass: registry disposers wrap ctx.effect's
promise-returning disposer behind a sync () => void (our public API),
BlockAssembler gains an invariant-checking mustGet instead of non-null
assertions, lastTurnNumber uses findLast, waterfall tails return
Promise.resolve instead of async-without-await arrows, and the two
deliberate suppressions (non-exhaustive derivation switch, unbound
execute pass-through) carry justification comments.
yarn lint / yarn lint:fix added.
2026-06-11 14:17:58 +08:00
"@stylistic/eslint-plugin" : "^5.10.0" ,
2026-07-14 21:25:58 +08:00
"@types/js-yaml" : "^4.0.9" ,
2026-07-03 01:32:01 +08:00
"@types/jsdom" : "^28.0.3" ,
refactor: detect md hard-wraps via mdast AST, not regex
Per review feedback (use a real markdown parser with an AST linked to
source positions), rewrite verify-md-wrap to parse each file with
mdast-util-from-markdown (the CommonMark parser behind remark) + the GFM
extension, then flag any `paragraph` node whose source span covers more
than one line.
Why a parser over the hand-rolled line scanner:
- It is a checker, not a formatter — it reports and never rewrites, so
zero cosmetic churn (no emphasis-marker or table-delimiter
normalization, which is why Prettier was rejected for this).
- The AST owns every structural exemption (fenced code of any fence
length, tables, lists, blockquotes, HTML, headings, reference defs),
fixing both bugs the regex version had: it now catches wrapped
list-item / blockquote prose (a `paragraph` inside those nodes) and no
longer false-positives on a longer ```` fence wrapping an inner ```.
Also unwrap two pre-existing hard-wrapped blockquotes (architecture.md,
adding-a-tool.md) that the stricter AST check correctly surfaced.
2026-06-16 23:35:33 +08:00
"@types/mdast" : "^4.0.4" ,
2026-07-06 11:46:10 +08:00
"@types/node" : "^22.20.0" ,
Enforce 100% per-file test coverage on packages/*/src
vitest coverage (v8 provider) with per-file 100% thresholds for
statements, branches, functions, and lines. Scope: our runtime source
only — types-only files, vendor/ (upstream code), and examples/
(exercised by the demo smoke test) are excluded. yarn test:coverage
runs the gate.
59 tests added to close every gap: llm generate-waterfall and adapter
disposal; assembler edge protocol (duplicate block-start, stragglers
after block-end, id fallback, usage omission, invariant violation);
the whole Inbox surface incl. the wakeup-overwrite race; LoopAgent
disposed-state throws and double-stop idempotence; config-driven agent
creation; loop backstop catches (throwing turn-start/turn-end
listeners, non-Error throws, non-JSON tool arguments); system-prompt
dynamic sections and disposer paths; tools errorMessage fallbacks and
the full schema-DSL emission matrix. Genuinely unreachable defensive
guards carry /* v8 ignore */ comments with stated reasons rather than
deletion (132 tests total).
2026-06-11 14:58:36 +08:00
"@vitest/coverage-v8" : "^4.1.8" ,
Add ESLint: typescript-eslint strict-type-checked + stylistic formatting
Flat config with two layers. Correctness (type-checked): the headline
rules for this codebase are no-floating-promises / no-misused-promises
(a lost promise in the agent loop is our primary bug class),
switch-exhaustiveness-check (we switch over merge-extensible unions
everywhere), no-unnecessary-condition, require-await, and
no-explicit-any. Style (@stylistic): 2-space, no semicolons, single
quotes, trailing commas, max-len 140 — the existing house style, now
enforced instead of drifting between agents. vendor/ is excluded
(vendored source keeps upstream style); tests relax the rules that
fight test ergonomics (non-null assertions after expects, async mock
signatures, non-Error throws).
Code adjusted to pass: registry disposers wrap ctx.effect's
promise-returning disposer behind a sync () => void (our public API),
BlockAssembler gains an invariant-checking mustGet instead of non-null
assertions, lastTurnNumber uses findLast, waterfall tails return
Promise.resolve instead of async-without-await arrows, and the two
deliberate suppressions (non-exhaustive derivation switch, unbound
execute pass-through) carry justification comments.
yarn lint / yarn lint:fix added.
2026-06-11 14:17:58 +08:00
"eslint" : "^10.4.1" ,
2026-07-13 23:42:54 +08:00
"eslint-plugin-sonarjs" : "^4.1.0" ,
2026-06-14 00:06:25 +08:00
"fast-check" : "^4.8.0" ,
2026-07-14 21:25:58 +08:00
"js-yaml" : "^4.2.0" ,
2026-07-13 23:42:54 +08:00
"jscpd" : "^5.0.12" ,
2026-07-03 01:32:01 +08:00
"jsdom" : "29.1.1" ,
2026-06-11 15:04:50 +08:00
"knip" : "^6.16.1" ,
2026-06-11 15:07:55 +08:00
"lefthook" : "^2.1.9" ,
refactor: detect md hard-wraps via mdast AST, not regex
Per review feedback (use a real markdown parser with an AST linked to
source positions), rewrite verify-md-wrap to parse each file with
mdast-util-from-markdown (the CommonMark parser behind remark) + the GFM
extension, then flag any `paragraph` node whose source span covers more
than one line.
Why a parser over the hand-rolled line scanner:
- It is a checker, not a formatter — it reports and never rewrites, so
zero cosmetic churn (no emphasis-marker or table-delimiter
normalization, which is why Prettier was rejected for this).
- The AST owns every structural exemption (fenced code of any fence
length, tables, lists, blockquotes, HTML, headings, reference defs),
fixing both bugs the regex version had: it now catches wrapped
list-item / blockquote prose (a `paragraph` inside those nodes) and no
longer false-positives on a longer ```` fence wrapping an inner ```.
Also unwrap two pre-existing hard-wrapped blockquotes (architecture.md,
adding-a-tool.md) that the stricter AST check correctly surfaced.
2026-06-16 23:35:33 +08:00
"mdast-util-from-markdown" : "^2.0.3" ,
"mdast-util-gfm" : "^3.1.0" ,
2026-07-03 01:32:01 +08:00
"mermaid" : "11.16.0" ,
refactor: detect md hard-wraps via mdast AST, not regex
Per review feedback (use a real markdown parser with an AST linked to
source positions), rewrite verify-md-wrap to parse each file with
mdast-util-from-markdown (the CommonMark parser behind remark) + the GFM
extension, then flag any `paragraph` node whose source span covers more
than one line.
Why a parser over the hand-rolled line scanner:
- It is a checker, not a formatter — it reports and never rewrites, so
zero cosmetic churn (no emphasis-marker or table-delimiter
normalization, which is why Prettier was rejected for this).
- The AST owns every structural exemption (fenced code of any fence
length, tables, lists, blockquotes, HTML, headings, reference defs),
fixing both bugs the regex version had: it now catches wrapped
list-item / blockquote prose (a `paragraph` inside those nodes) and no
longer false-positives on a longer ```` fence wrapping an inner ```.
Also unwrap two pre-existing hard-wrapped blockquotes (architecture.md,
adding-a-tool.md) that the stricter AST check correctly surfaced.
2026-06-16 23:35:33 +08:00
"micromark-extension-gfm" : "^3.0.0" ,
2026-06-11 15:04:50 +08:00
"publint" : "^0.3.21" ,
2026-07-14 23:09:01 +08:00
"saxes" : "^6.0.0" ,
Replace dumble with tsdown for JS bundling
dumble (0.2.x, ~530 dl/wk, single-maintainer) was a bus-factor risk as
the load-bearing bundler. tsdown (rolldown-based, ~2.5M dl/wk, actively
maintained) replaces it while output stays list-identical, verified by
snapshot diff: 17 JS bundles, externals preserved, schemastery dual
.mjs/.cjs and logger-console node+browser entries intact.
Root tsdown.config.ts uses workspace globs ['vendor/*', 'packages/*']
(explicit, so examples/* stays excluded); two per-package overrides in
vendor/ cover the special shapes and are logged in vendor/README.md as
ours (not upstream sync surface). scripts/build.ts (dumble
orchestration) is deleted; yarn build = tsc -b && tsdown. tsc -b keeps
owning declarations (dts: false, clean: false).
Rationale recorded in ADR 0008 (also covers the direct-esbuild and
pkgroll alternatives).
Gates: lint, typecheck, 134 tests, hygiene (knip/publint/constraints),
demo smoke all green.
2026-06-11 22:08:10 +08:00
"tsdown" : "^0.22.2" ,
2026-06-11 10:52:45 +08:00
"tsx" : "^4.22.4" ,
"typescript" : "^6.0.3" ,
Add ESLint: typescript-eslint strict-type-checked + stylistic formatting
Flat config with two layers. Correctness (type-checked): the headline
rules for this codebase are no-floating-promises / no-misused-promises
(a lost promise in the agent loop is our primary bug class),
switch-exhaustiveness-check (we switch over merge-extensible unions
everywhere), no-unnecessary-condition, require-await, and
no-explicit-any. Style (@stylistic): 2-space, no semicolons, single
quotes, trailing commas, max-len 140 — the existing house style, now
enforced instead of drifting between agents. vendor/ is excluded
(vendored source keeps upstream style); tests relax the rules that
fight test ergonomics (non-null assertions after expects, async mock
signatures, non-Error throws).
Code adjusted to pass: registry disposers wrap ctx.effect's
promise-returning disposer behind a sync () => void (our public API),
BlockAssembler gains an invariant-checking mustGet instead of non-null
assertions, lastTurnNumber uses findLast, waterfall tails return
Promise.resolve instead of async-without-await arrows, and the two
deliberate suppressions (non-exhaustive derivation switch, unbound
execute pass-through) carry justification comments.
yarn lint / yarn lint:fix added.
2026-06-11 14:17:58 +08:00
"typescript-eslint" : "^8.61.0" ,
2026-06-11 10:52:45 +08:00
"vite-tsconfig-paths" : "^6.1.1" ,
"vitest" : "^4.1.8"
}
}