Skip to content
Merged

0.8.0 #102

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
144 changes: 114 additions & 30 deletions .github/workflows/pypi.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ name: Publish to PyPI
on:
push:
branches: [release]
workflow_dispatch:

concurrency:
group: pypi-${{ github.ref }}
Expand All @@ -12,11 +13,12 @@ permissions:
contents: read

jobs:
build:
preflight:
runs-on: ubuntu-latest
outputs:
skip: ${{ steps.check.outputs.skip }}
version: ${{ steps.pkg.outputs.version }}
publish_needed: ${{ steps.pypi.outputs.publish_needed }}
release_assets_needed: ${{ steps.release.outputs.release_assets_needed }}
steps:
- name: Checkout
uses: actions/checkout@v4
Expand All @@ -32,80 +34,117 @@ jobs:
")
echo "version=$VERSION" >> $GITHUB_OUTPUT

- name: Check if version already on PyPI
id: check
- name: Check PyPI
id: pypi
env:
VERSION: ${{ steps.pkg.outputs.version }}
run: |
VERSION="${{ steps.pkg.outputs.version }}"
if pip index versions cptr 2>/dev/null | grep -q "$VERSION"; then
echo "skip=true" >> $GITHUB_OUTPUT
echo "Version $VERSION already on PyPI — skipping"
else
echo "skip=false" >> $GITHUB_OUTPUT
fi
python3 - <<'PY'
import os
import urllib.error
import urllib.request

version = os.environ["VERSION"]
exists = False
try:
with urllib.request.urlopen(f"https://pypi.org/pypi/cptr/{version}/json", timeout=15):
exists = True
except urllib.error.HTTPError as exc:
if exc.code != 404:
raise

with open(os.environ["GITHUB_OUTPUT"], "a", encoding="utf-8") as output:
output.write(f"publish_needed={'false' if exists else 'true'}\n")
print(f"Version {version} {'already exists on PyPI' if exists else 'is not on PyPI'}")
PY

- name: Check GitHub release assets
id: release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
VERSION: ${{ steps.pkg.outputs.version }}
run: |
set -euo pipefail
expected=(
"cptr-${VERSION}-py3-none-any.whl"
"cptr-${VERSION}-linux-wheelhouse.tar.gz"
"SHA256SUMS"
)

assets="$(gh release view "v${VERSION}" --json assets --jq '.assets[].name' 2>/dev/null || true)"
missing=false
for name in "${expected[@]}"; do
if ! grep -Fx "$name" <<< "$assets" >/dev/null; then
missing=true
echo "Missing release asset: $name"
fi
done

echo "release_assets_needed=$missing" >> "$GITHUB_OUTPUT"

build:
needs: preflight
if: github.ref == 'refs/heads/release' && (needs.preflight.outputs.publish_needed == 'true' || needs.preflight.outputs.release_assets_needed == 'true')
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Set up Node.js
if: steps.check.outputs.skip != 'true'
uses: actions/setup-node@v4
with:
node-version: "22"
cache: npm
cache-dependency-path: cptr/frontend/package-lock.json

- name: Build frontend
if: steps.check.outputs.skip != 'true'
working-directory: cptr/frontend
run: |
npm ci
npm run build

- name: Set up Python
if: steps.check.outputs.skip != 'true'
uses: actions/setup-python@v5
with:
python-version: "3.12"

- name: Install build tools
if: steps.check.outputs.skip != 'true'
run: pip install hatchling build

- name: Build package
if: steps.check.outputs.skip != 'true'
run: python -m build --wheel

- name: Build Linux wheelhouse
if: steps.check.outputs.skip != 'true'
run: |
VERSION="${{ steps.pkg.outputs.version }}"
VERSION="${{ needs.preflight.outputs.version }}"
WHEEL="dist/cptr-${VERSION}-py3-none-any.whl"
cp "$WHEEL" .
mkdir -p wheelhouse
python -m pip download --dest wheelhouse "${WHEEL}[all]"
tar -czf "cptr-${VERSION}-linux-wheelhouse.tar.gz" -C wheelhouse .

