Repository navigation
refactor: shared streaming pipes, typed wire JSON, and tooling hardening - #46
Merged
Merged
Conversation
Drops the interactive npm-install recovery flow (todo item G): a missing claude/codex now prints the recommended install command and exits. Also removes dead exports and narrows module-internal ones.
…hrough provider mappers All eight SSE pipes now run under withSsePipe (reader/heartbeat/teardown), emit protocol-appropriate terminal errors, and read token fields via the providers/usage field mappers instead of parsing raw payloads in the core.
payloads/pipes/finish per (endpoint, upstream protocol) replace three hand-written endpoint blocks that repeated the same non-stream tail.
…re path Providers and clients hand us parsed JSON that can't be fully trusted, so `any` let a misspelled field or a missing non-object check pass the compiler and fail at runtime. Introduce src/json.ts (JsonRecord plus typed field accessors) and read every payload through it, so those mistakes are now compiler errors. Also enables noUncheckedIndexedAccess, noUnusedLocals, noUnusedParameters and noImplicitOverride, and makes registerCustomProvider report the single model entry it always creates. Zero `any` remains under src/, and the strict flags catch two real gaps: a custom-provider model read that could be undefined, and unvalidated SQLite row fields.
Lint and type-check were the two gates a change could slip through without: `npm test` only builds and runs the suite. Adds an ESLint flat config whose rules cover what tsc can't see (a reintroduced `any` at a wire boundary, dead code), a `typecheck` script, `test:one` for running one file, and a CI lint job so the checks gate PRs. macOS joins the CI matrix because it is the developer platform whose paths and shell-profile handling differ from Linux. Also replaces the unused `text` accumulators in the streaming usage tests with a shared fake response that the tests now assert forwarded content against.
Three modules had no test of their own: src/json.ts (the accessors every wire payload is read through), src/fsutil.ts (atomicWriteFile, which is what keeps a crashed run from leaving a torn state file behind), and the shared Anthropic convert helpers. Their edge cases — a counter that arrives as "123", an image source that isn't a URL, DeepSeek-only controls leaking to other providers — are exactly the ones a caller can't see from the endpoint tests above them. Also covers runUsageStats end to end against a temporary usage dir, and moves lint, type-check and the package-content check into a CI job that runs once instead of six times, with macOS joining the test matrix.
The root-level spec was the brief the project was built from, not something a contributor reads today, so it moves to docs/plans/ marked as shipped with the current state pointed at docs/architecture.md. Documents what the last batch actually changed: src/json.ts as the only way to read a wire payload, lint/typecheck/single-test commands, the CI gates, and the completed auto-install removal. Also drops a code comment pointing at a todo item that no longer exists.
Replacing a destination another handle still holds surfaces a transient EPERM rather than a real failure, so back off and retry instead of dropping the write. A failed rename now also removes its temp file, which can otherwise leave a secret-bearing state payload on disk.
Keep PR #44's behaviour — tool-result images on every upstream protocol, count_tokens, authenticated model catalog, per-model headers, concurrency gate — while retaining this branch's typed wire payloads and single route table, so the new endpoints arrive already expressed in that shape.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
src/streaming/), and usage capture goes through the provider usage mappers instead of parsing upstream payloads in the streaming layer — restoring the "core only knowsTokenUsage" rule./v1/messages,/v1/responses,/v1/chat/completions) are driven from a single route table instead of per-endpoint handlers.src/json.ts(a typed JSON vocabulary:JsonValue/JsonRecord+ accessors) and removed everyanyfromsrc/; tsconfig gainednoUnusedLocals,noUnusedParameters,noImplicitOverride,noUncheckedIndexedAccess.no-explicit-anyas an error,npm run lint/typecheck/test:one, matchingmaketargets, and CI split into a single lint/pack job plus a 3-OS × Node 20/22/24 test matrix.claude/codexis missing.src/json.ts, atomic writes and the shared converters (366 tests, all green); architecture, README (EN + zh-CN) and CLAUDE.md updated, and the shipped original spec moved todocs/plans/initial-product-spec.md.Test plan
npm run lint— cleannpm test— 366 pass, 0 fail (no network, no API keys required)npm pack --dry-run— 44 files,dist/srconly (tests excluded)agentx claude/agentx codexstill launch against each upstream protocol after the streaming refactorCloses the remaining items from
docs/remaining-simplification-todos.mdexcept item K.