🎁 福利专区全网大模型免费应用 + 新用户福利 + 注册活动入口,低成本玩转 AI
广告☁️ 云服务器特惠阿里云首购 8 折 · 腾讯云合作特惠
DeepSeek Harness Hub
← 返回列表

x102201/dsh-helper-plugin-command-ask

DeepSeek Harnessspec-screened扫描:低风险在 GitHub 查看 ↗
⚠ 装前注意

dsh: 0.1.5-rc.2

基本兼容但装前注意:未发布到 npm registry,仅可从源码安装 · 最近上游提交 2026/9/20 · 已提供中文文档

dsh-helper plugin: a Cursor-style /ask mode for DeepSeek Harness — /ask <question> answers read-only for one turn (cited, no edits, enforced by a tool guard), then the next message is ordinary work again. | 中文:dsh-helper 插件——为 DeepSeek Harness 提供 /ask 只读问答模式,一轮即释放,内置工具守卫强制只读。

综合分
29.8
GitHub 分
29.8
用户评分
—
★ Stars
0
周下载量
—
安装插件(需先安装 dsh CLI 引擎:npm install -g @deepseek-ai/dsh)
dsh plugin --profile web add x102201/dsh-helper-plugin-command-ask
未发布到 npm registry,仅可从源码安装,改用 GitHub 源安装
信任档位:已验证本站已于 1 天前真实安装成功
是什么
dsh 原生插件 · chat
装得上吗
本站已真实安装成功(非静态推断)
安全吗
本站尚未对该插件做风险分级(暂未覆盖,不等同于无风险)
还在维护吗
活跃:最近一次提交在 5 天前

档位由下列信号合成:本站实装验证(真实安装,当前最高到 L4)· 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。下方各区块是它的证据明细。 验证判据与等级说明 →

🟢实装验证通过· 2026/9/25
由本站实装验证器在真实 dsh 环境安装成功,非静态推断。
数据截至 2026/9/22(元数据每日更新 · 实装验证按队列轮转,单条结论的验证时间见上方)
安装兼容性检查⚠ 装前注意

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

✗npm 包dsh-helper-plugin-command-ask(未发布到 npm,仅可源码安装)
✓Node 引擎要求 >=20 · 基线 Node 22.19 满足
✓dsh CLI 依赖未声明 dsh 版本约束
✓入口文件main/exports/bin 已声明

未发布到 npm registry,仅可从源码安装

验证方式:npm registry 存在性 + package.json 静态校验 · 最后验证 2026/9/22 15:34:21

用户评分
还没有人投票,来当第一个
订阅周报,不错过优质插件更新
每周一封 · 高评分插件 + 新用户活动

README

由 DeepSeek 最新模型翻译生成
dsh-helper-plugin-command-ask

license: MIT
dsh: 0.1.5-rc.2
tests: 82 passing

给 DeepSeek Harness(dsh)用的 /ask 模式插件:仿照官方 /plan 模式、对齐 Cursor 的 Ask 模式——对这一轮提问给出只读回答。

为什么需要它:平时 dsh 会话会边聊边改文件。但有时你只想要一个答案——这个配置在哪、为什么重试三次、改这里会牵连什么——而不希望 Agent 动任何东西。ask 轮里它只能看、不能改,而且工具守卫会真的拦下改动,即使模型忘了。

用起来是什么样:/ask 问题 只让这一轮变成只读问答——只引用实读内容、不改动任何东西——模式在该轮结束时自动释放,所以之后不带 /ask 的消息就是普通干活:先问,再说一句"执行"即可。/ask off 只是提前取消。

/ask 为什么重试预算是 3?      这一轮只读回答,然后恢复正常
/ask                          为下一轮预置 ask 模式
/ask off                      提前取消(从来不必要)

一行安装:

dsh plugin --profile web add link:/absolute/path/to/dsh-helper-plugin-command-ask
dsh plugin --profile web add github:x102201/dsh-helper-plugin-command-ask

在 dsh-helper 工作台实录(1.6 倍速)——左侧是实例列表,四个 dsh 环境并排运行,其中一个装着本插件。/ask 问题 拒绝写入并说明原因,随后一条普通消息"执行"就真的创建了文件。→ 更清晰的 MP4(0.8 MB)

它做了什么

