diff --git a/.github/workflows/publish-manifest.yml b/.github/workflows/publish-manifest.yml new file mode 100644 index 00000000..268e2ec6 --- /dev/null +++ b/.github/workflows/publish-manifest.yml @@ -0,0 +1,113 @@ +name: publish-manifest + +# Receives a `repository_dispatch` event of type `manifest-update` from +# `web4/.github/workflows/release.yml` after a tag ships. The event carries +# the rendered manifest in `client_payload.manifest`; this workflow merges it +# into `public/.well-known/latest.json` and commits to main, which triggers +# the Cloudflare Pages deploy. +# +# Merge rules: +# - `latest_stable` is only advanced when the incoming manifest is for a +# non-prerelease tag (`is_prerelease == false`). RC tags update only +# `latest_prerelease` and `channels.edge`. +# - `platforms` is replaced wholesale with the incoming map for the tag. +# - `updated_at` is taken from the incoming manifest. +# +# Manual trigger (`workflow_dispatch`) is available for the case where the +# dispatch from web4 was dropped (missing token, transient 5xx) and the +# operator needs to nudge the manifest forward by hand. + +on: + repository_dispatch: + types: [manifest-update] + workflow_dispatch: + inputs: + manifest: + description: 'Inline manifest JSON (overrides the dispatch payload path)' + required: true + +permissions: + contents: write + +jobs: + merge-and-commit: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + ref: main + fetch-depth: 0 + + - name: Resolve incoming manifest + id: incoming + env: + DISPATCH_MANIFEST: ${{ toJson(github.event.client_payload.manifest) }} + MANUAL_MANIFEST: ${{ inputs.manifest }} + run: | + if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then + echo "$MANUAL_MANIFEST" > /tmp/incoming.json + else + echo "$DISPATCH_MANIFEST" > /tmp/incoming.json + fi + jq . /tmp/incoming.json > /tmp/incoming.pretty.json + cp /tmp/incoming.pretty.json /tmp/incoming.json + echo "incoming manifest:" + cat /tmp/incoming.json + + - name: Merge into public/.well-known/latest.json + run: | + INCOMING=/tmp/incoming.json + CURRENT=public/.well-known/latest.json + mkdir -p public/.well-known + if [ ! -f "$CURRENT" ]; then + # First-ever publish — start from the incoming manifest, but + # rewrite the prerelease-aware fields into their final names. + jq '{ + "$schema": "https://pilotprotocol.network/.well-known/latest.schema.json", + "updated_at": .updated_at, + "latest_stable": (.proposed_stable // ""), + "latest_prerelease": (.proposed_edge // .tag), + "channels": { + "stable": (.proposed_stable // ""), + "edge": (.proposed_edge // .tag) + }, + "release_notes_url": .release_notes_url, + "homebrew_formula_url": .homebrew_formula_url, + "platforms": .platforms + }' "$INCOMING" > "$CURRENT" + else + jq --slurpfile inc "$INCOMING" ' + . as $cur | + $inc[0] as $i | + { + "$schema": ($cur["$schema"] // "https://pilotprotocol.network/.well-known/latest.schema.json"), + "updated_at": $i.updated_at, + "latest_stable": (if $i.is_prerelease then $cur.latest_stable else $i.proposed_stable end), + "latest_prerelease": ($i.proposed_edge // $i.tag), + "channels": { + "stable": (if $i.is_prerelease then $cur.channels.stable else $i.proposed_stable end), + "edge": ($i.proposed_edge // $i.tag) + }, + "release_notes_url": $i.release_notes_url, + "homebrew_formula_url": $i.homebrew_formula_url, + "platforms": $i.platforms + } + ' "$CURRENT" > "$CURRENT.new" + mv "$CURRENT.new" "$CURRENT" + fi + echo "merged manifest:" + cat "$CURRENT" + + - name: Commit and push + run: | + if git diff --quiet public/.well-known/latest.json; then + echo "manifest unchanged — nothing to commit." + exit 0 + fi + git config user.name "pilot-release-bot" + git config user.email "release-bot@pilotprotocol.network" + TAG=$(jq -r '.latest_prerelease // .latest_stable // "unknown"' public/.well-known/latest.json) + git add public/.well-known/latest.json + git commit -m "manifest: bump to ${TAG}" \ + -m "Triggered by upstream release workflow." + git push origin main diff --git a/public/.well-known/latest.json b/public/.well-known/latest.json new file mode 100644 index 00000000..29a4ee13 --- /dev/null +++ b/public/.well-known/latest.json @@ -0,0 +1,30 @@ +{ + "$schema": "https://pilotprotocol.network/.well-known/latest.schema.json", + "updated_at": "2026-05-28T14:00:00Z", + "latest_stable": "v1.10.5", + "latest_prerelease": "v1.10.5", + "channels": { + "stable": "v1.10.5", + "edge": "v1.10.5" + }, + "release_notes_url": "https://github.com/pilot-protocol/pilotprotocol/releases/tag/v1.10.5", + "homebrew_formula_url": "https://github.com/pilot-protocol/homebrew-pilot/raw/main/Formula/pilotprotocol.rb", + "platforms": { + "darwin-amd64": { + "url": "https://github.com/pilot-protocol/pilotprotocol/releases/download/v1.10.5/pilot-darwin-amd64.tar.gz", + "sha256": "eab41da1108068e965e4c500bfae6f5aa1b6a21d02b7feb3942fd2b6434fc3be" + }, + "darwin-arm64": { + "url": "https://github.com/pilot-protocol/pilotprotocol/releases/download/v1.10.5/pilot-darwin-arm64.tar.gz", + "sha256": "125fe7c8b83ce89f53487ec0ac1fe22decd4defd4af2b42559809042e2083597" + }, + "linux-amd64": { + "url": "https://github.com/pilot-protocol/pilotprotocol/releases/download/v1.10.5/pilot-linux-amd64.tar.gz", + "sha256": "b062e355f24d85b884345de396398cd95d5c70fd44d23a9633c1bbcd3003022b" + }, + "linux-arm64": { + "url": "https://github.com/pilot-protocol/pilotprotocol/releases/download/v1.10.5/pilot-linux-arm64.tar.gz", + "sha256": "37428a4b08e6880cffca5049df872746358c41f9d63c25d5896446c48aa7e165" + } + } +} diff --git a/src/components/Nav.astro b/src/components/Nav.astro index 9bfac85a..7e1b4974 100644 --- a/src/components/Nav.astro +++ b/src/components/Nav.astro @@ -1,13 +1,12 @@ --- interface Props { - active?: 'home' | 'docs' | 'blog' | 'plans' | 'for'; + active?: 'home' | 'docs' | 'blog' | 'plans' | 'for' | 'tech' | 'apps'; } const { active } = Astro.props; const forLinks = [ { href: '/for/p2p', label: 'Direct P2P', desc: 'Peer-to-peer for AI agents' }, { href: '/for/mcp', label: 'MCP + Pilot', desc: 'Give your MCP servers a network' }, - { href: '/app-store', label: 'App Store', desc: 'Agent apps, one command to install' }, { href: '/for/networks', label: 'Networks', desc: 'Domain networks agents self-organize into' }, ]; @@ -48,8 +47,10 @@ const statusText = version ? `Network live · v${version}` : 'Network live'; data-track="nav_click" data-track-target="docs">Docs Blog + App Store Plans + data-track="nav_click" data-track-target="plans">Plans