Bundle
@skillre/dsh-plugin-pomodoro
Pomodoro focus clock for the DSH Web UI: a persistent work/break timer with daily round counts and local preferences
- Source
- skillre
- License
- MIT
- Updated
- Updated 2 days ago
Readme
# @skillre/dsh-plugin-pomodoro
> 状态:experimental
在 DSH Web UI 里的番茄时钟:输入框下方常驻的专注计时器,带每日番茄数与本地偏好设置。
[English](README.en.md)
## 它做什么
- 在**输入框(composer)下方**显示一枚常驻胶囊:当前阶段、倒计时、本轮进度和三个按钮(开始/暂停、重来、跳到下一阶段)。
- 阶段按经典番茄工作法循环:专注 → 短休息 → … → 第 N 轮后进入长休息 → 回到专注。
- 记录**当天**完成的专注轮数与专注时长;跨过本地零点自动归零。
- 在 **设置** 里提供独立一页,调整各阶段时长、循环轮数和两个自动开始开关。
## 非目标
- 不做系统通知、声音提示或浏览器 Notification 授权(需要额外权限,首版不引入)。
- 不写入 Session 日志、不注册模型可见的 Tool:番茄钟是**纯 UI 状态**,模型不需要看到它。
- 不做跨设备的云同步。
- 不在 DSH 退出后继续走时(见「已知限制」)。
## 安装
发布后:
```sh
dsh plugin --profile <profile> add @skillre/dsh-plugin-pomodoro
```
本地开发内环(**必须走打包 tarball**):
```sh
npm install
npm run check
npm pack
dsh plugin --profile <dev-profile> add ./skillre-dsh-plugin-pomodoro-<version>.tgz
dsh --profile <dev-profile> --dump-config
dsh --profile <dev-profile>
```
不要用 `dsh plugin ... add .`:把源码目录交给包管理器会建立源码链接安装,插件因此解析到**自己的** `node_modules` 而不是宿主的,本地一切正常、打包安装却在启动时炸掉整个 profile。`file:<tarball>` 才是受支持的形态。
更新与回滚见 [UNINSTALL.md](UNINSTALL.md)。
## 配置与默认值
插件行**没有**配置项:`cordis.patch.yml` 只插入一行,不带 `config`。所有可调项属于用户偏好,存在浏览器本地(见下),因此在设置页里改,而不是在 `cordis.patch.yml` 里改。
| 偏好 | 默认值 | 范围 | 含义 |
|---|---|---|---|
| 专注时长 | `25` 分钟 | 1–180 | 一轮专注的长度 |
| 短休息 | `5` 分钟 | 1–180 | 普通专注轮次之后的休息 |
| 长休息 | `15` 分钟 | 1–180 | 完成一个循环后的休息 |
| 长休息前的专注轮数 | `4` | 1–12 | 一个循环包含几轮专注 |
| 自动开始休息 | 开 | 开/关 | 专注结束后直接进入休息 |
| 自动开始专注 | 关 | 开/关 | 休息结束后直接进入下一轮专注 |
越界的输入会被**收敛到范围内**,而不是报错:损坏或来自旧版本的数据也会退化成一个可用的配置。
## 显示元数据
DSH 读取插件卡片信息时**不激活插件**,所以这些资源随包发布:
- `locale/en.json`(必需)与 `locale/zh.json`:`{"meta": {"title": ..., "description": ...}}`。
它经 Node ESM resolver 解析,因此 `exports` 必须声明 `"./locale/*.json"`;缺这一条会抛
`ERR_PACKAGE_PATH_NOT_EXPORTED`,而 DSH 会**静默吞掉**该错误,卡片退化成裸包名。
- `icon`:顶层字段 `./icon.svg`,包内相对路径、小于 256 KiB、被 `files` 覆盖。
| locale | title | description |
|---|---|---|
| `en` | Pomodoro | A focus clock beside the composer, with daily rounds and local preferences. |
| `zh` | 番茄时钟 | 输入框旁的专注计时器:工作/休息循环、每日番茄数与本地偏好。 |
界面文案不在这里,而在客户端通过 Client locale 服务注册的 `skillre-pomodoro` 命名空间(`src/client/text.ts`,含 `en` 与 `zh` 两套词典)。
## 权限与副作用
- **网络**:无。
- **凭据 / 密钥**:无。
- **文件系统**:无。Host 半边是空入口,不做任何 I/O。
- **浏览器存储**:写入 `localStorage`,键为 `skillre-pomodoro/state`,内容只有计时状态、当天计数与偏好(payload 带 `version`,当前为 `2`),全部是插件自己的 JSON,不含 Session 内容、提示词或路径。存储不可用或写满时静默降级为纯内存运行,计时器不受影响。旧版本写入的记录会被丢弃并重新以暂停状态开始,而不是用当前配置去猜测它原本的长度。
- **UI 占用**:两个 slot 注册(`conversation.composer.dock` 与 `settings.section`),使用插件自己的类名前缀 `skp-pomodoro-` 和主题变量 `--dsw-alias-*`,不读写产品 DOM,不替换宿主结构。
- **定时器**:运行中每秒一次刷新;空闲时睡到下一个本地零点(最早的显示变化时刻)。两者都挂在插件 Fiber 上,卸载即清理。
## 生成的与模型可见的行为
没有。插件不注册 Tool、不注入 prompt、不写 Session 事件,模型看不到番茄钟。
## 兼容性
| DSH 版本 | 已完成的验证 | 日期 |
|---|---|---|
| 0.2.0-rc.2 | 打包 tarball 装入 `desktop` profile(`application: applied`);客户端模块在真实页面加载并把两个 slot 注册为 active occupant;产物按宿主模块信封契约在测试中加载通过 | 2026-09-30 |
**尚未完成**(因此 `compatibility.json#verified` 保持为空,`release:prepare` 会按设计失败):
- `dump-config` 与 `bounded-startup`:未在隔离 profile 中执行。
- `browser`:**没有**做真实浏览器视觉验证。当前环境的浏览器控制不可用(CDP 无法读取工作区沙箱之外的 Chrome 调试端口),因此渲染外观、明暗主题与交互均未被观察过。
按技能要求,无浏览器控制时只做语法、manifest 与 live Client slot 三项验证,不构造预览图或模拟渲染来替代。已完成的证据与待办记录在 `compatibility.json#observations`。Peer range 不是兼容性证据。
## 已知限制
- 计时依赖浏览器:**关闭整个页面**期间不推进播放,重开页面时按绝对时间戳结算到期的阶段(因此不会补记睡眠期间的多轮番茄)。
- `conversation.composer.dock` 的 scope 是 **session**,所以胶囊随笔输入框出现;没有活动 Session 的空白首页不显示它。设置页(root scope)不受影响。
- 「今天」按浏览器本地时区划分;跨零点时正在进行的阶段不中断,完成时才计入新的一天。
- 一次 `settle` 只结算一个到期阶段;长时间休眠后不会一次性补记多轮。
- 每个标签页各自持有一份计时状态,通过 `localStorage` 收敛,但**没有跨标签页的实时广播**:在 A 标签页开始,B 标签页要等下一次刷新才看到。
- 没有通知与声音提示。
## 开发
```sh
npm run typecheck # Host + tests,以及 Client 半边(DOM lib)
npm test # 先构建 lib/client.js,再跑单测与产物集成测试
npm run check # typecheck + test + pack:check
```
Client 半边用 esbuild 打包成**一个** CommonJS 文件(`src/client/index.ts` → `lib/client.js`),只有 baseline `react` 是 external;原因是模块信封里的 `require` 只能解析浏览器模块表,相对 `require('./store.js')` 在运行时无法解析。`tests/client-bundle.spec.ts` 会按宿主的方式加载产物,一旦多出第二个依赖就失败。
契约查询记录(2026-09-30,DSH `0.2.0-rc.2`):
- `Slots.listSubTree`:`conversation.composer.dock`(list,session scope,注册参数 `id`/`order`/`label`)、`settings.section`(list,root scope,ownerProps `{ close }`)。
- Client `Service`:`slots`(`inject`/`register`)、`locale`(`register(ns, locale, dict)`/`bind(ns)`/`getLocale`/`subscribe`)。
- `Builtin`:`ctx`(受限 Context,`ctx.effect`)、`React`;模块信封为 `window.__ModuleLoader__.load({ id, factory })`。
- `Theme`:仅使用 `--dsw-alias-*`。
## License
MIT
Install
dsh plugin --profile web add github:skillre/dsh-plugin-pomodoro
Profile: web
With the hub plugin installed, ask your agent to install it by name — it resolves the same plan shown here.
dsh plugin --profile web add github:stvlynn/dsh.fish#path:packages/dsh-plugin-hub
install skillre-dsh-plugin-pomodoro from the hub
- This package builds from source on install. pnpm will ask you to allow its build script — that is permission to run the package’s code on your machine, outside the agent sandbox. Only allow sources you trust.
- This source has no pinned commit, so a later push upstream changes what installs. Prefer pinning a commit.