├── .babelrc ├── .browserslistrc ├── .eslintrc.json ├── .github ├── main.workflow └── workflows │ └── nodejs.yml ├── .gitignore ├── .madrun.mjs ├── .npmignore ├── .nycrc.json ├── ChangeLog ├── LICENSE ├── README.md ├── bin └── gritty.js ├── client ├── get-el.js ├── get-env.js ├── get-host.js └── gritty.js ├── css └── style.css ├── help.json ├── img ├── linux.png └── windows.png ├── index.html ├── package.json ├── server └── gritty.js ├── test ├── before.js ├── client │ ├── get-el.js │ ├── get-env.js │ ├── get-host.js │ └── gritty.js └── server │ └── gritty.js └── webpack.config.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "@babel/preset-env" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /.browserslistrc: -------------------------------------------------------------------------------- 1 | last 2 Chrome versions 2 | last 2 Safari versions 3 | Firefox ESR 4 | not dead 5 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "plugin:putout/recommended" 4 | ], 5 | "plugins": [ 6 | "putout", 7 | "n" 8 | ], 9 | "overrides": [{ 10 | "files": ["bin/**/*.js"], 11 | "rules": { 12 | "n/no-console": 0, 13 | "n/no-process-exit": 0 14 | }, 15 | "extends": [ 16 | "plugin:n/recommended" 17 | ] 18 | }, { 19 | "files": ["client/**/*.js"], 20 | "env": { 21 | "browser": true 22 | } 23 | }] 24 | } 25 | -------------------------------------------------------------------------------- /.github/main.workflow: -------------------------------------------------------------------------------- 1 | workflow "Push" { 2 | resolves = ["lint", "coverage"] 3 | on = "push" 4 | } 5 | 6 | action "lint" { 7 | uses = "gimenete/eslint-action@1.0" 8 | } 9 | 10 | action "coverage" { 11 | uses = "coverallsapp/github-action@v1.0.1" 12 | } 13 | -------------------------------------------------------------------------------- /.github/workflows/nodejs.yml: -------------------------------------------------------------------------------- 1 | name: Node CI 2 | on: 3 | - push 4 | - pull_request 5 | jobs: 6 | build: 7 | runs-on: ubuntu-latest 8 | strategy: 9 | matrix: 10 | node-version: 11 | - 18.x 12 | - 20.x 13 | - 22.x 14 | - 23.x 15 | steps: 16 | - uses: actions/checkout@v4 17 | - uses: oven-sh/setup-bun@v1 18 | with: 19 | bun-version: latest 20 | - name: Use Node.js ${{ matrix.node-version }} 21 | uses: actions/setup-node@v4 22 | with: 23 | node-version: ${{ matrix.node-version }} 24 | - name: Install Redrun 25 | run: bun i redrun -g --no-save 26 | - name: Install 27 | run: bun i --no-save 28 | - name: Lint 29 | run: redrun lint 30 | - name: Coverage 31 | run: redrun coverage report 32 | - name: Coveralls 33 | uses: coverallsapp/github-action@v2 34 | continue-on-error: true 35 | with: 36 | github-token: ${{ secrets.GITHUB_TOKEN }} 37 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | package-lock.json 2 | node_modules 3 | npm-debug.log 4 | .nyc_output 5 | yarn-error.log 6 | coverage 7 | 8 | dist 9 | dist-dev 10 | 11 | *.swp 12 | 13 | .idea 14 | -------------------------------------------------------------------------------- /.madrun.mjs: -------------------------------------------------------------------------------- 1 | import {run, cutEnv} from 'madrun'; 2 | 3 | const SUPERTAPE_TIMEOUT = 15_000; 4 | 5 | export default { 6 | 'start': () => 'node bin/gritty', 7 | 'start:dev': () => 'NODE_ENV=development npm start', 8 | 'lint': () => 'putout .', 9 | 'fresh:lint': () => run('lint', '--fresh'), 10 | 'lint:fresh': () => run('lint', '--fresh'), 11 | 'fix:lint': () => run('lint', '--fix'), 12 | 'watch:test': () => run('watcher', 'npm test'), 13 | 'watcher': () => 'nodemon -w test -w client -w server --exec', 14 | 'build-progress': () => 'webpack --progress', 15 | '6to5:client': () => run('build-progress', '--mode production'), 16 | '6to5:client:dev': async () => `NODE_ENV=development ${await run('build-progress', '--mode development')}`, 17 | 'watch:client': () => run('6to5:client', '--watch'), 18 | 'watch:client:dev': () => run('6to5:client:dev', '--watch'), 19 | 'wisdom': () => run('build'), 20 | 'build': () => run('6to5:*'), 21 | 'build:start': () => run(['build:client', 'start']), 22 | 'build:start:dev': () => run(['build:client:dev', 'start:dev']), 23 | 'build:client': () => run('6to5:client'), 24 | 'build:client:dev': () => run('6to5:client:dev'), 25 | 'watch:lint': async () => `nodemon -w client -w server -w webpack.config.js -x ${await run('lint')}`, 26 | 'report': () => 'c8 report --reporter=lcov', 27 | 28 | 'coverage': async () => [`c8 ${await cutEnv('test')}`, { 29 | SUPERTAPE_TIMEOUT, 30 | }], 31 | 32 | 'test': () => [`tape 'test/**/*.js'`, { 33 | SUPERTAPE_TIMEOUT, 34 | }], 35 | }; 36 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .* 2 | 3 | webpack.config.js 4 | client 5 | test 6 | yarn-error.log 7 | coverage 8 | 9 | img 10 | 11 | *.swp 12 | 13 | *.config.* 14 | -------------------------------------------------------------------------------- /.nycrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "check-coverage": true, 3 | "all": true, 4 | "exclude": [ 5 | "bin", 6 | "coverage", 7 | "*.js", 8 | "dist**", 9 | "**/*.spec.js", 10 | "**/fixture", 11 | "test", 12 | ".*.{js,mjs}", 13 | "**/*.config.*" 14 | ], 15 | "branches": 100, 16 | "lines": 100, 17 | "functions": 100, 18 | "statements": 100 19 | } 20 | -------------------------------------------------------------------------------- /ChangeLog: -------------------------------------------------------------------------------- 1 | 2024.03.18, v8.1.2 2 | 3 | fix: 4 | - c630120 gritty: get back node-pty 5 | 6 | 2024.03.16, v8.1.1 7 | 8 | fix: 9 | - 92d7298 gritty: drop node-pty 10 | 11 | 2024.03.16, v8.1.0 12 | 13 | feature: 14 | - 72e34e0 gritty: serve-once v3.0.0 15 | 16 | 2024.03.12, v8.0.0 17 | 18 | feature: 19 | - f1b8576 gritty: drop support of node < 18 20 | - 6c1356c gritty: madrun v10.0.1 21 | - 0b9fb47 gritty: css-minimizer-webpack-plugin v6.0.0 22 | - 7475087 gritty: supertape v10.4.0 23 | - 3d8ca38 gritty: eslint-plugin-putout v22.4.1 24 | - 5b36dc7 gritty: putout v35.7.3 25 | - edddf41 gritty: xterm-addon-webgl v0.16.0 26 | - 4d813b6 gritty: xterm-addon-fit v0.8.0 27 | - 8b8aef7 gritty: c8 v9.1.0 28 | 29 | 2023.08.07, v7.2.0 30 | 31 | feature: 32 | - 3990464 package: css-minimizer-webpack-plugin v5.0.1 33 | - 6e4af5c package: eslint-plugin-n v16.0.1 34 | - e73b2d9 package: nodemon v3.0.1 35 | - 9802f3a package: webpack-cli v5.1.4 36 | - fe2b204 package: babel-loader v9.1.3 37 | - 675b292 package: c8 v8.0.1 38 | - 5153c28 package: xterm-addon-webgl v0.15.0 39 | - 7301a7d package: xterm-addon-fit v0.7.0 40 | - 6dfbb61 package: eslint-plugin-putout v19.0.3 41 | - ef0d9e6 package: putout v31.0.3 42 | - 9a3e5fd package: node-pty v1.0.0 43 | 44 | 2022.09.19, v7.1.0 45 | 46 | feature: 47 | - package: xterm-addon-webgl v0.13.0 48 | - package: xterm-addon-fit v0.6.0 49 | - package: supertape v8.1.0 50 | - package: xterm v5.0.0 51 | 52 | 2022.07.23, v7.0.0 53 | 54 | feature: 55 | - package: css-minimizer-webpack-plugin v4.0.0 56 | - (gritty) drop support of node < 16 57 | - (package) madrun v9.0.6 58 | - (package) eslint-plugin-putout v16.0.0 59 | - (package) putout v27.0.1 60 | - (package) supertape v7.6.0 61 | - (package) xterm-addon-webgl v0.12.0 62 | - (package) @iocmd/wait v2.1.0 63 | - (package) yargs-parser v21.0.1 64 | 65 | 2021.11.02, v6.1.0 66 | 67 | feature: 68 | - (package) eslint-plugin-putout v11.0.0 69 | - (package) clean-css-loader v4.1.1 70 | - (package) optimize-css-assets-webpack-plugin v6.0.1 71 | - (package) xterm v4.14.1 72 | - (package) supertape v6.10.0 73 | - (package) putout v21.1.0 74 | 75 | 76 | 2021.08.15, v6.0.6 77 | 78 | feature: 79 | - (package) es6-promisify v7.0.0 80 | 81 | 82 | 83 | 2021.08.15, v6.0.5 84 | 85 | feature: 86 | - (package) eslint v8.0.0-beta.0 87 | - (package) eslint-plugin-putout v9.0.1 88 | - (package) css-loader v6.2.0 89 | - (package) css-minimizer-webpack-plugin v3.0.2 90 | - (package) style-loader v3.2.1 91 | 92 | 93 | 94 | 2021.06.12, v6.0.4 95 | 96 | feature: 97 | - (package) xterm-addon-webgl v0.11.1 98 | - (package) putout v18.0.2 99 | - (package) xterm v4.13.0 100 | - (package) es6-promisify v7.0.0 101 | - (gritty) optimize-css-assets-webpack-plugin -> css-minimizer-webpack-plugin 102 | - (package) putout v16.10.1 103 | 104 | 105 | 2021.03.16, v6.0.3 106 | 107 | feature: 108 | - (package) socket.io-client v4.0.0 109 | - (package) socket.io v4.0.0 110 | - (package) supertape v5.1.0 111 | - (package) putout v15.7.2 112 | - (package) xerm v4.11.0 113 | - (package) xterm-addon-webgl v0.10.0 114 | 115 | 116 | 2021.02.04, v6.0.2 117 | 118 | fix: 119 | - (gritty) client: throw when minimized 120 | 121 | 122 | 2021.02.04, v6.0.1 123 | 124 | feature: 125 | - (package) node-pty v0.10.0 126 | - (package) xterm v4.10.0 127 | - (package) xterm-addon-fit v0.5.0 128 | - (package) clean-css-loader v3.0.0 129 | - (package) eslint-plugin-putout v7.0.0 130 | - (package) putout v14.0.0 131 | - (package) putout v13.7.0 132 | - (package) madrun v8.6.0 133 | - (package) supertape v4.7.0 134 | 135 | 136 | 2020.11.16, v6.0.0 137 | 138 | feature: 139 | - (gritty) client: dist -> destructuring 140 | - (gritty) drop support of socket.request.env 141 | - (package) socket.io-client v3.0.1 142 | - (package) socket.io v3.0.1 143 | - (package) eslint-plugin-putout v6.0.1 144 | - (package) putout v11.0.4 145 | - (webpack) v5 146 | - (package) webpack v5.1.3 147 | - (package) css-loader v5.0.0 148 | - (package) webpack-cli v4.0.0 149 | - (package) style-loader v2.0.0 150 | - (package) putout v10.0.3 151 | 152 | 153 | 2020.09.11, v5.0.0 154 | 155 | feature: 156 | - (gritty) drop support of node < 12 157 | - (package) yargs-parser v20.0.0 158 | 159 | 160 | 2020.09.09, v4.8.16 161 | 162 | feature: 163 | - (package) xterm-addon-webgl v0.9.0 164 | - (package) xterm v4.9.0 165 | 166 | 167 | 2020.08.13, v4.8.15 168 | 169 | feature: 170 | - (package) css-loader v4.2.1 171 | - (package) yargs-parser v19.0.1 172 | 173 | 174 | 2020.07.23, v4.8.14 175 | 176 | feature: 177 | - (package) xterm v4.8.1 178 | - (package) putout v9.0.0 179 | - (package) madrun v7.0.0 180 | - (package) eslint-plugin-putout v5.0.0 181 | 182 | 183 | 2020.06.20, v4.8.13 184 | 185 | feature: 186 | - (package) xterm v4.7.0 187 | - (package) xterm-addon-webgl v0.8.0 188 | 189 | 190 | 2020.05.31, v4.8.12 191 | 192 | feature: 193 | - (package) xterm-addon-webgl v0.7.0 194 | - (package) xterm-addon-fit v0.4.0 195 | - (package) xterm v4.6.0 196 | - (package) eslint v7.0.0 197 | - (package) @cloudcmd/stub v3.0.0 198 | - (package) supertape v2.0.1 199 | - (package) madrun v6.0.0 200 | - (package) putout v8.0.2 201 | - (package) eslint-plugin-putout v4.0.1 202 | 203 | 204 | 2020.04.14, v4.8.11 205 | 206 | feature: 207 | - (gritty) add webgl back 208 | - (package) xterm v4.5.0 209 | 210 | 211 | 2020.03.24, v4.8.10 212 | 213 | fix: 214 | - (gritty) webgl (#10) 215 | 216 | 217 | 2020.03.15, v4.8.9 218 | 219 | feature: 220 | - (package) xterm-addon-webgl v0.5.1 221 | - (package) yargs-parser v18.1.0 222 | - (package) serve-once v2.0.0 223 | 224 | 225 | 2020.02.17, v4.8.8 226 | 227 | feature: 228 | - (package) yargs-parser v17.0.0 229 | 230 | 231 | 2020.02.05, v4.8.7 232 | 233 | feature: 234 | - (package) xterm v4.4.0 235 | - (package) xterm-addon-webgl v0.5.0 236 | 237 | 238 | 2019.12.30, v4.8.6 239 | 240 | feature: 241 | - (package) xterm v4.3.0 (https://github.com/xtermjs/xterm.js/releases/tag/4.3.0) 242 | - (package) eslint-plugin-node v11.0.0 243 | - (package) nyc v15.0.0 244 | - (package) nodemon v2.0.1 245 | - (package) madrun v5.0.0 246 | - (package) putout v7.0.2 247 | - (package) eslint-plugin-putout v3.0.0 248 | 249 | 250 | 2019.10.27, v4.8.5 251 | 252 | feature: 253 | - (package) madrun v4.1.1 254 | - (package) xterm-addon-fit v0.3.0 255 | - (package) xterm v4.2.0 256 | - (package) yargs-parser v16.0.0 257 | 258 | 259 | 2019.10.16, v4.8.4 260 | 261 | feature: 262 | - (package) xterm v4.1.0 263 | - (package) yargs-parser v15.0.0 264 | 265 | 266 | 2019.09.25, v4.8.3 267 | 268 | feature: 269 | - (package) xterm v4.0.2 270 | 271 | 272 | 2019.09.19, v4.8.2 273 | 274 | feature: 275 | - (package) xterm v4.0.1 276 | - (package) putout v6.1.0 277 | - (package) currify v4.0.0 278 | 279 | 280 | 2019.09.09, v4.8.1 281 | 282 | feature: 283 | - (package) wraptile v3.0.0 284 | - (package) yargs-parser v14.0.0 285 | - (package) eslint-plugin-node v10.0.0 286 | 287 | 288 | 2019.09.04, v4.8.0 289 | 290 | feature: 291 | - (babelrc) add browserlist 292 | - (package) madrun v3.0.1 293 | - (package) node-pty v0.9.0-beta24 294 | - (package) eslint-plugin-putout v2.0.0 295 | - (package) putout v5.7.1 296 | - (package) style-loader v1.0.0 297 | 298 | 299 | 2019.07.11, v4.7.4 300 | 301 | feature: 302 | - (package) xterm v3.14.5 303 | 304 | 305 | 2019.07.01, v4.7.3 306 | 307 | feature: 308 | - (package) xterm v3.14.4 309 | - (package) css-loader v3.0.0 310 | - (package) eslint v6.0.1 311 | 312 | 313 | 2019.06.06, v4.7.2 314 | 315 | feature: 316 | - (package) xterm v3.14.2 317 | 318 | 319 | 2019.06.03, v4.7.1 320 | 321 | feature: 322 | - (package) xterm v3.14.1 323 | 324 | 325 | 2019.05.31, v4.7.0 326 | 327 | feature: 328 | - (gritty) add support of cwd 329 | 330 | 331 | 2019.05.27, v4.6.0 332 | 333 | feature: 334 | - (gritty) add ability to emit exit code 335 | - (gritty) add support of node v12 336 | 337 | 338 | 2019.05.27, v4.5.0 339 | 340 | feature: 341 | - (gritty) add support of quotes in command arguments 342 | 343 | 344 | 2019.05.22, v4.4.2 345 | 346 | feature: 347 | - (package) xterm v3.13.2 348 | 349 | 350 | 2019.05.17, v4.4.1 351 | 352 | feature: 353 | - (package) xterm v3.13.1 354 | 355 | 356 | 2019.05.10, v4.4.0 357 | 358 | feature: 359 | - (package) eslint-plugin-node v9.0.1 360 | - (package) clean-css-loader v2.0.0 361 | - (gritty) options: add support of command, autoRestart 362 | - (package) nyc v14.0.0 363 | 364 | 365 | 2019.04.16, v4.3.10 366 | 367 | fix: 368 | - (style) .terminal: height 369 | 370 | feature: 371 | - (package) xterm v3.12.2 372 | 373 | 374 | 2019.03.11, v4.3.9 375 | 376 | feature: 377 | - (package) xterm v3.12.0 378 | - (package) putout v4.0.0 379 | - (package) madrun v2.0.0 380 | 381 | 382 | 2019.02.12, v4.3.8 383 | 384 | feature: 385 | - (package) xterm v3.11.0 386 | - (package) yargs-parser v13.0.0 387 | - (package) add putout 388 | - (package) add @putout/eslint-config 389 | - (package) tape -> supertape 390 | 391 | 392 | 2019.01.10, v4.3.7 393 | 394 | feature: 395 | - (package) xterm v3.10.1 396 | 397 | 398 | 2018.12.25, v4.3.6 399 | 400 | feature: 401 | - (package) node-pty v0.8.0 402 | 403 | 404 | 2018.12.21, v4.3.5 405 | 406 | fix: 407 | - (gritty) --path 408 | 409 | 410 | 2018.12.20, v4.3.4 411 | 412 | feature: 413 | - (package) xterm v3.9.1 414 | - (package) css-loader v2.0.1 415 | - (gritty) sinon, sinon-called-with-diff -> @cloudcmd/stub 416 | 417 | 418 | 2018.11.06, v4.3.3 419 | 420 | feature: 421 | - (gritty) express -> router 422 | - (package) sinon-called-with-diff v3.0.0 423 | - (package) eslint-plugin-node v8.0.0 424 | - (package) sinon v7.0.0 425 | 426 | 427 | 2018.10.09, v4.3.2 428 | 429 | feature: 430 | - (package) currify v3.0.0 431 | 432 | 433 | 2018.10.08, v4.3.1 434 | 435 | feature: 436 | - (package) xterm v3.8.0 437 | - (package) yargs-parser v11.0.0 438 | 439 | 440 | 2018.09.28, v4.3.0 441 | 442 | feature: 443 | - (gritty) add --no-auto-restart 444 | 445 | 446 | 2018.09.28, v4.2.0 447 | 448 | feature: 449 | - (gritty) add --auto-restart 450 | - (package) redrun v7.0.0 451 | 452 | 453 | 2018.09.27, v4.1.0 454 | 455 | feature: 456 | - (gritty) add support of --command 457 | 458 | 459 | 2018.09.27, v4.0.0 460 | 461 | feature: 462 | - (package) debug v4.0.1 463 | - (package) drop support of node < 8 464 | 465 | 466 | 2018.09.08, v3.0.3 467 | 468 | feature: 469 | - (package) babel v7.0.0 470 | - (package) xterm v3.7.0 471 | - (package) babel-loader v8.0.2 472 | - (package) nyc v13.0.1 473 | - (package) style-loader v0.23.0 474 | 475 | 476 | 2018.08.25, v3.0.2 477 | 478 | feature: 479 | - (package) xterm v3.6.0 480 | - (package) style-loader v0.22.0 481 | 482 | 483 | 2018.07.23, v3.0.1 484 | 485 | feature: 486 | - (package) debug v3.1.0 487 | - (package) eslint-plugin-node v7.0.1 488 | 489 | 490 | 2018.07.16, v3.0.0 491 | 492 | feature: 493 | - (package) add eslint-plugin-node 494 | - (package) drop support of node < 6 495 | - (gritty) drop support of authCheck and cloudcmd <= v9.0.0 496 | - (gritty) rm fetch, Promise polyfill: provide your own polyfill if you needed 497 | - (package) optimize-css-assets-webpack-plugin v5.0.0 498 | 499 | 500 | 2018.07.13, v2.2.4 501 | 502 | feature: 503 | - (npmignore) add .* 504 | 505 | 506 | 2018.07.13, v2.2.3 507 | 508 | feature: 509 | - (package) xterm v3.5.1 510 | - (package) css-loader v1.0.0 511 | - (package) eslint v5.0.0 512 | - (package) sinon v6.0.0 513 | - (package) nyc v12.0.2 514 | - (package) webpack-cli v3.0.1 515 | 516 | 517 | 2018.05.30, v2.2.2 518 | 519 | feature: 520 | - (gritty) node-pty-prebuilt -> node-pty 521 | 522 | 523 | 2018.05.29, v2.2.1 524 | 525 | feature: 526 | - (package) promise-polyfill v8.0.0 527 | 528 | 529 | 2018.05.22, v2.2.0 530 | 531 | feature: 532 | - (gritty) add support of fontFamily 533 | 534 | 535 | 2018.05.22, v2.1.2 536 | 537 | feature: 538 | - (package) xterm v3.4.1: improve start up and overall performance of a terminal 539 | 540 | 541 | 2018.05.03, v2.1.1 542 | 543 | feature: 544 | - (package) wraptile v2.0.0 545 | - (package) clean-css-loader v1.0.1 546 | - (package) sinon v5.0.1 547 | - (package) style-loader v0.21.0 548 | 549 | 550 | 2018.04.19, v2.1.0 551 | 552 | feature: 553 | - (gritty) rm redundant .terminal 554 | - (index) rm callback 555 | - (gritty) timeout -> accept 556 | 557 | 558 | 2018.04.18, v2.0.1 559 | 560 | feature: 561 | - (package) xterm v3.3.0 562 | 563 | 564 | 2018.03.30, v2.0.0 565 | 566 | feature: 567 | - (gritty) add auth 568 | - (gritty) drop support of node < 4 569 | 570 | 571 | 2018.03.12, v1.5.2 572 | 573 | feature: 574 | - (package) xterm v3.2.0 575 | - (package) redrun v6.0.0 576 | 577 | 578 | 2018.03.01, v1.5.1 579 | 580 | feature: 581 | - (package) webpack v4.0.1 582 | 583 | 584 | 2018.02.14, v1.5.0 585 | 586 | feature: 587 | - (package) sinon-called-with-diff v2.0.0 588 | - (gritty) add ability to set ENV with help of socket.request.env #2 589 | 590 | 591 | 2018.02.12, v1.4.29 592 | 593 | feature: 594 | - (package) xterm v3.1.0 595 | 596 | 597 | 2018.01.31, v1.4.28 598 | 599 | feature: 600 | - (package) es6-promisify v6.0.0 601 | - (travis) node_js: 8, 9 602 | - (package) style-loader v0.20.1 603 | 604 | 605 | 2018.01.19, v1.4.27 606 | 607 | feature: 608 | - (package) xterm v3.0.2 609 | 610 | 611 | 2018.01.16, v1.4.26 612 | 613 | feature: 614 | - (package) node-pty -> node-pty-prebuilt: speed up install 615 | 616 | 617 | 2018.01.15, v1.4.25 618 | 619 | feature: 620 | - (package) xterm v3.0.1 621 | - (package) mock-require v3.0.1 622 | - (package) promise-polyfill v7.0.0 623 | 624 | 625 | 2017.12.21, v1.4.24 626 | 627 | feature: 628 | - (package) promise-polyfill v6.1.0 629 | - (package) style-loader v0.19.0 630 | - (package) coveralls v3.0.0 631 | - (package) sinon v4.0.0 632 | - (package) babel-preset-es2015 -> babel-preset-env 633 | 634 | 635 | 2017.08.28, v1.4.23 636 | 637 | feature: 638 | - (package) node-pty v0.7.0 639 | 640 | 641 | 2017.08.14, v1.4.22 642 | 643 | feature: 644 | - (package) xterm v2.9.2 645 | - (package) debug v3.0.0 646 | 647 | 648 | 2017.08.07, v1.4.21 649 | 650 | feature: 651 | - (package) xterm v2.9.1 652 | 653 | 654 | 2017.08.04, v1.4.20 655 | 656 | feature: 657 | - (package) sinon v3.0.0 658 | - (package) xterm v2.9.0 659 | 660 | 661 | 2017.07.17, v1.4.19 662 | 663 | fix: 664 | - (package) can work on engines lower then 4 via legacy suffix 665 | 666 | 667 | 2017.07.12, v1.4.18 668 | 669 | fix: 670 | - (package) rm duplicate wraptile 671 | 672 | feature: 673 | - (package) xterm v2.8.1 674 | - (package) clean-css-loader v0.1.2 675 | - (package) webpack v3.0.0 676 | - (package) eslint v4.0.0 677 | - (package) eslint v4.0.0 678 | 679 | 680 | 2017.06.08, v1.4.17 681 | 682 | feature: 683 | - (package) xterm v2.7.0 684 | - (gitignore) add package-lock.json 685 | - (package) nyc v11.0.2 686 | 687 | 688 | 2017.05.22, v1.4.16 689 | 690 | feature: 691 | - (package) clean-css-loader v0.0.6 692 | - (package) style-loader v0.18.0 693 | - (cursor-blink) rm unused 694 | 695 | 696 | 2017.05.20, v1.4.15 697 | 698 | fix: 699 | - (gritty) crash on exit 700 | - (package) add request 701 | - (package) watcher: add client, server 702 | 703 | 704 | 2017.05.12, v1.4.14 705 | 706 | fix: 707 | - (package) wraptile 708 | 709 | 710 | 2017.05.12, v1.4.13 711 | 712 | fix: 713 | - (gritty) add support of node v4 714 | 715 | 716 | 2017.05.10, v1.4.12 717 | 718 | fix: 719 | - (client) socket.io.min -> socket.io 720 | 721 | 722 | 2017.05.10, v1.4.11 723 | 724 | feature: 725 | - (package) socket.io v2.0.1 726 | - (package) socket.io-client v2.0.1 727 | - (package) style-loader v0.17.0 728 | 729 | 730 | 2017.05.08, v1.4.10 731 | 732 | feature: 733 | - (package) xterm v2.6.0 734 | 735 | 736 | 2017.04.26, v1.4.9 737 | 738 | fix: 739 | - (gritty) cursorBlink: insane: disable 740 | 741 | 742 | 2017.04.25, v1.4.8 743 | 744 | fix: 745 | - (webpack) libraryTarget: umd -> var 746 | 747 | feature: 748 | - (package) babel-loader v7.0.0 749 | 750 | 751 | 2017.04.13, v1.4.7 752 | 753 | feature: 754 | - (package) xterm v2.5.0 755 | 756 | 757 | 2017.04.13, v1.4.6 758 | 759 | fix: 760 | - (gritty) heigth 761 | 762 | 763 | 2017.04.12, v1.4.5 764 | 765 | feature: 766 | - (gritty) server/index.js -> server/gritty.js 767 | - (package) clean-css-loader v0.0.5 768 | - (package) add sinon-called-with-diff 769 | 770 | 771 | 2017.04.06, v1.4.4 772 | 773 | feature: 774 | - (gritty) wrap -> wraptile 775 | 776 | 777 | 2017.04.06, v1.4.3 778 | 779 | fix: 780 | - (server) socket connect when no authCheck 781 | 782 | feature: 783 | - (travis) add before_install 784 | - (travis) npm run build:client 785 | - (get-env) add 786 | - (package) add coveralls 787 | - (webpack) output: add pathinfo 788 | - (webpack) devtoolModuleFilenameTemplate: webpack:// -> gritty 789 | 790 | 791 | 2017.04.03, v1.4.2 792 | 793 | feature: 794 | - (package) scripts: build:client(:dev)? 795 | - (cursor-blink) add 796 | 797 | 798 | 2017.04.03, v1.4.1 799 | 800 | fix: 801 | - (gritty) cursorBlink: enable on connect, disable on disconnect 802 | 803 | 804 | 2017.03.31, v1.4.0 805 | 806 | feature: 807 | - (gritty) add ability to reconnect 808 | - (css) improved font 809 | 810 | 811 | 2017.03.30, v1.3.1 812 | 813 | feature: 814 | - (package) xterm v2.4.0 815 | - (package) css-loader v0.28.0 816 | - (package) style-loader v0.16.0 817 | - (package) style-loader v0.15.0 818 | - (package) css-loader v0.27.3 819 | - (package) style-loader v0.14.1 820 | 821 | 822 | 2017.03.04, v1.3.0 823 | 824 | feature: 825 | - (gritty) add --port, --path 826 | 827 | 828 | 2017.03.03, v1.2.1 829 | 830 | fix: 831 | - (gritty) resize: on windows 832 | - (gritty) --v -> --version 833 | 834 | 835 | 2017.03.03, v1.2.0 836 | 837 | feature: 838 | - (gritty) add --module-path 839 | 840 | 841 | 2017.03.03, v1.1.2 842 | 843 | fix: 844 | - (gritty) return {socket, terminal} 845 | 846 | 847 | 2017.03.03, v1.1.1 848 | 849 | fix: 850 | - (gritty) return socket 851 | 852 | 853 | 2017.03.03, v1.1.0 854 | 855 | feature: 856 | - (gritty) add ability to use as middleware 857 | 858 | 859 | 2017.03.02, v1.0.5 860 | 861 | fix: 862 | - (index) Console -> Gritty 863 | 864 | 865 | 2017.03.02, v1.0.4 866 | 867 | fix: 868 | - (style) html: height: 99% 869 | - (gritty) pid -> Pid 870 | 871 | 872 | 2017.03.02, v1.0.3 873 | 874 | fix: 875 | - (gritty) kill: ESRCH: wrong pid 876 | 877 | 878 | 2017.03.02, v1.0.2 879 | 880 | feature: 881 | - (package) xterm: devDependencies 882 | - (package) rm rendy 883 | - (package) rm join-io 884 | 885 | 886 | 2017.03.02, v1.0.1 887 | 888 | fix: 889 | - (package) console -> gritty 890 | 891 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) coderaiser 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. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Gritty [![License][LicenseIMGURL]][LicenseURL] [![NPM version][NPMIMGURL]][NPMURL] [![Build Status][BuildStatusIMGURL]][BuildStatusURL] [![Coverage Status][CoverageIMGURL]][CoverageURL] 2 | 3 | [NPMIMGURL]: https://img.shields.io/npm/v/gritty.svg?style=flat&longCache=true 4 | [BuildStatusURL]: https://github.com/cloudcmd/gritty/actions?query=workflow%3A%22Node+CI%22 "Build Status" 5 | [BuildStatusIMGURL]: https://github.com/cloudcmd/gritty/workflows/Node%20CI/badge.svg 6 | [LicenseIMGURL]: https://img.shields.io/badge/license-MIT-317BF9.svg?style=flat&longCache=true 7 | [NPM_INFO_IMG]: https://nodei.co/npm/cloudcmd.png 8 | [NPMURL]: https://npmjs.org/package/cloudcmd "npm" 9 | [BuildStatusURL]: https://travis-ci.org/cloudcmd/gritty "Build Status" 10 | [LicenseURL]: https://tldrlegal.com/license/mit-license "MIT License" 11 | [CoverageURL]: https://coveralls.io/github/cloudcmd/gritty?branch=master 12 | [CoverageIMGURL]: https://coveralls.io/repos/cloudcmd/gritty/badge.svg?branch=master&service=github 13 | 14 | Web terminal emulator. Based on [node-pty](https://github.com/Tyriar/node-pty) and [xterm.js](https://github.com/sourcelair/xterm.js). 15 | 16 |  17 | 18 | ## Install 19 | 20 | `npm i gritty -g` 21 | 22 | ## Usage 23 | 24 | ``` 25 | Usage: gritty [options] 26 | Options: 27 | -h, --help display this help and exit 28 | -v, --version output version information and exit 29 | --path output path of a gritty and exit 30 | --port set port number 31 | --command command to run in terminal (shell by default) 32 | --auto-restart restart command when on exit 33 | --no-auto-restart do not restart command on exit 34 | ``` 35 | 36 | ### Windows 37 | 38 | On `Windows` there is no build tools by default. When can't install `gritty` try to install `windows-build-tools` first. 39 | 40 | ```sh 41 | npm i windows-build-tools -g 42 | npm i gritty -g 43 | ``` 44 | 45 |  46 | 47 | ## Use as standalone 48 | 49 | Start `gritty`, and go to url `http://localhost:1337` 50 | 51 | ## API 52 | 53 | ### Client API 54 | 55 | #### gritty(element [, options]) 56 | 57 | ```js 58 | const prefix = '/gritty'; 59 | const env = {}; // default 60 | const fontFamily = 'Courier'; 61 | 62 | gritty('body', { 63 | prefix, 64 | env, 65 | fontFamily, 66 | }); 67 | ``` 68 | 69 | ### Server API 70 | 71 | #### gritty.listen(socket, [, options]) 72 | 73 | `Gritty` could be used as middleware: 74 | 75 | ```js 76 | const prefix = '/gritty'; 77 | 78 | const auth = (accept, reject) => (username, password) => { 79 | accept(); 80 | }; 81 | 82 | gritty.listen(socket, { 83 | prefix, 84 | auth, // optional 85 | }); 86 | ``` 87 | 88 | #### gritty(options) 89 | 90 | Middleware function: 91 | 92 | ```js 93 | const prefix = '/gritty'; 94 | 95 | gritty({ 96 | prefix, 97 | }); 98 | ``` 99 | 100 | ## Usage as middleware 101 | 102 | To use `gritty` in your programs you should make local install: 103 | 104 | `npm i gritty socket.io express --save` 105 | 106 | And use it this way: 107 | 108 | ```js 109 | // server.js 110 | const http = require('node:http'); 111 | const gritty = require('gritty'); 112 | 113 | const express = require('express'); 114 | const io = require('socket.io'); 115 | 116 | const app = express(); 117 | const server = http.createServer(app); 118 | const socket = io.listen(server); 119 | 120 | const port = 1337; 121 | const ip = '0.0.0.0'; 122 | 123 | app.use(gritty()); 124 | app.use(express.static(__dirname)); 125 | 126 | gritty.listen(socket, { 127 | command: 'mc', // optional 128 | autoRestart: true, // default 129 | }); 130 | 131 | server.listen(port, ip); 132 | ``` 133 | 134 | ```html 135 | 136 | 137 |
138 | 139 | 157 | ``` 158 | 159 | ## License 160 | 161 | MIT 162 | -------------------------------------------------------------------------------- /bin/gritty.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | 'use strict'; 4 | 5 | const {join} = require('node:path'); 6 | const process = require('node:process'); 7 | const args = require('yargs-parser')(process.argv.slice(2), { 8 | boolean: [ 9 | 'version', 10 | 'help', 11 | 'auto-restart', 12 | 'path', 13 | ], 14 | number: ['port'], 15 | string: ['command'], 16 | alias: { 17 | help: 'h', 18 | version: 'v', 19 | }, 20 | default: { 21 | 'port': process.env.PORT | 1337, 22 | 'auto-restart': true, 23 | }, 24 | }); 25 | 26 | const getMessage = (a) => a.message; 27 | 28 | main(args); 29 | 30 | function main(args) { 31 | if (args.help) 32 | return help(); 33 | 34 | if (args.version) 35 | return version(); 36 | 37 | if (args.path) 38 | return path(); 39 | 40 | start({ 41 | port: args.port, 42 | command: args.command, 43 | autoRestart: args.autoRestart, 44 | }); 45 | } 46 | 47 | function path() { 48 | console.log(join(__dirname, '..')); 49 | } 50 | 51 | function start(options) { 52 | const squad = require('squad'); 53 | 54 | const { 55 | port, 56 | command, 57 | autoRestart, 58 | } = options; 59 | 60 | check(port); 61 | 62 | const DIR = `${__dirname}/../`; 63 | 64 | const gritty = require('../'); 65 | const http = require('node:http'); 66 | 67 | const express = require('express'); 68 | const io = require('socket.io'); 69 | 70 | const app = express(); 71 | const server = http.createServer(app); 72 | 73 | const c9 = process.env.IP; 74 | const ip = c9 || '0.0.0.0'; 75 | 76 | app 77 | .use(gritty()) 78 | .use(express.static(DIR)); 79 | 80 | const socket = io(server); 81 | 82 | gritty.listen(socket, { 83 | command, 84 | autoRestart, 85 | }); 86 | 87 | server 88 | .listen(port, ip) 89 | .on('error', squad(exit, getMessage)); 90 | 91 | console.log(`url: http://localhost:${port}`); 92 | } 93 | 94 | function help() { 95 | const bin = require('../help'); 96 | const usage = 'Usage: gritty [options]'; 97 | 98 | console.log(usage); 99 | console.log('Options:'); 100 | 101 | for (const name of Object.keys(bin)) { 102 | console.log(' %s %s', name, bin[name]); 103 | } 104 | } 105 | 106 | function version() { 107 | const pack = require('../package'); 108 | console.log('v' + pack.version); 109 | } 110 | 111 | function check(port) { 112 | if (isNaN(port)) 113 | exit('port should be a number 0..65535'); 114 | } 115 | 116 | function exit(msg) { 117 | console.error(msg); 118 | process.exit(-1); 119 | } 120 | -------------------------------------------------------------------------------- /client/get-el.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const isString = (a) => typeof a === 'string'; 4 | 5 | module.exports = (el) => { 6 | if (isString(el)) 7 | return document.querySelector(el); 8 | 9 | return el; 10 | }; 11 | -------------------------------------------------------------------------------- /client/get-env.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const isFn = (a) => typeof a === 'function'; 4 | 5 | module.exports = (env) => { 6 | const obj = {}; 7 | 8 | for (const name of Object.keys(env)) { 9 | obj[name] = getValue(env[name]); 10 | } 11 | 12 | return obj; 13 | }; 14 | 15 | function getValue(value) { 16 | if (isFn(value)) 17 | return value(); 18 | 19 | return value; 20 | } 21 | -------------------------------------------------------------------------------- /client/get-host.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = () => { 4 | const l = location; 5 | 6 | return l.origin || l.protocol + '//' + l.host; 7 | }; 8 | -------------------------------------------------------------------------------- /client/gritty.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | require('@xterm/xterm/css/xterm.css'); 4 | 5 | const {FitAddon} = require('@xterm/addon-fit'); 6 | const {WebglAddon} = require('@xterm/addon-webgl'); 7 | const currify = require('currify'); 8 | const tryCatch = require('try-catch'); 9 | 10 | const wrap = require('wraptile'); 11 | 12 | const {io} = require('socket.io-client'); 13 | const {Terminal} = require('@xterm/xterm'); 14 | 15 | const getEl = require('./get-el'); 16 | const getHost = require('./get-host'); 17 | const getEnv = require('./get-env'); 18 | 19 | const onWindowResize = wrap(_onWindowResize); 20 | const onTermData = currify(_onTermData); 21 | const onTermResize = currify(_onTermResize); 22 | const onData = currify(_onData); 23 | 24 | const onDisconnect = wrap(_onDisconnect); 25 | 26 | const onConnect = wrap(_onConnect); 27 | 28 | module.exports = gritty; 29 | module.exports._onConnect = _onConnect; 30 | module.exports._onDisconnect = _onDisconnect; 31 | module.exports._onData = _onData; 32 | module.exports._onTermResize = _onTermResize; 33 | module.exports._onTermData = _onTermData; 34 | module.exports._onWindowResize = _onWindowResize; 35 | 36 | const defaultFontFamily = 'Menlo, Consolas, "Liberation Mono", Monaco, "Lucida Console", monospace'; 37 | 38 | module.exports._defaultFontFamily = defaultFontFamily; 39 | 40 | function gritty(element, options = {}) { 41 | const el = getEl(element); 42 | 43 | const { 44 | socketPath = '', 45 | fontFamily = defaultFontFamily, 46 | prefix = '/gritty', 47 | command, 48 | autoRestart, 49 | cwd, 50 | } = options; 51 | 52 | const env = getEnv(options.env || {}); 53 | const socket = connect(prefix, socketPath); 54 | 55 | return createTerminal(el, { 56 | env, 57 | cwd, 58 | command, 59 | autoRestart, 60 | socket, 61 | fontFamily, 62 | }); 63 | } 64 | 65 | function createTerminal(terminalContainer, {env, cwd, command, autoRestart, socket, fontFamily}) { 66 | const fitAddon = new FitAddon(); 67 | const webglAddon = new WebglAddon(); 68 | const terminal = new Terminal({ 69 | scrollback: 1000, 70 | tabStopWidth: 4, 71 | fontFamily, 72 | allowProposedApi: true, 73 | }); 74 | 75 | terminal.open(terminalContainer); 76 | terminal.focus(); 77 | 78 | terminal.loadAddon(webglAddon); 79 | terminal.loadAddon(fitAddon); 80 | fitAddon.fit(); 81 | 82 | terminal.onResize(onTermResize(socket)); 83 | terminal.onData(onTermData(socket)); 84 | 85 | window.addEventListener('resize', onWindowResize(fitAddon)); 86 | 87 | const {cols, rows} = terminal; 88 | 89 | socket.on('accept', onConnect(socket, fitAddon, { 90 | env, 91 | cwd, 92 | cols, 93 | rows, 94 | command, 95 | autoRestart, 96 | })); 97 | socket.on('disconnect', onDisconnect(terminal)); 98 | socket.on('data', onData(terminal)); 99 | 100 | return { 101 | socket, 102 | terminal, 103 | }; 104 | } 105 | 106 | function _onConnect(socket, fitAddon, {env, cwd, cols, rows, command, autoRestart}) { 107 | socket.emit('terminal', { 108 | env, 109 | cwd, 110 | cols, 111 | rows, 112 | command, 113 | autoRestart, 114 | }); 115 | socket.emit('resize', { 116 | cols, 117 | rows, 118 | }); 119 | fitAddon.fit(); 120 | } 121 | 122 | function _onDisconnect(terminal) { 123 | terminal.writeln('terminal disconnected...'); 124 | } 125 | 126 | function _onData(terminal, data) { 127 | terminal.write(data); 128 | } 129 | 130 | function _onTermResize(socket, {cols, rows}) { 131 | socket.emit('resize', { 132 | cols, 133 | rows, 134 | }); 135 | } 136 | 137 | function _onTermData(socket, data) { 138 | socket.emit('data', data); 139 | } 140 | 141 | function _onWindowResize(fitAddon) { 142 | // Uncaught Error: This API only accepts integers 143 | // when gritty mimized 144 | const fit = fitAddon.fit.bind(fitAddon); 145 | tryCatch(fit); 146 | } 147 | 148 | function connect(prefix, socketPath) { 149 | const href = getHost(); 150 | const FIVE_SECONDS = 5000; 151 | 152 | const path = `${socketPath}/socket.io`; 153 | const socket = io.connect(href + prefix, { 154 | 'max reconnection attempts': 2 ** 32, 155 | 'reconnection limit': FIVE_SECONDS, 156 | path, 157 | }); 158 | 159 | return socket; 160 | } 161 | -------------------------------------------------------------------------------- /css/style.css: -------------------------------------------------------------------------------- 1 | html { 2 | height: 100%; 3 | } 4 | 5 | body, 6 | .gritty { 7 | height: 100%; 8 | margin: 0; 9 | } 10 | 11 | .terminal { 12 | height: 100%; 13 | } 14 | -------------------------------------------------------------------------------- /help.json: -------------------------------------------------------------------------------- 1 | { 2 | "-h, --help ": "display this help and exit", 3 | "-v, --version ": "output version information and exit", 4 | "--path ": "output path of a gritty and exit", 5 | "--port ": "set port number", 6 | "--command ": "command to run (shell by default)", 7 | "--auto-restart ": "restart command on exit", 8 | "--no-auto-restart ": "do not restart command on exit" 9 | } 10 | -------------------------------------------------------------------------------- /img/linux.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudcmd/gritty/720e064fd7b748ac916b0f8b18366bbbcbb8ebc0/img/linux.png -------------------------------------------------------------------------------- /img/windows.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudcmd/gritty/720e064fd7b748ac916b0f8b18366bbbcbb8ebc0/img/windows.png -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |