Commit Graph

809 Commits

Author SHA1 Message Date
didericis-codex eb7cae1fea docs: link macos container prd to review comment 2026-06-10 22:25:00 -04:00
didericis-codex fe82dc7f2b feat: add macos container backend scaffold 2026-06-10 22:25:00 -04:00
didericis-claude b00b0ba4aa fix(git-gate): forward force push as +refspec to upstream
test / unit (pull_request) Successful in 38s
test / integration (pull_request) Successful in 22s
lint / lint (push) Successful in 1m47s
test / unit (push) Successful in 34s
test / integration (push) Successful in 20s
Update Quality Badges / update-badges (push) Successful in 1m21s
When $old != zero and $new is not a descendant of $old (detected via
git merge-base --is-ancestor), the hook now forwards +$new:$ref so the
upstream accepts the force push instead of rejecting it as a
non-fast-forward.

Closes #233
2026-06-11 02:17:27 +00:00
didericis-codex 3f04567290 egress: require opt-in for HTTPS git fetch
test / unit (pull_request) Successful in 42s
test / integration (pull_request) Successful in 27s
lint / lint (push) Successful in 1m53s
test / unit (push) Successful in 41s
test / integration (push) Successful in 23s
Update Quality Badges / update-badges (push) Successful in 1m35s
2026-06-10 07:00:01 +00:00
didericis-codex acb9cd67c6 fix(git-gate): forward push options
test / unit (pull_request) Successful in 29s
test / integration (pull_request) Successful in 17s
lint / lint (push) Successful in 1m28s
test / unit (push) Successful in 29s
test / integration (push) Successful in 16s
Update Quality Badges / update-badges (push) Successful in 1m7s
2026-06-10 02:36:47 -04:00
didericis-codex d90ab7e646 ci: enforce pylint threshold
lint / lint (push) Successful in 1m37s
test / unit (push) Successful in 34s
test / integration (push) Successful in 16s
Update Quality Badges / update-badges (push) Successful in 1m13s
2026-06-10 06:30:03 +00:00
didericis-codex 8ea90adcaf fix: raise git http body cap 2026-06-10 06:29:46 +00:00
Quality Badge Bot de803e1e76 chore: update quality badges
- Pylint: 9.94/10
- Pyright: 0 errors

[skip ci]
2026-06-10 05:34:38 +00:00
didericis-codex 019efab804 fix: narrow pi numeric settings types
test / unit (pull_request) Successful in 49s
test / integration (pull_request) Successful in 27s
lint / lint (push) Successful in 1m37s
test / unit (push) Successful in 31s
test / integration (push) Successful in 19s
Update Quality Badges / update-badges (push) Successful in 1m20s
2026-06-10 01:13:00 -04:00
didericis-codex 957d37f51f fix: merge egress routes across extends 2026-06-10 01:13:00 -04:00
Quality Badge Bot 8e084262a0 chore: update quality badges
- Pylint: 9.94/10
- Pyright: 4 errors

[skip ci]
2026-06-10 04:07:25 +00:00
didericis 504144eb9c fix(pi): prepare runtime state and agent workdir
lint / lint (push) Failing after 1m58s
test / unit (push) Successful in 41s
test / integration (push) Successful in 24s
Update Quality Badges / update-badges (push) Successful in 1m27s
2026-06-10 00:02:28 -04:00
didericis 86374ab293 fix(pi): select configured startup models
test / unit (pull_request) Successful in 30s
test / integration (pull_request) Successful in 17s
lint / lint (push) Successful in 1m37s
test / unit (push) Successful in 33s
test / integration (push) Successful in 17s
Update Quality Badges / update-badges (push) Successful in 1m6s
2026-06-09 06:57:33 -04:00
didericis 199edb228c feat(pi): add fd and ripgrep to image
test / unit (pull_request) Successful in 35s
test / integration (pull_request) Successful in 18s
2026-06-09 06:26:19 -04:00
didericis 598a20a3f0 fix(pi): keep interactive sessions open
lint / lint (push) Successful in 1m29s
test / unit (pull_request) Successful in 30s
test / integration (pull_request) Successful in 17s
2026-06-09 06:00:40 -04:00
didericis c8b5ba3812 feat(pi): support egress injected api keys
lint / lint (push) Successful in 1m38s
test / unit (pull_request) Successful in 31s
test / integration (pull_request) Successful in 17s
2026-06-09 05:56:39 -04:00
didericis-codex 5ea9fda69b docs: activate pi provider prd
lint / lint (push) Successful in 1m43s
test / unit (pull_request) Successful in 34s
test / integration (pull_request) Successful in 18s
2026-06-09 08:32:09 +00:00
didericis-codex 4f7cfc0418 feat: add pi agent provider 2026-06-09 08:31:48 +00:00
didericis-codex 1f38a96561 docs: add pi provider prd 2026-06-09 08:23:00 +00:00
Quality Badge Bot 660b9b3810 chore: update quality badges
- Pylint: 9.94/10
- Pyright: 0 errors

