terok-executor 0.2.1__tar.gz → 0.3.1__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.
Files changed (121) hide show
  1. {terok_executor-0.2.1 → terok_executor-0.3.1}/PKG-INFO +26 -21
  2. {terok_executor-0.2.1 → terok_executor-0.3.1}/README.md +16 -11
  3. {terok_executor-0.2.1 → terok_executor-0.3.1}/pyproject.toml +18 -18
  4. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/__init__.py +1 -1
  5. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/cli.py +8 -0
  6. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/commands.py +184 -20
  7. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/container/build.py +117 -37
  8. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/container/env.py +59 -20
  9. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/container/runner.py +135 -52
  10. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/credentials/auth.py +27 -2
  11. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/credentials/extractors.py +1 -0
  12. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/integrations/sandbox.py +2 -0
  13. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/paths.py +34 -0
  14. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/resources/agents/claude.yaml +1 -1
  15. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/resources/agents/codex.yaml +1 -1
  16. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/resources/agents/copilot.yaml +1 -1
  17. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/resources/agents/glab.yaml +6 -0
  18. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/resources/agents/opencode.yaml +1 -1
  19. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/resources/agents/pi.yaml +1 -1
  20. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/resources/agents/vibe.yaml +1 -1
  21. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/resources/scripts/hilfe +37 -17
  22. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/resources/scripts/init-ssh-and-repo.sh +22 -18
  23. terok_executor-0.3.1/src/terok_executor/resources/scripts/terok-agents.py +392 -0
  24. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/resources/templates/l1.agent-cli.Dockerfile.template +1 -0
  25. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/roster/loader.py +2 -0
  26. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/roster/schema.py +9 -0
  27. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/roster/types.py +12 -0
  28. terok_executor-0.2.1/src/terok_executor/resources/scripts/terok-agents.py +0 -227
  29. {terok_executor-0.2.1 → terok_executor-0.3.1}/LICENSE +0 -0
  30. {terok_executor-0.2.1 → terok_executor-0.3.1}/LICENSES/Apache-2.0.txt +0 -0
  31. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/_tree.py +0 -0
  32. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/_util/__init__.py +0 -0
  33. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/_util/_timezone.py +0 -0
  34. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/acp/__init__.py +0 -0
  35. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/acp/cache.py +0 -0
  36. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/acp/daemon.py +0 -0
  37. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/acp/endpoint.py +0 -0
  38. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/acp/model_options.py +0 -0
  39. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/acp/probe.py +0 -0
  40. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/acp/proxy.py +0 -0
  41. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/acp/roster.py +0 -0
  42. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/config.py +0 -0
  43. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/config_schema.py +0 -0
  44. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/container/__init__.py +0 -0
  45. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/container/cache.py +0 -0
  46. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/container/inject.py +0 -0
  47. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/credentials/__init__.py +0 -0
  48. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/credentials/vault_commands.py +0 -0
  49. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/credentials/vault_config.py +0 -0
  50. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/credentials/vendor_files.py +0 -0
  51. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/doctor.py +0 -0
  52. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/integrations/__init__.py +0 -0
  53. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/krun.py +0 -0
  54. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/preflight.py +0 -0
  55. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/provider/__init__.py +0 -0
  56. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/provider/agents.py +0 -0
  57. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/provider/instructions.py +0 -0
  58. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/provider/providers.py +0 -0
  59. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/provider/wrappers.py +0 -0
  60. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/py.typed +0 -0
  61. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/resources/__init__.py +0 -0
  62. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/resources/agents/__init__.py +0 -0
  63. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/resources/agents/caddy.yaml +0 -0
  64. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/resources/agents/coderabbit.yaml +0 -0
  65. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/resources/agents/gh.yaml +0 -0
  66. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/resources/agents/sonar.yaml +0 -0
  67. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/resources/agents/toad.yaml +0 -0
  68. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/resources/instructions/__init__.py +0 -0
  69. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/resources/instructions/default.md +0 -0
  70. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/resources/providers/anthropic.yaml +0 -0
  71. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/resources/providers/blablador.yaml +0 -0
  72. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/resources/providers/coderabbit.yaml +0 -0
  73. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/resources/providers/github.yaml +0 -0
  74. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/resources/providers/gitlab.yaml +0 -0
  75. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/resources/providers/kisski.yaml +0 -0
  76. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/resources/providers/mistral.yaml +0 -0
  77. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/resources/providers/openai.yaml +0 -0
  78. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/resources/providers/openrouter.yaml +0 -0
  79. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/resources/providers/sonarcloud.yaml +0 -0
  80. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/resources/scripts/Caddyfile +0 -0
  81. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/resources/scripts/__init__.py +0 -0
  82. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/resources/scripts/allthethings.sh +0 -0
  83. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/resources/scripts/mistral-model-sync.py +0 -0
  84. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/resources/scripts/opencode-provider +0 -0
  85. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/resources/scripts/opencode-provider-acp +0 -0
  86. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/resources/scripts/opencode-session-plugin.mjs +0 -0
  87. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/resources/scripts/opencode-toad +0 -0
  88. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/resources/scripts/pi-env.sh +0 -0
  89. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/resources/scripts/pi-git-identity.ts +0 -0
  90. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/resources/scripts/pi-provider +0 -0
  91. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/resources/scripts/pi-vault-routes.ts +0 -0
  92. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/resources/scripts/providers +0 -0
  93. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/resources/scripts/setup-codex-auth.sh +0 -0
  94. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/resources/scripts/terok-acp-env.sh +0 -0
  95. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/resources/scripts/terok-bash-banner.sh +0 -0
  96. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/resources/scripts/terok-claude-acp +0 -0
  97. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/resources/scripts/terok-codex-acp +0 -0
  98. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/resources/scripts/terok-copilot-acp +0 -0
  99. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/resources/scripts/terok-env-git-identity.sh +0 -0
  100. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/resources/scripts/terok-env.sh +0 -0
  101. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/resources/scripts/terok-native-provider +0 -0
  102. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/resources/scripts/terok-opencode-acp +0 -0
  103. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/resources/scripts/terok-toad-entry +0 -0
  104. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/resources/scripts/terok-trust-workspace.py +0 -0
  105. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/resources/scripts/terok-vibe-acp +0 -0
  106. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/resources/scripts/toad +0 -0
  107. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/resources/scripts/update-all-the-things +0 -0
  108. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/resources/scripts/vibe-model-sync.sh +0 -0
  109. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/resources/templates/__init__.py +0 -0
  110. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/resources/templates/agent-wrappers.sh.j2 +0 -0
  111. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/resources/templates/l0.dev.Dockerfile.template +0 -0
  112. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/resources/templates/l1.sidecar.Dockerfile.template +0 -0
  113. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/resources/tmux/__init__.py +0 -0
  114. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/resources/tmux/container-tmux.conf +0 -0
  115. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/resources/toad-agents/__init__.py +0 -0
  116. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/resources/toad-agents/blablador.helmholtz.de.toml +0 -0
  117. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/resources/toad-agents/kisski.academiccloud.de.toml +0 -0
  118. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/roster/__init__.py +0 -0
  119. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/sandbox.py +0 -0
  120. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/storage.py +0 -0
  121. {terok_executor-0.2.1 → terok_executor-0.3.1}/src/terok_executor/vault_addr.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: terok-executor
