Merge 78a17c824b into db1bc144ff
This commit is contained in:
commit
5eea18f7f4
|
|
@ -0,0 +1,93 @@
|
|||
# MiroFish Hermes Integration Contract
|
||||
|
||||
## Purpose
|
||||
|
||||
This document defines the minimum stable contract for Hermes and OpenClaw to use the MiroFish host safely.
|
||||
|
||||
## Canonical Paths
|
||||
|
||||
- Runtime: `/Users/Shared/OpenClaw/mirofish-runtime`
|
||||
- Transcribes: `/Users/Shared/OpenClaw/transcribes`
|
||||
- Source only: `/Users/adrianlat/Library/Mobile Documents/com~apple~CloudDocs/airShare/MiroFish`
|
||||
|
||||
## Service Identity
|
||||
|
||||
- Service label: `com.openclaw.mirofish`
|
||||
- Runtime owner: `airstride`
|
||||
- Access model: LAN + SSH only
|
||||
|
||||
## Network Endpoints
|
||||
|
||||
- Frontend LAN URL: `http://10.0.0.161:3000`
|
||||
- Backend LAN URL: `http://10.0.0.161:5001`
|
||||
- Backend health: `http://10.0.0.161:5001/health`
|
||||
- Frontend proxy health path: `http://10.0.0.161:3000/api/graph/project/list`
|
||||
|
||||
## SSH Access
|
||||
|
||||
- SSH alias: `openclaw-mirofish`
|
||||
- SSH user: `airstride`
|
||||
|
||||
Recommended tunnels:
|
||||
|
||||
```bash
|
||||
ssh -L 3000:127.0.0.1:3000 openclaw-mirofish
|
||||
ssh -L 5001:127.0.0.1:5001 openclaw-mirofish
|
||||
```
|
||||
|
||||
Tunnel-based local URLs:
|
||||
|
||||
- Frontend: `http://127.0.0.1:3000`
|
||||
- Backend: `http://127.0.0.1:5001`
|
||||
|
||||
## Required Health Checks
|
||||
|
||||
Before Hermes or OpenClaw send operational work to MiroFish, the host should pass:
|
||||
|
||||
```bash
|
||||
sudo launchctl print system/com.openclaw.mirofish
|
||||
curl -sS http://127.0.0.1:5001/health
|
||||
curl -sSI http://127.0.0.1:3000/
|
||||
curl -sS http://127.0.0.1:3000/api/graph/project/list
|
||||
```
|
||||
|
||||
Expected results:
|
||||
|
||||
- LaunchDaemon present in `system`
|
||||
- Backend returns `{"service":"MiroFish Backend","status":"ok"}`
|
||||
- Frontend returns `HTTP/1.1 200 OK`
|
||||
- Frontend proxy returns a successful JSON payload
|
||||
|
||||
## Smoke Test
|
||||
|
||||
Use the canonical smoke test after reboot or maintenance:
|
||||
|
||||
```bash
|
||||
/Users/Shared/OpenClaw/mirofish-runtime/scripts/host-smoke-test.sh
|
||||
```
|
||||
|
||||
## Operational Data Rules
|
||||
|
||||
- Do not run MiroFish from iCloud.
|
||||
- Do not write operational runtime state back into the iCloud source tree.
|
||||
- Treat `/Users/Shared/OpenClaw/mirofish-runtime/backend/uploads` as persistent operational state.
|
||||
- Treat `/Users/Shared/OpenClaw/transcribes` as the canonical local operational transcribes dataset.
|
||||
|
||||
## Consumption Rules
|
||||
|
||||
- Prefer SSH tunnels for operator access from other machines.
|
||||
- Use LAN URLs only inside the trusted local network.
|
||||
- Do not expose ports `3000` or `5001` through router forwarding or public internet ingress.
|
||||
- Hermes and OpenClaw should assume MiroFish is a long-lived host service, not an ephemeral dev process.
|
||||
|
||||
## Operational Commands
|
||||
|
||||
From `/Users/Shared/OpenClaw/mirofish-runtime`:
|
||||
|
||||
```bash
|
||||
./scripts/host-start.sh
|
||||
./scripts/host-stop.sh
|
||||
./scripts/host-status.sh
|
||||
tail -f runtime/logs/backend.log
|
||||
tail -f runtime/logs/frontend.log
|
||||
```
|
||||
|
|
@ -0,0 +1,145 @@
|
|||
# MiroFish Host Runbook
|
||||
|
||||
## Canonical Runtime
|
||||
|
||||
- Shared source of truth: `/Users/adrianlat/Library/Mobile Documents/com~apple~CloudDocs/airShare/MiroFish`
|
||||
- Canonical operational runtime: `/Users/Shared/OpenClaw/mirofish-runtime`
|
||||
- Canonical operational transcribes: `/Users/Shared/OpenClaw/transcribes`
|
||||
|
||||
The runtime should live outside iCloud because always-on services need stable local files, virtual environments, logs, and uploads that are not subject to iCloud eviction or placeholder behavior.
|
||||
|
||||
The iCloud source for breathwork transcribes remains:
|
||||
|
||||
- `/Users/adrianlat/Library/Mobile Documents/com~apple~CloudDocs/BreathWork/Transcribes`
|
||||
|
||||
That iCloud tree should be treated as source only. The shared operational copy should live in `/Users/Shared/OpenClaw/transcribes`.
|
||||
|
||||
## Ports
|
||||
|
||||
- Frontend: `3000`
|
||||
- Backend: `5001`
|
||||
|
||||
## Commands
|
||||
|
||||
Run from the runtime root:
|
||||
|
||||
```bash
|
||||
./scripts/host-start.sh
|
||||
./scripts/host-stop.sh
|
||||
./scripts/host-status.sh
|
||||
tail -f runtime/logs/backend.log
|
||||
tail -f runtime/logs/frontend.log
|
||||
./scripts/host-smoke-test.sh
|
||||
```
|
||||
|
||||
Sync transcribes from iCloud source to the shared operational path:
|
||||
|
||||
```bash
|
||||
./scripts/sync-transcribes.sh
|
||||
```
|
||||
|
||||
## SSH Tunnels
|
||||
|
||||
```bash
|
||||
ssh -L 3000:127.0.0.1:3000 openclaw-mirofish
|
||||
ssh -L 5001:127.0.0.1:5001 openclaw-mirofish
|
||||
```
|
||||
|
||||
## Suggested SSH Alias
|
||||
|
||||
```sshconfig
|
||||
Host openclaw-mirofish
|
||||
HostName 10.0.0.161
|
||||
User airstride
|
||||
ServerAliveInterval 30
|
||||
ServerAliveCountMax 3
|
||||
StrictHostKeyChecking accept-new
|
||||
```
|
||||
|
||||
## Legacy LaunchAgent Template
|
||||
|
||||
The current persistent service is the system LaunchDaemon below, running as `airstride`.
|
||||
Use this LaunchAgent template only for a user-session fallback.
|
||||
|
||||
The validated plist is:
|
||||
|
||||
- `/Users/adrianlat/Library/Mobile Documents/com~apple~CloudDocs/airShare/MiroFish/ops/launchd/airshare.mirofish.plist`
|
||||
|
||||
It should be installed by a privileged shell or by a shell already running as `airstride`. If you are running as `airstride`, use:
|
||||
|
||||
```bash
|
||||
cp /Users/adrianlat/Library/Mobile\ Documents/com~apple~CloudDocs/airShare/MiroFish/ops/launchd/airshare.mirofish.plist ~/Library/LaunchAgents/airshare.mirofish.plist
|
||||
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/airshare.mirofish.plist
|
||||
launchctl kickstart -k gui/$(id -u)/airshare.mirofish
|
||||
```
|
||||
|
||||
If you are running from another admin account, bootstrap into `airstride` requires root privileges or an interactive `airstride` session.
|
||||
|
||||
Template:
|
||||
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>Label</key>
|
||||
<string>airshare.mirofish</string>
|
||||
<key>ProgramArguments</key>
|
||||
<array>
|
||||
<string>/bin/zsh</string>
|
||||
<string>/Users/Shared/OpenClaw/mirofish-runtime/scripts/host-start.sh</string>
|
||||
<string>/Users/Shared/OpenClaw/mirofish-runtime</string>
|
||||
</array>
|
||||
<key>WorkingDirectory</key>
|
||||
<string>/Users/Shared/OpenClaw/mirofish-runtime</string>
|
||||
<key>RunAtLoad</key>
|
||||
<true/>
|
||||
<key>KeepAlive</key>
|
||||
<true/>
|
||||
<key>AbandonProcessGroup</key>
|
||||
<true/>
|
||||
<key>StandardOutPath</key>
|
||||
<string>/Users/Shared/OpenClaw/mirofish-runtime/runtime/logs/launchd.log</string>
|
||||
<key>StandardErrorPath</key>
|
||||
<string>/Users/Shared/OpenClaw/mirofish-runtime/runtime/logs/launchd.err.log</string>
|
||||
</dict>
|
||||
</plist>
|
||||
```
|
||||
|
||||
## Validated Constraints
|
||||
|
||||
- MiroFish is not run from iCloud.
|
||||
- Runtime path is local and shared.
|
||||
- SSH is LAN-only and should not be published through router/NAT.
|
||||
- Docker was not available during validation, so source deployment is the active path.
|
||||
|
||||
## LaunchDaemon Migration
|
||||
|
||||
For a true always-on host, prefer the system LaunchDaemon:
|
||||
|
||||
- Source plist: `/Users/Shared/OpenClaw/mirofish-runtime/ops/launchd/com.openclaw.mirofish.plist`
|
||||
- Installed plist: `/Library/LaunchDaemons/com.openclaw.mirofish.plist`
|
||||
- Label: `com.openclaw.mirofish`
|
||||
- User: `airstride`
|
||||
|
||||
Install with:
|
||||
|
||||
```bash
|
||||
sudo /Users/Shared/OpenClaw/mirofish-runtime/scripts/install-mirofish-launchdaemon.sh
|
||||
```
|
||||
|
||||
Validate with:
|
||||
|
||||
```bash
|
||||
sudo launchctl print system/com.openclaw.mirofish
|
||||
curl -sS http://127.0.0.1:5001/health
|
||||
curl -sSI http://127.0.0.1:3000/
|
||||
curl -sS http://127.0.0.1:3000/api/graph/project/list
|
||||
```
|
||||
|
||||
## Hermes Integration
|
||||
|
||||
The canonical integration contract for Hermes and OpenClaw lives at:
|
||||
|
||||
- `/Users/adrianlat/Library/Mobile Documents/com~apple~CloudDocs/airShare/MiroFish/docs/hosting/mirofish-hermes-integration-contract.md`
|
||||
- `/Users/Shared/OpenClaw/mirofish-runtime/docs/hosting/mirofish-hermes-integration-contract.md`
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
# MiroFish Ops Contract
|
||||
|
||||
## Canonical Paths
|
||||
|
||||
- Runtime: `/Users/Shared/OpenClaw/mirofish-runtime`
|
||||
- Transcribes: `/Users/Shared/OpenClaw/transcribes`
|
||||
- Source only: `/Users/adrianlat/Library/Mobile Documents/com~apple~CloudDocs/airShare/MiroFish`
|
||||
|
||||
## Ownership
|
||||
|
||||
- Service owner: `airstride`
|
||||
- LaunchDaemon label: `com.openclaw.mirofish`
|
||||
|
||||
## Local Health Checks
|
||||
|
||||
```bash
|
||||
sudo launchctl print system/com.openclaw.mirofish
|
||||
curl -sS http://127.0.0.1:5001/health
|
||||
curl -sSI http://127.0.0.1:3000/
|
||||
curl -sS http://127.0.0.1:3000/api/graph/project/list
|
||||
```
|
||||
|
||||
## Post-Reboot Smoke Test
|
||||
|
||||
```bash
|
||||
/Users/Shared/OpenClaw/mirofish-runtime/scripts/host-smoke-test.sh
|
||||
```
|
||||
|
||||
## LAN + SSH Access
|
||||
|
||||
- Frontend: `http://10.0.0.161:3000`
|
||||
- Backend: `http://10.0.0.161:5001`
|
||||
- SSH alias: `openclaw-mirofish`
|
||||
- SSH user: `airstride`
|
||||
|
||||
Recommended tunnels:
|
||||
|
||||
```bash
|
||||
ssh -L 3000:127.0.0.1:3000 openclaw-mirofish
|
||||
ssh -L 5001:127.0.0.1:5001 openclaw-mirofish
|
||||
```
|
||||
|
||||
## Operational Rule
|
||||
|
||||
- Do not run MiroFish from iCloud.
|
||||
- Do not change canonical runtime or transcribes paths without migration.
|
||||
- Treat `backend/uploads` and shared transcribes as operational state.
|
||||
|
|
@ -3,7 +3,7 @@ import i18n from '../i18n'
|
|||
|
||||
// 创建axios实例
|
||||
const service = axios.create({
|
||||
baseURL: import.meta.env.VITE_API_BASE_URL || 'http://localhost:5001',
|
||||
baseURL: import.meta.env.VITE_API_BASE_URL || '/api',
|
||||
timeout: 300000, // 5分钟超时(本体生成可能需要较长时间)
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
|
|
|
|||
|
|
@ -12,8 +12,20 @@ export default defineConfig({
|
|||
}
|
||||
},
|
||||
server: {
|
||||
host: '0.0.0.0',
|
||||
port: 3000,
|
||||
open: false,
|
||||
proxy: {
|
||||
'/api': {
|
||||
target: 'http://localhost:5001',
|
||||
changeOrigin: true,
|
||||
secure: false
|
||||
}
|
||||
}
|
||||
},
|
||||
preview: {
|
||||
host: '0.0.0.0',
|
||||
port: 3000,
|
||||
open: true,
|
||||
proxy: {
|
||||
'/api': {
|
||||
target: 'http://localhost:5001',
|
||||
|
|
|
|||
|
|
@ -0,0 +1,26 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>Label</key>
|
||||
<string>airshare.mirofish</string>
|
||||
<key>ProgramArguments</key>
|
||||
<array>
|
||||
<string>/bin/zsh</string>
|
||||
<string>/Users/Shared/OpenClaw/mirofish-runtime/scripts/host-start.sh</string>
|
||||
<string>/Users/Shared/OpenClaw/mirofish-runtime</string>
|
||||
</array>
|
||||
<key>WorkingDirectory</key>
|
||||
<string>/Users/Shared/OpenClaw/mirofish-runtime</string>
|
||||
<key>RunAtLoad</key>
|
||||
<true/>
|
||||
<key>KeepAlive</key>
|
||||
<true/>
|
||||
<key>AbandonProcessGroup</key>
|
||||
<true/>
|
||||
<key>StandardOutPath</key>
|
||||
<string>/Users/Shared/OpenClaw/mirofish-runtime/runtime/logs/launchd.log</string>
|
||||
<key>StandardErrorPath</key>
|
||||
<string>/Users/Shared/OpenClaw/mirofish-runtime/runtime/logs/launchd.err.log</string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>Label</key>
|
||||
<string>com.openclaw.mirofish</string>
|
||||
<key>ProgramArguments</key>
|
||||
<array>
|
||||
<string>/bin/zsh</string>
|
||||
<string>/Users/Shared/OpenClaw/mirofish-runtime/scripts/host-start.sh</string>
|
||||
<string>/Users/Shared/OpenClaw/mirofish-runtime</string>
|
||||
</array>
|
||||
<key>UserName</key>
|
||||
<string>airstride</string>
|
||||
<key>WorkingDirectory</key>
|
||||
<string>/Users/Shared/OpenClaw/mirofish-runtime</string>
|
||||
<key>EnvironmentVariables</key>
|
||||
<dict>
|
||||
<key>HOME</key>
|
||||
<string>/Users/airstride</string>
|
||||
<key>CODEX_HOME</key>
|
||||
<string>/Users/airstride/.codex-openclaw</string>
|
||||
<key>PATH</key>
|
||||
<string>/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin</string>
|
||||
</dict>
|
||||
<key>RunAtLoad</key>
|
||||
<true/>
|
||||
<key>KeepAlive</key>
|
||||
<true/>
|
||||
<key>ProcessType</key>
|
||||
<string>Background</string>
|
||||
<key>AbandonProcessGroup</key>
|
||||
<true/>
|
||||
<key>StandardOutPath</key>
|
||||
<string>/Users/Shared/OpenClaw/mirofish-runtime/runtime/logs/launchd.log</string>
|
||||
<key>StandardErrorPath</key>
|
||||
<string>/Users/Shared/OpenClaw/mirofish-runtime/runtime/logs/launchd.err.log</string>
|
||||
<key>ThrottleInterval</key>
|
||||
<integer>15</integer>
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
@ -0,0 +1,119 @@
|
|||
#!/bin/zsh
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_DIR="${1:-/Users/Shared/OpenClaw/mirofish-runtime}"
|
||||
TRANSCRIBES_DIR="${2:-/Users/Shared/OpenClaw/transcribes}"
|
||||
DAEMON_LABEL="${3:-com.openclaw.mirofish}"
|
||||
|
||||
export PATH="/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin"
|
||||
|
||||
CURL_BIN="${CURL_BIN:-$(command -v curl)}"
|
||||
LSOF_BIN="${LSOF_BIN:-$(command -v lsof)}"
|
||||
NC_BIN="${NC_BIN:-$(command -v nc || true)}"
|
||||
PLUTIL_BIN="${PLUTIL_BIN:-$(command -v plutil)}"
|
||||
|
||||
pass() {
|
||||
printf '[PASS] %s\n' "$1"
|
||||
}
|
||||
|
||||
fail() {
|
||||
printf '[FAIL] %s\n' "$1" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
run_with_optional_sudo() {
|
||||
"$@" 2>/tmp/mirofish-command.err || sudo -n "$@" 2>/tmp/mirofish-command.err
|
||||
}
|
||||
|
||||
check_port() {
|
||||
local port="$1"
|
||||
local output_file="/tmp/mirofish-port${port}.txt"
|
||||
|
||||
if run_with_optional_sudo "$LSOF_BIN" -nP "-iTCP:$port" -sTCP:LISTEN >"$output_file"; then
|
||||
cat "$output_file"
|
||||
pass "Port $port is listening"
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [[ -n "$NC_BIN" ]] && "$NC_BIN" -z 127.0.0.1 "$port" >/dev/null 2>&1; then
|
||||
pass "Port $port accepts TCP connections"
|
||||
return 0
|
||||
fi
|
||||
|
||||
cat /tmp/mirofish-command.err >&2 || true
|
||||
fail "Port $port is not listening"
|
||||
}
|
||||
|
||||
printf 'MiroFish smoke test\n'
|
||||
printf 'runtime=%s\n' "$ROOT_DIR"
|
||||
printf 'transcribes=%s\n' "$TRANSCRIBES_DIR"
|
||||
printf 'daemon=%s\n\n' "$DAEMON_LABEL"
|
||||
|
||||
if run_with_optional_sudo launchctl print "system/$DAEMON_LABEL" >/tmp/mirofish-daemon.txt; then
|
||||
sed -n '1,40p' /tmp/mirofish-daemon.txt
|
||||
if grep -Eq 'state = (running|spawn scheduled)' /tmp/mirofish-daemon.txt; then
|
||||
pass "LaunchDaemon is installed and active in launchd"
|
||||
else
|
||||
fail "LaunchDaemon is not active in launchd"
|
||||
fi
|
||||
else
|
||||
cat /tmp/mirofish-command.err >&2 || true
|
||||
fail "LaunchDaemon is not installed or not readable"
|
||||
fi
|
||||
|
||||
if "$CURL_BIN" -fsS http://127.0.0.1:5001/health >/tmp/mirofish-backend.json; then
|
||||
cat /tmp/mirofish-backend.json
|
||||
pass "Backend health endpoint responds"
|
||||
else
|
||||
fail "Backend health endpoint failed"
|
||||
fi
|
||||
|
||||
if "$CURL_BIN" -fsSI http://127.0.0.1:3000/ >/tmp/mirofish-frontend.headers; then
|
||||
sed -n '1,8p' /tmp/mirofish-frontend.headers
|
||||
pass "Frontend root responds"
|
||||
else
|
||||
fail "Frontend root failed"
|
||||
fi
|
||||
|
||||
if "$CURL_BIN" -fsS http://127.0.0.1:3000/api/graph/project/list >/tmp/mirofish-proxy.json; then
|
||||
cat /tmp/mirofish-proxy.json
|
||||
pass "Frontend proxy to backend responds"
|
||||
else
|
||||
fail "Frontend proxy failed"
|
||||
fi
|
||||
|
||||
check_port 3000
|
||||
check_port 5001
|
||||
|
||||
if [[ -r "$ROOT_DIR/runtime/logs/backend.log" && -r "$ROOT_DIR/runtime/logs/frontend.log" ]]; then
|
||||
tail -n 5 "$ROOT_DIR/runtime/logs/backend.log" || true
|
||||
printf '\n'
|
||||
tail -n 5 "$ROOT_DIR/runtime/logs/frontend.log" || true
|
||||
pass "Logs are present"
|
||||
else
|
||||
fail "Runtime logs are missing"
|
||||
fi
|
||||
|
||||
if [[ -d "$TRANSCRIBES_DIR" ]]; then
|
||||
transcribe_count="$(find "$TRANSCRIBES_DIR" -type f 2>/dev/null | wc -l | tr -d ' ')"
|
||||
transcribe_size="$(du -sh "$TRANSCRIBES_DIR" 2>/dev/null | awk '{print $1}')"
|
||||
printf 'transcribes_files=%s\n' "$transcribe_count"
|
||||
printf 'transcribes_size=%s\n' "$transcribe_size"
|
||||
if [[ "$transcribe_count" -gt 0 ]]; then
|
||||
pass "Transcribes path is populated"
|
||||
else
|
||||
fail "Transcribes path is empty"
|
||||
fi
|
||||
else
|
||||
fail "Transcribes path does not exist"
|
||||
fi
|
||||
|
||||
if [[ -f "/Library/LaunchDaemons/$DAEMON_LABEL.plist" ]]; then
|
||||
"$PLUTIL_BIN" -lint "/Library/LaunchDaemons/$DAEMON_LABEL.plist"
|
||||
pass "Installed LaunchDaemon plist is valid"
|
||||
else
|
||||
fail "Installed LaunchDaemon plist is missing"
|
||||
fi
|
||||
|
||||
printf '\nMiroFish smoke test completed successfully.\n'
|
||||
|
|
@ -0,0 +1,86 @@
|
|||
#!/bin/zsh
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_DIR="${1:-$(cd "$(dirname "$0")/.." && pwd)}"
|
||||
LOG_DIR="$ROOT_DIR/runtime/logs"
|
||||
PID_DIR="$ROOT_DIR/runtime/pids"
|
||||
export PATH="/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin"
|
||||
UV_BIN="${UV_BIN:-$(command -v uv)}"
|
||||
NPM_BIN="${NPM_BIN:-$(command -v npm)}"
|
||||
NPX_BIN="${NPX_BIN:-$(command -v npx)}"
|
||||
CURL_BIN="${CURL_BIN:-$(command -v curl)}"
|
||||
LSOF_BIN="${LSOF_BIN:-$(command -v lsof)}"
|
||||
|
||||
mkdir -p "$LOG_DIR" "$PID_DIR" "$ROOT_DIR/backend/uploads/reports" "$ROOT_DIR/backend/uploads/simulations"
|
||||
|
||||
monitor_existing_runtime() {
|
||||
echo "MiroFish already running"
|
||||
while true; do
|
||||
if ! "$CURL_BIN" -fsS http://127.0.0.1:5001/health >/dev/null 2>&1; then
|
||||
echo "Backend health check failed"
|
||||
exit 1
|
||||
fi
|
||||
if ! "$CURL_BIN" -fsS http://127.0.0.1:3000/ >/dev/null 2>&1; then
|
||||
echo "Frontend health check failed"
|
||||
exit 1
|
||||
fi
|
||||
sleep 30
|
||||
done
|
||||
}
|
||||
|
||||
if "$LSOF_BIN" -nP -iTCP:3000 -sTCP:LISTEN >/dev/null 2>&1; then
|
||||
if "$CURL_BIN" -fsS http://127.0.0.1:3000/ >/dev/null 2>&1 && \
|
||||
"$CURL_BIN" -fsS http://127.0.0.1:5001/health >/dev/null 2>&1; then
|
||||
monitor_existing_runtime
|
||||
fi
|
||||
echo "Port 3000 already in use by an unhealthy process"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if "$LSOF_BIN" -nP -iTCP:5001 -sTCP:LISTEN >/dev/null 2>&1; then
|
||||
if "$CURL_BIN" -fsS http://127.0.0.1:3000/ >/dev/null 2>&1 && \
|
||||
"$CURL_BIN" -fsS http://127.0.0.1:5001/health >/dev/null 2>&1; then
|
||||
monitor_existing_runtime
|
||||
fi
|
||||
echo "Port 5001 already in use by an unhealthy process"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cd "$ROOT_DIR/backend"
|
||||
env FLASK_DEBUG=False PYTHONUNBUFFERED=1 "$UV_BIN" run --no-sync python run.py < /dev/null > "$LOG_DIR/backend.log" 2>&1 &
|
||||
BACKEND_PID=$!
|
||||
echo "$BACKEND_PID" > "$PID_DIR/backend.pid"
|
||||
|
||||
for _ in {1..30}; do
|
||||
if "$CURL_BIN" -fsS http://127.0.0.1:5001/health >/dev/null 2>&1; then
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
|
||||
if ! "$CURL_BIN" -fsS http://127.0.0.1:5001/health >/dev/null 2>&1; then
|
||||
echo "Backend failed to start"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cd "$ROOT_DIR/frontend"
|
||||
"$NPM_BIN" run build >/dev/null
|
||||
"$NPX_BIN" vite preview --host 0.0.0.0 --port 3000 --strictPort < /dev/null > "$LOG_DIR/frontend.log" 2>&1 &
|
||||
FRONTEND_PID=$!
|
||||
echo "$FRONTEND_PID" > "$PID_DIR/frontend.pid"
|
||||
|
||||
for _ in {1..30}; do
|
||||
if "$CURL_BIN" -fsS http://127.0.0.1:3000/ >/dev/null 2>&1; then
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
|
||||
if ! "$CURL_BIN" -fsS http://127.0.0.1:3000/ >/dev/null 2>&1; then
|
||||
echo "Frontend failed to start"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "MiroFish started"
|
||||
wait "$BACKEND_PID" "$FRONTEND_PID"
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
#!/bin/zsh
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_DIR="${1:-$(cd "$(dirname "$0")/.." && pwd)}"
|
||||
PID_DIR="$ROOT_DIR/runtime/pids"
|
||||
export PATH="/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin"
|
||||
CURL_BIN="${CURL_BIN:-$(command -v curl)}"
|
||||
LSOF_BIN="${LSOF_BIN:-$(command -v lsof)}"
|
||||
|
||||
echo "Backend health:"
|
||||
"$CURL_BIN" -fsS http://127.0.0.1:5001/health || true
|
||||
echo
|
||||
echo
|
||||
echo "Frontend headers:"
|
||||
"$CURL_BIN" -fsSI http://127.0.0.1:3000/ || true
|
||||
echo
|
||||
echo "Ports:"
|
||||
"$LSOF_BIN" -nP -iTCP:3000 -sTCP:LISTEN || true
|
||||
"$LSOF_BIN" -nP -iTCP:5001 -sTCP:LISTEN || true
|
||||
echo
|
||||
echo "PID files:"
|
||||
ls -la "$PID_DIR" 2>/dev/null || true
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
#!/bin/zsh
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_DIR="${1:-$(cd "$(dirname "$0")/.." && pwd)}"
|
||||
PID_DIR="$ROOT_DIR/runtime/pids"
|
||||
export PATH="/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin"
|
||||
PKILL_BIN="${PKILL_BIN:-$(command -v pkill)}"
|
||||
|
||||
stop_pid_file() {
|
||||
local pid_file="$1"
|
||||
if [[ -f "$pid_file" ]]; then
|
||||
local pid
|
||||
pid="$(cat "$pid_file")"
|
||||
if kill -0 "$pid" >/dev/null 2>&1; then
|
||||
kill "$pid" >/dev/null 2>&1 || true
|
||||
for _ in {1..20}; do
|
||||
if ! kill -0 "$pid" >/dev/null 2>&1; then
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
kill -9 "$pid" >/dev/null 2>&1 || true
|
||||
fi
|
||||
rm -f "$pid_file"
|
||||
fi
|
||||
}
|
||||
|
||||
stop_pid_file "$PID_DIR/frontend.pid"
|
||||
stop_pid_file "$PID_DIR/backend.pid"
|
||||
|
||||
"$PKILL_BIN" -f "vite preview --host 0.0.0.0 --port 3000" >/dev/null 2>&1 || true
|
||||
"$PKILL_BIN" -f "uv run --no-sync python run.py" >/dev/null 2>&1 || true
|
||||
|
||||
echo "MiroFish stopped"
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
#!/bin/zsh
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
PLIST_SOURCE="/Users/Shared/OpenClaw/mirofish-runtime/ops/launchd/com.openclaw.mirofish.plist"
|
||||
PLIST_TARGET="/Library/LaunchDaemons/com.openclaw.mirofish.plist"
|
||||
|
||||
if [[ ! -f "$PLIST_SOURCE" ]]; then
|
||||
echo "Missing source plist: $PLIST_SOURCE"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ "$(id -u)" -ne 0 ]]; then
|
||||
echo "Run this script with sudo."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cp "$PLIST_SOURCE" "$PLIST_TARGET"
|
||||
chown root:wheel "$PLIST_TARGET"
|
||||
chmod 644 "$PLIST_TARGET"
|
||||
plutil -lint "$PLIST_TARGET"
|
||||
|
||||
launchctl bootout system/com.openclaw.mirofish 2>/dev/null || true
|
||||
launchctl bootstrap system "$PLIST_TARGET"
|
||||
launchctl kickstart -k system/com.openclaw.mirofish
|
||||
|
||||
echo "Installed LaunchDaemon at $PLIST_TARGET"
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
#!/bin/zsh
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
if [[ "$(id -un)" != "airstride" ]]; then
|
||||
echo "Run this script as airstride."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
RUNTIME_ROOT="/Users/Shared/OpenClaw/mirofish-runtime"
|
||||
PLIST_SOURCE="$RUNTIME_ROOT/ops/launchd/airshare.mirofish.plist"
|
||||
PLIST_TARGET="$HOME/Library/LaunchAgents/airshare.mirofish.plist"
|
||||
|
||||
mkdir -p "$HOME/Library/LaunchAgents"
|
||||
cp "$PLIST_SOURCE" "$PLIST_TARGET"
|
||||
|
||||
if launchctl print "gui/$(id -u)" >/dev/null 2>&1; then
|
||||
DOMAIN="gui/$(id -u)"
|
||||
else
|
||||
DOMAIN="user/$(id -u)"
|
||||
fi
|
||||
|
||||
launchctl bootout "$DOMAIN/airshare.mirofish" 2>/dev/null || true
|
||||
launchctl bootstrap "$DOMAIN" "$PLIST_TARGET"
|
||||
launchctl kickstart -k "$DOMAIN/airshare.mirofish"
|
||||
|
||||
echo "Installed LaunchAgent at $PLIST_TARGET in $DOMAIN"
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
#!/bin/zsh
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
SOURCE_DIR="${1:-/Users/adrianlat/Library/Mobile Documents/com~apple~CloudDocs/BreathWork/Transcribes}"
|
||||
TARGET_DIR="${2:-/Users/Shared/OpenClaw/transcribes}"
|
||||
|
||||
mkdir -p "$TARGET_DIR"
|
||||
rsync -a --delete --human-readable "$SOURCE_DIR/" "$TARGET_DIR/"
|
||||
chgrp -R openclawshare "$TARGET_DIR"
|
||||
chmod -R g+rwX "$TARGET_DIR"
|
||||
find "$TARGET_DIR" -type d -exec chmod g+s {} +
|
||||
|
||||
echo "Transcribes synced to $TARGET_DIR"
|
||||
Loading…
Reference in New Issue