feat(daemon): recover owned detached sessions #89
Workflow file for this run
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
| name: CI | |
| on: | |
| workflow_call: | |
| inputs: | |
| checkout_ref: | |
| description: Exact candidate commit to verify from a trusted Pylon workflow | |
| required: false | |
| type: string | |
| require_trusted: | |
| description: Fail the aggregate when a trusted caller is not recognized | |
| required: false | |
| default: false | |
| type: boolean | |
| push: | |
| branches: [pylon] | |
| pull_request: | |
| branches: [pylon] | |
| types: [opened, synchronize, reopened, ready_for_review] | |
| concurrency: | |
| group: ci-${{ inputs.checkout_ref || github.ref }} | |
| cancel-in-progress: true | |
| permissions: | |
| contents: read | |
| jobs: | |
| trust: | |
| name: Contributor trust | |
| if: github.event_name != 'pull_request' || github.event.pull_request.draft == false | |
| runs-on: ubuntu-latest | |
| outputs: | |
| allowed: ${{ steps.internal.outputs.allowed == 'true' || steps.sync.outputs.allowed == 'true' || steps.vouch.outputs.vouched == 'true' }} | |
| steps: | |
| - name: Recognize a trusted Pylon execution | |
| id: internal | |
| if: github.event_name == 'push' || inputs.checkout_ref != '' | |
| env: | |
| CHECKOUT_REF: ${{ inputs.checkout_ref }} | |
| CALLER_EVENT: ${{ github.event_name }} | |
| CALLER_REF: ${{ github.ref }} | |
| CALLER_REPOSITORY: ${{ github.repository }} | |
| run: | | |
| if [[ "$CALLER_REPOSITORY" != "pylon-code/prime-agent" || "$CALLER_REF" != "refs/heads/pylon" ]]; then | |
| exit 0 | |
| fi | |
| if [[ "$CALLER_EVENT" == "push" && -z "$CHECKOUT_REF" ]]; then | |
| echo "allowed=true" >> "$GITHUB_OUTPUT" | |
| elif [[ ("$CALLER_EVENT" == "workflow_dispatch" || "$CALLER_EVENT" == "schedule") && "$CHECKOUT_REF" =~ ^[0-9a-f]{40}$ ]]; then | |
| echo "allowed=true" >> "$GITHUB_OUTPUT" | |
| fi | |
| - name: Recognize the internal upstream sync pull request | |
| id: sync | |
| if: github.event_name == 'pull_request' | |
| env: | |
| HAS_SYNC_LABEL: ${{ contains(github.event.pull_request.labels.*.name, 'pylon-upstream-sync') }} | |
| HEAD_REF: ${{ github.event.pull_request.head.ref }} | |
| HEAD_REPOSITORY: ${{ github.event.pull_request.head.repo.full_name }} | |
| run: | | |
| if [ "$HAS_SYNC_LABEL" = true ] && [ "$HEAD_REPOSITORY" = "pylon-code/prime-agent" ] && [[ "$HEAD_REF" == automation/prime-upstream-* ]]; then | |
| echo "allowed=true" >> "$GITHUB_OUTPUT" | |
| fi | |
| - name: Check pull request author | |
| id: vouch | |
| if: github.event_name == 'pull_request' && steps.sync.outputs.allowed != 'true' | |
| uses: mitchellh/vouch/action/check-user@d66fa29a64600490892131ad87597c30c91fcac4 # v1 | |
| with: | |
| user: ${{ github.event.pull_request.user.login }} | |
| allow-fail: true | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| build-check: | |
| name: Build and check | |
| needs: trust | |
| if: needs.trust.outputs.allowed == 'true' | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 | |
| with: | |
| ref: ${{ inputs.checkout_ref || github.ref }} | |
| persist-credentials: false | |
| - name: Setup Node.js | |
| uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 | |
| with: | |
| node-version: 22 | |
| cache: npm | |
| - name: Install system dependencies | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y libcairo2-dev libpango1.0-dev libjpeg-dev libgif-dev librsvg2-dev fd-find ripgrep | |
| sudo ln -s "$(which fdfind)" /usr/local/bin/fd | |
| - name: Install dependencies | |
| run: npm ci | |
| - name: Build | |
| run: npm run build | |
| - name: Check | |
| run: npm run check | |
| test: | |
| name: Test (${{ matrix.name }}) | |
| needs: trust | |
| if: needs.trust.outputs.allowed == 'true' | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - name: agent-core | |
| package: packages/agent | |
| command: npm test | |
| install_uv: false | |
| - name: ai | |
| package: packages/ai | |
| command: npm test | |
| install_uv: false | |
| - name: tui | |
| package: packages/tui | |
| command: npm test | |
| install_uv: false | |
| - name: coding-agent 1/3 | |
| package: packages/coding-agent | |
| command: npm run test:ci -- --shard=1/3 | |
| install_uv: true | |
| - name: coding-agent 2/3 | |
| package: packages/coding-agent | |
| command: npm run test:ci -- --shard=2/3 | |
| install_uv: true | |
| - name: coding-agent 3/3 | |
| package: packages/coding-agent | |
| command: npm run test:ci -- --shard=3/3 | |
| install_uv: true | |
| - name: coding-agent process smoke | |
| package: packages/coding-agent | |
| command: npm run test:process | |
| install_uv: true | |
| - name: coding-agent kernel | |
| package: packages/coding-agent | |
| command: npm run test:kernel | |
| install_uv: true | |
| - name: runtime python | |
| package: prime-agent-runtime | |
| command: uv run python -m unittest discover -s test | |
| install_uv: true | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 | |
| with: | |
| ref: ${{ inputs.checkout_ref || github.ref }} | |
| persist-credentials: false | |
| - name: Setup Node.js | |
| uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 | |
| with: | |
| node-version: 22 | |
| cache: npm | |
| - name: Install system dependencies | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y libcairo2-dev libpango1.0-dev libjpeg-dev libgif-dev librsvg2-dev fd-find ripgrep | |
| sudo ln -s "$(which fdfind)" /usr/local/bin/fd | |
| - name: Install dependencies | |
| run: npm ci | |
| - name: Build | |
| run: npm run build | |
| - name: Install uv | |
| if: matrix.install_uv | |
| run: | | |
| python3 -m pip install --user uv | |
| echo "$HOME/.local/bin" >> "$GITHUB_PATH" | |
| - name: Test | |
| working-directory: ${{ matrix.package }} | |
| run: ${{ matrix.command }} | |
| owned-session-contract-windows: | |
| name: Caller-owned session contract (Windows named pipe) | |
| needs: trust | |
| if: needs.trust.outputs.allowed == 'true' | |
| runs-on: windows-latest | |
| timeout-minutes: 10 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 | |
| with: | |
| ref: ${{ inputs.checkout_ref || github.ref }} | |
| persist-credentials: false | |
| - name: Setup Node.js | |
| uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 | |
| with: | |
| node-version: 22 | |
| cache: npm | |
| - name: Install dependencies | |
| run: npm ci | |
| - name: Test named-pipe owned cleanup | |
| working-directory: packages/coding-agent | |
| run: npx tsx ../../node_modules/vitest/dist/cli.js --run test/daemon-supervisor-process.test.ts -t "proves exact owned cleanup over a Windows named pipe" | |
| pylon-artifact-pack: | |
| name: Pylon artifact pack (${{ matrix.copy }}) | |
| needs: trust | |
| if: needs.trust.outputs.allowed == 'true' | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 20 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| copy: [a, b] | |
| env: | |
| PYLON_RELEASE_NODE: 22.23.2 | |
| PYLON_RELEASE_NPM: 11.10.1 | |
| steps: | |
| - name: Checkout exact source | |
| uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 | |
| with: | |
| ref: ${{ inputs.checkout_ref || github.ref }} | |
| persist-credentials: false | |
| fetch-depth: 1 | |
| - name: Setup pinned Node.js | |
| uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 | |
| with: | |
| node-version: ${{ env.PYLON_RELEASE_NODE }} | |
| - name: Install pinned build inputs | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y libcairo2-dev libpango1.0-dev libjpeg-dev libgif-dev librsvg2-dev | |
| npm install --global "npm@${PYLON_RELEASE_NPM}" | |
| test "$(node --version)" = "v${PYLON_RELEASE_NODE}" | |
| test "$(npm --version)" = "${PYLON_RELEASE_NPM}" | |
| npm ci | |
| - name: Test release contract | |
| run: npm run test:pylon-release | |
| - name: Build offline and pack without network | |
| run: | | |
| sudo env \ | |
| "PATH=$PATH" \ | |
| "HOME=$HOME" \ | |
| "GIT_CONFIG_COUNT=1" \ | |
| "GIT_CONFIG_KEY_0=safe.directory" \ | |
| "GIT_CONFIG_VALUE_0=$GITHUB_WORKSPACE" \ | |
| unshare --net -- npm run release:pylon:pack | |
| - name: Verify artifact contract | |
| run: npm run release:pylon:verify | |
| - name: Upload candidate | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| with: | |
| name: pylon-prime-pack-${{ matrix.copy }} | |
| path: .npm/pylon-release/artifacts | |
| include-hidden-files: true | |
| if-no-files-found: error | |
| retention-days: 3 | |
| pylon-artifact-reproducibility: | |
| name: Pylon artifact reproducibility | |
| needs: pylon-artifact-pack | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 5 | |
| steps: | |
| - name: Download first isolated pack | |
| uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 | |
| with: | |
| name: pylon-prime-pack-a | |
| path: pack-a | |
| - name: Download second isolated pack | |
| uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 | |
| with: | |
| name: pylon-prime-pack-b | |
| path: pack-b | |
| - name: Require byte-identical outputs | |
| run: diff --recursive --brief pack-a pack-b | |
| pylon-artifact-install: | |
| name: Pylon artifact install (${{ matrix.os }}) | |
| needs: [trust, pylon-artifact-pack, pylon-artifact-reproducibility] | |
| if: needs.trust.outputs.allowed == 'true' | |
| runs-on: ${{ matrix.os }} | |
| timeout-minutes: 15 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| os: [ubuntu-24.04, macos-15] | |
| env: | |
| PYLON_RELEASE_NODE: 22.23.2 | |
| PYLON_RELEASE_NPM: 11.10.1 | |
| steps: | |
| - name: Checkout exact source | |
| uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 | |
| with: | |
| ref: ${{ inputs.checkout_ref || github.ref }} | |
| persist-credentials: false | |
| fetch-depth: 1 | |
| - name: Setup pinned Node.js | |
| uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 | |
| with: | |
| node-version: ${{ env.PYLON_RELEASE_NODE }} | |
| - name: Install pinned npm | |
| run: npm install --global "npm@${{ env.PYLON_RELEASE_NPM }}" | |
| - name: Download reproducible pack | |
| uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 | |
| with: | |
| name: pylon-prime-pack-a | |
| path: .npm/pylon-release/artifacts | |
| - name: Verify temporary-prefix runtime | |
| run: npm run release:pylon:smoke | |
| build-check-test: | |
| name: build-check-test | |
| if: always() && (needs.trust.outputs.allowed == 'true' || inputs.require_trusted) | |
| needs: | |
| - trust | |
| - build-check | |
| - test | |
| - owned-session-contract-windows | |
| - pylon-artifact-pack | |
| - pylon-artifact-reproducibility | |
| - pylon-artifact-install | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Verify CI results | |
| env: | |
| TRUST_ALLOWED: ${{ needs.trust.outputs.allowed }} | |
| BUILD_CHECK_RESULT: ${{ needs.build-check.result }} | |
| TEST_RESULT: ${{ needs.test.result }} | |
| WINDOWS_OWNED_SESSION_RESULT: ${{ needs.owned-session-contract-windows.result }} | |
| ARTIFACT_PACK_RESULT: ${{ needs.pylon-artifact-pack.result }} | |
| ARTIFACT_REPRODUCIBILITY_RESULT: ${{ needs.pylon-artifact-reproducibility.result }} | |
| ARTIFACT_INSTALL_RESULT: ${{ needs.pylon-artifact-install.result }} | |
| run: | | |
| test "$TRUST_ALLOWED" = true | |
| test "$BUILD_CHECK_RESULT" = success | |
| test "$TEST_RESULT" = success | |
| test "$WINDOWS_OWNED_SESSION_RESULT" = success | |
| test "$ARTIFACT_PACK_RESULT" = success | |
| test "$ARTIFACT_REPRODUCIBILITY_RESULT" = success | |
| test "$ARTIFACT_INSTALL_RESULT" = success |