3
- Version: 0.2.1
3
+ Version: 0.3.1
4
4
  Summary: Single-agent task runner for hardened Podman containers
5
5
  License-Expression: Apache-2.0
6
6
  License-File: LICENSE
@@ -23,15 +23,15 @@ Classifier: Programming Language :: Python :: 3.13
23
23
  Classifier: Programming Language :: Python :: 3.14
24
24
  Classifier: Topic :: Software Development :: Quality Assurance
25
25
  Classifier: Typing :: Typed
26
- Requires-Dist: Jinja2 (>=3.1)
27
- Requires-Dist: agent-client-protocol (>=0.10.1)
28
- Requires-Dist: prompt-toolkit (>=3.0)
29
- Requires-Dist: pydantic (>=2.9)
30
- Requires-Dist: rich (>=13.0)
31
- Requires-Dist: ruamel.yaml (>=0.18)
32
- Requires-Dist: terok-sandbox (>=0.3.0,<0.4.0)
33
- Requires-Dist: terok-util (>=0.2.0,<0.3.0)
34
- Requires-Dist: tomli-w (>=1.0)
26
+ Requires-Dist: Jinja2 (>=3.1,<4.0)
27
+ Requires-Dist: agent-client-protocol (==0.10.1)
28
+ Requires-Dist: prompt-toolkit (>=3.0,<4.0)
29
+ Requires-Dist: pydantic (>=2.13,<3.0)
30
+ Requires-Dist: rich (>=15.0,<16.0)
31
+ Requires-Dist: ruamel.yaml (==0.19.1)
32
+ Requires-Dist: terok-sandbox (>=0.4.1,<0.5.0)
33
+ Requires-Dist: terok-util (>=0.2.1,<0.3.0)
34
+ Requires-Dist: tomli-w (>=1.2,<2.0)
35
35
  Project-URL: Changelog, https://github.com/terok-ai/terok-executor/blob/master/CHANGELOG.md
36
36
  Project-URL: Documentation, https://terok-ai.github.io/terok-executor/
37
37
  Project-URL: Homepage, https://terok-ai.github.io/terok-executor/
@@ -70,7 +70,7 @@ Python when you want library-grade control.
70
70
 
71
71
  ```bash
72
72
  pip install terok-executor
73
- terok-executor run claude ~/my-workspace
73
+ terok-executor run claude ~/my-workspace -p "Fix the bug"
74
74
  ```
75
75
 
76
76
  The first `run` interactively offers any missing prerequisites — sandbox
@@ -112,16 +112,18 @@ hardening guarantees.
112
112
  | Claude Code | OAuth*, API key | Anthropic Claude Code |
113
113
  | Codex | OAuth*, API key | OpenAI Codex CLI |
114
114
  | Vibe | API key | Mistral Vibe |
115
- | OpenCode | API key | Generic LLM endpoint driver bundled defaults for Helmholtz Blablador, KISSKI AcademicCloud, and your own endpoint |
115
+ | Copilot | | GitHub Copilot (no vault route yet) |
116
+ | OpenCode | — (uses provider keys) | Harness that drives any OpenAI-compatible provider — curated configs for Helmholtz Blablador, KISSKI AcademicCloud, and OpenRouter (each authenticated with its own API key) |
117
+ | Pi | — (uses provider keys) | Multi-provider harness; routes through the phantom tokens of co-installed providers |
116
118
  | gh | OAuth, API key | GitHub CLI |
117
119
  | glab | API key | GitLab CLI |
120
+ | SonarCloud | API key | SonarCloud scanner |
118
121
  | CodeRabbit | API key | CodeRabbit (sidecar tool) |
119
- | SonarCloud | API key | SonarCloud scanner (sidecar tool) |
120
122
 
121
- \* Claude and Codex OAuth are experimental, and support must be explicitly allowed in the config file.
123
+ \* Claude and Codex OAuth are experimental.
122
124
 
123
- `terok-executor agents` lists the live roster (add `--all` to
124
- include the tool entries).
125
+ `terok-executor agents list` lists the live roster (add `--all` to
126
+ include tools and harness-driven providers).
125
127
 
126
128
  ## Where it sits in the stack
127
129
 
@@ -142,13 +144,16 @@ hooks).
142
144
  | `setup` | Bootstrap sandbox services + container images |
143
145
  | `uninstall` | Remove sandbox services + container images |
144
146
  | `auth` | Authenticate a provider |
145
- | `agents` | List the agent roster |
147
+ | `agents` | Inspect the agent roster (`list`) and set the build-time default selection (`set`) |
146
148
  | `build` | Build base + agent images explicitly |
147
- | `run-tool` | Run a sidecar tool (CodeRabbit, SonarCloud) |
148
- | `list` | List running containers |
149
- | `stop` | Stop a running container |
149
+ | `run-tool` | Run a sidecar tool (CodeRabbit) |
150
+ | `list` | List containers |
151
+ | `start` | Start a stopped container |
152
+ | `stop` | Stop a container (kept for a later `start`) |
153
+ | `rm` | Remove a container and its host-side state |
150
154
  | `show-config` | Print the effective `SandboxConfig` as YAML (diffable across orchestrators) |
151
- | `vault` | Vault management (start, stop, status, install, routes) |
155
+ | `vault` | Vault management (status, unlock, lock, list, passphrase, routes, clean) |
156
+ | `sandbox` | Full terok-sandbox command tree (shield, vault, ssh, doctor, …) |
152
157
 
153
158
  ### Config override
154
159
 
@@ -28,7 +28,7 @@ Python when you want library-grade control.
28
28
 
29
29
  ```bash
30
30
  pip install terok-executor
31
- terok-executor run claude ~/my-workspace
31
+ terok-executor run claude ~/my-workspace -p "Fix the bug"
32
32
  ```
33
33
 
34
34
  The first `run` interactively offers any missing prerequisites — sandbox
@@ -70,16 +70,18 @@ hardening guarantees.
70
70
  | Claude Code | OAuth*, API key | Anthropic Claude Code |
71
71
  | Codex | OAuth*, API key | OpenAI Codex CLI |
72
72
  | Vibe | API key | Mistral Vibe |
73
- | OpenCode | API key | Generic LLM endpoint driver bundled defaults for Helmholtz Blablador, KISSKI AcademicCloud, and your own endpoint |
73
+ | Copilot | | GitHub Copilot (no vault route yet) |
74
+ | OpenCode | — (uses provider keys) | Harness that drives any OpenAI-compatible provider — curated configs for Helmholtz Blablador, KISSKI AcademicCloud, and OpenRouter (each authenticated with its own API key) |
75
+ | Pi | — (uses provider keys) | Multi-provider harness; routes through the phantom tokens of co-installed providers |
74
76
  | gh | OAuth, API key | GitHub CLI |
75
77
  | glab | API key | GitLab CLI |
78
+ | SonarCloud | API key | SonarCloud scanner |
76
79
  | CodeRabbit | API key | CodeRabbit (sidecar tool) |
