`ao-cli` (alias `ao`) is a command-line interface (CLI) that helps you install, use, and configure the Autonomous Organization (AO). `ao-cli` is a Node/JavaScript CLI tool that wraps the functionality of Alchemy, AO administration, plus key AO features into one convenient interface. Command-line social networking.
`ao-cli` (alias `ao`) is a command-line interface (CLI) that helps you install, use, and configure the Autonomous Organization (AO). Command-line social networking for hackers.
To run immediately:
To run immediately:
@ -10,10 +10,46 @@ To install:
`npm i -g @autonomousorganization/ao-cli`
`npm i -g @autonomousorganization/ao-cli`
Then you can run with `ao-cli`. (Inside the menu you will find an option to add 'ao' as a shortcut.)
Then you can run with `ao-cli`. (In the menus you will find an option to add `ao` as an alias.)
### Version History
## Features
These features work right now:
* Browse the [AO User Manual](https://git.coalitionofinvisiblecolleges.org/autonomousorganization/ao-manual) and automatically download and keep it updated
* Manages your AO configuration file for you
* Wraps the functionality of (some of) Zen's Alchemy suite of scripts (system configuration, AO installation)
* `ao-cli` can self-update to the newest version
* Run AO unit tests to verify the up-to-spec functioning of the system's running AO API server
## Upcoming Features
These features are planned and many are mocked up in the menus:
* Join the AO .onion bootstrapping network and find public AO chatrooms p2p over tor
* Operate essential AO client features (like creating and sending cards p2p via tor)
* Easily install and configure your AO server installation
* Easily use hardware-owner-only god-mode features for your AO server including resetting any password or deleting any member
* Easily monitor your AO server status and start/stop the service
* Easily switch between serving different AO frontends: `ao-svelte`, `ao-3` (Vue), or `ao-react`
* Easily install/uninstall and turn on/off option AO features
* Easily update all your remote AOs at once
* Easily install your preferred flavor of Unix on any unsecured Windows computer given its IP address (j/k)
* Full interactive wizard to walk you through setting up and connecting new AO hardware resources to your AO server
## Important Locations
* `~/.ao/` Your AO saved data folder
* `~/.ao/database.sqlite3` Location of your AO database (copy to back up)
* `~/ao-cli/` Typical location for `ao-cli`
* `~/ao-svelte/` Typical location for `ao-svelte`
* `~/ao-3/` Typical location for `ao-3`
* `~/.ao/ao-manual/` Typical location of the AO manual (Markdown files)
* `~/Alchemy/` Typical location of Zen's Alchemy
## Version History
* 0.0.8 Added self-update feature and --version/-v arg
* 0.0.6 User manual downloads and updates automatically from [official ao-manual repo](https://git.coalitionofinvisiblecolleges.org/autonomousorganization/ao-manual)
* 0.0.6 User manual downloads and updates automatically from [official ao-manual repo](https://git.coalitionofinvisiblecolleges.org/autonomousorganization/ao-manual)
// These should become .env variables that are loaded intelligently
// These should become .env variables that are loaded intelligently
letdistro
letdistro
@ -32,15 +35,13 @@ function exitIfRoot() {
// Prints the AO Main Menu and executes the user's choice
// Prints the AO Main Menu and executes the user's choice
asyncfunctionmainMenu(){
asyncfunctionmainMenu(){
console.log(`\n${headerStyle('AO Main Menu')}\n`)
console.log(`\n${headerStyle('AO Main Menu')}\n`)
constmainMenuChoices=[
letmainMenuChoices=[
'Chat',
'AO',
'Alchemy',
'Features',
'Deck',
'Admin',
'Admin',
'Tests',
'Alchemy',
'Manual',
'Manual',
'Log Out',
'Exit'
'Exit',
]
]
constanswer=awaitinquirer.prompt({
constanswer=awaitinquirer.prompt({
name:'main_menu',
name:'main_menu',
@ -50,20 +51,17 @@ async function mainMenu() {
pageSize:mainMenuChoices.length
pageSize:mainMenuChoices.length
})
})
switch(answer.main_menu){
switch(answer.main_menu){
case'Chat':
case'AO':
while(awaitchatMenu()){}
while(awaituseAoMenu()){}
break
break
case'Alchemy':
case'Features':
while(awaitalchemyMenu()){}
while(awaitfeaturesMenu()){}
break
case'Deck':
awaittodoList('My Todo List',['Add full AO install process to ao-cli in convenient format','Add AO server unit tests to ao-cli','Get groceries','Play music every day'])
break
break
case'Admin':
case'Admin':
while(awaitadminMenu()){}
while(awaitadminMenu()){}
break
break
case'Tests':
case'Alchemy':
while(awaittestsMenu()){}
while(awaitalchemyMenu()){}
break
break
case'Manual':
case'Manual':
if(!isFolder(AO_MANUAL_PATH)){
if(!isFolder(AO_MANUAL_PATH)){
@ -78,14 +76,11 @@ async function mainMenu() {
updateManual()
updateManual()
}
}
awaitprintManualPage(AO_MANUAL_PATH)// Fencepost case - print overview page
awaitprintManualPage(AO_MANUAL_PATH)// Fencepost case - print overview page
letpreviousChoice=0
letpreviousChoice
do{
do{
previousChoice=awaitmanualFolderAsMenu(AO_MANUAL_PATH,'AO User Manual','Back to Main Menu',previousChoice+1)
previousChoice=awaitmanualFolderAsMenu(AO_MANUAL_PATH,'AO User Manual','Back to Main Menu',previousChoice+1)
}while(previousChoice!==false)
}while(previousChoice!==false)
break
break
case'Log Out':
awaitspinnerWait('Logging out... (just kidding)')
break
case'Exit':
case'Exit':
farewell()
farewell()
awaitsleep(310)
awaitsleep(310)
@ -94,6 +89,50 @@ async function mainMenu() {
returntrue
returntrue
}
}
// Prints the Use AO Menu and executes the user's choice
awaittodoList('My Todo List',['Add full AO install process to ao-cli in convenient format','Add AO server unit tests to ao-cli','Get groceries','Play music every day'])
break
case'Log In':
console.log('\nao-cli will use the AO API to log into the AO server at',(aoEnv('AO_CLI_TARGET_HOSTNAME')||AO_DEFAULT_HOSTNAME)+'.')
awaitloginPrompt()
break
case'Log Out':
awaitlogout()
//await spinnerWait('Logging out...')
break
case'Back to Main Menu':
returnfalse
}
returntrue
}
// Prints a menu that allows you to join the global AO chatrooms
// Prints a menu that allows you to join the global AO chatrooms
letpublicBootstrapStarted=false
letpublicBootstrapStarted=false
asyncfunctionchatMenu(){
asyncfunctionchatMenu(){
@ -159,6 +198,7 @@ async function chatMenu() {
}
}
// Prints the AO Admin Menu and executes the user's choice
// Prints the AO Admin Menu and executes the user's choice
// Maybe Alchemy menu should be installation and update, and admin menu should be more configuration & AO member admin
asyncfunctionadminMenu(){
asyncfunctionadminMenu(){
console.log(`\n${headerStyle('AO Admin Menu')}`)
console.log(`\n${headerStyle('AO Admin Menu')}`)
constadminChoices=[
constadminChoices=[
@ -166,12 +206,13 @@ async function adminMenu() {
'Update ao-cli',
'Update ao-cli',
'Check AO install',
'Check AO install',
'Update AO',
'Update AO',
'Configure AO features',
'Switch AO target server',
'Switch AO database',
'Switch AO database',
'Import/Export state/decks',
'Import/Export state/decks',
'Check AO service',
'Check AO service',
'Watch logs now',
'Watch logs now',
'Start/Stop AO service',
'Start/Stop AO service',
'Tests',
'Back to Main Menu'
'Back to Main Menu'
]
]
constanswer=awaitinquirer.prompt({
constanswer=awaitinquirer.prompt({
@ -190,9 +231,7 @@ async function adminMenu() {
break
break
case'Check AO install':
case'Check AO install':
case'Update AO':
case'Update AO':
case'Configure AO features':
case'Switch AO target server':
while(awaitfeaturesMenu()){}
break
case'Switch AO database':
case'Switch AO database':
case'Import/Export state/decks':
case'Import/Export state/decks':
case'Check AO service':
case'Check AO service':
@ -200,6 +239,9 @@ async function adminMenu() {
case'Start/Stop AO service':
case'Start/Stop AO service':
console.log("Not yet implemented.")
console.log("Not yet implemented.")
break
break
case'Tests':
while(awaittestsMenu()){}
break
default:
default:
returnfalse
returnfalse
}
}
@ -262,21 +304,29 @@ async function alchemyMenu() {
// Prints the Configure AO Features menu and executes the user's choice
// Prints the Configure AO Features menu and executes the user's choice
asyncfunctionfeaturesMenu(){
asyncfunctionfeaturesMenu(){
console.log(`\n${headerStyle('Configure AO Features')}`)
console.log(`\n${headerStyle('Configure AO Features')}`)
conststatus={
off:' '+chalk.grey('Off')+' ',
ins:chalk.yellow('Installed')+' ',
ena:' '+greenChalk('Enabled')+' ',
run:' '+greenChalk('Running')+' ',
err:' '+chalk.red('Error')+' '
}
letwidest=9
constfeatures=[
constfeatures=[
'nginx host AO publicly over the world wide web',
`Tor ${status.run} connect AOs p2p`,
'SSL/Certbot HTTPS for public web AO',
`Bitcoin ${status.run} payments`,
'Tor connect AOs p2p',
`Lightning ${status.ins} payments`,
'Bitcoin payments',
`nginx ${status.ins} host AO publicly over the world wide web`,
'Lightning payments',
`SSL/Certbot ${status.ins} HTTPS for public web AO`,
'Jitsi secure video chat',
`Jitsi ${status.err} secure video chat`,
'Signal notifications',
`Signal ${status.off} notifications`,
'File hosting file attachments on cards',
`File hosting ${status.err} file attachments on cards`,
console.log('\nao-cli self-updated automatically from version',beforeVersionNumber,'to version',afterVersionNumber,'from the official npm repository.')
console.log('\nao-cli self-updated automatically from version',beforeVersionNumber,'to version',afterVersionNumber,'from the official npm repository.')
// Different sets of messages that can be randomly selected from
// Different sets of messages that can be randomly selected from
constwelcomeMessages=[
constwelcomeMessages=[
@ -22,7 +23,9 @@ const welcomeMessages = [
`You are offered a choice between two pills. However, you have secretly built up an immunity to both pills, and trick your opponent into taking one. Inconceviably, you are in ${theAO}.`,
`You are offered a choice between two pills. However, you have secretly built up an immunity to both pills, and trick your opponent into taking one. Inconceviably, you are in ${theAO}.`,
`A young man with spiky hair and golden skin appears before you in a halo of light. He guides you to ${theAO}.`,
`A young man with spiky hair and golden skin appears before you in a halo of light. He guides you to ${theAO}.`,
`You enter a gap between two hedges and, after struggling through the brush, emerge into a sunny estate garden. You've found the AO.`,
`You enter a gap between two hedges and, after struggling through the brush, emerge into a sunny estate garden. You've found the AO.`,
`You find a small animal burrow dug near the riverside. Crawling in, you find a network of caves that lead to the AO.`
`You find a small animal burrow dug-out near the riverside. Crawling in, you find a network of caves that lead to ${theAO}.`,
`You receive a handwritten letter in the mail, which reads, in fine calligraphy:, "Dear —, You are in ${theAO}."`,
`An unexpected calm settles over you. The ${greenChalk.bold('AO')} is here: Here is ${theAO}.`