| 组成 | 行为 |
|---|---|
| /ask 命令 | 预置 ask 模式,可带后缀问题(支持图片/文件附件)。scope: turn(默认)只覆盖一轮;scope: session 是 /plan 式常驻模式,直到 /ask off。 |
| 轮次边界 | 逐轮模式由 harness 自己的 turn/end 事件释放,因此下一次请求组装时就已经没有它了——不需要 /ask off。 |
| ask:policy 提示词分段 | 模式生效时在每次请求都渲染部署方配置的引导文本;未生效时不贡献任何文本。 |
| 持久状态 | ask 投影单元从会话日志里折叠 /ask 的 command/run/command/done 记录以及 turn/end。插件不写任何自有事件类型,并且每次切换都用 ctx.sessions.flush() 立刻落盘,所以重启后模式仍在。 |
| 只读守卫 | 默认开启:用 ctx.tools.guard() 注册单调守卫,在 ask 模式生效时拒绝被列入的改动类工具,并告知模型改为「基于可查看的内容回答」。 |
| 与 plan 模式接力 | 仅在 scope: session 时:常驻 ask 模式与 plan 模式互斥,进入即退出对方。 |
| 编程接口 | 提供 ctx.askMode:get(agent)、set(agent, active)(走真实命令)、isActive(session)。 |

每一轮 ask 都是自包含的:引导文本只出现在它管辖的那几次请求里,而日志把每次开关记录成一条普通的 /ask 命令记录。

从 0.1.x 升级

0.1.x 把模式持久化成了它自己的会话事件类型 ask/mode。仓库外插件不能扩充 harness 的事件词汇表:Session.append() 无法设置信封上的 ignorable 标记,于是持久化读取路径会拒绝含该事件的日志("unknown to this harness and not marked ignorable; refusing to interpret the log"),所有跑过 /ask 的会话都无法再加载。0.2.0 不再写这种事件,并用 scripts/repair-ask-mode-logs.mjs 就地给遗留记录补上 ignorable 标记(不能直接删除:日志要求 seq 稠密):

node scripts/repair-ask-mode-logs.mjs --sessions /sessions                # 先干跑
node scripts/repair-ask-mode-logs.mjs --sessions /sessions --apply --backup

投影的 stateVersion 升到 2,0.1.x 写下的缓存行会被丢弃并从命令记录重新折叠——不需要额外的迁移。

安装

两种安装方式都支持。插件是纯 ESM(无需构建、零运行时依赖),所以安装时既不需要编译,也不会被 pnpm 拦下来要求 allowlist 构建脚本。

前置条件:dsh plugin 会把参数转发给 pnpm,所以 pnpm 必须在 PATH 上(corepack enable pnpm 即可提供)。缺了它会直接报 pnpm not found on PATH 并以 127 退出。

方式一:本地目录(link:)

dsh plugin --profile web add link:/absolute/path/to/dsh-helper-plugin-command-ask

- 路径请用绝对路径,或相对于你执行命令时所在的目录(CLI 会把相对的 link:/file: 规格锚定到调用目录,而不是 profile 目录)。
- link: 是符号链接,所以改 index.js/lib/.js 后重启 dsh web 即生效,不用重装。

方式二:Git 仓库(github:)

dsh plugin --profile web add github:/

- 仓库根目录就应该是这个包(即放 package.json 和 cordis.patch.yml 的那一层)。
- 需要可复现时钉住版本:github:/#。
- 因为没有 prepare/postinstall 脚本,pnpm 永远不会要求你 allowlist 构建。

背后发生了什么

dsh plugin ... add 会在 $DSH_HOME/profiles/web 里调用 pnpm,然后按已安装状态对齐 profile 清单(package.json):本包声明了 dsh.bundle.patch,于是它的包名会被自动追加进 dsh.profile.bundles。下次启动时,该 bundle 的补丁层插入一行 host 行:

- insert:
- id: command-ask
name: ./index.js      # 相对本补丁文件定位,因此任何安装布局都成立

重启 profile 即挂载:

dsh web            # 等价于:dsh --profile web

不安装也能直接试

examples/standalone.patch.yml 里的 ../index.js 是相对补丁文件定位的,所以一个裸 checkout 可以直接跑:

dsh --profile web --patch /examples/standalone.patch.yml

