@0xobelisk/sui-cli 1.2.0-pre.1 → 1.2.0-pre.100

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.
Files changed (38) hide show
  1. package/README.md +3 -3
  2. package/dist/dubhe.js +125 -66
  3. package/dist/dubhe.js.map +1 -1
  4. package/package.json +31 -19
  5. package/src/commands/build.ts +47 -16
  6. package/src/commands/call.ts +83 -83
  7. package/src/commands/checkBalance.ts +12 -5
  8. package/src/commands/configStore.ts +12 -4
  9. package/src/commands/convertJson.ts +70 -0
  10. package/src/commands/doctor.ts +1515 -0
  11. package/src/commands/faucet.ts +11 -7
  12. package/src/commands/generateKey.ts +3 -2
  13. package/src/commands/index.ts +16 -7
  14. package/src/commands/info.ts +55 -0
  15. package/src/commands/loadMetadata.ts +57 -0
  16. package/src/commands/localnode.ts +22 -12
  17. package/src/commands/publish.ts +21 -7
  18. package/src/commands/query.ts +101 -101
  19. package/src/commands/schemagen.ts +15 -4
  20. package/src/commands/shell.ts +198 -0
  21. package/src/commands/switchEnv.ts +26 -0
  22. package/src/commands/test.ts +54 -11
  23. package/src/commands/upgrade.ts +11 -4
  24. package/src/commands/wait.ts +333 -22
  25. package/src/commands/watch.ts +2 -1
  26. package/src/dubhe.ts +12 -4
  27. package/src/utils/axios-downloader.ts +116 -0
  28. package/src/utils/callHandler.ts +118 -118
  29. package/src/utils/constants.ts +5 -0
  30. package/src/utils/generateAccount.ts +1 -1
  31. package/src/utils/index.ts +4 -3
  32. package/src/utils/metadataHandler.ts +16 -0
  33. package/src/utils/publishHandler.ts +295 -290
  34. package/src/utils/queryStorage.ts +141 -141
  35. package/src/utils/startNode.ts +165 -108
  36. package/src/utils/storeConfig.ts +6 -12
  37. package/src/utils/upgradeHandler.ts +147 -86
  38. package/src/utils/utils.ts +771 -54
