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.
Files changed (99) hide show
  1. agentnet_cli/cli/__init__.py +1 -0
  2. agentnet_cli/cli/core/__init__.py +1 -0
  3. agentnet_cli/{connect.py → cli/core/connect.py} +4 -4
  4. agentnet_cli/{detect.py → cli/core/detect.py} +5 -5
  5. agentnet_cli/{disconnect.py → cli/core/disconnect.py} +3 -3
  6. agentnet_cli/{register.py → cli/core/register.py} +2 -2
  7. agentnet_cli/{setup.py → cli/core/setup_wizard.py} +20 -16
  8. agentnet_cli/{status.py → cli/core/status.py} +2 -5
  9. agentnet_cli/cli/core/updater.py +294 -0
  10. agentnet_cli/{main.py → cli/main.py} +81 -52
  11. agentnet_cli/cli/marketplace/__init__.py +1 -0
  12. agentnet_cli/cli/marketplace/agent.py +18 -0
  13. agentnet_cli/{commands → cli/marketplace}/discover.py +2 -2
  14. agentnet_cli/cli/marketplace/search.py +124 -0
  15. agentnet_cli/connectors/__init__.py +1 -0
  16. agentnet_cli/{agents → connectors}/claude.py +12 -8
  17. agentnet_cli/{agents → connectors}/codex.py +7 -5
  18. agentnet_cli/{agents → connectors}/copilot.py +5 -1
  19. agentnet_cli/{agents → connectors}/cursor.py +35 -1
  20. agentnet_cli/{agents → connectors}/hermes.py +4 -4
  21. agentnet_cli/connectors/openclaw.py +119 -0
  22. agentnet_cli/{agents → connectors}/registry.py +1 -1
  23. agentnet_cli/connectors/shims.py +18 -0
  24. agentnet_cli/connectors/templates/SKILL.hosted.md +161 -0
  25. agentnet_cli/connectors/templates/codex/skill.md +12 -0
  26. agentnet_cli/connectors/templates/copilot/agentnet.agent.md +16 -0
  27. agentnet_cli/connectors/templates/cursor/agent.md +9 -0
  28. agentnet_cli/connectors/templates/cursor/agentnet.mdc +8 -0
  29. agentnet_cli/connectors/templates/shared/context.md +82 -0
  30. agentnet_cli/connectors/templates/shared/default-chat.md +3 -0
  31. agentnet_cli/connectors/templates/vscode/instructions.md +5 -0
  32. agentnet_cli/{agents → connectors}/vscode.py +1 -1
  33. agentnet_cli/infra/__init__.py +1 -0
  34. agentnet_cli/{manifest.py → infra/manifest.py} +27 -1
  35. agentnet_cli/infra/package_paths.py +20 -0
  36. agentnet_cli/integrations/claude/.claude-plugin/marketplace.json +15 -0
  37. agentnet_cli/integrations/claude/plugin/.claude-plugin/plugin.json +13 -0
  38. agentnet_cli/integrations/claude/plugin/.mcp.json +8 -0
  39. agentnet_cli/integrations/claude/plugin/agents/marketplace.md +23 -0
  40. agentnet_cli/integrations/claude/plugin/hooks/hooks.json +22 -0
  41. agentnet_cli/integrations/claude/plugin/skills/agentnet/SKILL.md +35 -0
  42. agentnet_cli/integrations/openclaw/.mcp.json +10 -0
  43. agentnet_cli/integrations/openclaw/index.js +17 -0
  44. agentnet_cli/integrations/openclaw/openclaw.plugin.json +22 -0
  45. agentnet_cli/integrations/openclaw/package.json +24 -0
  46. agentnet_cli/integrations/openclaw/skills/agentnet/SKILL.md +32 -0
  47. agentnet_cli/integrations/shared/discovery-skill.base.md +82 -0
  48. agentnet_cli/marketplace/__init__.py +5 -0
  49. agentnet_cli/{marketplace.py → marketplace/auth.py} +2 -2
  50. agentnet_cli/marketplace/catalogs/__init__.py +1 -0
  51. agentnet_cli/marketplace/catalogs/claude_marketplace.py +89 -0
  52. agentnet_cli/marketplace/catalogs/clawhub.py +82 -0
  53. agentnet_cli/{platform → marketplace}/client.py +18 -2
  54. agentnet_cli/marketplace/skills/__init__.py +1 -0
  55. agentnet_cli/marketplace/skills/client.py +61 -0
  56. agentnet_cli/marketplace/skills/discovery.py +501 -0
  57. agentnet_cli/marketplace/skills/skillsmp.py +83 -0
  58. agentnet_cli/tools/__init__.py +1 -0
  59. agentnet_cli/tools/handlers.py +164 -0
  60. agentnet_cli/{hermes_plugin → tools/hermes}/__init__.py +6 -5
  61. agentnet_cli/{hermes_plugin → tools/hermes}/handlers.py +21 -12
  62. agentnet_cli/tools/hermes/plugin.yaml +24 -0
  63. agentnet_cli/tools/hermes/schemas.py +172 -0
  64. agentnet_cli/tools/hermes/skills/agentnet/SKILL.md +45 -0
  65. agentnet_cli/{mcp/server.py → tools/mcp_server.py} +112 -36
  66. {agentnet_cli-0.2.0.dist-info → agentnet_cli-0.2.2.dist-info}/METADATA +59 -71
  67. agentnet_cli-0.2.2.dist-info/RECORD +75 -0
  68. {agentnet_cli-0.2.0.dist-info → agentnet_cli-0.2.2.dist-info}/WHEEL +1 -1
  69. agentnet_cli-0.2.2.dist-info/entry_points.txt +5 -0
  70. agentnet_cli/agents/__init__.py +0 -0
  71. agentnet_cli/agents/openclaw.py +0 -54
  72. agentnet_cli/agents/shims.py +0 -9
  73. agentnet_cli/commands/__init__.py +0 -0
  74. agentnet_cli/commands/agent.py +0 -32
  75. agentnet_cli/commands/session.py +0 -35
  76. agentnet_cli/commands/wallet.py +0 -48
  77. agentnet_cli/hermes_plugin/plugin.yaml +0 -17
  78. agentnet_cli/hermes_plugin/schemas.py +0 -182
  79. agentnet_cli/hermes_plugin/skills/agentnet/SKILL.md +0 -46
  80. agentnet_cli/mcp/README.md +0 -64
  81. agentnet_cli/mcp/__init__.py +0 -0
  82. agentnet_cli/mcp/tools.py +0 -67
  83. agentnet_cli/platform/README.md +0 -79
  84. agentnet_cli/platform/__init__.py +0 -0
  85. agentnet_cli/shims/SKILL.md +0 -224
  86. agentnet_cli/shims/codex/skill.md +0 -8
  87. agentnet_cli/shims/copilot/agentnet.agent.md +0 -14
  88. agentnet_cli/shims/cursor/agent.md +0 -9
  89. agentnet_cli/shims/cursor/agentnet.mdc +0 -8
  90. agentnet_cli/shims/shared/context.md +0 -62
  91. agentnet_cli/shims/vscode/instructions.md +0 -3
  92. agentnet_cli/updater.py +0 -123
  93. agentnet_cli-0.2.0.dist-info/RECORD +0 -54
  94. agentnet_cli-0.2.0.dist-info/entry_points.txt +0 -5
  95. /agentnet_cli/{agents → connectors}/README.md +0 -0
  96. /agentnet_cli/{agents → connectors}/base.py +0 -0
  97. /agentnet_cli/{shims → connectors/templates}/README.md +0 -0
  98. /agentnet_cli/{config.py → infra/config.py} +0 -0
  99. /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 .agents.registry import get_connector
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 .agents.base import DetectionResult
4
- from .agents.registry import all_connectors
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 .agents.registry import get_connector
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 .platform.client import PlatformClient
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
- console.print(
47
- f" [bold]Step 3:[/bold] Choose agents to configure "
48
- f"([green]all recommended[/green], {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
-
55
- if connect_all:
56
- connect_command(connect_all=True)
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
- for agent_name in selected:
60
- connect_command(agent_name=agent_name)
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 . import __version__
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 refresh_stale_connections # noqa: PLC0415
35
+ from .core.updater import maybe_auto_update # noqa: PLC0415
36
36
 
37
- refresh_stale_connections(quiet=True)
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 choose which detected agents to configure."""
132
- from .setup import setup_command
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() -> None:
221
- """Check for updates and refresh agent configs."""
222
- from .updater import check_pypi_latest, refresh_stale_connections, self_upgrade # noqa: PLC0415
223
-
224
- console.print()
225
-
226
- latest = check_pypi_latest()
227
- if latest is None:
228
- console.print(" [yellow]![/yellow] Could not reach PyPI — skipping version check")
229
- console.print(" Refreshing agent configs...")
230
- n = refresh_stale_connections(quiet=False)
231
- if not n:
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 latest != __version__:
237
- console.print(f" Updating [bold]{__version__}[/bold] -> [bold]{latest}[/bold]...")
238
- ok, msg = self_upgrade()
239
- if ok:
240
- console.print(f" [green]✓[/green] Upgraded to [bold]{msg}[/bold]")
241
- console.print(" [dim]Agent configs will refresh on next command.[/dim]")
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
- console.print(f" Already on latest version ([bold]{__version__}[/bold])")
247
- n = refresh_stale_connections(quiet=False)
248
- if not n:
249
- console.print(" [dim]All agent configs are up to date.[/dim]")
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 .mcp.server import serve
290
+ from ..tools.mcp_server import serve
258
291
 
259
292
  serve()
260
293
 
261
294
 
262
295
  # -- Marketplace commands --
263
- from .commands.agent import agent as _agent_fn # noqa: E402
264
- from .commands.agent import hire as _hire_fn # noqa: E402
265
- from .commands.discover import agents as _agents_fn # noqa: E402
266
- from .commands.discover import discover as _discover_fn # noqa: E402
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)."""