Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
7f8d8f1
fix(budget,errors): a per-agent cap that cannot refill itself, and ac…
VickyXAI Sep 9, 2026
fa2809d
fix(models,video,docs): key the model cache by rail and chain, poll t…
VickyXAI Sep 9, 2026
1034bb9
fix(polymarket): say what the approval is WORTH before it is signed, …
VickyXAI Sep 9, 2026
737e094
fix(wallet): two regressions from 0.49.0's own Solana provisioning
VickyXAI Sep 9, 2026
350df27
fix(media,errors): the quote guard and the give-up booking reach the …
VickyXAI Sep 9, 2026
776b4a7
fix(apps,chat,realface): three ways a paid call could be made twice o…
VickyXAI Sep 9, 2026
e6fc902
fix(budget): book what the gateway charges, not what we reserved
VickyXAI Sep 9, 2026
83f469b
test(rails): the rail-parity matrix, and the four gaps it found on it…
VickyXAI Sep 9, 2026
783cfb3
fix(wallet,docs): a locked keychain is not a missing wallet, and five…
VickyXAI Sep 9, 2026
c82f196
fix(ci,apps,solana): pin the registry publisher, and four honesty fixes
VickyXAI Sep 9, 2026
758a949
fix(relayer,verify): arm the double-send guard only when the outcome …
VickyXAI Sep 9, 2026
8d0dcb4
feat(polymarket): enforce the previewed worst fill across the confirm…
VickyXAI Sep 9, 2026
084971a
0.50.0 — a second audit round, aimed at the first one
VickyXAI Sep 9, 2026
90a8ad4
fix(wallet): an empty .session must not overwrite a funded key in the…
VickyXAI Sep 9, 2026
ace5f2e
docs(polymarket): stop l1-auth-1271 from telling the next maintainer …
VickyXAI Sep 9, 2026
4e357af
fix(scripts): the live e2e scripts printed the wallet address they pr…
VickyXAI Sep 9, 2026
937c4c5
fix(scripts): smoke-speech charged the wallet for being run
VickyXAI Sep 9, 2026
efb9e2e
fix(scripts): the release automation could publish wrong numbers with…
VickyXAI Sep 9, 2026
3168f70
fix(docs): CONTRIBUTING told new contributors to copy a deleted file …
VickyXAI Sep 9, 2026
25b5825
docs(changelog): the release says the search was spent, then round 3 …
VickyXAI Sep 9, 2026
7f551d2
Merge remote-tracking branch 'origin/main' into fix/audit-r2
VickyXAI Sep 9, 2026
d111b25
Merge remote-tracking branch 'origin/main' into fix/audit-r3
VickyXAI Sep 13, 2026
76a75b9
docs(readme): document account API payments
VickyXAI Sep 15, 2026
b2e8a2f
fix(chat,errors): every chat path streams, classifies its failure by …
VickyXAI Sep 15, 2026
69795f2
fix(budget): the operator's BLOCKRUN_BUDGET_LIMIT is a ceiling the se…
VickyXAI Sep 15, 2026
058a2cf
fix(media): one per-call in-flight tracker replaces five hand-rolled …
VickyXAI Sep 15, 2026
0cbe90e
fix(path-tools): a shared catch that books a payment the origin never…
VickyXAI Sep 15, 2026
ba4825d
fix(wallet): four ways a funded key could be lost or shadowed, and on…
VickyXAI Sep 15, 2026
e656535
fix(polymarket): an unknown submit outcome is never a plain error, th…
VickyXAI Sep 15, 2026
375b5be
fix(ci,scripts): the release gates fail when they cannot verify, and …
VickyXAI Sep 15, 2026
9cde2fd
test(harness): pin HOME and every rail-selecting env var for the whol…
VickyXAI Sep 15, 2026
bc74e9d
docs(readme): re-measure the context cost — 13.0K tokens, trading 58%…
VickyXAI Sep 15, 2026
b85c1fd
fix(media): an answered error is never a maybe, every settled-at-subm…
VickyXAI Sep 15, 2026
1c27756
fix(budget): a call that settles while its agent is revoked still lan…
VickyXAI Sep 15, 2026
24634f4
fix(wallet): secret-tool's exit 1 is read by stderr, the legacy walle…
VickyXAI Sep 15, 2026
94b590e
fix(path-tools): a throw after the SDK counted the settlement books t…
VickyXAI Sep 15, 2026
02d9e74
fix(ci): only npm's E404 is "none" — a registry failure is "unknown" …
VickyXAI Sep 15, 2026
fe06bab
docs(search): there is no X/Twitter source — the skill, the README ro…
VickyXAI Sep 15, 2026
1aa023f
chore(release): 0.51.0 — round four went at round three
VickyXAI Sep 15, 2026
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
35 changes: 29 additions & 6 deletions .github/workflows/brand-sync.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,19 @@
# branch is protected the push fails and the fallback opens a PR instead.
# No third-party actions beyond actions/checkout — supply-chain surface stays
# at one GitHub-owned action.
#
# In THIS repo main is protected (required check `test`), so the direct push
# always fails, and GitHub Actions is not permitted to open PRs in this org
# (PR #141: "it pushed brand-sync/20260905 and left it for a manual PR"). The
# fallback's `|| echo …` then swallowed that too, and the run went GREEN having
# landed nothing — a stale count sat in the README for 26 days (#123) behind a
# green badge, which is the exact failure the header above promises cannot
# happen. A drift this job cannot land is a FAILURE: the run is red until a
# human opens the PR, and the branch name is fixed (`brand-sync`, force-pushed)
# so a month of Mondays does not leave a month of orphan branches.
# To make the fallback land on its own: enable "Allow GitHub Actions to create
# and approve pull requests" in the org/repo Actions settings, or give the step
# a PAT with pull-requests:write.
name: brand-sync
on:
schedule:
Expand Down Expand Up @@ -41,11 +54,21 @@ jobs:
git commit -m "chore: sync brand numbers from blockrun.ai/brand/numbers.json"
if git push origin "HEAD:${GITHUB_REF_NAME}"; then
echo "pushed to ${GITHUB_REF_NAME}"
else
BR="brand-sync/$(date +%Y%m%d)"
git push -f origin "HEAD:${BR}"
gh pr create --head "$BR" \
exit 0
fi
# One fixed branch, force-pushed: the rewrite is regenerated from the
# artifact every run, so the previous week's branch has nothing worth
# keeping and a dated name per run only accumulates orphans.
BR="brand-sync"
git push -f origin "HEAD:${BR}"
if gh pr create --head "$BR" \
--title "chore: sync brand numbers" \
--body "Automated marker refresh from https://blockrun.ai/brand/numbers.json (scripts/sync-brand-numbers.mjs --refresh). Opened as a PR because the default branch is protected." \
|| echo "PR creation unavailable — branch ${BR} pushed, needs manual PR"
--body "Automated marker refresh from https://blockrun.ai/brand/numbers.json (scripts/sync-brand-numbers.mjs --refresh). Opened as a PR because the default branch is protected."; then
echo "opened a PR from ${BR}"
exit 0
fi
# Not a warning. The numbers drifted, this job could not land the fix,
# and a green run here is how a stale count sat in the README for 26
# days. Red until a human opens the PR from the pushed branch.
echo "::error::brand numbers drifted and could not be landed: push to ${GITHUB_REF_NAME} was rejected and PR creation is unavailable to GITHUB_TOKEN. Branch ${BR} is pushed — open the PR by hand (or enable 'Allow GitHub Actions to create and approve pull requests')."
exit 1
88 changes: 79 additions & 9 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,21 @@ jobs:
id: v
run: |
PKG=$(node -p "require('./package.json').version")
NPM=$(npm view @blockrun/mcp version 2>/dev/null || echo "none")
# "none" ONLY on npm's own E404 (the package has never been published).
# Any other failure — a registry 5xx, a network error, a bad token —
# is "unknown", which the version gate step refuses. Spelling every
# failure as "none" made the gate pass on the one input where it must
# not: a package.json below latest during a registry blip, which would
# publish and downgrade `latest`.
if NPM=$(npm view @blockrun/mcp version 2>npm-view.err); then
:
elif grep -q "E404" npm-view.err; then
NPM=none
else
echo "::warning::npm view failed and it was not an E404:"; cat npm-view.err
NPM=unknown
fi
rm -f npm-view.err
# `version=latest` is load-bearing. Without it the search endpoint pages
# at 30 results with every isLatest=false, so the old `|| a[a.length-1]`
# fallback returned the last row of PAGE ONE — 0.32.8, frozen since July —
Expand All @@ -55,22 +69,41 @@ jobs:
# latest, isLatest=true.
REG=$(curl -s "https://registry.modelcontextprotocol.io/v0/servers?search=io.github.BlockRunAI/blockrun-mcp&version=latest" \
| node -e "let s='';process.stdin.on('data',d=>s+=d).on('end',()=>{try{const j=JSON.parse(s);const a=j.servers||[];console.log(a[0]?.server?.version||'none')}catch{console.log('none')}})")
# The tag is the third target, and it needs its OWN guard computed
# here, not derived from the npm one. Ask the remote: actions/checkout
# fetches no tags, so a local lookup always says "missing".
if git ls-remote --exit-code --tags origin "refs/tags/v${PKG}" >/dev/null 2>&1; then
TAG_MISSING=false
else
TAG_MISSING=true
fi
echo "pkg=$PKG" >> "$GITHUB_OUTPUT"
echo "npm=$NPM" >> "$GITHUB_OUTPUT"
echo "reg=$REG" >> "$GITHUB_OUTPUT"
echo "package.json=$PKG | npm=$NPM | registry=$REG"
echo "tag_missing=$TAG_MISSING" >> "$GITHUB_OUTPUT"
echo "package.json=$PKG | npm=$NPM | registry=$REG | tag v$PKG missing=$TAG_MISSING"

