anywhere-cli 0.1.4__tar.gz → 0.1.7__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 (56) hide show
  1. {anywhere_cli-0.1.4 → anywhere_cli-0.1.7}/.gitignore +38 -30
  2. {anywhere_cli-0.1.4 → anywhere_cli-0.1.7}/PKG-INFO +1 -1
  3. {anywhere_cli-0.1.4 → anywhere_cli-0.1.7}/README.md +94 -94
  4. {anywhere_cli-0.1.4 → anywhere_cli-0.1.7}/connector/__init__.py +3 -3
  5. {anywhere_cli-0.1.4 → anywhere_cli-0.1.7}/connector/adapter.py +39 -39
  6. {anywhere_cli-0.1.4 → anywhere_cli-0.1.7}/connector/attachments.py +36 -36
  7. {anywhere_cli-0.1.4 → anywhere_cli-0.1.7}/connector/capabilities.py +334 -334
  8. {anywhere_cli-0.1.4 → anywhere_cli-0.1.7}/connector/claude/__init__.py +8 -8
  9. {anywhere_cli-0.1.4 → anywhere_cli-0.1.7}/connector/claude/history_adapter.py +642 -642
  10. {anywhere_cli-0.1.4 → anywhere_cli-0.1.7}/connector/claude/normalized.py +23 -23
  11. {anywhere_cli-0.1.4 → anywhere_cli-0.1.7}/connector/claude/normalizers.py +97 -97
  12. {anywhere_cli-0.1.4 → anywhere_cli-0.1.7}/connector/claude/path_utils.py +13 -13
  13. {anywhere_cli-0.1.4 → anywhere_cli-0.1.7}/connector/claude/preferences.py +38 -38
  14. {anywhere_cli-0.1.4 → anywhere_cli-0.1.7}/connector/claude/sdk_adapter.py +1375 -1375
  15. {anywhere_cli-0.1.4 → anywhere_cli-0.1.7}/connector/claude/timeline_identity.py +47 -47
  16. {anywhere_cli-0.1.4 → anywhere_cli-0.1.7}/connector/claude/timeline_reducer.py +379 -379
  17. {anywhere_cli-0.1.4 → anywhere_cli-0.1.7}/connector/claude/trust.py +69 -69
  18. {anywhere_cli-0.1.4 → anywhere_cli-0.1.7}/connector/cli.py +280 -220
  19. {anywhere_cli-0.1.4 → anywhere_cli-0.1.7}/connector/codex/__init__.py +3 -3
  20. {anywhere_cli-0.1.4 → anywhere_cli-0.1.7}/connector/codex/adapter.py +1025 -1025
  21. {anywhere_cli-0.1.4 → anywhere_cli-0.1.7}/connector/codex/history.py +199 -199
  22. {anywhere_cli-0.1.4 → anywhere_cli-0.1.7}/connector/codex/reducer.py +1239 -1239
  23. {anywhere_cli-0.1.4 → anywhere_cli-0.1.7}/connector/codex/rpc.py +262 -262
  24. anywhere_cli-0.1.7/connector/control.py +298 -0
  25. anywhere_cli-0.1.7/connector/json_rpc.py +143 -0
  26. {anywhere_cli-0.1.4 → anywhere_cli-0.1.7}/connector/launch.py +104 -104
  27. {anywhere_cli-0.1.4 → anywhere_cli-0.1.7}/connector/local/__init__.py +6 -6
  28. {anywhere_cli-0.1.4 → anywhere_cli-0.1.7}/connector/local/common.py +118 -118
  29. {anywhere_cli-0.1.4 → anywhere_cli-0.1.7}/connector/local/file_ops.py +144 -122
  30. {anywhere_cli-0.1.4 → anywhere_cli-0.1.7}/connector/local/ops.py +83 -83
  31. {anywhere_cli-0.1.4 → anywhere_cli-0.1.7}/connector/local/shell.py +225 -225
  32. {anywhere_cli-0.1.4 → anywhere_cli-0.1.7}/connector/local/terminal.py +389 -389
  33. {anywhere_cli-0.1.4 → anywhere_cli-0.1.7}/connector/local_ops.py +5 -5
  34. anywhere_cli-0.1.7/connector/local_runtime.py +139 -0
  35. anywhere_cli-0.1.7/connector/logging.py +50 -0
  36. {anywhere_cli-0.1.4 → anywhere_cli-0.1.7}/connector/protocol.py +26 -26
  37. {anywhere_cli-0.1.4 → anywhere_cli-0.1.7}/connector/runtime.py +1021 -1021
  38. {anywhere_cli-0.1.4 → anywhere_cli-0.1.7}/connector/sync_state.py +155 -155
  39. {anywhere_cli-0.1.4 → anywhere_cli-0.1.7}/connector/time.py +7 -7
  40. {anywhere_cli-0.1.4 → anywhere_cli-0.1.7}/pyproject.toml +1 -1
  41. {anywhere_cli-0.1.4 → anywhere_cli-0.1.7}/run.sh +4 -4
  42. {anywhere_cli-0.1.4 → anywhere_cli-0.1.7}/tests/test_claude_history_adapter.py +344 -344
  43. {anywhere_cli-0.1.4 → anywhere_cli-0.1.7}/tests/test_claude_preferences.py +68 -68
  44. {anywhere_cli-0.1.4 → anywhere_cli-0.1.7}/tests/test_claude_sdk_adapter.py +884 -884
  45. {anywhere_cli-0.1.4 → anywhere_cli-0.1.7}/tests/test_claude_timeline_parity.py +252 -252
  46. {anywhere_cli-0.1.4 → anywhere_cli-0.1.7}/tests/test_claude_trust.py +60 -60
  47. {anywhere_cli-0.1.4 → anywhere_cli-0.1.7}/tests/test_codex_adapter.py +1476 -1476
  48. {anywhere_cli-0.1.4 → anywhere_cli-0.1.7}/tests/test_connector_capabilities.py +316 -316
  49. {anywhere_cli-0.1.4 → anywhere_cli-0.1.7}/tests/test_connector_cli.py +180 -170
  50. anywhere_cli-0.1.7/tests/test_connector_control.py +179 -0
  51. anywhere_cli-0.1.7/tests/test_connector_json_rpc.py +81 -0
  52. anywhere_cli-0.1.7/tests/test_connector_logging.py +28 -0
  53. {anywhere_cli-0.1.4 → anywhere_cli-0.1.7}/tests/test_connector_runtime.py +1269 -1264
  54. anywhere_cli-0.1.7/tests/test_local_runtime.py +47 -0
  55. {anywhere_cli-0.1.4 → anywhere_cli-0.1.7}/tests/test_terminal_backend.py +78 -78
  56. anywhere_cli-0.1.4/uv.lock +0 -912
