#!/bin/sh
set -e
RESTORE=0
case "${1:-}" in
--restore) RESTORE=1 ;;
"") ;;
*) echo "用法: $0 [--restore]"; exit 2 ;;
esac
NODE=/storage/Users/currentUser/.harmonybrew/bin/node
DSH_ROOT="/storage/Users/currentUser/.npm-global/lib/node_modules/@deepseek-ai/dsh"
SHIM_DST="$DSH_ROOT/node_modules/@deepseek-ai/harmonyos-link-shim.mjs"
SHIM_IMP='import { link } from "../../harmonyos-link-shim.mjs";'
SP="$DSH_ROOT/node_modules/@deepseek-ai/dsh-session-persistence-jsonl/lib/index.js"
FS="$DSH_ROOT/node_modules/@deepseek-ai/dsh-fs-local/lib/index.js"
ATT="$DSH_ROOT/node_modules/@deepseek-ai/dsh-attachment-local/lib/index.js"
[ -d "$DSH_ROOT/node_modules/@deepseek-ai" ] || { echo "未找到 dsh 依赖目录 $DSH_ROOT"; exit 1; }
patch_call_site() {
echo "==== $1 ===="
[ -f "$2" ] || { echo "未找到 $2,跳过"; return 0; }
if grep -q 'harmonyos-link-shim.mjs' "$2"; then
echo " [skip] 已含垫片补丁,跳过"
return 0
fi
if grep -q 'try { await link(tmp, finalPath); } catch' "$2"; then
if [ -f "$2.bak" ]; then
cp "$2.bak" "$2"
echo " 已从 .bak 还原(清除旧内联补丁): $2.bak"
else
echo " [WARN] 带旧内联补丁但无 .bak,基于当前内容直接打补丁"
fi
fi
cp "$2" "$2.bak"
"$NODE" - "$2" "$SHIM_IMP" <<'NODE'
const fs = require("fs");
const f = process.argv[2];
const shimImp = process.argv[3];
let s = fs.readFileSync(f, "utf8");
let changed = false;
// 1) 正则:从 node:fs/promises 的 import 中移除 `link`(不关心同行的其他包名)
const reImport = /import \{([^}]*)\} from "node:fs\/promises";/;
const m = reImport.exec(s);
if (m) {
const names = m[1].split(",").map((x) => x.trim());
if (names.includes("link")) {
const cleaned = names.filter((x) => x !== "link").join(", ");
s = s.replace(reImport, `import { ${cleaned} } from "node:fs/promises";`);
changed = true;
console.log(" [ok] 正则移除 fs/promises import 中的 link");
} else {
console.log(" [skip] fs/promises import 已不含 link");
}
} else {
console.error(" [FAIL] 未找到 node:fs/promises import 行"); process.exit(1);
}
// 2) 在 fs/promises import 行后引入垫片
if (!s.includes(shimImp)) {
const reInsert = /(import \{[^}]*\} from "node:fs\/promises";\n)/;
if (!reInsert.test(s)) { console.error(" [FAIL] 插入点未找到"); process.exit(1); }
s = s.replace(reInsert, `$1${shimImp}\n`);
changed = true;
console.log(" [ok] 引入垫片 import");
} else {
console.log(" [skip] 垫片已引入");
}
if (changed) fs.writeFileSync(f, s);
console.log(" 完成");
NODE
}
restore_call_site() {
echo "==== $1 ===="
[ -f "$2" ] || { echo "未找到 $2,跳过"; return 0; }
if grep -q 'harmonyos-link-shim.mjs\|try { await link(tmp, finalPath); } catch' "$2"; then
if [ -f "$2.bak" ]; then
cp "$2.bak" "$2"
echo " 已还原: $2.bak -> $2"
else
echo " [WARN] 文件含我们的补丁但无 .bak,无法自动还原,请手动处理"
fi
else
echo " [skip] 不含我们的补丁,无需还原"
fi
}
if [ "$RESTORE" -eq 1 ]; then
restore_call_site "1/3 dsh-session-persistence-jsonl(session 日志)" "$SP"
restore_call_site "2/3 dsh-fs-local(write 工具)" "$FS"
restore_call_site "3/3 dsh-attachment-local(附件对象)" "$ATT"
STILL=0
for f in "$SP" "$FS" "$ATT"; do
[ -f "$f" ] && grep -q 'harmonyos-link-shim.mjs' "$f" && STILL=1
done
if [ "$STILL" -eq 0 ] && [ -f "$SHIM_DST" ]; then
rm -f "$SHIM_DST"
echo "已移除垫片: $SHIM_DST"
elif [ "$STILL" -eq 1 ]; then
echo "[WARN] 仍有调用点引用垫片,保留: $SHIM_DST"
fi
echo
echo "已还原。重启 dsh web 生效。"
exit 0
fi
echo "==== 0/4 写入 link 垫片 ===="
cat > "$SHIM_DST" <<'SHIM'
import { constants } from "node:fs";
import { copyFile, link as systemLink } from "node:fs/promises";
export async function link(src, dest) {
try {
return await systemLink(src, dest);
} catch (error) {
if (error.code !== "EACCES" && error.code !== "EPERM") throw error;
return await copyFile(src, dest, constants.COPYFILE_EXCL);
}
}
export * from "node:fs/promises";
SHIM
echo " 已写入: $SHIM_DST"
patch_call_site "1/3 dsh-session-persistence-jsonl(session 日志)" "$SP"
patch_call_site "2/3 dsh-fs-local(write 工具)" "$FS"
patch_call_site "3/3 dsh-attachment-local(附件对象)" "$ATT"
echo
echo "垫片方案就绪。重启 dsh web 生效。"
echo "dsh 升级后重跑本脚本即可;各文件备份为 <文件>.bak;还原用 --restore"