agentnet-cli 0.2.0__py3-none-any.whl → 0.2.2__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.
- agentnet_cli/cli/__init__.py +1 -0
- agentnet_cli/cli/core/__init__.py +1 -0
- agentnet_cli/{connect.py → cli/core/connect.py} +4 -4
- agentnet_cli/{detect.py → cli/core/detect.py} +5 -5
- agentnet_cli/{disconnect.py → cli/core/disconnect.py} +3 -3
- agentnet_cli/{register.py → cli/core/register.py} +2 -2
- agentnet_cli/{setup.py → cli/core/setup_wizard.py} +20 -16
- agentnet_cli/{status.py → cli/core/status.py} +2 -5
- agentnet_cli/cli/core/updater.py +294 -0
- agentnet_cli/{main.py → cli/main.py} +81 -52
- agentnet_cli/cli/marketplace/__init__.py +1 -0
- agentnet_cli/cli/marketplace/agent.py +18 -0
- agentnet_cli/{commands → cli/marketplace}/discover.py +2 -2
- agentnet_cli/cli/marketplace/search.py +124 -0
- agentnet_cli/connectors/__init__.py +1 -0
- agentnet_cli/{agents → connectors}/claude.py +12 -8
- agentnet_cli/{agents → connectors}/codex.py +7 -5
- agentnet_cli/{agents → connectors}/copilot.py +5 -1
- agentnet_cli/{agents → connectors}/cursor.py +35 -1
- agentnet_cli/{agents → connectors}/hermes.py +4 -4
- agentnet_cli/connectors/openclaw.py +119 -0
- agentnet_cli/{agents → connectors}/registry.py +1 -1
- agentnet_cli/connectors/shims.py +18 -0
- agentnet_cli/connectors/templates/SKILL.hosted.md +161 -0
- agentnet_cli/connectors/templates/codex/skill.md +12 -0
- agentnet_cli/connectors/templates/copilot/agentnet.agent.md +16 -0
- agentnet_cli/connectors/templates/cursor/agent.md +9 -0
- agentnet_cli/connectors/templates/cursor/agentnet.mdc +8 -0
- agentnet_cli/connectors/templates/shared/context.md +82 -0
- agentnet_cli/connectors/templates/shared/default-chat.md +3 -0
- agentnet_cli/connectors/templates/vscode/instructions.md +5 -0
- agentnet_cli/{agents → connectors}/vscode.py +1 -1
- agentnet_cli/infra/__init__.py +1 -0
- agentnet_cli/{manifest.py → infra/manifest.py} +27 -1
- agentnet_cli/infra/package_paths.py +20 -0
- agentnet_cli/integrations/claude/.claude-plugin/marketplace.json +15 -0
- agentnet_cli/integrations/claude/plugin/.claude-plugin/plugin.json +13 -0
- agentnet_cli/integrations/claude/plugin/.mcp.json +8 -0
- agentnet_cli/integrations/claude/plugin/agents/marketplace.md +23 -0
- agentnet_cli/integrations/claude/plugin/hooks/hooks.json +22 -0
- agentnet_cli/integrations/claude/plugin/skills/agentnet/SKILL.md +35 -0
- agentnet_cli/integrations/openclaw/.mcp.json +10 -0
- agentnet_cli/integrations/openclaw/index.js +17 -0
- agentnet_cli/integrations/openclaw/openclaw.plugin.json +22 -0
- agentnet_cli/integrations/openclaw/package.json +24 -0
- agentnet_cli/integrations/openclaw/skills/agentnet/SKILL.md +32 -0
- agentnet_cli/integrations/shared/discovery-skill.base.md +82 -0
- agentnet_cli/marketplace/__init__.py +5 -0
- agentnet_cli/{marketplace.py → marketplace/auth.py} +2 -2
- agentnet_cli/marketplace/catalogs/__init__.py +1 -0
- agentnet_cli/marketplace/catalogs/claude_marketplace.py +89 -0
- agentnet_cli/marketplace/catalogs/clawhub.py +82 -0
- agentnet_cli/{platform → marketplace}/client.py +18 -2
- agentnet_cli/marketplace/skills/__init__.py +1 -0
- agentnet_cli/marketplace/skills/client.py +61 -0
- agentnet_cli/marketplace/skills/discovery.py +501 -0
- agentnet_cli/marketplace/skills/skillsmp.py +83 -0
- agentnet_cli/tools/__init__.py +1 -0
- agentnet_cli/tools/handlers.py +164 -0
- agentnet_cli/{hermes_plugin → tools/hermes}/__init__.py +6 -5
- agentnet_cli/{hermes_plugin → tools/hermes}/handlers.py +21 -12
- agentnet_cli/tools/hermes/plugin.yaml +24 -0
- agentnet_cli/tools/hermes/schemas.py +172 -0
- agentnet_cli/tools/hermes/skills/agentnet/SKILL.md +45 -0
- agentnet_cli/{mcp/server.py → tools/mcp_server.py} +112 -36
- {agentnet_cli-0.2.0.dist-info → agentnet_cli-0.2.2.dist-info}/METADATA +59 -71
- agentnet_cli-0.2.2.dist-info/RECORD +75 -0
- {agentnet_cli-0.2.0.dist-info → agentnet_cli-0.2.2.dist-info}/WHEEL +1 -1
- agentnet_cli-0.2.2.dist-info/entry_points.txt +5 -0
- agentnet_cli/agents/__init__.py +0 -0
- agentnet_cli/agents/openclaw.py +0 -54
- agentnet_cli/agents/shims.py +0 -9
- agentnet_cli/commands/__init__.py +0 -0
- agentnet_cli/commands/agent.py +0 -32
- agentnet_cli/commands/session.py +0 -35
- agentnet_cli/commands/wallet.py +0 -48
- agentnet_cli/hermes_plugin/plugin.yaml +0 -17
- agentnet_cli/hermes_plugin/schemas.py +0 -182
- agentnet_cli/hermes_plugin/skills/agentnet/SKILL.md +0 -46
- agentnet_cli/mcp/README.md +0 -64
- agentnet_cli/mcp/__init__.py +0 -0
- agentnet_cli/mcp/tools.py +0 -67
- agentnet_cli/platform/README.md +0 -79
- agentnet_cli/platform/__init__.py +0 -0
- agentnet_cli/shims/SKILL.md +0 -224
- agentnet_cli/shims/codex/skill.md +0 -8
- agentnet_cli/shims/copilot/agentnet.agent.md +0 -14
- agentnet_cli/shims/cursor/agent.md +0 -9
- agentnet_cli/shims/cursor/agentnet.mdc +0 -8
- agentnet_cli/shims/shared/context.md +0 -62
- agentnet_cli/shims/vscode/instructions.md +0 -3
- agentnet_cli/updater.py +0 -123
- agentnet_cli-0.2.0.dist-info/RECORD +0 -54
- agentnet_cli-0.2.0.dist-info/entry_points.txt +0 -5
- /agentnet_cli/{agents → connectors}/README.md +0 -0
- /agentnet_cli/{agents → connectors}/base.py +0 -0
- /agentnet_cli/{shims → connectors/templates}/README.md +0 -0
- /agentnet_cli/{config.py → infra/config.py} +0 -0
- /agentnet_cli/{paths.py → infra/paths.py} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""CLI entry point and command modules."""
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Core CLI commands: setup, connect, detect, register, status."""
|
|
@@ -2,11 +2,11 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
from rich.console import Console
|
|
4
4
|
|
|
5
|
-
from .
|
|
6
|
-
from .config import load_config
|
|
5
|
+
from ...connectors.registry import get_connector
|
|
6
|
+
from ...infra.config import load_config
|
|
7
7
|
from .detect import detect_all
|
|
8
|
-
from .manifest import record_connection
|
|
9
|
-
from .paths import AgentName, agent_display_name
|
|
8
|
+
from ...infra.manifest import record_connection
|
|
9
|
+
from ...infra.paths import AgentName, agent_display_name
|
|
10
10
|
|
|
11
11
|
console = Console()
|
|
12
12
|
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from .
|
|
4
|
-
from .
|
|
5
|
-
from .config import load_agent_paths
|
|
6
|
-
from .manifest import load_manifest
|
|
7
|
-
from .paths import AgentName, find_agent_binary
|
|
3
|
+
from ...connectors.base import DetectionResult
|
|
4
|
+
from ...connectors.registry import all_connectors
|
|
5
|
+
from ...infra.config import load_agent_paths
|
|
6
|
+
from ...infra.manifest import load_manifest
|
|
7
|
+
from ...infra.paths import AgentName, find_agent_binary
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
def detect_all() -> list[DetectionResult]:
|
|
@@ -2,9 +2,9 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
from rich.console import Console
|
|
4
4
|
|
|
5
|
-
from .
|
|
6
|
-
from .manifest import load_manifest, remove_connection
|
|
7
|
-
from .paths import AgentName, agent_display_name
|
|
5
|
+
from ...connectors.registry import get_connector
|
|
6
|
+
from ...infra.manifest import load_manifest, remove_connection
|
|
7
|
+
from ...infra.paths import AgentName, agent_display_name
|
|
8
8
|
|
|
9
9
|
console = Console()
|
|
10
10
|
|
|
@@ -10,8 +10,8 @@ import typer
|
|
|
10
10
|
from rich.console import Console
|
|
11
11
|
from rich.table import Table
|
|
12
12
|
|
|
13
|
-
from .config import load_config, save_config
|
|
14
|
-
from .
|
|
13
|
+
from ...infra.config import load_config, save_config
|
|
14
|
+
from ...marketplace.client import PlatformClient
|
|
15
15
|
|
|
16
16
|
console = Console()
|
|
17
17
|
|
|
@@ -10,16 +10,16 @@ import typer
|
|
|
10
10
|
from rich.console import Console
|
|
11
11
|
from rich.table import Table
|
|
12
12
|
|
|
13
|
-
from .config import load_config
|
|
13
|
+
from ...infra.config import load_config
|
|
14
14
|
from .connect import connect_command
|
|
15
15
|
from .detect import detect_all
|
|
16
|
-
from .paths import AgentName, agent_display_name
|
|
16
|
+
from ...infra.paths import AgentName, agent_display_name
|
|
17
17
|
from .register import default_agent_name, register_command
|
|
18
18
|
|
|
19
19
|
console = Console()
|
|
20
20
|
|
|
21
21
|
|
|
22
|
-
def setup_command(platform_url: str | None = None) -> None:
|
|
22
|
+
def setup_command(platform_url: str | None = None, *, choose: bool = False) -> None:
|
|
23
23
|
config = load_config()
|
|
24
24
|
if not config or not config.get("api_token"):
|
|
25
25
|
console.print()
|
|
@@ -43,21 +43,25 @@ def setup_command(platform_url: str | None = None) -> None:
|
|
|
43
43
|
return
|
|
44
44
|
|
|
45
45
|
console.print()
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
46
|
+
if choose:
|
|
47
|
+
console.print(
|
|
48
|
+
f" [bold]Step 3:[/bold] Choose agents to configure ({len(targets)} available)"
|
|
49
|
+
)
|
|
50
|
+
selected, connect_all = _select_targets(targets)
|
|
51
|
+
if not selected:
|
|
52
|
+
console.print("\n [dim]No agents configured.[/dim]\n")
|
|
53
|
+
return
|
|
54
|
+
if connect_all:
|
|
55
|
+
connect_command(connect_all=True)
|
|
56
|
+
return
|
|
57
|
+
for agent_name in selected:
|
|
58
|
+
connect_command(agent_name=agent_name)
|
|
57
59
|
return
|
|
58
60
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
+
console.print(
|
|
62
|
+
f" [bold]Step 3:[/bold] Configuring all detected agents ({len(targets)})"
|
|
63
|
+
)
|
|
64
|
+
connect_command(connect_all=True)
|
|
61
65
|
|
|
62
66
|
|
|
63
67
|
def _available_targets(results) -> list[str]:
|
|
@@ -3,9 +3,9 @@ from __future__ import annotations
|
|
|
3
3
|
from rich.console import Console
|
|
4
4
|
from rich.table import Table
|
|
5
5
|
|
|
6
|
-
from .config import load_config
|
|
6
|
+
from ...infra.config import load_config
|
|
7
7
|
from .detect import detect_all
|
|
8
|
-
from .paths import AgentName, agent_display_name, short_path
|
|
8
|
+
from ...infra.paths import AgentName, agent_display_name, short_path
|
|
9
9
|
|
|
10
10
|
console = Console()
|
|
11
11
|
|
|
@@ -23,9 +23,6 @@ def status_command() -> None:
|
|
|
23
23
|
console.print(f" URL: {config.get('platform_url')}")
|
|
24
24
|
token = config.get("api_token", "")
|
|
25
25
|
console.print(f" Token: [dim]...{token[-6:]}[/dim]" if len(token) > 6 else " Token: [dim]configured[/dim]")
|
|
26
|
-
if config.get("wallet_id"):
|
|
27
|
-
console.print(f" Wallet: {config['wallet_id']}")
|
|
28
|
-
|
|
29
26
|
results = detect_all()
|
|
30
27
|
detected_count = sum(1 for r in results if r.detected)
|
|
31
28
|
connected_count = sum(1 for r in results if r.already_connected)
|
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import re
|
|
5
|
+
import shutil
|
|
6
|
+
import subprocess
|
|
7
|
+
import sys
|
|
8
|
+
from dataclasses import dataclass
|
|
9
|
+
|
|
10
|
+
from rich.console import Console
|
|
11
|
+
|
|
12
|
+
from agentnet_cli import __version__
|
|
13
|
+
from ...connectors.registry import get_connector
|
|
14
|
+
from ...infra.config import load_config
|
|
15
|
+
from ...infra.manifest import load_manifest, record_connection, record_update_check, should_check_for_update
|
|
16
|
+
from ...infra.paths import AgentName
|
|
17
|
+
|
|
18
|
+
_err = Console(stderr=True)
|
|
19
|
+
|
|
20
|
+
_DEFAULT_CHECK_INTERVAL_HOURS = 24.0
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@dataclass
|
|
24
|
+
class AutoUpdateResult:
|
|
25
|
+
checked: bool = False
|
|
26
|
+
upgrade_started: bool = False
|
|
27
|
+
upgraded: bool = False
|
|
28
|
+
refreshed: int = 0
|
|
29
|
+
message: str | None = None
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def _auto_update_enabled() -> bool:
|
|
33
|
+
return os.environ.get("AGENTNET_AUTO_UPDATE", "1").strip().lower() not in {"0", "false", "no"}
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def _check_interval_hours() -> float:
|
|
37
|
+
raw = os.environ.get("AGENTNET_UPDATE_CHECK_INTERVAL_HOURS", "").strip()
|
|
38
|
+
if not raw:
|
|
39
|
+
return _DEFAULT_CHECK_INTERVAL_HOURS
|
|
40
|
+
try:
|
|
41
|
+
return max(0.0, float(raw))
|
|
42
|
+
except ValueError:
|
|
43
|
+
return _DEFAULT_CHECK_INTERVAL_HOURS
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def refresh_stale_connections(*, quiet: bool = False) -> int:
|
|
47
|
+
"""Re-run connect() for agents whose manifest cli_version != current version."""
|
|
48
|
+
config = load_config()
|
|
49
|
+
if not config or not config.get("api_token"):
|
|
50
|
+
return 0
|
|
51
|
+
|
|
52
|
+
manifest = load_manifest()
|
|
53
|
+
connections = manifest.get("connections", {})
|
|
54
|
+
if not connections:
|
|
55
|
+
return 0
|
|
56
|
+
|
|
57
|
+
refreshed = 0
|
|
58
|
+
for agent_name, conn_info in list(connections.items()):
|
|
59
|
+
if conn_info.get("cli_version") == __version__:
|
|
60
|
+
continue
|
|
61
|
+
|
|
62
|
+
try:
|
|
63
|
+
agent_enum = AgentName(agent_name)
|
|
64
|
+
connector = get_connector(agent_enum)
|
|
65
|
+
detection = connector.detect()
|
|
66
|
+
if not detection.detected:
|
|
67
|
+
continue
|
|
68
|
+
|
|
69
|
+
result = connector.connect(config)
|
|
70
|
+
if result.success:
|
|
71
|
+
record_connection(
|
|
72
|
+
agent_name,
|
|
73
|
+
files_created=result.files_created,
|
|
74
|
+
files_modified=result.files_modified,
|
|
75
|
+
mcp_entry=result.mcp_entry,
|
|
76
|
+
)
|
|
77
|
+
refreshed += 1
|
|
78
|
+
else:
|
|
79
|
+
print(f"Warning: refresh for {agent_name} returned success=False", file=sys.stderr)
|
|
80
|
+
except (OSError, ValueError, KeyError) as exc:
|
|
81
|
+
print(f"Warning: failed to refresh {agent_name}: {exc}", file=sys.stderr)
|
|
82
|
+
continue
|
|
83
|
+
|
|
84
|
+
if refreshed and not quiet:
|
|
85
|
+
_err.print(
|
|
86
|
+
f" [dim]Refreshed {refreshed} agent config(s) for v{__version__}[/dim]"
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
return refreshed
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def check_pypi_latest() -> str | None:
|
|
93
|
+
"""Check PyPI for the latest published version."""
|
|
94
|
+
try:
|
|
95
|
+
import httpx # noqa: PLC0415
|
|
96
|
+
|
|
97
|
+
resp = httpx.get(
|
|
98
|
+
"https://pypi.org/pypi/agentnet-cli/json",
|
|
99
|
+
timeout=5.0,
|
|
100
|
+
follow_redirects=True,
|
|
101
|
+
)
|
|
102
|
+
if resp.status_code == 200:
|
|
103
|
+
return resp.json()["info"]["version"]
|
|
104
|
+
except Exception:
|
|
105
|
+
pass
|
|
106
|
+
return None
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def detect_install_method() -> str:
|
|
110
|
+
"""Human-readable label for how this install will be upgraded."""
|
|
111
|
+
cmd = _upgrade_command()
|
|
112
|
+
if cmd[:2] == ["uv", "tool"]:
|
|
113
|
+
return "uv tool"
|
|
114
|
+
if cmd[0] == "pipx":
|
|
115
|
+
return "pipx"
|
|
116
|
+
if cmd[0] == "npm":
|
|
117
|
+
return "npm"
|
|
118
|
+
return "pip"
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def self_upgrade(*, background: bool = False, verbose: bool = False) -> tuple[bool, str]:
|
|
122
|
+
"""Upgrade agentnet-cli to latest. Returns (success, message)."""
|
|
123
|
+
cmd = _upgrade_command()
|
|
124
|
+
try:
|
|
125
|
+
if background:
|
|
126
|
+
subprocess.Popen( # noqa: S603
|
|
127
|
+
cmd,
|
|
128
|
+
stdout=subprocess.DEVNULL,
|
|
129
|
+
stderr=subprocess.DEVNULL,
|
|
130
|
+
start_new_session=True,
|
|
131
|
+
)
|
|
132
|
+
latest = check_pypi_latest()
|
|
133
|
+
return True, latest or "latest"
|
|
134
|
+
|
|
135
|
+
if verbose:
|
|
136
|
+
result = subprocess.run(cmd, timeout=300) # noqa: S603
|
|
137
|
+
detail = ""
|
|
138
|
+
else:
|
|
139
|
+
result = subprocess.run(cmd, capture_output=True, text=True, timeout=120) # noqa: S603
|
|
140
|
+
detail = result.stderr.strip()[:200]
|
|
141
|
+
|
|
142
|
+
if result.returncode == 0:
|
|
143
|
+
latest = check_pypi_latest()
|
|
144
|
+
return True, latest or "latest"
|
|
145
|
+
return False, detail or f"exit code {result.returncode}"
|
|
146
|
+
except Exception as e:
|
|
147
|
+
return False, str(e)
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def _spawn_refresh_with_upgraded_binary(*, quiet: bool = False) -> int:
|
|
151
|
+
"""Re-invoke the upgraded agentnet binary so integrations refresh at the new version."""
|
|
152
|
+
agentnet_bin = shutil.which("agentnet")
|
|
153
|
+
args = ["update", "--refresh-only"]
|
|
154
|
+
if quiet:
|
|
155
|
+
args.append("--quiet")
|
|
156
|
+
if agentnet_bin:
|
|
157
|
+
proc = subprocess.run([agentnet_bin, *args], timeout=120) # noqa: S603
|
|
158
|
+
return proc.returncode
|
|
159
|
+
return 0
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
def clean_update(*, quiet: bool = False, refresh_only: bool = False) -> AutoUpdateResult:
|
|
163
|
+
"""User-facing update: upgrade the package, then refresh integrations from the new install."""
|
|
164
|
+
if refresh_only:
|
|
165
|
+
refreshed = refresh_stale_connections(quiet=quiet)
|
|
166
|
+
return AutoUpdateResult(checked=True, refreshed=refreshed)
|
|
167
|
+
|
|
168
|
+
result = AutoUpdateResult(checked=True)
|
|
169
|
+
latest = check_pypi_latest()
|
|
170
|
+
record_update_check()
|
|
171
|
+
|
|
172
|
+
if latest is None:
|
|
173
|
+
result.message = "Could not reach PyPI"
|
|
174
|
+
result.refreshed = refresh_stale_connections(quiet=quiet)
|
|
175
|
+
return result
|
|
176
|
+
|
|
177
|
+
if latest == __version__:
|
|
178
|
+
result.message = f"Already on latest version ({__version__})"
|
|
179
|
+
result.refreshed = refresh_stale_connections(quiet=quiet)
|
|
180
|
+
return result
|
|
181
|
+
|
|
182
|
+
method = detect_install_method()
|
|
183
|
+
if not quiet:
|
|
184
|
+
_err.print(
|
|
185
|
+
f" Upgrading [bold]{__version__}[/bold] → [bold]{latest}[/bold] via {method}..."
|
|
186
|
+
)
|
|
187
|
+
|
|
188
|
+
ok, msg = self_upgrade(background=False, verbose=not quiet)
|
|
189
|
+
if not ok:
|
|
190
|
+
result.message = f"Upgrade failed: {msg}"
|
|
191
|
+
return result
|
|
192
|
+
|
|
193
|
+
result.upgraded = True
|
|
194
|
+
result.message = f"Upgraded to {msg}"
|
|
195
|
+
record_update_check(upgraded_to=msg)
|
|
196
|
+
|
|
197
|
+
if not quiet:
|
|
198
|
+
_err.print(" [dim]Refreshing agent integrations...[/dim]")
|
|
199
|
+
|
|
200
|
+
_spawn_refresh_with_upgraded_binary(quiet=quiet)
|
|
201
|
+
return result
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
def run_update(*, quiet: bool = False, background: bool = False, force: bool = False) -> AutoUpdateResult:
|
|
205
|
+
"""Check PyPI, upgrade if needed, then refresh stale agent integrations."""
|
|
206
|
+
result = AutoUpdateResult()
|
|
207
|
+
interval = _check_interval_hours()
|
|
208
|
+
|
|
209
|
+
if not force and not should_check_for_update(interval):
|
|
210
|
+
result.refreshed = refresh_stale_connections(quiet=quiet)
|
|
211
|
+
return result
|
|
212
|
+
|
|
213
|
+
result.checked = True
|
|
214
|
+
latest = check_pypi_latest()
|
|
215
|
+
record_update_check()
|
|
216
|
+
|
|
217
|
+
if latest is None:
|
|
218
|
+
result.message = "Could not reach PyPI"
|
|
219
|
+
result.refreshed = refresh_stale_connections(quiet=quiet)
|
|
220
|
+
if not quiet:
|
|
221
|
+
_err.print(" [yellow]![/yellow] Could not reach PyPI — skipping version check")
|
|
222
|
+
return result
|
|
223
|
+
|
|
224
|
+
if _auto_update_enabled() and latest != __version__:
|
|
225
|
+
ok, msg = self_upgrade(background=background)
|
|
226
|
+
if ok:
|
|
227
|
+
if background:
|
|
228
|
+
result.upgrade_started = True
|
|
229
|
+
result.message = f"Upgrade to {msg} started in background"
|
|
230
|
+
else:
|
|
231
|
+
result.upgraded = True
|
|
232
|
+
result.message = f"Upgraded to {msg}"
|
|
233
|
+
record_update_check(upgraded_to=msg)
|
|
234
|
+
else:
|
|
235
|
+
result.message = f"Upgrade failed: {msg}"
|
|
236
|
+
if not quiet:
|
|
237
|
+
_err.print(f" [red]✗[/red] Upgrade failed: {msg}")
|
|
238
|
+
elif not quiet and latest == __version__:
|
|
239
|
+
result.message = f"Already on latest version ({__version__})"
|
|
240
|
+
|
|
241
|
+
result.refreshed = refresh_stale_connections(quiet=quiet)
|
|
242
|
+
return result
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
def maybe_auto_update(*, quiet: bool = True) -> AutoUpdateResult:
|
|
246
|
+
"""Rate-limited silent auto-update used by CLI callback and MCP startup."""
|
|
247
|
+
if not _auto_update_enabled():
|
|
248
|
+
refreshed = refresh_stale_connections(quiet=quiet)
|
|
249
|
+
return AutoUpdateResult(refreshed=refreshed)
|
|
250
|
+
return run_update(quiet=quiet, background=True)
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
def _upgrade_command() -> list[str]:
|
|
254
|
+
"""Detect install method and return the right upgrade command."""
|
|
255
|
+
if shutil.which("uv"):
|
|
256
|
+
try:
|
|
257
|
+
r = subprocess.run(
|
|
258
|
+
["uv", "tool", "list"],
|
|
259
|
+
capture_output=True,
|
|
260
|
+
text=True,
|
|
261
|
+
timeout=10,
|
|
262
|
+
)
|
|
263
|
+
if re.search(r"^agentnet-cli\b", r.stdout, re.MULTILINE):
|
|
264
|
+
return ["uv", "tool", "upgrade", "agentnet-cli"]
|
|
265
|
+
except Exception:
|
|
266
|
+
pass
|
|
267
|
+
|
|
268
|
+
if shutil.which("pipx"):
|
|
269
|
+
try:
|
|
270
|
+
r = subprocess.run(
|
|
271
|
+
["pipx", "list", "--short"],
|
|
272
|
+
capture_output=True,
|
|
273
|
+
text=True,
|
|
274
|
+
timeout=10,
|
|
275
|
+
)
|
|
276
|
+
if re.search(r"^agentnet-cli\b", r.stdout, re.MULTILINE):
|
|
277
|
+
return ["pipx", "upgrade", "agentnet-cli"]
|
|
278
|
+
except Exception:
|
|
279
|
+
pass
|
|
280
|
+
|
|
281
|
+
if shutil.which("npm"):
|
|
282
|
+
try:
|
|
283
|
+
r = subprocess.run(
|
|
284
|
+
["npm", "list", "-g", "--depth=0", "agentnet-cli"],
|
|
285
|
+
capture_output=True,
|
|
286
|
+
text=True,
|
|
287
|
+
timeout=10,
|
|
288
|
+
)
|
|
289
|
+
if re.search(r"^agentnet-cli@", r.stdout, re.MULTILINE):
|
|
290
|
+
return ["npm", "install", "-g", "agentnet-cli@latest"]
|
|
291
|
+
except Exception:
|
|
292
|
+
pass
|
|
293
|
+
|
|
294
|
+
return [sys.executable, "-m", "pip", "install", "--upgrade", "agentnet-cli"]
|
|
@@ -8,7 +8,7 @@ import typer
|
|
|
8
8
|
from rich.console import Console
|
|
9
9
|
from rich.table import Table
|
|
10
10
|
|
|
11
|
-
from
|
|
11
|
+
from agentnet_cli import __version__
|
|
12
12
|
|
|
13
13
|
app = typer.Typer(
|
|
14
14
|
name="agentnet",
|
|
@@ -32,9 +32,9 @@ def main(
|
|
|
32
32
|
) -> None:
|
|
33
33
|
"""Discover AI coding agents on your system and connect them to the Agent-net marketplace."""
|
|
34
34
|
try:
|
|
35
|
-
from .updater import
|
|
35
|
+
from .core.updater import maybe_auto_update # noqa: PLC0415
|
|
36
36
|
|
|
37
|
-
|
|
37
|
+
maybe_auto_update(quiet=True)
|
|
38
38
|
except Exception:
|
|
39
39
|
pass
|
|
40
40
|
|
|
@@ -48,8 +48,8 @@ def main(
|
|
|
48
48
|
@app.command()
|
|
49
49
|
def detect() -> None:
|
|
50
50
|
"""Scan your system for installed AI coding agents."""
|
|
51
|
-
from .detect import detect_all
|
|
52
|
-
from .paths import AgentName, agent_display_name, short_path
|
|
51
|
+
from .core.detect import detect_all
|
|
52
|
+
from ..infra.paths import AgentName, agent_display_name, short_path
|
|
53
53
|
|
|
54
54
|
results = detect_all()
|
|
55
55
|
detected_count = sum(1 for r in results if r.detected)
|
|
@@ -117,7 +117,7 @@ def register(
|
|
|
117
117
|
),
|
|
118
118
|
) -> None:
|
|
119
119
|
"""Sign in through the browser and register a CLI identity."""
|
|
120
|
-
from .register import register_command
|
|
120
|
+
from .core.register import register_command
|
|
121
121
|
|
|
122
122
|
register_command(platform_url=url)
|
|
123
123
|
|
|
@@ -127,11 +127,16 @@ def setup(
|
|
|
127
127
|
url: Optional[str] = typer.Option(
|
|
128
128
|
None, "--url", help="Platform URL (default: https://app.agentnet.market)",
|
|
129
129
|
),
|
|
130
|
+
choose: bool = typer.Option(
|
|
131
|
+
False,
|
|
132
|
+
"--choose",
|
|
133
|
+
help="Interactively choose which detected agents to configure",
|
|
134
|
+
),
|
|
130
135
|
) -> None:
|
|
131
|
-
"""Sign in and
|
|
132
|
-
from .
|
|
136
|
+
"""Sign in and configure all detected agents (use --choose to pick individually)."""
|
|
137
|
+
from .core.setup_wizard import setup_command
|
|
133
138
|
|
|
134
|
-
setup_command(platform_url=url)
|
|
139
|
+
setup_command(platform_url=url, choose=choose)
|
|
135
140
|
|
|
136
141
|
|
|
137
142
|
@app.command()
|
|
@@ -142,7 +147,7 @@ def connect(
|
|
|
142
147
|
all_agents: bool = typer.Option(False, "--all", help="Connect all detected agents"),
|
|
143
148
|
) -> None:
|
|
144
149
|
"""Connect an agent to the Agent-net marketplace via MCP."""
|
|
145
|
-
from .connect import connect_command
|
|
150
|
+
from .core.connect import connect_command
|
|
146
151
|
|
|
147
152
|
connect_command(agent_name=agent, connect_all=all_agents)
|
|
148
153
|
|
|
@@ -153,7 +158,7 @@ def disconnect(
|
|
|
153
158
|
all_agents: bool = typer.Option(False, "--all", help="Disconnect all connected agents"),
|
|
154
159
|
) -> None:
|
|
155
160
|
"""Remove an agent's connection to Agent-net."""
|
|
156
|
-
from .disconnect import disconnect_command
|
|
161
|
+
from .core.disconnect import disconnect_command
|
|
157
162
|
|
|
158
163
|
disconnect_command(agent_name=agent, disconnect_all=all_agents)
|
|
159
164
|
|
|
@@ -161,7 +166,7 @@ def disconnect(
|
|
|
161
166
|
@app.command()
|
|
162
167
|
def status() -> None:
|
|
163
168
|
"""Show registration and agent connection status."""
|
|
164
|
-
from .status import status_command
|
|
169
|
+
from .core.status import status_command
|
|
165
170
|
|
|
166
171
|
status_command()
|
|
167
172
|
|
|
@@ -176,8 +181,8 @@ def set_path(
|
|
|
176
181
|
"""Set a custom binary path for an agent."""
|
|
177
182
|
from pathlib import Path as P
|
|
178
183
|
|
|
179
|
-
from .config import save_agent_path
|
|
180
|
-
from .paths import AgentName, agent_display_name
|
|
184
|
+
from ..infra.config import save_agent_path
|
|
185
|
+
from ..infra.paths import AgentName, agent_display_name
|
|
181
186
|
|
|
182
187
|
try:
|
|
183
188
|
display = agent_display_name(AgentName(agent))
|
|
@@ -200,8 +205,8 @@ def clear_path(
|
|
|
200
205
|
agent: str = typer.Argument(help="Agent name to clear custom path for"),
|
|
201
206
|
) -> None:
|
|
202
207
|
"""Remove a custom binary path and revert to auto-detection."""
|
|
203
|
-
from .config import remove_agent_path
|
|
204
|
-
from .paths import AgentName, agent_display_name
|
|
208
|
+
from ..infra.config import remove_agent_path
|
|
209
|
+
from ..infra.paths import AgentName, agent_display_name
|
|
205
210
|
|
|
206
211
|
try:
|
|
207
212
|
display = agent_display_name(AgentName(agent))
|
|
@@ -217,36 +222,64 @@ def clear_path(
|
|
|
217
222
|
|
|
218
223
|
|
|
219
224
|
@app.command()
|
|
220
|
-
def update(
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
225
|
+
def update(
|
|
226
|
+
quiet: bool = typer.Option(False, "--quiet", "-q", help="Suppress non-error output"),
|
|
227
|
+
background: bool = typer.Option(
|
|
228
|
+
False,
|
|
229
|
+
"--background",
|
|
230
|
+
help="Start upgrade in background (integrations refresh on next run)",
|
|
231
|
+
),
|
|
232
|
+
refresh_only: bool = typer.Option(
|
|
233
|
+
False,
|
|
234
|
+
"--refresh-only",
|
|
235
|
+
hidden=True,
|
|
236
|
+
help="Internal: refresh agent integrations at the current installed version",
|
|
237
|
+
),
|
|
238
|
+
) -> None:
|
|
239
|
+
"""Upgrade agentnet-cli and refresh connected agent integrations."""
|
|
240
|
+
from .core.updater import clean_update, run_update # noqa: PLC0415
|
|
241
|
+
|
|
242
|
+
if refresh_only:
|
|
243
|
+
result = clean_update(quiet=quiet, refresh_only=True)
|
|
244
|
+
if not quiet and result.refreshed:
|
|
245
|
+
console.print(f" [green]✓[/green] Refreshed {result.refreshed} agent config(s)")
|
|
246
|
+
elif not quiet:
|
|
232
247
|
console.print(" [dim]All agent configs are up to date.[/dim]")
|
|
233
|
-
console.print()
|
|
234
248
|
return
|
|
235
249
|
|
|
236
|
-
if
|
|
237
|
-
console.print(
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
else:
|
|
243
|
-
console.print(f" [red]✗[/red] Upgrade failed: {msg}")
|
|
244
|
-
console.print(" [dim]Try manually: pip install --upgrade agentnet-cli[/dim]")
|
|
250
|
+
if not quiet:
|
|
251
|
+
console.print()
|
|
252
|
+
console.print(" [dim]Checking PyPI for updates...[/dim]")
|
|
253
|
+
|
|
254
|
+
if background:
|
|
255
|
+
result = run_update(quiet=quiet, background=True, force=True)
|
|
245
256
|
else:
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
257
|
+
result = clean_update(quiet=quiet)
|
|
258
|
+
|
|
259
|
+
if quiet:
|
|
260
|
+
if result.message and not result.upgraded and not result.upgrade_started:
|
|
261
|
+
print(result.message, file=sys.stderr)
|
|
262
|
+
return
|
|
263
|
+
|
|
264
|
+
if result.upgrade_started:
|
|
265
|
+
console.print(f" [green]✓[/green] {result.message}")
|
|
266
|
+
console.print(" [dim]Restart your agent to pick up the new version.[/dim]")
|
|
267
|
+
elif result.upgraded:
|
|
268
|
+
console.print(f" [green]✓[/green] {result.message}")
|
|
269
|
+
console.print(" [dim]Agent integrations refreshed.[/dim]")
|
|
270
|
+
elif result.message and "failed" in result.message.lower():
|
|
271
|
+
console.print(f" [red]✗[/red] {result.message}")
|
|
272
|
+
method = "pip install --upgrade agentnet-cli"
|
|
273
|
+
console.print(f" [dim]Try manually: {method}[/dim]")
|
|
274
|
+
elif result.message == "Could not reach PyPI":
|
|
275
|
+
console.print(" [yellow]![/yellow] Could not reach PyPI — refreshing local configs only")
|
|
276
|
+
elif result.message:
|
|
277
|
+
console.print(f" {result.message}")
|
|
278
|
+
|
|
279
|
+
if result.refreshed and not result.upgraded:
|
|
280
|
+
console.print(f" [dim]Refreshed {result.refreshed} agent config(s).[/dim]")
|
|
281
|
+
elif result.checked and not result.upgraded and not result.upgrade_started and not result.refreshed:
|
|
282
|
+
console.print(" [dim]All agent configs are up to date.[/dim]")
|
|
250
283
|
|
|
251
284
|
console.print()
|
|
252
285
|
|
|
@@ -254,22 +287,18 @@ def update() -> None:
|
|
|
254
287
|
@app.command(name="mcp-serve", hidden=True)
|
|
255
288
|
def mcp_serve() -> None:
|
|
256
289
|
"""Start the AgentNet MCP server (internal)."""
|
|
257
|
-
from .
|
|
290
|
+
from ..tools.mcp_server import serve
|
|
258
291
|
|
|
259
292
|
serve()
|
|
260
293
|
|
|
261
294
|
|
|
262
295
|
# -- Marketplace commands --
|
|
263
|
-
from .
|
|
264
|
-
from .
|
|
265
|
-
from .
|
|
266
|
-
from .
|
|
267
|
-
from .commands.session import session_app # noqa: E402
|
|
268
|
-
from .commands.wallet import wallet_app # noqa: E402
|
|
296
|
+
from .marketplace.agent import agent as _agent_fn # noqa: E402
|
|
297
|
+
from .marketplace.discover import agents as _agents_fn # noqa: E402
|
|
298
|
+
from .marketplace.discover import discover as _discover_fn # noqa: E402
|
|
299
|
+
from .marketplace.search import search as _search_fn # noqa: E402
|
|
269
300
|
|
|
301
|
+
app.command(name="search")(_search_fn)
|
|
270
302
|
app.command(name="discover")(_discover_fn)
|
|
271
303
|
app.command(name="agents")(_agents_fn)
|
|
272
304
|
app.command(name="agent")(_agent_fn)
|
|
273
|
-
app.command(name="hire")(_hire_fn)
|
|
274
|
-
app.add_typer(wallet_app, name="wallet")
|
|
275
|
-
app.add_typer(session_app, name="session")
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Marketplace discovery commands (JSON output)."""
|