diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 606a03d..f61295e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -128,3 +128,52 @@ jobs: tags: | ghcr.io/${{ github.repository }}:${{ steps.ver.outputs.v }} ${{ steps.ver.outputs.latest }} + + dist: + name: Publish Homebrew + Scoop + needs: release # regenerate from the just-published npm tarball + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v5 + - uses: actions/setup-node@v5 + with: + node-version: 22 + + # Regenerate the formula + manifest from the published tarball (sha256). + - name: Generate dist files + id: gen + run: | + V=$(node -p "require('./package.json').version") + echo "v=$V" >> "$GITHUB_OUTPUT" + node scripts/gen-dist.mjs "$V" + + # Cross-repo push needs a PAT (the default GITHUB_TOKEN is scoped to this + # repo). Add a fine-grained TAP_TOKEN secret with contents:write on + # wavyx/homebrew-tap and wavyx/scoop-pdcli to enable auto-publish; without + # it this step no-ops so the release never fails on a missing secret. + # Prereleases are skipped (they must not move the stable formula/manifest). + - name: Push to tap repos + env: + TAP_TOKEN: ${{ secrets.TAP_TOKEN }} + V: ${{ steps.gen.outputs.v }} + run: | + case "$V" in *-*) echo "prerelease $V — skipping tap publish"; exit 0 ;; esac + if [ -z "$TAP_TOKEN" ]; then + echo "No TAP_TOKEN secret — skipping Homebrew/Scoop publish." + echo "Run 'node scripts/gen-dist.mjs $V' and push manually, or add the PAT." + exit 0 + fi + git config --global user.name "pdcli-release" + git config --global user.email "release@wavyx.dev" + push_file() { + repo="$1"; src="$2"; dest="$3" + tmp=$(mktemp -d) + git clone --depth 1 "https://x-access-token:${TAP_TOKEN}@github.com/${repo}.git" "$tmp" + mkdir -p "$(dirname "$tmp/$dest")" + cp "$src" "$tmp/$dest" + git -C "$tmp" add "$dest" + git -C "$tmp" commit -m "pdcli $V" || { echo "no change for $repo"; return 0; } + git -C "$tmp" push + } + push_file wavyx/homebrew-tap packaging/homebrew/pdcli.rb Formula/pdcli.rb + push_file wavyx/scoop-pdcli packaging/scoop/pdcli.json bucket/pdcli.json diff --git a/packaging/README.md b/packaging/README.md index b1f4d2f..ac96cd8 100644 --- a/packaging/README.md +++ b/packaging/README.md @@ -25,9 +25,15 @@ This downloads the npm tarball, computes its sha256, and writes: Both generated files are git-ignored here — they live in their own repos. -> Auto-bumping these on every release would need a cross-repo token (PAT); for -> now it's a one-line manual step. The Docker image and npm publish are fully -> automated in `.github/workflows/release.yml`. +## Automation + +The `dist` job in `.github/workflows/release.yml` regenerates both files from the +just-published tarball and pushes them to the tap repos on every stable release — +**as long as a `TAP_TOKEN` secret exists**. It must be a fine-grained PAT with +`contents:write` on `wavyx/homebrew-tap` and `wavyx/scoop-pdcli`. Without the +secret the job no-ops (the release never fails), and you publish with the manual +`node scripts/gen-dist.mjs ` step above. npm publish and the Docker image +are always automated. ## Container security caveat (env-var tokens) diff --git a/scripts/gen-dist.mjs b/scripts/gen-dist.mjs index 289848f..2453772 100644 --- a/scripts/gen-dist.mjs +++ b/scripts/gen-dist.mjs @@ -29,7 +29,7 @@ export function renderHomebrewFormula({ url, sha256 }) { # Homebrew build sandbox blocks network, so point node-jq at the Homebrew jq # instead (node-jq honors $JQ_PATH at runtime). (bin/"pdcli").write_env_script libexec/"bin/pdcli", - JQ_PATH: Formula["jq"].opt_bin/"jq" + JQ_PATH: formula_opt_bin("jq")/"jq" end test do diff --git a/website/astro.config.mjs b/website/astro.config.mjs index 4f5dca7..41f23e3 100644 --- a/website/astro.config.mjs +++ b/website/astro.config.mjs @@ -94,8 +94,9 @@ export default defineConfig({ label: 'Start here', items: [ { label: 'Installation', slug: 'start/installation' }, - { label: 'Distribution (all channels)', slug: 'start/distribution' }, { label: 'Quickstart', slug: 'start/quickstart' }, + { label: 'Which command do I use?', slug: 'start/tasks' }, + { label: 'Distribution (all channels)', slug: 'start/distribution' }, ], }, { diff --git a/website/public/demo.svg b/website/public/demo.svg new file mode 100644 index 0000000..4ce1945 --- /dev/null +++ b/website/public/demo.svg @@ -0,0 +1,19 @@ + + + + + + +zsh · ~/acme +pdcli pipeline health┌ SALES PIPELINE ───────────────── Q2 ┐Qualified 18 deals €142,000Contact 11 deals € 98,500Proposal 7 deals € 76,200Negotiation 4 deals € 51,000─────────────────────────────────────weighted forecast €221,480win rate 32% · avg cycle 24dpdcli deal update 4821 --status won✓ Acme renewal → Won · activity loggedpdcli audit┌ DATA HYGIENE ──────────── 11 checks ┐● 3 duplicate deals● 5 deals stale > 30 days○ 8 missing a next step─────────────────────────────────────3 must-fix · audit --strict gates CI + diff --git a/website/src/components/Home.astro b/website/src/components/Home.astro index a758848..679d958 100644 --- a/website/src/components/Home.astro +++ b/website/src/components/Home.astro @@ -48,7 +48,7 @@ const steps: [string, string, string, string][] = [ ], ]; -const features: { t: string; b: string; d: string }[] = [ +const features: { t: string; b: string; d: string; href?: string }[] = [ { t: 'Backup & data export', b: 'Stream your entire account to JSON with pdcli backup --resume, or export any resource to CSV. Resumable, scriptable, and perfect for archives or migrations.', @@ -63,6 +63,7 @@ const features: { t: string; b: string; d: string }[] = [ t: 'Built for AI agents', b: 'Runs as an MCP server — pdcli mcp serve — read-only by default, giving Claude and other hosts a safe, typed tool surface. For shell-driven agents there is also self-documenting --help, clean JSON, and deterministic exit codes.', d: '', + href: 'start/agents/', }, { t: 'Scriptable by design', @@ -170,6 +171,20 @@ const showcaseTerm = `$ pdcli