🎁 福利专区全网大模型免费应用 + 新用户福利 + 注册活动入口,低成本玩转 AI

飞牛 NAS 助手 MeetoHub/dsh-fnos

DeepSeek Harness
MeetoHub11 天前有提交已提供中文文档扫描:含敏感能力

在对话里授权登录飞牛 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 源安装(明细见下方安装检查)

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:仅索引
是什么
dsh 原生插件 · other
装得上吗
本站尚未做安装检查
L4 · 真实安装等级说明 →
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
活跃:最近一次提交在 11 天前
档位由哪些信号合成

本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。

验证判据与等级说明 →
社区实装还没有人打卡 · 装过的第一个就是你
安全扫描自动 · 静态分析源码
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。

如果这个插件帮你省了时间,点个 ⭐ 是最好的支持
预览分享卡片长什么样 ↓MeetoHub/dsh-fnos
分享 · DeepSeek Harness Hub
MeetoHub/dsh-fnos

在对话里授权登录飞牛 NAS,浏览目录并 @ 引用文件

这是你的仓库?认领条目

回到顶部