@@ -1,30 +1,38 @@
1
- .DS_Store
2
- xcuserdata/
3
- *.xcuserstate
4
- __pycache__/
5
- *.py[cod]
6
- .pytest_cache/
7
- .ruff_cache/
8
- .venv/
9
- .next/
10
- .env.local
11
- .env.*.local
12
-
13
- # Local Claude tooling (launch.json, transcripts, worktree metadata)
14
- .claude/
15
- .codex-run/
16
- agent-server/*-review.html
17
-
18
- # Local runtime state
19
- *.sqlite
20
- *.sqlite3
21
- *.db
22
- agent-server/agent-server.files/
23
-
24
- # Generated reference-doc caches live under docs/reference locally.
25
- docs/reference/*
26
- !docs/reference/README.md
27
-
28
- _reference/*
29
- !_reference/httpx-s3-client/
30
- !_reference/httpx-s3-client/**
1
+ .DS_Store
2
+ xcuserdata/
3
+ *.xcuserstate
4
+ __pycache__/
5
+ *.py[cod]
6
+ .pytest_cache/
7
+ .ruff_cache/
8
+ .venv/
9
+ .next/
10
+ web-next/out/
11
+ .env.local
12
+ .env.*.local
13
+
14
+ # Dependency lockfiles are intentionally not committed in this repo.
15
+ # Cross-platform package managers rewrite them frequently, creating noise.
16
+ uv.lock
17
+ yarn.lock
18
+ package-lock.json
19
+ pnpm-lock.yaml
20
+
21
+ # Local Claude tooling (launch.json, transcripts, worktree metadata)
22
+ .claude/
23
+ .codex-run/
24
+ agent-server/*-review.html
25
+
26
+ # Local runtime state
27
+ *.sqlite
28
+ *.sqlite3
29
+ *.db
30
+ agent-server/agent-server.files/
31
+
32
+ # Generated reference-doc caches live under docs/reference locally.
33
+ docs/reference/*
34
+ !docs/reference/README.md
35
+
36
+ _reference/*
37
+ !_reference/httpx-s3-client/
38
+ !_reference/httpx-s3-client/**
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: anywhere-cli
3
- Version: 0.1.4
3
+ Version: 0.1.7
4
4
  Summary: Local runtime connector for Agents Anywhere
5
5
  Requires-Python: >=3.12
6
6
  Requires-Dist: claude-agent-sdk
@@ -1,94 +1,94 @@
1
- # Anywhere CLI
2
-
3
- Local runtime connector for Agents Anywhere. It runs on the machine that owns
4
- the workspace and agent runtimes, connects to the server over HTTP/WebSocket,
5
- executes connector RPC locally, and uploads normalized runtime/session state
6
- back to the backend.
7
-
8
- ## Layout
9
-
10
- ```text
11
- connector/
12
- claude/ Claude Code discovery, adapter, reducer, and transcript logic
13
- codex/ Codex app-server discovery, RPC, adapter, and reducer logic
14
- local/ Local filesystem, shell, and terminal backends
15
- cli.py anywhere-cli CLI
16
- runtime.py Connector config, auth, WebSocket loop, and RPC dispatch
17
- tests/ Connector tests
18
- pyproject.toml Connector dependencies and console script
19
- run.sh Local helper for saved-config startup
20
- ```
21
-
22
- ## Run
23
-
24
- Install dependencies:
25
-
26
- ```bash
27
- uv sync
28
- ```
29
-
30
- Start with explicit credentials from the web pairing flow:
31
-
32
- ```bash
33
- uvx anywhere-cli start \
34
- --server-url http://127.0.0.1:8000 \
35
- --connector-id conn_xxx \
36
- --connector-token cxt_xxx
37
- ```
38
-
39
- Or save the config locally and start without arguments:
40
-
41
- ```bash
42
- uvx anywhere-cli configure \
43
- --server-url http://127.0.0.1:8000 \
44
- --connector-id conn_xxx \
45
- --connector-token cxt_xxx
46
-
47
- uvx anywhere-cli start
48
- ```
49
-
50
- The default config path is `~/.agent-server/connector.json`. Override it with
51
- `--config` or `AGENT_CONNECTOR_CONFIG`.
52
-
53
- ## Runtime Discovery
54
-
55
- The connector discovers Codex and Claude locally and reports attached runtime
56
- capabilities to the server. If a runtime is not on `PATH`, set one of:
57
-
58
- ```bash
59
- CODEX_BIN=/path/to/codex
60
- CLAUDE_BIN=/path/to/claude
61
- ```
62
-
63
- The connector uses local runtime credentials and local filesystem permissions.
64
- Agents Anywhere does not proxy Claude or Codex account credentials.
65
-
66
- ## Local Operations
67
-
68
- The server can ask an online connector to perform local work:
69
-
70
- - read/list/write files inside workspace-safe roots
71
- - upload/download file content through the server
72
- - run one-shot shell commands
73
- - start and wait for shell tasks
74
- - create, write, resize, stream, list, and close interactive terminals
75
- - start, interrupt, sync, and approve runtime turns
76
-
77
- ## Environment
78
-
79
- | Variable | Purpose |
80
- | --- | --- |
81
- | `AGENT_CONNECTOR_CONFIG` | Connector config path. |
82
- | `AGENT_SERVER_URL` | Server URL used when `--server-url` is omitted. |
83
- | `AGENT_CONNECTOR_ID` | Connector id used when `--connector-id` is omitted. |
84
- | `AGENT_CONNECTOR_TOKEN` | Connector token used when `--connector-token` is omitted. |
85
- | `AGENT_CONNECTOR_ATTACHMENTS_ROOT` | Runtime attachment download directory. Defaults to `~/.agents-anywhere/attachments`. |
86
- | `CODEX_BIN` | Explicit Codex CLI/app-server path. |
87
- | `CLAUDE_BIN` | Explicit Claude Code CLI path. |
88
-
89
- ## Verify
90
-
91
- ```bash
92
- uv run ruff check connector tests
93
- uv run pytest -q
94
- ```
1
+ # Anywhere CLI
2
+
3
+ Local runtime connector for Agents Anywhere. It runs on the machine that owns
4
+ the workspace and agent runtimes, connects to the server over HTTP/WebSocket,
5
+ executes connector RPC locally, and uploads normalized runtime/session state
6
+ back to the backend.
7
+
8
+ ## Layout
9
+
10
+ ```text
11
+ connector/
12
+ claude/ Claude Code discovery, adapter, reducer, and transcript logic
13
+ codex/ Codex app-server discovery, RPC, adapter, and reducer logic
14
+ local/ Local filesystem, shell, and terminal backends
15
+ cli.py anywhere-cli CLI
16
+ runtime.py Connector config, auth, WebSocket loop, and RPC dispatch
17
+ tests/ Connector tests
18
+ pyproject.toml Connector dependencies and console script
19
+ run.sh Local helper for saved-config startup
20
+ ```
21
+
22
+ ## Run
23
+
24
+ Install dependencies:
25
+
26
+ ```bash
27
+ uv sync
28
+ ```
29
+
30
+ Start with explicit credentials from the web pairing flow:
31
+
32
+ ```bash
33
+ uvx anywhere-cli start \
34
+ --server-url http://127.0.0.1:8000 \
35
+ --connector-id conn_xxx \
36
+ --connector-token cxt_xxx
37
+ ```
38
+
39
+ Or save the config locally and start without arguments:
40
+
41
+ ```bash
42
+ uvx anywhere-cli configure \
43
+ --server-url http://127.0.0.1:8000 \
44
+ --connector-id conn_xxx \
45
+ --connector-token cxt_xxx
46
+
47
+ uvx anywhere-cli start
48
+ ```
49
+
50
+ The default config path is `~/.agent-server/connector.json`. Override it with
51
+ `--config` or `AGENT_CONNECTOR_CONFIG`.
52
+
53
+ ## Runtime Discovery
54
+
55
+ The connector discovers Codex and Claude locally and reports attached runtime
56
+ capabilities to the server. If a runtime is not on `PATH`, set one of:
57
+
58
+ ```bash
59
+ CODEX_BIN=/path/to/codex
60
+ CLAUDE_BIN=/path/to/claude
61
+ ```
62
+
63
+ The connector uses local runtime credentials and local filesystem permissions.
64
+ Agents Anywhere does not proxy Claude or Codex account credentials.
65
+
66
+ ## Local Operations
67
+
68
+ The server can ask an online connector to perform local work:
69
+
70
+ - read/list/write files inside workspace-safe roots
71
+ - upload/download file content through the server
72
+ - run one-shot shell commands
73
+ - start and wait for shell tasks
74
+ - create, write, resize, stream, list, and close interactive terminals
75
+ - start, interrupt, sync, and approve runtime turns
76
+
77
+ ## Environment
78
+
79
+ | Variable | Purpose |
80
+ | --- | --- |
81
+ | `AGENT_CONNECTOR_CONFIG` | Connector config path. |
82
+ | `AGENT_SERVER_URL` | Server URL used when `--server-url` is omitted. |
83
+ | `AGENT_CONNECTOR_ID` | Connector id used when `--connector-id` is omitted. |
84
+ | `AGENT_CONNECTOR_TOKEN` | Connector token used when `--connector-token` is omitted. |
85
+ | `AGENT_CONNECTOR_ATTACHMENTS_ROOT` | Runtime attachment download directory. Defaults to `~/.agents-anywhere/attachments`. |
86
+ | `CODEX_BIN` | Explicit Codex CLI/app-server path. |
87
+ | `CLAUDE_BIN` | Explicit Claude Code CLI path. |
88
+
89
+ ## Verify
90
+
91
+ ```bash
92
+ uv run ruff check connector tests
93
+ uv run pytest -q
94
+ ```
@@ -1,3 +1,3 @@
1
- from connector.protocol import RpcNotification, RpcRequest, RpcResponse
2
-
3
- __all__ = ["RpcNotification", "RpcRequest", "RpcResponse"]
1
+ from connector.protocol import RpcNotification, RpcRequest, RpcResponse
2
+
3
+ __all__ = ["RpcNotification", "RpcRequest", "RpcResponse"]
@@ -1,39 +1,39 @@
1
- from __future__ import annotations
2
-
3
- from collections.abc import Awaitable, Callable
4
- from typing import Any, Protocol, runtime_checkable
5
-
6
-
7
- NotificationSink = Callable[[str, dict[str, Any]], Awaitable[None]] | None
8
-
9
-
10
- @runtime_checkable
11
- class Adapter(Protocol):
12
- """Per-runtime backend client (Codex / Claude / OpenCode / ACP).
13
-
14
- `BackendRpcClient` holds a dict of these keyed by runtime name and routes
15
- incoming RPCs by `params["runtime"]`. Every adapter must accept a
16
- `notification_sink` for pushing reduced backend notifications upstream
17
- (set after construction by the client).
18
- """
19
-
20
- notification_sink: NotificationSink
21
-
22
- async def create_session(self, params: dict[str, Any]) -> dict[str, Any]: ...
23
-
24
- async def sync_session(self, params: dict[str, Any]) -> dict[str, Any]: ...
25
-
26
- async def sync_existing_sessions(
27
- self,
28
- connector_id: str,
29
- *,
30
- limit: int = 100,
31
- force: bool = False,
32
- notification_sink: Callable[[list[dict[str, Any]]], Awaitable[None]] | None = None,
33
- ) -> dict[str, Any]: ...
34
-
35
- async def start_turn(self, params: dict[str, Any]) -> dict[str, Any]: ...
36
-
37
- async def interrupt_turn(self, params: dict[str, Any]) -> dict[str, Any]: ...
38
-
39
- async def resolve_approval(self, params: dict[str, Any]) -> dict[str, Any]: ...
1
+ from __future__ import annotations
2
+
3
+ from collections.abc import Awaitable, Callable
4
+ from typing import Any, Protocol, runtime_checkable
5
+
6
+
7
+ NotificationSink = Callable[[str, dict[str, Any]], Awaitable[None]] | None
8
+
9
+
10
+ @runtime_checkable
11
+ class Adapter(Protocol):
12
+ """Per-runtime backend client (Codex / Claude / OpenCode / ACP).
13
+
14
+ `BackendRpcClient` holds a dict of these keyed by runtime name and routes
15
+ incoming RPCs by `params["runtime"]`. Every adapter must accept a
16
+ `notification_sink` for pushing reduced backend notifications upstream
17
+ (set after construction by the client).
18
+ """
19
+
20
+ notification_sink: NotificationSink
21
+
22
+ async def create_session(self, params: dict[str, Any]) -> dict[str, Any]: ...
23
+
24
+ async def sync_session(self, params: dict[str, Any]) -> dict[str, Any]: ...
25
+
26
+ async def sync_existing_sessions(
27
+ self,
28
+ connector_id: str,
29
+ *,
30
+ limit: int = 100,
31
+ force: bool = False,
32
+ notification_sink: Callable[[list[dict[str, Any]]], Awaitable[None]] | None = None,
33
+ ) -> dict[str, Any]: ...
34
+
35
+ async def start_turn(self, params: dict[str, Any]) -> dict[str, Any]: ...
36
+
37
+ async def interrupt_turn(self, params: dict[str, Any]) -> dict[str, Any]: ...
38
+
39
+ async def resolve_approval(self, params: dict[str, Any]) -> dict[str, Any]: ...
@@ -1,36 +1,36 @@
1
- from __future__ import annotations
2
-
3
- import re
4
- from pathlib import Path
5
-
6
-
7
- ATTACHMENTS_ROOT_ENV = "AGENT_CONNECTOR_ATTACHMENTS_ROOT"
8
- DEFAULT_ATTACHMENTS_DIR = ".agents-anywhere/attachments"
9
- _SAFE_FILENAME_RE = re.compile(r"[^\w.\-+]+")
10
-
11
-
12
- def attachments_root() -> Path:
13
- """Return the connector-local root used for runtime attachment copies."""
14
- import os
15
-
16
- configured = os.environ.get(ATTACHMENTS_ROOT_ENV)
17
- root = Path(configured).expanduser() if configured else Path.home() / DEFAULT_ATTACHMENTS_DIR
18
- return root.resolve(strict=False)
19
-
20
-
21
- def session_attachments_dir(session_id: str) -> Path:
22
- session = _safe_filename(session_id) or "session"
23
- return attachments_root() / session
24
-
25
-
26
- def attachment_target(session_id: str, file_id: str, original_name: str | None) -> Path:
27
- safe_file_id = _safe_filename(file_id) or "file"
28
- safe_name = _safe_filename(original_name or "") or safe_file_id
29
- return session_attachments_dir(session_id) / f"{safe_file_id}-{safe_name}"
30
-
31
-
32
- def _safe_filename(name: str) -> str:
33
- """Reduce arbitrary user/server values to safe single path components."""
34
- name = name.rsplit("/", 1)[-1].rsplit("\\", 1)[-1]
35
- sanitized = _SAFE_FILENAME_RE.sub("_", name).strip("._") or ""
36
- return sanitized[:120]
1
+ from __future__ import annotations
2
+
3
+ import re
4
+ from pathlib import Path
5
+
6
+
7
+ ATTACHMENTS_ROOT_ENV = "AGENT_CONNECTOR_ATTACHMENTS_ROOT"
8
+ DEFAULT_ATTACHMENTS_DIR = ".agents-anywhere/attachments"
9
+ _SAFE_FILENAME_RE = re.compile(r"[^\w.\-+]+")
10
+
11
+
12
+ def attachments_root() -> Path:
13
+ """Return the connector-local root used for runtime attachment copies."""
14
+ import os
15
+
16
+ configured = os.environ.get(ATTACHMENTS_ROOT_ENV)
17
+ root = Path(configured).expanduser() if configured else Path.home() / DEFAULT_ATTACHMENTS_DIR
18
+ return root.resolve(strict=False)
19
+
20
+
21
+ def session_attachments_dir(session_id: str) -> Path:
22
+ session = _safe_filename(session_id) or "session"
23
+ return attachments_root() / session
24
+
25
+
26
+ def attachment_target(session_id: str, file_id: str, original_name: str | None) -> Path:
27
+ safe_file_id = _safe_filename(file_id) or "file"
28
+ safe_name = _safe_filename(original_name or "") or safe_file_id
29
+ return session_attachments_dir(session_id) / f"{safe_file_id}-{safe_name}"
30
+
31
+
32
+ def _safe_filename(name: str) -> str:
33
+ """Reduce arbitrary user/server values to safe single path components."""
34
+ name = name.rsplit("/", 1)[-1].rsplit("\\", 1)[-1]
35
+ sanitized = _SAFE_FILENAME_RE.sub("_", name).strip("._") or ""
36
+ return sanitized[:120]