- Add _load_user_plugin: loads AgentProvider subclass from
~/.bot-bottle/contrib/<name>/agent_provider.py; get_provider()
checks there first before falling back to built-ins
- Add Dockerfile cascade to docker prepare: per-bottle override →
manifest dockerfile → user plugin Dockerfile → provider default
- Move provision_ca and provision_git from backend-specific
provision/ modules to AgentProvider ABC as overridable defaults;
delete docker/provision/ca.py, docker/provision/git.py,
smolmachines/provision/ca.py, smolmachines/provision/git.py
- Add git_gate_insteadof_host/scheme properties to BottlePlan base;
SmolmachinesBottlePlan overrides them to return agent_git_gate_host
and "http" so provision_git works correctly on both backends
- Move SIGKILL retry from smolmachines provision/ca.py into
SmolmachinesBottle.exec via _exec_raw helper — all exec calls
on smolmachines now transparently retry once on exit 137
- Relax manifest_agent template validation to allow user-defined
template names; keep auth_token/forward_host_credentials guards
for built-in-only features
- Update tests: rewrite test_docker_provision_git_user and
test_smolmachines_provision to call provider methods directly;
add TestSmolmachinesBottleExec for SIGKILL retry coverage
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Remove .keys() iteration in favor of direct dictionary iteration
- Remove redundant os module reimport in tui.py
- Disable unnecessary-ellipsis rule in pylintrc to avoid conflict with pyright's
Protocol type requirements
pyright: 0 errors
pylint: 9.93/10
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Remove 35+ unused imports across 20+ files (W0611). Wrap 19 lines
to fit under 100 character limit (C0301). Add type casts and
annotations in egress_addon_core.py to resolve pyright errors
caused by JSON parsing of untyped objects.
Key changes:
- Remove unused imports (abstractmethod, mock utilities, etc)
- Split long lines at logical breaks (method calls, error messages)
- Add typing.cast() for proper type inference in JSON parsing
- Explicit type annotations for dict/list accesses
Results:
- Pylint rating: 8.73/10
- egress_addon_core.py: 0 pyright errors (was 15)
- All W0611 and C0301 issues fixed
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
- Rename _manifest_util.py → manifest_util.py (module isn't private)
- Rename _as_json_object → as_json_object, _parse_git_upstream → parse_git_upstream,
_parse_git_gate_config → parse_git_gate_config,
_validate_unique_git_names → validate_unique_git_names,
_validate_egress_routes → validate_egress_routes (none are private at
module boundary — underscore prefix was a carry-over from the old
monolithic manifest.py where everything lived in one namespace)
- Move _is_ip_literal → util.is_ip_literal (generic, belongs in the
top-level util module)
- Update all import sites across manifest_*.py, manifest_extends.py,
manifest_schema.py; existing callers of manifest.py are unaffected
All 867 unit tests pass.
Closes#157. Distributes the 1,026-line manifest.py across four
focused modules:
- _manifest_util.py: ManifestError + _as_json_object (shared base)
- manifest_git.py: GitEntry, GitUser, git-gate config helpers
- manifest_egress.py: EgressRoute, EgressConfig, PipelockRoutePolicy
- manifest_agent.py: AgentProvider, Agent
manifest.py is now the residual orchestration layer: Bottle, Manifest,
and re-exports of all public names so existing callers are unaffected.
All 867 unit tests pass.