改 index.js/lib/.js 时这是最快的循环:不用安装,也不用改 profile。

验证安装

组合后的配置树里应该能看到 command-ask 行:
dsh --profile web --dump-config | grep -A2 command-ask

然后在 Web 界面输入框里输入 /ask:斜杠菜单会列出 /ask Enter or leave ask mode (read-only Q&A),命令结果提示 Ask mode on (read-only). Use /ask off to leave.。随便问一个问题,再试着让它改代码:它应该只描述该怎么改;被守卫拦下的工具调用会返回 ask mode is read-only。

不想开浏览器时,可以拿 dsh web 打印出来的 URL 直接跑实时验证脚本:

node scripts/verify-live.mjs --url "http://127.0.0.1:PORT/?token=TOKEN" --workspace
node scripts/verify-live.mjs --url "..." --workspace  --model-turns

它走的是和浏览器同一套 HTTP RPC(先建一个真实会话,再对它下命令),断言 /ask 的注册信息、命令结果、实时 ask 投影值、以及落盘的 ask/mode 事件;加 --model-turns 会真的跑两轮模型回合——ask 模式下要求创建文件、/ask off 之后再要求一次——并断言文件只在第二轮出现。

卸载

dsh plugin --profile web remove dsh-helper-plugin-command-ask

依赖被移除后,对齐逻辑会把它从 dsh.profile.bundles 里摘掉。已经写进会话日志的 ask/mode 事件会保留,只是此后无人读取。

配置

所有键都可选,什么都不写就用默认值。配置在加载期校验:未知键、类型错误、section 为空都会让启动直接失败,而不是默默忽略。

- id: command-ask
config:
scope: turn          # 每次 /ask 只覆盖一轮(默认)……
enforce: false
blockedTools: [write, edit, pwsh]
…… 或 scope: session 回到 /plan 式常驻模式

| 键 | 类型 | 默认值 | 含义 |
|---|---|---|---|
| scope | turn \| session | turn | turn:ask 模式只覆盖它进入的那一轮,并在该轮边界写回关闭。session:常驻到 /ask off,与 /plan 同构。 |
| section | string | 按 scope 选择的内置引导文本(见 lib/config.js) | 模式生效时渲染进 ask:policy 提示词分段的文本。 |
| enforce | boolean | true | 是否注册只读工具守卫。false 表示模式只作建议:仅靠引导文本。 |
| blockedTools | string[] | 下面列出的 22 个改动类工具 | ask 模式生效时被拒绝的工具名。整体替换默认列表。 |
| allowedTools | string[] | [] | 永远放行的名字,优先于 blockedTools 判断。 |
| supersedePlanMode | boolean | turn 下为 false,session 下为 true | 进入 ask 模式时把 plan 模式置为关闭。逐轮模式不动周围的模式。 |
| narrate | boolean | turn 下为 false,session 下为 true | 跨轮次切换模式时注入一行「用户把本会话切到了 ask 模式」的提示。逐轮模式无需提示:引导文本只出现在它管辖的那一轮,之后自然消失。 |

显式配置永远优先:scope: turn 配 narrate: true 是合法(只是略啰嗦)的组合。

覆盖配置写在哪里:profile 自己的 cordis.patch.yml($DSH_HOME/profiles/web/cordis.patch.yml)、在 bundle 之后应用的 --patch 覆盖层,或直接参考 examples/profile-patch.yml。补丁会整体替换目标行的 config,而省略的键都会回落到插件默认值,所以只写你要改的部分即可。

默认拒绝列表(按意图分组):

- 文件改动 — write、edit、str_replace_editor、apply_patch、multi_edit、notebook_edit
- Shell(双用途,但任何东西都能经由它写出去)— pwsh、bash、terminal、shell
- 任务跟踪与持久目标 — todo_write、create_goal、update_goal
- 委派与编排(子代理不会继承本模式的承诺)— subagent、subagent_fork、subagent_codex、subagent_claude_code、workflow、ralph、send_message、interrupt_agent
- 后台任务控制 — job_kill

这里刻意用黑名单:本插件不可能穷举部署方的工具名,所以未知工具(某个 MCP 工具、别的插件注册的工具)默认仍然可调用,而不是被白名单误伤;需要拦就加进 blockedTools。只读类工具(read、glob、grep、job_list、job_output、web_search、web_fetch、skill、ask_user_question、present 等)不受影响。

