Files
luci-app-openclaw/docs/superpowers/plans/2026-03-18-custom-install-root.md
lingyuzeng 68f24e6658 feat(storage): support configurable install root
Add a LuCI install-root input, persist the selected path in UCI,
and route install, status, backup, uninstall, and runtime scripts
through the configured storage root for new installs.

Reference: custom install root flow
2026-03-18 13:48:07 +08:00

145 lines
5.3 KiB
Markdown

# Custom Install Root Implementation Plan
> **For agentic workers:** REQUIRED: Use superpowers:subagent-driven-development (if subagents available) or superpowers:executing-plans to implement this plan. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** Let new OpenClaw installs choose a LuCI-specified storage root and keep all runtime files under that configured root.
**Architecture:** Add a persisted UCI install-root setting, a shared shell path helper, and a small Lua path helper so UI checks and runtime scripts all derive the same directories. Keep `/opt` as the default and preserve the existing `/openclaw/{node,global,data}` subtree under whichever root the user selects.
**Tech Stack:** LuCI Lua, POSIX shell, Node.js runtime scripts, OpenWrt UCI
---
### Task 1: Add failing path derivation tests
**Files:**
- Create: `tests/test_openclaw_paths.lua`
- Create: `luasrc/openclaw/paths.lua`
- [ ] **Step 1: Write the failing test**
Create Lua assertions for:
- default root -> `/opt`
- `/mnt/emmc/` -> `/mnt/emmc`
- derived paths under `<root>/openclaw`
- invalid relative paths fall back to `/opt`
- [ ] **Step 2: Run test to verify it fails**
Run: `lua /Users/lingyuzeng/project/luci-app-openclaw/tests/test_openclaw_paths.lua`
Expected: FAIL because `luasrc/openclaw/paths.lua` does not exist yet.
- [ ] **Step 3: Write minimal implementation**
Add a pure-Lua helper exposing normalization and derived-path functions.
- [ ] **Step 4: Run test to verify it passes**
Run: `lua /Users/lingyuzeng/project/luci-app-openclaw/tests/test_openclaw_paths.lua`
Expected: PASS
### Task 2: Add shared shell path helper
**Files:**
- Create: `root/usr/libexec/openclaw-paths.sh`
- Modify: `Makefile`
- [ ] **Step 1: Write the failing test**
Extend the Lua test or add a shell smoke command that expects the helper to emit normalized install root and derived directories.
- [ ] **Step 2: Run test to verify it fails**
Run: `sh -c '. /Users/lingyuzeng/project/luci-app-openclaw/root/usr/libexec/openclaw-paths.sh; oc_load_paths'`
Expected: FAIL because the helper does not exist yet.
- [ ] **Step 3: Write minimal implementation**
Implement helper functions for normalization, derived directories, and `/opt`-specific OverlayFS handling guards. Install the helper in the package Makefile.
- [ ] **Step 4: Run test to verify it passes**
Run: `sh -n /Users/lingyuzeng/project/luci-app-openclaw/root/usr/libexec/openclaw-paths.sh`
Expected: PASS
### Task 3: Wire LuCI dialog and APIs
**Files:**
- Modify: `luasrc/model/cbi/openclaw/basic.lua`
- Modify: `luasrc/controller/openclaw.lua`
- Modify: `root/etc/config/openclaw`
- [ ] **Step 1: Add failing coverage mindset**
Use the existing Lua path test as the guardrail for normalization and manually confirm current UI/API code still hard-codes `/opt`.
- [ ] **Step 2: Implement API and dialog changes**
Add:
- UCI-backed default install root
- dialog input and explanatory copy
- `check_system` support for `install_root`
- `setup` support for persisting the root and refusing live path switches
- [ ] **Step 3: Verify behavior**
Run:
- `lua -e 'assert(loadfile("/Users/lingyuzeng/project/luci-app-openclaw/luasrc/controller/openclaw.lua"))'`
- `lua -e 'assert(loadfile("/Users/lingyuzeng/project/luci-app-openclaw/luasrc/model/cbi/openclaw/basic.lua"))'`
Expected: PASS
### Task 4: Route runtime scripts through the configured root
**Files:**
- Modify: `root/usr/bin/openclaw-env`
- Modify: `root/etc/init.d/openclaw`
- Modify: `root/etc/profile.d/openclaw.sh`
- Modify: `root/etc/uci-defaults/99-openclaw`
- Modify: `root/usr/share/openclaw/oc-config.sh`
- [ ] **Step 1: Update scripts**
Source the shared shell helper, derive paths from UCI or `OPENCLAW_INSTALL_ROOT`, and keep the `/opt` workaround only for the default root.
- [ ] **Step 2: Verify syntax**
Run:
- `sh -n /Users/lingyuzeng/project/luci-app-openclaw/root/usr/bin/openclaw-env`
- `sh -n /Users/lingyuzeng/project/luci-app-openclaw/root/etc/init.d/openclaw`
- `sh -n /Users/lingyuzeng/project/luci-app-openclaw/root/etc/profile.d/openclaw.sh`
- `sh -n /Users/lingyuzeng/project/luci-app-openclaw/root/etc/uci-defaults/99-openclaw`
- `sh -n /Users/lingyuzeng/project/luci-app-openclaw/root/usr/share/openclaw/oc-config.sh`
Expected: PASS
### Task 5: Fix remaining controller/runtime path call sites and verify
**Files:**
- Modify: `luasrc/controller/openclaw.lua`
- Modify: `luasrc/model/cbi/openclaw/basic.lua`
- Modify: `README.md`
- [ ] **Step 1: Replace remaining hard-coded `/opt/openclaw` references used by user-facing flows**
Cover status, uninstall, backup/restore, error hints, and install dialog copy.
- [ ] **Step 2: Run full verification**
Run:
- `lua /Users/lingyuzeng/project/luci-app-openclaw/tests/test_openclaw_paths.lua`
- `lua -e 'assert(loadfile("/Users/lingyuzeng/project/luci-app-openclaw/luasrc/controller/openclaw.lua"))'`
- `lua -e 'assert(loadfile("/Users/lingyuzeng/project/luci-app-openclaw/luasrc/model/cbi/openclaw/basic.lua"))'`
- `rg -n "/opt/openclaw" /Users/lingyuzeng/project/luci-app-openclaw`
Expected:
- tests and syntax checks PASS
- remaining `/opt/openclaw` hits are limited to historical docs or intentional compatibility text
- [ ] **Step 3: Commit**
```bash
git -C /Users/lingyuzeng/project/luci-app-openclaw add .
git -C /Users/lingyuzeng/project/luci-app-openclaw commit -m "feat: support configurable install root"
```