-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathpyproject.toml
More file actions
192 lines (170 loc) · 8.54 KB
/
Copy pathpyproject.toml
File metadata and controls
192 lines (170 loc) · 8.54 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
181
182
183
184
185
186
187
188
189
190
191
192
[project]
name = "famstack"
version = "0.3.0b2"
description = "Self-hosted family server stack for Apple Silicon"
requires-python = ">=3.11"
# The CLI itself depends only on the stdlib — stacklet containers carry
# their own runtime deps. These extras are for host-side tooling: tests
# and hook scripts that import bot modules directly.
[project.optional-dependencies]
test = [
"pytest>=8",
"pytest-asyncio>=0.21",
"pytest-httpserver>=1.0",
# Bot runtime deps — tests import the archivist and log into Matrix
# as test users, so the bot's own libraries must be installed here.
"matrix-nio>=0.25",
"aiohttp>=3.8",
"Pillow>=10",
"loguru",
"pyyaml",
"python-frontmatter>=1.0",
"markdown",
"pypdf>=4.0",
# PDF page rendering for vision-aware classifiers (scanned PDFs).
"pypdfium2>=4.0",
# URL → Markdown for the archivist's capture pipeline. Tests run
# trafilatura against fixture HTML in-process — no network calls.
"trafilatura>=1.12,<3.0",
# The framework LLM client (stack.ai.client) wraps the OpenAI SDK.
# Tests point it at a pytest-httpserver mock /v1 endpoint.
"openai>=1.50,<3.0",
# Strip quoted history + signatures from an email reply so the mail bot
# posts only the new message (stack.* / mail bot). Real lib in tests.
"email_reply_parser>=0.5",
# Convert HTML-only email bodies to Markdown (stack.email_message).
"html2text>=2024.2",
]
# Host-side tooling for generating the demo family-document set
# (tools/family-docs). Not needed to run the stack — only to render the
# example PDFs/images. reportlab lays out the native-text PDFs (clean
# text layer for the classifier); Pillow draws the scanned-look images.
demo = [
"reportlab>=4",
"Pillow>=10",
"pyyaml",
]
[tool.pytest.ini_options]
asyncio_mode = "auto"
# Pipeline-quality evals (real model, real Paperless, slow) are opt-in via
# `tests/integration/stacktests eval` — never collected by `pytest tests/`.
norecursedirs = ["tests/integration/eval"]
markers = [
"container_lifecycle: Docker lifecycle tests for stack up/down/destroy and rendered container environments",
"demo_rig: live demo-instance tests using Simpson accounts and the configured AI endpoint",
"smoke: fast e2e coverage for the integration rig inner loop",
"v2_only: tests for the lifecycle v2 refactor (will fail until migration is complete)",
"unverified: e2e intent specs not yet reconciled against the rig; non-blocking (xfail) until verified before the next beta tag",
]
[tool.ruff]
target-version = "py311"
[tool.ruff.lint]
# Ruff's default rule set: pyflakes (F) catches the real bugs — undefined
# names, unused imports and variables — alongside the pycodestyle import (E4),
# statement (E7) and runtime-error (E9) groups. Line-length (E5) is left off
# on purpose; the codebase favours long narrative docstrings.
select = ["E4", "E7", "E9", "F"]
[tool.ruff.lint.per-file-ignores]
# Stacklet CLI entrypoints and the test suite bootstrap sys.path so they can
# import the framework before it is on the default path — the module-level
# imports legitimately follow that setup, so E402 doesn't apply.
"stacklets/**/cli/**/*.py" = ["E402"]
"tests/**/*.py" = ["E402"]
# The top-level CLI wires up ~30 argparse subcommands with deliberate one-line
# `p = sub.add_parser(...); p.add_argument(...)` pairs — compact by design.
"lib/stack/cli.py" = ["E702"]
# ---------------------------------------------------------------------------
# Type checking (basedpyright)
# ---------------------------------------------------------------------------
# Ruff catches undefined names; this catches the layer above — wrong argument
# types, attribute access on Optional, unbound branches. Run it on the files
# you touched, not the tree: `uvx basedpyright <paths>`.
#
# The interesting part is the import roots. There is no installed package
# here: the framework lives in `lib/`, and every stacklet bootstraps its own
# directory onto `sys.path` at import time. A checker that only knows about
# the repo root sees `import stack.config` and `from bot import ...` as
# unresolved, and the noise buries the real findings. So each stacklet gets an
# execution environment naming its own root. They cannot be merged into one
# global `extraPaths` — `hooks/`, `cli/` and `bot/` exist in several stacklets
# and would resolve to whichever came first.
#
# Three roots recur: `stacklets/core/bot-runner` (every bot imports
# `microbot` from there), `stacklets` itself (cross-stacklet reads like
# `memory.lib`), and the stacklet's own `bot/` directory (bot modules import
# their siblings by bare name).
#
# What stays unresolved is what genuinely is not here: `nanobot`, `fastapi`
# and friends live only inside their containers. Install them into `.venv`
# only if you want those files checked too.
[tool.basedpyright]
# "standard" is pyright's own default. basedpyright's stricter default flags
# every bare `dict`/`list` annotation, which is style, not correctness.
typeCheckingMode = "standard"
pythonVersion = "3.11"
venvPath = "."
venv = ".venv"
extraPaths = ["lib"]
# `tests` is here so the language server can index it: without it, "find
# every caller" silently skips the test suite, which is where much of the
# calling happens. It reports nothing, though — see the tests execution
# environment at the bottom. Test fixtures pass deliberately loose dicts
# into typed SDK calls, and those 800-odd complaints would bury the ~200
# real ones in shipped code. `ignore` wins even over a filename passed on
# the command line, so to check a test file you comment that line out.
include = ["lib", "stacklets", "tools", "hooks", "tests"]
exclude = [
"**/__pycache__",
"**/node_modules",
".venv",
".stack",
"lib/simple_term_menu.py", # vendored third-party file
]
# Analysed but silent. `exclude` would drop these files from the index and
# take navigation with them; `ignore` keeps them resolved and suppresses
# their diagnostics. That is what buys find-references over the test suite
# without the fixture noise.
ignore = ["tests"]
[[tool.basedpyright.executionEnvironments]]
root = "lib"
extraPaths = ["lib", "stacklets/ai", "stacklets/core/bot-runner"]
[[tool.basedpyright.executionEnvironments]]
root = "stacklets/agent"
extraPaths = ["lib", "stacklets/agent", "stacklets/agent/bot", "stacklets/core/bot-runner", "stacklets"]
[[tool.basedpyright.executionEnvironments]]
root = "stacklets/ai"
extraPaths = ["lib", "stacklets/ai", "stacklets/core/bot-runner", "stacklets"]
[[tool.basedpyright.executionEnvironments]]
root = "stacklets/backup"
# on_install.py bootstraps the engine directory itself, not its parent, to
# import `sync` for the canary string.
extraPaths = ["lib", "stacklets/backup", "stacklets/backup/engines", "stacklets/backup/engines/external-disk", "stacklets/core/bot-runner", "stacklets"]
[[tool.basedpyright.executionEnvironments]]
root = "stacklets/chatai"
extraPaths = ["lib", "stacklets/chatai", "stacklets/core/bot-runner", "stacklets"]
[[tool.basedpyright.executionEnvironments]]
root = "stacklets/code"
extraPaths = ["lib", "stacklets/code", "stacklets/core/bot-runner", "stacklets"]
[[tool.basedpyright.executionEnvironments]]
root = "stacklets/core"
extraPaths = ["lib", "stacklets/core", "stacklets/core/bot", "stacklets/core/bot-runner", "stacklets"]
[[tool.basedpyright.executionEnvironments]]
root = "stacklets/docs"
# git_mirror.py reaches across to the memory stacklet's CLI for `todo_list`.
extraPaths = ["lib", "stacklets/docs", "stacklets/docs/bot", "stacklets/memory/bot/cli", "stacklets/core/bot-runner", "stacklets"]
[[tool.basedpyright.executionEnvironments]]
root = "stacklets/infra"
extraPaths = ["lib", "stacklets/infra", "stacklets/core/bot-runner", "stacklets"]
[[tool.basedpyright.executionEnvironments]]
root = "stacklets/memory"
# `wiki` and `todo_list` live one level deeper, under bot/cli.
extraPaths = ["lib", "stacklets/memory", "stacklets/memory/bot", "stacklets/memory/bot/cli", "stacklets/core/bot-runner", "stacklets"]
[[tool.basedpyright.executionEnvironments]]
root = "stacklets/messages"
extraPaths = ["lib", "stacklets/messages", "stacklets/messages/bot", "stacklets/core/bot-runner", "stacklets"]
[[tool.basedpyright.executionEnvironments]]
root = "stacklets/photos"
extraPaths = ["lib", "stacklets/photos", "stacklets/core/bot-runner", "stacklets"]
[[tool.basedpyright.executionEnvironments]]
root = "tests"
extraPaths = ["lib", ".", "stacklets", "stacklets/core/bot-runner", "stacklets/agent/bot", "stacklets/core/bot", "stacklets/core/tools-server", "stacklets/docs/bot", "stacklets/memory/bot", "stacklets/memory/bot/cli", "stacklets/messages/bot"]