Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
6a676a0
mcp: remove stale darwin-x64 package, fix Windows target triple
bpowers Mar 13, 2026
dc4a140
mcp: add publishConfig and repository to wrapper package.json
bpowers Mar 13, 2026
6334984
mcp: include publishConfig and repository in generated platform packages
bpowers Mar 13, 2026
44275e3
mcp: update build script integration test for publishConfig, reposito…
bpowers Mar 13, 2026
12c8473
mcp: add Dockerfile.cross for local cross-compilation toolchain
bpowers Mar 13, 2026
ce47837
mcp: add cross-build.sh for local multi-platform binary builds
bpowers Mar 13, 2026
f78effd
mcp: ignore cross-build dist/ output
bpowers Mar 13, 2026
a202066
mcp: fix smoke test to detect binary execution failures
bpowers Mar 13, 2026
1e70d67
mcp: add GitHub Actions workflow for npm release
bpowers Mar 13, 2026
3f557e0
doc: update CLAUDE.md files for mcp-npm-release
bpowers Mar 13, 2026
af52c5a
mcp: add missing test coverage from code review feedback
bpowers Mar 13, 2026
7246375
doc: add human test plan for MCP npm release
bpowers Mar 13, 2026
0f1942c
doc: add implementation plans for mcp-npm-release
bpowers Mar 13, 2026
e85ac3c
mcp: address review feedback for npm release pipeline
bpowers Mar 13, 2026
5e4bdfe
mcp: tighten publish guards, pin Rust toolchain in CI
bpowers Mar 13, 2026
7ab70b4
mcp: fix smoke test on arm64 Linux, clean up Dockerfile comment
bpowers Mar 13, 2026
72c729a
mcp: add zig version sync test, fix windows dev hint
bpowers Mar 13, 2026
c788073
mcp: include rust-toolchain.toml in CI cache key
bpowers Mar 13, 2026
3476554
mcp: clean root-owned dist files via Docker before rebuild
bpowers Mar 13, 2026
f555c0d
mcp: add --locked to release builds in CI
bpowers Mar 13, 2026
b750aee
mcp: fix docker cleanup glob, use structured YAML in zig test
bpowers Mar 13, 2026
9aa8bdb
mcp: cache cargo install metadata, add --locked to cross-build
bpowers Mar 13, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
234 changes: 234 additions & 0 deletions .github/workflows/mcp-release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,234 @@
name: MCP npm Release

on:
push:
tags:
- 'mcp-v*'
workflow_dispatch:

permissions:
contents: read

jobs:
validate:
name: Validate version
runs-on: ubuntu-latest
outputs:
version: ${{ steps.version.outputs.version }}
steps:
- uses: actions/checkout@v4

- name: Extract and validate version
id: version
run: |
CARGO_VERSION=$(grep '^version = ' src/simlin-mcp/Cargo.toml | head -1 | sed 's/version = "\(.*\)"/\1/')
echo "Cargo.toml version: $CARGO_VERSION"

if [[ "$GITHUB_REF" == refs/tags/mcp-v* ]]; then
TAG_VERSION="${GITHUB_REF_NAME#mcp-v}"
echo "Tag version: $TAG_VERSION"
if [ "$TAG_VERSION" != "$CARGO_VERSION" ]; then
echo "::error::Tag version ($TAG_VERSION) does not match Cargo.toml ($CARGO_VERSION)"
exit 1
fi
fi

echo "version=$CARGO_VERSION" >> "$GITHUB_OUTPUT"

build:
name: Build ${{ matrix.artifact }}
needs: validate
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- target: x86_64-unknown-linux-musl
os: ubuntu-latest
artifact: mcp-linux-x64
binary: simlin-mcp
use-zigbuild: true
- target: aarch64-unknown-linux-musl
os: ubuntu-latest
artifact: mcp-linux-arm64
binary: simlin-mcp
use-zigbuild: true
- target: x86_64-pc-windows-gnu
os: ubuntu-latest
artifact: mcp-win32-x64
binary: simlin-mcp.exe
use-zigbuild: true
- target: aarch64-apple-darwin
os: macos-latest
artifact: mcp-darwin-arm64
binary: simlin-mcp
use-zigbuild: false
steps:
- uses: actions/checkout@v4

- name: Read Rust toolchain version
id: rust-version
run: echo "version=$(grep '^channel' rust-toolchain.toml | sed 's/channel = \"\(.*\)\"/\1/')" >> "$GITHUB_OUTPUT"

- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@master
with:
toolchain: ${{ steps.rust-version.outputs.version }}
targets: ${{ matrix.target }}

