fix(cli): unblock prebuilt release entrypoint (SyntaxError + init deadlock) - #8
Closed
continued-agent wants to merge 1 commit into
Closed
fix(cli): unblock prebuilt release entrypoint (SyntaxError + init deadlock)#8continued-agent wants to merge 1 commit into
continued-agent wants to merge 1 commit into
Conversation
…dlock)
The bundled CLI produced by esbuild crashed at module load with
`SyntaxError: Unexpected reserved word` because circular static imports
between `src/compaction.ts` and `src/stream/streamChatResponse.ts`
(plus `src/subagent/executor.ts`) caused esbuild to emit a `__esm`
factory that contained a top-level `await` without the `async`
keyword. The previous fix (minifySyntax:false) only changed syntax
mangling; the underlying cycle remained and, once the SyntaxError was
removed, surfaced as a second bug: a deadlock in the module-init
promise chain (`init_streamChatResponse` <-> `init_subagent/executor`)
that hung the bundled CLI indefinitely.
Break the cycles by:
- extracting `pruneLastMessage` to `src/util/chatHistoryPrune.ts` so
the stream layer and compaction helpers no longer share a static
edge through the compaction module,
- moving `compactChatHistory` (and its `COMPACTION_PROMPT` /
`Compaction*` types) into a dedicated
`src/stream/streamChatResponse.compactChatHistory.ts` module so
`compaction.ts` becomes a leaf and `streamChatResponse.ts` is no
longer reachable from `autoCompaction.ts` through the compaction
module,
- resolving `streamChatResponse` at call time through a late-bound
`streamChatResponseRef` (`src/stream/streamChatResponse.lateRef.ts`)
from `compactChatHistory.ts` and `subagent/executor.ts`, so neither
module has a static import back into `streamChatResponse.ts`.
The release workflow () now validates
the exact artifact that will be published by copying `dist/index.js`,
`dist/cn.js`, `dist/xhr-sync-worker.js` and a minimal
`{"type":"module"}` `package.json` into a clean directory and
running `node cn.js --help` and `node cn.js --version` from there.
The GitHub release is only created when both commands succeed and
produce non-empty output. The README documents the packaging/validation
process and how to reproduce it locally.
All 1697 unit tests pass; the `node smoke-test.mjs` suite (which
invokes the bundled `dist/cn.js --help/--version`) passes; tsc and
eslint are clean.
Co-authored-by: kiloconnect[bot] <240665456+kiloconnect[bot]@users.noreply.github.com>
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.
Problem
The prebuilt CLI bundle produced by
npm run buildcrashes at module load with:The
Release CLIworkflow (triggered bycli-v*tag pushes) was building the bundle successfully but failing at theVerify release entrypointstep, socli-v0.1.0could not be released.Root cause
Circular static imports between three modules caused esbuild to emit a
__esmfactory forsrc/stream/streamChatResponse.autoCompaction.tsthat contained a top-levelawaitwithout theasynckeyword:src/compaction.ts<->src/stream/streamChatResponse.ts(the former calledstreamChatResponsefor streaming the summary; the latter usedpruneLastMessagefrom the former).src/subagent/executor.tsstatic-importedstreamChatResponse, adding a second cycle through the tools/subagent init chain.The earlier
minifySyntax: falsefix only stopped esbuild from mangling the keyword; it did not remove the cycle. With the cycle removed, a second symptom surfaced in the form of a module-init deadlock (init_streamChatResponsewaiting oninit_subagent/executorwaiting oninit_streamChatResponse) that hung the bundled CLI indefinitely.Fix
Break both cycles with the minimum number of files:
pruneLastMessageintosrc/util/chatHistoryPrune.tsso the stream layer and the compaction helpers no longer share a static edge throughcompaction.ts.compactChatHistory(and the relatedCOMPACTION_PROMPT/Compaction*types) into a newsrc/stream/streamChatResponse.compactChatHistory.tssocompaction.tsbecomes a leaf with no dependency on the stream layer, andstreamChatResponse.autoCompaction.tsno longer reachesstreamChatResponse.tsthroughcompaction.ts.streamChatResponseat call time through a late-boundstreamChatResponseRef(newsrc/stream/streamChatResponse.lateRef.ts) from bothcompactChatHistory.tsandsubagent/executor.ts, so neither module has a static import back intostreamChatResponse.ts.streamChatResponse.tsregisters itself in the ref at the end of its module factory, so consumers can call the function at runtime without creating a circular import.Release validation
The release workflow now validates the exact artifact that will be published by copying
dist/index.js,dist/cn.js,dist/xhr-sync-worker.jsand a minimal{"type":"module"}package.jsoninto a clean directory and running bothnode cn.js --helpandnode cn.js --versionfrom there. TheCreate GitHub releasestep is only reached when both commands succeed and produce non-empty output. This catches parse errors, top-levelawaitcycles, and missing-module issues before any release is published.Tests
node smoke-test.mjs(10/10 pass) — invokes the bundleddist/cn.js --help/--versionand other entrypoint checks.npx vitest run— 1697/1697 tests pass, 29 skipped.npx tsc --noEmit— clean.npx eslint .— clean.package.jsonto a clean directory and runningnode cn.js --helpandnode cn.js --versionsucceeds.Files
extensions/cli/src/util/chatHistoryPrune.ts(new) — leaf module forpruneLastMessage.extensions/cli/src/stream/streamChatResponse.compactChatHistory.ts(new) —compactChatHistoryand types.extensions/cli/src/stream/streamChatResponse.lateRef.ts(new) — late-boundstreamChatResponseRef.extensions/cli/src/compaction.ts— re-exportspruneLastMessagefor back-compat; no longer importsstreamChatResponse.extensions/cli/src/stream/streamChatResponse.ts— registers itself in the ref.extensions/cli/src/stream/streamChatResponse.autoCompaction.ts,extensions/cli/src/subagent/executor.ts,extensions/cli/src/ui/hooks/useChat.compaction.ts,extensions/cli/src/commands/chat.ts— updated imports.beforeAllwhere needed..github/workflows/release-cli.yml— combined verify/package step tests the exact published artifact (--helpand--version) in a clean directory; release is gated on success.extensions/cli/README.md,extensions/cli/CHANGELOG.md— document the packaging/validation process.