nixii 0.1.0__tar.gz

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.
nixii-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,116 @@
1
+ Metadata-Version: 2.3
2
+ Name: nixii
3
+ Version: 0.1.0
4
+ Summary: Local voice-command assistant for Linux
5
+ Requires-Dist: aiohttp==3.14.3
6
+ Requires-Dist: ddgs>=9.14.4
7
+ Requires-Dist: faster-whisper==1.2.1
8
+ Requires-Dist: google-genai>=2.16.0
9
+ Requires-Dist: numpy==2.5.1
10
+ Requires-Dist: rich>=15.0.0
11
+ Requires-Dist: sarvamai>=0.1.31
12
+ Requires-Dist: tenacity>=9.1.4
13
+ Requires-Python: >=3.13, <3.14
14
+ Description-Content-Type: text/markdown
15
+
16
+ # Nixi
17
+
18
+ A desktop voice assistant for Linux. Trigger Nixi, ask a question or give a
19
+ command, and it handles it — change the volume, set a wallpaper, take a
20
+ screenshot, control media, or answer general queries using Gemini.
21
+
22
+ ## What It Does
23
+
24
+ - **System control** — volume, brightness, mute, media playback, screenshots,
25
+ wallpaper changes, app launcher.
26
+ - **General queries** — ask anything. Nixi uses Gemini and can search the web
27
+ for live information like weather, news, and prices.
28
+ - **Vision** — say "open your eyes", "where should I click", or "why is this
29
+ red" and Nixi asks permission to screenshot your screen, then describes what
30
+ it sees. Approval is via desktop notification with a configurable timeout.
31
+ - **Voice interaction** — manual trigger-to-record mechanism, speech-to-text,
32
+ and text-to-speech. No constant background listening/wake-word overhead.
33
+
34
+ ## Installation & Setup
35
+
36
+ ### Option 1: Global Installation (Recommended)
37
+
38
+ Install Nixi globally on your system using [pipx](https://github.com/pypa/pipx):
39
+
40
+ ```sh
41
+ pipx install nixii
42
+ ```
43
+
44
+ This will automatically expose the commands globally. Run any command once to automatically initialize your configuration directory:
45
+
46
+ ```sh
47
+ nixi-server
48
+ ```
49
+
50
+ Now, configure your API keys by editing `~/.config/nixi/.env`:
51
+
52
+ ```dotenv
53
+ GOOGLE_CLOUD_API_KEY=your-vertex-express-mode-key
54
+ SARVAM_API_KEY=your-sarvam-key
55
+ ```
56
+
57
+ ### Option 2: Local Development Setup
58
+
59
+ If you'd like to run or develop Nixi locally, install [uv](https://docs.astral.sh/uv/) and sync dependencies:
60
+
61
+ ```sh
62
+ uv sync
63
+ ```
64
+
65
+ Run any command once (e.g. `uv run nixi-server`) to auto-generate your config, then add your API keys to `~/.config/nixi/.env`.
66
+
67
+ ## Run
68
+
69
+ > **Note:** If you are using the local development setup, prefix all of the following commands with `uv run ` (e.g., `uv run nixi-server`).
70
+
71
+ First, discover your desktop environment (keybinds, scripts, wallpapers):
72
+
73
+ ```sh
74
+ nixi-server --discover
75
+ ```
76
+
77
+ Then start the server:
78
+
79
+ ```sh
80
+ nixi-server
81
+ ```
82
+
83
+ Next, start the voice daemon (which runs as a background process listening for manual trigger events):
84
+
85
+ ```sh
86
+ nixi-voice
87
+ ```
88
+
89
+ To interact with Nixi, trigger the recording. You can bind keys or desktop shortcuts to run these commands:
90
+
91
+ - **Trigger Recording (Toggle)**: Start or stop recording your query.
92
+ ```sh
93
+ nixi-voice trigger
94
+ ```
95
+ - **New Session**: Start a fresh conversation session and trigger recording.
96
+ ```sh
97
+ nixi-voice new
98
+ ```
99
+
100
+ Run the command once to start recording, speak your request, and run it again to stop and process the audio!
101
+
102
+ ## Configuration
103
+
104
+ Nixi resolves its config in this order:
105
+
106
+ 1. `--config <path>` CLI flag
107
+ 2. `$NIXI_CONFIG` environment variable
108
+ 3. `~/.config/nixi/nixi.toml` (user config)
109
+ 4. `example_config/nixi.toml` (repo default)
110
+ 5. Code defaults (no file needed)
111
+
112
+ The system prompt lives in code. Set `agent_name` in your TOML to change the
113
+ persona — the prompt template uses it automatically.
114
+
115
+ Edit your TOML to configure audio thresholds, STT, TTS, model
116
+ settings, vision, and local actions.
nixii-0.1.0/README.md ADDED
@@ -0,0 +1,101 @@
1
+ # Nixi
2
+
3
+ A desktop voice assistant for Linux. Trigger Nixi, ask a question or give a
4
+ command, and it handles it — change the volume, set a wallpaper, take a
5
+ screenshot, control media, or answer general queries using Gemini.
6
+
7
+ ## What It Does
8
+
9
+ - **System control** — volume, brightness, mute, media playback, screenshots,
10
+ wallpaper changes, app launcher.
11
+ - **General queries** — ask anything. Nixi uses Gemini and can search the web
12
+ for live information like weather, news, and prices.
13
+ - **Vision** — say "open your eyes", "where should I click", or "why is this
14
+ red" and Nixi asks permission to screenshot your screen, then describes what
15
+ it sees. Approval is via desktop notification with a configurable timeout.
16
+ - **Voice interaction** — manual trigger-to-record mechanism, speech-to-text,
17
+ and text-to-speech. No constant background listening/wake-word overhead.
18
+
19
+ ## Installation & Setup
20
+
21
+ ### Option 1: Global Installation (Recommended)
22
+
23
+ Install Nixi globally on your system using [pipx](https://github.com/pypa/pipx):
24
+
25
+ ```sh
26
+ pipx install nixii
27
+ ```
28
+
29
+ This will automatically expose the commands globally. Run any command once to automatically initialize your configuration directory:
30
+
31
+ ```sh
32
+ nixi-server
33
+ ```
34
+
35
+ Now, configure your API keys by editing `~/.config/nixi/.env`:
36
+
37
+ ```dotenv
38
+ GOOGLE_CLOUD_API_KEY=your-vertex-express-mode-key
39
+ SARVAM_API_KEY=your-sarvam-key
40
+ ```
41
+
42
+ ### Option 2: Local Development Setup
43
+
44
+ If you'd like to run or develop Nixi locally, install [uv](https://docs.astral.sh/uv/) and sync dependencies:
45
+
46
+ ```sh
47
+ uv sync
48
+ ```
49
+
50
+ Run any command once (e.g. `uv run nixi-server`) to auto-generate your config, then add your API keys to `~/.config/nixi/.env`.
51
+
52
+ ## Run
53
+
54
+ > **Note:** If you are using the local development setup, prefix all of the following commands with `uv run ` (e.g., `uv run nixi-server`).
55
+
56
+ First, discover your desktop environment (keybinds, scripts, wallpapers):
57
+
58
+ ```sh
59
+ nixi-server --discover
60
+ ```
61
+
62
+ Then start the server:
63
+
64
+ ```sh
65
+ nixi-server
66
+ ```
67
+
68
+ Next, start the voice daemon (which runs as a background process listening for manual trigger events):
69
+
70
+ ```sh
71
+ nixi-voice
72
+ ```
73
+
74
+ To interact with Nixi, trigger the recording. You can bind keys or desktop shortcuts to run these commands:
75
+
76
+ - **Trigger Recording (Toggle)**: Start or stop recording your query.
77
+ ```sh
78
+ nixi-voice trigger
79
+ ```
80
+ - **New Session**: Start a fresh conversation session and trigger recording.
81
+ ```sh
82
+ nixi-voice new
83
+ ```
84
+
85
+ Run the command once to start recording, speak your request, and run it again to stop and process the audio!
86
+
87
+ ## Configuration
88
+
89
+ Nixi resolves its config in this order:
90
+
91
+ 1. `--config <path>` CLI flag
92
+ 2. `$NIXI_CONFIG` environment variable
93
+ 3. `~/.config/nixi/nixi.toml` (user config)
94
+ 4. `example_config/nixi.toml` (repo default)
95
+ 5. Code defaults (no file needed)
96
+
97
+ The system prompt lives in code. Set `agent_name` in your TOML to change the
98
+ persona — the prompt template uses it automatically.
99
+
100
+ Edit your TOML to configure audio thresholds, STT, TTS, model
101
+ settings, vision, and local actions.
@@ -0,0 +1 @@
1
+ """Nixi application packages."""
@@ -0,0 +1 @@
1
+ <svg fill="none" height="100%" width="100%" viewBox="0 0 650 650" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg"><g id="i0"><g transform="translate(195,347)"><animateTransform repeatCount="indefinite" type="translate" attributeName="transform" dur="2s" begin="0s" calcMode="spline" values="195 347; 195 347; 195 358; 195 347; 195 347; 195 358; 195 347; 195 347" keyTimes="0; 0.125; 0.25; 0.375; 0.6875; 0.8125; 0.9375; 1" keySplines="0 0 1 1; 0.333 0 0.667 1; 0.333 0 0.667 1; 0 0 1 1; 0.333 0 0.667 1; 0.333 0 0.667 1; 0 0 1 1" fill="freeze" /><g transform="scale(1,1)"><animateTransform repeatCount="indefinite" type="scale" attributeName="transform" dur="2s" begin="0s" calcMode="spline" values="1 1; 1 1; 1.06 0.93; 1 1; 0.98 1.03; 1 1; 1 1; 1.06 0.93; 1 1; 0.98 1.03; 1 1; 1 1" keyTimes="0; 0.125; 0.208333; 0.3125; 0.375; 0.416666; 0.6875; 0.770834; 0.875; 0.9375; 0.979167; 1" keySplines="0 0 1 1; 0.333 0 0.667 1; 0.333 0 0.667 1; 0.333 0 0.833 1; 0.167 0 0.667 1; 0.333 0 0.667 1; 0.333 0 0.667 1; 0.333 0 0.667 1; 0.333 0 0.833 1; 0.167 0 0.667 1; 0 0 1 1" fill="freeze" /><g transform="translate(130,-22)"><g id="i1" transform="matrix(1,0,0,1,-135.828,16)"><ellipse ry="195.813" rx="127.813" cy="0" cx="0" fill="#fafafa" /></g></g></g></g></g><g id="i0"><g transform="translate(195,347)"><animateTransform repeatCount="indefinite" type="translate" attributeName="transform" dur="2s" begin="0s" calcMode="spline" values="195 347; 195 347; 195 358; 195 347; 195 347; 195 358; 195 347; 195 347" keyTimes="0; 0.125; 0.25; 0.375; 0.6875; 0.8125; 0.9375; 1" keySplines="0 0 1 1; 0.333 0 0.667 1; 0.333 0 0.667 1; 0 0 1 1; 0.333 0 0.667 1; 0.333 0 0.667 1; 0 0 1 1" fill="freeze" /><g transform="scale(1,1)"><animateTransform repeatCount="indefinite" type="scale" attributeName="transform" dur="2s" begin="0s" calcMode="spline" values="1 1; 1 1; 1.06 0.93; 1 1; 0.98 1.03; 1 1; 1 1; 1.06 0.93; 1 1; 0.98 1.03; 1 1; 1 1" keyTimes="0; 0.125; 0.208333; 0.3125; 0.375; 0.416666; 0.6875; 0.770834; 0.875; 0.9375; 0.979167; 1" keySplines="0 0 1 1; 0.333 0 0.667 1; 0.333 0 0.667 1; 0.333 0 0.833 1; 0.167 0 0.667 1; 0.333 0 0.667 1; 0.333 0 0.667 1; 0.333 0 0.667 1; 0.333 0 0.833 1; 0.167 0 0.667 1; 0 0 1 1" fill="freeze" /><g transform="translate(130,-22)"><g id="i2"><g transform="translate(-135,20)"><animateTransform repeatCount="indefinite" type="translate" attributeName="transform" dur="2s" begin="0s" calcMode="spline" values="-135 20; -135 20; -135 69.176; -186 20; -186 20; -135 69.176; -135 20; -135 20" keyTimes="0; 0.125; 0.25; 0.375; 0.6875; 0.8125; 0.9375; 1" keySplines="0 0 1 1; 0.333 0 0.667 1; 0.333 0 0.667 1; 0 0 1 1; 0.167 0 0.667 1; 0.333 0 0.667 1; 0 0 1 1" fill="freeze" /><g transform="scale(1,1) translate(186,-20)"><g><g transform="translate(-186.82,16)"><g id="i3" transform="rotate(0)"><animateTransform repeatCount="indefinite" type="rotate" attributeName="transform" dur="2s" begin="0s" calcMode="spline" values="0; 0; -22; 0; 0" keyTimes="0; 0.25; 0.333333; 0.375; 1" keySplines="0 0 1 1; 0 0 1 1; 0 0 1 1; 0 0 1 1" fill="freeze" /><ellipse ry="80.813" rx="60.813" cy="0" cx="0" fill="#1d1d1d"><animate repeatCount="indefinite" attributeName="rx" dur="2s" begin="0s" fill="freeze" values="60.813; 60.813; 58.813; 60.813; 60.813" keyTimes="0; 0.25; 0.333333; 0.375; 1" keySplines="0 0 1 1; 0 0 1 1; 0 0 1 1; 0 0 1 1" calcMode="spline" /><animate repeatCount="indefinite" attributeName="ry" dur="2s" begin="0s" fill="freeze" values="80.813; 80.813; 87.313; 80.813; 80.813" keyTimes="0; 0.25; 0.333333; 0.375; 1" keySplines="0 0 1 1; 0 0 1 1; 0 0 1 1; 0 0 1 1" calcMode="spline" /></ellipse></g></g></g><g id="i4" transform="matrix(0.848,0.53,-0.53,0.848,-150.629,-32.18)"><ellipse ry="42.313" rx="31.84" cy="0" cx="0" fill="#fafafa" /></g></g></g></g></g></g></g></g><g id="i0"><g transform="translate(195,347)"><animateTransform repeatCount="indefinite" type="translate" attributeName="transform" dur="2s" begin="0s" calcMode="spline" values="195 347; 195 347; 195 358; 195 347; 195 347; 195 358; 195 347; 195 347" keyTimes="0; 0.125; 0.25; 0.375; 0.6875; 0.8125; 0.9375; 1" keySplines="0 0 1 1; 0.333 0 0.667 1; 0.333 0 0.667 1; 0 0 1 1; 0.333 0 0.667 1; 0.333 0 0.667 1; 0 0 1 1" fill="freeze" /><g transform="scale(1,1)"><animateTransform repeatCount="indefinite" type="scale" attributeName="transform" dur="2s" begin="0s" calcMode="spline" values="1 1; 1 1; 1.06 0.93; 1 1; 0.98 1.03; 1 1; 1 1; 1.06 0.93; 1 1; 0.98 1.03; 1 1; 1 1" keyTimes="0; 0.125; 0.208333; 0.3125; 0.375; 0.416666; 0.6875; 0.770834; 0.875; 0.9375; 0.979167; 1" keySplines="0 0 1 1; 0.333 0 0.667 1; 0.333 0 0.667 1; 0.333 0 0.833 1; 0.167 0 0.667 1; 0.333 0 0.667 1; 0.333 0 0.667 1; 0.333 0 0.667 1; 0.333 0 0.833 1; 0.167 0 0.667 1; 0 0 1 1" fill="freeze" /><g transform="translate(130,-22)"><g transform="matrix(1,0,0,1,0,0)" visibility="hidden" id="i5"><animate repeatCount="indefinite" begin="0s" calcMode="discrete" dur="2s" values="hidden; visible; hidden; hidden" keyTimes="0; 0.146; 0.375; 1" attributeName="visibility" /><g id="i6" transform="matrix(1,0,0,1,-135.828,16)"><path d="M127.813,0C127.813,108.144,70.589,195.812,0,195.812C-70.589,195.812,-127.812,108.144,-127.812,0C-127.991,0.498,-123.172,192,-0.346,195.377C120.79,198.707,128.825,0,127.813,0Z" stroke-width="20" stroke="#1d1d1d" fill="#fafafa"><animate repeatCount="indefinite" attributeName="d" dur="2s" begin="0s" calcMode="spline" values="M127.813,0C127.813,108.144,70.589,195.812,0,195.812C-70.589,195.812,-127.812,108.144,-127.812,0C-127.991,0.498,-123.172,192,-0.346,195.377C120.79,198.707,128.825,0,127.813,0Z; M127.813,0C127.813,108.144,70.589,195.812,0,195.812C-70.589,195.812,-127.812,108.144,-127.812,0C-127.991,0.498,-123.172,192,-0.346,195.377C120.79,198.707,128.825,0,127.813,0Z; M127.813,0C127.813,108.144,70.589,195.812,0,195.812C-70.589,195.812,-127.812,108.144,-127.812,0C-127.991,0.498,-64.112,0.5,-0.173,0.377C64.295,0.253,128.825,0,127.813,0Z; M127.812,0C127.812,108.144,70.589,195.812,0,195.812C-70.589,195.812,-127.812,108.144,-127.812,0C-127.991,0.498,-123.172,192,-0.346,195.377C120.79,198.707,128.824,0,127.812,0Z; M127.812,0C127.812,108.144,70.589,195.812,0,195.812C-70.589,195.812,-127.812,108.144,-127.812,0C-127.991,0.498,-123.172,192,-0.346,195.377C120.79,198.707,128.824,0,127.812,0Z" keyTimes="0; 0.125; 0.3125; 0.375; 1" keySplines="0 0 1 1; 0.065 0 0 1; 0.203 0 0 1; 0 0 1 1" fill="freeze" /></path></g><g id="i7" transform="matrix(1,0,0,1,-135.828,16)"><path d="M0,-195.812C70.589,-195.812,127.812,-108.144,127.812,0C128.319,-0.499,118.829,-198.691,0.352,-196.375C-121.172,-194,-127.491,0,-127.812,0C-127.812,-108.144,-70.589,-195.812,0,-195.812Z" stroke-width="20" stroke="#1d1d1d" fill="#fafafa"><animate repeatCount="indefinite" attributeName="d" dur="2s" begin="0s" calcMode="spline" values="M0,-195.812C70.589,-195.812,127.812,-108.144,127.812,0C128.319,-0.499,118.829,-198.691,0.352,-196.375C-121.172,-194,-127.491,0,-127.812,0C-127.812,-108.144,-70.589,-195.812,0,-195.812Z; M0,-195.812C70.589,-195.812,127.812,-108.144,127.812,0C128.319,-0.499,118.829,-198.691,0.352,-196.375C-121.172,-194,-127.491,0,-127.812,0C-127.812,-108.144,-70.589,-195.812,0,-195.812Z; M0,-195.812C70.589,-195.812,127.812,-108.144,127.812,0C128.319,-0.499,75.122,50,0.588,51.625C-69.901,53.161,-127.491,0,-127.812,0C-127.812,-108.144,-70.589,-195.812,0,-195.812Z; M0,-195.812C70.589,-195.812,127.812,-108.144,127.812,0C128.319,-0.499,75.122,50,0.588,51.625C-69.901,53.161,-127.491,0,-127.812,0C-127.812,-108.144,-70.589,-195.812,0,-195.812Z; M0,-195.812C70.589,-195.812,127.812,-108.144,127.812,0C128.319,-0.499,118.829,-198.691,0.352,-196.375C-121.172,-194,-127.491,0,-127.812,0C-127.812,-108.144,-70.589,-195.812,0,-195.812Z; M0,-195.812C70.589,-195.812,127.812,-108.144,127.812,0C128.319,-0.499,118.829,-198.691,0.352,-196.375C-121.172,-194,-127.491,0,-127.812,0C-127.812,-108.144,-70.589,-195.812,0,-195.812Z" keyTimes="0; 0.125; 0.25; 0.3125; 0.395833; 1" keySplines="0 0 1 1; 0.065 0 0 1; 0.167 0 0.833 1; 0.203 0 0 1; 0 0 1 1" fill="freeze" /></path></g></g></g></g></g></g><g id="i0"><g transform="translate(195,347)"><animateTransform repeatCount="indefinite" type="translate" attributeName="transform" dur="2s" begin="0s" calcMode="spline" values="195 347; 195 347; 195 358; 195 347; 195 347; 195 358; 195 347; 195 347" keyTimes="0; 0.125; 0.25; 0.375; 0.6875; 0.8125; 0.9375; 1" keySplines="0 0 1 1; 0.333 0 0.667 1; 0.333 0 0.667 1; 0 0 1 1; 0.333 0 0.667 1; 0.333 0 0.667 1; 0 0 1 1" fill="freeze" /><g transform="scale(1,1)"><animateTransform repeatCount="indefinite" type="scale" attributeName="transform" dur="2s" begin="0s" calcMode="spline" values="1 1; 1 1; 1.06 0.93; 1 1; 0.98 1.03; 1 1; 1 1; 1.06 0.93; 1 1; 0.98 1.03; 1 1; 1 1" keyTimes="0; 0.125; 0.208333; 0.3125; 0.375; 0.416666; 0.6875; 0.770834; 0.875; 0.9375; 0.979167; 1" keySplines="0 0 1 1; 0.333 0 0.667 1; 0.333 0 0.667 1; 0.333 0 0.833 1; 0.167 0 0.667 1; 0.333 0 0.667 1; 0.333 0 0.667 1; 0.333 0 0.667 1; 0.333 0 0.833 1; 0.167 0 0.667 1; 0 0 1 1" fill="freeze" /><g transform="translate(130,-22)"><g transform="matrix(1,0,0,1,0,0)" visibility="hidden" id="i8"><animate repeatCount="indefinite" begin="0s" calcMode="discrete" dur="2s" values="hidden; visible; hidden; hidden" keyTimes="0; 0.708; 0.938; 1" attributeName="visibility" /><g id="i9" transform="matrix(1,0,0,1,-135.828,16)"><path d="M127.813,0C127.813,108.144,70.589,195.812,0,195.812C-70.589,195.812,-127.812,108.144,-127.812,0C-127.991,0.498,-123.172,192,-0.346,195.377C120.79,198.707,128.825,0,127.813,0Z" stroke-width="20" stroke="#1d1d1d" fill="#fafafa"><animate repeatCount="indefinite" attributeName="d" dur="2s" begin="0s" calcMode="spline" values="M127.813,0C127.813,108.144,70.589,195.812,0,195.812C-70.589,195.812,-127.812,108.144,-127.812,0C-127.991,0.498,-123.172,192,-0.346,195.377C120.79,198.707,128.825,0,127.813,0Z; M127.813,0C127.813,108.144,70.589,195.812,0,195.812C-70.589,195.812,-127.812,108.144,-127.812,0C-127.991,0.498,-123.172,192,-0.346,195.377C120.79,198.707,128.825,0,127.813,0Z; M127.813,0C127.813,108.144,70.589,195.812,0,195.812C-70.589,195.812,-127.812,108.144,-127.812,0C-127.991,0.498,-64.112,0.5,-0.173,0.377C64.295,0.253,128.825,0,127.813,0Z; M127.812,0C127.812,108.144,70.589,195.812,0,195.812C-70.589,195.812,-127.812,108.144,-127.812,0C-127.991,0.498,-123.172,192,-0.346,195.377C120.79,198.707,128.824,0,127.812,0Z; M127.812,0C127.812,108.144,70.589,195.812,0,195.812C-70.589,195.812,-127.812,108.144,-127.812,0C-127.991,0.498,-123.172,192,-0.346,195.377C120.79,198.707,128.824,0,127.812,0Z" keyTimes="0; 0.6875; 0.875; 0.9375; 1" keySplines="0 0 1 1; 0.065 0 0 1; 0.203 0 0 1; 0 0 1 1" fill="freeze" /></path></g><g id="i10" transform="matrix(1,0,0,1,-135.828,16)"><path d="M0,-195.812C70.589,-195.812,127.812,-108.144,127.812,0C128.319,-0.499,118.829,-198.691,0.352,-196.375C-121.172,-194,-127.491,0,-127.812,0C-127.812,-108.144,-70.589,-195.812,0,-195.812Z" stroke-width="20" stroke="#1d1d1d" fill="#fafafa"><animate repeatCount="indefinite" attributeName="d" dur="2s" begin="0s" calcMode="spline" values="M0,-195.812C70.589,-195.812,127.812,-108.144,127.812,0C128.319,-0.499,118.829,-198.691,0.352,-196.375C-121.172,-194,-127.491,0,-127.812,0C-127.812,-108.144,-70.589,-195.812,0,-195.812Z; M0,-195.812C70.589,-195.812,127.812,-108.144,127.812,0C128.319,-0.499,118.829,-198.691,0.352,-196.375C-121.172,-194,-127.491,0,-127.812,0C-127.812,-108.144,-70.589,-195.812,0,-195.812Z; M0,-195.812C70.589,-195.812,127.812,-108.144,127.812,0C128.319,-0.499,75.122,50,0.588,51.625C-69.901,53.161,-127.491,0,-127.812,0C-127.812,-108.144,-70.589,-195.812,0,-195.812Z; M0,-195.812C70.589,-195.812,127.812,-108.144,127.812,0C128.319,-0.499,75.122,50,0.588,51.625C-69.901,53.161,-127.491,0,-127.812,0C-127.812,-108.144,-70.589,-195.812,0,-195.812Z; M0,-195.812C70.589,-195.812,127.812,-108.144,127.812,0C128.319,-0.499,118.829,-198.691,0.352,-196.375C-121.172,-194,-127.491,0,-127.812,0C-127.812,-108.144,-70.589,-195.812,0,-195.812Z; M0,-195.812C70.589,-195.812,127.812,-108.144,127.812,0C128.319,-0.499,118.829,-198.691,0.352,-196.375C-121.172,-194,-127.491,0,-127.812,0C-127.812,-108.144,-70.589,-195.812,0,-195.812Z" keyTimes="0; 0.6875; 0.8125; 0.875; 0.958333; 1" keySplines="0 0 1 1; 0.065 0 0 1; 0.167 0 0.833 1; 0.203 0 0 1; 0 0 1 1" fill="freeze" /></path></g></g></g></g></g></g><g id="i0"><g transform="translate(195,347)"><animateTransform repeatCount="indefinite" type="translate" attributeName="transform" dur="2s" begin="0s" calcMode="spline" values="195 347; 195 347; 195 358; 195 347; 195 347; 195 358; 195 347; 195 347" keyTimes="0; 0.125; 0.25; 0.375; 0.6875; 0.8125; 0.9375; 1" keySplines="0 0 1 1; 0.333 0 0.667 1; 0.333 0 0.667 1; 0 0 1 1; 0.333 0 0.667 1; 0.333 0 0.667 1; 0 0 1 1" fill="freeze" /><g transform="scale(1,1)"><animateTransform repeatCount="indefinite" type="scale" attributeName="transform" dur="2s" begin="0s" calcMode="spline" values="1 1; 1 1; 1.06 0.93; 1 1; 0.98 1.03; 1 1; 1 1; 1.06 0.93; 1 1; 0.98 1.03; 1 1; 1 1" keyTimes="0; 0.125; 0.208333; 0.3125; 0.375; 0.416666; 0.6875; 0.770834; 0.875; 0.9375; 0.979167; 1" keySplines="0 0 1 1; 0.333 0 0.667 1; 0.333 0 0.667 1; 0.333 0 0.833 1; 0.167 0 0.667 1; 0.333 0 0.667 1; 0.333 0 0.667 1; 0.333 0 0.667 1; 0.333 0 0.833 1; 0.167 0 0.667 1; 0 0 1 1" fill="freeze" /><g transform="translate(130,-22)"><g transform="matrix(1,0,0,1,0,0)" id="i11"><g id="i12" transform="matrix(1,0,0,1,-135.828,16)"><ellipse ry="195.813" rx="127.813" cy="0" cx="0" stroke-width="20" stroke="#1d1d1d" /></g></g></g></g></g></g><g id="i13"><g transform="translate(470,347)"><animateTransform repeatCount="indefinite" type="translate" attributeName="transform" dur="2s" begin="0s" calcMode="spline" values="470 347; 470 347; 470 358; 470 347; 470 347; 470 358; 470 347; 470 347" keyTimes="0; 0.125; 0.25; 0.375; 0.6875; 0.8125; 0.9375; 1" keySplines="0 0 1 1; 0.333 0 0.667 1; 0.333 0 0.667 1; 0 0 1 1; 0.333 0 0.667 1; 0.333 0 0.667 1; 0 0 1 1" fill="freeze" /><g transform="scale(1,1)"><animateTransform repeatCount="indefinite" type="scale" attributeName="transform" dur="2s" begin="0s" calcMode="spline" values="1 1; 1 1; 1.06 0.93; 1 1; 0.98 1.03; 1 1; 1 1; 1.06 0.93; 1 1; 0.98 1.03; 1 1; 1 1" keyTimes="0; 0.125; 0.208333; 0.3125; 0.375; 0.416666; 0.6875; 0.770834; 0.875; 0.9375; 0.979167; 1" keySplines="0 0 1 1; 0.333 0 0.667 1; 0.333 0 0.667 1; 0.333 0 0.833 1; 0.167 0 0.667 1; 0.333 0 0.667 1; 0.333 0 0.667 1; 0.333 0 0.667 1; 0.333 0 0.833 1; 0.167 0 0.667 1; 0 0 1 1" fill="freeze" /><g transform="translate(130,-22)"><g id="i14" transform="matrix(1,0,0,1,-135.828,16)"><ellipse ry="195.813" rx="127.813" cy="0" cx="0" fill="#fafafa" /></g></g></g></g></g><g id="i13"><g transform="translate(470,347)"><animateTransform repeatCount="indefinite" type="translate" attributeName="transform" dur="2s" begin="0s" calcMode="spline" values="470 347; 470 347; 470 358; 470 347; 470 347; 470 358; 470 347; 470 347" keyTimes="0; 0.125; 0.25; 0.375; 0.6875; 0.8125; 0.9375; 1" keySplines="0 0 1 1; 0.333 0 0.667 1; 0.333 0 0.667 1; 0 0 1 1; 0.333 0 0.667 1; 0.333 0 0.667 1; 0 0 1 1" fill="freeze" /><g transform="scale(1,1)"><animateTransform repeatCount="indefinite" type="scale" attributeName="transform" dur="2s" begin="0s" calcMode="spline" values="1 1; 1 1; 1.06 0.93; 1 1; 0.98 1.03; 1 1; 1 1; 1.06 0.93; 1 1; 0.98 1.03; 1 1; 1 1" keyTimes="0; 0.125; 0.208333; 0.3125; 0.375; 0.416666; 0.6875; 0.770834; 0.875; 0.9375; 0.979167; 1" keySplines="0 0 1 1; 0.333 0 0.667 1; 0.333 0 0.667 1; 0.333 0 0.833 1; 0.167 0 0.667 1; 0.333 0 0.667 1; 0.333 0 0.667 1; 0.333 0 0.667 1; 0.333 0 0.833 1; 0.167 0 0.667 1; 0 0 1 1" fill="freeze" /><g transform="translate(130,-22)"><g id="i15"><g transform="translate(-135,20)"><animateTransform repeatCount="indefinite" type="translate" attributeName="transform" dur="2s" begin="0s" calcMode="spline" values="-135 20; -135 20; -135 69.176; -186 20; -186 20; -135 69.176; -135 20; -135 20" keyTimes="0; 0.125; 0.25; 0.375; 0.6875; 0.8125; 0.9375; 1" keySplines="0 0 1 1; 0.333 0 0.667 1; 0.333 0 0.667 1; 0 0 1 1; 0.167 0 0.667 1; 0.333 0 0.667 1; 0 0 1 1" fill="freeze" /><g transform="scale(1,1) translate(186,-20)"><g><g transform="translate(-186.82,16)"><g id="i16" transform="rotate(0)"><animateTransform repeatCount="indefinite" type="rotate" attributeName="transform" dur="2s" begin="0s" calcMode="spline" values="0; 0; -22; 0; 0" keyTimes="0; 0.25; 0.333333; 0.375; 1" keySplines="0 0 1 1; 0 0 1 1; 0 0 1 1; 0 0 1 1" fill="freeze" /><ellipse ry="80.813" rx="60.813" cy="0" cx="0" fill="#1d1d1d"><animate repeatCount="indefinite" attributeName="rx" dur="2s" begin="0s" fill="freeze" values="60.813; 60.813; 58.813; 60.813; 60.813" keyTimes="0; 0.25; 0.333333; 0.375; 1" keySplines="0 0 1 1; 0 0 1 1; 0 0 1 1; 0 0 1 1" calcMode="spline" /><animate repeatCount="indefinite" attributeName="ry" dur="2s" begin="0s" fill="freeze" values="80.813; 80.813; 87.313; 80.813; 80.813" keyTimes="0; 0.25; 0.333333; 0.375; 1" keySplines="0 0 1 1; 0 0 1 1; 0 0 1 1; 0 0 1 1" calcMode="spline" /></ellipse></g></g></g><g id="i17" transform="matrix(0.848,0.53,-0.53,0.848,-150.629,-32.18)"><ellipse ry="42.313" rx="31.84" cy="0" cx="0" fill="#fafafa" /></g></g></g></g></g></g></g></g><g id="i13"><g transform="translate(470,347)"><animateTransform repeatCount="indefinite" type="translate" attributeName="transform" dur="2s" begin="0s" calcMode="spline" values="470 347; 470 347; 470 358; 470 347; 470 347; 470 358; 470 347; 470 347" keyTimes="0; 0.125; 0.25; 0.375; 0.6875; 0.8125; 0.9375; 1" keySplines="0 0 1 1; 0.333 0 0.667 1; 0.333 0 0.667 1; 0 0 1 1; 0.333 0 0.667 1; 0.333 0 0.667 1; 0 0 1 1" fill="freeze" /><g transform="scale(1,1)"><animateTransform repeatCount="indefinite" type="scale" attributeName="transform" dur="2s" begin="0s" calcMode="spline" values="1 1; 1 1; 1.06 0.93; 1 1; 0.98 1.03; 1 1; 1 1; 1.06 0.93; 1 1; 0.98 1.03; 1 1; 1 1" keyTimes="0; 0.125; 0.208333; 0.3125; 0.375; 0.416666; 0.6875; 0.770834; 0.875; 0.9375; 0.979167; 1" keySplines="0 0 1 1; 0.333 0 0.667 1; 0.333 0 0.667 1; 0.333 0 0.833 1; 0.167 0 0.667 1; 0.333 0 0.667 1; 0.333 0 0.667 1; 0.333 0 0.667 1; 0.333 0 0.833 1; 0.167 0 0.667 1; 0 0 1 1" fill="freeze" /><g transform="translate(130,-22)"><g transform="matrix(1,0,0,1,0,0)" visibility="hidden" id="i18"><animate repeatCount="indefinite" begin="0s" calcMode="discrete" dur="2s" values="hidden; visible; hidden; hidden" keyTimes="0; 0.146; 0.375; 1" attributeName="visibility" /><g id="i19" transform="matrix(1,0,0,1,-135.828,16)"><path d="M127.813,0C127.813,108.144,70.589,195.812,0,195.812C-70.589,195.812,-127.812,108.144,-127.812,0C-127.991,0.498,-123.172,192,-0.346,195.377C120.79,198.707,128.825,0,127.813,0Z" stroke-width="20" stroke="#1d1d1d" fill="#fafafa"><animate repeatCount="indefinite" attributeName="d" dur="2s" begin="0s" calcMode="spline" values="M127.813,0C127.813,108.144,70.589,195.812,0,195.812C-70.589,195.812,-127.812,108.144,-127.812,0C-127.991,0.498,-123.172,192,-0.346,195.377C120.79,198.707,128.825,0,127.813,0Z; M127.813,0C127.813,108.144,70.589,195.812,0,195.812C-70.589,195.812,-127.812,108.144,-127.812,0C-127.991,0.498,-123.172,192,-0.346,195.377C120.79,198.707,128.825,0,127.813,0Z; M127.813,0C127.813,108.144,70.589,195.812,0,195.812C-70.589,195.812,-127.812,108.144,-127.812,0C-127.991,0.498,-64.112,0.5,-0.173,0.377C64.295,0.253,128.825,0,127.813,0Z; M127.812,0C127.812,108.144,70.589,195.812,0,195.812C-70.589,195.812,-127.812,108.144,-127.812,0C-127.991,0.498,-123.172,192,-0.346,195.377C120.79,198.707,128.824,0,127.812,0Z; M127.812,0C127.812,108.144,70.589,195.812,0,195.812C-70.589,195.812,-127.812,108.144,-127.812,0C-127.991,0.498,-123.172,192,-0.346,195.377C120.79,198.707,128.824,0,127.812,0Z" keyTimes="0; 0.125; 0.3125; 0.375; 1" keySplines="0 0 1 1; 0.065 0 0 1; 0.203 0 0 1; 0 0 1 1" fill="freeze" /></path></g><g id="i20" transform="matrix(1,0,0,1,-135.828,16)"><path d="M0,-195.812C70.589,-195.812,127.812,-108.144,127.812,0C128.319,-0.499,118.829,-198.691,0.352,-196.375C-121.172,-194,-127.491,0,-127.812,0C-127.812,-108.144,-70.589,-195.812,0,-195.812Z" stroke-width="20" stroke="#1d1d1d" fill="#fafafa"><animate repeatCount="indefinite" attributeName="d" dur="2s" begin="0s" calcMode="spline" values="M0,-195.812C70.589,-195.812,127.812,-108.144,127.812,0C128.319,-0.499,118.829,-198.691,0.352,-196.375C-121.172,-194,-127.491,0,-127.812,0C-127.812,-108.144,-70.589,-195.812,0,-195.812Z; M0,-195.812C70.589,-195.812,127.812,-108.144,127.812,0C128.319,-0.499,118.829,-198.691,0.352,-196.375C-121.172,-194,-127.491,0,-127.812,0C-127.812,-108.144,-70.589,-195.812,0,-195.812Z; M0,-195.812C70.589,-195.812,127.812,-108.144,127.812,0C128.319,-0.499,75.122,50,0.588,51.625C-69.901,53.161,-127.491,0,-127.812,0C-127.812,-108.144,-70.589,-195.812,0,-195.812Z; M0,-195.812C70.589,-195.812,127.812,-108.144,127.812,0C128.319,-0.499,75.122,50,0.588,51.625C-69.901,53.161,-127.491,0,-127.812,0C-127.812,-108.144,-70.589,-195.812,0,-195.812Z; M0,-195.812C70.589,-195.812,127.812,-108.144,127.812,0C128.319,-0.499,118.829,-198.691,0.352,-196.375C-121.172,-194,-127.491,0,-127.812,0C-127.812,-108.144,-70.589,-195.812,0,-195.812Z; M0,-195.812C70.589,-195.812,127.812,-108.144,127.812,0C128.319,-0.499,118.829,-198.691,0.352,-196.375C-121.172,-194,-127.491,0,-127.812,0C-127.812,-108.144,-70.589,-195.812,0,-195.812Z" keyTimes="0; 0.125; 0.25; 0.3125; 0.395833; 1" keySplines="0 0 1 1; 0.065 0 0 1; 0.167 0 0.833 1; 0.203 0 0 1; 0 0 1 1" fill="freeze" /></path></g></g></g></g></g></g><g id="i13"><g transform="translate(470,347)"><animateTransform repeatCount="indefinite" type="translate" attributeName="transform" dur="2s" begin="0s" calcMode="spline" values="470 347; 470 347; 470 358; 470 347; 470 347; 470 358; 470 347; 470 347" keyTimes="0; 0.125; 0.25; 0.375; 0.6875; 0.8125; 0.9375; 1" keySplines="0 0 1 1; 0.333 0 0.667 1; 0.333 0 0.667 1; 0 0 1 1; 0.333 0 0.667 1; 0.333 0 0.667 1; 0 0 1 1" fill="freeze" /><g transform="scale(1,1)"><animateTransform repeatCount="indefinite" type="scale" attributeName="transform" dur="2s" begin="0s" calcMode="spline" values="1 1; 1 1; 1.06 0.93; 1 1; 0.98 1.03; 1 1; 1 1; 1.06 0.93; 1 1; 0.98 1.03; 1 1; 1 1" keyTimes="0; 0.125; 0.208333; 0.3125; 0.375; 0.416666; 0.6875; 0.770834; 0.875; 0.9375; 0.979167; 1" keySplines="0 0 1 1; 0.333 0 0.667 1; 0.333 0 0.667 1; 0.333 0 0.833 1; 0.167 0 0.667 1; 0.333 0 0.667 1; 0.333 0 0.667 1; 0.333 0 0.667 1; 0.333 0 0.833 1; 0.167 0 0.667 1; 0 0 1 1" fill="freeze" /><g transform="translate(130,-22)"><g transform="matrix(1,0,0,1,0,0)" visibility="hidden" id="i21"><animate repeatCount="indefinite" begin="0s" calcMode="discrete" dur="2s" values="hidden; visible; hidden; hidden" keyTimes="0; 0.708; 0.938; 1" attributeName="visibility" /><g id="i22" transform="matrix(1,0,0,1,-135.828,16)"><path d="M127.813,0C127.813,108.144,70.589,195.812,0,195.812C-70.589,195.812,-127.812,108.144,-127.812,0C-127.991,0.498,-123.172,192,-0.346,195.377C120.79,198.707,128.825,0,127.813,0Z" stroke-width="20" stroke="#1d1d1d" fill="#fafafa"><animate repeatCount="indefinite" attributeName="d" dur="2s" begin="0s" calcMode="spline" values="M127.813,0C127.813,108.144,70.589,195.812,0,195.812C-70.589,195.812,-127.812,108.144,-127.812,0C-127.991,0.498,-123.172,192,-0.346,195.377C120.79,198.707,128.825,0,127.813,0Z; M127.813,0C127.813,108.144,70.589,195.812,0,195.812C-70.589,195.812,-127.812,108.144,-127.812,0C-127.991,0.498,-123.172,192,-0.346,195.377C120.79,198.707,128.825,0,127.813,0Z; M127.813,0C127.813,108.144,70.589,195.812,0,195.812C-70.589,195.812,-127.812,108.144,-127.812,0C-127.991,0.498,-64.112,0.5,-0.173,0.377C64.295,0.253,128.825,0,127.813,0Z; M127.812,0C127.812,108.144,70.589,195.812,0,195.812C-70.589,195.812,-127.812,108.144,-127.812,0C-127.991,0.498,-123.172,192,-0.346,195.377C120.79,198.707,128.824,0,127.812,0Z; M127.812,0C127.812,108.144,70.589,195.812,0,195.812C-70.589,195.812,-127.812,108.144,-127.812,0C-127.991,0.498,-123.172,192,-0.346,195.377C120.79,198.707,128.824,0,127.812,0Z" keyTimes="0; 0.6875; 0.875; 0.9375; 1" keySplines="0 0 1 1; 0.065 0 0 1; 0.203 0 0 1; 0 0 1 1" fill="freeze" /></path></g><g id="i23" transform="matrix(1,0,0,1,-135.828,16)"><path d="M0,-195.812C70.589,-195.812,127.812,-108.144,127.812,0C128.319,-0.499,118.829,-198.691,0.352,-196.375C-121.172,-194,-127.491,0,-127.812,0C-127.812,-108.144,-70.589,-195.812,0,-195.812Z" stroke-width="20" stroke="#1d1d1d" fill="#fafafa"><animate repeatCount="indefinite" attributeName="d" dur="2s" begin="0s" calcMode="spline" values="M0,-195.812C70.589,-195.812,127.812,-108.144,127.812,0C128.319,-0.499,118.829,-198.691,0.352,-196.375C-121.172,-194,-127.491,0,-127.812,0C-127.812,-108.144,-70.589,-195.812,0,-195.812Z; M0,-195.812C70.589,-195.812,127.812,-108.144,127.812,0C128.319,-0.499,118.829,-198.691,0.352,-196.375C-121.172,-194,-127.491,0,-127.812,0C-127.812,-108.144,-70.589,-195.812,0,-195.812Z; M0,-195.812C70.589,-195.812,127.812,-108.144,127.812,0C128.319,-0.499,75.122,50,0.588,51.625C-69.901,53.161,-127.491,0,-127.812,0C-127.812,-108.144,-70.589,-195.812,0,-195.812Z; M0,-195.812C70.589,-195.812,127.812,-108.144,127.812,0C128.319,-0.499,75.122,50,0.588,51.625C-69.901,53.161,-127.491,0,-127.812,0C-127.812,-108.144,-70.589,-195.812,0,-195.812Z; M0,-195.812C70.589,-195.812,127.812,-108.144,127.812,0C128.319,-0.499,118.829,-198.691,0.352,-196.375C-121.172,-194,-127.491,0,-127.812,0C-127.812,-108.144,-70.589,-195.812,0,-195.812Z; M0,-195.812C70.589,-195.812,127.812,-108.144,127.812,0C128.319,-0.499,118.829,-198.691,0.352,-196.375C-121.172,-194,-127.491,0,-127.812,0C-127.812,-108.144,-70.589,-195.812,0,-195.812Z" keyTimes="0; 0.6875; 0.8125; 0.875; 0.958333; 1" keySplines="0 0 1 1; 0.065 0 0 1; 0.167 0 0.833 1; 0.203 0 0 1; 0 0 1 1" fill="freeze" /></path></g></g></g></g></g></g><g id="i13"><g transform="translate(470,347)"><animateTransform repeatCount="indefinite" type="translate" attributeName="transform" dur="2s" begin="0s" calcMode="spline" values="470 347; 470 347; 470 358; 470 347; 470 347; 470 358; 470 347; 470 347" keyTimes="0; 0.125; 0.25; 0.375; 0.6875; 0.8125; 0.9375; 1" keySplines="0 0 1 1; 0.333 0 0.667 1; 0.333 0 0.667 1; 0 0 1 1; 0.333 0 0.667 1; 0.333 0 0.667 1; 0 0 1 1" fill="freeze" /><g transform="scale(1,1)"><animateTransform repeatCount="indefinite" type="scale" attributeName="transform" dur="2s" begin="0s" calcMode="spline" values="1 1; 1 1; 1.06 0.93; 1 1; 0.98 1.03; 1 1; 1 1; 1.06 0.93; 1 1; 0.98 1.03; 1 1; 1 1" keyTimes="0; 0.125; 0.208333; 0.3125; 0.375; 0.416666; 0.6875; 0.770834; 0.875; 0.9375; 0.979167; 1" keySplines="0 0 1 1; 0.333 0 0.667 1; 0.333 0 0.667 1; 0.333 0 0.833 1; 0.167 0 0.667 1; 0.333 0 0.667 1; 0.333 0 0.667 1; 0.333 0 0.667 1; 0.333 0 0.833 1; 0.167 0 0.667 1; 0 0 1 1" fill="freeze" /><g transform="translate(130,-22)"><g transform="matrix(1,0,0,1,0,0)" id="i24"><g id="i25" transform="matrix(1,0,0,1,-135.828,16)"><ellipse ry="195.813" rx="127.813" cy="0" cx="0" stroke-width="20" stroke="#1d1d1d" /></g></g></g></g></g></g></svg>
Binary file
@@ -0,0 +1,41 @@
1
+ """Public configuration API shared by every Nixi component.
2
+
3
+ The implementation remains import-compatible with older ``app.server.config``
4
+ imports while new code can depend on this component-neutral module.
5
+ """
6
+
7
+ from app.server.config import (
8
+ DEFAULT_CONFIG_PATH,
9
+ DEFAULT_SYSTEM_PROMPT,
10
+ USER_CONFIG_PATH,
11
+ ActionConfig,
12
+ LLMConfig,
13
+ NixiConfig,
14
+ ServerConfig,
15
+ STTConfig,
16
+ TTSConfig,
17
+ VisionConfig,
18
+ VoiceConfig,
19
+ default_config,
20
+ load_config,
21
+ resolve_config_path,
22
+ ensure_config_exists,
23
+ )
24
+
25
+ __all__ = [
26
+ "DEFAULT_CONFIG_PATH",
27
+ "DEFAULT_SYSTEM_PROMPT",
28
+ "USER_CONFIG_PATH",
29
+ "ActionConfig",
30
+ "LLMConfig",
31
+ "NixiConfig",
32
+ "ServerConfig",
33
+ "STTConfig",
34
+ "TTSConfig",
35
+ "VisionConfig",
36
+ "VoiceConfig",
37
+ "default_config",
38
+ "load_config",
39
+ "resolve_config_path",
40
+ "ensure_config_exists",
41
+ ]
@@ -0,0 +1,37 @@
1
+ """Load local secrets for interactive and systemd launches."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import os
6
+ from pathlib import Path
7
+
8
+ REPO_ROOT = Path(__file__).resolve().parents[1]
9
+
10
+
11
+ def load_environment() -> None:
12
+ """Load simple KEY=VALUE secrets without overriding the process environment."""
13
+ from app.config import ensure_config_exists, USER_CONFIG_PATH
14
+ ensure_config_exists()
15
+
16
+ # Helper to parse and set non-empty environment variables from a file
17
+ def load_from_file(path: Path) -> None:
18
+ if not path.exists():
19
+ return
20
+ for raw_line in path.read_text(encoding="utf-8").splitlines():
21
+ line = raw_line.strip()
22
+ if not line or line.startswith("#") or "=" not in line:
23
+ continue
24
+ name, value = line.split("=", 1)
25
+ name = name.strip()
26
+ value = value.strip()
27
+ if len(value) >= 2 and value[0] == value[-1] and value[0] in {'"', "'"}:
28
+ value = value[1:-1]
29
+ if name and value:
30
+ os.environ.setdefault(name, value)
31
+
32
+ # 1. Load from ~/.config/nixi/.env first (user overrides)
33
+ load_from_file(USER_CONFIG_PATH.parent / ".env")
34
+
35
+ # 2. Fall back to REPO_ROOT / ".env" (local development)
36
+ if REPO_ROOT != USER_CONFIG_PATH.parent:
37
+ load_from_file(REPO_ROOT / ".env")
@@ -0,0 +1,18 @@
1
+ """Small structured event logger shared by Nixi processes."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import json
6
+ from datetime import datetime
7
+ from typing import Any
8
+
9
+
10
+ def log_event(component: str, event: str, request_id: str, **details: Any) -> None:
11
+ payload = {
12
+ "timestamp": datetime.now().astimezone().isoformat(timespec="milliseconds"),
13
+ "component": component,
14
+ "request_id": request_id,
15
+ "event": event,
16
+ **details,
17
+ }
18
+ print(json.dumps(payload, ensure_ascii=False, default=str), flush=True)
@@ -0,0 +1 @@
1
+ """GTK popup for Nixi."""
@@ -0,0 +1,18 @@
1
+ """Launch the GTK popup with the system interpreter that owns its GI bindings."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import os
6
+ from pathlib import Path
7
+
8
+
9
+ SYSTEM_PYTHON = "/usr/bin/python3"
10
+
11
+
12
+ def main() -> None:
13
+ popup = Path(__file__).with_name("main.py")
14
+ os.execv(SYSTEM_PYTHON, [SYSTEM_PYTHON, str(popup)])
15
+
16
+
17
+ if __name__ == "__main__":
18
+ main()