agentlink-cli 0.1.5__tar.gz → 0.1.6__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.
- {agentlink_cli-0.1.5 → agentlink_cli-0.1.6}/.gitignore +1 -0
- {agentlink_cli-0.1.5 → agentlink_cli-0.1.6}/PKG-INFO +8 -1
- {agentlink_cli-0.1.5 → agentlink_cli-0.1.6}/README.md +7 -0
- {agentlink_cli-0.1.5 → agentlink_cli-0.1.6}/connector/cli.py +7 -1
- {agentlink_cli-0.1.5 → agentlink_cli-0.1.6}/connector/codex/adapter.py +18 -0
- {agentlink_cli-0.1.5 → agentlink_cli-0.1.6}/connector/version.py +1 -1
- {agentlink_cli-0.1.5 → agentlink_cli-0.1.6}/pyproject.toml +1 -1
- {agentlink_cli-0.1.5 → agentlink_cli-0.1.6}/tests/test_codex_adapter.py +26 -0
- {agentlink_cli-0.1.5 → agentlink_cli-0.1.6}/tests/test_connector_cli.py +13 -0
- {agentlink_cli-0.1.5 → agentlink_cli-0.1.6}/tests/test_version.py +1 -1
- {agentlink_cli-0.1.5 → agentlink_cli-0.1.6}/uv.lock +1 -1
- {agentlink_cli-0.1.5 → agentlink_cli-0.1.6}/connector/__init__.py +0 -0
- {agentlink_cli-0.1.5 → agentlink_cli-0.1.6}/connector/acp/__init__.py +0 -0
- {agentlink_cli-0.1.5 → agentlink_cli-0.1.6}/connector/acp/adapter.py +0 -0
- {agentlink_cli-0.1.5 → agentlink_cli-0.1.6}/connector/acp/config_options.py +0 -0
- {agentlink_cli-0.1.5 → agentlink_cli-0.1.6}/connector/acp/discovery.py +0 -0
- {agentlink_cli-0.1.5 → agentlink_cli-0.1.6}/connector/acp/manifest.py +0 -0
- {agentlink_cli-0.1.5 → agentlink_cli-0.1.6}/connector/acp/manifests/__init__.py +0 -0
- {agentlink_cli-0.1.5 → agentlink_cli-0.1.6}/connector/acp/manifests/codebuddy.json +0 -0
- {agentlink_cli-0.1.5 → agentlink_cli-0.1.6}/connector/acp/manifests/cursor.json +0 -0
- {agentlink_cli-0.1.5 → agentlink_cli-0.1.6}/connector/acp/manifests/gemini.json +0 -0
- {agentlink_cli-0.1.5 → agentlink_cli-0.1.6}/connector/acp/manifests/grok_build.json +0 -0
- {agentlink_cli-0.1.5 → agentlink_cli-0.1.6}/connector/acp/reducer.py +0 -0
- {agentlink_cli-0.1.5 → agentlink_cli-0.1.6}/connector/acp/rpc.py +0 -0
- {agentlink_cli-0.1.5 → agentlink_cli-0.1.6}/connector/adapter.py +0 -0
- {agentlink_cli-0.1.5 → agentlink_cli-0.1.6}/connector/attachments.py +0 -0
- {agentlink_cli-0.1.5 → agentlink_cli-0.1.6}/connector/capabilities.py +0 -0
- {agentlink_cli-0.1.5 → agentlink_cli-0.1.6}/connector/claude/__init__.py +0 -0
- {agentlink_cli-0.1.5 → agentlink_cli-0.1.6}/connector/claude/history_adapter.py +0 -0
- {agentlink_cli-0.1.5 → agentlink_cli-0.1.6}/connector/claude/normalized.py +0 -0
- {agentlink_cli-0.1.5 → agentlink_cli-0.1.6}/connector/claude/normalizers.py +0 -0
- {agentlink_cli-0.1.5 → agentlink_cli-0.1.6}/connector/claude/path_utils.py +0 -0
- {agentlink_cli-0.1.5 → agentlink_cli-0.1.6}/connector/claude/preferences.py +0 -0
- {agentlink_cli-0.1.5 → agentlink_cli-0.1.6}/connector/claude/sdk_adapter.py +0 -0
- {agentlink_cli-0.1.5 → agentlink_cli-0.1.6}/connector/claude/timeline_identity.py +0 -0
- {agentlink_cli-0.1.5 → agentlink_cli-0.1.6}/connector/claude/timeline_reducer.py +0 -0
- {agentlink_cli-0.1.5 → agentlink_cli-0.1.6}/connector/claude/trust.py +0 -0
- {agentlink_cli-0.1.5 → agentlink_cli-0.1.6}/connector/codex/__init__.py +0 -0
- {agentlink_cli-0.1.5 → agentlink_cli-0.1.6}/connector/codex/collaboration.py +0 -0
- {agentlink_cli-0.1.5 → agentlink_cli-0.1.6}/connector/codex/history.py +0 -0
- {agentlink_cli-0.1.5 → agentlink_cli-0.1.6}/connector/codex/reducer.py +0 -0
- {agentlink_cli-0.1.5 → agentlink_cli-0.1.6}/connector/codex/rpc.py +0 -0
- {agentlink_cli-0.1.5 → agentlink_cli-0.1.6}/connector/control.py +0 -0
- {agentlink_cli-0.1.5 → agentlink_cli-0.1.6}/connector/json_rpc.py +0 -0
- {agentlink_cli-0.1.5 → agentlink_cli-0.1.6}/connector/launch.py +0 -0
- {agentlink_cli-0.1.5 → agentlink_cli-0.1.6}/connector/local/__init__.py +0 -0
- {agentlink_cli-0.1.5 → agentlink_cli-0.1.6}/connector/local/common.py +0 -0
- {agentlink_cli-0.1.5 → agentlink_cli-0.1.6}/connector/local/file_ops.py +0 -0
- {agentlink_cli-0.1.5 → agentlink_cli-0.1.6}/connector/local/ops.py +0 -0
- {agentlink_cli-0.1.5 → agentlink_cli-0.1.6}/connector/local/shell.py +0 -0
- {agentlink_cli-0.1.5 → agentlink_cli-0.1.6}/connector/local/terminal.py +0 -0
- {agentlink_cli-0.1.5 → agentlink_cli-0.1.6}/connector/local_ops.py +0 -0
- {agentlink_cli-0.1.5 → agentlink_cli-0.1.6}/connector/local_runtime.py +0 -0
- {agentlink_cli-0.1.5 → agentlink_cli-0.1.6}/connector/logging.py +0 -0
- {agentlink_cli-0.1.5 → agentlink_cli-0.1.6}/connector/perf.py +0 -0
- {agentlink_cli-0.1.5 → agentlink_cli-0.1.6}/connector/protocol.py +0 -0
- {agentlink_cli-0.1.5 → agentlink_cli-0.1.6}/connector/registry.py +0 -0
- {agentlink_cli-0.1.5 → agentlink_cli-0.1.6}/connector/runtime.py +0 -0
- {agentlink_cli-0.1.5 → agentlink_cli-0.1.6}/connector/sync_state.py +0 -0
- {agentlink_cli-0.1.5 → agentlink_cli-0.1.6}/connector/time.py +0 -0
- {agentlink_cli-0.1.5 → agentlink_cli-0.1.6}/run.sh +0 -0
- {agentlink_cli-0.1.5 → agentlink_cli-0.1.6}/tests/__init__.py +0 -0
- {agentlink_cli-0.1.5 → agentlink_cli-0.1.6}/tests/acp/__init__.py +0 -0
- {agentlink_cli-0.1.5 → agentlink_cli-0.1.6}/tests/acp/fake_agent/__init__.py +0 -0
- {agentlink_cli-0.1.5 → agentlink_cli-0.1.6}/tests/acp/fake_agent/__main__.py +0 -0
- {agentlink_cli-0.1.5 → agentlink_cli-0.1.6}/tests/acp/test_acp_adapter_fake.py +0 -0
- {agentlink_cli-0.1.5 → agentlink_cli-0.1.6}/tests/acp/test_acp_reducer_golden.py +0 -0
- {agentlink_cli-0.1.5 → agentlink_cli-0.1.6}/tests/acp/test_config_options.py +0 -0
- {agentlink_cli-0.1.5 → agentlink_cli-0.1.6}/tests/contract/__init__.py +0 -0
- {agentlink_cli-0.1.5 → agentlink_cli-0.1.6}/tests/contract/helpers.py +0 -0
- {agentlink_cli-0.1.5 → agentlink_cli-0.1.6}/tests/test_claude_history_adapter.py +0 -0
- {agentlink_cli-0.1.5 → agentlink_cli-0.1.6}/tests/test_claude_preferences.py +0 -0
- {agentlink_cli-0.1.5 → agentlink_cli-0.1.6}/tests/test_claude_sdk_adapter.py +0 -0
- {agentlink_cli-0.1.5 → agentlink_cli-0.1.6}/tests/test_claude_timeline_parity.py +0 -0
- {agentlink_cli-0.1.5 → agentlink_cli-0.1.6}/tests/test_claude_trust.py +0 -0
- {agentlink_cli-0.1.5 → agentlink_cli-0.1.6}/tests/test_connector_capabilities.py +0 -0
- {agentlink_cli-0.1.5 → agentlink_cli-0.1.6}/tests/test_connector_control.py +0 -0
- {agentlink_cli-0.1.5 → agentlink_cli-0.1.6}/tests/test_connector_json_rpc.py +0 -0
- {agentlink_cli-0.1.5 → agentlink_cli-0.1.6}/tests/test_connector_logging.py +0 -0
- {agentlink_cli-0.1.5 → agentlink_cli-0.1.6}/tests/test_connector_runtime.py +0 -0
- {agentlink_cli-0.1.5 → agentlink_cli-0.1.6}/tests/test_launch_command.py +0 -0
- {agentlink_cli-0.1.5 → agentlink_cli-0.1.6}/tests/test_local_runtime.py +0 -0
- {agentlink_cli-0.1.5 → agentlink_cli-0.1.6}/tests/test_perf.py +0 -0
- {agentlink_cli-0.1.5 → agentlink_cli-0.1.6}/tests/test_terminal_backend.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: agentlink-cli
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.6
|
|
4
4
|
Summary: Local runtime connector for AgentLink
|
|
5
5
|
Requires-Python: >=3.12
|
|
6
6
|
Requires-Dist: claude-agent-sdk
|
|
@@ -44,6 +44,13 @@ Install dependencies:
|
|
|
44
44
|
uv sync
|
|
45
45
|
```
|
|
46
46
|
|
|
47
|
+
Check the installed CLI version:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
agentlink-cli -v
|
|
51
|
+
agentlink-cli --version
|
|
52
|
+
```
|
|
53
|
+
|
|
47
54
|
Start with explicit credentials from the web pairing flow:
|
|
48
55
|
|
|
49
56
|
```bash
|
|
@@ -20,7 +20,7 @@ from connector.local_runtime import (
|
|
|
20
20
|
)
|
|
21
21
|
from connector.logging import install_rpc_log_sink
|
|
22
22
|
from connector.runtime import BackendRpcClient, ConnectorConfig
|
|
23
|
-
|
|
23
|
+
from connector.version import connector_version
|
|
24
24
|
|
|
25
25
|
SHELL_LIFETIME_WARNING = (
|
|
26
26
|
"Note: this connector runs in the current shell session. "
|
|
@@ -69,6 +69,12 @@ class CliError(RuntimeError):
|
|
|
69
69
|
|
|
70
70
|
def _build_parser() -> argparse.ArgumentParser:
|
|
71
71
|
parser = argparse.ArgumentParser(prog="agentlink-cli", description="Agent Server Codex connector CLI")
|
|
72
|
+
parser.add_argument(
|
|
73
|
+
"-v",
|
|
74
|
+
"--version",
|
|
75
|
+
action="version",
|
|
76
|
+
version=f"%(prog)s {connector_version()}",
|
|
77
|
+
)
|
|
72
78
|
subparsers = parser.add_subparsers(dest="command", metavar="{start,pair,configure,rpc}")
|
|
73
79
|
|
|
74
80
|
start = subparsers.add_parser("start", help="start the connector")
|
|
@@ -590,6 +590,24 @@ class CodexAdapter:
|
|
|
590
590
|
"target": target,
|
|
591
591
|
}
|
|
592
592
|
else:
|
|
593
|
+
# A connector restart clears the app-server's in-memory
|
|
594
|
+
# thread set. Resume the requested thread before reading its
|
|
595
|
+
# status so Codex resolves workspace-sensitive information
|
|
596
|
+
# (including Git state) against the thread's workspace.
|
|
597
|
+
try:
|
|
598
|
+
await self._ensure_thread_loaded(thread_id)
|
|
599
|
+
except Exception as exc:
|
|
600
|
+
# Archived/unresumable threads remain readable and status
|
|
601
|
+
# is intentionally a read-only command. Preserve that
|
|
602
|
+
# behavior when app-server refuses to resume them.
|
|
603
|
+
reason = _unresumable_thread_failure_reason(str(exc))
|
|
604
|
+
if reason not in {"archived", "unresumable"}:
|
|
605
|
+
raise
|
|
606
|
+
logger.info(
|
|
607
|
+
"codex status using read-only archived thread thread_id={} reason={}",
|
|
608
|
+
thread_id,
|
|
609
|
+
reason,
|
|
610
|
+
)
|
|
593
611
|
thread = await self.rpc.request(
|
|
594
612
|
"thread/read", {"threadId": thread_id, "includeTurns": False}
|
|
595
613
|
)
|
|
@@ -125,6 +125,7 @@ class ArchivedThreadListRpc(FakeCodexRpc):
|
|
|
125
125
|
class ArchivedResumeRpc(FakeCodexRpc):
|
|
126
126
|
async def request(self, method: str, params: dict[str, Any] | None = None) -> dict[str, Any]:
|
|
127
127
|
if method == "thread/resume":
|
|
128
|
+
self.requests.append((method, params))
|
|
128
129
|
raise RuntimeError(json.dumps({"code": -32600, "message": "thread is archived"}))
|
|
129
130
|
return await super().request(method, params)
|
|
130
131
|
|
|
@@ -1165,12 +1166,37 @@ def test_status_command_returns_thread_and_cached_token_usage() -> None:
|
|
|
1165
1166
|
assert result["status"] == "completed"
|
|
1166
1167
|
assert result["data"]["thread"]["id"] == "thr_1"
|
|
1167
1168
|
assert result["data"]["tokenUsage"]["total"]["totalTokens"] == 42
|
|
1169
|
+
assert ("thread/resume", {"threadId": "thr_1"}) in rpc.requests
|
|
1168
1170
|
assert ("thread/read", {"threadId": "thr_1", "includeTurns": False}) in rpc.requests
|
|
1169
1171
|
assert all(method != "turn/start" for method, _params in rpc.requests)
|
|
1170
1172
|
|
|
1171
1173
|
asyncio.run(exercise())
|
|
1172
1174
|
|
|
1173
1175
|
|
|
1176
|
+
def test_status_command_reads_archived_thread_when_resume_is_rejected() -> None:
|
|
1177
|
+
async def exercise() -> None:
|
|
1178
|
+
rpc = ArchivedResumeRpc()
|
|
1179
|
+
adapter = CodexAdapter(rpc=rpc) # type: ignore[arg-type]
|
|
1180
|
+
await adapter.start()
|
|
1181
|
+
adapter._loaded_thread_ids.clear() # noqa: SLF001
|
|
1182
|
+
|
|
1183
|
+
result = await adapter.execute_command(
|
|
1184
|
+
{
|
|
1185
|
+
"sessionId": "sess_1",
|
|
1186
|
+
"externalSessionId": "thr_1",
|
|
1187
|
+
"command": "status",
|
|
1188
|
+
"clientCommandId": "cmd_status_archived",
|
|
1189
|
+
}
|
|
1190
|
+
)
|
|
1191
|
+
|
|
1192
|
+
assert result["status"] == "completed"
|
|
1193
|
+
assert result["data"]["thread"]["id"] == "thr_1"
|
|
1194
|
+
assert ("thread/resume", {"threadId": "thr_1"}) in rpc.requests
|
|
1195
|
+
assert ("thread/read", {"threadId": "thr_1", "includeTurns": False}) in rpc.requests
|
|
1196
|
+
|
|
1197
|
+
asyncio.run(exercise())
|
|
1198
|
+
|
|
1199
|
+
|
|
1174
1200
|
def test_reducer_normalizes_review_and_compaction_items() -> None:
|
|
1175
1201
|
reducer = TimelineReducer()
|
|
1176
1202
|
reducer.bind_session("sess_1", "thr_1")
|
|
@@ -3,6 +3,8 @@ from __future__ import annotations
|
|
|
3
3
|
import asyncio
|
|
4
4
|
from typing import Any
|
|
5
5
|
|
|
6
|
+
import pytest
|
|
7
|
+
|
|
6
8
|
import connector.cli as cli_module
|
|
7
9
|
from connector.runtime import ConnectorConfig
|
|
8
10
|
|
|
@@ -80,6 +82,17 @@ class FakeBackendRpcClient:
|
|
|
80
82
|
self.started_configs.append(self.config)
|
|
81
83
|
|
|
82
84
|
|
|
85
|
+
@pytest.mark.parametrize("flag", ["-v", "--version"])
|
|
86
|
+
def test_version_flags_print_connector_version(monkeypatch, capsys, flag: str) -> None:
|
|
87
|
+
monkeypatch.setattr(cli_module, "connector_version", lambda: "9.8.7")
|
|
88
|
+
|
|
89
|
+
with pytest.raises(SystemExit) as exc_info:
|
|
90
|
+
cli_module.main([flag])
|
|
91
|
+
|
|
92
|
+
assert exc_info.value.code == 0
|
|
93
|
+
assert capsys.readouterr().out == "agentlink-cli 9.8.7\n"
|
|
94
|
+
|
|
95
|
+
|
|
83
96
|
def test_pair_starts_connector_after_saving_credentials(monkeypatch, tmp_path, capsys) -> None:
|
|
84
97
|
config_path = tmp_path / "connector.json"
|
|
85
98
|
FakeBackendRpcClient.started_configs = []
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|