agent-nook 0.1.2__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.
- agent_nook-0.1.2/.github/workflows/publish-to-pypi.yml +143 -0
- agent_nook-0.1.2/.github/workflows/tests.yml +65 -0
- agent_nook-0.1.2/.gitignore +143 -0
- agent_nook-0.1.2/.lsp.json +9 -0
- agent_nook-0.1.2/.ruff.toml +154 -0
- agent_nook-0.1.2/AGENTS.md +52 -0
- agent_nook-0.1.2/LICENSE +665 -0
- agent_nook-0.1.2/PKG-INFO +506 -0
- agent_nook-0.1.2/README.md +480 -0
- agent_nook-0.1.2/pyproject.toml +242 -0
- agent_nook-0.1.2/run_lint.sh +17 -0
- agent_nook-0.1.2/run_tests.sh +7 -0
- agent_nook-0.1.2/src/agent_nook/__init__.py +35 -0
- agent_nook-0.1.2/src/agent_nook/__main__.py +356 -0
- agent_nook-0.1.2/src/agent_nook/config/__init__.py +40 -0
- agent_nook-0.1.2/src/agent_nook/config/config.py +468 -0
- agent_nook-0.1.2/src/agent_nook/config/loader.py +776 -0
- agent_nook-0.1.2/src/agent_nook/config/opencode-sandbox.yaml +196 -0
- agent_nook-0.1.2/src/agent_nook/config/sandbox.yaml +197 -0
- agent_nook-0.1.2/src/agent_nook/sandbox/__init__.py +26 -0
- agent_nook-0.1.2/src/agent_nook/sandbox/builder.py +252 -0
- agent_nook-0.1.2/src/agent_nook/sandbox/bwrap_sandbox.py +140 -0
- agent_nook-0.1.2/src/agent_nook/utils/directories.py +33 -0
- agent_nook-0.1.2/src/agent_nook/utils/logger.py +257 -0
- agent_nook-0.1.2/tests/README.md +264 -0
- agent_nook-0.1.2/tests/config/test_config.py +251 -0
- agent_nook-0.1.2/tests/config/test_env_var_expansion.py +553 -0
- agent_nook-0.1.2/tests/config/test_loader.py +258 -0
- agent_nook-0.1.2/tests/conftest.py +181 -0
- agent_nook-0.1.2/tests/integration/test_auto_init.py +132 -0
- agent_nook-0.1.2/tests/integration/test_cli.py +693 -0
- agent_nook-0.1.2/tests/integration/test_logs_follow.py +182 -0
- agent_nook-0.1.2/tests/integration/test_unset_all_env_config.yaml +14 -0
- agent_nook-0.1.2/tests/integration/test_unset_all_env_config_no_fallback.yaml +14 -0
- agent_nook-0.1.2/tests/sandbox/test_builder.py +412 -0
- agent_nook-0.1.2/tests/sandbox/test_bwrap_sandbox.py +347 -0
- agent_nook-0.1.2/tests/test_logger.py +97 -0
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
name: Publish Python 🐍 distribution 📦 to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- 'v*'
|
|
7
|
+
- 'b*'
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
build:
|
|
11
|
+
name: Build distribution 📦
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
steps:
|
|
14
|
+
- name: Checkout repository
|
|
15
|
+
uses: actions/checkout@v6
|
|
16
|
+
|
|
17
|
+
- name: Set up Python
|
|
18
|
+
uses: actions/setup-python@v7
|
|
19
|
+
with:
|
|
20
|
+
python-version: '3.x'
|
|
21
|
+
|
|
22
|
+
- name: Install build
|
|
23
|
+
run: pip install build
|
|
24
|
+
|
|
25
|
+
- name: Build a binary wheel and a source tarball
|
|
26
|
+
run: python -m build
|
|
27
|
+
|
|
28
|
+
- name: Store the distribution packages
|
|
29
|
+
uses: actions/upload-artifact@v7
|
|
30
|
+
with:
|
|
31
|
+
name: python-package-distributions
|
|
32
|
+
path: dist/
|
|
33
|
+
retention-days: 3
|
|
34
|
+
|
|
35
|
+
validate-tag:
|
|
36
|
+
name: Validate tag format
|
|
37
|
+
runs-on: ubuntu-latest
|
|
38
|
+
outputs:
|
|
39
|
+
is-valid-version: ${{ steps.validate.outputs.is-valid-version }}
|
|
40
|
+
is-prerelease: ${{ steps.validate.outputs.is-prerelease }}
|
|
41
|
+
version-matches: ${{ steps.validate.outputs.version-matches }}
|
|
42
|
+
steps:
|
|
43
|
+
- name: Checkout repository
|
|
44
|
+
uses: actions/checkout@v6
|
|
45
|
+
|
|
46
|
+
- name: Validate tag
|
|
47
|
+
id: validate
|
|
48
|
+
run: |
|
|
49
|
+
TAG="${{ github.ref_name }}"
|
|
50
|
+
VERSION_FILE="src/agent_nook/__init__.py"
|
|
51
|
+
|
|
52
|
+
# Single source of truth for the version; hatch reads this dynamically.
|
|
53
|
+
SRC_VERSION="$(grep -E "^[[:space:]]*__version__[[:space:]]*=" "$VERSION_FILE" \
|
|
54
|
+
| head -n1 \
|
|
55
|
+
| sed -E 's/.*= *"([^"]+)".*/\1/')"
|
|
56
|
+
|
|
57
|
+
# Strip a single leading v/b prefix from the tag to get the numeric version.
|
|
58
|
+
TAG_VERSION="$(printf '%s' "$TAG" | sed -E 's/^[vb]//')"
|
|
59
|
+
|
|
60
|
+
echo "tag='${TAG}' tag-version='${TAG_VERSION}' package-version='${SRC_VERSION}'"
|
|
61
|
+
|
|
62
|
+
# The tag version must match the version declared in the package.
|
|
63
|
+
if [[ "$TAG_VERSION" != "$SRC_VERSION" ]]; then
|
|
64
|
+
echo "::error::Tag version '${TAG_VERSION}' does not match the package version '${SRC_VERSION}' in src/agent_nook/__init__.py"
|
|
65
|
+
exit 1
|
|
66
|
+
fi
|
|
67
|
+
echo "version-matches=true" >> $GITHUB_OUTPUT
|
|
68
|
+
|
|
69
|
+
# Tag format: vMAJOR.MINOR.PATCH is a stable release, bMAJOR.MINOR.PATCH is a beta.
|
|
70
|
+
if [[ "$TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
|
71
|
+
echo "is-valid-version=true" >> $GITHUB_OUTPUT
|
|
72
|
+
echo "is-prerelease=false" >> $GITHUB_OUTPUT
|
|
73
|
+
elif [[ "$TAG" =~ ^b[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
|
74
|
+
echo "is-valid-version=true" >> $GITHUB_OUTPUT
|
|
75
|
+
echo "is-prerelease=true" >> $GITHUB_OUTPUT
|
|
76
|
+
else
|
|
77
|
+
echo "is-valid-version=false" >> $GITHUB_OUTPUT
|
|
78
|
+
echo "is-prerelease=false" >> $GITHUB_OUTPUT
|
|
79
|
+
fi
|
|
80
|
+
|
|
81
|
+
publish:
|
|
82
|
+
name: Publish Python 🐍 distribution 📦 to PyPI
|
|
83
|
+
runs-on: ubuntu-latest
|
|
84
|
+
needs: [build, validate-tag]
|
|
85
|
+
environment:
|
|
86
|
+
name: pypi
|
|
87
|
+
url: https://pypi.org/p/agent-nook
|
|
88
|
+
permissions:
|
|
89
|
+
id-token: write
|
|
90
|
+
if: ${{ needs.validate-tag.outputs.is-valid-version == 'true' && needs.validate-tag.outputs.is-prerelease == 'false' && needs.validate-tag.outputs.version-matches == 'true' }}
|
|
91
|
+
steps:
|
|
92
|
+
- name: Download all the dists
|
|
93
|
+
uses: actions/download-artifact@v8
|
|
94
|
+
with:
|
|
95
|
+
name: python-package-distributions
|
|
96
|
+
path: dist/
|
|
97
|
+
|
|
98
|
+
- name: Publish distribution 📦 to PyPI
|
|
99
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
100
|
+
|
|
101
|
+
publish-test:
|
|
102
|
+
name: Publish Python 🐍 distribution 📦 to TestPyPI
|
|
103
|
+
runs-on: ubuntu-latest
|
|
104
|
+
needs: [build, validate-tag]
|
|
105
|
+
environment:
|
|
106
|
+
name: testpypi
|
|
107
|
+
url: https://test.pypi.org/p/agent-nook
|
|
108
|
+
permissions:
|
|
109
|
+
id-token: write
|
|
110
|
+
if: ${{ needs.validate-tag.outputs.is-valid-version == 'true' && needs.validate-tag.outputs.version-matches == 'true' }}
|
|
111
|
+
steps:
|
|
112
|
+
- name: Download all the dists
|
|
113
|
+
uses: actions/download-artifact@v8
|
|
114
|
+
with:
|
|
115
|
+
name: python-package-distributions
|
|
116
|
+
path: dist/
|
|
117
|
+
|
|
118
|
+
- name: Publish distribution 📦 to TestPyPI
|
|
119
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
120
|
+
with:
|
|
121
|
+
repository-url: https://test.pypi.org/legacy/
|
|
122
|
+
|
|
123
|
+
release:
|
|
124
|
+
name: Create GitHub Release 🏷️
|
|
125
|
+
runs-on: ubuntu-latest
|
|
126
|
+
needs: [build, validate-tag]
|
|
127
|
+
permissions:
|
|
128
|
+
contents: write
|
|
129
|
+
if: ${{ needs.validate-tag.outputs.is-valid-version == 'true' && needs.validate-tag.outputs.version-matches == 'true' }}
|
|
130
|
+
steps:
|
|
131
|
+
- name: Download all the dists
|
|
132
|
+
uses: actions/download-artifact@v8
|
|
133
|
+
with:
|
|
134
|
+
name: python-package-distributions
|
|
135
|
+
path: dist/
|
|
136
|
+
|
|
137
|
+
- name: Create GitHub Release
|
|
138
|
+
id: create_release
|
|
139
|
+
uses: softprops/action-gh-release@v3
|
|
140
|
+
with:
|
|
141
|
+
files: dist/*
|
|
142
|
+
body: ${{ needs.validate-tag.outputs.is-prerelease == 'false' && '🎉 A new stable release is available!' || '🧪 A new beta/pre-release is available!' }}
|
|
143
|
+
prerelease: ${{ needs.validate-tag.outputs.is-prerelease == 'true' }}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
name: Tests
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
pull_request:
|
|
6
|
+
|
|
7
|
+
concurrency:
|
|
8
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
9
|
+
cancel-in-progress: true
|
|
10
|
+
|
|
11
|
+
permissions:
|
|
12
|
+
contents: read
|
|
13
|
+
|
|
14
|
+
jobs:
|
|
15
|
+
test:
|
|
16
|
+
name: pytest (Python ${{ matrix.python-version }})
|
|
17
|
+
runs-on: ubuntu-latest
|
|
18
|
+
strategy:
|
|
19
|
+
fail-fast: false
|
|
20
|
+
matrix:
|
|
21
|
+
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
|
|
22
|
+
steps:
|
|
23
|
+
- name: Checkout repository
|
|
24
|
+
uses: actions/checkout@v6
|
|
25
|
+
|
|
26
|
+
- name: Set up Python
|
|
27
|
+
uses: actions/setup-python@v7
|
|
28
|
+
with:
|
|
29
|
+
python-version: ${{ matrix.python-version }}
|
|
30
|
+
cache: pip
|
|
31
|
+
|
|
32
|
+
- name: Install bubblewrap
|
|
33
|
+
run: |
|
|
34
|
+
sudo apt-get update
|
|
35
|
+
sudo apt-get install -y bubblewrap
|
|
36
|
+
# Ubuntu 24.04 blocks unprivileged user namespaces by default
|
|
37
|
+
sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0
|
|
38
|
+
|
|
39
|
+
- name: Verify bwrap works
|
|
40
|
+
run: bwrap --bind / / -- echo bwrap-ok
|
|
41
|
+
|
|
42
|
+
- name: Install package with dev extras
|
|
43
|
+
run: pip install -e ".[dev]"
|
|
44
|
+
|
|
45
|
+
- name: Run test suite
|
|
46
|
+
run: ./run_tests.sh
|
|
47
|
+
|
|
48
|
+
lint:
|
|
49
|
+
name: ruff
|
|
50
|
+
runs-on: ubuntu-latest
|
|
51
|
+
steps:
|
|
52
|
+
- name: Checkout repository
|
|
53
|
+
uses: actions/checkout@v6
|
|
54
|
+
|
|
55
|
+
- name: Set up Python
|
|
56
|
+
uses: actions/setup-python@v7
|
|
57
|
+
with:
|
|
58
|
+
python-version: "3.14"
|
|
59
|
+
cache: pip
|
|
60
|
+
|
|
61
|
+
- name: Install package with dev extras
|
|
62
|
+
run: pip install -e ".[dev]"
|
|
63
|
+
|
|
64
|
+
- name: Run lint checks
|
|
65
|
+
run: ./run_lint.sh --check
|
|
@@ -0,0 +1,143 @@
|
|
|
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
|
+
*.egg-info/
|
|
24
|
+
.installed.cfg
|
|
25
|
+
*.egg
|
|
26
|
+
|
|
27
|
+
# PyInstaller
|
|
28
|
+
*.manifest
|
|
29
|
+
*.spec
|
|
30
|
+
|
|
31
|
+
# Installer logs
|
|
32
|
+
pip-log.txt
|
|
33
|
+
pip-delete-this-directory.txt
|
|
34
|
+
|
|
35
|
+
# Unit test / coverage reports
|
|
36
|
+
htmlcov/
|
|
37
|
+
.tox/
|
|
38
|
+
.coverage
|
|
39
|
+
.coverage.*
|
|
40
|
+
.cache
|
|
41
|
+
nosetests.xml
|
|
42
|
+
coverage.xml
|
|
43
|
+
*.cover
|
|
44
|
+
*.py,cover
|
|
45
|
+
.hypothesis/
|
|
46
|
+
.pytest_cache/
|
|
47
|
+
|
|
48
|
+
# Translations
|
|
49
|
+
*.mo
|
|
50
|
+
*.pot
|
|
51
|
+
|
|
52
|
+
# Django stuff:
|
|
53
|
+
*.log
|
|
54
|
+
local_settings.py
|
|
55
|
+
db.sqlite3
|
|
56
|
+
db.sqlite3-journal
|
|
57
|
+
|
|
58
|
+
# Flask stuff:
|
|
59
|
+
instance/
|
|
60
|
+
.webassets-cache
|
|
61
|
+
|
|
62
|
+
# Scrapy stuff:
|
|
63
|
+
.scrapy
|
|
64
|
+
|
|
65
|
+
# Sphinx documentation
|
|
66
|
+
docs/_build/
|
|
67
|
+
|
|
68
|
+
# PyBuilder
|
|
69
|
+
target/
|
|
70
|
+
|
|
71
|
+
# Jupyter Notebook
|
|
72
|
+
.ipynb_checkpoints
|
|
73
|
+
|
|
74
|
+
# IPython
|
|
75
|
+
profile_default/
|
|
76
|
+
ipython_config.py
|
|
77
|
+
|
|
78
|
+
# pyenv
|
|
79
|
+
.python-version
|
|
80
|
+
|
|
81
|
+
# pipenv
|
|
82
|
+
Pipfile.lock
|
|
83
|
+
|
|
84
|
+
# PEP 582
|
|
85
|
+
__pypackages__/
|
|
86
|
+
|
|
87
|
+
# Celery stuff
|
|
88
|
+
celerybeat-schedule
|
|
89
|
+
celerybeat.pid
|
|
90
|
+
|
|
91
|
+
# SageMath parsed files
|
|
92
|
+
*.sage.py
|
|
93
|
+
|
|
94
|
+
# Environments
|
|
95
|
+
.env
|
|
96
|
+
.venv
|
|
97
|
+
env/
|
|
98
|
+
venv/
|
|
99
|
+
ENV/
|
|
100
|
+
env.bak/
|
|
101
|
+
venv.bak/
|
|
102
|
+
|
|
103
|
+
# Spyder project settings
|
|
104
|
+
.spyderproject
|
|
105
|
+
.spyproject
|
|
106
|
+
|
|
107
|
+
# Rope project settings
|
|
108
|
+
.ropeproject
|
|
109
|
+
|
|
110
|
+
# mkdocs documentation
|
|
111
|
+
/site
|
|
112
|
+
|
|
113
|
+
# mypy
|
|
114
|
+
.mypy_cache/
|
|
115
|
+
.dmypy.json
|
|
116
|
+
dmypy.json
|
|
117
|
+
|
|
118
|
+
# Pyre type checker
|
|
119
|
+
.pyre/
|
|
120
|
+
|
|
121
|
+
# pytype static type analyzer
|
|
122
|
+
.pytype/
|
|
123
|
+
|
|
124
|
+
# Cython debug symbols
|
|
125
|
+
cython_debug/
|
|
126
|
+
|
|
127
|
+
# IDE
|
|
128
|
+
.idea/
|
|
129
|
+
.vscode/
|
|
130
|
+
*.swp
|
|
131
|
+
*.swo
|
|
132
|
+
*~
|
|
133
|
+
.DS_Store
|
|
134
|
+
Thumbs.db
|
|
135
|
+
|
|
136
|
+
# OS files
|
|
137
|
+
.DS_Store
|
|
138
|
+
.DS_Store?
|
|
139
|
+
._*
|
|
140
|
+
.Spotlight-V100
|
|
141
|
+
.Trashes
|
|
142
|
+
ehthumbs.db
|
|
143
|
+
Thumbs.db
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
# Ruff configuration for pylsp LSP integration
|
|
2
|
+
# This file is loaded by pylsp when it uses ruff for linting
|
|
3
|
+
# See: https://github.com/charliermarsh/ruff-lsp
|
|
4
|
+
|
|
5
|
+
# ───────────────────────────────────────────────────────────────────────────────
|
|
6
|
+
# LSP CONFIGURATION RULES
|
|
7
|
+
# ───────────────────────────────────────────────────────────────────────────────
|
|
8
|
+
#
|
|
9
|
+
# This configuration is specifically designed for the agent-nook project.
|
|
10
|
+
# It enforces the following rules:
|
|
11
|
+
#
|
|
12
|
+
# ✅ FIX AUTOMATICALLY (Error/Warning level):
|
|
13
|
+
# - E, W: pycodestyle errors/warnings (except minor style issues)
|
|
14
|
+
# - F: flake8 errors (undefined names, imports, etc.)
|
|
15
|
+
# - B: bugbear rules (bug-prone patterns)
|
|
16
|
+
# - I: import sorting
|
|
17
|
+
# - N: pep8-naming
|
|
18
|
+
# - C4: comprehensions
|
|
19
|
+
# - TCH: type checking hints
|
|
20
|
+
# - UP: pyupgrade (modernize code)
|
|
21
|
+
# - PLC, PLR, PLW: pylint rules (errors only, not warnings)
|
|
22
|
+
# - RUF: ruff-specific rules
|
|
23
|
+
# - SIM: flake8-simplify (simplify code)
|
|
24
|
+
# - BLE: flake8-blind-except
|
|
25
|
+
# - A: flake8-builtins (shadowing builtins)
|
|
26
|
+
#
|
|
27
|
+
# 🟡 IGNORE (Warning only, or suppress entirely):
|
|
28
|
+
# - D: pydocstyle (we use comprehensive docstrings)
|
|
29
|
+
# - ERA: eradicate (commented code)
|
|
30
|
+
# - FA: flake8-future-annotations (we use future imports)
|
|
31
|
+
# - PGH: pygrep-hooks (not needed)
|
|
32
|
+
# - PT: flake8-pytest-style (we have our own conventions)
|
|
33
|
+
# - RSE: flake8-raise (we use logging for errors)
|
|
34
|
+
# - S: flake8-bandit (security - we handle security manually)
|
|
35
|
+
# - SLF: flake8-self (private method access)
|
|
36
|
+
# - TID: flake8-tidy-imports (we allow relative imports)
|
|
37
|
+
# - TRY: tryceratops (we handle exceptions intentionally)
|
|
38
|
+
# - W191, W291, W293: Minor style issues (let humans decide)
|
|
39
|
+
# - PYI034, PYI036: Type hints (handled with type: ignore if needed)
|
|
40
|
+
# - C901: Too complex function (we keep complexity manageable)
|
|
41
|
+
# - PLR0911-PLR0917: Return/branch/arg/statement counts (we manage manually)
|
|
42
|
+
# - RUF012: Mutable defaults (we use dataclasses with field())
|
|
43
|
+
# - SIM102: Nested if statements (useful in some cases)
|
|
44
|
+
# - BLE001: Blind except (we handle specific exception types)
|
|
45
|
+
# - PLC0415: Function-level imports (needed for CLI)
|
|
46
|
+
# - PLR2004: Magic values (intentional)
|
|
47
|
+
# - PLW2901: Loop variable overwritten (intentional)
|
|
48
|
+
# - E712: Equality with True (use for clarity)
|
|
49
|
+
# - B007: Unused loop variable (intentional pattern)
|
|
50
|
+
# - PLW0603: Global statement (used in logger init)
|
|
51
|
+
# - TC003: Type checking imports (conditional use)
|
|
52
|
+
# - E501: Line too long (we have 135 char limit)
|
|
53
|
+
#
|
|
54
|
+
# ❌ NEVER FIX (Critical issues we must handle manually):
|
|
55
|
+
# - No critical security issues (S*) - we handle security manually
|
|
56
|
+
# - No deprecated code (deprecated is warning only)
|
|
57
|
+
# - No known issues in production code
|
|
58
|
+
# ───────────────────────────────────────────────────────────────────────────────
|
|
59
|
+
|
|
60
|
+
# Line length (matches pep8, but we allow longer lines for docstrings)
|
|
61
|
+
line-length = 135
|
|
62
|
+
|
|
63
|
+
# Target Python version
|
|
64
|
+
target-version = "py310"
|
|
65
|
+
|
|
66
|
+
# Exclude patterns
|
|
67
|
+
exclude = [
|
|
68
|
+
"__pycache__",
|
|
69
|
+
".git",
|
|
70
|
+
"dist",
|
|
71
|
+
"build",
|
|
72
|
+
".venv",
|
|
73
|
+
"venv",
|
|
74
|
+
".pytest_cache",
|
|
75
|
+
".mypy_cache",
|
|
76
|
+
".pytype",
|
|
77
|
+
"*.egg-info",
|
|
78
|
+
]
|
|
79
|
+
|
|
80
|
+
# Enable automatic fixing (safe fixes only)
|
|
81
|
+
fix = true
|
|
82
|
+
|
|
83
|
+
[lint]
|
|
84
|
+
select = [
|
|
85
|
+
# pycodestyle errors and warnings
|
|
86
|
+
"E", "W",
|
|
87
|
+
# flake8
|
|
88
|
+
"F",
|
|
89
|
+
# bugbear
|
|
90
|
+
"B",
|
|
91
|
+
# isort
|
|
92
|
+
"I",
|
|
93
|
+
# pep8 naming
|
|
94
|
+
"N",
|
|
95
|
+
# comprehensions
|
|
96
|
+
"C4",
|
|
97
|
+
# type checking
|
|
98
|
+
"TCH",
|
|
99
|
+
# pyupgrade
|
|
100
|
+
"UP",
|
|
101
|
+
# pylint (errors only, not warnings)
|
|
102
|
+
"PLC", "PLR", "PLW",
|
|
103
|
+
# ruff-specific
|
|
104
|
+
"RUF",
|
|
105
|
+
# flake8-simplify
|
|
106
|
+
"SIM",
|
|
107
|
+
# flake8-blind-except
|
|
108
|
+
"BLE",
|
|
109
|
+
# flake8-builtins
|
|
110
|
+
"A",
|
|
111
|
+
]
|
|
112
|
+
|
|
113
|
+
# Rules to ignore
|
|
114
|
+
ignore = [
|
|
115
|
+
"W191", # Tab before character
|
|
116
|
+
"W291", # Trailing whitespace (minor)
|
|
117
|
+
"W293", # Blank line with whitespace (minor)
|
|
118
|
+
"PYI034", # Non-self return type
|
|
119
|
+
"PYI036", # Bad exit annotation
|
|
120
|
+
"C901", # Too complex function
|
|
121
|
+
"PLR0911", # Too many return statements
|
|
122
|
+
"PLR0912", # Too many branches
|
|
123
|
+
"PLR0913", # Too many arguments
|
|
124
|
+
"PLR0915", # Too many statements
|
|
125
|
+
"PLR0917", # Too many positional arguments
|
|
126
|
+
"RUF012", # Mutable default value
|
|
127
|
+
"SIM102", # Collapsible if
|
|
128
|
+
"BLE001", # Blind except
|
|
129
|
+
"PLC0415", # Import at function level (CLI needs late imports)
|
|
130
|
+
"PLR2004", # Magic values
|
|
131
|
+
"PLW2901", # Loop variable overwritten
|
|
132
|
+
"E712", # Equality with True
|
|
133
|
+
"B007", # Unused loop variable
|
|
134
|
+
"PLW0603", # Global statement
|
|
135
|
+
"PLW0602", # Global statement with no assignment (logger.py)
|
|
136
|
+
"TC003", # Type checking imports
|
|
137
|
+
"E501", # Line too long (we have 135 char limit)
|
|
138
|
+
]
|
|
139
|
+
|
|
140
|
+
[lint.per-file-ignores]
|
|
141
|
+
"src/agent_nook/config/loader.py" = ["TID252"]
|
|
142
|
+
"src/agent_nook/config/config.py" = ["TID252"]
|
|
143
|
+
"src/agent_nook/sandbox/builder.py" = ["TID252"]
|
|
144
|
+
|
|
145
|
+
[lint.isort]
|
|
146
|
+
force-single-line = true
|
|
147
|
+
lines-after-imports = 2
|
|
148
|
+
known-first-party = ["agent_nook"]
|
|
149
|
+
|
|
150
|
+
[lint.pyflakes]
|
|
151
|
+
allowed-unused-imports = []
|
|
152
|
+
|
|
153
|
+
[lint.pycodestyle]
|
|
154
|
+
max-line-length = 135
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# AGENTS.md — Rules & Guidelines
|
|
2
|
+
|
|
3
|
+
## Core Principles
|
|
4
|
+
- **Simplicity first**: Straightforward solutions, no overengineering.
|
|
5
|
+
- **Solid engineering**: Follow best practices, document everything.
|
|
6
|
+
- **Unprivileged**: NO root/sudo. Runs as normal user.
|
|
7
|
+
- **Sandboxing**: Bubblewrap (`bwrap`) ONLY. NO podman, docker, or apptainer. No dedicated images; starts from host FS. Uses `--unshare=cgroup`.
|
|
8
|
+
|
|
9
|
+
## XDG Configuration & Paths
|
|
10
|
+
- **Config**: `~/.config/agent-nook/sandbox.yaml` (default copied from `src/agent_nook/config/sandbox.yaml`), `logging.yaml`
|
|
11
|
+
- **State/Logs**: `~/.local/state/agent-nook/`
|
|
12
|
+
- **Cache**: `~/.local/state/agent-nook/cache/`
|
|
13
|
+
- **Format**: Human-readable YAML. `/home` mounted as tmpfs by default.
|
|
14
|
+
|
|
15
|
+
## Code Quality & DRY
|
|
16
|
+
- **NEVER DUPLICATE CODE**: Do not copy-paste logic. If you write the same logic twice, you failed.
|
|
17
|
+
- **Rule of Two (MANDATORY)**: If identical control flow, validation, or data processing appears ≥2 times, you MUST extract it into a shared, generic helper.
|
|
18
|
+
- **Search First**: Always check existing utilities before writing new helpers, array manipulations, or API wrappers. Re-use and extend existing code.
|
|
19
|
+
- **Single Source of Truth**: Business logic (validation, calculations, permissions) must exist in EXACTLY ONE authoritative location. NEVER duplicate domain rules across files.
|
|
20
|
+
- **Avoid Over-Engineering**: Keep extracted helpers minimal and single-purpose. No complex "do-everything" functions with boolean flags.
|
|
21
|
+
- **Permitted Duplication**: ONLY allowed for Unit/Integration tests (prioritize DAMP readability) and decoupled DTOs/schemas across distinct service boundaries.
|
|
22
|
+
- **Refactoring Protocol**: If removing duplication requires changing public signatures or adding shared modules, PROPOSE the plan first and wait for approval.
|
|
23
|
+
|
|
24
|
+
## Testing & Verification (MANDATORY)
|
|
25
|
+
Run after EVERY change:
|
|
26
|
+
- `./run_tests.sh`
|
|
27
|
+
- `ruff check src/ --fix`
|
|
28
|
+
- `ruff format src/`
|
|
29
|
+
- Update tests for all behavior changes. Tests are the contract.
|
|
30
|
+
|
|
31
|
+
## Linting (Ruff)
|
|
32
|
+
- **Tool**: Ruff only. Line length: 135.
|
|
33
|
+
- **Action**: Auto-fix safe violations. Use `# type: ignore` for intentional type issues.
|
|
34
|
+
- **Disabled entirely**: D, ERA, FA, PGH, PT, RSE, S, SLF, TID, TRY.
|
|
35
|
+
- **Ignore (manual review)**: W191, W291, W293, PYI034, PYI036, C901, PLR0911-PLR0917, RUF012, SIM102, BLE001, PLC0415, PLR2004, PLW2901, E712, B007, PLW0603, TC003, E501.
|
|
36
|
+
|
|
37
|
+
## Documentation Contract
|
|
38
|
+
Update docs for ANY change:
|
|
39
|
+
- Signature change → Update docstrings.
|
|
40
|
+
- Config/CLI change → Update README + examples.
|
|
41
|
+
- New/Removed feature → Update README.
|
|
42
|
+
- **Pre-commit**: Verify docstrings, README examples run, and remove dead code.
|
|
43
|
+
|
|
44
|
+
## Error Handling
|
|
45
|
+
- Wrap agent execution in `try/except` with specific exceptions.
|
|
46
|
+
- Log `ERROR` with stack traces for debugging.
|
|
47
|
+
- Use `sys.exit(non-zero)` for unrecoverable errors. Prominently report sandbox failures.
|
|
48
|
+
|
|
49
|
+
## Git Hygiene (STRICT)
|
|
50
|
+
- ONLY `git add <specific files>` or `git add -p`.
|
|
51
|
+
- NEVER `git add -A` or `git add .`.
|
|
52
|
+
- NEVER delete untracked files unless explicitly requested or part of the feature. Ask if unsure.
|