工作原理

/ask ──► ctx.commands.register('ask')  ──► session.append('command/run' | 'command/done')
│
▼
ctx.sessionProjections 单元 'ask'
折叠 /ask 记录 + turn/end  ──►  view { active, pending }
│
┌─────────────────────────────┴──────────────────────────┐
▼                                                        ▼
ctx.systemPrompt.section('ask:policy')                  ctx.tools.guard(read-only)
(生效时注入到每次请求)                                  (生效时拒绝改动类工具)

- 持久状态就是命令记录本身。 /ask 是一条命令,命令注册表本来就会为它写 command/run + command/done;模式只是把这些记录加上 harness 自己的 turn/end、request/header 折叠出来的结果。resume / fork / compaction 通过重放日志恢复,没有需要同步的活动镜像。
- 不写自有词汇表。 仓库外的插件无法新增会话事件类型:Session.append() 设置不了信封上的 ignorable 标记,而持久化读取路径会拒绝缺少该标记的未知类型。这里的一切都用 harness 已知的事件表达,因此会话日志对任何 harness 都可读——装不装本插件都一样。test/plugin.test.mjs 会断言日志里没有别的东西。
- 立刻落盘。 投影的变更回调会调用 ctx.sessions.flush(session)(harness 自己的检查点入口),所以一次开关远不到一秒就写到磁盘,而不必等下一次模型请求。
- 逐轮释放。 默认 scope: turn 下,模式由 harness 自己的 turn/end 记录结束;下一次请求组装时已经没有 ask:policy、也没有守卫。这正是「先问一句、再说'执行'」不需要 /ask off 的原因。
- 提示词稳定。 分段只注册一次,模式关闭时返回 '',因此进出模式都不会改变请求的工具目录。这也是为什么可以用「守卫」而不是「藏工具」来实现强制只读。
- 切换提示(narration,仅 scope: session)。 当上一次 request/header 描述的模式与当前生效的不一致时,一条 notice 会搭上下一个被接受步骤的消息,避免模型继续按旧姿态推理。逐轮模式不需要它:引导文本只出现在它管辖的那一轮。
- 强制点。 ctx.tools.guard() 是单调的,且在 tools/pre-execute 瀑布之后运行:任何监听器都无法翻案,而且对 run_code 的嵌套子调用同样生效(工具注册表会把调用方 Agent 传给子调用)。
- 与 plan 模式接力(仅 scope: session)。 常驻 ask 模式严格弱于 plan 模式,因此二者互斥。插件直接写 plan 模式自己的已知事件 plan/mode,而不是调用它的服务:不跨隔离域,日志折叠能像其它模式切换一样恢复结果;若该 profile 没挂 plan 模式,读到的是「无此投影」,什么都不做。

与 /plan 的差异

| | /plan | /ask(默认) | /ask(scope: session) |
|---|---|---|---|
| 目的 | 先设计,批准后再执行 | 只回答这一个问题,什么都不改 | 持续只回答,什么都不改 |
| 生命周期 | 直到 exit_plan_mode//plan off | 一轮 | 直到 /ask off |
| 退出方式 | exit_plan_mode + 用户审阅,或 /plan off | 轮次边界自动退出 | /ask off |
| 强制力 | 仅引导文本(沙箱/审批由部署方决定) | 引导文本 加上 黑名单工具守卫(enforce) | 同上 |
| 对其他模式 | 占用会话姿态 | 不动 plan 模式 | 会把 plan 模式置为关闭 |
| 浏览器 UI | 输入框的 “Plan” 徽标,读 plan 投影 | 无,靠命令结果文本 | 无,另有切换提示 |
| 挂载平面 | 每个 Agent preset、entry-local 隔离域 | 一行 host 行,对所有 Agent 全局生效 | 同上 |

ask 模式不是的边界

