@artblocks/abx-cli 0.1.0-alpha.0 → 0.1.0-alpha.2
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/flags.d.ts +6 -0
- package/dist/flags.d.ts.map +1 -1
- package/dist/flags.js +7 -1
- package/dist/flags.js.map +1 -1
- package/dist/main.js +128 -20
- package/dist/main.js.map +1 -1
- package/dist/update-check.d.ts +58 -0
- package/dist/update-check.d.ts.map +1 -0
- package/dist/update-check.js +231 -0
- package/dist/update-check.js.map +1 -0
- package/package.json +3 -3
- package/skill/SKILL.md +4 -0
- package/skill/reference/hosting.md +1 -1
package/dist/flags.d.ts
CHANGED
|
@@ -12,6 +12,12 @@
|
|
|
12
12
|
export type Flags = Record<string, string | undefined>;
|
|
13
13
|
/** Flags where every occurrence counts (values comma-join, in argv order). */
|
|
14
14
|
export declare const REPEATABLE_FLAGS: ReadonlySet<string>;
|
|
15
|
+
/**
|
|
16
|
+
* Flags valid on ANY command (handled centrally in main, not by a command handler), so
|
|
17
|
+
* {@link unknownFlags} never flags them as unrecognized regardless of the per-command allowlist.
|
|
18
|
+
* `no-update-check` opts out of the startup update nudge (see update-check.ts).
|
|
19
|
+
*/
|
|
20
|
+
export declare const GLOBAL_FLAGS: ReadonlySet<string>;
|
|
15
21
|
export declare function parseFlags(args: string[]): Flags;
|
|
16
22
|
/**
|
|
17
23
|
* The flag keys in `flags` that are NOT in `allowed` — for a non-fatal "unrecognized flag"
|
package/dist/flags.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"flags.d.ts","sourceRoot":"","sources":["../src/flags.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,MAAM,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;AAEvD,8EAA8E;AAC9E,eAAO,MAAM,gBAAgB,EAAE,WAAW,CAAC,MAAM,CAA8B,CAAC;AAEhF,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,KAAK,CAchD;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,GAAG,MAAM,EAAE,CAG9E"}
|
|
1
|
+
{"version":3,"file":"flags.d.ts","sourceRoot":"","sources":["../src/flags.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,MAAM,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;AAEvD,8EAA8E;AAC9E,eAAO,MAAM,gBAAgB,EAAE,WAAW,CAAC,MAAM,CAA8B,CAAC;AAEhF;;;;GAIG;AACH,eAAO,MAAM,YAAY,EAAE,WAAW,CAAC,MAAM,CAAgC,CAAC;AAE9E,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,KAAK,CAchD;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,GAAG,MAAM,EAAE,CAG9E"}
|
package/dist/flags.js
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
/** Flags where every occurrence counts (values comma-join, in argv order). */
|
|
2
2
|
export const REPEATABLE_FLAGS = new Set(['dep', 'schema']);
|
|
3
|
+
/**
|
|
4
|
+
* Flags valid on ANY command (handled centrally in main, not by a command handler), so
|
|
5
|
+
* {@link unknownFlags} never flags them as unrecognized regardless of the per-command allowlist.
|
|
6
|
+
* `no-update-check` opts out of the startup update nudge (see update-check.ts).
|
|
7
|
+
*/
|
|
8
|
+
export const GLOBAL_FLAGS = new Set(['no-update-check']);
|
|
3
9
|
export function parseFlags(args) {
|
|
4
10
|
const out = {};
|
|
5
11
|
const set = (k, v) => {
|
|
@@ -29,6 +35,6 @@ export function parseFlags(args) {
|
|
|
29
35
|
*/
|
|
30
36
|
export function unknownFlags(flags, allowed) {
|
|
31
37
|
const ok = new Set(allowed);
|
|
32
|
-
return Object.keys(flags).filter((k) => !ok.has(k));
|
|
38
|
+
return Object.keys(flags).filter((k) => !ok.has(k) && !GLOBAL_FLAGS.has(k));
|
|
33
39
|
}
|
|
34
40
|
//# sourceMappingURL=flags.js.map
|
package/dist/flags.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"flags.js","sourceRoot":"","sources":["../src/flags.ts"],"names":[],"mappings":"AAaA,8EAA8E;AAC9E,MAAM,CAAC,MAAM,gBAAgB,GAAwB,IAAI,GAAG,CAAC,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC;AAEhF,MAAM,UAAU,UAAU,CAAC,IAAc;IACvC,MAAM,GAAG,GAAU,EAAE,CAAC;IACtB,MAAM,GAAG,GAAG,CAAC,CAAS,EAAE,CAAS,EAAE,EAAE;QACnC,GAAG,CAAC,CAAC,CAAC,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IAClF,CAAC,CAAC;IACF,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC;YAAE,SAAS;QAClC,MAAM,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAC1B,IAAI,EAAE,KAAK,CAAC,CAAC;YAAE,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC;aAC/C,IAAI,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC;YAAE,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;;YAC7E,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;IAC/B,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,YAAY,CAAC,KAAY,EAAE,OAAyB;IAClE,MAAM,EAAE,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC;IAC5B,OAAO,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"flags.js","sourceRoot":"","sources":["../src/flags.ts"],"names":[],"mappings":"AAaA,8EAA8E;AAC9E,MAAM,CAAC,MAAM,gBAAgB,GAAwB,IAAI,GAAG,CAAC,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC;AAEhF;;;;GAIG;AACH,MAAM,CAAC,MAAM,YAAY,GAAwB,IAAI,GAAG,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC;AAE9E,MAAM,UAAU,UAAU,CAAC,IAAc;IACvC,MAAM,GAAG,GAAU,EAAE,CAAC;IACtB,MAAM,GAAG,GAAG,CAAC,CAAS,EAAE,CAAS,EAAE,EAAE;QACnC,GAAG,CAAC,CAAC,CAAC,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IAClF,CAAC,CAAC;IACF,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC;YAAE,SAAS;QAClC,MAAM,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAC1B,IAAI,EAAE,KAAK,CAAC,CAAC;YAAE,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC;aAC/C,IAAI,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC;YAAE,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;;YAC7E,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;IAC/B,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,YAAY,CAAC,KAAY,EAAE,OAAyB;IAClE,MAAM,EAAE,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC;IAC5B,OAAO,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;AAC9E,CAAC"}
|
package/dist/main.js
CHANGED
|
@@ -34,13 +34,14 @@
|
|
|
34
34
|
* abx storage backup-key copy the managed Turbo/Arweave key (holds credits) to a safe path
|
|
35
35
|
* abx status list indexed projects + node info
|
|
36
36
|
* abx doctor check environment (key, RPC, balance, factory, storage)
|
|
37
|
-
* abx skill install install the abx agent skill into your agent
|
|
37
|
+
* abx skill install install the version-locked abx agent skill into your agent(s)
|
|
38
|
+
* (default: Claude Code + the neutral .agents/skills; --agent/--global)
|
|
38
39
|
*
|
|
39
40
|
* Every write picks a signing lane: default hot (env key signs), `--sign` (a human
|
|
40
41
|
* approves in their own wallet via a one-shot localhost page), `--unsigned` (print
|
|
41
42
|
* the tx for a multisig / offline signer). The agent picks the lane; the CLI signs.
|
|
42
43
|
*/
|
|
43
|
-
import { appendFileSync, copyFileSync, cpSync, existsSync, mkdirSync, readdirSync, readFileSync, statSync, writeFileSync } from 'node:fs';
|
|
44
|
+
import { appendFileSync, copyFileSync, cpSync, existsSync, mkdirSync, readdirSync, readFileSync, rmSync, statSync, writeFileSync } from 'node:fs';
|
|
44
45
|
import { randomBytes } from 'node:crypto';
|
|
45
46
|
import { basename, extname, join as joinPath, resolve as resolvePath } from 'node:path';
|
|
46
47
|
import { fileURLToPath } from 'node:url';
|
|
@@ -54,6 +55,7 @@ import { DEP_RESOLUTION, deploySeedSource, deploySeriesCodeFactory, prepareCodeS
|
|
|
54
55
|
import { checkRegistryDeps, dependencySetupCalls, parseDepFlag, resolveDepRegistryPointer } from './deps.js';
|
|
55
56
|
import { composeParamsKeys, expectedChainComplete, hasOnChainUriLane, onchainUriSetupCalls, onChainUriReport } from './onchain-uri.js';
|
|
56
57
|
import { parseFlags, unknownFlags } from './flags.js';
|
|
58
|
+
import { AGENT_SKILL_PARENTS, checkForCliUpdate, compareVersions, installedSkillVersions, readCliVersion, readSkillVersion, SKILL_DIR_NAME, } from './update-check.js';
|
|
57
59
|
import { analyzeScript, recommendLane } from './inspect.js';
|
|
58
60
|
import { parseSchemaSpecs, describeSchema } from './schema.js';
|
|
59
61
|
import { parseSeriesTraits, looksPerTokenAttributes, parseSeriesTraitsById } from './series-traits.js';
|
|
@@ -110,10 +112,49 @@ const step = (s) => console.log(`\n${p(`[${++stepN}]`)} ${bold(s)}`);
|
|
|
110
112
|
const ok = (s) => console.log(` ${g('✓')} ${s}`);
|
|
111
113
|
const info = (s) => console.log(` ${dim(s)}`);
|
|
112
114
|
const warn = (s) => console.log(` ${c.orange}⚠${c.reset} ${s}`);
|
|
115
|
+
/**
|
|
116
|
+
* Notify-only update nudge. Prints an upgrade one-liner to STDERR (never stdout — an agent may be
|
|
117
|
+
* parsing that) when a newer @artblocks/abx-cli is published, plus a nudge when a locally-installed
|
|
118
|
+
* skill has drifted behind the running CLI. Fully suppressed by CI / ABX_NO_UPDATE_CHECK /
|
|
119
|
+
* --no-update-check, and wrapped so it can NEVER break a command (all failures are swallowed).
|
|
120
|
+
*/
|
|
121
|
+
async function maybeNotifyUpdate(flags) {
|
|
122
|
+
try {
|
|
123
|
+
if (flags['no-update-check'] !== undefined || process.env.ABX_NO_UPDATE_CHECK || process.env.CI)
|
|
124
|
+
return;
|
|
125
|
+
const current = readCliVersion();
|
|
126
|
+
// Skill drift (cheap, offline): the skill and CLI are co-versioned, but a separately-installed
|
|
127
|
+
// skill copy doesn't move when the CLI upgrades. Nudge a reinstall when the CLI is ahead.
|
|
128
|
+
for (const v of installedSkillVersions()) {
|
|
129
|
+
if (compareVersions(current, v) > 0) {
|
|
130
|
+
console.error(` ${c.orange}⚠${c.reset} installed abx skill is v${v} but the CLI is v${current} — refresh it: ${g('abx skill install')}`);
|
|
131
|
+
break;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
const latest = await checkForCliUpdate(current);
|
|
135
|
+
if (latest) {
|
|
136
|
+
console.error(`\n ${c.orange}⚠${c.reset} update available: ${bold('abx')} ${dim(current)} → ${g(latest)}\n` +
|
|
137
|
+
` upgrade: ${g('npm i -g @artblocks/abx-cli@latest')} ${dim('· or invoke:')} ${g('npx abx@latest <command>')}\n` +
|
|
138
|
+
` release notes: https://github.com/ArtBlocks/abx/releases ${dim('· silence: ABX_NO_UPDATE_CHECK=1')}\n`);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
catch {
|
|
142
|
+
/* an update check must never break a command */
|
|
143
|
+
}
|
|
144
|
+
}
|
|
113
145
|
async function main() {
|
|
114
146
|
loadDotEnv();
|
|
115
147
|
const [cmd, ...rest] = process.argv.slice(2);
|
|
116
148
|
const flags = parseFlags(rest);
|
|
149
|
+
// `version` / --version / -v is a crisp query — print and exit, no update nag around it.
|
|
150
|
+
if (cmd === 'version' || cmd === '--version' || cmd === '-v') {
|
|
151
|
+
console.log(readCliVersion());
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
// Notify-only "you're behind" nudge (cached, opt-out, stderr — see update-check.ts). Awaited so
|
|
155
|
+
// the notice lands before command output, but it hits the network at most once a day and never
|
|
156
|
+
// throws, so it can't break or meaningfully slow a command. Skipped for the pure help path below.
|
|
157
|
+
await maybeNotifyUpdate(flags);
|
|
117
158
|
// SAFETY: --help / -h on ANY command is read-only — print usage, never execute.
|
|
118
159
|
// (A write command must never deploy/mint/spend just because someone asked for help.)
|
|
119
160
|
if (cmd && cmd !== 'help' && (flags.help !== undefined || rest.includes('-h'))) {
|
|
@@ -4220,6 +4261,21 @@ async function cmdDoctor(flags) {
|
|
|
4220
4261
|
const jwk = loadArweaveJwk();
|
|
4221
4262
|
console.log(` ${dim('↳ Turbo/Arweave key ' + (jwk ? arweaveAddress(jwk) + ' ' : '') + 'holds your upload credits — back it up: `abx storage backup-key --out <path>`')}`);
|
|
4222
4263
|
}
|
|
4264
|
+
// Agent skill co-versioning — the skill drives this CLI and is version-locked to it (its version
|
|
4265
|
+
// lives in SKILL.md frontmatter). Report any installed copy and flag drift; notify-only, so a
|
|
4266
|
+
// stale/absent skill never fails doctor (`abx skill install` resyncs).
|
|
4267
|
+
const cliVersion = readCliVersion();
|
|
4268
|
+
const skillVersions = installedSkillVersions();
|
|
4269
|
+
const staleSkills = skillVersions.filter((v) => compareVersions(cliVersion, v) > 0);
|
|
4270
|
+
if (skillVersions.length === 0) {
|
|
4271
|
+
console.log(` ${dim('↳ agent skill: not installed here — `abx skill install` so a coding agent can drive abx')}`);
|
|
4272
|
+
}
|
|
4273
|
+
else if (staleSkills.length > 0) {
|
|
4274
|
+
console.log(` ${c.orange}⚠${c.reset} agent skill behind CLI${dim(` installed v${staleSkills.join(', v')} · CLI v${cliVersion} — refresh: `)}${g('abx skill install')}`);
|
|
4275
|
+
}
|
|
4276
|
+
else {
|
|
4277
|
+
check(`agent skill in sync (v${cliVersion})`, true);
|
|
4278
|
+
}
|
|
4223
4279
|
console.log('');
|
|
4224
4280
|
}
|
|
4225
4281
|
// ── shared output ─────────────────────────────────────────────────────────--
|
|
@@ -4518,12 +4574,15 @@ function keepAlive() {
|
|
|
4518
4574
|
// ── per-command usage (printed by `<cmd> --help` / `abx help <cmd>`; read-only) ──
|
|
4519
4575
|
const COMMAND_HELP = {
|
|
4520
4576
|
skill: `
|
|
4521
|
-
${bold('abx skill')} ${dim('— install the abx agent skill so your coding agent can drive abx')}
|
|
4522
|
-
${g('abx skill install')} copy the skill
|
|
4523
|
-
${
|
|
4524
|
-
${g('--
|
|
4577
|
+
${bold('abx skill')} ${dim('— install the version-locked abx agent skill so your coding agent can drive abx')}
|
|
4578
|
+
${g('abx skill install')} copy the bundled skill (version-locked to this CLI) into your agent(s)
|
|
4579
|
+
${dim('default: both')} ${bold('.claude/skills')} ${dim('(Claude Code) and')} ${bold('.agents/skills')} ${dim('(Cursor · Codex · Gemini · Copilot)')}
|
|
4580
|
+
${g('--agent <name>')} only one agent: ${dim('claude | cursor | codex | gemini | copilot')}
|
|
4581
|
+
${g('--global')} install into your home dir (~) instead of the current project
|
|
4582
|
+
${g('--target <dir>')} install the skill folder straight under <dir> (writes <dir>/abx-self-host)
|
|
4525
4583
|
${g('abx skill path')} print the absolute path to the bundled skill (for ${g('npx skills add <path>')} or manual copy)
|
|
4526
|
-
${dim('Restart your agent after installing so it picks up the skill.
|
|
4584
|
+
${dim('Restart your agent after installing so it picks up the skill. Once the repo is public, the git-based')}
|
|
4585
|
+
${dim('cross-agent installer also works (not version-locked):')} ${g('npx skills add ArtBlocks/abx --skill abx-self-host')}`,
|
|
4527
4586
|
deploy: `
|
|
4528
4587
|
${bold('abx deploy')} ${dim('— deploy + index a 1/1 (no server). Sends a tx in the chosen lane.')}
|
|
4529
4588
|
--image <path> custody your own image (png · jpg · gif · svg · webp); else generative demo art
|
|
@@ -4979,9 +5038,11 @@ function help() {
|
|
|
4979
5038
|
${g('abx forget')} <address> drop a project's local registration + projection (on-chain untouched)
|
|
4980
5039
|
${g('abx status')} list indexed projects + node info
|
|
4981
5040
|
${g('abx doctor')} check environment (key, RPC, balance, factory, storage)
|
|
4982
|
-
${g('abx skill install')} install the abx
|
|
5041
|
+
${g('abx skill install')} install the version-locked abx skill into your agent(s) [--agent <name>] [--global] [--target <dir>] · ${g('abx skill path')} prints the bundled skill
|
|
5042
|
+
${g('abx version')} print the installed CLI version
|
|
4983
5043
|
|
|
4984
5044
|
${dim('Run')} ${g('abx <command> --help')} ${dim('for per-command usage. --help / -h never executes — it only prints usage.')}
|
|
5045
|
+
${dim('abx checks npm for a newer release (once a day, notify-only). Silence with')} ${g('ABX_NO_UPDATE_CHECK=1')} ${dim('or')} ${g('--no-update-check')}${dim('.')}
|
|
4985
5046
|
`);
|
|
4986
5047
|
}
|
|
4987
5048
|
/** Validate an explicit --salt (a 32-byte hex). Undefined when absent. */
|
|
@@ -4999,8 +5060,13 @@ function parseSaltFlag(raw) {
|
|
|
4999
5060
|
// ── skill: install the abx agent skill into the user's coding agent ───────────────────────
|
|
5000
5061
|
// The skill is the agentic half of the toolkit — the CLI is only useful once an agent knows how
|
|
5001
5062
|
// to drive it. It ships bundled inside the published package (packages/cli/skill/, created at
|
|
5002
|
-
// prepack); in dev the same command reads the canonical copy straight from the repo.
|
|
5003
|
-
//
|
|
5063
|
+
// prepack); in dev the same command reads the canonical copy straight from the repo. This is the
|
|
5064
|
+
// CANONICAL install path precisely because the bundle is version-locked to the CLI it ships inside
|
|
5065
|
+
// (the version lives in SKILL.md frontmatter — see update-check.ts). By default it writes to BOTH
|
|
5066
|
+
// `.claude/skills` (Claude Code) and the neutral `.agents/skills` (Cursor · Codex · Gemini ·
|
|
5067
|
+
// Copilot all read it), so one command covers the whole ecosystem; `--agent` narrows it. A separate
|
|
5068
|
+
// git-based channel, `npx skills add ArtBlocks/abx --skill abx-self-host`, works once the repo is public but is NOT
|
|
5069
|
+
// version-locked to a local CLI — prefer `abx skill install`.
|
|
5004
5070
|
/** Locate the skill folder: the bundled copy beside the compiled CLI (published), else the
|
|
5005
5071
|
* canonical repo copy (dev). Returns null if neither is present. */
|
|
5006
5072
|
function resolveBundledSkill() {
|
|
@@ -5064,29 +5130,71 @@ function cmdScaffoldRenderer(rest, flags) {
|
|
|
5064
5130
|
console.log(` ${g('abx deploy-code --image-renderer <MyRenderer> --attributes-renderer <MyTraits> --onchain-uri --schema palette:HexColor:TokenOwner --name "…" --symbol …')}`);
|
|
5065
5131
|
info(`full walkthrough: ${bold(`${basename(dir)}/README.md`)} · interface + invariants: https://abx.docs.artblocks.io/protocol/renderers/`);
|
|
5066
5132
|
}
|
|
5133
|
+
/** Human label for each skills-parent dir — which agents pick the skill up from there. */
|
|
5134
|
+
const SKILL_PARENT_LABELS = {
|
|
5135
|
+
'.claude/skills': 'Claude Code',
|
|
5136
|
+
'.agents/skills': 'Cursor · Codex · Gemini · Copilot',
|
|
5137
|
+
};
|
|
5138
|
+
/** Resolve which skills-parent dirs `install` should write to. No `--agent` → the whole-ecosystem
|
|
5139
|
+
* default (Claude Code + the neutral `.agents/skills` everyone else reads). `--agent a,b` narrows
|
|
5140
|
+
* to those agents' dirs (de-duped, since several share `.agents/skills`). */
|
|
5141
|
+
function resolveInstallParents(agentFlag) {
|
|
5142
|
+
if (!agentFlag || agentFlag === 'true')
|
|
5143
|
+
return ['.claude/skills', '.agents/skills'];
|
|
5144
|
+
const parents = new Set();
|
|
5145
|
+
for (const raw of agentFlag.split(',')) {
|
|
5146
|
+
const a = raw.trim().toLowerCase();
|
|
5147
|
+
const parent = AGENT_SKILL_PARENTS[a];
|
|
5148
|
+
if (!parent) {
|
|
5149
|
+
throw new Error(`unknown --agent '${a}'. Use one of: ${Object.keys(AGENT_SKILL_PARENTS).join(', ')} (or omit --agent to install for every agent).`);
|
|
5150
|
+
}
|
|
5151
|
+
parents.add(parent);
|
|
5152
|
+
}
|
|
5153
|
+
return [...parents];
|
|
5154
|
+
}
|
|
5155
|
+
/** Copy the bundled skill folder to `dest`, replacing any prior copy so a re-install after an
|
|
5156
|
+
* upgrade never leaves stale reference files behind. */
|
|
5157
|
+
function installSkillTo(src, dest) {
|
|
5158
|
+
mkdirSync(joinPath(dest, '..'), { recursive: true });
|
|
5159
|
+
rmSync(dest, { recursive: true, force: true });
|
|
5160
|
+
cpSync(src, dest, { recursive: true });
|
|
5161
|
+
}
|
|
5067
5162
|
async function cmdSkill(rest, flags) {
|
|
5068
5163
|
const sub = rest[0] ?? 'install';
|
|
5069
5164
|
const src = resolveBundledSkill();
|
|
5070
5165
|
if (!src) {
|
|
5071
5166
|
throw new Error('bundled skill not found (expected <pkg>/skill or .claude/skills/abx-self-host). ' +
|
|
5072
|
-
'Reinstall @artblocks/abx-cli, or install cross-agent with: npx skills add ArtBlocks/abx');
|
|
5167
|
+
'Reinstall @artblocks/abx-cli, or install cross-agent with: npx skills add ArtBlocks/abx --skill abx-self-host');
|
|
5073
5168
|
}
|
|
5074
5169
|
if (sub === 'path') {
|
|
5075
5170
|
console.log(src);
|
|
5076
5171
|
return;
|
|
5077
5172
|
}
|
|
5078
5173
|
if (sub === 'install') {
|
|
5079
|
-
const
|
|
5080
|
-
|
|
5081
|
-
|
|
5082
|
-
|
|
5083
|
-
|
|
5084
|
-
|
|
5085
|
-
|
|
5086
|
-
|
|
5174
|
+
const version = readSkillVersion(joinPath(src, 'SKILL.md')) ?? readCliVersion();
|
|
5175
|
+
// Escape hatch: --target <dir> writes the skill folder straight under <dir> (for an agent
|
|
5176
|
+
// whose skills dir we don't special-case, or a bespoke location).
|
|
5177
|
+
if (typeof flags.target === 'string' && flags.target !== 'true') {
|
|
5178
|
+
const dest = joinPath(resolvePath(flags.target), SKILL_DIR_NAME);
|
|
5179
|
+
installSkillTo(src, dest);
|
|
5180
|
+
ok(`installed the abx skill v${version} → ${dest}`);
|
|
5181
|
+
info('restart your agent so it loads the skill, then ask it to launch an NFT with abx.');
|
|
5182
|
+
return;
|
|
5183
|
+
}
|
|
5184
|
+
const base = flags.global !== undefined ? homedir() : process.cwd();
|
|
5185
|
+
const parents = resolveInstallParents(flags.agent);
|
|
5186
|
+
ok(`installed the abx skill v${version}${flags.global !== undefined ? ' (global, ~)' : ''}:`);
|
|
5187
|
+
for (const parent of parents) {
|
|
5188
|
+
const dest = joinPath(base, parent, SKILL_DIR_NAME);
|
|
5189
|
+
installSkillTo(src, dest);
|
|
5190
|
+
const label = SKILL_PARENT_LABELS[parent];
|
|
5191
|
+
console.log(` ${g(joinPath(parent, SKILL_DIR_NAME))}${label ? dim(' → ' + label) : ''}`);
|
|
5192
|
+
}
|
|
5193
|
+
info('restart your agent so it loads the skill, then ask it to launch an NFT with abx.');
|
|
5194
|
+
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.`);
|
|
5087
5195
|
return;
|
|
5088
5196
|
}
|
|
5089
|
-
throw new Error('usage: abx skill <install|path> [--global] [--target <dir>]');
|
|
5197
|
+
throw new Error('usage: abx skill <install|path> [--agent claude|cursor|codex|gemini|copilot] [--global] [--target <dir>]');
|
|
5090
5198
|
}
|
|
5091
5199
|
main().catch((err) => {
|
|
5092
5200
|
// Keep the actionable message; strip viem's verbose boilerplate trailer (Docs:/Version: lines) so
|