# `pkg != npm` is inequality, not order. npm publish does not compare
# semver and points `latest` at whatever it just published, so a
# package.json LOWER than npm latest (a typo'd 0.5.1 for 0.51.0, or a
# number proposed off a stale VERSION file) would ship and downgrade
# every `npx -y @blockrun/mcp@latest` user. Plain Node: runs before npm ci.
- name: Refuse a version below npm latest
run: node scripts/version-gate.mjs "${{ steps.v.outputs.pkg }}" "${{ steps.v.outputs.npm }}"

- name: Install dependencies
run: npm ci

- name: Build, typecheck, test
id: build
run: |
npm run build
npm run typecheck
npm test

# ---- npm ----
- name: Publish to npm
id: npm
if: steps.v.outputs.pkg != steps.v.outputs.npm
run: npm publish --provenance --access public
env:
Expand All @@ -81,12 +114,31 @@ jobs:
run: echo "npm already at ${{ steps.v.outputs.pkg }} — skipping npm publish"

# ---- MCP registry ----
# PINNED, and checksum-verified against the same release.
#
# This used to curl `releases/latest` straight into `tar -xz` and then into
# /usr/local/bin — an unpinned third-party binary, executed in a job that
# holds the npm publish token, whose contents could change between two runs
# of the same commit with nothing in this repo recording it. Pinning is the
# part that matters: the version moves when someone here changes this line.
# The checksum file ships from the same release, so it proves the download
# is intact, not that the release is trustworthy — that is what pinning is
# for. Bump deliberately; the registry's own releases page lists the tag.
- name: Install mcp-publisher
if: steps.v.outputs.pkg != steps.v.outputs.reg
env:
MCP_PUBLISHER_VERSION: v1.8.1
run: |
curl -sL "https://github.com/modelcontextprotocol/registry/releases/latest/download/mcp-publisher_$(uname -s | tr '[:upper:]' '[:lower:]')_amd64.tar.gz" \
| tar -xz mcp-publisher
set -euo pipefail
os=$(uname -s | tr '[:upper:]' '[:lower:]')
tarball="mcp-publisher_${os}_amd64.tar.gz"
base="https://github.com/modelcontextprotocol/registry/releases/download/${MCP_PUBLISHER_VERSION}"
curl -fsSL -o "$tarball" "${base}/${tarball}"
curl -fsSL -o checksums.txt "${base}/registry_${MCP_PUBLISHER_VERSION#v}_checksums.txt"
grep " ${tarball}$" checksums.txt | sha256sum -c -
tar -xzf "$tarball" mcp-publisher
sudo mv mcp-publisher /usr/local/bin/
rm -f "$tarball" checksums.txt