- 守卫是黑名单:名字不在列表里的改动类工具(例如部署方自己的工具)仍然可调用。需要拦就加进 blockedTools。
- 真正的硬边界仍在原处:dsh 的 sandbox 模式与审批策略。ask 模式只是按工具名收窄「可以做什么」,它不改变文件系统或进程权限;要真正只读,用 sandbox: read-only,与本插件相互独立。
- 模型仍然可能答错。引导文本要求它给出出处、明说「未能确认」的部分——仅此而已。
- scope: turn 下,那一轮进行中你发的所有内容都还在这一轮里,因此仍是只读;模式是按轮释放,不是按条消息释放。想恢复普通干活,下一条排队即可。
- 一次开关是异步落盘的:ctx.sessions.flush() 会让它远不到一秒内写到磁盘,但如果在输入 /ask 之后立刻硬杀进程(不给任何 I/O 时间),这条记录可能还没落盘;普通重启(工作台的停止按钮)会走优雅退出,不做特殊处理也不会丢。真丢了也只是模式回到关闭,重新发一次 /ask 即可。

兼容性

按 dsh 0.1.5-rc.2 编写。用到的服务与接缝(全部位于 host 平面):

| 接缝 | 用途 |
|---|---|
| ctx.commands.register()(可选注入——没有命令面板的 profile 也能用模式本身) | /ask 命令;它的记录就是持久状态 |
| ctx.systemPrompt.section() + getSectionOrder('PLAN_POLICY') | ask:policy 分段 |
| ctx.sessionProjections.register() / stateOf() / onChanged() | ask 单元,读取 plan/turnBoundary,以及触发落盘 |
| ctx.sessions.flush() | 让一次开关立刻持久化 |
| ctx.tools.guard() | 只读拒绝 |
| ctx.on('agent/pre-step')、agent.steer() | scope: session 的切换提示,以及把后缀问题 steer 出去 |
| session.append()(只写 plan/mode)、ctx.provide('askMode') | plan 接力与编程接口 |
| session.append()、ctx.provide('askMode') | 持久状态与编程接口 |
| 投影的 stateSchema/viewSchema | 自带的极简 parse 兼容校验器,不依赖 zod |

两处刻意的「软着陆」,避免缺少某个前置时拖垮启动:ask/plan 投影缺失时按「关闭」处理;turnBoundary 投影缺失时按「没有打开的轮次」处理(并告警一次)。插件也完全不 import 任何裸模块名——这正是 link: 与 github: 两种安装行为一致的原因(Node 会按真实路径解析被链接包的 import,落在 profile 的 node_modules 之外)。test/package.test.mjs 会强制守住这条性质。

也可以把插件挂进 Agent preset 而不是 host 平面,见 examples/agent-preset-mount.yml。

测试

npm test              # node --test
npm run test:direct   # 单进程运行(适配会拦子进程的沙箱环境)

82 个测试覆盖:配置校验(含 scope 的默认值耦合)、投影折叠与 schema、只读侧的模式读取与 plan 接力、守卫、包的可安装性性质,以及在伪 Cordis 树上的完整接线——包括「多个 ask 轮各自在自己的轮次结束」、开关立即落盘、ctx.askMode.set 走真实命令,以及 resume 后的模式重放。

验证状态

下面每一层都实跑过;带「实时」字样的几层使用一次性 $DSH_HOME,并在独立的 dsh 环境(env_001ca237)中进行,没有碰过承载本次对话的那个 profile。完整的命令与原始输出见 VERIFICATION.zh.md。

1. 行为 —— 82 个单元/集成测试,跑真实的 index.js/lib/.js,对接忠实的 Cordis 接缝替身(test-support/harness.mjs)。
2. 包形态 —— 静态测试守住两种安装方式都依赖的性质:运行时代码不 import 任何裸模块名(link: 安装无法解析裸名,Node 按真实路径解析被链接包的 import),且不携带任何需要 pnpm allowlist 的安装期脚本。
3. 两种安装命令 —— 在一次性 profile 上、dsh 0.1.5-rc.2 + pnpm 12.5.1:
- dsh plugin --profile web add link: → 初始化 profile、建立链接,对齐逻辑自己把 dsh-helper-plugin-command-ask 追加进 dsh.profile.bundles。
- pnpm pack → 24 个文件,再 dsh plugin --profile web add  → 同样的对齐、同样的行。
- 对本仓库 git clone --bare,再 dsh plugin --profile web add git+file:// → 同样的对齐、同样的行。这条走的就是 pnpm 的 git fetcher,也就是 github: 的代码路径,只是换了本地传输。
三种情况下 --dump-config 都组合出 id: command-ask(名字锚定在已安装副本内部),--port 0 --no-open 都能激活并对外服务。
4. 真实树里的激活 —— scripts/verify-profile.ps1 -Probe 会从 apply() 内部打印标记:行确实达到 active 状态(dsh 对任何未激活条目都会响亮失败),apply() 执行时 commands/tools/systemPrompt/sessionProjections/sessions 全部解析成功,因此注册 /ask 的 ctx.inject(['commands'], …) 回调确实跑了。
5. 实时行为(含真实模型回合,逐轮模式) —— 对运行中的 web 实例跑 scripts/verify-live.mjs --model-turns:22/22 全部通过,其中包括 "every event in the log belongs to the harness vocabulary (no plugin-defined types)"、"ask mode ended with its turn, with no /ask off"、"the next message without /ask created the file"*。

