在对话里授权登录飞牛 NAS,浏览目录并 @ 引用文件
30.8/100
综合分
1
GitHub 星标
—
npm 周下载
—/5
用户评分
数据截至 2026/10/24 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。
安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add MeetoHub/dsh-fnos该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)
状态速览
判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态信任档位:仅索引
档位由哪些信号合成
本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。
社区实装还没有人打卡 · 装过的第一个就是你
安全扫描自动 · 静态分析源码v2.7.0🔵 扫描:含敏感能力尚无人工评估展开查看扫描说明与证据 ↓
安全扫描自动 · 静态分析源码
v2.7.0静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。
可执行外部命令读写/删除本地文件发起外部网络请求
查看扫描证据(共 73 处,展示前 51 条)
- 发起网络请求lib/client.js:43
const res = await fetch(BASE + path, init); - 发起网络请求lib/client.js:211
const r = await fetch('/fnos/discover?port=' + port).then((x) => x.json()); - 发起网络请求lib/client.js:443
const r = await fetch('/fnos/files?path=' + encodeURIComponent(p)).then((x) => x.json()); - 发起网络请求lib/client.js:456
try { await fetch('/fnos/me').then((x) => x.json()); } catch { } - 写入本地文件lib/auth.js:34
mkdirSync(dirname(target), { recursive: true }) - 写入本地文件lib/auth.js:35
appendFileSync(target, text, 'utf8') - 读取本地文件lib/cli.js:36
if (!existsSync(CLI_HOME)) return null - 读取本地文件lib/cli.js:37
const dirs = readdirSync(CLI_HOME) - 读取本地文件lib/cli.js:39
.map((d) => ({ d, at: statSync(join(CLI_HOME, d)).mtimeMs })) - 读取本地文件lib/cli.js:43
if (existsSync(p) && statSync(p).isFile() && statSync(p).size > MIN_VALID_BYTES) return p - 读取本地文件lib/cli.js:43
if (existsSync(p) && statSync(p).isFile() && statSync(p).size > MIN_VALID_BYTES) return p - 发起网络请求lib/cli.js:58
return await fetch(url, { - 写入本地文件lib/cli.js:130
mkdirSync(dir, { recursive: true }) - 写入本地文件lib/cli.js:131
writeFileSync(partPath, buf) - 写入本地文件lib/cli.js:132
try { chmodSync(partPath, 0o755) } catch { } - 写入本地文件lib/cli.js:133
renameSync(partPath, finalPath) - 写入本地文件lib/cli.js:134
try { chmodSync(finalPath, 0o755) } catch { } - 删除本地文件lib/cli.js:139
try { rmSync(partPath, { force: true }) } catch { } - 读取本地文件lib/impl.js:113
if (!existsSync(CLI_HOME_DIR)) return null - 读取本地文件lib/impl.js:120
if (existsSync(p) && statSync(p).isFile() && statSync(p).size > CLI_MIN_VALID_BYTES) return p - 读取本地文件lib/impl.js:157
const j = JSON.parse(readFileSync(join(SKILL_HOME, 'current.json'), 'utf8')) - 读取本地文件lib/impl.js:158
if (j && j.version && j.dir && existsSync(j.dir)) return j - 读取本地文件lib/impl.js:168
const j = JSON.parse(readFileSync(IDENTITY_FILE, 'utf8')) - 写入本地文件lib/impl.js:175
mkdirSync(dirname(IDENTITY_FILE), { recursive: true }) - 写入本地文件lib/impl.js:176
writeFileSync(IDENTITY_FILE, JSON.stringify(obj), 'utf8') - 读取本地文件lib/impl.js:230
if (existsSync(candidate)) return candidate - 写入本地文件lib/impl.js:545
mkdirSync(dirname(CACHE_FILE), { recursive: true }) - 写入本地文件lib/impl.js:548
writeFileSync(CACHE_FILE, JSON.stringify(obj), 'utf8') - 删除本地文件lib/impl.js:615
try { unlinkSync(CACHE_FILE) } catch { } - 写入本地文件lib/impl.js:626
mkdirSync(dirname(target), { recursive: true }) - 写入本地文件lib/impl.js:627
appendFileSync(target, text, 'utf8') - 读取本地文件lib/official.js:57
const j = JSON.parse(readFileSync(CURRENT_FILE, 'utf8')) - 读取本地文件lib/official.js:58
if (j && j.version && j.dir && existsSync(j.dir)) return j - 读取本地文件lib/official.js:85
if (existsSync(dir)) { - 读取本地文件lib/official.js:86
const archives = readdirSync(dir).filter((f) => f.includes('.done-')) - 删除本地文件lib/official.js:89
rmSync(join(dir, name), { force: true }) - 读取本地文件lib/official.js:99
const dirs = readdirSync(SKILL_HOME) - 读取本地文件lib/official.js:104
return statSync(full).isDirectory() ? { name, at: statSync(full).mtimeMs } : null - 删除本地文件递归lib/official.js:119
rmSync(join(SKILL_HOME, d.name), { recursive: true, force: true }) - 发起网络请求lib/official.js:153
return await fetch(url, { - 写入本地文件lib/official.js:181
mkdirSync(destDir, { recursive: true }) - 执行外部命令来自配置/变量lib/official.js:194
execFileSync(cmd, args, { stdio: 'ignore', timeout: 120_000 }) - 写入本地文件lib/official.js:224
mkdirSync(SKILL_HOME, { recursive: true }) - 写入本地文件lib/official.js:235
mkdirSync(incomingDir, { recursive: true }) - 删除本地文件lib/official.js:244
try { rmSync(p, { force: true }) } catch { } - 写入本地文件lib/official.js:308
writeFileSync(tmpZip, buf) - 删除本地文件递归lib/official.js:324
try { rmSync(finalDir, { recursive: true, force: true }) } catch { } - 写入本地文件lib/official.js:325
renameSync(root, finalDir) - 写入本地文件lib/official.js:326
writeFileSync(CURRENT_FILE, JSON.stringify({ - 删除本地文件lib/official.js:335
try { rmSync(tmpZip, { force: true }) } catch { } - 删除本地文件递归lib/official.js:336
try { rmSync(tmpDir, { recursive: true, force: true }) } catch { }
扫描于 2026/11/4(0 天前) · 范围 入口闭包 + 发布文件清单 · 来源 GitHub 仓库
静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。
给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个
飞牛 fnOS 的 DSH 插件:远程授权登录、文件/文件夹 @引用选择器、目录树后台缓存
README
由 DeepSeek 最新模型翻译生成dsh-fnos
在对话里直接遥控你的飞牛 NAS
授权、翻目录、把 NAS 上的文件 @ 进对话 —— 全程不打开终端。
为什么需要它
飞牛 fnOS 提供了官方命令行(trim-cli),能力很全 —— 但它是个终端工具。想在 AI 对话里让智能体帮你操作 NAS,你得反复:
trim-cli login # 打开浏览器、粘一次性授权码 trim-cli file ls /vol1/1000 # 一层层翻目录找路径然后手动把路径复制进对话
dsh-fnos 把这三步搬进 DSH 界面:
- 授权变成插件详情页里的一个按钮
- 翻目录变成输入框旁边的浮层,点两下就到
- 引用文件变成 Ctrl + 点击,路径自动变成 @文件名
对智能体来说,它还同时注册了 fnOS 技能,智能体知道该调哪些命令、参数怎么填。
展开完整文档(README 剩余 1 节)
dsh-fnos
在对话里直接遥控你的飞牛 NAS
授权、翻目录、把 NAS 上的文件 @ 进对话 —— 全程不打开终端。
为什么需要它
飞牛 fnOS 提供了官方命令行(trim-cli),能力很全 —— 但它是个终端工具。想在 AI 对话里让智能体帮你操作 NAS,你得反复:
trim-cli login # 打开浏览器、粘一次性授权码 trim-cli file ls /vol1/1000 # 一层层翻目录找路径然后手动把路径复制进对话
dsh-fnos 把这三步搬进 DSH 界面:
- 授权变成插件详情页里的一个按钮
- 翻目录变成输入框旁边的浮层,点两下就到
- 引用文件变成 Ctrl + 点击,路径自动变成 @文件名
对智能体来说,它还同时注册了 fnOS 技能,智能体知道该调哪些命令、参数怎么填。
界面预览
文件 / 文件夹选择器输入框左侧飞牛图标点开即目录树,文件夹可下钻;Ctrl + 点击 直接以 @文件 引用插入,不用先打 /
插件详情页主机 / 端口 / 协议 / 证书校验都写在插件自己的页面里,授权状态一目了然,不污染全局设置
在插件列表里以「飞牛 NAS」出现 —— 标题与图标来自 locale/ 与 icon.png,跟随深浅色主题
功能
| | 能力 | 说明 |
| 🔐 | 授权登录 | 走 trim-cli 的 OAuth 设备码流程,插件页里点一下 → 打开浏览器 → 粘回授权码。结论只认 system info,不会被"静默退出"骗过 |
| 📂 | 文件 / 文件夹选择器 | 目录树浮层,文件夹可下钻、文件可选中,Ctrl/Cmd + 点击 直接插入引用 |
| ⚡ | 目录缓存 | 内存直读 + 落盘快照,打开恒为毫秒级;冷启动实测 3366 ms → 3–81 ms |
| 🎨 | 主题跟随 | 全部用 --dsw-alias- 变量 + 毛玻璃,跟随 DSH 皮肤,深色/浅色都不破相 |
| 🧠 | 技能自动注册 | 插件激活即向 DSH 注册 fnos 技能,智能体立刻知道怎么用 NAS |
| 🩺 | 自检探针 | GET /fnos/probe 返回服务可用性、命令行路径、缓存规模,排障不用猜 |
安装
三种方式,都不需要 clone、不需要构建 —— lib/ 已是可直接运行的代码。
最快(推荐)
在 DSH 里把 Release 的 tgz 地址交给插件管理器。
按你的系统选一个(包里已含本平台的 trim-cli,装完即可用,无需再下载):
| 系统 | 下载量 | 包名 |
| Windows x64(最常见) | 3.1 MB | dsh-fnos-windows-x64.tgz |
| Windows ARM64 | 2.8 MB | dsh-fnos-windows-arm64.tgz |
| macOS Apple 芯片 | 3.3 MB | dsh-fnos-darwin-arm64.tgz |
| macOS Intel | 3.4 MB | dsh-fnos-darwin-x64.tgz |
| Linux x64 | 3.3 MB | dsh-fnos-linux-x64.tgz |
| Linux ARM64 | 3.1 MB | dsh-fnos-linux-arm64.tgz |
| 不确定 / 想一次覆盖所有平台 | 17.5 MB | dsh-fnos.tgz |
以 Windows x64 为例:
plugin_manager install_bundle target = https://github.com/MeetoHub/dsh-fnos/releases/latest/download/dsh-fnos-windows-x64.tgz
为什么要分平台:官方 trim-cli 有 6 个平台的二进制,合计 41 MB。
全塞进一个包,用户得多下十几 MB 才能用;只装自己那一个,下载量降到 1/5.7。
完整包 dsh-fnos.tgz 仍然保留,兼容不确定自己平台的情况。
粘仓库地址
plugin_manager install_bundle target = github:MeetoHub/dsh-fnos
会完整拉取仓库(含 bin/ 二进制),比上一个慢。要固定版本加 #v0.4.0。
⚠️ 必须写成 github:MeetoHub/dsh-fnos(github: 开头,没有 https://)。
直接把浏览器地址栏的 https://github.com/MeetoHub/dsh-fnos 粘进去会装不上——那是一个网页地址,pnpm 拿它 clone 只会拿到 HTML,表现为「安装失败 / 无输出」。
⚠️ 网络受限时不要用远程 URL 安装
用 https://…/dsh-fnos-x.y.z.tgz 这类远程 URL 装进配置档后,pnpm 会把它当作一条需要联网校验的依赖。之后你安装任何其它插件,pnpm 都会重新解析整张依赖图,从而再次请求这个 GitHub 地址。
如果该地址不可达(实测部分网络对 GitHub releases 超时 21 秒),表现为「插件安装中…」一直转圈、新插件装不上,而且很难联想到是 fnos 引起的。
受限网络下的正确做法:
bash
① 开发态:本地软链,完全不联网 plugin_manager install_bundle target = /path/to/dsh-fnos
② 离线安装:先把 tgz 下到本地,再用文件路径 plugin_manager install_bundle target = file:/path/to/dsh-fnos-0.2.2.tgz
③ 确认配置档里没有残留的远程依赖 grep 'https\?://' "$DSH_PROFILE_DIR/package.json"
源码开发态 bash
cd "$DSH_PROFILE_DIR"
pnpm add link:/path/to/dsh-fnos
改代码即时生效(宿主侧在插件管理器里关/开一次,客户端侧刷新页面)。
装完需重启一次 DSH(宿主半边是 Node 模块,启动时装载)。
完整步骤、前置条件、卸载与排错见 docs/INSTALL.md。
它怎么工作
插件由两个半边组成:
| 半边 | 文件 | 职责 |
| 客户端 | lib/client.js | 输入框图标、文件选择浮层、插件详情页配置。跑在 Web UI |
| 宿主 | lib/impl.js · lib/auth.js | HTTP 路由、授权状态机、目录缓存。跑在 DSH 主进程 |
两者只通过 DSH 自己的 HTTP 路由通信(/fnos/auth/、/fnos/files、/fnos/probe),不使用任何私有 IPC —— 所以插件升级不会因为 DSH 内部变动而失效。
对 NAS 只有一种依赖:官方 trim-cli,按三级顺序查找:
FNO_TRIM_CLI 环境变量 → 包内 bin/ → 系统 PATH
三级都没有时报一条可操作的中文错误,而不是拿不存在的路径去 spawn。
性能
目录读取走内存 + 落盘快照,打开永远不阻塞:
| 场景 | 耗时 |
| 冷启动(实时调 NAS) | 3366 ms |
| 缓存命中 | 3 – 81 ms |
| DSH 重启后(从磁盘恢复) | 9 – 67 ms |
后台刷新默认关闭:spawnTerminal 每次调用在本平台会残留约 11 个句柄,而打开目录树本来就靠 peek() 走内存。需要更新鲜的数据时带 ?fresh=1 强制刷新,或设 FNO_BACKGROUND_REFRESH=1 打开自调度刷新(20 秒 / 每轮 1 条 / 不重叠)。
这一条来自一次真实事故 —— 详见 docs/PITFALLS.md 第 9 条。
技能与 CLI 的更新
官方技能包是带版本号的 zip(含 SKILL.md、entries/、reference/、bin/trim-cli),版本与 SHA256 公布在官网下载页。本插件启动时会非阻塞地检查并同步最新版:
| 步骤 | 说明 |
| 检查 | 抓 fnnas.com/download,解析官方公布的 {version, url, sha256} |
| 下载 | ① 直连官方 CDN → ② Release 镜像 |
| 校验 | SHA256 必须一致,否则整包丢弃 |
| 安装 | 解压到 ~/.dsh/fnos-skill/v{ver}/,成功后原子切换 current.json |
| 兜底 | 失败静默,已装版本继续可用;装坏可回退 |
| 清理 | 装成功后立即删除原始 zip,版本目录只留当前 + 上一个,不会越攒越多 |
CLI 查找顺序随之升级为四级:
FNO_TRIM_CLI → 官方技能包 bin/ → 插件内 bin/ → 系统 PATH
技能内容也优先取同步下来的官方版本(source: runtime),所以文档不会随插件发版而落后。
官方 CDN 被墙时
部分网络对 iso.liveupdate.fnnas.com 直接返回 403(实测 curl / Node / 真实浏览器内核均被挡)。
这时把官方 zip 放进下面这个目录,重载插件即自动安装(文件名任意,.zip 结尾即可):
~/.dsh/fnos-skill/incoming/fnos-skill.zip
安装成功后原始 zip 会被立即删除(回滚点由保留下来的上一个版本目录提供),不会重复安装,也不会长期占用空间。
关闭自动同步:设环境变量 FNO_SKILL_SYNC=0。
安全与隐私
- 凭据不出本机:授权状态由 trim-cli 自己管理,插件不落盘任何 token
- 不做外发:除你的 NAS 地址外,插件不向任何第三方发起请求
- 自签证书:默认容忍设备的自签证书(tlsInsecure),仅影响该 NAS 的 TLS 校验
- 可审计:全部逻辑在 lib/(约 1.6k 行),无混淆、无压缩产物
常见问题
装完看不到图标?
首次安装新包必须重启 DSH,仅刷新页面不够(宿主半边在启动时装载)。
授权一直失败 / 授权页报「参数异常」?
海外版 FygoOS 固件的 OAuth 端点不识别 trim-cli 的 client_id,属设备侧限制,插件无法绕过。国内版 fnOS 正常。
提示找不到 trim-cli?
按提示任选一种:放进插件 bin/ 目录、加入系统 PATH、或用 FNO_TRIM_CLI 指定绝对路径。
从 GitHub 地址安装时报 NPM_EPERM?
说明该插件已经以本地软链形式装着,同一个包名不能两种装法并存。
先 remove_bundle,再装,或继续用软链(开发态更适合)。
参与开发
| 文档 | 内容 |
| docs/DEVELOPMENT.md | 开发循环、分支与版本约定、发版流程、三道安全防线 |
| docs/PITFALLS.md | 10 条踩坑记录(含一起内存泄漏事故的完整复盘) |
| docs/INSTALL.md | 三种安装方式的完整说明与排错 |
新克隆仓库后请先启用敏感内容扫描(防把内网地址带进公开历史): bash
git config core.hooksPath scripts/hooks
发版只要三步: bash
npm version patch --no-git-tag-version
git commit -am "chore: release vX.Y.Z" && git push
git tag vX.Y.Z && git push origin vX.Y.Z # CI 自动建 Release 并附 tgz
许可
自有代码 MIT,见 LICENSE。
bin/ 下是飞牛官方 trim-cli 预编译产物(六个平台,约 41 MB),版权归飞牛 fnOS 所有,仅随本插件分发作运行依赖 —— 不构成对本项目的授权。详见 NOTICE。
如果这个插件帮你省了时间,点个 ⭐ 是最好的支持预览分享卡片长什么样 ↓
分享 · DeepSeek Harness Hub
MeetoHub/dsh-fnos
在对话里授权登录飞牛 NAS,浏览目录并 @ 引用文件
相关插件 · 其他
模型破甲清洗HunYiSage/dsh-purge
⚔️ DeepSeek Harness 网络安全红队工具dsh-purge
★ 16,993已汉化DeepSeek 客户端
73
女娲蒸馏alchaincyf/nuwa-skill
输入名人名字,提炼其思维模型与决策方式供你调用
★ 37,308已汉化DSH
72
逆向分析桥接Fanqi89/dsh-rea
REA(Reverse Engineer Anything)MCP 桥接,用来把 REA 逆向工具接入 DSH 插件
★ 51已汉化DSH
72
语音女友beiyege-01/dsh-voice-ai-girlfriend
语音 AI 女友Voice AI girlfriend for DeepSeek Harness:Whisper…
★ 888已汉化DSH
71.6
红队越狱测试套件Minglink/dsh-infinite-gen-5
DeepSeek v4.1 flash 逆向工具无限五代 求 Star 收藏 ⭐欢迎大家提交项目的改进
★ 3,759已汉化DSH
71.4
协同办公空间dream-num/univer-workspace
一个让人类与 AI Agent 共同创作、协作和审阅的开源 Office 工作空间。
★ 2,269已汉化DSH
70.8
这是你的仓库?认领条目