direxio-deployer 0.1.1 → 0.1.2

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 CHANGED
@@ -23,6 +23,12 @@ Install the deployer skill from npm, then place it into the current agent runtim
23
23
 
24
24
  The GitHub repository keeps tests for maintainers and CI, but the published npm package and installed skill copy exclude `tests/` to keep user installs small.
25
25
 
26
+ If you want Codex to install and deploy in one instruction, do not say "install skills <GitHub URL>". That triggers GitHub skill installation and can place the skill in the global `~/.codex` directory. Say this instead:
27
+
28
+ ```text
29
+ Install the Direxio deployer skill in the current project via npm: run npm install -g direxio-deployer@latest, then run direxio-deployer skill install --agent codex --scope project --project .; do not install the skill from GitHub and do not install it globally under ~/.codex. After installation, use that skill to deploy Direxio with domain __DOMAIN__.
30
+ ```
31
+
26
32
  POSIX shells:
27
33
 
28
34
  ```bash
@@ -53,7 +59,7 @@ direxio-deployer skill install --agent codex --scope global
53
59
  The installer writes `.direxio-skill-install.json` into the target directory and refuses to overwrite unmanaged existing content unless `--force` is provided. To pin a version, install that package version first:
54
60
 
55
61
  ```bash
56
- npm install -g direxio-deployer@0.1.1
62
+ npm install -g direxio-deployer@0.1.2
57
63
  direxio-deployer skill update --agent codex --scope project --project .
58
64
  ```
59
65
 
@@ -120,7 +126,7 @@ bash scripts/orchestrate.sh
120
126
  ```
121
127
 
122
128
  Supported install modes: `recommended` and `cc-connect`.
123
- If `DIREXIO_AGENT_PLATFORM=auto` cannot identify a single supported runtime, set `DIREXIO_CC_CONNECT_AGENT` explicitly. For OpenClaw or Hermes defaults, force the host runtime with `DIREXIO_AGENT_PLATFORM=openclaw` or `DIREXIO_AGENT_PLATFORM=hermes`; setting only `DIREXIO_CC_CONNECT_AGENT=acp` selects generic ACP and requires manual options. For OpenClaw Gateway ACP, set `DIREXIO_OPENCLAW_ACP_URL`, `DIREXIO_OPENCLAW_ACP_TOKEN_FILE`, and `DIREXIO_OPENCLAW_ACP_SESSION` from the current OpenClaw runtime after pairing. Use `DIREXIO_OPENCLAW_ACP_ARGS_TOML` only when you need to provide the complete OpenClaw ACP args array yourself. Use `DIREXIO_HERMES_ACP_ARGS_TOML` for the child Hermes args; S6 prefixes the `hermes-acp-adapter -- <hermes-command>` wrapper automatically.
129
+ If `DIREXIO_AGENT_PLATFORM=auto` cannot identify a single supported runtime, set `DIREXIO_CC_CONNECT_AGENT` explicitly. For OpenClaw or Hermes defaults, force the host runtime with `DIREXIO_AGENT_PLATFORM=openclaw` or `DIREXIO_AGENT_PLATFORM=hermes`; setting only `DIREXIO_CC_CONNECT_AGENT=acp` selects generic ACP and requires manual options. OpenClaw Gateway ACP defaults to `["acp", "--session", "agent:main:main"]` and lets `openclaw acp` auto-detect the Gateway from `~/.openclaw/openclaw.json`. To force explicit Gateway settings, set all of `DIREXIO_OPENCLAW_ACP_URL`, `DIREXIO_OPENCLAW_ACP_TOKEN_FILE`, and `DIREXIO_OPENCLAW_ACP_SESSION` from the current OpenClaw runtime after pairing. Use `DIREXIO_OPENCLAW_ACP_ARGS_TOML` only when you need to provide the complete OpenClaw ACP args array yourself. Use `DIREXIO_HERMES_ACP_ARGS_TOML` for the child Hermes args; S6 prefixes the `hermes-acp-adapter -- <hermes-command>` wrapper automatically.
124
130
 
125
131
  Check status:
126
132
 
package/README_zh.md CHANGED
@@ -21,6 +21,12 @@
21
21
 
22
22
  GitHub 仓库保留测试用于维护和 CI,但发布到 npm 的包以及安装到智能体 skill 目录的副本不包含 `tests/`,以减小用户安装体积。
23
23
 
24
+ 如果你想让 Codex 一句话安装并开始部署,不要说“安装 skills <GitHub 链接>”。那会触发 GitHub skill 安装器,容易安装到全局 `~/.codex`。推荐这样说:
25
+
26
+ ```text
27
+ 请在当前项目用 npm 安装 Direxio deployer skill:运行 npm install -g direxio-deployer@latest,然后运行 direxio-deployer skill install --agent codex --scope project --project .;不要从 GitHub 安装 skill,不要安装到全局 ~/.codex。安装后使用该 skill 部署 Direxio 服务,域名使用 __DOMAIN__。
28
+ ```
29
+
24
30
  POSIX shell:
