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
87 changes: 55 additions & 32 deletions .github/workflows/bump-homebrew.yml
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
name: Bump Homebrew formula

# Keeps tambo-labs/homebrew-tap's charming.rb pointed at the latest
# published npm tarball. Triggers off this repo's own GitHub Release
# (created by release.yml), so it only ever points at a version that
# already published successfully.
# published npm tarball. Called directly by release.yml as a job
# (workflow_call) right after a successful npm publish, not left to
# trigger off `release: published` — GitHub doesn't let events from
# the default GITHUB_TOKEN (which creates that release) trigger other
# workflows, so that path silently never ran.
#
# Uses HOMEBREW_TAP_TOKEN, a fine-grained PAT scoped to just
# tambo-labs/homebrew-tap with Contents: read/write — not the
Expand All @@ -12,13 +14,21 @@ name: Bump Homebrew formula
# disabled and has never run).

on:
release:
types: [published]
workflow_call:
inputs:
version:
description: Version to bump the formula to (no leading v, e.g. 0.1.2)
required: true
type: string
secrets:
HOMEBREW_TAP_TOKEN:
required: true
workflow_dispatch:
inputs:
version:
description: Version to bump the formula to (no leading v, e.g. 0.1.2)
required: true
type: string

permissions:
contents: read
Expand All @@ -27,21 +37,27 @@ jobs:
bump:
runs-on: ubuntu-latest
steps:
- name: Resolve version
id: version
- name: Validate version
env:
VERSION: ${{ inputs.version }}
run: |
version="${{ inputs.version }}"
if [ -z "$version" ]; then
version="${GITHUB_REF_NAME#v}"
if ! [[ "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "::error::version must be a bare semver like 0.1.2, got: $VERSION" >&2
exit 1
fi
echo "version=$version" >> "$GITHUB_OUTPUT"
echo "version=$VERSION" >> "$GITHUB_ENV"

- name: Download tarball and compute sha256
id: tarball
env:
VERSION: ${{ env.version }}
run: |
version="${{ steps.version.outputs.version }}"
url="https://registry.npmjs.org/usecharming/-/usecharming-${version}.tgz"
curl -sL -o package.tgz "$url"
url="https://registry.npmjs.org/usecharming/-/usecharming-${VERSION}.tgz"
curl -fsSL -o package.tgz "$url"
if ! tar -tzf package.tgz >/dev/null; then
echo "::error::downloaded file is not a valid tarball — $url likely 404'd" >&2
exit 1
fi
sha256=$(shasum -a 256 package.tgz | cut -d' ' -f1)
echo "url=$url" >> "$GITHUB_OUTPUT"
echo "sha256=$sha256" >> "$GITHUB_OUTPUT"
Expand All @@ -54,12 +70,19 @@ jobs:

- name: Update formula
working-directory: homebrew-tap
env:
URL: ${{ steps.tarball.outputs.url }}
SHA256: ${{ steps.tarball.outputs.sha256 }}
run: |
version="${{ steps.version.outputs.version }}"
url="${{ steps.tarball.outputs.url }}"
sha256="${{ steps.tarball.outputs.sha256 }}"
sed -i "s#^ url \".*\"# url \"${url}\"#" Formula/charming.rb
sed -i "s#^ sha256 \".*\"# sha256 \"${sha256}\"#" Formula/charming.rb
sed -i "s#^ url \".*\"# url \"${URL}\"#" Formula/charming.rb
sed -i "s#^ sha256 \".*\"# sha256 \"${SHA256}\"#" Formula/charming.rb
# Assert the rewrite actually took, not just that *something* changed —
# a formatting drift that makes the sed anchors stop matching would
# otherwise leave the formula untouched while still reporting success.
if ! grep -qF "$URL" Formula/charming.rb || ! grep -qF "$SHA256" Formula/charming.rb; then
echo "::error::sed rewrite didn't take — check Formula/charming.rb's url/sha256 line format" >&2
exit 1
fi
if git diff --quiet; then
echo "changed=false" >> "$GITHUB_ENV"
else
Expand All @@ -69,29 +92,29 @@ jobs:
- if: env.changed == 'true'
name: Commit and push
working-directory: homebrew-tap
env:
VERSION: ${{ env.version }}
GH_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN }}
run: |
version="${{ steps.version.outputs.version }}"
git config user.name "charming-cli-release[bot]"
git config user.email "charming-cli-release[bot]@users.noreply.github.com"
git switch -C "bump/charming-${version}"
git switch -C "bump/charming-${VERSION}"
git add Formula/charming.rb
git commit -m "charming ${version}"
git push --force origin "bump/charming-${version}"
env:
GH_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN }}
git commit -m "charming ${VERSION}"
git push --force origin "bump/charming-${VERSION}"

- if: env.changed == 'true'
name: Open PR
working-directory: homebrew-tap
env:
VERSION: ${{ env.version }}
GH_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN }}
run: |
version="${{ steps.version.outputs.version }}"
count=$(gh pr list --repo tambo-labs/homebrew-tap --head "bump/charming-${version}" --state open --json number --jq length)
count=$(gh pr list --repo tambo-labs/homebrew-tap --head "bump/charming-${VERSION}" --state open --json number --jq length)
if [ "$count" -eq 0 ]; then
gh pr create --repo tambo-labs/homebrew-tap \
--base main \
--head "bump/charming-${version}" \
--title "charming ${version}" \
--body "Bumps the charming formula to ${version}, matching the npm release."
--head "bump/charming-${VERSION}" \
--title "charming ${VERSION}" \
--body "Bumps the charming formula to ${VERSION}, matching the npm release."
fi
env:
GH_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN }}
24 changes: 18 additions & 6 deletions .github/workflows/clawhub-publish.yml
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
name: ClawHub publish

