@spectratools/assembly-cli 0.2.0 → 0.3.1
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/README.md +15 -7
- package/dist/cli.js +283 -65
- package/package.json +19 -2
package/README.md
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
# @spectratools/assembly-cli
|
|
2
2
|
|
|
3
|
-
Assembly governance
|
|
3
|
+
Assembly is the governance layer for protocols on the Abstract chain: it manages membership, council seats, proposals, forum participation, and treasury controls through onchain contracts. Abstract is an Ethereum L2 focused on consumer-facing apps and agent-friendly infrastructure. This CLI gives operators and agents one interface to query Assembly state, run checks, and power automation.
|
|
4
|
+
|
|
5
|
+
Learn more:
|
|
6
|
+
|
|
7
|
+
- Abstract site: https://abs.xyz
|
|
8
|
+
- Abstract docs: https://docs.abs.xyz
|
|
4
9
|
|
|
5
10
|
## Install
|
|
6
11
|
|
|
@@ -47,27 +52,30 @@ assembly-cli <group> <command> [args] [options]
|
|
|
47
52
|
|
|
48
53
|
```bash
|
|
49
54
|
# 1) Agent startup snapshot: report system health in one call
|
|
50
|
-
assembly-cli status --
|
|
55
|
+
assembly-cli status --json
|
|
51
56
|
|
|
52
57
|
# 2) Verify whether an address can currently participate as council
|
|
53
58
|
assembly-cli council is-member 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045 --format json
|
|
54
59
|
|
|
55
60
|
# 3) Pull active member roster with relative activity timings
|
|
56
|
-
|
|
61
|
+
# Note: best results require ASSEMBLY_INDEXER_URL; if the indexer returns 404/unavailable,
|
|
62
|
+
# the CLI falls back to onchain Registered events and output may be slower or partial.
|
|
63
|
+
assembly-cli members list --json
|
|
57
64
|
|
|
58
65
|
# 4) Pre-vote automation: list proposals and fetch one in detail
|
|
59
66
|
assembly-cli governance proposals --format json
|
|
60
|
-
assembly-cli governance proposal 1 --
|
|
67
|
+
assembly-cli governance proposal 1 --json
|
|
61
68
|
|
|
62
69
|
# 5) Treasury monitoring loop: balance + spend lock status
|
|
63
70
|
assembly-cli treasury balance --format json
|
|
64
|
-
assembly-cli treasury major-spend-status --
|
|
71
|
+
assembly-cli treasury major-spend-status --json
|
|
65
72
|
```
|
|
66
73
|
|
|
67
74
|
## Output Mode
|
|
68
75
|
|
|
69
|
-
All commands support structured JSON output for agents
|
|
76
|
+
All commands support structured JSON output for agents with either `--json` or `--format json`:
|
|
70
77
|
|
|
71
78
|
```bash
|
|
79
|
+
assembly-cli forum threads --json
|
|
72
80
|
assembly-cli forum threads --format json
|
|
73
|
-
```
|
|
81
|
+
```
|
package/dist/cli.js
CHANGED
|
@@ -4281,6 +4281,10 @@ var ABSTRACT_MAINNET_ADDRESSES = {
|
|
|
4281
4281
|
governance: "0xe82a25937e07a3855d8B8352b85fF4B4Aa3fb0C0",
|
|
4282
4282
|
treasury: "0xC2e6DDbdc1A8e4DcCc60A78B6Faa197967a8FEb9"
|
|
4283
4283
|
};
|
|
4284
|
+
var ABSTRACT_MAINNET_DEPLOYMENT_BLOCKS = {
|
|
4285
|
+
// https://abscan.org/tx/0xe1dd27a739944c9847a7f366ea2363e7bf0fc2067377020fd749a8301e09b1ec
|
|
4286
|
+
registry: 43782651n
|
|
4287
|
+
};
|
|
4284
4288
|
|
|
4285
4289
|
// src/contracts/client.ts
|
|
4286
4290
|
import { http, createPublicClient, defineChain } from "viem";
|
|
@@ -4317,6 +4321,11 @@ function decodeAuction(value) {
|
|
|
4317
4321
|
const [highestBidder, highestBid, settled] = value;
|
|
4318
4322
|
return { highestBidder, highestBid, settled };
|
|
4319
4323
|
}
|
|
4324
|
+
function deriveAuctionStatus(params) {
|
|
4325
|
+
if (params.settled) return "settled";
|
|
4326
|
+
if (params.currentTimestamp < params.windowEnd) return "bidding";
|
|
4327
|
+
return "closed";
|
|
4328
|
+
}
|
|
4320
4329
|
var council = Cli.create("council", {
|
|
4321
4330
|
description: "Inspect council seats, members, auctions, and seat parameters."
|
|
4322
4331
|
});
|
|
@@ -4516,7 +4525,10 @@ council.command("auctions", {
|
|
|
4516
4525
|
slot: z.number(),
|
|
4517
4526
|
highestBidder: z.string(),
|
|
4518
4527
|
highestBid: z.string(),
|
|
4519
|
-
settled: z.boolean()
|
|
4528
|
+
settled: z.boolean(),
|
|
4529
|
+
windowEnd: z.number(),
|
|
4530
|
+
windowEndRelative: z.string(),
|
|
4531
|
+
status: z.enum(["bidding", "closed", "settled"])
|
|
4520
4532
|
})
|
|
4521
4533
|
)
|
|
4522
4534
|
}),
|
|
@@ -4545,27 +4557,50 @@ council.command("auctions", {
|
|
|
4545
4557
|
if (d < 0) continue;
|
|
4546
4558
|
for (let s = 0; s < Number(slotsPerDay); s++) recent.push({ day: BigInt(d), slot: s });
|
|
4547
4559
|
}
|
|
4548
|
-
const auctionTuples
|
|
4549
|
-
|
|
4550
|
-
|
|
4551
|
-
|
|
4552
|
-
|
|
4553
|
-
|
|
4554
|
-
|
|
4555
|
-
|
|
4556
|
-
|
|
4560
|
+
const [auctionTuples, windowEnds, latestBlock] = await Promise.all([
|
|
4561
|
+
recent.length ? client.multicall({
|
|
4562
|
+
allowFailure: false,
|
|
4563
|
+
contracts: recent.map((x) => ({
|
|
4564
|
+
abi: councilSeatsAbi,
|
|
4565
|
+
address: ABSTRACT_MAINNET_ADDRESSES.councilSeats,
|
|
4566
|
+
functionName: "auctions",
|
|
4567
|
+
args: [x.day, x.slot]
|
|
4568
|
+
}))
|
|
4569
|
+
}) : Promise.resolve([]),
|
|
4570
|
+
recent.length ? client.multicall({
|
|
4571
|
+
allowFailure: false,
|
|
4572
|
+
contracts: recent.map((x) => ({
|
|
4573
|
+
abi: councilSeatsAbi,
|
|
4574
|
+
address: ABSTRACT_MAINNET_ADDRESSES.councilSeats,
|
|
4575
|
+
functionName: "auctionWindowEnd",
|
|
4576
|
+
args: [x.day, x.slot]
|
|
4577
|
+
}))
|
|
4578
|
+
}) : Promise.resolve([]),
|
|
4579
|
+
client.getBlock({ blockTag: "latest" })
|
|
4580
|
+
]);
|
|
4557
4581
|
const auctions = auctionTuples.map(decodeAuction);
|
|
4582
|
+
const currentTimestamp = latestBlock.timestamp;
|
|
4558
4583
|
return c.ok(
|
|
4559
4584
|
{
|
|
4560
4585
|
currentDay: asNum(day),
|
|
4561
4586
|
currentSlot: asNum(slot),
|
|
4562
|
-
auctions: recent.map((x, i) =>
|
|
4563
|
-
|
|
4564
|
-
|
|
4565
|
-
|
|
4566
|
-
|
|
4567
|
-
|
|
4568
|
-
|
|
4587
|
+
auctions: recent.map((x, i) => {
|
|
4588
|
+
const windowEnd = windowEnds[i];
|
|
4589
|
+
return {
|
|
4590
|
+
day: Number(x.day),
|
|
4591
|
+
slot: x.slot,
|
|
4592
|
+
highestBidder: toChecksum(auctions[i].highestBidder),
|
|
4593
|
+
highestBid: eth(auctions[i].highestBid),
|
|
4594
|
+
settled: auctions[i].settled,
|
|
4595
|
+
windowEnd: asNum(windowEnd),
|
|
4596
|
+
windowEndRelative: relTime(windowEnd),
|
|
4597
|
+
status: deriveAuctionStatus({
|
|
4598
|
+
settled: auctions[i].settled,
|
|
4599
|
+
windowEnd,
|
|
4600
|
+
currentTimestamp
|
|
4601
|
+
})
|
|
4602
|
+
};
|
|
4603
|
+
})
|
|
4569
4604
|
},
|
|
4570
4605
|
{
|
|
4571
4606
|
cta: {
|
|
@@ -4591,24 +4626,45 @@ council.command("auction", {
|
|
|
4591
4626
|
slot: z.number(),
|
|
4592
4627
|
highestBidder: z.string(),
|
|
4593
4628
|
highestBid: z.string(),
|
|
4594
|
-
settled: z.boolean()
|
|
4629
|
+
settled: z.boolean(),
|
|
4630
|
+
windowEnd: z.number(),
|
|
4631
|
+
windowEndRelative: z.string(),
|
|
4632
|
+
status: z.enum(["bidding", "closed", "settled"])
|
|
4595
4633
|
}),
|
|
4596
4634
|
examples: [{ args: { day: 0, slot: 0 }, description: "Inspect day 0, slot 0 auction" }],
|
|
4597
4635
|
async run(c) {
|
|
4598
4636
|
const client = createAssemblyPublicClient(c.env.ABSTRACT_RPC_URL);
|
|
4599
|
-
const auctionTuple = await
|
|
4600
|
-
|
|
4601
|
-
|
|
4602
|
-
|
|
4603
|
-
|
|
4604
|
-
|
|
4637
|
+
const [auctionTuple, windowEnd, latestBlock] = await Promise.all([
|
|
4638
|
+
client.readContract({
|
|
4639
|
+
abi: councilSeatsAbi,
|
|
4640
|
+
address: ABSTRACT_MAINNET_ADDRESSES.councilSeats,
|
|
4641
|
+
functionName: "auctions",
|
|
4642
|
+
args: [BigInt(c.args.day), c.args.slot]
|
|
4643
|
+
}),
|
|
4644
|
+
client.readContract({
|
|
4645
|
+
abi: councilSeatsAbi,
|
|
4646
|
+
address: ABSTRACT_MAINNET_ADDRESSES.councilSeats,
|
|
4647
|
+
functionName: "auctionWindowEnd",
|
|
4648
|
+
args: [BigInt(c.args.day), c.args.slot]
|
|
4649
|
+
}),
|
|
4650
|
+
client.getBlock({ blockTag: "latest" })
|
|
4651
|
+
]);
|
|
4605
4652
|
const auction = decodeAuction(auctionTuple);
|
|
4653
|
+
const windowEndTimestamp = windowEnd;
|
|
4654
|
+
const currentTimestamp = latestBlock.timestamp;
|
|
4606
4655
|
return c.ok({
|
|
4607
4656
|
day: c.args.day,
|
|
4608
4657
|
slot: c.args.slot,
|
|
4609
4658
|
highestBidder: toChecksum(auction.highestBidder),
|
|
4610
4659
|
highestBid: eth(auction.highestBid),
|
|
4611
|
-
settled: auction.settled
|
|
4660
|
+
settled: auction.settled,
|
|
4661
|
+
windowEnd: asNum(windowEndTimestamp),
|
|
4662
|
+
windowEndRelative: relTime(windowEndTimestamp),
|
|
4663
|
+
status: deriveAuctionStatus({
|
|
4664
|
+
settled: auction.settled,
|
|
4665
|
+
windowEnd: windowEndTimestamp,
|
|
4666
|
+
currentTimestamp
|
|
4667
|
+
})
|
|
4612
4668
|
});
|
|
4613
4669
|
}
|
|
4614
4670
|
});
|
|
@@ -4767,17 +4823,20 @@ var forum = Cli2.create("forum", {
|
|
|
4767
4823
|
forum.command("threads", {
|
|
4768
4824
|
description: "List forum threads with author and creation metadata.",
|
|
4769
4825
|
env: env2,
|
|
4770
|
-
output: z2.
|
|
4771
|
-
z2.
|
|
4772
|
-
|
|
4773
|
-
|
|
4774
|
-
|
|
4775
|
-
|
|
4776
|
-
|
|
4777
|
-
|
|
4778
|
-
|
|
4779
|
-
|
|
4780
|
-
|
|
4826
|
+
output: z2.object({
|
|
4827
|
+
threads: z2.array(
|
|
4828
|
+
z2.object({
|
|
4829
|
+
id: z2.number(),
|
|
4830
|
+
kind: z2.number(),
|
|
4831
|
+
author: z2.string(),
|
|
4832
|
+
createdAt: z2.number(),
|
|
4833
|
+
createdAtRelative: z2.string(),
|
|
4834
|
+
category: z2.string().nullable().optional(),
|
|
4835
|
+
title: z2.string().nullable().optional()
|
|
4836
|
+
})
|
|
4837
|
+
),
|
|
4838
|
+
count: z2.number()
|
|
4839
|
+
}),
|
|
4781
4840
|
examples: [{ description: "List all forum threads" }],
|
|
4782
4841
|
async run(c) {
|
|
4783
4842
|
const client = createAssemblyPublicClient(c.env.ABSTRACT_RPC_URL);
|
|
@@ -4797,16 +4856,20 @@ forum.command("threads", {
|
|
|
4797
4856
|
}))
|
|
4798
4857
|
}) : [];
|
|
4799
4858
|
const items = threadTuples.map(decodeThread);
|
|
4859
|
+
const threads = items.map((x) => ({
|
|
4860
|
+
id: x.id,
|
|
4861
|
+
kind: x.kind,
|
|
4862
|
+
author: x.author,
|
|
4863
|
+
createdAt: x.createdAt,
|
|
4864
|
+
createdAtRelative: relTime(x.createdAt),
|
|
4865
|
+
category: x.category ?? null,
|
|
4866
|
+
title: x.title ?? null
|
|
4867
|
+
}));
|
|
4800
4868
|
return c.ok(
|
|
4801
|
-
|
|
4802
|
-
|
|
4803
|
-
|
|
4804
|
-
|
|
4805
|
-
createdAt: x.createdAt,
|
|
4806
|
-
createdAtRelative: relTime(x.createdAt),
|
|
4807
|
-
category: x.category ?? null,
|
|
4808
|
-
title: x.title ?? null
|
|
4809
|
-
})),
|
|
4869
|
+
{
|
|
4870
|
+
threads,
|
|
4871
|
+
count: threads.length
|
|
4872
|
+
},
|
|
4810
4873
|
{
|
|
4811
4874
|
cta: {
|
|
4812
4875
|
description: "Inspect or comment:",
|
|
@@ -5131,16 +5194,19 @@ var governance = Cli3.create("governance", {
|
|
|
5131
5194
|
governance.command("proposals", {
|
|
5132
5195
|
description: "List governance proposals with status and vote end time.",
|
|
5133
5196
|
env: env3,
|
|
5134
|
-
output: z3.
|
|
5135
|
-
z3.
|
|
5136
|
-
|
|
5137
|
-
|
|
5138
|
-
|
|
5139
|
-
|
|
5140
|
-
|
|
5141
|
-
|
|
5142
|
-
|
|
5143
|
-
|
|
5197
|
+
output: z3.object({
|
|
5198
|
+
proposals: z3.array(
|
|
5199
|
+
z3.object({
|
|
5200
|
+
id: z3.number(),
|
|
5201
|
+
kind: z3.number(),
|
|
5202
|
+
status: z3.number(),
|
|
5203
|
+
title: z3.string().nullable().optional(),
|
|
5204
|
+
voteEndAt: z3.number(),
|
|
5205
|
+
voteEndRelative: z3.string()
|
|
5206
|
+
})
|
|
5207
|
+
),
|
|
5208
|
+
count: z3.number()
|
|
5209
|
+
}),
|
|
5144
5210
|
examples: [{ description: "List all proposals" }],
|
|
5145
5211
|
async run(c) {
|
|
5146
5212
|
const client = createAssemblyPublicClient(c.env.ABSTRACT_RPC_URL);
|
|
@@ -5160,15 +5226,19 @@ governance.command("proposals", {
|
|
|
5160
5226
|
}))
|
|
5161
5227
|
}) : [];
|
|
5162
5228
|
const proposals = proposalTuples.map(decodeProposal);
|
|
5229
|
+
const items = proposals.map((p, i) => ({
|
|
5230
|
+
id: i + 1,
|
|
5231
|
+
kind: asNum(p.kind),
|
|
5232
|
+
status: asNum(p.status),
|
|
5233
|
+
title: p.title ?? null,
|
|
5234
|
+
voteEndAt: asNum(p.voteEndAt),
|
|
5235
|
+
voteEndRelative: relTime(p.voteEndAt)
|
|
5236
|
+
}));
|
|
5163
5237
|
return c.ok(
|
|
5164
|
-
|
|
5165
|
-
|
|
5166
|
-
|
|
5167
|
-
|
|
5168
|
-
title: p.title ?? null,
|
|
5169
|
-
voteEndAt: asNum(p.voteEndAt),
|
|
5170
|
-
voteEndRelative: relTime(p.voteEndAt)
|
|
5171
|
-
})),
|
|
5238
|
+
{
|
|
5239
|
+
proposals: items,
|
|
5240
|
+
count: items.length
|
|
5241
|
+
},
|
|
5172
5242
|
{
|
|
5173
5243
|
cta: {
|
|
5174
5244
|
description: "Inspect or vote:",
|
|
@@ -5301,6 +5371,7 @@ governance.command("params", {
|
|
|
5301
5371
|
import { Cli as Cli4, z as z4 } from "incur";
|
|
5302
5372
|
var DEFAULT_MEMBER_SNAPSHOT_URL = "https://www.theaiassembly.org/api/indexer/members";
|
|
5303
5373
|
var REGISTERED_EVENT_SCAN_STEP = 100000n;
|
|
5374
|
+
var REGISTERED_EVENT_SCAN_TIMEOUT_MS = 2e4;
|
|
5304
5375
|
var env4 = z4.object({
|
|
5305
5376
|
ABSTRACT_RPC_URL: z4.string().optional().describe("Abstract RPC URL override"),
|
|
5306
5377
|
ASSEMBLY_INDEXER_URL: z4.string().optional().describe("Optional members snapshot endpoint (default: theaiassembly.org indexer)")
|
|
@@ -5351,10 +5422,25 @@ async function memberSnapshot(url) {
|
|
|
5351
5422
|
response: json
|
|
5352
5423
|
});
|
|
5353
5424
|
}
|
|
5425
|
+
async function withTimeout(promise, timeoutMs, timeoutMessage) {
|
|
5426
|
+
let timer;
|
|
5427
|
+
try {
|
|
5428
|
+
return await Promise.race([
|
|
5429
|
+
promise,
|
|
5430
|
+
new Promise((_, reject) => {
|
|
5431
|
+
timer = setTimeout(() => {
|
|
5432
|
+
reject(new Error(timeoutMessage));
|
|
5433
|
+
}, timeoutMs);
|
|
5434
|
+
})
|
|
5435
|
+
]);
|
|
5436
|
+
} finally {
|
|
5437
|
+
if (timer) clearTimeout(timer);
|
|
5438
|
+
}
|
|
5439
|
+
}
|
|
5354
5440
|
async function membersFromRegisteredEvents(client) {
|
|
5355
5441
|
const latestBlock = await client.getBlockNumber();
|
|
5356
5442
|
const addresses = /* @__PURE__ */ new Set();
|
|
5357
|
-
for (let fromBlock =
|
|
5443
|
+
for (let fromBlock = ABSTRACT_MAINNET_DEPLOYMENT_BLOCKS.registry; fromBlock <= latestBlock; fromBlock += REGISTERED_EVENT_SCAN_STEP) {
|
|
5358
5444
|
const toBlock = fromBlock + REGISTERED_EVENT_SCAN_STEP - 1n > latestBlock ? latestBlock : fromBlock + REGISTERED_EVENT_SCAN_STEP - 1n;
|
|
5359
5445
|
const events = await client.getContractEvents({
|
|
5360
5446
|
abi: registryAbi,
|
|
@@ -5433,7 +5519,11 @@ members.command("list", {
|
|
|
5433
5519
|
}
|
|
5434
5520
|
fallbackReason = error.details;
|
|
5435
5521
|
try {
|
|
5436
|
-
addresses = await
|
|
5522
|
+
addresses = await withTimeout(
|
|
5523
|
+
membersFromRegisteredEvents(client),
|
|
5524
|
+
REGISTERED_EVENT_SCAN_TIMEOUT_MS,
|
|
5525
|
+
`Registered event fallback scan timed out after ${REGISTERED_EVENT_SCAN_TIMEOUT_MS}ms`
|
|
5526
|
+
);
|
|
5437
5527
|
} catch (fallbackError) {
|
|
5438
5528
|
return c.error({
|
|
5439
5529
|
code: "MEMBER_LIST_SOURCE_UNAVAILABLE",
|
|
@@ -5708,6 +5798,133 @@ treasury.command("executed", {
|
|
|
5708
5798
|
}
|
|
5709
5799
|
});
|
|
5710
5800
|
|
|
5801
|
+
// src/error-handling.ts
|
|
5802
|
+
import { AsyncLocalStorage } from "async_hooks";
|
|
5803
|
+
import { Errors } from "incur";
|
|
5804
|
+
var VIEM_VERSION_PATTERN = /\n*Version:\s*viem@[^\n]+/i;
|
|
5805
|
+
var VIEM_VERSION_PATTERN_GLOBAL = /\n*Version:\s*viem@[^\n]+/gi;
|
|
5806
|
+
var debugFlagStore = new AsyncLocalStorage();
|
|
5807
|
+
var VIEM_ERROR_NAMES = /* @__PURE__ */ new Set([
|
|
5808
|
+
"CallExecutionError",
|
|
5809
|
+
"ContractFunctionExecutionError",
|
|
5810
|
+
"ContractFunctionRevertedError",
|
|
5811
|
+
"HttpRequestError",
|
|
5812
|
+
"InvalidAddressError",
|
|
5813
|
+
"TransactionExecutionError"
|
|
5814
|
+
]);
|
|
5815
|
+
function parseDebugFlag(argv) {
|
|
5816
|
+
const cleaned = [];
|
|
5817
|
+
let debug = false;
|
|
5818
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
5819
|
+
const token = argv[i];
|
|
5820
|
+
if (token === "--debug") {
|
|
5821
|
+
debug = true;
|
|
5822
|
+
continue;
|
|
5823
|
+
}
|
|
5824
|
+
if (token === "--debug=true" || token === "--debug=1") {
|
|
5825
|
+
debug = true;
|
|
5826
|
+
continue;
|
|
5827
|
+
}
|
|
5828
|
+
if (token === "--debug=false" || token === "--debug=0") {
|
|
5829
|
+
debug = false;
|
|
5830
|
+
continue;
|
|
5831
|
+
}
|
|
5832
|
+
cleaned.push(token);
|
|
5833
|
+
}
|
|
5834
|
+
return { argv: cleaned, debug };
|
|
5835
|
+
}
|
|
5836
|
+
function isViemLikeError(error) {
|
|
5837
|
+
if (!(error instanceof Error)) return false;
|
|
5838
|
+
const shortMessage = error.shortMessage;
|
|
5839
|
+
return VIEM_ERROR_NAMES.has(error.name) || VIEM_VERSION_PATTERN.test(error.message) || typeof shortMessage === "string" && error.message.includes("Docs: https://viem.sh");
|
|
5840
|
+
}
|
|
5841
|
+
function sanitizeViemMessage(message) {
|
|
5842
|
+
return message.replace(VIEM_VERSION_PATTERN_GLOBAL, "").trim();
|
|
5843
|
+
}
|
|
5844
|
+
function toFriendlyViemError(error) {
|
|
5845
|
+
const shortMessage = typeof error.shortMessage === "string" && error.shortMessage.trim().length > 0 ? error.shortMessage.trim() : void 0;
|
|
5846
|
+
if (error.name === "InvalidAddressError" || shortMessage?.startsWith('Address "')) {
|
|
5847
|
+
return {
|
|
5848
|
+
code: "INVALID_ADDRESS",
|
|
5849
|
+
message: `${shortMessage ?? "Invalid address."} Use a valid 0x-prefixed 20-byte address. Run with --debug for full error details.`
|
|
5850
|
+
};
|
|
5851
|
+
}
|
|
5852
|
+
if (shortMessage?.toLowerCase().includes("http request failed") || error.message.toLowerCase().includes("http request failed")) {
|
|
5853
|
+
return {
|
|
5854
|
+
code: "RPC_CONNECTION_FAILED",
|
|
5855
|
+
message: "RPC connection failed. Check ABSTRACT_RPC_URL and try again. Run with --debug for full error details."
|
|
5856
|
+
};
|
|
5857
|
+
}
|
|
5858
|
+
if (shortMessage || VIEM_VERSION_PATTERN.test(error.message)) {
|
|
5859
|
+
return {
|
|
5860
|
+
code: "UPSTREAM_ERROR",
|
|
5861
|
+
message: `${sanitizeViemMessage(shortMessage ?? error.message)} Run with --debug for full error details.`
|
|
5862
|
+
};
|
|
5863
|
+
}
|
|
5864
|
+
return void 0;
|
|
5865
|
+
}
|
|
5866
|
+
function isMissingRequiredArgValidation(error) {
|
|
5867
|
+
return error.fieldErrors.some((fieldError) => {
|
|
5868
|
+
const msg = fieldError.message.toLowerCase();
|
|
5869
|
+
return msg.includes("received undefined") || fieldError.received === "";
|
|
5870
|
+
});
|
|
5871
|
+
}
|
|
5872
|
+
function missingArgPaths(error) {
|
|
5873
|
+
const paths = /* @__PURE__ */ new Set();
|
|
5874
|
+
for (const fieldError of error.fieldErrors) {
|
|
5875
|
+
const msg = fieldError.message.toLowerCase();
|
|
5876
|
+
if (msg.includes("received undefined") || fieldError.received === "") {
|
|
5877
|
+
paths.add(fieldError.path);
|
|
5878
|
+
}
|
|
5879
|
+
}
|
|
5880
|
+
return [...paths];
|
|
5881
|
+
}
|
|
5882
|
+
function toFriendlyValidationError(ctx, error) {
|
|
5883
|
+
const missing = missingArgPaths(error);
|
|
5884
|
+
if (missing.length === 0) return void 0;
|
|
5885
|
+
const helpCommand = `${ctx.name} ${ctx.command} --help`;
|
|
5886
|
+
const argsList = missing.join(", ");
|
|
5887
|
+
return {
|
|
5888
|
+
code: "VALIDATION_ERROR",
|
|
5889
|
+
cta: {
|
|
5890
|
+
description: "See command usage:",
|
|
5891
|
+
commands: [{ command: helpCommand }]
|
|
5892
|
+
},
|
|
5893
|
+
message: missing.length === 1 ? `Missing required argument: ${argsList}. Run \`${helpCommand}\` for usage.` : `Missing required arguments: ${argsList}. Run \`${helpCommand}\` for usage.`
|
|
5894
|
+
};
|
|
5895
|
+
}
|
|
5896
|
+
function handleError(ctx, error) {
|
|
5897
|
+
if (debugFlagStore.getStore()) throw error;
|
|
5898
|
+
if (error instanceof Errors.ValidationError && isMissingRequiredArgValidation(error)) {
|
|
5899
|
+
const friendly = toFriendlyValidationError(ctx, error);
|
|
5900
|
+
if (friendly) {
|
|
5901
|
+
return ctx.error(friendly);
|
|
5902
|
+
}
|
|
5903
|
+
}
|
|
5904
|
+
if (isViemLikeError(error)) {
|
|
5905
|
+
const friendly = toFriendlyViemError(error);
|
|
5906
|
+
if (friendly) {
|
|
5907
|
+
return ctx.error(friendly);
|
|
5908
|
+
}
|
|
5909
|
+
}
|
|
5910
|
+
throw error;
|
|
5911
|
+
}
|
|
5912
|
+
function applyFriendlyErrorHandling(cli2) {
|
|
5913
|
+
const originalServe = cli2.serve.bind(cli2);
|
|
5914
|
+
cli2.serve = (async (argv, options) => {
|
|
5915
|
+
const rawArgv = argv ?? process.argv.slice(2);
|
|
5916
|
+
const parsed = parseDebugFlag(rawArgv);
|
|
5917
|
+
return debugFlagStore.run(parsed.debug, () => originalServe(parsed.argv, options));
|
|
5918
|
+
});
|
|
5919
|
+
cli2.use(async (context, next) => {
|
|
5920
|
+
try {
|
|
5921
|
+
await next();
|
|
5922
|
+
} catch (error) {
|
|
5923
|
+
return handleError(context, error);
|
|
5924
|
+
}
|
|
5925
|
+
});
|
|
5926
|
+
}
|
|
5927
|
+
|
|
5711
5928
|
// src/cli.ts
|
|
5712
5929
|
var cli = Cli6.create("assembly", {
|
|
5713
5930
|
description: "Assembly governance CLI for Abstract chain."
|
|
@@ -5843,6 +6060,7 @@ cli.command("health", {
|
|
|
5843
6060
|
});
|
|
5844
6061
|
}
|
|
5845
6062
|
});
|
|
6063
|
+
applyFriendlyErrorHandling(cli);
|
|
5846
6064
|
var isMain = process.argv[1] === fileURLToPath(import.meta.url);
|
|
5847
6065
|
if (isMain) {
|
|
5848
6066
|
cli.serve();
|
package/package.json
CHANGED
|
@@ -1,10 +1,27 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@spectratools/assembly-cli",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.3.1",
|
|
4
|
+
"description": "CLI for Assembly governance on Abstract (members, council, forum, proposals, and treasury).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"author": "spectra-the-bot",
|
|
8
|
+
"keywords": [
|
|
9
|
+
"assembly",
|
|
10
|
+
"abstract",
|
|
11
|
+
"governance",
|
|
12
|
+
"dao",
|
|
13
|
+
"ethereum",
|
|
14
|
+
"web3",
|
|
15
|
+
"cli",
|
|
16
|
+
"incur",
|
|
17
|
+
"spectratools"
|
|
18
|
+
],
|
|
19
|
+
"repository": {
|
|
20
|
+
"type": "git",
|
|
21
|
+
"url": "git+https://github.com/spectra-the-bot/spectra-tools.git",
|
|
22
|
+
"directory": "packages/assembly"
|
|
23
|
+
},
|
|
24
|
+
"homepage": "https://github.com/spectra-the-bot/spectra-tools/tree/main/packages/assembly#readme",
|
|
8
25
|
"engines": {
|
|
9
26
|
"node": ">=20"
|
|
10
27
|
},
|