From 9262c5c89818d31097b1b68fcf74af967ab7c5e5 Mon Sep 17 00:00:00 2001 From: Tal Weiss Date: Mon, 27 Apr 2026 20:37:37 +0200 Subject: [PATCH] feat(sdk,cli,mcp): agent-DX blob CDN diagnostics (v1.45) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Coordinated public-repo half of the v1.33 agent-DX blob CDN release. All additive — no existing API surface broken. SDK (sdk/src/namespaces/blobs.{ts,types.ts}): - Widen blobs.put return into AssetRef: keeps the snake_case fields for back-compat AND adds size, contentSha256, contentType, immutableUrl, etag, sri, contentDigest, cacheKind, cdn:{version,invalidationId,invalidationStatus,ready,hint}. - buildAssetRef derives etag/sri/contentDigest locally from the SHA so the SDK surface is stable across gateway versions. - New helpers: client.blobs.diagnoseUrl(projectId, url) and client.blobs.waitFresh(projectId, {url, sha256, timeoutMs?}). Signed slightly differently from the spec scenarios (added projectId first arg) for consistency with put/get/ls. - 8 new tests in blobs.test.ts (22 total). CLI (cli/lib/blob.mjs, cli/lib/cdn.mjs, cli/cli.mjs, openclaw/scripts/cdn.mjs): - run402 blob diagnose — exit 0 on SHA match, 1 otherwise (shell-loop friendly). - run402 cdn wait-fresh --sha [--timeout ] — polls until fresh. - Both --help docs include exit-code semantics and the vantage caveat. MCP tools (src/tools/blob-{diagnose,wait-fresh}.ts, src/index.ts): - diagnose_public_url + wait_for_cdn_freshness with explicit agent guidance ('mutable URLs only'). - wait_for_cdn_freshness returns isError=true on timeout so agents branch into the immutableUrl fallback. Docs (SKILL.md, cli/llms-cli.txt): - 'Prefer immutableUrl in generated HTML/CSS/JS' guidance with reasoning (read-after-write correctness, integrity via SRI). - New tool sections for diagnose_public_url + wait_for_cdn_freshness. Notes: - sync.test.ts updated for the new SURFACE rows + cdn namespace; the llms.txt-alignment assertion fails locally until the private-repo PR merges (it reads ~/Developer/run402-private/site/llms.txt). CI in the public repo skips the suite when the path is absent. - Version is already 1.45.0 (chore: bump in 143f408). After this PR merges, run npm publish in coordination with the v1.33 backend cutover. Co-Authored-By: Claude Opus 4.7 (1M context) --- SKILL.md | 37 ++++- cli/cli.mjs | 8 +- cli/lib/blob.mjs | 65 +++++++- cli/lib/cdn.mjs | 130 ++++++++++++++++ cli/llms-cli.txt | 19 ++- openclaw/scripts/cdn.mjs | 1 + sdk/src/namespaces/blobs.test.ts | 244 ++++++++++++++++++++++++++++++ sdk/src/namespaces/blobs.ts | 211 +++++++++++++++++++++++++- sdk/src/namespaces/blobs.types.ts | 143 ++++++++++++++++- src/index.ts | 16 ++ src/tools/blob-diagnose.ts | 49 ++++++ src/tools/blob-wait-fresh.ts | 61 ++++++++ sync.test.ts | 10 +- 13 files changed, 980 insertions(+), 14 deletions(-) create mode 100644 cli/lib/cdn.mjs create mode 100644 openclaw/scripts/cdn.mjs create mode 100644 src/tools/blob-diagnose.ts create mode 100644 src/tools/blob-wait-fresh.ts diff --git a/SKILL.md b/SKILL.md index ad9755c9..811bf6d3 100644 --- a/SKILL.md +++ b/SKILL.md @@ -109,7 +109,14 @@ Upload a blob (any size, up to 5 TiB) to project storage via direct-to-S3 presig - `immutable` (optional, default: `false`) — If true with `sha256`, also produces a content-addressed URL that gets `Cache-Control: immutable`. - `sha256` (optional) — Required when `immutable: true`. Client-asserted hash; gateway verifies if S3 returns one. -**Returns:** `{ key, size_bytes, sha256, url, immutable_url? }`. `url` is the CDN URL (on `pr-.run402.com`); `immutable_url` is the content-addressed variant when applicable. +**Returns:** an `AssetRef`: `{ key, size_bytes, sha256, visibility, url, immutable_url, size, contentSha256, contentType, immutableUrl, etag, sri, contentDigest, cacheKind, cdn: { version, invalidationId, invalidationStatus, ready, hint } }`. The legacy snake_case fields (`size_bytes`, `sha256`, `immutable_url`) are kept for back-compat; the camelCase fields are the v1.45 agent-DX surface. + +**Prefer `immutableUrl` in generated HTML/CSS/JS code.** Reasoning: +- Read-after-write correctness: the immutable URL is bound to the SHA at upload time and was never previously cached. The mutable `url` is "eventually fresh" — invalidation is asynchronous, so a `