@artblocks/abx-cli 0.1.0-alpha.14 → 0.1.0-alpha.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +1243 -0
- package/assets/renderer-scaffold/src/interfaces/IAbxParams.sol +17 -0
- package/assets/renderer-scaffold/test/MyRenderer.t.sol +51 -2
- package/dist/flags.d.ts +7 -0
- package/dist/flags.d.ts.map +1 -1
- package/dist/flags.js +19 -0
- package/dist/flags.js.map +1 -1
- package/dist/main.js +267 -35
- package/dist/main.js.map +1 -1
- package/dist/ownerops.d.ts +53 -1
- package/dist/ownerops.d.ts.map +1 -1
- package/dist/ownerops.js +181 -13
- package/dist/ownerops.js.map +1 -1
- package/dist/scaffold.d.ts +10 -0
- package/dist/scaffold.d.ts.map +1 -0
- package/dist/scaffold.js +52 -0
- package/dist/scaffold.js.map +1 -0
- package/package.json +7 -6
- package/skill/SKILL.md +6 -2
- package/skill/reference/code-projects.md +4 -3
- package/skill/reference/creator-token.md +71 -0
- package/skill/reference/operating.md +2 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,1243 @@
|
|
|
1
|
+
# @artblocks/abx-cli
|
|
2
|
+
|
|
3
|
+
## 0.1.0-alpha.16
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 8f3c63c: Four output surfaces that misinformed: an occupied port, a repeated `verify` advisory, a silently-dropped `tokenuri` argument, and a release-notes URL that 404s.
|
|
8
|
+
|
|
9
|
+
**`abx serve` / `abx preview` on an occupied port crashed with a raw Node stack trace.** `listen()` had
|
|
10
|
+
no `'error'` handler, so `EADDRINUSE` reached Node's default handler and printed a trace through
|
|
11
|
+
`node:net` and our own `dist/` paths. In a CLI where every other error is formatted, that reads as a
|
|
12
|
+
crash inside abx rather than a port conflict, and it leaks internal paths. Both commands now preflight
|
|
13
|
+
the port and name the port and the fix in one line — `demo` already did this, and the check it used is
|
|
14
|
+
now shared. (`preview`'s default 8788 colliding with a studio left running in another terminal was
|
|
15
|
+
reported as the harder-to-diagnose half of this.)
|
|
16
|
+
|
|
17
|
+
**`abx verify` printed the identical thumbnail advisory once per token.** On a 32-token project with no
|
|
18
|
+
local renders that was 32 consecutive copies of the same full sentence — ~4KB of text for one fact —
|
|
19
|
+
which pushed the four lines that answer "did my deploy work" off a default terminal. It now prints one
|
|
20
|
+
line per outcome with a count and the affected token ids (truncated past 12), so the same information
|
|
21
|
+
costs three lines at 32 tokens and three lines at 1000.
|
|
22
|
+
|
|
23
|
+
**`abx tokenuri <address> 0` silently ignored the `0`** (the token id is `--token`) and printed token 0 —
|
|
24
|
+
a _coincidentally correct_ answer, which is the dangerous kind: `… <address> 7` would have printed token 0
|
|
25
|
+
just as confidently and exited 0. A stray positional is now refused, and a numeric one names the
|
|
26
|
+
corrected invocation. The `positionalArgs` helper moved next to `parseFlags`, because the two must
|
|
27
|
+
consume argv by the same rule — the obvious hand-rolled version of this check reads `--token 0` as a
|
|
28
|
+
stray `0`.
|
|
29
|
+
|
|
30
|
+
**The update banner pointed at `github.com/ArtBlocks/abx/releases`, which 404s** for anyone outside the
|
|
31
|
+
org, and no changelog shipped in the package — so "what changed?" was unanswerable. A tester
|
|
32
|
+
reconstructed the diff by running the same dry run on two versions, which is how they discovered the
|
|
33
|
+
canonical singletons had moved and then had no way to tell whether it needed them to act.
|
|
34
|
+
`CHANGELOG.md` now ships with the package and **`abx changelog`** prints it (offline, version-matched;
|
|
35
|
+
`--all` for the full history), with npm's version list as the online pointer. The upgrading guide now
|
|
36
|
+
also states the thing they had to test for themselves: a singleton redeploy repoints the manifest for
|
|
37
|
+
_new_ deploys and leaves already-deployed contracts unaffected.
|
|
38
|
+
|
|
39
|
+
**Plus one propagation note.** `arweave.net` — the default gateway, and the one baked into the locator —
|
|
40
|
+
indexes new uploads on a delay, so a freshly published render can 404 there for minutes while Turbo has
|
|
41
|
+
already confirmed it. A tester saw 32/32 404ing on arweave.net while 22/32 already served from other
|
|
42
|
+
ar.io gateways. Unexplained, that reads as a failed render, and the natural next move is
|
|
43
|
+
`abx render --force` on everything — a full re-upload that fixes nothing. `abx render` now says so after
|
|
44
|
+
an Arweave publish, and names `ABX_ARWEAVE_GATEWAY` for baking a different gateway (it is fixed at
|
|
45
|
+
publish time, since the locator is what the resolver registers). The note stays quiet when the operator
|
|
46
|
+
has already chosen a non-default gateway.
|
|
47
|
+
|
|
48
|
+
_(From the 2026-08-04 tester batch: feedback `eb972036`, `57bee789`, `dcfdc6f4`, `5a052398`, `e0f30e22`.)_
|
|
49
|
+
|
|
50
|
+
- 8f3c63c: Two writes that reported success without doing what the creator meant now refuse: `lock-field` on a parameter key, and a `Bytes` parameter given text.
|
|
51
|
+
|
|
52
|
+
Both are the same defect wearing different clothes — the CLI made statements that were individually
|
|
53
|
+
true and collectively a promise it wasn't keeping.
|
|
54
|
+
|
|
55
|
+
**`lock-field` reported "permanent" on a PostParam key and left the param writable.** A tester welded
|
|
56
|
+
`grid` — a `Bytes` param holding the artwork — with `abx lock-field <addr> --field grid`. It printed
|
|
57
|
+
`Lock token #0 field "grid" — permanent`, `tokenFieldLocked(0,"grid")` returned `true`, and the very next
|
|
58
|
+
`configure-param grid <junk>` **succeeded** and overwrote the artwork. Nothing lied: fields and params
|
|
59
|
+
are separate namespaces that may share a name, and `lock-field` had locked the _field_. But the creator
|
|
60
|
+
was told their work was permanently protected when it had no protection at all, and permanence is the
|
|
61
|
+
pitch. `lock-field` now reads `paramSchema(<name>)` first and **refuses** a declared param key, naming
|
|
62
|
+
the mechanism that does weld a param (`abx set-schema … --schema <key>:<Type>:<Auth>:lock=now`), with
|
|
63
|
+
`--force-field` for the rare case where you really do mean the metadata field.
|
|
64
|
+
|
|
65
|
+
**A `Bytes` parameter stored whatever characters you typed, as UTF-8.** Passing base64 — reasonable,
|
|
66
|
+
since the params docs say a `Bytes` value "becomes base64" — stored 172 bytes of base64 _ASCII_ where
|
|
67
|
+
128 packed bytes were meant; `0x`-prefixed hex was stored as its 258 literal characters too. Nothing
|
|
68
|
+
errored, and an in-chain renderer reading the param drew garbage from ASCII with no failure anywhere in
|
|
69
|
+
the chain. A `Bytes` value must now say what its bytes are: `0x`-prefixed hex, or `--file <path>`. A bare
|
|
70
|
+
string is **refused** rather than guessed at, because there is no safe guess between "these characters"
|
|
71
|
+
and "these bytes", and the wrong guess is invisible until an artwork renders wrong. (`String` is
|
|
72
|
+
unchanged — there, the characters _are_ the value.)
|
|
73
|
+
|
|
74
|
+
The docs' "becomes base64" describes the **read** side — how a program receives the value — and now says
|
|
75
|
+
so, next to the two write forms.
|
|
76
|
+
|
|
77
|
+
Also fixed: the byte count that was already the tell. The write echoed the _input string's_ length, so
|
|
78
|
+
the mismatch was visible at write time and printed as if it were fine (`Configure grid (data, 172
|
|
79
|
+
bytes)`). It now echoes the decoded byte count and where the bytes came from.
|
|
80
|
+
|
|
81
|
+
_(From the 2026-08-04 tester batch: feedback `e86081a1`, `b0e88b17`.)_
|
|
82
|
+
|
|
83
|
+
- 8f3c63c: The renderer scaffold's `IAbxParams` can now read `Bytes` and `String` parameters — the two types that can carry an actual payload.
|
|
84
|
+
|
|
85
|
+
The scaffold's interface declared only `tokenParam` / `contractParam`, both returning
|
|
86
|
+
`(bytes32 value, bool valueIsHash, bool isSet)`. So a renderer written against the documented interface
|
|
87
|
+
could not reach a `Bytes` or `String` value at all: it got a keccak commitment and no way to the blob.
|
|
88
|
+
The token has always exposed `tokenParamData(uint256,bytes32)` and `contractParamData(bytes32)` — a
|
|
89
|
+
tester found them by grepping the CLI's bundled ABI, declared them by hand, and it worked.
|
|
90
|
+
|
|
91
|
+
Since `Bytes` and `String` are precisely the types that can hold a real payload (~24KB per key), leaving
|
|
92
|
+
them out made the in-chain art lane look limited to scalars unless you went digging. Both readers are now
|
|
93
|
+
in `src/interfaces/IAbxParams.sol`, with the rule stated where the mistake happens: scalars come from the
|
|
94
|
+
`bytes32` reader, payloads from the data reader, and a `Bytes` param read through `tokenParam` hands you a
|
|
95
|
+
hash — which renders garbage without failing anywhere.
|
|
96
|
+
|
|
97
|
+
The scaffold's own tests carry the pattern rather than just describing it: `MockParams` now models a
|
|
98
|
+
payload param the way the real contract does (the scalar slot holds `keccak256(content)` with
|
|
99
|
+
`valueIsHash` true), and two tests show the read plus the commitment check, and that an unset payload key
|
|
100
|
+
returns empty bytes rather than reverting. The renderers page documents the pair alongside the scalar one.
|
|
101
|
+
|
|
102
|
+
_(From the 2026-08-04 tester batch: feedback `d2ac4f2e`.)_
|
|
103
|
+
|
|
104
|
+
- 8f3c63c: `abx scaffold-renderer` wrote **zero files** for every installed user while reporting success — fixed, and pinned by the test that was missing.
|
|
105
|
+
|
|
106
|
+
The command created the target directory, printed the full green-check walkthrough (`cd renderer`,
|
|
107
|
+
`forge soldeer install`, `forge test`, the deploy script, "full walkthrough: renderer/README.md") and
|
|
108
|
+
**exited 0**. The directory was empty. No `src/`, no `foundry.toml`, no `README.md`. Three testers
|
|
109
|
+
reproduced it independently — 3 of 3 and 4 of 4 attempts, across all three invocation forms (relative
|
|
110
|
+
name, absolute path, and the no-arg default) — on alpha.9, alpha.12 and alpha.14.
|
|
111
|
+
|
|
112
|
+
**The cause was a path filter that judged absolute paths.** The copy excluded build dirs with
|
|
113
|
+
|
|
114
|
+
```js
|
|
115
|
+
filter: (s) =>
|
|
116
|
+
!/(^|\/)(out|cache|dependencies|broadcast|node_modules)(\/|$)/.test(s);
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
`cpSync` hands `filter` **absolute** source paths, and an installed CLI lives at
|
|
120
|
+
`…/node_modules/@artblocks/abx-cli/assets/renderer-scaffold`. So the pattern matched the source
|
|
121
|
+
**root**; `cpSync` skips a directory's entire subtree when the directory itself is filtered out, and
|
|
122
|
+
does it _silently_ rather than erroring. A dev checkout's path
|
|
123
|
+
(`…/packages/cli/assets/renderer-scaffold`) contains no `node_modules`, so every test we ran passed and
|
|
124
|
+
every user got an empty directory. The scaffold assets were always in the published package — this was
|
|
125
|
+
never missing content, only a copy step that no-oped.
|
|
126
|
+
|
|
127
|
+
Fixed on both axes, because either one alone would have let this ship:
|
|
128
|
+
|
|
129
|
+
- **The filter judges paths relative to the scaffold root**, so `node_modules` in the _install_ path is
|
|
130
|
+
irrelevant while `out/`, `cache/`, `dependencies/`, `broadcast/` inside the scaffold are still skipped.
|
|
131
|
+
- **The command asserts its own output.** It now throws if `src/MyRenderer.sol` isn't there afterwards,
|
|
132
|
+
instead of printing a success banner over nothing. Exit 0 plus a green check is what made this
|
|
133
|
+
expensive: an agent has no reason to look back at a step that reported success, so the failure
|
|
134
|
+
surfaced far away — `forge soldeer install` dying in an empty directory.
|
|
135
|
+
|
|
136
|
+
The copy logic moved to `src/scaffold.ts` so it can be tested at all (importing `main.ts` runs the CLI),
|
|
137
|
+
and `test/scaffold.test.ts` copies **from a path containing `node_modules`** — the layout every user has
|
|
138
|
+
and the one case no previous test covered — plus an end-to-end run asserting the scaffolded project is
|
|
139
|
+
non-empty and contains the files the success message names.
|
|
140
|
+
|
|
141
|
+
This was the documented entry point to the in-chain Solidity lane and the only documented route to
|
|
142
|
+
`--image-renderer` / `--attributes-renderer`, so it blocked that lane outright. The full walkthrough
|
|
143
|
+
(`forge soldeer install` → `forge test`) now runs clean: 10 tests pass in a freshly scaffolded project.
|
|
144
|
+
|
|
145
|
+
_(From the 2026-08-04 tester batch: feedback `6f2f980a`, `b45bc0f8`, `d2ac4f2e`.)_
|
|
146
|
+
|
|
147
|
+
- 8f3c63c: The agent skill now names the both-worlds code lane, the payload-param reader, and the verb that welds a parameter.
|
|
148
|
+
|
|
149
|
+
Four corrections, all from the same batch that produced the CLI fixes — the skill described the lanes in a
|
|
150
|
+
way that made the strongest option invisible:
|
|
151
|
+
|
|
152
|
+
- **`--script` plus `--image-renderer` is now a lane in its own right.** The table and the in-chain
|
|
153
|
+
section both said "no `--script`", which is a true constraint of the _renderer-only_ shape and read as a
|
|
154
|
+
prohibition on combining them. A program with Solidity renderers gets `animation_url` from its on-chain
|
|
155
|
+
chunks _and_ an on-chain `image`/`attributes` — every marketplace surface in-chain with nothing to
|
|
156
|
+
render, host, or refresh. That is the best available answer for an interactive generative drop and it
|
|
157
|
+
was reachable only by ignoring the skill.
|
|
158
|
+
- **Renderers are told which reader a `Bytes`/`String` param needs.** The guidance said to read params via
|
|
159
|
+
`tokenParam`/`contractParam`, which for the two payload types returns a keccak commitment — so a
|
|
160
|
+
renderer written from the skill drew garbage from a hash with nothing failing. `tokenParamData` /
|
|
161
|
+
`contractParamData` are now named where the mistake happens.
|
|
162
|
+
- **`configure-param`'s payload encoding is explicit**: `String` takes text, `Bytes` takes `0x` hex or
|
|
163
|
+
`--file`, and a bare string on a `Bytes` key is refused.
|
|
164
|
+
- **Locking a param points at `set-schema … :lock=now`**, since `lock-field` freezes the same-named
|
|
165
|
+
_field_ and now refuses a declared param key.
|
|
166
|
+
|
|
167
|
+
_(From the 2026-08-04 tester batch: feedback `c283d767`, `d2ac4f2e`, `b0e88b17`, `e86081a1`.)_
|
|
168
|
+
|
|
169
|
+
- 8f3c63c: The `deploy-code` **Surfaces** preflight no longer contradicts itself, and a script plus an on-chain image renderer is now a documented combination rather than an open question.
|
|
170
|
+
|
|
171
|
+
The `[5] Surfaces` block is the most-praised thing in the deploy preflight — a tester singled out its
|
|
172
|
+
"not backfillable" framing as the direct fix for a confusion they'd filed a version earlier. It also
|
|
173
|
+
told two lies in adjacent lines, both found while answering their follow-up question.
|
|
174
|
+
|
|
175
|
+
**"One or more surfaces resolve to NOTHING a marketplace can see" fired when none did.** An undeclared
|
|
176
|
+
param was folded into the broken-surface test, so a deploy with both renderers set printed
|
|
177
|
+
`thumbnail: ON-CHAIN ✓` and `traits: on-chain ✓` and then, two lines later, that a surface resolved to
|
|
178
|
+
nothing — re-recommending `--image-renderer` and `--attributes-renderer`, the exact flags already
|
|
179
|
+
passed. A dropped param is not a dead surface: the piece renders, that input takes its default. The
|
|
180
|
+
alarm now covers only the thumbnail and traits, names only the remedies for what is actually broken, and
|
|
181
|
+
says _which_ surface. Dropped params keep their own, milder line.
|
|
182
|
+
|
|
183
|
+
**An on-chain image renderer was told to stand up a render runner.** With `--image-renderer` _and_ a
|
|
184
|
+
script, the block recommended `abx deploy-effects`, a one-shot `abx render`, and a publish-capable
|
|
185
|
+
storage backend — none of which apply, because an in-chain SVG has no off-chain still to render, host,
|
|
186
|
+
or refresh. It now says `nothing to render` for any on-chain image lane, with the from-chain check.
|
|
187
|
+
|
|
188
|
+
**And the question the tester explicitly flagged as untested — does passing a script _and_ an
|
|
189
|
+
`--image-renderer` yield both a live `animation_url` and an on-chain thumbnail? — is yes.** Verified on a
|
|
190
|
+
dry run: `animation_url` still assembles on-chain from the script chunks while `image` and `attributes`
|
|
191
|
+
are computed by the Solidity renderers, so every marketplace surface has an on-chain home in one deploy
|
|
192
|
+
with nothing to run. The deploy guide now leads the content-lane section with that combination instead of
|
|
193
|
+
implying the two lanes are an either-or.
|
|
194
|
+
|
|
195
|
+
The guide also gains the correction to the _other_ half of that question. A resolver plus
|
|
196
|
+
`abx render --backend arweave` does **not** backfill a `--onchain-uri` drop's marketplace surfaces: it
|
|
197
|
+
sends no transaction, so `tokenURI` keeps returning the on-chain JSON with its placeholder `image` and
|
|
198
|
+
no `attributes`, which is what marketplaces read. Checked against the reporter's own live 32-token
|
|
199
|
+
contract — `tokenURIBase` is empty, the metadata renderer is authoritative, and `image` provenance still
|
|
200
|
+
reads `fallback — image field unset`. Publishing stills to a resolver is real and useful, and closing
|
|
201
|
+
those surfaces afterwards takes owner transactions that re-point resolution. The guide now says so
|
|
202
|
+
plainly, since "just render to a resolver later" would have been a new false promise in place of the
|
|
203
|
+
old one.
|
|
204
|
+
|
|
205
|
+
Three tests pin the block: an undeclared param never claims a dead surface, an on-chain image renderer
|
|
206
|
+
is never sent to a runner, and a script with no renderer and no resolver still reports both surfaces
|
|
207
|
+
dead.
|
|
208
|
+
|
|
209
|
+
_(From the 2026-08-04 tester batch: feedback `c283d767`, `991dc8e2`, `7936334b`, `a319e53f`.)_
|
|
210
|
+
|
|
211
|
+
## 0.1.0-alpha.15
|
|
212
|
+
|
|
213
|
+
### Minor Changes
|
|
214
|
+
|
|
215
|
+
- e325b46: Opt-in ERC-721C support across the toolkit — plain ERC-721 stays the transparent default.
|
|
216
|
+
|
|
217
|
+
SDK: `OneOfOneInitParams`/`SeriesInitParams` (and `SeriesCodeInitParams` by inheritance) gain
|
|
218
|
+
`transferValidator` immediately after `royaltyBps` — `zeroAddress` = plain ERC-721 forever (the
|
|
219
|
+
default), non-zero = permanent 721C enrollment with that validator. A new `creator-token` module
|
|
220
|
+
ships the per-chain `RECOMMENDED_TRANSFER_VALIDATOR` (OpenSea's
|
|
221
|
+
StrictAuthorizedTransferSecurityRegistry, verified live on Sepolia + Base Sepolia), the two
|
|
222
|
+
creator-token ERC-165 ids + the ABX extension id, `readCreatorTokenStatus()` (`{enrolled,
|
|
223
|
+
validator}`), and a `prepareSetTransferValidator()` write wrapper.
|
|
224
|
+
|
|
225
|
+
CLI: the deploy commands take `--721c [recommended|0x…]` — absent means zero behavior/output
|
|
226
|
+
change; `recommended` resolves the per-chain constant (refused, naming the chains that have one,
|
|
227
|
+
where none is known); an explicit address is EIP-55-validated and pre-checked for code before any
|
|
228
|
+
gas. Enrolling prints one plain statement of what enforcement means. A new owner op
|
|
229
|
+
`abx set-transfer-validator <address> <0x…|none|recommended>` re-points or suspends an ENROLLED
|
|
230
|
+
collection's validator (guards `--dry-run`; refuses plain ERC-721s up front — enrollment is a
|
|
231
|
+
deploy-time decision). `abx state` shows the validator for enrolled collections only.
|
|
232
|
+
|
|
233
|
+
### Patch Changes
|
|
234
|
+
|
|
235
|
+
- Updated dependencies [e325b46]
|
|
236
|
+
- @artblocks/abx-sdk@0.1.0-alpha.8
|
|
237
|
+
- @artblocks/abx-indexer@0.1.0-alpha.9
|
|
238
|
+
- @artblocks/abx-storage@0.1.0-alpha.8
|
|
239
|
+
- @artblocks/abx-token-api@0.1.0-alpha.11
|
|
240
|
+
|
|
241
|
+
## 0.1.0-alpha.14
|
|
242
|
+
|
|
243
|
+
### Minor Changes
|
|
244
|
+
|
|
245
|
+
- 1b50f9d: On-chain param enumeration: a project's parameters are now readable from the chain that holds them, and the `params.keys` convention is retired.
|
|
246
|
+
|
|
247
|
+
The params store was unenumerable by design, so anything that wanted to know _which_ parameters a
|
|
248
|
+
project has had to be told. The answer was a convention: a `params.keys` contract param holding a
|
|
249
|
+
comma-separated list, composed by `deploy-code` from the `--schema` flags and hand-maintained
|
|
250
|
+
thereafter. It worked, and it had the defect every hand-maintained index has — a key configured but
|
|
251
|
+
not listed was **silently omitted from every render**. The schema existed, a collector could set it,
|
|
252
|
+
the art never saw the value, and nothing anywhere reported a problem. The CLI grew a nudge, then a
|
|
253
|
+
same-transaction companion write, and both were treatments for a design that should not have needed
|
|
254
|
+
them.
|
|
255
|
+
|
|
256
|
+
**The token now maintains its own key lists.** `SeriesCode` gains `tokenParamKeys(tokenId)`,
|
|
257
|
+
`contractParamKeys()`, and `paramSchemaKeys()` (plus `…Paged` variants for surfaces past an RPC's
|
|
258
|
+
return cap). The lists are updated inside the write paths themselves, so `key ∈ list ⟺ the param is
|
|
259
|
+
set` holds for every writer — raw owner writes, governed `configure-param` writes, hook-driven writes,
|
|
260
|
+
all of them. No caller can forget, because no caller is involved. (`seed` is deliberately never listed:
|
|
261
|
+
every consumer reads it as a tokenData coordinate, and indexing it would charge every seeded mint for
|
|
262
|
+
nothing.) `paramSchemaKeys()` closes the other half — a chain-only frontend can now build a configure
|
|
263
|
+
UI, including for keys declared but never yet written, which nothing off-chain could previously
|
|
264
|
+
discover.
|
|
265
|
+
|
|
266
|
+
**The canonical `AbxGenerator` reads that surface instead of the CSV.** It no longer looks at
|
|
267
|
+
`params.keys` at all, and a `params.keys` value set on a new project is simply an ordinary parameter —
|
|
268
|
+
enumerated and emitted like any other, by both the generator and the SDK. A latent parity bug dies with
|
|
269
|
+
the convention: the generator's no-CSV path emitted tokenData in insertion order while the canonical
|
|
270
|
+
serializer sorts, so the two byte-forms could disagree; there is now one form.
|
|
271
|
+
|
|
272
|
+
**`AbxMetadataRenderer` is spec v4.** `tokenURI` gains a computed `abx_params` object — every set
|
|
273
|
+
parameter, contract and token scope merged, token wins, sorted, decoded by the same rules the generator
|
|
274
|
+
and the SDK use. A data-backed value over 2048 bytes is emitted as `{"keccak256":"0x…"}` — its on-chain
|
|
275
|
+
commitment — rather than inline, so a large `Bytes` parameter cannot bloat `tokenURI` past a single
|
|
276
|
+
`eth_call`; every key still appears, and an oversized one degrades self-describingly. Parameters are
|
|
277
|
+
_not_ folded into `attributes`: that stays the creator's surface. Also in v4: an `animation_url` carried
|
|
278
|
+
by the `inline` or `reader` representation is now wrapped as `data:text/html;base64,…`, exactly as
|
|
279
|
+
`image` already was — the asymmetry was an oversight, and it meant a fully on-chain animation was
|
|
280
|
+
handed to wallets as bare text.
|
|
281
|
+
|
|
282
|
+
Both changes are additive on the read side: pointed at a token that predates enumeration, a v4 renderer
|
|
283
|
+
simply emits no params block. **Repointing the metadata renderer is safe anywhere.** Repointing the
|
|
284
|
+
_generator_ is not, and `abx set-field` now refuses it: a legacy implementation plus the current
|
|
285
|
+
generator means every parameter silently vanishes behind a `tokenURI` that still looks healthy, so the
|
|
286
|
+
CLI stops you rather than warning you, and names both ways out (stay on the project's existing
|
|
287
|
+
generator, or redeploy).
|
|
288
|
+
|
|
289
|
+
Everywhere else in the toolkit, the convention is simply gone:
|
|
290
|
+
|
|
291
|
+
- `deploy-code --onchain-uri` sets up in **three** legs, not four (animation field → generator, plus
|
|
292
|
+
the two URI renderers). There is no key list to compose, report, or keep in sync, and the help text
|
|
293
|
+
no longer teaches one.
|
|
294
|
+
- `abx set-schema` is a single op again — no companion write, no multicall. This **supersedes**
|
|
295
|
+
alpha.13, which shipped `set-schema` writing `params.keys` in the same transaction to stop a governed
|
|
296
|
+
key going unlisted: the contract now maintains its own key list, so there is nothing to keep in step
|
|
297
|
+
and the drift that fix guarded against is gone rather than mitigated. Same for that release's note
|
|
298
|
+
that "there is no on-chain enumeration of schema keys" — `paramSchemaKeys()` is exactly that.
|
|
299
|
+
- `abx state` reads the governed surface from `paramSchemaKeys()` and the collection-scope values from
|
|
300
|
+
`contractParamKeys()`. A project deployed before enumeration falls back to reading its old
|
|
301
|
+
`params.keys` list, read-only, so live testnet drops still describe themselves.
|
|
302
|
+
- `abx verify` notes when a project's enumerated surface exceeds ~64 keys — the documented design
|
|
303
|
+
envelope. The write side is unbounded; the read side is what grows, since `tokenURI` and `tokenData`
|
|
304
|
+
assemble every parameter per call.
|
|
305
|
+
- `abx configure-param <addr> - params.keys <csv>` no longer has a special path. Writing that key is
|
|
306
|
+
now an ordinary schema-less contract param, and it shows up in tokenData as one — honest, and
|
|
307
|
+
documented.
|
|
308
|
+
- `abx_params` joins `artifacts` and `abx_provenance` as a computed key `set-field` and `attach` refuse.
|
|
309
|
+
|
|
310
|
+
The SDK needed no semantic change: `buildTokenData` has always been event-derived (coordinates + seed +
|
|
311
|
+
every set param, both scopes, token wins, augment entries), and the contract enumeration implements
|
|
312
|
+
exactly that rule. Its `deployments` manifest carries the new addresses.
|
|
313
|
+
|
|
314
|
+
### Patch Changes
|
|
315
|
+
|
|
316
|
+
- 1b50f9d: Fixes from an integrator batch: a machine-readable `tokenuri`, one Arweave identity across CLI and SDK, a correct OpenSea refresh, and attach telling the truth.
|
|
317
|
+
|
|
318
|
+
**`abx tokenuri --json`.** The command abbreviated long values (`… (382 chars)`) with no way to turn it
|
|
319
|
+
off, so for a token whose whole point is on-chain content it returned something that _looked_ like the
|
|
320
|
+
metadata and wasn't. An integrator scraped it, stored a `data:` URI cut to 96 characters, and only
|
|
321
|
+
found out in production; they abandoned the CLI as a read path and reimplemented `eth_call`. `--json`
|
|
322
|
+
now emits the verbatim decoded document — no banner, no ANSI, no truncation — so
|
|
323
|
+
`abx tokenuri <addr> --json | jq` is a supported read path. The human view still abbreviates, and now
|
|
324
|
+
says `[--json for the full value]`.
|
|
325
|
+
|
|
326
|
+
**One Arweave identity, resolved in one place.** `arweaveConfigFromEnv()` read `ARWEAVE_JWK` and
|
|
327
|
+
nothing else, while the CLI mints and manages `.abx-self-host/arweave-key.json`. Porting a working CLI
|
|
328
|
+
flow to the SDK — same machine, minutes later — failed every upload with "Arweave via Turbo needs an
|
|
329
|
+
identity", a message that says storage was never configured when the truth was that two layers
|
|
330
|
+
disagreed about where the identity lives. `@artblocks/abx-storage` now exports `resolveArweaveJwk()`
|
|
331
|
+
(env → managed key file) and the CLI delegates to it. Its diagnostics come with it: an empty key file
|
|
332
|
+
now reports the **path** and the remedy instead of `Unexpected end of JSON input`, and a corrupt one
|
|
333
|
+
says the same.
|
|
334
|
+
|
|
335
|
+
**`abx refresh` on the default chain.** The OpenSea slug map held only `sepolia` and `mainnet`, so
|
|
336
|
+
`base-sepolia` — the CLI's own default — fell through to the raw key: the refresh POST went to a slug
|
|
337
|
+
OpenSea doesn't know, and the printed link pointed at **mainnet** `opensea.io` for a testnet token.
|
|
338
|
+
Slugs are now correct (`base_sepolia`), `testnet` comes from the chain registry rather than a second
|
|
339
|
+
hand-maintained set, and a chain with no known slug produces **no link** instead of a wrong one. Same
|
|
340
|
+
shape as the hardcoded explorer table that once sent every Base Sepolia link to Etherscan.
|
|
341
|
+
|
|
342
|
+
**`abx attach` names its dependency.** Attaching artifacts to a project that resolves on-chain now
|
|
343
|
+
warns, before the send, that they will **not** appear in `tokenURI` — the on-chain renderer carries
|
|
344
|
+
reserved fields only, and the artifacts manifest comes from a resolver. A team attached five audio
|
|
345
|
+
stems to a fully-on-chain token and found them "paid for, stored on-chain, and invisible"; the note
|
|
346
|
+
that existed was one dim line that read as a footnote rather than as a missing service.
|
|
347
|
+
|
|
348
|
+
**`ensureChunkStore` moved to the SDK.** The bootstrap every on-chain-content path needs existed only
|
|
349
|
+
inside the CLI, so an SDK integrator got `resolveChunkStore()` (may return undefined) plus a separate
|
|
350
|
+
`storeSupportsWriteContent()` they had to remember — forget it and an incapable store fails _deep
|
|
351
|
+
inside a mint, after transactions have landed_. One team hand-rolled the guard for exactly that reason.
|
|
352
|
+
`ensureChunkStore(publicClient, send, {chainId, override, onEvent})` is now exported; the SDK reports
|
|
353
|
+
progress through `onEvent` instead of printing, and the CLI keeps its narration.
|
|
354
|
+
|
|
355
|
+
**`abx storage upload --json`.** The locator as data. They scraped this line, captured its ANSI colour
|
|
356
|
+
codes along with the URL, wrote the result into a _stored_ player URL, and found out when it 404'd in
|
|
357
|
+
production. In `--json` mode stdout carries the JSON and nothing else; progress moves to stderr.
|
|
358
|
+
|
|
359
|
+
**`--backend ipfs` no longer hides a missing credential.** Without `PINATA_JWT` the backend resolves to
|
|
360
|
+
**kubo against a local node**, so a dry run looked fine and the real upload failed for anyone not running
|
|
361
|
+
one. The preview now says so. Related correction: the skill claimed "a backend missing its secret falls
|
|
362
|
+
back to `fs`" — it does not. `cloud` refuses up front naming the missing values, and `ipfs` goes to the
|
|
363
|
+
local node; nothing silently degrades to local disk. Both sides now say the same thing.
|
|
364
|
+
|
|
365
|
+
Reported in the 2026-08-03 MXRR integration batch (feedback 869f27b1, a256217f, 119d7e8e, 975c363e,
|
|
366
|
+
e38216db, e267078b).
|
|
367
|
+
|
|
368
|
+
- 1b50f9d: Unknown flags on a command that can send now **refuse** instead of warning — and `--chain` teaches `ABX_CHAIN`.
|
|
369
|
+
|
|
370
|
+
`abx deploy-code … --chain sepolia` ran to completion **on the default chain** (base-sepolia). There is
|
|
371
|
+
no `--chain` flag — the chain comes from the `ABX_CHAIN` environment variable — and the generic
|
|
372
|
+
stray-flag warning said so, accurately, and then the command carried on. On a dry run that is a
|
|
373
|
+
confused minute; on a funded send it is a wrong-chain deploy with real artifacts at an address nobody
|
|
374
|
+
is watching. Prose that gets ignored once gets ignored again, so:
|
|
375
|
+
|
|
376
|
+
- **`--chain` is refused on every command**, read-only ones included (a command that quietly ignored it
|
|
377
|
+
would still teach the wrong model). The message names the mechanism, the chain that _is_ active, the
|
|
378
|
+
known chain keys, and the corrected invocation: `ABX_CHAIN=sepolia abx deploy-code …`.
|
|
379
|
+
- **`deploy`, `deploy-series` and `deploy-code` refuse any unrecognized flag**, naming the offender and
|
|
380
|
+
pointing at `abx help <command>`. `--dry-run` refuses identically — a preview that accepts what the
|
|
381
|
+
real send rejects is its own trap, since you would validate a command and have it fail at the one
|
|
382
|
+
moment it matters.
|
|
383
|
+
- **Read-only commands still only warn.** Nothing can be mis-sent, and a stray flag shouldn't stop a
|
|
384
|
+
creator mid-iteration.
|
|
385
|
+
|
|
386
|
+
Refusing is safe rather than risky here, and this was verified rather than assumed: a flag absent from a
|
|
387
|
+
command's allowlist is by construction one that command never reads. Every `flags.x` read inside
|
|
388
|
+
`cmdDeploy`, `cmdDeploySeries` and `cmdDeployCode` was compared against its allowlist — no gaps — so
|
|
389
|
+
refusal cannot break a working flag, only make an already-ignored one loud.
|
|
390
|
+
|
|
391
|
+
Five tests cover it, including the literal `--chain sepolia` repro, dry-run/real-send parity, and a
|
|
392
|
+
no-false-refusal pass over the documented deploy flags.
|
|
393
|
+
|
|
394
|
+
- 1b50f9d: `abx preview --shoot --param key=value`, and `set-schema --force` says what it overrode.
|
|
395
|
+
|
|
396
|
+
**`--shoot` can render the collector-has-set-it state.** It only ever shot the _unset_ one, so
|
|
397
|
+
answering "what does this collection look like when someone picks a theme?" meant hand-rolling a
|
|
398
|
+
Playwright script against the preview server's `/view` — which is exactly what one agent did. `--param`
|
|
399
|
+
is repeatable (`--param theme=Neon --param mood=Calm`) and forwards into every frame. An empty value
|
|
400
|
+
(`--param theme=`) shoots the unset state explicitly, matching the wire shape production uses for a
|
|
401
|
+
param nobody has written.
|
|
402
|
+
|
|
403
|
+
**`set-schema --force` no longer applies a value-stranding change silently.** It refuses such a change
|
|
404
|
+
by default; with `--force` it now prints each risk it is overriding and notes that any token already
|
|
405
|
+
holding a value keeps it, now outside what its schema allows. Applying that quietly was the one outcome
|
|
406
|
+
worse than refusing — nobody, including the operator, got a record of what may have just been
|
|
407
|
+
invalidated.
|
|
408
|
+
|
|
409
|
+
- Updated dependencies [1b50f9d]
|
|
410
|
+
- Updated dependencies [1b50f9d]
|
|
411
|
+
- @artblocks/abx-sdk@0.1.0-alpha.7
|
|
412
|
+
- @artblocks/abx-storage@0.1.0-alpha.7
|
|
413
|
+
- @artblocks/abx-indexer@0.1.0-alpha.8
|
|
414
|
+
- @artblocks/abx-token-api@0.1.0-alpha.10
|
|
415
|
+
|
|
416
|
+
## 0.1.0-alpha.13
|
|
417
|
+
|
|
418
|
+
### Minor Changes
|
|
419
|
+
|
|
420
|
+
- 1158420: Expose the PostParam schema lifecycle: `abx set-schema`, `abx retire-param`, Address legs, and `lock=`.
|
|
421
|
+
|
|
422
|
+
Three capabilities the contracts have always had, that the toolkit could not reach — so they read to
|
|
423
|
+
creators as protocol limitations. All three were reported in the 2026-08-03 tester batch.
|
|
424
|
+
|
|
425
|
+
**A project's param surface was never frozen at deploy.** `setParamSchema` is owner-gated with no
|
|
426
|
+
deploy-time restriction and no `exists` check, so it is an upsert usable for the life of a project.
|
|
427
|
+
There was just no command for it, and the CLI said so out loud ("Adding a param to an already-deployed
|
|
428
|
+
contract isn't a CLI command yet"), which pushed designers toward guessing their full param surface up
|
|
429
|
+
front or redeploying — losing the address, the mints, and the collectors. `abx set-schema <addr>
|
|
430
|
+
--schema key:Type:Auth` attaches or replaces one key.
|
|
431
|
+
|
|
432
|
+
Because it is a **full-row upsert on a contract that never re-validates stored values**, the command
|
|
433
|
+
carries a guard rather than a warning: it prints before/after, and _refuses_ a change that could strand
|
|
434
|
+
values already written under the key — a narrowed bound, a dropped `Select` option, a changed type —
|
|
435
|
+
unless you pass `--force`. It also flags an existing `lock=` you are about to drop by not restating it.
|
|
436
|
+
|
|
437
|
+
**A parameter can be retired.** There is no delete in the contract (`exists` is only ever set true), but
|
|
438
|
+
a `lockAfter` in the past makes every later write revert `ParamLockExpired`, permanently. `abx
|
|
439
|
+
retire-param <addr> <key>` does exactly that, reading the current schema and changing _only_ the lock so
|
|
440
|
+
type/auth/bounds/options carry forward untouched. It does not remove the key and does not erase a stored
|
|
441
|
+
value — a value written under a `TokenOwner`/`Address` leg came from a collector, and the artist
|
|
442
|
+
deliberately cannot delete it.
|
|
443
|
+
|
|
444
|
+
**An `Address` auth leg is now expressible.** `--schema` previously rejected every Address-bearing leg
|
|
445
|
+
with "set that schema post-deploy via the contract" — advice pointing at a command that did not exist.
|
|
446
|
+
The auth token now names its holder inline (`board:Bytes:Address(0xabc…)`), and the error for a bare
|
|
447
|
+
`Address` says what the leg is for: a **contract** may hold it, which is how open and multi-party
|
|
448
|
+
participation is built today. `authAddress` and `lockAfter` were also hardcoded to zero at the
|
|
449
|
+
deploy-time call site, so neither was reachable there either; both now flow through `--schema`.
|
|
450
|
+
|
|
451
|
+
`--schema` gains an optional 4th field, `lock=<when>` (ISO date, unix seconds, or `now`), sharing the
|
|
452
|
+
Timestamp grammar the bounds already use. A 4th field that is not `lock=` now reports the spec-shape
|
|
453
|
+
error instead of a mangled "malformed type", which is what a `:` inside a `Select` label used to produce.
|
|
454
|
+
|
|
455
|
+
New in the SDK: `prepareSetParamSchema`, `prepareRetireParam`, `readParamSchema`, `OnChainParamSchema`.
|
|
456
|
+
|
|
457
|
+
(feedback 4a0c213a, 5d530681, 381bdcbe)
|
|
458
|
+
|
|
459
|
+
> [Superseded 2026-08-03: params now enumerate **on-chain** (renderer spec v4, `abx_params`) and
|
|
460
|
+
>
|
|
461
|
+
> > `params.keys` is retired — the contract maintains its own key list, so nothing off-chain has to keep
|
|
462
|
+
> > it in step and `abx state` reads the chain directly. See the on-chain param enumeration entry.]
|
|
463
|
+
|
|
464
|
+
`set-schema` also keeps **`params.keys` in step, in the same transaction**. On the on-chain URI lane
|
|
465
|
+
the canonical generator builds tokenData from that CSV, so a key that is governed but not listed is
|
|
466
|
+
silently omitted from every render — the schema exists, a collector can set it, and the art never sees
|
|
467
|
+
the value. `deploy-code` composes the list from `--schema` for exactly this reason; without the
|
|
468
|
+
companion write, a schema added later would have quietly half-worked. Projects not on that lane (where
|
|
469
|
+
`params.keys` is unset) get no extra write.
|
|
470
|
+
|
|
471
|
+
> [Superseded 2026-08-03: params now enumerate **on-chain** (renderer spec v4, `abx_params`) and
|
|
472
|
+
>
|
|
473
|
+
> > `params.keys` is retired — the contract maintains its own key list, so nothing off-chain has to keep
|
|
474
|
+
> > it in step and `abx state` reads the chain directly. See the on-chain param enumeration entry.]
|
|
475
|
+
|
|
476
|
+
And `abx state` now prints the governed PostParam surface — each key's type, auth, bounds/options, an
|
|
477
|
+
upcoming lock date, and a `retired` marker for one whose lock has passed. There is no on-chain
|
|
478
|
+
enumeration of schema keys, so it reads the project's own `params.keys` list, which is also what the
|
|
479
|
+
generator reads; anything missing from it is invisible to renders anyway. It also names keys listed
|
|
480
|
+
there with no schema. This is what makes `set-schema`'s upsert safe to use: you can see a key's current
|
|
481
|
+
shape before overwriting it.
|
|
482
|
+
|
|
483
|
+
- 1158420: `abx deploy` (1/1) can finally do "image off-chain, JSON on-chain, no server" — the pattern the docs already recommended.
|
|
484
|
+
|
|
485
|
+
The decisions table calls this pattern 2 and presents it as the sweet spot for static art. It worked
|
|
486
|
+
on `deploy-series`. On the 1/1 command it silently did not: `--onchain-uri` inlines the image only
|
|
487
|
+
when it is an SVG, and a raster fell through to keccak256 custody with no URL wired anywhere, so the
|
|
488
|
+
on-chain renderer held a hash it could not serve and `tokenURI` returned a **placeholder — forever**.
|
|
489
|
+
Adding `--backend arweave` changed nothing, which was the cruel part: it looked exactly like the
|
|
490
|
+
documented recipe. A cold agent asked for "no server, still there in ten years", followed the docs,
|
|
491
|
+
and would have shipped a permanently broken token.
|
|
492
|
+
|
|
493
|
+
`deploy` now takes the same route the Series takes. When `--onchain-uri` meets a non-inlinable image
|
|
494
|
+
and a backend that can serve a public URL (`arweave` · `ipfs` · `cloud`), the file is uploaded as a
|
|
495
|
+
one-entry directory — `putDirectory`, the identical call `deploy-series` makes, so both commands
|
|
496
|
+
produce the same URL shape from one code path — and its URL is baked on-chain as the image field. The
|
|
497
|
+
bytes are still stored under their content hash as well, so `abx verify` keeps working. A backend that
|
|
498
|
+
can only serve from this machine (`fs`) still falls through to custody, and still warns.
|
|
499
|
+
|
|
500
|
+
The readouts learned that this is a three-way distinction, not a binary, because "no server" and
|
|
501
|
+
"on-chain" are different promises and a creator buying permanence is choosing between them:
|
|
502
|
+
|
|
503
|
+
- image genuinely on-chain (`--onchain-image`, or an inlined SVG) → **"Done — fully on-chain."**
|
|
504
|
+
- image at a durable URL the on-chain JSON points at → **"Done — metadata on-chain, image on ipfs."**
|
|
505
|
+
plus a line naming whose permanence it actually is (Arweave paid-once-forever; IPFS while pinned).
|
|
506
|
+
- neither → the placeholder warning, before the spend, naming both routes that would fix it.
|
|
507
|
+
|
|
508
|
+
Verified end to end on Base Sepolia (`0xdE5aCD35b74B6d002781De51217590a9c5B53EDC`): `tokenURI(0)` read
|
|
509
|
+
straight from chain with `cast` — no `abx`, no server — returns an IPFS gateway URL that serves HTTP
|
|
510
|
+
200 with bytes identical to the source file, and reports itself honestly in `abx_provenance` as
|
|
511
|
+
`source: url · onChain: false`.
|
|
512
|
+
|
|
513
|
+
Closes B17. Found by the 2026-08-03 parallel agent sweep.
|
|
514
|
+
|
|
515
|
+
### Patch Changes
|
|
516
|
+
|
|
517
|
+
- 1158420: `abx inspect` no longer reports dependencies, params, or runtime problems that aren't in the code.
|
|
518
|
+
|
|
519
|
+
Every detector in the analyzer was a regex over the raw file, so prose counted as code. One
|
|
520
|
+
tokenizer pass now gives the detectors a comments-stripped, string-blanked view:
|
|
521
|
+
|
|
522
|
+
- **A comment or string mentioning a library is no longer a dependency.** A dependency-free
|
|
523
|
+
vanilla-canvas sketch whose header read `// no p5` was reported as `libraries: p5`, and the lane
|
|
524
|
+
recommendation then said `--dep p5@<version>` — advice an agent adopts verbatim, which bloats the
|
|
525
|
+
stored on-chain document and can push a drop to a chain whose dependency registry it needs.
|
|
526
|
+
Real `p5`/`THREE`/`Tone` usage is still detected (pinned by tests).
|
|
527
|
+
- **Reserved coordinates are never listed as PostParams.** `tokenId`, `chainId`, and
|
|
528
|
+
`contractAddress` (like `seed` before them) are injected by the runtime and cannot be declared,
|
|
529
|
+
but they landed in the "declare EACH at deploy or it's silently dropped" warning with
|
|
530
|
+
`--schema tokenId:<Type>:<Auth>` advice that must not be followed.
|
|
531
|
+
- **A dotted param key read through an alias is detected.** `const d = abx.tokenData;` then
|
|
532
|
+
`d['collapse.index']` was invisible, producing a false "dropped at render" warning on a correct
|
|
533
|
+
program — and ABX's own output-naming convention is dotted (`effect.render.image`), so the
|
|
534
|
+
documented idiom tripped the analyzer.
|
|
535
|
+
|
|
536
|
+
Reported in the 2026-08-03 tester batch (feedback 3b66e443, f69e15d6, 8184f7dd, 6d32f874).
|
|
537
|
+
|
|
538
|
+
- 1158420: `abx deploy --onchain-uri` no longer claims "fully on-chain" over a token whose image isn't.
|
|
539
|
+
|
|
540
|
+
`--onchain-uri` puts the metadata JSON on-chain. It inlines the _image_ only when the image is an
|
|
541
|
+
SVG; a raster falls through to keccak256 custody, and the on-chain renderer then serves a
|
|
542
|
+
**placeholder** image. The success banner printed "Done — fully on-chain … no server or hosting
|
|
543
|
+
needed" for that configuration, so a creator would believe they had permanence they did not have —
|
|
544
|
+
and only discover it later via `abx tokenuri` (`source: "fallback"`, `onChain: false`).
|
|
545
|
+
|
|
546
|
+
Two changes, both computed from the actual file rather than the flag:
|
|
547
|
+
|
|
548
|
+
- The dry run (and the real run) now warn **before the spend** that the image is a keccak256 anchor
|
|
549
|
+
and `tokenURI` will serve a placeholder, pointing at `--onchain-image --compress fastlz` or a
|
|
550
|
+
served base URL. The code lane's dry run already warned about this case; the 1/1 lane shipped it
|
|
551
|
+
silently.
|
|
552
|
+
- The success banner says "Done — metadata on-chain" and names the image's real status. An SVG (or
|
|
553
|
+
`--onchain-image`) still gets the unqualified "fully on-chain" banner, because that one is true.
|
|
554
|
+
|
|
555
|
+
Reported in the 2026-08-03 tester batch (feedback a8921f18).
|
|
556
|
+
|
|
557
|
+
- 1158420: Fix `deploy-code` reverting `DeploymentFailed()` — the setup transaction was sent with a gas limit estimated against a contract that did not exist yet.
|
|
558
|
+
|
|
559
|
+
Every `deploy-code` attempt in a reporter's Base Sepolia session reverted with Solady's
|
|
560
|
+
`DeploymentFailed()` (`0x30116425`), in both the on-chain and hosted-resolver lanes, with a minimal
|
|
561
|
+
case of storing a single 3,563-byte script chunk. It was not a defect in the chunk path: the two
|
|
562
|
+
transactions simply **ran out of gas**.
|
|
563
|
+
|
|
564
|
+
```
|
|
565
|
+
0xcad74d07… gasLimit 201,616 gasUsed 198,870 (98.6%)
|
|
566
|
+
0xf4350724… gasLimit 169,301 gasUsed 166,810 (98.5%)
|
|
567
|
+
```
|
|
568
|
+
|
|
569
|
+
A code project deploys in two transactions: create the clone, then one setup `multicall`. The second
|
|
570
|
+
targets the contract the first just created — and `eth_estimateGas` for that call, taken while the
|
|
571
|
+
answering node has not yet seen the deploy block, returns the **calldata cost alone**. Replaying both
|
|
572
|
+
payloads against a codeless address reproduces the sent limits _to the gas_ (201,616 and 169,301);
|
|
573
|
+
against the real contract the same calls need 941,331. A setup multicall's cost is dominated by
|
|
574
|
+
CREATE code deposit (~200 gas per stored byte), so the underfunded CREATE inside `SSTORE2.write`
|
|
575
|
+
returned 0 and reverted. The 1/1 lane was unaffected because its setup fits inside a calldata-sized
|
|
576
|
+
budget.
|
|
577
|
+
|
|
578
|
+
This is the same read-after-write lag the deploy loop already pins the **nonce** against, one field
|
|
579
|
+
over. The fix has two halves, and deliberately does not include a third:
|
|
580
|
+
|
|
581
|
+
- **Every leg after the first waits for the target's code to be visible** to the client doing the
|
|
582
|
+
estimating, so a lagging node cannot produce a meaningless estimate in the first place. This is the
|
|
583
|
+
actual repair.
|
|
584
|
+
- **An impossible estimate is detected and refused, not replaced.** `PreparedTx` gained an optional
|
|
585
|
+
`gasFloor` carrying only the _provable_ part of a payload's cost — EVM code deposit at exactly 200
|
|
586
|
+
gas per stored byte. An estimate below that is not "low", it is proof the node is on stale state, so
|
|
587
|
+
the sender retries and then errors out with what it saw.
|
|
588
|
+
- **What we did NOT do: substitute a computed gas limit.** Only the deposit is derivable; the same
|
|
589
|
+
setup multicall also carries schema writes, dependency legs, URI legs and mints whose cost cannot be
|
|
590
|
+
known without simulating them. A "probably enough" constant is tuned to whoever's example was in
|
|
591
|
+
front of its author — it would have covered the reported single-chunk case and then under-funded a
|
|
592
|
+
three-schema deploy by ~200k, reproducing the identical `DeploymentFailed()` with a fresh mystery
|
|
593
|
+
attached. Refusing to send is strictly better than sending a transaction we can prove is
|
|
594
|
+
under-funded, which would burn the gas and orphan the contract.
|
|
595
|
+
|
|
596
|
+
All three signing lanes carry this, not just the hot one: the env-key lane pins the limit before
|
|
597
|
+
`sendTransaction`, the wallet lane waits for code and hands the browser an explicit `gas` (a wallet
|
|
598
|
+
estimates against its own RPC, which we don't control and which lags the same way), and the cold lane
|
|
599
|
+
prints `gasMustExceed` — labelled a floor, not a limit — plus a note telling an external signer to
|
|
600
|
+
re-estimate rather than send if their own number comes back below it. The rule lives in one place
|
|
601
|
+
(`packages/cli/src/gas.ts`) so the lanes cannot drift apart on it.
|
|
602
|
+
|
|
603
|
+
Reported in the 2026-08-03 tester batch (feedback 156ea0fb, 172111ae), root-caused from the full
|
|
604
|
+
transaction hashes supplied in the follow-up addendum.
|
|
605
|
+
|
|
606
|
+
- 1158420: `abx preview` stops fabricating param values, and `--shoot` stops blaming the program for its own timeouts.
|
|
607
|
+
|
|
608
|
+
- **An unset PostParam is now absent from the preview's `tokenData`, exactly as on-chain.** Preview
|
|
609
|
+
injected a per-type default for every declared key — `Select` got its FIRST option — so an
|
|
610
|
+
optional `theme:Select[Newsprint|…]` override rendered every frame as `Newsprint` with nobody
|
|
611
|
+
having set anything: nine seed-distinct pieces collapsed into one palette, while the deployed drop
|
|
612
|
+
(where the key is genuinely absent) would take the program's other branch entirely. Production
|
|
613
|
+
(`buildTokenData`) only injects params that actually have a value; preview now matches it, so the
|
|
614
|
+
program's own `?? fallback` runs in both places. The studio's `Select` control gained an explicit
|
|
615
|
+
"— unset (program fallback) —" default position, so unset is now expressible rather than
|
|
616
|
+
indistinguishable from the first option.
|
|
617
|
+
- **`--shoot` distinguishes "the program reported no traits" from "we stopped waiting."** A wait
|
|
618
|
+
that expired was swallowed, so a loaded machine turned a correct, trait-reporting program into
|
|
619
|
+
"NO frame reported traits" — inverting the one line agents are told to trust and costing a full
|
|
620
|
+
diagnostic cycle. Timed-out frames now report `timed out — traits unknown` and a warning that
|
|
621
|
+
names it a measurement failure and suggests `--timeout-ms`; the silent-killer alarm only fires
|
|
622
|
+
when the program really did report nothing.
|
|
623
|
+
- **A missing Chromium build names the install command for the Playwright that actually loaded**
|
|
624
|
+
(`node <resolved>/cli.js install chromium`). The stock hint (`npx playwright install`) can resolve
|
|
625
|
+
a different Playwright version than the one that just launched, so you download a browser
|
|
626
|
+
revision it won't use, get the identical error, and run the same command again.
|
|
627
|
+
|
|
628
|
+
Reported in the 2026-08-03 tester batch (feedback f843c952, 994f1d67, 534835d9).
|
|
629
|
+
|
|
630
|
+
- 1158420: Teach the agent skill how to handle audio and time-based work.
|
|
631
|
+
|
|
632
|
+
A "can ABX host a music tool?" session found zero mentions of audio, music, or sound anywhere in the
|
|
633
|
+
skill. The protocol supports it — `animation_url` is an HTML document, so Web Audio works, and
|
|
634
|
+
`attach` handles `.wav`/`.mp3`/`.mid` — but five judgments a sound piece needs were unauthored, so an
|
|
635
|
+
agent had to guess or decline: browser autoplay policy (a marketplace iframe cannot start audio
|
|
636
|
+
without a gesture), what the thumbnail _is_ for non-visual work, `abx.done()` semantics for a
|
|
637
|
+
duration-based piece (settle the visual, don't wait out playback), the dependency lane for audio
|
|
638
|
+
libraries (`tone` needs a registry entry ⇒ Sepolia, like `p5`), and the fact that there is no
|
|
639
|
+
`render/audio` output declaration to reach for.
|
|
640
|
+
|
|
641
|
+
Reported in the 2026-08-03 tester batch (feedback fd6109db).
|
|
642
|
+
|
|
643
|
+
- 1158420: `abx skill install` can no longer overwrite a newer skill with an older one, or delete the skill it is installing.
|
|
644
|
+
|
|
645
|
+
Two ways the same command could destroy the thing it exists to install, both hit while working in the
|
|
646
|
+
abx repo itself:
|
|
647
|
+
|
|
648
|
+
- **A stale prepack bundle shadowed the canonical skill.** `<pkg>/skill` is gitignored build output
|
|
649
|
+
written at `prepack`; the canonical copy lives at `.claude/skills/abx-self-host`. Resolution
|
|
650
|
+
preferred the bundle unconditionally, so a leftover `skill/` from an old `npm pack` was installed
|
|
651
|
+
**over** the canonical skill — silently replacing v0.1.0-alpha.12 with v0.1.0-alpha.4, after which
|
|
652
|
+
the CLI's own drift check reported the stale version as if the user had put it there. When running
|
|
653
|
+
from source (the repo working tree) the canonical copy now wins; the published layout, which has no
|
|
654
|
+
repo and no canonical copy, still uses the bundle.
|
|
655
|
+
- **Installing onto the source deleted it.** `installSkillTo` removes the destination before copying,
|
|
656
|
+
so when destination _was_ the source (a cwd-relative install inside the repo) it deleted the
|
|
657
|
+
canonical skill and then had nothing to copy from. Same-path installs are now a no-op that reports
|
|
658
|
+
`already the canonical copy — left as is`.
|
|
659
|
+
|
|
660
|
+
- 1158420: Fixes from a parallel cold-agent sweep: a chain typo no longer crashes every command, and `inspect` stops over-promising on hand-written PRNGs.
|
|
661
|
+
|
|
662
|
+
**An unknown `ABX_CHAIN` printed a raw Node stack trace — from every command.** Chain-derived values
|
|
663
|
+
were resolved at module scope, in `token-api` (which the CLI imports) and in the CLI itself, so the
|
|
664
|
+
throw happened during module evaluation, before `main()` existed to catch it. `ABX_CHAIN=mainnet abx
|
|
665
|
+
doctor` dumped an internal source path and exited 1 — including from the one command whose job is to
|
|
666
|
+
tell you what is wrong with your environment. Those resolutions are lazy now, and the CLI validates
|
|
667
|
+
the variable up front with an answer rather than a crash: unknown values list the shipped chains, and
|
|
668
|
+
a mainnet-shaped value says plainly that ABX is testnet-only today.
|
|
669
|
+
|
|
670
|
+
**`abx inspect` reported "(no PRNG)" for a hand-written seeded generator — with the _stronger_
|
|
671
|
+
reproducibility verdict attached.** The `seeded` check only recognized p5's `randomSeed(`, so a
|
|
672
|
+
vanilla LCG or xorshift matched no branch and fell through to "traits look derived from the
|
|
673
|
+
seed/params directly". That is the common case, not an edge one — the skill's own canonical
|
|
674
|
+
dependency-free example hand-rolls an LCG, and all three sketches written by agents in the sweep hit
|
|
675
|
+
it. A hand-rolled generator now gets the `careful` verdict and is told the truth: deterministic and
|
|
676
|
+
reproducible on-chain, but only by porting that exact generator and call order into Solidity.
|
|
677
|
+
|
|
678
|
+
Also: `--yes` is now documented in `deploy-code --help` (its own placeholder-identity refusal already
|
|
679
|
+
told you to pass it), and the `--onchain-uri` raster warning now names the two routes that actually
|
|
680
|
+
deliver a no-server image instead of only one.
|
|
681
|
+
|
|
682
|
+
Found by the 2026-08-03 parallel sweep (8 cold Sonnet/Haiku agents, isolated sandboxes).
|
|
683
|
+
|
|
684
|
+
- Updated dependencies [1158420]
|
|
685
|
+
- Updated dependencies [1158420]
|
|
686
|
+
- Updated dependencies [1158420]
|
|
687
|
+
- @artblocks/abx-sdk@0.1.0-alpha.6
|
|
688
|
+
- @artblocks/abx-token-api@0.1.0-alpha.9
|
|
689
|
+
- @artblocks/abx-indexer@0.1.0-alpha.7
|
|
690
|
+
- @artblocks/abx-storage@0.1.0-alpha.6
|
|
691
|
+
|
|
692
|
+
## 0.1.0-alpha.12
|
|
693
|
+
|
|
694
|
+
### Minor Changes
|
|
695
|
+
|
|
696
|
+
- feba8c2: A resolver is no longer an object store: effect outputs split into **bound** and **referenced**
|
|
697
|
+
(`specs/protocol/effects.md → Bound vs referenced`), and the artifact registry enforces the split.
|
|
698
|
+
|
|
699
|
+
An output is **bound** iff a binding stitches its _content_ into the metadata JSON (today exactly
|
|
700
|
+
`render/traits` → `attributes`); everything else is **referenced** — the projection carries its URL,
|
|
701
|
+
or it only appears in the `artifacts` manifest. That one distinction decides who holds the bytes, and
|
|
702
|
+
it is now the wire rule rather than a runner constant.
|
|
703
|
+
|
|
704
|
+
- **`POST /v1/effect-artifacts` derives the mode from the binding, and refuses both mismatches.**
|
|
705
|
+
Bytes for a referenced output → `400` (the resolver redirects either way, so the bytes buy no
|
|
706
|
+
capability and cost it storage, retention and egress). A locator for a bound output → `400` (its
|
|
707
|
+
content is assembled into `tokenURI`; a pointer there used to be recorded and then silently never
|
|
708
|
+
stitch — a wrong answer served confidently). Bound content is capped at **64 KB**, and a locator
|
|
709
|
+
that only the producer could resolve (loopback/private host, presigned expiring URL) is rejected.
|
|
710
|
+
The resolver never fetches a locator while handling the write, and serves registered locators by
|
|
711
|
+
`302` — never by proxying.
|
|
712
|
+
- **Bound content moved out of byte custody** into the artifact row (`effect_artifacts.bytes`). Two
|
|
713
|
+
distinct rules, deliberately not one: a node **MUST** serve and stitch bound content only at the
|
|
714
|
+
token's current settled `inputsHash`, and it **MAY** drop superseded content whenever it likes
|
|
715
|
+
(nothing may read it, and it is re-creatable). The reference drops eagerly, on each bound
|
|
716
|
+
registration, so it holds at most `64 KB × minted × bound outputs` — but retention is a service
|
|
717
|
+
policy, not an obligation. Either way "conforming means holding a bounded amount of JSON in the
|
|
718
|
+
database you already run" is now literally true: a resolver in the publish topology needs no object
|
|
719
|
+
storage at all.
|
|
720
|
+
- **`abx-effects-publish/v1` is gone** (not deprecated): the two routes ride `abx-control-plane/v1`.
|
|
721
|
+
Once referenced output is locator-only, accepting a registration is a database insert, so the
|
|
722
|
+
capability flag described a distinction that no longer exists. A service that won't take a caller's
|
|
723
|
+
artifacts refuses on the credential (`403`) — interfaces describe wire grammar, tokens describe
|
|
724
|
+
permission. The interface ids are also explicitly **all-or-nothing**, and the conformance fixture
|
|
725
|
+
now checks that every route a declared interface names actually answers.
|
|
726
|
+
- **The runner declares bound outputs** (`EffectOutputDecl.bound`), refuses to start when it has a
|
|
727
|
+
publish token but a backend that can't name a locator, preflights the descriptor + credential
|
|
728
|
+
before spending a render, and **latches** on a permanent (4xx) publish failure instead of
|
|
729
|
+
re-rendering every sweep forever. Skips now re-register rows, so a transient publish failure heals
|
|
730
|
+
without a re-render.
|
|
731
|
+
- **The CLI refuses the impossible combination up front**: `abx render --remote`, `abx effects`
|
|
732
|
+
against a remote resolver, and `abx deploy-effects` all require a backend that can name a reachable
|
|
733
|
+
URL — `cloud` (S3/R2 + public base), `ipfs`, or `arweave`, named as **peers**. Derived output is
|
|
734
|
+
re-creatable, so the protocol has no preference among schemes: a chosen `https://` gateway or
|
|
735
|
+
bucket URL is exactly as legitimate as `ipfs://`/`ar://`, and reachability — not durability — is
|
|
736
|
+
the requirement. Rendering **co-located** with the resolver remains fully supported on any backend,
|
|
737
|
+
including `fs`.
|
|
738
|
+
|
|
739
|
+
Breaking for producers that relied on pushing media bytes to a resolver: publish a locator instead,
|
|
740
|
+
or co-locate. Breaking for clients that read `abx-effects-publish/v1` from a descriptor.
|
|
741
|
+
|
|
742
|
+
### Patch Changes
|
|
743
|
+
|
|
744
|
+
- Updated dependencies [feba8c2]
|
|
745
|
+
- @artblocks/abx-sdk@0.1.0-alpha.5
|
|
746
|
+
- @artblocks/abx-token-api@0.1.0-alpha.8
|
|
747
|
+
- @artblocks/abx-indexer@0.1.0-alpha.6
|
|
748
|
+
- @artblocks/abx-storage@0.1.0-alpha.5
|
|
749
|
+
|
|
750
|
+
## 0.1.0-alpha.11
|
|
751
|
+
|
|
752
|
+
### Minor Changes
|
|
753
|
+
|
|
754
|
+
- 67b686b: `abx contracturi`, and the read plane stops answering a bare 404 to three different problems.
|
|
755
|
+
|
|
756
|
+
Both halves come from one real failure: an agent driving a hosted resolver wanted collection
|
|
757
|
+
metadata, pattern-matched off `/t/{chainId}/{address}/{id}`, dropped the token id, got a bare `404`,
|
|
758
|
+
and reported the service as broken. The documented route (`/c/{chainId}/{address}`) was right there —
|
|
759
|
+
but there was also no command to just _ask_, and the 404 gave it nothing to correct.
|
|
760
|
+
|
|
761
|
+
- **New `abx contracturi <address>`** — the collection-level counterpart of `tokenuri`. Reads
|
|
762
|
+
`contractURI()` (ERC-7572) from the contract, **follows it**, and decodes: a `data:` URI inline
|
|
763
|
+
(the on-chain lane), an `https://` URL by fetching it (the off-chain lane). A contract commits its
|
|
764
|
+
own metadata base on-chain (`contractURIBase`), so the chain — not a doc, not a service
|
|
765
|
+
descriptor — is the authoritative answer to where a project's metadata lives. Nobody needs to
|
|
766
|
+
hand-build a resolver URL. When the fetch fails, the message says so plainly: the URL came from
|
|
767
|
+
the chain, so a bad status is about the _service_ (unregistered project · wrong chain · down),
|
|
768
|
+
never a mistyped path.
|
|
769
|
+
- **Read-plane responses now carry a machine `code`**, so the three causes of "no metadata came
|
|
770
|
+
back" are distinguishable — they were one indistinguishable `{"error": "…"}` `404`:
|
|
771
|
+
- `400 invalid_request` — a real route, wrong shape. Names the correct template, and carries
|
|
772
|
+
`didYouMean` when the fix is obvious (a `/t/…` missing its token id → `/c/{chainId}/{address}`).
|
|
773
|
+
- `404 unknown_route` — this node serves nothing at that path; the body lists what it does serve.
|
|
774
|
+
- `404 not_registered` — the path and chain were fine; this node doesn't index that contract.
|
|
775
|
+
- `400 unsupported_chain` — wrong chain, plus the `chains` this node does serve. Was a bare `404`;
|
|
776
|
+
now matches what the control plane already answered for the same condition.
|
|
777
|
+
- `ServiceErrorCode` gains `unknown_route`. The spec's Errors section now covers the read plane too,
|
|
778
|
+
with a **MUST** on distinguishing the three misses — and an explicit **MUST NOT** on treating
|
|
779
|
+
route templates as per-node discoverable configuration. The route grammar is fixed by the
|
|
780
|
+
`abx-token-api/v1` interface; these responses are diagnostics, not a discovery mechanism.
|
|
781
|
+
- **The conformance fixture checks all of it** (`pnpm conformance <base-url>`), so any provider can
|
|
782
|
+
self-verify in one command. Also fixed: the documented `pnpm conformance -- <base-url>` form
|
|
783
|
+
parsed `--` as a flag and swallowed the base URL, printing usage instead of running.
|
|
784
|
+
|
|
785
|
+
### Patch Changes
|
|
786
|
+
|
|
787
|
+
- Updated dependencies [67b686b]
|
|
788
|
+
- @artblocks/abx-sdk@0.1.0-alpha.4
|
|
789
|
+
- @artblocks/abx-token-api@0.1.0-alpha.7
|
|
790
|
+
- @artblocks/abx-indexer@0.1.0-alpha.5
|
|
791
|
+
- @artblocks/abx-storage@0.1.0-alpha.4
|
|
792
|
+
|
|
793
|
+
## 0.1.0-alpha.10
|
|
794
|
+
|
|
795
|
+
### Minor Changes
|
|
796
|
+
|
|
797
|
+
- a72723d: A standard indexing lifecycle, and registration that no longer blocks on a slow chain RPC
|
|
798
|
+
(specs/self-host-toolkit/remote-services.md → The indexing lifecycle).
|
|
799
|
+
|
|
800
|
+
- **Fixed: a slow register triggered a retry storm.** The SDK's per-attempt timeout (30s) plus its
|
|
801
|
+
retry ladder meant a cold reconstruct that outran one request was **re-POSTed up to four times**,
|
|
802
|
+
each starting another full replay against the RPC that was already too slow to answer — and the
|
|
803
|
+
caller then saw "nothing responded" even though the registration was durable and indexing was
|
|
804
|
+
underway. A timed-out register now asks whether it landed (a status read) instead of re-POSTing, and
|
|
805
|
+
the resolver coalesces concurrent catch-ups for one project into a single run.
|
|
806
|
+
- **`POST /v1/projects` answers in two conformant shapes, discriminated by HTTP status:** `200` with
|
|
807
|
+
the completed summary, or `202` + `{accepted, project: {status}}` when catch-up is deferred. The
|
|
808
|
+
registration is normatively **durable before catch-up** and visible on the list immediately, so a
|
|
809
|
+
flaky RPC makes for a slower backfill rather than a lost add. No `?wait=`/`Prefer:` negotiation — the
|
|
810
|
+
status code is the discriminator, and clients handle both. The reference resolver answers _by
|
|
811
|
+
deadline_ (`ABX_REGISTER_DEADLINE_MS`, default 8s): the common case (a fresh deploy) stays
|
|
812
|
+
synchronous with real counts; only the pathological case defers.
|
|
813
|
+
- **Closed lifecycle enum + error classes, on the status and list routes:**
|
|
814
|
+
`queued | backfilling | live | stale | failed`, plus credential-free
|
|
815
|
+
`error.class ∈ {rpc_unavailable, rpc_rate_limited, not_abx_contract, internal}` (fixed per-class
|
|
816
|
+
messages, never a scrubbed upstream string). Status gains top-level `headBlock` (so lag / % complete
|
|
817
|
+
is computable without knowing a service has a watcher) and `attempts`; the list carries `status` +
|
|
818
|
+
the error class, so a client renders "3 live, 1 backfilling, 1 failed (rpc_rate_limited)" in one
|
|
819
|
+
request. SDK: `IndexStatus`, `IndexErrorClass`, `isAccepted()`, `indexProgress()`,
|
|
820
|
+
`classifyIndexError()`, and `AbxServiceClient.awaitIndexed()` — one wait loop for the CLI, the
|
|
821
|
+
effects runner, and any hosted agent.
|
|
822
|
+
- **The same five words on your own node.** `abx status [address] [--remote [name|url]] [--watch]`:
|
|
823
|
+
bare is the node summary (now with each project's state), an address gives lifecycle + scan floor +
|
|
824
|
+
blocks-indexed-vs-head + cause, and `--remote` asks a service. (`status` = who is serving it and how
|
|
825
|
+
fresh; `state` = what the chain says. Both `--help` texts now say so.)
|
|
826
|
+
- **New observability the self-hosted node never had:** the chain watcher marks projects `stale` when
|
|
827
|
+
it falls far behind head or its ticks keep failing (previously visible only in the node's log),
|
|
828
|
+
re-queues a backfill interrupted by a restart (previously left registered-but-empty until a manual
|
|
829
|
+
`abx index`), and retries a `failed` catch-up on exponential backoff instead of hammering a
|
|
830
|
+
rate-limited RPC every tick. Lifecycle rows live in their own table: they survive a projection wipe
|
|
831
|
+
and are never clobbered by a re-add.
|
|
832
|
+
- **CLI:** `abx add|index --remote` prints `registered — backfilling…`, polls to `live`, then prints
|
|
833
|
+
the same summary a synchronous service would have given; `--no-wait` returns at the 202 and names
|
|
834
|
+
the command to check later. A post-op nudge (`ownerops`) never blocks on someone else's backfill.
|
|
835
|
+
A caught-up project with **0 events** now warns instead of printing ✓ (a real ABX clone always emits
|
|
836
|
+
a spine, so zero means wrong chain/floor or an RPC that didn't serve the logs).
|
|
837
|
+
- **Conformance fixture** accepts either register shape, asserts durable-before-catch-up, lifecycle
|
|
838
|
+
membership, `headBlock`, that a deferred catch-up actually reaches `live`, and that no error message
|
|
839
|
+
carries a URL.
|
|
840
|
+
- Fixed `scripts/mock-remote-service.mts`, which imported the token API by a path that resolved
|
|
841
|
+
against `scripts/` and could silently fall back to a _published_ build outside the repo — the
|
|
842
|
+
fixture was testing the last release instead of the working tree. The fixture also re-points
|
|
843
|
+
scenarios by their fixture header now, so a new one can't keep a dead contract address.
|
|
844
|
+
|
|
845
|
+
Found by a cold-agent sweep over the above (10 parallel clean rooms, haiku + sonnet) and fixed here:
|
|
846
|
+
|
|
847
|
+
- **`abx status --remote <name>` with no address** parsed the flag itself as the address and sent it
|
|
848
|
+
as a URL path segment.
|
|
849
|
+
- **A register whose catch-up already failed** was announced as "registered — failed (…is catching
|
|
850
|
+
up…)", and with `--no-wait` it exited 0 and then claimed the provider "now serves" the project. A
|
|
851
|
+
known failure is now an error in both lanes — there is nothing left to wait for.
|
|
852
|
+
- **A `failed` status said what broke but not whose problem it was.** Both the failure error and
|
|
853
|
+
`abx status` now carry a per-class action line ("the SERVICE can't reach its chain RPC — not your
|
|
854
|
+
key, address, or chain…"), plus a `follow` line naming `--watch`, so a red word isn't a dead end.
|
|
855
|
+
- **A `live` project showed a misleading completion percentage.** `toBlock` only advances when a
|
|
856
|
+
project has _events_, so a fully current project on a busy chain read as `2/202 (0%)`.
|
|
857
|
+
`indexProgress()` now returns a ratio only while `backfilling`; `live` reads "caught up", `stale`
|
|
858
|
+
reads "not tracking head right now".
|
|
859
|
+
- **`--remote-token` was misattributed on a 401** — the error blamed `ABX_REMOTE_<NAME>_TOKEN` even
|
|
860
|
+
when the caller passed an override, making the override look ignored at exactly the moment someone
|
|
861
|
+
is testing a replacement key.
|
|
862
|
+
- **`not_registered` on a read** (status/reindex) now names the register command instead of echoing a
|
|
863
|
+
404, and a 5xx carrying a failure `class` becomes a wait-vs-broken error.
|
|
864
|
+
- **`abx verify`'s summary** read `✓ 0/1 up to date` for a project with no off-chain renders at all —
|
|
865
|
+
"zero of one succeeded" to two independent reviewers. It now says "nothing to render for this
|
|
866
|
+
project", and otherwise leads with polarity ("N of M token(s) current").
|
|
867
|
+
- **`abx doctor` now reports named remotes** and flags a credential stored under a name the CLI does
|
|
868
|
+
not read (`ABX_REMOTE_<NAME>_KEY`). That fault presents as "it acts like I never gave it a key" and
|
|
869
|
+
previously only surfaced from `abx remote <name>` — which a creator reaches _after_ doctor.
|
|
870
|
+
- **Skill: the `npx --no-install abx version` probe was documented as failing cleanly.** It doesn't —
|
|
871
|
+
npm will run any `abx` binary already in the npx cache, which in a real sweep reported a months-old
|
|
872
|
+
build as the project's CLI (and if a plain `npx abx` ever ran on that machine, the bare name is a
|
|
873
|
+
squatted package). The skill now probes `./node_modules/.bin/abx` directly.
|
|
874
|
+
- Also documented: how a multi-word provider name folds into `ABX_REMOTE_<NAME>_*`, and what
|
|
875
|
+
`watching: no` means on a status readout.
|
|
876
|
+
|
|
877
|
+
A second sweep round over those fixes caught three more, including one the first round's fix created:
|
|
878
|
+
|
|
879
|
+
- **`abx verify --remote` never checked byte integrity at all** — both of its lanes only ask "is there
|
|
880
|
+
a current render / is this a placeholder", and a green ✓ from that was standing in for "the served
|
|
881
|
+
bytes match the on-chain commitment". A reviewer hit the worst version of this: `--remote` (the form
|
|
882
|
+
the skill tells you to use for a hosted project) reported ✓ on a token whose bytes genuinely did NOT
|
|
883
|
+
hash-match, while bare `abx verify` on the same project reported `✗ keccak256 MISMATCH`. It now calls
|
|
884
|
+
the service's own purpose-built `GET /api/project/:addr/verify` (which holds both the bytes and the
|
|
885
|
+
chain) and reports that verdict separately from the render summary — and when it _can't_ run that
|
|
886
|
+
check (no credential, older node) it says "byte integrity NOT checked" instead of leaving a ✓ to
|
|
887
|
+
imply it passed. The remedy names both real causes (an unbridged durable locator vs. bytes that only
|
|
888
|
+
exist on the creator's machine, which a hosted resolver can never serve).
|
|
889
|
+
- **`abx verify` exited 0 while printing a byte MISMATCH**, in both lanes — nothing could gate on it.
|
|
890
|
+
An integrity mismatch now fails the command; a missing render or placeholder is a normal state and
|
|
891
|
+
still exits 0.
|
|
892
|
+
- **`abx add --dry-run` silently ignored the flag and performed the registration**, local or remote.
|
|
893
|
+
It now refuses and names the read-only commands (`abx state`, `abx status`) instead. Silently doing
|
|
894
|
+
the thing when the caller asked to preview is the one outcome that must never happen.
|
|
895
|
+
- **`PRAGMA busy_timeout` was set third in the store schema**, after the WAL switch it needs to
|
|
896
|
+
protect — so two processes opening the same store at once (parallel CLI runs, or a co-located
|
|
897
|
+
effects runner starting alongside the resolver) could fail outright with `database is locked`
|
|
898
|
+
instead of waiting the moment out. It is now the first statement.
|
|
899
|
+
|
|
900
|
+
A third round, re-running the scenario that found the verify bug (it now catches it) turned up:
|
|
901
|
+
|
|
902
|
+
- **`abx add --remote` ended on "it now serves <url>"** — true about indexing, silent about whether
|
|
903
|
+
the bytes are right, and two reviewers stopped there and reported a blank page as fixed. It now names
|
|
904
|
+
the byte check (`abx verify <addr> --remote <name>`) in the same breath.
|
|
905
|
+
- **`canonical:` collapsed a tri-state.** `isCanonical` is `true | false | null`, and both readouts
|
|
906
|
+
printed "unverified" for the last two — so "the chain says this is NOT a clone of the configured
|
|
907
|
+
factory" (a trust finding) looked identical to "the check never ran" (no factory on this chain, normal
|
|
908
|
+
on a dev chain). Two reviewers read the collapsed word as a second failure sitting next to a real one.
|
|
909
|
+
- **`abx verify --remote` gave a bare `fetch failed`** for an endpoint that was down, where
|
|
910
|
+
`abx status --remote` names the host and asks whether it's running. Two commands, one condition, two
|
|
911
|
+
error qualities — now consistent.
|
|
912
|
+
- `abx status <addr>` printed the address twice when the project has no name.
|
|
913
|
+
- Skill: registering with a provider on **their** hostname vs. a domain you control decides whether
|
|
914
|
+
leaving later costs a transaction — now stated in the managed-provider section, before you bake it.
|
|
915
|
+
|
|
916
|
+
### Patch Changes
|
|
917
|
+
|
|
918
|
+
- Updated dependencies [a72723d]
|
|
919
|
+
- @artblocks/abx-sdk@0.1.0-alpha.3
|
|
920
|
+
- @artblocks/abx-indexer@0.1.0-alpha.4
|
|
921
|
+
- @artblocks/abx-token-api@0.1.0-alpha.6
|
|
922
|
+
- @artblocks/abx-storage@0.1.0-alpha.3
|
|
923
|
+
|
|
924
|
+
## 0.1.0-alpha.9
|
|
925
|
+
|
|
926
|
+
### Minor Changes
|
|
927
|
+
|
|
928
|
+
- 3745bd3: Remote services are first-class: a provider-neutral control plane, named remotes, and a service
|
|
929
|
+
descriptor (specs/self-host-toolkit/remote-services.md).
|
|
930
|
+
|
|
931
|
+
- **Control plane moves to `/v1`** (hard cutover; `/admin/*` is gone — redeploy self-hosted nodes):
|
|
932
|
+
`POST/GET /v1/projects`, `DELETE|reindex|status /v1/projects/{chainId}/{address}`,
|
|
933
|
+
`POST /v1/effect-artifacts|effect-status`. `chainId` is explicit and validated everywhere; every
|
|
934
|
+
error carries a machine `code` (`unauthorized` 401 · `forbidden` 403 · `unsupported_chain` ·
|
|
935
|
+
`not_registered` · `disabled`) replacing the old prose-sniffed 404. One bearer guard replaces the
|
|
936
|
+
four inline copies; OPTIONS preflight now answers so browser clients can send `Authorization`.
|
|
937
|
+
- **`GET /.well-known/abx-service`** — the public service descriptor: `interfaces` (present iff
|
|
938
|
+
actually enabled), `chains`, `auth` (with optional provider-set `signupUrl`/`docsUrl` via
|
|
939
|
+
`ABX_SERVICE_*` env), and `render.attached` (managed rendering, probed from the runner's
|
|
940
|
+
`/health`) — so an agent can match a project to a provider before registering.
|
|
941
|
+
- **Named remotes in the CLI**: `--remote <name>` reads `ABX_REMOTE_<NAME>_URL`/`_TOKEN`
|
|
942
|
+
(a managed provider's per-account key — never falls back to `ABX_RESOLVER_ADMIN_TOKEN`);
|
|
943
|
+
`--remote <url> [--remote-token <t>]` for ad-hoc targets; bare `--remote` stays the self-host
|
|
944
|
+
default. New `abx remote [name|url]` inspects a service's descriptor and the projects a token
|
|
945
|
+
sees. `migrate --from/--to` accept names; only the destination needs a credential.
|
|
946
|
+
- **The SDK gains its first HTTP surface**: `AbxServiceClient` (endpoint + injected bearer, retry
|
|
947
|
+
on 5xx/network, immediate typed `AbxServiceError` on 4xx) — shared by the CLI and the effects
|
|
948
|
+
runner's publish lane. `envSuffix()` is the shared env-name normalization.
|
|
949
|
+
- **Conformance fixture**: `pnpm conformance -- <base-url> [--token …]` self-verifies any
|
|
950
|
+
implementation; the e2e suite runs it against the reference container.
|
|
951
|
+
|
|
952
|
+
### Patch Changes
|
|
953
|
+
|
|
954
|
+
- 3745bd3: Membrane fixes found by a 20-run cold-agent regression sweep (sonnet + haiku, black-box clean rooms).
|
|
955
|
+
|
|
956
|
+
- **A 500 no longer leaks the node's own credentials.** An upstream RPC failure surfaced viem's
|
|
957
|
+
message, which embeds the endpoint URL — and a keyed RPC URL _is_ a credential, so on a
|
|
958
|
+
multi-tenant provider any tenant who could provoke a 500 got the operator's RPC key. The cause now
|
|
959
|
+
goes to the node's log; the wire gets a generic message, an `internal_error` code, and a
|
|
960
|
+
credential-free hint about the failure class. Normative in the remote-services spec.
|
|
961
|
+
- **The service client no longer discards a 5xx body.** The service's own words survive the retry
|
|
962
|
+
ladder, and an exhausted ladder says "failed — last response …" rather than mislabelling a
|
|
963
|
+
server that answered as "unreachable". The descriptor probe drops to 2 attempts, so a typo'd
|
|
964
|
+
provider URL fails in ~1s instead of grinding 5s, with distinct "nothing responded" vs
|
|
965
|
+
"answered, but serves no descriptor" messages.
|
|
966
|
+
- **Conflicting duplicate `.env` keys are reported.** First-wins is unchanged, but a stale second
|
|
967
|
+
`ABX_RPC_URLS_<CHAIN>` line silently pointed the CLI at another network while every check read
|
|
968
|
+
green — the symptom surfaced far away as "no contract at that address". Only genuinely
|
|
969
|
+
_conflicting_ duplicates warn (identical repeats stay quiet).
|
|
970
|
+
- **"No contract at …" errors now name the endpoint they asked** (redacted), because a chain key
|
|
971
|
+
can't distinguish two RPCs that both claim it.
|
|
972
|
+
- **A misnamed remote credential is called out.** `ABX_REMOTE_<NAME>_KEY` (or `_API_KEY`, `_SECRET`)
|
|
973
|
+
is not read, so it previously reported as "no token" while the value sat in `.env`; both
|
|
974
|
+
`abx remote` and the register path now name the near-miss and the correct `_TOKEN` name.
|
|
975
|
+
- **`--dry-run` explains a missing trust anchor instead of crashing.** On a chain where the
|
|
976
|
+
configured factory has no code, `deploy`/`deploy-series` previews died inside
|
|
977
|
+
`predictDeterministicAddress` with a raw `returned no data ("0x")`; they now report it the way
|
|
978
|
+
`abx predict` and a real deploy already did, and name the two ways forward. The keyless
|
|
979
|
+
`--for` requirement also fails fast instead of after several steps of output.
|
|
980
|
+
- **The placeholder-identity guard is one shared predicate** across all three deploy commands
|
|
981
|
+
(it was copy-pasted, and one copy's comment claimed coverage it didn't have), pinned by a new
|
|
982
|
+
regression test: a real send refuses tool defaults, a preview only warns.
|
|
983
|
+
- **The served dashboard's empty state no longer prints `pnpm abx demo`** — a contributor-only
|
|
984
|
+
invocation on a page a published user sees.
|
|
985
|
+
|
|
986
|
+
- Updated dependencies [3745bd3]
|
|
987
|
+
- Updated dependencies [3745bd3]
|
|
988
|
+
- @artblocks/abx-sdk@0.1.0-alpha.2
|
|
989
|
+
- @artblocks/abx-token-api@0.1.0-alpha.5
|
|
990
|
+
- @artblocks/abx-indexer@0.1.0-alpha.3
|
|
991
|
+
- @artblocks/abx-storage@0.1.0-alpha.2
|
|
992
|
+
|
|
993
|
+
## 0.1.0-alpha.8
|
|
994
|
+
|
|
995
|
+
### Patch Changes
|
|
996
|
+
|
|
997
|
+
- 4074766: Fix the dashboard's block-explorer links, which were hardcoded to `https://sepolia.etherscan.io`. Every
|
|
998
|
+
link on the page — contract, owner, implementation, each event's tx — pointed at Ethereum Sepolia no
|
|
999
|
+
matter which chain was being served, so a dashboard for a normal `abx demo` (Base Sepolia by default)
|
|
1000
|
+
sent you to an explorer where the contract does not exist. The SDK now derives the explorer from viem's
|
|
1001
|
+
own chain metadata (`explorerUrl`/`chainById`), so adding a chain brings its explorer along and no
|
|
1002
|
+
hand-maintained table can drift. The CLI's separate copy of that table is collapsed into the same
|
|
1003
|
+
helper; `signer.ts` was already doing it correctly.
|
|
1004
|
+
|
|
1005
|
+
Drop the demo's opening "trust anchor" step. It asserted that only the canonical factory can make a
|
|
1006
|
+
token that _is_ an ABX token, which is false — anything following the protocol's event spine is an ABX
|
|
1007
|
+
token, and the factory is one route to that, not the definition. The same overclaim in the index step
|
|
1008
|
+
("verified real") now reports the fact instead: made by the canonical factory, or not. The demo opens
|
|
1009
|
+
on the renderer step, and resolving the factory no longer prints a line of its own there.
|
|
1010
|
+
|
|
1011
|
+
- Updated dependencies [4074766]
|
|
1012
|
+
- @artblocks/abx-sdk@0.1.0-alpha.1
|
|
1013
|
+
- @artblocks/abx-token-api@0.1.0-alpha.4
|
|
1014
|
+
- @artblocks/abx-indexer@0.1.0-alpha.2
|
|
1015
|
+
- @artblocks/abx-storage@0.1.0-alpha.1
|
|
1016
|
+
|
|
1017
|
+
## 0.1.0-alpha.7
|
|
1018
|
+
|
|
1019
|
+
### Patch Changes
|
|
1020
|
+
|
|
1021
|
+
- c16c0f0: Shorten the update check's cache from 24h to **6h**. A day-long cache let someone work a whole
|
|
1022
|
+
session — deploys included — against a CLI that had been superseded that morning, without ever being
|
|
1023
|
+
told. In a fast-moving alpha line that's the common case, not the edge one.
|
|
1024
|
+
|
|
1025
|
+
The agent skill now **acts** on version drift instead of reporting it. It already reconciled
|
|
1026
|
+
skill⇄CLI drift, but nothing told it what to do when the CLI's own `update available` notice fired —
|
|
1027
|
+
so on an agent-driven surface that notice landed as a human-shaped message and got relayed or
|
|
1028
|
+
ignored. The skill now upgrades the CLI itself (matching how it was installed), resyncs the skill, and
|
|
1029
|
+
reloads before deploying, with the reason stated: a stale CLI can hold canonical addresses that have
|
|
1030
|
+
since moved, and a mid-run `… is not a function` is usually exactly this.
|
|
1031
|
+
|
|
1032
|
+
Docs: the Upgrading page now leads with the two install shapes in the same order as the quickstart
|
|
1033
|
+
(global, then per-project) instead of opening on a one-off `npx` invocation, drops the update-check
|
|
1034
|
+
silencing details (they live in the CLI reference, alongside `version`), and answers the question the
|
|
1035
|
+
old "Upgrade the SDK" section provoked — upgrading the CLI upgrades the SDK it pins, so a CLI user has
|
|
1036
|
+
nothing separate to maintain; you install the SDK only when writing TypeScript against ABX directly.
|
|
1037
|
+
|
|
1038
|
+
## 0.1.0-alpha.6
|
|
1039
|
+
|
|
1040
|
+
### Patch Changes
|
|
1041
|
+
|
|
1042
|
+
- c21ea30: `abx demo` now runs **fully on-chain** by default, and speaks plainly.
|
|
1043
|
+
|
|
1044
|
+
Its generative SVG is inlined into the contract, so no `http://localhost:8787` is baked into the
|
|
1045
|
+
on-chain `tokenURI` base. The old default shipped a first-ever token that resolved for nobody but its
|
|
1046
|
+
author — broken on every marketplace, dead the moment `abx serve` stopped — and taught that as the
|
|
1047
|
+
normal shape of an NFT. It also undercut the demo's own claim: with the art on-chain, "rebuilt from the
|
|
1048
|
+
chain alone" now covers the image, not just the metadata. The final dashboard still starts, but is
|
|
1049
|
+
framed as a local viewer rather than infrastructure. Hand the demo an `--image`, a `--backend`, or a
|
|
1050
|
+
`--public-base-url` and it switches back to off-chain custody, where that split is real and worth
|
|
1051
|
+
teaching.
|
|
1052
|
+
|
|
1053
|
+
Fixed alongside it: on every on-chain lane (1/1 and Series, wallet and `--onchain-image`) the deploy
|
|
1054
|
+
step announced `URIs point at http://localhost:8787` even though nothing was baked — in the demo, two
|
|
1055
|
+
lines after promising no localhost anywhere.
|
|
1056
|
+
|
|
1057
|
+
The walkthrough's teaching text is rewritten in plain language, with the protocol vocabulary kept as a
|
|
1058
|
+
dim aside instead of the headline: steps are now "Who vouches for this token?", "Mint it", "What the
|
|
1059
|
+
chain knows now", and "The moment of truth · delete it all". The read-back step reads from the real
|
|
1060
|
+
source per lane — `tokenURI(0)` on the contract when fully on-chain (what a marketplace actually does,
|
|
1061
|
+
and it proves no server is involved), the resolver when custody is off-chain.
|
|
1062
|
+
|
|
1063
|
+
The browser-wallet signing prompt now says to connect a wallet holding testnet ETH and links a faucet.
|
|
1064
|
+
That was the one funding surface with no guidance: on `--sign` without `--for` the address isn't known
|
|
1065
|
+
until the wallet connects, so the up-front balance check never ran and an empty wallet's first signal
|
|
1066
|
+
was a failed transaction.
|
|
1067
|
+
|
|
1068
|
+
- c21ea30: Make the update check independent of which npm dist-tag prereleases are published under. It now
|
|
1069
|
+
resolves the `latest` tag and, when the running version is a prerelease, that version's own channel
|
|
1070
|
+
tag (`alpha`, `beta`, …), reporting whichever is newer. Previously it only asked for `latest`, which
|
|
1071
|
+
works today only because `ci:publish` passes no `--tag`; the day a stable release ships and
|
|
1072
|
+
prereleases move to `--tag alpha`, the nudge would have gone silent for prerelease users with
|
|
1073
|
+
nothing erroring. The on-disk cache is now keyed by release channel too, so switching between the
|
|
1074
|
+
alpha and stable lines re-checks instead of serving a day-stale answer.
|
|
1075
|
+
- Updated dependencies [c21ea30]
|
|
1076
|
+
- @artblocks/abx-indexer@0.1.0-alpha.1
|
|
1077
|
+
- @artblocks/abx-token-api@0.1.0-alpha.3
|
|
1078
|
+
|
|
1079
|
+
## 0.1.0-alpha.5
|
|
1080
|
+
|
|
1081
|
+
### Patch Changes
|
|
1082
|
+
|
|
1083
|
+
- afb36a3: Fix three bugs that made the documented first run (`abx demo`) look broken.
|
|
1084
|
+
|
|
1085
|
+
**A 0-event index was reported as success, and served.** `eth_getLogs` is
|
|
1086
|
+
read-after-write inconsistent on load-balanced RPCs: `waitForTransactionReceipt`
|
|
1087
|
+
resolves against a node that has the block, then the log query lands on one that
|
|
1088
|
+
doesn't yet and returns nothing for a block we _know_ contains our deploy. The CLI
|
|
1089
|
+
took that single read at face value, printed `✓ reconstructed 0 events`, stored the
|
|
1090
|
+
empty projection and served an empty dashboard — no events, no token, nothing to
|
|
1091
|
+
look at. This reproduced 100% of the time against `https://sepolia.base.org`, which
|
|
1092
|
+
is the **default endpoint when there is no `.env`** — so the documented first run
|
|
1093
|
+
was the path that broke. Every post-deploy index (`deploy`, `demo`, `deploy-series`,
|
|
1094
|
+
`deploy-code`, `add`) now re-scans with backoff instead of trusting one read, since
|
|
1095
|
+
having just minted means the spine cannot legitimately be empty. If it still comes
|
|
1096
|
+
back empty, that is now reported as a failure naming `abx index <addr> --full` as
|
|
1097
|
+
the recovery, rather than dressed up as a ✓.
|
|
1098
|
+
|
|
1099
|
+
**The demo told you to press a button that does not exist.** It ended with _"Open
|
|
1100
|
+
the dashboard, then hit 'Re-index from chain'"_. The dashboard is read-only —
|
|
1101
|
+
re-index and verify are admin actions that 404 unless the node has an
|
|
1102
|
+
`ABX_RESOLVER_ADMIN_TOKEN` — so that control isn't there to find. It now points at
|
|
1103
|
+
the spine table (which _is_ the reconstruction) and at `abx index <addr> --full` to
|
|
1104
|
+
replay it. The dashboard's own note also stopped printing a **shortened** address
|
|
1105
|
+
inside a copy-pasteable command, and no longer suggests `--remote` for a local node.
|
|
1106
|
+
|
|
1107
|
+
**Re-running the demo crashed after spending a transaction.** With port 8787 already
|
|
1108
|
+
busy — an `abx demo` or `abx serve` in another terminal, i.e. exactly what happens
|
|
1109
|
+
when you run the demo twice — the deploy went through, was paid for, and _then_ the
|
|
1110
|
+
serve step died with an unhandled Node `EADDRINUSE` stack trace. The port is now
|
|
1111
|
+
preflighted before anything irreversible, so it refuses with "Nothing was deployed"
|
|
1112
|
+
and suggests `--port <n+1>`.
|
|
1113
|
+
|
|
1114
|
+
**`abx demo` is now a walkthrough rather than a smoke test.** The docs point a
|
|
1115
|
+
first-time reader here, but it asserted its interesting claims without ever showing
|
|
1116
|
+
them — "reconstructed 9 events — no provider involved" with the events invisible.
|
|
1117
|
+
It now teaches, continuously and without pauses (so agents and CI behave
|
|
1118
|
+
identically): it explains why the trust anchor is the factory and not a spoofable
|
|
1119
|
+
event, names what goes on chain versus what stays a keccak256 commitment, prints
|
|
1120
|
+
the reconstructed event spine with what each event told us (tagged ABX vs plain
|
|
1121
|
+
ERC-721/7572), then **deletes its own local projection and replays it from the
|
|
1122
|
+
deploy block**, comparing a sha256 fingerprint of every chain-derived field to prove
|
|
1123
|
+
it lands on identical state. Finally it reads the token back the way a marketplace
|
|
1124
|
+
would. `abx deploy` is unchanged — it stays terse.
|
|
1125
|
+
|
|
1126
|
+
Adds `Store.dropProjection(address)` / `SelfHostIndexer.dropProjection()`: discard a
|
|
1127
|
+
project's reconstructed projection while keeping its registration, so the next index
|
|
1128
|
+
rebuilds from the deploy block. That's the primitive the rebuild proof needs, and it
|
|
1129
|
+
makes "the projection is a disposable cache" a checkable claim rather than a comment.
|
|
1130
|
+
|
|
1131
|
+
- Updated dependencies [afb36a3]
|
|
1132
|
+
- @artblocks/abx-token-api@0.1.0-alpha.2
|
|
1133
|
+
|
|
1134
|
+
## 0.1.0-alpha.4
|
|
1135
|
+
|
|
1136
|
+
### Minor Changes
|
|
1137
|
+
|
|
1138
|
+
- 48d96c5: Add **`abx preview`** — the studio lane for code projects: run the program on
|
|
1139
|
+
localhost, live, while it's still being made. No chain, no key, no deploy.
|
|
1140
|
+
|
|
1141
|
+
`abx preview --script art.js --schema "palette:HexColor:TokenOwner"` serves a
|
|
1142
|
+
studio on `localhost:8788` — shuffle seeds, drive every declared PostParam from a
|
|
1143
|
+
real typed input (a color picker for `HexColor`, a dropdown for `Select`), read the
|
|
1144
|
+
traits the program actually reported, and `/grid` to see N seeds at once. `/view`
|
|
1145
|
+
is the bare document. The program is re-read from disk on every render, so the loop
|
|
1146
|
+
is edit-and-refresh with no watcher and no restart.
|
|
1147
|
+
|
|
1148
|
+
It serves the **same template-mode document the generator serves** — the real
|
|
1149
|
+
`abx.js`, the real canonical `tokenData` shape, the real dependency script tags —
|
|
1150
|
+
with a synthetic bytes32 seed in place of a minted one, so what you approve is what
|
|
1151
|
+
deploys. There is no second copy of the runtime to drift from. (`@artblocks/abx-token-api`
|
|
1152
|
+
now exports `ABX_JS` and the inline-safety escapes so the CLI can build that exact
|
|
1153
|
+
document rather than reimplement it.)
|
|
1154
|
+
|
|
1155
|
+
`--shoot <dir>` drives the same server headlessly to PNGs plus a `traits.json` and
|
|
1156
|
+
exits — that's how an agent, which can't open a browser, sees what the creator sees.
|
|
1157
|
+
It also flags the two silent killers: no frame reporting traits (⇒ no marketplace
|
|
1158
|
+
`attributes` on any lane) and identical traits across every seed (⇒ the program
|
|
1159
|
+
isn't reading `abx.tokenData.seed`, so the drop mints N identical tokens).
|
|
1160
|
+
|
|
1161
|
+
Why a live server rather than a screenshot sweep: a still flattens every time-based
|
|
1162
|
+
piece, and `abx.done()` exists precisely because stills need a settle point — so a
|
|
1163
|
+
proof sheet of an animated piece is a set of arbitrary frozen frames presented as
|
|
1164
|
+
the work. Frames render into a fixed 1000×1000 viewport and are scaled to fit their
|
|
1165
|
+
slot, so a program that hardcodes its canvas size is never clipped to its own corner.
|
|
1166
|
+
|
|
1167
|
+
Skill: add **Phase 0**, an explicit authoring phase that puts every deploy decision
|
|
1168
|
+
(hosting, thumbnail, traits, storage, wallet, supply, royalties, name/symbol) off
|
|
1169
|
+
the table until the creator says ship, and points at `abx preview` for the loop. The
|
|
1170
|
+
skill previously went straight from "the creator brought an idea" to "pick a deploy
|
|
1171
|
+
lane", so an agent helping someone _design_ a piece front-loaded infrastructure
|
|
1172
|
+
questions while there was still nothing to look at.
|
|
1173
|
+
|
|
1174
|
+
Skill: also teach CLI resolution — probe project-local (`npx --no-install abx`)
|
|
1175
|
+
before global, install `@artblocks/abx-cli` (not `@artblocks/abx-sdk`, which ships
|
|
1176
|
+
no binary), and default to a per-project install. The skill previously assumed `abx`
|
|
1177
|
+
was already on PATH and gave no bootstrap path at all, so agents improvised — one
|
|
1178
|
+
installed the SDK, then went global unprompted.
|
|
1179
|
+
|
|
1180
|
+
### Patch Changes
|
|
1181
|
+
|
|
1182
|
+
- 48d96c5: `abx demo` now honors the signing lane instead of silently discarding it. It
|
|
1183
|
+
hard-forced the hot (env-key) lane, so `abx demo --sign` failed confusingly when
|
|
1184
|
+
no key was configured — and, worse, signed from the env key when one _was_
|
|
1185
|
+
present, even though the operator had explicitly asked for their browser wallet.
|
|
1186
|
+
`--sign` (and `--for` to pin the connecting wallet) now work on `demo` exactly as
|
|
1187
|
+
they do on `deploy`.
|
|
1188
|
+
|
|
1189
|
+
`abx demo --unsigned` and `abx demo --dry-run` are now refused with an
|
|
1190
|
+
explanation rather than ignored: both skip the broadcast, and `demo` indexes and
|
|
1191
|
+
serves the contract it just deployed, so there would be nothing to index. Use
|
|
1192
|
+
`abx deploy --unsigned` / `abx deploy --dry-run` for those lanes.
|
|
1193
|
+
|
|
1194
|
+
Also documents the `demo` signing flags in `abx help demo`.
|
|
1195
|
+
|
|
1196
|
+
- Updated dependencies [48d96c5]
|
|
1197
|
+
- @artblocks/abx-token-api@0.1.0-alpha.1
|
|
1198
|
+
|
|
1199
|
+
## 0.1.0-alpha.3
|
|
1200
|
+
|
|
1201
|
+
### Patch Changes
|
|
1202
|
+
|
|
1203
|
+
- 6fbb62e: Restructure `abx doctor` for clarity. Two tiers now: PASS/FAIL checks (✓/✗) for
|
|
1204
|
+
things that are working or broken — agent skill (shown first and prominently; a
|
|
1205
|
+
missing/stale skill is a ✗ since agent-driven use is the primary UX), RPC,
|
|
1206
|
+
factory, storage — and an "Optional — depends how you deploy" block (·) for
|
|
1207
|
+
path-dependent setup (signing lane, resolver URL, Arweave key). `⚠` is no longer
|
|
1208
|
+
used for values that are unset-but-fine (it read as noise); it's reserved for a
|
|
1209
|
+
genuine gotcha such as a range-capped-only RPC. The RPC report collapses to one
|
|
1210
|
+
line.
|
|
1211
|
+
- 6fbb62e: Fix the update-check hint to invoke the CLI by its scoped package name
|
|
1212
|
+
(`npx @artblocks/abx-cli@latest <command>`). The bare `npx abx` resolves an
|
|
1213
|
+
unrelated squatted `abx` package on npm, not this CLI, so the old hint pointed
|
|
1214
|
+
users at a command that fails. (Installed users — global or per-project — run
|
|
1215
|
+
`abx` / `npx abx` as before; only the zero-install invocation needs the scoped
|
|
1216
|
+
name.)
|
|
1217
|
+
|
|
1218
|
+
## 0.1.0-alpha.2
|
|
1219
|
+
|
|
1220
|
+
### Minor Changes
|
|
1221
|
+
|
|
1222
|
+
- 02fc0e0: Make `abx skill install` agent-aware and strictly version-lock the skill to the CLI.
|
|
1223
|
+
|
|
1224
|
+
`skill install` now installs to the directories every supported agent actually reads: by default
|
|
1225
|
+
both `.claude/skills` (Claude Code) and the neutral `.agents/skills` (Cursor, Codex CLI, Gemini CLI,
|
|
1226
|
+
GitHub Copilot), so one command covers the whole ecosystem. `--agent claude|cursor|codex|gemini|copilot`
|
|
1227
|
+
narrows it to one; `--target <dir>` now writes the skill folder straight under `<dir>`.
|
|
1228
|
+
|
|
1229
|
+
The skill's version now lives in its `SKILL.md` frontmatter (`metadata.version`), stamped at release
|
|
1230
|
+
to equal the CLI version (replacing the old `.abx-skill-version` sidecar). Because the version travels
|
|
1231
|
+
inside the skill file, the drift check finds a stale copy no matter how it was installed — including
|
|
1232
|
+
`npx skills add` — and `abx doctor` reports the skill/CLI version match explicitly. A publish-time gate
|
|
1233
|
+
(and `pnpm ci:version` stamping) keeps the two from ever shipping out of lockstep.
|
|
1234
|
+
|
|
1235
|
+
## 0.1.0-alpha.1
|
|
1236
|
+
|
|
1237
|
+
### Patch Changes
|
|
1238
|
+
|
|
1239
|
+
- b5d201f: Add `abx version` and a notify-only update check. On startup `abx` now checks npm at most once a
|
|
1240
|
+
day and, when a newer release is published, prints an upgrade hint to stderr (never stdout, so it
|
|
1241
|
+
never corrupts machine-readable output an agent is parsing). It also nudges to reinstall the agent
|
|
1242
|
+
skill when the installed copy has drifted behind the CLI. Opt out with `ABX_NO_UPDATE_CHECK=1` or
|
|
1243
|
+
`--no-update-check`; it is a no-op in CI and when offline.
|