@net-protocol/cli 0.1.24 → 0.1.26
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 +23 -7
- package/dist/cli/index.mjs +389 -22
- package/dist/cli/index.mjs.map +1 -1
- package/dist/profile/index.mjs +260 -2
- package/dist/profile/index.mjs.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -472,6 +472,7 @@ netp profile set-x-username \
|
|
|
472
472
|
- `--chain-id` (optional): Chain ID. Can also be set via `NET_CHAIN_ID` environment variable
|
|
473
473
|
- `--rpc-url` (optional): Custom RPC URL. Can also be set via `NET_RPC_URL` environment variable
|
|
474
474
|
- `--encode-only` (optional): Output transaction data as JSON instead of executing
|
|
475
|
+
- `--address` (optional): Wallet address to preserve existing metadata for (used with --encode-only)
|
|
475
476
|
|
|
476
477
|
**Example:**
|
|
477
478
|
|
|
@@ -485,9 +486,10 @@ netp profile set-x-username \
|
|
|
485
486
|
--username "@myusername" \
|
|
486
487
|
--chain-id 8453
|
|
487
488
|
|
|
488
|
-
# Encode-only
|
|
489
|
+
# Encode-only (--address preserves existing bio, display name, token address)
|
|
489
490
|
netp profile set-x-username \
|
|
490
491
|
--username "myusername" \
|
|
492
|
+
--address 0xYourWalletAddress \
|
|
491
493
|
--chain-id 8453 \
|
|
492
494
|
--encode-only
|
|
493
495
|
```
|
|
@@ -512,6 +514,7 @@ netp profile set-bio \
|
|
|
512
514
|
- `--chain-id` (optional): Chain ID. Can also be set via `NET_CHAIN_ID` environment variable
|
|
513
515
|
- `--rpc-url` (optional): Custom RPC URL. Can also be set via `NET_RPC_URL` environment variable
|
|
514
516
|
- `--encode-only` (optional): Output transaction data as JSON instead of executing
|
|
517
|
+
- `--address` (optional): Wallet address to preserve existing metadata for (used with --encode-only)
|
|
515
518
|
|
|
516
519
|
**Example:**
|
|
517
520
|
|
|
@@ -521,9 +524,10 @@ netp profile set-bio \
|
|
|
521
524
|
--bio "Building cool stuff on Net Protocol" \
|
|
522
525
|
--chain-id 8453
|
|
523
526
|
|
|
524
|
-
# Encode-only
|
|
527
|
+
# Encode-only (--address preserves existing x_username, display name, token address)
|
|
525
528
|
netp profile set-bio \
|
|
526
529
|
--bio "Building cool stuff on Net Protocol" \
|
|
530
|
+
--address 0xYourWalletAddress \
|
|
527
531
|
--chain-id 8453 \
|
|
528
532
|
--encode-only
|
|
529
533
|
```
|
|
@@ -548,6 +552,7 @@ netp profile set-display-name \
|
|
|
548
552
|
- `--chain-id` (optional): Chain ID. Can also be set via `NET_CHAIN_ID` environment variable
|
|
549
553
|
- `--rpc-url` (optional): Custom RPC URL. Can also be set via `NET_RPC_URL` environment variable
|
|
550
554
|
- `--encode-only` (optional): Output transaction data as JSON instead of executing
|
|
555
|
+
- `--address` (optional): Wallet address to preserve existing metadata for (used with --encode-only)
|
|
551
556
|
|
|
552
557
|
**Example:**
|
|
553
558
|
|
|
@@ -557,9 +562,10 @@ netp profile set-display-name \
|
|
|
557
562
|
--name "Alice" \
|
|
558
563
|
--chain-id 8453
|
|
559
564
|
|
|
560
|
-
# Encode-only
|
|
565
|
+
# Encode-only (--address preserves existing bio, x_username, token address)
|
|
561
566
|
netp profile set-display-name \
|
|
562
567
|
--name "Alice" \
|
|
568
|
+
--address 0xYourWalletAddress \
|
|
563
569
|
--chain-id 8453 \
|
|
564
570
|
--encode-only
|
|
565
571
|
```
|
|
@@ -584,6 +590,7 @@ netp profile set-token-address \
|
|
|
584
590
|
- `--chain-id` (optional): Chain ID. Can also be set via `NET_CHAIN_ID` environment variable
|
|
585
591
|
- `--rpc-url` (optional): Custom RPC URL. Can also be set via `NET_RPC_URL` environment variable
|
|
586
592
|
- `--encode-only` (optional): Output transaction data as JSON instead of executing
|
|
593
|
+
- `--address` (optional): Wallet address to preserve existing metadata for (used with --encode-only)
|
|
587
594
|
|
|
588
595
|
**Example:**
|
|
589
596
|
|
|
@@ -593,9 +600,10 @@ netp profile set-token-address \
|
|
|
593
600
|
--token-address 0x1234567890abcdef1234567890abcdef12345678 \
|
|
594
601
|
--chain-id 8453
|
|
595
602
|
|
|
596
|
-
# Encode-only (
|
|
603
|
+
# Encode-only (--address preserves existing bio, x_username, display name)
|
|
597
604
|
netp profile set-token-address \
|
|
598
605
|
--token-address 0x1234567890abcdef1234567890abcdef12345678 \
|
|
606
|
+
--address 0xYourWalletAddress \
|
|
599
607
|
--chain-id 8453 \
|
|
600
608
|
--encode-only
|
|
601
609
|
```
|
|
@@ -778,12 +786,20 @@ src/
|
|
|
778
786
|
│ ├── profile/ # Profile command module
|
|
779
787
|
│ │ ├── index.ts # Profile command definition
|
|
780
788
|
│ │ ├── get.ts # Profile get logic
|
|
781
|
-
│ │ ├── set-picture.ts
|
|
782
|
-
│ │ ├── set-username.ts
|
|
789
|
+
│ │ ├── set-picture.ts # Set profile picture
|
|
790
|
+
│ │ ├── set-username.ts # Set X username
|
|
791
|
+
│ │ ├── set-bio.ts # Set profile bio
|
|
792
|
+
│ │ ├── set-display-name.ts # Set display name
|
|
783
793
|
│ │ ├── set-token-address.ts # Set token address
|
|
794
|
+
│ │ ├── set-canvas.ts # Set profile canvas
|
|
795
|
+
│ │ ├── get-canvas.ts # Get profile canvas
|
|
784
796
|
│ │ └── types.ts # Profile-specific types
|
|
797
|
+
│ ├── feed/ # Feed command module
|
|
785
798
|
│ ├── message/ # Message command module
|
|
786
|
-
│
|
|
799
|
+
│ ├── token/ # Token command module
|
|
800
|
+
│ ├── bazaar/ # NFT Bazaar command module
|
|
801
|
+
│ ├── chains/ # Chains listing command
|
|
802
|
+
│ └── info/ # Contract info command
|
|
787
803
|
└── shared/ # Shared utilities across commands
|
|
788
804
|
└── types.ts # Common types (CommonOptions, etc.)
|
|
789
805
|
```
|
package/dist/cli/index.mjs
CHANGED
|
@@ -4,8 +4,8 @@ import 'dotenv/config';
|
|
|
4
4
|
import { Command } from 'commander';
|
|
5
5
|
import { createRequire } from 'module';
|
|
6
6
|
import chalk4 from 'chalk';
|
|
7
|
-
import * as
|
|
8
|
-
import { readFileSync } from 'fs';
|
|
7
|
+
import * as fs6 from 'fs';
|
|
8
|
+
import { readFileSync, existsSync, mkdirSync, writeFileSync } from 'fs';
|
|
9
9
|
import { OPTIMAL_CHUNK_SIZE, StorageClient, detectFileTypeFromBase64, base64ToDataUri, shouldSuggestXmlStorage, getStorageKeyBytes, encodeStorageKeyForUrl, chunkDataForStorage, CHUNKED_STORAGE_CONTRACT, STORAGE_CONTRACT as STORAGE_CONTRACT$1 } from '@net-protocol/storage';
|
|
10
10
|
import { stringToHex, createWalletClient, http, hexToString, parseEther, encodeFunctionData, publicActions, defineChain } from 'viem';
|
|
11
11
|
import { privateKeyToAccount } from 'viem/accounts';
|
|
@@ -13,11 +13,13 @@ import { getNetContract, getChainName, getPublicClient, getChainRpcUrls, NetClie
|
|
|
13
13
|
import { createRelayX402Client, createRelaySession, checkBackendWalletBalance, fundBackendWallet, batchTransactions, submitTransactionsViaRelay, waitForConfirmations, retryFailedTransactions as retryFailedTransactions$1 } from '@net-protocol/relay';
|
|
14
14
|
import { FeedRegistryClient, FeedClient, AgentRegistryClient } from '@net-protocol/feeds';
|
|
15
15
|
import { isNetrSupportedChain, NetrClient } from '@net-protocol/netr';
|
|
16
|
-
import { PROFILE_PICTURE_STORAGE_KEY, PROFILE_METADATA_STORAGE_KEY, parseProfileMetadata, PROFILE_CANVAS_STORAGE_KEY, isValidUrl, getProfilePictureStorageArgs, STORAGE_CONTRACT, isValidXUsername, getProfileMetadataStorageArgs, isValidBio, isValidDisplayName, isValidTokenAddress } from '@net-protocol/profiles';
|
|
16
|
+
import { PROFILE_PICTURE_STORAGE_KEY, PROFILE_METADATA_STORAGE_KEY, parseProfileMetadata, PROFILE_CANVAS_STORAGE_KEY, PROFILE_CSS_STORAGE_KEY, isValidUrl, getProfilePictureStorageArgs, STORAGE_CONTRACT, isValidXUsername, getProfileMetadataStorageArgs, isValidBio, isValidDisplayName, isValidTokenAddress, DEMO_THEMES, MAX_CSS_SIZE, isValidCSS, getProfileCSSStorageArgs, buildCSSPrompt } from '@net-protocol/profiles';
|
|
17
17
|
import { base } from 'viem/chains';
|
|
18
18
|
import * as path from 'path';
|
|
19
|
+
import { join } from 'path';
|
|
19
20
|
import { BazaarClient } from '@net-protocol/bazaar';
|
|
20
21
|
import * as os from 'os';
|
|
22
|
+
import { homedir } from 'os';
|
|
21
23
|
import * as readline from 'readline';
|
|
22
24
|
|
|
23
25
|
var DEFAULT_CHAIN_ID = 8453;
|
|
@@ -1255,7 +1257,7 @@ async function encodeStorageUpload(options) {
|
|
|
1255
1257
|
} else {
|
|
1256
1258
|
operatorAddress = "0x0000000000000000000000000000000000000000";
|
|
1257
1259
|
}
|
|
1258
|
-
const fileContent =
|
|
1260
|
+
const fileContent = fs6.readFileSync(options.filePath, "utf-8");
|
|
1259
1261
|
const fileSize = Buffer.byteLength(fileContent, "utf-8");
|
|
1260
1262
|
const client = new StorageClient({
|
|
1261
1263
|
chainId: readOnlyOptions.chainId
|
|
@@ -1558,8 +1560,8 @@ function registerStorageCommand(program2) {
|
|
|
1558
1560
|
console.log(chalk4.blue(`\u{1F4C1} Reading file: ${options.file}`));
|
|
1559
1561
|
console.log(chalk4.blue(`\u{1F517} Using relay API: ${options.apiUrl}`));
|
|
1560
1562
|
const result = await uploadFileWithRelay(uploadRelayOptions);
|
|
1561
|
-
const { privateKeyToAccount:
|
|
1562
|
-
const userAccount =
|
|
1563
|
+
const { privateKeyToAccount: privateKeyToAccount26 } = await import('viem/accounts');
|
|
1564
|
+
const userAccount = privateKeyToAccount26(commonOptions.privateKey);
|
|
1563
1565
|
const storageUrl = generateStorageUrl(
|
|
1564
1566
|
userAccount.address,
|
|
1565
1567
|
commonOptions.chainId,
|
|
@@ -2394,7 +2396,22 @@ async function executeProfileGet(options) {
|
|
|
2394
2396
|
throw error;
|
|
2395
2397
|
}
|
|
2396
2398
|
}
|
|
2397
|
-
|
|
2399
|
+
let cssSize;
|
|
2400
|
+
try {
|
|
2401
|
+
const cssResult = await client.readStorageData({
|
|
2402
|
+
key: PROFILE_CSS_STORAGE_KEY,
|
|
2403
|
+
operator: options.address
|
|
2404
|
+
});
|
|
2405
|
+
if (cssResult.data) {
|
|
2406
|
+
cssSize = cssResult.data.length;
|
|
2407
|
+
}
|
|
2408
|
+
} catch (error) {
|
|
2409
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
2410
|
+
if (errorMessage !== "StoredDataNotFound") {
|
|
2411
|
+
throw error;
|
|
2412
|
+
}
|
|
2413
|
+
}
|
|
2414
|
+
const hasProfile = profilePicture || xUsername || bio || tokenAddress || canvasSize || cssSize;
|
|
2398
2415
|
if (options.json) {
|
|
2399
2416
|
const output = {
|
|
2400
2417
|
address: options.address,
|
|
@@ -2404,6 +2421,7 @@ async function executeProfileGet(options) {
|
|
|
2404
2421
|
bio: bio || null,
|
|
2405
2422
|
tokenAddress: tokenAddress || null,
|
|
2406
2423
|
canvas: canvasSize ? { size: canvasSize, isDataUri: canvasIsDataUri } : null,
|
|
2424
|
+
css: cssSize ? { size: cssSize } : null,
|
|
2407
2425
|
hasProfile
|
|
2408
2426
|
};
|
|
2409
2427
|
console.log(JSON.stringify(output, null, 2));
|
|
@@ -2427,6 +2445,9 @@ async function executeProfileGet(options) {
|
|
|
2427
2445
|
console.log(
|
|
2428
2446
|
` ${chalk4.cyan("Canvas:")} ${canvasSize ? `${canvasSize} bytes${canvasIsDataUri ? " (data URI)" : ""}` : chalk4.gray("(not set)")}`
|
|
2429
2447
|
);
|
|
2448
|
+
console.log(
|
|
2449
|
+
` ${chalk4.cyan("Custom CSS:")} ${cssSize ? `${cssSize} bytes` : chalk4.gray("(not set)")}`
|
|
2450
|
+
);
|
|
2430
2451
|
if (!hasProfile) {
|
|
2431
2452
|
console.log(chalk4.yellow("\n No profile data found for this address."));
|
|
2432
2453
|
}
|
|
@@ -2989,10 +3010,10 @@ async function executeProfileSetCanvas(options) {
|
|
|
2989
3010
|
let canvasContent;
|
|
2990
3011
|
if (options.file) {
|
|
2991
3012
|
const filePath = path.resolve(options.file);
|
|
2992
|
-
if (!
|
|
3013
|
+
if (!fs6.existsSync(filePath)) {
|
|
2993
3014
|
exitWithError(`File not found: ${filePath}`);
|
|
2994
3015
|
}
|
|
2995
|
-
const buffer =
|
|
3016
|
+
const buffer = fs6.readFileSync(filePath);
|
|
2996
3017
|
if (buffer.length > MAX_CANVAS_SIZE) {
|
|
2997
3018
|
exitWithError(
|
|
2998
3019
|
`File too large: ${buffer.length} bytes exceeds maximum of ${MAX_CANVAS_SIZE} bytes (60KB).`
|
|
@@ -3167,12 +3188,12 @@ async function executeProfileGetCanvas(options) {
|
|
|
3167
3188
|
if (!path.extname(outputPath)) {
|
|
3168
3189
|
finalPath = outputPath + getExtensionFromMimeType(mimeType);
|
|
3169
3190
|
}
|
|
3170
|
-
|
|
3191
|
+
fs6.writeFileSync(finalPath, buffer);
|
|
3171
3192
|
console.log(
|
|
3172
3193
|
chalk4.green(`Canvas written to: ${finalPath} (${buffer.length} bytes)`)
|
|
3173
3194
|
);
|
|
3174
3195
|
} else {
|
|
3175
|
-
|
|
3196
|
+
fs6.writeFileSync(outputPath, canvasContent, "utf-8");
|
|
3176
3197
|
console.log(
|
|
3177
3198
|
chalk4.green(
|
|
3178
3199
|
`Canvas written to: ${outputPath} (${canvasContent.length} bytes)`
|
|
@@ -3188,6 +3209,197 @@ async function executeProfileGetCanvas(options) {
|
|
|
3188
3209
|
);
|
|
3189
3210
|
}
|
|
3190
3211
|
}
|
|
3212
|
+
async function executeProfileSetCSS(options) {
|
|
3213
|
+
const sourceCount = [options.file, options.content, options.theme].filter(
|
|
3214
|
+
Boolean
|
|
3215
|
+
).length;
|
|
3216
|
+
if (sourceCount === 0) {
|
|
3217
|
+
exitWithError(
|
|
3218
|
+
"Must provide one of --file, --content, or --theme to set CSS."
|
|
3219
|
+
);
|
|
3220
|
+
}
|
|
3221
|
+
if (sourceCount > 1) {
|
|
3222
|
+
exitWithError("Cannot provide more than one of --file, --content, --theme.");
|
|
3223
|
+
}
|
|
3224
|
+
let cssContent;
|
|
3225
|
+
if (options.theme) {
|
|
3226
|
+
const theme = DEMO_THEMES[options.theme];
|
|
3227
|
+
if (!theme) {
|
|
3228
|
+
const available = Object.entries(DEMO_THEMES).map(([key, val]) => ` ${key} \u2014 ${val.name}`).join("\n");
|
|
3229
|
+
exitWithError(
|
|
3230
|
+
`Unknown theme: "${options.theme}"
|
|
3231
|
+
|
|
3232
|
+
Available themes:
|
|
3233
|
+
${available}`
|
|
3234
|
+
);
|
|
3235
|
+
}
|
|
3236
|
+
cssContent = theme.css;
|
|
3237
|
+
console.log(chalk4.gray(` Using theme: ${theme.name}`));
|
|
3238
|
+
} else if (options.file) {
|
|
3239
|
+
const filePath = path.resolve(options.file);
|
|
3240
|
+
if (!fs6.existsSync(filePath)) {
|
|
3241
|
+
exitWithError(`File not found: ${filePath}`);
|
|
3242
|
+
}
|
|
3243
|
+
const buffer = fs6.readFileSync(filePath);
|
|
3244
|
+
if (buffer.length > MAX_CSS_SIZE) {
|
|
3245
|
+
exitWithError(
|
|
3246
|
+
`File too large: ${buffer.length} bytes exceeds maximum of ${MAX_CSS_SIZE} bytes (10KB).`
|
|
3247
|
+
);
|
|
3248
|
+
}
|
|
3249
|
+
cssContent = buffer.toString("utf-8");
|
|
3250
|
+
} else {
|
|
3251
|
+
cssContent = options.content;
|
|
3252
|
+
const contentSize = Buffer.byteLength(cssContent, "utf-8");
|
|
3253
|
+
if (contentSize > MAX_CSS_SIZE) {
|
|
3254
|
+
exitWithError(
|
|
3255
|
+
`Content too large: ${contentSize} bytes exceeds maximum of ${MAX_CSS_SIZE} bytes (10KB).`
|
|
3256
|
+
);
|
|
3257
|
+
}
|
|
3258
|
+
}
|
|
3259
|
+
if (!isValidCSS(cssContent)) {
|
|
3260
|
+
exitWithError(
|
|
3261
|
+
"Invalid CSS: content is empty, too large, or contains disallowed patterns (script injection)."
|
|
3262
|
+
);
|
|
3263
|
+
}
|
|
3264
|
+
const storageArgs = getProfileCSSStorageArgs(cssContent);
|
|
3265
|
+
if (options.encodeOnly) {
|
|
3266
|
+
const readOnlyOptions = parseReadOnlyOptions({
|
|
3267
|
+
chainId: options.chainId,
|
|
3268
|
+
rpcUrl: options.rpcUrl
|
|
3269
|
+
});
|
|
3270
|
+
const encoded = encodeTransaction(
|
|
3271
|
+
{
|
|
3272
|
+
to: STORAGE_CONTRACT.address,
|
|
3273
|
+
abi: STORAGE_CONTRACT.abi,
|
|
3274
|
+
functionName: "put",
|
|
3275
|
+
args: [storageArgs.bytesKey, storageArgs.topic, storageArgs.bytesValue]
|
|
3276
|
+
},
|
|
3277
|
+
readOnlyOptions.chainId
|
|
3278
|
+
);
|
|
3279
|
+
console.log(JSON.stringify(encoded, null, 2));
|
|
3280
|
+
return;
|
|
3281
|
+
}
|
|
3282
|
+
const commonOptions = parseCommonOptions(
|
|
3283
|
+
{
|
|
3284
|
+
privateKey: options.privateKey,
|
|
3285
|
+
chainId: options.chainId,
|
|
3286
|
+
rpcUrl: options.rpcUrl
|
|
3287
|
+
},
|
|
3288
|
+
true
|
|
3289
|
+
);
|
|
3290
|
+
try {
|
|
3291
|
+
const account = privateKeyToAccount(commonOptions.privateKey);
|
|
3292
|
+
const rpcUrls = getChainRpcUrls({
|
|
3293
|
+
chainId: commonOptions.chainId,
|
|
3294
|
+
rpcUrl: commonOptions.rpcUrl
|
|
3295
|
+
});
|
|
3296
|
+
const client = createWalletClient({
|
|
3297
|
+
account,
|
|
3298
|
+
chain: base,
|
|
3299
|
+
transport: http(rpcUrls[0])
|
|
3300
|
+
}).extend(publicActions);
|
|
3301
|
+
console.log(chalk4.blue(`Setting profile CSS...`));
|
|
3302
|
+
console.log(
|
|
3303
|
+
chalk4.gray(
|
|
3304
|
+
` Content size: ${Buffer.byteLength(cssContent, "utf-8")} bytes`
|
|
3305
|
+
)
|
|
3306
|
+
);
|
|
3307
|
+
console.log(chalk4.gray(` Address: ${account.address}`));
|
|
3308
|
+
const hash = await client.writeContract({
|
|
3309
|
+
address: STORAGE_CONTRACT.address,
|
|
3310
|
+
abi: STORAGE_CONTRACT.abi,
|
|
3311
|
+
functionName: "put",
|
|
3312
|
+
args: [storageArgs.bytesKey, storageArgs.topic, storageArgs.bytesValue]
|
|
3313
|
+
});
|
|
3314
|
+
console.log(chalk4.blue(`Waiting for confirmation...`));
|
|
3315
|
+
const receipt = await client.waitForTransactionReceipt({ hash });
|
|
3316
|
+
if (receipt.status === "success") {
|
|
3317
|
+
console.log(
|
|
3318
|
+
chalk4.green(
|
|
3319
|
+
`
|
|
3320
|
+
CSS updated successfully!
|
|
3321
|
+
Transaction: ${hash}
|
|
3322
|
+
Content size: ${Buffer.byteLength(cssContent, "utf-8")} bytes`
|
|
3323
|
+
)
|
|
3324
|
+
);
|
|
3325
|
+
} else {
|
|
3326
|
+
exitWithError(`Transaction failed: ${hash}`);
|
|
3327
|
+
}
|
|
3328
|
+
} catch (error) {
|
|
3329
|
+
exitWithError(
|
|
3330
|
+
`Failed to set CSS: ${error instanceof Error ? error.message : String(error)}`
|
|
3331
|
+
);
|
|
3332
|
+
}
|
|
3333
|
+
}
|
|
3334
|
+
async function executeProfileGetCSS(options) {
|
|
3335
|
+
const readOnlyOptions = parseReadOnlyOptions({
|
|
3336
|
+
chainId: options.chainId,
|
|
3337
|
+
rpcUrl: options.rpcUrl
|
|
3338
|
+
});
|
|
3339
|
+
const client = new StorageClient({
|
|
3340
|
+
chainId: readOnlyOptions.chainId,
|
|
3341
|
+
overrides: options.rpcUrl ? { rpcUrls: [options.rpcUrl] } : void 0
|
|
3342
|
+
});
|
|
3343
|
+
try {
|
|
3344
|
+
let cssContent;
|
|
3345
|
+
try {
|
|
3346
|
+
const result = await client.readStorageData({
|
|
3347
|
+
key: PROFILE_CSS_STORAGE_KEY,
|
|
3348
|
+
operator: options.address
|
|
3349
|
+
});
|
|
3350
|
+
if (result.data) {
|
|
3351
|
+
cssContent = result.data;
|
|
3352
|
+
}
|
|
3353
|
+
} catch (error) {
|
|
3354
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
3355
|
+
if (errorMessage !== "StoredDataNotFound") {
|
|
3356
|
+
throw error;
|
|
3357
|
+
}
|
|
3358
|
+
}
|
|
3359
|
+
if (options.json) {
|
|
3360
|
+
const output = {
|
|
3361
|
+
address: options.address,
|
|
3362
|
+
chainId: readOnlyOptions.chainId,
|
|
3363
|
+
css: cssContent || null,
|
|
3364
|
+
hasCSS: !!cssContent,
|
|
3365
|
+
contentLength: cssContent ? cssContent.length : 0
|
|
3366
|
+
};
|
|
3367
|
+
console.log(JSON.stringify(output, null, 2));
|
|
3368
|
+
return;
|
|
3369
|
+
}
|
|
3370
|
+
if (!cssContent) {
|
|
3371
|
+
exitWithError(`No custom CSS found for address: ${options.address}`);
|
|
3372
|
+
}
|
|
3373
|
+
if (options.output) {
|
|
3374
|
+
const outputPath = path.resolve(options.output);
|
|
3375
|
+
fs6.writeFileSync(outputPath, cssContent, "utf-8");
|
|
3376
|
+
console.log(
|
|
3377
|
+
chalk4.green(
|
|
3378
|
+
`CSS written to: ${outputPath} (${cssContent.length} bytes)`
|
|
3379
|
+
)
|
|
3380
|
+
);
|
|
3381
|
+
return;
|
|
3382
|
+
}
|
|
3383
|
+
console.log(cssContent);
|
|
3384
|
+
} catch (error) {
|
|
3385
|
+
exitWithError(
|
|
3386
|
+
`Failed to read CSS: ${error instanceof Error ? error.message : String(error)}`
|
|
3387
|
+
);
|
|
3388
|
+
}
|
|
3389
|
+
}
|
|
3390
|
+
async function executeProfileCSSPrompt(options) {
|
|
3391
|
+
if (options.listThemes) {
|
|
3392
|
+
console.log("Available demo themes:\n");
|
|
3393
|
+
for (const [key, theme] of Object.entries(DEMO_THEMES)) {
|
|
3394
|
+
console.log(` ${key} \u2014 ${theme.name}`);
|
|
3395
|
+
}
|
|
3396
|
+
console.log(
|
|
3397
|
+
"\nUse with: net profile set-css --theme <name>"
|
|
3398
|
+
);
|
|
3399
|
+
return;
|
|
3400
|
+
}
|
|
3401
|
+
console.log(buildCSSPrompt());
|
|
3402
|
+
}
|
|
3191
3403
|
|
|
3192
3404
|
// src/commands/profile/index.ts
|
|
3193
3405
|
function registerProfileCommand(program2) {
|
|
@@ -3378,6 +3590,51 @@ function registerProfileCommand(program2) {
|
|
|
3378
3590
|
json: options.json
|
|
3379
3591
|
});
|
|
3380
3592
|
});
|
|
3593
|
+
const setCSSCommand = new Command("set-css").description("Set your profile custom CSS theme").option("--file <path>", "Path to CSS file").option("--content <css>", "CSS content (inline)").option("--theme <name>", "Use a built-in demo theme (e.g. hotPink, midnightGrunge, ocean)").option(
|
|
3594
|
+
"--private-key <key>",
|
|
3595
|
+
"Private key (0x-prefixed hex, 66 characters). Can also be set via NET_PRIVATE_KEY env var"
|
|
3596
|
+
).option(
|
|
3597
|
+
"--chain-id <id>",
|
|
3598
|
+
"Chain ID. Can also be set via NET_CHAIN_ID env var",
|
|
3599
|
+
(value) => parseInt(value, 10)
|
|
3600
|
+
).option(
|
|
3601
|
+
"--rpc-url <url>",
|
|
3602
|
+
"Custom RPC URL. Can also be set via NET_RPC_URL env var"
|
|
3603
|
+
).option(
|
|
3604
|
+
"--encode-only",
|
|
3605
|
+
"Output transaction data as JSON instead of executing"
|
|
3606
|
+
).action(async (options) => {
|
|
3607
|
+
await executeProfileSetCSS({
|
|
3608
|
+
file: options.file,
|
|
3609
|
+
content: options.content,
|
|
3610
|
+
theme: options.theme,
|
|
3611
|
+
privateKey: options.privateKey,
|
|
3612
|
+
chainId: options.chainId,
|
|
3613
|
+
rpcUrl: options.rpcUrl,
|
|
3614
|
+
encodeOnly: options.encodeOnly
|
|
3615
|
+
});
|
|
3616
|
+
});
|
|
3617
|
+
const getCSSCommand = new Command("get-css").description("Get profile custom CSS for an address").requiredOption("--address <address>", "Wallet address to get CSS for").option("--output <path>", "Write CSS content to file instead of stdout").option(
|
|
3618
|
+
"--chain-id <id>",
|
|
3619
|
+
"Chain ID. Can also be set via NET_CHAIN_ID env var",
|
|
3620
|
+
(value) => parseInt(value, 10)
|
|
3621
|
+
).option(
|
|
3622
|
+
"--rpc-url <url>",
|
|
3623
|
+
"Custom RPC URL. Can also be set via NET_RPC_URL env var"
|
|
3624
|
+
).option("--json", "Output in JSON format").action(async (options) => {
|
|
3625
|
+
await executeProfileGetCSS({
|
|
3626
|
+
address: options.address,
|
|
3627
|
+
output: options.output,
|
|
3628
|
+
chainId: options.chainId,
|
|
3629
|
+
rpcUrl: options.rpcUrl,
|
|
3630
|
+
json: options.json
|
|
3631
|
+
});
|
|
3632
|
+
});
|
|
3633
|
+
const cssPromptCommand = new Command("css-prompt").description("Print the AI prompt for generating profile CSS themes").option("--list-themes", "List available demo themes instead of the prompt").action(async (options) => {
|
|
3634
|
+
await executeProfileCSSPrompt({
|
|
3635
|
+
listThemes: options.listThemes
|
|
3636
|
+
});
|
|
3637
|
+
});
|
|
3381
3638
|
profileCommand.addCommand(getCommand);
|
|
3382
3639
|
profileCommand.addCommand(setPictureCommand);
|
|
3383
3640
|
profileCommand.addCommand(setUsernameCommand);
|
|
@@ -3386,6 +3643,9 @@ function registerProfileCommand(program2) {
|
|
|
3386
3643
|
profileCommand.addCommand(setTokenAddressCommand);
|
|
3387
3644
|
profileCommand.addCommand(setCanvasCommand);
|
|
3388
3645
|
profileCommand.addCommand(getCanvasCommand);
|
|
3646
|
+
profileCommand.addCommand(setCSSCommand);
|
|
3647
|
+
profileCommand.addCommand(getCSSCommand);
|
|
3648
|
+
profileCommand.addCommand(cssPromptCommand);
|
|
3389
3649
|
}
|
|
3390
3650
|
|
|
3391
3651
|
// src/commands/bazaar/format.ts
|
|
@@ -5472,14 +5732,14 @@ var MAX_HISTORY_ENTRIES = 100;
|
|
|
5472
5732
|
var STATE_DIR = path.join(os.homedir(), ".botchan");
|
|
5473
5733
|
var STATE_FILE = path.join(STATE_DIR, "state.json");
|
|
5474
5734
|
function ensureStateDir() {
|
|
5475
|
-
if (!
|
|
5476
|
-
|
|
5735
|
+
if (!fs6.existsSync(STATE_DIR)) {
|
|
5736
|
+
fs6.mkdirSync(STATE_DIR, { recursive: true });
|
|
5477
5737
|
}
|
|
5478
5738
|
}
|
|
5479
5739
|
function loadState() {
|
|
5480
5740
|
try {
|
|
5481
|
-
if (
|
|
5482
|
-
const data =
|
|
5741
|
+
if (fs6.existsSync(STATE_FILE)) {
|
|
5742
|
+
const data = fs6.readFileSync(STATE_FILE, "utf-8");
|
|
5483
5743
|
return JSON.parse(data);
|
|
5484
5744
|
}
|
|
5485
5745
|
} catch {
|
|
@@ -5489,8 +5749,8 @@ function loadState() {
|
|
|
5489
5749
|
function saveState(state) {
|
|
5490
5750
|
ensureStateDir();
|
|
5491
5751
|
const tempFile = `${STATE_FILE}.tmp`;
|
|
5492
|
-
|
|
5493
|
-
|
|
5752
|
+
fs6.writeFileSync(tempFile, JSON.stringify(state, null, 2));
|
|
5753
|
+
fs6.renameSync(tempFile, STATE_FILE);
|
|
5494
5754
|
}
|
|
5495
5755
|
function getLastSeenTimestamp(feedName) {
|
|
5496
5756
|
const state = loadState();
|
|
@@ -5531,8 +5791,8 @@ function getFullState() {
|
|
|
5531
5791
|
return loadState();
|
|
5532
5792
|
}
|
|
5533
5793
|
function resetState() {
|
|
5534
|
-
if (
|
|
5535
|
-
|
|
5794
|
+
if (fs6.existsSync(STATE_FILE)) {
|
|
5795
|
+
fs6.unlinkSync(STATE_FILE);
|
|
5536
5796
|
}
|
|
5537
5797
|
}
|
|
5538
5798
|
function getStateFilePath() {
|
|
@@ -6334,10 +6594,10 @@ async function confirm(message) {
|
|
|
6334
6594
|
input: process.stdin,
|
|
6335
6595
|
output: process.stdout
|
|
6336
6596
|
});
|
|
6337
|
-
return new Promise((
|
|
6597
|
+
return new Promise((resolve5) => {
|
|
6338
6598
|
rl.question(`${message} (y/N): `, (answer) => {
|
|
6339
6599
|
rl.close();
|
|
6340
|
-
|
|
6600
|
+
resolve5(answer.toLowerCase() === "y" || answer.toLowerCase() === "yes");
|
|
6341
6601
|
});
|
|
6342
6602
|
});
|
|
6343
6603
|
}
|
|
@@ -6654,6 +6914,86 @@ function registerFeedCommand(program2) {
|
|
|
6654
6914
|
registerFeedHistoryCommand(feedCommand);
|
|
6655
6915
|
registerAgentRegisterCommand(feedCommand);
|
|
6656
6916
|
}
|
|
6917
|
+
var CACHE_DIR = join(homedir(), ".netp");
|
|
6918
|
+
var CACHE_FILE = join(CACHE_DIR, "update-check.json");
|
|
6919
|
+
var CHECK_INTERVAL_MS = 4 * 60 * 60 * 1e3;
|
|
6920
|
+
var FETCH_TIMEOUT_MS = 5e3;
|
|
6921
|
+
function isNewerVersion(latest, current) {
|
|
6922
|
+
const l = latest.split(".").map(Number);
|
|
6923
|
+
const c = current.split(".").map(Number);
|
|
6924
|
+
for (let i = 0; i < 3; i++) {
|
|
6925
|
+
if ((l[i] || 0) > (c[i] || 0)) return true;
|
|
6926
|
+
if ((l[i] || 0) < (c[i] || 0)) return false;
|
|
6927
|
+
}
|
|
6928
|
+
return false;
|
|
6929
|
+
}
|
|
6930
|
+
function readCache() {
|
|
6931
|
+
try {
|
|
6932
|
+
if (existsSync(CACHE_FILE)) {
|
|
6933
|
+
return JSON.parse(readFileSync(CACHE_FILE, "utf-8"));
|
|
6934
|
+
}
|
|
6935
|
+
} catch {
|
|
6936
|
+
}
|
|
6937
|
+
return null;
|
|
6938
|
+
}
|
|
6939
|
+
function writeCache(cache) {
|
|
6940
|
+
try {
|
|
6941
|
+
if (!existsSync(CACHE_DIR)) {
|
|
6942
|
+
mkdirSync(CACHE_DIR, { recursive: true });
|
|
6943
|
+
}
|
|
6944
|
+
writeFileSync(CACHE_FILE, JSON.stringify(cache));
|
|
6945
|
+
} catch {
|
|
6946
|
+
}
|
|
6947
|
+
}
|
|
6948
|
+
async function fetchLatestVersion(pkg) {
|
|
6949
|
+
try {
|
|
6950
|
+
const controller = new AbortController();
|
|
6951
|
+
const timeout = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);
|
|
6952
|
+
const res = await fetch(
|
|
6953
|
+
`https://registry.npmjs.org/${encodeURIComponent(pkg).replace("%40", "@")}/latest`,
|
|
6954
|
+
{ signal: controller.signal }
|
|
6955
|
+
);
|
|
6956
|
+
clearTimeout(timeout);
|
|
6957
|
+
if (res.ok) {
|
|
6958
|
+
const data = await res.json();
|
|
6959
|
+
return data.version;
|
|
6960
|
+
}
|
|
6961
|
+
} catch {
|
|
6962
|
+
}
|
|
6963
|
+
return null;
|
|
6964
|
+
}
|
|
6965
|
+
async function getUpdateInfo(currentVersion) {
|
|
6966
|
+
const cache = readCache();
|
|
6967
|
+
if (cache && Date.now() - cache.lastCheck < CHECK_INTERVAL_MS) {
|
|
6968
|
+
if (cache.latestVersion && isNewerVersion(cache.latestVersion, currentVersion)) {
|
|
6969
|
+
return { latest: cache.latestVersion };
|
|
6970
|
+
}
|
|
6971
|
+
return null;
|
|
6972
|
+
}
|
|
6973
|
+
const latest = await fetchLatestVersion("@net-protocol/cli");
|
|
6974
|
+
writeCache({
|
|
6975
|
+
lastCheck: Date.now(),
|
|
6976
|
+
latestVersion: latest
|
|
6977
|
+
});
|
|
6978
|
+
if (latest && isNewerVersion(latest, currentVersion)) {
|
|
6979
|
+
return { latest };
|
|
6980
|
+
}
|
|
6981
|
+
return null;
|
|
6982
|
+
}
|
|
6983
|
+
function printUpdateBanner(current, latest) {
|
|
6984
|
+
console.error("");
|
|
6985
|
+
console.error(
|
|
6986
|
+
chalk4.yellow(
|
|
6987
|
+
` Update available: ${chalk4.gray(current)} \u2192 ${chalk4.green(latest)}`
|
|
6988
|
+
)
|
|
6989
|
+
);
|
|
6990
|
+
console.error(
|
|
6991
|
+
chalk4.yellow(
|
|
6992
|
+
` Run ${chalk4.cyan("npm install -g @net-protocol/cli@latest")} to update`
|
|
6993
|
+
)
|
|
6994
|
+
);
|
|
6995
|
+
console.error("");
|
|
6996
|
+
}
|
|
6657
6997
|
|
|
6658
6998
|
// src/cli/index.ts
|
|
6659
6999
|
var proxyUrl = process.env.https_proxy || process.env.HTTPS_PROXY;
|
|
@@ -6673,6 +7013,33 @@ registerTokenCommand(program);
|
|
|
6673
7013
|
registerProfileCommand(program);
|
|
6674
7014
|
registerBazaarCommand(program);
|
|
6675
7015
|
registerFeedCommand(program);
|
|
6676
|
-
program.
|
|
7016
|
+
program.command("update").description("Update netp to the latest version").action(async () => {
|
|
7017
|
+
const { execSync } = await import('child_process');
|
|
7018
|
+
console.log("Updating @net-protocol/cli...");
|
|
7019
|
+
try {
|
|
7020
|
+
execSync("npm install -g @net-protocol/cli@latest", {
|
|
7021
|
+
stdio: "inherit"
|
|
7022
|
+
});
|
|
7023
|
+
console.log(chalk4.green("\n\u2713 netp updated successfully"));
|
|
7024
|
+
} catch {
|
|
7025
|
+
console.error(
|
|
7026
|
+
chalk4.red(
|
|
7027
|
+
"Failed to update. Try manually: npm install -g @net-protocol/cli@latest"
|
|
7028
|
+
)
|
|
7029
|
+
);
|
|
7030
|
+
}
|
|
7031
|
+
});
|
|
7032
|
+
var updatePromise = getUpdateInfo(version).catch(() => null);
|
|
7033
|
+
await program.parseAsync();
|
|
7034
|
+
try {
|
|
7035
|
+
const updateInfo = await Promise.race([
|
|
7036
|
+
updatePromise,
|
|
7037
|
+
new Promise((resolve5) => setTimeout(() => resolve5(null), 1500))
|
|
7038
|
+
]);
|
|
7039
|
+
if (updateInfo) {
|
|
7040
|
+
printUpdateBanner(version, updateInfo.latest);
|
|
7041
|
+
}
|
|
7042
|
+
} catch {
|
|
7043
|
+
}
|
|
6677
7044
|
//# sourceMappingURL=index.mjs.map
|
|
6678
7045
|
//# sourceMappingURL=index.mjs.map
|