77
- | SonarCloud | API key | SonarCloud scanner (sidecar tool) |
78
80
 
79
- \* Claude and Codex OAuth are experimental, and support must be explicitly allowed in the config file.
81
+ \* Claude and Codex OAuth are experimental.
80
82
 
81
- `terok-executor agents` lists the live roster (add `--all` to
82
- include the tool entries).
83
+ `terok-executor agents list` lists the live roster (add `--all` to
84
+ include tools and harness-driven providers).
83
85
 
84
86
  ## Where it sits in the stack
85
87
 
@@ -100,13 +102,16 @@ hooks).
100
102
  | `setup` | Bootstrap sandbox services + container images |
101
103
  | `uninstall` | Remove sandbox services + container images |
102
104
  | `auth` | Authenticate a provider |
103
- | `agents` | List the agent roster |
105
+ | `agents` | Inspect the agent roster (`list`) and set the build-time default selection (`set`) |
104
106
  | `build` | Build base + agent images explicitly |
105
- | `run-tool` | Run a sidecar tool (CodeRabbit, SonarCloud) |
106
- | `list` | List running containers |
107
- | `stop` | Stop a running container |
107
+ | `run-tool` | Run a sidecar tool (CodeRabbit) |
108
+ | `list` | List containers |
109
+ | `start` | Start a stopped container |
110
+ | `stop` | Stop a container (kept for a later `start`) |
111
+ | `rm` | Remove a container and its host-side state |
108
112
  | `show-config` | Print the effective `SandboxConfig` as YAML (diffable across orchestrators) |
109
- | `vault` | Vault management (start, stop, status, install, routes) |
113
+ | `vault` | Vault management (status, unlock, lock, list, passphrase, routes, clean) |
114
+ | `sandbox` | Full terok-sandbox command tree (shield, vault, ssh, doctor, …) |
110
115
 
111
116
  ### Config override
112
117
 