- name: Cache Cargo artifacts
uses: actions/cache@v4
with:
path: |
~/.cargo/bin
~/.cargo/.crates.toml
~/.cargo/.crates2.json
~/.cargo/registry
~/.cargo/git
target
key: cargo-mcp-${{ matrix.os }}-${{ matrix.target }}-${{ hashFiles('**/Cargo.lock', 'rust-toolchain.toml') }}
restore-keys: |
cargo-mcp-${{ matrix.os }}-${{ matrix.target }}-

- name: Install Zig
if: matrix.use-zigbuild
uses: mlugg/setup-zig@v2
with:
# Keep in sync with src/simlin-mcp/Dockerfile.cross
version: '0.15.2'

- name: Install cargo-zigbuild
if: matrix.use-zigbuild
run: cargo install --locked cargo-zigbuild@0.22

- name: Build (zigbuild)
if: matrix.use-zigbuild
run: cargo zigbuild -p simlin-mcp --locked --release --target ${{ matrix.target }}

- name: Build (native)
if: ${{ !matrix.use-zigbuild }}
run: cargo build -p simlin-mcp --locked --release --target ${{ matrix.target }}

- name: Upload binary
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.artifact }}
path: target/${{ matrix.target }}/release/${{ matrix.binary }}
if-no-files-found: error
retention-days: 1

publish-platform:
name: Publish platform packages
needs: [validate, build]
runs-on: ubuntu-latest
if: startsWith(github.ref, 'refs/tags/mcp-v')
permissions:
contents: read
id-token: write
steps:
- uses: actions/checkout@v4

- uses: actions/setup-node@v4
with:
node-version: '22'

- run: npm install -g npm@latest

- uses: actions/download-artifact@v4
with:
path: artifacts/

- name: Prepare platform packages
working-directory: src/simlin-mcp
run: |
bash build-npm-packages.sh

cp ../../artifacts/mcp-linux-x64/simlin-mcp npm/@simlin/mcp-linux-x64/bin/
cp ../../artifacts/mcp-linux-arm64/simlin-mcp npm/@simlin/mcp-linux-arm64/bin/
cp ../../artifacts/mcp-win32-x64/simlin-mcp.exe npm/@simlin/mcp-win32-x64/bin/
cp ../../artifacts/mcp-darwin-arm64/simlin-mcp npm/@simlin/mcp-darwin-arm64/bin/

chmod +x npm/@simlin/mcp-linux-x64/bin/simlin-mcp
chmod +x npm/@simlin/mcp-linux-arm64/bin/simlin-mcp
chmod +x npm/@simlin/mcp-darwin-arm64/bin/simlin-mcp

- name: Publish @simlin/mcp-linux-x64
working-directory: src/simlin-mcp/npm/@simlin/mcp-linux-x64
run: |
VERSION=$(jq -r .version package.json)
if npm view "@simlin/mcp-linux-x64@$VERSION" version > /dev/null 2>&1; then
echo "Already published @simlin/mcp-linux-x64@$VERSION, skipping"
else
npm publish --provenance --access public
fi

- name: Publish @simlin/mcp-linux-arm64
working-directory: src/simlin-mcp/npm/@simlin/mcp-linux-arm64
run: |
VERSION=$(jq -r .version package.json)
if npm view "@simlin/mcp-linux-arm64@$VERSION" version > /dev/null 2>&1; then
echo "Already published @simlin/mcp-linux-arm64@$VERSION, skipping"
else
npm publish --provenance --access public
fi

- name: Publish @simlin/mcp-win32-x64
working-directory: src/simlin-mcp/npm/@simlin/mcp-win32-x64
run: |
VERSION=$(jq -r .version package.json)
if npm view "@simlin/mcp-win32-x64@$VERSION" version > /dev/null 2>&1; then
echo "Already published @simlin/mcp-win32-x64@$VERSION, skipping"
else
npm publish --provenance --access public
fi

- name: Publish @simlin/mcp-darwin-arm64
working-directory: src/simlin-mcp/npm/@simlin/mcp-darwin-arm64
run: |
VERSION=$(jq -r .version package.json)
if npm view "@simlin/mcp-darwin-arm64@$VERSION" version > /dev/null 2>&1; then
echo "Already published @simlin/mcp-darwin-arm64@$VERSION, skipping"
else
npm publish --provenance --access public
fi

publish-wrapper:
name: Publish @simlin/mcp
needs: [validate, publish-platform]
runs-on: ubuntu-latest
if: startsWith(github.ref, 'refs/tags/mcp-v')
permissions:
contents: read
id-token: write
steps:
- uses: actions/checkout@v4

- uses: actions/setup-node@v4
with:
node-version: '22'

- run: npm install -g npm@latest

