@0xobelisk/sui-cli 1.2.0-pre.99 → 2.0.0

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@0xobelisk/sui-cli",
3
- "version": "1.2.0-pre.99",
3
+ "version": "2.0.0",
4
4
  "description": "Tookit for interacting with move eps framework",
5
5
  "keywords": [
6
6
  "sui",
@@ -24,28 +24,7 @@
24
24
  "bin": {
25
25
  "dubhe": "./dist/dubhe.js"
26
26
  },
27
- "scripts": {
28
- "build": "pnpm run type-check && pnpm run build:js",
29
- "build:js": "tsup && chmod +x ./dist/dubhe.js",
30
- "clean": "pnpm run clean:js",
31
- "clean:js": "rimraf dist",
32
- "dev": "tsup --watch",
33
- "format": "prettier --write .",
34
- "format:check": "prettier --check .",
35
- "lint": "eslint . --ext .ts",
36
- "test": "vitest run",
37
- "test:all": "pnpm test && pnpm test:integration",
38
- "test:coverage": "vitest run --coverage",
39
- "test:integration": "vitest run --config vitest.integration.config.ts",
40
- "test:localnet": "vitest run --config vitest.integration.config.ts tests/integration/localnet.test.ts",
41
- "test:testnet": "vitest run --config vitest.integration.config.ts tests/integration/testnet.test.ts",
42
- "test:watch": "vitest",
43
- "type-check": "tsc --noEmit",
44
- "validate": "pnpm format:check && pnpm type-check"
45
- },
46
27
  "dependencies": {
47
- "@0xobelisk/sui-client": "workspace:*",
48
- "@0xobelisk/sui-common": "workspace:*",
49
28
  "@mysten/sui": "1.35.0",
50
29
  "@types/wait-on": "^5.3.4",
51
30
  "axios": "^1.12.0",
@@ -67,7 +46,9 @@
67
46
  "wait-on": "^7.0.1",
68
47
  "yargs": "^17.7.1",
69
48
  "zod": "^3.22.3",
70
- "zod-validation-error": "^1.3.0"
49
+ "zod-validation-error": "^1.3.0",
50
+ "@0xobelisk/sui-common": "2.0.0",
51
+ "@0xobelisk/sui-client": "2.0.0"
71
52
  },
72
53
  "devDependencies": {
73
54
  "@types/cli-progress": "^3.11.5",
@@ -89,5 +70,24 @@
89
70
  },
90
71
  "publishConfig": {
91
72
  "access": "public"
73
+ },
74
+ "scripts": {
75
+ "build": "pnpm run type-check && pnpm run build:js",
76
+ "build:js": "tsup && chmod +x ./dist/dubhe.js",
77
+ "clean": "pnpm run clean:js",
78
+ "clean:js": "rimraf dist",
79
+ "dev": "tsup --watch",
80
+ "format": "prettier --write .",
81
+ "format:check": "prettier --check .",
82
+ "lint": "eslint . --ext .ts",
83
+ "test": "vitest run",
84
+ "test:all": "pnpm test && pnpm test:integration",
85
+ "test:coverage": "vitest run --coverage",
86
+ "test:integration": "vitest run --config vitest.integration.config.ts",
87
+ "test:localnet": "vitest run --config vitest.integration.config.ts tests/integration/localnet.test.ts",
88
+ "test:testnet": "vitest run --config vitest.integration.config.ts tests/integration/testnet.test.ts",
89
+ "test:watch": "vitest",
90
+ "type-check": "tsc --noEmit",
91
+ "validate": "pnpm format:check && pnpm type-check"
92
92
  }
93
- }
93
+ }
@@ -4,12 +4,13 @@ import nodePath from 'path';
4
4
  import chalk from 'chalk';
5
5
  import { DubheConfig, loadConfig } from '@0xobelisk/sui-common';
6
6
  import { handlerExit } from './shell';
7
- import { getDefaultNetwork, switchEnv } from '../utils';
7
+ import { getDefaultNetwork, switchEnv, lintSystemGuards, formatLintWarnings } from '../utils';
8
8
 