[skip ci]
2026-06-09 05:46:00 +00:00
didericis 328069809b fix(pyright): remove unused shlex imports from bottle backends
test / unit (pull_request) Successful in 31s
test / integration (pull_request) Successful in 15s
lint / lint (push) Successful in 1m35s
test / unit (push) Successful in 31s
test / integration (push) Successful in 17s
Update Quality Badges / update-badges (push) Successful in 1m30s
shlex is now only used in terminal.py after the exec_shell_script refactor.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-09 00:48:46 -04:00
didericis b1551045dc feat(terminal): tint terminal background per agent color
test / unit (pull_request) Successful in 29s
test / integration (pull_request) Successful in 17s
Add backend-agnostic terminal color support via OSC escape sequences:
- New backend/terminal.py with palette_printf() and exec_shell_script()
  shared by both Docker and smolmachines bottle backends
- Emits OSC 4 (indexed palette) + OSC 11 (default background tint)
  before launching; resets both on agent exit via OSC 104/111
- OSC 11 background tint is visible even when the TUI uses true/24-bit
  colors (which bypass the palette), as Codex does for its chrome
- Fix Codex [tui] config: status_line=["model-with-reasoning"],
  theme="ansi" (dark-ansi and cwd/directory were invalid identifiers)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-09 00:47:55 -04:00
didericis d02226aab9 feat: forward agent style via native CLI config and terminal title
Replace prompt-injection for display identity with native UI wiring:
- Claude: writes a statusline shell script + custom theme JSON, wired up
  via settings.json so label/color show in the status bar and theme
- Codex: writes [tui] block into codex-config.toml (status_line,
  terminal_title, dark-ansi theme)
