direxio-deployer 0.1.7 → 0.1.9
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/LICENSE +1 -1
- package/README.md +17 -9
- package/README_zh.md +15 -9
- package/SKILL.md +73 -29
- package/agents/README.md +5 -5
- package/agents/openai.yaml +3 -3
- package/package.json +1 -1
- package/references/agent-targets.md +1 -1
- package/references/architecture.md +4 -4
- package/references/bug-history.md +2 -2
- package/references/deployment-lessons.md +10 -9
- package/references/deployment-optimization-audit.md +14 -10
- package/references/deployment-workflow.md +29 -22
- package/references/iam-policy.json +1 -1
- package/references/runtime-wiring.md +2 -2
- package/references/state-machine.md +1 -1
- package/references/token-refresh.md +3 -1
- package/references/tooling.md +6 -3
- package/references/user-journey.md +1 -1
- package/references/verification-recovery.md +11 -5
- package/references/voip-turn-runbook.md +2 -2
- package/scripts/cloud-init/docker-compose.yml +7 -7
- package/scripts/cloud-init/init-tokens.sh +4 -4
- package/scripts/destroy.ps1 +3 -3
- package/scripts/destroy.sh +9 -9
- package/scripts/json.mjs +2 -0
- package/scripts/lib/paths.sh +1 -3
- package/scripts/lib/state.sh +9 -9
- package/scripts/orchestrate.ps1 +3 -3
- package/scripts/orchestrate.sh +18 -19
- package/scripts/phases/s2_domain.sh +4 -4
- package/scripts/phases/s3_provision.sh +6 -6
- package/scripts/phases/s5_init_tokens.sh +1 -1
- package/scripts/phases/s6_wire_local.sh +23 -1
- package/scripts/reset-app-data.sh +1 -1
- package/scripts/update.sh +2 -10
|
@@ -31,15 +31,19 @@ DOMAIN=__DOMAIN__ bash scripts/orchestrate.sh status
|
|
|
31
31
|
If state has resources, require one:
|
|
32
32
|
|
|
33
33
|
```bash
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
DIREXIO_EXISTING_STATE_ACTION=continue
|
|
35
|
+
DIREXIO_EXISTING_STATE_ACTION=destroy
|
|
36
36
|
DOMAIN=<different-domain>
|
|
37
37
|
```
|
|
38
38
|
|
|
39
|
-
For first-time credentials,
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
39
|
+
For first-time credentials, offer the operator two paths before provisioning:
|
|
40
|
+
root access key or dedicated IAM deployment user. The root path is the fastest
|
|
41
|
+
because it uses the account owner identity directly, but it is highly
|
|
42
|
+
privileged; tell the operator to save the CSV securely, never paste or commit
|
|
43
|
+
it, and rotate or delete the root key after deployment. The dedicated
|
|
44
|
+
`DirexioDeployer` IAM user path is safer because it avoids root keys, but it
|
|
45
|
+
requires more AWS console steps. Import the selected AWS access-key CSV and
|
|
46
|
+
verify the identity before provisioning:
|
|
43
47
|
|
|
44
48
|
```bash
|
|
45
49
|
bash scripts/aws-credentials.sh import-csv /path/to/accessKeys.csv direxio-deployer <region>
|
|
@@ -98,14 +102,14 @@ Destroy allows root AWS access-key identity when the operator explicitly chose
|
|
|
98
102
|
root credentials. Use the same deployment profile for teardown that was used
|
|
99
103
|
for provisioning.
|
|
100
104
|
|
|
101
|
-
Use `
|
|
105
|
+
Use `DIREXIO_KEEP_WORKDIR=1 DOMAIN=__DOMAIN__ bash scripts/destroy.sh` on POSIX, or set `$env:DIREXIO_KEEP_WORKDIR = "1"` before `.\scripts\destroy.ps1` on Windows, only when preserving local state files for debugging; if used, report that the service directory still exists.
|
|
102
106
|
|
|
103
107
|
## Run
|
|
104
108
|
|
|
105
109
|
From the repository root:
|
|
106
110
|
|
|
107
111
|
```bash
|
|
108
|
-
AWS_PROFILE=
|
|
112
|
+
AWS_PROFILE=direxio-deployer \
|
|
109
113
|
AWS_DEFAULT_REGION=us-east-1 \
|
|
110
114
|
DOMAIN=__DOMAIN__ \
|
|
111
115
|
DOMAIN_MODE=user \
|
|
@@ -149,19 +153,22 @@ reminders, `billing.cost_estimate`, destroy read-back evidence under
|
|
|
149
153
|
contain the initialization code, AWS secrets, access tokens, agent tokens, or
|
|
150
154
|
Matrix session tokens. User/runtime evidence is also scrubbed for
|
|
151
155
|
eight-or-more digit numeric strings because users may paste initialization
|
|
152
|
-
codes into confirmation notes. After
|
|
156
|
+
codes into confirmation notes. After reset/redeploy, the report must show
|
|
153
157
|
`credentials.status=refresh_pending`, `connect.install_status=refresh_pending`,
|
|
154
158
|
and `mcp.status=refresh_pending` until S5/S6/S7 and runtime checks refresh
|
|
155
|
-
local evidence.
|
|
159
|
+
local evidence. Image-only update does not clear local credentials,
|
|
160
|
+
confirmations, runtime checks, cc-connect state, or MCP artifacts.
|
|
156
161
|
|
|
157
162
|
When the user or runtime evidence confirms a manual product gate, write it back
|
|
158
163
|
to state before regenerating the report. Connect daemon status is a
|
|
159
164
|
service-scoped local bridge check, MCP doctor is a non-polluting runtime check,
|
|
160
165
|
MCP tools is stdio `tools/list` discovery, and MCP smoke is a read-only backend
|
|
161
|
-
call. In the
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
166
|
+
call. In the `DIREXIO_AGENT_INSTALL=recommend` path, `verify runtime` records
|
|
167
|
+
`connect_daemon=manual_pending` instead of failing the aggregate, because
|
|
168
|
+
daemon installation is an explicit operator action. The default
|
|
169
|
+
`DIREXIO_AGENT_INSTALL=auto` path expects cc-connect and direxio-mcp to be
|
|
170
|
+
installed automatically during S6. These checks are not the full runtime
|
|
171
|
+
product gate:
|
|
165
172
|
|
|
166
173
|
```bash
|
|
167
174
|
DOMAIN=__DOMAIN__ bash scripts/orchestrate.sh verify runtime
|
|
@@ -201,7 +208,7 @@ data:
|
|
|
201
208
|
|
|
202
209
|
```bash
|
|
203
210
|
DOMAIN=__DOMAIN__ MESSAGE_SERVER_IMAGE=direxio/message-server:latest bash scripts/update.sh
|
|
204
|
-
|
|
211
|
+
DIREXIO_EXISTING_STATE_ACTION=continue DOMAIN=__DOMAIN__ bash scripts/orchestrate.sh
|
|
205
212
|
```
|
|
206
213
|
|
|
207
214
|
`update.sh` SSHes to the recorded EC2 instance, runs Docker Compose pull/up,
|
|
@@ -218,7 +225,7 @@ TLS volumes:
|
|
|
218
225
|
|
|
219
226
|
```bash
|
|
220
227
|
DIREXIO_RESET_APP_DATA_CONFIRM=1 DOMAIN=__DOMAIN__ bash scripts/reset-app-data.sh
|
|
221
|
-
|
|
228
|
+
DIREXIO_EXISTING_STATE_ACTION=continue DOMAIN=__DOMAIN__ bash scripts/orchestrate.sh
|
|
222
229
|
```
|
|
223
230
|
|
|
224
231
|
`reset-app-data.sh` removes only `postgres-data`, `message-config`, and
|
|
@@ -254,9 +261,9 @@ If rate-limited, the log shows `retry after <timestamp> UTC`.
|
|
|
254
261
|
```
|
|
255
262
|
Once the endpoint returns 200, re-run orchestrate.sh to complete:
|
|
256
263
|
```bash
|
|
257
|
-
|
|
264
|
+
DIREXIO_EXISTING_STATE_ACTION=continue \
|
|
258
265
|
DNS_READY=1 \
|
|
259
|
-
AWS_PROFILE=
|
|
266
|
+
AWS_PROFILE=direxio-deployer \
|
|
260
267
|
AWS_DEFAULT_REGION=us-east-1 \
|
|
261
268
|
DOMAIN=<DOMAIN> \
|
|
262
269
|
DOMAIN_MODE=route53 \
|
|
@@ -291,7 +298,7 @@ that the old IP is safe to replace:
|
|
|
291
298
|
|
|
292
299
|
```bash
|
|
293
300
|
DIREXIO_CONFIRM_DNS_OVERWRITE=1 \
|
|
294
|
-
|
|
301
|
+
DIREXIO_EXISTING_STATE_ACTION=continue \
|
|
295
302
|
DOMAIN=__DOMAIN__ \
|
|
296
303
|
DOMAIN_MODE=route53 \
|
|
297
304
|
CONFIRM_DOMAIN_BINDING=1 \
|
|
@@ -308,7 +315,7 @@ node scripts/json.mjs get ~/.direxio/nodes/<service_id>/state.json resources
|
|
|
308
315
|
After authoritative DNS returns the new IP, continue with the same state:
|
|
309
316
|
|
|
310
317
|
```bash
|
|
311
|
-
|
|
318
|
+
DIREXIO_EXISTING_STATE_ACTION=continue \
|
|
312
319
|
DOMAIN=__DOMAIN__ \
|
|
313
320
|
DOMAIN_MODE=route53 \
|
|
314
321
|
CONFIRM_DOMAIN_BINDING=1 \
|
|
@@ -334,14 +341,14 @@ After authoritative DNS returns the new IP:
|
|
|
334
341
|
|
|
335
342
|
```bash
|
|
336
343
|
DNS_READY=1 \
|
|
337
|
-
AWS_PROFILE=
|
|
344
|
+
AWS_PROFILE=direxio-deployer \
|
|
338
345
|
AWS_DEFAULT_REGION=us-east-1 \
|
|
339
346
|
DOMAIN=__DOMAIN__ \
|
|
340
347
|
DOMAIN_MODE=user \
|
|
341
348
|
CONFIRM_DOMAIN_BINDING=1 \
|
|
342
349
|
INSTANCE_TYPE=t3.small \
|
|
343
350
|
MESSAGE_SERVER_IMAGE=direxio/message-server:latest \
|
|
344
|
-
|
|
351
|
+
DIREXIO_EXISTING_STATE_ACTION=continue \
|
|
345
352
|
bash scripts/orchestrate.sh
|
|
346
353
|
```
|
|
347
354
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"Version": "2012-10-17",
|
|
3
|
-
"Comment": "
|
|
3
|
+
"Comment": "Direxio 一键部署所需的最小 IAM 权限。用户建 IAM 用户时附加此策略,再为其生成 AK/SK 交给 agent。比给 AdministratorAccess 安全得多。",
|
|
4
4
|
"Statement": [
|
|
5
5
|
{
|
|
6
6
|
"Sid": "Preflight",
|
|
@@ -137,8 +137,8 @@ Defaults:
|
|
|
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
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
|
-
- `DIREXIO_AGENT_INSTALL=
|
|
141
|
-
- `DIREXIO_AGENT_INSTALL=
|
|
140
|
+
- `DIREXIO_AGENT_INSTALL=auto` is the default. It runs `npm install -g direxio-connent@latest`, installs the `direxio-connect` daemon with the generated config and `--service-name <service_id>`, and runs `npm install -g direxio-mcp@latest`. cc-connect 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`. MCP records `mcp_install_status=installed` only when npm succeeds.
|
|
141
|
+
- `DIREXIO_AGENT_INSTALL=recommend` prints and records commands only. `verify runtime` records the daemon check as `manual_pending` in this mode and still verifies MCP doctor/tools/smoke when the MCP command is available.
|
|
142
142
|
- `DIREXIO_AGENT_INSTALL_MODE=recommended` maps every supported local runtime to `cc-connect`.
|
|
143
143
|
- Speech defaults to `DIREXIO_SPEECH_PROVIDER=openai` and `DIREXIO_SPEECH_LANGUAGE=zh`. Provider-specific keys are also accepted: `DIREXIO_SPEECH_OPENAI_API_KEY` or `OPENAI_API_KEY`, `DIREXIO_SPEECH_GROQ_API_KEY` or `GROQ_API_KEY`, `DIREXIO_SPEECH_QWEN_API_KEY` or `DASHSCOPE_API_KEY`, and `DIREXIO_SPEECH_GEMINI_API_KEY`, `GEMINI_API_KEY`, or `GOOGLE_API_KEY`. Set `DIREXIO_SPEECH_ENABLED=false` to suppress speech config generation even when a key exists.
|
|
144
144
|
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
|
|
18
18
|
- `postgres`: PostgreSQL 18,数据卷 `/var/lib/postgresql`。
|
|
19
19
|
- `message-init`: 生成 Direxio message-server 配置和 TURN 配置。
|
|
20
|
-
- `message-server`: 运行 Matrix +
|
|
20
|
+
- `message-server`: 运行 Matrix + Direxio 统一后端,公开容器内 8008。
|
|
21
21
|
- `caddy`: 对外 80/443,反代 `/_matrix/*` 和 `/_p2p/*`。
|
|
22
22
|
- `coturn`: TURN relay。
|
|
23
23
|
|
|
@@ -4,7 +4,9 @@
|
|
|
4
4
|
|
|
5
5
|
从服务端同步过来的 `password` 和 owner `access_token` 必须按一次性/易失凭据处理。`password` 是后端字段名,对用户展示时必须叫八位 App 初始化码。用户完成初始化或 token exchange 后,服务端可能立刻重置这些值;任何需要再次获取初始化码,或需要用 `access_token` 调 owner 身份 API/Matrix Client API,或需要用 `agent_token` 调 `agent.matrix_session.create` 的操作,都必须先重新从服务器拉取最新 `/opt/p2p/bootstrap.json`,再更新本地 `credentials.json`。不要复用聊天记录、旧 `state.json`、旧 `credentials.json` 或历史部署输出里的 password/access token。
|
|
6
6
|
|
|
7
|
-
现有节点执行 `scripts/update.sh`
|
|
7
|
+
现有节点执行 `scripts/update.sh` 只做镜像刷新和远端服务重启,不清理应用卷,也不重置本地 `password`、`access_token`、`agent_token`、`agent_room_id`、`user_confirmations`、`runtime_checks`、cc-connect daemon 状态或 MCP artifacts。除非验证发现远端确实重新生成了 bootstrap credentials,否则 update 后不要强制续跑 S4-S7。
|
|
8
|
+
|
|
9
|
+
执行 `scripts/reset-app-data.sh`、清理应用挂载卷或重新部署服务后,本地旧证据必须作废。脚本会清掉旧 `password`、`access_token`、`agent_token`、`agent_room_id`、`user_confirmations` 和 `runtime_checks`,把 `agent_install_status` 和 `mcp_install_status` 标成 `refresh_pending`,并只在 `WorkDir` 匹配当前 service 时停止对应的本地 bridge(stops only the matching service-scoped direxio-connect daemon),再把 S4-S7 标回 pending。这样旧的用户确认、MCP discovery、Agent runtime probe、旧 bridge 安装状态或 MCP 安装状态不会被误用到重置后的节点。后续必须续跑 `scripts/orchestrate.sh`,让 S5/S6/S7 重新生成本地 credentials/MCP snippets,并默认自动重新安装/重启 cc-connect 和 direxio-mcp,再通过 `verify runtime` 写入当前证据。
|
|
8
10
|
|
|
9
11
|
## 远端凭据
|
|
10
12
|
|
package/references/tooling.md
CHANGED
|
@@ -82,7 +82,10 @@ If distro packages are too old or missing, ask before using the official AWS CLI
|
|
|
82
82
|
|
|
83
83
|
## Credentials
|
|
84
84
|
|
|
85
|
-
|
|
85
|
+
For first-time setup, offer a root access key as the fastest path and a
|
|
86
|
+
temporary `DirexioDeployer` IAM user or role as the safer path. Root keys are
|
|
87
|
+
highly privileged; the operator must save the CSV securely, never paste or
|
|
88
|
+
commit it, and rotate or delete it after deployment. If the user provides an
|
|
86
89
|
AWS access-key CSV, import it through the repository helper so command output
|
|
87
90
|
stays redacted and the identity is marked as `root=true|false`:
|
|
88
91
|
|
|
@@ -96,8 +99,8 @@ Existing profiles can still be used, including root profiles when the operator
|
|
|
96
99
|
explicitly chooses root credentials:
|
|
97
100
|
|
|
98
101
|
```bash
|
|
99
|
-
aws configure --profile
|
|
100
|
-
export AWS_PROFILE=
|
|
102
|
+
aws configure --profile direxio-deployer
|
|
103
|
+
export AWS_PROFILE=direxio-deployer
|
|
101
104
|
export AWS_DEFAULT_REGION=us-east-1
|
|
102
105
|
aws sts get-caller-identity
|
|
103
106
|
```
|
|
@@ -47,7 +47,7 @@ Rerun the same command after fixing the blocker; state resumes from the first un
|
|
|
47
47
|
|
|
48
48
|
After S3, do not reset or delete state just to silence an error. If EC2, public
|
|
49
49
|
IPv4/EIP, or other AWS resources are recorded, preserve `state.json`, repair the
|
|
50
|
-
blocker, and rerun with `
|
|
50
|
+
blocker, and rerun with `DIREXIO_EXISTING_STATE_ACTION=continue`; or destroy first
|
|
51
51
|
if the user wants to stop billing.
|
|
52
52
|
|
|
53
53
|
## Destroy
|
|
@@ -72,13 +72,19 @@ remain outside automatic destroy scope.
|
|
|
72
72
|
|
|
73
73
|
## Update / Reset Follow-Up
|
|
74
74
|
|
|
75
|
-
After `scripts/
|
|
75
|
+
After `scripts/reset-app-data.sh`, rerun:
|
|
76
76
|
|
|
77
77
|
```bash
|
|
78
|
-
|
|
78
|
+
DIREXIO_EXISTING_STATE_ACTION=continue DOMAIN=__DOMAIN__ bash scripts/orchestrate.sh
|
|
79
79
|
```
|
|
80
80
|
|
|
81
|
-
The
|
|
81
|
+
The reset script intentionally marks S4-S7 pending and clears stale local secret
|
|
82
82
|
fields. Do not copy old initialization codes or tokens from chat history,
|
|
83
83
|
`state.json`, or `credentials.json`; S5 must fetch fresh bootstrap data and S6
|
|
84
|
-
must rewrite service-scoped local credentials/MCP snippets
|
|
84
|
+
must rewrite service-scoped local credentials/MCP snippets and reinstall local
|
|
85
|
+
packages by default.
|
|
86
|
+
|
|
87
|
+
After `scripts/update.sh`, do not rerun S4-S7 just because the service was
|
|
88
|
+
restarted. Image-only update preserves local credentials, cc-connect daemon
|
|
89
|
+
state, MCP artifacts, confirmations, and runtime checks unless a separate
|
|
90
|
+
verification shows the server regenerated bootstrap credentials.
|
|
@@ -58,7 +58,7 @@ skill 不部署 coturn,只把服务商给的 `uris + username/password` 写进 D
|
|
|
58
58
|
# DOMAIN/PUBLIC_IP/TURN_SECRET 由 .env 注入(user-data 写)。
|
|
59
59
|
coturn:
|
|
60
60
|
image: coturn/coturn:latest
|
|
61
|
-
network_mode: host # relay 必须;不要放进
|
|
61
|
+
network_mode: host # relay 必须;不要放进 direxio-net 桥接网络
|
|
62
62
|
restart: unless-stopped
|
|
63
63
|
command:
|
|
64
64
|
- -n
|
|
@@ -74,7 +74,7 @@ skill 不部署 coturn,只把服务商给的 `uris + username/password` 写进 D
|
|
|
74
74
|
- --no-tls
|
|
75
75
|
- --no-dtls
|
|
76
76
|
```
|
|
77
|
-
> 注:`network_mode: host` 与现有 `networks: [
|
|
77
|
+
> 注:`network_mode: host` 与现有 `networks: [direxio-net]` 不兼容,coturn 单独用 host 网络。
|
|
78
78
|
> 其余服务不变。
|
|
79
79
|
|
|
80
80
|
### 2. `phases/s3_provision.sh` — 安全组加 TURN 端口
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
# docker-compose.yml - cloud-side Direxio message-server stack.
|
|
2
2
|
#
|
|
3
|
-
# Layers: Caddy (public 443/TLS) -> Direxio message-server (Matrix +
|
|
4
|
-
# PostgreSQL 18 persists Matrix and
|
|
3
|
+
# Layers: Caddy (public 443/TLS) -> Direxio message-server (Matrix + Direxio API).
|
|
4
|
+
# PostgreSQL 18 persists Matrix and Direxio business tables. The local agent bridge
|
|
5
5
|
# process is not started in the cloud by default.
|
|
6
6
|
|
|
7
7
|
networks:
|
|
8
|
-
|
|
8
|
+
direxio-net:
|
|
9
9
|
|
|
10
10
|
volumes:
|
|
11
11
|
postgres-data:
|
|
@@ -17,7 +17,7 @@ volumes:
|
|
|
17
17
|
services:
|
|
18
18
|
postgres:
|
|
19
19
|
image: postgres:18-alpine
|
|
20
|
-
networks: [
|
|
20
|
+
networks: [direxio-net]
|
|
21
21
|
environment:
|
|
22
22
|
POSTGRES_USER: direxio_message_server
|
|
23
23
|
POSTGRES_PASSWORD: direxio_message_server
|
|
@@ -33,7 +33,7 @@ services:
|
|
|
33
33
|
|
|
34
34
|
message-init:
|
|
35
35
|
image: ${MESSAGE_SERVER_IMAGE}
|
|
36
|
-
networks: [
|
|
36
|
+
networks: [direxio-net]
|
|
37
37
|
depends_on:
|
|
38
38
|
postgres:
|
|
39
39
|
condition: service_healthy
|
|
@@ -58,7 +58,7 @@ services:
|
|
|
58
58
|
|
|
59
59
|
message-server:
|
|
60
60
|
image: ${MESSAGE_SERVER_IMAGE}
|
|
61
|
-
networks: [
|
|
61
|
+
networks: [direxio-net]
|
|
62
62
|
depends_on:
|
|
63
63
|
postgres:
|
|
64
64
|
condition: service_healthy
|
|
@@ -86,7 +86,7 @@ services:
|
|
|
86
86
|
|
|
87
87
|
caddy:
|
|
88
88
|
image: caddy:2
|
|
89
|
-
networks: [
|
|
89
|
+
networks: [direxio-net]
|
|
90
90
|
depends_on:
|
|
91
91
|
message-server:
|
|
92
92
|
condition: service_healthy
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
# init-tokens.sh - wait for message-server bootstrap credentials after compose is up.
|
|
3
3
|
set -euo pipefail
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
COMPOSE="docker compose -f ${
|
|
5
|
+
DIREXIO_DIR=${DIREXIO_DIR:-/opt/p2p}
|
|
6
|
+
COMPOSE="docker compose -f ${DIREXIO_DIR}/docker-compose.yml --env-file ${DIREXIO_DIR}/.env"
|
|
7
7
|
DOMAIN=${DOMAIN:?DOMAIN is required (e.g. __DOMAIN__)}
|
|
8
8
|
CONTAINER_BOOTSTRAP_FILE=${CONTAINER_BOOTSTRAP_FILE:-/var/direxio-message-server/p2p/bootstrap.json}
|
|
9
9
|
BOOTSTRAP_FILE=${BOOTSTRAP_FILE:-/opt/p2p/bootstrap.json}
|
|
@@ -13,7 +13,7 @@ log() { echo "[init-tokens] $*" >&2; }
|
|
|
13
13
|
|
|
14
14
|
env_string() {
|
|
15
15
|
local key=$1
|
|
16
|
-
grep -E "^${key}=" "${
|
|
16
|
+
grep -E "^${key}=" "${DIREXIO_DIR}/.env" 2>/dev/null \
|
|
17
17
|
| tail -1 \
|
|
18
18
|
| cut -d= -f2- \
|
|
19
19
|
|| true
|
|
@@ -94,7 +94,7 @@ bootstrap_portal() {
|
|
|
94
94
|
password=${P2P_PORTAL_PASSWORD:-}
|
|
95
95
|
[ -n "$password" ] || password=$(env_string P2P_PORTAL_PASSWORD)
|
|
96
96
|
if [ -z "$password" ]; then
|
|
97
|
-
log "FATAL: P2P_PORTAL_PASSWORD is missing from environment and ${
|
|
97
|
+
log "FATAL: P2P_PORTAL_PASSWORD is missing from environment and ${DIREXIO_DIR}/.env"
|
|
98
98
|
return 1
|
|
99
99
|
fi
|
|
100
100
|
tmp=$(mktemp)
|
package/scripts/destroy.ps1
CHANGED
|
@@ -35,9 +35,9 @@ $env:DIREXIO_WINDOWS_HOME = $windowsDirexioHome
|
|
|
35
35
|
$env:DIREXIO_HOME = ConvertTo-GitBashPath $windowsDirexioHome
|
|
36
36
|
$env:DIREXIO_LOCAL_PATH_STYLE = 'windows'
|
|
37
37
|
|
|
38
|
-
if ($env:
|
|
39
|
-
$env:
|
|
40
|
-
$env:
|
|
38
|
+
if ($env:DIREXIO_WORKDIR) {
|
|
39
|
+
$env:DIREXIO_WORKDIR_WINDOWS = $env:DIREXIO_WORKDIR
|
|
40
|
+
$env:DIREXIO_WORKDIR = ConvertTo-GitBashPath $env:DIREXIO_WORKDIR
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
$repoRootForBash = ConvertTo-GitBashPath $RepoRoot
|
package/scripts/destroy.sh
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
# destroy.sh - remove AWS resources recorded by deployment state.
|
|
3
3
|
#
|
|
4
4
|
# Source:
|
|
5
|
-
# 1. $
|
|
5
|
+
# 1. $DIREXIO_WORKDIR/state.json written by orchestrate.sh; by default
|
|
6
6
|
# DOMAIN=__DOMAIN__ maps to ~/.direxio/nodes/<service_id>/state.json.
|
|
7
7
|
# 2. explicit argument: bash destroy.sh /path/to/state.json
|
|
8
8
|
#
|
|
@@ -18,7 +18,7 @@ source "$HERE/lib/paths.sh"
|
|
|
18
18
|
source "$HERE/lib/aws.sh"
|
|
19
19
|
# shellcheck disable=SC1090
|
|
20
20
|
source "$HERE/lib/operation_report.sh"
|
|
21
|
-
|
|
21
|
+
DIREXIO_WORKDIR=$(direxio_default_workdir)
|
|
22
22
|
|
|
23
23
|
log() { echo -e "\033[33m[destroy]\033[0m $*"; }
|
|
24
24
|
|
|
@@ -162,12 +162,12 @@ verify_key_pair_deleted() {
|
|
|
162
162
|
# Resolve source and load INSTANCE_ID/EIP_ID/SG_ID/KEY_NAME/KEY_FILE/REGION.
|
|
163
163
|
SRC=${1:-}
|
|
164
164
|
if [ -z "$SRC" ]; then
|
|
165
|
-
if [ -f "$
|
|
166
|
-
else echo "state.json not found; set DOMAIN=<service domain> or
|
|
165
|
+
if [ -f "$DIREXIO_WORKDIR/state.json" ]; then SRC="$DIREXIO_WORKDIR/state.json"
|
|
166
|
+
else echo "state.json not found; set DOMAIN=<service domain> or DIREXIO_WORKDIR=<service dir> to destroy a specific deployment."; exit 1
|
|
167
167
|
fi
|
|
168
168
|
fi
|
|
169
169
|
[ -f "$SRC" ] || { echo "$SRC not found."; exit 1; }
|
|
170
|
-
|
|
170
|
+
DIREXIO_ROOT=$(cd "${DIREXIO_HOME:-$HOME/.direxio}" 2>/dev/null && pwd -P || printf '%s' "${DIREXIO_HOME:-$HOME/.direxio}")
|
|
171
171
|
|
|
172
172
|
REGION=$(json_get "$SRC" region)
|
|
173
173
|
INSTANCE_ID=$(json_get "$SRC" resources.instance_id)
|
|
@@ -245,7 +245,7 @@ delete_route53_record() {
|
|
|
245
245
|
change_file=$(mktemp)
|
|
246
246
|
cat > "$change_file" <<EOF
|
|
247
247
|
{
|
|
248
|
-
"Comment": "
|
|
248
|
+
"Comment": "Direxio destroy",
|
|
249
249
|
"Changes": [
|
|
250
250
|
{
|
|
251
251
|
"Action": "DELETE",
|
|
@@ -470,8 +470,8 @@ stop_current_cc_connect_daemon() {
|
|
|
470
470
|
cleanup_local_service_dir() {
|
|
471
471
|
local service_dir=$1 root=$2 nodes_root src_real nodes_real src_norm nodes_norm name
|
|
472
472
|
|
|
473
|
-
if [ "${
|
|
474
|
-
log "keeping local service dir because
|
|
473
|
+
if [ "${DIREXIO_KEEP_WORKDIR:-0}" = "1" ]; then
|
|
474
|
+
log "keeping local service dir because DIREXIO_KEEP_WORKDIR=1: $service_dir"
|
|
475
475
|
return 0
|
|
476
476
|
fi
|
|
477
477
|
|
|
@@ -567,4 +567,4 @@ if REPORT_PATH=$(operation_report_write destroy destroy_processed "$SRC" 2>/dev/
|
|
|
567
567
|
else
|
|
568
568
|
log "operation report was not written; keep destroy logs for audit"
|
|
569
569
|
fi
|
|
570
|
-
cleanup_local_service_dir "$CURRENT_SERVICE_DIR" "$
|
|
570
|
+
cleanup_local_service_dir "$CURRENT_SERVICE_DIR" "$DIREXIO_ROOT"
|
package/scripts/json.mjs
CHANGED
|
@@ -373,6 +373,7 @@ function cmdMutate(args) {
|
|
|
373
373
|
delete data[key];
|
|
374
374
|
}
|
|
375
375
|
data.agent_install_status = "refresh_pending";
|
|
376
|
+
data.mcp_install_status = "refresh_pending";
|
|
376
377
|
data.phase = startPhase;
|
|
377
378
|
if (!isObject(data.phases)) data.phases = {};
|
|
378
379
|
if (startPhase === "S4_BOOTSTRAP_STACK") {
|
|
@@ -513,6 +514,7 @@ function buildOperationReport(operation, status, stateFile, generatedAt, st) {
|
|
|
513
514
|
},
|
|
514
515
|
mcp: {
|
|
515
516
|
status: localRefreshStatus,
|
|
517
|
+
install_status: st.mcp_install_status || "",
|
|
516
518
|
package: st.mcp_npm_package || "direxio-mcp@latest",
|
|
517
519
|
server_name: st.mcp_server_name || "",
|
|
518
520
|
config_dir: st.mcp_config_dir || "",
|
package/scripts/lib/paths.sh
CHANGED
|
@@ -23,9 +23,7 @@ direxio_service_dir() {
|
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
direxio_default_workdir() {
|
|
26
|
-
if [ -n "${
|
|
27
|
-
printf '%s\n' "$P2P_WORKDIR"
|
|
28
|
-
elif [ -n "${DIREXIO_WORKDIR:-}" ]; then
|
|
26
|
+
if [ -n "${DIREXIO_WORKDIR:-}" ]; then
|
|
29
27
|
printf '%s\n' "$DIREXIO_WORKDIR"
|
|
30
28
|
elif [ -n "${DOMAIN:-}" ]; then
|
|
31
29
|
direxio_service_dir "$DOMAIN"
|
package/scripts/lib/state.sh
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# Sourced by orchestrate.sh and phases/*.sh. All state.json reads/writes go
|
|
5
5
|
# through this file to keep structure and fields consistent. Requires Node.js.
|
|
6
6
|
#
|
|
7
|
-
# state.json path: $
|
|
7
|
+
# state.json path: $DIREXIO_WORKDIR/state.json.
|
|
8
8
|
# By default, DOMAIN=__DOMAIN__ maps to ~/.direxio/nodes/<service_id>/state.json.
|
|
9
9
|
#
|
|
10
10
|
# PHASES order is the state-machine execution order.
|
|
@@ -28,17 +28,17 @@ PHASES=(
|
|
|
28
28
|
)
|
|
29
29
|
|
|
30
30
|
# Paths.
|
|
31
|
-
|
|
32
|
-
STATE_JSON="$
|
|
31
|
+
DIREXIO_WORKDIR=$(direxio_default_workdir)
|
|
32
|
+
STATE_JSON="$DIREXIO_WORKDIR/state.json"
|
|
33
33
|
|
|
34
34
|
# Timestamp helper.
|
|
35
35
|
_now() { date -u +%Y-%m-%dT%H:%M:%SZ; }
|
|
36
36
|
|
|
37
37
|
# Shared logging helpers.
|
|
38
|
-
log() { echo -e "\033[36m[
|
|
39
|
-
ok() { echo -e "\033[32m[
|
|
40
|
-
warn() { echo -e "\033[33m[
|
|
41
|
-
fail() { echo -e "\033[31m[
|
|
38
|
+
log() { echo -e "\033[36m[direxio]\033[0m $*" >&2; }
|
|
39
|
+
ok() { echo -e "\033[32m[direxio]\033[0m $*" >&2; }
|
|
40
|
+
warn() { echo -e "\033[33m[direxio]\033[0m $*" >&2; }
|
|
41
|
+
fail() { echo -e "\033[31m[direxio][FATAL]\033[0m $*" >&2; exit 1; }
|
|
42
42
|
is_yes() {
|
|
43
43
|
case "$(printf '%s' "$1" | tr '[:upper:]' '[:lower:]')" in
|
|
44
44
|
y|yes|true|1) return 0 ;;
|
|
@@ -88,8 +88,8 @@ _windows_current_user() {
|
|
|
88
88
|
|
|
89
89
|
# Initialize state.json for a new deployment.
|
|
90
90
|
state_init() {
|
|
91
|
-
mkdir -p "$
|
|
92
|
-
local run_id=${RUN_ID:-
|
|
91
|
+
mkdir -p "$DIREXIO_WORKDIR"
|
|
92
|
+
local run_id=${RUN_ID:-direxio-$(date -u +%Y%m%d-%H%M%S)}
|
|
93
93
|
: > "$STATE_JSON"
|
|
94
94
|
json_mutate "$STATE_JSON" state-init "$run_id" "${AWS_DEFAULT_REGION:-${AWS_REGION:-}}" "$(_now)" "${PHASES[@]}"
|
|
95
95
|
log "Initialized state.json -> $STATE_JSON (run_id=$run_id)"
|
package/scripts/orchestrate.ps1
CHANGED
|
@@ -75,9 +75,9 @@ if (-not $env:DIREXIO_AGENT_WORKSPACE) {
|
|
|
75
75
|
$env:DIREXIO_AGENT_WORKSPACE_WINDOWS = (Get-Location).ProviderPath
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
-
if ($env:
|
|
79
|
-
$env:
|
|
80
|
-
$env:
|
|
78
|
+
if ($env:DIREXIO_WORKDIR) {
|
|
79
|
+
$env:DIREXIO_WORKDIR_WINDOWS = $env:DIREXIO_WORKDIR
|
|
80
|
+
$env:DIREXIO_WORKDIR = ConvertTo-GitBashPath $env:DIREXIO_WORKDIR
|
|
81
81
|
}
|
|
82
82
|
|
|
83
83
|
if (-not $env:DIREXIO_CODEX_COMMAND) {
|
package/scripts/orchestrate.sh
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
|
-
# orchestrate.sh -
|
|
2
|
+
# orchestrate.sh - Direxio deployment state-machine engine.
|
|
3
3
|
#
|
|
4
|
-
# Turns "one AWS credential -> working
|
|
5
|
-
# (S0..S7). State is persisted to $
|
|
4
|
+
# Turns "one AWS credential -> working Direxio server -> local direxio-connect bridge" into 8 phases
|
|
5
|
+
# (S0..S7). State is persisted to $DIREXIO_WORKDIR/state.json and supports:
|
|
6
6
|
# - resume: continue from the first unfinished phase
|
|
7
7
|
# - checkpoints: wait for user/AWS actions without losing progress
|
|
8
8
|
# - destroy: every AWS resource is recorded for destroy.sh
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
set -uo pipefail
|
|
22
22
|
|
|
23
23
|
HERE=$(cd "$(dirname "$0")" && pwd)
|
|
24
|
-
|
|
24
|
+
DIREXIO_INSTALL_SCRIPTS_DIR="$HERE"
|
|
25
25
|
|
|
26
26
|
# Prefer workspace-local tools when present.
|
|
27
27
|
REPO_ROOT=$(cd "$HERE/.." && pwd)
|
|
@@ -30,7 +30,6 @@ if [ -d "$REPO_ROOT/.tools/bin" ]; then
|
|
|
30
30
|
export PATH
|
|
31
31
|
fi
|
|
32
32
|
|
|
33
|
-
P2P_WORKDIR_WAS_SET=${P2P_WORKDIR+x}
|
|
34
33
|
DIREXIO_WORKDIR_WAS_SET=${DIREXIO_WORKDIR+x}
|
|
35
34
|
|
|
36
35
|
source "$HERE/lib/state.sh"
|
|
@@ -67,8 +66,8 @@ check_deps() {
|
|
|
67
66
|
warn "Install AWS CLI v2 and configure credentials first:"
|
|
68
67
|
warn " macOS: curl 'https://awscli.amazonaws.com/AWSCLIV2.pkg' -o AWSCLIV2.pkg && sudo installer -pkg ./AWSCLIV2.pkg -target /"
|
|
69
68
|
warn " Linux x86_64: curl 'https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip' -o awscliv2.zip && unzip awscliv2.zip && sudo ./aws/install"
|
|
70
|
-
warn " Configure: aws configure --profile
|
|
71
|
-
warn " Use: export AWS_PROFILE=
|
|
69
|
+
warn " Configure: aws configure --profile direxio-deployer"
|
|
70
|
+
warn " Use: export AWS_PROFILE=direxio-deployer AWS_DEFAULT_REGION=<region>"
|
|
72
71
|
warn "See references/user-journey.md for the AWS CLI setup guide."
|
|
73
72
|
;;
|
|
74
73
|
esac
|
|
@@ -184,7 +183,7 @@ status_resume_safety() {
|
|
|
184
183
|
local current=$1 billable
|
|
185
184
|
billable=$(recorded_billable_resources)
|
|
186
185
|
if [ -n "$billable" ] || phase_at_or_after_s3 "$current"; then
|
|
187
|
-
echo "do not reset state; fix the issue and rerun with
|
|
186
|
+
echo "do not reset state; fix the issue and rerun with DIREXIO_EXISTING_STATE_ACTION=continue"
|
|
188
187
|
else
|
|
189
188
|
echo "safe to rerun the same command after the next action is complete"
|
|
190
189
|
fi
|
|
@@ -196,7 +195,7 @@ local_refresh_pending() {
|
|
|
196
195
|
|
|
197
196
|
status_local_refresh() {
|
|
198
197
|
if local_refresh_pending; then
|
|
199
|
-
echo "
|
|
198
|
+
echo "reset/redeploy cleared old credentials, user confirmations, runtime checks, bridge install proof, and MCP install proof"
|
|
200
199
|
fi
|
|
201
200
|
}
|
|
202
201
|
|
|
@@ -204,7 +203,7 @@ status_next_action() {
|
|
|
204
203
|
if local_refresh_pending; then
|
|
205
204
|
case "$1" in
|
|
206
205
|
S4_BOOTSTRAP_STACK|S5_INIT_TOKENS|S6_WIRE_LOCAL|S7_VERIFY_E2E|DONE)
|
|
207
|
-
echo "rerun the deployment workflow to refresh S4-S7, local credentials, MCP snippets, and runtime checks"
|
|
206
|
+
echo "rerun the deployment workflow to refresh S4-S7, local credentials, MCP snippets, automatic installs, and runtime checks"
|
|
208
207
|
return 0
|
|
209
208
|
;;
|
|
210
209
|
esac
|
|
@@ -257,12 +256,12 @@ print_recovery_summary() {
|
|
|
257
256
|
|
|
258
257
|
cmd_status() {
|
|
259
258
|
if [ ! -f "$STATE_JSON" ]; then
|
|
260
|
-
if [ -z "${DOMAIN:-}" ] && [ -z "$
|
|
259
|
+
if [ -z "${DOMAIN:-}" ] && [ -z "$DIREXIO_WORKDIR_WAS_SET" ]; then
|
|
261
260
|
cmd_status_inventory
|
|
262
261
|
return 0
|
|
263
262
|
fi
|
|
264
263
|
warn "state.json not found: $STATE_JSON"
|
|
265
|
-
warn "Set DOMAIN=<service domain> or explicit
|
|
264
|
+
warn "Set DOMAIN=<service domain> or explicit DIREXIO_WORKDIR=<service dir> to inspect a specific deployment."
|
|
266
265
|
return 0
|
|
267
266
|
fi
|
|
268
267
|
echo "run_id : $(state_get run_id)"
|
|
@@ -426,7 +425,7 @@ precheck_new_deploy_domain_env() {
|
|
|
426
425
|
return 2
|
|
427
426
|
fi
|
|
428
427
|
if [ -z "$domain" ]; then
|
|
429
|
-
warn "Deployment blocked: DOMAIN is missing.
|
|
428
|
+
warn "Deployment blocked: DOMAIN is missing. Direxio requires a confirmed production Matrix server_name."
|
|
430
429
|
warn "Use this skill to prepare domain/DNS, then rerun:"
|
|
431
430
|
warn " DOMAIN=__DOMAIN__ DOMAIN_MODE=user CONFIRM_DOMAIN_BINDING=1 bash $0"
|
|
432
431
|
return 2
|
|
@@ -473,7 +472,7 @@ ensure_production_domain_selected() {
|
|
|
473
472
|
return 2
|
|
474
473
|
fi
|
|
475
474
|
if [ -z "$domain" ]; then
|
|
476
|
-
warn "Deployment blocked: DOMAIN is missing.
|
|
475
|
+
warn "Deployment blocked: DOMAIN is missing. Direxio requires a confirmed production Matrix server_name."
|
|
477
476
|
warn "Use this skill to prepare domain/DNS, then rerun:"
|
|
478
477
|
warn " DOMAIN=__DOMAIN__ DOMAIN_MODE=user CONFIRM_DOMAIN_BINDING=1 bash $0"
|
|
479
478
|
return 2
|
|
@@ -501,14 +500,14 @@ guard_existing_state() {
|
|
|
501
500
|
if [ "$(json_get "$STATE_JSON" domain_mode)" = "ec2" ]; then
|
|
502
501
|
warn "Found legacy temporary-domain deployment state (domain_mode=ec2). Production deployment no longer supports resuming this mode."
|
|
503
502
|
warn "Destroy and rebuild, or use a new service directory:"
|
|
504
|
-
warn "
|
|
503
|
+
warn " DIREXIO_EXISTING_STATE_ACTION=destroy bash $0"
|
|
505
504
|
warn " DOMAIN=__DOMAIN__ DOMAIN_MODE=user CONFIRM_DOMAIN_BINDING=1 bash $0"
|
|
506
505
|
return 2
|
|
507
506
|
fi
|
|
508
507
|
confirmed=$(json_get "$STATE_JSON" existing_state_confirmed false)
|
|
509
508
|
[ "$confirmed" = "true" ] && return 0
|
|
510
509
|
|
|
511
|
-
action=${
|
|
510
|
+
action=${DIREXIO_EXISTING_STATE_ACTION:-}
|
|
512
511
|
if [ -z "$action" ] && [ -t 0 ]; then
|
|
513
512
|
warn "Found existing deployment state with recorded AWS resources:"
|
|
514
513
|
json_entries "$STATE_JSON" resources | sed 's/^/ /' >&2
|
|
@@ -529,12 +528,12 @@ guard_existing_state() {
|
|
|
529
528
|
return 0 ;;
|
|
530
529
|
""|abort)
|
|
531
530
|
warn "Existing service state must be handled explicitly to avoid accidental reuse or duplicate EC2 creation."
|
|
532
|
-
warn "Resume:
|
|
533
|
-
warn "Rebuild:
|
|
531
|
+
warn "Resume: DIREXIO_EXISTING_STATE_ACTION=continue bash $0"
|
|
532
|
+
warn "Rebuild: DIREXIO_EXISTING_STATE_ACTION=destroy bash $0"
|
|
534
533
|
warn "New service: DOMAIN=__DOMAIN__ DOMAIN_MODE=user CONFIRM_DOMAIN_BINDING=1 bash $0"
|
|
535
534
|
return 2 ;;
|
|
536
535
|
*)
|
|
537
|
-
warn "Unknown
|
|
536
|
+
warn "Unknown DIREXIO_EXISTING_STATE_ACTION=$action (expected continue|destroy|abort)."
|
|
538
537
|
return 2 ;;
|
|
539
538
|
esac
|
|
540
539
|
}
|