vana-cli 1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Vana
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,96 @@
1
+ # Vana CLI
2
+
3
+ > **⚠️ ALPHA SOFTWARE - EXPERIMENTAL USE ONLY**
4
+ >
5
+ > This CLI is in early alpha development and is **NOT SUITABLE FOR PRODUCTION USE**.
6
+ > Features may change without notice, and data loss or unexpected behavior may occur.
7
+ > Use at your own risk and avoid using with mainnet assets or critical operations.
8
+
9
+ A command-line interface for interacting with the Vana L1 network and related services.
10
+
11
+ ## Installation
12
+
13
+ Install globally via npm:
14
+
15
+ ```bash
16
+ npm install -g vana-cli
17
+ ```
18
+
19
+ Or use directly with npx:
20
+
21
+ ```bash
22
+ npx vana-cli --help
23
+ ```
24
+
25
+ ## Quick Start
26
+
27
+ > **Note**: This is alpha software. Only use with testnet/development environments.
28
+
29
+ 1. **Initialize configuration**:
30
+ ```bash
31
+ vana config init
32
+ ```
33
+
34
+ 2. **Set your wallet private key**:
35
+ ```bash
36
+ vana config set wallet_private_key 63...
37
+ ```
38
+
39
+ 3. **Get refiner statistics**:
40
+ ```bash
41
+ vana stats refiner --id 45
42
+ ```
43
+
44
+ ## Commands
45
+
46
+ ### Configuration Management
47
+
48
+ - `vana config init` - Initialize configuration with defaults
49
+ - `vana config get [key]` - Get configuration values
50
+ - `vana config set <key> <value>` - Set configuration values
51
+
52
+ ### Statistics
53
+
54
+ - `vana stats refiner --id <id>` - Get ingestion statistics for a specific refiner
55
+
56
+ ## Configuration
57
+
58
+ The CLI stores configuration in:
59
+ - **Unprotected values**: `~/.vana/cli.config.toml`
60
+ - **Protected values** (like private keys): OS keyring
61
+
62
+ ### Available Configuration Keys
63
+
64
+ - `network` - Network to connect to (vana|moksha)
65
+ - `rpc_endpoint` - RPC endpoint URL
66
+ - `wallet_private_key` - Your wallet private key (stored securely in keyring)
67
+
68
+ ## Examples
69
+
70
+ ```bash
71
+ # Initialize with defaults
72
+ vana config init
73
+
74
+ # Set network
75
+ vana config set network moksha
76
+
77
+ # Set custom RPC endpoint
78
+ vana config set rpc_endpoint https://rpc.moksha.vana.org
79
+
80
+ # Get refiner stats with verbose output
81
+ vana stats refiner --id 45 --verbose
82
+
83
+ # Get stats in JSON format
84
+ vana stats refiner --id 45 --json
85
+
86
+ # Use custom endpoint for one-off query
87
+ vana stats refiner --id 45 --endpoint https://custom.api.com
88
+ ```
89
+
90
+ ## Development
91
+
92
+ See [DEVELOPMENT.md](DEVELOPMENT.md) for development setup and contribution guidelines.
93
+
94
+ ## License
95
+
96
+ MIT
package/dist/cli.d.ts ADDED
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node
package/dist/cli.js ADDED
@@ -0,0 +1,115 @@
1
+ #!/usr/bin/env node
2
+ import{Cli as fe,Builtins as re}from"clipanion";import{Command as G,Option as k}from"clipanion";import{ethers as ne}from"ethers";var I=class{constructor(e){this.baseUrl=e;this.baseUrl=e}async getRefinerIngestionStats(e,t){try{let r=t.startsWith("0x")?t:`0x${t}`,i=new ne.Wallet(r),o=e.toString(),s=await i.signMessage(o),c=`${this.baseUrl}/stats/refiner/${e}`,u=await fetch(c,{method:"GET",headers:{"X-Refiner-Signature":s,"Content-Type":"application/json"}});if(!u.ok){let E=await u.text(),S=`HTTP ${u.status}: ${u.statusText}`;try{let N=JSON.parse(E);S=N.detail||N.message||S}catch{S=E||S}throw new Error(S)}return await u.json()}catch(r){throw r instanceof Error?r:new Error(`Failed to get refiner ingestion stats: ${String(r)}`)}}};import{promises as _}from"fs";import{join as H,dirname as ie}from"path";import{homedir as oe}from"os";import L from"keytar";var R={network:"moksha",rpc_endpoint:"https://rpc.moksha.vana.org"},q="vana",j=H(oe(),".vana"),x=H(j,"cli.config.toml"),d=class n{static instance;unprotectedConfig=null;constructor(){}static getInstance(){return n.instance||(n.instance=new n),n.instance}async initialize(){try{await _.mkdir(j,{recursive:!0});try{await _.access(x)}catch{await this.writeUnprotectedConfig(R)}}catch(e){throw new Error(`Failed to initialize config: ${e instanceof Error?e.message:String(e)}`)}}async getConfig(){let e=await this.getUnprotectedConfig(),t=await this.getProtectedConfig();return{...e,...t}}async getUnprotectedConfig(){if(this.unprotectedConfig)return this.unprotectedConfig;try{let e=await _.readFile(x,"utf-8");return this.unprotectedConfig=this.parseToml(e),this.unprotectedConfig}catch{return this.unprotectedConfig={...R},this.unprotectedConfig}}async getProtectedConfig(){try{return{wallet_private_key:await L.getPassword(q,"wallet_private_key")||void 0}}catch{return{}}}async setConfig(e,t){this.isProtectedKey(e)?await this.setProtectedConfig(e,t):await this.setUnprotectedConfig(e,t)}async getConfigValue(e){return(await this.getConfig())[e]}async setUnprotectedConfig(e,t){let r=await this.getUnprotectedConfig();if(e==="network"&&!["vana","moksha"].includes(t))throw new Error(`Invalid network value: ${t}. Must be 'vana' or 'moksha'`);r[e]=t,await this.writeUnprotectedConfig(r),this.unprotectedConfig=r}async setProtectedConfig(e,t){try{await L.setPassword(q,e,t)}catch(r){throw new Error(`Failed to store ${e} in keyring: ${r instanceof Error?r.message:String(r)}`)}}async writeUnprotectedConfig(e){let t=this.generateToml(e);try{await _.mkdir(ie(x),{recursive:!0}),await _.writeFile(x,t,"utf-8")}catch(r){throw new Error(`Failed to write config file: ${r instanceof Error?r.message:String(r)}`)}}isProtectedKey(e){return e==="wallet_private_key"}parseToml(e){let t={},r=e.split(`
3
+ `);for(let i of r){let o=i.trim();if(o&&!o.startsWith("#")){let[s,...c]=o.split("=");if(s&&c.length>0){let u=s.trim(),E=c.join("=").trim().replace(/['"]/g,"");(u==="network"||u==="rpc_endpoint")&&(t[u]=E)}}}return{...R,...t}}generateToml(e){return`# Vana CLI Configuration
4
+ # This file stores unprotected configuration values
5
+ # Secrets like private keys are stored securely in the OS keyring
6
+
7
+ network = "${e.network}"
8
+ rpc_endpoint = "${e.rpc_endpoint}"
9
+ `}getConfigKeys(){return{unprotected:["network","rpc_endpoint"],protected:["wallet_private_key"]}}async reset(){await this.writeUnprotectedConfig(R),this.unprotectedConfig=null;try{await L.deletePassword(q,"wallet_private_key")}catch{}}getConfigPath(){return x}};import l from"chalk";function w(n,e){return n==="wallet_private_key"&&e?e.length>10?e.substring(0,6)+"..."+e.substring(e.length-4):e.substring(0,4)+"..."+e.substring(e.length-2):e}function b(n){return["wallet_private_key","private_key","secret","password","token"].some(t=>n.toLowerCase().includes(t))}function a(n,e,t={}){let{maskSensitive:r=!1,indent:i=2}=t,o=" ".repeat(i);if(e===void 0)return`${o}${l.cyan(n)}: ${l.gray("(not set)")}`;let s=r&&b(n)?w(n,e):e;return`${o}${l.cyan(n)}: ${s}`}function P(n,e){let t=l.blue.bold(`
10
+ ${n}:`);return e&&(t+=l.gray(` (${e})`)),t}function f(n){return l.bold(n)+`
11
+ `+"\u2500".repeat(Math.min(n.length,50))}function K(n){return l.green(`\u2713 ${n}`)}function A(n){return l.red(`\u2717 ${n}`)}function B(n){return l.yellow(`\u26A0 ${n}`)}function J(n){return l.blue(`\u2139 ${n}`)}function D(n){return l.gray(n)}function se(n){return l.gray(` $ ${n}`)}var g={configSection(n,e,t,r={}){let{maskSensitive:i=!1,showEmpty:o=!0}=r,s=P(n,e)+`
12
+ `;for(let[c,u]of Object.entries(t))(u!==void 0||o)&&(s+=a(c,u,{maskSensitive:i})+`
13
+ `);return s},examples(n,e){let t=P(n)+`
14
+ `;for(let r of e)t+=se(r)+`
15
+ `;return t},nextSteps(n){let e=P("Next steps")+`
16
+ `;for(let t of n)e+=D(` \u2022 ${t}`)+`
17
+ `;return e},troubleshooting(n,e){let t=P(n)+`
18
+ `;for(let r of e)t+=D(` \u2022 ${r}`)+`
19
+ `;return t}};var F=class{constructor(e){this.context=e}success(e){this.context.stdout.write(K(e)+`
20
+ `)}error(e){this.context.stderr.write(A(e)+`
21
+ `)}warning(e){this.context.stderr.write(B(e)+`
22
+ `)}info(e){this.context.stdout.write(J(e)+`
23
+ `)}log(e){this.context.stdout.write(e+`
24
+ `)}write(e){this.context.stdout.write(e)}},p={configNotFound:n=>`Configuration key '${n}' not found`,invalidValue:(n,e,t)=>`Invalid value '${e}' for '${n}'${t?`. Expected: ${t}`:""}`,missingRequired:n=>`Missing required field: ${n}`,keyringAccess:n=>`Failed to ${n} keyring. Ensure your system keyring is accessible`,fileAccess:(n,e)=>`Failed to ${e} file: ${n}`,networkError:n=>`Network error connecting to: ${n}`,authenticationFailed:n=>`Authentication failed${n?`: ${n}`:""}`,permissionDenied:n=>`Permission denied accessing: ${n}`,unexpectedError:n=>`Unexpected error: ${n instanceof Error?n.message:String(n)}`},v={configSet:(n,e)=>`Set ${n} in ${e}`,configInitialized:()=>"Configuration initialized",configReset:()=>"Configuration reset to defaults",operationComplete:n=>`${n} completed successfully`},z={secretsCleared:()=>"Protected values (like private keys) have been cleared",keyringUnavailable:()=>"OS keyring unavailable, secrets cannot be stored securely",deprecatedOption:(n,e)=>`Option '${n}' is deprecated, use '${e}' instead`,experimentalFeature:n=>`${n} is experimental and may change in future versions`},y={configLocation:n=>`Config file: ${n}`,useSecretsFlag:()=>"Use --secrets to view protected values",interactiveMode:()=>"Interactive mode requires a prompt library like inquirer",nextSteps:{setPrivateKey:()=>"Set your wallet private key: vana config set wallet_private_key 63...",viewConfig:()=>"View all settings: vana config get",viewSecrets:()=>"View with secrets: vana config get --secrets"}};function m(n){return new F({stdout:n.stdout,stderr:n.stderr})}import ae from"ora";var Q=["Verify the refiner ID exists","Check your private key is correct","Ensure the API URL is accessible","Verify you have permission to view this refiner's stats"],$=class extends G{static paths=[["stats","refiner"]];static usage=G.Usage({category:"Stats",description:"Get ingestion statistics for a specific refiner",details:`
25
+ Retrieves comprehensive ingestion statistics for a refiner including:
26
+ \u2022 File contributions and data rows
27
+ \u2022 Query execution metrics
28
+ \u2022 Error breakdowns by type
29
+ \u2022 Table-specific row counts
30
+ \u2022 Contributor and timing information
31
+
32
+ Requires cryptographic authentication using your wallet private key.
33
+ `,examples:[["Get stats for refiner ID 45","vana stats refiner --id 45 --endpoint https://query-engine.api.com"],["Get stats with private key override","vana stats refiner --id 45 --private-key 63... --endpoint https://query-engine.api.com"],["Get stats in JSON format","vana stats refiner --id 45 --endpoint https://query-engine.api.com --json"],["Get verbose stats with raw response","vana stats refiner --id 45 --endpoint https://query-engine.api.com --verbose --include-raw"]]});refinerId=k.String("--id,-i",{description:"Refiner ID to get statistics for",required:!0});privateKey=k.String("--private-key,-pk",{description:"Private key for authentication (overrides config)"});endpoint=k.String("--endpoint,-e",{description:"Query Engine API URL (required - stats come from Query Engine, not RPC)"});json=k.Boolean("--json,-j",!1,{description:"Output in JSON format"});verbose=k.Boolean("--verbose,-v",!1,{description:"Show verbose output with additional details"});includeRaw=k.Boolean("--include-raw",!1,{description:"Include raw API response in output"});async execute(){let e=m(this.context);try{let t=this.validateRefinerId(e);if(t===null)return 1;let{privateKey:r,apiUrl:i}=await this.getConfiguration(e);if(!r||!i)return 1;this.verbose&&this.displayVerboseInfo(e,t,i,r);let o=await this.fetchRefinerStats(e,t,i,r);return o?(this.displayResults(e,o),e.success(v.operationComplete("Refiner stats retrieved")),this.verbose&&e.warning("\u26A0\uFE0F Alpha software: Verify all data independently before making decisions"),0):(e.write(g.troubleshooting("Troubleshooting",Q)),1)}catch(t){return e.error(p.unexpectedError(t)),e.write(g.troubleshooting("Troubleshooting",Q)),1}}validateRefinerId(e){let t=parseInt(this.refinerId);return isNaN(t)||t<0?(e.error("Invalid refiner ID. Must be a non-negative number."),null):t}async getConfiguration(e){let t=d.getInstance();await t.initialize();let r=this.privateKey;if(!r)try{r=await t.getConfigValue("wallet_private_key")}catch{}if(!r)return e.error("No private key provided."),e.write(g.examples("Set private key with",["vana config set wallet_private_key 63...","or use --private-key option"])),{privateKey:null,apiUrl:null};let i=this.endpoint;return i?{privateKey:r,apiUrl:i}:(e.error("Query Engine API URL is required for refiner stats."),e.info("Refiner stats are retrieved from the Query Engine API, not on-chain RPC."),e.write(g.examples("Provide Query Engine API URL with",["vana stats refiner --id 45 --endpoint https://query-engine.api.com"])),{privateKey:null,apiUrl:null})}displayVerboseInfo(e,t,r,i){e.write(f("\u{1F50D} Refiner Ingestion Stats")+`
34
+ `),e.write(a("Refiner ID",t.toString())+`
35
+ `),e.write(a("API URL",r)+`
36
+ `),e.write(a("Private Key",w("wallet_private_key",i))+`
37
+ `),e.write(`
38
+ `)}async fetchRefinerStats(e,t,r,i){let o=new I(r),s=ae(`Fetching ingestion stats for refiner ${t}...`).start();try{let c=await o.getRefinerIngestionStats(t,i);return s.succeed(),c}catch(c){return s.fail(),e.error(`Failed to fetch refiner stats: ${c instanceof Error?c.message:String(c)}`),null}}displayResults(e,t){this.json?e.write(JSON.stringify(t,null,2)+`
39
+ `):this.displayFormattedStats(e,t),this.includeRaw&&!this.json&&(e.write(`
40
+ `+f("\u{1F4C4} Raw API Response")+`
41
+ `),e.write(JSON.stringify(t,null,2)+`
42
+ `))}displayFormattedStats(e,t){e.write(f(`\u{1F4CA} Refiner ${t.refiner_id} - Ingestion Statistics`)+`
43
+
44
+ `),this.displayDataIngestionStats(e,t),this.displayQueryExecutionStats(e,t),this.displayQueryErrorsBreakdown(e,t),this.displayRowsPerTable(e,t),this.verbose&&this.displayTechnicalDetails(e,t)}displayDataIngestionStats(e,t){e.write(f("\u{1F4C1} Data Ingestion")+`
45
+ `),e.write(a("File Contributions",t.total_file_contributions.toLocaleString())+`
46
+ `),e.write(a("Total Data Rows",t.total_data_rows.toLocaleString())+`
47
+ `),e.write(a("Unique Contributors",t.unique_contributors.toLocaleString())+`
48
+ `),t.first_ingestion_at&&e.write(a("First Ingestion",new Date(t.first_ingestion_at).toLocaleString())+`
49
+ `),t.last_ingestion_at&&e.write(a("Last Ingestion",new Date(t.last_ingestion_at).toLocaleString())+`
50
+ `),t.ingestion_period_days&&e.write(a("Ingestion Period",`${t.ingestion_period_days.toFixed(1)} days`)+`
51
+ `),e.write(a("Avg Rate/Hour",t.average_ingestion_rate_per_hour.toFixed(2))+`
52
+ `)}displayQueryExecutionStats(e,t){if(e.write(`
53
+ `+f("\u{1F50D} Query Execution")+`
54
+ `),e.write(a("Total Queries",t.total_queries_executed.toLocaleString())+`
55
+ `),e.write(a("Successful",t.successful_queries.toLocaleString())+`
56
+ `),e.write(a("Failed",t.failed_queries.toLocaleString())+`
57
+ `),t.total_queries_executed>0){let r=(t.successful_queries/t.total_queries_executed*100).toFixed(1);e.write(a("Success Rate",`${r}%`)+`
58
+ `)}}displayQueryErrorsBreakdown(e,t){Object.keys(t.query_errors_by_type).length!==0&&(e.write(`
59
+ `+f("\u274C Query Errors by Type")+`
60
+ `),Object.entries(t.query_errors_by_type).sort(([,r],[,i])=>i-r).forEach(([r,i])=>{e.write(a(r,i.toLocaleString())+`
61
+ `)}))}displayRowsPerTable(e,t){Object.keys(t.rows_per_table).length!==0&&(e.write(`
62
+ `+f("\u{1F4CB} Rows per Table")+`
63
+ `),Object.entries(t.rows_per_table).sort(([,r],[,i])=>i-r).forEach(([r,i])=>{e.write(a(r,i.toLocaleString())+`
64
+ `)}))}displayTechnicalDetails(e,t){e.write(`
65
+ `+f("\u{1F527} Technical Details")+`
66
+ `),t.last_processed_block&&e.write(a("Last Processed Block",t.last_processed_block.toLocaleString())+`
67
+ `)}};import{Command as W,Option as V}from"clipanion";var M=class extends W{static paths=[["config","get"]];static usage=W.Usage({category:"Configuration",description:"Get configuration values",details:`
68
+ Get configuration values from the Vana CLI config.
69
+
70
+ By default, only unprotected values are shown.
71
+ Use --secrets to include protected values from the keyring.
72
+
73
+ Examples:
74
+ $ vana config get # Show all unprotected config
75
+ $ vana config get network # Show specific key
76
+ $ vana config get --secrets # Show all config including secrets
77
+ $ vana config get --json # Output as JSON
78
+ `});key=V.String({required:!1});secrets=V.Boolean("--secrets",!1,{description:"Include protected values from keyring"});json=V.Boolean("--json",!1,{description:"Output as JSON"});async execute(){let e=m(this.context);try{let t=d.getInstance();if(await t.initialize(),this.key){let r=await t.getConfigValue(this.key);if(r===void 0)return e.error(p.configNotFound(this.key)),1;if(this.json){let i=!this.secrets&&b(this.key)?w(this.key,r):r;e.write(JSON.stringify({[this.key]:i},null,2)+`
79
+ `)}else{let i=!this.secrets&&b(this.key)?w(this.key,r):r;e.log(`${this.key}: ${i}`)}}else{let r;if(this.secrets?r=await t.getConfig():r=await t.getUnprotectedConfig(),this.json){let i={...r};if(!this.secrets)for(let[o,s]of Object.entries(i))typeof s=="string"&&b(o)&&(i[o]=w(o,s));e.write(JSON.stringify(i,null,2)+`
80
+ `)}else this.displayConfig(r,e,t)}return 0}catch(t){return e.error(p.unexpectedError(t)),1}}displayConfig(e,t,r){t.write(f("Vana CLI Configuration")+`
81
+ `);let i=r.getConfigKeys(),o={};for(let s of i.unprotected)o[s]=e[s];if(t.write(g.configSection("Unprotected","stored in ~/.vana/cli.config.toml",o,{maskSensitive:!1,showEmpty:!1})),this.secrets){let s={};for(let c of i.protected)s[c]=e[c];t.write(g.configSection("Protected","stored in OS keyring",s,{maskSensitive:!0,showEmpty:!0}))}else t.info(y.useSecretsFlag());t.info(y.configLocation(r.getConfigPath()))}};import{Command as X,Option as U}from"clipanion";import ce from"ora";var O=class extends X{static paths=[["config","set"]];static usage=X.Usage({category:"Configuration",description:"Set configuration values",details:`
82
+ Set configuration values for the Vana CLI.
83
+
84
+ Unprotected values are stored in ~/.vana/cli.config.toml
85
+ Protected values (like private keys) are stored securely in the OS keyring.
86
+
87
+ Available keys:
88
+ - network (vana|moksha)
89
+ - rpc_endpoint (string)
90
+ - wallet_private_key (string, stored in keyring)
91
+
92
+ Examples:
93
+ $ vana config set network moksha
94
+ $ vana config set rpc_endpoint https://rpc.moksha.vana.org
95
+ $ vana config set wallet_private_key 0x1234...
96
+ $ vana config set --interactive
97
+ `});key=U.String({required:!1});value=U.String({required:!1});interactive=U.Boolean("--interactive",!1,{description:"Interactive configuration setup"});quiet=U.Boolean("--quiet",!1,{description:"Suppress output messages"});async execute(){let e=m(this.context);try{let t=d.getInstance();if(await t.initialize(),this.interactive)return await this.runInteractiveSetup(t,e);if(!this.key||!this.value)return e.error(p.missingRequired("key and value")),e.info("Usage: vana config set <key> <value>"),e.info("Or use: vana config set --interactive"),1;let r=ce("Setting configuration...").start();try{if(await t.setConfig(this.key,this.value),r.succeed(),!this.quiet){let o=this.isProtectedKey(this.key)?"OS keyring":"~/.vana/cli.config.toml";e.success(v.configSet(this.key,o))}return 0}catch(i){throw r.fail(),i}}catch(t){return e.error(p.unexpectedError(t)),1}}async runInteractiveSetup(e,t){t.write(f("\u{1F527} Vana CLI Interactive Configuration")+`
98
+
99
+ `);try{let r=await e.getConfig(),i={network:r.network,rpc_endpoint:r.rpc_endpoint},o={wallet_private_key:r.wallet_private_key};return t.write(g.configSection("Current Configuration","unprotected values",i,{maskSensitive:!1,showEmpty:!0})),t.write(g.configSection("Protected Configuration","stored in keyring",o,{maskSensitive:!0,showEmpty:!0})),t.warning(y.interactiveMode()),t.info("Use: vana config set <key> <value> to set individual values"),t.write(g.examples("Example commands",["vana config set network moksha","vana config set rpc_endpoint https://rpc.moksha.vana.org","vana config set wallet_private_key 63..."])),0}catch(r){return t.error(p.unexpectedError(r)),1}}isProtectedKey(e){return e==="wallet_private_key"}};import{Command as Y,Option as Z}from"clipanion";import ee from"ora";var T=class extends Y{static paths=[["config","init"]];static usage=Y.Usage({category:"Configuration",description:"Initialize configuration with defaults",details:`
100
+ Initialize the Vana CLI configuration with default values.
101
+
102
+ Default configuration:
103
+ - network: moksha
104
+ - rpc_endpoint: https://rpc.moksha.vana.org
105
+
106
+ This creates ~/.vana/cli.config.toml with the default settings.
107
+ Protected values (like private keys) are not set by init.
108
+
109
+ Examples:
110
+ $ vana config init # Initialize with defaults
111
+ $ vana config init --reset # Reset existing config to defaults
112
+ `});reset=Z.Boolean("--reset",!1,{description:"Reset existing configuration to defaults"});quiet=Z.Boolean("--quiet",!1,{description:"Suppress output messages"});async execute(){let e=m(this.context);try{let t=d.getInstance();if(this.reset){let r=ee("Resetting configuration to defaults...").start();try{await t.reset(),r.succeed(),this.quiet||(e.success(v.configReset()),e.warning(z.secretsCleared()))}catch(i){throw r.fail(),i}}else{let r=ee("Initializing configuration...").start();try{await t.initialize(),r.succeed(),this.quiet||(e.success(v.configInitialized()),e.warning("\u26A0\uFE0F This is alpha software - only use for testing/development"))}catch(i){throw r.fail(),i}}if(!this.quiet){let r=await t.getUnprotectedConfig();e.write(`
113
+ `+f("Current Configuration")+`
114
+ `);let i={network:r.network,rpc_endpoint:r.rpc_endpoint};e.write(g.configSection("Configuration","unprotected values",i,{maskSensitive:!1,showEmpty:!0})),e.info(y.configLocation(t.getConfigPath())),e.write(g.nextSteps([y.nextSteps.setPrivateKey(),y.nextSteps.viewConfig(),y.nextSteps.viewSecrets()]))}return 0}catch(t){return e.error(p.unexpectedError(t)),1}}};import te from"chalk";import{readFileSync as ge}from"fs";import{fileURLToPath as ue}from"url";import{dirname as le,join as pe}from"path";var de=ue(import.meta.url),ye=le(de),me=JSON.parse(ge(pe(ye,"../package.json"),"utf-8")),[ct,ft,...C]=process.argv;C.length>0&&!C.includes("--help")&&!C.includes("-h")&&!C.includes("--version")&&!C.includes("-v")&&(console.error(te.yellow("\u26A0\uFE0F ALPHA SOFTWARE - Use only for testing/development")),console.error(te.gray(` Not suitable for production use. Features may change without notice.
115
+ `)));var h=new fe({binaryLabel:"Vana CLI (Alpha)",binaryName:"vana",binaryVersion:me.version});h.register(re.HelpCommand);h.register(re.VersionCommand);h.register(M);h.register(O);h.register(T);h.register($);await h.runExit(C,{stdin:process.stdin,stdout:process.stdout});
package/package.json ADDED
@@ -0,0 +1,74 @@
1
+ {
2
+ "name": "vana-cli",
3
+ "version": "1.0.0",
4
+ "description": "[ALPHA] Vana CLI for interacting with the Vana L1 network and related services - experimental software",
5
+ "main": "dist/cli.js",
6
+ "bin": {
7
+ "vana": "./dist/cli.js"
8
+ },
9
+ "files": [
10
+ "dist",
11
+ "README.md",
12
+ "LICENSE"
13
+ ],
14
+ "scripts": {
15
+ "build": "tsup src/cli.ts --format esm --dts --minify",
16
+ "dev": "npm run build && npm link",
17
+ "unlink": "npm unlink -g",
18
+ "lint": "biome lint src",
19
+ "format": "biome format src --write",
20
+ "check": "biome check .",
21
+ "precommit": "biome lint --apply",
22
+ "test": "vitest run",
23
+ "test:watch": "vitest",
24
+ "prepublishOnly": "npm run build && npm test"
25
+ },
26
+ "repository": {
27
+ "type": "git",
28
+ "url": "git+https://github.com/vana-com/vana-cli.git"
29
+ },
30
+ "keywords": [
31
+ "vana",
32
+ "cli",
33
+ "blockchain",
34
+ "web3",
35
+ "datadao",
36
+ "data-sovereignty",
37
+ "alpha",
38
+ "experimental"
39
+ ],
40
+ "author": "Vana",
41
+ "license": "MIT",
42
+ "type": "module",
43
+ "bugs": {
44
+ "url": "https://github.com/vana-com/vana-cli/issues"
45
+ },
46
+ "homepage": "https://github.com/vana-com/vana-cli#readme",
47
+ "publishConfig": {
48
+ "access": "public"
49
+ },
50
+ "dependencies": {
51
+ "chalk": "^5.4.1",
52
+ "clipanion": "^4.0.0-rc.4",
53
+ "ethers": "^6.14.4",
54
+ "keytar": "^7.9.0",
55
+ "ora": "^8.2.0"
56
+ },
57
+ "devDependencies": {
58
+ "@biomejs/biome": "^2.0.0",
59
+ "@semantic-release/commit-analyzer": "^13.0.0",
60
+ "@semantic-release/github": "^11.0.0",
61
+ "@semantic-release/npm": "^12.0.1",
62
+ "@semantic-release/release-notes-generator": "^14.0.1",
63
+ "@types/node": "^24.0.3",
64
+ "@vitest/coverage-v8": "^3.2.4",
65
+ "conventional-changelog-conventionalcommits": "^8.0.0",
66
+ "semantic-release": "^24.0.0",
67
+ "tsup": "^8.5.0",
68
+ "typescript": "^5.8.3",
69
+ "vitest": "^3.2.4"
70
+ },
71
+ "engines": {
72
+ "node": ">=20"
73
+ }
74
+ }