# Keeps clawhub.ai's charming skill listing pointed at the version in
# skills/charming/SKILL.md. `clawhub sync` fingerprints skill folders
# (deriving the slug from the folder name) and only publishes new or
# changed ones, so it's safe to run on every release even if the skill
# itself didn't change.
# Keeps clawhub.ai's charming skill listing in sync with skills/charming/.
# `clawhub sync` fingerprints the skill folder's actual content and only
# publishes when it changed, bumping the registry's own patch version —
# there's no version field in SKILL.md itself to point at. That makes it
# safe to call on every release even if the skill didn't change.
#
# Called directly by release.yml as a job (workflow_call) rather than
# relying on `release: published` — GitHub doesn't let events from the
# default GITHUB_TOKEN (which creates that release) trigger other
# workflows, so that path silently never ran.
#
# This repo requires every `uses:` action pinned to a full commit SHA
# (org policy: sha_pinning_required). ClawHub's own reusable workflow
Expand All @@ -15,7 +20,10 @@ name: ClawHub publish
#
# Skills have no OIDC/trusted-publisher option yet, so this uses
# CLAWHUB_TOKEN, a token from `clawhub login` + `clawhub token`, scoped to
# the charming publisher (clawhub.ai/settings?view=organizations).
# the charming publisher (clawhub.ai/settings?view=organizations). The PR
# dry-run below has no token, so it resolves the registry state
# unauthenticated — it verifies the sync command runs cleanly against the
# real skill content, not that the real publish's auth/ownership works.

on:
pull_request:
Expand All @@ -24,6 +32,10 @@ on:
- skills/**
release:
types: [published]
workflow_call:
secrets:
CLAWHUB_TOKEN:
required: true
workflow_dispatch:

permissions:
Expand Down
25 changes: 25 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,13 @@ name: Release
#
# A tag alone doesn't publish: `bun run check` (the same gate ci.yml
# runs) must pass, and the tag must match package.json's version.
#
# bump-homebrew and clawhub-publish are called directly as jobs
# (workflow_call), not left to trigger off `release: published`.
# GitHub does not let events created by the default GITHUB_TOKEN
# (like the `gh release create` below) trigger other workflows —
# that path silently never fired, and Homebrew/ClawHub stayed on the
# old version forever with everything upstream showing green.

on:
push:
Expand All @@ -23,9 +30,15 @@ jobs:
permissions:
contents: write # create the GitHub Release
id-token: write # npm trusted publishing (OIDC)
outputs:
version: ${{ steps.version.outputs.version }}
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

- name: Resolve version
id: version
run: echo "version=${GITHUB_REF_NAME#v}" >> "$GITHUB_OUTPUT"

- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
with:
bun-version: 1.3.14
Expand Down Expand Up @@ -65,3 +78,15 @@ jobs:
- run: gh release create "$GITHUB_REF_NAME" --generate-notes --verify-tag
env:
GH_TOKEN: ${{ github.token }}

bump-homebrew:
needs: release
uses: ./.github/workflows/bump-homebrew.yml
with:
version: ${{ needs.release.outputs.version }}
secrets: inherit

clawhub-publish:
needs: release
uses: ./.github/workflows/clawhub-publish.yml
secrets: inherit
4 changes: 1 addition & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,13 @@ Build and manage personal apps hosted by [Charming](https://charm.ing) from a te

## Install

Not published yet. Once it is, the plan is:

```bash
npm install -g usecharming
# or
brew install tambo-labs/tap/charming
```

Until then, install from source:
Or install from source:

```bash
git clone https://github.com/tambo-labs/charming-cli.git
Expand Down
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
"bin",
"dist",
"examples",
"templates",
"provenance.json",
"UPSTREAM.json",
"skills"
Expand Down
2 changes: 1 addition & 1 deletion skills/charming/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ Do not free-hand the skeleton. Copy `templates/crud`, then change the data model
## Start

1. `charming auth status`. If `"authenticated": false`, run `charming auth login --no-open` and give the user the approval URL and code.
2. Copy the CRUD template into a working directory: `cp -r "$(npm root -g)/usecharming/templates/crud" ./my-app` Change `manifest.id`, `manifest.meta.name`, the storage key, and the `window.charming.api("<id>")` argument in `ui.js` to match.
2. Copy the CRUD template into a working directory: `cp -r "$(npm root -g)/usecharming/skills/charming/templates/crud" ./my-app` Change `manifest.id`, `manifest.meta.name`, the storage key, and the `window.charming.api("<id>")` argument in `ui.js` to match.
3. `charming apps create ./my-app --description "<one line>" --dry-run`
4. `charming apps create ./my-app --description "<one line>" --yes`
5. Smoke-test the backend before you claim it works: `charming apps call <app-id> list --input '{}'`
Expand Down
File renamed without changes.
File renamed without changes.
Loading