diff --git a/README.md b/README.md index 30ee729..2370474 100644 --- a/README.md +++ b/README.md @@ -4,11 +4,15 @@ To run immediately: -`npx @autonomousorganization/ao-cli` +``` +npx @autonomousorganization/ao-cli +``` To install: -`npm i -g @autonomousorganization/ao-cli` +``` +npm i -g @autonomousorganization/ao-cli +``` Then you can run with `ao-cli`. @@ -17,8 +21,8 @@ Then you can run with `ao-cli`. 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 -* Interactive install wizard install the AO for you +* Manages your AO configuration (.env) file for you +* Interactive install wizard installs the AO 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 diff --git a/index.js b/index.js index 43132bb..62efd35 100644 --- a/index.js +++ b/index.js @@ -8,6 +8,7 @@ import { exitIfRoot, detectOS, updateSoftware } from './scripts/system.js' import { checkAoEnvFile, aoEnv, setAoEnv, AO_ENV_FILE_PATH } from './scripts/settings.js' import { unicornPortal, asciiArt, clearScreen } from './scripts/console.js' import { welcome, exclaim, farewell, yesOrNo } from './scripts/welcome.js' +import wander from './scripts/forest.js' import useAoMenu from './scripts/ao.js' import aoInstallWizard, { chooseAoVersion, checkAo } from './scripts/wizard.js' import testsMenu from './scripts/tests.js' @@ -158,6 +159,10 @@ async function handleArgs(args) { case '-v': console.log(await aoCli.version()) return false + case '--interstitial': + case '-cd': + console.log(wander(args[1])) + return false } return true } diff --git a/scripts/features/ao-cli.js b/scripts/features/ao-cli.js index b134185..1ccfe98 100644 --- a/scripts/features/ao-cli.js +++ b/scripts/features/ao-cli.js @@ -73,6 +73,36 @@ function installAoAlias() { } } + +// Returns true if the cd hook function has already been addded to .bashrc +function checkCdHook() { + try { + execSync('grep "function cd \{ builtin cd.*--interstitial.* ; \}$" ~/\.bashrc') + } catch(err) { + return 'off' + } + return 'installed' +} + +// Adds a line to .bashrc to make 'ao' an alias for 'ao-cli', to simplify using the AO from the command line +function installCdHook() { + try { + execSync('echo \'function cd { builtin cd "\$@" && node \~/ao-cli \-\-interstitial "\$\@" ; }\' >> $HOME/.bashrc') + console.log('Added alias line to ~/.bashrc. Try typing \'cd\' in a terminal.') + } catch(err) { + console.log('Failed to add alias, sorry.') + } +} + +function removeCdHook() { + try { + let result = execSync('sed -i \'/^function cd.*/d\' ' + process.env.HOME + '/.bashrc') + console.log('sed:', result.toString()) + } catch(error) { + console.log(error.output.toString()) + } +} + export default { description: 'this AO command-line interface', status: cliStatus, @@ -81,8 +111,12 @@ export default { update: selfUpdate, add_alias: installAoAlias, remove_alias: () => console.log("Not implemented yet."), + add_cd: installCdHook, + remove_cd: removeCdHook, menu: [ { name: () => checkAoAlias() === 'installed' ? 'Remove \'ao\' shortcut for \'ao-cli\'' : 'Install \'ao\' shortcut for \'ao-cli\'', - value: () => checkAoAlias() === 'installed' ? 'remove_alias' : 'add_alias' } + value: () => checkAoAlias() === 'installed' ? 'remove_alias' : 'add_alias' }, + { name: () => checkCdHook() === 'installed' ? 'Remove \'cd\' fantasy hook' : 'Install \'cd\' fantasy hook', + value: () => checkCdHook() === 'installed' ? 'remove_cd' : 'add_cd' }, ] } diff --git a/scripts/forest.js b/scripts/forest.js new file mode 100644 index 0000000..886e793 --- /dev/null +++ b/scripts/forest.js @@ -0,0 +1,100 @@ +// Greeting text functions that can be hooked into your cd function so that moving between folders becomes an experience of the AO +import { selectRandom } from './util.js' + +const stepMessages = [ + 'You find a door and walk through.', + 'You walk over there now.', + 'You head over.', + 'Walking briskly, you arrive quickly.', +] +const walkMessages = [ + 'You take a winding path near a river.', + 'A few meadows away is the place you are looking for.', + 'A deer leads you a few galleries away to where you were going.', +] +const wanderMessages = { + up: [ + 'You crane your head upwards to get a better view.', + 'You lean back to try and get a better vantage point.', + 'You stand on your toes to see above the underbrush.', + 'You pull yourself up to a nearby branch.', + 'You climb up into the branches to get an overview.', + 'After traveling up a slight incline, you realize you are higher than you were before.', + 'You climb up onto a boulder so you can see futher around you.', + 'You send your trained falcon on ahead to get an aerial view.', + 'A rope ladder here leads up to a cozy treehouse with a window you can look out from.', + 'Agily climbing the boulders next to a small waterfall, you can see the pool below.', + 'A trapdoor? Here? You climb right up through it, pulling yourself up on your forearms.', + 'A small trampoline allows you to reach the next platform.', + ], + home: [ + 'You are weary from your journey. You return home.', + 'You head home.', + 'You return home.', + 'Time to go home.', + 'Your journey eventually takes you, once again, back to your home.', + 'You return to your origin tree.', + 'You fall asleep and when you wake up, you are home again. Was it all a dream?', + 'Home, sweet, home.', + 'There\'s no place like home!', + 'You head to the heart of the forest, where you have built a glowing shrine.', + ], + root: [ + 'You are weary of this world. You head up the Mountain, up where the air is thin, to the very acme of creation!', + 'On your many long journeys you sometimes find occasion to return to the Headwaters.', + 'Deep under the World-Tree lies the root of all things.', + 'You take out your compass and it spins wildly. You are at the Center.', + 'A large bird swoops down and takes you high into the sky,', + 'A rather ungainly solar-powered dirigible carries you safely into the heavens.', + 'Without further ado, you ascend.', + 'Returning to the center once again, you feel your memories bend around you.', + ], + 0: [ + 'Wherever you go, there you are.', + 'You\'re going nowhere.', + 'You\'re already here.', + ], + 1: stepMessages, + 2: stepMessages, + 3: stepMessages, + 4: walkMessages, + 5: [ + 'You teleport.', + 'You fold space and arrive there in the blink of an eye.', + 'You wrinkle time and arrive there in two shakes of a cat\'s tail.', + 'You perform a basic transit spell to take you to your destination.', + 'Turning your mind inside out, you transmigrate zones.', + 'You bilocate and, when the confusion clears, there you are.', + ] +} + +export default function wander(direction) { + direction = !!direction ? direction.trim() : 'home' + switch(direction) { + case '..': + direction = 'up' + break + case '': + case '~': + case process.env.HOME: + case 'home': + direction = 'home' + break + case '/': + direction = 'root' + break + default: + // To find the jump-distance, add the slashes in the old and new paths, then subtract the number of filenames/folder names they share × 2 + // This rewards making further jumps with cd with a cooler flavor text message, encouraging diligence and direct transit. + if(direction && direction.length >= 1) { + const findSlashes = /\//g + const slashesInOldPwd = process.env.OLDPWD.match(findSlashes)?.length + const slashesInNewPwd = process.env.PWD.match(findSlashes)?.length + const sharedWordsCount = process.env.OLDPWD.split('/').filter(word => word != '' && process.env.PWD.split('/').includes(word)).length + let totalSlashes = slashesInOldPwd + slashesInNewPwd - (sharedWordsCount * 2) + if(totalSlashes < 0) totalSlashes = 0 + direction = Math.min(parseInt(totalSlashes), 5) + } + } + return selectRandom(wanderMessages[direction]) +} \ No newline at end of file diff --git a/scripts/strings.js b/scripts/strings.js index 13a83b4..319f759 100644 --- a/scripts/strings.js +++ b/scripts/strings.js @@ -15,8 +15,6 @@ export const repeatString = (str, n) => { return new Array(1 + (n || 0)).join(str) } -String.prototype.repeat = repeatString - String.prototype.centerInConsole = function (width = 80) { const consoleWidth = process.stdout.columns const padding = Math.floor((consoleWidth - width) / 2) diff --git a/scripts/welcome.js b/scripts/welcome.js index 9162cab..d769606 100644 --- a/scripts/welcome.js +++ b/scripts/welcome.js @@ -98,6 +98,10 @@ export function farewell() { console.log(chalk.yellow.bold(selectRandom(farewellMessages))) } +export function wander() { + //console.lo(selectRa)) +} + // Asks the given yes or no answer returns true or false for their response export async function yesOrNo(prompt = 'Yes or no?', defaultAnswer = true) { const answer = await inquirer.prompt({ @@ -120,3 +124,4 @@ export async function askQuestionText(prompt = 'Please enter a string:', promptO const answer = await inquirer.prompt(options) return answer.text } + diff --git a/scripts/wizard.js b/scripts/wizard.js index 364ebe8..364bf6f 100644 --- a/scripts/wizard.js +++ b/scripts/wizard.js @@ -69,7 +69,7 @@ async function chooseInstallLevel() { type: 'list', message: 'What kind of installation?', choices: [ - { name: 'Minimal'.padEnd(11) + 'only core AO web server', value: 'minimal', short: 'minimal install' }, + { name: 'Minimal'.padEnd(11) + 'only core AO web server (or only ao-cli)', value: 'minimal', short: 'minimal install' }, { name: 'Standard'.padEnd(11) + 'most AO features installed (recommended)', value: 'standard', short: 'standard install' }, { name: 'Full'.padEnd(11) + 'all AO features installed', value: 'full', short: 'full install' }, { name: 'Cancel', value: false }