25
31
 
26
32
  ```bash
@@ -51,7 +57,7 @@ direxio-deployer skill install --agent codex --scope global
51
57
  安装器会在目标目录写入 `.direxio-skill-install.json`,并拒绝覆盖没有该 manifest 的既有目录,除非显式传入 `--force`。如需固定版本,先安装指定 npm 版本:
52
58
 
53
59
  ```bash
54
- npm install -g direxio-deployer@0.1.1
60
+ npm install -g direxio-deployer@0.1.2
55
61
  direxio-deployer skill update --agent codex --scope project --project .
56
62
  ```
57
63
 
@@ -117,7 +123,7 @@ bash scripts/orchestrate.sh
117
123
  ```
118
124
 
119
125
  可选安装模式:`recommended`、`cc-connect`。
120
- 如果 `DIREXIO_AGENT_PLATFORM=auto` 无法唯一识别当前运行时,显式设置 `DIREXIO_CC_CONNECT_AGENT`。需要触发 OpenClaw 或 Hermes 默认配置时,设置 `DIREXIO_AGENT_PLATFORM=openclaw` 或 `DIREXIO_AGENT_PLATFORM=hermes`;只设置 `DIREXIO_CC_CONNECT_AGENT=acp` 会进入通用 ACP,需要手动提供 options。OpenClaw Gateway ACP 必须在完成 pairing 后,从当前 OpenClaw runtime 填写 `DIREXIO_OPENCLAW_ACP_URL`、`DIREXIO_OPENCLAW_ACP_TOKEN_FILE` 和 `DIREXIO_OPENCLAW_ACP_SESSION`。只有需要完整覆盖 OpenClaw ACP args 数组时才使用 `DIREXIO_OPENCLAW_ACP_ARGS_TOML`;Hermes 自定义参数用 `DIREXIO_HERMES_ACP_ARGS_TOML`,S6 会自动在前面加上 `hermes-acp-adapter -- <hermes-command>`。
126
+ 如果 `DIREXIO_AGENT_PLATFORM=auto` 无法唯一识别当前运行时,显式设置 `DIREXIO_CC_CONNECT_AGENT`。需要触发 OpenClaw 或 Hermes 默认配置时,设置 `DIREXIO_AGENT_PLATFORM=openclaw` 或 `DIREXIO_AGENT_PLATFORM=hermes`;只设置 `DIREXIO_CC_CONNECT_AGENT=acp` 会进入通用 ACP,需要手动提供 options。OpenClaw Gateway ACP 默认写入 `["acp", "--session", "agent:main:main"]`,让 `openclaw acp` 从 `~/.openclaw/openclaw.json` 自动发现 Gateway。需要强制指定 Gateway 时,完成 pairing 后从当前 OpenClaw runtime 同时填写 `DIREXIO_OPENCLAW_ACP_URL`、`DIREXIO_OPENCLAW_ACP_TOKEN_FILE` 和 `DIREXIO_OPENCLAW_ACP_SESSION`。只有需要完整覆盖 OpenClaw ACP args 数组时才使用 `DIREXIO_OPENCLAW_ACP_ARGS_TOML`;Hermes 自定义参数用 `DIREXIO_HERMES_ACP_ARGS_TOML`,S6 会自动在前面加上 `hermes-acp-adapter -- <hermes-command>`。
121
127
 
122
128
  查看状态:
123
129
 
package/SKILL.md CHANGED
@@ -207,6 +207,18 @@ Step-by-step onboarding flow:
207
207
  - Give a short billing warning before the first mutating AWS command:
208
208
  "This will create paid AWS resources for the server. They keep billing
209
209
  until destroyed."
210
+ - When AWS CLI is available after credentials are verified, make a best
211
+ effort Free Tier account-plan check:
212
+ ```bash
213
+ aws freetier get-account-plan-state --output json
214
+ ```
215
+ If it returns `accountPlanRemainingCredits`, mention the remaining credit
216
+ amount and expiration without treating it as a guarantee. If the command
217
+ is unavailable or fails, use the fixed wording: "AWS currently advertises
218
+ 100 USD initial credits for new customer accounts, plus possible
219
+ additional credits after completing Free Tier activities. These credits
220
+ may cover a small trial deployment, but coverage is account-specific and
221
+ must be verified in AWS Billing Console."
210
222
  - **Provide an upfront monthly cost estimate** based on the selected
211
223
  region and instance type, so the user can decide whether to proceed.
212
224
  `scripts/orchestrate.sh` records `cost_estimate` in state before the
@@ -252,10 +264,15 @@ Step-by-step onboarding flow:
252
264
  - If the user asks what is billed, mention EC2/server, fixed public IPv4 or