@@ -16,20 +16,20 @@ maintainers = [
16
16
  keywords = ["podman", "containers", "agent", "ai", "coding-agent"]
17
17
  requires-python = ">=3.12,<3.15"
18
18
  dynamic = ["classifiers"]
19
+ # Dependency pins follow the policy in AGENTS.md ("Dependency Pinning &
20
+ # pyproject.toml Hygiene"). Keep the dependency list comment-free.
19
21
  dependencies = [
20
- # 0.3.0 floor: write_sidecar (the canonical sidecar writer this
21
- # package calls) entered the public API in that release.
22
- "terok-sandbox>=0.3.0,<0.4.0",
23
- "terok-util>=0.2.0,<0.3.0",
24
- "ruamel.yaml>=0.18",
25
- "Jinja2>=3.1",
26
- "tomli-w>=1.0",
27
- "prompt-toolkit>=3.0",
28
- "pydantic>=2.9",
29
- "rich>=13.0",
30
- "agent-client-protocol>=0.10.1",
22
+ "terok-sandbox>=0.4.1,<0.5.0",
23
+ "terok-util>=0.2.1,<0.3.0",
24
+ "ruamel.yaml==0.19.1",
25
+ "Jinja2~=3.1",
26
+ "tomli-w~=1.2",
27
+ "prompt-toolkit~=3.0",
28
+ "pydantic~=2.13",
29
+ "rich~=15.0",
30
+ "agent-client-protocol==0.10.1",
31
31
  ]
32
- version = "0.2.1"
32
+ version = "0.3.1"
33
33
 
34
34
  [project.urls]
35
35
  Homepage = "https://terok-ai.github.io/terok-executor/"
@@ -60,18 +60,18 @@ packages = [
60
60
 
61
61
  [tool.poetry.group.dev.dependencies]
62
62
  pre-commit = ">=4.0"
63
- ruff = ">=0.15.16"
63
+ ruff = ">=0.15.20"
64
64
  bandit = ">=1.7"
65
65
  docstr-coverage = "^2.3.2"
66
- complexipy = ">=5.5.0"
66
+ complexipy = ">=6.0.1"
67
67
  vulture = ">=2.12"
68
68
  reuse = "^6.2.0"
69
69
  tach = "^0.35.0"
70
70
  mypy = ">=2.1.0,<3.0"
71
- import-linter = ">=2.1"
71
+ import-linter = ">=2.13"
72
72
 
73
73
  [tool.poetry.group.test.dependencies]
74
- pytest = ">=9.0.3"
74
+ pytest = ">=9.1.1"
75
75
  pytest-cov = ">=4.0"
76
76
  pytest-timeout = ">=2.0"
77
77
 
@@ -131,7 +131,7 @@ quote-style = "double"
131
131
  indent-style = "space"
132
132
  docstring-code-format = true
133
133
 
134
- # Static type checking see `make typecheck`.
134
+ # Static type checking -- see `make typecheck`.
135
135
  # ``resources/`` is excluded entirely: it holds container-side scripts and
136
136
  # bundled agent assets that aren't part of the host-side import graph
137
137
  # (``resources/toad-agents/`` isn't even a valid Python package name).
@@ -152,7 +152,7 @@ pretty = true
152
152
  show_error_codes = true
153
153
 
154
154
  # ``resources/`` holds container-side scripts (run inside task containers, not
155
- # part of the host import graph the same reason mypy excludes it). Tests
155
+ # part of the host import graph -- the same reason mypy excludes it). Tests
156
156
  # exercise them by path-loading (``SourceFileLoader``), which coverage.py can't
157
157
  # attribute, so they report 0%; omit them rather than chase phantom misses.
158
158
  [tool.coverage.run]
@@ -20,7 +20,7 @@ in their submodules; reach into ``terok_executor.<sub>`` when you
20
20
  need them.
21
21
  """
22
22
 
23
- __version__: str = "0.2.1" # placeholder; replaced at build time
23
+ __version__: str = "0.3.1" # placeholder; replaced at build time
24
24
 
25
25
  from importlib.metadata import PackageNotFoundError, version as _meta_version
26
26
 
@@ -36,6 +36,13 @@ except PackageNotFoundError:
36
36
  __version__ = "0.0.0"
37
37
 
38
38
 
39
+ #: Spelling under which sandbox setup is reachable in this front-end;
40
+ #: declared at CLI entry so sandbox-composed re-run hints name a verb
41
+ #: this CLI actually exposes (protocol: env var name, shared by string).
42
+ _SETUP_INVOCATION_ENV = "TEROK_SETUP_INVOCATION"
43
+ _SETUP_INVOCATION = "terok-executor setup"
44
+
45
+
39
46
  def main() -> None:
40
47
  """Run the terok-executor CLI.
41
48
 
@@ -44,6 +51,7 @@ def main() -> None:
44
51
  subparser convention, matching the placement used by ``docker`` and
45
52
  ``kubectl``.
46
53
  """
54
+ os.environ.setdefault(_SETUP_INVOCATION_ENV, _SETUP_INVOCATION)
47
55
  parser = argparse.ArgumentParser(
48
56
  prog="terok-executor",
49
57
  description="Single-agent task runner for hardened Podman containers",
@@ -202,7 +202,7 @@ def _resolve_host_git_identity() -> tuple[str | None, str | None]:
202
202
  def _handle_run(
203
203
  *,
204
204
  agent: str,
205
- repo: str = ".",
205
+ repo: str | None = None,
206
206
  prompt: str | None = None,
207
207
  model: str | None = None,
208
208
  max_turns: int | None = None,
@@ -218,6 +218,8 @@ def _handle_run(
218
218
  gpu: bool = False,
219
219
  memory: str | None = None,
220
220
  cpus: str | None = None,
221
+ workspace: str | None = None,
222
+ ephemeral: bool = False,
221
223
  git_identity_from_host: bool = False,
222
224
  shared_dir: str | None = None,
223
225
  shared_mount: str = "/shared",
@@ -249,6 +251,11 @@ def _handle_run(
249
251
  else:
250
252
  print("Warning: --git-identity-from-host: git config user.name not set, skipping")
251
253
 
254
+ # Bare ``run <agent>`` works on an isolated clone of the current repo;
255
+ # with --workspace the mounted directory's own content is the default.
256
+ if repo is None and workspace is None:
257
+ repo = "."
258
+
252
259
  effective_gate = gate and not no_gate
253
260
  runner = AgentRunner(base_image=base, family=family, cfg=cfg)
254
261
  resolved_shared_dir = Path(shared_dir) if shared_dir else None
@@ -260,6 +267,8 @@ def _handle_run(
260
267
  "gpu": gpu,
261
268
  "memory": memory,
262
269
  "cpus": cpus,
270
+ "workspace": Path(workspace) if workspace else None,
271
+ "ephemeral": ephemeral,
263
272
  "human_name": human_name,
264
273
  "human_email": human_email,
265
274
  "authorship": authorship,
@@ -295,12 +304,14 @@ def _handle_run(
295
304
  def _handle_run_tool(
296
305
  *,
297
306
  tool: str,
298
- repo: str = ".",
307
+ repo: str | None = None,
299
308
  branch: str | None = None,
300
309
  gate: bool = True,
301
310
  no_gate: bool = False,
302
311
  name: str | None = None,
303
312
  timeout: int = 600,
313
+ workspace: str | None = None,
314
+ ephemeral: bool = False,
304
315
  tool_args: list[str] | None = None,
305
316
  base: str = DEFAULT_BASE_IMAGE,
306
317
  family: str | None = None,
@@ -318,6 +329,11 @@ def _handle_run_tool(
318
329
 
319
330
  from .container.runner import AgentRunner
320
331
 
332
+ # Same default policy as ``run``: bare invocation works on an isolated
333
+ # clone of the current repo; --workspace brings its own content.
334
+ if repo is None and workspace is None:
335
+ repo = "."
336
+
321
337
  effective_gate = gate and not no_gate
322
338
  runner = AgentRunner(base_image=base, family=family, cfg=cfg)
323
339
  cname = runner.run_tool(
@@ -328,6 +344,8 @@ def _handle_run_tool(
328
344
  gate=effective_gate,
329
345
  name=name,
330
346
  timeout=timeout,
347
+ workspace=Path(workspace) if workspace else None,
348
+ ephemeral=ephemeral,
331
349
  timezone=timezone,
332
350
  )
333
351
  print(f"Container: {cname}")
@@ -338,10 +356,27 @@ def _handle_auth(
338
356
  agent: str,
339
357
  api_key: str | None = None,
340
358
  base_image: str | None = None,
359
+ device_auth: bool = False,
341
360
  ) -> None:
342
- """Run auth flow for an agent."""
361
+ """Run auth flow for an agent.
362
+
363
+ With *device_auth* the interactive method chooser is skipped and the
364
+ provider's headless device-code login runs directly — for remote or
365
+ headless hosts where the browser callback can't open. ``--api-key`` and
366
+ ``--device-auth`` are mutually exclusive; passing both takes the API-key
367
+ route (no container) and warns that ``--device-auth`` was ignored.
368
+ """
343
369
  from .credentials.auth import AUTH_PROVIDERS, Authenticator, store_api_key
344
370
 
371
+ if api_key is not None and device_auth:
372
+ import sys
373
+
374
+ print(
375
+ "Warning: --device-auth is ignored when --api-key is given; "
376
+ "the API key takes precedence (no auth container is launched).",
377
+ file=sys.stderr,
378
+ )
379
+
345
380
  if api_key is not None:
346
381
  if not api_key.strip():
347
382
  raise SystemExit("API key cannot be empty.")
@@ -361,6 +396,7 @@ def _handle_auth(
361
396
  None,
362
397
  mounts_dir=mounts_dir(),
363
398
  image=lambda: ImageBuilder(base).ensure_default_l1(),
399
+ device_auth=device_auth,
364
400
  )
365
401
 
366
402
  # Write vault URLs to shared config files (e.g. Vibe config.toml, gh config.yml)
@@ -455,12 +491,29 @@ def _handle_build(
455
491
 
456
492
 
457
493
  def _handle_list() -> None:
458
- """List running terok-executor containers."""
494
+ """List executor-managed containers and their states.
495
+
496
+ Two name sources meet here: the ``terok-executor-`` default-name
497
+ prefix, and the per-container state dirs under
498
+ [`container_state_root`][terok_executor.paths.container_state_root]
499
+ — the latter makes ``--name`` overrides visible. Podman stays the
500
+ truth for liveness: the dirs only contribute names to ask about,
501
+ and a name whose container is gone is skipped.
502
+ """
459
503
  from terok_executor.integrations.sandbox import PodmanRuntime
504
+ from terok_executor.paths import container_state_root
460
505
 
461
- states = PodmanRuntime().container_states("terok-executor")
506
+ runtime = PodmanRuntime()
507
+ states = runtime.container_states("terok-executor")
508
+ if states is None:
509
+ raise SystemExit("Container runtime unavailable — cannot query container states.")
510
+ run_root = container_state_root()
511
+ named = (p.name for p in run_root.iterdir() if p.is_dir()) if run_root.is_dir() else ()
512
+ for name in named:
513
+ if name not in states and (state := runtime.container(name).state) is not None:
514
+ states[name] = state
462
515
  if not states:
463
- print("No running containers.")
516
+ print("No containers.")
464
517
  return
465
518
  for name, state in sorted(states.items()):
466
519
  print(f"{name} {state}")
@@ -510,19 +563,57 @@ def _handle_show_config(*, cfg: SandboxConfig | None = None) -> None:
510
563
  yaml.dump(data, sys.stdout)
511
564
 
512
565
 
513
- def _handle_stop(*, name: str) -> None:
514
- """Stop a running container (best-effort)."""
515
- from terok_executor.integrations.sandbox import PodmanRuntime
566
+ def _handle_start(*, name: str) -> None:
567
+ """Start a stopped container, re-establishing its host scaffolding."""
568
+ from terok_executor.integrations.sandbox import PodmanRuntime, Sandbox
516
569
 
517
- runtime = PodmanRuntime()
518
- container = runtime.container(name)
519
- if container.state is None:
520
- print(f"Container not found: {name}")
521
- return
522
- runtime.force_remove([container])
570
+ try:
571
+ Sandbox(runtime=PodmanRuntime()).start(name)
572
+ except RuntimeError as exc:
573
+ raise SystemExit(str(exc)) from exc
574
+ print(f"Started: {name}")
575
+
576
+
577
+ def _handle_stop(*, name: str, timeout: int = 10) -> None:
578
+ """Stop a container, keeping it for a later ``start``.
579
+
580
+ A missing container is an error, exactly as ``podman stop`` treats
581
+ it — the facade's ``RuntimeError`` carries podman's own message.
582
+ """
583
+ from terok_executor.integrations.sandbox import PodmanRuntime, Sandbox
584
+
585
+ try:
586
+ Sandbox(runtime=PodmanRuntime()).stop([name], timeout=timeout)
587
+ except RuntimeError as exc:
588
+ raise SystemExit(str(exc)) from exc
523
589
  print(f"Stopped: {name}")
524
590
 
525
591
 
592
+ def _handle_rm(*, name: str) -> None:
593
+ """Remove a container together with its host-side state.
594
+
595
+ Also sweeps the per-container state when the container is already
596
+ gone — the one situation (crash, out-of-band ``podman rm``) where
597
+ residue outlives its container.
598
+ """
599
+ import shutil
600
+
601
+ from terok_executor.integrations.sandbox import (
602
+ PodmanRuntime,
603
+ Sandbox,
604
+ remove_container_state,
605
+ )
606
+ from terok_executor.paths import container_state_dir
607
+
608
+ sandbox = Sandbox(runtime=PodmanRuntime())
609
+ [result] = sandbox.rm([name])
610
+ if not result.removed:
611
+ raise SystemExit(f"Could not remove {name}: {result.error}")
612
+ remove_container_state(name, cfg=sandbox.config)
613
+ shutil.rmtree(container_state_dir(name), ignore_errors=True)
614
+ print(f"Removed: {name}")
615
+
616
+
526
617
  def _handle_setup(
527
618
  *,
528
619
  check: bool = False,
@@ -530,6 +621,7 @@ def _handle_setup(
530
621
  no_images: bool = False,
531
622
  base: str = DEFAULT_BASE_IMAGE,
532
623
  family: str | None = None,
624
+ passphrase_tier: str | None = None,
533
625
  cfg: SandboxConfig | None = None,
534
626
  ) -> None:
535
627
  """Bootstrap the full terok-executor stack on a fresh host.
@@ -546,7 +638,7 @@ def _handle_setup(
546
638
  if not no_sandbox:
547
639
  from .sandbox import ensure_sandbox_ready
548
640
 
549
- ensure_sandbox_ready(cfg=cfg)
641
+ ensure_sandbox_ready(cfg=cfg, passphrase_tier=passphrase_tier)
550
642
 
551
643
  if not no_images:
552
644
  _build_images_with_banner(base, family)
@@ -656,7 +748,13 @@ RUN_COMMAND = CommandDef(
656
748
  handler=_handle_run,
657
749
  args=(
658
750
  ArgDef(name="agent", help="Agent name (claude, codex, vibe, ...)"),
659
- ArgDef(name="repo", nargs="?", default=".", help="Local path or git URL (default: .)"),
751
+ ArgDef(
752
+ name="repo",
753
+ nargs="?",
754
+ default=None,
755
+ help="Git URL or local dir cloned into the workspace via the gate "
756
+ "(default: . — unless --workspace brings its own content)",
757
+ ),
660
758
  ArgDef(name="-p", dest="prompt", help="Prompt for headless mode"),
661
759
  ArgDef(name="-m", dest="model", help="Model override"),
662
760
  ArgDef(name="--max-turns", type=int, help="Maximum agent turns"),
@@ -676,6 +774,17 @@ RUN_COMMAND = CommandDef(
676
774
  ArgDef(name="--gpu", action="store_true", help="Enable GPU passthrough"),
677
775
  ArgDef(name="--memory", help="Container memory limit (e.g. 4g, 512m)"),
678
776
  ArgDef(name="--cpus", help="Container CPU limit (e.g. 2.0, 0.5)"),
777
+ ArgDef(
778
+ name="--workspace",
779
+ help="Host directory to mount at /workspace "
780
+ "(default: the workspace lives in the container)",
781
+ ),
782
+ ArgDef(
783
+ name="--rm",
784
+ dest="ephemeral",
785
+ action="store_true",
786
+ help="Remove the container when it exits (podman --rm)",
787
+ ),
679
788
  ArgDef(
680
789
  name="--git-identity-from-host",
681
790
  action="store_true",
@@ -726,12 +835,29 @@ RUN_TOOL_COMMAND = CommandDef(
726
835
  handler=_handle_run_tool,
727
836
  args=(
728
837
  ArgDef(name="tool", help="Tool name (coderabbit)"),
729
- ArgDef(name="repo", nargs="?", default=".", help="Local path or git URL (default: .)"),
838
+ ArgDef(
839
+ name="repo",
840
+ nargs="?",
841
+ default=None,
842
+ help="Git URL or local dir cloned into the workspace via the gate "
843
+ "(default: . — unless --workspace brings its own content)",
844
+ ),
730
845
  ArgDef(name="--branch", help="Git branch to check out"),
731
846
  ArgDef(name="--gate", action="store_true", default=True, help="Use gate (default)"),
732
847
  ArgDef(name="--no-gate", action="store_true", help="Disable gate"),
733
848
  ArgDef(name="--name", help="Container name override"),
734
849
  ArgDef(name="--timeout", type=int, default=600, help="Timeout in seconds (default: 600)"),
850
+ ArgDef(
851
+ name="--workspace",
852
+ help="Host directory to mount at /workspace "
853
+ "(default: the workspace lives in the container)",
854
+ ),
855
+ ArgDef(
856
+ name="--rm",
857
+ dest="ephemeral",
858
+ action="store_true",
859
+ help="Remove the container when it exits (podman --rm)",
860
+ ),
735
861
  ArgDef(name="tool_args", nargs="*", help="Extra args passed to the tool (after --)"),
736
862
  ArgDef(
737
863
  name="--base",
@@ -773,6 +899,11 @@ AUTH_COMMAND = CommandDef(
773
899
  args=(
774
900
  ArgDef(name="agent", help="Agent or tool name (claude, codex, gh, ...)"),
775
901
  ArgDef(name="--api-key", help="Store an API key directly (skip interactive auth)"),
902
+ ArgDef(
903
+ name="--device-auth",
904
+ action="store_true",
905
+ help="Force the headless device-code login (skip the method chooser)",
906
+ ),
776
907
  ArgDef(
777
908
  name="--base-image",
778
909
  help=(
@@ -871,7 +1002,7 @@ ACP_COMMAND = CommandDef(
871
1002
  )
872
1003
 
873
1004
 
874
- LIST_COMMAND = CommandDef(name="list", help="List running containers", handler=_handle_list)
1005
+ LIST_COMMAND = CommandDef(name="list", help="List containers", handler=_handle_list)
875
1006
 
876
1007
  SHOW_CONFIG_COMMAND = CommandDef(
877
1008
  name="show-config",
@@ -879,10 +1010,32 @@ SHOW_CONFIG_COMMAND = CommandDef(
879
1010
  handler=_handle_show_config,
880
1011
  )
881
1012
 
1013
+ START_COMMAND = CommandDef(
1014
+ name="start",
1015
+ help="Start a stopped container",
1016
+ handler=_handle_start,
1017
+ args=(ArgDef(name="name", help="Container name"),),
1018
+ )
1019
+
882
1020
  STOP_COMMAND = CommandDef(
883
1021
  name="stop",
884
- help="Stop a running container",
1022
+ help="Stop a container (kept for a later start)",
885
1023
  handler=_handle_stop,
1024
+ args=(
1025
+ ArgDef(name="name", help="Container name"),
1026
+ ArgDef(
1027
+ name="--timeout",
1028
+ type=int,
1029
+ default=10,
1030
+ help="Seconds before the stop escalates to SIGKILL (default: 10)",
1031
+ ),
1032
+ ),
1033
+ )
1034
+
1035
+ RM_COMMAND = CommandDef(
1036
+ name="rm",
1037
+ help="Remove a container and its host-side state",
1038
+ handler=_handle_rm,
886
1039
  args=(ArgDef(name="name", help="Container name"),),
887
1040
  )
888
1041
 
@@ -918,6 +1071,15 @@ SETUP_COMMAND = CommandDef(
918
1071
  default=None,
919
1072
  help="Override package family for unknown base images (deb or rpm)",
920
1073
  ),
1074
+ ArgDef(
1075
+ name="--passphrase-tier",
1076
+ default=None,
1077
+ help=(
1078
+ "Force credentials-DB passphrase storage to a specific tier"
1079
+ " (systemd-creds | keyring | session-file | config); required"
1080
+ " on a non-TTY host without systemd-creds"
1081
+ ),
1082
+ ),
921
1083
  ),
922
1084
  )
923
1085
 
@@ -956,7 +1118,9 @@ COMMANDS: tuple[CommandDef, ...] = (
956
1118
  SETUP_COMMAND,
957
1119
  UNINSTALL_COMMAND,
958
1120
  LIST_COMMAND,
1121
+ START_COMMAND,
959
1122
  STOP_COMMAND,
1123
+ RM_COMMAND,
960
1124
  SHOW_CONFIG_COMMAND,
961
1125
  ACP_COMMAND,
962
1126
  )