handler-ai 0.1.0__py3-none-any.whl
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.
- handler_ai-0.1.0.dist-info/METADATA +60 -0
- handler_ai-0.1.0.dist-info/RECORD +234 -0
- handler_ai-0.1.0.dist-info/WHEEL +4 -0
- handler_ai-0.1.0.dist-info/entry_points.txt +6 -0
- handler_cli/__init__.py +1 -0
- handler_cli/account_commands.py +314 -0
- handler_cli/addon_commands.py +128 -0
- handler_cli/agent_commands.py +139 -0
- handler_cli/app_commands.py +175 -0
- handler_cli/app_window.py +85 -0
- handler_cli/automation_commands.py +309 -0
- handler_cli/bridge.py +42 -0
- handler_cli/cli.py +326 -0
- handler_cli/client.py +81 -0
- handler_cli/daemon_commands.py +108 -0
- handler_cli/image_commands.py +102 -0
- handler_cli/inbox_commands.py +33 -0
- handler_cli/output.py +12 -0
- handler_cli/project_commands.py +63 -0
- handler_cli/provider_commands.py +113 -0
- handler_cli/secret_commands.py +64 -0
- handler_cli/session_bridge.py +93 -0
- handler_cli/session_commands.py +485 -0
- handler_cli/setup.py +120 -0
- handler_cli/terminal.py +280 -0
- handler_cli/terminal_client.py +37 -0
- handler_contracts/__init__.py +642 -0
- handler_contracts/account.py +36 -0
- handler_contracts/acp_endpoint.py +69 -0
- handler_contracts/addon.py +147 -0
- handler_contracts/agent_spec.py +75 -0
- handler_contracts/automation.py +285 -0
- handler_contracts/common.py +229 -0
- handler_contracts/control.py +1208 -0
- handler_contracts/harness.py +300 -0
- handler_contracts/miniapp.py +141 -0
- handler_contracts/provider.py +82 -0
- handler_contracts/remote.py +167 -0
- handler_contracts/sandbox.py +199 -0
- handler_contracts/schemas.py +313 -0
- handler_contracts/terminal.py +32 -0
- handler_control/__init__.py +7 -0
- handler_control/access.py +62 -0
- handler_control/accounts.py +279 -0
- handler_control/addon_install.py +268 -0
- handler_control/addons.py +118 -0
- handler_control/agent_state.py +46 -0
- handler_control/agents.py +257 -0
- handler_control/api/__init__.py +137 -0
- handler_control/api/accounts.py +231 -0
- handler_control/api/acp.py +116 -0
- handler_control/api/addons.py +95 -0
- handler_control/api/agents.py +150 -0
- handler_control/api/apps.py +104 -0
- handler_control/api/automations.py +128 -0
- handler_control/api/bindings.py +105 -0
- handler_control/api/builtin_agents.py +22 -0
- handler_control/api/caches.py +79 -0
- handler_control/api/catalog.py +197 -0
- handler_control/api/common.py +205 -0
- handler_control/api/contexts.py +88 -0
- handler_control/api/folders.py +51 -0
- handler_control/api/images.py +164 -0
- handler_control/api/inbox.py +21 -0
- handler_control/api/projects.py +170 -0
- handler_control/api/providers.py +107 -0
- handler_control/api/remote.py +45 -0
- handler_control/api/secrets.py +177 -0
- handler_control/api/sessions.py +192 -0
- handler_control/api/skills.py +270 -0
- handler_control/app_api.py +84 -0
- handler_control/app_http.py +214 -0
- handler_control/app_remote.py +206 -0
- handler_control/apps.py +867 -0
- handler_control/auth.py +48 -0
- handler_control/automation_config.py +255 -0
- handler_control/automations.py +1134 -0
- handler_control/bindings.py +149 -0
- handler_control/builds.py +341 -0
- handler_control/builtin_agents.py +82 -0
- handler_control/caches.py +113 -0
- handler_control/checks.py +287 -0
- handler_control/compose.py +317 -0
- handler_control/config_files.py +41 -0
- handler_control/contexts.py +75 -0
- handler_control/daemon.py +64 -0
- handler_control/data/automation/bin/handler-llm +85 -0
- handler_control/data/automations/env-issues/automation.toml +17 -0
- handler_control/data/automations/env-issues/extract.py +73 -0
- handler_control/data/automations/env-issues/findings.schema.json +28 -0
- handler_control/data/automations/env-issues/prompt.md +19 -0
- handler_control/data/builtin-agents/skill-creator/agent.toml +10 -0
- handler_control/data/builtin-agents/skill-creator/instructions.md +5 -0
- handler_control/data/builtin-agents/skill-creator/skills/handler-skills/SKILL.md +44 -0
- handler_control/data/builtin-agents/skill-creator/skills/skill-creator/LICENSE.txt +202 -0
- handler_control/data/builtin-agents/skill-creator/skills/skill-creator/SKILL.md +485 -0
- handler_control/data/builtin-agents/skill-creator/skills/skill-creator/agents/analyzer.md +274 -0
- handler_control/data/builtin-agents/skill-creator/skills/skill-creator/agents/comparator.md +202 -0
- handler_control/data/builtin-agents/skill-creator/skills/skill-creator/agents/grader.md +223 -0
- handler_control/data/builtin-agents/skill-creator/skills/skill-creator/assets/eval_review.html +146 -0
- handler_control/data/builtin-agents/skill-creator/skills/skill-creator/eval-viewer/generate_review.py +471 -0
- handler_control/data/builtin-agents/skill-creator/skills/skill-creator/eval-viewer/viewer.html +1325 -0
- handler_control/data/builtin-agents/skill-creator/skills/skill-creator/references/schemas.md +430 -0
- handler_control/data/builtin-agents/skill-creator/skills/skill-creator/scripts/__init__.py +0 -0
- handler_control/data/builtin-agents/skill-creator/skills/skill-creator/scripts/aggregate_benchmark.py +401 -0
- handler_control/data/builtin-agents/skill-creator/skills/skill-creator/scripts/generate_report.py +326 -0
- handler_control/data/builtin-agents/skill-creator/skills/skill-creator/scripts/improve_description.py +247 -0
- handler_control/data/builtin-agents/skill-creator/skills/skill-creator/scripts/package_skill.py +136 -0
- handler_control/data/builtin-agents/skill-creator/skills/skill-creator/scripts/quick_validate.py +103 -0
- handler_control/data/builtin-agents/skill-creator/skills/skill-creator/scripts/run_eval.py +310 -0
- handler_control/data/builtin-agents/skill-creator/skills/skill-creator/scripts/run_loop.py +328 -0
- handler_control/data/builtin-agents/skill-creator/skills/skill-creator/scripts/utils.py +47 -0
- handler_control/data/builtin-agents/skill-review/agent.toml +13 -0
- handler_control/data/builtin-agents/skill-review/instructions.md +30 -0
- handler_control/data/builtin-agents/skill-review/interface.json +83 -0
- handler_control/data/interfaces/llm/v1/interface.toml +17 -0
- handler_control/data/interfaces/llm/v1/tools.json +138 -0
- handler_control/data/templates/README.md +10 -0
- handler_control/data/templates/providers/anthropic-api.toml +18 -0
- handler_control/data/templates/providers/llamacpp.toml +210 -0
- handler_control/data/templates/providers/mistral-api.toml +14 -0
- handler_control/data/templates/providers/ollama.toml +10 -0
- handler_control/data/templates/providers/openai-api.toml +13 -0
- handler_control/data/templates/providers/openrouter.toml +10 -0
- handler_control/desktop.py +68 -0
- handler_control/display.py +62 -0
- handler_control/files.py +23 -0
- handler_control/folders.py +68 -0
- handler_control/git_read.py +39 -0
- handler_control/image_check.py +322 -0
- handler_control/image_updates.py +174 -0
- handler_control/inbox.py +70 -0
- handler_control/interfaces.py +151 -0
- handler_control/knowledge.py +237 -0
- handler_control/launcher.py +356 -0
- handler_control/llm.py +194 -0
- handler_control/migrations/__init__.py +62 -0
- handler_control/policy.py +305 -0
- handler_control/projects.py +266 -0
- handler_control/providers.py +180 -0
- handler_control/relay.py +133 -0
- handler_control/remote.py +888 -0
- handler_control/remote_crypto.py +97 -0
- handler_control/runtime.py +140 -0
- handler_control/sandbox_process.py +224 -0
- handler_control/schedules.py +58 -0
- handler_control/secrets.py +242 -0
- handler_control/service_router.py +180 -0
- handler_control/services.py +92 -0
- handler_control/session_files.py +429 -0
- handler_control/sessions.py +1116 -0
- handler_control/settings.py +129 -0
- handler_control/shortcuts.py +80 -0
- handler_control/skill_scan.py +88 -0
- handler_control/skill_sources.py +61 -0
- handler_control/skills.py +378 -0
- handler_control/terminal.py +79 -0
- handler_control/terminals.py +108 -0
- handler_control/transcript.py +174 -0
- handler_control/web-ui/assets/index-1w5RPsfA.js +190 -0
- handler_control/web-ui/assets/index-dWnzCLzQ.css +1 -0
- handler_control/web-ui/assets/inter-cyrillic-ext-wght-normal-BOeWTOD4.woff2 +0 -0
- handler_control/web-ui/assets/inter-cyrillic-wght-normal-DqGufNeO.woff2 +0 -0
- handler_control/web-ui/assets/inter-greek-ext-wght-normal-DlzME5K_.woff2 +0 -0
- handler_control/web-ui/assets/inter-greek-wght-normal-CkhJZR-_.woff2 +0 -0
- handler_control/web-ui/assets/inter-latin-ext-wght-normal-DO1Apj_S.woff2 +0 -0
- handler_control/web-ui/assets/inter-latin-wght-normal-Dx4kXJAl.woff2 +0 -0
- handler_control/web-ui/assets/inter-vietnamese-wght-normal-CBcvBZtf.woff2 +0 -0
- handler_control/web-ui/favicon.svg +1 -0
- handler_control/web-ui/index.html +15 -0
- handler_control/webpush.py +90 -0
- handler_control/webui.py +105 -0
- handler_harness/__init__.py +13 -0
- handler_harness/addons.py +129 -0
- handler_harness/catalog.py +116 -0
- handler_harness/cli.py +109 -0
- handler_harness/data/addons/README.md +44 -0
- handler_harness/data/addons/miniapp/Containerfile +20 -0
- handler_harness/data/addons/miniapp/PROVISIONING.md +16 -0
- handler_harness/data/addons/miniapp/addon.toml +16 -0
- handler_harness/data/addons/miniapp/skills/miniapp/SKILL.md +140 -0
- handler_harness/data/addons/miniapp/skills/miniapp/template/.gitignore +2 -0
- handler_harness/data/addons/miniapp/skills/miniapp/template/app.toml +15 -0
- handler_harness/data/addons/miniapp/skills/miniapp/template/server/db.ts +30 -0
- handler_harness/data/addons/miniapp/skills/miniapp/template/server/deno.json +7 -0
- handler_harness/data/addons/miniapp/skills/miniapp/template/server/handler.ts +26 -0
- handler_harness/data/addons/miniapp/skills/miniapp/template/server/main.ts +18 -0
- handler_harness/data/addons/miniapp/skills/miniapp/template/server/main_test.ts +32 -0
- handler_harness/data/addons/miniapp/skills/miniapp/template/server/migrations/001_notes.sql +6 -0
- handler_harness/data/addons/miniapp/skills/miniapp/template/server/routes.ts +32 -0
- handler_harness/data/addons/miniapp/skills/miniapp/template/ui/deno.json +12 -0
- handler_harness/data/addons/miniapp/skills/miniapp/template/ui/index.html +12 -0
- handler_harness/data/addons/miniapp/skills/miniapp/template/ui/src/App.svelte +44 -0
- handler_harness/data/addons/miniapp/skills/miniapp/template/ui/src/api.ts +16 -0
- handler_harness/data/addons/miniapp/skills/miniapp/template/ui/src/app.css +24 -0
- handler_harness/data/addons/miniapp/skills/miniapp/template/ui/src/main.ts +5 -0
- handler_harness/data/addons/miniapp/skills/miniapp/template/ui/vite.config.ts +17 -0
- handler_harness/data/catalog/README.md +12 -0
- handler_harness/data/catalog/playwright/Containerfile +28 -0
- handler_harness/data/catalog/playwright/PROVISIONING.md +53 -0
- handler_harness/data/catalog/playwright/addon.toml +25 -0
- handler_harness/data/catalog/playwright/handler/playwright-mcp-check.mjs +23 -0
- handler_harness/data/catalog/playwright/handler/playwright-mcp.mjs +61 -0
- handler_harness/data/catalog/playwright/skills/browser/SKILL.md +41 -0
- handler_harness/data/catalog/shopify/Containerfile +22 -0
- handler_harness/data/catalog/shopify/PROVISIONING.md +49 -0
- handler_harness/data/catalog/shopify/addon.toml +39 -0
- handler_harness/data/catalog/shopify/skills/shopify/SKILL.md +41 -0
- handler_harness/data/handler-sandbox-env +30 -0
- handler_harness/data/harnesses/README.md +47 -0
- handler_harness/data/harnesses/claude-code/Containerfile +27 -0
- handler_harness/data/harnesses/claude-code/harness.toml +95 -0
- handler_harness/data/harnesses/codex/Containerfile +26 -0
- handler_harness/data/harnesses/codex/harness.toml +103 -0
- handler_harness/data/harnesses/pi/Containerfile +27 -0
- handler_harness/data/harnesses/pi/harness.toml +65 -0
- handler_harness/data/harnesses/vibe/Containerfile +19 -0
- handler_harness/data/harnesses/vibe/harness.toml +96 -0
- handler_harness/data/toolbox/Containerfile +56 -0
- handler_harness/data/toolbox/README.md +24 -0
- handler_harness/data/toolbox/toolbox.toml +41 -0
- handler_harness/images.py +62 -0
- handler_harness/providers.py +300 -0
- handler_harness/render.py +472 -0
- handler_sandbox_podman/__init__.py +1 -0
- handler_sandbox_podman/caches.py +97 -0
- handler_sandbox_podman/check.py +121 -0
- handler_sandbox_podman/cli.py +239 -0
- handler_sandbox_podman/egress.py +118 -0
- handler_sandbox_podman/images.py +199 -0
- handler_sandbox_podman/launch.py +474 -0
- handler_sandbox_podman/podman.py +108 -0
- handler_sandbox_podman/proxy/Containerfile +6 -0
- handler_sandbox_podman/proxy/addon.py +255 -0
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: handler-ai
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Run coding agents (Claude Code, Codex, Vibe, pi) in rootless Podman sandboxes on Linux
|
|
5
|
+
Project-URL: Homepage, https://github.com/macray/handler-ai
|
|
6
|
+
Project-URL: Documentation, https://macray.github.io/handler-ai/
|
|
7
|
+
Project-URL: Changelog, https://github.com/macray/handler-ai/blob/main/CHANGELOG.md
|
|
8
|
+
Project-URL: Issues, https://github.com/macray/handler-ai/issues
|
|
9
|
+
License-Expression: Apache-2.0
|
|
10
|
+
Keywords: acp,agents,ai,claude-code,codex,podman,sandbox
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Environment :: Web Environment
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Topic :: Software Development
|
|
17
|
+
Requires-Python: >=3.12
|
|
18
|
+
Requires-Dist: cryptography>=45
|
|
19
|
+
Requires-Dist: dulwich>=1.2
|
|
20
|
+
Requires-Dist: fastapi>=0.141
|
|
21
|
+
Requires-Dist: httpx>=0.28
|
|
22
|
+
Requires-Dist: jsonschema>=4.23
|
|
23
|
+
Requires-Dist: pydantic<3,>=2.13
|
|
24
|
+
Requires-Dist: pyyaml>=6
|
|
25
|
+
Requires-Dist: tomlkit>=0.13
|
|
26
|
+
Requires-Dist: uvicorn>=0.53
|
|
27
|
+
Requires-Dist: websockets>=17
|
|
28
|
+
Description-Content-Type: text/markdown
|
|
29
|
+
|
|
30
|
+
# Handler
|
|
31
|
+
|
|
32
|
+
**Handler**: every agent needs one.
|
|
33
|
+
|
|
34
|
+
Run coding agents in containers on your Linux machine. Each agent (Claude Code, Codex, Mistral
|
|
35
|
+
Vibe or pi) runs in its own rootless Podman container that sees only its project folder and reaches
|
|
36
|
+
only the hosts you allow. A daemon keeps the sessions, which you follow from a web UI, the
|
|
37
|
+
terminal, your editor (over ACP) or your phone.
|
|
38
|
+
|
|
39
|
+
## Install
|
|
40
|
+
|
|
41
|
+
**You need:** Linux with rootless Podman, `passt` and a systemd user session, and about 3 GB of
|
|
42
|
+
disk for the images, built on your machine.
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
uv tool install handler-ai # or: pipx install handler-ai
|
|
46
|
+
handler setup # starts handlerd as a user service, checks this machine, builds the images
|
|
47
|
+
handler ui # opens the web UI
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
The first `handler setup` downloads and builds the images: from a few minutes to half an hour.
|
|
51
|
+
Without uv: `curl -fsSL https://github.com/macray/handler-ai/releases/latest/download/install.sh | sh`
|
|
52
|
+
installs it, then Handler. To update: `uv tool upgrade handler-ai`.
|
|
53
|
+
|
|
54
|
+
## More
|
|
55
|
+
|
|
56
|
+
- [README](https://github.com/macray/handler-ai#readme): what Handler does, compared with other
|
|
57
|
+
sandboxes, and a first session.
|
|
58
|
+
- [Documentation](https://macray.github.io/handler-ai/)
|
|
59
|
+
- [Changelog](https://github.com/macray/handler-ai/blob/main/CHANGELOG.md) ·
|
|
60
|
+
[Issues](https://github.com/macray/handler-ai/issues)
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
handler_cli/__init__.py,sha256=1VgCiquupUdYG5B7rt6M3zbxntmKWM6ky6R8szDS1e0,98
|
|
2
|
+
handler_cli/account_commands.py,sha256=peiT-VCCN2DGr3UBgD-XYin__hUSDh8YTlXoJgpgq1A,13680
|
|
3
|
+
handler_cli/addon_commands.py,sha256=1SxEXbcUznwqkyOrbxFcE3dXegooK-Pbm4sLP0jcbdE,5356
|
|
4
|
+
handler_cli/agent_commands.py,sha256=rurfdJPx3ydFL8hUILflL361Xm0JqnACpPguTdB6Cqg,6164
|
|
5
|
+
handler_cli/app_commands.py,sha256=l0mLyPZjRBVA2hjAaytpwQULl5ebDF4fxIpL9ErFSa4,7001
|
|
6
|
+
handler_cli/app_window.py,sha256=gV29B8z-NJQtRj8pINKydZ_uOqN_3OAyqfnmH1Y8zaw,3275
|
|
7
|
+
handler_cli/automation_commands.py,sha256=RVhDqcjsQFDQRDGvDAbTMpHQkJIGgw9LCyaZcPFi1vI,12795
|
|
8
|
+
handler_cli/bridge.py,sha256=R6AdT9VvnkyufMl-tXtYTKrDk1OwrhFShjDvhJy9N90,1602
|
|
9
|
+
handler_cli/cli.py,sha256=xU2YmvYcmVddzfqAWX6HMW2sT1WN64r3rfCvuNP_j4g,14904
|
|
10
|
+
handler_cli/client.py,sha256=3IzRnG7GkSK2I0TOEInvIRdDIAYkSR_1fsOJ6OqqRL0,2812
|
|
11
|
+
handler_cli/daemon_commands.py,sha256=RkagiMchdlWtoD-ciDZDPvkLAtpv1kmFSqCEjdC1bck,3472
|
|
12
|
+
handler_cli/image_commands.py,sha256=PhgLBCyS9sZ13mmeVDUiWlZ3pA8vLWvTQEOhGGyq9O0,4119
|
|
13
|
+
handler_cli/inbox_commands.py,sha256=M7chRV-r2d99RRLH3FQW7CeRy2OoaHvm1n8TAZTjooA,1006
|
|
14
|
+
handler_cli/output.py,sha256=SJ6x6-ORzVk40Cilwee3Ln9tnQBX63jwifCR4TR0MfA,425
|
|
15
|
+
handler_cli/project_commands.py,sha256=tzoHRjL8k8I5NtUmbSkeK8tuLdNCxZGIVIfCvuDNkrc,2462
|
|
16
|
+
handler_cli/provider_commands.py,sha256=aSwuLC3_MCjL22ewM8NTQmQ2fAPj7RQyTktBsIuix9s,5482
|
|
17
|
+
handler_cli/secret_commands.py,sha256=I6g3ta5bhWigllmmb_eyr0kZ7k2sOW4QFloLtw8h6qs,2806
|
|
18
|
+
handler_cli/session_bridge.py,sha256=yMeeoZptr4MnGbVF5f6YRiSY--ieeMvCR7G1OxIaucM,4133
|
|
19
|
+
handler_cli/session_commands.py,sha256=E7fG3V2FvOcIbsOmsC27y7NLqRS_2K5KGiIWVkSBzDg,22123
|
|
20
|
+
handler_cli/setup.py,sha256=s_jqJ3MVL-GBy5sbZDWkzKgD_n4Dklj58_ZIw9VOPx4,4663
|
|
21
|
+
handler_cli/terminal.py,sha256=2pBB2lkeFbeJHfOJELAY5MhuYcdiWoDtd2PMoRrhIDA,12057
|
|
22
|
+
handler_cli/terminal_client.py,sha256=ocmCVyOrHRqT95v1vlklURjUsrGxsEzUZOGwMrf3TRw,1627
|
|
23
|
+
handler_contracts/__init__.py,sha256=uEdyK24gkQQaDXvNZX7LXpDP-BzvoQiXQjQiRDEt2Gs,14777
|
|
24
|
+
handler_contracts/account.py,sha256=pd-T_zCv8MVnQYLZpiTktNFJMcM4zR-nYpb5JN0gB7M,1758
|
|
25
|
+
handler_contracts/acp_endpoint.py,sha256=hEjzGWK8oBJxJ-jWGAOMTQWJhMyAHYbBh73Ay3ZsxyE,2311
|
|
26
|
+
handler_contracts/addon.py,sha256=7zq39o2oI79aE-K8XaG9b87m5GW9_p_ncehrjlYaOxQ,6527
|
|
27
|
+
handler_contracts/agent_spec.py,sha256=8ljmD4j2qd01cedU_5lXUzwK2RT2rDxaCXm8mD2WmnI,3157
|
|
28
|
+
handler_contracts/automation.py,sha256=8eeVoxMjlFbE0jkrQjARyaKOsZs8_Mr8De0LmS6xYhw,10864
|
|
29
|
+
handler_contracts/common.py,sha256=MHsph8XtcNsDv7jbRf96VA7XaEMvxR69sPXwHSPv9cs,8264
|
|
30
|
+
handler_contracts/control.py,sha256=vW_cX92NuzIJvoyFouviS5QVnLdk00756fSeuNBZNO4,47775
|
|
31
|
+
handler_contracts/harness.py,sha256=e4sfmPJGqcLprLGQ36RG2ow8FMVYzAlsIEmELENa0RI,13379
|
|
32
|
+
handler_contracts/miniapp.py,sha256=foDgXDvnYBabTMzwEFsL5toLk0X_XpoGYxaOra0pc3Y,5630
|
|
33
|
+
handler_contracts/provider.py,sha256=R3iy4_z-hapzTPZgfxLDHHST4-2kEJzX_3mgH0I1AdI,3754
|
|
34
|
+
handler_contracts/remote.py,sha256=NxbXZrjGmi2dNCYADxqZWa3sQQyp3KjOf4S6YQpnW6E,4886
|
|
35
|
+
handler_contracts/sandbox.py,sha256=MGqKpwQIBiA2bgPsCaEKUBaERJyE6EMj7comTDpE3ys,7299
|
|
36
|
+
handler_contracts/schemas.py,sha256=RagEVAohXA4sSTQGFN8UG2zHKu7OCblWZQmGT72QvI4,10715
|
|
37
|
+
handler_contracts/terminal.py,sha256=lEMfu5blpK0bYDoHbDYBmwGackoDtnnu6aOWMXxPcA4,1134
|
|
38
|
+
handler_control/__init__.py,sha256=AHQb0rB8Lb-tvHPl2PyZHhsUL7p2A-kaJ6hz2FvZht4,294
|
|
39
|
+
handler_control/access.py,sha256=hQ9IDPZyhnZXdwc9ZqAHB8zItMt8InJVeyWCTTwdxDM,2699
|
|
40
|
+
handler_control/accounts.py,sha256=KK9Q89YsYabZBDoW5LYXrn47Q_qnJT2OJ3YFuikZB9E,10459
|
|
41
|
+
handler_control/addon_install.py,sha256=9YXmKu3FemIzYn0EXNAD_7W9DGPOEH6C8cHlzv2esy8,10510
|
|
42
|
+
handler_control/addons.py,sha256=vk_OEjbbI0yFU1ON-hgsCWuiAsjEZ14AnGxv8e-px2I,5226
|
|
43
|
+
handler_control/agent_state.py,sha256=ECIkdH0Dvlw6Fys_2biZiwTOD4QEduZmKpWGSIzPpiA,2000
|
|
44
|
+
handler_control/agents.py,sha256=gdYkP0A10oDsJWXmzB3lE9qyUglP6icHAcsmBHOI3mU,10911
|
|
45
|
+
handler_control/app_api.py,sha256=QH06bi8NylItlhMdXzuNCoBOc2o4HxvOY8qlJ2HfEUU,3375
|
|
46
|
+
handler_control/app_http.py,sha256=I8dj_swK1omdEaPR8EsWsnnnbKDvkZB1swhI18tjiqg,9652
|
|
47
|
+
handler_control/app_remote.py,sha256=BUyBHEirnSzcNACW4IWBY4oGJ3DQ6triwO2Sq02rkfU,8891
|
|
48
|
+
handler_control/apps.py,sha256=9QCk1muB1lncTAnOIdpF1nrjjNnqROWnAMuZKU_0fCs,38403
|
|
49
|
+
handler_control/auth.py,sha256=s3vhQGoPqckaEfMqh34Hkwd-F4Fi2cJ7WAqzUj_tUQA,1619
|
|
50
|
+
handler_control/automation_config.py,sha256=XKWGtELZbiWpzn4ImEKHp5iNXOAYFDEFu-IeQmwHLw4,10160
|
|
51
|
+
handler_control/automations.py,sha256=kmNptFeNXR_fIl6xeuDy6zMi-5F7WmnToh5DHDHMON0,51445
|
|
52
|
+
handler_control/bindings.py,sha256=JvUD0cZi5MBR9HVED2v_vqjZgR6MNHdhC55_sT3fKxg,5572
|
|
53
|
+
handler_control/builds.py,sha256=VVid-YQmbef3qR1N7r-yevQYzPgRMveQotkag7Ffq2I,14879
|
|
54
|
+
handler_control/builtin_agents.py,sha256=9Fd_NZLuMdmYOVYLsuMLH33t2mDfJ-wRtek2XIHxlQk,3149
|
|
55
|
+
handler_control/caches.py,sha256=OYqGZvopS8S6Qk7pH_c1A9-hLEbsCD7ooSh53jfs6b0,4327
|
|
56
|
+
handler_control/checks.py,sha256=FX7zy_Ee6-QBpRIL2vIkQfzt-cHRSZ-31t4VII34F8c,12436
|
|
57
|
+
handler_control/compose.py,sha256=ahJiD1MW1L3SUuLSvoB4XUCZI8urR0sqonLFxQRAwV8,12006
|
|
58
|
+
handler_control/config_files.py,sha256=36P64ss5gvGfAalt4BKzTJDUFIb1bUquEqpoB1MY1MI,1412
|
|
59
|
+
handler_control/contexts.py,sha256=GTLbWYnMQ3xXTGAuN1lJsRnIBO0sgmEV8QuepFvRMnU,3137
|
|
60
|
+
handler_control/daemon.py,sha256=840RRUIP6x1PJIEUpMgufd-7cLkilp0QC__XovSDtss,2073
|
|
61
|
+
handler_control/desktop.py,sha256=esxpMAA_9t3GMxlKR-WRyL2KSHiIHiRrrL7ErmNmbgs,2699
|
|
62
|
+
handler_control/display.py,sha256=WA59tT1xmq_w0sjedPPiN9DIvRQ0AuFXBgmO0524an4,2371
|
|
63
|
+
handler_control/files.py,sha256=EEw44CyZTGoQ9EJu2q13iNfnUPOGXok0_H3LufNfmnI,733
|
|
64
|
+
handler_control/folders.py,sha256=3DSNrPF19PfEtUu48BVie-Eembsumo9PqXtH-Ty1snA,2740
|
|
65
|
+
handler_control/git_read.py,sha256=3dOP8trIWG5SjksVKENft4o3Wpki8MFTWrka48VEhrQ,1477
|
|
66
|
+
handler_control/image_check.py,sha256=Mxq4KTImuSMwnNw7krTUjkDhBVdbo0beDGWZjPI8U6Y,14329
|
|
67
|
+
handler_control/image_updates.py,sha256=7LJncW2_vE6aSVsHa98XEkGMVVSJdANwbfG2shwgUPg,7266
|
|
68
|
+
handler_control/inbox.py,sha256=aP7KNd7XzdtNCcexBnLWgT7BkQvqCRgUB_vlj5DkiXk,2718
|
|
69
|
+
handler_control/interfaces.py,sha256=o5EbP0gY45sZVnwUkbd-ot5FRAlLANWLGEXHAWZdE8U,6522
|
|
70
|
+
handler_control/knowledge.py,sha256=oedlumsLO6R2jSrEt3Hz0x-z9iunY6XQl6cED2d3_pw,9894
|
|
71
|
+
handler_control/launcher.py,sha256=OfkuSL6FzTRGxJCKhFn79u60klxeRbBHeHjcRiNWjag,14206
|
|
72
|
+
handler_control/llm.py,sha256=E9enxXXu3K_TM2ApfxtrW5C4Ga4DSaCvfey3CL1X0dw,8152
|
|
73
|
+
handler_control/policy.py,sha256=UYvniHObbrHawC8HTe1-pPZaXZeaexBSEjmUWHohzRQ,13097
|
|
74
|
+
handler_control/projects.py,sha256=VklzEM_8B8PI7zoCbAKDOtcvu_L_C4VvV23jlVUSa8k,10581
|
|
75
|
+
handler_control/providers.py,sha256=cU4S8tONF5WTVT-30pbCs8YdtYwllMnqZIXr1yZrzlk,6311
|
|
76
|
+
handler_control/relay.py,sha256=5KcF4qnTfw_HB761Wq8phNB2SvsXmwUPa3w4J5y3c0U,5156
|
|
77
|
+
handler_control/remote.py,sha256=AW3YwJYYzsSXVFiyNIo0t2d8sP6RVkP3Sf1XzUpA_s4,38297
|
|
78
|
+
handler_control/remote_crypto.py,sha256=VXZlQSkU1JiFWHH0b87r6MEbGBJrJhrlhw5DkVyDg9Q,3861
|
|
79
|
+
handler_control/runtime.py,sha256=Eh3t6xBQL0Y2Zv-pwuZixkYcp5dKTrXQ39bVlo1yqnk,5435
|
|
80
|
+
handler_control/sandbox_process.py,sha256=B565YLoH8pwwxZksGSlCi0rDtQWa0CkYmIaLDpjD4RA,8395
|
|
81
|
+
handler_control/schedules.py,sha256=Uf8rrigyg2kGP5caVPd4nm8Ci5jI2oG_qot044FCUEo,2708
|
|
82
|
+
handler_control/secrets.py,sha256=Sp1ENmXk6KeldY3iH-ckDLsxJCWym0T4yjq_w7iZ0b0,9261
|
|
83
|
+
handler_control/service_router.py,sha256=Y_y7fMuW2o1eDxesQOXVQt6A6DaWXAxJQBzjZIO0H_c,7812
|
|
84
|
+
handler_control/services.py,sha256=fDOHCUOocXBnLud1Q0oS6rd2vws6_a_Epu3H7CySsUQ,3530
|
|
85
|
+
handler_control/session_files.py,sha256=72Rh-toPeHzBLZKf_9MxL_j6Ed9TPmzWH56GPWfQe0M,16457
|
|
86
|
+
handler_control/sessions.py,sha256=xPRrAY6WzI8BC7NixJ-lVQDC63eMFE8aiOPD86AzTOY,50976
|
|
87
|
+
handler_control/settings.py,sha256=e9UG5lzGOc6W6Gi3mNEJkl9hqK_2exP1Z5KO8nvzkQk,6747
|
|
88
|
+
handler_control/shortcuts.py,sha256=hsFl5vrR67OAO8wKx3WfJOulrvV5SCxmjPNfQoR11f0,2716
|
|
89
|
+
handler_control/skill_scan.py,sha256=BjI-mEikMVGbPb-TLxGDfBXLu_uzuHdqkLcvatkPo14,3643
|
|
90
|
+
handler_control/skill_sources.py,sha256=WymoWDFCXjxVyqedo2Q3RhDDEmafrtfXo8cIb5kxYcI,2600
|
|
91
|
+
handler_control/skills.py,sha256=nhGfggLa2WTI4s7gvPvwFXA4kE_1kqzsN1kkonqL01E,15781
|
|
92
|
+
handler_control/terminal.py,sha256=Uhvc9bYNo-etJq1w8_4xD_iPvuLM0fY66ASflDnT7rw,2907
|
|
93
|
+
handler_control/terminals.py,sha256=lNEiqMc5STt-m62wMIa8g7p5yZGFNNv1y-qZOG6Wy-k,3867
|
|
94
|
+
handler_control/transcript.py,sha256=ZHzUNpgvg-Y1Pkj2rbVltF4NzTSm20qVD2BPFZAF71w,6953
|
|
95
|
+
handler_control/webpush.py,sha256=QyzaJySJL-c_qrCVhahlFdkzm9tp6rXV8HAvgv_Wtyo,3474
|
|
96
|
+
handler_control/webui.py,sha256=ALYd4PlibTbtnNKrJSljHH2ctMmGxtphtzlLYhO-juc,3989
|
|
97
|
+
handler_control/api/__init__.py,sha256=E-5vvIc6_-WI8zbzG4EAwFGyBvXOFZsALgywHdR-Ybc,5709
|
|
98
|
+
handler_control/api/accounts.py,sha256=Z17Q_Y7Ca9Afrhj6AUVu772sRfyH1es2AYliGYWymSE,9756
|
|
99
|
+
handler_control/api/acp.py,sha256=RERJW0ZSz4713XycMn6kV887hq6oJfSstCoeEbgn7rY,4622
|
|
100
|
+
handler_control/api/addons.py,sha256=oaxmq1ZDMMn9DeYwtXUnbHxcQiU8jFIUTRNgwwL1RnE,3971
|
|
101
|
+
handler_control/api/agents.py,sha256=h-sDv20DglAMc6UE_05Kc330WDYH0iMyEL266_LyCkg,6383
|
|
102
|
+
handler_control/api/apps.py,sha256=BgrOYx8hJvFkGxGOWUCUluSa6Rk7XDbB2A1s9slzjac,4179
|
|
103
|
+
handler_control/api/automations.py,sha256=Fa1k7gUGxBEozf7NIr4zL3rQwOQShn-pefCJSr00B0c,5468
|
|
104
|
+
handler_control/api/bindings.py,sha256=V7dtp9DllM8mDhqHkmqAvNlA_dhr1-GffzLTFF3SfqQ,4452
|
|
105
|
+
handler_control/api/builtin_agents.py,sha256=EQDJ2qM44KIkz964VjGXQxnKUweiPOzZWENA4X8BdbU,824
|
|
106
|
+
handler_control/api/caches.py,sha256=bxcKzdopHT5quNYfBPmDa419hvskeqdvRJPn7n3WdYM,3309
|
|
107
|
+
handler_control/api/catalog.py,sha256=9MgCLFUE6jCbSiPtoJPmrypWctDO3faCG0now2dZtKI,7527
|
|
108
|
+
handler_control/api/common.py,sha256=dzdQwW6zblD1auclynll4KC_XbzQXGNbqUVS9pYYXkk,7284
|
|
109
|
+
handler_control/api/contexts.py,sha256=ahUqhToNdLmeYEy8JR-k_Un9DJ1J6CJ2whdbrCOSEIU,3591
|
|
110
|
+
handler_control/api/folders.py,sha256=TbjyPa5-U3e0QdYqdnRcmtUAXh6IBz7PsB_I7O78bEQ,1846
|
|
111
|
+
handler_control/api/images.py,sha256=6VpC_dF6jOCH3AiEJFE3s47iEgATKDKIkRYM8kDJVa8,6290
|
|
112
|
+
handler_control/api/inbox.py,sha256=7UStolnSC88-P7EKWY-8Q3Zdxnl93O7fvVf2atz-Lyw,716
|
|
113
|
+
handler_control/api/projects.py,sha256=9ihmtUgyAkb2apE_47FpeIUHx-saoa8fiyW3XlCHM4I,7118
|
|
114
|
+
handler_control/api/providers.py,sha256=FerD5O4pailjNObAS2vVdUwB_dOOwGFkhgxgZpVhfYs,4460
|
|
115
|
+
handler_control/api/remote.py,sha256=zbVqzMoJPdW6YLmt2XY7R3jtlUD0_DObY6c2HxyhpfQ,1740
|
|
116
|
+
handler_control/api/secrets.py,sha256=spUEtbMhKAEtmyyNPWFWnZ2LUkdxbAdpPrrhpWmtGa8,7242
|
|
117
|
+
handler_control/api/sessions.py,sha256=plg9d0YDqCD8zinuJ9Uj6te8OnrbL6TNTDCT9ayjE0Y,8171
|
|
118
|
+
handler_control/api/skills.py,sha256=vR_6Dpin1XdPzMAXsbE1Tyd7PcXNhO2q8dXSYgbYnK0,11932
|
|
119
|
+
handler_control/data/automation/bin/handler-llm,sha256=6QWsiPUsCtwXfvovlDi5-vLi05A_-eKwppVXePGRaTc,3511
|
|
120
|
+
handler_control/data/automations/env-issues/automation.toml,sha256=kBv4ebS-is1D66WZ00z-FOm6UYjqTPFtIJDLaxXucjk,891
|
|
121
|
+
handler_control/data/automations/env-issues/extract.py,sha256=Me21j2Z7RQXIpDkGO8rNriiVYPZhzNVoRbvusbD_6Q4,2466
|
|
122
|
+
handler_control/data/automations/env-issues/findings.schema.json,sha256=5g-LAd6XTsjEynIBC9wR6MDtRXdnv6OWYivrUhiXFBU,622
|
|
123
|
+
handler_control/data/automations/env-issues/prompt.md,sha256=cKDaL9Cee4LKWNxAox1S4kBffGZqjhpqWngjabAfAV4,1187
|
|
124
|
+
handler_control/data/builtin-agents/skill-creator/agent.toml,sha256=zGr-NMM1Ok7LfBZEg29o43bOiPdMBYmh1ww5wwvYBVI,629
|
|
125
|
+
handler_control/data/builtin-agents/skill-creator/instructions.md,sha256=xJ5IBfGPrhv8I7AYa2etXOFk3U1r0WtTramDnhAcZ1Y,437
|
|
126
|
+
handler_control/data/builtin-agents/skill-creator/skills/handler-skills/SKILL.md,sha256=0II6NFtfz0gK2SmG6qlFwZVWeacF-s2vZGvrKUCPmeg,2449
|
|
127
|
+
handler_control/data/builtin-agents/skill-creator/skills/skill-creator/LICENSE.txt,sha256=vGs68vMxy8f7DaE0Tvssvlh3oxSYtNcNvHAA80BaE2I,11345
|
|
128
|
+
handler_control/data/builtin-agents/skill-creator/skills/skill-creator/SKILL.md,sha256=3NSAPmHpE-b8JylBhM06cfCfXpJP8gyKmiAXPns8K88,33168
|
|
129
|
+
handler_control/data/builtin-agents/skill-creator/skills/skill-creator/agents/analyzer.md,sha256=v2j0ysWlbGc6kowubWGVhsW5PqNkAmqzdUd3LLRaZjo,10376
|
|
130
|
+
handler_control/data/builtin-agents/skill-creator/skills/skill-creator/agents/comparator.md,sha256=_h_JeHxJXYZMXW6tpHOWR4VyMl_eGzOpbXi_S4Sbej4,7287
|
|
131
|
+
handler_control/data/builtin-agents/skill-creator/skills/skill-creator/agents/grader.md,sha256=VxNNoMGk7qM_vXShycRKqBTwfWvGTeMD7bWG-UHl0ho,9049
|
|
132
|
+
handler_control/data/builtin-agents/skill-creator/skills/skill-creator/assets/eval_review.html,sha256=zkd9zHTcHA0dM1JkankWe1pjY06TaxAZFgAlBll05FI,7058
|
|
133
|
+
handler_control/data/builtin-agents/skill-creator/skills/skill-creator/eval-viewer/generate_review.py,sha256=_J0bkkP-WrYBLr1Xm9dtADXeG3n9O5ad4RTe-rJkePs,16365
|
|
134
|
+
handler_control/data/builtin-agents/skill-creator/skills/skill-creator/eval-viewer/viewer.html,sha256=pTITQm7hEARB1wGjoNSc2nqEL5ktLDZGP008wCWFdfo,44998
|
|
135
|
+
handler_control/data/builtin-agents/skill-creator/skills/skill-creator/references/schemas.md,sha256=joh2GAqJibQGpNPt3fh1sEzf1YBcyGFmhtVSsRzkRV8,12061
|
|
136
|
+
handler_control/data/builtin-agents/skill-creator/skills/skill-creator/scripts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
137
|
+
handler_control/data/builtin-agents/skill-creator/skills/skill-creator/scripts/aggregate_benchmark.py,sha256=Ej7xKOpczAGksawhLvVWfyHpwT09JAYJeAvusyAMSao,14386
|
|
138
|
+
handler_control/data/builtin-agents/skill-creator/skills/skill-creator/scripts/generate_report.py,sha256=E99xGKPFDIPEwyUKYG1fKyCyWj1Ey8OSs9Zp7HUoFFM,12847
|
|
139
|
+
handler_control/data/builtin-agents/skill-creator/skills/skill-creator/scripts/improve_description.py,sha256=h9hkVwIgtpn6xS2jCdLW79sGBke_68dPdoEo5kasz4A,11116
|
|
140
|
+
handler_control/data/builtin-agents/skill-creator/skills/skill-creator/scripts/package_skill.py,sha256=GjMFmw2x73M3XUbVE-XqgTadLog4yXBZew1S3e-NHA8,4234
|
|
141
|
+
handler_control/data/builtin-agents/skill-creator/skills/skill-creator/scripts/quick_validate.py,sha256=Z89XA0AgE5Nsj7da1qGv7NiEHUXMXmBrY06wWCX942U,3972
|
|
142
|
+
handler_control/data/builtin-agents/skill-creator/skills/skill-creator/scripts/run_eval.py,sha256=Q-O4-A2_acNDlnunfiaPrpkdn6PtaLMqD_AlMs1IZX8,11464
|
|
143
|
+
handler_control/data/builtin-agents/skill-creator/skills/skill-creator/scripts/run_loop.py,sha256=e9b2dCAxaFIFF-7JTFX0k8DRVDObBhtNfA8NrRh9DyE,13605
|
|
144
|
+
handler_control/data/builtin-agents/skill-creator/skills/skill-creator/scripts/utils.py,sha256=OviuYsQMc6txIgdDag2amB6EXyXFpwQCKesYnMjkW7E,1661
|
|
145
|
+
handler_control/data/builtin-agents/skill-review/agent.toml,sha256=mHnQB_jXXzOP-jf_y-UcF6F4FXY-UZF1dLicvstT-tw,676
|
|
146
|
+
handler_control/data/builtin-agents/skill-review/instructions.md,sha256=mAj4TRdTq_rZYJHYWJd7VycOAohGWOzZB8_2zAcMzXo,2215
|
|
147
|
+
handler_control/data/builtin-agents/skill-review/interface.json,sha256=lc6B_tyC1B8eC8RcFswj6BEA9DaqhUpYowCpf0LRlQs,2689
|
|
148
|
+
handler_control/data/interfaces/llm/v1/interface.toml,sha256=QPP3ydQSmYaDCIXnSu5FGh9mnUyNgkIGSLleHnpeApw,780
|
|
149
|
+
handler_control/data/interfaces/llm/v1/tools.json,sha256=_S9q677uQUJolGYIC2sXfb0uD7kc7rP-n6xWT2wGvso,3011
|
|
150
|
+
handler_control/data/templates/README.md,sha256=1bqiDC1BHTFreB3GenMhRyOyYb7H5At9zfGxi3egFa4,534
|
|
151
|
+
handler_control/data/templates/providers/anthropic-api.toml,sha256=uIBXxdZ5lu_daN3ur4LfpfT1ppVSe1IEi7E6pPRwOrE,332
|
|
152
|
+
handler_control/data/templates/providers/llamacpp.toml,sha256=gviB-Qm8OHU3_YWrENa3E6WrHCBHCUf-4HVH7g-dQ_I,17552
|
|
153
|
+
handler_control/data/templates/providers/mistral-api.toml,sha256=fFu0rsWYyMFOdwCZFfyv7olcvNLWonlsN51Uq6ceS6k,276
|
|
154
|
+
handler_control/data/templates/providers/ollama.toml,sha256=DGZ0mLso7H6rov-zmFFGe4bT0ygFrEMDkRdKapvwwzs,289
|
|
155
|
+
handler_control/data/templates/providers/openai-api.toml,sha256=GFJqY8RcBITfg3P2JdeXqzc4zIYjqiMm_-YzeNz3p7w,256
|
|
156
|
+
handler_control/data/templates/providers/openrouter.toml,sha256=DyLuMB5UOSpfyAPeqBhOV94BTIiMxqFZJfFUXtR3Vdg,208
|
|
157
|
+
handler_control/migrations/__init__.py,sha256=RoB8DgI4wLaAXFzZC6VTRVR67KSHu4GxbtFE-3v3L9Y,2496
|
|
158
|
+
handler_control/web-ui/favicon.svg,sha256=l7nmpf_PxjUNKE_U6PhDkwPDc9fMgN6e8BYQvx3ZVps,774
|
|
159
|
+
handler_control/web-ui/index.html,sha256=EM6S5P_N4kPFw4xEnSR-2QJ7nDsKPipgxW1L5H7XhkQ,507
|
|
160
|
+
handler_control/web-ui/assets/index-1w5RPsfA.js,sha256=4M62_lok_9g52vXDA0SJ_rhdh8pLUf_p6oJcJh-0VlU,1009903
|
|
161
|
+
handler_control/web-ui/assets/index-dWnzCLzQ.css,sha256=Z2z7TQVOPrmaZYHeq5A3LHEys36KrQMhX3RmXuuKW0A,99761
|
|
162
|
+
handler_control/web-ui/assets/inter-cyrillic-ext-wght-normal-BOeWTOD4.woff2,sha256=yhVwYzOaxK1BjyFPOr_tEZsHmKtNN3OGzlyeWnpDXr0,25960
|
|
163
|
+
handler_control/web-ui/assets/inter-cyrillic-wght-normal-DqGufNeO.woff2,sha256=cdXuk8wenx1SCjqLZkVt4Yx4edjfCdV_zS6v91_vAHU,18748
|
|
164
|
+
handler_control/web-ui/assets/inter-greek-ext-wght-normal-DlzME5K_.woff2,sha256=bp4CCiX5tW1BjywIWx08CXJaTaI_5pOltGMGRgZzIZA,11232
|
|
165
|
+
handler_control/web-ui/assets/inter-greek-wght-normal-CkhJZR-_.woff2,sha256=G-NEjikvvwX_4Xb-HkPxNQE9ULHn0yStGlWPYj07tvY,18996
|
|
166
|
+
handler_control/web-ui/assets/inter-latin-ext-wght-normal-DO1Apj_S.woff2,sha256=NLnFBMq3pz43t0Y0OkSRMuVs97VIGvLLgdx03P8lyVY,85068
|
|
167
|
+
handler_control/web-ui/assets/inter-latin-wght-normal-Dx4kXJAl.woff2,sha256=MQDndehhbNJhG-7PojpCY9cDdYZ4m0PwNSNqLm-9TGI,48256
|
|
168
|
+
handler_control/web-ui/assets/inter-vietnamese-wght-normal-CBcvBZtf.woff2,sha256=XGb54H6QxtSsSSLMaNYN4mwXsYWOZ3-15gP845UrP_I,10252
|
|
169
|
+
handler_harness/__init__.py,sha256=gcqXmlxXEJoFCWAz4esFMZXObAa8I0i-QSQQF39dEZc,605
|
|
170
|
+
handler_harness/addons.py,sha256=Y7CRbEB-ezO6oUWniF6kWrPL2_p4dljIGSlhavnysLg,4534
|
|
171
|
+
handler_harness/catalog.py,sha256=hm3pBm7L3-A7_sV6kal_Jguwp_kql8EYJvjaWgE8glE,4184
|
|
172
|
+
handler_harness/cli.py,sha256=tM2riQ7j3Y-O1UyxyS0KX6kG_npxxtAiugpDTJUimo0,4189
|
|
173
|
+
handler_harness/images.py,sha256=u35iolGdG0BfhX3iyDoA-jecfUqQ9P_89A9OYwM01fw,2423
|
|
174
|
+
handler_harness/providers.py,sha256=br3S7hsb1Zw_MxsnmOrKBYTnpp3R2ItM4FLiZyQpjD8,11667
|
|
175
|
+
handler_harness/render.py,sha256=SJpF8Gsd5mqiP-Q3oJpMFLSYwsH0Qg7QbkK4GOSl-kM,20540
|
|
176
|
+
handler_harness/data/handler-sandbox-env,sha256=KC9BsL52Tg8lPIZgybeE10p2HPSibW8QFP2R6hWGBus,1152
|
|
177
|
+
handler_harness/data/addons/README.md,sha256=01iz8vdkigS66fpQ-En0cyKSYWyCVp7R48wSM9k7Mc0,2642
|
|
178
|
+
handler_harness/data/addons/miniapp/Containerfile,sha256=g5sYRS3lbDsx1qkSyrNAZfYm9_DZNT5TS_4icDlxqrA,844
|
|
179
|
+
handler_harness/data/addons/miniapp/PROVISIONING.md,sha256=gJAQZYnoFyNxv-Et8ht330KRbXr58L7tVnemFOZL_uY,603
|
|
180
|
+
handler_harness/data/addons/miniapp/addon.toml,sha256=Hkq_KesAHtkuxkceofWsPGiZelJ1OnU-S1dpZf7QdCw,868
|
|
181
|
+
handler_harness/data/addons/miniapp/skills/miniapp/SKILL.md,sha256=6w-KWy8twsfaNGxFdRCkXanZUrs14j7SRMB1JZ6ERBU,8814
|
|
182
|
+
handler_harness/data/addons/miniapp/skills/miniapp/template/.gitignore,sha256=Ww_P8-8E2jmWEf6J-z_tsG6K0ZKOfRwc2XrPgirp_II,31
|
|
183
|
+
handler_harness/data/addons/miniapp/skills/miniapp/template/app.toml,sha256=LE_uJYWk_hvt1-wCSmxREjsEXIyGFQcQwGl_k0o2-zA,586
|
|
184
|
+
handler_harness/data/addons/miniapp/skills/miniapp/template/server/db.ts,sha256=eIdgPAY5OTOhEeZGIT1T3aja0eUKI7SE0INCT26vge0,1077
|
|
185
|
+
handler_harness/data/addons/miniapp/skills/miniapp/template/server/deno.json,sha256=GpeLDbbvO6QBf0vzVF-TeC4Jkyh3uf9iSAlgZP4VoO4,255
|
|
186
|
+
handler_harness/data/addons/miniapp/skills/miniapp/template/server/handler.ts,sha256=9vXpqdySnz185J8tVaQSc8ZwWZz2OG3_BZQZMmOLAAY,1185
|
|
187
|
+
handler_harness/data/addons/miniapp/skills/miniapp/template/server/main.ts,sha256=2K8s8Di1HWXlj_f2-1x-6qNzEZIrbJWKsaW655AF4rw,818
|
|
188
|
+
handler_harness/data/addons/miniapp/skills/miniapp/template/server/main_test.ts,sha256=FFCMemfxFEdCee-6O_FQ85u0G_GyBBdrJ0XYptbhFzI,1363
|
|
189
|
+
handler_harness/data/addons/miniapp/skills/miniapp/template/server/routes.ts,sha256=5ihC8GUw_FZCK631VKtwFEqfQlMsAertG8gusIF-TuE,1487
|
|
190
|
+
handler_harness/data/addons/miniapp/skills/miniapp/template/server/migrations/001_notes.sql,sha256=IFx5b26gHM0NJ4JHcxjHE0_r3TsrA-mgOBghRP08clA,171
|
|
191
|
+
handler_harness/data/addons/miniapp/skills/miniapp/template/ui/deno.json,sha256=7tnHhD96JpRI4snnkwZy60sb4lGPa5dBhsJP7dByoLk,291
|
|
192
|
+
handler_harness/data/addons/miniapp/skills/miniapp/template/ui/index.html,sha256=cS5eAJ9v3uNBuQHiA65jsRe5Rb43x_DEzdn2NryKCwY,288
|
|
193
|
+
handler_harness/data/addons/miniapp/skills/miniapp/template/ui/vite.config.ts,sha256=uRQMeTR2JDd4GFZc9mDz5Mx20WSnacpxtLOOxFPXNYw,675
|
|
194
|
+
handler_harness/data/addons/miniapp/skills/miniapp/template/ui/src/App.svelte,sha256=cszVVXfAM2_lZ226J-G-ZTxSFcho1vWvWDN7ZAEG7DE,1121
|
|
195
|
+
handler_harness/data/addons/miniapp/skills/miniapp/template/ui/src/api.ts,sha256=WV1TT_HW94xBD5mvL0ZC78wcZx8QQsNbw1EmwJ13Ldw,1035
|
|
196
|
+
handler_harness/data/addons/miniapp/skills/miniapp/template/ui/src/app.css,sha256=HPUcFTr42E4bKNhl26vtN09tdaVr4wemaxXMdLDyq08,289
|
|
197
|
+
handler_harness/data/addons/miniapp/skills/miniapp/template/ui/src/main.ts,sha256=62oaXZ_afOhKSVUO7pGeMDGAdxePQevyhX9Q9glHWRI,142
|
|
198
|
+
handler_harness/data/catalog/README.md,sha256=YseuqgRKTY5-vC-3D8ZKYkp333wPVmp_2jHKMxEh-do,883
|
|
199
|
+
handler_harness/data/catalog/playwright/Containerfile,sha256=FuXXP1Xoyl8D_qNVG8yza23RzRvBn8tc1hAWDF12Ees,1699
|
|
200
|
+
handler_harness/data/catalog/playwright/PROVISIONING.md,sha256=mVanfu4eQr4_ZLD-dpx0dxz7GOMgRC3Mte3aCE9rv2E,2153
|
|
201
|
+
handler_harness/data/catalog/playwright/addon.toml,sha256=x3c2iNnAMNFLK4ExpBW8sv2abLbkhB1bE7LSWrgQN1c,1312
|
|
202
|
+
handler_harness/data/catalog/playwright/handler/playwright-mcp-check.mjs,sha256=Attl0Zd0L-dn3UwH23K0VclQL8Jt70XdOi-bvnJyHx8,998
|
|
203
|
+
handler_harness/data/catalog/playwright/handler/playwright-mcp.mjs,sha256=qk0-o8j2FmmE6Mm6730DhwZ6JWQy1GkY4kCfWyzulOY,2801
|
|
204
|
+
handler_harness/data/catalog/playwright/skills/browser/SKILL.md,sha256=sFfU8fBUtOuuELSWNnv1Ooa_xfUGNQw08_AXKt0Yjzg,2192
|
|
205
|
+
handler_harness/data/catalog/shopify/Containerfile,sha256=w3m7fzYkMhhTON6h_P1sAB6ga6zP01ybzUMW_WOwZR4,1208
|
|
206
|
+
handler_harness/data/catalog/shopify/PROVISIONING.md,sha256=XgBVN5T6vVVB7BiJQj_RzTAMmFc8u9O28IliuRU4yH0,2110
|
|
207
|
+
handler_harness/data/catalog/shopify/addon.toml,sha256=Jxzy3HrcuNHq1OPCaeMX-y6C2cj1yQWkgYzIVe1v30U,1836
|
|
208
|
+
handler_harness/data/catalog/shopify/skills/shopify/SKILL.md,sha256=BNhDos63S7x5-w2arSsAffCO79Cx4NpkDpFmRXvaTBI,1971
|
|
209
|
+
handler_harness/data/harnesses/README.md,sha256=REl5xKr_Gb0UHRiAgsCXvYq_gsw4C-JC4OKPiAQ65_g,4083
|
|
210
|
+
handler_harness/data/harnesses/claude-code/Containerfile,sha256=NoB-o3ZsEgKG8zQAsPzgwF5aFrEtpN8yZxn2oI42IDw,1639
|
|
211
|
+
handler_harness/data/harnesses/claude-code/harness.toml,sha256=OHnL3rsjengn5Ww-mqLOKwbm1uyuS7faUseqUJJxpiQ,4955
|
|
212
|
+
handler_harness/data/harnesses/codex/Containerfile,sha256=eYzhS2LPOBZ4NnhrH4d4fvYlRKO0zkNAGxW-C4E5McU,1744
|
|
213
|
+
handler_harness/data/harnesses/codex/harness.toml,sha256=zcRex6oTmxTZRSqQNbWlzgJZLxeSzMMxBt6NdRNCuNk,5047
|
|
214
|
+
handler_harness/data/harnesses/pi/Containerfile,sha256=TX_D2KrebETpy_ATRSh87KHgitDTRPzwP8100I4oGqI,1653
|
|
215
|
+
handler_harness/data/harnesses/pi/harness.toml,sha256=LWxf77QcaCAV6it56lqWwVUlyvaOuf2KAOoVZsYMglU,3314
|
|
216
|
+
handler_harness/data/harnesses/vibe/Containerfile,sha256=FMdNXEvyAKXtZSVqJF4SQf1p8JrZUMrIN4stXkovPjc,884
|
|
217
|
+
handler_harness/data/harnesses/vibe/harness.toml,sha256=VJuUEwGC3Mvx5iIVv_KoM3rTeR1vTook3Jt3XJecIKg,4322
|
|
218
|
+
handler_harness/data/toolbox/Containerfile,sha256=PpH0e-JEpnr_eHV5hrggQQq-qrqSeFJ8lvDaJ90I1ck,2988
|
|
219
|
+
handler_harness/data/toolbox/README.md,sha256=bFy_D0Nv69dR159xvE-t-fAz9vjPHGEjFs2Rm1jsMms,1648
|
|
220
|
+
handler_harness/data/toolbox/toolbox.toml,sha256=W5lYuAxNQ_IQQuY41HPbn13u4L1v03o2KhC1loAktVc,1243
|
|
221
|
+
handler_sandbox_podman/__init__.py,sha256=mL_TJ6_6NuZHTBItyYSMYYzjS22Oosyc8kxLhTWqoz8,62
|
|
222
|
+
handler_sandbox_podman/caches.py,sha256=pld6dVa784TubQMCxcKzV22lPtwMxjrRJLvQTUFDlXI,3953
|
|
223
|
+
handler_sandbox_podman/check.py,sha256=i4QUc49CS669DA7dRf769GU0N4dCz0_eHpJchlfk0d0,4274
|
|
224
|
+
handler_sandbox_podman/cli.py,sha256=NFYBsmg-_Afa76HBR2ypQlUNtgRtK8ct1SqHGo3QpZc,10016
|
|
225
|
+
handler_sandbox_podman/egress.py,sha256=_xkMBp3bHkjtUigdC8TsvOBoa_pWAU_ylH6e_Iwo9rQ,4720
|
|
226
|
+
handler_sandbox_podman/images.py,sha256=dw8yeiWsi0X1Uw1F_zcuAMC2VHnQtDjY2CsA46Dmo4s,7192
|
|
227
|
+
handler_sandbox_podman/launch.py,sha256=Wvy5QOuP7S9_jLxQsaD-G3JTLG0gzGkZllU69Hwiokw,21528
|
|
228
|
+
handler_sandbox_podman/podman.py,sha256=Qnqfw4Dv_Shu7rxm5q4zV31QSqEQhkYHTsXdsdvBNAA,4445
|
|
229
|
+
handler_sandbox_podman/proxy/Containerfile,sha256=dF56zLSfELXw94CC2zJEYz8FVBRbz6zDWGbmv9Tzq4g,401
|
|
230
|
+
handler_sandbox_podman/proxy/addon.py,sha256=Pr8dXkFR7A5mrsJUAMij3lOQjOQpTVC-Jc2j-rydB0c,10659
|
|
231
|
+
handler_ai-0.1.0.dist-info/METADATA,sha256=IEmlmZf3Ul1i0qMWIv9SKtS-dbZkldfwCWl0vNEKgO0,2497
|
|
232
|
+
handler_ai-0.1.0.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
|
|
233
|
+
handler_ai-0.1.0.dist-info/entry_points.txt,sha256=BVznYHkhvLm9-vMiNdqoGKhZGx5guBFxIuLEuCNbNnA,222
|
|
234
|
+
handler_ai-0.1.0.dist-info/RECORD,,
|
handler_cli/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""handler — command line client of handlerd (contracts C and D only; never touches podman)."""
|
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
"""`handler account …` — accounts (contract D.9): a subscription one harness logs in with.
|
|
2
|
+
|
|
3
|
+
A token login (Claude Code): you run its sign-in yourself (`claude setup-token`, Anthropic's own,
|
|
4
|
+
in your browser) and give handler the token it prints, or tell handler where you keep it; handler
|
|
5
|
+
never runs that sign-in nor reads its output. A file login (Codex, Vibe): handler runs the harness's
|
|
6
|
+
login here and keeps the credential file it leaves.
|
|
7
|
+
|
|
8
|
+
handler account list accounts, their harness, plan, login and contexts
|
|
9
|
+
handler account add NAME HARNESS [--description TEXT] [--plan PLAN] [--context CONTEXT …]
|
|
10
|
+
[--token | --token-env VAR | --token-file PATH | --token-command CMD]
|
|
11
|
+
PLAN: its subscription's (e.g. pro, max for claude-code),
|
|
12
|
+
told to the harness, which cannot learn it from a token.
|
|
13
|
+
--context: the project contexts it is made for (Work,
|
|
14
|
+
Personal…, or any; none: it runs nowhere a project has one)
|
|
15
|
+
--token…: its token login at once (as `handler account token`)
|
|
16
|
+
handler account token NAME [--env VAR | --file PATH | --command CMD]
|
|
17
|
+
a token login: the token your own sign-in printed (asked
|
|
18
|
+
for, or read from stdin), kept in handler's secret store; or
|
|
19
|
+
where you keep it: an env var of handlerd, a file (its first
|
|
20
|
+
line), a command printing it (e.g. 'pass show claude-pro')
|
|
21
|
+
handler account login NAME [--keep-open] a file login: its harness's own login runs here, on this
|
|
22
|
+
computer (npx or uvx fetches it), its state in a folder of
|
|
23
|
+
its own; handler keeps the file it leaves. --keep-open: wait
|
|
24
|
+
for Enter at the end (a window the web UI opened for it)
|
|
25
|
+
handler account import NAME FILE or give a file login done elsewhere: the credential file it
|
|
26
|
+
left (e.g. ~/.codex/auth.json after `codex login`)
|
|
27
|
+
handler account rm NAME it and its login (refused while an agent uses it)
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
import argparse
|
|
31
|
+
import contextlib
|
|
32
|
+
import fcntl
|
|
33
|
+
import getpass
|
|
34
|
+
import os
|
|
35
|
+
import pty
|
|
36
|
+
import pwd
|
|
37
|
+
import select
|
|
38
|
+
import shlex
|
|
39
|
+
import shutil
|
|
40
|
+
import signal
|
|
41
|
+
import struct
|
|
42
|
+
import subprocess
|
|
43
|
+
import sys
|
|
44
|
+
import tempfile
|
|
45
|
+
import termios
|
|
46
|
+
import tty
|
|
47
|
+
from pathlib import Path
|
|
48
|
+
from typing import Any
|
|
49
|
+
|
|
50
|
+
from .client import ClientError, Daemon
|
|
51
|
+
from .output import table
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def add_parser(sub: Any) -> None:
|
|
55
|
+
account = sub.add_parser("account", help="accounts", description=__doc__,
|
|
56
|
+
formatter_class=argparse.RawDescriptionHelpFormatter) # fmt: skip
|
|
57
|
+
a = account.add_subparsers(dest="account_cmd", required=True)
|
|
58
|
+
a.add_parser("list")
|
|
59
|
+
add = a.add_parser("add")
|
|
60
|
+
add.add_argument("name")
|
|
61
|
+
add.add_argument("harness")
|
|
62
|
+
add.add_argument("--description")
|
|
63
|
+
add.add_argument("--plan")
|
|
64
|
+
add.add_argument(
|
|
65
|
+
"--context",
|
|
66
|
+
action="append",
|
|
67
|
+
metavar="CONTEXT",
|
|
68
|
+
default=[],
|
|
69
|
+
help="a project context it is made for (Work, any…); repeatable",
|
|
70
|
+
)
|
|
71
|
+
given = add.add_mutually_exclusive_group()
|
|
72
|
+
given.add_argument("--token", action="store_true", help="ask for the token now")
|
|
73
|
+
given.add_argument("--token-env", metavar="VAR")
|
|
74
|
+
given.add_argument("--token-file", metavar="PATH")
|
|
75
|
+
given.add_argument("--token-command", metavar="CMD")
|
|
76
|
+
token = a.add_parser("token")
|
|
77
|
+
token.add_argument("name")
|
|
78
|
+
where = token.add_mutually_exclusive_group()
|
|
79
|
+
where.add_argument("--env", metavar="VAR")
|
|
80
|
+
where.add_argument("--file", metavar="PATH")
|
|
81
|
+
where.add_argument("--command", metavar="CMD")
|
|
82
|
+
log_in = a.add_parser("login")
|
|
83
|
+
log_in.add_argument("name")
|
|
84
|
+
log_in.add_argument("--keep-open", action="store_true", help="wait for Enter at the end")
|
|
85
|
+
imp = a.add_parser("import")
|
|
86
|
+
imp.add_argument("name")
|
|
87
|
+
imp.add_argument("file", type=Path)
|
|
88
|
+
a.add_parser("rm").add_argument("name")
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def dispatch(args: argparse.Namespace) -> int:
|
|
92
|
+
d = Daemon()
|
|
93
|
+
if args.account_cmd == "list":
|
|
94
|
+
rows = [["NAME", "HARNESS", "PLAN", "LOGIN", "CONTEXTS", "AGENTS"]]
|
|
95
|
+
for a in d.call("GET", "/v1/accounts"):
|
|
96
|
+
harness, plan = a.get("harness") or "?", a.get("plan") or "-"
|
|
97
|
+
contexts = ", ".join(a.get("contexts", [])) or "-"
|
|
98
|
+
rows.append([a["name"], harness, plan, login_status(a), contexts,
|
|
99
|
+
", ".join(a["agents"])]) # fmt: skip
|
|
100
|
+
table(rows) if len(rows) > 1 else print("no account")
|
|
101
|
+
return 0
|
|
102
|
+
if args.account_cmd == "add":
|
|
103
|
+
return add(d, args)
|
|
104
|
+
if args.account_cmd == "token":
|
|
105
|
+
return give_token(d, args.name, token_body(args.name, args.env, args.file, args.command))
|
|
106
|
+
if args.account_cmd == "import":
|
|
107
|
+
return import_login(d, args.name, args.file)
|
|
108
|
+
if args.account_cmd == "login":
|
|
109
|
+
return login_window(d, args.name, keep_open=args.keep_open)
|
|
110
|
+
d.call("DELETE", f"/v1/accounts/{args.name}")
|
|
111
|
+
print(f"{args.name}: removed")
|
|
112
|
+
return 0
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def login_window(d: Daemon, name: str, *, keep_open: bool) -> int:
|
|
116
|
+
"""`handler account login`, its errors said in its own terminal (a window may close at once)."""
|
|
117
|
+
try:
|
|
118
|
+
return login(d, name)
|
|
119
|
+
except ClientError as e:
|
|
120
|
+
print(f"handler: {e}")
|
|
121
|
+
return 1
|
|
122
|
+
finally:
|
|
123
|
+
if keep_open:
|
|
124
|
+
with contextlib.suppress(EOFError, KeyboardInterrupt):
|
|
125
|
+
input("\nPress Enter to close this window.")
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def login_status(a: dict[str, Any]) -> str:
|
|
129
|
+
"""Its login as `handler account list` says it: logged in (and how), or what is missing."""
|
|
130
|
+
if a["status"] == "invalid":
|
|
131
|
+
return a.get("error") or "invalid"
|
|
132
|
+
if a["status"] != "ready":
|
|
133
|
+
return "; ".join(a.get("problems") or ["not logged in"])
|
|
134
|
+
where = {"secret": "token in handler", "env": "token from an env var",
|
|
135
|
+
"file": "token from a file",
|
|
136
|
+
"command": "token from a command"}.get(a.get("token") or "", "logged in") # fmt: skip
|
|
137
|
+
expires = a.get("expiresAt")
|
|
138
|
+
return f"{where}, until {expires[:10]}" if expires else where
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def add(d: Daemon, args: argparse.Namespace) -> int:
|
|
142
|
+
body = {
|
|
143
|
+
"name": args.name,
|
|
144
|
+
"harness": args.harness,
|
|
145
|
+
"description": args.description,
|
|
146
|
+
"contexts": args.context,
|
|
147
|
+
}
|
|
148
|
+
body |= {"plan": args.plan} if args.plan else {}
|
|
149
|
+
made = d.call("POST", "/v1/accounts", body)
|
|
150
|
+
print(f"{args.name}: created")
|
|
151
|
+
if args.token or args.token_env or args.token_file or args.token_command:
|
|
152
|
+
given = token_body(args.name, args.token_env, args.token_file, args.token_command)
|
|
153
|
+
return give_token(d, args.name, given)
|
|
154
|
+
if made.get("login") == "token":
|
|
155
|
+
print(f"log it in: run `{token_command(d, args.harness)}`, then: handler account token "
|
|
156
|
+
f"{args.name}") # fmt: skip
|
|
157
|
+
elif made.get("login") == "file":
|
|
158
|
+
print(f"log it in: handler account login {args.name}")
|
|
159
|
+
return 0
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
def token_command(d: Daemon, harness: str) -> str:
|
|
163
|
+
found = next((h for h in d.call("GET", "/v1/harnesses") if h["name"] == harness), None)
|
|
164
|
+
return ((found or {}).get("login") or {}).get("tokenCommand") or "its sign-in"
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def token_body(name: str, env: str | None, file: str | None, command: str | None) -> dict[str, Any]:
|
|
168
|
+
"""`PUT …/login`'s body: a reference to where the token is kept, else the token, asked for."""
|
|
169
|
+
if env:
|
|
170
|
+
return {"tokenRef": {"env": env}}
|
|
171
|
+
if file:
|
|
172
|
+
return {"tokenRef": {"file": str(Path(file).expanduser().resolve())}}
|
|
173
|
+
if command:
|
|
174
|
+
return {"tokenRef": {"command": shlex.split(command)}}
|
|
175
|
+
return {"token": ask_token(name)}
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
def give_token(d: Daemon, name: str, body: dict[str, Any]) -> int:
|
|
179
|
+
if not body.get("tokenRef") and not body.get("token"):
|
|
180
|
+
raise ClientError(f"no token given for {name}")
|
|
181
|
+
return save(d, name, body)
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
def import_login(d: Daemon, name: str, file: Path) -> int:
|
|
185
|
+
account = next((a for a in d.call("GET", "/v1/accounts") if a["name"] == name), None)
|
|
186
|
+
if account is None:
|
|
187
|
+
raise ClientError(f"no account '{name}' (handler account list)")
|
|
188
|
+
if account.get("login") != "file":
|
|
189
|
+
raise ClientError(f"the login of '{name}' is a token: handler account token {name}")
|
|
190
|
+
return save(d, name, {"file": file.read_text()})
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
def ask_token(name: str, what: str = "token") -> str:
|
|
194
|
+
prompt = f"{what} for {name}: "
|
|
195
|
+
return (getpass.getpass(prompt) if sys.stdin.isatty() else sys.stdin.readline()).strip()
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
def save(d: Daemon, name: str, body: dict[str, Any]) -> int:
|
|
199
|
+
made = d.call("PUT", f"/v1/accounts/{name}/login", body)
|
|
200
|
+
logged_in = made["status"] == "ready"
|
|
201
|
+
print(f"{name}: {'logged in' if logged_in else login_status(made)}")
|
|
202
|
+
return 0 if logged_in else 1
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
def login(d: Daemon, name: str) -> int:
|
|
206
|
+
"""A file login (D.9) on this computer, on a terminal of its own relayed to this one: its
|
|
207
|
+
state in a folder given as `{dir}`, then the file it leaves there becomes the account's
|
|
208
|
+
login. A token login is the person's own to run: said, not run."""
|
|
209
|
+
account = next((a for a in d.call("GET", "/v1/accounts") if a["name"] == name), None)
|
|
210
|
+
if account is None:
|
|
211
|
+
raise ClientError(f"no account '{name}' (handler account list)")
|
|
212
|
+
harness = next(
|
|
213
|
+
(h for h in d.call("GET", "/v1/harnesses") if h["name"] == account.get("harness")), None
|
|
214
|
+
)
|
|
215
|
+
recipe = harness and harness.get("login")
|
|
216
|
+
if not recipe:
|
|
217
|
+
raise ClientError(f"'{name}': {account.get('error') or 'its harness has no login'}")
|
|
218
|
+
if recipe.get("tokenCommand"):
|
|
219
|
+
raise ClientError(
|
|
220
|
+
f"'{name}' logs in with a token you make: run `{recipe['tokenCommand']}`, "
|
|
221
|
+
f"then: handler account token {name}"
|
|
222
|
+
)
|
|
223
|
+
if not harness.get("loginFile"): # a handlerd older than this handler
|
|
224
|
+
raise ClientError("handlerd does not say where the login leaves its file: restart it")
|
|
225
|
+
path = search_path(recipe["command"][0], account["harness"])
|
|
226
|
+
argv = [str(shutil.which(recipe["command"][0], path=path)), *recipe["command"][1:]]
|
|
227
|
+
if recipe.get("help"):
|
|
228
|
+
print(recipe["help"])
|
|
229
|
+
with tempfile.TemporaryDirectory(prefix="handler-login-") as folder:
|
|
230
|
+
env = (
|
|
231
|
+
dict(os.environ)
|
|
232
|
+
| {"PATH": path}
|
|
233
|
+
| {k: v.replace("{dir}", folder) for k, v in (recipe.get("env") or {}).items()}
|
|
234
|
+
)
|
|
235
|
+
code = on_terminal(argv, env, folder)
|
|
236
|
+
file = Path(folder) / harness["loginFile"]
|
|
237
|
+
if not file.is_file() or not file.read_text(errors="replace").strip():
|
|
238
|
+
print(f"\n{name}: not logged in: it left no {file.name} (exit {code})")
|
|
239
|
+
return 1
|
|
240
|
+
return save(d, name, {"file": file.read_text()})
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
def search_path(program: str, harness: str) -> str:
|
|
244
|
+
"""The PATH the login runs with: this one when it has the program, else the person's login
|
|
245
|
+
shell's (a window handlerd opened has handlerd's, a systemd service's: without ~/.local/bin…),
|
|
246
|
+
where what the program needs (node for npx) is too."""
|
|
247
|
+
for path in (os.environ.get("PATH", ""), login_path()):
|
|
248
|
+
if shutil.which(program, path=path):
|
|
249
|
+
return path
|
|
250
|
+
raise ClientError(
|
|
251
|
+
f"the {harness} login runs {program} on this computer: install it "
|
|
252
|
+
"(npx: Node.js and npm; uvx: uv)"
|
|
253
|
+
)
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
def login_path() -> str:
|
|
257
|
+
shell = pwd.getpwuid(os.getuid()).pw_shell or "/bin/sh"
|
|
258
|
+
with contextlib.suppress(OSError, subprocess.SubprocessError):
|
|
259
|
+
printed = subprocess.run(
|
|
260
|
+
[shell, "-lc", "printenv PATH"],
|
|
261
|
+
capture_output=True,
|
|
262
|
+
text=True,
|
|
263
|
+
timeout=10,
|
|
264
|
+
stdin=subprocess.DEVNULL,
|
|
265
|
+
check=False,
|
|
266
|
+
).stdout.strip()
|
|
267
|
+
if printed:
|
|
268
|
+
return printed.splitlines()[-1] # after what its shell profile may print
|
|
269
|
+
return ""
|
|
270
|
+
|
|
271
|
+
|
|
272
|
+
def on_terminal(argv: list[str], env: dict[str, str], cwd: str) -> int:
|
|
273
|
+
"""Run `argv` on a terminal of its own, relayed to this one (raw while it runs, resized with
|
|
274
|
+
it): its exit code."""
|
|
275
|
+
pid, master = pty.fork()
|
|
276
|
+
if pid == 0: # the child, on the new terminal
|
|
277
|
+
os.chdir(cwd)
|
|
278
|
+
os.execve(argv[0], argv, env)
|
|
279
|
+
interactive = sys.stdin.isatty()
|
|
280
|
+
saved = termios.tcgetattr(0) if interactive else None
|
|
281
|
+
|
|
282
|
+
def resize(*_: object) -> None:
|
|
283
|
+
cols, rows = shutil.get_terminal_size()
|
|
284
|
+
fcntl.ioctl(master, termios.TIOCSWINSZ, struct.pack("HHHH", rows, cols, 0, 0))
|
|
285
|
+
|
|
286
|
+
resize()
|
|
287
|
+
inputs = [0, master]
|
|
288
|
+
try:
|
|
289
|
+
if interactive:
|
|
290
|
+
tty.setraw(0)
|
|
291
|
+
signal.signal(signal.SIGWINCH, resize)
|
|
292
|
+
while True:
|
|
293
|
+
ready, _, _ = select.select(inputs, [], [])
|
|
294
|
+
if master in ready:
|
|
295
|
+
try:
|
|
296
|
+
data = os.read(master, 65536)
|
|
297
|
+
except OSError: # EIO: the command and all it started are gone
|
|
298
|
+
data = b""
|
|
299
|
+
if not data:
|
|
300
|
+
break
|
|
301
|
+
os.write(1, data)
|
|
302
|
+
if 0 in ready:
|
|
303
|
+
data = os.read(0, 4096)
|
|
304
|
+
if data:
|
|
305
|
+
os.write(master, data)
|
|
306
|
+
else: # stdin ended (piped): the command goes on without it
|
|
307
|
+
inputs.remove(0)
|
|
308
|
+
finally:
|
|
309
|
+
if saved is not None:
|
|
310
|
+
termios.tcsetattr(0, termios.TCSADRAIN, saved)
|
|
311
|
+
signal.signal(signal.SIGWINCH, signal.SIG_DFL)
|
|
312
|
+
os.close(master)
|
|
313
|
+
_, status = os.waitpid(pid, 0)
|
|
314
|
+
return os.waitstatus_to_exitcode(status)
|