typing.works 0.0.0-stage → 0.3.0-beta.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +16 -0
- package/README.md +82 -2
- package/bin/typing.works.js +18 -0
- package/install.ps1 +97 -0
- package/install.sh +97 -0
- package/package.json +15 -4
- package/vendor/darwin-arm64/typingworks +0 -0
- package/vendor/darwin-x64/typingworks +0 -0
- package/vendor/linux-arm64/typingworks +0 -0
- package/vendor/linux-ia32/typingworks +0 -0
- package/vendor/linux-x64/typingworks +0 -0
- package/vendor/win32-arm64/typingworks.exe +0 -0
- package/vendor/win32-x64/typingworks.exe +0 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
typing.works — terminal
|
|
2
|
+
Copyright © 2026 Perspective. All rights reserved.
|
|
3
|
+
|
|
4
|
+
이 소프트웨어(실행 파일과 함께 배포되는 파일)는 무료로 내려받아 개인적·비상업적으로 쓸 수 있습니다.
|
|
5
|
+
다음은 허락하지 않습니다: 수정, 재배포·재판매, 역설계·디컴파일·분해(관련 법이 명시적으로 허용하는 범위를 넘어서),
|
|
6
|
+
typing.works 서비스에 대한 자동화된 남용(랭크 기록 조작 등).
|
|
7
|
+
|
|
8
|
+
You may download and use this software free of charge for personal, non-commercial use.
|
|
9
|
+
You may not modify, redistribute or resell it, or reverse engineer, decompile or disassemble it
|
|
10
|
+
(except to the extent applicable law expressly permits), or use it to abuse the typing.works service.
|
|
11
|
+
|
|
12
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED. IN NO EVENT SHALL THE
|
|
13
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY ARISING FROM THE SOFTWARE
|
|
14
|
+
OR ITS USE.
|
|
15
|
+
|
|
16
|
+
typing.works 서비스 이용에는 typing.works 이용약관과 개인정보처리방침이 적용됩니다.
|
package/README.md
CHANGED
|
@@ -1,3 +1,83 @@
|
|
|
1
|
-
#
|
|
1
|
+
# typing.works — terminal (beta)
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
터미널에서 치는 [typing.works](https://typing.works). 한글·영문 타자 연습, 웹과 같은 판정, 로그인하면 기록·통계·랭크전까지.
|
|
4
|
+
Typing practice from [typing.works](https://typing.works), in your terminal — Korean & English, same scoring as the web, records, stats and ranked matches.
|
|
5
|
+
|
|
6
|
+
## 설치 · Install
|
|
7
|
+
|
|
8
|
+
macOS · Linux
|
|
9
|
+
|
|
10
|
+
```sh
|
|
11
|
+
curl -fsSL https://cdn.jsdelivr.net/npm/typing.works/install.sh | sh
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Windows 10 · 11 (PowerShell)
|
|
15
|
+
|
|
16
|
+
```powershell
|
|
17
|
+
irm https://cdn.jsdelivr.net/npm/typing.works/install.ps1 | iex
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
아무것도 미리 깔 필요가 없습니다. 실행 파일을 받아 해시를 대조하고 `~/.local/bin`(Windows 는 `%LOCALAPPDATA%\typingworks\bin`)에 둡니다 — 그다음 `typingworks`.
|
|
21
|
+
Nothing else needed. Downloads the binary, verifies its checksum, puts it on your PATH — then run `typingworks`.
|
|
22
|
+
|
|
23
|
+
다른 방법 · Other ways:
|
|
24
|
+
|
|
25
|
+
```sh
|
|
26
|
+
npx typing.works # Node 가 있으면, 설치 없이 바로 · run without installing
|
|
27
|
+
npm i -g typing.works # Node · install → `typingworks`
|
|
28
|
+
brew install pers-dev/tap/typing.works # Homebrew
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
macOS (Apple Silicon · Intel) · Linux (x64 · arm64 · 32-bit x86) · Windows 10 1809+ · 11 (x64 · arm64, Windows Terminal 권장).
|
|
32
|
+
통신(로그인 · 기록)에만 `curl` 을 씁니다(Windows 10+ 에 들어 있습니다). 인터넷 없이도 연습 · 판정 · 기록은 그대로 됩니다.
|
|
33
|
+
Works offline; `curl` is used only for sign-in, records and ranked (built into Windows 10+).
|
|
34
|
+
|
|
35
|
+
## 쓰는 법 · Keys
|
|
36
|
+
|
|
37
|
+
켜면 바로 단문을 칩니다. · It opens straight into typing.
|
|
38
|
+
|
|
39
|
+
| 키 | |
|
|
40
|
+
|---|---|
|
|
41
|
+
| Enter · Space | 문장 끝 · finish |
|
|
42
|
+
| Esc | 처음부터 · restart |
|
|
43
|
+
| ↑ ↓ | 다음·이전 문장 · next/prev |
|
|
44
|
+
| Tab | 한/영 — 입력기는 영문으로 두고 두벌식 자리 그대로 · Korean/English (keep your OS input in English) |
|
|
45
|
+
| ^S ^L ^P | 단문 · 장문 · 팬그램 · sentence · paragraph · pangram |
|
|
46
|
+
| ^E | 문장 언어 · language |
|
|
47
|
+
| ^Z | 문장 크게/보통(macOS 터미널 · xterm) · bigger text |
|
|
48
|
+
| ^R | 기록 · 통계 · records & stats |
|
|
49
|
+
| ^K | 랭크전 · ranked |
|
|
50
|
+
| ^O ^A ^G ^Q | 설정 · 계정 · 도움말 · 끝 · settings · account · help · quit |
|
|
51
|
+
|
|
52
|
+
계정은 typing.works 와 같습니다. 한글은 한글이 든 고정폭 글꼴(D2Coding · Sarasa Mono K 등)에서 가장 보기 좋습니다.
|
|
53
|
+
|
|
54
|
+
## 익명 사용 통계 · Anonymous usage stats
|
|
55
|
+
|
|
56
|
+
어떻게 쓰이는지 알려고 아주 적은 것만 보냅니다. · We send a small amount of anonymous data to learn how it's used.
|
|
57
|
+
|
|
58
|
+
- **보내는 것 · sent**: 켰다 · 묶음을 끝냈다(언어 · 갈래 · 문장 수 · 평균 타/분 · 정확도) · 랭크 판 결과 · 로그인했다 — 판 번호 · OS · 터미널 이름과 함께. 사람이 아니라 이 기기에서 만든 난수 ID로 셉니다.
|
|
59
|
+
- **보내지 않는 것 · never sent**: 친 글 · 문장 · 계정(이메일 · 닉네임).
|
|
60
|
+
- **끄기 · opt out**: 설정(^O) «익명 사용 통계» · `TW_NO_TELEMETRY=1` · `DO_NOT_TRACK=1` · `typingworks --no-telemetry`
|
|
61
|
+
- **무엇이 나가는지 보기 · see exactly what is sent**: `TW_TELEMETRY_LOG=~/tw-telemetry.log typingworks`
|
|
62
|
+
|
|
63
|
+
## 새 판 · Updates
|
|
64
|
+
|
|
65
|
+
켤 때(6시간에 한 번) npm 에 새 판이 있는지 보고, 있으면 오른쪽 위에 알립니다. **^U** 를 누르면 깐 방법대로 올리고 새 판으로 다시 켭니다.
|
|
66
|
+
Checks npm for a newer version (every 6 hours) and shows it top-right. Press **^U** to update the way you installed it and restart.
|
|
67
|
+
|
|
68
|
+
| 깐 방법 · installed with | ^U 가 돌리는 것 · runs |
|
|
69
|
+
|---|---|
|
|
70
|
+
| brew | `brew upgrade typing.works` |
|
|
71
|
+
| npm i -g | `npm i -g typing.works@latest` |
|
|
72
|
+
| npx | `npx typing.works@latest` |
|
|
73
|
+
| 설치 스크립트 · install script | 같은 스크립트를 다시 · reruns `install.sh` / `install.ps1` |
|
|
74
|
+
|
|
75
|
+
끄기 · disable: `TW_NO_UPDATE_CHECK=1`
|
|
76
|
+
|
|
77
|
+
## 저장 · Data
|
|
78
|
+
|
|
79
|
+
`~/.typingworks` — 설정 · 이 기기의 기록 · 로그인 토큰(이 파일에만, 권한 600). 지우면 처음 상태가 됩니다.
|
|
80
|
+
|
|
81
|
+
## License
|
|
82
|
+
|
|
83
|
+
© 2026 Perspective. All rights reserved. 무료로 쓸 수 있습니다. 자세한 것은 LICENSE.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// typing.works — 이 기기에 맞는 실행 파일을 골라 그대로 넘긴다(입출력 · 종료 코드 · 신호 그대로). 설치 스크립트는 없다.
|
|
3
|
+
"use strict";
|
|
4
|
+
const { spawnSync } = require("child_process");
|
|
5
|
+
const path = require("path");
|
|
6
|
+
const fs = require("fs");
|
|
7
|
+
const key = `${process.platform}-${process.arch}`;
|
|
8
|
+
const exe = path.join(__dirname, "..", "vendor", key, process.platform === "win32" ? "typingworks.exe" : "typingworks");
|
|
9
|
+
if (!fs.existsSync(exe)) {
|
|
10
|
+
console.error(`typing.works: ${key} 은 아직 지원하지 않습니다 — macOS · Linux(x64 · arm64 · x86) · Windows(x64 · arm64).`);
|
|
11
|
+
console.error(`typing.works: ${key} is not supported yet — macOS, Linux and Windows (x64 · arm64).`);
|
|
12
|
+
process.exit(1);
|
|
13
|
+
}
|
|
14
|
+
try { fs.accessSync(exe, fs.constants.X_OK); } catch { try { fs.chmodSync(exe, 0o755); } catch {} }
|
|
15
|
+
const r = spawnSync(exe, process.argv.slice(2), { stdio: "inherit" });
|
|
16
|
+
if (r.error) { console.error(`typing.works: ${r.error.message}`); process.exit(1); }
|
|
17
|
+
if (r.signal) process.kill(process.pid, r.signal);
|
|
18
|
+
process.exit(r.status === null ? 1 : r.status);
|
package/install.ps1
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# typing.works - terminal installer for Windows
|
|
2
|
+
# irm https://cdn.jsdelivr.net/npm/typing.works/install.ps1 | iex
|
|
3
|
+
#
|
|
4
|
+
# What it does
|
|
5
|
+
# 1. Downloads the typing.works npm package (about 2 MB, holds all seven binaries) and takes the one for this PC
|
|
6
|
+
# (Windows 10 1809+ / 11, x64 or arm64)
|
|
7
|
+
# 2. Verifies it against the sha512 the npm registry publishes - stops on mismatch
|
|
8
|
+
# 3. Puts typingworks.exe and typing.works.exe in %LOCALAPPDATA%\typingworks\bin (override: TW_INSTALL_DIR)
|
|
9
|
+
# 4. Adds that folder to your user PATH (skip: TW_NO_MODIFY_PATH=1)
|
|
10
|
+
# The version follows the latest "typing.works" on npm (pin: TW_VERSION). Ctrl+U in the app re-runs this script.
|
|
11
|
+
# No source code is downloaded - only the binary, README and LICENSE.
|
|
12
|
+
# Uninstall: delete that folder and %USERPROFILE%\.typingworks
|
|
13
|
+
# (ASCII only on purpose: Windows PowerShell 5.1 reads BOM-less script files in the ANSI code page.)
|
|
14
|
+
& {
|
|
15
|
+
$ErrorActionPreference = 'Stop'
|
|
16
|
+
$ProgressPreference = 'SilentlyContinue' # the progress bar slows downloads a lot on PowerShell 5.1
|
|
17
|
+
[Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12
|
|
18
|
+
$reg = if ($env:TW_REGISTRY) { $env:TW_REGISTRY } else { 'https://registry.npmjs.org' } # an npm mirror, if you use one
|
|
19
|
+
$dir = if ($env:TW_INSTALL_DIR) { $env:TW_INSTALL_DIR } else { Join-Path $env:LOCALAPPDATA 'typingworks\bin' }
|
|
20
|
+
|
|
21
|
+
# The real CPU - pick arm64 even when x64 PowerShell runs under emulation on ARM
|
|
22
|
+
$arch = $null
|
|
23
|
+
try { $arch = [System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture.ToString() } catch { }
|
|
24
|
+
if (-not $arch) { $arch = if ($env:PROCESSOR_ARCHITEW6432) { $env:PROCESSOR_ARCHITEW6432 } else { $env:PROCESSOR_ARCHITECTURE } }
|
|
25
|
+
switch -regex ($arch) {
|
|
26
|
+
'^(Arm64|ARM64)$' { $arch = 'arm64' }
|
|
27
|
+
'^(X64|AMD64)$' { $arch = 'x64' }
|
|
28
|
+
default { throw "typing.works: $arch is not supported yet (Windows x64 / arm64)" }
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
# Version and the package's sha512 in one request - latest unless TW_VERSION is set
|
|
32
|
+
$tag = if ($env:TW_VERSION) { $env:TW_VERSION } else { 'latest' }
|
|
33
|
+
$meta = $null
|
|
34
|
+
try { $meta = Invoke-RestMethod -UseBasicParsing "$reg/typing.works/$tag" } catch { }
|
|
35
|
+
if (-not $meta -or -not $meta.version -or -not $meta.dist.integrity) { throw 'typing.works: could not read the npm registry (check your internet connection)' }
|
|
36
|
+
$ver = $meta.version
|
|
37
|
+
$integrity = $meta.dist.integrity
|
|
38
|
+
if ($integrity -notlike 'sha512-*') { throw "typing.works: unexpected integrity format: $integrity" }
|
|
39
|
+
$tar = (Get-Command tar.exe -ErrorAction SilentlyContinue).Source # built in since Windows 10 1803
|
|
40
|
+
if (-not $tar) { throw 'typing.works: tar.exe was not found (Windows 10 1803 or later is needed)' }
|
|
41
|
+
# Download with the built-in curl.exe (Windows 10 1803+). PowerShell 5.1's Invoke-WebRequest follows GitHub's redirect to a
|
|
42
|
+
# signed asset URL but mangles the signature and gets 404 (seen 2026-10-13). Fall back to it only when curl.exe is missing.
|
|
43
|
+
$curl = (Get-Command curl.exe -ErrorAction SilentlyContinue).Source
|
|
44
|
+
function Get-File([string]$from, [string]$to) {
|
|
45
|
+
if ($curl -and $from -notlike 'file:*') {
|
|
46
|
+
& $curl -fsSL --retry 2 -o $to $from
|
|
47
|
+
if ($LASTEXITCODE -ne 0) { throw "typing.works: download failed ($LASTEXITCODE): $from" }
|
|
48
|
+
} else {
|
|
49
|
+
Invoke-WebRequest -UseBasicParsing $from -OutFile $to
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
$tmp = Join-Path ([IO.Path]::GetTempPath()) ('typingworks-' + [guid]::NewGuid().ToString('N'))
|
|
53
|
+
New-Item -ItemType Directory -Path $tmp | Out-Null
|
|
54
|
+
try {
|
|
55
|
+
Write-Host "typing.works $ver (win32-$arch) downloading..."
|
|
56
|
+
$tgz = Join-Path $tmp "typing.works-$ver.tgz"
|
|
57
|
+
Get-File "$reg/typing.works/-/typing.works-$ver.tgz" $tgz
|
|
58
|
+
$want = -join ([Convert]::FromBase64String($integrity.Substring(7)) | ForEach-Object { $_.ToString('x2') })
|
|
59
|
+
$got = (Get-FileHash -Algorithm SHA512 $tgz).Hash.ToLower()
|
|
60
|
+
if ($got -ne $want) { throw 'typing.works: checksum mismatch - not installed' }
|
|
61
|
+
$inner = "package/vendor/win32-$arch/typingworks.exe"
|
|
62
|
+
& $tar -xzf $tgz -C $tmp $inner
|
|
63
|
+
if ($LASTEXITCODE -ne 0) { throw "typing.works: could not extract $inner" }
|
|
64
|
+
|
|
65
|
+
New-Item -ItemType Directory -Force -Path $dir | Out-Null
|
|
66
|
+
# A running .exe cannot be deleted but can be renamed - move the old one aside, then place the new one (Ctrl+U comes this way)
|
|
67
|
+
foreach ($n in @('typingworks.exe', 'typing.works.exe')) {
|
|
68
|
+
$p = Join-Path $dir $n
|
|
69
|
+
Remove-Item ($p + '.old') -Force -ErrorAction SilentlyContinue
|
|
70
|
+
if (Test-Path $p) { Move-Item $p ($p + '.old') -Force }
|
|
71
|
+
}
|
|
72
|
+
$exe = Join-Path $dir 'typingworks.exe'
|
|
73
|
+
Copy-Item (Join-Path $tmp ("package\vendor\win32-$arch\typingworks.exe")) $exe
|
|
74
|
+
Copy-Item $exe (Join-Path $dir 'typing.works.exe') # same program under both names
|
|
75
|
+
foreach ($n in @('typingworks.exe.old', 'typing.works.exe.old')) { Remove-Item (Join-Path $dir $n) -Force -ErrorAction SilentlyContinue }
|
|
76
|
+
|
|
77
|
+
# Tell the app it was installed by this script, so Ctrl+U re-runs it (UTF-8 without BOM - user folders may be non-ASCII)
|
|
78
|
+
$tw = Join-Path $HOME '.typingworks'
|
|
79
|
+
New-Item -ItemType Directory -Force -Path $tw | Out-Null
|
|
80
|
+
[IO.File]::WriteAllText((Join-Path $tw 'install-script'), $exe + "`n", (New-Object Text.UTF8Encoding $false))
|
|
81
|
+
|
|
82
|
+
Write-Host "OK typing.works $ver -> $exe"
|
|
83
|
+
$userPath = [Environment]::GetEnvironmentVariable('Path', 'User')
|
|
84
|
+
$has = $false
|
|
85
|
+
if ($userPath) { foreach ($e in $userPath.Split(';')) { if ($e.TrimEnd('\') -ieq $dir.TrimEnd('\')) { $has = $true } } }
|
|
86
|
+
if (-not $has -and $env:TW_NO_MODIFY_PATH -ne '1') {
|
|
87
|
+
$new = if ($userPath) { $userPath.TrimEnd(';') + ';' + $dir } else { $dir }
|
|
88
|
+
[Environment]::SetEnvironmentVariable('Path', $new, 'User')
|
|
89
|
+
$env:Path = $env:Path.TrimEnd(';') + ';' + $dir
|
|
90
|
+
Write-Host " added $dir to your PATH - open a new terminal, then run: typingworks"
|
|
91
|
+
} else {
|
|
92
|
+
Write-Host ' run: typingworks'
|
|
93
|
+
}
|
|
94
|
+
} finally {
|
|
95
|
+
Remove-Item $tmp -Recurse -Force -ErrorAction SilentlyContinue
|
|
96
|
+
}
|
|
97
|
+
}
|
package/install.sh
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
# typing.works — terminal 설치 · install
|
|
3
|
+
# curl -fsSL https://cdn.jsdelivr.net/npm/typing.works/install.sh | sh
|
|
4
|
+
#
|
|
5
|
+
# 하는 일 · what it does
|
|
6
|
+
# 1. npm 의 typing.works 꾸러미(실행 파일 일곱 가지가 든 약 2MB)를 받아 이 기기(macOS · Linux, arm64 · x64 · x86)에 맞는 것만 꺼낸다
|
|
7
|
+
# 2. npm 이 알려 주는 sha512 와 대조한다 — 다르면 멈춘다
|
|
8
|
+
# 3. ~/.local/bin 에 typingworks 와 typing.works 를 둔다(TW_INSTALL_DIR 로 바꿀 수 있다)
|
|
9
|
+
# 4. 그 폴더가 PATH 에 없으면 셸 설정 파일에 한 줄 더하고 알린다
|
|
10
|
+
# 판 번호는 npm 의 typing.works 최신 판을 따른다(TW_VERSION=0.3.0 처럼 고를 수 있다). 앱 안 ^U 가 이 스크립트를 다시 돌린다.
|
|
11
|
+
# 소스 코드는 없다 — npm 꾸러미에는 실행 파일 · 설명서 · 라이선스 · 이 스크립트뿐. 지우기: rm ~/.local/bin/typingworks ~/.local/bin/typing.works ; rm -rf ~/.typingworks
|
|
12
|
+
set -eu
|
|
13
|
+
|
|
14
|
+
REG="${TW_REGISTRY:-https://registry.npmjs.org}" # npm 미러를 쓰는 곳이면 바꾼다
|
|
15
|
+
DIR="${TW_INSTALL_DIR:-$HOME/.local/bin}"
|
|
16
|
+
say() { printf '%s\n' "$*"; }
|
|
17
|
+
die() { printf 'typing.works: %s\n' "$*" >&2; exit 1; }
|
|
18
|
+
|
|
19
|
+
command -v curl >/dev/null 2>&1 || die "curl 이 필요합니다 · curl is required"
|
|
20
|
+
command -v tar >/dev/null 2>&1 || die "tar 가 필요합니다 · tar is required"
|
|
21
|
+
|
|
22
|
+
os="$(uname -s)"; arch="$(uname -m)"
|
|
23
|
+
case "$os" in
|
|
24
|
+
Darwin) os=darwin ;;
|
|
25
|
+
Linux) os=linux ;;
|
|
26
|
+
*) die "$os 은 아직 지원하지 않습니다 — macOS · Linux (Windows 는 PowerShell 설치를 쓰세요) · $os is not supported yet" ;;
|
|
27
|
+
esac
|
|
28
|
+
case "$arch" in
|
|
29
|
+
arm64|aarch64) arch=arm64 ;;
|
|
30
|
+
x86_64|amd64) arch=x64 ;;
|
|
31
|
+
i386|i486|i586|i686) arch=ia32 ;;
|
|
32
|
+
*) die "$arch 은 아직 지원하지 않습니다 · $arch is not supported yet" ;;
|
|
33
|
+
esac
|
|
34
|
+
[ "$os" = darwin ] && [ "$arch" = ia32 ] && die "32비트 macOS 는 지원하지 않습니다 · 32-bit macOS is not supported"
|
|
35
|
+
# Rosetta 로 돌린 셸이어도 진짜 칩에 맞춘다
|
|
36
|
+
if [ "$os" = darwin ] && [ "$arch" = x64 ] && [ "$(sysctl -n sysctl.proc_translated 2>/dev/null || echo 0)" = 1 ]; then arch=arm64; fi
|
|
37
|
+
|
|
38
|
+
# 판 번호와 꾸러미의 sha512 를 한 번에 — 판을 안 주면 latest
|
|
39
|
+
meta="$(curl -fsSL "$REG/typing.works/${TW_VERSION:-latest}")" || die "판 정보를 못 읽었습니다(인터넷 연결을 확인하세요) · could not reach the npm registry"
|
|
40
|
+
ver="$(printf '%s' "$meta" | grep -o '"version":"[^"]*"' | head -n 1 | cut -d'"' -f4)"
|
|
41
|
+
integ="$(printf '%s' "$meta" | grep -o '"integrity":"sha512-[^"]*"' | head -n 1 | cut -d'"' -f4)"
|
|
42
|
+
[ -n "$ver" ] && [ -n "$integ" ] || die "판 정보가 이상합니다 · unexpected registry response"
|
|
43
|
+
|
|
44
|
+
# base64 → 16진수(base64 -d 는 GNU · 새 macOS, -D 는 옛 macOS, 없으면 openssl)
|
|
45
|
+
b64hex() {
|
|
46
|
+
for d in "base64 -d" "base64 -D" "openssl base64 -d -A"; do
|
|
47
|
+
h="$(printf '%s' "$1" | $d 2>/dev/null | od -An -v -tx1 | tr -d ' \n')"
|
|
48
|
+
[ -n "$h" ] && { printf '%s' "$h"; return 0; }
|
|
49
|
+
done
|
|
50
|
+
return 1
|
|
51
|
+
}
|
|
52
|
+
want="$(b64hex "${integ#sha512-}")" || die "sha512 를 풀 도구가 없습니다 · no base64 tool"
|
|
53
|
+
|
|
54
|
+
tmp="$(mktemp -d 2>/dev/null || mktemp -d -t typingworks)"
|
|
55
|
+
trap 'rm -rf "$tmp"' EXIT INT TERM
|
|
56
|
+
tgz="$tmp/typing.works-$ver.tgz"
|
|
57
|
+
|
|
58
|
+
say "typing.works $ver ($os-$arch) 받는 중 · downloading…"
|
|
59
|
+
curl -fsSL "$REG/typing.works/-/typing.works-$ver.tgz" -o "$tgz" || die "받지 못했습니다 · download failed"
|
|
60
|
+
if command -v sha512sum >/dev/null 2>&1; then got="$(sha512sum "$tgz" | cut -d' ' -f1)"
|
|
61
|
+
elif command -v shasum >/dev/null 2>&1; then got="$(shasum -a 512 "$tgz" | cut -d' ' -f1)"
|
|
62
|
+
elif command -v openssl >/dev/null 2>&1; then got="$(openssl dgst -sha512 -r "$tgz" | cut -d' ' -f1)"
|
|
63
|
+
else die "sha512 도구가 없어 대조할 수 없습니다 · no sha512 tool"; fi
|
|
64
|
+
[ "$got" = "$want" ] || die "해시가 다릅니다 — 설치하지 않았습니다 · checksum mismatch, not installed"
|
|
65
|
+
|
|
66
|
+
tar -xzf "$tgz" -C "$tmp" "package/vendor/$os-$arch/typingworks" || die "풀지 못했습니다 · could not extract"
|
|
67
|
+
mv "$tmp/package/vendor/$os-$arch/typingworks" "$tmp/typingworks"
|
|
68
|
+
mkdir -p "$DIR"
|
|
69
|
+
# 같은 폴더에 새 이름으로 둔 뒤 바꿔 끼운다 — 돌고 있는 typingworks 가 있어도 안전하다(^U 가 이 길로 온다)
|
|
70
|
+
cp "$tmp/typingworks" "$DIR/.typingworks.new"
|
|
71
|
+
chmod 755 "$DIR/.typingworks.new"
|
|
72
|
+
mv -f "$DIR/.typingworks.new" "$DIR/typingworks"
|
|
73
|
+
ln -sf typingworks "$DIR/typing.works"
|
|
74
|
+
|
|
75
|
+
# 앱이 «스크립트로 깔았다»를 알게 — ^U 가 이 스크립트를 다시 돌린다
|
|
76
|
+
mkdir -p "$HOME/.typingworks"
|
|
77
|
+
printf '%s\n' "$DIR/typingworks" > "$HOME/.typingworks/install-script"
|
|
78
|
+
|
|
79
|
+
say "✓ typing.works $ver → $DIR/typingworks"
|
|
80
|
+
|
|
81
|
+
case ":$PATH:" in
|
|
82
|
+
*":$DIR:"*) say " 실행 · run: typingworks" ;;
|
|
83
|
+
*)
|
|
84
|
+
line="export PATH=\"$DIR:\$PATH\""
|
|
85
|
+
case "${SHELL:-}" in
|
|
86
|
+
*/zsh) rc="$HOME/.zshrc" ;;
|
|
87
|
+
*/bash) if [ "$os" = darwin ]; then rc="$HOME/.bash_profile"; else rc="$HOME/.bashrc"; fi ;;
|
|
88
|
+
*) rc="$HOME/.profile" ;;
|
|
89
|
+
esac
|
|
90
|
+
if [ "${TW_NO_MODIFY_PATH:-}" != 1 ] && ! grep -qsF "$line" "$rc"; then
|
|
91
|
+
printf '\n# typing.works\n%s\n' "$line" >> "$rc"
|
|
92
|
+
say " $DIR 를 PATH 에 더했습니다($rc) · added to PATH"
|
|
93
|
+
fi
|
|
94
|
+
say " 새 터미널을 열거나 · open a new terminal, or: $line"
|
|
95
|
+
say " 실행 · run: typingworks"
|
|
96
|
+
;;
|
|
97
|
+
esac
|
package/package.json
CHANGED
|
@@ -1,6 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "typing.works",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.3.0-beta.10",
|
|
4
|
+
"description": "typing.works in your terminal — Korean & English typing practice, records, stats and ranked matches",
|
|
5
|
+
"bin": {
|
|
6
|
+
"typing.works": "bin/typing.works.js",
|
|
7
|
+
"typingworks": "bin/typing.works.js"
|
|
8
|
+
},
|
|
9
|
+
"files": ["bin", "vendor", "install.sh", "install.ps1", "README.md", "LICENSE"],
|
|
10
|
+
"os": ["darwin", "linux", "win32"],
|
|
11
|
+
"cpu": ["arm64", "x64", "ia32"],
|
|
12
|
+
"engines": { "node": ">=14" },
|
|
13
|
+
"license": "SEE LICENSE IN LICENSE",
|
|
14
|
+
"homepage": "https://typing.works",
|
|
15
|
+
"author": "typing.works",
|
|
16
|
+
"keywords": ["typing", "typing-practice", "typing-test", "korean", "hangul", "terminal", "tui", "cli", "wpm"]
|
|
17
|
+
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|