@@ -0,0 +1,198 @@
1
+ import readline from 'readline';
2
+
3
+ import yargs, { CommandModule } from 'yargs';
4
+ import { commands } from '.';
5
+ import chalk from 'chalk';
6
+ import { getDefaultNetwork, printDubhe } from '../utils';
7
+ import dotenv from 'dotenv';
8
+ import { spawn } from 'child_process';
9
+
10
+ dotenv.config();
11
+
12
+ let shouldHandlerExit = true;
13
+
14
+ // Blacklist of commands not available inside shell
15
+ const SHELL_BLACKLIST_COMMANDS = ['shell', 'wait'];
16
+
17
+ export const handlerExit = (status: number = 0) => {
18
+ if (shouldHandlerExit) process.exit(status);
19
+ };
20
+
21
+ type Options = {
22
+ network: any;
23
+ };
24
+
25
+ const parseCommandNames = () => {
26
+ return commands
27
+ .filter((command) => !SHELL_BLACKLIST_COMMANDS.includes(command.command as string))
28
+ .map((command) => command.command);
29
+ };
30
+
31
+ const ShellCommand: CommandModule<Options, Options> = {
32
+ command: 'shell',
33
+ describe: 'Open a shell to interact with the Dubhe System',
34
+ builder(yargs) {
35
+ return yargs.options({
36
+ network: {
37
+ type: 'string',
38
+ choices: ['mainnet', 'testnet', 'devnet', 'localnet', 'default'],
39
+ default: 'default',
40
+ desc: 'Node network (mainnet/testnet/devnet/localnet)'
41
+ }
42
+ });
43
+ },
44
+ handler: async ({ network }) => {
45
+ if (network == 'default') {
46
+ network = await getDefaultNetwork();
47
+ console.log(chalk.yellow(`Use default network: [${network}]`));
48
+ }
49
+ shouldHandlerExit = false;
50
+ const commandHistory: string[] = [];
51
+
52
+ function completer(line: string) {
53
+ const hits = parseCommandNames().filter((c) => {
54
+ if (!c) return false;
55
+ return (c as string).startsWith(line.toLowerCase());
56
+ });
57
+ return [hits.length ? hits : parseCommandNames(), line];
58
+ }
59
+
60
+ const rl = readline.createInterface({
61
+ input: process.stdin,
62
+ output: process.stdout,
63
+ prompt: `dubhe(${chalk.green(network)}) ${chalk.bold('>')} `,
64
+ completer: completer,
65
+ historySize: 200
66
+ });
67
+
68
+ rl.on('line', async (line) => {
69
+ const fullCommand = line.trim();
70
+ if (!fullCommand) {
71
+ rl.prompt();
72
+ return;
73
+ }
74
+
75
+ // Add command to history
76
+ commandHistory.push(fullCommand);
77
+
78
+ const parts = fullCommand.split(/\s+/);
79
+ const commandName = parts[0].toLowerCase();
80
+
81
+ const command = commands.find(
82
+ (c) => c.command === commandName && !SHELL_BLACKLIST_COMMANDS.includes(commandName)
83
+ );
84
+
85
+ // Check if user is asking for help
86
+ if (parts.includes('--help') || parts.includes('-h')) {
87
+ if (command) {
88
+ try {
89
+ // Use spawn to call dubhe help externally to avoid validation issues
90
+ const dubheProcess = spawn('node', [process.argv[1], commandName, '--help'], {
91
+ stdio: 'inherit',
92
+ env: { ...process.env }
93
+ });
94
+
95
+ dubheProcess.on('exit', () => {
96
+ rl.prompt();
97
+ });
98
+
99
+ dubheProcess.on('error', () => {
100
+ // Fallback: show basic help information
101
+ console.log(`\n${command.describe || `${commandName} command`}`);
102
+ console.log(`\nUsage: ${commandName} [options]`);
103
+ console.log('\nFor complete help with all options, please exit shell and run:');
104
+ console.log(chalk.cyan(` dubhe ${commandName} --help`));
105
+ rl.prompt();
106
+ });
107
+
108
+ return; // Don't call rl.prompt() here as it's handled in the callbacks
109
+ } catch {
110
+ // Fallback: show basic help information
111
+ console.log(`\n${command.describe || `${commandName} command`}`);
112
+ console.log(`\nUsage: ${commandName} [options]`);
113
+ console.log('\nFor complete help with all options, please exit shell and run:');
114
+ console.log(chalk.cyan(` dubhe ${commandName} --help`));
115
+ }
116
+ } else {
117
+ console.log(
118
+ `🤷 Unknown command: "${commandName}". Type 'help' to see available commands.`
119
+ );
120
+ }
121
+ rl.prompt();
122
+ return;
123
+ }
124
+
125
+ if (command) {
126
+ try {
127
+ const { builder, handler } = command;
128
+ const yargsInstance = yargs().exitProcess(false);
129
+ if (builder) {
130
+ if (typeof builder === 'function') {
131
+ builder(yargsInstance);
132
+ } else {
133
+ yargsInstance.options(builder);
134
+ }
135
+ const argv = yargsInstance.parseSync([
136
+ commandName,
137
+ '--network',
138
+ network,
139
+ ...parts.slice(1)
140
+ ]);
141
+ if (handler) {
142
+ await handler(argv);
143
+ }
144
+ }
145
+ } catch (error) {
146
+ console.log(chalk.red(error));
147
+ }
148
+ } else if (commandName == 'help') {
149
+ console.log('Available dubhe commands:');
150
+
151
+ // Find the longest command name for alignment (excluding blacklisted commands)
152
+ const availableCommands = commands.filter(
153
+ (c) => !SHELL_BLACKLIST_COMMANDS.includes(c.command as string)
154
+ );
155
+ const maxCommandLength = Math.max(
156
+ ...availableCommands.map((c) => {
157
+ const command =
158
+ typeof c.command === 'string'
159
+ ? c.command
160
+ : Array.isArray(c.command)
161
+ ? c.command[0]
162
+ : '';
163
+ return command.length;
164
+ })
165
+ );
166
+
167
+ availableCommands.forEach((c) => {
168
+ const command =
169
+ typeof c.command === 'string'
170
+ ? c.command
171
+ : Array.isArray(c.command)
172
+ ? c.command[0]
173
+ : '';
174
+ const paddedCommand = command.padEnd(maxCommandLength);
175
+ console.log(` ${chalk.green(paddedCommand)} ${c.describe}`);
176
+ });
177
+ rl.prompt();
178
+ return;
179
+ } else if (['exit', 'quit'].indexOf(commandName) !== -1) {
180
+ console.log('Goodbye You will have a nice day! 👋');
181
+ rl.close();
182
+ return;
183
+ } else {
184
+ console.log(`🤷 Unknown command: "${fullCommand}". Type 'help' to see available commands.`);
185
+ }
186
+ rl.prompt();
187
+ });
188
+
189
+ rl.on('close', () => {
190
+ process.exit(0);
191
+ });
192
+
193
+ printDubhe();
194
+ rl.prompt();
195
+ }
196
+ };
197
+
198
+ export default ShellCommand;
@@ -0,0 +1,26 @@
1
+ import type { CommandModule, ArgumentsCamelCase } from 'yargs';
2
+ import { switchEnv } from '../utils';
3
+ import { handlerExit } from './shell';
4
+
5
+ type Options = {
6
+ network: 'mainnet' | 'testnet' | 'devnet' | 'localnet' | 'default';
7
+ };
8
+
9
+ const commandModule: CommandModule<Options, Options> = {
10
+ command: 'switch-env',
11
+ describe: 'Switch environment',
12
+ 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)'
18
+ }) as any;
19
+ },
20
+ async handler(argv: ArgumentsCamelCase<Options>) {
21
+ await switchEnv(argv.network as 'mainnet' | 'testnet' | 'devnet' | 'localnet');
22
+ handlerExit();
23
+ }
24
+ };
25
+
26
+ export default commandModule;
@@ -1,6 +1,19 @@
1
1
  import type { CommandModule } from 'yargs';
2
2
  import { execSync } from 'child_process';
3
3
  import { DubheConfig, loadConfig } from '@0xobelisk/sui-common';
4
+ import { handlerExit } from './shell';
5
+
6
+ /**
7
+ * Returns the active Sui client environment (e.g. "localnet", "testnet").
8
+ * Falls back to "testnet" if the command fails.
9
+ */
10
+ function getActiveSuiEnv(): string {
11
+ try {
12
+ return execSync('sui client active-env', { encoding: 'utf-8', stdio: 'pipe' }).trim();
13
+ } catch {
14
+ return 'testnet';
15
+ }
16
+ }
4
17
 
5
18
  type Options = {
6
19
  'config-path': string;
@@ -8,21 +21,45 @@ type Options = {
8
21
  'gas-limit'?: string;
9
22
  };
10
23
 
24
+ /**
25
+ * Core Move test runner for Dubhe contracts.
26
+ * Runs `sui move test` against the package at `src/<dubheConfig.name>`.
27
+ *
28
+ * Move unit tests compile packages locally — no network or published address required.
29
+ */
30
+ export async function testHandler(
31
+ dubheConfig: DubheConfig,
32
+ test?: string,
33
+ gasLimit: string = '100000000',
34
+ buildEnv?: string
35
+ ): Promise<string> {
36
+ const cwd = process.cwd();
37
+ const projectPath = `${cwd}/src/${dubheConfig.name}`;
38
+ // --build-env overrides the active Sui client environment for dependency resolution.
39
+ // Required for localnet (which is not in Move.toml [environments]) when the
40
+ // active client env has been set to localnet from a previous run.
41
+ const buildEnvFlag = buildEnv ? `--build-env ${buildEnv}` : '';
42
+ const command = `sui move test ${buildEnvFlag} --path ${projectPath} ${
43
+ test ? `--test ${test}` : ''
44
+ } --gas-limit ${gasLimit}`;
45
+ return execSync(command, { stdio: 'pipe', encoding: 'utf-8' });
46
+ }
47
+
11
48
  const commandModule: CommandModule<Options, Options> = {
12
49
  command: 'test',
13
50
 
14
- describe: 'Run tests in Dubhe contracts',
51
+ describe: 'Run Move unit tests in Dubhe contracts',
15
52
 
16
53
  builder(yargs) {
17
54
  return yargs.options({
18
55
  'config-path': {
19
56
  type: 'string',
20
57
  default: 'dubhe.config.ts',
21
- description: 'Options to pass to forge test'
58
+ description: 'Path to the Dubhe config file'
22
59
  },
23
60
  test: {
24
61
  type: 'string',
25
- desc: 'Run a specific test'
62
+ desc: 'Run a specific test by name'
26
63
  },
27
64
  'gas-limit': {
28
65
  type: 'string',
@@ -33,19 +70,25 @@ const commandModule: CommandModule<Options, Options> = {
33
70
  },
34
71
 
35
72
  async handler({ 'config-path': configPath, test, 'gas-limit': gasLimit }) {
36
- // Start an internal anvil process if no world address is provided
37
73
  try {
38
74
  console.log('🚀 Running move test');
39
75
  const dubheConfig = (await loadConfig(configPath)) as DubheConfig;
40
- const path = process.cwd();
41
- const projectPath = `${path}/contracts/${dubheConfig.name}`;
42
- const command = `sui move test --path ${projectPath} ${
43
- test ? ` --test ${test}` : ''
44
- } --gas-limit ${gasLimit}`;
45
- execSync(command, { stdio: 'inherit', encoding: 'utf-8' });
76
+
77
+ // Ephemeral networks (localnet/devnet) are not defined in Move.toml [environments].
78
+ // Use --build-env testnet for dependency resolution so `sui move test` can resolve
79
+ // git dependencies without requiring a localnet env entry.
80
+ const activeEnv = getActiveSuiEnv();
81
+ const buildEnv = activeEnv === 'localnet' || activeEnv === 'devnet' ? 'testnet' : undefined;
82
+
83
+ const output = await testHandler(dubheConfig, test, gasLimit, buildEnv);
84
+ if (output) process.stdout.write(output);
46
85
  } catch (error: any) {
47
- process.exit(0);
86
+ if (error.stdout) process.stdout.write(error.stdout);
87
+ if (error.stderr) process.stderr.write(error.stderr);
88
+ if (!error.stdout && !error.stderr && error.message) process.stderr.write(error.message);
89
+ handlerExit(1);
48
90
  }
91
+ handlerExit();
49
92
  }
50
93
  };
51
94
 
@@ -2,6 +2,9 @@ import type { CommandModule } from 'yargs';
2
2
  import { logError } from '../utils/errors';
3
3
  import { upgradeHandler } from '../utils/upgradeHandler';
4
4
  import { DubheConfig, loadConfig } from '@0xobelisk/sui-common';
5
+ import { handlerExit } from './shell';
6
+ import { getDefaultNetwork } from '../utils';
7
+ import chalk from 'chalk';
5
8
 
6
9
  type Options = {
7
10
  network: any;
@@ -17,8 +20,8 @@ const commandModule: CommandModule<Options, Options> = {
17
20
  return yargs.options({
18
21
  network: {
19
22
  type: 'string',
20
- choices: ['mainnet', 'testnet', 'devnet', 'localnet'],
21
- default: 'localnet',
23
+ choices: ['mainnet', 'testnet', 'devnet', 'localnet', 'default'],
24
+ default: 'default',
22
25
  desc: 'Network of the node (mainnet/testnet/devnet/localnet)'
23
26
  },
24
27
  'config-path': {
@@ -31,13 +34,17 @@ const commandModule: CommandModule<Options, Options> = {
31
34
 
32
35
  async handler({ network, 'config-path': configPath }) {
33
36
  try {
37
+ if (network == 'default') {
38
+ network = await getDefaultNetwork();
39
+ console.log(chalk.yellow(`Use default network: [${network}]`));
40
+ }
34
41
  const dubheConfig = (await loadConfig(configPath)) as DubheConfig;
35
42
  await upgradeHandler(dubheConfig, dubheConfig.name, network);
36
43
  } catch (error: any) {
37
44
  logError(error);
38
- process.exit(1);
45
+ handlerExit(1);
39
46
  }
40
- process.exit(0);
47
+ handlerExit();
41
48
  }
42
49
  };
43
50