253
265
  Elastic IP, storage, DNS, network traffic, and call relay traffic.
254
266
 
255
- Required first-time deployment confirmation:
267
+ Required first-time deployment confirmation. Fill in the concrete domain,
268
+ profile, and region, and include the Free Tier sentence immediately before the
269
+ confirmation line:
256
270
 
257
271
  ```text
258
- I confirm that I have an active AWS account, a real long-lived domain, and an AWS access key CSV or AWS profile for this deployment. I understand this can create billable AWS resources and that they keep billing until destroyed.
272
+ Please confirm before I deploy. AWS new customer accounts may have Free Tier credits, currently advertised as 100 USD initial credits plus possible additional credits; these credits may cover a small trial deployment, but actual coverage must be verified in AWS Billing Console.
273
+
274
+ Reply with this exact sentence:
275
+ I confirm that I have an active AWS account, the long-lived domain <domain>, and authorize the current <profile-or-identity> AWS profile in <region> to create the Direxio service. I understand this can create billable AWS resources, credits are not guaranteed to cover all usage, and resources keep billing until destroyed.
259
276
  ```
260
277
 
261
278
  If any prerequisite is missing, stop deployment and guide the user through that
@@ -280,6 +297,13 @@ Lightsail is a future deployment mode, not a current automatic option. Lightsail
280
297
 
281
298
  When the user asks to install or update this skill itself, or asks to wire Direxio into a local agent runtime, read `references/agent-targets.md` first. It is the source of truth for connent/connect agent targets, legacy host-runtime aliases, generic targets, and unknown targets.
282
299
 
300
+ If the user says "install skills" and includes the GitHub repository URL
301
+ `YingSuiAI/direxio-deployer`, do not use a generic GitHub skill installer for
302
+ normal deployment use. First install the npm package and then run
303
+ `direxio-deployer skill install --agent <runtime> --scope project --project
304
+ <project-root>`. Use a Git clone only when the user explicitly asks for
305
+ deployer development or local patching.
306
+
283
307
  For this skill repository itself, first determine whether the current working directory belongs to a project or workspace. Treat an explicit workspace root, project files, or an existing agent-specific directory such as `.codex/`, `.claude/`, `.gemini/`, `.cursor/`, `.github/copilot/`, `.devin/`, `.opencode/`, `.qoder/`, `.pi/`, `.openclaw/`, or `.hermes/` as a project target.
284
308
 
285
309
  If a project target exists, install or update this skill with the versioned npm CLI at the runtime-specific project-local path from `references/agent-targets.md`:
@@ -316,9 +340,9 @@ Post-deploy agent wiring is controlled by:
316
340
  ```bash
317
341
  DIREXIO_AGENT_PLATFORM=auto
318
342
  DIREXIO_CC_CONNECT_AGENT=<optional connect agent>
319
- DIREXIO_OPENCLAW_ACP_URL=<required for OpenClaw gateway URL>
320
- DIREXIO_OPENCLAW_ACP_TOKEN_FILE=<required for OpenClaw gateway token file>
321
- DIREXIO_OPENCLAW_ACP_SESSION=<required for OpenClaw ACP session>
343
+ DIREXIO_OPENCLAW_ACP_URL=<optional explicit OpenClaw gateway URL>
344
+ DIREXIO_OPENCLAW_ACP_TOKEN_FILE=<optional explicit OpenClaw gateway token file>
345
+ DIREXIO_OPENCLAW_ACP_SESSION=<optional OpenClaw ACP session; defaults to agent:main:main>
322
346
  DIREXIO_AGENT_INSTALL=recommend
323
347
  DIREXIO_AGENT_INSTALL_MODE=recommended
324
348
  ```
@@ -327,7 +351,7 @@ The only supported local conversation bridge is `direxio-connect`, installed fro
327
351
 
328
352
  The local MCP tool surface is `direxio-mcp`, installed from `direxio-mcp@latest` by default. S6 writes `mcp/codex.toml`, `mcp/openclaw.md`, `mcp/openclaw-server.json`, `mcp/hermes.mcp.json`, `mcp/mcp-servers.json`, and `mcp/env`; these artifacts point to `credentials.json` by `DIREXIO_CREDENTIALS_FILE`. OpenClaw must be configured through the generated `openclaw mcp set` command in `mcp/openclaw.md`; do not paste MCP JSON into `~/.openclaw/openclaw.json`. Keep this separate from cc-connect: cc-connect must use its direct Matrix config and must not use `DIREXIO_CREDENTIALS_FILE`.
329
353
 
