-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpyproject.toml
More file actions
180 lines (162 loc) · 5.41 KB
/
Copy pathpyproject.toml
File metadata and controls
180 lines (162 loc) · 5.41 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[project]
name = "uxon"
dynamic = ["version"]
description = "Multi-user wrapper for managing terminal AI coding agent sessions (claude, codex, cursor)"
readme = "README.md"
license = "MIT"
requires-python = ">=3.11"
authors = [{ name = "Vasily Zakharov", email = "vz@vz.team" }]
keywords = ["tmux", "claude", "codex", "cursor", "ai-agents", "cli"]
classifiers = [
"Development Status :: 5 - Production/Stable",
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 3 :: Only",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Operating System :: POSIX :: Linux",
"Environment :: Console",
"Environment :: Console :: Curses",
"Topic :: Terminals",
"Topic :: System :: Systems Administration",
"Topic :: Software Development",
"Intended Audience :: Developers",
"Intended Audience :: System Administrators",
]
dependencies = [
"textual>=0.80,<9",
"tomlkit",
"platformdirs>=4",
"structlog>=24",
"msgspec>=0.18",
]
[project.urls]
Homepage = "https://github.com/vzd3v/uxon"
Issues = "https://github.com/vzd3v/uxon/issues"
Source = "https://github.com/vzd3v/uxon"
Changelog = "https://github.com/vzd3v/uxon/blob/main/CHANGELOG.md"
[project.scripts]
uxon = "uxon.cli:main"
[project.optional-dependencies]
dev = [
"pytest",
"pytest-xdist",
"ruff",
"pyright",
"import-linter>=2.11",
]
# ---------------------------------------------------------------------------
# Build backend configuration (hatchling)
# ---------------------------------------------------------------------------
[tool.hatch.version]
path = "src/uxon/__init__.py"
[tool.hatch.build.targets.wheel]
packages = ["src/uxon"]
# styles.tcss inside src/uxon/tui/ ships automatically — hatchling
# includes everything inside a package directory.
[tool.hatch.build.targets.sdist]
include = [
"src/uxon",
"tests",
"install",
"config/config.example.toml",
"examples",
"docs",
"README.md",
"LICENSE",
"CHANGELOG.md",
"CONTRIBUTING.md",
"SECURITY.md",
]
exclude = [
"docs/agents",
]
# ---------------------------------------------------------------------------
# Tool configuration
# ---------------------------------------------------------------------------
[tool.ruff]
target-version = "py311"
line-length = 100
extend-exclude = [
"docs/agents",
"**/__pycache__",
]
[tool.ruff.lint]
# Conservative initial set; SIM/RET ratchet-up tracked as follow-up.
select = ["E", "F", "W", "I", "B", "UP"]
# E501 — long lines are allowed; the formatter handles wrapping.
# B008 — argparse default factories trigger this in CLI code.
# B007 — unused loop variable in tests is sometimes deliberate.
ignore = ["E501", "B008", "B007"]
[tool.ruff.format]
quote-style = "double"
[tool.pyright]
# Tests use Textual via dynamic Pilot harness patterns that pyright cannot
# follow without aggressive ignores; keep them out of the type-check
# surface to preserve the "pyright clean" gate. The package source +
# the installer must stay clean.
include = ["src", "install"]
exclude = [
"**/__pycache__",
"docs/agents",
"tests/harness/__pycache__",
]
pythonVersion = "3.11"
typeCheckingMode = "basic"
# textual / tomlkit are now hard runtime deps but pyright still tolerates
# missing imports for stripped editor environments.
reportMissingImports = "warning"
[tool.pytest.ini_options]
testpaths = ["tests"]
addopts = "-q"
filterwarnings = [
"error",
"ignore::DeprecationWarning:textual.*",
]
# ---------------------------------------------------------------------------
# Import Linter — enforces the package layering (run `lint-imports`).
#
# The single source of truth for "lower layers must not import higher" is the
# layered contract below. It walks lazy/function-scoped imports too, so the
# known downward lazy edges (cli/main → uxon.tui inside do_interactive, the
# app/* lazy infra imports, bridge → domain.host_breaker) all satisfy it —
# tui is BELOW cli, so the lazy tui import is allowed. The latency invariant
# ("import uxon.cli" stays textual-free at MODULE LOAD) is orthogonal and is
# enforced separately by tests/test_uxon_imports.py.
#
# Zero `ignore_imports` by design — a layering violation is fixed structurally,
# never excepted (Part 2 plan, criterion #6).
# ---------------------------------------------------------------------------
[tool.importlinter]
root_package = "uxon"
# Required because the forbidden contracts below reference the external
# `textual` package; the layered contract still only reasons about uxon.*.
include_external_packages = true
[[tool.importlinter.contracts]]
name = "uxon layered architecture"
type = "layers"
layers = [
"uxon.cli",
"uxon.tui",
"uxon.app",
"uxon.gitremote",
"uxon.infra",
"uxon.domain",
"uxon.errors",
]
# Layers higher in the list may import lower ones, never the reverse. Sibling
# modules within a layer (e.g. uxon.app.kill ↔ uxon.app.listing) may import
# each other — independence is not required here.
[[tool.importlinter.contracts]]
name = "domain stays pure (no Textual)"
type = "forbidden"
source_modules = ["uxon.domain"]
forbidden_modules = ["textual"]
[[tool.importlinter.contracts]]
name = "infra never reaches into Textual"
type = "forbidden"
source_modules = ["uxon.infra"]
forbidden_modules = ["textual"]