- name: Update wrapper version
working-directory: src/simlin-mcp
run: |
VERSION="${{ needs.validate.outputs.version }}"
jq --arg v "$VERSION" '
.version = $v |
.optionalDependencies = (
.optionalDependencies | to_entries | map(.value = $v) | from_entries
)
' package.json > package.json.tmp && mv package.json.tmp package.json

echo "Updated wrapper package.json:"
cat package.json

- name: Publish @simlin/mcp
working-directory: src/simlin-mcp
run: |
VERSION=$(jq -r .version package.json)
if npm view "@simlin/mcp@$VERSION" version > /dev/null 2>&1; then
echo "Already published @simlin/mcp@$VERSION, skipping"
else
npm publish --provenance --access public
fi
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -98,3 +98,4 @@ __pycache__/
# simlin-mcp npm packaging artifacts
/src/simlin-mcp/vendor
/src/simlin-mcp/npm
/src/simlin-mcp/dist
28 changes: 14 additions & 14 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,20 @@ For documentation index, see [docs/README.md](/docs/README.md).

## Components

| Component | Language | Description | Docs |
|---------------------|----------|--------------------------------------------------|-------------------------------------------|
| `src/simlin-engine` | Rust | Compiles, type-checks, and simulates SD models | [CLAUDE.md](/src/simlin-engine/CLAUDE.md) |
| `src/libsimlin` | Rust | Flat C FFI to simlin-engine (WASM, CGo, C/C++) | [CLAUDE.md](/src/libsimlin/CLAUDE.md) |
| `src/simlin-mcp` | Rust | MCP server for viewing and editing models | [CLAUDE.md](/src/simlin-mcp/CLAUDE.md) |
| `src/engine` | TypeScript | Promise-based TypeScript API for WASM engine | [CLAUDE.md](/src/engine/CLAUDE.md) |
| `src/core` | TypeScript | Shared data models and common utilities | [CLAUDE.md](/src/core/CLAUDE.md) |
| `src/diagram` | TypeScript | React model editor and visualization toolkit | [CLAUDE.md](/src/diagram/CLAUDE.md) |
| `src/app` | TypeScript | Full-featured SD application | [CLAUDE.md](/src/app/CLAUDE.md) |
| `src/server` | TypeScript | Express.js backend (Firebase Auth, Firestore) | [CLAUDE.md](/src/server/CLAUDE.md) |
| `src/xmutil` | C++/Rust | Vensim-to-XMILE converter (test-only) | -- |
| `src/simlin-cli` | Rust | CLI for simulation/conversion (testing/debugging) | [CLAUDE.md](/src/simlin-cli/CLAUDE.md) |
| `src/pysimlin` | Python/Rust | Python bindings for the simulation engine | [CLAUDE.md](/src/pysimlin/CLAUDE.md) |
| `website` | TypeScript | Rspress-based documentation site | [CLAUDE.md](/website/CLAUDE.md) |
| Component | Language | Description | Docs |
|---------------------|-------------|---------------------------------------------------|-------------------------------------------|
| `src/simlin-engine` | Rust | Compiles, type-checks, and simulates SD models | [CLAUDE.md](/src/simlin-engine/CLAUDE.md) |
| `src/libsimlin` | Rust | Flat C FFI to simlin-engine (WASM, CGo, C/C++) | [CLAUDE.md](/src/libsimlin/CLAUDE.md) |
| `src/simlin-mcp` | Rust/JS | MCP server for AI assistants (`@simlin/mcp` npm) | [CLAUDE.md](/src/simlin-mcp/CLAUDE.md) |
| `src/engine` | TypeScript | Promise-based TypeScript API for WASM engine | [CLAUDE.md](/src/engine/CLAUDE.md) |
| `src/core` | TypeScript | Shared data models and common utilities | [CLAUDE.md](/src/core/CLAUDE.md) |
| `src/diagram` | TypeScript | React model editor and visualization toolkit | [CLAUDE.md](/src/diagram/CLAUDE.md) |
| `src/app` | TypeScript | Full-featured SD application | [CLAUDE.md](/src/app/CLAUDE.md) |
| `src/server` | TypeScript | Express.js backend (Firebase Auth, Firestore) | [CLAUDE.md](/src/server/CLAUDE.md) |
| `src/xmutil` | C++/Rust | Vensim-to-XMILE converter (test-only) | -- |
| `src/simlin-cli` | Rust | CLI for simulation/conversion (testing/debugging) | [CLAUDE.md](/src/simlin-cli/CLAUDE.md) |
| `src/pysimlin` | Python/Rust | Python bindings for the simulation engine | [CLAUDE.md](/src/pysimlin/CLAUDE.md) |
| `website` | TypeScript | Rspress-based documentation site | [CLAUDE.md](/website/CLAUDE.md) |

## Environment Setup

Expand Down
20 changes: 20 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading