1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
|
#!/usr/bin/env bash
set -euo pipefail
PATCH_FILE="openclaw-adjustment.patch"
patch_source() {
# 1. package.json
echo "Patching package.json..."
if ! grep -q '"node-gyp":' package.json; then
# Verify original strings exist before patching
grep -q '"scripts": {' package.json
grep -q '"packageManager": "pnpm@' package.json
grep -q '"lit":' package.json
sed -i '/"scripts": {/,/},/ s/pnpm/bun run/g' package.json
# Replace npm package manager definition
sed -i 's/"packageManager": "pnpm@[^"]*"/"packageManager": "bun@1.2.0"/' package.json
# Insert node-gyp
sed -i '/"lit":/a \ "node-gyp": "^12.2.0",' package.json
# Remove @discordjs/opus if it exists (don't fail if already gone)
sed -i '/"@discordjs\/opus":/d' package.json
fi
# 2. scripts/bundle-a2ui.sh
echo "Patching scripts/bundle-a2ui.sh..."
if ! grep -q 'bun run tsc' scripts/bundle-a2ui.sh; then
grep -q 'pnpm -s exec tsc' scripts/bundle-a2ui.sh
sed -i 's/pnpm -s exec tsc/bun run tsc/' scripts/bundle-a2ui.sh
fi
# 3. scripts/ui.js
echo "Patching scripts/ui.js..."
# Insert bun detection
if ! grep -q 'const bun = which("bun");' scripts/ui.js; then
grep -q 'const pnpm = which("pnpm");' scripts/ui.js
sed -i '/const pnpm = which("pnpm");/i \ const bun = which("bun");\n if (bun) {\n return { cmd: bun, kind: "bun" };\n }' scripts/ui.js
fi
if ! grep -q 'install bun or pnpm, then retry' scripts/ui.js; then
grep -q 'install pnpm, then retry' scripts/ui.js
sed -i 's/install pnpm, then retry/install bun or pnpm, then retry/' scripts/ui.js
fi
# 4. src/discord/voice/manager.ts (moved to extensions/discord/src/voice/manager.ts)
VOICE_MANAGER=""
for f in src/discord/voice/manager.ts extensions/discord/src/voice/manager.ts; do
if [ -f "$f" ]; then
VOICE_MANAGER="$f"
break
fi
done
if [ -n "$VOICE_MANAGER" ]; then
echo "Patching $VOICE_MANAGER..."
if ! grep -q 'any' "$VOICE_MANAGER" 2>/dev/null || ! grep -q 'opus' "$VOICE_MANAGER" 2>/dev/null; then
if grep -q 'typeof import("@discordjs/opus")' "$VOICE_MANAGER"; then
sed -i 's/typeof import("@discordjs\/opus")/any/g' "$VOICE_MANAGER"
fi
fi
else
echo "Skipping discord voice/manager.ts patch (file not found, upstream removed opus)"
fi
# 5. src/agents/skills-install.ts
echo "Patching src/agents/skills-install.ts..."
if ! grep -q 'CONFIG_DIR' src/agents/skills-install.ts; then
grep -q 'import { resolveUserPath } from "../utils.js";' src/agents/skills-install.ts
grep -q 'env?: NodeJS.ProcessEnv;' src/agents/skills-install.ts
grep -q 'env: params.env,' src/agents/skills-install.ts
grep -q 'const uvInstallFailure = await ensureUvInstalled' src/agents/skills-install.ts
grep -q 'if (spec.kind === "brew" && brewExe && argv?\.\[0\] === "brew") {' src/agents/skills-install.ts
grep -q 'return withWarnings(await executeInstallCommand({ argv, timeoutMs, env }), warnings);' src/agents/skills-install.ts
sed -i 's/import { resolveUserPath } from "..\/utils.js";/import { resolveUserPath, CONFIG_DIR } from "..\/utils.js";/' src/agents/skills-install.ts
sed -i 's/env?: NodeJS.ProcessEnv;/env?: NodeJS.ProcessEnv;\n cwd?: string;/' src/agents/skills-install.ts
sed -i 's/env: params.env,/env: params.env,\n cwd: params.cwd,/' src/agents/skills-install.ts
sed -i '/const uvInstallFailure = await ensureUvInstalled({ spec, brewExe, timeoutMs });/i \
// Force installation into user config directory if package.json exists there or forced by env\
const configPkgJson = path.join(CONFIG_DIR, "package.json");\
const forceLocal = process.env.OPENCLAW_FORCE_LOCAL_SKILLS === "1";\
' src/agents/skills-install.ts
sed -i '/if (spec.kind === "brew" && brewExe && argv?\.\[0\] === "brew") {/i \
if (spec.kind === "node" && argv && (forceLocal || fs.existsSync(configPkgJson))) {\
// Remove global flags\
for (let i = 0; i < argv.length; i++) {\
if (argv[i] === "-g" || argv[i] === "global") {\
argv.splice(i, 1);\
i--;\
}\
}\
}\
' src/agents/skills-install.ts
sed -i 's/return withWarnings(await executeInstallCommand({ argv, timeoutMs, env }), warnings);/\
\/\/ Use CONFIG_DIR as cwd if we are installing locally (stripped globals)\
const cwd = (spec.kind === "node" \&\& (forceLocal || fs.existsSync(configPkgJson)))\
? CONFIG_DIR\
: undefined;\
\
return withWarnings(await executeInstallCommand({ argv, timeoutMs, env, cwd }), warnings);/' src/agents/skills-install.ts
fi
}
show_help() {
echo "Usage: $0 [OPTION]"
echo "Options:"
echo " --patch Apply changes to the source"
echo " --refresh-patch Recreate the patch file from pristine source for reference"
echo " --help Show this help"
}
case "${1:-}" in
--patch)
patch_source
;;
--refresh-patch)
echo "Refreshing pristine sources..."
updpkgsums
makepkg -Co --noprepare
cd src/openclaw
echo "Creating backups for diff..."
cp package.json package.json.orig
cp scripts/bundle-a2ui.sh scripts/bundle-a2ui.sh.orig
cp scripts/ui.js scripts/ui.js.orig
cp src/discord/voice/manager.ts src/discord/voice/manager.ts.orig
cp src/agents/skills-install.ts src/agents/skills-install.ts.orig
patch_source
echo "Generating new $PATCH_FILE..."
{
diff -u package.json.orig package.json || true
diff -u scripts/bundle-a2ui.sh.orig scripts/bundle-a2ui.sh || true
diff -u scripts/ui.js.orig scripts/ui.js || true
diff -u src/discord/voice/manager.ts.orig src/discord/voice/manager.ts || true
diff -u src/agents/skills-install.ts.orig src/agents/skills-install.ts || true
} >"../../$PATCH_FILE"
cd ../..
echo "Updating PKGBUILD checksums..."
updpkgsums
echo "Done! You can now review $PATCH_FILE."
;;
--help | "")
show_help
;;
*)
echo "Unknown option: $1"
show_help
exit 1
;;
esac
|