Skip to content

ci: publish immutable npm dev packages#146

Merged
alongubkin merged 15 commits into
alon/alien-270-complete-reliable-tcp-and-stateful-workload-support-end-tofrom
alon/alien-270-npm-dev-publication
Jul 20, 2026
Merged

ci: publish immutable npm dev packages#146
alongubkin merged 15 commits into
alon/alien-270-complete-reliable-tcp-and-stateful-workload-support-end-tofrom
alon/alien-270-npm-dev-publication

Conversation

@alongubkin

Copy link
Copy Markdown
Member

Summary

  • add a workflow-dispatched npm development publication lane for exact source revisions
  • version the complete public npm graph as immutable <base>-dev.<git-sha> prereleases and publish only under the dev dist-tag
  • build native binding packages on their target architectures, then pack and smoke-install the complete graph before publishing
  • make retries safe by comparing npm integrity for any already-published version and refusing mismatched bytes
  • record exact versions and SHA-256 tarball digests in the workflow summary and retained artifacts

The default is a dry run. The workflow never commits version changes, creates git tags, or updates npm latest.

Validation

  • node --test scripts/npm-dev-release.test.mjs
  • real npm pack of rewritten core and commands packages; verified exact internal dependency pin and built JS/type declarations in the tarballs
  • pnpm install --frozen-lockfile
  • package build passed for core, commands, bindings, SDK, testing, and manager API; local full build hit the host Node heap limit while building the large generated platform API with the default 4 GiB heap, while the workflow explicitly sets 8 GiB
  • actionlint (only repository-specific Depot runner labels ignored)
  • git diff --check

@greptile-apps

greptile-apps Bot commented Jul 20, 2026

Copy link
Copy Markdown

Greptile Summary

This PR introduces a workflow_dispatch-triggered pipeline (publish-npm-dev.yml) that builds native addons across four architectures, rewrites the entire npm package graph to immutable <base>-dev.<12-char-sha> prereleases, packs and smoke-installs all packages, and publishes them under the dev dist-tag with an integrity-guarded idempotency check to make retries safe. It ships the rewrite/validate/digest logic as a standalone ESM script (npm-dev-release.mjs) with a matching test suite.

  • The workflow default is dry-run (dry_run: true) and never commits version changes, creates tags, or updates latest.
  • A hardcoded version assertion in the test will cause the prepare job to fail the next time either @alienplatform/core or @alienplatform/platform-api is bumped, blocking future dev publishes until the literal is updated.
  • describeTarballs in npm-dev-release.mjs is exported but never called.

Confidence Score: 4/5

Safe to merge for the workflow structure and publish logic; the test hardcoded version literals will silently break the next triggered dev publish after any routine version bump.

The workflow, rewrite logic, integrity-guarded publish, and dry-run default are all well-structured. The only concrete defect is in the test: it pins the expected dev version to a literal string, so any version bump to core or platform-api will cause the prepare job to fail, blocking every subsequent workflow_dispatch run until the literal is fixed.

scripts/npm-dev-release.test.mjs — the hardcoded version assertions need attention before the next package bump.

Important Files Changed

Filename Overview
.github/workflows/publish-npm-dev.yml New workflow_dispatch pipeline — prepare → parallel native-addon builds → pack-and-publish. Integrity guard, dry-run default, and version-format assertion before publish are all well-structured.
scripts/npm-dev-release.mjs Version rewrite/validate/digest script; logic is correct. describeTarballs is exported but dead code.
scripts/npm-dev-release.test.mjs Test harness works but hardcodes version literals 1.14.1 and 1.14.3 that will break the workflow prepare job after any routine version bump.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    WD[workflow_dispatch] --> P
    subgraph prepare
        P[Checkout + verify SHA] --> T[node --test npm-dev-release.test.mjs]
        T --> OUT[outputs: git_sha, short_sha]
    end
    OUT --> B1 & B2 & B3 & B4
    subgraph build-addon
        B1[macos darwin-arm64]
        B2[macos darwin-x64 cross]
        B3[linux x86_64]
        B4[linux aarch64]
    end
    B1 & B2 & B3 & B4 -->|artifacts| AP[npm-dev-addon-*]
    subgraph pack-and-publish
        AP --> ST[Stage addons]
        ST --> RW[rewrite versions to dev.sha]
        RW --> INJ[inject-optional-deps]
        INJ --> VAL[validate manifests]
        VAL --> PK[npm pack x11]
        PK --> DG[digest tarballs]
        DG --> SMK[smoke install]
        SMK -->|dry_run=false| PUB[npm publish integrity-guarded]
        PUB --> EV[upload evidence artifact]
    end
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    WD[workflow_dispatch] --> P
    subgraph prepare
        P[Checkout + verify SHA] --> T[node --test npm-dev-release.test.mjs]
        T --> OUT[outputs: git_sha, short_sha]
    end
    OUT --> B1 & B2 & B3 & B4
    subgraph build-addon
        B1[macos darwin-arm64]
        B2[macos darwin-x64 cross]
        B3[linux x86_64]
        B4[linux aarch64]
    end
    B1 & B2 & B3 & B4 -->|artifacts| AP[npm-dev-addon-*]
    subgraph pack-and-publish
        AP --> ST[Stage addons]
        ST --> RW[rewrite versions to dev.sha]
        RW --> INJ[inject-optional-deps]
        INJ --> VAL[validate manifests]
        VAL --> PK[npm pack x11]
        PK --> DG[digest tarballs]
        DG --> SMK[smoke install]
        SMK -->|dry_run=false| PUB[npm publish integrity-guarded]
        PUB --> EV[upload evidence artifact]
    end
