diff --git a/.github/workflows/llrt-native.yml b/.github/workflows/llrt-native.yml index 4eb801e..881e67d 100644 --- a/.github/workflows/llrt-native.yml +++ b/.github/workflows/llrt-native.yml @@ -2,6 +2,12 @@ name: LLRT Native Packages on: workflow_dispatch: + inputs: + publish: + description: Publish the LLRT package family + required: false + default: false + type: boolean pull_request: branches: [main] paths: @@ -20,8 +26,10 @@ on: - "pnpm-lock.yaml" - "pnpm-workspace.yaml" - "Taskfile.yml" - release: - types: [published] + +concurrency: + group: llrt-native-${{ github.ref }} + cancel-in-progress: false permissions: contents: read @@ -131,19 +139,19 @@ jobs: - run: pnpm --filter @robinbraemer/llrt run smoke:packed-install - name: Prepare native package metadata - if: github.event_name == 'release' + if: inputs.publish && github.ref == 'refs/heads/main' env: GITHUB_REPOSITORY: "" run: pnpm --filter @robinbraemer/llrt run prepare:native-publish - name: Publish optional native packages - if: github.event_name == 'release' + if: inputs.publish && github.ref == 'refs/heads/main' run: | for package_dir in packages/llrt/npm/*; do (cd "${package_dir}" && npm publish --access public) done - name: Publish main LLRT package - if: github.event_name == 'release' + if: inputs.publish && github.ref == 'refs/heads/main' run: npm publish --access public working-directory: packages/llrt diff --git a/internal/superpowers/specs/2026-06-10-standalone-llrt-typescript-runtime-design.md b/internal/superpowers/specs/2026-06-10-standalone-llrt-typescript-runtime-design.md index d26cdd6..8ecab06 100644 --- a/internal/superpowers/specs/2026-06-10-standalone-llrt-typescript-runtime-design.md +++ b/internal/superpowers/specs/2026-06-10-standalone-llrt-typescript-runtime-design.md @@ -235,7 +235,7 @@ It builds every declared napi target on an explicit GitHub-hosted runner: The workflow dry-run-packs each optional native package, uploads the native artifact, assembles all artifacts in a packaging job, dry-run-packs the main package and optional packages together, and publishes the LLRT package family -only for release events. +only when manually dispatched with publishing enabled on the `main` branch. `pnpm --filter @robinbraemer/llrt run verify:native-artifacts` verifies that the optional native package manifests match the root package's declared diff --git a/packages/codemode/package.json b/packages/codemode/package.json index 3a300e5..a48ef26 100644 --- a/packages/codemode/package.json +++ b/packages/codemode/package.json @@ -1,6 +1,6 @@ { "name": "@robinbraemer/codemode", - "version": "0.4.1", + "version": "0.4.2", "description": "Code Mode MCP tools from OpenAPI specs. Two tools (search + execute) replace hundreds of individual MCP tools.", "type": "module", "main": "./dist/index.js", diff --git a/packages/llrt/test/native-prebuild-workflow.test.ts b/packages/llrt/test/native-prebuild-workflow.test.ts index cbe49fb..b6cbbd5 100644 --- a/packages/llrt/test/native-prebuild-workflow.test.ts +++ b/packages/llrt/test/native-prebuild-workflow.test.ts @@ -17,6 +17,32 @@ function getNamedStep(workflow: string, stepName: string) { } describe("LLRT native prebuild workflow", () => { + + it("publishes only through an explicit LLRT release dispatch", () => { + const workflow = readFileSync(workflowPath, "utf8"); + const publishCondition = "if: inputs.publish && github.ref == 'refs/heads/main'"; + + expect(workflow).not.toContain(" release:\n types: [published]"); + expect(workflow).toContain("publish:\n description: Publish the LLRT package family"); + expect(workflow).toContain("default: false"); + expect(workflow).toContain("type: boolean"); + for (const stepName of [ + "Prepare native package metadata", + "Publish optional native packages", + "Publish main LLRT package", + ]) { + expect(getNamedStep(workflow, stepName)).toContain(publishCondition); + } + }); + + it("serializes LLRT package runs without cancelling an active publish", () => { + const workflow = readFileSync(workflowPath, "utf8"); + + expect(workflow).toContain("concurrency:"); + expect(workflow).toContain("group: llrt-native-${{ github.ref }}"); + expect(workflow).toContain("cancel-in-progress: false"); + }); + it("builds every napi target declared by the package manifest", () => { const workflow = readFileSync(workflowPath, "utf8");