@artblocks/abx-cli 0.1.0-alpha.3 → 0.1.0-alpha.4

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.
@@ -0,0 +1,63 @@
1
+ import { type ParsedDependencyRef } from '@artblocks/abx-sdk';
2
+ import type { Flags } from './flags.js';
3
+ import { type ParsedSchema } from './schema.js';
4
+ /** The studio's default port — deliberately not the resolver's (8787), so both can run at once. */
5
+ export declare const DEFAULT_PREVIEW_PORT = 8788;
6
+ /**
7
+ * A deterministic preview seed per index. The on-chain seed is a full bytes32, and sha256 hex is
8
+ * exactly 64 chars — real width, well mixed, and STABLE across runs, so re-rendering after an edit
9
+ * is a like-for-like comparison instead of a whole new set of art. (A short stub seed would starve
10
+ * the sketch's PRNG of entropy and can hide a distribution bug until it's permanent.)
11
+ */
12
+ export declare function previewSeed(index: number): string;
13
+ export interface PreviewSource {
14
+ kind: 'script' | 'dir';
15
+ /** Template mode: the script file. Directory mode: the build root. */
16
+ path: string;
17
+ }
18
+ export interface PreviewConfig {
19
+ source: PreviewSource;
20
+ schemas: ParsedSchema[];
21
+ deps: ParsedDependencyRef[];
22
+ }
23
+ /**
24
+ * Dependency script tags for the preview. Without a chain we can't read registry on-chain bytes,
25
+ * so a `name@version` ref resolves through the SAME built-in CDN map the resolver falls back to,
26
+ * and a raw on-chain data-contract ref can't be fetched at all (reported, not silently dropped).
27
+ */
28
+ export declare function previewDepTags(deps: ParsedDependencyRef[]): {
29
+ tags: string[];
30
+ notes: string[];
31
+ };
32
+ /**
33
+ * The template-mode document — deliberately the same shape and order as
34
+ * `assembleGeneratorDocument` in @artblocks/abx-token-api (token-api/src/code.ts). If that changes,
35
+ * change this with it.
36
+ */
37
+ export declare function buildPreviewDocument(script: string, tokenDataJson: string, depTags: string[]): string;
38
+ export interface PreviewServerHandle {
39
+ port: number;
40
+ url: string;
41
+ close: () => Promise<void>;
42
+ }
43
+ export declare function startPreviewServer(cfg: PreviewConfig, port: number): Promise<PreviewServerHandle>;
44
+ export interface ShootResult {
45
+ seed: string;
46
+ file: string;
47
+ traits: Record<string, unknown> | null;
48
+ done: boolean;
49
+ }
50
+ /**
51
+ * Render `count` seeds from a running preview server to PNGs, collecting each frame's reported
52
+ * traits. This is how an agent (which cannot open localhost) sees the work — and because it drives
53
+ * the same `/view` document the creator sees, there is nothing to keep in sync.
54
+ */
55
+ export declare function shootPreview(base: string, outDir: string, count: number, opts?: {
56
+ width?: number;
57
+ timeoutMs?: number;
58
+ }): Promise<ShootResult[]>;
59
+ export declare const PREVIEW_FLAGS: ReadonlySet<string>;
60
+ /** Resolve `--script`/`--code-dir` into a source, with the same either-or rule as `deploy-code`. */
61
+ export declare function previewSourceFromFlags(flags: Flags): PreviewSource;
62
+ export declare function previewConfigFromFlags(flags: Flags): PreviewConfig;
63
+ //# sourceMappingURL=preview.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preview.d.ts","sourceRoot":"","sources":["../src/preview.ts"],"names":[],"mappings":"AAyBA,OAAO,EAAsC,KAAK,mBAAmB,EAAC,MAAM,oBAAoB,CAAC;AAEjG,OAAO,KAAK,EAAC,KAAK,EAAC,MAAM,YAAY,CAAC;AACtC,OAAO,EAAmB,KAAK,YAAY,EAAC,MAAM,aAAa,CAAC;AAGhE,mGAAmG;AACnG,eAAO,MAAM,oBAAoB,OAAO,CAAC;AAOzC;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEjD;AAkBD,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,QAAQ,GAAG,KAAK,CAAC;IACvB,sEAAsE;IACtE,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,aAAa,CAAC;IACtB,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,IAAI,EAAE,mBAAmB,EAAE,CAAC;CAC7B;AA+BD;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,mBAAmB,EAAE,GAAG;IAAC,IAAI,EAAE,MAAM,EAAE,CAAC;IAAC,KAAK,EAAE,MAAM,EAAE,CAAA;CAAC,CAiB7F;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,MAAM,CAYrG;AAwOD,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5B;AAED,wBAAsB,kBAAkB,CAAC,GAAG,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAkEvG;AAID,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IACvC,IAAI,EAAE,OAAO,CAAC;CACf;AAED;;;;GAIG;AACH,wBAAsB,YAAY,CAChC,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,EACb,IAAI,GAAE;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAM,GAC9C,OAAO,CAAC,WAAW,EAAE,CAAC,CAkDxB;AAID,eAAO,MAAM,aAAa,EAAE,WAAW,CAAC,MAAM,CAE5C,CAAC;AAEH,oGAAoG;AACpG,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,KAAK,GAAG,aAAa,CASlE;AAED,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,KAAK,GAAG,aAAa,CAMlE"}
@@ -0,0 +1,483 @@
1
+ /**
2
+ * `abx preview` — the studio lane: run a code project on localhost, live, before deploying it.
3
+ *
4
+ * The gap this closes: `abx inspect` proves a script is WIRED correctly (static analysis) and a
5
+ * testnet deploy shows the real thing, but neither lets a creator sit with a piece and refine it.
6
+ * A still-image sweep isn't enough either — it flattens every time-based piece, and `abx.done()`
7
+ * exists precisely because stills need a settle point. So the primary surface is a real browser
8
+ * page the creator opens, refreshes, and drives.
9
+ *
10
+ * FIDELITY IS THE WHOLE POINT: `/view` serves the *same* template-mode document
11
+ * `assembleGeneratorDocument` builds (same shape, same real `ABX_JS`, same dependency script tags,
12
+ * same canonical tokenData serialization) with a synthetic seed in place of a minted one. There is
13
+ * no second copy of the runtime to drift — that was the flaw in hand-rolled preview harnesses,
14
+ * which stub `window.abx` themselves and happily run a sketch that reads its seed the wrong way.
15
+ *
16
+ * The script is re-read from disk on every request, so edit-then-refresh needs no watcher.
17
+ *
18
+ * `--shoot <dir>` drives the SAME server headlessly (Playwright) and exits — that's how an agent,
19
+ * which can't open localhost, sees what the creator sees. Captures are a derived read of the
20
+ * preview document, never a parallel harness.
21
+ */
22
+ import { createServer } from 'node:http';
23
+ import { readFile, mkdir, writeFile } from 'node:fs/promises';
24
+ import { createHash, randomBytes } from 'node:crypto';
25
+ import { extname, join, resolve as resolvePath } from 'node:path';
26
+ import { PARAM_TYPES, canonicalTokenDataJson } from '@artblocks/abx-sdk';
27
+ import { ABX_JS, escapeInlineScript, escapeInlineJson, injectTokenDataIntoHtml, registryDepUrl } from '@artblocks/abx-token-api';
28
+ import { parseSchemaSpecs } from './schema.js';
29
+ import { parseDepFlag } from './deps.js';
30
+ /** The studio's default port — deliberately not the resolver's (8787), so both can run at once. */
31
+ export const DEFAULT_PREVIEW_PORT = 8788;
32
+ /** A stand-in collection address. Real shape (20 bytes, lowercase) so `contractAddress` reads true. */
33
+ const PREVIEW_ADDRESS = '0x' + '11'.repeat(20);
34
+ const PREVIEW_CHAIN_ID = 84532;
35
+ // ── seeds ────────────────────────────────────────────────────────────────────────
36
+ /**
37
+ * A deterministic preview seed per index. The on-chain seed is a full bytes32, and sha256 hex is
38
+ * exactly 64 chars — real width, well mixed, and STABLE across runs, so re-rendering after an edit
39
+ * is a like-for-like comparison instead of a whole new set of art. (A short stub seed would starve
40
+ * the sketch's PRNG of entropy and can hide a distribution bug until it's permanent.)
41
+ */
42
+ export function previewSeed(index) {
43
+ return '0x' + createHash('sha256').update(`abx-preview-seed-${index}`).digest('hex');
44
+ }
45
+ /** A fresh unpredictable seed — what the studio's "new" button asks for. */
46
+ function randomSeed() {
47
+ return '0x' + randomBytes(32).toString('hex');
48
+ }
49
+ function normalizeSeed(raw, fallbackIndex = 0) {
50
+ const t = String(raw ?? '').trim();
51
+ if (/^0x[0-9a-fA-F]{64}$/.test(t))
52
+ return t.toLowerCase();
53
+ // Tolerate a short hex seed (someone pasting by hand) by left-padding to bytes32 — the same
54
+ // width the chain would give it, so the sketch sees production-shaped entropy either way.
55
+ if (/^0x[0-9a-fA-F]{1,64}$/.test(t))
56
+ return ('0x' + t.slice(2).toLowerCase().padStart(64, '0'));
57
+ return previewSeed(fallbackIndex);
58
+ }
59
+ /** Build the flat tokenData a token would carry, in the canonical shape `buildTokenData` produces. */
60
+ function previewTokenData(cfg, seed, tokenId, params) {
61
+ const data = {
62
+ chainId: PREVIEW_CHAIN_ID,
63
+ contractAddress: PREVIEW_ADDRESS,
64
+ tokenId,
65
+ seed,
66
+ };
67
+ // Every declared schema key is present, so a sketch reading `abx.tokenData.<key>` sees the same
68
+ // shape it will on-chain — a key that only appears once someone sets it is a preview that lies.
69
+ for (const s of cfg.schemas)
70
+ data[s.key] = params[s.key] ?? defaultParamValue(s);
71
+ return { data, json: canonicalTokenDataJson(data) };
72
+ }
73
+ /** A sensible starting value per param type, so the first frame renders without any input. */
74
+ function defaultParamValue(s) {
75
+ switch (PARAM_TYPES[s.paramType]) {
76
+ case 'Bool': return 'false';
77
+ case 'Select': return s.selectOptions[0] ?? '';
78
+ case 'HexColor': return '#3355ff';
79
+ case 'Timestamp': return '0';
80
+ case 'Uint256Range':
81
+ case 'Int256Range':
82
+ case 'DecimalRange': return '0';
83
+ case 'Bytes': return '0x';
84
+ default: return '';
85
+ }
86
+ }
87
+ /**
88
+ * Dependency script tags for the preview. Without a chain we can't read registry on-chain bytes,
89
+ * so a `name@version` ref resolves through the SAME built-in CDN map the resolver falls back to,
90
+ * and a raw on-chain data-contract ref can't be fetched at all (reported, not silently dropped).
91
+ */
92
+ export function previewDepTags(deps) {
93
+ const tags = [];
94
+ const notes = [];
95
+ for (const d of deps) {
96
+ if (d.display.startsWith('0x')) {
97
+ notes.push(`${d.display} — an on-chain data contract; not fetchable offline, so it is NOT loaded in preview`);
98
+ continue;
99
+ }
100
+ const url = registryDepUrl(d.display);
101
+ if (url) {
102
+ tags.push(`<script src="${url}"></script>`);
103
+ notes.push(`${d.display} → ${url} (built-in CDN map; on-chain bytes are resolved at deploy)`);
104
+ }
105
+ else {
106
+ notes.push(`${d.display} — unresolvable to a CDN URL; not loaded in preview`);
107
+ }
108
+ }
109
+ return { tags, notes };
110
+ }
111
+ /**
112
+ * The template-mode document — deliberately the same shape and order as
113
+ * `assembleGeneratorDocument` in @artblocks/abx-token-api (token-api/src/code.ts). If that changes,
114
+ * change this with it.
115
+ */
116
+ export function buildPreviewDocument(script, tokenDataJson, depTags) {
117
+ return [
118
+ '<!doctype html>',
119
+ '<html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">',
120
+ '<style>html,body{margin:0;padding:0;overflow:hidden}canvas{display:block}</style>',
121
+ `<script>window.abxTokenData=${escapeInlineJson(tokenDataJson)};</script>`,
122
+ `<script>${ABX_JS}</script>`,
123
+ ...depTags,
124
+ '</head><body>',
125
+ `<script>\n${escapeInlineScript(script)}\n</script>`,
126
+ '</body></html>',
127
+ ].join('\n');
128
+ }
129
+ /**
130
+ * The logical viewport every preview frame renders into, then CSS-scaled to fit its slot.
131
+ *
132
+ * Why not just size the iframe to the slot: a sketch that hardcodes a 1000×1000 canvas (most do)
133
+ * would be CLIPPED to the top-left corner of itself — which made an early grid look like a wall of
134
+ * blank tiles. Giving every frame the same generous square (a typical marketplace live-view size)
135
+ * and scaling the *result* means you always see the whole composition, and every tile is directly
136
+ * comparable. The sketch's own view of the world is unchanged, so nothing is misrepresented.
137
+ */
138
+ const STAGE_PX = 1000;
139
+ /** Fit-to-slot scaling for a fixed-size frame. Shared by the studio stage and every grid cell. */
140
+ const FIT_SNIPPET = `<script>(function(){
141
+ var LOGICAL = ${STAGE_PX};
142
+ function fit(){
143
+ for (var s of document.querySelectorAll('.stage')) {
144
+ s.style.setProperty('--k', (s.clientWidth / LOGICAL).toFixed(4));
145
+ }
146
+ }
147
+ window.addEventListener('resize', fit);
148
+ if (window.ResizeObserver) {
149
+ var ro = new ResizeObserver(fit);
150
+ for (var s of document.querySelectorAll('.stage')) ro.observe(s);
151
+ }
152
+ fit();
153
+ })();</script>`;
154
+ /** Stage CSS: a square slot holding a fixed-size frame, scaled down to fit it. */
155
+ const STAGE_CSS = `
156
+ .stage{position:relative;aspect-ratio:1;overflow:hidden;background:#000;border:1px solid #24242c}
157
+ .stage iframe{position:absolute;top:0;left:0;border:0;display:block;
158
+ width:${STAGE_PX}px;height:${STAGE_PX}px;transform:scale(var(--k,0.25));transform-origin:0 0}`;
159
+ /** Report traits + completion back to the studio chrome (and to --shoot). Preview-only chrome. */
160
+ const REPORT_SNIPPET = `<script>(function(){
161
+ function post(){
162
+ try {
163
+ parent.postMessage({abxPreview:true, traits: window.abx && window.abx.__traits,
164
+ done: !!(window.abx && window.abx.__done), t: Math.round(performance.now())}, '*');
165
+ } catch (e) {}
166
+ }
167
+ document.addEventListener('abx:traits', post);
168
+ document.addEventListener('abx:done', post);
169
+ setTimeout(post, 400); setTimeout(post, 1500);
170
+ })();</script>`;
171
+ async function renderViewDocument(cfg, seed, tokenId, params, withReport) {
172
+ const { json } = previewTokenData(cfg, seed, tokenId, params);
173
+ const { tags } = previewDepTags(cfg.deps);
174
+ if (cfg.source.kind === 'dir') {
175
+ // Directory mode mirrors the resolver's primary serving path: fetch the build's own entry
176
+ // document and inject tokenData into it (the build ships its own abx.js by convention).
177
+ const html = await readFile(join(cfg.source.path, 'index.html'), 'utf8');
178
+ const injected = injectTokenDataIntoHtml(html, json, '/__abx_code/');
179
+ return withReport ? injected.replace(/<\/body>/i, `${REPORT_SNIPPET}</body>`) : injected;
180
+ }
181
+ const script = await readFile(cfg.source.path, 'utf8'); // re-read per request → edit + refresh
182
+ const doc = buildPreviewDocument(script, json, tags);
183
+ return withReport ? doc.replace('</body>', `${REPORT_SNIPPET}</body>`) : doc;
184
+ }
185
+ // ── the studio chrome ────────────────────────────────────────────────────────────
186
+ function paramControl(s) {
187
+ const type = PARAM_TYPES[s.paramType];
188
+ const id = `p_${s.key}`;
189
+ const label = `<label for="${id}">${escapeHtml(s.key)}<span class="ty">${escapeHtml(type)}</span></label>`;
190
+ let input;
191
+ switch (type) {
192
+ case 'Bool':
193
+ input = `<input type="checkbox" id="${id}" data-key="${escapeHtml(s.key)}" data-kind="bool">`;
194
+ break;
195
+ case 'Select':
196
+ input = `<select id="${id}" data-key="${escapeHtml(s.key)}" data-kind="text">${s.selectOptions
197
+ .map((o) => `<option value="${escapeHtml(o)}">${escapeHtml(o)}</option>`)
198
+ .join('')}</select>`;
199
+ break;
200
+ case 'HexColor':
201
+ input = `<input type="color" id="${id}" value="#3355ff" data-key="${escapeHtml(s.key)}" data-kind="text">`;
202
+ break;
203
+ case 'Uint256Range':
204
+ case 'Int256Range':
205
+ case 'DecimalRange':
206
+ case 'Timestamp':
207
+ input = `<input type="number" id="${id}" value="0" data-key="${escapeHtml(s.key)}" data-kind="text">`;
208
+ break;
209
+ default:
210
+ input = `<input type="text" id="${id}" data-key="${escapeHtml(s.key)}" data-kind="text" placeholder="${escapeHtml(type)}">`;
211
+ }
212
+ return `<div class="ctl">${label}${input}</div>`;
213
+ }
214
+ function escapeHtml(s) {
215
+ return s.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
216
+ }
217
+ function studioPage(cfg, depNotes) {
218
+ const controls = cfg.schemas.map(paramControl).join('\n');
219
+ const sourceLabel = cfg.source.kind === 'dir' ? `${cfg.source.path}/ (directory build)` : cfg.source.path;
220
+ return `<!doctype html><html><head><meta charset="utf-8"><title>abx preview — studio</title>
221
+ <style>
222
+ :root{color-scheme:dark}
223
+ *{box-sizing:border-box}
224
+ body{margin:0;background:#0d0d10;color:#e6e6ea;font:13px/1.5 ui-sans-serif,system-ui,-apple-system,sans-serif}
225
+ header{display:flex;flex-wrap:wrap;gap:10px;align-items:center;padding:10px 14px;border-bottom:1px solid #24242c;background:#131318}
226
+ button{background:#22222b;color:#e6e6ea;border:1px solid #33333f;border-radius:6px;padding:5px 11px;font:inherit;cursor:pointer}
227
+ button:hover{background:#2c2c37}
228
+ .seed{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px;color:#9a9aa8;cursor:pointer}
229
+ .seed:hover{color:#e6e6ea}
230
+ .grow{flex:1}
231
+ .ctls{display:flex;flex-wrap:wrap;gap:14px;padding:8px 14px;border-bottom:1px solid #24242c;background:#101014}
232
+ .ctl{display:flex;align-items:center;gap:7px}
233
+ .ctl label{color:#9a9aa8}
234
+ .ctl .ty{color:#5b5b6b;margin-left:5px;font-size:11px}
235
+ input,select{background:#1b1b22;color:#e6e6ea;border:1px solid #33333f;border-radius:5px;padding:3px 6px;font:inherit}
236
+ input[type=color]{padding:1px;width:34px;height:24px}
237
+ main{padding:16px;display:flex;justify-content:center}
238
+ main .stage{width:min(78vh,100%)}
239
+ ${STAGE_CSS}
240
+ footer{padding:9px 14px;border-top:1px solid #24242c;background:#131318;display:flex;flex-wrap:wrap;gap:16px;align-items:center}
241
+ .traits{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px}
242
+ .warn{color:#e0a03a}.ok{color:#7ec07e}.dim{color:#6b6b7b}
243
+ a{color:#8fa8e0}
244
+ code{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;color:#9a9aa8;word-break:break-all}
245
+ .src{padding:0 14px 16px;font-size:12px}
246
+ </style></head><body>
247
+ <header>
248
+ <button id="new">↻ new seed</button>
249
+ <button id="prev">←</button><button id="next">→</button>
250
+ <span class="seed" id="seedLabel" title="click to copy"></span>
251
+ <span class="dim" id="idx"></span>
252
+ <span class="grow"></span>
253
+ <a href="/grid" target="_blank">grid ↗</a>
254
+ <a href="#" id="viewLink" target="_blank">bare view ↗</a>
255
+ </header>
256
+ ${controls ? `<div class="ctls">${controls}</div>` : ''}
257
+ <main><div class="stage"><iframe id="stage" title="preview"></iframe></div></main>
258
+ <footer>
259
+ <span class="dim">traits</span> <span class="traits" id="traits">—</span>
260
+ <span class="grow"></span>
261
+ <span id="done" class="dim">waiting…</span>
262
+ </footer>
263
+ <div class="src dim">
264
+ <code>${escapeHtml(sourceLabel)}</code> — re-read from disk on every render, so edit and refresh.
265
+ Rendered at ${STAGE_PX}×${STAGE_PX} and scaled to fit.
266
+ ${depNotes.length ? `<br>deps: ${depNotes.map((n) => escapeHtml(n)).join('<br>')}` : ''}
267
+ </div>
268
+ ${FIT_SNIPPET}
269
+ <script>
270
+ let index = 0, seed = null;
271
+ const stage = document.getElementById('stage');
272
+ function params() {
273
+ const out = {};
274
+ for (const el of document.querySelectorAll('[data-key]')) {
275
+ out[el.dataset.key] = el.dataset.kind === 'bool' ? String(el.checked) : String(el.value);
276
+ }
277
+ return out;
278
+ }
279
+ function url(extra) {
280
+ const q = new URLSearchParams({tokenId: String(index), ...params(), ...(extra || {})});
281
+ if (seed) q.set('seed', seed);
282
+ return '/view?' + q.toString();
283
+ }
284
+ function render() {
285
+ document.getElementById('traits').textContent = '—';
286
+ const d = document.getElementById('done'); d.textContent = 'waiting…'; d.className = 'dim';
287
+ const u = url();
288
+ stage.src = u;
289
+ document.getElementById('viewLink').href = u;
290
+ document.getElementById('idx').textContent = '#' + index;
291
+ }
292
+ function setSeed(s) { seed = s; document.getElementById('seedLabel').textContent = s.slice(0, 10) + '…' + s.slice(-4); }
293
+ document.getElementById('new').onclick = async () => {
294
+ const r = await fetch('/api/seed'); setSeed((await r.json()).seed); render();
295
+ };
296
+ document.getElementById('next').onclick = () => { index++; seed = null; boot(); };
297
+ document.getElementById('prev').onclick = () => { if (index > 0) { index--; seed = null; boot(); } };
298
+ document.getElementById('seedLabel').onclick = () => seed && navigator.clipboard?.writeText(seed);
299
+ for (const el of document.querySelectorAll('[data-key]')) el.addEventListener('change', render);
300
+ window.addEventListener('message', (e) => {
301
+ if (!e.data || !e.data.abxPreview) return;
302
+ const t = e.data.traits;
303
+ document.getElementById('traits').textContent = t && Object.keys(t).length
304
+ ? Object.entries(t).map(([k, v]) => k + ' ' + v).join(' · ')
305
+ : 'none reported — abx.traits({…}) is the ONLY thing that becomes attributes';
306
+ document.getElementById('traits').className = 'traits' + (t && Object.keys(t).length ? '' : ' warn');
307
+ const d = document.getElementById('done');
308
+ d.textContent = e.data.done ? 'abx.done() ✓ ' + e.data.t + 'ms' : 'no abx.done() yet — stills capture on a timeout fallback';
309
+ d.className = e.data.done ? 'ok' : 'warn';
310
+ });
311
+ async function boot() { const r = await fetch('/api/seed?index=' + index); setSeed((await r.json()).seed); render(); }
312
+ boot();
313
+ </script></body></html>`;
314
+ }
315
+ function gridPage(count) {
316
+ const cells = Array.from({ length: count }, (_, i) => {
317
+ const seed = previewSeed(i);
318
+ const src = `/view?tokenId=${i}&seed=${seed}`;
319
+ return `<figure><div class="stage"><iframe src="${src}" loading="lazy" title="seed ${i}"></iframe></div>
320
+ <figcaption><a href="${src}" target="_blank">#${i}</a> <span>${seed.slice(0, 10)}…</span></figcaption></figure>`;
321
+ }).join('\n');
322
+ return `<!doctype html><html><head><meta charset="utf-8"><title>abx preview — grid</title>
323
+ <style>
324
+ :root{color-scheme:dark}
325
+ body{margin:0;background:#0d0d10;color:#e6e6ea;font:13px/1.5 ui-sans-serif,system-ui,sans-serif}
326
+ h1{font-size:14px;font-weight:600;padding:12px 16px;margin:0;border-bottom:1px solid #24242c;background:#131318}
327
+ h1 span{color:#6b6b7b;font-weight:400}
328
+ .wrap{display:grid;grid-template-columns:repeat(auto-fill,minmax(240px,1fr));gap:14px;padding:16px}
329
+ figure{margin:0}
330
+ ${STAGE_CSS}
331
+ figcaption{padding:5px 2px;color:#9a9aa8;font-family:ui-monospace,Menlo,monospace;font-size:11px}
332
+ figcaption span{color:#5b5b6b}
333
+ figcaption a{color:#9a9aa8;text-decoration:none}figcaption a:hover{color:#e6e6ea}
334
+ </style></head><body>
335
+ <h1>${count} seeds, live <span>— every frame is the real preview document, animated. Rendered at ${STAGE_PX}×${STAGE_PX}, scaled to fit. Click a number to open one.</span></h1>
336
+ <div class="wrap">${cells}</div>
337
+ ${FIT_SNIPPET}</body></html>`;
338
+ }
339
+ // ── the server ───────────────────────────────────────────────────────────────────
340
+ const MIME = {
341
+ '.html': 'text/html; charset=utf-8', '.js': 'text/javascript; charset=utf-8',
342
+ '.mjs': 'text/javascript; charset=utf-8', '.css': 'text/css; charset=utf-8',
343
+ '.json': 'application/json; charset=utf-8', '.png': 'image/png', '.jpg': 'image/jpeg',
344
+ '.jpeg': 'image/jpeg', '.gif': 'image/gif', '.svg': 'image/svg+xml', '.webp': 'image/webp',
345
+ '.wasm': 'application/wasm', '.woff2': 'font/woff2', '.ttf': 'font/ttf', '.mp3': 'audio/mpeg',
346
+ };
347
+ export async function startPreviewServer(cfg, port) {
348
+ const { notes } = previewDepTags(cfg.deps);
349
+ const server = createServer((req, res) => {
350
+ void (async () => {
351
+ const u = new URL(req.url ?? '/', 'http://localhost');
352
+ const send = (code, type, body) => {
353
+ // Never cache: the whole point is that a refresh picks up the edit you just made.
354
+ res.writeHead(code, { 'content-type': type, 'cache-control': 'no-store' });
355
+ res.end(body);
356
+ };
357
+ try {
358
+ if (u.pathname === '/')
359
+ return send(200, MIME['.html'], studioPage(cfg, notes));
360
+ if (u.pathname === '/api/seed') {
361
+ const idx = u.searchParams.get('index');
362
+ const seed = idx === null ? randomSeed() : previewSeed(Number(idx) || 0);
363
+ return send(200, MIME['.json'], JSON.stringify({ seed }));
364
+ }
365
+ if (u.pathname === '/grid') {
366
+ const count = Math.min(Math.max(Number(u.searchParams.get('count') ?? 9) || 9, 1), 64);
367
+ return send(200, MIME['.html'], gridPage(count));
368
+ }
369
+ if (u.pathname === '/view') {
370
+ const tokenId = String(Number(u.searchParams.get('tokenId') ?? 0) || 0);
371
+ const seed = normalizeSeed(u.searchParams.get('seed') ?? undefined, Number(tokenId));
372
+ const params = {};
373
+ for (const s of cfg.schemas) {
374
+ const v = u.searchParams.get(s.key);
375
+ if (v !== null)
376
+ params[s.key] = v;
377
+ }
378
+ const report = u.searchParams.get('report') !== '0';
379
+ return send(200, MIME['.html'], await renderViewDocument(cfg, seed, tokenId, params, report));
380
+ }
381
+ // Directory mode: serve the build's own assets under a fixed base.
382
+ if (cfg.source.kind === 'dir' && u.pathname.startsWith('/__abx_code/')) {
383
+ const rel = decodeURIComponent(u.pathname.slice('/__abx_code/'.length));
384
+ const root = resolvePath(cfg.source.path);
385
+ const target = resolvePath(join(root, rel));
386
+ // Path-traversal guard: a build asset can never escape the declared root.
387
+ if (target !== root && !target.startsWith(root + '/'))
388
+ return send(403, 'text/plain', 'forbidden');
389
+ const body = await readFile(target);
390
+ return send(200, MIME[extname(target).toLowerCase()] ?? 'application/octet-stream', body);
391
+ }
392
+ send(404, 'text/plain', 'not found');
393
+ }
394
+ catch (err) {
395
+ send(500, 'text/plain', `preview error: ${err.message}`);
396
+ }
397
+ })();
398
+ });
399
+ const actual = await new Promise((res2, rej) => {
400
+ server.on('error', rej);
401
+ // Port 0 ⇒ let the OS pick, so a busy studio port never blocks a --shoot run.
402
+ server.listen(port, () => res2(server.address().port));
403
+ });
404
+ return {
405
+ port: actual,
406
+ url: `http://localhost:${actual}`,
407
+ close: () => new Promise((res2) => server.close(() => res2())),
408
+ };
409
+ }
410
+ /**
411
+ * Render `count` seeds from a running preview server to PNGs, collecting each frame's reported
412
+ * traits. This is how an agent (which cannot open localhost) sees the work — and because it drives
413
+ * the same `/view` document the creator sees, there is nothing to keep in sync.
414
+ */
415
+ export async function shootPreview(base, outDir, count, opts = {}) {
416
+ // Playwright is a BUILD-TIME type dependency only (a `devDependency` of this package), never a
417
+ // runtime one: `--shoot` is opt-in and the interactive studio needs no browser at all, so shipping
418
+ // it as a real dependency would force every `abx` install to pull a browser driver it won't use.
419
+ // Hence: declared for `tsc`, imported dynamically, and absence handled below.
420
+ // Do NOT promote this to `dependencies`, and do NOT drop the devDependency — an undeclared
421
+ // `import('playwright')` typechecks locally only if a stray copy sits in some PARENT directory of
422
+ // the checkout, then fails in CI with TS2307. That exact hole broke a release.
423
+ let chromium;
424
+ try {
425
+ ({ chromium } = await import('playwright'));
426
+ }
427
+ catch {
428
+ throw new Error('--shoot needs Playwright + its Chromium build (the interactive preview does not — that runs in YOUR browser).\n' +
429
+ ' install: npm i -D playwright && npx playwright install chromium\n' +
430
+ ' or drop --shoot and open the preview URL yourself.');
431
+ }
432
+ // Same logical square the interactive stage uses, so a shot frames the piece identically.
433
+ const width = opts.width ?? STAGE_PX;
434
+ const timeoutMs = opts.timeoutMs ?? 10_000;
435
+ await mkdir(outDir, { recursive: true });
436
+ const browser = await chromium.launch();
437
+ try {
438
+ const page = await browser.newPage({ viewport: { width, height: width } });
439
+ const out = [];
440
+ for (let i = 0; i < count; i++) {
441
+ const seed = previewSeed(i);
442
+ await page.goto(`${base}/view?tokenId=${i}&seed=${seed}&report=0`, { waitUntil: 'load' });
443
+ // Wait for the sketch's own completion signal; a piece that never calls abx.done() (or
444
+ // animates forever) still gets captured — same timeout fallback the render effect uses.
445
+ await page
446
+ .waitForFunction('window.abx && (window.abx.__done || window.abx.__traits)', { timeout: timeoutMs })
447
+ .catch(() => { });
448
+ const file = join(outDir, `seed-${i}.png`);
449
+ await page.screenshot({ path: file });
450
+ const probe = (await page.evaluate('({traits: (window.abx && window.abx.__traits) || null, done: !!(window.abx && window.abx.__done)})'));
451
+ out.push({ seed, file, traits: probe.traits, done: probe.done });
452
+ }
453
+ await writeFile(join(outDir, 'traits.json'), JSON.stringify(out.map(({ seed, traits, done }) => ({ seed, traits, done })), null, 2));
454
+ return out;
455
+ }
456
+ finally {
457
+ await browser.close();
458
+ }
459
+ }
460
+ // ── flag surface ─────────────────────────────────────────────────────────────────
461
+ export const PREVIEW_FLAGS = new Set([
462
+ 'script', 'code-dir', 'schema', 'dep', 'port', 'shoot', 'count', 'width', 'timeout-ms',
463
+ ]);
464
+ /** Resolve `--script`/`--code-dir` into a source, with the same either-or rule as `deploy-code`. */
465
+ export function previewSourceFromFlags(flags) {
466
+ const script = flags.script && flags.script !== 'true' ? String(flags.script) : undefined;
467
+ const dir = flags['code-dir'] && flags['code-dir'] !== 'true' ? String(flags['code-dir']) : undefined;
468
+ if (script && dir)
469
+ throw new Error('pass either --script <file> or --code-dir <dir>, not both.');
470
+ if (script)
471
+ return { kind: 'script', path: script };
472
+ if (dir)
473
+ return { kind: 'dir', path: dir };
474
+ throw new Error('abx preview needs the program: --script <file.js> (a single sketch) or --code-dir <dir> (a build).');
475
+ }
476
+ export function previewConfigFromFlags(flags) {
477
+ return {
478
+ source: previewSourceFromFlags(flags),
479
+ schemas: parseSchemaSpecs(flags.schema),
480
+ deps: parseDepFlag(flags.dep),
481
+ };
482
+ }
483
+ //# sourceMappingURL=preview.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preview.js","sourceRoot":"","sources":["../src/preview.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@artblocks/abx-cli",
3
- "version": "0.1.0-alpha.3",
3
+ "version": "0.1.0-alpha.4",
4
4
  "license": "MIT",
5
5
  "description": "ABX CLI ('abx') — the agentic UX surface of the Self-Host Toolkit (Layer 3). Deploy, index, serve, and demo a self-hosted ABX project end to end. Wraps the SDK; runs a different implementation and the protocol works identically.",
6
6
  "type": "module",
@@ -38,14 +38,17 @@
38
38
  },
39
39
  "dependencies": {
40
40
  "viem": "^2.21.0",
41
- "@artblocks/abx-sdk": "0.1.0-alpha.0",
42
41
  "@artblocks/abx-indexer": "0.1.0-alpha.0",
42
+ "@artblocks/abx-sdk": "0.1.0-alpha.0",
43
43
  "@artblocks/abx-storage": "0.1.0-alpha.0",
44
- "@artblocks/abx-token-api": "0.1.0-alpha.0"
44
+ "@artblocks/abx-token-api": "0.1.0-alpha.1"
45
45
  },
46
46
  "optionalDependencies": {
47
47
  "@artblocks/abx-effects": "0.1.0-alpha.0"
48
48
  },
49
+ "devDependencies": {
50
+ "playwright": "1.61.1"
51
+ },
49
52
  "scripts": {
50
53
  "build": "tsc -b tsconfig.build.json"
51
54
  },