├── .gitignore ├── ask.js ├── executeCommand.js ├── index.js ├── options.js ├── package-lock.json ├── package.json ├── process.js └── readme.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | .pnpm-debug.log* 9 | 10 | # Diagnostic reports (https://nodejs.org/api/report.html) 11 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 12 | 13 | # Runtime data 14 | pids 15 | *.pid 16 | *.seed 17 | *.pid.lock 18 | 19 | # Directory for instrumented libs generated by jscoverage/JSCover 20 | lib-cov 21 | 22 | # Coverage directory used by tools like istanbul 23 | coverage 24 | *.lcov 25 | 26 | # nyc test coverage 27 | .nyc_output 28 | 29 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 30 | .grunt 31 | 32 | # Bower dependency directory (https://bower.io/) 33 | bower_components 34 | 35 | # node-waf configuration 36 | .lock-wscript 37 | 38 | # Compiled binary addons (https://nodejs.org/api/addons.html) 39 | build/Release 40 | 41 | # Dependency directories 42 | node_modules/ 43 | jspm_packages/ 44 | 45 | # Snowpack dependency directory (https://snowpack.dev/) 46 | web_modules/ 47 | 48 | # TypeScript cache 49 | *.tsbuildinfo 50 | 51 | # Optional npm cache directory 52 | .npm 53 | 54 | # Optional eslint cache 55 | .eslintcache 56 | 57 | # Optional stylelint cache 58 | .stylelintcache 59 | 60 | # Microbundle cache 61 | .rpt2_cache/ 62 | .rts2_cache_cjs/ 63 | .rts2_cache_es/ 64 | .rts2_cache_umd/ 65 | 66 | # Optional REPL history 67 | .node_repl_history 68 | 69 | # Output of 'npm pack' 70 | *.tgz 71 | 72 | # Yarn Integrity file 73 | .yarn-integrity 74 | 75 | # dotenv environment variable files 76 | .env 77 | .env.development.local 78 | .env.test.local 79 | .env.production.local 80 | .env.local 81 | 82 | # parcel-bundler cache (https://parceljs.org/) 83 | .cache 84 | .parcel-cache 85 | 86 | # Next.js build output 87 | .next 88 | out 89 | 90 | # Nuxt.js build / generate output 91 | .nuxt 92 | dist 93 | 94 | # Gatsby files 95 | .cache/ 96 | # Comment in the public line in if your project uses Gatsby and not Next.js 97 | # https://nextjs.org/blog/next-9-1#public-directory-support 98 | # public 99 | 100 | # vuepress build output 101 | .vuepress/dist 102 | 103 | # vuepress v2.x temp and cache directory 104 | .temp 105 | .cache 106 | 107 | # Docusaurus cache and generated files 108 | .docusaurus 109 | 110 | # Serverless directories 111 | .serverless/ 112 | 113 | # FuseBox cache 114 | .fusebox/ 115 | 116 | # DynamoDB Local files 117 | .dynamodb/ 118 | 119 | # TernJS port file 120 | .tern-port 121 | 122 | # Stores VSCode versions used for testing VSCode extensions 123 | .vscode-test 124 | 125 | # yarn v2 126 | .yarn/cache 127 | .yarn/unplugged 128 | .yarn/build-state.yml 129 | .yarn/install-state.gz 130 | .pnp.* -------------------------------------------------------------------------------- /ask.js: -------------------------------------------------------------------------------- 1 | async function ask(question) { 2 | try { 3 | const response = await fetch(`https://api.functionj.com/v1/ask?question=${question}`); 4 | if (!response.ok) { 5 | if (response.status === 404) console.log('Resource not found') 6 | else if (response.status === 400) console.log('Please retry'); 7 | else console.log('\x1b[31m%s\x1b[0m', response.statusText); 8 | return false 9 | } else { 10 | return await response.json(); 11 | } 12 | } catch (error) { 13 | console.error('\x1b[31m%s\x1b[0m', 'An error occurred:', error); 14 | } 15 | } 16 | 17 | module.exports = ask 18 | -------------------------------------------------------------------------------- /executeCommand.js: -------------------------------------------------------------------------------- 1 | const { exec } = require('child_process'); 2 | 3 | function executeCommand(command) { 4 | console.log(`-------------------------------------------------------\n`); 5 | exec(`bash -c '${command}'`, (error, stdout, _) => { 6 | if (error) return console.log('\x1b[31m%s\x1b[0m', error.stack); 7 | console.log(`${stdout}`); 8 | }); 9 | } 10 | 11 | module.exports = executeCommand -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | require('./process') 4 | const ask = require('./ask') 5 | const { setOptions } = require('./options') 6 | 7 | const question = process.argv.slice(2).join(" "); 8 | ask(question).then(response => { 9 | setOptions(response || []) 10 | }) 11 | 12 | -------------------------------------------------------------------------------- /options.js: -------------------------------------------------------------------------------- 1 | const options = { 2 | list: [], 3 | index: 0, 4 | selected: '' 5 | } 6 | 7 | function setOptions(newValue) { 8 | options.list = newValue; 9 | displayOptions(); 10 | } 11 | 12 | function setIndex(newValue) { 13 | options.index = newValue; 14 | displayOptions(); 15 | } 16 | 17 | function displayOptions() { 18 | options.selected = options.list[options.index]; 19 | 20 | process.stdout.clearLine(); 21 | process.stdout.cursorTo(0); 22 | 23 | for (let i = 0; i < options.list.length; i++) { 24 | 25 | i === options.index ? 26 | process.stdout.write(`\x1b[42m${options.list[i]}\x1b[0m`) 27 | : process.stdout.write(options.list[i]); 28 | 29 | if (i < options.list.length - 1) { 30 | process.stdout.write(' | '); 31 | } 32 | } 33 | } 34 | 35 | 36 | module.exports = { 37 | options, 38 | setOptions, 39 | setIndex, 40 | } -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "function-j", 3 | "version": "1.1.4", 4 | "lockfileVersion": 3, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "function-j", 9 | "version": "1.1.4", 10 | "license": "ISC", 11 | "dependencies": { 12 | "keypress": "^0.2.1", 13 | "openai": "^4.10.0" 14 | }, 15 | "bin": { 16 | "fj": "index.js" 17 | } 18 | }, 19 | "node_modules/@types/node": { 20 | "version": "18.17.19", 21 | "resolved": "https://registry.npmjs.org/@types/node/-/node-18.17.19.tgz", 22 | "integrity": "sha512-+pMhShR3Or5GR0/sp4Da7FnhVmTalWm81M6MkEldbwjETSaPalw138Z4KdpQaistvqQxLB7Cy4xwYdxpbSOs9Q==" 23 | }, 24 | "node_modules/@types/node-fetch": { 25 | "version": "2.6.6", 26 | "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.6.tgz", 27 | "integrity": "sha512-95X8guJYhfqiuVVhRFxVQcf4hW/2bCuoPwDasMf/531STFoNoWTT7YDnWdXHEZKqAGUigmpG31r2FE70LwnzJw==", 28 | "dependencies": { 29 | "@types/node": "*", 30 | "form-data": "^4.0.0" 31 | } 32 | }, 33 | "node_modules/abort-controller": { 34 | "version": "3.0.0", 35 | "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", 36 | "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", 37 | "dependencies": { 38 | "event-target-shim": "^5.0.0" 39 | }, 40 | "engines": { 41 | "node": ">=6.5" 42 | } 43 | }, 44 | "node_modules/agentkeepalive": { 45 | "version": "4.5.0", 46 | "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.5.0.tgz", 47 | "integrity": "sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew==", 48 | "dependencies": { 49 | "humanize-ms": "^1.2.1" 50 | }, 51 | "engines": { 52 | "node": ">= 8.0.0" 53 | } 54 | }, 55 | "node_modules/asynckit": { 56 | "version": "0.4.0", 57 | "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", 58 | "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" 59 | }, 60 | "node_modules/base-64": { 61 | "version": "0.1.0", 62 | "resolved": "https://registry.npmjs.org/base-64/-/base-64-0.1.0.tgz", 63 | "integrity": "sha512-Y5gU45svrR5tI2Vt/X9GPd3L0HNIKzGu202EjxrXMpuc2V2CiKgemAbUUsqYmZJvPtCXoUKjNZwBJzsNScUbXA==" 64 | }, 65 | "node_modules/charenc": { 66 | "version": "0.0.2", 67 | "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", 68 | "integrity": "sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==", 69 | "engines": { 70 | "node": "*" 71 | } 72 | }, 73 | "node_modules/combined-stream": { 74 | "version": "1.0.8", 75 | "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", 76 | "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", 77 | "dependencies": { 78 | "delayed-stream": "~1.0.0" 79 | }, 80 | "engines": { 81 | "node": ">= 0.8" 82 | } 83 | }, 84 | "node_modules/crypt": { 85 | "version": "0.0.2", 86 | "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", 87 | "integrity": "sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==", 88 | "engines": { 89 | "node": "*" 90 | } 91 | }, 92 | "node_modules/delayed-stream": { 93 | "version": "1.0.0", 94 | "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", 95 | "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", 96 | "engines": { 97 | "node": ">=0.4.0" 98 | } 99 | }, 100 | "node_modules/digest-fetch": { 101 | "version": "1.3.0", 102 | "resolved": "https://registry.npmjs.org/digest-fetch/-/digest-fetch-1.3.0.tgz", 103 | "integrity": "sha512-CGJuv6iKNM7QyZlM2T3sPAdZWd/p9zQiRNS9G+9COUCwzWFTs0Xp8NF5iePx7wtvhDykReiRRrSeNb4oMmB8lA==", 104 | "dependencies": { 105 | "base-64": "^0.1.0", 106 | "md5": "^2.3.0" 107 | } 108 | }, 109 | "node_modules/event-target-shim": { 110 | "version": "5.0.1", 111 | "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", 112 | "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", 113 | "engines": { 114 | "node": ">=6" 115 | } 116 | }, 117 | "node_modules/form-data": { 118 | "version": "4.0.0", 119 | "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", 120 | "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", 121 | "dependencies": { 122 | "asynckit": "^0.4.0", 123 | "combined-stream": "^1.0.8", 124 | "mime-types": "^2.1.12" 125 | }, 126 | "engines": { 127 | "node": ">= 6" 128 | } 129 | }, 130 | "node_modules/form-data-encoder": { 131 | "version": "1.7.2", 132 | "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-1.7.2.tgz", 133 | "integrity": "sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==" 134 | }, 135 | "node_modules/formdata-node": { 136 | "version": "4.4.1", 137 | "resolved": "https://registry.npmjs.org/formdata-node/-/formdata-node-4.4.1.tgz", 138 | "integrity": "sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==", 139 | "dependencies": { 140 | "node-domexception": "1.0.0", 141 | "web-streams-polyfill": "4.0.0-beta.3" 142 | }, 143 | "engines": { 144 | "node": ">= 12.20" 145 | } 146 | }, 147 | "node_modules/humanize-ms": { 148 | "version": "1.2.1", 149 | "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", 150 | "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", 151 | "dependencies": { 152 | "ms": "^2.0.0" 153 | } 154 | }, 155 | "node_modules/is-buffer": { 156 | "version": "1.1.6", 157 | "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", 158 | "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" 159 | }, 160 | "node_modules/keypress": { 161 | "version": "0.2.1", 162 | "resolved": "https://registry.npmjs.org/keypress/-/keypress-0.2.1.tgz", 163 | "integrity": "sha512-HjorDJFNhnM4SicvaUXac0X77NiskggxJdesG72+O5zBKpSqKFCrqmndKVqpu3pFqkla0St6uGk8Ju0sCurrmg==" 164 | }, 165 | "node_modules/md5": { 166 | "version": "2.3.0", 167 | "resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz", 168 | "integrity": "sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==", 169 | "dependencies": { 170 | "charenc": "0.0.2", 171 | "crypt": "0.0.2", 172 | "is-buffer": "~1.1.6" 173 | } 174 | }, 175 | "node_modules/mime-db": { 176 | "version": "1.52.0", 177 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", 178 | "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", 179 | "engines": { 180 | "node": ">= 0.6" 181 | } 182 | }, 183 | "node_modules/mime-types": { 184 | "version": "2.1.35", 185 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", 186 | "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", 187 | "dependencies": { 188 | "mime-db": "1.52.0" 189 | }, 190 | "engines": { 191 | "node": ">= 0.6" 192 | } 193 | }, 194 | "node_modules/ms": { 195 | "version": "2.1.3", 196 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", 197 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" 198 | }, 199 | "node_modules/node-domexception": { 200 | "version": "1.0.0", 201 | "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", 202 | "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", 203 | "funding": [ 204 | { 205 | "type": "github", 206 | "url": "https://github.com/sponsors/jimmywarting" 207 | }, 208 | { 209 | "type": "github", 210 | "url": "https://paypal.me/jimmywarting" 211 | } 212 | ], 213 | "engines": { 214 | "node": ">=10.5.0" 215 | } 216 | }, 217 | "node_modules/node-fetch": { 218 | "version": "2.7.0", 219 | "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", 220 | "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", 221 | "dependencies": { 222 | "whatwg-url": "^5.0.0" 223 | }, 224 | "engines": { 225 | "node": "4.x || >=6.0.0" 226 | }, 227 | "peerDependencies": { 228 | "encoding": "^0.1.0" 229 | }, 230 | "peerDependenciesMeta": { 231 | "encoding": { 232 | "optional": true 233 | } 234 | } 235 | }, 236 | "node_modules/openai": { 237 | "version": "4.10.0", 238 | "resolved": "https://registry.npmjs.org/openai/-/openai-4.10.0.tgz", 239 | "integrity": "sha512-II4b5/7qzwYkqA9MSjgqdofCc798EW+dtF2h6qNaVLet+qO7FShAJTWnoyzb50J4ZH1rPxRFAsmDLIhY3PT6DQ==", 240 | "dependencies": { 241 | "@types/node": "^18.11.18", 242 | "@types/node-fetch": "^2.6.4", 243 | "abort-controller": "^3.0.0", 244 | "agentkeepalive": "^4.2.1", 245 | "digest-fetch": "^1.3.0", 246 | "form-data-encoder": "1.7.2", 247 | "formdata-node": "^4.3.2", 248 | "node-fetch": "^2.6.7" 249 | }, 250 | "bin": { 251 | "openai": "bin/cli" 252 | } 253 | }, 254 | "node_modules/tr46": { 255 | "version": "0.0.3", 256 | "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", 257 | "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" 258 | }, 259 | "node_modules/web-streams-polyfill": { 260 | "version": "4.0.0-beta.3", 261 | "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz", 262 | "integrity": "sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==", 263 | "engines": { 264 | "node": ">= 14" 265 | } 266 | }, 267 | "node_modules/webidl-conversions": { 268 | "version": "3.0.1", 269 | "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", 270 | "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" 271 | }, 272 | "node_modules/whatwg-url": { 273 | "version": "5.0.0", 274 | "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", 275 | "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", 276 | "dependencies": { 277 | "tr46": "~0.0.3", 278 | "webidl-conversions": "^3.0.0" 279 | } 280 | } 281 | } 282 | } 283 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "function-j", 3 | "version": "1.1.4", 4 | "repository": { 5 | "type": "git", 6 | "url": "https://github.com/ThisIsHermanCheng/function-J.git" 7 | }, 8 | "description": "Transform plain text instructions into ready-to-use terminal commands. Say goodbye to memorizing complex commands.", 9 | "main": "index.js", 10 | "bin": { 11 | "fj": "./index.js" 12 | }, 13 | "keywords": [ 14 | "ai", 15 | "terminal assistant", 16 | "command", 17 | "terminal" 18 | ], 19 | "author": "Function J", 20 | "license": "ISC", 21 | "dependencies": { 22 | "keypress": "^0.2.1", 23 | "openai": "^4.10.0" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /process.js: -------------------------------------------------------------------------------- 1 | const readline = require('readline'); 2 | const keypress = require('keypress'); 3 | const { setIndex, options } = require('./options') 4 | const executeCommand = require('./executeCommand') 5 | 6 | const rl = readline.createInterface({ 7 | input: process.stdin, 8 | output: process.stdout, 9 | }); 10 | 11 | process.stdout.write(`\x1B[?25l`); 12 | process.on('exit', () => process.stdout.write('\x1B[?25h\n')); 13 | 14 | keypress(process.stdin); 15 | process.stdin.setRawMode(true); 16 | 17 | let inputting = false 18 | 19 | process.stdin.on('keypress', (_, key) => { 20 | if (!key) return 21 | if (key.name === 'tab') setIndex((options.index + 1) % 3) 22 | else if (key.name === 'return') { 23 | 24 | if (inputting) return 25 | 26 | const regex = /\{([^}]+)\}/g; 27 | const matches = []; 28 | let match; 29 | while ((match = regex.exec(options.selected)) !== null) { 30 | matches.push(match[1]); 31 | } 32 | 33 | if (matches.length == 0) { 34 | rl.close(); 35 | executeCommand(options.selected) 36 | inputting = false 37 | } else { 38 | console.log("-------------------------------------------------------") 39 | console.log("Please input the following values") 40 | 41 | inputting = true 42 | currentIndex = 0 43 | 44 | function askQuestion() { 45 | rl.question(matches[currentIndex] + ': ', (answer) => { 46 | options.selected = options.selected.replace(`{${matches[currentIndex]}}`, answer) 47 | currentIndex++; 48 | if (currentIndex < matches.length) { 49 | askQuestion(); 50 | } else { 51 | executeCommand(options.selected) 52 | rl.close(); 53 | } 54 | }); 55 | } 56 | 57 | 58 | askQuestion(); 59 | 60 | } 61 | 62 | 63 | } 64 | }); 65 | 66 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Function J - Free Terminal Assistant Powered by AI 2 | 3 | Say goodbye to memorizing complex commands 4 | 5 | ## Overview 6 | 7 | Function J is a free terminal assistant powered by AI. It is designed to help you convert plain text instructions into ready-to-use commands. With Function J, you can quickly transform natural language into executable commands, making your terminal tasks more efficient and accessible. 8 | 9 | ## Features 10 | 11 | - **Natural Language to Command Conversion:** Simply type your desired action in plain English, and Function J will quickly provide you with a list of relevant terminal commands. 12 | - **Command Choices:** When Function J generates commands, it presents you with multiple options to choose from, ensuring that you select the command that best suits your needs. 13 | - **Interactive Selection:** Use the tab key to navigate through the list of generated commands and press enter to execute your chosen command. 14 | - **Intuitive Usage:** Designed for users who dislike memorizing long and complex terminal commands or those who frequently perform repetitive tasks. 15 | 16 | ## Installation 17 | 18 | To install Function J, use npm, the Node.js package manager: 19 | 20 | ```bash 21 | npm install -g function-j 22 | ``` 23 | 24 | ## Getting Started 25 | 26 | To start using Function J, open your terminal and simply prefix your instructions with 'fj'. 27 | 28 | For example: 29 | 30 | ``` 31 | fj show containers 32 | ``` 33 | 34 | Function J will provide a list of command options. Select the most suitable command using the `tab` key and execute it by pressing `enter`. 35 | 36 | ``` 37 | docker ps | docker container ls | docker ps -a 38 | ``` 39 | 40 | For some cases, user input is needed within the command options containing curly braces. 41 | 42 | ``` 43 | fj creat file 44 | ``` 45 | 46 | ``` 47 | touch {file_name} | echo > {file_name} | cat > {file_name} 48 | ------------------------------------------------------- 49 | Please input the following values 50 | file_name: 51 | ``` 52 | 53 | ## Demo 54 | 55 | ![Animation](https://github.com/ThisIsHermanCheng/function-J/assets/45646023/009da273-44d8-4f5c-afcb-d6c26001c885) 56 | 57 | [👉 Try it online 👈](https://functionj.com) 58 | 59 | ## Why Use Function J? 60 | 61 | **_Dislike Memorizing Commands_** 62 | 63 | Tired of trying to remember lengthy and intricate terminal commands. 64 | Frequently Forget Commands: Find themselves forgetting commands, even if they've used them multiple times. 65 | 66 | **_Prefer Easy Access to Commands_** 67 | 68 | Don't want to spend time searching online for command syntax. 69 | Question Command Options: Want clarity on command parameters like '-h' and what they stand for (help, host, header, etc.). 70 | 71 | **_Keyboard-Friendly Shortcut_** 72 | 73 | The choice of 'fj' as the prefix for Function J was intentional. These keys are conveniently located on the keyboard, making it effortless to access this powerful terminal assistant. 74 | 75 | ![keyboard](https://github.com/ThisIsHermanCheng/function-J/assets/45646023/8483cceb-828b-450f-84fe-e9057027ff2b) 76 | 77 | --- 78 | 79 | Now, say goodbye to the hassle of memorizing complex commands and enjoy a more straightforward way to interact with your terminal using Function J! 80 | 81 | Happy terminal navigating with Function J! 🚀 82 | --------------------------------------------------------------------------------