├── .gitignore ├── README.md ├── art ├── index.js ├── package-lock.json ├── package.json └── screenshot.png /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | generated-repo/ 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GitHub history art 2 | 3 | Paint some sweet art in your GitHub commit history. 4 | 5 | ## [Example](https://github.com/KATT) 6 | 7 | 8 | 9 | ## HOW?!? 😻 10 | 11 | 1. [Create a personal API token](https://github.com/settings/tokens) 12 | 1. Run 13 | ```sh 14 | npx gitkatt 15 | ``` 16 | 1. (Optional): Update `./art` with other art 17 | 1. Follow the rest of steps 18 | 19 | 20 | ### Custom art 21 | 22 | 23 | A file called `./art` will be created automatically with a template. 24 | * any non-whitespace char gets filled 25 | * the canvas is 7 in height (7 days) 26 | 27 | ### Optional: set default options 28 | 29 | ```sh 30 | export GITHUB_USER='YOUR_GITHUB_USER' 31 | export GITHUB_API_TOKEN='YOUR_GITHUB_API_TOKEN' 32 | export DRAW_START_DATE='2017-02-26' 33 | export ART_FILENAME='art' 34 | ``` 35 | 36 | ### Notes 37 | 38 | - Every time you run it it will delete (clears the graph) and create a repo called `gitkatt-child-repo` ([Example repo](https://github.com/KATT/gitkatt-child-repo)). 39 | - The more layers you choose, the longer it'll run, & the darker your dots become. 40 | 41 | -------------------------------------------------------------------------------- /art: -------------------------------------------------------------------------------- 1 | ▋ ▋ ▋ 2 | ▋▋ ▋▋ ▋ 3 | ▋ ▋ ▋▋▋▋▋▋▋ ▋ 4 | ▋ ▋ ▋ ▋ 5 | ▋▋▋ ▋▋ 6 | ▋▋▋▋▋▋▋▋▋ 7 | ▋ ▋ ▋ ▋ 8 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const { readFileSync, existsSync, writeFileSync } = require('fs'); 4 | const path = require('path'); 5 | 6 | const { promisify } = require('util'); 7 | const _exec = promisify(require('child_process').exec); 8 | const moment = require('moment'); 9 | const { prompt } = require('inquirer'); 10 | const GitHub = require('github'); 11 | const ProgressBar = require('progress'); 12 | 13 | const DRY_RUN = !!process.env.DRY_RUN; 14 | 15 | DRY_RUN && console.log('❗️ DRY RUN ❗️'); 16 | function exec(cmd) { 17 | if (DRY_RUN) { 18 | return new Promise(resolve => setTimeout(resolve, 1)); 19 | } 20 | return _exec(`${cmd}`); 21 | } 22 | 23 | function getMomentForPosition(x, y, refDate) { 24 | return moment(refDate) 25 | .add(x, 'weeks') 26 | .add(y, 'days') 27 | .hour(12); 28 | } 29 | 30 | async function recreateRepo({ GITHUB_API_TOKEN, GITHUB_REPO, GITHUB_USER }) { 31 | // removing the repo removes the dots from the graph 32 | const github = new GitHub(); 33 | github.authenticate({ 34 | type: 'token', 35 | token: GITHUB_API_TOKEN, 36 | }); 37 | try { 38 | !DRY_RUN && 39 | (await github.repos.delete({ 40 | owner: GITHUB_USER, 41 | repo: GITHUB_REPO, 42 | })); 43 | console.log(`✅ Deleted repo ${GITHUB_USER}:${GITHUB_REPO}`); 44 | } catch (err) { 45 | // prob 404 46 | } 47 | !DRY_RUN && 48 | (await github.repos.create({ 49 | name: GITHUB_REPO, 50 | description: '🐱 Generated by gitkatt', 51 | homepage: 'https://github.com/KATT/gitkatt', 52 | })); 53 | console.log(`✅ Created repo ${GITHUB_USER}:${GITHUB_REPO}..`); 54 | } 55 | 56 | function paintingToCoords(art, refDate) { 57 | const painting = []; 58 | let x = 0, 59 | y = 0; 60 | for (const char of art) { 61 | if (char === '\n') { 62 | y++; 63 | x = 0; 64 | continue; 65 | } 66 | if (y > 6) { 67 | throw new Error('Too many lines in art (max 7 rows).'); 68 | } 69 | 70 | const date = getMomentForPosition(x, y, refDate); 71 | 72 | painting.push({ date, char }); 73 | 74 | x++; 75 | } 76 | 77 | return painting; 78 | } 79 | 80 | async function main() { 81 | if (!existsSync('./art')) { 82 | const contents = readFileSync(path.join(__dirname, 'art')); 83 | writeFileSync('./art', contents); 84 | const info = [ 85 | 'ℹ️ Notied that you didn\'t an "art" file. So we created an example for you.', 86 | 'ℹ️ Have a look and edit it to your liking.', 87 | ]; 88 | console.log(info.join('\n')); 89 | } 90 | const questions = [ 91 | { 92 | type: 'input', 93 | name: 'GITHUB_USER', 94 | message: 'GitHub username', 95 | default: process.env.GITHUB_USER, 96 | validate: val => !!val, 97 | }, 98 | { 99 | type: 'input', 100 | name: 'GITHUB_API_TOKEN', 101 | message: 'GitHub API Token', 102 | default: process.env.GITHUB_API_TOKEN, 103 | validate: val => val.length > 10 || 'Enter a valid API TOKEN', 104 | }, 105 | { 106 | type: 'input', 107 | name: 'ART_FILENAME', 108 | message: 'Filename for art', 109 | default: process.env.ART_FILENAME || 'art', 110 | validate: val => existsSync(`./${val}`) || 'Enter an existing file', 111 | }, 112 | { 113 | type: 'input', 114 | name: 'GITHUB_REPO', 115 | message: 'Repository name', 116 | default: process.env.GITHUB_REPO || 'gitkatt-child-repo', 117 | validate: val => !!val, 118 | }, 119 | { 120 | type: 'input', 121 | name: 'DRAW_START_DATE', 122 | message: 'Start date for drawing', 123 | default: process.env.DRAW_START_DATE || '2017-03-05', 124 | validate: val => moment(val).isoWeekday() === 7 || 'Needs to be a Sunday', 125 | }, 126 | { 127 | type: 'input', 128 | name: 'NUM_LAYERS', 129 | message: 'Number of layers to draw', 130 | default: process.env.NUM_LAYERS || 30, 131 | filter: val => parseInt(val), 132 | validate: val => (val > 0 && val < 100) || 'Needs to be 1-100', 133 | }, 134 | ]; 135 | 136 | const { 137 | GITHUB_USER, 138 | GITHUB_API_TOKEN, 139 | GITHUB_REPO, 140 | DRAW_START_DATE, 141 | ART_FILENAME, 142 | NUM_LAYERS, 143 | } = await prompt(questions); 144 | 145 | const ART = readFileSync(`./${ART_FILENAME}`).toString(); 146 | 147 | console.log(ART); 148 | 149 | const painting = paintingToCoords(ART, DRAW_START_DATE); 150 | 151 | const bar = new ProgressBar('🚧 Creating git history :percent :etas', { 152 | complete: '=', 153 | incomplete: ' ', 154 | width: 20, 155 | total: NUM_LAYERS * painting.length, 156 | }); 157 | // recreate repo a few times to have more history (makes it darker) 158 | await exec( 159 | `rm -rf ./generated-repo && mkdir ./generated-repo && cd ./generated-repo && git init && git checkout -b main`, 160 | ); 161 | for (let i = 0; i < NUM_LAYERS; i++) { 162 | for (const { date, char } of painting) { 163 | bar.tick(); 164 | if (char === ' ') { 165 | continue; 166 | } 167 | const d = date 168 | .clone() 169 | .add(Math.random() * 60, 'm') 170 | .add(Math.random() * 60, 's'); 171 | const content = `${d.format('YYYY-MM-DD')} ${Math.random()}`; 172 | const cmd = `echo '${ 173 | content 174 | }' >> meow && git add meow && git commit --date='${d.toJSON()}' -m '🐱'`; 175 | 176 | await exec(`cd ./generated-repo && ${cmd}`); 177 | } 178 | } 179 | 180 | await recreateRepo({ GITHUB_API_TOKEN, GITHUB_USER, GITHUB_REPO }); 181 | await exec( 182 | `cd ./generated-repo && git remote add origin git@github.com:${ 183 | GITHUB_USER 184 | }/${GITHUB_REPO}.git && git push origin main --force`, 185 | ); 186 | } 187 | 188 | main() 189 | .then(() => { 190 | console.log('😻 - it should be all set and done! '); 191 | }) 192 | .catch(err => { 193 | console.error('🙀', err); 194 | }); 195 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gitkatt", 3 | "version": "1.1.3", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "@types/github": { 8 | "version": "7.1.0", 9 | "resolved": "https://registry.npmjs.org/@types/github/-/github-7.1.0.tgz", 10 | "integrity": "sha1-8vMwFz5iLgUDwoI2loNRHEG17I0=", 11 | "dev": true, 12 | "requires": { 13 | "github": "13.0.1" 14 | } 15 | }, 16 | "@types/lodash": { 17 | "version": "4.14.88", 18 | "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.88.tgz", 19 | "integrity": "sha512-S+7dONqCP8kXqOPCPxra7Vw8FndWS8pNfVkClMSzRCPMjXkA3BaI3ybMBCiSd4y+r1vC49UEjNthnm+fO8J/dw==", 20 | "dev": true 21 | }, 22 | "@types/moment": { 23 | "version": "2.13.0", 24 | "resolved": "https://registry.npmjs.org/@types/moment/-/moment-2.13.0.tgz", 25 | "integrity": "sha1-YE69GJvDvDShVIaJQE5hoqSqyJY=", 26 | "dev": true, 27 | "requires": { 28 | "moment": "2.19.4" 29 | } 30 | }, 31 | "@types/node": { 32 | "version": "8.0.58", 33 | "resolved": "https://registry.npmjs.org/@types/node/-/node-8.0.58.tgz", 34 | "integrity": "sha512-V746iUU7eHNdzQipoACuguDlVhC7IHK8CES1jSkuFt352wwA84BCWPXaGekBd7R5XdNK5ReHONDVKxlL9IreAw==", 35 | "dev": true 36 | }, 37 | "@types/progress": { 38 | "version": "2.0.0", 39 | "resolved": "https://registry.npmjs.org/@types/progress/-/progress-2.0.0.tgz", 40 | "integrity": "sha1-0WayhETbTiSn7J8dwrVFUf4Hbd8=", 41 | "dev": true, 42 | "requires": { 43 | "@types/node": "8.0.58" 44 | } 45 | }, 46 | "agent-base": { 47 | "version": "4.1.2", 48 | "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.1.2.tgz", 49 | "integrity": "sha512-VE6QoEdaugY86BohRtfGmTDabxdU5sCKOkbcPA6PXKJsRzEi/7A3RCTxJal1ft/4qSfPht5/iQLhMh/wzSkkNw==", 50 | "requires": { 51 | "es6-promisify": "5.0.0" 52 | } 53 | }, 54 | "ansi-escapes": { 55 | "version": "3.0.0", 56 | "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.0.0.tgz", 57 | "integrity": "sha512-O/klc27mWNUigtv0F8NJWbLF00OcegQalkqKURWdosW08YZKi4m6CnSUSvIZG1otNJbTWhN01Hhz389DW7mvDQ==" 58 | }, 59 | "ansi-regex": { 60 | "version": "3.0.0", 61 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", 62 | "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" 63 | }, 64 | "ansi-styles": { 65 | "version": "3.2.0", 66 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", 67 | "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", 68 | "requires": { 69 | "color-convert": "1.9.1" 70 | } 71 | }, 72 | "chalk": { 73 | "version": "2.3.0", 74 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.0.tgz", 75 | "integrity": "sha512-Az5zJR2CBujap2rqXGaJKaPHyJ0IrUimvYNX+ncCy8PJP4ltOGTrHUIo097ZaL2zMeKYpiCdqDvS6zdrTFok3Q==", 76 | "requires": { 77 | "ansi-styles": "3.2.0", 78 | "escape-string-regexp": "1.0.5", 79 | "supports-color": "4.5.0" 80 | } 81 | }, 82 | "chardet": { 83 | "version": "0.4.2", 84 | "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz", 85 | "integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I=" 86 | }, 87 | "cli-cursor": { 88 | "version": "2.1.0", 89 | "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", 90 | "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", 91 | "requires": { 92 | "restore-cursor": "2.0.0" 93 | } 94 | }, 95 | "cli-width": { 96 | "version": "2.2.0", 97 | "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", 98 | "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=" 99 | }, 100 | "color-convert": { 101 | "version": "1.9.1", 102 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.1.tgz", 103 | "integrity": "sha512-mjGanIiwQJskCC18rPR6OmrZ6fm2Lc7PeGFYwCmy5J34wC6F1PzdGL6xeMfmgicfYcNLGuVFA3WzXtIDCQSZxQ==", 104 | "requires": { 105 | "color-name": "1.1.3" 106 | } 107 | }, 108 | "color-name": { 109 | "version": "1.1.3", 110 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", 111 | "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" 112 | }, 113 | "debug": { 114 | "version": "3.1.0", 115 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", 116 | "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", 117 | "requires": { 118 | "ms": "2.0.0" 119 | } 120 | }, 121 | "dotenv": { 122 | "version": "4.0.0", 123 | "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-4.0.0.tgz", 124 | "integrity": "sha1-hk7xN5rO1Vzm+V3r7NzhefegzR0=" 125 | }, 126 | "es6-promise": { 127 | "version": "4.1.1", 128 | "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.1.1.tgz", 129 | "integrity": "sha512-OaU1hHjgJf+b0NzsxCg7NdIYERD6Hy/PEmFLTjw+b65scuisG3Kt4QoTvJ66BBkPZ581gr0kpoVzKnxniM8nng==" 130 | }, 131 | "es6-promisify": { 132 | "version": "5.0.0", 133 | "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", 134 | "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", 135 | "requires": { 136 | "es6-promise": "4.1.1" 137 | } 138 | }, 139 | "escape-string-regexp": { 140 | "version": "1.0.5", 141 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", 142 | "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" 143 | }, 144 | "external-editor": { 145 | "version": "2.1.0", 146 | "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.1.0.tgz", 147 | "integrity": "sha512-E44iT5QVOUJBKij4IIV3uvxuNlbKS38Tw1HiupxEIHPv9qtC2PrDYohbXV5U+1jnfIXttny8gUhj+oZvflFlzA==", 148 | "requires": { 149 | "chardet": "0.4.2", 150 | "iconv-lite": "0.4.19", 151 | "tmp": "0.0.33" 152 | } 153 | }, 154 | "figures": { 155 | "version": "2.0.0", 156 | "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", 157 | "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", 158 | "requires": { 159 | "escape-string-regexp": "1.0.5" 160 | } 161 | }, 162 | "github": { 163 | "version": "13.0.1", 164 | "resolved": "https://registry.npmjs.org/github/-/github-13.0.1.tgz", 165 | "integrity": "sha512-rApJzcnzy6E3WXhjGlSeRlWKnKM/yoi0fAxNjcOuq+1fjX4dMsiS/AWakrrhpMV3ZHi+mbNgNopS5d3go2AopQ==", 166 | "requires": { 167 | "debug": "3.1.0", 168 | "dotenv": "4.0.0", 169 | "https-proxy-agent": "2.1.1", 170 | "lodash": "4.17.4", 171 | "proxy-from-env": "1.0.0", 172 | "url-template": "2.0.8" 173 | } 174 | }, 175 | "has-flag": { 176 | "version": "2.0.0", 177 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", 178 | "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=" 179 | }, 180 | "https-proxy-agent": { 181 | "version": "2.1.1", 182 | "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.1.1.tgz", 183 | "integrity": "sha512-LK6tQUR/VOkTI6ygAfWUKKP95I+e6M1h7N3PncGu1CATHCnex+CAv9ttR0lbHu1Uk2PXm/WoAHFo6JCGwMjVMw==", 184 | "requires": { 185 | "agent-base": "4.1.2", 186 | "debug": "3.1.0" 187 | } 188 | }, 189 | "iconv-lite": { 190 | "version": "0.4.19", 191 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz", 192 | "integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ==" 193 | }, 194 | "inquirer": { 195 | "version": "4.0.1", 196 | "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-4.0.1.tgz", 197 | "integrity": "sha512-HVU3eq/6DCt5Wkt46N6cooQBLlQy55UcmTGwMOe7XEmuxgdVjNxllS3pxrKDc8+OmNIbu+saotsCfH7m+IxHfg==", 198 | "requires": { 199 | "ansi-escapes": "3.0.0", 200 | "chalk": "2.3.0", 201 | "cli-cursor": "2.1.0", 202 | "cli-width": "2.2.0", 203 | "external-editor": "2.1.0", 204 | "figures": "2.0.0", 205 | "lodash": "4.17.4", 206 | "mute-stream": "0.0.7", 207 | "run-async": "2.3.0", 208 | "rx-lite": "4.0.8", 209 | "rx-lite-aggregates": "4.0.8", 210 | "string-width": "2.1.1", 211 | "strip-ansi": "4.0.0", 212 | "through": "2.3.8" 213 | } 214 | }, 215 | "is-fullwidth-code-point": { 216 | "version": "2.0.0", 217 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", 218 | "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" 219 | }, 220 | "is-promise": { 221 | "version": "2.1.0", 222 | "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", 223 | "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=" 224 | }, 225 | "lodash": { 226 | "version": "4.17.4", 227 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", 228 | "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=" 229 | }, 230 | "mimic-fn": { 231 | "version": "1.1.0", 232 | "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.1.0.tgz", 233 | "integrity": "sha1-5md4PZLonb00KBi1IwudYqZyrRg=" 234 | }, 235 | "moment": { 236 | "version": "2.19.4", 237 | "resolved": "https://registry.npmjs.org/moment/-/moment-2.19.4.tgz", 238 | "integrity": "sha512-1xFTAknSLfc47DIxHDUbnJWC+UwgWxATmymaxIPQpmMh7LBm7ZbwVEsuushqwL2GYZU0jie4xO+TK44hJPjNSQ==" 239 | }, 240 | "ms": { 241 | "version": "2.0.0", 242 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 243 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" 244 | }, 245 | "mute-stream": { 246 | "version": "0.0.7", 247 | "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", 248 | "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=" 249 | }, 250 | "onetime": { 251 | "version": "2.0.1", 252 | "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", 253 | "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", 254 | "requires": { 255 | "mimic-fn": "1.1.0" 256 | } 257 | }, 258 | "os-tmpdir": { 259 | "version": "1.0.2", 260 | "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", 261 | "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" 262 | }, 263 | "progress": { 264 | "version": "2.0.0", 265 | "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.0.tgz", 266 | "integrity": "sha1-ihvjZr+Pwj2yvSPxDG/pILQ4nR8=" 267 | }, 268 | "proxy-from-env": { 269 | "version": "1.0.0", 270 | "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.0.0.tgz", 271 | "integrity": "sha1-M8UDmPcOp+uW0h97gXYwpVeRx+4=" 272 | }, 273 | "restore-cursor": { 274 | "version": "2.0.0", 275 | "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", 276 | "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", 277 | "requires": { 278 | "onetime": "2.0.1", 279 | "signal-exit": "3.0.2" 280 | } 281 | }, 282 | "run-async": { 283 | "version": "2.3.0", 284 | "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz", 285 | "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", 286 | "requires": { 287 | "is-promise": "2.1.0" 288 | } 289 | }, 290 | "rx-lite": { 291 | "version": "4.0.8", 292 | "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-4.0.8.tgz", 293 | "integrity": "sha1-Cx4Rr4vESDbwSmQH6S2kJGe3lEQ=" 294 | }, 295 | "rx-lite-aggregates": { 296 | "version": "4.0.8", 297 | "resolved": "https://registry.npmjs.org/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz", 298 | "integrity": "sha1-dTuHqJoRyVRnxKwWJsTvxOBcZ74=", 299 | "requires": { 300 | "rx-lite": "4.0.8" 301 | } 302 | }, 303 | "signal-exit": { 304 | "version": "3.0.2", 305 | "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", 306 | "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" 307 | }, 308 | "string-width": { 309 | "version": "2.1.1", 310 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", 311 | "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", 312 | "requires": { 313 | "is-fullwidth-code-point": "2.0.0", 314 | "strip-ansi": "4.0.0" 315 | } 316 | }, 317 | "strip-ansi": { 318 | "version": "4.0.0", 319 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", 320 | "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", 321 | "requires": { 322 | "ansi-regex": "3.0.0" 323 | } 324 | }, 325 | "supports-color": { 326 | "version": "4.5.0", 327 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz", 328 | "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=", 329 | "requires": { 330 | "has-flag": "2.0.0" 331 | } 332 | }, 333 | "through": { 334 | "version": "2.3.8", 335 | "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", 336 | "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" 337 | }, 338 | "tmp": { 339 | "version": "0.0.33", 340 | "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", 341 | "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", 342 | "requires": { 343 | "os-tmpdir": "1.0.2" 344 | } 345 | }, 346 | "url-template": { 347 | "version": "2.0.8", 348 | "resolved": "https://registry.npmjs.org/url-template/-/url-template-2.0.8.tgz", 349 | "integrity": "sha1-/FZaPMy/93MMd19WQflVV5FDnyE=" 350 | } 351 | } 352 | } 353 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gitkatt", 3 | "version": "1.1.5", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "node index" 8 | }, 9 | "files": [ 10 | "index.js", 11 | "art" 12 | ], 13 | "engines": { 14 | "node": ">8.0.0" 15 | }, 16 | "engineStrict": true, 17 | "bin": { 18 | "gitkatt": "./index.js" 19 | }, 20 | "author": "KATT", 21 | "license": "MIT", 22 | "dependencies": { 23 | "github": "^13.0.1", 24 | "inquirer": "^4.0.1", 25 | "moment": "^2.19.4", 26 | "progress": "^2.0.0" 27 | }, 28 | "devDependencies": { 29 | "@types/github": "^7.1.0", 30 | "@types/lodash": "^4.14.88", 31 | "@types/moment": "^2.13.0", 32 | "@types/progress": "^2.0.0" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KATT/gitkatt/4a015c9c6a5bac06f4c36355e8bedf1716140bbf/screenshot.png --------------------------------------------------------------------------------