330
- `DIREXIO_CC_CONNECT_AGENT` is the preferred explicit selector. Supported values match connent/connect: `acp`, `antigravity`, `claudecode`, `codex`, `copilot`, `cursor`, `devin`, `gemini`, `iflow`, `kimi`, `opencode`, `pi`, `qoder`, `reasonix`, and `tmux`. Detected OpenClaw and Hermes runtimes map to `cc_connect_agent=acp`; they are not native connect agent types. OpenClaw uses `cmd = "openclaw"` but S6 requires the current agent/operator to supply the real `DIREXIO_OPENCLAW_ACP_URL`, `DIREXIO_OPENCLAW_ACP_TOKEN_FILE`, and `DIREXIO_OPENCLAW_ACP_SESSION`; do not guess these values or reuse old chat output. Hermes uses `cmd = "direxio-connect"` with `args = ["hermes-acp-adapter", "--", "hermes", "acp"]` so the Direxio compatibility layer can suppress Hermes reasoning text before it reaches the Matrix room. Use `DIREXIO_CC_CONNECT_AGENT_CMD`, `DIREXIO_<AGENT>_COMMAND`, and when needed `DIREXIO_CC_CONNECT_AGENT_OPTIONS_TOML` for agent-specific launch details. OpenClaw and Hermes also accept `DIREXIO_OPENCLAW_COMMAND`, `DIREXIO_HERMES_COMMAND`, `DIREXIO_HERMES_ACP_ADAPTER_COMMAND`, `DIREXIO_OPENCLAW_ACP_ARGS_TOML`, and `DIREXIO_HERMES_ACP_ARGS_TOML`; Hermes custom args are child Hermes args and S6 prefixes the adapter wrapper automatically.
354
+ `DIREXIO_CC_CONNECT_AGENT` is the preferred explicit selector. Supported values match connent/connect: `acp`, `antigravity`, `claudecode`, `codex`, `copilot`, `cursor`, `devin`, `gemini`, `iflow`, `kimi`, `opencode`, `pi`, `qoder`, `reasonix`, and `tmux`. Detected OpenClaw and Hermes runtimes map to `cc_connect_agent=acp`; they are not native connect agent types. OpenClaw uses `cmd = "openclaw"` with args `["acp", "--session", "agent:main:main"]` by default, letting `openclaw acp` auto-discover the Gateway from `~/.openclaw/openclaw.json`. If the operator needs to force explicit Gateway settings, S6 requires all three real values from the current OpenClaw runtime after pairing: `DIREXIO_OPENCLAW_ACP_URL`, `DIREXIO_OPENCLAW_ACP_TOKEN_FILE`, and `DIREXIO_OPENCLAW_ACP_SESSION`; do not guess these values or reuse old chat output. Hermes uses `cmd = "direxio-connect"` with `args = ["hermes-acp-adapter", "--", "hermes", "acp"]` so the Direxio compatibility layer can suppress Hermes reasoning text before it reaches the Matrix room. Use `DIREXIO_CC_CONNECT_AGENT_CMD`, `DIREXIO_<AGENT>_COMMAND`, and when needed `DIREXIO_CC_CONNECT_AGENT_OPTIONS_TOML` for agent-specific launch details. OpenClaw and Hermes also accept `DIREXIO_OPENCLAW_COMMAND`, `DIREXIO_HERMES_COMMAND`, `DIREXIO_HERMES_ACP_ADAPTER_COMMAND`, `DIREXIO_OPENCLAW_ACP_ARGS_TOML`, and `DIREXIO_HERMES_ACP_ARGS_TOML`; Hermes custom args are child Hermes args and S6 prefixes the adapter wrapper automatically.
331
355
 
332
356
  `DIREXIO_AGENT_PLATFORM` describes the host runtime following the skill, while `DIREXIO_CC_CONNECT_AGENT` describes the local agent backend that `direxio-connect` should launch. Host runtimes such as Hermes or OpenClaw are not native cc-connect backend types; S6 maps them to the generic ACP backend by default and records `cc_connect_agent=acp`. Override `DIREXIO_CC_CONNECT_AGENT` only when the operator intentionally wants a different local backend.
333
357
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "direxio-deployer",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "Versioned Direxio deployer agent skill and portable deployment orchestration tools.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -6,6 +6,12 @@ Use this file when installing or updating this skill and when reviewing S6 local
6
6
 
7
7
  Prefer a project-local npm-managed install when a project or workspace exists. Install the versioned package, then let the CLI copy the skill bundle into the runtime-specific target:
8
8
 
9
+ Do not use a generic "install skills <GitHub URL>" instruction for normal users. That can invoke a host's GitHub skill installer and place this repository under the global runtime directory before the npm-managed installer runs. For Codex, the project-local instruction is:
10
+
11
+ ```text
12
+ Install the Direxio deployer skill in the current project via npm: run npm install -g direxio-deployer@latest, then run direxio-deployer skill install --agent codex --scope project --project .; do not install the skill from GitHub and do not install it globally under ~/.codex.
13
+ ```
14
+
9
15
  POSIX shells:
10
16
 