- Both backends set the terminal title via ANSI OSC 0 escape before
  exec-ing the agent when a label is present

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-09 00:47:55 -04:00
didericis-codex 39811c9b32 feat: forward agent display identity to prompts 2026-06-09 00:47:55 -04:00
github-actions[bot] f7f161e60f ci(prd): assign sequential numbers to new PRDs 2026-06-09 03:37:10 +00:00
didericis-codex e6040fc824 fix(start): skip backend selector
test / unit (pull_request) Successful in 40s
test / integration (pull_request) Successful in 24s
lint / lint (push) Successful in 1m47s
prd-number / assign-numbers (push) Successful in 29s
test / unit (push) Successful in 38s
test / integration (push) Successful in 27s
Update Quality Badges / update-badges (push) Failing after 1m20s
2026-06-09 03:31:26 +00:00
didericis-codex 17fc44d0d8 complete(prd): mark smolmachines default active
lint / lint (push) Successful in 1m46s
test / unit (pull_request) Successful in 41s
test / integration (pull_request) Successful in 22s
2026-06-09 03:27:58 +00:00
didericis-codex 1bebb7467f feat(backend): default to smolmachines 2026-06-09 03:27:31 +00:00
didericis cc1d986a74 test: fix smolmachines proxy assertions
lint / lint (push) Successful in 1m52s
test / unit (pull_request) Successful in 41s
test / integration (pull_request) Successful in 25s
2026-06-08 23:22:47 -04:00
didericis-codex fabcd026af test(smolmachines): verify TSI egress proxy path
lint / lint (push) Successful in 1m47s
test / unit (pull_request) Successful in 39s
test / integration (pull_request) Successful in 23s
2026-06-09 03:14:58 +00:00
didericis aff042855a ci(prd): rename PRD to prd-new placeholder per new convention
lint / lint (push) Successful in 1m47s
2026-06-08 23:10:09 -04:00
didericis 39b0c4f720 docs(prd): renumber PRD 0055 → 0058 (0055 slot taken by extended-outbound-scan) 2026-06-08 23:10:09 -04:00
didericis 43a5700ae6 docs(prd): PRD 0055 - promote smolmachines to default backend 2026-06-08 23:10:09 -04:00
didericis-codex 7acdabaf96 test: narrow metadata assertions for pyright 2026-06-08 23:05:14 -04:00
didericis-codex dfd2d5f620 fix: restore runtime workspace provisioning 2026-06-08 23:05:14 -04:00
didericis-codex f24e2857ab fix: restore backend prepare wiring 2026-06-08 23:05:14 -04:00
didericis-codex d38432f640 fix: resolve pyright strict errors 2026-06-08 23:05:14 -04:00
didericis 4e570e3e2b fix(egress): ignore stripped auth header in DLP scan 2026-06-08 23:05:14 -04:00
didericis-claude a64e3170cd refactor: make AgentProvisionPlan the source of truth for instance_name, prompt_file, image, dockerfile, guest_home
Drop the parallel fields passed through prepare() → _resolve_plan and
read everything from agent_provision instead. The provider plugin now
declares its own guest_home (so the backend stops hardcoding
"/home/node") and the wrapper that builds the provision plan accepts
instance_name and prompt_file, which providers store on the plan.

DockerBottlePlan and SmolmachinesBottlePlan expose container_name /
machine_name, image / agent_image, dockerfile_path /
agent_dockerfile_path, and prompt_file as properties that delegate to
agent_provision so existing call sites keep working unchanged.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-08 23:05:14 -04:00
didericis-claude 4da4babcf4 fix: fall back to provider's bundled Dockerfile when manifest doesn't override
BottleBackend.prepare was calling resolve_manifest_dockerfile("", spec)
for every bottle where the manifest did not set agent_provider.dockerfile.
That resolves an empty string against user_cwd, returning the cwd
itself — which docker then tried to read as a Dockerfile, giving
"is a directory" errors during image build.

When the manifest doesn't override, use the provider plugin's bundled
Dockerfile path (next to its agent_provider.py module) — mirroring
the pre-refactor behavior.
2026-06-08 23:05:14 -04:00
didericis-claude 384e496a1b fix: thread slug + resolved_env from prepare to each backend's _resolve_plan
BottleBackend.prepare computed slug and resolved_env but never passed
them to _resolve_plan. The concrete docker/smolmachines _resolve_plan
methods still had the old (spec, *, stage_dir) signature too, so
prepare's kwargs blew up with "unexpected keyword argument
'instance_name'" the moment cli.py start was invoked.

Update the abstract _resolve_plan signature and both backend
implementations to accept the full kwarg set prepare passes, and
forward to resolve_plan.resolve_plan() with everything.
2026-06-08 23:05:14 -04:00
didericis-claude b38c6110f2 chore: comment out workspace + capability_apply, fix circular imports
The recent refactor partially removed workspace planning and
capability-apply logic. This commit finishes the cleanup so the
test suite imports cleanly:

- Comment out workspace_plan field/property on BottlePlan and the
  provision_workspace dispatch.
- Comment out workspace usages in docker.util (build_image_with_cwd),
  smolmachines.provision.workspace, agent_provider.provision_git,
  smolmachines.backend.
- Comment out capability_apply imports in cli.start and cli.supervise;
  add a local CapabilityApplyError placeholder so the supervise CLI
  module still imports.
- Break the bottle_state → backend.docker → backend circular import
  by lazy-loading docker_mod inside bottle_identity, and by moving the
  resolve_common import inside BottleBackend.prepare.
