.
dybdeskarphet-niri-companion-6d9cebf/README.md 0000664 0000000 0000000 00000003300 15207340103 0021315 0 ustar 00root root 0000000 0000000
🫂 niri-companion
niri-companion is a toolkit that adds extra functionality to
niri
Wiki
•
Changelog
## Overview
- `niri-genconfig` – allows having configuration groups for layered `niri ✨` setups
- `niri-workspaces` – creates sessions for different tasks.
- `niri-ipcext` – performs IPC-like modifications.
## Installation
Install with `pipx`, `pip` or `uv` accordingly:
```
pipx install niri-companion
pip install niri-companion
uv tool install niri-companion
```
- For Arch-based distributions, you can use the [`niri-companion`](https://aur.archlinux.org/packages/niri-companion) AUR package
- `git clone https://aur.archlinux.org/niri-companion.git && cd niri-companion && makepkg -si` **(recommended)**
- `paru -S niri-companion`
- `yay -S niri-companion`
- For Debian-based distributions, you can use the [`niri-companion`](https://tracker.debian.org/pkg/niri-companion) package (Available in Debian 14 and Above)
- `apt install niri-companion`
dybdeskarphet-niri-companion-6d9cebf/cliff.toml 0000664 0000000 0000000 00000007762 15207340103 0022036 0 ustar 00root root 0000000 0000000 # git-cliff ~ configuration file
# https://git-cliff.org/docs/configuration
[changelog]
# A Tera template to be rendered for each release in the changelog.
# See https://keats.github.io/tera/docs/#introduction
body = """
{% if version %}\
## [{{ version | trim_start_matches(pat="v") }}] - {{ timestamp | date(format="%Y-%m-%d") }}
{% else %}\
## [unreleased]
{% endif %}\
{% for group, commits in commits | group_by(attribute="group") %}
### {{ group | striptags | trim | upper_first }}
{% for commit in commits %}
- {% if commit.scope %}*({{ commit.scope }})* {% endif %}\
{% if commit.breaking %}[**breaking**] {% endif %}\
{{ commit.message | upper_first }}\
{% endfor %}
{% endfor %}
"""
# Remove leading and trailing whitespaces from the changelog's body.
trim = true
# Render body even when there are no releases to process.
render_always = true
# An array of regex based postprocessors to modify the changelog.
postprocessors = [
# Replace the placeholder with a URL.
#{ pattern = '', replace = "https://github.com/orhun/git-cliff" },
]
# render body even when there are no releases to process
# render_always = true
# output file path
# output = "test.md"
[git]
# Parse commits according to the conventional commits specification.
# See https://www.conventionalcommits.org
conventional_commits = true
# Exclude commits that do not match the conventional commits specification.
filter_unconventional = true
# Require all commits to be conventional.
# Takes precedence over filter_unconventional.
require_conventional = false
# Split commits on newlines, treating each line as an individual commit.
split_commits = false
# An array of regex based parsers to modify commit messages prior to further processing.
commit_preprocessors = [
# Replace issue numbers with link templates to be updated in `changelog.postprocessors`.
#{ pattern = '\((\w+\s)?#([0-9]+)\)', replace = "([#${2}](/issues/${2}))"},
# Check spelling of the commit message using https://github.com/crate-ci/typos.
# If the spelling is incorrect, it will be fixed automatically.
#{ pattern = '.*', replace_command = 'typos --write-changes -' },
]
# Prevent commits that are breaking from being excluded by commit parsers.
protect_breaking_commits = false
# An array of regex based parsers for extracting data from the commit message.
# Assigns commits to groups.
# Optionally sets the commit's scope and can decide to exclude commits from further processing.
commit_parsers = [
{ message = "^feat", group = "🚀 Features" },
{ message = "^fix", group = "🐛 Bug Fixes" },
{ message = "^doc", group = "📚 Documentation", skip = true },
{ message = "^perf", group = "⚡ Performance" },
{ message = "^refactor", group = "🚜 Refactor" },
{ message = "^style", group = "🎨 Styling" },
{ message = "^test", group = "🧪 Testing" },
{ message = "^chore\\(release\\): prepare for", skip = true },
{ message = "^chore\\(deps.*\\)", skip = true },
{ message = "^chore\\(pr\\)", skip = true },
{ message = "^chore\\(pull\\)", skip = true },
{ message = "^chore|^ci", group = "⚙️ Miscellaneous Tasks" },
{ body = ".*security", group = "🛡️ Security" },
{ message = "^revert", group = "◀️ Revert" },
{ message = ".*", group = "💼 Other" },
]
# Exclude commits that are not matched by any commit parser.
filter_commits = false
# An array of link parsers for extracting external references, and turning them into URLs, using regex.
link_parsers = []
# Include only the tags that belong to the current branch.
use_branch_tags = false
# Order releases topologically instead of chronologically.
topo_order = false
# Order releases topologically instead of chronologically.
topo_order_commits = true
# Order of commits in each group/release within the changelog.
# Allowed values: newest, oldest
sort_commits = "oldest"
# Process submodules commits
recurse_submodules = false
dybdeskarphet-niri-companion-6d9cebf/default.nix 0000664 0000000 0000000 00000002334 15207340103 0022210 0 ustar 00root root 0000000 0000000 {
pkgs ? import {},
python ? (
if pkgs ? python3_13
then pkgs.python3_13
else pkgs.python3
),
}: let
lib = pkgs.lib;
pypkgs = python.pkgs;
# Override typer to a version compatible with pyproject (>=0.19.1)
typer_019 = pypkgs.typer.overrideAttrs (old: rec {
version = "0.19.1";
src = pkgs.fetchPypi {
pname = "typer";
inherit version;
sha256 = "sha256-y4gUM6SxXazIdbsFg9GmHnhJeAZ0H5q6eSq8qzkMA+Y=";
};
});
in
pypkgs.buildPythonPackage rec {
pname = "niri-companion";
version = "2.4.0";
# PEP 517/518 build using setuptools declared in pyproject.toml
pyproject = true;
src = ./.;
build-system = [pypkgs.setuptools];
# Runtime dependencies from pyproject.toml
dependencies = [
pypkgs.pydantic
pypkgs.rich
pypkgs."tomli-w"
typer_019
pypkgs.watchdog
];
# Run tests with pytest
nativeCheckInputs = [pypkgs.pytestCheckHook];
doCheck = false;
# Optional: only import safe submodules during import checks
# to avoid triggering config load at import time.
pythonImportsCheck = [
"companion.utils.general"
"companion.utils.genconfig"
"companion.models.config"
];
}
dybdeskarphet-niri-companion-6d9cebf/examples/ 0000775 0000000 0000000 00000000000 15207340103 0021660 5 ustar 00root root 0000000 0000000 dybdeskarphet-niri-companion-6d9cebf/examples/settings.toml 0000664 0000000 0000000 00000001334 15207340103 0024416 0 ustar 00root root 0000000 0000000 [general]
output_path = "~/.config/niri/config.kdl"
[genconfig]
watch_dir="$XDG_CONFIG_HOME/niri/src/"
sources = [
"$XDG_CONFIG_HOME/niri/src/internal.kdl",
"$XDG_CONFIG_HOME/niri/src/monitors.kdl",
"$XDG_CONFIG_HOME/niri/src/input.kdl",
"$XDG_CONFIG_HOME/niri/src/keybindings.kdl",
"$XDG_CONFIG_HOME/niri/src/visual.kdl",
"$XDG_CONFIG_HOME/niri/src/rules.kdl",
]
[workspaces]
dmenu_command = "rofi -dmenu -theme ~/.local/share/rofi/themes/basic_launcher/rounded_with_listview.rasi -p ' workspace'"
task_delay = 0.6
[workspaces.items]
"leetcoding" = [
{ workspace = 1, run = 'footclient -e fish -c "nvim; fish"' },
{ workspace = 1, run = "brave --new-window https://leetcode.com/ https://neetcode.io/" },
]
dybdeskarphet-niri-companion-6d9cebf/man/ 0000775 0000000 0000000 00000000000 15207340103 0020615 5 ustar 00root root 0000000 0000000 dybdeskarphet-niri-companion-6d9cebf/man/convert.sh 0000775 0000000 0000000 00000000112 15207340103 0022626 0 ustar 00root root 0000000 0000000 #!/bin/bash
for f in *.1.md; do pandoc "$f" -s -t man -o "${f%.md}"; done
dybdeskarphet-niri-companion-6d9cebf/man/niri-genconfig.1 0000664 0000000 0000000 00000004275 15207340103 0023605 0 ustar 00root root 0000000 0000000 .\" Automatically generated by Pandoc 3.9.0.2
.\"
.TH "NIRI\-GENCONFIG" "1" "May 2026" "niri\-genconfig 4.0.1" "niri\-companion Manual"
.SH NAME
niri\-genconfig \- niri\-companion config generation tool
.SH SYNOPSIS
\f[B]niri\-genconfig\f[R] [\f[I]OPTIONS\f[R]] \f[I]COMMAND\f[R]
[\f[I]ARGS\f[R]]\&...
.SH DESCRIPTION
\f[B]niri\-genconfig\f[R] manages niri configuration by combining
multiple KDL files.
It supports grouping sources, allowing users to switch between different
visual styles or monitor setups easily.
.SH OPTIONS
.TP
\f[B]\-h, \(enhelp\f[R]
Show help message and exit.
.SH COMMANDS
.SS generate [\f[I]GROUP\f[R]]
Combine source files into the final niri configuration.
.TP
\f[B]\-u, \(enuse\-include\f[R]
Instead of merging file contents, write a file containing KDL
\f[CR]include\f[R] statements for each source.
Useful for debugging or keeping the output file clean.
.TP
\f[B]GROUP\f[R]
Select a specific configuration group.
Standalone source strings are always included.
Objects matching the group name are included.
Defaults to \(lqdefault\(rq.
.SS daemon [\f[I]GROUP\f[R]]
Start a daemon that monitors the \f[CR]watch_dir\f[R].
It regenerates the configuration automatically whenever a source file is
modified.
.TP
\f[B]GROUP\f[R]
The configuration group to use for automatic generation.
.SH CONFIGURATION
Stored in \f[CR]\(ti/.config/niri\-companion/settings.toml\f[R].
.SS [general]
.TP
\f[B]output_path\f[R]
Target niri config (e.g.,
\f[CR]\(dq\(ti/.config/niri/config.kdl\(dq\f[R]).
.SS [genconfig]
.TP
\f[B]watch_dir\f[R]
Directory to monitor (default:
\f[CR]\(dq\(ti/.config/niri/sources\(dq\f[R]).
.TP
\f[B]sources\f[R]
List of strings (paths) or arrays of objects (groups).
.SS Example Configuration
.IP
.EX
\f[B][genconfig]\f[R]
sources = [
\(dq\(ti/niri/base.kdl\(dq,
[
{ group = \(dqdefault\(dq, path = \(dq\(ti/niri/visual_standard.kdl\(dq },
{ group = \(dqcool\(dq, path = \(dq\(ti/niri/visual_custom.kdl\(dq },
]
]
.EE
.SH EXAMPLES
Generate the default configuration:
.RS
.PP
\f[B]niri\-genconfig generate\f[R]
.RE
.PP
Generate a specific group using includes:
.RS
.PP
\f[B]niri\-genconfig generate \-u cool\f[R]
.RE
.SH SEE ALSO
\f[B]niri\-ipcext\f[R](1), \f[B]niri\-workspaces\f[R](1)
dybdeskarphet-niri-companion-6d9cebf/man/niri-genconfig.1.md 0000664 0000000 0000000 00000003613 15207340103 0024177 0 ustar 00root root 0000000 0000000 ---
title: NIRI-GENCONFIG
section: 1
date: May 2026
header: niri-companion Manual
footer: niri-genconfig 4.0.1
---
# NAME
niri-genconfig - niri-companion config generation tool
# SYNOPSIS
**niri-genconfig** [*OPTIONS*] _COMMAND_ [*ARGS*]...
# DESCRIPTION
**niri-genconfig** manages niri configuration by combining multiple KDL files. It supports grouping sources, allowing users to switch between different visual styles or monitor setups easily.
# OPTIONS
**-h, --help**
: Show help message and exit.
# COMMANDS
## generate [*GROUP*]
Combine source files into the final niri configuration.
**-u, --use-include**
: Instead of merging file contents, write a file containing KDL `include` statements for each source. Useful for debugging or keeping the output file clean.
**GROUP**
: Select a specific configuration group. Standalone source strings are always included. Objects matching the group name are included. Defaults to "default".
## daemon [*GROUP*]
Start a daemon that monitors the `watch_dir`. It regenerates the configuration automatically whenever a source file is modified.
**GROUP**
: The configuration group to use for automatic generation.
# CONFIGURATION
Stored in `~/.config/niri-companion/settings.toml`.
## [general]
**output_path**
: Target niri config (e.g., `"~/.config/niri/config.kdl"`).
## [genconfig]
**watch_dir**
: Directory to monitor (default: `"~/.config/niri/sources"`).
**sources**
: List of strings (paths) or arrays of objects (groups).
### Example Configuration
```toml
[genconfig]
sources = [
"~/niri/base.kdl",
[
{ group = "default", path = "~/niri/visual_standard.kdl" },
{ group = "cool", path = "~/niri/visual_custom.kdl" },
]
]
```
# EXAMPLES
Generate the default configuration:
> **niri-genconfig generate**
Generate a specific group using includes:
> **niri-genconfig generate -u cool**
# SEE ALSO
**niri-ipcext**(1), **niri-workspaces**(1)
dybdeskarphet-niri-companion-6d9cebf/man/niri-ipcext.1 0000664 0000000 0000000 00000002506 15207340103 0023135 0 ustar 00root root 0000000 0000000 .\" Automatically generated by Pandoc 3.9.0.2
.\"
.TH "NIRI\-IPCEXT" "1" "May 2026" "niri\-ipcext 4.0.1" "niri\-companion Manual"
.SH NAME
niri\-ipcext \- niri\-companion IPC\-like configuration tool
.SH SYNOPSIS
\f[B]niri\-ipcext\f[R] [\f[I]OPTIONS\f[R]] \f[I]COMMAND\f[R]
[\f[I]ARGS\f[R]]\&...
.SH DESCRIPTION
\f[B]niri\-ipcext\f[R] simulates IPC behavior by directly modifying the
niri configuration file.
It is useful for making temporary visual changes (like borders or gaps)
without manually editing files.
.SH OPTIONS
.TP
\f[B]\-h, \(enhelp\f[R]
Show help message and exit.
.SH COMMANDS
.SS replace \f[I]OLD\f[R] \f[I]NEW\f[R]
Surgically replaces a string in the config file.
.TP
\f[B]OLD\f[R]
The exact text to find.
Must match spaces and indentation perfectly.
.TP
\f[B]NEW\f[R]
The replacement text.
.SS restore
Wipes manual changes and restores the config to its base state by
running \f[B]niri\-genconfig generate\f[R].
.SH EXAMPLES
Changing border width from 2 to 10: > \f[B]niri\-ipcext replace `width
2' `width 10'\f[R]
.PP
Resetting all temporary changes: > \f[B]niri\-ipcext restore\f[R]
.SH NOTES
This tool modifies the file defined in \f[CR]general.output_path\f[R].
Because niri reloads its config when the file is touched, changes take
effect immediately.
.SH SEE ALSO
\f[B]niri\-genconfig\f[R](1), \f[B]niri\-workspaces\f[R](1)
dybdeskarphet-niri-companion-6d9cebf/man/niri-ipcext.1.md 0000664 0000000 0000000 00000002253 15207340103 0023533 0 ustar 00root root 0000000 0000000 ---
title: NIRI-IPCEXT
section: 1
date: May 2026
header: niri-companion Manual
footer: niri-ipcext 4.0.1
---
# NAME
niri-ipcext - niri-companion IPC-like configuration tool
# SYNOPSIS
**niri-ipcext** [*OPTIONS*] *COMMAND* [*ARGS*]...
# DESCRIPTION
**niri-ipcext** simulates IPC behavior by directly modifying the niri configuration file. It is useful for making temporary visual changes (like borders or gaps) without manually editing files.
# OPTIONS
**-h, --help**
: Show help message and exit.
# COMMANDS
## replace *OLD* *NEW*
Surgically replaces a string in the config file.
**OLD**
: The exact text to find. Must match spaces and indentation perfectly.
**NEW**
: The replacement text.
## restore
Wipes manual changes and restores the config to its base state by running **niri-genconfig generate**.
# EXAMPLES
Changing border width from 2 to 10:
> **niri-ipcext replace 'width 2' 'width 10'**
Resetting all temporary changes:
> **niri-ipcext restore**
# NOTES
This tool modifies the file defined in `general.output_path`. Because niri reloads its config when the file is touched, changes take effect immediately.
# SEE ALSO
**niri-genconfig**(1), **niri-workspaces**(1)
dybdeskarphet-niri-companion-6d9cebf/man/niri-workspaces.1 0000664 0000000 0000000 00000003101 15207340103 0024012 0 ustar 00root root 0000000 0000000 .\" Automatically generated by Pandoc 3.9.0.2
.\"
.TH "NIRI\-WORKSPACES" "1" "May 2026" "niri\-workspaces 4.0.1" "niri\-companion Manual"
.SH NAME
niri\-workspaces \- niri\-companion workspace management tool
.SH SYNOPSIS
\f[B]niri\-workspaces\f[R]
.SH DESCRIPTION
\f[B]niri\-workspaces\f[R] manages complex workspace layouts.
It presents a list of workspaces via a dmenu\-compatible picker (like
rofi).
Selecting a workspace triggers a sequence of commands to open specific
applications on specific workspaces.
.SH CONFIGURATION
Stored in \f[CR]\(ti/.config/niri\-companion/settings.toml\f[R].
.SS [workspaces]
.TP
\f[B]dmenu_command\f[R]
Picker command (default: \f[CR]\(dqrofi \-dmenu\(dq\f[R]).
.TP
\f[B]task_delay\f[R]
Default wait time in seconds between starting applications.
.SS [workspaces.items]
Defines the workspaces available in the picker.
Each item is a list of task objects.
.SS Task Object Fields
.TP
\f[B]workspace\f[R]
Target workspace number.
.TP
\f[B]run\f[R]
Shell command to execute.
.TP
\f[B]task_delay\f[R]
(Optional) Specific delay for this task.
.SH EXAMPLES
.SS Example Workspace Setup
.IP
.EX
\f[B][workspaces.items]\f[R]
\(dqdev\(dq = [
{ workspace = 1, run = \(aqfoot \-e nvim\(aq },
{ workspace = 2, run = \(aqbrave \-\-new\-window github.com\(aq, task_delay = 1.5 }
]
.EE
.SS Usage
Running the tool: > \f[B]niri\-workspaces\f[R]
.PP
Selecting \(lqdev\(rq will: 1.
Open a terminal with nvim on workspace 1.
2.
Wait 0.8s (default).
3.
Open Brave on workspace 2.
4.
Wait 1.5s (specific override).
.SH SEE ALSO
\f[B]niri\-genconfig\f[R](1), \f[B]niri\-ipcext\f[R](1)
dybdeskarphet-niri-companion-6d9cebf/man/niri-workspaces.1.md 0000664 0000000 0000000 00000002637 15207340103 0024426 0 ustar 00root root 0000000 0000000 ---
title: NIRI-WORKSPACES
section: 1
date: May 2026
header: niri-companion Manual
footer: niri-workspaces 4.0.1
---
# NAME
niri-workspaces - niri-companion workspace management tool
# SYNOPSIS
**niri-workspaces**
# DESCRIPTION
**niri-workspaces** manages complex workspace layouts. It presents a list of workspaces via a dmenu-compatible picker (like rofi). Selecting a workspace triggers a sequence of commands to open specific applications on specific workspaces.
# CONFIGURATION
Stored in `~/.config/niri-companion/settings.toml`.
## [workspaces]
**dmenu_command**
: Picker command (default: `"rofi -dmenu"`).
**task_delay**
: Default wait time in seconds between starting applications.
## [workspaces.items]
Defines the workspaces available in the picker. Each item is a list of task objects.
### Task Object Fields
**workspace**
: Target workspace number.
**run**
: Shell command to execute.
**task_delay**
: (Optional) Specific delay for this task.
# EXAMPLES
## Example Workspace Setup
```toml
[workspaces.items]
"dev" = [
{ workspace = 1, run = 'foot -e nvim' },
{ workspace = 2, run = 'brave --new-window github.com', task_delay = 1.5 }
]
```
## Usage
Running the tool:
> **niri-workspaces**
Selecting "dev" will:
1. Open a terminal with nvim on workspace 1.
2. Wait 0.8s (default).
3. Open Brave on workspace 2.
4. Wait 1.5s (specific override).
# SEE ALSO
**niri-genconfig**(1), **niri-ipcext**(1)
dybdeskarphet-niri-companion-6d9cebf/pyproject.toml 0000664 0000000 0000000 00000002043 15207340103 0022755 0 ustar 00root root 0000000 0000000 [project]
name = "niri-companion"
version = "5.0.0"
license = "GPL-3.0-or-later"
keywords = ["niri", "companion", "niri-companion", "wayland", "compositor"]
maintainers = [
{ name = "Ahmet Arda Kavakcı", email = "ahmetardakavakci@gmail.com" },
]
description = "Niri companion scripts"
readme = "README.md"
requires-python = ">=3.13"
dependencies = [
"pydantic>=2.11.7",
"rich>=14.1.0",
"tomli-w>=1.2.0",
"typer>=0.19.1",
"watchdog>=6.0.0",
]
[project.urls]
Documentation = "https://github.com/dybdeskarphet/niri-companion"
Issues = "https://github.com/dybdeskarphet/niri-companion/issues"
Repository = "https://github.com/dybdeskarphet/niri-companion"
Changelog = "https://github.com/dybdeskarphet/niri-companion/blob/main/CHANGELOG.md"
[project.scripts]
niri-genconfig = "companion.genconfig:app"
niri-ipcext = "companion.ipcext:app"
niri-workspaces = "companion.workspaces:main"
[tool.setuptools]
package-dir = { "" = "src" }
[tool.setuptools.packages.find]
where = ["src"]
[dependency-groups]
dev = ["pytest>=8.4.2", "pytest-cov>=7.0.0"]
dybdeskarphet-niri-companion-6d9cebf/pytest.ini 0000664 0000000 0000000 00000000074 15207340103 0022074 0 ustar 00root root 0000000 0000000 [pytest]
minversion = 6.0
addopts = -ra -q
pythonpath = src
dybdeskarphet-niri-companion-6d9cebf/shell.nix 0000664 0000000 0000000 00000000506 15207340103 0021672 0 ustar 00root root 0000000 0000000 {
pkgs ? import {},
python ? pkgs.python3,
}: let
pypkgs = python.pkgs;
package = import ./default.nix {inherit pkgs python;};
in
pkgs.mkShell {
packages = [
python
package
pypkgs.pip
pypkgs.setuptools
pypkgs.wheel
pypkgs.pytest
pypkgs."pytest-cov"
];
}
dybdeskarphet-niri-companion-6d9cebf/src/ 0000775 0000000 0000000 00000000000 15207340103 0020631 5 ustar 00root root 0000000 0000000 dybdeskarphet-niri-companion-6d9cebf/src/companion/ 0000775 0000000 0000000 00000000000 15207340103 0022614 5 ustar 00root root 0000000 0000000 dybdeskarphet-niri-companion-6d9cebf/src/companion/config.py 0000664 0000000 0000000 00000010222 15207340103 0024430 0 ustar 00root root 0000000 0000000 from os import environ
from pathlib import Path
import tomllib
from companion.models.config import (
AppConfig,
ConfigItem,
GenConfigSection,
GeneralConfig,
WorkspaceConfigSection,
WorkspaceItem,
WorkspaceItemsSection,
)
from companion.utils.general import expandall
import tomli_w
from pydantic import ValidationError
from companion.utils.logger import console, error, log, warn
class ConfigPath:
dir: Path
def __init__(self, program: str) -> None:
home = environ.get("HOME")
xdg_config = environ.get("XDG_CONFIG_HOME")
if home:
if xdg_config:
self.dir = Path(xdg_config) / program
else:
self.dir = Path(home) / ".config" / program
else:
error("No home directory found.")
# TODO: Typo, make it create_dir
def create_dir(self):
self.dir.mkdir(parents=True, exist_ok=True)
companion_config = ConfigPath("niri-companion")
companion_config.create_dir()
COMPANION_SETTINGS_PATH = companion_config.dir / "settings.toml"
def create_empty_config(path: Path):
empty_config = AppConfig(
general=GeneralConfig(output_path="~/.config/niri/probably_config.kdl"),
workspaces=WorkspaceConfigSection(
dmenu_command="rofi -dmenu",
task_delay=0.8,
items=WorkspaceItemsSection(
{"example": [WorkspaceItem(workspace=1, run="brave")]}
),
),
genconfig=GenConfigSection(
sources=[
"~/.config/niri/sources/first_config.kdl",
"~/.config/niri/sources/second_config.kdl",
[
ConfigItem(
group="default",
path="~/.config/niri/sources/default_visuals.kdl",
),
ConfigItem(
group="custom",
path="~/.config/niri/sources/custom_visuals.kdl",
),
],
],
watch_dir="~/.config/niri/sources/",
),
)
try:
with open(str(path), "wb") as f:
tomli_w.dump(empty_config.model_dump(exclude_none=True), f)
log("Config file created successfully!")
warn(
"Please edit the configuration file. Default configurations serve as placeholders."
)
except PermissionError:
error("No permission to write this file :/")
def read_config_file():
try:
with open(COMPANION_SETTINGS_PATH, "rb") as f:
return tomllib.load(f)
except FileNotFoundError:
from rich.prompt import Confirm
error(f"Config file not found at {COMPANION_SETTINGS_PATH}")
ans = Confirm.ask("Do you want to create a new configuration file?")
if ans:
create_empty_config(COMPANION_SETTINGS_PATH)
exit(1)
except tomllib.TOMLDecodeError as e:
error(f"Failed to parse TOML: {e}")
exit(1)
def expand_config(config: AppConfig):
for i, s in enumerate(config.genconfig.sources):
if isinstance(s, list):
for item in s:
item.path = expandall(item.path)
else:
config.genconfig.sources[i] = expandall(s)
config.genconfig.watch_dir = expandall(config.genconfig.watch_dir)
if not Path(config.genconfig.watch_dir).exists():
error("Watch directory doesn't exist, check your genconfig.watch_dir:")
exit(1)
config.general.output_path = expandall(config.general.output_path)
config.workspaces.dmenu_command = expandall(config.workspaces.dmenu_command)
def load_config():
try:
raw = read_config_file()
config = AppConfig(**raw)
except ValidationError as e:
from rich.table import Table
from rich import box
table = Table("Location", "Message", "Type", box=box.ROUNDED, min_width=80)
for err in e.errors():
loc = " -> ".join(str(x) for x in err["loc"])
table.add_row(loc, err["msg"], err["type"])
error(f"Invalid config file:")
console.print(table)
exit(1)
expand_config(config)
return config
config = load_config()
dybdeskarphet-niri-companion-6d9cebf/src/companion/genconfig.py 0000775 0000000 0000000 00000011235 15207340103 0025132 0 ustar 00root root 0000000 0000000 from pathlib import Path
import threading
import time
from typing import Annotated, override
import typer
from watchdog.events import DirModifiedEvent, FileModifiedEvent, FileSystemEventHandler
from companion.config import config
from companion.utils.genconfig import return_source
from companion.utils.logger import log, warn
class FileChangeHandler(FileSystemEventHandler):
def __init__(self, gen_config: "GenConfig"):
self.gen_config: GenConfig = gen_config
self.timer = None
@override
def on_modified(self, event: DirModifiedEvent | FileModifiedEvent):
if event.is_directory:
return
log(f"{event.src_path} changed, regenerating...")
if self.timer:
self.timer.cancel()
# NOTE: Modern editors don't do in-place editing, instead they
# use a temp file and replace the old file with the new file. watchdog
# is really fast so this behaviour makes it think that file doesn't
# exist for a moment and throws errors. 0.4 enough even for older hardware.
self.timer = threading.Timer(0.4, self.gen_config.generate)
self.timer.start()
class GenConfig:
def __init__(self, group: str = "default", use_include: bool = False) -> None:
self.group: str = group
self.use_include: bool = use_include
def check_files(self):
non_existent_files: list[str] = []
for source in config.genconfig.sources:
parsed_source_path = return_source(source, self.group)
if not Path(parsed_source_path).exists():
non_existent_files.append(parsed_source_path)
if len(non_existent_files) != 0:
warn("Couldn't find the files below, check your genconfig.sources:")
print(*non_existent_files, sep="\n")
exit(1)
def generate(self):
# I know it looks ugly but this is faster than checking
# if use_include is true at every iteration.
with open(config.general.output_path, "w", encoding="utf-8") as outfile:
if self.use_include:
for source in config.genconfig.sources:
parsed_source_path = return_source(
source,
self.group,
)
_ = outfile.write(f'include "{parsed_source_path}"')
_ = outfile.write("\n")
else:
for source in config.genconfig.sources:
parsed_source_path = return_source(
source,
self.group,
)
with open(parsed_source_path, "r", encoding="utf-8") as infile:
_ = outfile.write(infile.read())
_ = outfile.write("\n")
log(f"Generation successful! Output written to: {config.general.output_path}")
def daemon(self):
from watchdog.observers import Observer
self.generate()
observer = Observer()
handler = FileChangeHandler(self)
_ = observer.schedule(handler, config.genconfig.watch_dir, recursive=True)
observer.start()
log(
f"Watching {config.genconfig.watch_dir} for changes, press [yellow]Ctrl+C[/yellow] to stop the daemon."
)
try:
while True:
time.sleep(1)
except KeyboardInterrupt:
log("Killing the daemon, goodbye!")
observer.stop()
observer.join()
app = typer.Typer(
help="niri-companion config generation tool",
context_settings={"help_option_names": ["-h", "--help"]},
)
CombineArg = Annotated[
bool,
typer.Option(
"--combine",
"-c",
help="Combine configs instead of including in the result config.kdl",
),
]
UseIncludeArg = Annotated[
bool,
typer.Option(
"--use-include",
"-u",
help="Include configs instead of combining in the result config.kdl (deprecated flag, this is now the default behaviour)",
),
]
GroupArg = Annotated[str, typer.Argument()]
@app.command(help="Generate configuration")
def generate(
group: GroupArg = "default",
use_include: UseIncludeArg = False,
combine: CombineArg = False,
):
if combine and use_include:
raise typer.BadParameter(
"Cannot use --combine/-c and --use-include/-u together."
)
is_include_mode = use_include or not combine
gen = GenConfig(group, is_include_mode)
gen.check_files()
gen.generate()
@app.command(help="Start config generation daemon")
def daemon(
group: GroupArg = "default",
):
gen = GenConfig(group)
gen.check_files()
gen.daemon()
if __name__ == "__main__":
app()
dybdeskarphet-niri-companion-6d9cebf/src/companion/ipcext.py 0000775 0000000 0000000 00000002720 15207340103 0024466 0 ustar 00root root 0000000 0000000 from typing import Annotated
import typer
from companion.config import config
from companion.genconfig import GenConfig
from companion.utils.logger import console, log
class IpcExt:
def __init__(self) -> None:
pass
def restore(self):
GenConfig().generate()
def replace_line(self, old: str, new: str):
with open(config.general.output_path, "r") as f:
lines = f.readlines()
matching_lines = [i for i, line in enumerate(lines) if old in line]
if len(matching_lines) == 0:
console.print("No matching line found.")
return False
elif len(matching_lines) > 1:
console.print("Error: More than one matching line found.")
return False
index = matching_lines[0]
lines[index] = new + "\n"
with open(config.general.output_path, "w") as f:
f.writelines(lines)
return True
app = typer.Typer(
help="niri-companion IPC-like configuration tool",
context_settings={"help_option_names": ["-h", "--help"]},
)
@app.command(help="Replace string inside niri configuration file")
def replace(
old: Annotated[str, typer.Argument()], new: Annotated[str, typer.Argument()]
):
res = IpcExt().replace_line(old, new)
if res:
log("Done!")
exit(0)
@app.command(help="Restore default settings")
def restore():
res = IpcExt().restore()
log("Done!")
exit(0)
if __name__ == "__main__":
app()
dybdeskarphet-niri-companion-6d9cebf/src/companion/models/ 0000775 0000000 0000000 00000000000 15207340103 0024077 5 ustar 00root root 0000000 0000000 dybdeskarphet-niri-companion-6d9cebf/src/companion/models/config.py 0000664 0000000 0000000 00000001465 15207340103 0025724 0 ustar 00root root 0000000 0000000 from pydantic import BaseModel, RootModel
class ConfigItem(BaseModel):
group: str
path: str
class GeneralConfig(BaseModel):
output_path: str
class GenConfigSection(BaseModel):
sources: list[str | list[ConfigItem]]
watch_dir: str = "~/.config/niri/soruces"
class WorkspaceItem(BaseModel):
workspace: int
run: str
task_delay: float | None = None
class WorkspaceItemsSection(RootModel[dict[str, list[WorkspaceItem]]]):
def __getitem__(self, item: str) -> list[WorkspaceItem]:
return self.root[item]
class WorkspaceConfigSection(BaseModel):
items: WorkspaceItemsSection
dmenu_command: str = "rofi -dmenu"
task_delay: float = 0.8
class AppConfig(BaseModel):
workspaces: WorkspaceConfigSection
general: GeneralConfig
genconfig: GenConfigSection
dybdeskarphet-niri-companion-6d9cebf/src/companion/utils/ 0000775 0000000 0000000 00000000000 15207340103 0023754 5 ustar 00root root 0000000 0000000 dybdeskarphet-niri-companion-6d9cebf/src/companion/utils/genconfig.py 0000664 0000000 0000000 00000001043 15207340103 0026263 0 ustar 00root root 0000000 0000000 from companion.models.config import ConfigItem
from companion.utils.logger import error
def return_source(source: str | list[ConfigItem], group: str):
if isinstance(source, str):
return source
else:
for source_array_item in source:
if source_array_item.group == group:
return source_array_item.path
else:
continue
error(
f"The '{group}' group could not be found, or the group defined in one array is not defined in the other arrays."
)
exit(1)
dybdeskarphet-niri-companion-6d9cebf/src/companion/utils/general.py 0000664 0000000 0000000 00000000336 15207340103 0025745 0 ustar 00root root 0000000 0000000 from os import path
from pathlib import Path
def expandall(p: str):
if p.startswith("~"):
return path.expanduser(path.expandvars(p))
else:
return path.expandvars(p).replace("~", str(Path.home()))
dybdeskarphet-niri-companion-6d9cebf/src/companion/utils/logger.py 0000664 0000000 0000000 00000000516 15207340103 0025607 0 ustar 00root root 0000000 0000000 from rich.console import Console
console = Console()
def error(msg: str):
console.print(rf"[bold red]\[niri-companion][/bold red] {msg}")
def log(msg: str):
console.print(rf"[bold green]\[niri-companion][/bold green] {msg}")
def warn(msg: str):
console.print(rf"[bold yellow]\[niri-companion][/bold yellow] {msg}")
dybdeskarphet-niri-companion-6d9cebf/src/companion/workspaces.py 0000775 0000000 0000000 00000002424 15207340103 0025354 0 ustar 00root root 0000000 0000000 import subprocess
import time
from companion.config import config
from companion.utils.logger import error, log
def main():
workspace_strings = list(config.workspaces.items.root.keys())
menu = "\n".join(workspace_strings)
try:
result = subprocess.run(
config.workspaces.dmenu_command,
input=menu,
shell=True,
text=True,
capture_output=True,
)
choice = result.stdout.strip()
if choice:
log(f"You picked: {choice}")
else:
error(f"You didn't pick anything")
exit(1)
except Exception as e:
print("Error:", e)
exit(1)
for item in config.workspaces.items.root[choice]:
ws = item.workspace
command = item.run
task_delay = item.task_delay
_ = subprocess.run(f"niri msg action focus-workspace {str(ws)}", shell=True)
time.sleep(0.3)
_ = subprocess.run(f"niri msg action spawn-sh -- '{command}'", shell=True)
if task_delay is not None:
time.sleep(task_delay)
else:
time.sleep(config.workspaces.task_delay)
_ = subprocess.run(f"niri msg action maximize-column", shell=True)
time.sleep(0.2)
if __name__ == "__main__":
main()
dybdeskarphet-niri-companion-6d9cebf/tests/ 0000775 0000000 0000000 00000000000 15207340103 0021204 5 ustar 00root root 0000000 0000000 dybdeskarphet-niri-companion-6d9cebf/tests/test_utils.py 0000664 0000000 0000000 00000001750 15207340103 0023760 0 ustar 00root root 0000000 0000000 import os
from pathlib import Path
import pytest
from companion.models.config import ConfigItem
from companion.utils.genconfig import return_source
from companion.utils.general import expandall
def test_expandall():
os.environ["HOME"] = "/home/testing"
home = os.environ["HOME"]
assert expandall("~/.config/niri") == str(Path(home) / ".config" / "niri")
assert expandall("$HOME/.config/niri") == str(Path(home) / ".config" / "niri")
assert (
expandall("This is a ~/.config/niri sentence.")
== "This is a " + str(Path(home) / ".config" / "niri") + " sentence."
)
def test_source_array():
config_items = [
ConfigItem(group="default", path="somewhere"),
ConfigItem(group="cool", path="someone"),
]
assert return_source(config_items, "default") == "somewhere"
assert return_source(config_items, "cool") == "someone"
assert return_source("hey", "default") == "hey"
assert return_source("hey", "invalid group") == "hey"
dybdeskarphet-niri-companion-6d9cebf/uv.lock 0000664 0000000 0000000 00000122335 15207340103 0021354 0 ustar 00root root 0000000 0000000 version = 1
revision = 3
requires-python = ">=3.13"
[[package]]
name = "annotated-types"
version = "0.7.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081, upload-time = "2024-05-20T21:33:25.928Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" },
]
[[package]]
name = "click"
version = "8.3.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "colorama", marker = "sys_platform == 'win32'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/46/61/de6cd827efad202d7057d93e0fed9294b96952e188f7384832791c7b2254/click-8.3.0.tar.gz", hash = "sha256:e7b8232224eba16f4ebe410c25ced9f7875cb5f3263ffc93cc3e8da705e229c4", size = 276943, upload-time = "2025-09-18T17:32:23.696Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/db/d3/9dcc0f5797f070ec8edf30fbadfb200e71d9db6b84d211e3b2085a7589a0/click-8.3.0-py3-none-any.whl", hash = "sha256:9b9f285302c6e3064f4330c05f05b81945b2a39544279343e6e7c5f27a9baddc", size = 107295, upload-time = "2025-09-18T17:32:22.42Z" },
]
[[package]]
name = "colorama"
version = "0.4.6"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" },
]
[[package]]
name = "coverage"
version = "7.10.7"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/51/26/d22c300112504f5f9a9fd2297ce33c35f3d353e4aeb987c8419453b2a7c2/coverage-7.10.7.tar.gz", hash = "sha256:f4ab143ab113be368a3e9b795f9cd7906c5ef407d6173fe9675a902e1fffc239", size = 827704, upload-time = "2025-09-21T20:03:56.815Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/9a/94/b765c1abcb613d103b64fcf10395f54d69b0ef8be6a0dd9c524384892cc7/coverage-7.10.7-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:981a651f543f2854abd3b5fcb3263aac581b18209be49863ba575de6edf4c14d", size = 218320, upload-time = "2025-09-21T20:01:56.629Z" },
{ url = "https://files.pythonhosted.org/packages/72/4f/732fff31c119bb73b35236dd333030f32c4bfe909f445b423e6c7594f9a2/coverage-7.10.7-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:73ab1601f84dc804f7812dc297e93cd99381162da39c47040a827d4e8dafe63b", size = 218575, upload-time = "2025-09-21T20:01:58.203Z" },
{ url = "https://files.pythonhosted.org/packages/87/02/ae7e0af4b674be47566707777db1aa375474f02a1d64b9323e5813a6cdd5/coverage-7.10.7-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:a8b6f03672aa6734e700bbcd65ff050fd19cddfec4b031cc8cf1c6967de5a68e", size = 249568, upload-time = "2025-09-21T20:01:59.748Z" },
{ url = "https://files.pythonhosted.org/packages/a2/77/8c6d22bf61921a59bce5471c2f1f7ac30cd4ac50aadde72b8c48d5727902/coverage-7.10.7-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:10b6ba00ab1132a0ce4428ff68cf50a25efd6840a42cdf4239c9b99aad83be8b", size = 252174, upload-time = "2025-09-21T20:02:01.192Z" },
{ url = "https://files.pythonhosted.org/packages/b1/20/b6ea4f69bbb52dac0aebd62157ba6a9dddbfe664f5af8122dac296c3ee15/coverage-7.10.7-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c79124f70465a150e89340de5963f936ee97097d2ef76c869708c4248c63ca49", size = 253447, upload-time = "2025-09-21T20:02:02.701Z" },
{ url = "https://files.pythonhosted.org/packages/f9/28/4831523ba483a7f90f7b259d2018fef02cb4d5b90bc7c1505d6e5a84883c/coverage-7.10.7-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:69212fbccdbd5b0e39eac4067e20a4a5256609e209547d86f740d68ad4f04911", size = 249779, upload-time = "2025-09-21T20:02:04.185Z" },
{ url = "https://files.pythonhosted.org/packages/a7/9f/4331142bc98c10ca6436d2d620c3e165f31e6c58d43479985afce6f3191c/coverage-7.10.7-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:7ea7c6c9d0d286d04ed3541747e6597cbe4971f22648b68248f7ddcd329207f0", size = 251604, upload-time = "2025-09-21T20:02:06.034Z" },
{ url = "https://files.pythonhosted.org/packages/ce/60/bda83b96602036b77ecf34e6393a3836365481b69f7ed7079ab85048202b/coverage-7.10.7-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b9be91986841a75042b3e3243d0b3cb0b2434252b977baaf0cd56e960fe1e46f", size = 249497, upload-time = "2025-09-21T20:02:07.619Z" },
{ url = "https://files.pythonhosted.org/packages/5f/af/152633ff35b2af63977edd835d8e6430f0caef27d171edf2fc76c270ef31/coverage-7.10.7-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:b281d5eca50189325cfe1f365fafade89b14b4a78d9b40b05ddd1fc7d2a10a9c", size = 249350, upload-time = "2025-09-21T20:02:10.34Z" },
{ url = "https://files.pythonhosted.org/packages/9d/71/d92105d122bd21cebba877228990e1646d862e34a98bb3374d3fece5a794/coverage-7.10.7-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:99e4aa63097ab1118e75a848a28e40d68b08a5e19ce587891ab7fd04475e780f", size = 251111, upload-time = "2025-09-21T20:02:12.122Z" },
{ url = "https://files.pythonhosted.org/packages/a2/9e/9fdb08f4bf476c912f0c3ca292e019aab6712c93c9344a1653986c3fd305/coverage-7.10.7-cp313-cp313-win32.whl", hash = "sha256:dc7c389dce432500273eaf48f410b37886be9208b2dd5710aaf7c57fd442c698", size = 220746, upload-time = "2025-09-21T20:02:13.919Z" },
{ url = "https://files.pythonhosted.org/packages/b1/b1/a75fd25df44eab52d1931e89980d1ada46824c7a3210be0d3c88a44aaa99/coverage-7.10.7-cp313-cp313-win_amd64.whl", hash = "sha256:cac0fdca17b036af3881a9d2729a850b76553f3f716ccb0360ad4dbc06b3b843", size = 221541, upload-time = "2025-09-21T20:02:15.57Z" },
{ url = "https://files.pythonhosted.org/packages/14/3a/d720d7c989562a6e9a14b2c9f5f2876bdb38e9367126d118495b89c99c37/coverage-7.10.7-cp313-cp313-win_arm64.whl", hash = "sha256:4b6f236edf6e2f9ae8fcd1332da4e791c1b6ba0dc16a2dc94590ceccb482e546", size = 220170, upload-time = "2025-09-21T20:02:17.395Z" },
{ url = "https://files.pythonhosted.org/packages/bb/22/e04514bf2a735d8b0add31d2b4ab636fc02370730787c576bb995390d2d5/coverage-7.10.7-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:a0ec07fd264d0745ee396b666d47cef20875f4ff2375d7c4f58235886cc1ef0c", size = 219029, upload-time = "2025-09-21T20:02:18.936Z" },
{ url = "https://files.pythonhosted.org/packages/11/0b/91128e099035ece15da3445d9015e4b4153a6059403452d324cbb0a575fa/coverage-7.10.7-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:dd5e856ebb7bfb7672b0086846db5afb4567a7b9714b8a0ebafd211ec7ce6a15", size = 219259, upload-time = "2025-09-21T20:02:20.44Z" },
{ url = "https://files.pythonhosted.org/packages/8b/51/66420081e72801536a091a0c8f8c1f88a5c4bf7b9b1bdc6222c7afe6dc9b/coverage-7.10.7-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:f57b2a3c8353d3e04acf75b3fed57ba41f5c0646bbf1d10c7c282291c97936b4", size = 260592, upload-time = "2025-09-21T20:02:22.313Z" },
{ url = "https://files.pythonhosted.org/packages/5d/22/9b8d458c2881b22df3db5bb3e7369e63d527d986decb6c11a591ba2364f7/coverage-7.10.7-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:1ef2319dd15a0b009667301a3f84452a4dc6fddfd06b0c5c53ea472d3989fbf0", size = 262768, upload-time = "2025-09-21T20:02:24.287Z" },
{ url = "https://files.pythonhosted.org/packages/f7/08/16bee2c433e60913c610ea200b276e8eeef084b0d200bdcff69920bd5828/coverage-7.10.7-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:83082a57783239717ceb0ad584de3c69cf581b2a95ed6bf81ea66034f00401c0", size = 264995, upload-time = "2025-09-21T20:02:26.133Z" },
{ url = "https://files.pythonhosted.org/packages/20/9d/e53eb9771d154859b084b90201e5221bca7674ba449a17c101a5031d4054/coverage-7.10.7-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:50aa94fb1fb9a397eaa19c0d5ec15a5edd03a47bf1a3a6111a16b36e190cff65", size = 259546, upload-time = "2025-09-21T20:02:27.716Z" },
{ url = "https://files.pythonhosted.org/packages/ad/b0/69bc7050f8d4e56a89fb550a1577d5d0d1db2278106f6f626464067b3817/coverage-7.10.7-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:2120043f147bebb41c85b97ac45dd173595ff14f2a584f2963891cbcc3091541", size = 262544, upload-time = "2025-09-21T20:02:29.216Z" },
{ url = "https://files.pythonhosted.org/packages/ef/4b/2514b060dbd1bc0aaf23b852c14bb5818f244c664cb16517feff6bb3a5ab/coverage-7.10.7-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:2fafd773231dd0378fdba66d339f84904a8e57a262f583530f4f156ab83863e6", size = 260308, upload-time = "2025-09-21T20:02:31.226Z" },
{ url = "https://files.pythonhosted.org/packages/54/78/7ba2175007c246d75e496f64c06e94122bdb914790a1285d627a918bd271/coverage-7.10.7-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:0b944ee8459f515f28b851728ad224fa2d068f1513ef6b7ff1efafeb2185f999", size = 258920, upload-time = "2025-09-21T20:02:32.823Z" },
{ url = "https://files.pythonhosted.org/packages/c0/b3/fac9f7abbc841409b9a410309d73bfa6cfb2e51c3fada738cb607ce174f8/coverage-7.10.7-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:4b583b97ab2e3efe1b3e75248a9b333bd3f8b0b1b8e5b45578e05e5850dfb2c2", size = 261434, upload-time = "2025-09-21T20:02:34.86Z" },
{ url = "https://files.pythonhosted.org/packages/ee/51/a03bec00d37faaa891b3ff7387192cef20f01604e5283a5fabc95346befa/coverage-7.10.7-cp313-cp313t-win32.whl", hash = "sha256:2a78cd46550081a7909b3329e2266204d584866e8d97b898cd7fb5ac8d888b1a", size = 221403, upload-time = "2025-09-21T20:02:37.034Z" },
{ url = "https://files.pythonhosted.org/packages/53/22/3cf25d614e64bf6d8e59c7c669b20d6d940bb337bdee5900b9ca41c820bb/coverage-7.10.7-cp313-cp313t-win_amd64.whl", hash = "sha256:33a5e6396ab684cb43dc7befa386258acb2d7fae7f67330ebb85ba4ea27938eb", size = 222469, upload-time = "2025-09-21T20:02:39.011Z" },
{ url = "https://files.pythonhosted.org/packages/49/a1/00164f6d30d8a01c3c9c48418a7a5be394de5349b421b9ee019f380df2a0/coverage-7.10.7-cp313-cp313t-win_arm64.whl", hash = "sha256:86b0e7308289ddde73d863b7683f596d8d21c7d8664ce1dee061d0bcf3fbb4bb", size = 220731, upload-time = "2025-09-21T20:02:40.939Z" },
{ url = "https://files.pythonhosted.org/packages/23/9c/5844ab4ca6a4dd97a1850e030a15ec7d292b5c5cb93082979225126e35dd/coverage-7.10.7-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:b06f260b16ead11643a5a9f955bd4b5fd76c1a4c6796aeade8520095b75de520", size = 218302, upload-time = "2025-09-21T20:02:42.527Z" },
{ url = "https://files.pythonhosted.org/packages/f0/89/673f6514b0961d1f0e20ddc242e9342f6da21eaba3489901b565c0689f34/coverage-7.10.7-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:212f8f2e0612778f09c55dd4872cb1f64a1f2b074393d139278ce902064d5b32", size = 218578, upload-time = "2025-09-21T20:02:44.468Z" },
{ url = "https://files.pythonhosted.org/packages/05/e8/261cae479e85232828fb17ad536765c88dd818c8470aca690b0ac6feeaa3/coverage-7.10.7-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:3445258bcded7d4aa630ab8296dea4d3f15a255588dd535f980c193ab6b95f3f", size = 249629, upload-time = "2025-09-21T20:02:46.503Z" },
{ url = "https://files.pythonhosted.org/packages/82/62/14ed6546d0207e6eda876434e3e8475a3e9adbe32110ce896c9e0c06bb9a/coverage-7.10.7-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:bb45474711ba385c46a0bfe696c695a929ae69ac636cda8f532be9e8c93d720a", size = 252162, upload-time = "2025-09-21T20:02:48.689Z" },
{ url = "https://files.pythonhosted.org/packages/ff/49/07f00db9ac6478e4358165a08fb41b469a1b053212e8a00cb02f0d27a05f/coverage-7.10.7-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:813922f35bd800dca9994c5971883cbc0d291128a5de6b167c7aa697fcf59360", size = 253517, upload-time = "2025-09-21T20:02:50.31Z" },
{ url = "https://files.pythonhosted.org/packages/a2/59/c5201c62dbf165dfbc91460f6dbbaa85a8b82cfa6131ac45d6c1bfb52deb/coverage-7.10.7-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:93c1b03552081b2a4423091d6fb3787265b8f86af404cff98d1b5342713bdd69", size = 249632, upload-time = "2025-09-21T20:02:51.971Z" },
{ url = "https://files.pythonhosted.org/packages/07/ae/5920097195291a51fb00b3a70b9bbd2edbfe3c84876a1762bd1ef1565ebc/coverage-7.10.7-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:cc87dd1b6eaf0b848eebb1c86469b9f72a1891cb42ac7adcfbce75eadb13dd14", size = 251520, upload-time = "2025-09-21T20:02:53.858Z" },
{ url = "https://files.pythonhosted.org/packages/b9/3c/a815dde77a2981f5743a60b63df31cb322c944843e57dbd579326625a413/coverage-7.10.7-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:39508ffda4f343c35f3236fe8d1a6634a51f4581226a1262769d7f970e73bffe", size = 249455, upload-time = "2025-09-21T20:02:55.807Z" },
{ url = "https://files.pythonhosted.org/packages/aa/99/f5cdd8421ea656abefb6c0ce92556709db2265c41e8f9fc6c8ae0f7824c9/coverage-7.10.7-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:925a1edf3d810537c5a3abe78ec5530160c5f9a26b1f4270b40e62cc79304a1e", size = 249287, upload-time = "2025-09-21T20:02:57.784Z" },
{ url = "https://files.pythonhosted.org/packages/c3/7a/e9a2da6a1fc5d007dd51fca083a663ab930a8c4d149c087732a5dbaa0029/coverage-7.10.7-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2c8b9a0636f94c43cd3576811e05b89aa9bc2d0a85137affc544ae5cb0e4bfbd", size = 250946, upload-time = "2025-09-21T20:02:59.431Z" },
{ url = "https://files.pythonhosted.org/packages/ef/5b/0b5799aa30380a949005a353715095d6d1da81927d6dbed5def2200a4e25/coverage-7.10.7-cp314-cp314-win32.whl", hash = "sha256:b7b8288eb7cdd268b0304632da8cb0bb93fadcfec2fe5712f7b9cc8f4d487be2", size = 221009, upload-time = "2025-09-21T20:03:01.324Z" },
{ url = "https://files.pythonhosted.org/packages/da/b0/e802fbb6eb746de006490abc9bb554b708918b6774b722bb3a0e6aa1b7de/coverage-7.10.7-cp314-cp314-win_amd64.whl", hash = "sha256:1ca6db7c8807fb9e755d0379ccc39017ce0a84dcd26d14b5a03b78563776f681", size = 221804, upload-time = "2025-09-21T20:03:03.4Z" },
{ url = "https://files.pythonhosted.org/packages/9e/e8/71d0c8e374e31f39e3389bb0bd19e527d46f00ea8571ec7ec8fd261d8b44/coverage-7.10.7-cp314-cp314-win_arm64.whl", hash = "sha256:097c1591f5af4496226d5783d036bf6fd6cd0cbc132e071b33861de756efb880", size = 220384, upload-time = "2025-09-21T20:03:05.111Z" },
{ url = "https://files.pythonhosted.org/packages/62/09/9a5608d319fa3eba7a2019addeacb8c746fb50872b57a724c9f79f146969/coverage-7.10.7-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:a62c6ef0d50e6de320c270ff91d9dd0a05e7250cac2a800b7784bae474506e63", size = 219047, upload-time = "2025-09-21T20:03:06.795Z" },
{ url = "https://files.pythonhosted.org/packages/f5/6f/f58d46f33db9f2e3647b2d0764704548c184e6f5e014bef528b7f979ef84/coverage-7.10.7-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:9fa6e4dd51fe15d8738708a973470f67a855ca50002294852e9571cdbd9433f2", size = 219266, upload-time = "2025-09-21T20:03:08.495Z" },
{ url = "https://files.pythonhosted.org/packages/74/5c/183ffc817ba68e0b443b8c934c8795553eb0c14573813415bd59941ee165/coverage-7.10.7-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:8fb190658865565c549b6b4706856d6a7b09302c797eb2cf8e7fe9dabb043f0d", size = 260767, upload-time = "2025-09-21T20:03:10.172Z" },
{ url = "https://files.pythonhosted.org/packages/0f/48/71a8abe9c1ad7e97548835e3cc1adbf361e743e9d60310c5f75c9e7bf847/coverage-7.10.7-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:affef7c76a9ef259187ef31599a9260330e0335a3011732c4b9effa01e1cd6e0", size = 262931, upload-time = "2025-09-21T20:03:11.861Z" },
{ url = "https://files.pythonhosted.org/packages/84/fd/193a8fb132acfc0a901f72020e54be5e48021e1575bb327d8ee1097a28fd/coverage-7.10.7-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6e16e07d85ca0cf8bafe5f5d23a0b850064e8e945d5677492b06bbe6f09cc699", size = 265186, upload-time = "2025-09-21T20:03:13.539Z" },
{ url = "https://files.pythonhosted.org/packages/b1/8f/74ecc30607dd95ad50e3034221113ccb1c6d4e8085cc761134782995daae/coverage-7.10.7-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:03ffc58aacdf65d2a82bbeb1ffe4d01ead4017a21bfd0454983b88ca73af94b9", size = 259470, upload-time = "2025-09-21T20:03:15.584Z" },
{ url = "https://files.pythonhosted.org/packages/0f/55/79ff53a769f20d71b07023ea115c9167c0bb56f281320520cf64c5298a96/coverage-7.10.7-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:1b4fd784344d4e52647fd7857b2af5b3fbe6c239b0b5fa63e94eb67320770e0f", size = 262626, upload-time = "2025-09-21T20:03:17.673Z" },
{ url = "https://files.pythonhosted.org/packages/88/e2/dac66c140009b61ac3fc13af673a574b00c16efdf04f9b5c740703e953c0/coverage-7.10.7-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:0ebbaddb2c19b71912c6f2518e791aa8b9f054985a0769bdb3a53ebbc765c6a1", size = 260386, upload-time = "2025-09-21T20:03:19.36Z" },
{ url = "https://files.pythonhosted.org/packages/a2/f1/f48f645e3f33bb9ca8a496bc4a9671b52f2f353146233ebd7c1df6160440/coverage-7.10.7-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:a2d9a3b260cc1d1dbdb1c582e63ddcf5363426a1a68faa0f5da28d8ee3c722a0", size = 258852, upload-time = "2025-09-21T20:03:21.007Z" },
{ url = "https://files.pythonhosted.org/packages/bb/3b/8442618972c51a7affeead957995cfa8323c0c9bcf8fa5a027421f720ff4/coverage-7.10.7-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:a3cc8638b2480865eaa3926d192e64ce6c51e3d29c849e09d5b4ad95efae5399", size = 261534, upload-time = "2025-09-21T20:03:23.12Z" },
{ url = "https://files.pythonhosted.org/packages/b2/dc/101f3fa3a45146db0cb03f5b4376e24c0aac818309da23e2de0c75295a91/coverage-7.10.7-cp314-cp314t-win32.whl", hash = "sha256:67f8c5cbcd3deb7a60b3345dffc89a961a484ed0af1f6f73de91705cc6e31235", size = 221784, upload-time = "2025-09-21T20:03:24.769Z" },
{ url = "https://files.pythonhosted.org/packages/4c/a1/74c51803fc70a8a40d7346660379e144be772bab4ac7bb6e6b905152345c/coverage-7.10.7-cp314-cp314t-win_amd64.whl", hash = "sha256:e1ed71194ef6dea7ed2d5cb5f7243d4bcd334bfb63e59878519be558078f848d", size = 222905, upload-time = "2025-09-21T20:03:26.93Z" },
{ url = "https://files.pythonhosted.org/packages/12/65/f116a6d2127df30bcafbceef0302d8a64ba87488bf6f73a6d8eebf060873/coverage-7.10.7-cp314-cp314t-win_arm64.whl", hash = "sha256:7fe650342addd8524ca63d77b2362b02345e5f1a093266787d210c70a50b471a", size = 220922, upload-time = "2025-09-21T20:03:28.672Z" },
{ url = "https://files.pythonhosted.org/packages/ec/16/114df1c291c22cac3b0c127a73e0af5c12ed7bbb6558d310429a0ae24023/coverage-7.10.7-py3-none-any.whl", hash = "sha256:f7941f6f2fe6dd6807a1208737b8a0cbcf1cc6d7b07d24998ad2d63590868260", size = 209952, upload-time = "2025-09-21T20:03:53.918Z" },
]
[[package]]
name = "iniconfig"
version = "2.1.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/f2/97/ebf4da567aa6827c909642694d71c9fcf53e5b504f2d96afea02718862f3/iniconfig-2.1.0.tar.gz", hash = "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7", size = 4793, upload-time = "2025-03-19T20:09:59.721Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl", hash = "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760", size = 6050, upload-time = "2025-03-19T20:10:01.071Z" },
]
[[package]]
name = "markdown-it-py"
version = "4.0.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "mdurl" },
]
sdist = { url = "https://files.pythonhosted.org/packages/5b/f5/4ec618ed16cc4f8fb3b701563655a69816155e79e24a17b651541804721d/markdown_it_py-4.0.0.tar.gz", hash = "sha256:cb0a2b4aa34f932c007117b194e945bd74e0ec24133ceb5bac59009cda1cb9f3", size = 73070, upload-time = "2025-08-11T12:57:52.854Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl", hash = "sha256:87327c59b172c5011896038353a81343b6754500a08cd7a4973bb48c6d578147", size = 87321, upload-time = "2025-08-11T12:57:51.923Z" },
]
[[package]]
name = "mdurl"
version = "0.1.2"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729, upload-time = "2022-08-14T12:40:10.846Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" },
]
[[package]]
name = "niri-companion"
version = "5.0.0"
source = { virtual = "." }
dependencies = [
{ name = "pydantic" },
{ name = "rich" },
{ name = "tomli-w" },
{ name = "typer" },
{ name = "watchdog" },
]
[package.dev-dependencies]
dev = [
{ name = "pytest" },
{ name = "pytest-cov" },
]
[package.metadata]
requires-dist = [
{ name = "pydantic", specifier = ">=2.11.7" },
{ name = "rich", specifier = ">=14.1.0" },
{ name = "tomli-w", specifier = ">=1.2.0" },
{ name = "typer", specifier = ">=0.19.1" },
{ name = "watchdog", specifier = ">=6.0.0" },
]
[package.metadata.requires-dev]
dev = [
{ name = "pytest", specifier = ">=8.4.2" },
{ name = "pytest-cov", specifier = ">=7.0.0" },
]
[[package]]
name = "packaging"
version = "25.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size = 165727, upload-time = "2025-04-19T11:48:59.673Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469, upload-time = "2025-04-19T11:48:57.875Z" },
]
[[package]]
name = "pluggy"
version = "1.6.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" },
]
[[package]]
name = "pydantic"
version = "2.11.7"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "annotated-types" },
{ name = "pydantic-core" },
{ name = "typing-extensions" },
{ name = "typing-inspection" },
]
sdist = { url = "https://files.pythonhosted.org/packages/00/dd/4325abf92c39ba8623b5af936ddb36ffcfe0beae70405d456ab1fb2f5b8c/pydantic-2.11.7.tar.gz", hash = "sha256:d989c3c6cb79469287b1569f7447a17848c998458d49ebe294e975b9baf0f0db", size = 788350, upload-time = "2025-06-14T08:33:17.137Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/6a/c0/ec2b1c8712ca690e5d61979dee872603e92b8a32f94cc1b72d53beab008a/pydantic-2.11.7-py3-none-any.whl", hash = "sha256:dde5df002701f6de26248661f6835bbe296a47bf73990135c7d07ce741b9623b", size = 444782, upload-time = "2025-06-14T08:33:14.905Z" },
]
[[package]]
name = "pydantic-core"
version = "2.33.2"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "typing-extensions" },
]
sdist = { url = "https://files.pythonhosted.org/packages/ad/88/5f2260bdfae97aabf98f1778d43f69574390ad787afb646292a638c923d4/pydantic_core-2.33.2.tar.gz", hash = "sha256:7cb8bc3605c29176e1b105350d2e6474142d7c1bd1d9327c4a9bdb46bf827acc", size = 435195, upload-time = "2025-04-23T18:33:52.104Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/46/8c/99040727b41f56616573a28771b1bfa08a3d3fe74d3d513f01251f79f172/pydantic_core-2.33.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:1082dd3e2d7109ad8b7da48e1d4710c8d06c253cbc4a27c1cff4fbcaa97a9e3f", size = 2015688, upload-time = "2025-04-23T18:31:53.175Z" },
{ url = "https://files.pythonhosted.org/packages/3a/cc/5999d1eb705a6cefc31f0b4a90e9f7fc400539b1a1030529700cc1b51838/pydantic_core-2.33.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f517ca031dfc037a9c07e748cefd8d96235088b83b4f4ba8939105d20fa1dcd6", size = 1844808, upload-time = "2025-04-23T18:31:54.79Z" },
{ url = "https://files.pythonhosted.org/packages/6f/5e/a0a7b8885c98889a18b6e376f344da1ef323d270b44edf8174d6bce4d622/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a9f2c9dd19656823cb8250b0724ee9c60a82f3cdf68a080979d13092a3b0fef", size = 1885580, upload-time = "2025-04-23T18:31:57.393Z" },
{ url = "https://files.pythonhosted.org/packages/3b/2a/953581f343c7d11a304581156618c3f592435523dd9d79865903272c256a/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2b0a451c263b01acebe51895bfb0e1cc842a5c666efe06cdf13846c7418caa9a", size = 1973859, upload-time = "2025-04-23T18:31:59.065Z" },
{ url = "https://files.pythonhosted.org/packages/e6/55/f1a813904771c03a3f97f676c62cca0c0a4138654107c1b61f19c644868b/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ea40a64d23faa25e62a70ad163571c0b342b8bf66d5fa612ac0dec4f069d916", size = 2120810, upload-time = "2025-04-23T18:32:00.78Z" },
{ url = "https://files.pythonhosted.org/packages/aa/c3/053389835a996e18853ba107a63caae0b9deb4a276c6b472931ea9ae6e48/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0fb2d542b4d66f9470e8065c5469ec676978d625a8b7a363f07d9a501a9cb36a", size = 2676498, upload-time = "2025-04-23T18:32:02.418Z" },
{ url = "https://files.pythonhosted.org/packages/eb/3c/f4abd740877a35abade05e437245b192f9d0ffb48bbbbd708df33d3cda37/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fdac5d6ffa1b5a83bca06ffe7583f5576555e6c8b3a91fbd25ea7780f825f7d", size = 2000611, upload-time = "2025-04-23T18:32:04.152Z" },
{ url = "https://files.pythonhosted.org/packages/59/a7/63ef2fed1837d1121a894d0ce88439fe3e3b3e48c7543b2a4479eb99c2bd/pydantic_core-2.33.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:04a1a413977ab517154eebb2d326da71638271477d6ad87a769102f7c2488c56", size = 2107924, upload-time = "2025-04-23T18:32:06.129Z" },
{ url = "https://files.pythonhosted.org/packages/04/8f/2551964ef045669801675f1cfc3b0d74147f4901c3ffa42be2ddb1f0efc4/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:c8e7af2f4e0194c22b5b37205bfb293d166a7344a5b0d0eaccebc376546d77d5", size = 2063196, upload-time = "2025-04-23T18:32:08.178Z" },
{ url = "https://files.pythonhosted.org/packages/26/bd/d9602777e77fc6dbb0c7db9ad356e9a985825547dce5ad1d30ee04903918/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:5c92edd15cd58b3c2d34873597a1e20f13094f59cf88068adb18947df5455b4e", size = 2236389, upload-time = "2025-04-23T18:32:10.242Z" },
{ url = "https://files.pythonhosted.org/packages/42/db/0e950daa7e2230423ab342ae918a794964b053bec24ba8af013fc7c94846/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:65132b7b4a1c0beded5e057324b7e16e10910c106d43675d9bd87d4f38dde162", size = 2239223, upload-time = "2025-04-23T18:32:12.382Z" },
{ url = "https://files.pythonhosted.org/packages/58/4d/4f937099c545a8a17eb52cb67fe0447fd9a373b348ccfa9a87f141eeb00f/pydantic_core-2.33.2-cp313-cp313-win32.whl", hash = "sha256:52fb90784e0a242bb96ec53f42196a17278855b0f31ac7c3cc6f5c1ec4811849", size = 1900473, upload-time = "2025-04-23T18:32:14.034Z" },
{ url = "https://files.pythonhosted.org/packages/a0/75/4a0a9bac998d78d889def5e4ef2b065acba8cae8c93696906c3a91f310ca/pydantic_core-2.33.2-cp313-cp313-win_amd64.whl", hash = "sha256:c083a3bdd5a93dfe480f1125926afcdbf2917ae714bdb80b36d34318b2bec5d9", size = 1955269, upload-time = "2025-04-23T18:32:15.783Z" },
{ url = "https://files.pythonhosted.org/packages/f9/86/1beda0576969592f1497b4ce8e7bc8cbdf614c352426271b1b10d5f0aa64/pydantic_core-2.33.2-cp313-cp313-win_arm64.whl", hash = "sha256:e80b087132752f6b3d714f041ccf74403799d3b23a72722ea2e6ba2e892555b9", size = 1893921, upload-time = "2025-04-23T18:32:18.473Z" },
{ url = "https://files.pythonhosted.org/packages/a4/7d/e09391c2eebeab681df2b74bfe6c43422fffede8dc74187b2b0bf6fd7571/pydantic_core-2.33.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:61c18fba8e5e9db3ab908620af374db0ac1baa69f0f32df4f61ae23f15e586ac", size = 1806162, upload-time = "2025-04-23T18:32:20.188Z" },
{ url = "https://files.pythonhosted.org/packages/f1/3d/847b6b1fed9f8ed3bb95a9ad04fbd0b212e832d4f0f50ff4d9ee5a9f15cf/pydantic_core-2.33.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95237e53bb015f67b63c91af7518a62a8660376a6a0db19b89acc77a4d6199f5", size = 1981560, upload-time = "2025-04-23T18:32:22.354Z" },
{ url = "https://files.pythonhosted.org/packages/6f/9a/e73262f6c6656262b5fdd723ad90f518f579b7bc8622e43a942eec53c938/pydantic_core-2.33.2-cp313-cp313t-win_amd64.whl", hash = "sha256:c2fc0a768ef76c15ab9238afa6da7f69895bb5d1ee83aeea2e3509af4472d0b9", size = 1935777, upload-time = "2025-04-23T18:32:25.088Z" },
]
[[package]]
name = "pygments"
version = "2.19.2"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size = 4968631, upload-time = "2025-06-21T13:39:12.283Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" },
]
[[package]]
name = "pytest"
version = "8.4.2"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "colorama", marker = "sys_platform == 'win32'" },
{ name = "iniconfig" },
{ name = "packaging" },
{ name = "pluggy" },
{ name = "pygments" },
]
sdist = { url = "https://files.pythonhosted.org/packages/a3/5c/00a0e072241553e1a7496d638deababa67c5058571567b92a7eaa258397c/pytest-8.4.2.tar.gz", hash = "sha256:86c0d0b93306b961d58d62a4db4879f27fe25513d4b969df351abdddb3c30e01", size = 1519618, upload-time = "2025-09-04T14:34:22.711Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/a8/a4/20da314d277121d6534b3a980b29035dcd51e6744bd79075a6ce8fa4eb8d/pytest-8.4.2-py3-none-any.whl", hash = "sha256:872f880de3fc3a5bdc88a11b39c9710c3497a547cfa9320bc3c5e62fbf272e79", size = 365750, upload-time = "2025-09-04T14:34:20.226Z" },
]
[[package]]
name = "pytest-cov"
version = "7.0.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "coverage" },
{ name = "pluggy" },
{ name = "pytest" },
]
sdist = { url = "https://files.pythonhosted.org/packages/5e/f7/c933acc76f5208b3b00089573cf6a2bc26dc80a8aece8f52bb7d6b1855ca/pytest_cov-7.0.0.tar.gz", hash = "sha256:33c97eda2e049a0c5298e91f519302a1334c26ac65c1a483d6206fd458361af1", size = 54328, upload-time = "2025-09-09T10:57:02.113Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/ee/49/1377b49de7d0c1ce41292161ea0f721913fa8722c19fb9c1e3aa0367eecb/pytest_cov-7.0.0-py3-none-any.whl", hash = "sha256:3b8e9558b16cc1479da72058bdecf8073661c7f57f7d3c5f22a1c23507f2d861", size = 22424, upload-time = "2025-09-09T10:57:00.695Z" },
]
[[package]]
name = "rich"
version = "14.1.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "markdown-it-py" },
{ name = "pygments" },
]
sdist = { url = "https://files.pythonhosted.org/packages/fe/75/af448d8e52bf1d8fa6a9d089ca6c07ff4453d86c65c145d0a300bb073b9b/rich-14.1.0.tar.gz", hash = "sha256:e497a48b844b0320d45007cdebfeaeed8db2a4f4bcf49f15e455cfc4af11eaa8", size = 224441, upload-time = "2025-07-25T07:32:58.125Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/e3/30/3c4d035596d3cf444529e0b2953ad0466f6049528a879d27534700580395/rich-14.1.0-py3-none-any.whl", hash = "sha256:536f5f1785986d6dbdea3c75205c473f970777b4a0d6c6dd1b696aa05a3fa04f", size = 243368, upload-time = "2025-07-25T07:32:56.73Z" },
]
[[package]]
name = "shellingham"
version = "1.5.4"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/58/15/8b3609fd3830ef7b27b655beb4b4e9c62313a4e8da8c676e142cc210d58e/shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de", size = 10310, upload-time = "2023-10-24T04:13:40.426Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686", size = 9755, upload-time = "2023-10-24T04:13:38.866Z" },
]
[[package]]
name = "tomli-w"
version = "1.2.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/19/75/241269d1da26b624c0d5e110e8149093c759b7a286138f4efd61a60e75fe/tomli_w-1.2.0.tar.gz", hash = "sha256:2dd14fac5a47c27be9cd4c976af5a12d87fb1f0b4512f81d69cce3b35ae25021", size = 7184, upload-time = "2025-01-15T12:07:24.262Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/c7/18/c86eb8e0202e32dd3df50d43d7ff9854f8e0603945ff398974c1d91ac1ef/tomli_w-1.2.0-py3-none-any.whl", hash = "sha256:188306098d013b691fcadc011abd66727d3c414c571bb01b1a174ba8c983cf90", size = 6675, upload-time = "2025-01-15T12:07:22.074Z" },
]
[[package]]
name = "typer"
version = "0.19.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "click" },
{ name = "rich" },
{ name = "shellingham" },
{ name = "typing-extensions" },
]
sdist = { url = "https://files.pythonhosted.org/packages/03/ea/9cc57c3c627fd7a6a0907ea371019fe74c3ec00e3cf209a6864140a602ad/typer-0.19.1.tar.gz", hash = "sha256:cb881433a4b15dacc875bb0583d1a61e78497806741f9aba792abcab390c03e6", size = 104802, upload-time = "2025-09-20T08:59:22.692Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/1e/fa/6473c00b5eb26a2ba427813107699d3e6f4e1a4afad3f7494b17bdef3422/typer-0.19.1-py3-none-any.whl", hash = "sha256:914b2b39a1da4bafca5f30637ca26fa622a5bf9f515e5fdc772439f306d5682a", size = 46876, upload-time = "2025-09-20T08:59:21.153Z" },
]
[[package]]
name = "typing-extensions"
version = "4.15.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" },
]
[[package]]
name = "typing-inspection"
version = "0.4.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "typing-extensions" },
]
sdist = { url = "https://files.pythonhosted.org/packages/f8/b1/0c11f5058406b3af7609f121aaa6b609744687f1d158b3c3a5bf4cc94238/typing_inspection-0.4.1.tar.gz", hash = "sha256:6ae134cc0203c33377d43188d4064e9b357dba58cff3185f22924610e70a9d28", size = 75726, upload-time = "2025-05-21T18:55:23.885Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/17/69/cd203477f944c353c31bade965f880aa1061fd6bf05ded0726ca845b6ff7/typing_inspection-0.4.1-py3-none-any.whl", hash = "sha256:389055682238f53b04f7badcb49b989835495a96700ced5dab2d8feae4b26f51", size = 14552, upload-time = "2025-05-21T18:55:22.152Z" },
]
[[package]]
name = "watchdog"
version = "6.0.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/db/7d/7f3d619e951c88ed75c6037b246ddcf2d322812ee8ea189be89511721d54/watchdog-6.0.0.tar.gz", hash = "sha256:9ddf7c82fda3ae8e24decda1338ede66e1c99883db93711d8fb941eaa2d8c282", size = 131220, upload-time = "2024-11-01T14:07:13.037Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/68/98/b0345cabdce2041a01293ba483333582891a3bd5769b08eceb0d406056ef/watchdog-6.0.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:490ab2ef84f11129844c23fb14ecf30ef3d8a6abafd3754a6f75ca1e6654136c", size = 96480, upload-time = "2024-11-01T14:06:42.952Z" },
{ url = "https://files.pythonhosted.org/packages/85/83/cdf13902c626b28eedef7ec4f10745c52aad8a8fe7eb04ed7b1f111ca20e/watchdog-6.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:76aae96b00ae814b181bb25b1b98076d5fc84e8a53cd8885a318b42b6d3a5134", size = 88451, upload-time = "2024-11-01T14:06:45.084Z" },
{ url = "https://files.pythonhosted.org/packages/fe/c4/225c87bae08c8b9ec99030cd48ae9c4eca050a59bf5c2255853e18c87b50/watchdog-6.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a175f755fc2279e0b7312c0035d52e27211a5bc39719dd529625b1930917345b", size = 89057, upload-time = "2024-11-01T14:06:47.324Z" },
{ url = "https://files.pythonhosted.org/packages/a9/c7/ca4bf3e518cb57a686b2feb4f55a1892fd9a3dd13f470fca14e00f80ea36/watchdog-6.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:7607498efa04a3542ae3e05e64da8202e58159aa1fa4acddf7678d34a35d4f13", size = 79079, upload-time = "2024-11-01T14:06:59.472Z" },
{ url = "https://files.pythonhosted.org/packages/5c/51/d46dc9332f9a647593c947b4b88e2381c8dfc0942d15b8edc0310fa4abb1/watchdog-6.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:9041567ee8953024c83343288ccc458fd0a2d811d6a0fd68c4c22609e3490379", size = 79078, upload-time = "2024-11-01T14:07:01.431Z" },
{ url = "https://files.pythonhosted.org/packages/d4/57/04edbf5e169cd318d5f07b4766fee38e825d64b6913ca157ca32d1a42267/watchdog-6.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:82dc3e3143c7e38ec49d61af98d6558288c415eac98486a5c581726e0737c00e", size = 79076, upload-time = "2024-11-01T14:07:02.568Z" },
{ url = "https://files.pythonhosted.org/packages/ab/cc/da8422b300e13cb187d2203f20b9253e91058aaf7db65b74142013478e66/watchdog-6.0.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:212ac9b8bf1161dc91bd09c048048a95ca3a4c4f5e5d4a7d1b1a7d5752a7f96f", size = 79077, upload-time = "2024-11-01T14:07:03.893Z" },
{ url = "https://files.pythonhosted.org/packages/2c/3b/b8964e04ae1a025c44ba8e4291f86e97fac443bca31de8bd98d3263d2fcf/watchdog-6.0.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:e3df4cbb9a450c6d49318f6d14f4bbc80d763fa587ba46ec86f99f9e6876bb26", size = 79078, upload-time = "2024-11-01T14:07:05.189Z" },
{ url = "https://files.pythonhosted.org/packages/62/ae/a696eb424bedff7407801c257d4b1afda455fe40821a2be430e173660e81/watchdog-6.0.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:2cce7cfc2008eb51feb6aab51251fd79b85d9894e98ba847408f662b3395ca3c", size = 79077, upload-time = "2024-11-01T14:07:06.376Z" },
{ url = "https://files.pythonhosted.org/packages/b5/e8/dbf020b4d98251a9860752a094d09a65e1b436ad181faf929983f697048f/watchdog-6.0.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:20ffe5b202af80ab4266dcd3e91aae72bf2da48c0d33bdb15c66658e685e94e2", size = 79078, upload-time = "2024-11-01T14:07:07.547Z" },
{ url = "https://files.pythonhosted.org/packages/07/f6/d0e5b343768e8bcb4cda79f0f2f55051bf26177ecd5651f84c07567461cf/watchdog-6.0.0-py3-none-win32.whl", hash = "sha256:07df1fdd701c5d4c8e55ef6cf55b8f0120fe1aef7ef39a1c6fc6bc2e606d517a", size = 79065, upload-time = "2024-11-01T14:07:09.525Z" },
{ url = "https://files.pythonhosted.org/packages/db/d9/c495884c6e548fce18a8f40568ff120bc3a4b7b99813081c8ac0c936fa64/watchdog-6.0.0-py3-none-win_amd64.whl", hash = "sha256:cbafb470cf848d93b5d013e2ecb245d4aa1c8fd0504e863ccefa32445359d680", size = 79070, upload-time = "2024-11-01T14:07:10.686Z" },
{ url = "https://files.pythonhosted.org/packages/33/e8/e40370e6d74ddba47f002a32919d91310d6074130fe4e17dabcafc15cbf1/watchdog-6.0.0-py3-none-win_ia64.whl", hash = "sha256:a1914259fa9e1454315171103c6a30961236f508b9b623eae470268bbcc6a22f", size = 79067, upload-time = "2024-11-01T14:07:11.845Z" },
]
dybdeskarphet-niri-companion-6d9cebf/wiki/ 0000775 0000000 0000000 00000000000 15207340103 0021005 5 ustar 00root root 0000000 0000000 dybdeskarphet-niri-companion-6d9cebf/wiki/Home.md 0000664 0000000 0000000 00000000166 15207340103 0022222 0 ustar 00root root 0000000 0000000 # niri-companion
Welcome to the niri-companion documentation!
Feel free to look through other wiki pages for usage.
dybdeskarphet-niri-companion-6d9cebf/wiki/assets/ 0000775 0000000 0000000 00000000000 15207340103 0022307 5 ustar 00root root 0000000 0000000 dybdeskarphet-niri-companion-6d9cebf/wiki/assets/workspaces_rofi.png 0000664 0000000 0000000 00000254602 15207340103 0026226 0 ustar 00root root 0000000 0000000 PNG
IHDR . YIIDATx$Yw̧rKcm۶m۶m۶miJ23"vjz;kO]wꪫꪫ?n}j{laۧv?^{laۧv?}j{l^ߘ_?}j{l^ߘ{_ c>=O=O~S;c>ÿdۧv?}j{lao%}/?qS;['1/}/ޗ2o}/'1^ߘ_~o}/^ߘ_5>/eg,o{_˼'1k|{_˼'1k|{_˼'1k|{_˼'1k|g%k|g%k|{_˼'1k|{_<=O5>/eޗ2Y^ߘ_yO|c~K ]wu檫ꪫS;~ۧv?O~S;c>=O~S;<{laۧv?}j{lao%}/ޗ2o}/ޗ2 >}jMyn=Op{lyO|c~KzO|c^_5>/e^ߘ_湽'1k|{_˼'1k|{_˼'1k|{_˼'1k|{_˼'1k|s_5>/e^ߘ_5>}/[ޗ2o}/zO|c~K'1^ߘ_5>/e^ߘ_5>/e^ߘ_5>/e^ߘ_5>/e^ߘ_5>/e^ߘ_5>/e^ߘ_5>/e^ߘ_5>/e^ߘ_5>/e^ߘ_5>/e^ߘ_5>/e^ߘ_5>/e^ߘ_5>/e^]wu檫ꪫg>}j{laۧv?}j{lao%}/ޗ2=O~S;c>=Kޑ_5>/~ҏ}j{laۧv?}j7~k|s_5>/e^ߘ_?k|{_˼'1k|{_=O~S;c>k|{_˼'1k|{_˼'1=O~S;c?^ߘ/e }j{laۧvxO|c%k|{_˼'1ޗ2o}/ޗ25>/eޗ2o~K7yO|c~K7yO|c~K7~k|s_5>}/<_5>/eޗ2{O|c~K7yO|c~K7yO|c~K7yO|c~K7yO|c~K7yO|c~K7yO|c~K7yO|c~K7yO|c~K7yO|c~K7yO|c~K7yO|c~K7yO|c~K ]wu檫ꪫS;c>}j{laۧv?}j{闼#k|{_5>/e }j{laۧv?}j7~=O~S;c>=O@o}/^ߘޗ2o}/ޗ2o}/ޗ2/k|{_5>/e^To}/ޗ2o}/s7ޗ2o}/ޗ2o}/ޗ2o}/ޗ2o}/ޗ2o}/ޗ2o}/ޗ2o}/ޗ2U^ߘ_~o}/oޗ2/k|{_5>/eޗ2/"tuיꪫO~ma>=}j{o>=O~S;c>s?}j{laۧv?_ޗ2o}/ޗ2o}/'(ۧv?}j{laۧvx7?~S;/e^ߘ_5>/e^ߘ_5>/e^ߘ_5>/e^ߘ_5>/e^ߘ_5>/e^ߘ_5>/e^ߘ_5>/e^ߘ_5>/e^ߘ_5>/e^ߘ_5>/e^ߘ_5>/e^ߘ_5>/e^ߘ_5>/e^]wu檫ꪫ*O~S;cqS;M/e^ߘ_?}j{la>=O}j{laۧv?}jk|s_5>/e^ߘ_k|{_˼'1k|{_=Op{laۧv?}j{lao%}/ޗ2o}/ޗ2o/~ҏ}j{laۧv?}j{lc>=Op{l5>/e^ߘ_湽'1/}/zO|c~K7'1^ߘޗ2o}/ޗ2őyO|c{_˼'1/e^ߘޗ2o~K7ޗ2Y^ߘ_5>/e^ߘ_5>/e^ߘ_5>/e^ߘ_5>/e^ߘ_5>/e^ߘ_5>/e^ߘ_5>/e^ߘ_5>/e^ߘ_5>/e^ߘ_5>/e^ߘ_5>/e^ߘ_5>/e^ߘ_~o}/뮻\uUW]uUW?}j{laۧv?}j{laۧv? ^ߘ_5>/ehۧv?}j{laۧv?}j{laۧv?}j{laۧvx7ynos/e^ߘ_5>/e^To}/ޗ2o}/^ߘ{_˼'1k|{_˼'1k|{_˼'1k|{_˼'1k|{_˼'1k|{_˼'1k|{_˼'17yO|c~K7k|{_gyO|c~K5>/eu]g;lۤwD ꪫꪫ#-7Xq#`b{
G,7X`b{
?br#,Xlo?br }ۗ~ɿo<'
G,7X`b{
G,7X~#ob{-Xlo ط}YceyO%}ۗq?