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

跨机远控 Rinai-R/kivotos

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

在任意一台电脑或手机上,使用你的每一个 DeepSeek Harness。

36/100
综合分
9
GitHub 星标
—
npm 周下载
—/5
用户评分

数据截至 2026/10/23 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。

自动兼容检查未通过:缺少 main/exports/bin 入口声明;仓库 package.json 标记 private,未发布到 npm,需从源码安装。以下命令仍可尝试,但可能失败。
安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add Rinai-R/kivotos
该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)

状态速览

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

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

验证判据与等级说明 →
⚠︎ 实装验证未通过(unknown · 2026/10/24) ——可能是验证环境差异,装前建议到 GitHub 仓库确认最近更新与 issue。
社区实装还没有人打卡 · 装过的第一个就是你
安装兼容性检查需源码安装

缺少 main/exports/bin 入口声明;仓库 package.json 标记 private,未发布到 npm,需从源码安装

展开查看检查明细 ↓

以下结论由程序自动检查 npm 包、engines 声明与入口文件得出,未做人工实机验证——能装不等于用着没问题。

✗npm 包kivotos-workspace(未发布到 npm,仅可源码安装)
✓Node 引擎要求 ^22.19.0 || >=24 · 基线 Node 22.19 满足
✓dsh CLI 依赖未声明 dsh 版本约束
✗入口文件缺少入口声明

源码安装时若 pnpm 拦截 prepare 脚本,按其提示在 pnpm-workspace.yaml 的 allowBuilds 中放行后重跑。

验证方式:npm registry 存在性 + package.json 静态校验 · 最后检查 2026/11/1 10:27:03

安全扫描自动 · 静态分析源码
v2.7.0
🔵 扫描:含敏感能力尚无人工评估
展开查看扫描说明与证据 ↓

静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。