- Delete tests for workspace and capability_apply (unit + integration).
- Update test fixtures to drop removed kwargs (container_name_pinned,
  derived_image, env_file, workspace_plan, agent_image_ref) from
  DockerBottlePlan / SmolmachinesBottlePlan constructors.
- Delete the obsolete test_smolmachines_prepare.py (tested the old
  resolve_plan signature; the shared prepare flow now lives in
  BottleBackend.prepare).
- Adjust test_supervise.py for the new Supervise.prepare signature
  (dockerfile_content arg removed).

925 → 897 tests, all passing.
2026-06-08 23:05:14 -04:00
didericis 74efb1c143 chore: sketch out desired refactor
Manual refactor into the rough shape we want/how we want the
resolve_plan logic to be consolidated. Needs subsequent fixes.
2026-06-08 23:05:14 -04:00
didericis-claude f23b2b9683 refactor: move guest_home onto AgentProvisionPlan as source of truth
guest_home is now a field on AgentProvisionPlan (set by each provider's
provision_plan() method). BottlePlan.guest_home becomes a read-only
property delegating to agent_provision.guest_home so existing callers
(provision_git, provision_skills, provision_prompt) are unchanged.

Both resolve_plan.py files drop guest_home from the plan constructor
call; the local variable still exists as an intermediary for the
workspace_plan call that precedes agent_provision_plan.
2026-06-08 23:05:14 -04:00
didericis-claude 423003aa05 refactor: extract shared resolve_plan helpers into backend/resolve_common.py
Both docker and smolmachines resolve_plan.py duplicated: slug minting,
metadata writing, agent state dir setup, git gate / egress / supervise
preparation, env_vars merge, and manifest dockerfile path resolution.

These are now consolidated in bot_bottle/backend/resolve_common.py.
Each backend's resolve_plan retains only its own logic (container name
resolution + env-file for docker; subnet allocation + guest_env build
for smolmachines).
2026-06-08 23:05:14 -04:00
didericis-claude af82f2ba20 refactor: move bottle_state.py to top-level bot_bottle package
Both docker and smolmachines backends use bottle state helpers.
Moving to bot_bottle/ makes the sharing explicit and removes the
cross-backend dependency (smolmachines importing from ..docker).

All callers updated: docker backend, smolmachines backend, cli
modules, and tests.
2026-06-08 23:05:14 -04:00
didericis-claude fe8e15d211 refactor: rename prepare.py → resolve_plan.py in both backends 2026-06-08 23:05:14 -04:00
didericis-claude b098556757 refactor: prefix all manifest data classes with Manifest
Avoids name collisions with same-named runtime/plugin classes
(e.g. manifest AgentProvider vs plugin AgentProvider ABC,
manifest EgressRoute vs runtime EgressRoute). Renamed:

  AgentProvider        → ManifestAgentProvider   (manifest_agent.py)
  Agent                → ManifestAgent            (manifest_agent.py)
  EgressRoute          → ManifestEgressRoute      (manifest_egress.py)
  PathMatch            → ManifestPathMatch        (manifest_egress.py)
  HeaderMatch          → ManifestHeaderMatch      (manifest_egress.py)
  MatchEntry           → ManifestMatchEntry       (manifest_egress.py)
  EgressConfig         → ManifestEgressConfig     (manifest_egress.py)
  Bottle               → ManifestBottle           (manifest.py)
  ProvisionedKeyConfig → ManifestProvisionedKeyConfig (manifest_git.py)
  GitEntry             → ManifestGitEntry         (manifest_git.py)
  GitUser              → ManifestGitUser          (manifest_git.py)
2026-06-08 23:05:14 -04:00
didericis-claude 5c5f277d6d refactor: set image/dockerfile from provider default first, override after
Since every provider always has a dockerfile, establish the default
image and dockerfile_path from the provider up front and override for
per-bottle or manifest-specified cases. Removes the image_default
intermediate variable and the trailing else branch.
2026-06-08 23:05:14 -04:00
didericis-claude 2fa5229695 refactor: AgentProvider.dockerfile always returns Path, never None
The convention is that every provider declares a Dockerfile location;
callers that care whether the file actually exists check .is_file().
Drops all `is not None` guards on the property result.
2026-06-08 23:05:14 -04:00