另外单独做了一次实时探针:ask 轮里让它执行 git status,模型连续三次调用 pwsh,每次都被拒绝,随后改用 glob/read 完成回答:

Error: dsh-helper-plugin-command-ask: ask mode is read-only, so the "pwsh" tool is
blocked for this turn. Answer from what you can inspect instead, and tell the user to
send the change as a normal message (without /ask), or to run /ask off to leave ask
mode early.

也就是说:真正改变结果的是模式(而不是沙箱),并且模式在轮次边界自行释放。
6. 重启与恢复 —— 同一个环境在跑过 /ask 的会话之后被重启(含硬杀):这些会话都能重新加载(session/page 返回其记录),模式从日志恢复;一个「已预置但尚未使用」的 /ask 也能挺过硬重启,因为开关会当场落盘:

session-8d4ba696 … : 重启后 6 条记录
seq 3 command/run name=ask args=""
seq 4 command/done kind=success
ask before paging : {"active":true,"pending":false}

未覆盖:浏览器里 Web 输入框的往返(插件没有客户端半边,反馈靠命令结果文本,scope: session 下另有切换 notice)。命令面能触达的部分,上面都已覆盖。

目录结构

index.js                     Cordis 插件:接线 + /ask 命令处理器
cordis.patch.yml             bundle 补丁(dsh.bundle.patch):插入一行 host 行
lib/config.js                配置 schema、默认值、内置引导文本
lib/controller.js            只读侧模式读取、plan 接力、切换提示
lib/projection.js            ask 会话投影单元(折叠 /ask 记录与 turn/end)
lib/guard.js                 只读工具守卫
lib/message.js               零依赖的 createUserMessage / notice
lib/schema.js                极简 parse 兼容 schema(不用 zod)
examples/                    profile 补丁、可携带 --patch 覆盖层、preset 挂载示例
scripts/run-tests.mjs        单进程测试运行器
scripts/verify-profile.ps1   针对真实 dsh 的一次性 profile 验证(--dump-config + 启动 + -Probe)
scripts/verify-live.mjs      针对运行中实例的实时验证(HTTP RPC;--model-turns)
scripts/repair-ask-mode-logs.mjs    修复 0.1.x 写坏的日志(给遗留记录补 ignorable)
test/                        测试套件(配置、投影、只读读取、守卫、接线、包形态)
test-support/harness.mjs     驱动接线测试的伪 Cordis 树
README.md / README.zh.md     中英双语的完整说明
VERIFICATION.md / .zh.md     实际跑过的验证与原始输出

为 dsh-helper 工作台而做

本插件是 dsh-helper 工作台生态的一部分——那个把多个 DeepSeek Harness 实例并排放在桌面上的应用,每个实例有独立的 profile、插件与会话。上面的演示就是它的真实录屏。

- 主页 / 下载:https://102201.com/products/dsh-helper/zh/
- 工作台跑的是原版 dsh;像本插件这样的扩展按 profile 安装,就是前面 安装 里那两条命令——不需要 fork,也不需要改 dsh。

许可证

MIT。

上游仓库有新提交时邮件通知你(每天最多一封,无更新不打扰),随时一键退订。

同作者(x102201)的其他插件

💬 加入社群

插件用法、部署报错、新插件第一时间同步——群里问,比一个人翻文档快。

DPharness QQ 群二维码,QQ 扫码进群
QQ 扫码进群
DPharness 飞书群二维码,飞书扫码进群
飞书扫码进群