可执行外部命令读写/删除本地文件发起外部网络请求
查看扫描证据(共 81 处,展示前 71 条)
  • 读取本地文件
    scripts/install-hooks.mjs:7
    if (existsSync(".git")) {
  • 执行外部命令固定命令
    scripts/install-hooks.mjs:8
    execFileSync("npx", ["--no-install", "lefthook", "install", "--force"], { stdio: "inherit" });
  • 删除本地文件递归
    packages/kivotos/src/cache.ts:333
    await rm(dir, { recursive: true, force: true });
  • 写入本地文件
    packages/kivotos/src/cache.ts:336
    await mkdir(dir, { recursive: true, mode: 0o700 });
  • 读取本地文件
    packages/kivotos/src/cache.ts:338
    for (const peer of await readdir(dir)) {
  • 删除本地文件递归
    packages/kivotos/src/cache.ts:341
    await rm(path.join(dir, peer), { recursive: true, force: true });
  • 读取本地文件
    packages/kivotos/src/cache.ts:362
    files = await readdir(dir);
  • 读取本地文件
    packages/kivotos/src/cache.ts:372
    const raw = await readFile(path.join(dir, file), "utf8");
  • 读取本地文件
    packages/kivotos/src/cache.ts:374
    const body = await stat(path.join(dir, `${name}.body`));
  • 删除本地文件递归
    packages/kivotos/src/cache.ts:386
    if (!kept.has(file)) await rm(path.join(dir, file), { recursive: true, force: true });
  • 删除本地文件递归
    packages/kivotos/src/cache.ts:406
    await rm(path.join(this.options.dir, peer), { recursive: true, force: true }).catch(
  • 写入本地文件
    packages/kivotos/src/cache.ts:433
    utimes(this.file(entry.peer, entry.name, ".body"), now, now).catch(() => undefined);
  • 删除本地文件
    packages/kivotos/src/cache.ts:446
    await rm(this.file(entry.peer, entry.name, ".json"), { force: true }).catch(() => undefined);
  • 删除本地文件
    packages/kivotos/src/cache.ts:447
    await rm(this.file(entry.peer, entry.name, ".body"), { force: true }).catch(() => undefined);
  • 写入本地文件
    packages/kivotos/src/cache.ts:615
    await mkdir(path.dirname(temp), { recursive: true, mode: 0o700 });
  • 写入本地文件
    packages/kivotos/src/cache.ts:670
    await rename(`${temp}.body.tmp`, this.file(peer, name, ".body"));
  • 写入本地文件
    packages/kivotos/src/cache.ts:678
    await rename(`${temp}.json.tmp`, this.file(peer, name, ".json"));
  • 发起网络请求
    packages/kivotos/src/index.ts:390
    const res = await fetch(url, { redirect: "manual" });
  • 写入本地文件
    packages/kivotos/src/index.ts:555
    await mkdir(dir, { recursive: true, mode: 0o700 });
  • 读取本地文件
    packages/kivotos/src/index.ts:559
    return { cert: await readFile(certFile), key: await readFile(keyFile) };
  • 发起网络请求
    packages/kivotos/src/index.ts:763
    await frontend.request(req, res, who);
  • 读取本地文件
    packages/kivotos/src/index.ts:1057
    text = await readFile(this.file, "utf8");
  • 写入本地文件
    packages/kivotos/src/index.ts:1178
    await mkdir(path.dirname(this.file), { recursive: true });
  • 写入本地文件
    packages/kivotos/src/index.ts:1179
    await writeFile(this.file, text);
  • 发起网络请求
    packages/kivotos/src/proxy.ts:173
    ? https.request({ ...base, servername: upstream.servername ?? upstream.host })
  • 发起网络请求
    packages/kivotos/src/proxy.ts:174
    : http.request(base);
  • 读取本地文件
    packages/kivotos/src/relay-host.ts:109
    text = await readFile(file, "utf8");
  • 写入本地文件
    packages/kivotos/src/relay-host.ts:120
    await mkdir(path.dirname(file), { recursive: true });
  • 写入本地文件
    packages/kivotos/src/relay-host.ts:121
    await writeFile(file, JSON.stringify(value, null, 2), { mode: 0o600 });
  • 写入本地文件
    packages/kivotos/src/relay-host.ts:122
    await chmod(file, 0o600);
  • 发起网络请求
    packages/kivotos/src/relay-host.ts:151
    serve.request(req, res, this.caller(req)).catch((error: unknown) => {
  • 删除本地文件
    packages/kivotos/src/relay-host.ts:352
    await rm(this.networkFile, { force: true });
  • 执行外部命令来自配置/变量
    packages/kivotos/src/tailscale.ts:42
    execFile(binary, args, { timeout: timeoutMs, maxBuffer: 16 * 1024 * 1024 }, (error, stdout) => {
  • 写入本地文件
    packages/kivotos/src/trace.ts:58
    await mkdir(this.dir, { recursive: true });
  • 读取本地文件
    packages/kivotos/src/trace.ts:60
    for (const name of await readdir(this.dir)) {
  • 删除本地文件
    packages/kivotos/src/trace.ts:62
    if (day !== undefined && day < oldest) await unlink(path.join(this.dir, name));
  • 写入本地文件
    packages/kivotos/src/trace.ts:106
    this.stream = createWriteStream(path.join(this.dir, `trace-${day}.jsonl`), { flags: "a" });
  • 发起网络请求
    packages/mobile/src/machines.ts:75
    const res = await fetch(`${url}/kivotos/hello`, { signal: controller.signal });
  • 读取本地文件
    scripts/check-dsh-boundary.mjs:30
    for (const name of readdirSync(dir)) {
  • 读取本地文件
    scripts/check-dsh-boundary.mjs:32
    if (statSync(file).isDirectory()) out.push(...files(file));
  • 读取本地文件
    scripts/check-dsh-boundary.mjs:52
    const lines = code(readFileSync(file, "utf8")).split("\n");
  • 读取本地文件
    scripts/dev.mjs:92
    accessSync(file, constants.X_OK);
  • 读取本地文件
    scripts/dev.mjs:93
    if (statSync(file).isFile()) return file;
  • 读取本地文件
    scripts/dev.mjs:106
    accessSync(given, constants.X_OK);
  • 读取本地文件
    scripts/dev.mjs:136
    if (existsSync(dir)) {
  • 读取本地文件
    scripts/dev.mjs:137
    if (!statSync(dir).isDirectory()) throw new Failure(`${dir} exists and is not a directory`, 2);
  • 读取本地文件
    scripts/dev.mjs:138
    if (!existsSync(path.join(dir, MARKER)) && readdirSync(dir).length > 0) {
  • 写入本地文件
    scripts/dev.mjs:145
    mkdirSync(dir, { recursive: true });
  • 执行外部命令来自配置/变量
    scripts/dev.mjs:158
    const result = spawnSync(command, args, {
  • 执行外部命令来自配置/变量
    scripts/dev.mjs:185
    const child = spawn(command, args, {
  • 删除本地文件递归
    scripts/dev.mjs:248
    else rmSync(labDir, { recursive: true, force: true });
  • 删除本地文件递归
    scripts/dev.mjs:273
    rmSync(dir, { recursive: true, force: true });
  • 写入本地文件
    scripts/dev.mjs:276
    mkdirSync(path.join(dir, sub), { recursive: true });
  • 写入本地文件
    scripts/dev.mjs:278
    writeFileSync(path.join(dir, MARKER), "");
  • 写入本地文件
    scripts/dev.mjs:291
    writeFileSync(patch, "- id: kivotos\n config:\n listen: false\n discover: false\n");
  • 写入本地文件
    scripts/dev.mjs:299
    writeFileSync(path.join(dir, home, "kivotos", "relay.json"), membership);
  • 写入本地文件
    scripts/dev.mjs:302
    writeFileSync(path.join(dir, "invite.txt"), invite);
  • 执行外部命令来自配置/变量
    scripts/dev.mjs:348
    const list = spawnSync(relay, ["network", "list", "--data-dir", data], { encoding: "utf8" });
  • 读取本地文件
    scripts/dsh-compat.mjs:79
    for (const name of readdirSync(dir)) {
  • 读取本地文件
    scripts/dsh-compat.mjs:81
    const info = statSync(file);
  • 执行外部命令来自配置/变量
    scripts/dsh-compat.mjs:90
    const child = spawn(
  • 发起网络请求
    scripts/dsh-compat.mjs:121
    const response = await fetch(url, { redirect: "manual" });
  • 执行外部命令固定命令
    scripts/dsh-compat.mjs:138
    execFileSync(
  • 读取本地文件
    scripts/dsh-compat.mjs:146
    version = JSON.parse(readFileSync(path.join(dsh, "package.json"), "utf8")).version;
  • 执行外部命令来自配置/变量
    scripts/dsh-compat.mjs:149
    execFileSync(
  • 写入本地文件
    scripts/dsh-compat.mjs:159
    writeFileSync(patch, "- id: kivotos\n config:\n listen: false\n discover: false\n");
  • 发起网络请求
    scripts/dsh-compat.mjs:166
    const get = (where) => fetch(new URL(where, origin), { headers: { cookie } });
  • 读取本地文件
    scripts/dsh-compat.mjs:194
    readFileSync(file, "utf8"),
  • 删除本地文件递归
    scripts/dsh-compat.mjs:205
    rmSync(work, { recursive: true, force: true, maxRetries: 3 });
  • 执行外部命令固定命令
    scripts/dsh-compat.mjs:214
    const version = execFileSync("npm", ["view", `@deepseek-ai/dsh@${tag}`, "version"], {
  • 写入本地文件
    scripts/dsh-compat.mjs:242
    if (process.env.GITHUB_STEP_SUMMARY) appendFileSync(process.env.GITHUB_STEP_SUMMARY, `${text}\n`);
扫描于 2026/11/3(1 天前) · 范围 入口闭包 + 全包扫描 · 来源 GitHub 仓库

静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。

给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个

功能亮点

  • 跨设备打开操控
  • 适配手机布局

从任意 dsh 打开并操控 tailnet 上的每个 dsh,配完整手机布局。

README

由 DeepSeek 最新模型翻译生成
Kivotos English ·简体中文 ·日本語 · 在任意一台电脑或手机上,使用你的每一个 DeepSeek Harness。 Kivotos 是 DeepSeek Harness(dsh)的开源插件。在任意一台机器上打开其它机器的 dsh,界面完整可用:会话、审批、模型、设置、文件和终端。它还为 dsh 加上了手机布局,并附带一个安卓 App。 - 所有机器: 在 dsh 侧边栏里切换。看到的就是远端 dsh 自己的界面,所有功能都能用。 - 两种连接方式: Tailscale,或你自己部署的中继服务器。一台机器可以同时使用两种。 - 不可信中继: 中继只转发端到端加密的数据,读不到内容,也无法加入你的网络。 - 手机布局: 抽屉式侧边栏,输入框固定在底部,适配安全区,支持浅色和深色。 - 安卓 App: 完整的 dsh 界面,在需要审批、提问或任务完成时通知你。 - 自托管: 无需账号,没有遥测,不依赖推送服务。 快速开始 前置条件 - DeepSeek Harness 0.2.1-rc.2 - 所有设备登录同一个 Tailscale 账号,或者有一台自建的中继服务器 插件 在每台机器上安装。在 dsh 里打开 插件 → 安装第三方插件,填入 kivotos。
展开完整文档(README 剩余 1 节)
Kivotos

English ·简体中文 ·日本語 ·

在任意一台电脑或手机上,使用你的每一个 DeepSeek Harness。

Kivotos 是 DeepSeek Harness(dsh)的开源插件。在任意一台机器上打开其它机器的 dsh,界面完整可用:会话、审批、模型、设置、文件和终端。它还为 dsh 加上了手机布局,并附带一个安卓 App。

- 所有机器: 在 dsh 侧边栏里切换。看到的就是远端 dsh 自己的界面,所有功能都能用。
- 两种连接方式: Tailscale,或你自己部署的中继服务器。一台机器可以同时使用两种。
- 不可信中继: 中继只转发端到端加密的数据,读不到内容,也无法加入你的网络。
- 手机布局: 抽屉式侧边栏,输入框固定在底部,适配安全区,支持浅色和深色。
- 安卓 App: 完整的 dsh 界面,在需要审批、提问或任务完成时通知你。
- 自托管: 无需账号,没有遥测,不依赖推送服务。

快速开始

前置条件

- DeepSeek Harness 0.2.1-rc.2
- 所有设备登录同一个 Tailscale 账号,或者有一台自建的中继服务器

插件

在每台机器上安装。在 dsh 里打开 插件 → 安装第三方插件,填入 kivotos。也可以用命令行:

dsh plugin --profile web add kivotos

重启 dsh 后,其它机器会出现在侧边栏底部的 机器 里。

手机

从发布页下载 APK 安装。在电脑上打开 机器 → 配对手机,用 App 扫码。

中继

在一台有公网地址的服务器上用 Docker Compose 运行中继:

curl -O https://raw.githubusercontent.com/Rinai-R/kivotos/main/packages/relay/docker-compose.yml
docker compose up -d

在第一台电脑上打开 设置 → 远程连接 → 自建中继,填写中继地址并创建网络,再在中继上执行 docker compose exec relay 加页面显示的命令完成登记。其它电脑和手机用邀请链接或二维码加入。

拿到邀请链接的人,或登录了你 Tailscale 账号的人,都能完全控制你的机器。

开发

- packages/kivotos:dsh 插件(TypeScript)
- packages/mobile:安卓 App(Expo、Kotlin)
- packages/relay:中继服务器(Go)

npm install # install tools and build the plugin
npm run build # rebuild the plugin after changing src/
npm run typecheck
npm test

npm run apk -w packages/mobile # Android APK (JDK 17, Android SDK)
cd packages/relay && go test ./...

构建、测试和贡献见 CONTRIBUTING.md,在本地起一个中继和两个 dsh 实例用 npm run dev。架构和约定见 AGENTS.md,报告漏洞见 SECURITY.md。

许可证

Apache-2.0。Kivotos 与 DeepSeek 和 Tailscale 均无关联。
预览分享卡片长什么样 ↓Rinai-R/kivotos
分享 · DeepSeek Harness Hub
Rinai-R/kivotos

在任意一台电脑或手机上,使用你的每一个 DeepSeek Harness。

这是你的仓库?认领条目

回到顶部