knowop 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- knowop-0.1.0/.gitignore +140 -0
- knowop-0.1.0/.pre-commit-config.yaml +468 -0
- knowop-0.1.0/AI_POLICY.md +13 -0
- knowop-0.1.0/CHANGELOG.md +26 -0
- knowop-0.1.0/CODE_OF_CONDUCT.md +25 -0
- knowop-0.1.0/CONTRIBUTING.md +45 -0
- knowop-0.1.0/LICENSE +201 -0
- knowop-0.1.0/PKG-INFO +153 -0
- knowop-0.1.0/README.md +117 -0
- knowop-0.1.0/RELEASING.md +80 -0
- knowop-0.1.0/SECURITY.md +34 -0
- knowop-0.1.0/conftest.py +19 -0
- knowop-0.1.0/knowop/__init__.py +1 -0
- knowop-0.1.0/knowop/__main__.py +17 -0
- knowop-0.1.0/knowop/agent/__init__.py +14 -0
- knowop-0.1.0/knowop/agent/__main__.py +19 -0
- knowop-0.1.0/knowop/agent/box_hook/__init__.py +4 -0
- knowop-0.1.0/knowop/agent/box_hook/__main__.py +21 -0
- knowop-0.1.0/knowop/agent/box_hook/entry.py +14 -0
- knowop-0.1.0/knowop/agent/box_hook/entry_test.py +27 -0
- knowop-0.1.0/knowop/agent/box_hook/hook.py +414 -0
- knowop-0.1.0/knowop/agent/box_hook/hook_test.py +535 -0
- knowop-0.1.0/knowop/agent/claude_stream.py +756 -0
- knowop-0.1.0/knowop/agent/claude_stream_test.py +1573 -0
- knowop-0.1.0/knowop/agent/cli.py +184 -0
- knowop-0.1.0/knowop/agent/cli_test.py +380 -0
- knowop-0.1.0/knowop/agent/codex.py +19 -0
- knowop-0.1.0/knowop/agent/codex_app.py +837 -0
- knowop-0.1.0/knowop/agent/codex_app_fake.py +91 -0
- knowop-0.1.0/knowop/agent/codex_app_fake_test.py +119 -0
- knowop-0.1.0/knowop/agent/codex_app_test.py +1488 -0
- knowop-0.1.0/knowop/agent/commands.py +194 -0
- knowop-0.1.0/knowop/agent/commands_test.py +235 -0
- knowop-0.1.0/knowop/agent/custom_types.py +57 -0
- knowop-0.1.0/knowop/agent/detach.py +747 -0
- knowop-0.1.0/knowop/agent/detach_test.py +1542 -0
- knowop-0.1.0/knowop/agent/entrypoint_test.py +84 -0
- knowop-0.1.0/knowop/agent/errors.py +39 -0
- knowop-0.1.0/knowop/agent/headless.py +708 -0
- knowop-0.1.0/knowop/agent/headless_test.py +1074 -0
- knowop-0.1.0/knowop/agent/inbound.py +282 -0
- knowop-0.1.0/knowop/agent/inbound_test.py +327 -0
- knowop-0.1.0/knowop/agent/materialize.py +689 -0
- knowop-0.1.0/knowop/agent/materialize_test.py +933 -0
- knowop-0.1.0/knowop/agent/placement.py +107 -0
- knowop-0.1.0/knowop/agent/placement_test.py +140 -0
- knowop-0.1.0/knowop/agent/program.py +12 -0
- knowop-0.1.0/knowop/agent/prompt_bridge.py +601 -0
- knowop-0.1.0/knowop/agent/prompt_bridge_test.py +997 -0
- knowop-0.1.0/knowop/agent/resume.py +347 -0
- knowop-0.1.0/knowop/agent/resume_test.py +1145 -0
- knowop-0.1.0/knowop/agent/session.py +3851 -0
- knowop-0.1.0/knowop/agent/session_capture_test.py +197 -0
- knowop-0.1.0/knowop/agent/session_test.py +10204 -0
- knowop-0.1.0/knowop/agent/sink.py +1440 -0
- knowop-0.1.0/knowop/agent/sink_test.py +2990 -0
- knowop-0.1.0/knowop/agent/slash.py +202 -0
- knowop-0.1.0/knowop/agent/slash_test.py +150 -0
- knowop-0.1.0/knowop/agent/testdata/seams/goalCommand.json +30 -0
- knowop-0.1.0/knowop/agent/testdata/seams/trustAnswer.json +10 -0
- knowop-0.1.0/knowop/agent/testdata/seams/trustCard.json +36 -0
- knowop-0.1.0/knowop/agent/testdata/sessions/claude_main.jsonl +28 -0
- knowop-0.1.0/knowop/agent/testdata/sessions/claude_sidechain.jsonl +4 -0
- knowop-0.1.0/knowop/agent/testdata/sessions/codex_main.jsonl +16 -0
- knowop-0.1.0/knowop/agent/truncate.py +273 -0
- knowop-0.1.0/knowop/agent/truncate_test.py +310 -0
- knowop-0.1.0/knowop/agent/trust.py +411 -0
- knowop-0.1.0/knowop/agent/trust_test.py +575 -0
- knowop-0.1.0/knowop/agent/worktree_diff.py +461 -0
- knowop-0.1.0/knowop/agent/worktree_diff_cli_test.py +109 -0
- knowop-0.1.0/knowop/agent/worktree_diff_test.py +479 -0
- knowop-0.1.0/knowop/cli.py +524 -0
- knowop-0.1.0/knowop/cli_test.py +1161 -0
- knowop-0.1.0/knowop/import_boundary_test.py +108 -0
- knowop-0.1.0/knowop/jobs/__init__.py +1 -0
- knowop-0.1.0/knowop/jobs/__main__.py +17 -0
- knowop-0.1.0/knowop/jobs/cli.py +87 -0
- knowop-0.1.0/knowop/jobs/cli_test.py +249 -0
- knowop-0.1.0/knowop/jobs/entrypoint_test.py +75 -0
- knowop-0.1.0/knowop/jobs/job.py +620 -0
- knowop-0.1.0/knowop/jobs/job_fetch.py +246 -0
- knowop-0.1.0/knowop/jobs/job_fetch_test.py +472 -0
- knowop-0.1.0/knowop/jobs/job_records.py +114 -0
- knowop-0.1.0/knowop/jobs/job_records_test.py +312 -0
- knowop-0.1.0/knowop/jobs/job_source.py +356 -0
- knowop-0.1.0/knowop/jobs/job_source_test.py +716 -0
- knowop-0.1.0/knowop/jobs/job_ssh.py +423 -0
- knowop-0.1.0/knowop/jobs/job_ssh_test.py +533 -0
- knowop-0.1.0/knowop/jobs/job_test.py +1342 -0
- knowop-0.1.0/knowop/lib/__init__.py +1 -0
- knowop-0.1.0/knowop/lib/testing/__init__.py +15 -0
- knowop-0.1.0/knowop/lib/testing/posix.py +162 -0
- knowop-0.1.0/knowop/lib/testing/posix_test.py +143 -0
- knowop-0.1.0/knowop/lib/testing/resources.py +918 -0
- knowop-0.1.0/knowop/lib/testing/resources_test.py +863 -0
- knowop-0.1.0/knowop/lib/testing/runner.py +39 -0
- knowop-0.1.0/knowop/lib/testing/runner_test.py +39 -0
- knowop-0.1.0/knowop/machines.py +364 -0
- knowop-0.1.0/knowop/machines_test.py +566 -0
- knowop-0.1.0/knowop/shell/__init__.py +1 -0
- knowop-0.1.0/knowop/shell/exec_command.py +359 -0
- knowop-0.1.0/knowop/shell/exec_command_test.py +181 -0
- knowop-0.1.0/knowop/shell/exec_host.py +296 -0
- knowop-0.1.0/knowop/shell/exec_host_test.py +871 -0
- knowop-0.1.0/knowop/shell/exec_stream.py +101 -0
- knowop-0.1.0/knowop/shell/exec_stream_test.py +86 -0
- knowop-0.1.0/knowop/shell/machine_host.py +371 -0
- knowop-0.1.0/knowop/shell/machine_host_test.py +851 -0
- knowop-0.1.0/knowop/shell/serve.py +278 -0
- knowop-0.1.0/knowop/shell/serve_test.py +730 -0
- knowop-0.1.0/knowop/shell/terminal_direct.py +392 -0
- knowop-0.1.0/knowop/shell/terminal_direct_aiortc.py +115 -0
- knowop-0.1.0/knowop/shell/terminal_direct_aiortc_test.py +198 -0
- knowop-0.1.0/knowop/shell/terminal_direct_test.py +589 -0
- knowop-0.1.0/knowop/shell/terminal_host.py +558 -0
- knowop-0.1.0/knowop/shell/terminal_host_test.py +1302 -0
- knowop-0.1.0/knowop/shell/trax_context.py +35 -0
- knowop-0.1.0/knowop/shell/trax_context_test.py +49 -0
- knowop-0.1.0/knowop/skills/README.md +12 -0
- knowop-0.1.0/knowop/skills/agent/SKILL.md +103 -0
- knowop-0.1.0/knowop/skills/jobs/SKILL.md +69 -0
- knowop-0.1.0/knowop/skills/shell/SKILL.md +97 -0
- knowop-0.1.0/pyproject.toml +722 -0
- knowop-0.1.0/tools/__init__.py +1 -0
- knowop-0.1.0/tools/gate/__init__.py +1 -0
- knowop-0.1.0/tools/gate/__main__.py +17 -0
- knowop-0.1.0/tools/gate/fakes.py +155 -0
- knowop-0.1.0/tools/gate/fakes_test.py +105 -0
- knowop-0.1.0/tools/gate/gate.py +364 -0
- knowop-0.1.0/tools/gate/gate_test.py +283 -0
- knowop-0.1.0/tools/gate/spool.py +93 -0
- knowop-0.1.0/tools/gate/spool_test.py +87 -0
- knowop-0.1.0/tools/gate/worker_count.py +304 -0
- knowop-0.1.0/tools/gate/worker_count_test.py +384 -0
- knowop-0.1.0/tools/testing/__init__.py +1 -0
- knowop-0.1.0/tools/testing/__main__.py +17 -0
- knowop-0.1.0/tools/testing/coverage_summary.py +85 -0
- knowop-0.1.0/tools/testing/coverage_summary_test.py +143 -0
- knowop-0.1.0/tools/testing/testing.py +296 -0
- knowop-0.1.0/tools/testing/testing_test.py +549 -0
- knowop-0.1.0/tools/testing/tiers.py +89 -0
- knowop-0.1.0/tools/testing/tiers_test.py +62 -0
- knowop-0.1.0/tools/typecheck/__init__.py +1 -0
- knowop-0.1.0/tools/typecheck/__main__.py +17 -0
- knowop-0.1.0/tools/typecheck/scope.py +61 -0
- knowop-0.1.0/tools/typecheck/scope_test.py +71 -0
- knowop-0.1.0/tools/typecheck/typecheck.py +179 -0
- knowop-0.1.0/tools/typecheck/typecheck_test.py +281 -0
- knowop-0.1.0/typings/.gitkeep +0 -0
- knowop-0.1.0/uv.lock +1566 -0
knowop-0.1.0/.gitignore
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# C extensions
|
|
7
|
+
*.so
|
|
8
|
+
|
|
9
|
+
# Distribution / packaging
|
|
10
|
+
.Python
|
|
11
|
+
build/
|
|
12
|
+
develop-eggs/
|
|
13
|
+
dist/
|
|
14
|
+
downloads/
|
|
15
|
+
eggs/
|
|
16
|
+
.eggs/
|
|
17
|
+
# lib/
|
|
18
|
+
# lib64/
|
|
19
|
+
parts/
|
|
20
|
+
sdist/
|
|
21
|
+
var/
|
|
22
|
+
wheels/
|
|
23
|
+
share/python-wheels/
|
|
24
|
+
*.egg-info/
|
|
25
|
+
.installed.cfg
|
|
26
|
+
*.egg
|
|
27
|
+
MANIFEST
|
|
28
|
+
|
|
29
|
+
# PyInstaller
|
|
30
|
+
# Usually these files are written by a python script from a template
|
|
31
|
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
32
|
+
*.manifest
|
|
33
|
+
*.spec
|
|
34
|
+
|
|
35
|
+
# Installer logs
|
|
36
|
+
pip-log.txt
|
|
37
|
+
pip-delete-this-directory.txt
|
|
38
|
+
|
|
39
|
+
# Unit test / coverage reports
|
|
40
|
+
htmlcov/
|
|
41
|
+
.tox/
|
|
42
|
+
.nox/
|
|
43
|
+
.coverage
|
|
44
|
+
.coverage.*
|
|
45
|
+
.cache
|
|
46
|
+
nosetests.xml
|
|
47
|
+
coverage.xml
|
|
48
|
+
*.cover
|
|
49
|
+
*.py,cover
|
|
50
|
+
.hypothesis/
|
|
51
|
+
.pytest_cache/
|
|
52
|
+
.testmondata
|
|
53
|
+
# Covers the SQLite sidecars testmon leaves behind (-journal, -shm, -wal).
|
|
54
|
+
.testmondata-*
|
|
55
|
+
cover/
|
|
56
|
+
|
|
57
|
+
# Translations
|
|
58
|
+
*.mo
|
|
59
|
+
*.pot
|
|
60
|
+
|
|
61
|
+
# Sphinx documentation
|
|
62
|
+
docs/_build/
|
|
63
|
+
|
|
64
|
+
# PyBuilder
|
|
65
|
+
.pybuilder/
|
|
66
|
+
target/
|
|
67
|
+
|
|
68
|
+
# Jupyter Notebook
|
|
69
|
+
.ipynb_checkpoints
|
|
70
|
+
|
|
71
|
+
# IPython
|
|
72
|
+
profile_default/
|
|
73
|
+
ipython_config.py
|
|
74
|
+
|
|
75
|
+
# pyenv
|
|
76
|
+
.python-version
|
|
77
|
+
|
|
78
|
+
# pipenv
|
|
79
|
+
Pipfile.lock
|
|
80
|
+
|
|
81
|
+
# poetry
|
|
82
|
+
poetry.lock
|
|
83
|
+
|
|
84
|
+
# pdm
|
|
85
|
+
.pdm.toml
|
|
86
|
+
.pdm-python
|
|
87
|
+
.pdm-build/
|
|
88
|
+
|
|
89
|
+
# PEP 582
|
|
90
|
+
__pypackages__/
|
|
91
|
+
|
|
92
|
+
# Celery stuff
|
|
93
|
+
celerybeat-schedule
|
|
94
|
+
celerybeat.pid
|
|
95
|
+
|
|
96
|
+
# SageMath parsed files
|
|
97
|
+
*.sage.py
|
|
98
|
+
|
|
99
|
+
# Environments
|
|
100
|
+
.env
|
|
101
|
+
.venv
|
|
102
|
+
env/
|
|
103
|
+
venv/
|
|
104
|
+
ENV/
|
|
105
|
+
env.bak/
|
|
106
|
+
venv.bak/
|
|
107
|
+
|
|
108
|
+
# Spyder project settings
|
|
109
|
+
.spyderproject.db
|
|
110
|
+
.spyproject
|
|
111
|
+
|
|
112
|
+
# Rope project settings
|
|
113
|
+
.ropeproject
|
|
114
|
+
|
|
115
|
+
# mkdocs documentation
|
|
116
|
+
/site
|
|
117
|
+
|
|
118
|
+
# mypy
|
|
119
|
+
.mypy_cache/
|
|
120
|
+
.dmypy.json
|
|
121
|
+
dmypy.json
|
|
122
|
+
|
|
123
|
+
# Pyre type checker
|
|
124
|
+
.pyre/
|
|
125
|
+
|
|
126
|
+
# pytype static type analyzer
|
|
127
|
+
.pytype/
|
|
128
|
+
|
|
129
|
+
# Cython debug symbols
|
|
130
|
+
cython_debug/
|
|
131
|
+
|
|
132
|
+
# IDE
|
|
133
|
+
.idea/
|
|
134
|
+
.vscode/
|
|
135
|
+
*.swp
|
|
136
|
+
*.swo
|
|
137
|
+
|
|
138
|
+
# OS
|
|
139
|
+
.DS_Store
|
|
140
|
+
Thumbs.db
|
|
@@ -0,0 +1,468 @@
|
|
|
1
|
+
# NEVER EDIT THIS FILE!
|
|
2
|
+
|
|
3
|
+
# Universal Style and Quality Enforcement
|
|
4
|
+
# Pre-commit/pre-push checks _and_ source-of-truth for Github workflows.
|
|
5
|
+
#
|
|
6
|
+
# Usage:
|
|
7
|
+
# The `pre-commit` dependency group supplies every tool the hooks below
|
|
8
|
+
# invoke. Naming it explicitly is belt-and-braces, NOT a requirement: uv
|
|
9
|
+
# defaults `default-groups` to `["dev"]`, and pyproject's `dev` includes
|
|
10
|
+
# `pre-commit`, so a bare `uv run` already resolves the tools (verified on a
|
|
11
|
+
# scratch project). Name it anyway so the command does not depend on that
|
|
12
|
+
# chain staying intact.
|
|
13
|
+
#
|
|
14
|
+
# uv --quiet run --frozen --group pre-commit pre-commit install
|
|
15
|
+
# uv --quiet run --frozen --group pre-commit pre-commit autoupdate
|
|
16
|
+
# uv --quiet run --frozen --group pre-commit pre-commit run --all-files
|
|
17
|
+
#
|
|
18
|
+
# May need: git config --unset-all core.hooksPath
|
|
19
|
+
# if: [ERROR] Cowardly refusing to install hooks with `core.hooksPath` set.
|
|
20
|
+
#
|
|
21
|
+
# Stages. `default_stages: [pre-commit]` below means a bare `run` sees only
|
|
22
|
+
# the pre-commit hooks; the heavy ones (ty-check-global, basedpyright-global,
|
|
23
|
+
# pytest*) declare `stages: [pre-push]` and need it named explicitly:
|
|
24
|
+
#
|
|
25
|
+
# uv --quiet run --frozen --group pre-commit pre-commit run --all-files
|
|
26
|
+
# uv --quiet run --frozen --group pre-commit pre-commit run --all-files --hook-stage pre-push
|
|
27
|
+
# uv --quiet run --frozen --group pre-commit pre-commit run --all-files --hook-stage commit-msg
|
|
28
|
+
#
|
|
29
|
+
# Always pass --files or --all-files. Bare `run` (and the hook `git commit`
|
|
30
|
+
# fires on a dirty tree) STASHES your changes -- a git mutation, and this
|
|
31
|
+
# worktree is shared.
|
|
32
|
+
#
|
|
33
|
+
#
|
|
34
|
+
# NUL-delimited, per AGENTS.md: a path containing a space becomes two
|
|
35
|
+
# arguments under `$(...)` or a bare `xargs`, and a rename record yields the
|
|
36
|
+
# name that no longer exists.
|
|
37
|
+
#
|
|
38
|
+
# # Harvest all changed files from the perspective of CWD.
|
|
39
|
+
# git -C "$(git rev-parse --show-toplevel)" diff -z --name-only --diff-filter=d HEAD \
|
|
40
|
+
# | xargs -0 --no-run-if-empty uv --quiet run --frozen --group pre-commit pre-commit run --files
|
|
41
|
+
#
|
|
42
|
+
# # Run only the files from the CWD.
|
|
43
|
+
# git --no-pager diff -z --name-only --cached --relative \
|
|
44
|
+
# | xargs -0 --no-run-if-empty uv --quiet run --frozen --group pre-commit pre-commit run --files
|
|
45
|
+
#
|
|
46
|
+
# # Run all the files from CWD.
|
|
47
|
+
# uv --quiet run --frozen --group pre-commit pre-commit run --files $(git ls-files .)
|
|
48
|
+
#
|
|
49
|
+
# One hook at a time, by id (`ruff-check`, `ty-check`, `pytest-global`, ...):
|
|
50
|
+
# uv --quiet run --frozen --group pre-commit pre-commit run ruff-check --all-files
|
|
51
|
+
# uv --quiet run --frozen --group pre-commit pre-commit run pytest-global --hook-stage pre-push
|
|
52
|
+
#
|
|
53
|
+
# Force full pytest tiers despite testmon's warm dependency database:
|
|
54
|
+
# PYTEST_FORCE_ALL=1 uv --quiet run --frozen --group pre-commit pre-commit run pytest-global --hook-stage pre-push
|
|
55
|
+
#
|
|
56
|
+
# Individual tests: the pytest hooks take no test selector, so call pytest
|
|
57
|
+
# directly.
|
|
58
|
+
#
|
|
59
|
+
# uv --quiet run --frozen --group pre-commit pytest path/to/thing_test.py
|
|
60
|
+
# uv --quiet run --frozen --group pre-commit pytest path/to/thing_test.py::test_name
|
|
61
|
+
# uv --quiet run --frozen --group pre-commit pytest -k some_substring path/to/
|
|
62
|
+
# uv --quiet run --frozen --group pre-commit pytest -n 5 path/to/
|
|
63
|
+
#
|
|
64
|
+
# Marker tiers mirror the pytest-slow-global / -ci-smoke-global /
|
|
65
|
+
# -integration-global hooks; the
|
|
66
|
+
# default `-m` filter lives in pyproject addopts, so ask for them by name:
|
|
67
|
+
#
|
|
68
|
+
# uv --quiet run --frozen --group pre-commit pytest -m slow path/to/
|
|
69
|
+
#
|
|
70
|
+
# Skipping. SKIP takes hook ids, comma-separated, and reports "Skipped":
|
|
71
|
+
#
|
|
72
|
+
# SKIP=ruff-check uv --quiet run --frozen --group pre-commit pre-commit run --all-files
|
|
73
|
+
# SKIP=pytest-global,pytest-slow-global uv --quiet run --frozen --group pre-commit pre-commit run --hook-stage pre-push --all-files
|
|
74
|
+
#
|
|
75
|
+
# `git commit --no-verify` / `git push --no-verify` bypass every hook. Both
|
|
76
|
+
# are a last resort, not a way past a red gate -- the gates are house rules
|
|
77
|
+
# (see AGENTS.md "Never suppress gates"). Fix the code the hook protects.
|
|
78
|
+
# The legitimate use is an unrelated pre-existing failure blocking an
|
|
79
|
+
# urgent unrelated commit; say so in the commit message when you do it.
|
|
80
|
+
#
|
|
81
|
+
#
|
|
82
|
+
# On Source of Truthness:
|
|
83
|
+
#
|
|
84
|
+
# Preferred location for any tool setting, in order:
|
|
85
|
+
# pyproject.toml > .pre-commit-config.yaml > .github/workflows/ci.yml
|
|
86
|
+
#
|
|
87
|
+
# Put a setting as high in this chain as the tool allows. Only drop to a
|
|
88
|
+
# lower file when the higher one cannot express it (e.g. a CLI-only flag with
|
|
89
|
+
# no config key). pyproject.toml holds tool config; .pre-commit-config.yaml
|
|
90
|
+
# is the sole source for how hooks run (thread/worker counts, heap caps);
|
|
91
|
+
# .github/workflows/ci.yml only invokes the hooks and must not redefine
|
|
92
|
+
# any of these.
|
|
93
|
+
#
|
|
94
|
+
#
|
|
95
|
+
# Design Philosophy;
|
|
96
|
+
#
|
|
97
|
+
# Only fail if there's things which cannot be auto-fixed.
|
|
98
|
+
# Hooks fix files in place; if anything changes, pre-commit reports
|
|
99
|
+
# "files were modified" and the commit is aborted. Run `git add -u`
|
|
100
|
+
# then re-commit -- the second attempt always passes.
|
|
101
|
+
#
|
|
102
|
+
# See also:
|
|
103
|
+
#
|
|
104
|
+
# https://pre-commit.com
|
|
105
|
+
# https://pre-commit.com/hooks.html
|
|
106
|
+
# https://learn.scientific-python.org/development/guides/style/
|
|
107
|
+
|
|
108
|
+
fail_fast: false
|
|
109
|
+
default_stages: [pre-commit]
|
|
110
|
+
|
|
111
|
+
repos:
|
|
112
|
+
|
|
113
|
+
# === Pre-Commit Gates =======================================================
|
|
114
|
+
|
|
115
|
+
- repo: https://github.com/pre-commit/pre-commit-hooks
|
|
116
|
+
rev: v6.0.0
|
|
117
|
+
hooks:
|
|
118
|
+
|
|
119
|
+
- id: end-of-file-fixer
|
|
120
|
+
name: end-of-file-fixer
|
|
121
|
+
stages: [pre-commit]
|
|
122
|
+
exclude: |
|
|
123
|
+
(?x)^(
|
|
124
|
+
(.*/)?third_party/
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
- id: trailing-whitespace
|
|
128
|
+
name: trailing-whitespace
|
|
129
|
+
stages: [pre-commit]
|
|
130
|
+
exclude: |
|
|
131
|
+
(?x)^(
|
|
132
|
+
(.*/)?third_party/
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
- id: check-added-large-files
|
|
136
|
+
name: check-added-large-files
|
|
137
|
+
stages: [pre-commit]
|
|
138
|
+
args: [--maxkb=800, --enforce-all]
|
|
139
|
+
exclude: |
|
|
140
|
+
(?x)^(
|
|
141
|
+
uv\.lock
|
|
142
|
+
|typings/
|
|
143
|
+
|(.*/)?chrome/chrome_(desktop|android)_useragents\.txt
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
- id: check-merge-conflict
|
|
147
|
+
name: check-merge-conflict
|
|
148
|
+
stages: [pre-commit]
|
|
149
|
+
args: [--assume-in-merge]
|
|
150
|
+
|
|
151
|
+
- id: check-yaml
|
|
152
|
+
name: check-yaml
|
|
153
|
+
stages: [pre-commit]
|
|
154
|
+
|
|
155
|
+
- id: check-toml
|
|
156
|
+
name: check-toml
|
|
157
|
+
stages: [pre-commit]
|
|
158
|
+
|
|
159
|
+
# Type-checks `${{ }}` expressions, action inputs, runner labels, and `run:`
|
|
160
|
+
# shell. A workflow expression error fails the job in 0s with no log, so
|
|
161
|
+
# nothing downstream catches it; `check-yaml` only proves the file parses.
|
|
162
|
+
# Self-selects on `^\.github/workflows/`.
|
|
163
|
+
#
|
|
164
|
+
# `actionlint`, not `-docker`/`-system`: only the golang hook provisions
|
|
165
|
+
# itself. `-docker` needs a daemon this host lacks, `-system` a hand-installed
|
|
166
|
+
# binary -- both fail closed on a fresh checkout, which is how the tool went
|
|
167
|
+
# uninstalled while the docs cited it.
|
|
168
|
+
#
|
|
169
|
+
# SC2016 only: the export workflows single-quote
|
|
170
|
+
# `--validation-command 'wheel="$wheel" ...'` deliberately -- those `$` belong
|
|
171
|
+
# to the inner shell, so "expressions don't expand" inverts the intent. Every
|
|
172
|
+
# other shellcheck rule stays live, and shellcheck runs only where installed,
|
|
173
|
+
# so this is stricter on CI than on a dev box.
|
|
174
|
+
- repo: https://github.com/rhysd/actionlint
|
|
175
|
+
rev: v1.7.12
|
|
176
|
+
hooks:
|
|
177
|
+
- id: actionlint
|
|
178
|
+
name: actionlint
|
|
179
|
+
stages: [pre-commit]
|
|
180
|
+
args: [-ignore, "SC2016:"]
|
|
181
|
+
|
|
182
|
+
# Validates uv.lock matches pyproject.toml (no network needed).
|
|
183
|
+
# Run `uv lock` manually when changing dependencies.
|
|
184
|
+
- repo: https://github.com/astral-sh/uv-pre-commit
|
|
185
|
+
rev: 0.12.17
|
|
186
|
+
hooks:
|
|
187
|
+
|
|
188
|
+
- id: uv-lock
|
|
189
|
+
name: uv-lock
|
|
190
|
+
stages: [pre-commit]
|
|
191
|
+
files: ^(pyproject\.toml|uv\.lock)$
|
|
192
|
+
|
|
193
|
+
- repo: local
|
|
194
|
+
hooks:
|
|
195
|
+
# Worker counts. Every heavy hook below sizes its own pool with
|
|
196
|
+
# `gate.workers`, which falls back to
|
|
197
|
+
# `tools.gate.worker_count.default_workers`, whose docstring derives the
|
|
198
|
+
# formula, and runs below interactive priority. Overrides, most specific
|
|
199
|
+
# first: `WORKERS_<HOOK_ID>` (`WORKERS_PYTEST_GLOBAL=1`),
|
|
200
|
+
# then `WORKERS_DEFAULT`. Per hook is what CI needs: the integration tier
|
|
201
|
+
# holds ~1.8 GB of torch/jax per worker and OOM-killed a 2-vCPU runner at
|
|
202
|
+
# two, while a type checker on the same box wants more.
|
|
203
|
+
#
|
|
204
|
+
- id: codespell
|
|
205
|
+
name: codespell
|
|
206
|
+
language: system
|
|
207
|
+
stages: [pre-commit]
|
|
208
|
+
types_or: [python, markdown, jupyter, shell]
|
|
209
|
+
entry: uv --quiet run --frozen --group pre-commit codespell
|
|
210
|
+
args: [-w]
|
|
211
|
+
exclude: |
|
|
212
|
+
(?x)^(
|
|
213
|
+
typings/
|
|
214
|
+
|(.*/)?third_party/
|
|
215
|
+
|docs/symbols\.md
|
|
216
|
+
)
|
|
217
|
+
|
|
218
|
+
- repo: https://github.com/astral-sh/ruff-pre-commit
|
|
219
|
+
rev: v0.16.8
|
|
220
|
+
hooks:
|
|
221
|
+
# Exclusions defined in pyproject.toml.
|
|
222
|
+
#
|
|
223
|
+
# `require_serial: true` on all: ruff is rayon-parallel, so pre-commit's
|
|
224
|
+
# argv partitioning stacks cpu_count saturating processes on top. Cheap
|
|
225
|
+
# here (sub-second tree-wide), same defect `basedpyright` below documents.
|
|
226
|
+
#
|
|
227
|
+
# format -> check --fix -> format, deliberately. COM812 is enabled so
|
|
228
|
+
# that any bracket the formatter wraps gets a trailing comma and is
|
|
229
|
+
# exploded one-element-per-line. The formatter's hug layout has no
|
|
230
|
+
# trailing comma, so COM812 only fires AFTER a format pass; the second
|
|
231
|
+
# format honors the comma it added. The single check->format order
|
|
232
|
+
# upstream documents converges only on the next commit attempt.
|
|
233
|
+
# COM812 is ignored in pyproject.toml (it makes `ruff format` warn) and
|
|
234
|
+
# selected only here: format -> fix (adds trailing comma to compact
|
|
235
|
+
# multi-line args) -> format (explodes them one-per-line). Dropping
|
|
236
|
+
# `--extend-select COM812` silently loses that explosion (ruff#9216).
|
|
237
|
+
- id: ruff-format
|
|
238
|
+
name: ruff-format-pre
|
|
239
|
+
stages: [pre-commit]
|
|
240
|
+
require_serial: true
|
|
241
|
+
types_or: [python, pyi, jupyter]
|
|
242
|
+
- id: ruff-check
|
|
243
|
+
name: ruff-check
|
|
244
|
+
stages: [pre-commit]
|
|
245
|
+
require_serial: true
|
|
246
|
+
types_or: [python, pyi, jupyter]
|
|
247
|
+
args: [--fix, --extend-select, COM812]
|
|
248
|
+
- id: ruff-format
|
|
249
|
+
name: ruff-format
|
|
250
|
+
stages: [pre-commit]
|
|
251
|
+
require_serial: true
|
|
252
|
+
types_or: [python, pyi, jupyter]
|
|
253
|
+
|
|
254
|
+
- repo: local
|
|
255
|
+
hooks:
|
|
256
|
+
# No official ty hook yet (https://github.com/astral-sh/ty/issues/269).
|
|
257
|
+
# The `typecheck` module holds these gates: each runs once over the
|
|
258
|
+
# files its `-spool` twin collected, sizes its own workers, and drops
|
|
259
|
+
# what `[tool.pyrefly] project-excludes` names. `pyrefly-check` checks
|
|
260
|
+
# the files `ty-check` checked, so a graph walk runs once.
|
|
261
|
+
#
|
|
262
|
+
# Each twin's `alias` is its gate's id, so `pre-commit run ty-check`
|
|
263
|
+
# selects both; a gate whose spool was never written fails rather than
|
|
264
|
+
# pass on nothing.
|
|
265
|
+
#
|
|
266
|
+
# `require_serial: true`: the checkers saturate every core alone, and
|
|
267
|
+
# pre-commit would otherwise run cpu_count of them at once.
|
|
268
|
+
- id: ty-check-spool
|
|
269
|
+
name: ty-check-spool
|
|
270
|
+
alias: ty-check
|
|
271
|
+
language: system
|
|
272
|
+
stages: [pre-commit]
|
|
273
|
+
require_serial: true
|
|
274
|
+
types_or: [python, pyi]
|
|
275
|
+
entry: uv --quiet run --frozen --group pre-commit python -m tools.gate spool ty-check
|
|
276
|
+
- id: ty-check
|
|
277
|
+
name: ty-check
|
|
278
|
+
language: system
|
|
279
|
+
stages: [pre-commit]
|
|
280
|
+
require_serial: true
|
|
281
|
+
pass_filenames: false
|
|
282
|
+
# See `superseded-at-pre-push` at the head of the Pre-Push Gates section.
|
|
283
|
+
alias: superseded-at-pre-push
|
|
284
|
+
types_or: [python, pyi]
|
|
285
|
+
entry: uv --quiet run --frozen --group pre-commit python -m tools.typecheck ty-check
|
|
286
|
+
# Off: `pyrefly-check` is the checker. Run with `--hook-stage manual`.
|
|
287
|
+
# Named files bypass pyproject's `[tool.basedpyright] exclude`, so the
|
|
288
|
+
# twin's exclude mirrors it.
|
|
289
|
+
- id: basedpyright-spool
|
|
290
|
+
name: basedpyright-spool
|
|
291
|
+
alias: basedpyright
|
|
292
|
+
language: system
|
|
293
|
+
stages: [manual]
|
|
294
|
+
require_serial: true
|
|
295
|
+
types_or: [python, pyi]
|
|
296
|
+
entry: uv --quiet run --frozen --group pre-commit python -m tools.gate spool basedpyright
|
|
297
|
+
exclude: |
|
|
298
|
+
(?x)^(
|
|
299
|
+
typings/
|
|
300
|
+
|(.*/)?third_party/
|
|
301
|
+
)
|
|
302
|
+
- id: basedpyright
|
|
303
|
+
name: basedpyright
|
|
304
|
+
language: system
|
|
305
|
+
stages: [manual]
|
|
306
|
+
# Pre-commit discards a PASSING hook's output (see the Pre-Push Gates
|
|
307
|
+
# note on `verbose`); this keeps basedpyright's summary line visible.
|
|
308
|
+
verbose: true
|
|
309
|
+
require_serial: true
|
|
310
|
+
pass_filenames: false
|
|
311
|
+
types_or: [python, pyi]
|
|
312
|
+
entry: >-
|
|
313
|
+
env NODE_OPTIONS=--max-old-space-size=2048
|
|
314
|
+
uv --quiet run --frozen --group pre-commit python -m tools.typecheck
|
|
315
|
+
basedpyright
|
|
316
|
+
# Default type checker; `basedpyright` above runs only under
|
|
317
|
+
# `--hook-stage manual`.
|
|
318
|
+
- id: pyrefly-check-spool
|
|
319
|
+
name: pyrefly-check-spool
|
|
320
|
+
alias: pyrefly-check
|
|
321
|
+
language: system
|
|
322
|
+
stages: [pre-commit]
|
|
323
|
+
require_serial: true
|
|
324
|
+
types_or: [python, pyi]
|
|
325
|
+
entry: uv --quiet run --frozen --group pre-commit python -m tools.gate spool pyrefly-check
|
|
326
|
+
- id: pyrefly-check
|
|
327
|
+
name: pyrefly-check
|
|
328
|
+
language: system
|
|
329
|
+
stages: [pre-commit]
|
|
330
|
+
require_serial: true
|
|
331
|
+
pass_filenames: false
|
|
332
|
+
# See `superseded-at-pre-push` at the head of the Pre-Push Gates section.
|
|
333
|
+
alias: superseded-at-pre-push
|
|
334
|
+
types_or: [python, pyi]
|
|
335
|
+
entry: uv --quiet run --frozen --group pre-commit python -m tools.typecheck pyrefly-check
|
|
336
|
+
- repo: local
|
|
337
|
+
hooks:
|
|
338
|
+
# Each heavy hook below is a `-spool` twin, which collects pre-commit's
|
|
339
|
+
# file chunks, then the hook, which runs once over all of them through
|
|
340
|
+
# the `gate` or `testing` module at this machine's worker count.
|
|
341
|
+
#
|
|
342
|
+
# Runs the tests PAIRED with each changed file (`x_test.py`, `test_x.py`,
|
|
343
|
+
# beside it or under `tests/`), then applies `fail_under` to the changed
|
|
344
|
+
# sources alone. ~1s, versus the whole suite at pre-push. Green with no
|
|
345
|
+
# pair found means "untested", acceptable only because pre-push is the
|
|
346
|
+
# gate. Exit 5 (nothing collected) passes: a selection whose every test
|
|
347
|
+
# carries a deselected marker is not a failure.
|
|
348
|
+
#
|
|
349
|
+
#
|
|
350
|
+
# `-n` only from 16 test files (SIDECAR_XDIST_MIN overrides): xdist's ~5s
|
|
351
|
+
# startup lost below that on the 16-thread workstation at 5 workers.
|
|
352
|
+
#
|
|
353
|
+
# files 8 12 16 20 60
|
|
354
|
+
# serial 5.7s 7.6s 6.8s 12.4s 27.8s
|
|
355
|
+
# -n5 8.1s 9.0s 7.5s 8.0s 16.3s
|
|
356
|
+
#
|
|
357
|
+
# Coverage targets are directories, never dotted modules: coverage
|
|
358
|
+
# imports a dotted target's package before collection, and a package
|
|
359
|
+
# importing torch then fails every later torch import.
|
|
360
|
+
- id: pytest-spool
|
|
361
|
+
name: pytest-spool
|
|
362
|
+
# `run pytest` selects this twin too, so its spool exists.
|
|
363
|
+
alias: pytest
|
|
364
|
+
language: system
|
|
365
|
+
stages: [pre-commit]
|
|
366
|
+
require_serial: true
|
|
367
|
+
types: [python]
|
|
368
|
+
entry: uv --quiet run --frozen --group pre-commit python -m tools.gate spool pytest
|
|
369
|
+
- id: pytest
|
|
370
|
+
name: pytest
|
|
371
|
+
language: system
|
|
372
|
+
stages: [pre-commit]
|
|
373
|
+
require_serial: true
|
|
374
|
+
pass_filenames: false
|
|
375
|
+
# A passing hook's output is discarded otherwise, which made "did any
|
|
376
|
+
# test run at all?" unanswerable from a green line.
|
|
377
|
+
verbose: true
|
|
378
|
+
# See `superseded-at-pre-push` at the head of the Pre-Push Gates section.
|
|
379
|
+
alias: superseded-at-pre-push
|
|
380
|
+
types: [python]
|
|
381
|
+
entry: uv --quiet run --frozen --group pre-commit python -m tools.testing pytest
|
|
382
|
+
# === Pre-Push Gates =========================================================
|
|
383
|
+
#
|
|
384
|
+
# To enable: uv run pre-commit install --hook-type pre-push
|
|
385
|
+
# To disable: uv run pre-commit uninstall --hook-type pre-push
|
|
386
|
+
#
|
|
387
|
+
# `ty-check`, `pyrefly-check` and `pytest` above each answer a strictly weaker
|
|
388
|
+
# question than a hook here, so all three carry
|
|
389
|
+
# `alias: superseded-at-pre-push` -- a plain `SKIP=` selector letting a lane
|
|
390
|
+
# that runs the pre-push tier drop them in one token, with no hook ids to
|
|
391
|
+
# drift. pre-commit skips every hook sharing an alias.
|
|
392
|
+
#
|
|
393
|
+
# Not cosmetic: the per-file `basedpyright` turned repo-wide when CI's
|
|
394
|
+
# periodic lane ran the commit stage `--all-files` (passing filenames also
|
|
395
|
+
# voids pyproject's excludes), and on a 2-vCPU runner it blew the 30-minute
|
|
396
|
+
# job cap while `basedpyright-global` answered the same question in 12.
|
|
397
|
+
#
|
|
398
|
+
# The pytest tiers are defined in the `testing` module's `tiers.py`: each
|
|
399
|
+
# tier's marker, empty-collection tolerance and capability guard, and the
|
|
400
|
+
# rules for when testmon may select. `verbose: true` because pre-commit prints
|
|
401
|
+
# a PASSING hook's output only under it, and every tier runs for minutes.
|
|
402
|
+
|
|
403
|
+
- repo: local
|
|
404
|
+
hooks:
|
|
405
|
+
- id: ty-check-global
|
|
406
|
+
name: ty-check-global
|
|
407
|
+
language: system
|
|
408
|
+
always_run: true
|
|
409
|
+
pass_filenames: false
|
|
410
|
+
stages: [pre-push]
|
|
411
|
+
entry: uv --quiet run --frozen --group pre-commit ty check
|
|
412
|
+
# Exclusions defined in pyproject.toml.
|
|
413
|
+
|
|
414
|
+
- id: basedpyright-global
|
|
415
|
+
name: basedpyright-global
|
|
416
|
+
language: system
|
|
417
|
+
always_run: true
|
|
418
|
+
pass_filenames: false
|
|
419
|
+
# Off: `pyrefly-check-global` is the checker. Run with `--hook-stage manual`.
|
|
420
|
+
stages: [manual]
|
|
421
|
+
entry: >-
|
|
422
|
+
env NODE_OPTIONS=--max-old-space-size=2048
|
|
423
|
+
uv --quiet run --frozen --group pre-commit python -m tools.gate
|
|
424
|
+
threaded basedpyright-global -- basedpyright --threads={workers}
|
|
425
|
+
|
|
426
|
+
- id: pyrefly-check-global
|
|
427
|
+
name: pyrefly-check-global
|
|
428
|
+
language: system
|
|
429
|
+
always_run: true
|
|
430
|
+
pass_filenames: false
|
|
431
|
+
stages: [pre-push]
|
|
432
|
+
entry: >-
|
|
433
|
+
uv --quiet run --frozen --group pre-commit python -m tools.gate
|
|
434
|
+
threaded pyrefly-check-global -- pyrefly check --threads={workers}
|
|
435
|
+
|
|
436
|
+
- id: pytest-global
|
|
437
|
+
name: pytest-global
|
|
438
|
+
language: system
|
|
439
|
+
always_run: true
|
|
440
|
+
pass_filenames: false
|
|
441
|
+
stages: [pre-push]
|
|
442
|
+
verbose: true
|
|
443
|
+
entry: uv --quiet run --frozen --group pre-commit python -m tools.testing tier pytest-global
|
|
444
|
+
- id: pytest-slow-global
|
|
445
|
+
name: pytest-slow-global
|
|
446
|
+
language: system
|
|
447
|
+
always_run: true
|
|
448
|
+
pass_filenames: false
|
|
449
|
+
stages: [pre-push]
|
|
450
|
+
verbose: true
|
|
451
|
+
entry: uv --quiet run --frozen --group pre-commit python -m tools.testing tier pytest-slow-global
|
|
452
|
+
- id: pytest-ci-smoke-global
|
|
453
|
+
name: pytest-ci-smoke-global
|
|
454
|
+
language: system
|
|
455
|
+
always_run: true
|
|
456
|
+
pass_filenames: false
|
|
457
|
+
stages: [pre-push]
|
|
458
|
+
verbose: true
|
|
459
|
+
entry: uv --quiet run --frozen --group pre-commit python -m tools.testing tier pytest-ci-smoke-global
|
|
460
|
+
- id: pytest-integration-global
|
|
461
|
+
name: pytest-integration-global
|
|
462
|
+
language: system
|
|
463
|
+
always_run: true
|
|
464
|
+
pass_filenames: false
|
|
465
|
+
stages: [pre-push]
|
|
466
|
+
verbose: true
|
|
467
|
+
entry: uv --quiet run --frozen --group pre-commit python -m tools.testing tier pytest-integration-global
|
|
468
|
+
# NEVER EDIT THIS FILE!
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
We support using AI (i.e., LLMs) as tools for coding. However, you remain responsible for any code you publish and we are responsible for any code we merge and release. We hold a high bar for all contributions to our projects.
|
|
2
|
+
|
|
3
|
+
**AI should not be used to generate comments when communicating with maintainers**. We expect comments on our projects to be written by humans. We may hide any comments that we believe are AI generated.
|
|
4
|
+
|
|
5
|
+
If you are opening an issue, we expect you to describe the problem in your own words.
|
|
6
|
+
|
|
7
|
+
If you are opening a pull request, we expect you to be able to explain the proposed changes in your own words. This includes the pull request body and responses to questions. **Do not copy responses from the AI when replying to questions from maintainers.**
|
|
8
|
+
|
|
9
|
+
Due to the foundational nature of our projects, we require a human in the loop who understands the work produced by AI. **We do not allow autonomous agents to be used for contributing to our projects**. We will close any pull requests that we believe were created autonomously.
|
|
10
|
+
|
|
11
|
+
If you wish to include context from an interaction with AI in your comments, it must be in a quote block (e.g., using `>`) and disclosed as such. It must be accompanied by human commentary explaining the relevance and implications of the context. Do not share long snippets.
|
|
12
|
+
|
|
13
|
+
We understand that AI is useful when communicating as a non-native English speaker. If you are using AI to edit your comments for this purpose, please take the time to ensure it reflects your own voice and ideas. If using AI for translation, we recommend writing in your native language and including the AI translation in a quote block.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable knowop changes are documented here. This project follows
|
|
4
|
+
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|
5
|
+
|
|
6
|
+
## Unreleased
|
|
7
|
+
|
|
8
|
+
## 0.1.0
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- `knowop login [ORG|URL]`: device login, approved in a browser. No argument
|
|
13
|
+
means `https://alpha.knowop.ai`; `ORG` means `https://ORG.knowop.ai`.
|
|
14
|
+
- `knowop connect [ORG|URL] [--name N] [--no-exec] [--sandbox]`: logs in when
|
|
15
|
+
needed, enrolling and confirming this computer in the same approval, then
|
|
16
|
+
serves its terminal, and the assistant's commands unless `--no-exec`.
|
|
17
|
+
- `knowop status`, `knowop logout`.
|
|
18
|
+
- `knowop run claude|codex`: Claude Code or Codex in this folder, recorded and
|
|
19
|
+
reachable from Chat; `knowop run attach|ls|log|send|stop NAME` reaches a
|
|
20
|
+
detached run, and `knowop run claude|codex resume SESSION` re-enters a stored
|
|
21
|
+
one.
|
|
22
|
+
- `knowop job`: runs a job on a GPU node from this repository, reads its log and
|
|
23
|
+
results, lists and cancels jobs, and keeps the secrets a job may use.
|
|
24
|
+
- `knowop machine`: the machines campaigns may run on.
|
|
25
|
+
- The `direct` extra: the direct terminal link between the browser and this
|
|
26
|
+
computer.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Code of Conduct
|
|
2
|
+
|
|
3
|
+
We want knowop to be a respectful, productive project for contributors and users.
|
|
4
|
+
|
|
5
|
+
This file gives maintainers a public moderation policy before the repository accepts outside issues and pull requests.
|
|
6
|
+
|
|
7
|
+
## Expected behavior
|
|
8
|
+
|
|
9
|
+
- Be respectful and constructive.
|
|
10
|
+
- Assume good intent.
|
|
11
|
+
- Focus criticism on ideas and code, not people.
|
|
12
|
+
- Help keep discussions clear and actionable.
|
|
13
|
+
|
|
14
|
+
## Unacceptable behavior
|
|
15
|
+
|
|
16
|
+
- Harassment, threats, or discriminatory language.
|
|
17
|
+
- Personal attacks or sustained disruption.
|
|
18
|
+
- Publishing private information without consent.
|
|
19
|
+
|
|
20
|
+
Disclose security issues privately through the process in `SECURITY.md`, not in
|
|
21
|
+
a public issue.
|
|
22
|
+
|
|
23
|
+
## Enforcement
|
|
24
|
+
|
|
25
|
+
Project maintainers may moderate discussions, close issues, or restrict participation when necessary to keep the project safe and productive. Report concerns privately to hello@rekursiv.ai.
|