记下想法待办,等 API 平价时段自动开会话执行
29.5/100
综合分
0
GitHub 星标
—
npm 周下载
—/5
用户评分
数据截至 2026/9/27 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。
相关生态插件(非 dsh 原生,按其对应运行时安装)
git clone https://github.com/Tungpeng/dsh-offpeak-inbox.git状态速览
判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态信任档位:仅索引
是什么
生态应用
桌面端 / Web 外壳,不以 dsh plugin add 安装
装得上吗
本站尚未做安装检查
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
更新放缓:最近一次提交在 42 天前
档位由哪些信号合成
本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。
社区实装还没有人打卡 · 装过的第一个就是你
安全扫描自动 · 静态分析源码v2.7.0🔵 扫描:含敏感能力尚无人工评估展开查看扫描说明与证据 ↓
安全扫描自动 · 静态分析源码
v2.7.0静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。
读写/删除本地文件发起外部网络请求
查看扫描证据(共 11 处,展示前 11 条)
- 发起网络请求src/client.ts:311
const response = await fetch(`${API}/state`, { cache: 'no-store' }); - 发起网络请求src/client.ts:318
const response = await fetch(`${API}/action`, { - 发起网络请求src/client.ts:330
const response = await fetch(`${API}/sessions`, { cache: 'no-store' }); - 发起网络请求src/client.ts:946
void fetch(`${API}/action`, { - 发起网络请求src/client.ts:963
void fetch(`${API}/action`, { - 发起网络请求src/client.ts:1103
const response = await fetch(`${API}/action`, { - 读取本地文件src/ledger.ts:159
raw = readFileSync(this.path, 'utf8') - 写入本地文件src/ledger.ts:185
writeFileSync(target, raw, 'utf8') - 写入本地文件src/ledger.ts:195
mkdirSync(dirname(this.path), { recursive: true }) - 写入本地文件src/ledger.ts:197
writeFileSync(temporary, `${JSON.stringify(this.document, null, 2)}\n`, 'utf8') - 写入本地文件src/ledger.ts:198
renameSync(temporary, this.path)
扫描于 2026/11/2(1 天前) · 范围 入口闭包 + 发布文件清单 · 来源 GitHub 仓库
静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。
依赖的 DSH / Cordis 模块
@deepseek-ai/cordis给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个
功能亮点
- 记录想法与待办
- 错峰时段自动开会话
- 按错峰价计费执行
DeepSeek Harness 的错峰收件箱:随时记下想法和待办,主机只在 DeepSeek API 按错峰价计费时,才把每一条启动成真正的会话。
README
由 DeepSeek 最新模型翻译生成dsh-offpeak-inbox — DSH 错峰收件箱
平时把想法、待办或"待会儿要聊的事"记进收件箱;只在 DeepSeek API 平价(错峰)时段自动把它们推送给 DSH,各开一个新会话执行。
目的很直接:贵的时候不烧钱,便宜的时候再干活。
它做什么
- 侧边栏多一个「错峰收件箱」入口,点开就能记一条(标题可选 + 正文)。
- 每条记录都会算好"最早可执行时刻":
- 在平价窗口内记下的 → 立刻进入当前窗口,很快执行;
- 在高峰时段或两段高峰之间记下的 → 等下一个平价窗口开始。
- 到点后 Host 自动新建一个 DSH 会话,把条目原文下发执行;结果留在那个会话里,随时点开看。
- 状态一眼可见:等待错峰 / 执行中 / 已完成 / 失败,并支持立即执行、删除、失败后重试。
攒多了怎么翻:折叠的历史 + 搜索
收件箱用久了,面板里的旧条目会越堆越长。列表因此分成两段:
- 还在动的(等待错峰 / 执行中 / 失败)一直留在列表里。失败的那条尤其不能藏——它还在等你重试或者删掉。
- 已经落地的(已完成 / 已取消)收进一条「历史记录(N 条)」横条,默认折起来;点一下展开,一次画最近 20 条,再往下按「再看更早的 N 条」。折叠状态记在浏览器里(localStorage 的 dsh.offpeak.historyOpen),下次打开还是上次那样。
展开完整文档(README 剩余 1 节)
dsh-offpeak-inbox — DSH 错峰收件箱 平时把想法、待办或"待会儿要聊的事"记进收件箱;只在 DeepSeek API 平价(错峰)时段自动把它们推送给 DSH,各开一个新会话执行。 目的很直接:贵的时候不烧钱,便宜的时候再干活。 它做什么 - 侧边栏多一个「错峰收件箱」入口,点开就能记一条(标题可选 + 正文)。 - 每条记录都会算好"最早可执行时刻": - 在平价窗口内记下的 → 立刻进入当前窗口,很快执行; - 在高峰时段或两段高峰之间记下的 → 等下一个平价窗口开始。 - 到点后 Host 自动新建一个 DSH 会话,把条目原文下发执行;结果留在那个会话里,随时点开看。 - 状态一眼可见:等待错峰 / 执行中 / 已完成 / 失败,并支持立即执行、删除、失败后重试。 攒多了怎么翻:折叠的历史 + 搜索 收件箱用久了,面板里的旧条目会越堆越长。列表因此分成两段: - 还在动的(等待错峰 / 执行中 / 失败)一直留在列表里。失败的那条尤其不能藏——它还在等你重试或者删掉。 - 已经落地的(已完成 / 已取消)收进一条「历史记录(N 条)」横条,默认折起来;点一下展开,一次画最近 20 条,再往下按「再看更早的 N 条」。折叠状态记在浏览器里(localStorage 的 dsh.offpeak.historyOpen),下次打开还是上次那样。 折叠只是显示上的收起来,一条都没删:数据仍旧完整躺在 $DSH_HOME/offpeak-inbox/inbox.json 里。要翻旧账就用历史横条上面的搜索框: - 搜索范围是整条记录,不只是屏幕上那几行:标题、正文、报错文本、会话 id、状态、捕获日期、以及等待中的条目才会印出来的「计划 … 起可执行」那个时间点都能命中; - 被折叠起来的历史一样搜得到——搜到就列出来,不受折叠状态影响;命中很多时同样一页 20 条,按「再看更多匹配」往下翻; - 搜索框清空即回到「常驻条目 + 折叠历史」的视图。 已有会话也能错峰 不想另开新会话,而是"这句话我现在写好,等便宜了再发给我正在聊的这个会话",用输入框旁边的「错峰」按钮: - 在高峰时段点它 → 内容攒起来,等下一个平价窗口开始后自动发进当前这个会话;高峰时段不会提前发。 - 在平价窗口内点它 → 钱已经便宜了,直接发(面板/提示会说明这一点)。 - 内容取自输入框里已经写好的字;点了才会攒,不会自动拦截你正常发送的消息。 - 发出去之后,条目在收件箱里显示「已发到已有会话 」并结算为已完成——投递的凭据是宿主的接受回执,不是"那个会话还在不在跑"(它之后还会跑你自己的轮次)。 - 条目上的「立即执行」对定向条目同样有效:它会立刻投递到你指定的那个会话,不会新建会话(不然就与这一行写的目的地自相矛盾了)。 - 面板的记录区还能用「发到」下拉直接选任意已有会话(子代理会话不在列表里),适合给别的会话攒一条。存进面板的定向条目,在收件箱里点「立即执行」也是走同一个目的会话。 按钮只认得浏览器自己记住的当前会话(localStorage 里的 dsh.sessions.current)。要是刚打开页面还没有会话,或那个值读不到,它会明确说"没认出当前会话",而不是猜一个错的发出去。 平价时段怎么算 按 DeepSeek 官方定价页的口径(高峰 = 平价价的 2 倍): | | 时段(UTC) | | 高峰(贵) | 周一至周五 01:00–04:00、06:00–10:00 | | 平价(半价) | 其余全部时间,周末全天 | 面板顶部会直接显示"现在是高峰还是平价"、当前窗口的起止,以及下一个平价窗口何时开始,不用自己换算时区。 重要边界 - Host 必须在运行。 插件活在 dsh web 进程里,进程停了就不跑了。 - 错过的窗口不补跑。 但每条记录的"最早可执行时刻"在记录当下就已经算好,所以你半夜记的东西不会因为当时没开窗口就丢失——等下一个窗口就是了。 - 不唤醒睡眠的机器。 电脑睡着了,到点也不会自己醒过来干活。 - 执行要花 API 额度,跟普通会话一样。省的是差价(平价约为高峰的五折),不是免费。 安装 下面几条都会往 profile 里写一行,而 profile 只在启动时读取一次——装完请重启 dsh web。 装预构建的 tarball。 安装期不执行本包的任何代码,所以不需要构建、也不需要授权构建脚本: dsh plugin --profile web add https://github.com/Tungpeng/dsh-offpeak-inbox/releases/latest/download/dsh-offpeak-inbox.tgz 直接从本仓库装。 这条路拉的是源码,pnpm 会执行本包的 prepare 构建;而 pnpm 10 在得到显式允许前拒绝运行 git 依赖的构建脚本。第一次 dsh plugin add 会失败,并打印要填进该 profile pnpm-workspace.yaml 的确切键名——填在 allowBuilds 下面,键是包名、值是 true。补上后重跑一次即可。请把这项授权理解为「允许本包的代码在安装时于你的机器上执行」;想锁住实际运行的内容,就钉住 commit(github:Tungpeng/dsh-offpeak-inbox#)。 dsh plugin --profile web add github:Tungpeng/dsh-offpeak-inbox 从 npm 装(包尚未发布,现在请先用上面两条): dsh plugin --profile web add dsh-offpeak-inbox 开发时也可以用本地目录直接挂载,改完重建即生效: dsh plugin --profile web add link: 挂载之前先构建。 link: 直接指向源码目录,而 lib/ 是构建产物、故意不入库。如果宿主启动时 lib/client.js 不存在,dsh web 会在加载插件阶段直接退出;守护脚本随后按退避反复重启,所以外面看起来像"卡死"而不是一条明确的报错。挂载前先跑一次 npm install(会经 prepare 自动构建)或 npm run build 即可避免。 配置 cordis.patch.yml 里的配置项: | 键 | 默认 | 说明 | | enabled | true | 总开关。关掉后只收不跑。 | | timeZone | UTC | 高峰时段按哪个时区解释;默认 UTC 即官方口径。 | | ranges | 01:00–04:00、06:00–10:00 | 工作日高峰区间,可改成自己的口径。 | | announceToAgent | true | 是否向 agent 声明本插件的存在与用法。 | | launchIntervalSeconds | 10 | 两次启动尝试之间的间隔,下限 2 秒。每轮最多启动一条会话,所以这个值决定的是积压排空的速度(越小 = 同时在跑的越多),而不是每轮跑几条。旧名 tickSeconds 仍被接受。 | | executionTimeoutSeconds | 14400 | 单次执行超时上限,超过则标记失败并提示查看会话。 | 数据位置 $DSH_HOME/offpeak-inbox/inbox.json($DSH_HOME 未设置时取 ~/.dsh)。 条目字段:title / prompt / createdAt / runAfter / status。另有三种互斥的归属信息:targetSessionId(用户指定的已有会话,投递被接受后写入 deliveredAt)、sessionId + startedAt(插件新建的会话,正在执行)、以及 settledAt / error(终态与原因)。 写入是原子的(临时文件 + rename)。文件若无法解析,会被改名到 inbox.json.corrupt- 保留现场,调度器以空账本启动并在控制台报错——绝不静默丢数据。 开发者速览 src/calendar.ts 错峰日历:isPeak / currentWindow / nextWindowStartMs(纯函数,含测试) src/ledger.ts 持久化与条目状态机 src/runner.ts 启动真实 DSH 会话(gateway create/rename/prompt)+ 投递到已有会话 src/service.ts 调度循环、启动决策、执行结果回收 src/routes.ts 同源 HTTP 接口(state / sessions / action / events) src/index.ts Cordis 插件入口(装配 + 设置 + 系统提示声明) src/client.ts 浏览器半区源码(vanilla TS,Shadow DOM 面板 + 输入框旁的「错峰」按钮,零依赖) lib/index.mjs 构建产物:Host 半区 lib/client.js 构建产物:浏览器半区,必须是 __ModuleLoader__.load 包装体 设计上的几个要点: - Host 半区运行时依赖为零。 所有 harness 服务都通过 Cordis 注入,会话 RPC 走注入的 gateway;配置校验直接用 Standard Schema 手写实现,设置页要读的序列化 schema 同样手写,因此不需要 schemastery 之类的 schema 库。 - 投递统一走 session/prompt,不直接往运行中的 agent 里塞消息。 harness 收件箱里的一条消息是完整的 UserMessage(身份、角色、content、source);自行拼装而缺 source 会让下一轮直接以 Cannot read properties of undefined (reading 'kind') 失败。交给 gateway 组装可让插件不碰内部消息字段,运行中的 agent 句柄只用于读取执行状态。发往已有会话的条目走的是同一个方法,只是目的会话在捕获时就写在 targetSessionId 上。 - 定向条目不占用 sessionId 字段。 sessionId 的语义是"插件建出来的那个会话,用来盯它跑完没有";用户指定的目的会话写在 targetSessionId 上,投递被接受即结算,避免把用户之后的轮次误当成这次执行。 - 当前会话来自浏览器自己的持久化值。 按钮读 localStorage 的 dsh.sessions.current(宿主 sessions 服务把选中项持久化在这),不解析 URL、不猜标题;读不到就明确报错。 - 宿主上报的执行错误会把条目标成失败。 回收逻辑只能看到会话是否还在运行,因此中途失败的轮次会被误判为已完成;api-session/error 提供失败原因。 - 可选服务一律走 ctx.get。 Cordis 的属性代理对未在 inject 里声明的服务名是抛异常而不是返回 undefined(一个可选时钟服务曾因此让整个插件无法启动)。插件只硬声明必需的四个服务,其余通过 ctx.get 读取。 - 测试用的时钟注入: 若宿主提供了一个名为 now 的服务(返回毫秒时间戳的函数),调度器就用它取时;没有则用 Date.now。这是给测试做确定性时间用的,生产环境无需提供。 - 验收口径在 calendar.ts。 边界判定对"未对齐 15 分钟网格的时刻"做过修正(03:10 曾会算成 01:10),相关回归测试保留在 test/calendar.test.ts。 - test/runtime.test.ts 针对构建产物(lib/index.mjs)跑真实 Cordis 运行时;test/client.test.ts 把 lib/client.js 当作浏览器模块加载器会加载的那种经典脚本求值,再调用它导出的纯判定函数——所以「构建把 internals 丢了」「包装器不再导出」这类问题会先在测试里炸,而不是在浏览器里。npm test 前会自动先构建(pretest)。 npm install # 安装开发依赖 npm run build # 构建 Host 半区 + 产出 lib/client.js npm run typecheck # Host 与浏览器半区两套类型检查 npm test # 自动构建后跑:单元测试 + 针对构建产物的运行时测试 部署注意(踩过的坑) - 改完浏览器半区,怎么让它生效。 客户端模块注册表在启动时会把产物字节读进内存,所以「只刷新页面」本身换不掉旧代码。标准 web 组合里另有一行常驻的 @deepseek-ai/dsh-client-hmr(packages/bundle/web-app/cordis.patch.yml 注明 always mounted):它按 pollIntervalMs(默认 500ms)比对每个客户端产物,内容变了就重新组合该 row,并通过 /plugins/events 的 SSE 让浏览器重载对应插件。因此重建 lib/client.js 后一般不需要重启 Host;面板没变化时先刷新页面,仍然没变化再重启 dsh web。 - 重建后哪一半需要重启。 lib/client.js 由 dsh-client-hmr 行在数百毫秒内重新组合并推给浏览器(见上一条),所以只改浏览器半区不用重启 Host;但 lib/index.mjs(Host 半区:路由、调度、账本)是进程启动时装配进 Cordis 的,改完必须重启 dsh web 才生效,npm run build 只负责把新字节写到磁盘。 - 面板骨架带版本号,挂载带世代号——因为热重载会真的发生。 面板是「关闭即隐藏」而不是卸载,热重载后页面上会留着旧半区构建的那棵树:PANEL_VERSION 不匹配就把它整体丢弃重建,否则新代码会去读旧树里不存在的部件(搜索框、计数位)而抛错。侧边栏入口与「错峰」按钮同理,靠 window.__dshOffpeakEpoch 仲裁:旧半区的 MutationObserver 发现世代不是自己的就停手,不再把自己那套节点重新插回页面。改这两处时别把它们当装饰。 - lib/client.js 必须是 __ModuleLoader__.load 包裹的产物,不能是 src/client.js 的原样拷贝。 package.json 的 ./client 指向它,而 tsdown 只产出 Host 半区;scripts/publish-client.mjs 负责包装、并用 vm.Script 校验(解析不过或缺少守卫标记就直接报错)。客户端注册表把各插件的动态半区并进一个合并包、由 当经典脚本加载——里面只要有顶层 export,整包 SyntaxError,浏览器报的是 Failed to load plugins … via __ModuleLoader__.load,看上去像"所有插件都坏了"。 - 构建脚本不要用管道捕获子进程输出。 受限沙箱会拒绝打开管道(EPERM),失败会伪装成"tsc 没有产出";改用继承的文件描述符(stdio: 'inherit')。 - tsdown 不传 --out-dir 会输出到 dist/,而包入口指向 lib/——构建脚本必须显式指定输出目录。 - 浏览器半区只能用真实 DOM 元素。 React 的内部结构(例如 props.children 里的组件函数)会混进 children 集合;不做 instanceof HTMLElement 断言,注入逻辑会抛 button.closest is not a function 并让入口消失。 - 面板刷新必须是增量更新,不能重建子树。 早期实现每次轮询清空影子树重建,输入框会被换成新节点,正在输入的文字和光标一起丢;现在骨架只建一次,刷新只更新可变部分,"关闭"只隐藏不销毁。执行级测试断言 textarea 跨刷新是同一个对象且文字不丢。 - 诊断开关: 打开面板前,客户端会 POST 一次 clientLoaded。state.view.clientLoads 为 0 就说明浏览器半区根本没执行——这是一眼区分"脚本没跑"和"插不进 DOM"的最快办法。 - 输入框旁的按钮要插进 trailing 组,不能挂在 composer 卡片上。 composer 卡片是 flex 纵向布局,直接挂上去会变成控件行下面另起一行;正确锚点是发送按钮本身(sendButtonOf),insertBefore(button, send)。另外判断"已经放好了"要让下一次 DOM 变更时的检查为假,否则每次变更都重插一次,自己触发自己的 MutationObserver。 - [class*="trailing"] 不止一个。 斜杠菜单的可下钻行也用这个类名,而且它在输入覆盖层里、比输入行更靠前,那一组里没有 ——按"第一个 trailing 组"取发送键会让按钮在菜单展开时被移除(收起后自愈)。sendButtonOf 因此改成"取第一个含 button 的 trailing 组"。 - 按钮是否落位要上报给宿主。 面板有没有按钮都能打开,所以宿主无法区分"浏览器半区没跑"和"跑了但没找到输入框"。client.ts 会把落位结果(placed / no-composer / no-send-control)POST 给 action: buttonState,state.view.buttonMounted / buttonReason 一眼可查。 - dsh.sessions.current 是同源唯一的键,多标签页会互相覆盖。 全 packages/client 里没有任何 storage 事件监听,所以另一个标签页切换会话后,这个标签页的按钮会读到别的会话 id。按钮因此做了两件事:发之前核对这个 id 是否在宿主返回的会话列表里(不在就不发,并说明这个会话不在可选列表里——重新点一次不会变好,因为列表里确实没有它),以及把目的会话标题写进提示文案,让人能一眼看出到底发去了哪。 - DOM 变更观察会自己触发自己。 该按钮的观察器与侧边栏入口共用 queueMicrotask 合并策略:一轮微任务里只尝试一次,且已经就位时不写 DOM。 - 注册给设置系统的 schema 必须能序列化,否则整个设置页都打不开。 宿主回答设置页时会对每一个已注册的命名空间调用 schema.toJSON()(SettingsProvider.describe()),中间没有按命名空间兜底,因此少一个方法就整条 RPC 抛错——挂掉的是所有插件的设置卡片,不只是出错的那个。0.1.0 注册的就是一个普通函数,结果正是如此;现在 test/runtime.test.ts 的假宿主也按同样方式读取 schema,这个故障不会再悄悄回来。 许可 MIT
预览分享卡片长什么样 ↓
分享 · DeepSeek Harness Hub
Tungpeng/dsh-offpeak-inbox
记下想法待办,等 API 平价时段自动开会话执行
相关插件 · 对话 / 记忆
上下文中枢oceanbase/powercontext
上下文跟着工作走 —— 跨会话、跨智能体、跨人。
★ 1,487已汉化DSH
73
智能体记忆库plastic-labs/honcho
Honcho 是记忆基础设施,用来构建有状态的智能体。这些智能体能理解不断变化的人、智能体、群组、项目和想法。
★ 7,894已汉化DSH
71.7
长程智能体控制面loopx-project/loopx
给 Agent 一个目标,让工作持续向前。
★ 6,358已汉化DSH
71.3
智能体上下文数据库volcengine/OpenViking
给 AI 智能体用的上下文数据库
★ 41,379已汉化DSH
71.3
长效机器人团队Fei2411/DS-Bot
DS Bot 是一个基于 DeepSeek Harness简称 dsh的 bot 插件,插件将 dsh 改造为 bot…
★ 5,084已汉化DSH
71.1
可携带记忆层EverMind-AI/EverOS
为什么选择 EverOS
★ 13,778已汉化DSH
71.1
这是你的仓库?认领条目