Loading
Prompt To Fix All With AI
Fix the following 2 code review issues. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 2
scripts/npm-dev-release.test.mjs:29-30
Hardcoded version snapshot will fail after any version bump. The assertions pin `1.14.1` and `1.14.3` as literal strings, so the next time `@alienplatform/core` or `@alienplatform/platform-api` are bumped the `prepare` job will fail — breaking the entire publish workflow until someone manually updates the test. The base versions should be derived from the fixture's package.json files at runtime.

```suggestion
  const coreBase = JSON.parse(readFileSync(resolve(root, "packages/core/package.json"), "utf8")).version.replace(/-.*$/, "")
  const platformBase = JSON.parse(readFileSync(resolve(root, "client-sdks/platform/typescript/package.json"), "utf8")).version.replace(/-.*$/, "")
  assert.equal(versions.get("@alienplatform/core"), `${coreBase}-dev.0123456789ab`)
  assert.equal(versions.get("@alienplatform/platform-api"), `${platformBase}-dev.0123456789ab`)
```

### Issue 2 of 2
scripts/npm-dev-release.mjs:98-106
`describeTarballs` is dead code — it is exported but never called in the workflow or the tests. The workflow uses the `digest` subcommand for tarball evidence instead. Either call it or remove the export to keep the public API surface clean.

Reviews (1): Last reviewed commit: "fix: decouple npm source and workflow re..." | Re-trigger Greptile

Comment on lines +29 to +30
validateManifests(root, sha)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Hardcoded version snapshot will fail after any version bump. The assertions pin 1.14.1 and 1.14.3 as literal strings, so the next time @alienplatform/core or @alienplatform/platform-api are bumped the prepare job will fail — breaking the entire publish workflow until someone manually updates the test. The base versions should be derived from the fixture's package.json files at runtime.

Suggested change
validateManifests(root, sha)
const coreBase = JSON.parse(readFileSync(resolve(root, "packages/core/package.json"), "utf8")).version.replace(/-.*$/, "")
const platformBase = JSON.parse(readFileSync(resolve(root, "client-sdks/platform/typescript/package.json"), "utf8")).version.replace(/-.*$/, "")
assert.equal(versions.get("@alienplatform/core"), `${coreBase}-dev.0123456789ab`)
assert.equal(versions.get("@alienplatform/platform-api"), `${platformBase}-dev.0123456789ab`)
Prompt To Fix With AI
This is a comment left during a code review.
Path: scripts/npm-dev-release.test.mjs
Line: 29-30

Comment:
Hardcoded version snapshot will fail after any version bump. The assertions pin `1.14.1` and `1.14.3` as literal strings, so the next time `@alienplatform/core` or `@alienplatform/platform-api` are bumped the `prepare` job will fail — breaking the entire publish workflow until someone manually updates the test. The base versions should be derived from the fixture's package.json files at runtime.

```suggestion
  const coreBase = JSON.parse(readFileSync(resolve(root, "packages/core/package.json"), "utf8")).version.replace(/-.*$/, "")
  const platformBase = JSON.parse(readFileSync(resolve(root, "client-sdks/platform/typescript/package.json"), "utf8")).version.replace(/-.*$/, "")
  assert.equal(versions.get("@alienplatform/core"), `${coreBase}-dev.0123456789ab`)
  assert.equal(versions.get("@alienplatform/platform-api"), `${platformBase}-dev.0123456789ab`)
```

How can I resolve this? If you propose a fix, please make it concise.

Comment thread scripts/npm-dev-release.mjs Outdated
Comment on lines +98 to +106
export function describeTarballs(packResults) {
return packResults.map(result => ({
name: result.name,
version: result.version,
filename: basename(result.filename),
integrity: result.integrity,
shasum: result.shasum,
}))
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 describeTarballs is dead code — it is exported but never called in the workflow or the tests. The workflow uses the digest subcommand for tarball evidence instead. Either call it or remove the export to keep the public API surface clean.

Prompt To Fix With AI
This is a comment left during a code review.
Path: scripts/npm-dev-release.mjs
Line: 98-106

Comment:
`describeTarballs` is dead code — it is exported but never called in the workflow or the tests. The workflow uses the `digest` subcommand for tarball evidence instead. Either call it or remove the export to keep the public API surface clean.

How can I resolve this? If you propose a fix, please make it concise.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

@alongubkin
alongubkin merged commit ad5e9c2 into alon/alien-270-complete-reliable-tcp-and-stateful-workload-support-end-to Jul 20, 2026
35 of 36 checks passed
@alongubkin
alongubkin deleted the alon/alien-270-npm-dev-publication branch July 20, 2026 12:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant