Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
12 changes: 12 additions & 0 deletions .claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"name": "tower",
"description": "Tower compute platform — run and deploy Python apps, pipelines, and AI agents",
"version": "1.0.0",
"author": {
"name": "Tower",
"url": "https://tower.dev"
},
"homepage": "https://tower.dev/docs",
"repository": "https://github.com/tower/tower-cli",
"license": "MIT"
}
4 changes: 4 additions & 0 deletions .coderabbit.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
language: en-US
reviews:
base_branches:
- develop
Comment thread
bradhe marked this conversation as resolved.
44 changes: 44 additions & 0 deletions .github/workflows/publish-docker.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Publish a release Docker image to GHCR.
#
# Assumed to run as a subworkflow of .github/workflows/release.yml; specifically, as a publish job
# within `cargo-dist`. Runs after `host`, so the GitHub Release and its binary artifacts exist;
# the Dockerfile fetches the prebuilt musl binary from the release at image-build time.

name: "[tower] Publish Docker image"

on:
workflow_call:
inputs:
plan:
required: true
type: string

jobs:
docker-publish:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v6
- uses: docker/setup-buildx-action@v3
- uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
env:
TAG: ${{ fromJson(inputs.plan).announcement_tag }}
PRERELEASE: ${{ fromJson(inputs.plan).announcement_is_prerelease }}
run: |
VERSION="${TAG#v}"
TAGS=(--tag "ghcr.io/tower/tower-cli:$VERSION")
if [ "$PRERELEASE" != "true" ]; then
TAGS+=(--tag "ghcr.io/tower/tower-cli:latest")
fi
docker buildx build \
--platform linux/amd64,linux/arm64 \
--build-arg VERSION="$VERSION" \
"${TAGS[@]}" \
--push .
48 changes: 48 additions & 0 deletions .github/workflows/publish-npm.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Publish tower-package-wasm to npm.
# Uses OIDC Trusted Publishing — no NPM_TOKEN needed, but the package must have a trusted publisher
# configured on npmjs.com matching this repo, this workflow file, and the `release` environment.
name: "[tower] Publish to npm"

on:
workflow_call:
inputs:
plan:
required: true
type: string

jobs:
npm-publish:
name: Upload to npm
runs-on: ubuntu-latest
environment:
name: release
permissions:
contents: read
id-token: write
steps:
- uses: actions/checkout@v6

- name: Set up Rust
uses: actions-rust-lang/setup-rust-toolchain@v1.11.0
with:
target: wasm32-unknown-unknown

- name: Install wasm-pack
uses: jetli/wasm-pack-action@v0.4.0

- name: Set up Node
uses: actions/setup-node@v4
with:
node-version: 22
registry-url: 'https://registry.npmjs.org'

- name: Upgrade npm for Trusted Publishing
run: npm install -g npm@latest

- name: Build wasm package
working-directory: crates/tower-package
run: ./scripts/build.sh bundler

- name: Publish to npm
working-directory: crates/tower-package/pkg
run: npm publish --access public --provenance
47 changes: 47 additions & 0 deletions .github/workflows/regenerate-skill.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
name: Regenerate SKILL.md

on:
push:
branches: [develop]
paths:
- 'crates/tower-cmd/**'
- 'crates/tower/**'
- 'skills/tower/SKILL.md'
- '.github/workflows/regenerate-skill.yml'

concurrency:
group: regenerate-skill
cancel-in-progress: false

jobs:
regenerate:
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write

steps:
- uses: actions/checkout@v6

- name: Set up Rust
run: rustup show

- name: Cache Rust
uses: Swatinem/rust-cache@v2

- name: Regenerate SKILL.md
run: cargo run --quiet --bin tower -- skill generate > skills/tower/SKILL.md

- name: Open PR if SKILL.md changed
uses: peter-evans/create-pull-request@v7
with:
commit-message: "chore: regenerate SKILL.md"
title: "chore: regenerate SKILL.md"
body: |
`tower skill generate` output has drifted from the checked-in `skills/tower/SKILL.md`.

This PR was opened automatically by the `Regenerate SKILL.md` workflow after a merge to `develop`.
branch: chore/regenerate-skill
base: develop
delete-branch: true
add-paths: skills/tower/SKILL.md
33 changes: 19 additions & 14 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -302,20 +302,25 @@ jobs:
"id-token": "write"
"packages": "write"

announce:
custom-publish-npm:
needs:
- plan
- host
- custom-publish-pypi
# use "always() && ..." to allow us to wait for all publish jobs while
# still allowing individual publish jobs to skip themselves (for prereleases).
# "host" however must run to completion, no skipping allowed!
if: ${{ always() && needs.host.result == 'success' && (needs.custom-publish-pypi.result == 'skipped' || needs.custom-publish-pypi.result == 'success') }}
runs-on: "ubuntu-22.04"
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- uses: actions/checkout@v6
with:
persist-credentials: false
submodules: recursive
if: ${{ !fromJson(needs.plan.outputs.val).announcement_is_prerelease || fromJson(needs.plan.outputs.val).publish_prereleases }}
uses: ./.github/workflows/publish-npm.yml
with:
plan: ${{ needs.plan.outputs.val }}
secrets: inherit

custom-publish-docker:
needs:
- plan
- host
if: ${{ !fromJson(needs.plan.outputs.val).announcement_is_prerelease || fromJson(needs.plan.outputs.val).publish_prereleases }}
uses: ./.github/workflows/publish-docker.yml
with:
plan: ${{ needs.plan.outputs.val }}
secrets: inherit
permissions:
"contents": "read"
"packages": "write"
52 changes: 52 additions & 0 deletions .github/workflows/test-wasm.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
name: "[tower] Test wasm"

on:
pull_request:
paths:
- 'crates/tower-package/**'
- '.github/workflows/test-wasm.yml'
- 'Cargo.toml'
- 'Cargo.lock'

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

env:
RUST_BACKTRACE: 1

jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6

- name: Set up Rust
uses: actions-rust-lang/setup-rust-toolchain@v1.11.0
with:
target: wasm32-unknown-unknown

- name: Cache Rust
uses: Swatinem/rust-cache@v2
with:
save-if: ${{ github.ref_name == 'main' }}

- name: Install wasm-pack
uses: jetli/wasm-pack-action@v0.4.0

- name: Build wasm package
working-directory: crates/tower-package
run: ./scripts/build.sh nodejs

- name: Set up Node
uses: actions/setup-node@v4
with:
node-version: 20

- name: Install test deps
working-directory: crates/tower-package/test
run: npm install

- name: Run tests
working-directory: crates/tower-package/test
run: npm test
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,6 @@ pytest.ini

# wheel build artifacts
*.data/

# local MCP overrides (e.g. internal tooling with secrets)
.mcp.json.local
8 changes: 8 additions & 0 deletions .mcp.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"mcpServers": {
"tower": {
"command": "uvx",
"args": ["tower", "mcp-server"]
}
}
}
Loading
Loading