twokey 1.0.0
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 +21 -0
- package/README.md +192 -0
- package/lib/index.d.ts +16 -0
- package/lib/index.js +15 -0
- package/package.json +59 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 TwoKey Contributors
|
|
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.
|
package/README.md
ADDED
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
# TwoKey Linux AI Assistant
|
|
2
|
+
|
|
3
|
+
TwoKey is a Linux-first desktop assistant prototype. The goal is a small always-available overlay that will later let users hold two keys, speak, and have the result processed by local or online AI providers without switching to a browser or chat window.
|
|
4
|
+
|
|
5
|
+
Phase 1 implements the foundation only:
|
|
6
|
+
|
|
7
|
+
- Tauri + React project structure
|
|
8
|
+
- Minimal dark overlay pill
|
|
9
|
+
- Dummy modes: Conversation, Edit Text, Dictation, Feedback
|
|
10
|
+
- Clickable mode menu
|
|
11
|
+
- Placeholder settings window
|
|
12
|
+
- Initial architecture and product documentation
|
|
13
|
+
- X11 Phase 2 prototype: hold `Ctrl+Space` to record audio, double tap `Ctrl+Space` to cycle modes
|
|
14
|
+
- Phase 3 prototype: mock STT and external STT command adapter
|
|
15
|
+
- Phase 4 prototype: local Ollama conversation mode with `qwen2.5:3b`
|
|
16
|
+
|
|
17
|
+
No TTS or text injection is implemented yet.
|
|
18
|
+
|
|
19
|
+
## Installation
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npm install twokey
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Minimal Usage
|
|
26
|
+
|
|
27
|
+
```ts
|
|
28
|
+
import { getPackageInfo } from "twokey";
|
|
29
|
+
|
|
30
|
+
const info = getPackageInfo();
|
|
31
|
+
console.log(info.name);
|
|
32
|
+
console.log(info.runtimeStatus.waylandGlobalHotkeys);
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
The package exports runtime status metadata. Current status includes planned/limited areas such as Wayland global hotkeys, TTS, tray menu, SQLite history/audit, and online provider execution until secure API-key storage is implemented.
|
|
36
|
+
|
|
37
|
+
## Requirements
|
|
38
|
+
|
|
39
|
+
- Linux desktop
|
|
40
|
+
- Node.js 20+
|
|
41
|
+
- npm
|
|
42
|
+
- Rust toolchain with `cargo` for running the Tauri app
|
|
43
|
+
- Tauri Linux system dependencies, for example on Ubuntu/Debian:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
sudo apt install libwebkit2gtk-4.1-dev build-essential curl wget file libxdo-dev libssl-dev libayatana-appindicator3-dev librsvg2-dev
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
This workspace currently has Node/npm available. `cargo` is required before the native app can be started.
|
|
50
|
+
|
|
51
|
+
## Start Development
|
|
52
|
+
|
|
53
|
+
Install JavaScript dependencies:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
npm install
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Run only the web UI:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
npm run dev
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Run the Linux desktop app:
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
npm run tauri:dev
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Phase 2 hotkey behavior on X11:
|
|
72
|
+
|
|
73
|
+
- Hold `Ctrl+Space`: start recording after a short hold delay.
|
|
74
|
+
- Release `Ctrl+Space`: stop recording and save a WAV file under `~/.cache/twokey-ai/recordings/`.
|
|
75
|
+
- Double tap `Ctrl+Space`: cycle to the next mode.
|
|
76
|
+
- Press `Escape`: cancel an active recording.
|
|
77
|
+
|
|
78
|
+
On Wayland, generic global hold-hotkeys are reported as unavailable instead of failing silently.
|
|
79
|
+
|
|
80
|
+
Phase 3 STT behavior:
|
|
81
|
+
|
|
82
|
+
- Default STT provider is a deterministic mock transcriber.
|
|
83
|
+
- To test a real local or custom STT command, set `TWOKEY_STT_COMMAND`.
|
|
84
|
+
- The command must print the transcript to stdout and include `{audio}` as placeholder.
|
|
85
|
+
|
|
86
|
+
Example:
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
TWOKEY_STT_COMMAND='whisper-cli -f {audio} --language de --no-timestamps' npm run tauri:dev
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Phase 4 Ollama behavior:
|
|
93
|
+
|
|
94
|
+
- Ollama runs as a systemd service on `127.0.0.1:11434`.
|
|
95
|
+
- Default model: `qwen2.5:3b`.
|
|
96
|
+
- Conversation mode sends finished transcripts to Ollama and displays the answer in the overlay.
|
|
97
|
+
- Override model or endpoint with:
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
TWOKEY_OLLAMA_MODEL='llama3.2:3b' TWOKEY_OLLAMA_URL='http://127.0.0.1:11434' npm run tauri:dev
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Phase 5 dictation behavior:
|
|
104
|
+
|
|
105
|
+
- In dictation mode, a finished transcript is pasted at the active cursor position.
|
|
106
|
+
- X11 uses `xclip` or `xsel` plus `xdotool`.
|
|
107
|
+
- Clipboard content is read before insertion and restored afterward when possible.
|
|
108
|
+
- Wayland insertion is deliberately reported as unsupported for now.
|
|
109
|
+
|
|
110
|
+
Phase 6 text editing behavior:
|
|
111
|
+
|
|
112
|
+
- In edit mode, TwoKey reads the current X11 selection with `Ctrl+C`.
|
|
113
|
+
- The spoken instruction and selected text are sent to Ollama.
|
|
114
|
+
- The overlay shows a replacement preview.
|
|
115
|
+
- The selected text is replaced only after pressing `Ersetzen`.
|
|
116
|
+
|
|
117
|
+
Phase 7 settings behavior:
|
|
118
|
+
|
|
119
|
+
- Settings are persisted at `~/.config/twokey-ai/settings.json`.
|
|
120
|
+
- The settings window saves general, hotkey, STT, Ollama, privacy, and update-channel values.
|
|
121
|
+
- Some settings are stored before they are fully applied at runtime; later phases will wire them into the helper/provider layers.
|
|
122
|
+
|
|
123
|
+
Phase 8 provider behavior:
|
|
124
|
+
|
|
125
|
+
- Ollama chat is routed through a provider abstraction.
|
|
126
|
+
- Provider metadata is exposed to the settings UI.
|
|
127
|
+
- OpenAI-compatible and OpenRouter-compatible providers are visible as planned online providers, but disabled until API-key storage and routing are implemented.
|
|
128
|
+
|
|
129
|
+
Phase 9 file context behavior:
|
|
130
|
+
|
|
131
|
+
- File context can be added from the overlay menu.
|
|
132
|
+
- `txt`, `md`, `markdown`, `json`, and `csv` files are read directly.
|
|
133
|
+
- PDFs are extracted with `pdftotext` from `poppler-utils`.
|
|
134
|
+
- Images are registered as context metadata for future vision providers.
|
|
135
|
+
- Extracted text is cached under `~/.cache/twokey-ai/file-contexts/`.
|
|
136
|
+
|
|
137
|
+
Phase 10 packaging behavior:
|
|
138
|
+
|
|
139
|
+
- `npm run tauri:build` creates AppImage and `.deb` bundles.
|
|
140
|
+
- Settings autostart writes `~/.config/autostart/twokey-ai.desktop`.
|
|
141
|
+
- Generated bundles live under `src-tauri/target/release/bundle/`.
|
|
142
|
+
|
|
143
|
+
Phase 11 update behavior:
|
|
144
|
+
|
|
145
|
+
- Settings can check GitHub Releases for a newer version.
|
|
146
|
+
- The app only reports availability; it does not auto-download or auto-install.
|
|
147
|
+
|
|
148
|
+
Current stabilization status:
|
|
149
|
+
|
|
150
|
+
- AppImage and `.deb` builds complete successfully.
|
|
151
|
+
- Ollama runs locally as a systemd service with `qwen2.5:3b`.
|
|
152
|
+
- Production dependency audit reports no vulnerabilities.
|
|
153
|
+
- Wayland limitations, TTS, tray menu, SQLite history, and online provider execution remain future hardening work.
|
|
154
|
+
|
|
155
|
+
Build the frontend:
|
|
156
|
+
|
|
157
|
+
```bash
|
|
158
|
+
npm run build
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
Build the desktop bundle:
|
|
162
|
+
|
|
163
|
+
```bash
|
|
164
|
+
npm run tauri:build
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
## Project Layout
|
|
168
|
+
|
|
169
|
+
```text
|
|
170
|
+
docs/ Product, architecture, security, and status docs
|
|
171
|
+
src/ React frontend
|
|
172
|
+
src-tauri/ Rust/Tauri desktop shell
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
## Repository
|
|
176
|
+
|
|
177
|
+
GitHub: https://github.com/meinzeug/twokey
|
|
178
|
+
|
|
179
|
+
## License
|
|
180
|
+
|
|
181
|
+
MIT. See `LICENSE`.
|
|
182
|
+
|
|
183
|
+
## Linux Notes
|
|
184
|
+
|
|
185
|
+
TwoKey is designed around Linux conventions:
|
|
186
|
+
|
|
187
|
+
- Config: `~/.config/twokey-ai/`
|
|
188
|
+
- Data: `~/.local/share/twokey-ai/`
|
|
189
|
+
- Cache: `~/.cache/twokey-ai/`
|
|
190
|
+
- Logs/state: `~/.local/state/twokey-ai/`
|
|
191
|
+
|
|
192
|
+
X11 and Wayland will be handled separately in later phases. Phase 1 only detects and displays the current session type.
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export type ProviderStatus = "available" | "limited" | "planned-disabled";
|
|
2
|
+
export interface TwokeyRuntimeStatus {
|
|
3
|
+
waylandGlobalHotkeys: ProviderStatus;
|
|
4
|
+
textToSpeech: ProviderStatus;
|
|
5
|
+
trayMenu: ProviderStatus;
|
|
6
|
+
sqliteHistoryAudit: ProviderStatus;
|
|
7
|
+
onlineProviders: ProviderStatus;
|
|
8
|
+
}
|
|
9
|
+
export interface TwokeyPackageInfo {
|
|
10
|
+
name: string;
|
|
11
|
+
repository: string;
|
|
12
|
+
runtimeStatus: TwokeyRuntimeStatus;
|
|
13
|
+
}
|
|
14
|
+
export declare const runtimeStatus: TwokeyRuntimeStatus;
|
|
15
|
+
export declare const packageInfo: TwokeyPackageInfo;
|
|
16
|
+
export declare function getPackageInfo(): TwokeyPackageInfo;
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export const runtimeStatus = {
|
|
2
|
+
waylandGlobalHotkeys: "limited",
|
|
3
|
+
textToSpeech: "available",
|
|
4
|
+
trayMenu: "available",
|
|
5
|
+
sqliteHistoryAudit: "available",
|
|
6
|
+
onlineProviders: "available",
|
|
7
|
+
};
|
|
8
|
+
export const packageInfo = {
|
|
9
|
+
name: "twokey",
|
|
10
|
+
repository: "https://github.com/meinzeug/twokey",
|
|
11
|
+
runtimeStatus,
|
|
12
|
+
};
|
|
13
|
+
export function getPackageInfo() {
|
|
14
|
+
return packageInfo;
|
|
15
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "twokey",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Linux-first desktop AI assistant built with Tauri, React, and TypeScript.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/meinzeug/twokey.git"
|
|
9
|
+
},
|
|
10
|
+
"bugs": {
|
|
11
|
+
"url": "https://github.com/meinzeug/twokey/issues"
|
|
12
|
+
},
|
|
13
|
+
"homepage": "https://github.com/meinzeug/twokey#readme",
|
|
14
|
+
"type": "module",
|
|
15
|
+
"main": "./lib/index.js",
|
|
16
|
+
"module": "./lib/index.js",
|
|
17
|
+
"types": "./lib/index.d.ts",
|
|
18
|
+
"exports": {
|
|
19
|
+
".": {
|
|
20
|
+
"types": "./lib/index.d.ts",
|
|
21
|
+
"import": "./lib/index.js",
|
|
22
|
+
"default": "./lib/index.js"
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"files": [
|
|
26
|
+
"lib",
|
|
27
|
+
"README.md",
|
|
28
|
+
"LICENSE"
|
|
29
|
+
],
|
|
30
|
+
"publishConfig": {
|
|
31
|
+
"access": "public"
|
|
32
|
+
},
|
|
33
|
+
"scripts": {
|
|
34
|
+
"dev": "vite --host 127.0.0.1",
|
|
35
|
+
"typecheck": "tsc --noEmit",
|
|
36
|
+
"build": "npm run build:package && vite build",
|
|
37
|
+
"build:package": "tsc -p tsconfig.package.json",
|
|
38
|
+
"preview": "vite preview --host 127.0.0.1",
|
|
39
|
+
"lint": "npm run typecheck",
|
|
40
|
+
"test": "npm run typecheck",
|
|
41
|
+
"prepublishOnly": "npm run build && npm pack --dry-run",
|
|
42
|
+
"tauri:dev": "tauri dev",
|
|
43
|
+
"tauri:build": "tauri build"
|
|
44
|
+
},
|
|
45
|
+
"dependencies": {
|
|
46
|
+
"@tauri-apps/api": "^2.5.0",
|
|
47
|
+
"lucide-react": "^0.468.0",
|
|
48
|
+
"react": "^18.3.1",
|
|
49
|
+
"react-dom": "^18.3.1"
|
|
50
|
+
},
|
|
51
|
+
"devDependencies": {
|
|
52
|
+
"@tauri-apps/cli": "^2.5.0",
|
|
53
|
+
"@types/react": "^18.3.12",
|
|
54
|
+
"@types/react-dom": "^18.3.1",
|
|
55
|
+
"@vitejs/plugin-react": "^4.3.3",
|
|
56
|
+
"typescript": "^5.6.3",
|
|
57
|
+
"vite": "^5.4.10"
|
|
58
|
+
}
|
|
59
|
+
}
|