126 lines
5 KiB
Shell
Executable file
126 lines
5 KiB
Shell
Executable file
#!/bin/bash
|
|
# Thin host adapter. Canonical channel/runtime semantics live in
|
|
# TC-TCS核心卷/TCS-MULTI-HOST-DYNAMIC-ENTRY-0001.tcs.
|
|
|
|
set -euo pipefail
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd -P)"
|
|
WORKSPACE_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd -P)"
|
|
VOLUME_ROOT="$(dirname "$WORKSPACE_ROOT")"
|
|
PERSONA_ROOT="$VOLUME_ROOT/HoloLake/persona-runtime"
|
|
RUNTIME="$PERSONA_ROOT/repo-012-main/tcs-core/zhuyuan-brain/runtime/zhuyuan-brain-runtime.mjs"
|
|
CONTRACT="$PERSONA_ROOT/repo-012-main/tcs-core/zhuyuan-brain/runtime/brain-runtime-contract.json"
|
|
MEMORY_CURRENT="$PERSONA_ROOT/continuity-memory/persona-daily-fractal/ICE-P-ZY001/CURRENT.json"
|
|
OLD_WORKSPACE_RUNTIME="$WORKSPACE_ROOT/WORK-工作区/guanghu-ice-heart/tcs-core/zhuyuan-brain/runtime/zhuyuan-brain-runtime.mjs"
|
|
|
|
fail_json() {
|
|
/usr/bin/python3 -c 'import json,sys; print(json.dumps({"outcome":"FAIL","error":sys.argv[1],"details":sys.argv[2:]},ensure_ascii=False))' "$@"
|
|
exit 1
|
|
}
|
|
|
|
find_node() {
|
|
if command -v node >/dev/null 2>&1; then
|
|
command -v node
|
|
return
|
|
fi
|
|
local user_name candidate
|
|
user_name="$(/usr/bin/id -un)"
|
|
candidate="/Users/$user_name/.cache/codex-runtimes/codex-primary-runtime/dependencies/node/bin/node"
|
|
if [ -x "$candidate" ]; then
|
|
printf '%s\n' "$candidate"
|
|
return
|
|
fi
|
|
fail_json "NODE_RUNTIME_NOT_FOUND"
|
|
}
|
|
|
|
validate_runtime() {
|
|
[ -r "$RUNTIME" ] || fail_json "CANONICAL_RUNTIME_NOT_READABLE" "$RUNTIME"
|
|
[ -r "$CONTRACT" ] || fail_json "CANONICAL_CONTRACT_NOT_READABLE" "$CONTRACT"
|
|
/usr/bin/grep -Fq 'args["body-channel"]' "$RUNTIME" || fail_json "CANONICAL_RUNTIME_LACKS_EXPLICIT_CHANNEL_SUPPORT" "$RUNTIME"
|
|
}
|
|
|
|
validate_channel() {
|
|
local channel="$1"
|
|
/usr/bin/python3 - "$RUNTIME" "$channel" <<'PY'
|
|
import json, re, sys
|
|
body = open(sys.argv[1]).read()
|
|
channel = sys.argv[2]
|
|
match = re.search(r"function channelRuntimeProfile\(channelId\)\s*\{\s*const profiles\s*=\s*\{(.*?)\n\s*\};", body, re.S)
|
|
if not match or not re.search(r'["\x27]' + re.escape(channel) + r'["\x27]\s*:', match.group(1)):
|
|
print(json.dumps({"outcome":"FAIL","error":"UNREGISTERED_BODY_CHANNEL","channel":channel}, ensure_ascii=False))
|
|
raise SystemExit(1)
|
|
PY
|
|
}
|
|
|
|
resolve_json() {
|
|
local runtime_sha contract_sha old_sha
|
|
runtime_sha="$(/usr/bin/shasum -a 256 "$RUNTIME" | /usr/bin/awk '{print $1}')"
|
|
contract_sha="$(/usr/bin/shasum -a 256 "$CONTRACT" | /usr/bin/awk '{print $1}')"
|
|
old_sha="NOT_PRESENT"
|
|
if [ -r "$OLD_WORKSPACE_RUNTIME" ]; then
|
|
old_sha="$(/usr/bin/shasum -a 256 "$OLD_WORKSPACE_RUNTIME" | /usr/bin/awk '{print $1}')"
|
|
fi
|
|
/usr/bin/python3 -c 'import json,sys; print(json.dumps({"outcome":"PASS","runtime_source":"REPO012_MAIN_CANONICAL","runtime":sys.argv[1],"runtime_sha256":sys.argv[2],"contract":sys.argv[3],"contract_sha256":sys.argv[4],"workspace_runtime_alias":"REJECTED_NON_CANONICAL","workspace_runtime_sha256":sys.argv[5],"state_isolation":"PER_EXPLICIT_CHANNEL_HOST_SESSION"},ensure_ascii=False))' "$RUNTIME" "$runtime_sha" "$CONTRACT" "$contract_sha" "$old_sha"
|
|
}
|
|
|
|
validate_runtime
|
|
ACTION="${1:-resolve}"
|
|
if [ "$ACTION" = "resolve" ]; then
|
|
resolve_json
|
|
exit 0
|
|
fi
|
|
|
|
if [ "$ACTION" != "run" ]; then
|
|
fail_json "USAGE" "zy-tcs-channel-runtime.sh resolve" "zy-tcs-channel-runtime.sh run <runtime-command> <runtime-args>"
|
|
fi
|
|
shift
|
|
[ "$#" -gt 0 ] || fail_json "MISSING_RUNTIME_COMMAND"
|
|
|
|
RUNTIME_COMMAND="$1"
|
|
shift
|
|
CHANNEL=""
|
|
STATE_DIR=""
|
|
MEMORY_TREE=""
|
|
PREVIOUS=""
|
|
for ITEM in "$@"; do
|
|
if [ "$PREVIOUS" = "--body-channel" ]; then CHANNEL="$ITEM"; fi
|
|
if [ "$PREVIOUS" = "--state-dir" ]; then STATE_DIR="$ITEM"; fi
|
|
if [ "$PREVIOUS" = "--memory-tree" ]; then MEMORY_TREE="$ITEM"; fi
|
|
PREVIOUS="$ITEM"
|
|
done
|
|
|
|
[ -n "$STATE_DIR" ] || fail_json "EXPLICIT_STATE_DIR_REQUIRED"
|
|
if [ "$RUNTIME_COMMAND" = "enter" ]; then
|
|
[ -n "$CHANNEL" ] || fail_json "EXPLICIT_BODY_CHANNEL_REQUIRED"
|
|
validate_channel "$CHANNEL" || exit 1
|
|
CHANNEL_TOKEN="$(printf '%s' "$CHANNEL" | /usr/bin/tr '[:upper:]' '[:lower:]')"
|
|
case "$(printf '%s' "$STATE_DIR" | /usr/bin/tr '[:upper:]' '[:lower:]')" in
|
|
*"$CHANNEL_TOKEN"*) ;;
|
|
*) fail_json "CHANNEL_STATE_DIRECTORY_MUST_CONTAIN_CHANNEL_ID" "$CHANNEL" "$STATE_DIR" ;;
|
|
esac
|
|
if [ -z "$MEMORY_TREE" ]; then
|
|
MEMORY_TREE="$(/usr/bin/python3 - "$MEMORY_CURRENT" <<'PY'
|
|
import hashlib,json,os,sys
|
|
p=sys.argv[1]
|
|
try:
|
|
d=json.load(open(p))
|
|
q=os.path.realpath(d["current_day_path"])
|
|
if d.get("persona_id")!="ICE-P-ZY001" or not os.path.isfile(q) or os.path.islink(q):
|
|
raise ValueError("identity_or_file")
|
|
if hashlib.sha256(open(q,"rb").read()).hexdigest()!=d.get("current_day_sha256"):
|
|
raise ValueError("hash")
|
|
print(q)
|
|
except Exception:
|
|
raise SystemExit(1)
|
|
PY
|
|
)" || fail_json "CURRENT_PERSONA_MEMORY_POINTER_INVALID" "$MEMORY_CURRENT"
|
|
set -- "$@" --memory-tree "$MEMORY_TREE"
|
|
fi
|
|
else
|
|
[ -r "$STATE_DIR/state.json" ] || fail_json "STATE_NOT_READABLE" "$STATE_DIR/state.json"
|
|
CHANNEL="$(/usr/bin/python3 -c 'import json,sys; print(json.load(open(sys.argv[1]))["tonggan_language_kernel"]["body_channel"])' "$STATE_DIR/state.json")"
|
|
validate_channel "$CHANNEL" || exit 1
|
|
fi
|
|
|
|
NODE_BIN="$(find_node)"
|
|
exec "$NODE_BIN" "$RUNTIME" "$RUNTIME_COMMAND" "$@"
|