fix(compression): prevent empty compression split when history is tool-heavy #1687
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
| # .github/workflows/ci.yml | |
| name: 'LLxprt Code CI' | |
| on: | |
| push: | |
| branches: | |
| - 'main' | |
| - 'release/**' | |
| pull_request: | |
| branches: | |
| - 'main' | |
| - 'release/**' | |
| merge_group: | |
| workflow_dispatch: | |
| # Manual trigger - no inputs needed, uses repository variables | |
| permissions: | |
| checks: 'write' | |
| contents: 'read' | |
| statuses: 'write' | |
| defaults: | |
| run: | |
| shell: 'bash' | |
| env: | |
| ACTIONLINT_VERSION: '1.7.7' | |
| SHELLCHECK_VERSION: '0.11.0' | |
| YAMLLINT_VERSION: '1.35.1' | |
| jobs: | |
| doc_change_filter: | |
| name: 'Detect doc-only changes' | |
| runs-on: 'ubuntu-latest' | |
| env: | |
| GH_TOKEN: '${{ github.token }}' | |
| outputs: | |
| docs_only: '${{ steps.detect.outputs.docs_only }}' | |
| steps: | |
| - name: 'Checkout' | |
| uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8' # ratchet:actions/checkout@v5 | |
| with: | |
| fetch-depth: 1 | |
| - name: 'Determine documentation-only PR' | |
| id: 'detect' | |
| env: | |
| PR_NUMBER: >- | |
| ${{ github.event_name == 'pull_request' && github.event.pull_request.number || '' }} | |
| run: | | |
| set -euo pipefail | |
| if [[ -z "${PR_NUMBER:-}" ]]; then | |
| echo "docs_only=false" >>"$GITHUB_OUTPUT" | |
| exit 0 | |
| fi | |
| files="$(gh api \ | |
| --paginate \ | |
| -H "Accept: application/vnd.github+json" \ | |
| "repos/${GITHUB_REPOSITORY}/pulls/${PR_NUMBER}/files" \ | |
| --jq '.[].filename' || true)" | |
| if [[ -z "$files" ]]; then | |
| echo "docs_only=false" >>"$GITHUB_OUTPUT" | |
| { | |
| echo "### Unable to determine doc-only status" | |
| echo "GitHub API returned no files; running full CI to be safe." | |
| } >>"$GITHUB_STEP_SUMMARY" | |
| exit 0 | |
| fi | |
| docs_only=true | |
| while IFS= read -r file; do | |
| [[ -z "$file" ]] && continue | |
| case "$file" in | |
| docs/*|README.md|README.*|*.md|*.mdx|*.rst|*.txt|*.adoc) | |
| ;; | |
| *) | |
| docs_only=false | |
| break | |
| ;; | |
| esac | |
| done <<<"$files" | |
| echo "docs_only=${docs_only}" >>"$GITHUB_OUTPUT" | |
| if [[ "$docs_only" == "true" ]]; then | |
| { | |
| echo "### Documentation-only PR detected" | |
| echo "Skipping automated test suites (unit + coverage) for this PR." | |
| } >>"$GITHUB_STEP_SUMMARY" | |
| fi | |
| # | |
| # Lint: GitHub Actions | |
| # | |
| lint_github_actions: | |
| name: 'Lint (GitHub Actions)' | |
| runs-on: 'ubuntu-latest' | |
| steps: | |
| - name: 'Checkout' | |
| uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8' # ratchet:actions/checkout@v5 | |
| with: | |
| fetch-depth: 1 | |
| - name: 'Install shellcheck' # Actionlint uses shellcheck | |
| run: |- | |
| mkdir -p "${RUNNER_TEMP}/shellcheck" | |
| curl -sSLo "${RUNNER_TEMP}/.shellcheck.txz" "https://github.com/koalaman/shellcheck/releases/download/v${SHELLCHECK_VERSION}/shellcheck-v${SHELLCHECK_VERSION}.linux.x86_64.tar.xz" | |
| tar -xf "${RUNNER_TEMP}/.shellcheck.txz" -C "${RUNNER_TEMP}/shellcheck" --strip-components=1 | |
| echo "${RUNNER_TEMP}/shellcheck" >> "${GITHUB_PATH}" | |
| - name: 'Install actionlint' | |
| run: |- | |
| mkdir -p "${RUNNER_TEMP}/actionlint" | |
| curl -sSLo "${RUNNER_TEMP}/.actionlint.tgz" "https://github.com/rhysd/actionlint/releases/download/v${ACTIONLINT_VERSION}/actionlint_${ACTIONLINT_VERSION}_linux_amd64.tar.gz" | |
| tar -xzf "${RUNNER_TEMP}/.actionlint.tgz" -C "${RUNNER_TEMP}/actionlint" | |
| echo "${RUNNER_TEMP}/actionlint" >> "${GITHUB_PATH}" | |
| # For actionlint, we specifically ignore shellcheck rules that are | |
| # annoying or unhelpful. See the shellcheck action for a description. | |
| - name: 'Run actionlint' | |
| run: |- | |
| actionlint \ | |
| -color \ | |
| -format "{{range \$err := .}}::error file={{\$err.Filepath}},line={{\$err.Line}},col={{\$err.Column}}::{{\$err.Filepath}}@{{\$err.Line}} {{\$err.Message}}%0A\`\`\`%0A{{replace \$err.Snippet \"\\\\n\" \"%0A\"}}%0A\`\`\`\\n{{end}}" \ | |
| -ignore 'SC2002:' \ | |
| -ignore 'SC2016:info' \ | |
| -ignore 'SC2129:' \ | |
| -ignore 'label ".+" is unknown' | |
| - name: 'Run ratchet' | |
| uses: 'sethvargo/ratchet@8b4ca256dbed184350608a3023620f267f0a5253' # ratchet:sethvargo/ratchet@v0.11.4 | |
| with: | |
| files: |- | |
| .github/workflows/*.yml | |
| .github/actions/**/*.yml | |
| # | |
| # Lint: Javascript | |
| # | |
| lint_javascript: | |
| name: 'Lint (Javascript)' | |
| runs-on: 'ubuntu-latest' | |
| steps: | |
| - name: 'Checkout' | |
| uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8' # ratchet:actions/checkout@v5 | |
| with: | |
| fetch-depth: 0 | |
| - name: 'Set up Node.js' | |
| uses: 'actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020' # ratchet:actions/setup-node@v4.4.0 | |
| with: | |
| node-version-file: '.nvmrc' | |
| cache: 'npm' | |
| - name: 'Setup Bun' | |
| uses: 'oven-sh/setup-bun@735343b667d3e6f658f44d0eca948eb6282f2b76' # ratchet:oven-sh/setup-bun@v2 | |
| with: | |
| bun-version: 'latest' | |
| - name: 'Run lockfile check' | |
| run: |- | |
| npm run check:lockfile | |
| - name: 'Install dependencies' | |
| run: |- | |
| npm ci | |
| - name: 'Install UI dependencies (bun)' | |
| run: |- | |
| cd packages/ui && bun install | |
| - name: Fix rollup platform dependency | |
| run: | | |
| # Explicitly install the platform-specific rollup package | |
| # This is a workaround for https://github.com/npm/cli/issues/4828 | |
| if [ "${{ runner.os }}" == "Linux" ]; then | |
| npm install @rollup/rollup-linux-x64-gnu --no-save || true | |
| elif [ "${{ runner.os }}" == "Windows" ]; then | |
| npm install @rollup/rollup-win32-x64-msvc --no-save || true | |
| fi | |
| shell: bash | |
| - name: 'Run formatter check' | |
| run: |- | |
| npm run format | |
| # Check for changes, excluding project-plans directory and bun.lock (regenerated by bun install) | |
| git diff --exit-code -- . ':!project-plans/' ':!packages/ui/bun.lock' | |
| - name: 'Run linter' | |
| run: |- | |
| npm run lint:ci | |
| - name: 'Run UI linter (bun)' | |
| run: |- | |
| cd packages/ui && bun run lint | |
| - name: 'Run linter on integration tests' | |
| run: |- | |
| npx eslint integration-tests --max-warnings 0 | |
| - name: 'Run formatter on integration tests' | |
| run: |- | |
| npx prettier --check integration-tests | |
| git diff --exit-code -- . ':!packages/ui/bun.lock' | |
| - name: 'Build project' | |
| run: |- | |
| npm run build | |
| - name: Create bundle | |
| run: npm run bundle | |
| - name: 'Run type check' | |
| run: |- | |
| npm run typecheck | |
| - name: 'Run UI type check (bun)' | |
| run: |- | |
| cd packages/ui && bun run typecheck | |
| - name: 'Run sensitive keyword linter' | |
| run: 'node scripts/lint.js --sensitive-keywords' | |
| # | |
| # Lint: Shell | |
| # | |
| lint_shell: | |
| name: 'Lint (Shell)' | |
| runs-on: 'ubuntu-latest' | |
| steps: | |
| - name: 'Checkout' | |
| uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8' # ratchet:actions/checkout@v5 | |
| with: | |
| fetch-depth: 1 | |
| - name: 'Install shellcheck' | |
| run: |- | |
| mkdir -p "${RUNNER_TEMP}/shellcheck" | |
| curl -sSLo "${RUNNER_TEMP}/.shellcheck.txz" "https://github.com/koalaman/shellcheck/releases/download/v${SHELLCHECK_VERSION}/shellcheck-v${SHELLCHECK_VERSION}.linux.x86_64.tar.xz" | |
| tar -xf "${RUNNER_TEMP}/.shellcheck.txz" -C "${RUNNER_TEMP}/shellcheck" --strip-components=1 | |
| echo "${RUNNER_TEMP}/shellcheck" >> "${GITHUB_PATH}" | |
| - name: 'Install shellcheck problem matcher' | |
| run: |- | |
| cat > "${RUNNER_TEMP}/shellcheck/problem-matcher-lint-shell.json" <<"EOF" | |
| { | |
| "problemMatcher": [ | |
| { | |
| "owner": "lint_shell", | |
| "pattern": [ | |
| { | |
| "regexp": "^(.*):(\\\\d+):(\\\\d+):\\\\s+(?:fatal\\\\s+)?(warning|error):\\\\s+(.*)$", | |
| "file": 1, | |
| "line": 2, | |
| "column": 3, | |
| "severity": 4, | |
| "message": 5 | |
| } | |
| ] | |
| } | |
| ] | |
| } | |
| EOF | |
| echo "::add-matcher::${RUNNER_TEMP}/shellcheck/problem-matcher-lint-shell.json" | |
| # Note that only warning and error severity show up in the github files | |
| # page. So we replace 'style' and 'note' with 'warning' to make it show | |
| # up. | |
| # | |
| # We also try and find all bash scripts even if they don't have an | |
| # explicit extension. | |
| # | |
| # We explicitly ignore the following rules: | |
| # | |
| # - SC2002: This rule suggests using "cmd < file" instead of "cat | cmd". | |
| # While < is more efficient, pipes are much more readable and expected. | |
| # | |
| # - SC2129: This rule suggests grouping multiple writes to a file in | |
| # braces like "{ cmd1; cmd2; } >> file". This is unexpected and less | |
| # readable. | |
| # | |
| # - SC2310: This is an optional warning that only appears with "set -e" | |
| # and when a command is used as a conditional. | |
| - name: 'Run shellcheck' | |
| run: |- | |
| git ls-files | grep -E '^([^.]+|.*\.(sh|zsh|bash))$' | xargs file --mime-type \ | |
| | grep "text/x-shellscript" | awk '{ print substr($1, 1, length($1)-1) }' \ | |
| | xargs shellcheck \ | |
| --check-sourced \ | |
| --enable=all \ | |
| --exclude=SC2002,SC2129,SC2310,SC2311,SC2312 \ | |
| --severity=style \ | |
| --format=gcc \ | |
| --color=never | sed -e 's/note:/warning:/g' -e 's/style:/warning:/g' | |
| # | |
| # Lint: YAML | |
| # | |
| lint_yaml: | |
| name: 'Lint (YAML)' | |
| runs-on: 'ubuntu-latest' | |
| steps: | |
| - name: 'Checkout' | |
| uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8' # ratchet:actions/checkout@v5 | |
| with: | |
| fetch-depth: 1 | |
| - name: 'Setup Python' | |
| uses: 'actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065' # ratchet:actions/setup-python@v5 | |
| with: | |
| python-version: '3' | |
| - name: 'Install yamllint' | |
| run: |- | |
| pip install --user "yamllint==${YAMLLINT_VERSION}" | |
| - name: 'Run yamllint' | |
| run: |- | |
| git ls-files | grep -E '\.(yaml|yml)' | xargs yamllint --format github | |
| # | |
| # Lint: All | |
| # | |
| # This is a virtual job that other jobs depend on to wait for all linters to | |
| # finish. It's also used to ensure linting happens on CI via required | |
| # workflows. | |
| lint: | |
| name: 'Lint' | |
| needs: | |
| - 'lint_github_actions' | |
| - 'lint_javascript' | |
| - 'lint_shell' | |
| - 'lint_yaml' | |
| runs-on: 'ubuntu-latest' | |
| steps: | |
| - run: |- | |
| echo 'All linters finished!' | |
| # | |
| # Test: Node | |
| # | |
| test: | |
| name: 'Test' | |
| runs-on: '${{ matrix.os }}' | |
| needs: | |
| - 'lint' | |
| - 'doc_change_filter' | |
| if: ${{ needs.doc_change_filter.outputs.docs_only != 'true' }} | |
| permissions: | |
| contents: 'read' | |
| checks: 'write' | |
| pull-requests: 'write' | |
| strategy: | |
| fail-fast: false # So we can see all test failures | |
| matrix: | |
| os: | |
| - 'ubuntu-latest' | |
| - 'macos-latest' | |
| - 'windows-latest' | |
| node-version: | |
| - '24.x' | |
| steps: | |
| - name: 'Checkout' | |
| uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8' # ratchet:actions/checkout@v5 | |
| - name: 'Set up Node.js ${{ matrix.node-version }}' | |
| uses: 'actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020' # ratchet:actions/setup-node@v4 | |
| with: | |
| node-version: '${{ matrix.node-version }}' | |
| cache: 'npm' | |
| - name: 'Setup Bun' | |
| uses: 'oven-sh/setup-bun@735343b667d3e6f658f44d0eca948eb6282f2b76' # ratchet:oven-sh/setup-bun@v2 | |
| with: | |
| bun-version: 'latest' | |
| - name: 'Install dependencies for testing' | |
| run: |- | |
| npm ci | |
| - name: 'Install UI dependencies (bun)' | |
| run: |- | |
| cd packages/ui && bun install | |
| - name: 'Build project' | |
| run: |- | |
| npm run build | |
| - name: 'Create bundle' | |
| run: |- | |
| npm run bundle | |
| - name: 'Fix rollup platform dependency' | |
| run: |- | |
| # Explicitly install the platform-specific rollup package | |
| # This is a workaround for https://github.com/npm/cli/issues/4828 | |
| if [ "${{ runner.os }}" == "Linux" ]; then | |
| npm install @rollup/rollup-linux-x64-gnu --no-save || true | |
| elif [ "${{ runner.os }}" == "Windows" ]; then | |
| npm install @rollup/rollup-win32-x64-msvc --no-save || true | |
| fi | |
| shell: 'bash' | |
| - name: 'Run tests and generate reports' | |
| env: | |
| # Provider configuration from repository secrets/variables | |
| OPENAI_API_KEY: ${{ secrets[vars.KEY_VAR_NAME] }} | |
| OPENAI_BASE_URL: ${{ vars.OPENAI_BASE_URL }} | |
| LLXPRT_DEFAULT_MODEL: ${{ vars.LLXPRT_DEFAULT_MODEL }} | |
| LLXPRT_DEFAULT_PROVIDER: ${{ vars.LLXPRT_DEFAULT_PROVIDER }} | |
| # Set auth type to provider for API key authentication | |
| LLXPRT_AUTH_TYPE: provider | |
| NO_COLOR: true | |
| # Ensure OAuth tests are skipped in CI (they require browser interaction) | |
| CI: true | |
| # Allow OpenAI integration tests to exceed Vitest's 5s default timeout (issue #338) | |
| VITEST_TEST_TIMEOUT: 15000 | |
| run: 'npm run test' | |
| - name: 'Run script harness tests (macOS)' | |
| if: matrix.os == 'macos-latest' | |
| env: | |
| CI: true | |
| run: npm run test:scripts | |
| - name: 'Run UI tests (vitest with happy-dom)' | |
| env: | |
| CI: true | |
| run: |- | |
| cd packages/ui && bun run test | |
| - name: 'Smoke test bundle' | |
| run: 'node ./bundle/llxprt.js --version' | |
| - name: 'Wait for file system sync' | |
| run: 'sleep 2' | |
| - name: 'Publish Test Report (for non-forks)' | |
| if: |- | |
| ${{ always() && (github.event.pull_request.head.repo.full_name == github.repository) }} | |
| uses: 'dorny/test-reporter@dc3a92680fcc15842eef52e8c4606ea7ce6bd3f3' # ratchet:dorny/test-reporter@v2 | |
| with: | |
| name: 'Test Results (Node ${{ matrix.node-version }})' | |
| path: 'packages/*/junit.xml' | |
| reporter: 'java-junit' | |
| fail-on-error: 'false' | |
| - name: 'Upload Test Results Artifact (for forks)' | |
| if: |- | |
| ${{ always() && (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository) }} | |
| uses: 'actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02' # ratchet:actions/upload-artifact@v4 | |
| with: | |
| name: 'test-results-fork-${{ matrix.node-version }}-${{ matrix.os }}' | |
| path: 'packages/*/junit.xml' | |
| - name: 'Upload coverage reports' | |
| if: |- | |
| ${{ always() }} | |
| uses: 'actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02' # ratchet:actions/upload-artifact@v4 | |
| with: | |
| name: 'coverage-reports-${{ matrix.node-version }}-${{ matrix.os }}' | |
| path: 'packages/*/coverage' | |
| post_coverage_comment: | |
| name: 'Post Coverage Comment' | |
| runs-on: 'ubuntu-latest' | |
| needs: 'test' | |
| if: |- | |
| ${{ always() && github.event_name == 'pull_request' && (github.event.pull_request.head.repo.full_name == github.repository) }} | |
| continue-on-error: true | |
| permissions: | |
| contents: 'read' # For checkout | |
| pull-requests: 'write' # For commenting | |
| strategy: | |
| matrix: | |
| # Reduce noise by only posting the comment once | |
| os: | |
| - 'ubuntu-latest' | |
| node-version: | |
| - '24.x' | |
| steps: | |
| - name: 'Checkout' | |
| uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8' # ratchet:actions/checkout@v5 | |
| - name: 'Download coverage reports artifact' | |
| uses: 'actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0' # ratchet:actions/download-artifact@v5 | |
| with: | |
| name: 'coverage-reports-${{ matrix.node-version }}-${{ matrix.os }}' | |
| path: 'coverage_artifact' # Download to a specific directory | |
| - name: 'Post Coverage Comment using Composite Action' | |
| uses: './.github/actions/post-coverage-comment' # Path to the composite action directory | |
| with: | |
| cli_json_file: 'coverage_artifact/cli/coverage/coverage-summary.json' | |
| core_json_file: 'coverage_artifact/core/coverage/coverage-summary.json' | |
| cli_full_text_summary_file: 'coverage_artifact/cli/coverage/full-text-summary.txt' | |
| core_full_text_summary_file: 'coverage_artifact/core/coverage/full-text-summary.txt' | |
| node_version: '${{ matrix.node-version }}' | |
| os: '${{ matrix.os }}' | |
| github_token: '${{ secrets.GITHUB_TOKEN }}' | |
| codeql: | |
| name: 'CodeQL' | |
| runs-on: 'ubuntu-latest' | |
| permissions: | |
| actions: 'read' | |
| contents: 'read' | |
| security-events: 'write' | |
| steps: | |
| - name: 'Checkout' | |
| uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8' # ratchet:actions/checkout@v5 | |
| - name: 'Initialize CodeQL' | |
| uses: 'github/codeql-action/init@df559355d593797519d70b90fc8edd5db049e7a2' # ratchet:github/codeql-action/init@v3 | |
| with: | |
| languages: 'javascript' | |
| - name: 'Perform CodeQL Analysis' | |
| uses: 'github/codeql-action/analyze@df559355d593797519d70b90fc8edd5db049e7a2' # ratchet:github/codeql-action/analyze@v3 |