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

协会工作坊 Denghui1835/njau-ca-dsh

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

把社团事务拆成可装卸插件,换届也能接着用

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

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

安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add Denghui1835/njau-ca-dsh
该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:需留意
是什么[目录]—
dsh 原生插件 · other
暂无时间戳·判据 →
装得上吗[实装验证]!
实装验证未通过(unknown),装前请到仓库确认最近更新与 issue
L4 · 真实安装等级说明 →
数据截至 2026/10/21·判据 →
安全吗[自动扫描]—
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
数据截至 2026/11/04·判据 →
还在维护吗[仓库]✓
活跃:最近一次提交在 15 天前
暂无时间戳·判据 →
图例:✓ 通过! 需注意— 未判定 / 无数据· 「未判定」= 本站尚无数据,不代表插件有问题
档位由哪些信号合成

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

验证判据与等级说明 →

可信度证据

⚠︎ 实装验证未通过(unknown · 2026/10/21) ——可能是验证环境差异,装前建议到 GitHub 仓库确认最近更新与 issue。
安全扫描自动 · 静态分析源码
v2.7.0
🔵 扫描:含敏感能力尚无人工评估
展开查看扫描说明与证据 ↓

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

可执行外部命令读写/删除本地文件
查看扫描证据(共 128 处,展示前 73 条)
  • 读取本地文件
    packages/code/lib/env.js:20
    if (!existsSync(root)) mkdirSync(root, { recursive: true })
  • 写入本地文件
    packages/code/lib/env.js:20
    if (!existsSync(root)) mkdirSync(root, { recursive: true })
  • 读取本地文件
    packages/code/lib/env.js:24
    identity = JSON.parse(readFileSync(join(root, 'identity.json'), 'utf8'))
  • 写入本地文件
    packages/code/lib/service.js:57
    mkdirSync(dirname(path), { recursive: true })
  • 写入本地文件
    packages/code/lib/service.js:60
    writeFileSync(tmp, buffer)
  • 写入本地文件
    packages/code/lib/service.js:61
    renameSync(tmp, path)
  • 读取本地文件
    packages/code/lib/service.js:64
    if (existsSync(tmp)) unlinkSync(tmp)
  • 删除本地文件
    packages/code/lib/service.js:64
    if (existsSync(tmp)) unlinkSync(tmp)
  • 执行外部命令来自配置/变量
    packages/code/lib/service.js:88
    const child = spawn(process.env.COMSPEC ?? 'cmd.exe', ['/d', '/s', '/c', commandLine], {
  • 读取本地文件
    packages/code/lib/service.js:160
    if (!existsSync(abs) || !statSync(abs).isDirectory()) throw new Error(`项目不存在:${clean}`)
  • 读取本地文件
    packages/code/lib/service.js:160
    if (!existsSync(abs) || !statSync(abs).isDirectory()) throw new Error(`项目不存在:${clean}`)
  • 读取本地文件
    packages/code/lib/service.js:176
    if (!existsSync(path)) return null
  • 读取本地文件
    packages/code/lib/service.js:178
    return JSON.parse(readFileSync(path, 'utf8'))
  • 读取本地文件
    packages/code/lib/service.js:185
    if (existsSync(join(dir, 'pnpm-lock.yaml'))) return 'pnpm'
  • 读取本地文件
    packages/core/lib/skills.js:53
    if (!existsSync(dir)) return [];
  • 读取本地文件
    packages/core/lib/skills.js:55
    for (const entry of readdirSync(dir).sort()) {
  • 读取本地文件
    packages/core/lib/skills.js:57
    if (!existsSync(skillFile)) continue;
  • 读取本地文件
    packages/core/lib/skills.js:59
    if (!statSync(skillFile).isFile()) continue;
  • 读取本地文件
    packages/core/lib/skills.js:85
    raw = readFileSync(item.file, 'utf8');
  • 读取本地文件
    packages/core/lib/store.js:129
    if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
  • 写入本地文件
    packages/core/lib/store.js:129
    if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
  • 读取本地文件
    packages/core/lib/store.js:165
    return readFileSync(abs, 'utf8');
  • 写入本地文件
    packages/core/lib/store.js:173
    writeFileSync(tmp, text, 'utf8');
  • 写入本地文件
    packages/core/lib/store.js:174
    renameSync(tmp, abs);
  • 读取本地文件
    packages/core/lib/store.js:179
    if (!existsSync(abs)) return null;
  • 读取本地文件
    packages/core/lib/store.js:180
    const raw = readFileSync(abs, 'utf8');
  • 读取本地文件
    packages/core/lib/store.js:192
    if (!existsSync(base)) return [];
  • 读取本地文件
    packages/core/lib/store.js:195
    for (const name of readdirSync(dir).sort()) {
  • 读取本地文件
    packages/deck/lib/skills.js:41
    if (!existsSync(dir)) return [];
  • 读取本地文件
    packages/deck/lib/skills.js:43
    for (const entry of readdirSync(dir).sort()) {
  • 读取本地文件
    packages/deck/lib/skills.js:45
    if (!existsSync(skillFile)) continue;
  • 读取本地文件
    packages/deck/lib/skills.js:47
    if (!statSync(skillFile).isFile()) continue;
  • 读取本地文件
    packages/deck/lib/skills.js:68
    try { raw = readFileSync(item.file, 'utf8'); } catch { continue; }
  • 读取本地文件
    packages/manju/lib/env.js:21
    if (!existsSync(root)) mkdirSync(root, { recursive: true })
  • 写入本地文件
    packages/manju/lib/env.js:21
    if (!existsSync(root)) mkdirSync(root, { recursive: true })
  • 读取本地文件
    packages/manju/lib/env.js:25
    identity = JSON.parse(readFileSync(join(root, 'identity.json'), 'utf8'))
  • 写入本地文件
    packages/manju/lib/service.js:39
    mkdirSync(dirname(path), { recursive: true })
  • 写入本地文件
    packages/manju/lib/service.js:42
    writeFileSync(tmp, buffer)
  • 写入本地文件
    packages/manju/lib/service.js:43
    renameSync(tmp, path)
  • 读取本地文件
    packages/manju/lib/service.js:46
    if (existsSync(tmp)) unlinkSync(tmp)
  • 删除本地文件
    packages/manju/lib/service.js:46
    if (existsSync(tmp)) unlinkSync(tmp)
  • 读取本地文件
    packages/manju/lib/service.js:100
    if (!existsSync(path)) return ''
  • 读取本地文件
    packages/manju/lib/service.js:101
    return readFileSync(path, 'utf8')
  • 读取本地文件
    packages/manju/lib/service.js:106
    if (!existsSync(path)) return null
  • 读取本地文件
    packages/manju/lib/service.js:107
    const raw = readFileSync(path, 'utf8')
  • 读取本地文件
    packages/manju/lib/service.js:122
    entries = readdirSync(current, { withFileTypes: true })
  • 写入本地文件
    packages/manju/lib/service.js:190
    mkdirSync(join(dir, 'assets'), { recursive: true })
  • 写入本地文件
    packages/manju/lib/service.js:191
    writeFileSync(join(dir, '剧本.md'), SCRIPT_TEMPLATE(clean), 'utf8')
  • 读取本地文件
    packages/office/lib/env.js:23
    if (!existsSync(root)) mkdirSync(root, { recursive: true })
  • 写入本地文件
    packages/office/lib/env.js:23
    if (!existsSync(root)) mkdirSync(root, { recursive: true })
  • 读取本地文件
    packages/office/lib/env.js:27
    identity = JSON.parse(readFileSync(join(root, 'identity.json'), 'utf8'))
  • 写入本地文件
    packages/office/lib/service.js:44
    mkdirSync(dirname(path), { recursive: true })
  • 写入本地文件
    packages/office/lib/service.js:47
    writeFileSync(tmp, buffer)
  • 写入本地文件
    packages/office/lib/service.js:48
    renameSync(tmp, path)
  • 读取本地文件
    packages/office/lib/service.js:51
    if (existsSync(tmp)) unlinkSync(tmp)
  • 删除本地文件
    packages/office/lib/service.js:51
    if (existsSync(tmp)) unlinkSync(tmp)
  • 读取本地文件
    packages/office/lib/service.js:96
    if (!existsSync(abs)) return FAIL('file/missing', `文件不存在:${abs}`)
  • 读取本地文件
    packages/office/lib/service.js:97
    const st = statSync(abs)
  • 读取本地文件
    packages/office/lib/service.js:98
    const buffer = readFileSync(abs)
  • 读取本地文件
    packages/office/lib/service.js:105
    if (!existsSync(base)) return FAIL('dir/missing', `目录不存在:${base}`)
  • 读取本地文件
    packages/office/lib/service.js:107
    for (const entry of readdirSync(base, { withFileTypes: true })) {
  • 读取本地文件
    packages/workshop/lib/env.js:32
    if (!existsSync(root)) mkdirSync(root, { recursive: true })
  • 写入本地文件
    packages/workshop/lib/env.js:32
    if (!existsSync(root)) mkdirSync(root, { recursive: true })
  • 读取本地文件
    packages/workshop/lib/env.js:36
    identity = JSON.parse(readFileSync(join(root, 'identity.json'), 'utf8'))
  • 读取本地文件
    packages/workshop/lib/lines.js:46
    return statSync(path)
  • 读取本地文件
    packages/workshop/lib/lines.js:59
    entries = readdirSync(dir, { withFileTypes: true })
  • 读取本地文件
    packages/workshop/lib/lines.js:75
    if (existsSync(base)) walk(base, 0)
  • 读取本地文件
    packages/workshop/lib/lines.js:82
    if (!existsSync(base)) return { dir: base, projects: [] }
  • 读取本地文件
    packages/workshop/lib/lines.js:84
    for (const entry of readdirSync(base, { withFileTypes: true })) {
  • 读取本地文件
    packages/workshop/lib/lines.js:95
    const parsed = JSON.parse(readFileSync(board.path, 'utf8'))
  • 写入本地文件
    packages/workshop/lib/lines.js:276
    mkdirSync(join(dir, 'assets'), { recursive: true })
  • 写入本地文件
    packages/workshop/lib/lines.js:277
    writeFileSync(join(dir, '剧本.md'), SCRIPT_TEMPLATE(clean), 'utf8')
  • 写入本地文件
    packages/workshop/lib/lines.js:278
    writeFileSync(join(dir, 'storyboard.json'), STORYBOARD_TEMPLATE(clean), 'utf8')
扫描于 2026/11/4(0 天前) · 范围 全包扫描 · 来源 GitHub 仓库

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

社区实装还没有人打卡 · 装过的第一个就是你
给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个

南农计协 · DSH:把协会的事务做成一套能一代一代传下去的工具。办公 / 漫剧 / 开发三条产线的工作坊,全部插件化,零运行时依赖。

README

由 DeepSeek 最新模型翻译生成
南农计协 · DSH 南京农业大学计算机爱好者协会的协会操作系统。 不是官网,是一整套接手协会大小事务的工具,跑在 DeepSeek Harness 上。 这是什么 一句话:把协会的活儿,做成一套能一代一代传下去的工具。 DSH 的立场是「一切皆插件」。我们顺着这个立场,把协会的事务拆成一批插件:纳新、活动、经费、宣传、周报、竞赛、知识库、年审材料、共享资源库、PPT…… 每一块都是独立插件,装上去就能用,不想要就摘掉,互不牵连。 它取代官网的位置。 官网只能"看",这套东西能"干活"。 现在长成了一间「工作坊」 三条产线收在同一个界面里,共用协会身份与数据目录: | 产线 | 干什么 | 状态 | | 办公 | 表格、纪要、立项书、报销单、年审材料、宣讲 PPT —— 自带 OOXML 引擎,不装 WPS/Office 也能直接改 .docx / .xlsx / .pptx | ✅ 可用 | | 漫剧 | 剧本 → 分镜 → 出图 → 配音字幕 → 合成 | 前两步可用(剧本 + 分镜编辑),后三步待建 | | 开发 | 协会网站、工具、脚本 —— 文件树 + 自带轻量代码编辑器 + 白名单运行 | ✅ 读写与运行可用,脚手架/发布待建 | 别的社团能用吗 能。
展开完整文档(README 剩余 1 节)
南农计协 · DSH

南京农业大学计算机爱好者协会的协会操作系统。
不是官网,是一整套接手协会大小事务的工具,跑在 DeepSeek Harness 上。

这是什么

一句话:把协会的活儿,做成一套能一代一代传下去的工具。

DSH 的立场是「一切皆插件」。我们顺着这个立场,把协会的事务拆成一批插件:纳新、活动、经费、宣传、周报、竞赛、知识库、年审材料、共享资源库、PPT……
每一块都是独立插件,装上去就能用,不想要就摘掉,互不牵连。

它取代官网的位置。 官网只能"看",这套东西能"干活"。

现在长成了一间「工作坊」

三条产线收在同一个界面里,共用协会身份与数据目录:

| 产线 | 干什么 | 状态 |
| 办公 | 表格、纪要、立项书、报销单、年审材料、宣讲 PPT —— 自带 OOXML 引擎,不装 WPS/Office 也能直接改 .docx / .xlsx / .pptx | ✅ 可用 |
| 漫剧 | 剧本 → 分镜 → 出图 → 配音字幕 → 合成 | 前两步可用(剧本 + 分镜编辑),后三步待建 |
| 开发 | 协会网站、工具、脚本 —— 文件树 + 自带轻量代码编辑器 + 白名单运行 | ✅ 读写与运行可用,脚手架/发布待建 |

别的社团能用吗

能。这套东西里没有一个字节依赖南农计协:协会名、学年、业务域都从数据目录里的 identity.json 和 packages/workshop/lib/lines.js 的产线表读出来。

复刻一份自己的:

1. fork 本仓库;
2. 改 identity.json(协会名、简称、motto、学年)—— 这个文件在数据目录,不在仓库里;
3. 改 lib/lines.js 的 LINES(你们的产线与业务域目录);
4. 跑 scripts/install.ps1,装进你们自己的 profile。

三条架构铁律(插件互不调用 / 零运行时依赖 / 数据纯文本)是这套东西最值得抄的部分,见 docs/architecture.md 与 docs/adr/。

为什么不做网站

网站是死的:做完就定型,改一次求一次人,换届就烂尾,还容易被当成"门面工程"。

而协会真正的痛点是事务:纳新的表格、活动的立项书、年审的材料、报销的单据。
这些活儿每年重复、每年靠人肉、每年换届就断档。

所以我们不做网站,做一套能继承的工作台。

现在有什么

| 包 | 作用 | 状态 |
| packages/core | 协会底座:数据目录、6 个工具、技能发现、斜杠命令、人设段 | 已验证 |
| packages/brand | 品牌与人设:侧栏标识、标题、主题色、协会人设 | 已验证 |
| packages/workshop | 工作坊外壳:三条产线(办公 / 漫剧 / 开发)的统一入口与现状总览 | 外壳已通(三柱待填) |
| packages/office | 办公柱:自带 OOXML 引擎,直接打开、改、存 .docx / .xlsx / .pptx,不依赖 WPS/Office | 三类文件全通 |
| packages/manju | 漫剧柱:剧本与分镜的编辑器,一条漫剧的所有工序都挂在 storyboard.json 上 | 已通前两步(出图/配音/合成待建) |
| packages/code | 开发柱:项目发现 + 文件树 + 代码编辑器 + 白名单运行(npm scripts / 只读 git) | 读写与运行可用(脚手架/发布待建) |

三条产线现在都能干活:办公改 .docx、漫剧写剧本拆分镜、开发改代码跑构建。
尚未做的:漫剧的出图/配音/合成三步、办公的 xlsx/pptx、开发的脚手架与发布。
路线与边界见 docs/workshop.md。

快速开始

双击 scripts\install.cmd —— 装完再双击 scripts\doctor.cmd 确认没问题。

命令行等价写法:

powershell -ExecutionPolicy Bypass -File .\scripts\install.ps1
powershell -ExecutionPolicy Bypass -File .\scripts\doctor.ps1
dsh njau --port 0 --no-open

装对了的话,doctor 最后一行是 doctor: 28 ok, 0 warn, 0 fail。

直接跑 .ps1 可能被 Windows 执行策略拦住,这不是仓库的毛病。
三种解法见 docs/install.md 第 1 节。

详见 docs/install.md。

接班的人从这里开始

1. 读 HANDOVER.md —— 交接清单,照着打勾。
2. 读 docs/vision.md —— 为什么这么做、要往哪走。
3. 读 docs/architecture.md —— 三条架构铁律。
4. 每个包里的 OWNER.md —— 那个包谁负责、交接要交代什么。
5. 想动手改?先读 CONTRIBUTING.md。

三条铁律

这三条是这个仓库能活过换届的原因,改代码前先读 docs/architecture.md。

1. 插件之间不互相调用。 跨域协作由人(和 agent)编排多个插件的工具完成,而不是插件 A 依赖插件 B。所以任何一个插件都能被单独删掉。
2. 零运行时依赖。 只用 Node 内置模块,不 import 任何 @deepseek-ai/* 运行时包。
DSH 升级不会因为版本声明不匹配而把我们拒载。
3. 数据是纯文本。 Markdown / YAML / JSON,永不引入数据库。
这样能进 git、能 diff、能回滚、能被子孙读懂。

红线

学生社团不是公司。这个仓库里不允许出现:

- 商业合同、收款、开票、代理销售相关的内容;
- 冒充学校官方、或让外界误认为是学校官方的表述;
- 学校系统的自动登录、刷接口、模拟点击(绝不);
- 内部敏感材料(整改、关联方、举报、内部汇报)。

排版、宣传材料、对外文案一律遵守学校对社团的现行规定。
完整红线表见 GOVERNANCE.md 第五节。

目录

packages/ 各插件,一个域一个包 core/ 协会底座:数据目录、工具、技能、斜杠命令、人设段 brand/ 品牌:侧栏标识、窗口标题、主题色 deck/ PPT 大纲与模板 workshop/ ★ 工作坊外壳:三条产线的统一入口与现状总览 office/ ★ 办公柱:自带 OOXML 引擎,直接读写 .docx manju/ ★ 漫剧柱:剧本 ⇄ 分镜编辑(出图/配音/合成待建) code/ ★ 开发柱:文件树 + 代码编辑器 + 白名单运行 docs/ 愿景、架构、安装、工作坊、ADR、年度归档 workshop.md 工作坊的分层、边界与三柱路线 adr/ 架构决策记录(为什么是现在这样) archive/ 每学年一份只读快照 scripts/ 安装 / 卸载 / 体检 / 自检(.ps1 本体 + .cmd 双击包装) tests/ 冒烟测试,改完代码跑一遍

仓库只有代码和文档。协会的业务数据在 %USERPROFILE%\.dsh\njau-ca\,不进 git。

本地自检(不需要装 DSH)

node scripts/check.mjs # 包结构与语法
node tests/smoke-core.mjs # 底座:工具 / 命令 / 技能契约
node tests/smoke-deck.mjs # PPT:模板解析 / 大纲写入 / 路径穿越防护
node tests/smoke-workshop.mjs # 工作坊 + 办公柱:真 HTTP + 真 .docx 往返
node tests/smoke-manju.mjs # 漫剧柱:分镜增删改排序 / 脏数据修复 / 素材直出
node tests/smoke-code.mjs # 开发柱:文件树 / 读写与冲突 / 真跑一次 npm script / 白名单
node tests/smoke-sheet.mjs # 表格:新建 / 改格与公式 / 并发冲突 / 落盘往返
node tests/smoke-pptx.mjs # 幻灯片:新建 / 改标题段落 / 删段落 / 并发冲突

装进 DSH 之后,还可以对一个正在运行的实例做端到端体检(会自己建临时项目再删掉):

node scripts/verify-live.mjs http://127.0.0.1:<port>

上面这些测试不依赖 DSH、不依赖 pnpm、不联网:假 ctx 把插件真跑起来,再把注册到的 HTTP 路由挂到真 http 服务上,用 fetch 走一遍面板会走的请求。
文档引擎还会真的落一份 .docx 到临时目录、读回来逐字比对。

许可

MIT。见 LICENSE。

代码开放,数据不开放 —— 数据归协会所有,单独交接。
与学校的关系、数据归属、红线清单见 NOTICE.md。

欢迎 fork、抄架构、抄那三条铁律。如果这套东西对你们社团有用,开个 issue 说一声就行。
预览分享卡片长什么样 ↓Denghui1835/njau-ca-dsh
分享 · DeepSeek Harness Hub
Denghui1835/njau-ca-dsh

把社团事务拆成可装卸插件,换届也能接着用

这个插件是你维护的吗?
作者本人可认领并核对本条目;认领通过后,详情页会显示「作者已认领」标记。
认领条目 →
回到顶部