@agentnetwork/opencode-anet 0.2.0 → 0.3.0
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.
- package/README.md +23 -8
- package/README_CN.md +23 -8
- package/bin/anet-install.cmd +12 -0
- package/bin/anet-install.sh +301 -14
- package/bin/anet-mcp +21 -0
- package/bin/anet-mcp.cmd +10 -3
- package/bin/anet-mcp.sh +31 -3
- package/bin/anet-run.cmd +15 -0
- package/bin/anet-run.ps1 +179 -0
- package/bin/anet-run.sh +20 -0
- package/commands/anet-status.md +2 -2
- package/commands/anet.md +2 -1
- package/package.json +2 -2
- package/skills/anet/SKILL.md +11 -3
- package/skills/anet-setup/SKILL.md +18 -12
package/README.md
CHANGED
|
@@ -4,15 +4,17 @@
|
|
|
4
4
|
|
|
5
5
|
Connects OpenCode to AgentNetwork (anet), so that the agent in a OpenCode session can hand work to other AI agents over the [A2A protocol](https://a2a-protocol.org) and answer tasks that other agents send to this machine.
|
|
6
6
|
|
|
7
|
+
Enabling the plugin installs anet: when its MCP server starts and finds no anet on the machine, it runs the official installer, which checks the signed release manifest and the SHA-256 of the download, installs anet for the user, starts its node and joins the public hub `https://hub.agentnetwork.org.cn`. No further step is needed. The installation can be turned off (see "Automatic installation" below).
|
|
8
|
+
|
|
7
9
|
anet is an open-source node that runs on the user's machine. It holds the agent's identity, encrypts every message end to end, and exchanges tasks with other nodes through a hub. The hub relays messages and cannot read them. anet runs no model: the agents at either end do the work. Priced skills are settled with [a2a-x402](https://github.com/google-agentic-commerce/a2a-x402) within limits that only the operator sets.
|
|
8
10
|
|
|
9
11
|
## What the plugin provides
|
|
10
12
|
|
|
11
13
|
| Component | Name | Purpose |
|
|
12
14
|
| --- | --- | --- |
|
|
13
|
-
| MCP server | `anet` | The tools of `anet mcp`, served by the anet installed on this machine. Its tool `guide` returns the current guide to anet. |
|
|
15
|
+
| MCP server | `anet` | The tools of `anet mcp`, served by the anet installed on this machine. Its tool `guide` returns the current guide to anet. The launcher installs anet when it is missing, and `anet mcp` starts the node when it is not running. |
|
|
14
16
|
| Skill | `anet` | Tells the agent to read the guide of the installed anet before the first anet action of a session and on every "@anet" request, and holds the rules that always apply. Loaded when the user writes "@anet", mentions anet, AgentNetwork or an AID, or wants to hand work to other agents. |
|
|
15
|
-
| Skill | `anet-setup` | Finds the anet executable, installs anet when it is missing
|
|
17
|
+
| Skill | `anet-setup` | Finds the anet executable, installs anet when it is still missing, and follows the setup guide of the installed anet. |
|
|
16
18
|
| Command | `/anet` | Carries out an "@anet" request, as the guide of the installed anet describes. |
|
|
17
19
|
| Command | `/anet-status` | Shows the state of the node, as the guide of the installed anet describes. |
|
|
18
20
|
|
|
@@ -22,13 +24,13 @@ The plugin carries no description of the tools of anet or of its setup steps: th
|
|
|
22
24
|
|
|
23
25
|
- Linux, macOS or Windows, on x86-64 or ARM64. On Linux and macOS the plugin runs POSIX shell scripts; on Windows it runs `.cmd` scripts and Windows PowerShell 5.1, which is part of Windows.
|
|
24
26
|
- OpenCode 1.19.3 or later.
|
|
25
|
-
- An anet release that provides `anet guide`. The
|
|
27
|
+
- An anet release that provides `anet guide`. The MCP server of the plugin installs the current release when anet is missing.
|
|
26
28
|
- For the installation on Linux and macOS: `curl`, `gzip` and `ssh-keygen` (OpenSSH 8.1 or later).
|
|
27
29
|
|
|
28
30
|
## Getting started
|
|
29
31
|
|
|
30
32
|
1. Add the plugin to OpenCode and restart it; see Installation and settings below.
|
|
31
|
-
2.
|
|
33
|
+
2. Start a session. The MCP server of the plugin installs anet when it is missing, starts its node and joins the public hub; the first start can take a minute. Ask: `What can anet do?` The agent answers from the state of the node. If the anet tools are missing, the agent runs the `anet-setup` skill, which completes the installation and follows the setup guide of the installed anet.
|
|
32
34
|
3. Restart OpenCode, so that the MCP server starts, and run `/anet-status`.
|
|
33
35
|
4. Make a request that begins with `@anet`, or describe the work for another agent in plain words.
|
|
34
36
|
|
|
@@ -62,11 +64,23 @@ OpenCode reads its configuration when it starts: restart it after a change. The
|
|
|
62
64
|
| `identity` | empty | A named identity (`anet id ls`). Empty selects the default identity. |
|
|
63
65
|
| `anetPath` | empty | Absolute path of the `anet` executable (`anet.exe` on Windows). Empty searches `PATH`, then `~/.local/bin`, `/usr/local/bin` and `/opt/homebrew/bin` on Linux and macOS, or the install locations of the Windows installer (`%LOCALAPPDATA%\Programs\anet`, `%LOCALAPPDATA%\anet\bin`, `%USERPROFILE%\.anet-bin`) on Windows. A path that is not an executable file is reported as an error; no other copy is used and the setup skill does not install one. |
|
|
64
66
|
|
|
67
|
+
## Automatic installation
|
|
68
|
+
|
|
69
|
+
When the MCP server of the plugin starts and finds no anet executable (the setting `anetPath` is empty, and none is on `PATH` or in the install locations listed above), it installs anet before it starts `anet mcp`:
|
|
70
|
+
|
|
71
|
+
- It runs the official installer, `https://agentnetwork.org.cn/install.sh` on Linux and macOS and `https://agentnetwork.org.cn/install.ps1` on Windows (with Windows PowerShell of the system directory, as the installation guide gives the command), without arguments. Nothing from the workspace or the session is passed to it.
|
|
72
|
+
- The installer checks the signed release manifest and the SHA-256 of the download and stops without changing anything when a check fails. It installs anet for the current user without administrator rights, adds its directory to `PATH` (the shell profiles on Linux and macOS, the user environment on Windows), creates an identity with safe defaults in `~/.anet`, starts the node and joins the public hub `https://hub.agentnetwork.org.cn`.
|
|
73
|
+
- The installer runs in the home directory, with no input, no terminal and no window; its output goes to the error output of the MCP server, never to the MCP session. On Linux and macOS it also stays in `~/.cache/anet-plugin/install.log`.
|
|
74
|
+
- One installation runs at a time: a second host that starts at the same moment waits for the first one and does not install again.
|
|
75
|
+
- A setting `anetPath` that names a missing file is reported as an error; nothing is installed in its place.
|
|
76
|
+
|
|
77
|
+
To turn the automatic installation off, set the environment variable `ANET_PLUGIN_NO_INSTALL=1` in the environment of OpenCode. The MCP server then reports that anet is not installed, and the `anet-setup` skill asks before it installs.
|
|
78
|
+
|
|
65
79
|
## Security and side effects
|
|
66
80
|
|
|
67
|
-
- **Commands run.** Every `anet` command of the plugin goes through the runner of the plugin, `bin/anet-run.sh` on Linux and macOS and `bin/anet-run.cmd` on Windows, which apply the two settings above: the MCP server (`anet mcp`), the commands `/anet` and `/anet-status` and the skills reach the same executable and the same identity. Outside the MCP server, the script reads these two settings, and nothing else, from its environment, which the plugin sets for the shell commands of the agent. The runners never run a file of the working directory or of the workspace.
|
|
68
|
-
- **Network access.** The plugin itself opens no connection. The anet node connects to the hub it has joined and, through it, to other nodes.
|
|
69
|
-
- **Files written.** The plugin writes
|
|
81
|
+
- **Commands run.** Every `anet` command of the plugin goes through the runner of the plugin, `bin/anet-run.sh` on Linux and macOS and `bin/anet-run.cmd` on Windows, which apply the two settings above: the MCP server (`anet mcp`), the commands `/anet` and `/anet-status` and the skills reach the same executable and the same identity. Outside the MCP server, the script reads these two settings, and nothing else, from its environment, which the plugin sets for the shell commands of the agent. The runners never run a file of the working directory or of the workspace. When anet is missing, the MCP launcher runs the official installer (`https://agentnetwork.org.cn/install.sh`, or `install.ps1` on Windows), as described under "Automatic installation"; the `anet-setup` skill runs the same installer when anet is still missing. `anet mcp` starts the node of the selected identity when it is not running. The plugin has no hooks.
|
|
82
|
+
- **Network access.** The plugin itself opens no connection. The installer downloads from `agentnetwork.org.cn` and the release mirrors that it names. The anet node connects to the hub it has joined (by default the public hub) and, through it, to other nodes.
|
|
83
|
+
- **Files written.** The plugin itself writes only the lock and the log of an automatic installation, in `~/.cache/anet-plugin` (`%LOCALAPPDATA%\anet-plugin` on Windows). The anet installer writes the anet executable into a directory of the user, adds that directory to `PATH`, and creates the identity and the configuration in `~/.anet` (`%USERPROFILE%\.anet` on Windows). The skills tell the agent never to read the files of that directory.
|
|
70
84
|
- **Safe defaults.** A new node accepts no tasks from other agents, publishes nothing, and has spending limits of 0. Opening the node, trusting a peer and raising a limit are decisions of the user; the skills tell the agent to name those commands rather than run them.
|
|
71
85
|
- **Untrusted input.** Results and tasks from other agents are text from third parties. The `anet` skill tells the agent not to follow instructions in them and not to send secrets or files the user did not ask to send.
|
|
72
86
|
- **Data.** Task content is end-to-end encrypted between nodes. The hub sees which nodes communicate, and when.
|
|
@@ -75,7 +89,8 @@ OpenCode reads its configuration when it starts: restart it after a change. The
|
|
|
75
89
|
|
|
76
90
|
| Symptom | Action |
|
|
77
91
|
| --- | --- |
|
|
78
|
-
| The anet tools do not appear in a session |
|
|
92
|
+
| The anet tools do not appear in a session | The installation did not finish before the host gave up on the MCP server, or it failed; the error output of the MCP server names the reason. Run `/anet-status`, or ask the agent to run the `anet-setup` skill, then restart OpenCode. |
|
|
93
|
+
| `node_status` reports `running: false` | The node could not be started; its `next` member names the command that fixes it. The agent runs `anet up` itself; other fixes belong to the user. |
|
|
79
94
|
| A refusal ends with a code in brackets | The line after it names the next command. See also the [reason codes](https://docs.agentnetwork.org.cn/docs/en/latest/reference/reason-codes.html). |
|
|
80
95
|
|
|
81
96
|
## Links
|
package/README_CN.md
CHANGED
|
@@ -4,15 +4,17 @@
|
|
|
4
4
|
|
|
5
5
|
将 OpenCode 接入 AgentNetwork(anet)。接入后,OpenCode 会话中的智能体可以通过 [A2A 协议](https://a2a-protocol.org)把任务交给其他 AI 智能体,并答复其他智能体发送到本机的任务。
|
|
6
6
|
|
|
7
|
+
启用本插件即会安装 anet:插件的 MCP 服务启动时如果在本机找不到 anet,会运行官方安装程序。安装程序校验已签名的发布清单和下载文件的 SHA-256,为当前用户安装 anet,启动其节点并加入公共 hub `https://hub.agentnetwork.org.cn`,无需其他步骤。自动安装可以关闭(参见下文“自动安装”)。
|
|
8
|
+
|
|
7
9
|
anet 是运行在用户本机上的开源节点。它保存智能体的身份,对每条消息进行端到端加密,并通过 hub 与其他节点交换任务。hub 只负责中转,无法读取消息内容。anet 本身不运行模型,任务由两端的智能体完成。付费技能按 [a2a-x402](https://github.com/google-agentic-commerce/a2a-x402) 结算,额度只能由运营者设定。
|
|
8
10
|
|
|
9
11
|
## 插件内容
|
|
10
12
|
|
|
11
13
|
| 组件 | 名称 | 用途 |
|
|
12
14
|
| --- | --- | --- |
|
|
13
|
-
| MCP 服务 | `anet` | `anet mcp` 提供的工具,由本机安装的 anet 提供。其中的工具 `guide` 返回 anet
|
|
15
|
+
| MCP 服务 | `anet` | `anet mcp` 提供的工具,由本机安装的 anet 提供。其中的工具 `guide` 返回 anet 的当前指南。未安装 anet 时由启动脚本安装;节点未运行时由 `anet mcp` 启动。 |
|
|
14
16
|
| Skill | `anet` | 要求智能体在会话中首次执行 anet 操作之前以及每次收到“@anet”请求时,先阅读已安装 anet 的指南,并列出始终适用的规则。用户输入“@anet”,提到 anet、AgentNetwork 或 AID,或希望把工作交给其他智能体时加载。 |
|
|
15
|
-
| Skill | `anet-setup` | 查找 anet 可执行文件;anet
|
|
17
|
+
| Skill | `anet-setup` | 查找 anet 可执行文件;anet 仍未安装时进行安装,然后按已安装 anet 的设置指南完成设置。 |
|
|
16
18
|
| 命令 | `/anet` | 按已安装 anet 的指南执行一项“@anet”请求。 |
|
|
17
19
|
| 命令 | `/anet-status` | 按已安装 anet 的指南显示节点状态。 |
|
|
18
20
|
|
|
@@ -22,13 +24,13 @@ anet 是运行在用户本机上的开源节点。它保存智能体的身份,
|
|
|
22
24
|
|
|
23
25
|
- Linux、macOS 或 Windows,x86-64 或 ARM64。在 Linux 和 macOS 上,插件运行 POSIX shell 脚本;在 Windows 上,插件运行 `.cmd` 脚本和 Windows 自带的 Windows PowerShell 5.1。
|
|
24
26
|
- OpenCode 1.19.3 或更高版本。
|
|
25
|
-
- 提供 `anet guide` 命令的 anet 版本。未安装 anet
|
|
27
|
+
- 提供 `anet guide` 命令的 anet 版本。未安装 anet 时,插件的 MCP 服务会安装当前版本。
|
|
26
28
|
- 在 Linux 和 macOS 上安装需要 `curl`、`gzip` 和 `ssh-keygen`(OpenSSH 8.1 或更高版本)。
|
|
27
29
|
|
|
28
30
|
## 快速开始
|
|
29
31
|
|
|
30
32
|
1. 将插件添加到 OpenCode 并重启;见下文“安装与设置”。
|
|
31
|
-
2.
|
|
33
|
+
2. 启动一个会话。未安装 anet 时,插件的 MCP 服务会安装 anet、启动其节点并加入公共 hub;首次启动可能需要约一分钟。然后输入:`What can anet do?`(或“anet 能做什么”)。智能体会根据节点的实际状态作答。如果会话中没有 anet 工具,智能体会运行 `anet-setup` skill,完成安装并按已安装 anet 的设置指南完成设置。
|
|
32
34
|
3. 重启 OpenCode,使 MCP 服务启动,然后运行 `/anet-status`。
|
|
33
35
|
4. 输入以 `@anet` 开头的请求,或直接描述要交给其他智能体的工作。
|
|
34
36
|
|
|
@@ -62,11 +64,23 @@ OpenCode 在启动时读取配置:修改后须重启。若已存在 `mcp.anet`
|
|
|
62
64
|
| `identity` | 空 | 指定的命名身份(`anet id ls`)。为空时使用默认身份。 |
|
|
63
65
|
| `anetPath` | 空 | `anet` 可执行文件(Windows 上为 `anet.exe`)的绝对路径。为空时先查找 `PATH`,然后在 Linux 和 macOS 上查找 `~/.local/bin`、`/usr/local/bin` 和 `/opt/homebrew/bin`,在 Windows 上查找 Windows 安装程序的安装位置(`%LOCALAPPDATA%\Programs\anet`、`%LOCALAPPDATA%\anet\bin`、`%USERPROFILE%\.anet-bin`)。若该路径不是可执行文件,则报告错误;不会改用其他副本,安装 skill 也不会另行安装。 |
|
|
64
66
|
|
|
67
|
+
## 自动安装
|
|
68
|
+
|
|
69
|
+
插件的 MCP 服务启动时,如果找不到 anet 可执行文件(设置项 `anetPath` 为空,且 `PATH` 和上述安装位置中都没有),会在启动 `anet mcp` 之前安装 anet:
|
|
70
|
+
|
|
71
|
+
- 运行官方安装程序,不带任何参数:Linux 和 macOS 上为 `https://agentnetwork.org.cn/install.sh`,Windows 上为 `https://agentnetwork.org.cn/install.ps1`(按安装指南给出的命令,使用系统目录中的 Windows PowerShell 运行)。工作区或会话中的任何内容都不会传给安装程序。
|
|
72
|
+
- 安装程序校验已签名的发布清单和下载文件的 SHA-256,任何一项校验失败即停止,不做任何改动。它无需管理员权限,为当前用户安装 anet,把安装目录加入 `PATH`(Linux 和 macOS 上写入 shell 配置文件,Windows 上写入用户环境变量),在 `~/.anet` 中以安全默认值创建身份,启动节点并加入公共 hub `https://hub.agentnetwork.org.cn`。
|
|
73
|
+
- 安装程序在用户主目录中运行,没有输入、终端或窗口;其输出写入 MCP 服务的错误输出,不会进入 MCP 会话。在 Linux 和 macOS 上,输出还保存在 `~/.cache/anet-plugin/install.log` 中。
|
|
74
|
+
- 同一时间只运行一个安装:同时启动的另一个宿主会等待第一个安装完成,不会重复安装。
|
|
75
|
+
- 如果设置项 `anetPath` 指向不存在的文件,会报告错误,不会改为安装其他副本。
|
|
76
|
+
|
|
77
|
+
要关闭自动安装,请在 OpenCode 的运行环境中设置环境变量 `ANET_PLUGIN_NO_INSTALL=1`。此后 MCP 服务会报告 anet 未安装,`anet-setup` skill 会在安装前先征得同意。
|
|
78
|
+
|
|
65
79
|
## 安全与副作用
|
|
66
80
|
|
|
67
|
-
- **执行的命令。** 插件的所有 `anet` 命令都经由插件的运行脚本执行(Linux 和 macOS 上为 `bin/anet-run.sh`,Windows 上为 `bin/anet-run.cmd`),并应用上述两项设置:MCP 服务(`anet mcp`)、`/anet` 与 `/anet-status` 命令以及各 skill 使用同一可执行文件和同一身份。在 MCP 服务之外,该脚本只从自身环境变量中读取这两项设置,由插件为智能体的 shell
|
|
68
|
-
- **网络访问。**
|
|
69
|
-
- **写入的文件。**
|
|
81
|
+
- **执行的命令。** 插件的所有 `anet` 命令都经由插件的运行脚本执行(Linux 和 macOS 上为 `bin/anet-run.sh`,Windows 上为 `bin/anet-run.cmd`),并应用上述两项设置:MCP 服务(`anet mcp`)、`/anet` 与 `/anet-status` 命令以及各 skill 使用同一可执行文件和同一身份。在 MCP 服务之外,该脚本只从自身环境变量中读取这两项设置,由插件为智能体的 shell 命令设置。运行脚本从不执行工作目录或工作区中的文件。未安装 anet 时,MCP 启动脚本按“自动安装”所述运行官方安装程序(`https://agentnetwork.org.cn/install.sh`,Windows 上为 `install.ps1`);anet 仍未安装时,`anet-setup` skill 运行同一安装程序。所选身份的节点未运行时,`anet mcp` 会启动它。本插件不包含 Hook。
|
|
82
|
+
- **网络访问。** 插件本身不建立任何连接。安装程序从 `agentnetwork.org.cn` 及其列出的发布镜像下载。anet 节点连接其加入的 hub(默认为公共 hub),并经由 hub 与其他节点通信。
|
|
83
|
+
- **写入的文件。** 插件本身只写入自动安装的锁和日志,位于 `~/.cache/anet-plugin`(Windows 上为 `%LOCALAPPDATA%\anet-plugin`)。anet 安装程序将 anet 可执行文件写入用户目录,把该目录加入 `PATH`,并在 `~/.anet`(Windows 上为 `%USERPROFILE%\.anet`)中创建身份和配置。Skill 要求智能体不得读取该目录中的文件。
|
|
70
84
|
- **安全默认值。** 新节点不接受其他智能体的任务,不发布任何能力,支付额度为 0。开放节点、信任对端和提高额度均由用户决定;Skill 要求智能体只给出这些命令,不代为执行。
|
|
71
85
|
- **不可信输入。** 其他智能体返回的结果和发来的任务都是第三方文本。`anet` skill 要求智能体不执行其中的指令,也不发送用户未要求发送的密钥或文件。
|
|
72
86
|
- **数据。** 节点之间的任务内容端到端加密。hub 能看到哪些节点在通信以及通信时间。
|
|
@@ -75,7 +89,8 @@ OpenCode 在启动时读取配置:修改后须重启。若已存在 `mcp.anet`
|
|
|
75
89
|
|
|
76
90
|
| 现象 | 处理 |
|
|
77
91
|
| --- | --- |
|
|
78
|
-
| 会话中没有 anet 工具 |
|
|
92
|
+
| 会话中没有 anet 工具 | 宿主在安装完成前放弃了 MCP 服务,或安装失败;MCP 服务的错误输出给出原因。运行 `/anet-status`,或让智能体运行 `anet-setup` skill,然后重启 OpenCode。 |
|
|
93
|
+
| `node_status` 报告 `running: false` | 节点无法启动;其 `next` 字段给出修复命令。智能体会自行运行 `anet up`;其他修复由用户决定。 |
|
|
79
94
|
| 拒绝信息末尾带有方括号中的代码 | 其下一行给出下一步命令。另请参见[原因代码](https://docs.agentnetwork.org.cn/docs/zh-cn/latest/reference/reason-codes.html)。 |
|
|
80
95
|
|
|
81
96
|
## 链接
|
package/bin/anet-install.cmd
CHANGED
|
@@ -6,6 +6,18 @@ rem PowerShell, over TLS 1.2. The installer checks the signed release manifest
|
|
|
6
6
|
rem and the SHA-256 of the binary, stops without changing anything when a check
|
|
7
7
|
rem fails, installs into a directory of this user and puts it on the user PATH.
|
|
8
8
|
rem The Windows counterpart of anet-install.sh.
|
|
9
|
+
rem
|
|
10
|
+
rem Every program is named by its full path: PowerShell as
|
|
11
|
+
rem %SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe, the scripts of
|
|
12
|
+
rem the plugin by the directory of this file. Nothing is looked up in the
|
|
13
|
+
rem working directory or on PATH, where cmd.exe would look in the working
|
|
14
|
+
rem directory (a workspace) first. SystemRoot is set by Windows for every
|
|
15
|
+
rem process and is not compared with the system directory here: cmd.exe cannot
|
|
16
|
+
rem ask Windows for that directory without running a program, which would have
|
|
17
|
+
rem to be found the same way, and a host that sets SystemRoot for its MCP
|
|
18
|
+
rem servers already chooses every program they run. (The automatic installation
|
|
19
|
+
rem of the MCP launcher, in anet-run.ps1, asks Windows for the system directory
|
|
20
|
+
rem with [Environment]::GetFolderPath.)
|
|
9
21
|
setlocal EnableExtensions DisableDelayedExpansion
|
|
10
22
|
%SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe -NoLogo -NoProfile -NonInteractive -ExecutionPolicy Bypass -Command "[Net.ServicePointManager]::SecurityProtocol=3072; & ([scriptblock]::Create((irm -UseBasicParsing https://agentnetwork.org.cn/install.ps1)))" 0<NUL
|
|
11
23
|
exit /b %ERRORLEVEL%
|
package/bin/anet-install.sh
CHANGED
|
@@ -1,25 +1,312 @@
|
|
|
1
1
|
#!/bin/sh
|
|
2
2
|
# Installs the anet command line with the official installer.
|
|
3
3
|
#
|
|
4
|
-
# `sh install
|
|
4
|
+
# `sh anet-install.sh [installer arguments]` downloads https://agentnetwork.org.cn/install.sh
|
|
5
5
|
# into a new private directory, runs it only when the download succeeded, and
|
|
6
6
|
# removes the directory afterwards. The installer checks the signed release
|
|
7
7
|
# manifest and the SHA-256 of the binary and stops without changing anything
|
|
8
|
-
# when a check fails
|
|
9
|
-
#
|
|
10
|
-
#
|
|
8
|
+
# when a check fails; by default it installs anet for this user, starts the
|
|
9
|
+
# node and joins the public hub. The script exists so that an agent host that
|
|
10
|
+
# refuses command substitution in a shell command can still run the
|
|
11
|
+
# installation as one plain command (the anet-setup skill).
|
|
12
|
+
#
|
|
13
|
+
# `sh anet-install.sh --mcp` is the first step of the MCP launcher
|
|
14
|
+
# (anet-mcp.sh): it installs anet when the runner finds no anet executable, so
|
|
15
|
+
# that enabling the plugin is enough to have anet installed and its node
|
|
16
|
+
# running. It does nothing when the environment variable ANET_PLUGIN_NO_INSTALL
|
|
17
|
+
# is set to a value other than 0, when the plugin setting anetPath is set (an
|
|
18
|
+
# invalid one is reported by the runner, and no other copy is installed), and
|
|
19
|
+
# in a POSIX shell on Windows (anet-mcp.cmd installs there). Otherwise it runs
|
|
20
|
+
# the installer without arguments: nothing from the workspace or the session
|
|
21
|
+
# reaches it, the user's settings select nothing of it either. The installer
|
|
22
|
+
# runs
|
|
23
|
+
# * with no input and no controlling terminal (in a session of its own, with
|
|
24
|
+
# setsid or Perl where available), so that it never asks for a password
|
|
25
|
+
# on the terminal of the host, and never reads the MCP session;
|
|
26
|
+
# * in the user's home directory, not in the working directory of the
|
|
27
|
+
# session (a workspace);
|
|
28
|
+
# * with its output written to install.log in the state directory, which is
|
|
29
|
+
# copied to standard error afterwards (the launcher sends this script's
|
|
30
|
+
# output to standard error: standard output is the MCP session). Because
|
|
31
|
+
# the installer does not write to the host's pipe and has a session of
|
|
32
|
+
# its own, a host that gives up on a slow start does not end it halfway;
|
|
33
|
+
# it finishes, and the next session finds anet.
|
|
34
|
+
# It waits for the installer at most 15 minutes, and exits with status 0 in
|
|
35
|
+
# every case: the launcher goes on, and the runner reports anet as missing
|
|
36
|
+
# when the installation did not succeed.
|
|
37
|
+
#
|
|
38
|
+
# One installation at a time. Both forms hold the lock directory
|
|
39
|
+
# <state>/install.lock while the installer runs, with the process ID of the
|
|
40
|
+
# holder and its start time (as ps prints it) in the file pid; <state> is
|
|
41
|
+
# $XDG_CACHE_HOME/anet-plugin, or ~/.cache/anet-plugin (an absolute path only;
|
|
42
|
+
# without one the --mcp form installs nothing). Another host that starts at
|
|
43
|
+
# the same moment waits for it, at most 10 minutes (5 for the plain form), and
|
|
44
|
+
# then installs nothing itself when the first installation left an anet
|
|
45
|
+
# behind. A lock whose holder no longer runs (no process with that ID, or one
|
|
46
|
+
# that started at another time: the ID was reused), or that is older than 30
|
|
47
|
+
# minutes, is removed.
|
|
11
48
|
set -u
|
|
12
49
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
50
|
+
# Programs (sh, sed, uname and the others) are found only in the absolute
|
|
51
|
+
# directories of PATH: a relative entry (such as "." or an empty one) would
|
|
52
|
+
# find a file of the working directory of the session, which can be an
|
|
53
|
+
# untrusted workspace. This comes before the first command that is not built
|
|
54
|
+
# into the shell, and the scripts started from here inherit it.
|
|
55
|
+
_abs=
|
|
56
|
+
_ifs=$IFS
|
|
57
|
+
IFS=:
|
|
58
|
+
set -f
|
|
59
|
+
for _d in ${PATH:-}; do
|
|
60
|
+
case $_d in
|
|
61
|
+
/*) _abs=${_abs:+$_abs:}$_d ;;
|
|
62
|
+
esac
|
|
63
|
+
done
|
|
64
|
+
IFS=$_ifs
|
|
65
|
+
set +f
|
|
66
|
+
PATH=${_abs:-/usr/bin:/bin}
|
|
67
|
+
export PATH
|
|
68
|
+
unset _abs _ifs _d
|
|
69
|
+
|
|
70
|
+
here=$(cd "$(dirname "$0")" 2>/dev/null && pwd) || here=$(dirname "$0")
|
|
71
|
+
self="$here/anet-install.sh"
|
|
72
|
+
|
|
73
|
+
say() { printf '%s\n' "$*" >&2; }
|
|
74
|
+
|
|
75
|
+
# state_dir prints the directory of the lock and the log, or fails.
|
|
76
|
+
state_dir() {
|
|
77
|
+
_base=${XDG_CACHE_HOME:-}
|
|
78
|
+
case $_base in
|
|
79
|
+
/*) ;;
|
|
80
|
+
*) _base=${HOME:-}/.cache ;;
|
|
81
|
+
esac
|
|
82
|
+
case $_base in
|
|
83
|
+
/*) printf '%s/anet-plugin\n' "$_base" ;;
|
|
84
|
+
*) return 1 ;;
|
|
85
|
+
esac
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
# anet_missing: whether the runner finds no anet executable and no anetPath is
|
|
89
|
+
# set (its --resolve prints "executable: not found" exactly then).
|
|
90
|
+
anet_missing() {
|
|
91
|
+
[ "$(sh "$here/anet-run.sh" --resolve 2>/dev/null | sed -n 1p)" = "executable: not found" ]
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
# started PID prints when the process PID started, as one line, or nothing
|
|
95
|
+
# where ps cannot say.
|
|
96
|
+
started() {
|
|
97
|
+
ps -o lstart= -p "$1" 2>/dev/null | sed -e 's/ */ /g' -e 's/^ //' -e 's/ $//' -e 1q
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
# holder_runs LINE: whether the holder that the line of a lock names ("PID
|
|
101
|
+
# START") still runs: a process with that ID exists and, when the line has a
|
|
102
|
+
# start time and ps gives one, it started then. (kill -0 sends no signal; it
|
|
103
|
+
# only checks that the process exists.)
|
|
104
|
+
holder_runs() {
|
|
105
|
+
_pid=${1%% *}
|
|
106
|
+
case $_pid in
|
|
107
|
+
'' | *[!0-9]*) return 1 ;;
|
|
108
|
+
esac
|
|
109
|
+
kill -0 "$_pid" 2>/dev/null || return 1
|
|
110
|
+
_was=
|
|
111
|
+
case $1 in
|
|
112
|
+
*" "*) _was=${1#* } ;;
|
|
113
|
+
esac
|
|
114
|
+
[ -n "$_was" ] || return 0
|
|
115
|
+
_now=$(started "$_pid")
|
|
116
|
+
[ -z "$_now" ] || [ "$_now" = "$_was" ]
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
# take_lock SECONDS: takes the lock, waiting at most SECONDS. Sets waited=1
|
|
120
|
+
# when another installation held it.
|
|
121
|
+
waited=0
|
|
122
|
+
take_lock() {
|
|
123
|
+
_left=$1
|
|
124
|
+
while :; do
|
|
125
|
+
if mkdir "$lock" 2>/dev/null; then
|
|
126
|
+
_me=$(started "$$")
|
|
127
|
+
printf '%s\n' "$$${_me:+ $_me}" >"$lock/pid" && return 0
|
|
128
|
+
rmdir "$lock" 2>/dev/null
|
|
129
|
+
return 1
|
|
130
|
+
fi
|
|
131
|
+
_holder=$(cat "$lock/pid" 2>/dev/null) || _holder=
|
|
132
|
+
_stale=0
|
|
133
|
+
if [ -n "$(find "$lock" -prune -mmin +30 2>/dev/null)" ]; then
|
|
134
|
+
_stale=1
|
|
135
|
+
elif [ -n "$_holder" ]; then
|
|
136
|
+
holder_runs "$_holder" || _stale=1
|
|
137
|
+
elif [ -n "$(find "$lock" -prune -mmin +1 2>/dev/null)" ]; then
|
|
138
|
+
_stale=1 # created more than a minute ago and never given a holder
|
|
139
|
+
fi
|
|
140
|
+
if [ "$_stale" -eq 1 ]; then
|
|
141
|
+
# Moved aside first, so that of two processes that found it stale only
|
|
142
|
+
# one removes it; a lock that changed holder in the meantime is put back.
|
|
143
|
+
_aside="$lock.stale.$$"
|
|
144
|
+
if mv "$lock" "$_aside" 2>/dev/null; then
|
|
145
|
+
if [ "$(cat "$_aside/pid" 2>/dev/null)" = "$_holder" ]; then
|
|
146
|
+
rm -f "$_aside/pid"
|
|
147
|
+
rmdir "$_aside" 2>/dev/null
|
|
148
|
+
else
|
|
149
|
+
mv "$_aside" "$lock" 2>/dev/null || { rm -f "$_aside/pid"; rmdir "$_aside" 2>/dev/null; }
|
|
150
|
+
fi
|
|
151
|
+
fi
|
|
152
|
+
continue
|
|
153
|
+
fi
|
|
154
|
+
[ "$_left" -gt 0 ] || return 1
|
|
155
|
+
if [ "$waited" -eq 0 ]; then
|
|
156
|
+
say "Another installation of anet is running; waiting for it to finish."
|
|
157
|
+
fi
|
|
158
|
+
waited=1
|
|
159
|
+
sleep 1
|
|
160
|
+
_left=$((_left - 1))
|
|
161
|
+
done
|
|
17
162
|
}
|
|
18
|
-
trap 'rm -rf "$dir"' EXIT
|
|
19
|
-
trap 'exit 1' HUP INT TERM
|
|
20
163
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
164
|
+
release_lock() {
|
|
165
|
+
_line=$(cat "${lock:-/nonexistent}/pid" 2>/dev/null) || _line=
|
|
166
|
+
if [ -n "${lock:-}" ] && [ "${_line%% *}" = "$$" ]; then
|
|
167
|
+
rm -f "$lock/pid"
|
|
168
|
+
rmdir "$lock" 2>/dev/null
|
|
169
|
+
fi
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
# lock_live: whether a running process holds the lock.
|
|
173
|
+
lock_live() {
|
|
174
|
+
_h=$(cat "$lock/pid" 2>/dev/null) || _h=
|
|
175
|
+
[ -n "$_h" ] && holder_runs "$_h"
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
# cleanup runs on exit: the lock of this process and the download directory.
|
|
179
|
+
_dir=
|
|
180
|
+
cleanup() {
|
|
181
|
+
release_lock
|
|
182
|
+
if [ -n "$_dir" ]; then
|
|
183
|
+
rm -rf "$_dir"
|
|
184
|
+
fi
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
# run_installer [installer arguments]: download and run the official installer.
|
|
188
|
+
run_installer() {
|
|
189
|
+
umask 077
|
|
190
|
+
_dir=$(mktemp -d 2>/dev/null) || {
|
|
191
|
+
_dir=
|
|
192
|
+
echo "Error: a temporary directory could not be created." >&2
|
|
193
|
+
return 1
|
|
194
|
+
}
|
|
195
|
+
if ! curl --proto '=https' --tlsv1.2 -fsSL https://agentnetwork.org.cn/install.sh -o "$_dir/install.sh"; then
|
|
196
|
+
echo "Error: the installer could not be downloaded." >&2
|
|
197
|
+
return 1
|
|
198
|
+
fi
|
|
199
|
+
# The home directory, not the working directory of the session: the node
|
|
200
|
+
# that the installer starts keeps its working directory.
|
|
201
|
+
case ${HOME:-} in
|
|
202
|
+
/*) cd "$HOME" 2>/dev/null || cd / ;;
|
|
203
|
+
*) cd / ;;
|
|
204
|
+
esac
|
|
205
|
+
sh "$_dir/install.sh" "$@"
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
# detached COMMAND...: COMMAND in a session of its own (no controlling
|
|
209
|
+
# terminal), where setsid or Perl can make one; otherwise as it is.
|
|
210
|
+
detached() {
|
|
211
|
+
if command -v setsid >/dev/null 2>&1; then
|
|
212
|
+
exec setsid "$@"
|
|
213
|
+
fi
|
|
214
|
+
if command -v perl >/dev/null 2>&1; then
|
|
215
|
+
exec perl -MPOSIX -e 'POSIX::setsid(); exec { $ARGV[0] } @ARGV or exit 127' -- "$@"
|
|
216
|
+
fi
|
|
217
|
+
exec "$@"
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
opted_out() {
|
|
221
|
+
case ${ANET_PLUGIN_NO_INSTALL:-} in
|
|
222
|
+
"" | 0) return 1 ;;
|
|
223
|
+
*) return 0 ;;
|
|
224
|
+
esac
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
case ${1:-} in
|
|
228
|
+
--mcp)
|
|
229
|
+
opted_out && exit 0
|
|
230
|
+
case $(uname -s 2>/dev/null) in
|
|
231
|
+
MINGW* | MSYS* | CYGWIN*) exit 0 ;;
|
|
232
|
+
esac
|
|
233
|
+
anet_missing || exit 0
|
|
234
|
+
state=$(state_dir) || {
|
|
235
|
+
say "anet is not installed, and it was not installed automatically: HOME is not an absolute path."
|
|
236
|
+
exit 0
|
|
237
|
+
}
|
|
238
|
+
(umask 077 && mkdir -p "$state") || exit 0
|
|
239
|
+
lock="$state/install.lock"
|
|
240
|
+
log="$state/install.log"
|
|
241
|
+
result=$(mktemp "$state/result.XXXXXX" 2>/dev/null) || exit 0
|
|
242
|
+
say "anet is not installed. Installing it with the official installer (https://agentnetwork.org.cn/install.sh),"
|
|
243
|
+
say "which checks the signed release manifest, installs anet for this user, starts its node and joins the public hub."
|
|
244
|
+
say "Set the environment variable ANET_PLUGIN_NO_INSTALL=1 to turn this off."
|
|
245
|
+
(detached sh "$self" --mcp-worker "$result" </dev/null >/dev/null 2>&1) &
|
|
246
|
+
worker=$!
|
|
247
|
+
left=900
|
|
248
|
+
gone=0
|
|
249
|
+
while [ ! -s "$result" ] && [ "$left" -gt 0 ]; do
|
|
250
|
+
# The worker is gone without a result and no installation holds the
|
|
251
|
+
# lock, for three seconds in a row: nothing is coming.
|
|
252
|
+
if ! kill -0 "$worker" 2>/dev/null && ! lock_live; then
|
|
253
|
+
gone=$((gone + 1))
|
|
254
|
+
[ "$gone" -lt 3 ] || break
|
|
255
|
+
else
|
|
256
|
+
gone=0
|
|
257
|
+
fi
|
|
258
|
+
sleep 1
|
|
259
|
+
left=$((left - 1))
|
|
260
|
+
done
|
|
261
|
+
outcome=$(cat "$result" 2>/dev/null) || outcome=
|
|
262
|
+
rm -f "$result"
|
|
263
|
+
case $outcome in
|
|
264
|
+
installed:*)
|
|
265
|
+
cat "$log" >&2 2>/dev/null
|
|
266
|
+
say "The anet installer ended with status ${outcome#installed:}."
|
|
267
|
+
;;
|
|
268
|
+
other) say "Another installation of anet has finished." ;;
|
|
269
|
+
busy) say "Another installation of anet is still running; anet was not installed by this session." ;;
|
|
270
|
+
*) say "The installation of anet has not finished; it goes on in the background (log: $log)." ;;
|
|
271
|
+
esac
|
|
272
|
+
exit 0
|
|
273
|
+
;;
|
|
274
|
+
--mcp-worker)
|
|
275
|
+
# The detached part of --mcp; $2 is the file for the outcome.
|
|
276
|
+
result=${2:-}
|
|
277
|
+
state=$(state_dir) || exit 0
|
|
278
|
+
lock="$state/install.lock"
|
|
279
|
+
log="$state/install.log"
|
|
280
|
+
if ! take_lock 600; then
|
|
281
|
+
printf 'busy\n' >"$result"
|
|
282
|
+
exit 0
|
|
283
|
+
fi
|
|
284
|
+
trap cleanup EXIT
|
|
285
|
+
trap 'exit 1' HUP INT TERM
|
|
286
|
+
if [ "$waited" -eq 1 ] && ! anet_missing; then
|
|
287
|
+
printf 'other\n' >"$result"
|
|
288
|
+
exit 0
|
|
289
|
+
fi
|
|
290
|
+
(umask 077 && : >"$log")
|
|
291
|
+
run_installer </dev/null >"$log" 2>&1
|
|
292
|
+
printf 'installed:%s\n' "$?" >"$result"
|
|
293
|
+
exit 0
|
|
294
|
+
;;
|
|
295
|
+
esac
|
|
296
|
+
|
|
297
|
+
# The plain form: the installer with the given arguments, its output on this
|
|
298
|
+
# terminal.
|
|
299
|
+
trap cleanup EXIT
|
|
300
|
+
trap 'exit 1' HUP INT TERM
|
|
301
|
+
if state=$(state_dir) && (umask 077 && mkdir -p "$state"); then
|
|
302
|
+
lock="$state/install.lock"
|
|
303
|
+
if ! take_lock 300; then
|
|
304
|
+
echo "Error: another installation of anet is still running; try again when it has finished." >&2
|
|
305
|
+
exit 1
|
|
306
|
+
fi
|
|
307
|
+
if [ "$waited" -eq 1 ] && ! anet_missing; then
|
|
308
|
+
say "Another installation of anet has finished. Run the runner with --resolve to see it."
|
|
309
|
+
exit 0
|
|
310
|
+
fi
|
|
24
311
|
fi
|
|
25
|
-
|
|
312
|
+
run_installer "$@"
|
package/bin/anet-mcp
CHANGED
|
@@ -2,4 +2,25 @@
|
|
|
2
2
|
# Starts the MCP server of the local anet node through anet-mcp.sh, for a
|
|
3
3
|
# host that starts the launcher by its path: on Windows the same path, without
|
|
4
4
|
# an extension, selects anet-mcp.cmd.
|
|
5
|
+
|
|
6
|
+
# Programs (sh, sed, uname and the others) are found only in the absolute
|
|
7
|
+
# directories of PATH: a relative entry (such as "." or an empty one) would
|
|
8
|
+
# find a file of the working directory of the session, which can be an
|
|
9
|
+
# untrusted workspace. This comes before the first command that is not built
|
|
10
|
+
# into the shell, and the scripts started from here inherit it.
|
|
11
|
+
_abs=
|
|
12
|
+
_ifs=$IFS
|
|
13
|
+
IFS=:
|
|
14
|
+
set -f
|
|
15
|
+
for _d in ${PATH:-}; do
|
|
16
|
+
case $_d in
|
|
17
|
+
/*) _abs=${_abs:+$_abs:}$_d ;;
|
|
18
|
+
esac
|
|
19
|
+
done
|
|
20
|
+
IFS=$_ifs
|
|
21
|
+
set +f
|
|
22
|
+
PATH=${_abs:-/usr/bin:/bin}
|
|
23
|
+
export PATH
|
|
24
|
+
unset _abs _ifs _d
|
|
25
|
+
|
|
5
26
|
exec sh "$(dirname "$0")/anet-mcp.sh" "$@"
|
package/bin/anet-mcp.cmd
CHANGED
|
@@ -2,8 +2,15 @@
|
|
|
2
2
|
rem Starts the MCP server of the local anet node ("anet mcp", stdio) for the
|
|
3
3
|
rem executable and identity of the plugin settings, which the host passes in
|
|
4
4
|
rem ANET_PLUGIN_BIN and ANET_PLUGIN_IDENTITY; see anet-run.cmd. The Windows
|
|
5
|
-
rem counterpart of anet-mcp.sh.
|
|
6
|
-
rem
|
|
7
|
-
rem
|
|
5
|
+
rem counterpart of anet-mcp.sh.
|
|
6
|
+
rem
|
|
7
|
+
rem ANET_RUN_INSTALL=missing asks anet-run.ps1 to install anet with the
|
|
8
|
+
rem official installer (install.ps1, which also starts the node and joins the
|
|
9
|
+
rem public hub) when it finds no anet.exe, unless ANET_PLUGIN_NO_INSTALL=1 is
|
|
10
|
+
rem set; all of its output goes to standard error, because standard output is
|
|
11
|
+
rem the MCP session. "anet mcp" then starts the node of the selected identity
|
|
12
|
+
rem when it is not running, and serves the tools even when the node cannot
|
|
13
|
+
rem run: node_status then names the reason and the command that fixes it.
|
|
8
14
|
set "ANET_PLUGIN_SETTINGS=env"
|
|
15
|
+
set "ANET_RUN_INSTALL=missing"
|
|
9
16
|
"%~dp0anet-run.cmd" mcp
|
package/bin/anet-mcp.sh
CHANGED
|
@@ -1,9 +1,37 @@
|
|
|
1
1
|
#!/bin/sh
|
|
2
2
|
# Starts the MCP server of the local anet node (`anet mcp`, stdio) for the
|
|
3
|
-
# executable and identity of the plugin settings; see anet-run.sh.
|
|
4
|
-
#
|
|
5
|
-
#
|
|
3
|
+
# executable and identity of the plugin settings; see anet-run.sh.
|
|
4
|
+
#
|
|
5
|
+
# When the runner finds no anet executable, anet-install.sh --mcp installs it
|
|
6
|
+
# first with the official installer (which also starts the node and joins the
|
|
7
|
+
# public hub), unless ANET_PLUGIN_NO_INSTALL=1 is set; see that script. All of
|
|
8
|
+
# its output goes to standard error, because standard output is the MCP
|
|
9
|
+
# session. `anet mcp` then starts the node of the selected identity when it is
|
|
10
|
+
# not running, and serves the tools even when the node cannot run: node_status
|
|
11
|
+
# then names the reason and the command that fixes it.
|
|
6
12
|
set -u
|
|
13
|
+
|
|
14
|
+
# Programs (sh, sed, uname and the others) are found only in the absolute
|
|
15
|
+
# directories of PATH: a relative entry (such as "." or an empty one) would
|
|
16
|
+
# find a file of the working directory of the session, which can be an
|
|
17
|
+
# untrusted workspace. This comes before the first command that is not built
|
|
18
|
+
# into the shell, and the scripts started from here inherit it.
|
|
19
|
+
_abs=
|
|
20
|
+
_ifs=$IFS
|
|
21
|
+
IFS=:
|
|
22
|
+
set -f
|
|
23
|
+
for _d in ${PATH:-}; do
|
|
24
|
+
case $_d in
|
|
25
|
+
/*) _abs=${_abs:+$_abs:}$_d ;;
|
|
26
|
+
esac
|
|
27
|
+
done
|
|
28
|
+
IFS=$_ifs
|
|
29
|
+
set +f
|
|
30
|
+
PATH=${_abs:-/usr/bin:/bin}
|
|
31
|
+
export PATH
|
|
32
|
+
unset _abs _ifs _d
|
|
33
|
+
|
|
7
34
|
ANET_PLUGIN_SETTINGS=env
|
|
8
35
|
export ANET_PLUGIN_SETTINGS
|
|
36
|
+
sh "$(dirname "$0")/anet-install.sh" --mcp </dev/null >&2
|
|
9
37
|
exec sh "$(dirname "$0")/anet-run.sh" mcp
|
package/bin/anet-run.cmd
CHANGED
|
@@ -13,9 +13,23 @@ rem the settings itself and returns only an absolute path of an .exe file
|
|
|
13
13
|
rem (which cannot contain a double quote) and a validated identity name.
|
|
14
14
|
rem PowerShell gets no standard input (0<NUL): the input of this script is the
|
|
15
15
|
rem input of anet, for example the MCP session of anet-mcp.cmd.
|
|
16
|
+
rem
|
|
17
|
+
rem Every program is named by its full path: PowerShell as
|
|
18
|
+
rem %SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe, the scripts of
|
|
19
|
+
rem the plugin by the directory of this file. Nothing is looked up in the
|
|
20
|
+
rem working directory or on PATH, where cmd.exe would look in the working
|
|
21
|
+
rem directory (a workspace) first. SystemRoot is set by Windows for every
|
|
22
|
+
rem process and is not compared with the system directory here: cmd.exe cannot
|
|
23
|
+
rem ask Windows for that directory without running a program, which would have
|
|
24
|
+
rem to be found the same way, and a host that sets SystemRoot for its MCP
|
|
25
|
+
rem servers already chooses every program they run. anet-run.ps1 asks Windows
|
|
26
|
+
rem for the system directory ([Environment]::GetFolderPath) before it starts
|
|
27
|
+
rem the installer.
|
|
16
28
|
setlocal EnableExtensions DisableDelayedExpansion
|
|
17
29
|
set "ANET_RUN_SCRIPT=%~dp0anet-run.ps1"
|
|
18
30
|
set "ANET_RUN_SELF=%~f0"
|
|
31
|
+
rem Only the MCP launcher (anet-mcp.cmd, "anet-run.cmd mcp") installs anet.
|
|
32
|
+
if not "%~1"=="mcp" set "ANET_RUN_INSTALL="
|
|
19
33
|
if "%~1"=="--resolve" goto resolve
|
|
20
34
|
set "ANET_RUN_MODE=locate"
|
|
21
35
|
set "ANET_RUN_EXE="
|
|
@@ -28,6 +42,7 @@ if not defined ANET_RUN_EXE exit /b 1
|
|
|
28
42
|
set "ANET_RUN_MODE="
|
|
29
43
|
set "ANET_RUN_SCRIPT="
|
|
30
44
|
set "ANET_RUN_SELF="
|
|
45
|
+
set "ANET_RUN_INSTALL="
|
|
31
46
|
if defined ANET_RUN_ID goto with_identity
|
|
32
47
|
"%ANET_RUN_EXE%" %*
|
|
33
48
|
exit /b %ERRORLEVEL%
|
package/bin/anet-run.ps1
CHANGED
|
@@ -22,6 +22,10 @@
|
|
|
22
22
|
# resolve: print the executable, its version, the
|
|
23
23
|
# identity and the runner command, and exit 0.
|
|
24
24
|
# ANET_RUN_SELF the full path of anet-run.cmd, for the runner line.
|
|
25
|
+
# ANET_RUN_INSTALL missing: set by anet-mcp.cmd (the MCP launcher) and
|
|
26
|
+
# by no other caller. In the mode locate, when no
|
|
27
|
+
# anetPath is set and no anet.exe is found, anet is
|
|
28
|
+
# installed first (Install-AnetForMcp, below).
|
|
25
29
|
#
|
|
26
30
|
# Rules (the same as anet-run.sh):
|
|
27
31
|
# * A configured anetPath is used as it is and never replaced by another
|
|
@@ -166,6 +170,177 @@ function Find-AnetExecutable {
|
|
|
166
170
|
'Ask the agent to run the anet-setup skill of the anet plugin, or see https://docs.agentnetwork.org.cn/docs/en/latest/intro/install.html')
|
|
167
171
|
}
|
|
168
172
|
|
|
173
|
+
# Install-AnetForMcp installs anet for the MCP launcher when it is missing,
|
|
174
|
+
# so that enabling the plugin is enough to have anet installed and its node
|
|
175
|
+
# running. It runs the official Windows installer exactly as the installation
|
|
176
|
+
# guide gives it, with Windows PowerShell of the system directory, which is
|
|
177
|
+
# asked of Windows ([Environment]::GetFolderPath('System')), so that no
|
|
178
|
+
# environment variable can move it (off Windows, where PowerShell 7 runs the
|
|
179
|
+
# tests of this script, SystemRoot stands in for it):
|
|
180
|
+
#
|
|
181
|
+
# powershell.exe -NoProfile -NonInteractive -ExecutionPolicy Bypass -Command
|
|
182
|
+
# "[Net.ServicePointManager]::SecurityProtocol=3072; & ([scriptblock]::Create((irm -UseBasicParsing https://agentnetwork.org.cn/install.ps1)))"
|
|
183
|
+
#
|
|
184
|
+
# install.ps1 checks the signed release manifest and the SHA-256 of the
|
|
185
|
+
# binary, stops without changing anything when a check fails, installs anet
|
|
186
|
+
# for this user, starts the node and joins the public hub. It receives no
|
|
187
|
+
# argument and nothing from the workspace or the session: no input (its input
|
|
188
|
+
# is closed at once), no window, the user's home directory as its working
|
|
189
|
+
# directory. Its output and its errors are copied to standard error, line by
|
|
190
|
+
# line, after it ends: standard output is read by anet-run.cmd and is then the
|
|
191
|
+
# MCP session. Nothing is installed when ANET_PLUGIN_NO_INSTALL is set to a
|
|
192
|
+
# value other than 0.
|
|
193
|
+
#
|
|
194
|
+
# One installation at a time: the file anet-plugin\install.lock in
|
|
195
|
+
# %LOCALAPPDATA% is held open without sharing while the installer runs, so
|
|
196
|
+
# that a second host that starts at the same moment waits for it (at most 10
|
|
197
|
+
# minutes) and then installs nothing when an anet is there. Windows releases
|
|
198
|
+
# the file when the process ends, however it ends. The file also names the
|
|
199
|
+
# installer while it runs (its process ID and start time), and is emptied
|
|
200
|
+
# when it ends: when a host ends this script but not the installer (which is
|
|
201
|
+
# a process of its own), the next one still waits for that installer rather
|
|
202
|
+
# than start a second one. The installer is waited for at most 15 minutes;
|
|
203
|
+
# it is not ended when that passes, and it stays named in the file.
|
|
204
|
+
function Test-AnetInstallOptOut {
|
|
205
|
+
$v = Get-AnetEnv 'ANET_PLUGIN_NO_INSTALL'
|
|
206
|
+
return ($v -ne '' -and $v -ne '0')
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
function Find-AnetQuietly {
|
|
210
|
+
try { return (Find-AnetExecutable) } catch { return $null }
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
function Write-AnetErrorLines([string]$Text) {
|
|
214
|
+
foreach ($line in ($Text -split "`r?`n")) {
|
|
215
|
+
if ($line.Trim() -ne '') { [Console]::Error.WriteLine($line) }
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
# The system directory (System32): asked of Windows, never of the
|
|
220
|
+
# environment. Off Windows there is none; the tests of this script run it
|
|
221
|
+
# with PowerShell 7 and a SystemRoot of their own.
|
|
222
|
+
function Get-AnetSystemDirectory {
|
|
223
|
+
if ($AnetOnWindows) { return [Environment]::GetFolderPath([Environment+SpecialFolder]::System) }
|
|
224
|
+
$root = Get-AnetEnv 'SystemRoot'
|
|
225
|
+
if ($root -eq '' -or -not (Test-AnetAbsolutePath $root)) { return '' }
|
|
226
|
+
return (Join-Path $root 'System32')
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
# Whether the installer that the lock file names ("<process ID> <start time
|
|
230
|
+
# in UTC ticks>") still runs: a process with that ID that started then (within
|
|
231
|
+
# a second: off Windows, .NET derives the start time from the boot time,
|
|
232
|
+
# which varies slightly between two readings).
|
|
233
|
+
function Test-AnetLockHolderRuns($Stream) {
|
|
234
|
+
try {
|
|
235
|
+
$Stream.Position = 0
|
|
236
|
+
$buf = New-Object byte[] 64
|
|
237
|
+
$n = $Stream.Read($buf, 0, $buf.Length)
|
|
238
|
+
$text = [Text.Encoding]::ASCII.GetString($buf, 0, $n).Trim()
|
|
239
|
+
if ($text -notmatch '^([0-9]+) ([0-9]+)$') { return $false }
|
|
240
|
+
$ticks = [long]$Matches[2]
|
|
241
|
+
$proc = [Diagnostics.Process]::GetProcessById([int]$Matches[1])
|
|
242
|
+
try { return ((-not $proc.HasExited) -and [Math]::Abs($proc.StartTime.ToUniversalTime().Ticks - $ticks) -le 10000000) } finally { $proc.Dispose() }
|
|
243
|
+
} catch {
|
|
244
|
+
return $false
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
function Set-AnetLockHolder($Stream, [string]$Text) {
|
|
249
|
+
$Stream.SetLength(0)
|
|
250
|
+
$b = [Text.Encoding]::ASCII.GetBytes($Text)
|
|
251
|
+
$Stream.Write($b, 0, $b.Length)
|
|
252
|
+
$Stream.Flush()
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
function Install-AnetForMcp {
|
|
256
|
+
$sys = Get-AnetSystemDirectory
|
|
257
|
+
if ($sys -eq '' -or -not (Test-AnetAbsolutePath $sys)) { return }
|
|
258
|
+
$ps = Join-Path (Join-Path (Join-Path $sys 'WindowsPowerShell') 'v1.0') 'powershell.exe'
|
|
259
|
+
if (-not (Test-Path -LiteralPath $ps -PathType Leaf)) { return }
|
|
260
|
+
$local = Get-AnetEnv 'LOCALAPPDATA'
|
|
261
|
+
if ($local -eq '' -or -not (Test-AnetAbsolutePath $local)) { return }
|
|
262
|
+
$userHome = Get-AnetUserHome
|
|
263
|
+
if ($userHome -eq '' -or -not (Test-AnetAbsolutePath $userHome)) { $userHome = $local }
|
|
264
|
+
$state = Join-Path $local 'anet-plugin'
|
|
265
|
+
$lock = $null
|
|
266
|
+
try {
|
|
267
|
+
$null = [IO.Directory]::CreateDirectory($state)
|
|
268
|
+
$lockPath = Join-Path $state 'install.lock'
|
|
269
|
+
$deadline = [DateTime]::UtcNow.AddMinutes(10)
|
|
270
|
+
$waited = $false
|
|
271
|
+
while ($null -eq $lock) {
|
|
272
|
+
$busy = $false
|
|
273
|
+
try {
|
|
274
|
+
$lock = [IO.File]::Open($lockPath, [IO.FileMode]::OpenOrCreate, [IO.FileAccess]::ReadWrite, [IO.FileShare]::None)
|
|
275
|
+
if (Test-AnetLockHolderRuns $lock) {
|
|
276
|
+
# The installer of a host that ended without it still runs.
|
|
277
|
+
$lock.Dispose()
|
|
278
|
+
$lock = $null
|
|
279
|
+
$busy = $true
|
|
280
|
+
}
|
|
281
|
+
} catch [IO.IOException] {
|
|
282
|
+
$busy = $true
|
|
283
|
+
}
|
|
284
|
+
if ($busy) {
|
|
285
|
+
if ([DateTime]::UtcNow -ge $deadline) {
|
|
286
|
+
[Console]::Error.WriteLine('Another installation of anet is still running; anet was not installed by this session.')
|
|
287
|
+
return
|
|
288
|
+
}
|
|
289
|
+
if (-not $waited) { [Console]::Error.WriteLine('Another installation of anet is running; waiting for it to finish.') }
|
|
290
|
+
$waited = $true
|
|
291
|
+
Start-Sleep -Seconds 1
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
if ($waited -and $null -ne (Find-AnetQuietly)) {
|
|
295
|
+
[Console]::Error.WriteLine('Another installation of anet has finished.')
|
|
296
|
+
return
|
|
297
|
+
}
|
|
298
|
+
[Console]::Error.WriteLine('anet is not installed. Installing it with the official installer (https://agentnetwork.org.cn/install.ps1),')
|
|
299
|
+
[Console]::Error.WriteLine('which checks the signed release manifest, installs anet for this user, starts its node and joins the public hub.')
|
|
300
|
+
[Console]::Error.WriteLine('Set the environment variable ANET_PLUGIN_NO_INSTALL=1 to turn this off.')
|
|
301
|
+
$psi = New-Object System.Diagnostics.ProcessStartInfo
|
|
302
|
+
$psi.FileName = $ps
|
|
303
|
+
$psi.Arguments = '-NoLogo -NoProfile -NonInteractive -ExecutionPolicy Bypass -Command "[Net.ServicePointManager]::SecurityProtocol=3072; & ([scriptblock]::Create((irm -UseBasicParsing https://agentnetwork.org.cn/install.ps1)))"'
|
|
304
|
+
$psi.UseShellExecute = $false
|
|
305
|
+
$psi.RedirectStandardInput = $true
|
|
306
|
+
$psi.RedirectStandardOutput = $true
|
|
307
|
+
$psi.RedirectStandardError = $true
|
|
308
|
+
$psi.CreateNoWindow = $true
|
|
309
|
+
$psi.WorkingDirectory = $userHome
|
|
310
|
+
$p = New-Object System.Diagnostics.Process
|
|
311
|
+
$p.StartInfo = $psi
|
|
312
|
+
try {
|
|
313
|
+
$null = $p.Start()
|
|
314
|
+
} catch {
|
|
315
|
+
[Console]::Error.WriteLine('The anet installer could not be started: ' + $_.Exception.Message)
|
|
316
|
+
return
|
|
317
|
+
}
|
|
318
|
+
try {
|
|
319
|
+
try { Set-AnetLockHolder $lock ([string]$p.Id + ' ' + [string]$p.StartTime.ToUniversalTime().Ticks) } catch { }
|
|
320
|
+
$p.StandardInput.Close()
|
|
321
|
+
$out = $p.StandardOutput.ReadToEndAsync()
|
|
322
|
+
$err = $p.StandardError.ReadToEndAsync()
|
|
323
|
+
if (-not $p.WaitForExit(15 * 60 * 1000)) {
|
|
324
|
+
[Console]::Error.WriteLine('The installation of anet has not finished; it goes on in the background.')
|
|
325
|
+
return
|
|
326
|
+
}
|
|
327
|
+
$p.WaitForExit()
|
|
328
|
+
try { Set-AnetLockHolder $lock '' } catch { }
|
|
329
|
+
# The node that the installer started may hold the other end of the
|
|
330
|
+
# pipes; what arrived within a few seconds is shown.
|
|
331
|
+
if ($out.Wait(5000)) { Write-AnetErrorLines ([string]$out.Result) }
|
|
332
|
+
if ($err.Wait(1000)) { Write-AnetErrorLines ([string]$err.Result) }
|
|
333
|
+
[Console]::Error.WriteLine('The anet installer ended with status ' + [string]$p.ExitCode + '.')
|
|
334
|
+
} finally {
|
|
335
|
+
$p.Dispose()
|
|
336
|
+
}
|
|
337
|
+
} catch {
|
|
338
|
+
[Console]::Error.WriteLine('anet could not be installed: ' + $_.Exception.Message)
|
|
339
|
+
} finally {
|
|
340
|
+
if ($null -ne $lock) { $lock.Dispose() }
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
|
|
169
344
|
# The .cmd file reads the selection through the code page of the console. A
|
|
170
345
|
# path with a character that this code page cannot represent is replaced by its
|
|
171
346
|
# short (8.3) form; when that does not help either, the path is refused rather
|
|
@@ -221,6 +396,10 @@ if ($mode -eq 'resolve') {
|
|
|
221
396
|
exit 0
|
|
222
397
|
}
|
|
223
398
|
if ($mode -eq 'locate') {
|
|
399
|
+
if ((Get-AnetEnv 'ANET_RUN_INSTALL') -eq 'missing' -and (Get-AnetEnv 'ANET_PLUGIN_SETTINGS') -eq 'env' -and
|
|
400
|
+
$AnetPath -eq '' -and -not (Test-AnetInstallOptOut) -and $null -eq (Find-AnetQuietly)) {
|
|
401
|
+
Install-AnetForMcp
|
|
402
|
+
}
|
|
224
403
|
try {
|
|
225
404
|
$exe = ConvertTo-AnetConsolePath (Find-AnetExecutable)
|
|
226
405
|
Test-AnetIdentity
|
package/bin/anet-run.sh
CHANGED
|
@@ -23,6 +23,26 @@
|
|
|
23
23
|
# to stderr with exit status 1.
|
|
24
24
|
set -u
|
|
25
25
|
|
|
26
|
+
# Programs (sh, sed, uname and the others) are found only in the absolute
|
|
27
|
+
# directories of PATH: a relative entry (such as "." or an empty one) would
|
|
28
|
+
# find a file of the working directory of the session, which can be an
|
|
29
|
+
# untrusted workspace. This comes before the first command that is not built
|
|
30
|
+
# into the shell, and the scripts started from here inherit it.
|
|
31
|
+
_abs=
|
|
32
|
+
_ifs=$IFS
|
|
33
|
+
IFS=:
|
|
34
|
+
set -f
|
|
35
|
+
for _d in ${PATH:-}; do
|
|
36
|
+
case $_d in
|
|
37
|
+
/*) _abs=${_abs:+$_abs:}$_d ;;
|
|
38
|
+
esac
|
|
39
|
+
done
|
|
40
|
+
IFS=$_ifs
|
|
41
|
+
set +f
|
|
42
|
+
PATH=${_abs:-/usr/bin:/bin}
|
|
43
|
+
export PATH
|
|
44
|
+
unset _abs _ifs _d
|
|
45
|
+
|
|
26
46
|
# read_settings prints two lines, anetPath and identity, from the environment
|
|
27
47
|
# of the caller. A host without a plugin settings store passes the two values
|
|
28
48
|
# as ANET_PLUGIN_BIN and ANET_PLUGIN_IDENTITY.
|
package/commands/anet-status.md
CHANGED
|
@@ -12,8 +12,8 @@ anet tools are not available in this session, run `<runner> guide status` instea
|
|
|
12
12
|
- Windows (PowerShell or cmd): `"${ANET_PLUGIN_ROOT}/bin/anet-run.cmd"`; in PowerShell, put `&` and a
|
|
13
13
|
space before the quoted path.
|
|
14
14
|
|
|
15
|
-
When the runner reports that anet is not installed or not running,
|
|
16
|
-
|
|
15
|
+
When the runner reports that anet is not installed or not running, run the `anet-setup` skill of
|
|
16
|
+
this plugin.
|
|
17
17
|
|
|
18
18
|
Do not change any setting, and do not read or edit the OpenCode configuration (`~/.config/opencode`, `opencode.json`);
|
|
19
19
|
the runner reads the plugin settings itself. Optional focus from the user: $ARGUMENTS
|
package/commands/anet.md
CHANGED
|
@@ -9,7 +9,8 @@ requests.
|
|
|
9
9
|
Request: $ARGUMENTS
|
|
10
10
|
|
|
11
11
|
If the request is empty, show the tasks that other agents sent to this node and the state of
|
|
12
|
-
the node, as the guide describes.
|
|
12
|
+
the node, as the guide describes. When the anet tools are not available in this session, run the
|
|
13
|
+
`anet-setup` skill of this plugin first, without asking.
|
|
13
14
|
|
|
14
15
|
`<runner>` is the runner of this plugin; run every `anet` command that the guide names through
|
|
15
16
|
it:
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agentnetwork/opencode-anet",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Delegate tasks to other AI agents over A2A through a local AgentNetwork (anet) node: find agents, send and track end-to-end encrypted tasks, settle priced skills within operator limits, and answer tasks sent to this node.",
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "Delegate tasks to other AI agents over A2A through a local AgentNetwork (anet) node: find agents, send and track end-to-end encrypted tasks, settle priced skills within operator limits, and answer tasks sent to this node. Enabling the plugin installs anet with the official signed installer, starts its node and joins the public hub; set ANET_PLUGIN_NO_INSTALL=1 to turn the installation off.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"anet",
|
|
7
7
|
"agentnetwork",
|
package/skills/anet/SKILL.md
CHANGED
|
@@ -9,6 +9,10 @@ This machine runs AgentNetwork through the `anet` program. The anet that is inst
|
|
|
9
9
|
the current guide to anet: what it can do, how to use it, and how to set it up. The guide
|
|
10
10
|
changes with every release of anet; this plugin does not, so it does not repeat the guide.
|
|
11
11
|
|
|
12
|
+
Enabling this plugin installs anet with the official installer, starts its node and joins the
|
|
13
|
+
public hub; the user's installation of the plugin is the consent to that. Act on anet; do not
|
|
14
|
+
describe it from this text.
|
|
15
|
+
|
|
12
16
|
## Read the guide first
|
|
13
17
|
|
|
14
18
|
Before the first anet action of a session, and whenever the user writes "@anet …", read the
|
|
@@ -16,8 +20,12 @@ guide and follow it:
|
|
|
16
20
|
|
|
17
21
|
- Call the tool `guide` of the `anet` MCP server, without arguments, or with the `topic` that
|
|
18
22
|
the guide names.
|
|
19
|
-
- When the anet tools are not available in this session, run
|
|
20
|
-
`<runner> guide <topic>`)
|
|
23
|
+
- When the anet tools are not available in this session, run the `anet-setup` skill of this
|
|
24
|
+
plugin at once, without asking first, and then `<runner> guide` (and `<runner> guide <topic>`).
|
|
25
|
+
|
|
26
|
+
A question about anet itself, such as what anet can do, and "@anet" without a request are
|
|
27
|
+
answered from the node: read the guide and do what it says for them, which shows the real state
|
|
28
|
+
of the node and what it can do now. Do not answer such a question from this skill alone.
|
|
21
29
|
|
|
22
30
|
When the user invokes this skill with a request, treat the request as an "@anet" request. With an
|
|
23
31
|
empty request, show the tasks that other agents sent to this node and the state of the node, as
|
|
@@ -37,7 +45,7 @@ executable or another identity than the plugin uses.
|
|
|
37
45
|
`${ANET_PLUGIN_ROOT}` is the environment variable `ANET_PLUGIN_ROOT`, which the plugin sets for the shell commands of the agent: in PowerShell write it as `$env:ANET_PLUGIN_ROOT`, in cmd as `%ANET_PLUGIN_ROOT%`. If it is empty, the plugin is not loaded: stop and tell the user.
|
|
38
46
|
|
|
39
47
|
`<runner> --resolve` prints the executable, its version, the identity, and in its `runner` line
|
|
40
|
-
the command to use on this machine. When it reports that anet is not found,
|
|
48
|
+
the command to use on this machine. When it reports that anet is not found, run the
|
|
41
49
|
`anet-setup` skill of this plugin.
|
|
42
50
|
|
|
43
51
|
## Rules that always apply
|
|
@@ -6,9 +6,8 @@ description: Find or install the anet command line and set up the local AgentNet
|
|
|
6
6
|
# Set up anet for OpenCode
|
|
7
7
|
|
|
8
8
|
This skill finds the anet executable that the plugin settings select, installs anet when it is
|
|
9
|
-
missing
|
|
10
|
-
|
|
11
|
-
complete output.
|
|
9
|
+
missing, and then follows the setup guide of the installed anet. Run each step, check its
|
|
10
|
+
result, and stop at the first step that fails; report the command and its complete output.
|
|
12
11
|
|
|
13
12
|
## 1. Find the runner
|
|
14
13
|
|
|
@@ -34,14 +33,20 @@ identity than the plugin uses.
|
|
|
34
33
|
configuration file, and do not install another copy.
|
|
35
34
|
- `executable: not found`: continue with step 2.
|
|
36
35
|
|
|
37
|
-
## 2. Install anet
|
|
36
|
+
## 2. Install anet
|
|
38
37
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
38
|
+
Installing this plugin is the user's consent to install anet: the MCP server of the plugin
|
|
39
|
+
installs it by itself when it starts without one. Do not ask again; tell the user in one sentence
|
|
40
|
+
that anet is being installed, and run the installer helper. Ask first, and wait for an explicit
|
|
41
|
+
yes, only when the user said that anet must not be installed, or turned the automatic
|
|
42
|
+
installation off with the environment variable `ANET_PLUGIN_NO_INSTALL=1`.
|
|
43
43
|
|
|
44
|
-
|
|
44
|
+
The official installer downloads anet from `https://agentnetwork.org.cn`, checks the signed
|
|
45
|
+
release manifest and the SHA-256 of the download, stops without changing anything when a check
|
|
46
|
+
fails, installs into a directory of this user without administrator rights, creates an identity
|
|
47
|
+
with safe defaults, starts the node and joins the public hub.
|
|
48
|
+
|
|
49
|
+
Run the installer helper of this plugin:
|
|
45
50
|
|
|
46
51
|
- Linux and macOS: `sh "${ANET_PLUGIN_ROOT}/bin/anet-install.sh"`. It downloads the official installer
|
|
47
52
|
`https://agentnetwork.org.cn/install.sh` into a new private directory, runs it, and removes the
|
|
@@ -50,9 +55,10 @@ After consent, run the installer helper of this plugin:
|
|
|
50
55
|
official installer `https://agentnetwork.org.cn/install.ps1` with Windows PowerShell.
|
|
51
56
|
|
|
52
57
|
Pass no options to the installer: this plugin already provides the MCP server and the skills to
|
|
53
|
-
OpenCode. When
|
|
54
|
-
|
|
55
|
-
|
|
58
|
+
OpenCode. When an installation that the MCP server started is still running, the helper waits for
|
|
59
|
+
it and installs nothing itself. When the command fails or prints a line beginning with `Error:`,
|
|
60
|
+
stop and report it. Otherwise run the runner with `--resolve` again; it finds the new
|
|
61
|
+
installation without a new session.
|
|
56
62
|
|
|
57
63
|
## 3. Follow the setup guide
|
|
58
64
|
|