Files
dsh-context/.github/workflows
bowenliang123 8692c31162 build: adopt the official lint stack (oxlint + tsgolint, type-aware)
Mirror dsh's own lint setup (oxlint 1.76.0 pinned exact, oxlint-tsgolint
7.0.2001 with options.typeAware, correctness category off, hand-picked
rule list; jsPlugins: eslint-plugin-sonarjs + @stylistic/eslint-plugin
with the official style profile: indent 2, semi never, single quotes,
comma-dangle multiline, max-len 140). Scope mirrors official too: src TS
only, generated/bundled output (lib, *.js, *.mjs, *.config.ts) ignored.

Wiring: pnpm run lint / lint:fix scripts, plus a Lint step in the
release workflow between Build and Test.

Fixes applied (runtime behavior unchanged; verified against dsh
0.1.0-rc.7 and 0.1.1-rc.2 wire shapes, see below):

- autofix pass: arrow-parens, comma-dangle, eol-last, indent, quotes
- restrict-plus-operands: 31 string+number concatenations -> template
  literals (restrict-template-expressions allows numbers)
- no-unused-vars: drop unused imports/destructured names
- no-unnecessary-type-conversion: drop redundant String() where the
  field is already string-typed
- no-unsafe-*: type the fetch-json boundary in latestVersion, narrow
  unknown before spread/cast instead of trusting any
- no-unnecessary-condition, three honest categories:
  * boundary sanitizers (services.timelineOf/headersOf, RawBlocks,
    headers.recordOf) now read through Record<string, unknown> instead
    of casting first, so the defensive checks are type-meaningful again
  * post-sanitize consumers (contextView/headline/assemble/browser)
    drop the fallback-empty-array on collections the sanitizer
    guarantees
  * array-index-undefined gaps (fold turn attach, headers dedupe) use
    .at() so the past-the-end guard is real to the type system
- no-non-null-assertion: stackedBar reserve carries the checked max
- no-floating-promises: void the fire-and-forget version check
- intentional-contract suppressions with rationale: react.ts keeps its
  injected require (closure-factory loader contract)
- type-honest hardening kept deliberately: MessageSource.sections
  entries stay nullable (foreign plugins author snapshot sources) and
  isInjection still rejects a null source — foreign message payloads
  must never crash the fold

Cross-version audit (0.1.0-rc.7 vs 0.1.1-rc.2, message parsing focus):
- core/session types.ts: only additive optional interrupted on
  assistant/message (unread by us); every event payload we fold
  (request/header, request/context, tool/call, tool/result,
  user/message, assistant/message, compaction/*) is byte-identical
- llm types.ts / message.ts / content.ts block shapes: identical
- token-meter estimate.ts: identical, and official has NO null-entry
  guards on content blocks — our removed guards match official trust,
  our retained fallback-empty-string / typeof reads stay a leniency
  superset
- deriveEventMessage (core/session surface.ts): identical
- ui-conversation chat-nodes contract: unchanged; our client reads are
  minimally-typed unknowns by design
- tool/call callId is a branded string in both versions, so the
  narrowed typeof guard drops only an impossible coercion
2026-08-22 03:10:41 +08:00
..