@artblocks/abx-cli 0.1.0-alpha.5 → 0.1.0-alpha.6
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/dist/config.d.ts +11 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +19 -0
- package/dist/config.js.map +1 -1
- package/dist/main.js +231 -73
- package/dist/main.js.map +1 -1
- package/dist/prompt.d.ts +17 -0
- package/dist/prompt.d.ts.map +1 -0
- package/dist/prompt.js +19 -0
- package/dist/prompt.js.map +1 -0
- package/dist/signer.d.ts.map +1 -1
- package/dist/signer.js +7 -0
- package/dist/signer.js.map +1 -1
- package/dist/update-check.d.ts +31 -4
- package/dist/update-check.d.ts.map +1 -1
- package/dist/update-check.js +58 -10
- package/dist/update-check.js.map +1 -1
- package/package.json +4 -4
- package/skill/SKILL.md +3 -3
package/dist/config.d.ts
CHANGED
|
@@ -8,6 +8,17 @@ export declare function dataDir(): string;
|
|
|
8
8
|
* duplicated inline — that drift is exactly how `deploy-code` shipped without the guard).
|
|
9
9
|
*/
|
|
10
10
|
export declare function loopbackBaseUrl(baseUrl: string): boolean;
|
|
11
|
+
/**
|
|
12
|
+
* A short faucet pointer for a testnet — a 0-balance signer's #1 next step. A known URL plus a
|
|
13
|
+
* search hint (URLs rot; the search always works), so "fund it" is never a dead end.
|
|
14
|
+
*
|
|
15
|
+
* Lives here rather than in main.ts because the browser-wallet signing prompt needs it too, and
|
|
16
|
+
* importing main.ts would execute the CLI. That prompt is the one funding surface `warnUnfunded`
|
|
17
|
+
* can't cover: on the `--sign` lane without `--for` we don't learn the address until the wallet
|
|
18
|
+
* connects, so the up-front balance check never runs and the only warning a creator would get is
|
|
19
|
+
* a failed transaction.
|
|
20
|
+
*/
|
|
21
|
+
export declare function faucetHint(chainKey: string): string;
|
|
11
22
|
/** Canonical clone factory for the active chain — flag override → `ABX_FACTORY` → manifest. */
|
|
12
23
|
export declare function factoryAddress(override?: string): Address | null;
|
|
13
24
|
/** Canonical Series clone factory — flag override → `ABX_SERIES_FACTORY` → manifest. */
|
package/dist/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAEA,OAAO,EAGL,KAAK,UAAU,EACf,KAAK,qBAAqB,EAC3B,MAAM,wBAAwB,CAAC;AAChC,OAAO,EASL,KAAK,OAAO,EACb,MAAM,oBAAoB,CAAC;AAoB5B,wBAAgB,OAAO,IAAI,MAAM,CAEhC;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAExD;AAOD,+FAA+F;AAC/F,wBAAgB,cAAc,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,CAEhE;AAED,wFAAwF;AACxF,wBAAgB,oBAAoB,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,CAEtE;AAED,wFAAwF;AACxF,wBAAgB,eAAe,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,CAEjE;AAED,mGAAmG;AACnG,wBAAgB,iBAAiB,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,CAEnE;AAED,iGAAiG;AACjG,wBAAgB,uBAAuB,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,CAEzE;AAID,yGAAyG;AACzG,MAAM,WAAW,gBAAgB;IAC/B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAC;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,GAAG,cAAc,CAAC;IACpC;;4CAEwC;IACxC,aAAa,CAAC,EAAE,SAAS,GAAG,KAAK,CAAC;CACnC;AAED,wFAAwF;AACxF,wBAAgB,mBAAmB,CAAC,EAAE,GAAE,gBAAqB,GAAG,SAAS,GAAG,KAAK,CAGhF;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,EAAE,GAAE,gBAAqB,GAAG,qBAAqB,CAgD/E;AAED,wEAAwE;AACxE,wBAAgB,eAAe,IAAI,MAAM,CAExC;AAED,qFAAqF;AACrF,wBAAgB,iBAAiB,CAAC,EAAE,GAAE,gBAAqB,GAAG;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,GAAG,KAAK,GAAG,SAAS,CAAA;CAAC,CAIlH;AAaD,6EAA6E;AAC7E,wBAAgB,kBAAkB,IAAI,MAAM,CAE3C;AAOD;;;;GAIG;AACH,wBAAgB,cAAc,IAAI,UAAU,GAAG,SAAS,CAKvD;AAED,gGAAgG;AAChG,wBAAgB,gBAAgB,IAAI;IAAC,GAAG,EAAE,UAAU,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAC,CAQrG"}
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAEA,OAAO,EAGL,KAAK,UAAU,EACf,KAAK,qBAAqB,EAC3B,MAAM,wBAAwB,CAAC;AAChC,OAAO,EASL,KAAK,OAAO,EACb,MAAM,oBAAoB,CAAC;AAoB5B,wBAAgB,OAAO,IAAI,MAAM,CAEhC;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAExD;AAED;;;;;;;;;GASG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAQnD;AAOD,+FAA+F;AAC/F,wBAAgB,cAAc,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,CAEhE;AAED,wFAAwF;AACxF,wBAAgB,oBAAoB,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,CAEtE;AAED,wFAAwF;AACxF,wBAAgB,eAAe,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,CAEjE;AAED,mGAAmG;AACnG,wBAAgB,iBAAiB,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,CAEnE;AAED,iGAAiG;AACjG,wBAAgB,uBAAuB,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,CAEzE;AAID,yGAAyG;AACzG,MAAM,WAAW,gBAAgB;IAC/B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAC;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,GAAG,cAAc,CAAC;IACpC;;4CAEwC;IACxC,aAAa,CAAC,EAAE,SAAS,GAAG,KAAK,CAAC;CACnC;AAED,wFAAwF;AACxF,wBAAgB,mBAAmB,CAAC,EAAE,GAAE,gBAAqB,GAAG,SAAS,GAAG,KAAK,CAGhF;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,EAAE,GAAE,gBAAqB,GAAG,qBAAqB,CAgD/E;AAED,wEAAwE;AACxE,wBAAgB,eAAe,IAAI,MAAM,CAExC;AAED,qFAAqF;AACrF,wBAAgB,iBAAiB,CAAC,EAAE,GAAE,gBAAqB,GAAG;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,GAAG,KAAK,GAAG,SAAS,CAAA;CAAC,CAIlH;AAaD,6EAA6E;AAC7E,wBAAgB,kBAAkB,IAAI,MAAM,CAE3C;AAOD;;;;GAIG;AACH,wBAAgB,cAAc,IAAI,UAAU,GAAG,SAAS,CAKvD;AAED,gGAAgG;AAChG,wBAAgB,gBAAgB,IAAI;IAAC,GAAG,EAAE,UAAU,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAC,CAQrG"}
|
package/dist/config.js
CHANGED
|
@@ -30,6 +30,25 @@ export function dataDir() {
|
|
|
30
30
|
export function loopbackBaseUrl(baseUrl) {
|
|
31
31
|
return /^https?:\/\/(localhost|127\.0\.0\.1|0\.0\.0\.0|\[::1\])(?:[:/]|$)/i.test(baseUrl);
|
|
32
32
|
}
|
|
33
|
+
/**
|
|
34
|
+
* A short faucet pointer for a testnet — a 0-balance signer's #1 next step. A known URL plus a
|
|
35
|
+
* search hint (URLs rot; the search always works), so "fund it" is never a dead end.
|
|
36
|
+
*
|
|
37
|
+
* Lives here rather than in main.ts because the browser-wallet signing prompt needs it too, and
|
|
38
|
+
* importing main.ts would execute the CLI. That prompt is the one funding surface `warnUnfunded`
|
|
39
|
+
* can't cover: on the `--sign` lane without `--for` we don't learn the address until the wallet
|
|
40
|
+
* connects, so the up-front balance check never runs and the only warning a creator would get is
|
|
41
|
+
* a failed transaction.
|
|
42
|
+
*/
|
|
43
|
+
export function faucetHint(chainKey) {
|
|
44
|
+
const url = {
|
|
45
|
+
'base-sepolia': 'https://portal.cdp.coinbase.com/products/faucet',
|
|
46
|
+
sepolia: 'https://www.alchemy.com/faucets/ethereum-sepolia',
|
|
47
|
+
};
|
|
48
|
+
return url[chainKey]
|
|
49
|
+
? `get free test ETH from a ${chainKey} faucet (${url[chainKey]} — or search "${chainKey} faucet"), usually ≤1 min`
|
|
50
|
+
: `get test ETH from a "${chainKey}" faucet`;
|
|
51
|
+
}
|
|
33
52
|
// ── canonical infrastructure (shipped manifest → env → flag) ─────────────────
|
|
34
53
|
// Thin CLI wrappers over the SDK resolvers, pinned to the active chain. Return null (not
|
|
35
54
|
// undefined) to read cleanly at call sites (`factoryAddress() ?? 'none'`). `null` means the
|
package/dist/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
package/dist/main.js
CHANGED
|
@@ -60,6 +60,7 @@ import { AGENT_SKILL_PARENTS, checkForCliUpdate, compareVersions, installedSkill
|
|
|
60
60
|
import { analyzeScript, recommendLane } from './inspect.js';
|
|
61
61
|
import { previewConfigFromFlags, previewDepTags, shootPreview, startPreviewServer, DEFAULT_PREVIEW_PORT, PREVIEW_FLAGS } from './preview.js';
|
|
62
62
|
import { parseSchemaSpecs, describeSchema } from './schema.js';
|
|
63
|
+
import { declinesSkillInstall } from './prompt.js';
|
|
63
64
|
import { parseSeriesTraits, looksPerTokenAttributes, parseSeriesTraitsById } from './series-traits.js';
|
|
64
65
|
/** The `--schema` type/auth/format catalog, shown wherever the CLI nudges `--schema`. Kept accurate
|
|
65
66
|
* to the on-chain enums (PARAM_TYPES / AUTH_OPTIONS) + the Select-options / Range-bounds format —
|
|
@@ -77,7 +78,7 @@ import { cmdTransfer, cmdMint, cmdSetMinter, cmdSetMaxInvocations, cmdConfigureP
|
|
|
77
78
|
import { openWalletSession, signTx } from './signer.js';
|
|
78
79
|
import { remoteAddProject, remoteRemoveProject } from './remote.js';
|
|
79
80
|
import { buildMigrationPlan, repinNodeCustody, verifyParity } from './migrate.js';
|
|
80
|
-
import { activeBackendId, arweaveKeyFilePath, backendResolution, ensureArweaveJwk, factoryAddress, seriesFactoryAddress, fixedPriceMinterAddress, loadArweaveJwk, loopbackBaseUrl, rendererAddress, storageOptions, storageSignerChoice, } from './config.js';
|
|
81
|
+
import { activeBackendId, arweaveKeyFilePath, backendResolution, ensureArweaveJwk, factoryAddress, seriesFactoryAddress, fixedPriceMinterAddress, loadArweaveJwk, loopbackBaseUrl, faucetHint, rendererAddress, storageOptions, storageSignerChoice, } from './config.js';
|
|
81
82
|
const CHAIN = process.env.ABX_CHAIN ?? DEFAULT_CHAIN_KEY;
|
|
82
83
|
// Block explorer base per chain (keyed by EIP-155 chainId), for the tx/address links the CLI prints.
|
|
83
84
|
const EXPLORERS = {
|
|
@@ -297,17 +298,6 @@ async function detectCanonicalFactory(address, override, stored) {
|
|
|
297
298
|
}
|
|
298
299
|
return factoryAddress() ?? undefined;
|
|
299
300
|
}
|
|
300
|
-
/** A short faucet pointer for the active testnet — a 0-balance signer's #1 next step. A known URL
|
|
301
|
-
* plus a search hint (URLs rot; the search always works), so "fund it" isn't a dead end. */
|
|
302
|
-
function faucetHint(chainKey) {
|
|
303
|
-
const url = {
|
|
304
|
-
'base-sepolia': 'https://portal.cdp.coinbase.com/products/faucet',
|
|
305
|
-
sepolia: 'https://www.alchemy.com/faucets/ethereum-sepolia',
|
|
306
|
-
};
|
|
307
|
-
return url[chainKey]
|
|
308
|
-
? `get free test ETH from a ${chainKey} faucet (${url[chainKey]} — or search "${chainKey} faucet"), usually ≤1 min`
|
|
309
|
-
: `get test ETH from a "${chainKey}" faucet`;
|
|
310
|
-
}
|
|
311
301
|
// Funding preflight — a 0-balance signer fails only at the tx, with a confusing error. Surface it
|
|
312
302
|
// up front. Especially the wallet lane (--sign/--for), which has no env key for `doctor` to check.
|
|
313
303
|
async function warnUnfunded(publicClient, address) {
|
|
@@ -987,7 +977,7 @@ async function cmdDeploy(flags, serveAfter) {
|
|
|
987
977
|
// lockable) — mirrors the description model. On-chain wins if both ever set the same trait.
|
|
988
978
|
const traits = parseDeployTraits(flags);
|
|
989
979
|
console.log(serveAfter
|
|
990
|
-
? bold(`\n ABX
|
|
980
|
+
? bold(`\n ABX · your first token\n ${dim("we'll put art on a blockchain — then delete our copy and get all of it back")}`)
|
|
991
981
|
: bold(`\n ABX Self-Host Toolkit — deploy\n ${dim('a project, served from chain alone')}`));
|
|
992
982
|
// Signing lane. `demo` used to hard-force the hot lane, which SILENTLY dropped `--sign`: with no
|
|
993
983
|
// env key it died confusingly, and WITH one it signed from that key while the operator had asked
|
|
@@ -1048,7 +1038,7 @@ async function cmdDeploy(flags, serveAfter) {
|
|
|
1048
1038
|
if (signer)
|
|
1049
1039
|
await warnUnfunded(publicClient, signer);
|
|
1050
1040
|
}
|
|
1051
|
-
step('Trust anchor');
|
|
1041
|
+
step(serveAfter ? 'Who vouches for this token?' : 'Trust anchor');
|
|
1052
1042
|
let factory;
|
|
1053
1043
|
if (dryRun) {
|
|
1054
1044
|
const existing = factoryAddress(flags.factory);
|
|
@@ -1064,10 +1054,13 @@ async function cmdDeploy(flags, serveAfter) {
|
|
|
1064
1054
|
factory = await ensureFactory(flags.factory, !!flags['bootstrap-factory']);
|
|
1065
1055
|
}
|
|
1066
1056
|
// The demo explains what it just did; `deploy` stays terse. The authenticity point is the least
|
|
1067
|
-
// obvious thing about ABX and the easiest to get wrong, so it's worth
|
|
1057
|
+
// obvious thing about ABX and the easiest to get wrong, so it's worth spelling out — but in plain
|
|
1058
|
+
// language, with the actual term parked in a dim aside for whoever wants to look it up.
|
|
1068
1059
|
if (serveAfter) {
|
|
1069
|
-
|
|
1070
|
-
|
|
1060
|
+
console.log(` ${g('✦')} anyone can write a contract that ${bold('claims')} to be an ABX token`);
|
|
1061
|
+
console.log(` ${g('✦')} only this one factory can make a token that ${bold('is')} one`);
|
|
1062
|
+
info(dim('so "is this real?" is a yes/no question anyone can ask the chain — not a matter of trusting us'));
|
|
1063
|
+
info(dim(`the factory answers it on-chain: isAbxClone(yourToken) · ${EXPLORER}/address/${factory}`));
|
|
1071
1064
|
}
|
|
1072
1065
|
// --onchain-uri: resolve tokenURI/contractURI fully on-chain via the canonical renderer
|
|
1073
1066
|
// (the JSON is assembled from on-chain fields → no resolver needed, ever). The off-chain
|
|
@@ -1075,18 +1068,32 @@ async function cmdDeploy(flags, serveAfter) {
|
|
|
1075
1068
|
// --onchain-image: stage the --image bytes on-chain (chunk store, ownerless) and bake a
|
|
1076
1069
|
// `reader` field into the deploy — so large on-chain content needs NO post-deploy tx. It
|
|
1077
1070
|
// implies on-chain URI resolution (the renderer emits the reader-backed image).
|
|
1078
|
-
const onchainImage = !!flags['onchain-image'];
|
|
1079
|
-
const onChainUri = !!flags['onchain-uri'] || onchainImage;
|
|
1080
|
-
// On-chain traits when explicitly asked, or implied by --onchain-uri (the renderer can only
|
|
1081
|
-
// emit on-chain fields, so off-chain-only traits would be invisible there). Else off-chain.
|
|
1082
|
-
const traitsOnchain = traits.length > 0 && (!!flags['traits-onchain'] || onChainUri);
|
|
1083
1071
|
// A fully on-chain token self-resolves via the renderer; the stored off-chain pointer is
|
|
1084
1072
|
// never read while a renderer is set. So bake a real URL only if one was explicitly given —
|
|
1085
1073
|
// otherwise leave it EMPTY rather than baking a misleading localhost into the contract.
|
|
1086
1074
|
const hasPublicUrl = !!(flags['public-base-url'] || process.env.ABX_PUBLIC_BASE_URL);
|
|
1075
|
+
const onchainImage = !!flags['onchain-image'];
|
|
1076
|
+
// `abx demo` defaults to FULLY ON-CHAIN. Its default art is a generative SVG, which the renderer
|
|
1077
|
+
// can inline — so the token self-resolves and, crucially, NO localhost gets baked into the
|
|
1078
|
+
// contract as the tokenURI base. The old default shipped a first-ever token that resolved for
|
|
1079
|
+
// nobody but its author (broken on every marketplace, dead the moment `abx serve` stops) and
|
|
1080
|
+
// taught that as the normal shape of an NFT. It also undercut the demo's own claim: with the art
|
|
1081
|
+
// on-chain, "rebuilt from the chain alone" now covers the IMAGE, not just the metadata.
|
|
1082
|
+
//
|
|
1083
|
+
// Opting back into off-chain custody is anything that says "I have somewhere to host": a real base
|
|
1084
|
+
// URL, an explicit --backend, or a RASTER --image. An SVG --image still goes on-chain — inlining is
|
|
1085
|
+
// exactly what the renderer supports (v1 is SVG-only), so there's no reason to send someone's own
|
|
1086
|
+
// vector art down the localhost path. Raster stays off-chain because forcing it on-chain would
|
|
1087
|
+
// silently inline a placeholder instead of their image.
|
|
1088
|
+
const demoImageInlineable = !flags.image || contentTypeFromPath(flags.image) === 'image/svg+xml';
|
|
1089
|
+
const demoDefaultsOnChain = serveAfter && demoImageInlineable && !flags.backend && !hasPublicUrl;
|
|
1090
|
+
const onChainUri = !!flags['onchain-uri'] || onchainImage || demoDefaultsOnChain;
|
|
1091
|
+
// On-chain traits when explicitly asked, or implied by --onchain-uri (the renderer can only
|
|
1092
|
+
// emit on-chain fields, so off-chain-only traits would be invisible there). Else off-chain.
|
|
1093
|
+
const traitsOnchain = traits.length > 0 && (!!flags['traits-onchain'] || onChainUri);
|
|
1087
1094
|
let renderer = zeroAddress;
|
|
1088
1095
|
if (onChainUri) {
|
|
1089
|
-
step('On-chain renderer');
|
|
1096
|
+
step(serveAfter ? 'What will answer when someone asks about your token' : 'On-chain renderer');
|
|
1090
1097
|
if (dryRun) {
|
|
1091
1098
|
renderer = rendererAddress(flags.renderer) ?? zeroAddress;
|
|
1092
1099
|
info(renderer === zeroAddress ? 'would deploy the canonical renderer first' : `would use renderer ${renderer}`);
|
|
@@ -1094,13 +1101,27 @@ async function cmdDeploy(flags, serveAfter) {
|
|
|
1094
1101
|
else {
|
|
1095
1102
|
renderer = await ensureRenderer(flags.renderer);
|
|
1096
1103
|
}
|
|
1104
|
+
// A first-timer has no idea what a "renderer" is, and the word suggests something that draws
|
|
1105
|
+
// pictures. What it actually does is assemble the JSON a marketplace asks for, on-chain, out of
|
|
1106
|
+
// the fields your contract holds — worth one plain sentence, since it's why no server is needed.
|
|
1107
|
+
if (serveAfter) {
|
|
1108
|
+
info(dim('a marketplace asks your contract a question; this shared contract composes the answer'));
|
|
1109
|
+
info(dim('already deployed, used by every ABX token, owned by no one — you are not paying to set it up'));
|
|
1110
|
+
}
|
|
1097
1111
|
}
|
|
1098
|
-
step(serveAfter ? `
|
|
1099
|
-
//
|
|
1100
|
-
// invisible unless someone says it out loud.
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1112
|
+
step(serveAfter ? `Mint it · one transaction on ${CHAIN}` : `Deploy a ${DIMENSIONS[dimension].label} (--type ${dimension}) to ${CHAIN}`);
|
|
1113
|
+
// What the chain ends up holding is the single most useful thing to understand about an ABX token,
|
|
1114
|
+
// and it's invisible unless someone says it out loud. Two honest versions, because the answer is
|
|
1115
|
+
// genuinely different per lane. Demo only — `deploy` prints the same facts per-field.
|
|
1116
|
+
if (serveAfter && onChainUri) {
|
|
1117
|
+
console.log(` Your art goes ${bold('INTO')} the contract. Not a link to it — the image itself.`);
|
|
1118
|
+
console.log(` ${g('✦')} the chain will hold ${dim('your art · your name on it · your royalty · you as owner')}`);
|
|
1119
|
+
console.log(` ${g('✦')} you will need ${dim('nothing else. no server, no IPFS pin, no monthly bill to forget')}`);
|
|
1120
|
+
}
|
|
1121
|
+
else if (serveAfter) {
|
|
1122
|
+
console.log(` ${g('✦')} the chain will hold ${dim('your name · your royalty · you as owner · a fingerprint of the art')}`);
|
|
1123
|
+
console.log(` ${g('✦')} this computer holds ${dim('the image bytes themselves')}`);
|
|
1124
|
+
info(dim('the chain proves the bytes are unaltered; it does not store them (that fingerprint is a keccak256 hash)'));
|
|
1104
1125
|
}
|
|
1105
1126
|
// Off-chain custody (no renderer) bakes the resolver URL straight into the on-chain
|
|
1106
1127
|
// tokenURI/contractURI at deploy. A localhost / loopback URL there resolves for NO ONE —
|
|
@@ -1128,7 +1149,14 @@ async function cmdDeploy(flags, serveAfter) {
|
|
|
1128
1149
|
}
|
|
1129
1150
|
}
|
|
1130
1151
|
}
|
|
1131
|
-
if (onChainUri) {
|
|
1152
|
+
if (onChainUri && serveAfter) {
|
|
1153
|
+
// The demo's version of the same fact, in words a first-timer can act on. Naming what we are
|
|
1154
|
+
// NOT doing matters here: a localhost URL written into a contract is the single most common way
|
|
1155
|
+
// a first NFT ends up permanently broken, and the demo used to model exactly that.
|
|
1156
|
+
info(dim('nothing points at this computer — no http://localhost anywhere in your contract.'));
|
|
1157
|
+
info(dim('anyone can read your token from the chain, forever, with you offline.'));
|
|
1158
|
+
}
|
|
1159
|
+
else if (onChainUri) {
|
|
1132
1160
|
info('tokenURI/contractURI resolve ON-CHAIN via the renderer — no resolver, no server, no localhost.');
|
|
1133
1161
|
if (!hasPublicUrl)
|
|
1134
1162
|
info('off-chain fallback pointer left empty (the renderer is authoritative); set --public-base-url to bake one anyway.');
|
|
@@ -1305,7 +1333,9 @@ async function cmdDeploy(flags, serveAfter) {
|
|
|
1305
1333
|
// wallet lane + on-chain staging: ONE sign session signs every chunk write AND the deploy.
|
|
1306
1334
|
// The connecting wallet pays for (and is the deployer of) all of it — staging can't precede
|
|
1307
1335
|
// the connect here, so it happens inside the session, then the deploy bakes in the manifest.
|
|
1308
|
-
|
|
1336
|
+
// --onchain-image implies on-chain resolution, so NOTHING points at baseUrl — saying it did was
|
|
1337
|
+
// a flat contradiction of the line above it (and reintroduced the localhost the lane exists to avoid).
|
|
1338
|
+
info('a wallet will become the owner; the token resolves from chain — no URI base is baked in.');
|
|
1309
1339
|
const plan = computeContentPlan(readFileSync(resolvePath(flags.image)), parseCompress(flags.compress)).plan;
|
|
1310
1340
|
const stagingTxs = plan.mode === 'single' ? 1 : plan.txCount;
|
|
1311
1341
|
const session = await openWalletSession({
|
|
@@ -1370,8 +1400,12 @@ async function cmdDeploy(flags, serveAfter) {
|
|
|
1370
1400
|
info(`tx ${EXPLORER}/tx/${r.txHash} (block ${blockNumber})`);
|
|
1371
1401
|
}
|
|
1372
1402
|
else {
|
|
1373
|
-
// wallet lane (off-chain custody) or cold lane: a single deploy tx, no staging
|
|
1374
|
-
|
|
1403
|
+
// wallet lane (off-chain custody OR on-chain URI) or cold lane: a single deploy tx, no staging.
|
|
1404
|
+
// Only claim a URI base when one is actually written — on the on-chain lane this line used to
|
|
1405
|
+
// announce `http://localhost:8787` two lines after promising no localhost anywhere.
|
|
1406
|
+
info(onChainUri
|
|
1407
|
+
? 'a wallet will become the owner; the token resolves from chain — no URI base is baked in.'
|
|
1408
|
+
: `a wallet will become the owner; URIs point at ${baseUrl}`);
|
|
1375
1409
|
const result = await signTx(async (signer) => {
|
|
1376
1410
|
const { clone: predicted, params, salt } = await buildForDeployer(signer);
|
|
1377
1411
|
return prepareDeployOneOfOne({ factory, params, salt, chainId: resolveChain(CHAIN).id, clone: predicted });
|
|
@@ -1384,7 +1418,7 @@ async function cmdDeploy(flags, serveAfter) {
|
|
|
1384
1418
|
blockNumber = result.blockNumber;
|
|
1385
1419
|
ok(`deployed ${clone}`);
|
|
1386
1420
|
}
|
|
1387
|
-
step('Index it — replay the event spine from chain');
|
|
1421
|
+
step(serveAfter ? 'What the chain knows now' : 'Index it — replay the event spine from chain');
|
|
1388
1422
|
const indexer = new SelfHostIndexer();
|
|
1389
1423
|
// Off-chain traits ride in the registration (on-chain ones are already in the contract fields).
|
|
1390
1424
|
const offChainTraits = !traitsOnchain && traits.length ? JSON.stringify(traits) : undefined;
|
|
@@ -1400,12 +1434,19 @@ async function cmdDeploy(flags, serveAfter) {
|
|
|
1400
1434
|
};
|
|
1401
1435
|
indexer.register(baseReg);
|
|
1402
1436
|
const { state, elapsedMs } = await reindexAfterDeploy(indexer, clone);
|
|
1403
|
-
if (
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1437
|
+
if (serveAfter) {
|
|
1438
|
+
if (state.eventCount > 0)
|
|
1439
|
+
ok(`read ${bold(String(state.eventCount))} events straight off ${CHAIN} in ${elapsedMs}ms — no API key, no company's server`);
|
|
1440
|
+
info(`it says: "${state.name}" · owned by ${state.owner} · ${state.isCanonical ? `${g('verified real')} ${dim('(that factory vouched for it)')}` : `${c.orange}unverified${c.reset}`}`);
|
|
1441
|
+
info(dim(`optional features switched on: ${state.extensions.map((e) => e.name.replace(/^abx\.extension\./, '')).join(' · ') || 'none'}`));
|
|
1408
1442
|
walkthroughSpine(state);
|
|
1443
|
+
}
|
|
1444
|
+
else {
|
|
1445
|
+
if (state.eventCount > 0)
|
|
1446
|
+
ok(`reconstructed ${state.eventCount} events in ${elapsedMs}ms — no provider involved`);
|
|
1447
|
+
info(`name "${state.name}" · owner ${state.owner} · canonical: ${state.isCanonical ? 'yes (factory-verified)' : 'unverified'}`);
|
|
1448
|
+
info(`extensions: ${state.extensions.map((e) => e.name).join(', ') || 'none'}`);
|
|
1449
|
+
}
|
|
1409
1450
|
// For off-chain custody (image committed as keccak256), resolve the durable locator (ipfs://…)
|
|
1410
1451
|
// from this machine's content index and store it on the registration — so the LOCAL resolver
|
|
1411
1452
|
// points `image` at IPFS, and `abx add --remote` can ship it to a hosted one (the localhost-image fix).
|
|
@@ -1463,8 +1504,12 @@ async function cmdDeploy(flags, serveAfter) {
|
|
|
1463
1504
|
// while the read-back prints below, which reads like the step failed.
|
|
1464
1505
|
const { url } = await startTokenApiServer({ indexer, port, baseUrl, storage: resolveBackend(storageOptions()) });
|
|
1465
1506
|
if (serveAfter)
|
|
1466
|
-
await walkthroughReadBack(state, url);
|
|
1467
|
-
|
|
1507
|
+
await walkthroughReadBack(state, url, onChainUri);
|
|
1508
|
+
// On the on-chain lane this server is a convenience, not infrastructure — say so, or standing one
|
|
1509
|
+
// up as the finale re-teaches the dependency the whole run just disproved.
|
|
1510
|
+
step(onChainUri ? 'Go look at it' : 'Serve the token API + dashboard');
|
|
1511
|
+
if (onChainUri)
|
|
1512
|
+
info(dim('a local viewer, purely for your eyes — your token does not need it. Ctrl-C whenever; the token stays up.'));
|
|
1468
1513
|
printServing(url, clone);
|
|
1469
1514
|
keepAlive();
|
|
1470
1515
|
}
|
|
@@ -1906,8 +1951,11 @@ async function cmdDeploySeries(flags) {
|
|
|
1906
1951
|
}
|
|
1907
1952
|
else {
|
|
1908
1953
|
// wallet lane (off-chain / inline) or cold lane: a single deploy tx, no staging sequence —
|
|
1909
|
-
// tokenFields is already built.
|
|
1910
|
-
|
|
1954
|
+
// tokenFields is already built. Same correction as the 1/1 lane: only claim a URI base when one
|
|
1955
|
+
// is actually written, or an --onchain-uri Series announces a localhost it never bakes.
|
|
1956
|
+
info(onChainUri
|
|
1957
|
+
? 'a wallet will become the owner; tokens resolve from chain — no URI base is baked in.'
|
|
1958
|
+
: `a wallet will become the owner; URIs point at ${baseUrl}`);
|
|
1911
1959
|
const result = await signTx(async (signer) => {
|
|
1912
1960
|
const { clone: predicted, params, salt } = await buildForDeployer(signer);
|
|
1913
1961
|
return prepareDeploySeries({ factory, params, salt, chainId: resolveChain(CHAIN).id, clone: predicted });
|
|
@@ -2345,9 +2393,9 @@ function walkthroughSpine(state) {
|
|
|
2345
2393
|
const reg = e.register === 2 ? p('ABX') : dim('ERC');
|
|
2346
2394
|
console.log(` ${dim(`#${String(i + 1).padStart(2)}`)} ${reg} ${e.name.padEnd(width)} ${dim(e.what)}`);
|
|
2347
2395
|
});
|
|
2348
|
-
console.log(` ${dim('→')} those ${bold(String(state.events.length))}
|
|
2349
|
-
dim('no
|
|
2350
|
-
console.log(` ${p('ABX')} ${dim('=
|
|
2396
|
+
console.log(` ${dim('→')} those ${bold(String(state.events.length))} lines ${bold('are')} the database. ` +
|
|
2397
|
+
dim('There is no other copy that counts — not ours, not anyone\'s.'));
|
|
2398
|
+
console.log(` ${p('ABX')} ${dim('= ABX\'s own events')} ${dim('ERC')} ${dim('= bog-standard ERC-721/7572, which is why wallets and marketplaces that have never heard of ABX still show your token.')}`);
|
|
2351
2399
|
}
|
|
2352
2400
|
/**
|
|
2353
2401
|
* [4] The claim, demonstrated: delete the local projection and rebuild it from the chain.
|
|
@@ -2357,37 +2405,78 @@ function walkthroughSpine(state) {
|
|
|
2357
2405
|
* fingerprint of everything chain-derived. If ABX's premise is wrong, this step fails loudly.
|
|
2358
2406
|
*/
|
|
2359
2407
|
async function walkthroughRebuild(indexer, address, before) {
|
|
2360
|
-
step('
|
|
2408
|
+
step('The moment of truth · delete it all');
|
|
2361
2409
|
const fpBefore = projectionFingerprint(before);
|
|
2362
2410
|
indexer.dropProjection(address);
|
|
2363
2411
|
const gone = indexer.getProject(address) === null;
|
|
2364
|
-
console.log(` ${dim('
|
|
2412
|
+
console.log(` ${dim('wiping this computer\'s copy …')} ${gone ? g('gone. nothing left locally.') : `${c.orange}⚠ still present${c.reset}`}`);
|
|
2365
2413
|
const { state: after, elapsedMs } = await indexer.reindex(address, { full: true });
|
|
2366
2414
|
const fpAfter = projectionFingerprint(after);
|
|
2367
|
-
console.log(` ${dim(`
|
|
2368
|
-
`${g(
|
|
2415
|
+
console.log(` ${dim(`asking ${CHAIN} to tell us everything again …`)} ` +
|
|
2416
|
+
`${g(`${after.eventCount} events, ${elapsedMs}ms`)}`);
|
|
2369
2417
|
if (fpBefore === fpAfter) {
|
|
2370
|
-
ok(
|
|
2371
|
-
info('
|
|
2418
|
+
ok(bold('byte-for-byte identical.'));
|
|
2419
|
+
info('Your token just survived losing every local file. No backup, no API key, no company —');
|
|
2420
|
+
info(`the chain remembered. ${dim('That is the whole point of ABX.')}`);
|
|
2421
|
+
info(dim(`checked by hashing every chain-derived field, not by eyeballing it: sha256 ${fpAfter.slice(0, 12)}…`));
|
|
2372
2422
|
}
|
|
2373
2423
|
else {
|
|
2374
2424
|
warn('the rebuilt state does NOT match what we just had — that is a real bug, please report it.');
|
|
2375
2425
|
info(`before ${fpBefore.slice(0, 16)}… · after ${fpAfter.slice(0, 16)}…`);
|
|
2376
2426
|
}
|
|
2377
2427
|
}
|
|
2378
|
-
/**
|
|
2379
|
-
|
|
2428
|
+
/**
|
|
2429
|
+
* [5] Read the token back the way a marketplace would.
|
|
2430
|
+
*
|
|
2431
|
+
* Which is genuinely a different act per lane, so it reads from the real source in each case rather
|
|
2432
|
+
* than always going through the local server:
|
|
2433
|
+
* • fully on-chain → call `tokenURI(0)` on the contract. That IS what a marketplace does, and on
|
|
2434
|
+
* this lane the whole answer (art included) comes back from the chain with nothing else running.
|
|
2435
|
+
* • off-chain custody → fetch the resolver, because that's what the baked URI points at.
|
|
2436
|
+
* Reading the on-chain lane over HTTP would have quietly implied the local server was load-bearing
|
|
2437
|
+
* when it isn't — the opposite of the lesson.
|
|
2438
|
+
*/
|
|
2439
|
+
async function walkthroughReadBack(state, baseUrl, onChainUri) {
|
|
2380
2440
|
step('Read it back the way a marketplace would');
|
|
2381
2441
|
const token = state.tokens[0];
|
|
2382
2442
|
if (!token?.minted) {
|
|
2383
2443
|
info('no minted token to read yet.');
|
|
2384
2444
|
return;
|
|
2385
2445
|
}
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
|
|
2446
|
+
if (onChainUri) {
|
|
2447
|
+
info(dim(`calling tokenURI(0) on your contract — the same call OpenSea makes …`));
|
|
2448
|
+
try {
|
|
2449
|
+
const uri = (await makePublicClient({ chainKey: CHAIN }).readContract({
|
|
2450
|
+
address: state.address,
|
|
2451
|
+
abi: oneOfOneImageAbi,
|
|
2452
|
+
functionName: 'tokenURI',
|
|
2453
|
+
args: [0n],
|
|
2454
|
+
}));
|
|
2455
|
+
const json = decodeOnChainJson(uri);
|
|
2456
|
+
if (json) {
|
|
2457
|
+
const parsed = JSON.parse(json);
|
|
2458
|
+
const img = typeof parsed.image === 'string' ? parsed.image : '';
|
|
2459
|
+
console.log(` ${g('✓')} came back with: ${bold(String(parsed.name ?? '(no name)'))}`);
|
|
2460
|
+
console.log(` ${dim(`image: ${img.slice(0, 48)}${img.length > 48 ? '…' : ''}`)}`);
|
|
2461
|
+
// The punchline of the whole lane: a data: URI means the art travelled IN the answer.
|
|
2462
|
+
if (img.startsWith('data:'))
|
|
2463
|
+
info(`${g('the art itself came back in that answer')} ${dim('— no link to follow, nothing to go missing')}`);
|
|
2464
|
+
}
|
|
2465
|
+
else {
|
|
2466
|
+
console.log(` ${dim(uri.slice(0, 160))}${uri.length > 160 ? dim('…') : ''}`);
|
|
2467
|
+
}
|
|
2468
|
+
info(dim('nothing was running to answer that. no server of ours, no server of yours.'));
|
|
2469
|
+
}
|
|
2470
|
+
catch (e) {
|
|
2471
|
+
info(dim(`could not read tokenURI from the chain: ${e.message}`));
|
|
2472
|
+
}
|
|
2473
|
+
console.log(` ${dim('read it yourself any time:')} ${bold(`abx tokenuri ${state.address}`)}`);
|
|
2474
|
+
return;
|
|
2475
|
+
}
|
|
2476
|
+
info(`tokenURI(0) ${dim('on chain →')} ${token.tokenURI ?? dim('(none)')}`);
|
|
2477
|
+
// Off-chain custody: the CHAIN holds a keccak256 commitment to the image and a URI base; this NODE
|
|
2478
|
+
// holds the bytes. That split is the thing worth understanding, so name it rather than implying the
|
|
2479
|
+
// JSON came from the chain.
|
|
2391
2480
|
info(dim('the chain stored a URI base + a keccak256 commitment; this node serves the bytes.'));
|
|
2392
2481
|
try {
|
|
2393
2482
|
const res = await fetch(`${baseUrl}/t/${resolveChain(CHAIN).id}/${state.address}/0`);
|
|
@@ -4459,6 +4548,44 @@ async function cmdMigrate(address, flags) {
|
|
|
4459
4548
|
info('keep the source running until DNS / base-URI propagates (source-only images were already re-pinned above, unless a warning said otherwise).');
|
|
4460
4549
|
}
|
|
4461
4550
|
// ── doctor ────────────────────────────────────────────────────────────────--
|
|
4551
|
+
/**
|
|
4552
|
+
* Doctor's "want me to fix that?" for a missing or stale skill. Three lanes, deliberately:
|
|
4553
|
+
* `--fix` install without asking (CI, scripts, an agent running doctor for someone)
|
|
4554
|
+
* interactive name the exact directories, then ask — Enter accepts, since doctor's whole job is
|
|
4555
|
+
* getting setup right and this is the one check whose fix is a local file copy
|
|
4556
|
+
* non-TTY change NOTHING and print how to do it; a diagnostic must never mutate a
|
|
4557
|
+
* scripted environment just because nobody was there to say no
|
|
4558
|
+
* Honors `--global` / `--agent` so the fix can target the same place an explicit install would.
|
|
4559
|
+
*/
|
|
4560
|
+
async function offerSkillInstall(flags, stale, indent) {
|
|
4561
|
+
const opts = { global: flags.global !== undefined, agent: flags.agent };
|
|
4562
|
+
const src = resolveBundledSkill();
|
|
4563
|
+
if (!src)
|
|
4564
|
+
return; // no bundled skill to install (dev checkout oddity) — the hint above still stands
|
|
4565
|
+
const verb = stale ? 'resync' : 'install';
|
|
4566
|
+
const dests = defaultSkillDests(opts);
|
|
4567
|
+
if (flags.fix === undefined) {
|
|
4568
|
+
if (!process.stdin.isTTY) {
|
|
4569
|
+
console.log(`${indent}${dim(`non-interactive — run \`abx doctor --fix\` (or \`abx skill install\`) to ${verb} it.`)}`);
|
|
4570
|
+
return;
|
|
4571
|
+
}
|
|
4572
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
4573
|
+
const answer = await new Promise((resolve) => {
|
|
4574
|
+
// EOF (Ctrl-D) closes the interface WITHOUT firing the question callback — awaiting only the
|
|
4575
|
+
// callback would hang doctor forever. Treat a closed stream as a decline: the safe direction is
|
|
4576
|
+
// always "change nothing", never "write files because nobody answered".
|
|
4577
|
+
rl.once('close', () => resolve('n'));
|
|
4578
|
+
rl.question(`${indent}${verb} the abx skill into ${bold(dests)} now? [Y/n] `, resolve);
|
|
4579
|
+
});
|
|
4580
|
+
rl.close();
|
|
4581
|
+
if (declinesSkillInstall(answer)) {
|
|
4582
|
+
console.log(`${indent}${dim(`skipped — \`abx skill install\` when you want it.`)}`);
|
|
4583
|
+
return;
|
|
4584
|
+
}
|
|
4585
|
+
}
|
|
4586
|
+
console.log('');
|
|
4587
|
+
installSkillToDefaults(src, opts);
|
|
4588
|
+
}
|
|
4462
4589
|
async function cmdDoctor(flags) {
|
|
4463
4590
|
console.log(bold('\n abx doctor') + dim(` · ${CHAIN}`) + '\n');
|
|
4464
4591
|
// Two visual tiers: PASS/FAIL checks (✓/✗) for things that are either working or broken, and an
|
|
@@ -4475,16 +4602,28 @@ async function cmdDoctor(flags) {
|
|
|
4475
4602
|
const cliVersion = readCliVersion();
|
|
4476
4603
|
const skillVersions = installedSkillVersions();
|
|
4477
4604
|
const staleSkills = skillVersions.filter((v) => compareVersions(cliVersion, v) > 0);
|
|
4478
|
-
|
|
4605
|
+
const skillMissing = skillVersions.length === 0;
|
|
4606
|
+
const skillStale = !skillMissing && staleSkills.length > 0;
|
|
4607
|
+
if (skillMissing) {
|
|
4479
4608
|
check('agent skill', false, `not installed — run ${g('abx skill install')}`);
|
|
4480
4609
|
console.log(`${CONT}${dim('(recommended: let a coding agent drive abx)')}`);
|
|
4481
4610
|
}
|
|
4482
|
-
else if (
|
|
4611
|
+
else if (skillStale) {
|
|
4483
4612
|
check('agent skill', false, `v${staleSkills.join(', v')} behind CLI v${cliVersion} — run ${g('abx skill install')}`);
|
|
4484
4613
|
}
|
|
4485
4614
|
else {
|
|
4486
4615
|
check('agent skill', true, `in sync (v${cliVersion})`);
|
|
4487
4616
|
}
|
|
4617
|
+
// Offer to fix it here rather than only naming the command. `npm i -g` + `abx skill install` was a
|
|
4618
|
+
// two-step install flow where the second step is easy to skip and invisible when skipped (an agent
|
|
4619
|
+
// that never learned abx just... doesn't use it). Doctor is already the documented first run, so
|
|
4620
|
+
// this collapses the flow without an npm `postinstall` hook — which could not work anyway: npm runs
|
|
4621
|
+
// lifecycle scripts with cwd set to the installed package dir (so the skill would land inside
|
|
4622
|
+
// node_modules), pnpm gates install scripts by default, and writing to a user's ~/.claude on
|
|
4623
|
+
// install is the kind of side effect that belongs to the user, not to us.
|
|
4624
|
+
if (skillMissing || skillStale) {
|
|
4625
|
+
await offerSkillInstall(flags, skillStale, CONT);
|
|
4626
|
+
}
|
|
4488
4627
|
console.log('');
|
|
4489
4628
|
// 2. Core environment (✓/✗). Signing-wallet balances are computed here (they need the RPC) but
|
|
4490
4629
|
// printed in the Optional block below, so buffer them.
|
|
@@ -5193,8 +5332,12 @@ const COMMAND_HELP = {
|
|
|
5193
5332
|
${bold('abx set-max-invocations')} <address> --max <N> ${dim('— LOWER the supply cap (Series). Sends a tx.')}
|
|
5194
5333
|
--max <N> the new cap — MONOTONIC: can only DECREASE, and never below what's already minted (else it reverts)`,
|
|
5195
5334
|
doctor: `
|
|
5196
|
-
${bold('abx doctor')} ${dim('— preflight readiness: signing key/wallet, RPC health, canonical factory, storage.
|
|
5335
|
+
${bold('abx doctor')} ${dim('— preflight readiness: agent skill, signing key/wallet, RPC health, canonical factory, storage.')}
|
|
5197
5336
|
--for 0x.. also report that address's balance (fund before signing)
|
|
5337
|
+
${g('--fix')} ${dim('install/resync the agent skill without asking (the one thing doctor can repair)')}
|
|
5338
|
+
${g('--global')} · ${g('--agent')} <a> ${dim('where --fix installs the skill (mirrors `abx skill install`)')}
|
|
5339
|
+
${dim('Read-only apart from --fix. Interactively it OFFERS to install a missing/stale skill; a non-TTY')}
|
|
5340
|
+
${dim('run changes nothing and just prints the command, so scripts and CI are never mutated.')}
|
|
5198
5341
|
${dim('a missing signing key is NOT fatal — the wallet lane (`--sign`) needs no key in `.env`.')}`,
|
|
5199
5342
|
status: `
|
|
5200
5343
|
${bold('abx status')} ${dim('— list the projects this node has indexed, plus node info. Read-only.')}`,
|
|
@@ -5472,6 +5615,31 @@ function installSkillTo(src, dest) {
|
|
|
5472
5615
|
rmSync(dest, { recursive: true, force: true });
|
|
5473
5616
|
cpSync(src, dest, { recursive: true });
|
|
5474
5617
|
}
|
|
5618
|
+
/**
|
|
5619
|
+
* Install the bundled skill into the default per-agent parents (or `~` with `global`), reporting
|
|
5620
|
+
* each destination. Shared by `abx skill install` and `abx doctor`'s offer to fix a missing/stale
|
|
5621
|
+
* skill — one implementation, so the two can't drift on where the skill lands or what it prints.
|
|
5622
|
+
*/
|
|
5623
|
+
function installSkillToDefaults(src, opts = {}) {
|
|
5624
|
+
const version = readSkillVersion(joinPath(src, 'SKILL.md')) ?? readCliVersion();
|
|
5625
|
+
const base = opts.global ? homedir() : process.cwd();
|
|
5626
|
+
const parents = resolveInstallParents(opts.agent);
|
|
5627
|
+
ok(`installed the abx skill v${version}${opts.global ? ' (global, ~)' : ''}:`);
|
|
5628
|
+
for (const parent of parents) {
|
|
5629
|
+
const dest = joinPath(base, parent, SKILL_DIR_NAME);
|
|
5630
|
+
installSkillTo(src, dest);
|
|
5631
|
+
const label = SKILL_PARENT_LABELS[parent];
|
|
5632
|
+
console.log(` ${g(joinPath(parent, SKILL_DIR_NAME))}${label ? dim(' → ' + label) : ''}`);
|
|
5633
|
+
}
|
|
5634
|
+
info('restart your agent so it loads the skill, then ask it to launch an NFT with abx.');
|
|
5635
|
+
info(`the skill is version-locked to this CLI (v${version}); re-run ${g('abx skill install')} after upgrading so the two stay in sync.`);
|
|
5636
|
+
return version;
|
|
5637
|
+
}
|
|
5638
|
+
/** The default skill destinations, as a display string — what doctor's prompt has to name up front. */
|
|
5639
|
+
function defaultSkillDests(opts = {}) {
|
|
5640
|
+
const prefix = opts.global ? '~/' : './';
|
|
5641
|
+
return resolveInstallParents(opts.agent).map((p) => `${prefix}${p}`).join(' and ');
|
|
5642
|
+
}
|
|
5475
5643
|
async function cmdSkill(rest, flags) {
|
|
5476
5644
|
const sub = rest[0] ?? 'install';
|
|
5477
5645
|
const src = resolveBundledSkill();
|
|
@@ -5494,17 +5662,7 @@ async function cmdSkill(rest, flags) {
|
|
|
5494
5662
|
info('restart your agent so it loads the skill, then ask it to launch an NFT with abx.');
|
|
5495
5663
|
return;
|
|
5496
5664
|
}
|
|
5497
|
-
|
|
5498
|
-
const parents = resolveInstallParents(flags.agent);
|
|
5499
|
-
ok(`installed the abx skill v${version}${flags.global !== undefined ? ' (global, ~)' : ''}:`);
|
|
5500
|
-
for (const parent of parents) {
|
|
5501
|
-
const dest = joinPath(base, parent, SKILL_DIR_NAME);
|
|
5502
|
-
installSkillTo(src, dest);
|
|
5503
|
-
const label = SKILL_PARENT_LABELS[parent];
|
|
5504
|
-
console.log(` ${g(joinPath(parent, SKILL_DIR_NAME))}${label ? dim(' → ' + label) : ''}`);
|
|
5505
|
-
}
|
|
5506
|
-
info('restart your agent so it loads the skill, then ask it to launch an NFT with abx.');
|
|
5507
|
-
info(`the skill is version-locked to this CLI (v${version}); re-run ${g('abx skill install')} after upgrading so the two stay in sync.`);
|
|
5665
|
+
installSkillToDefaults(src, { global: flags.global !== undefined, agent: flags.agent });
|
|
5508
5666
|
return;
|
|
5509
5667
|
}
|
|
5510
5668
|
throw new Error('usage: abx skill <install|path> [--agent claude|cursor|codex|gemini|copilot] [--global] [--target <dir>]');
|