11
17
  ```bash
@@ -125,4 +131,4 @@ Use `mcp/codex.toml` for Codex and `mcp/hermes.mcp.json` for Hermes. For OpenCla
125
131
 
126
132
  Prefer `DIREXIO_CC_CONNECT_AGENT=<agent>` to choose the local agent that `direxio-connect` should run. Keep `DIREXIO_AGENT_PLATFORM=<runtime>` for auto-detection overrides and legacy host-runtime naming. Use `DIREXIO_AGENT_INSTALL_MODE=cc-connect` only when overriding the default `recommended` mapping explicitly.
127
133
  Use `DIREXIO_CC_CONNECT_AGENT_OPTIONS_TOML` for agent-specific options that cannot be represented by `work_dir` or `cmd`; for example `reasonix` requires `serve_url`, `tmux` requires `session`, and generic `acp` requires a command when `DIREXIO_CC_CONNECT_AGENT_CMD` is not enough.
128
- For OpenClaw Gateway ACP, complete OpenClaw pairing first, then set `DIREXIO_OPENCLAW_ACP_URL`, `DIREXIO_OPENCLAW_ACP_TOKEN_FILE`, and `DIREXIO_OPENCLAW_ACP_SESSION` from the current OpenClaw runtime. S6 writes `["acp", "--url", <url>, "--token-file", <local path>, "--session", <session>]` and converts the token-file with `DIREXIO_LOCAL_PATH_STYLE`. `DIREXIO_OPENCLAW_ACP_ARGS_TOML` replaces the OpenClaw ACP args array only when the runtime needs a fully custom argument list. `DIREXIO_HERMES_ACP_ARGS_TOML` supplies the child Hermes args and keeps the Direxio adapter prefix.
134
+ For OpenClaw Gateway ACP, S6 defaults to `["acp", "--session", "agent:main:main"]` and lets `openclaw acp` auto-discover the Gateway from `~/.openclaw/openclaw.json`. To force an explicit Gateway, complete OpenClaw pairing first, then set all of `DIREXIO_OPENCLAW_ACP_URL`, `DIREXIO_OPENCLAW_ACP_TOKEN_FILE`, and `DIREXIO_OPENCLAW_ACP_SESSION` from the current OpenClaw runtime. S6 writes `["acp", "--url", <url>, "--token-file", <local path>, "--session", <session>]` and converts the token-file with `DIREXIO_LOCAL_PATH_STYLE`. `DIREXIO_OPENCLAW_ACP_ARGS_TOML` replaces the OpenClaw ACP args array only when the runtime needs a fully custom argument list. `DIREXIO_HERMES_ACP_ARGS_TOML` supplies the child Hermes args and keeps the Direxio adapter prefix.
@@ -55,9 +55,13 @@ bash scripts/pricing-estimate.sh --state ~/.direxio/nodes/<service_id>/state.jso
55
55
  selection and refreshes it in S3 after the final EC2 instance type is known.
56
56
  The estimate includes EC2, gp3 storage, public IPv4, and Route53 hosted-zone
57
57
  cost when applicable. It excludes data transfer, TURN relay traffic, domain
58
- registration, taxes, and AWS credits. Credit coverage is not guaranteed; verify
59
- credits and actual charges in AWS Billing Console, and set an AWS Budget or
60
- billing alert before leaving the node running.
58
+ registration, taxes, and AWS credits. When available, check the Free Tier
59
+ account plan with `aws freetier get-account-plan-state --output json`;
60
+ otherwise tell the user that AWS currently advertises 100 USD initial credits
61
+ for new customer accounts plus possible additional credits after Free Tier
62
+ activities. Credit coverage is not guaranteed; verify credits and actual
63
+ charges in AWS Billing Console, and set an AWS Budget or billing alert before
64
+ leaving the node running.
61
65
 
62
66
  ## Destroy
63
67
 
@@ -112,9 +112,9 @@ DIREXIO_<AGENT>_COMMAND=<optional agent-specific executable path>
112
112
  DIREXIO_CC_CONNECT_AGENT_OPTIONS_TOML=<optional extra TOML under projects.agent.options>
113
113
  DIREXIO_OPENCLAW_COMMAND=<optional OpenClaw executable path>
114
114
  DIREXIO_HERMES_COMMAND=<optional Hermes executable path>
115
- DIREXIO_OPENCLAW_ACP_URL=<required OpenClaw gateway URL>
116
- DIREXIO_OPENCLAW_ACP_TOKEN_FILE=<required OpenClaw ACP token file>
117
- DIREXIO_OPENCLAW_ACP_SESSION=<required OpenClaw ACP session>
115
+ DIREXIO_OPENCLAW_ACP_URL=<optional explicit OpenClaw gateway URL>
116
+ DIREXIO_OPENCLAW_ACP_TOKEN_FILE=<optional explicit OpenClaw ACP token file>
117
+ DIREXIO_OPENCLAW_ACP_SESSION=<optional OpenClaw ACP session; defaults to agent:main:main>
118
118
  DIREXIO_OPENCLAW_ACP_ARGS_TOML=<optional OpenClaw ACP TOML array>
119
119
  DIREXIO_HERMES_ACP_ARGS_TOML=<optional Hermes ACP TOML array>
120
120
  DIREXIO_CC_CONNECT_NPM_PACKAGE=direxio-connent@latest
@@ -131,11 +131,11 @@ DIREXIO_SPEECH_LANGUAGE=zh
131
131
  Defaults:
132
132
 
133
133
  - `DIREXIO_CC_CONNECT_AGENT` is the preferred explicit selector. It accepts every connent/connect agent: `acp`, `antigravity`, `claudecode`, `codex`, `copilot`, `cursor`, `devin`, `gemini`, `iflow`, `kimi`, `opencode`, `pi`, `qoder`, `reasonix`, and `tmux`.
134
- - `DIREXIO_AGENT_PLATFORM=auto` detects the local agent runtime and maps it to a `direxio-connect` agent type only when it can identify one unambiguously. OpenClaw and Hermes map to the generic `acp` connect agent. OpenClaw requires explicit real ACP Gateway settings from the current runtime; Hermes uses the `direxio-connect hermes-acp-adapter -- hermes acp` compatibility wrapper by default.
134
+ - `DIREXIO_AGENT_PLATFORM=auto` detects the local agent runtime and maps it to a `direxio-connect` agent type only when it can identify one unambiguously. OpenClaw and Hermes map to the generic `acp` connect agent. OpenClaw uses `openclaw acp --session agent:main:main` by default and lets OpenClaw discover its Gateway config; Hermes uses the `direxio-connect hermes-acp-adapter -- hermes acp` compatibility wrapper by default.
135
135
  - `DIREXIO_LOCAL_PATH_STYLE=windows` writes Windows-compatible `data_dir`, `work_dir`, config paths, and install commands. `scripts/orchestrate.ps1` sets this automatically. Linux, macOS, and WSL Bash runs should leave the default `posix` style. Windows Git Bash/MSYS2 users who run `scripts/orchestrate.sh` directly must set `DIREXIO_LOCAL_PATH_STYLE=windows` when the local bridge is a Windows process.
136
136
  - `DIREXIO_CC_CONNECT_AGENT_CMD` writes `cmd = "<path>"` into `[projects.agent.options]`. Agent-specific forms such as `DIREXIO_CODEX_COMMAND`, `DIREXIO_CLAUDE_CODE_COMMAND`, `DIREXIO_GEMINI_COMMAND`, `DIREXIO_OPENCODE_COMMAND`, `DIREXIO_QODERCLI_COMMAND`, and `DIREXIO_OPENCLAW_COMMAND` are also accepted. For Hermes, `DIREXIO_HERMES_COMMAND` selects the child Hermes executable behind the adapter, while `DIREXIO_HERMES_ACP_ADAPTER_COMMAND` overrides the adapter command itself.
137
137
  - `DIREXIO_CC_CONNECT_AGENT_OPTIONS_TOML` appends agent-specific options under `[projects.agent.options]`; use it for agents with required non-command options such as `reasonix` (`serve_url`) or `tmux` (`session`).
138
- - OpenClaw Gateway ACP uses `DIREXIO_OPENCLAW_ACP_URL`, `DIREXIO_OPENCLAW_ACP_TOKEN_FILE`, and `DIREXIO_OPENCLAW_ACP_SESSION` to write `--url`, `--token-file`, and `--session`. Complete OpenClaw pairing first and use the real session that should receive Direxio messages; do not guess a default session or reuse old chat output.
138
+ - OpenClaw Gateway ACP auto-detects the Gateway from `~/.openclaw/openclaw.json` when `DIREXIO_OPENCLAW_ACP_URL` and `DIREXIO_OPENCLAW_ACP_TOKEN_FILE` are unset. It uses `DIREXIO_OPENCLAW_ACP_SESSION` when provided, otherwise `agent:main:main`. To force explicit Gateway settings, complete OpenClaw pairing first and set all three real values: `DIREXIO_OPENCLAW_ACP_URL`, `DIREXIO_OPENCLAW_ACP_TOKEN_FILE`, and `DIREXIO_OPENCLAW_ACP_SESSION`.
139
139
  - `DIREXIO_OPENCLAW_ACP_ARGS_TOML` replaces the generated OpenClaw ACP args array, for example `["acp", "--url", "wss://gateway.example.test:18789", "--token-file", "$HOME/.openclaw/gateway.token", "--session", "agent:main:main"]`. `DIREXIO_HERMES_ACP_ARGS_TOML` supplies the child Hermes args; S6 prefixes `["hermes-acp-adapter", "--", "<hermes-command>"]` automatically.
140
140
  - `DIREXIO_AGENT_INSTALL=recommend` prints and records the command only.
141
141
  - `DIREXIO_AGENT_INSTALL=auto` runs `npm install -g direxio-connent@latest` and then installs the `direxio-connect` daemon with the generated config and `--service-name <service_id>`. It is recorded as installed only when `direxio-connect daemon status --service-name <service_id>` reports `Status: Running` and recent daemon logs do not show ACP session initialization failure; otherwise S6 records `agent_install_status=install_failed`.
@@ -26,6 +26,7 @@ child.stderr.on("data", (chunk) => {
26
26
  child.stdout.on("data", (chunk) => {
27
27
  stdout = Buffer.concat([stdout, chunk]);
28
28
  readFrames();
29
+ if (completed) return;
29
30
  if (responses.has(2)) {
30
31
  const response = responses.get(2);
31
32
  const tools = Array.isArray(response?.result?.tools) ? response.result.tools : [];
@@ -60,35 +61,78 @@ send({ jsonrpc: "2.0", method: "notifications/initialized", params: {} });
60
61
  send({ jsonrpc: "2.0", id: 2, method: "tools/list", params: {} });
61
62
 
62
63
  function send(message) {
63
- child.stdin.write(`${JSON.stringify(message)}\n`);
64
+ const body = JSON.stringify(message);
65
+ child.stdin.write(`Content-Length: ${Buffer.byteLength(body, "utf8")}\r\n\r\n${body}`);
64
66
  }
65
67
 
66
68
  function readFrames() {
67
69
  while (true) {
68
- const headerEnd = stdout.indexOf("\r\n\r\n");
69
- if (headerEnd >= 0) {
70
- const header = stdout.subarray(0, headerEnd).toString("utf8");
71
- const match = /^Content-Length:\s*(\d+)/im.exec(header);
72
- if (match) {
73
- const length = Number.parseInt(match[1], 10);
74
- const bodyStart = headerEnd + 4;
75
- if (stdout.length < bodyStart + length) return;
76
- const body = stdout.subarray(bodyStart, bodyStart + length).toString("utf8");
77
- stdout = stdout.subarray(bodyStart + length);
78
- recordMessage(JSON.parse(body));
79
- continue;
70
+ if (stdout.length === 0) return;
71
+ if (stdout[0] === 10 || stdout[0] === 13) {
72
+ stdout = stdout.subarray(1);
73
+ continue;
74
+ }
75
+ if (startsWithHeader(stdout, "Content-Length:")) {
76
+ const header = readHeader(stdout);
77
+ if (!header) return;
78
+ const contentLength = parseContentLength(header.text);
79
+ if (!Number.isSafeInteger(contentLength) || contentLength < 0) {
80
+ finishWithError("MCP response frame is missing a valid Content-Length header");
81
+ return;
80
82
  }
83
+ const messageEnd = header.bodyStart + contentLength;
84
+ if (stdout.length < messageEnd) return;
85
+ const body = stdout.subarray(header.bodyStart, messageEnd).toString("utf8");
86
+ stdout = stdout.subarray(messageEnd);
87
+ handleMessage(body);
88
+ if (completed) return;
89
+ continue;
81
90
  }
91
+
82
92
  const lineEnd = stdout.indexOf("\n");
83
93
  if (lineEnd < 0) return;
84
94
  const line = stdout.subarray(0, lineEnd).toString("utf8").replace(/\r$/, "");
85
95
  stdout = stdout.subarray(lineEnd + 1);
86
96
  if (line.length === 0) continue;
87
- recordMessage(JSON.parse(line));
97
+ handleMessage(line);
98
+ if (completed) return;
99
+ }
100
+ }
101
+
102
+ function startsWithHeader(buffer, header) {
103
+ return buffer.subarray(0, header.length).toString("utf8").toLowerCase() === header.toLowerCase();
104
+ }
105
+
106
+ function readHeader(buffer) {
107
+ let marker = "\r\n\r\n";
108
+ let headerEnd = buffer.indexOf(marker);
109
+ if (headerEnd < 0) {
110
+ marker = "\n\n";
111
+ headerEnd = buffer.indexOf(marker);
112
+ }
113
+ if (headerEnd < 0) return null;
114
+ return {
115
+ text: buffer.subarray(0, headerEnd).toString("utf8"),
116
+ bodyStart: headerEnd + marker.length
117
+ };
118
+ }
119
+
120
+ function parseContentLength(headerText) {
121
+ for (const line of headerText.split(/\r?\n/)) {
122
+ const match = /^content-length:\s*(\d+)\s*$/i.exec(line);
123
+ if (match) return Number.parseInt(match[1], 10);
88
124
  }
125
+ return NaN;
89
126
  }
90
127
 
91
- function recordMessage(message) {
128
+ function handleMessage(raw) {
129
+ let message;
130
+ try {
131
+ message = JSON.parse(raw);
132
+ } catch (error) {
133
+ finishWithError(`invalid MCP JSON response: ${error.message}`);
134
+ return;
135
+ }
92
136
  if (typeof message.id !== "undefined") {
93
137
  responses.set(message.id, message);
94
138
  }
@@ -395,6 +395,25 @@ ensure_cost_estimate() {
395
395
  else
396
396
  warn "Could not write AWS cost estimate. Continue only after giving the user a manual billing estimate."
397
397
  fi
398
+ ensure_free_tier_credit_notice
399
+ }
400
+
401
+ ensure_free_tier_credit_notice() {
402
+ local output plan_status plan_type amount unit expires
403
+ if output=$(aws freetier get-account-plan-state --output json 2>/dev/null); then
404
+ plan_type=$(printf '%s\n' "$output" | json_stdin_get accountPlanType "unknown" 2>/dev/null)
405
+ plan_status=$(printf '%s\n' "$output" | json_stdin_get accountPlanStatus "unknown" 2>/dev/null)
406
+ amount=$(printf '%s\n' "$output" | json_stdin_get accountPlanRemainingCredits.amount "" 2>/dev/null)
407
+ unit=$(printf '%s\n' "$output" | json_stdin_get accountPlanRemainingCredits.unit "USD" 2>/dev/null)
408
+ expires=$(printf '%s\n' "$output" | json_stdin_get accountPlanExpirationDate "" 2>/dev/null)
409
+ if [ -n "$amount" ]; then
410
+ log "AWS Free Tier plan: type=${plan_type:-unknown}, status=${plan_status:-unknown}, remaining_credits=${amount} ${unit:-USD}${expires:+, expires=$expires}."
411
+ warn "Credits can reduce actual charges, but AWS resources still accrue charges until destroyed; verify credit coverage in AWS Billing Console."
412
+ return 0
413
+ fi
414
+ fi
415
+ warn "AWS new customer accounts may include Free Tier credits, currently advertised as 100 USD initial credits plus possible additional credits."
416
+ warn "Credits may cover a small trial deployment, but coverage is account-specific; verify credits in AWS Billing Console and destroy the node when finished."
398
417
  }
399
418
 
400
419
  precheck_new_deploy_domain_env() {
@@ -572,15 +572,21 @@ _openclaw_acp_args_toml() {
572
572
  url=${DIREXIO_OPENCLAW_ACP_URL:-}
573
573
  token_file=${DIREXIO_OPENCLAW_ACP_TOKEN_FILE:-}
574
574
  session=${DIREXIO_OPENCLAW_ACP_SESSION:-}
575
- [ -n "$url" ] || missing="${missing} DIREXIO_OPENCLAW_ACP_URL"
576
- [ -n "$token_file" ] || missing="${missing} DIREXIO_OPENCLAW_ACP_TOKEN_FILE"
577
- [ -n "$session" ] || missing="${missing} DIREXIO_OPENCLAW_ACP_SESSION"
578
- if [ -n "$missing" ]; then
579
- fail "OpenClaw ACP requires real Gateway settings:${missing}. Set them from the current OpenClaw runtime, or provide DIREXIO_OPENCLAW_ACP_ARGS_TOML with the complete args array."
575
+ if [ -n "$url" ] && [ -n "$token_file" ] && [ -n "$session" ]; then
576
+ token_file=$(_local_connect_path "$token_file")
577
+ _toml_array acp --url "$url" --token-file "$token_file" --session "$session"
578
+ return 0
579
+ fi
580
+ if [ -n "$url" ] || [ -n "$token_file" ]; then
581
+ [ -n "$url" ] || missing="${missing} DIREXIO_OPENCLAW_ACP_URL"
582
+ [ -n "$token_file" ] || missing="${missing} DIREXIO_OPENCLAW_ACP_TOKEN_FILE"
583
+ [ -n "$session" ] || missing="${missing} DIREXIO_OPENCLAW_ACP_SESSION"
584
+ fail "OpenClaw ACP explicit Gateway settings are incomplete:${missing}. Set all of DIREXIO_OPENCLAW_ACP_URL, DIREXIO_OPENCLAW_ACP_TOKEN_FILE, and DIREXIO_OPENCLAW_ACP_SESSION; otherwise leave URL/token-file unset so openclaw acp can auto-detect from its config."
580
585
  return 1
581
586
  fi
582
- token_file=$(_local_connect_path "$token_file")
583
- _toml_array acp --url "$url" --token-file "$token_file" --session "$session"
587
+ # Fallback: OpenClaw acp auto-discovers gateway from ~/.openclaw/openclaw.json.
588
+ warn "OpenClaw ACP: Gateway URL/token-file not set; using session '${session:-agent:main:main}' and letting openclaw acp auto-detect the Gateway from its config."
589
+ _toml_array acp --session "${session:-agent:main:main}"
584
590
  }
585
591
 
586
592
  _hermes_acp_args_toml() {