- name: Generate checksums
if: steps.check.outputs.skip != 'true'
run: |
sha256sum dist/*.whl cptr-*-linux-wheelhouse.tar.gz > SHA256SUMS
sha256sum cptr-*.whl cptr-*-linux-wheelhouse.tar.gz > SHA256SUMS

- name: Upload dist artifacts
if: steps.check.outputs.skip != 'true'
uses: actions/upload-artifact@v4
with:
name: dist
path: dist/

- name: Upload release artifacts
if: steps.check.outputs.skip != 'true'
uses: actions/upload-artifact@v4
with:
name: release-assets
path: |
dist/*.whl
cptr-*.whl
cptr-*-linux-wheelhouse.tar.gz
SHA256SUMS

publish:
needs: build
if: needs.build.outputs.skip != 'true'
needs: [preflight, build]
if: github.ref == 'refs/heads/release' && needs.preflight.outputs.publish_needed == 'true'
runs-on: ubuntu-latest
environment: pypi
permissions:
Expand All @@ -117,14 +156,39 @@ jobs:
name: dist
path: dist/

- name: Check if version already on PyPI
id: check
env:
VERSION: ${{ needs.preflight.outputs.version }}
run: |
python3 - <<'PY'
import os
import urllib.error
import urllib.request

version = os.environ["VERSION"]
exists = False
try:
with urllib.request.urlopen(f"https://pypi.org/pypi/cptr/{version}/json", timeout=15):
exists = True
except urllib.error.HTTPError as exc:
if exc.code != 404:
raise

with open(os.environ["GITHUB_OUTPUT"], "a", encoding="utf-8") as output:
output.write(f"skip={'true' if exists else 'false'}\n")
print(f"Version {version} {'already exists on PyPI, skipping publish' if exists else 'is not on PyPI'}")
PY

- name: Publish to PyPI
if: steps.check.outputs.skip != 'true'
uses: pypa/gh-action-pypi-publish@release/v1
# No API token needed - uses OIDC trusted publishing.
# Configure at: https://pypi.org/manage/project/cptr/settings/publishing/

github-release-assets:
needs: build
if: needs.build.outputs.skip != 'true'
needs: [preflight, build]
if: github.ref == 'refs/heads/release' && needs.preflight.outputs.release_assets_needed == 'true'
runs-on: ubuntu-latest
permissions:
contents: write
Expand All @@ -138,11 +202,31 @@ jobs:
- name: Attach GitHub release artifacts
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
VERSION: ${{ needs.build.outputs.version }}
VERSION: ${{ needs.preflight.outputs.version }}
run: |
for attempt in {1..12}; do
set -euo pipefail
ls -lah release-assets
mapfile -t files < <(find release-assets -maxdepth 1 -type f -print | sort)
if [ "${#files[@]}" -eq 0 ]; then
echo "No release asset files found" >&2
exit 1
fi

for attempt in {1..60}; do
if gh release view "v${VERSION}" >/dev/null 2>&1; then
gh release upload "v${VERSION}" release-assets/* --clobber
gh release upload "v${VERSION}" "${files[@]}" --clobber

assets="$(gh release view "v${VERSION}" --json assets --jq '.assets[].name')"
for expected in \
"cptr-${VERSION}-py3-none-any.whl" \
"cptr-${VERSION}-linux-wheelhouse.tar.gz" \
"SHA256SUMS"
do
if ! grep -Fx "$expected" <<< "$assets" >/dev/null; then
echo "Missing release asset after upload: $expected" >&2
exit 1
fi
done
exit 0
fi
sleep 10
Expand Down
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,19 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.8.0] - 2026-07-06

### Added

- 🧰 **Create skills from chat.** Use `/skills:create` to turn a workflow into a reusable skill for the current workspace.
- 📚 **Skill list in chat.** Use `/skills:list` to see available skills, including which ones Computer can manage directly.
- 📄 **Inline file previews.** Files can now open inside chat, including images, PDFs, documents, text, Markdown, JSON, CSV, HTML, SVG, audio, and video.

### Changed

- 🖼️ **Generated images appear as files.** New images are saved to the workspace and displayed in chat with the same preview controls as other files.
- 📦 **More reliable release downloads.** Release runs can refill missing download files and checksums without republishing an existing package.

## [0.7.7] - 2026-07-06

### Added
Expand Down
8 changes: 1 addition & 7 deletions cptr/frontend/src/app.css
Original file line number Diff line number Diff line change
Expand Up @@ -378,11 +378,5 @@

/* Tippy tooltip theme */
.tippy-box[data-theme~='cptr'] {
background: #1a1a1a;
color: #e0e0e0;
font-size: 0.6875rem;
font-weight: 500;
padding: 0.125rem 0.25rem;
border-radius: 0.375rem;
box-shadow: 0 0.125rem 0.5rem rgba(0, 0, 0, 0.3);
@apply rounded-lg bg-gray-950 text-xs border border-gray-900 shadow-xl;
}
1 change: 1 addition & 0 deletions cptr/frontend/src/lib/apis/skills.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export interface SkillInfo {
source: string; // "workspace" | "global"
license?: string;
compatibility?: string;
managed?: boolean;
}

export const getSkills = (workspace: string) =>
Expand Down
Loading
Loading