9
9
  type Options = {
10
10
  'config-path': string;
11
11
  network: any;
12
12
  'dump-bytecode-as-base64'?: boolean;
13
+ 'rpc-url'?: string;
13
14
  };
14
15
 
15
16
  /**
@@ -61,6 +62,10 @@ const commandModule: CommandModule<Options, Options> = {
61
62
  type: 'boolean',
62
63
  default: false,
63
64
  desc: 'Dump bytecode as base64'
65
+ },
66
+ 'rpc-url': {
67
+ type: 'string',
68
+ desc: 'Custom RPC endpoint URL (overrides the default for the selected network)'
64
69
  }
65
70
  });
66
71
  },
@@ -68,7 +73,8 @@ const commandModule: CommandModule<Options, Options> = {
68
73
  async handler({
69
74
  'config-path': configPath,
70
75
  network,
71
- 'dump-bytecode-as-base64': dumpBytecodeAsBase64
76
+ 'dump-bytecode-as-base64': dumpBytecodeAsBase64,
77
+ 'rpc-url': rpcUrl
72
78
  }) {
73
79
  try {
74
80
  if (network == 'default') {
@@ -77,7 +83,13 @@ const commandModule: CommandModule<Options, Options> = {
77
83
  }
78
84
  console.log('🚀 Running move build');
79
85
  const dubheConfig = (await loadConfig(configPath)) as DubheConfig;
80
- await switchEnv(network);
86
+ await switchEnv(network, rpcUrl);
87
+
88
+ const projectPath = nodePath.join(process.cwd(), 'src', dubheConfig.name);
89
+ const lintResults = lintSystemGuards(projectPath);
90
+ const warnings = formatLintWarnings(lintResults);
91
+ if (warnings) process.stdout.write(warnings);
92
+
81
93
  const output = await buildHandler(dubheConfig, network, dumpBytecodeAsBase64);
82
94
  console.log(output);
83
95
  exec(`pnpm dubhe convert-json --config-path ${configPath}`);
@@ -6,26 +6,34 @@ import { getDefaultNetwork } from '../utils';
6
6
 
7
7
  type Options = {
8
8
  network: 'mainnet' | 'testnet' | 'devnet' | 'localnet' | 'default';
9
+ 'rpc-url'?: string;
9
10
  };
10
11
 
11
12
  const commandModule: CommandModule<Options, Options> = {
12
13
  command: 'check-balance',
13
14
  describe: 'Check the balance of the account',
14
- builder: {
15
- network: {
16
- type: 'string',
17
- choices: ['mainnet', 'testnet', 'devnet', 'localnet', 'default'],
18
- desc: 'Network to check balance on',
19
- default: 'default'
20
- }
15
+ builder(yargs) {
16
+ return yargs.options({
17
+ network: {
18
+ type: 'string',
19
+ choices: ['mainnet', 'testnet', 'devnet', 'localnet', 'default'],
20
+ desc: 'Network to check balance on',
21
+ default: 'default'
22
+ },
23
+ 'rpc-url': {
24
+ type: 'string',
25
+ desc: 'Custom RPC endpoint URL (overrides the default for the selected network)'
26
+ }
27
+ }) as any;
21
28
  },
22
- async handler({ network }) {
29
+ async handler({ network, 'rpc-url': rpcUrl }) {
23
30
  try {
24
31
  if (network == 'default') {
25
32
  network = await getDefaultNetwork();
26
33
  console.log(chalk.yellow(`Use default network: [${network}]`));
27
34
  }
28
- await checkBalanceHandler(network);
35
+ const fullnodeUrls = rpcUrl ? [rpcUrl] : undefined;
36
+ await checkBalanceHandler(network, fullnodeUrls);
29
37
  } catch (error) {
30
38
  console.error('Error checking balance:', error);
31
39
  handlerExit(1);
@@ -10,6 +10,34 @@ type Options = {
10
10
  'output-path': string;
11
11
  };
12
12
 
13
+ const RUNTIME_FIELDS = [
14
+ 'original_package_id',
15
+ 'dubhe_object_id',
16
+ 'original_dubhe_package_id',
17
+ 'dapp_key',
18
+ 'start_checkpoint',
19
+ 'package_ids'
20
+ ];
21
+
22
+ export function mergeConfigJsonRuntimeFields(
23
+ schemaJson: Record<string, unknown>,
24
+ existing: Record<string, unknown>
25
+ ): Record<string, unknown> {
26
+ const merged: Record<string, unknown> = { ...schemaJson };
27
+ for (const field of RUNTIME_FIELDS) {
28
+ if (existing[field] !== undefined) {
29
+ merged[field] = existing[field];
30
+ }
31
+ }
32
+ // If dapp_key is missing but original_package_id is present, compute it.
33
+ // This handles configs created before dapp_key was introduced.
34
+ if (!merged['dapp_key'] && merged['original_package_id']) {
35
+ const hex = (merged['original_package_id'] as string).replace(/^0x/i, '').padStart(64, '0');
36
+ merged['dapp_key'] = `${hex}::dapp_key::DappKey`;
37
+ }
38
+ return merged;
39
+ }
40
+
13
41
  const commandModule: CommandModule<Options, Options> = {
14
42
  command: 'convert-json',
15
43
  describe: 'Convert JSON from Dubhe config to config.json',
@@ -18,7 +46,7 @@ const commandModule: CommandModule<Options, Options> = {
18
46
  'config-path': {
19
47
  type: 'string',
20
48
  default: 'dubhe.config.ts',
21
- description: 'Options to pass to forge test'
49
+ description: 'Path to the Dubhe config file'
22
50
  },
23
51
  'output-path': {
24
52
  type: 'string',
@@ -34,33 +62,28 @@ const commandModule: CommandModule<Options, Options> = {
34
62
  const dubheConfig = (await loadConfig(configPath)) as DubheConfig;
35
63
  const schemaJson = JSON.parse(generateConfigJson(dubheConfig));
36
64
 
37
- // Preserve runtime fields written by publishHandler (package IDs, checkpoint, etc.)
38
- // so that re-running convert-json after publish does not wipe deployment info.
39
- const RUNTIME_FIELDS = [
40
- 'original_package_id',
41
- 'dubhe_object_id',
42
- 'original_dubhe_package_id',
43
- 'start_checkpoint'
44
- ];
45
65
  let existing: Record<string, unknown> = {};
46
- if (fs.existsSync(outputPath)) {
66
+ const isUpdate = fs.existsSync(outputPath);
67
+ if (isUpdate) {
47
68
  try {
48
69
  existing = JSON.parse(fs.readFileSync(outputPath, 'utf-8'));
49
70
  } catch {
50
71
  // ignore parse errors – start fresh
51
72
  }
52
73
  }
53
- const merged: Record<string, unknown> = { ...schemaJson };
54
- for (const field of RUNTIME_FIELDS) {
55
- if (existing[field] !== undefined) {
56
- merged[field] = existing[field];
57
- }
74
+ const merged = mergeConfigJsonRuntimeFields(schemaJson, existing);
75
+
76
+ // Log which runtime fields were preserved from the existing file
77
+ const preserved = RUNTIME_FIELDS.filter((f) => existing[f] !== undefined);
78
+ if (preserved.length > 0) {
79
+ console.log(chalk.gray(` preserved runtime fields: ${preserved.join(', ')}`));
58
80
  }
59
81
 
60
82
  fs.writeFileSync(outputPath, JSON.stringify(merged, null, 2));
83
+ console.log(chalk.green(`✅ ${isUpdate ? 'Updated' : 'Created'} ${outputPath}`));
61
84
  } catch (error: any) {
62
85
  console.error(chalk.red('Error executing convert json:'));
63
- console.log(error.stdout);
86
+ if (error.message) console.error(error.message);
64
87
  handlerExit(1);
65
88
  }
66
89
  handlerExit();
@@ -7,6 +7,7 @@ import { handlerExit } from './shell';
7
7
  type Options = {
8
8
  network: any;
9
9
  recipient?: string;
10
+ 'rpc-url'?: string;
10
11
  };
11
12
 
12
13
  const MAX_RETRIES = 60; // 60s timeout
@@ -28,15 +29,20 @@ const commandModule: CommandModule<Options, Options> = {
28
29
  },
29
30
  recipient: {
30
31
  type: 'string',
32
+ alias: 'r',
31
33
  desc: 'Sui address to fund'
34
+ },
35
+ 'rpc-url': {
36
+ type: 'string',
37
+ desc: 'Custom RPC endpoint URL for balance check (overrides the default for the selected network)'
32
38
  }
33
39
  });
34
40
  },
35
41
 
36
- async handler({ network, recipient }) {
42
+ async handler({ network, recipient, 'rpc-url': rpcUrl }) {
37
43
  let faucet_address = '';
38
44
  if (recipient === undefined) {
39
- const dubhe = initializeDubhe(network);
45
+ const dubhe = initializeDubhe({ network });
40
46
  faucet_address = dubhe.getAddress();
41
47
  } else {
42
48
  faucet_address = recipient;
@@ -107,7 +113,7 @@ const commandModule: CommandModule<Options, Options> = {
107
113
  process.stdout.write('\r' + ' '.repeat(50) + '\r');
108
114
 
109
115
  console.log(' └─ Checking balance...');
110
- const client = new SuiClient({ url: getFullnodeUrl(network) });
116
+ const client = new SuiClient({ url: rpcUrl || getFullnodeUrl(network) });
111
117
  let params = {
112
118
  owner: faucet_address
113
119
  } as GetBalanceParams;
@@ -1,5 +1,5 @@
1
1
  import type { CommandModule } from 'yargs';
2
- import { schemaGen, loadConfig, DubheConfig } from '@0xobelisk/sui-common';
2
+ import { codegen, loadConfig, DubheConfig } from '@0xobelisk/sui-common';
3
3
  import chalk from 'chalk';
4
4
  import path from 'node:path';
5
5
  import { handlerExit } from './shell';
@@ -8,12 +8,15 @@ import { getDefaultNetwork } from '../utils';
8
8
  type Options = {
9
9
  'config-path'?: string;
10
10
  network?: 'mainnet' | 'testnet' | 'devnet' | 'localnet' | 'default';
11
+ mode?: 'user_pays' | 'dapp_subsidizes';
11
12
  };
12
13
 
13
14
  const commandModule: CommandModule<Options, Options> = {
14
- command: 'schemagen',
15
+ command: 'generate',
16
+ // 'schemagen' kept as a deprecated alias for backward compatibility
17
+ aliases: ['schemagen'],
15
18
 
16
- describe: 'Autogenerate Dubhe schemas based on the config file',
19
+ describe: 'Generate Move code from dubhe.config.ts',
17
20
 
18
21
  builder: {
19
22
  'config-path': {
@@ -26,10 +29,16 @@ const commandModule: CommandModule<Options, Options> = {
26
29
  choices: ['mainnet', 'testnet', 'devnet', 'localnet', 'default'] as const,
27
30
  default: 'default',
28
31
  desc: 'Node network (mainnet/testnet/devnet/localnet)'
32
+ },
33
+ mode: {
34
+ type: 'string',
35
+ choices: ['user_pays', 'dapp_subsidizes'] as const,
36
+ default: 'user_pays',
37
+ desc: 'Initial settlement mode for this DApp (only applies on first generate)'
29
38
  }
30
39
  },
31
40
 
32
- async handler({ 'config-path': configPath, network }) {
41
+ async handler({ 'config-path': configPath, network, mode }) {
33
42
  try {
34
43
  if (!configPath) throw new Error('Config path is required');
35
44
  if (network == 'default') {
@@ -38,10 +47,11 @@ const commandModule: CommandModule<Options, Options> = {
38
47
  }
39
48
  const dubheConfig = (await loadConfig(configPath)) as DubheConfig;
40
49
  const rootDir = path.dirname(configPath);
41
- await schemaGen(rootDir, dubheConfig, network);
50
+ const initialMode: 0 | 1 = mode === 'dapp_subsidizes' ? 0 : 1;
51
+ await codegen(rootDir, dubheConfig, network, initialMode);
42
52
  handlerExit();
43
53
  } catch (error: any) {
44
- console.log(chalk.red('Schemagen failed!'));
54
+ console.log(chalk.red('Generate failed!'));
45
55
  console.error(error.message);
46
56
  handlerExit(1);
47
57
  }
@@ -2,14 +2,14 @@ import { CommandModule } from 'yargs';
2
2
 
3
3
  import localnode from './localnode';
4
4
  import faucet from './faucet';
5
- import schemagen from './schemagen';
5
+ import generate from './generate';
6
6
  import publish from './publish';
7
7
  import test from './test';
8
8
  import build from './build';
9
9
  import hello from './hello';
10
10
  import generateKey from './generateKey';
11
11
  import checkBalance from './checkBalance';
12
- import configStore from './configStore';
12
+ import storeConfig from './storeConfig';
13
13
  import watch from './watch';
14
14
  import wait from './wait';
15
15
  import switchEnv from './switchEnv';
@@ -26,14 +26,14 @@ export const commands: CommandModule<any, any>[] = [
26
26
  // call,
27
27
  // query,
28
28
  faucet,
29
- schemagen,
29
+ generate,
30
30
  upgrade,
31
31
  test,
32
32
  build,
33
33
  hello,
34
34
  generateKey,
35
35
  checkBalance,
36
- configStore,
36
+ storeConfig,
37
37
  watch,
38
38
  wait,
39
39
  switchEnv,
@@ -7,6 +7,7 @@ dotenv.config();
7
7
 
8
8
  type Options = {
9
9
  network: any;
10
+ 'rpc-url'?: string;
10
11
  };
11
12
 
12
13
  const InfoCommand: CommandModule<Options, Options> = {
@@ -19,16 +20,21 @@ const InfoCommand: CommandModule<Options, Options> = {
19
20
  choices: ['mainnet', 'testnet', 'devnet', 'localnet', 'default'],
20
21
  default: 'default',
21
22
  desc: 'Node network (mainnet/testnet/devnet/localnet)'
23
+ },
24
+ 'rpc-url': {
25
+ type: 'string',
26
+ desc: 'Custom RPC endpoint URL (overrides the default for the selected network)'
22
27
  }
23
28
  });
24
29
  },
25
- handler: async ({ network }) => {
30
+ handler: async ({ network, 'rpc-url': rpcUrl }) => {
26
31
  try {
27
32
  if (network == 'default') {
28
33
  network = await getDefaultNetwork();
29
34
  console.log(chalk.yellow(`Use default network: [${network}]`));
30
35
  }
31
- const dubhe = initializeDubhe({ network });
36
+ const fullnodeUrls = rpcUrl ? [rpcUrl] : undefined;
37
+ const dubhe = initializeDubhe({ network, fullnodeUrls });
32
38
  const keypair = dubhe.getSigner();
33
39
 
34
40
  console.log(chalk.blue('Account Information:'));
@@ -10,6 +10,7 @@ type Options = {
10
10
  network: any;
11
11
  'config-path': string;
12
12
  'package-id'?: string;
13
+ 'rpc-url'?: string;
13
14
  };
14
15
 
15
16
  const commandModule: CommandModule<Options, Options> = {
@@ -34,18 +35,28 @@ const commandModule: CommandModule<Options, Options> = {
34
35
  type: 'string',
35
36
  desc: 'Package ID to load metadata for',
36
37
  optional: true
38
+ },
39
+ 'rpc-url': {
40
+ type: 'string',
41
+ desc: 'Custom RPC endpoint URL (overrides the default for the selected network)'
37
42
  }
38
43
  });
39
44
  },
40
45
 
41
- async handler({ network, 'config-path': configPath, 'package-id': packageId }) {
46
+ async handler({
47
+ network,
48
+ 'config-path': configPath,
49
+ 'package-id': packageId,
50
+ 'rpc-url': rpcUrl
51
+ }) {
42
52
  try {
43
53
  if (network == 'default') {
44
54
  network = await getDefaultNetwork();
45
55
  console.log(chalk.yellow(`Use default network: [${network}]`));
46
56
  }
47
57
  const dubheConfig = (await loadConfig(configPath)) as DubheConfig;
48
- await loadMetadataHandler(dubheConfig, network, packageId);
58
+ const fullnodeUrls = rpcUrl ? [rpcUrl] : undefined;
59
+ await loadMetadataHandler(dubheConfig, network, packageId, fullnodeUrls);
49
60
  } catch (error: any) {
50
61
  logError(error);
51
62
  handlerExit(1);
@@ -1,8 +1,15 @@
1
1
  import type { CommandModule } from 'yargs';
2
2
  import { logError } from '../utils/errors';
3
- import { getDefaultNetwork, publishHandler } from '../utils';
3
+ import {
4
+ getDefaultNetwork,
5
+ publishHandler,
6
+ lintSystemGuards,
7
+ formatLintWarnings,
8
+ confirm
9
+ } from '../utils';
4
10
  import { loadConfig, DubheConfig } from '@0xobelisk/sui-common';
5
11
  import { execSync } from 'child_process';
12
+ import { join as pathJoin } from 'path';
6
13
  import { handlerExit } from './shell';
7
14
  import chalk from 'chalk';
8
15
 
@@ -11,6 +18,7 @@ type Options = {
11
18
  'config-path': string;
12
19
  force: boolean;
13
20
  'gas-budget'?: number;
21
+ 'rpc-url'?: string;
14
22
  };
15
23
 
16
24
  const commandModule: CommandModule<Options, Options> = {
@@ -38,21 +46,47 @@ const commandModule: CommandModule<Options, Options> = {
38
46
  },
39
47
  force: {
40
48
  type: 'boolean',
41
- default: true,
42
- desc: 'Force publish: do not update dependencies'
49
+ default: false,
50
+ desc: 'Clear existing published state for this network before build (use when re-publishing or to fix PublishErrorNonZeroAddress)'
51
+ },
52
+ 'rpc-url': {
53
+ type: 'string',
54
+ desc: 'Custom RPC endpoint URL (overrides the default for the selected network)'
43
55
  }
44
56
  });
45
57
  },
46
58
 
47
- async handler({ network, 'config-path': configPath, 'gas-budget': gasBudget, force }) {
59
+ async handler({
60
+ network,
61
+ 'config-path': configPath,
62
+ 'gas-budget': gasBudget,
63
+ force,
64
+ 'rpc-url': rpcUrl
65
+ }) {
48
66
  try {
49
67
  if (network == 'default') {
50
68
  network = await getDefaultNetwork();
51
69
  console.log(chalk.yellow(`Use default network: [${network}]`));
52
70
  }
53
71
  const dubheConfig = (await loadConfig(configPath)) as DubheConfig;
72
+
73
+ const projectPath = pathJoin(process.cwd(), 'src', dubheConfig.name);
74
+ const lintResults = lintSystemGuards(projectPath);
75
+ if (lintResults.length > 0) {
76
+ process.stdout.write(formatLintWarnings(lintResults));
77
+ const proceed = await confirm(
78
+ 'Some entry functions are missing ensure_latest_version. Proceed with publish anyway?'
79
+ );
80
+ if (!proceed) {
81
+ console.log(chalk.red('Publish cancelled.'));
82
+ handlerExit(1);
83
+ return;
84
+ }
85
+ }
86
+
87
+ const fullnodeUrls = rpcUrl ? [rpcUrl] : undefined;
54
88
  execSync(`pnpm dubhe convert-json --config-path ${configPath}`, { encoding: 'utf-8' });
55
- await publishHandler(dubheConfig, network, force, gasBudget);
89
+ await publishHandler(dubheConfig, network, force, gasBudget, fullnodeUrls);
56
90
  } catch (error: any) {
57
91
  logError(error);
58
92
  handlerExit(1);
@@ -20,6 +20,7 @@ export const handlerExit = (status: number = 0) => {
20
20
 
21
21
  type Options = {
22
22
  network: any;
23
+ 'rpc-url'?: string;
23
24
  };
24
25
 
25
26
  const parseCommandNames = () => {
@@ -38,10 +39,14 @@ const ShellCommand: CommandModule<Options, Options> = {
38
39
  choices: ['mainnet', 'testnet', 'devnet', 'localnet', 'default'],
39
40
  default: 'default',
40
41
  desc: 'Node network (mainnet/testnet/devnet/localnet)'
42
+ },
43
+ 'rpc-url': {
44
+ type: 'string',
45
+ desc: 'Custom RPC endpoint URL injected into every sub-command (overrides the default for the selected network)'
41
46
  }
42
47
  });
43
48
  },
44
- handler: async ({ network }) => {
49
+ handler: async ({ network, 'rpc-url': rpcUrl }) => {
45
50
  if (network == 'default') {
46
51
  network = await getDefaultNetwork();
47
52
  console.log(chalk.yellow(`Use default network: [${network}]`));
@@ -60,7 +65,9 @@ const ShellCommand: CommandModule<Options, Options> = {
60
65
  const rl = readline.createInterface({
61
66
  input: process.stdin,
62
67
  output: process.stdout,
63
- prompt: `dubhe(${chalk.green(network)}) ${chalk.bold('>')} `,
68
+ prompt: `dubhe(${chalk.green(network)}${
69
+ rpcUrl ? chalk.gray('[custom-rpc]') : ''
70
+ }) ${chalk.bold('>')} `,
64
71
  completer: completer,
65
72
  historySize: 200
66
73
  });
@@ -132,11 +139,14 @@ const ShellCommand: CommandModule<Options, Options> = {
132
139
  } else {
133
140
  yargsInstance.options(builder);
134
141
  }
142
+ const userArgs = parts.slice(1);
143
+ const hasNetworkFlag = userArgs.includes('--network') || userArgs.includes('-n');
144
+ const hasRpcUrlFlag = userArgs.includes('--rpc-url');
135
145
  const argv = yargsInstance.parseSync([
136
146
  commandName,
137
- '--network',
138
- network,
139
- ...parts.slice(1)
147
+ ...(hasNetworkFlag ? [] : ['--network', network]),
148
+ ...(hasRpcUrlFlag || !rpcUrl ? [] : ['--rpc-url', rpcUrl]),
149
+ ...userArgs
140
150
  ]);
141
151
  if (handler) {
142
152
  await handler(argv);
@@ -12,7 +12,7 @@ type Options = {
12
12
  };
13
13
 
14
14
  const commandModule: CommandModule<Options, Options> = {
15
- command: 'config-store',
15
+ command: 'store-config',
16
16
 
17
17
  describe: 'Store configuration for the Dubhe project',
18
18
 
@@ -30,6 +30,7 @@ const commandModule: CommandModule<Options, Options> = {
30
30
  },
31
31
  'output-ts-path': {
32
32
  type: 'string',
33
+ default: './deployment.ts',
33
34
  desc: 'Specify the output path for the generated TypeScript configuration file (e.g., ./src/config/generated.ts)'
34
35
  }
35
36
  },
@@ -4,21 +4,28 @@ import { handlerExit } from './shell';
4
4
 
5
5
  type Options = {
6
6
  network: 'mainnet' | 'testnet' | 'devnet' | 'localnet' | 'default';
7
+ 'rpc-url'?: string;
7
8
  };
8
9
 
9
10
  const commandModule: CommandModule<Options, Options> = {
10
11
  command: 'switch-env',
11
12
  describe: 'Switch environment',
12
13
  builder(yargs) {
13
- return yargs.option('network', {
14
- type: 'string',
15
- choices: ['mainnet', 'testnet', 'devnet', 'localnet'] as const,
16
- default: 'localnet',
17
- desc: 'Switch to node network (mainnet/testnet/devnet/localnet)'
14
+ return yargs.options({
15
+ network: {
16
+ type: 'string',
17
+ choices: ['mainnet', 'testnet', 'devnet', 'localnet'] as const,
18
+ default: 'localnet',
19
+ desc: 'Switch to node network (mainnet/testnet/devnet/localnet)'
20
+ },
21
+ 'rpc-url': {
22
+ type: 'string',
23
+ desc: 'Custom RPC endpoint URL (overrides the default for the selected network)'
24
+ }
18
25
  }) as any;
19
26
  },
20
27
  async handler(argv: ArgumentsCamelCase<Options>) {
21
- await switchEnv(argv.network as 'mainnet' | 'testnet' | 'devnet' | 'localnet');
28
+ await switchEnv(argv.network as 'mainnet' | 'testnet' | 'devnet' | 'localnet', argv['rpc-url']);
22
29
  handlerExit();
23
30
  }
24
31
  };