- name: Stamp + publish server.json to MCP registry
if: steps.v.outputs.pkg != steps.v.outputs.reg
Expand All @@ -108,12 +160,30 @@ jobs:
# Same independent-guard shape as the two publishes above — it checks
# whether the tag already exists rather than assuming, so re-runs and
# workflow_dispatch are safe.
# Gated on the same version diff as the npm publish above. Without it, a
# push that only touched publish.yml (or a workflow_dispatch) would tag
# HEAD and title the release from an unrelated commit subject — precisely
# in the "release is missing" state this automation exists to repair.
#
# INDEPENDENT means its own guard, not npm's. This step used to be gated
# on `pkg != npm`, which is false the moment npm has published — so a
# job that went red AFTER npm (the mcp-publisher download, a registry
# 400, the tag push itself) could never be repaired by re-running it: the
# re-run found npm == pkg, skipped this step by its `if:`, and went green
# with no tag and no release. The in-step `gh release view` / `git
# ls-remote` checks that make re-runs safe never executed, because the
# outer condition short-circuited them. That is the drift this step was
# written to end, reported as success.
#
# So the gate is: the tag is ABSENT (resolved against origin, up front),
# and npm carries this version — either this run published it, or it was
# already there. A push that only touched publish.yml still cannot tag
# HEAD under a stale number, because then the tag already exists. A run
# whose build or npm publish FAILED does not tag either: `!cancelled()`
# lets this step run past a registry failure, and the outcome checks
# keep it from running past a real one.
- name: Tag + GitHub release
if: steps.v.outputs.pkg != steps.v.outputs.npm
if: >-
!cancelled()
&& steps.v.outputs.tag_missing == 'true'
&& steps.build.outcome == 'success'
&& (steps.npm.outcome == 'success' || steps.v.outputs.pkg == steps.v.outputs.npm)
env:
GH_TOKEN: ${{ github.token }}
VERSION: ${{ steps.v.outputs.pkg }}
Expand Down
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
node_modules/
node_modules
dist/
*.log
.DS_Store
Expand Down
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# BlockRun MCP

MCP server giving Codex real-time data — markets, research, X/Twitter, crypto. Pay per call with USDC.
MCP server giving Codex real-time data — markets, research, web search, crypto. Pay per call with USDC.

## Commands

Expand Down
Loading
Loading