Skip to content
dsh.fish
Bundle

dsh-park-notes

Parked thoughts for later: jot follow-up topics while the AI is working, without interrupting the conversation, and push them into the composer draft when the time is right. DSH web plugin. 稍后说:等待 AI 时记下想聊的话题,不打断当前对话,稍后一键带入输入框。

Source
kevin-zx
License
MIT
Updated
Updated 6 hours ago

Readme

# dsh-park-notes · 稍后说 / Talk later

Park thoughts while the AI is working — without interrupting the conversation.

**⚠️ Disclaimer / 免责声明**

Plugins run third-party code on your machine. Review the source before
installing — this project is a community plugin, not affiliated with
DeepSeek. / 插件会在你的机器上执行第三方代码,安装前请自行审阅源码;本项目为社区插件,与 DeepSeek 官方无关联。

---

## The problem / 要解决的问题

**Scenario — 你在和 AI 对话的过程中,突然想到"这个也想和 AI 聊聊"。**

- AI 正在输出,你的思路被带跑了——刚想到一条新的问题/话题/补充,想立刻说;
- 但如果**直接发送**:要么打断 AI 当前的生成(它本该一次说完那件事),要么把两件不相关的事揉进下一个回合,节奏全乱;
- 如果**等一会儿再说**:等它生成完,你的想法往往已经忘了,或者只记得"好像有个事要说"却想不起来是什么。

**一句话:在"现在说会打断"和"晚点说会忘"之间,缺一个零成本的中间态。**

## What it solves / 它如何解决

`稍后说` 在输入框上方放了一条**常驻便签条**:想到什么,点开随手记一条(回车即可,不打断正在进行的对话),然后继续专注当前的事。等这轮聊完、你想聊那个话题了,**一键把便签带进输入框草稿**(只填草稿、不自动发送),确认后发送即可。

- **记的时候**:零打断——便签在输入框旁,3 秒完成,AI 的生成不受影响;
- **存的时候**:随会话走——每条便签挂在当前会话下,刷新、重启都不丢;
- **用的时候**:一键带入——不再靠记忆,草稿里就是你要聊的内容;
- **用完即清**:带入后自动从便签列表移除,不会重复携带。

While the agent is busy writing, you think of something worth raising later.
`稍后说` gives you a tiny strip above the composer: jot the thought, forget
about it, and when the current exchange is over push the parked items straight
into your next draft (never sent automatically), then delete them with one
click.

---

## Install / 安装

Requires the web profile (`dsh web`). / 需要 web 版 dsh(`dsh web`)。

```bash
# from a git checkout / 从 Git 仓库安装
dsh plugin --profile web add github:kevin-zx/dsh-park-notes

# or once published to npm / 或发布 npm 后:
dsh plugin --profile web add dsh-park-notes
```

Restart `dsh web` (or refresh the page after the live patch reload), and the
`💡 稍后说` strip appears above the message composer in every session. /
重启 `dsh web`(或刷新页面),输入框上方即出现 `💡 稍后说` 条带。

Manual alternative — in `$DSH_HOME/profiles/web/cordis.patch.yml` / 手动方式:

```yaml
- insert:
    - id: park-notes
      name: 'dsh-park-notes'
```

Use **either** the bundle install (`dsh plugin add ...`) **or** the manual
row — not both, or the row id collides. / 二选一,不能同时用,否则行 id 冲突。

## Update / 更新

One command pulls the latest `main` commit; then restart `dsh web` (a
browser-half-only change may appear after a page refresh, a host-half change —
like the `/note` command — needs the restart). / 一条命令拉取 `main` 最新提交,
然后重启 `dsh web`(只有浏览器半边变化时刷新页面即可;宿主半边变化——比如
`/note` 命令——需要重启)。

```bash
dsh plugin --profile web update dsh-park-notes
```

Check what is installed / 查看当前版本:

- **Settings → Plugins** in the web UI lists `dsh-park-notes` with its version. /
  网页界面 **设置 → 插件** 里能看到 `dsh-park-notes` 的版本号。
- `dsh web --dump-config | grep park-notes` confirms the row is mounted. /
  该命令可确认挂载行存在。

Notes / 说明:

- Installed **without a ref** (`github:kevin-zx/dsh-park-notes`) keeps tracking
  `main`, so updates just work. Installing a pinned ref
  (`...#v0.5.0`) freezes the version — re-`add` the unpinned spec to follow
  again. / **不加 ref** 安装才会跟随 `main` 更新;装了固定 tag(`...#v0.5.0`)
  就冻结在那个版本,需要重新用不带 ref 的形式 add 一次。
- If GitHub is unreachable, export a proxy first
  (`$env:HTTPS_PROXY="http://127.0.0.1:1080"` style) or install a tarball. /
  GitHub 不通时先设置代理环境变量,或改用 tarball 安装。
- **Updating never touches your notes or images** — they live in the browser
  (localStorage + IndexedDB), not in the package. / **更新不会影响便签与图片**,
  它们存在浏览器里,不在插件包里。

## Usage / 用法

- **`/note <text>`** — type it in the composer and press Enter: the text is parked
  as a pending note, the command runs directly against the agent (no model
  message is created) and its result row confirms it. Keyboard-only and fully
  non-interrupting. / **`/note 内容`** — 在输入框直接敲,回车即记录;命令直接
  对 agent 执行、**不产生模型消息**,结果行给出确认。纯键盘、零打断。
- **`Alt+N`** — reveal and focus the capture box without touching the mouse. /
  **`Alt+N`** — 打开并聚焦记录框,不用鼠标。
- **Collapsed**: `💡 稍后说 (2)` — always visible, shows the pending count. /
  **折叠**:常驻条带,显示待聊数量。
- **Expanded**: pending notes (pinned first), an optional search box, the
  quick-capture input, then a collapsed **history**. / **展开**:待聊列表
  (置顶优先)→ 搜索框(便签 ≥ 3 条时出现)→ 快捷记录框 → 折叠的「已带入」历史。
  - `Enter` records (IME-safe, `Shift+Enter` newline), `Esc` collapses. /
    `Enter` 记录(支持中文输入法,`Shift+Enter` 换行),`Esc` 收起。
  - **带入** appends a note to the composer draft (not sent) and moves it to
    history; **删除** drops it; **全部带入输入框** does both at once. /
    「带入」= 追加到输入框草稿(不发送)并移入历史;「删除」直接丢弃。
  - **Edit**: click a note's text to edit in place (`Enter` saves, `Esc` cancels). /
    **二次编辑**:点击条目文字就地编辑(`Enter` 保存、`Esc` 取消)。
  - **Pin**: 📌 keeps a note on top of the pending list. /
    **置顶**:📌 把条目固定在待聊列表最前。
  - **Images**: paste, drop, or `+图片` to attach images to a note; thumbnails
    show in the note, click one to enlarge, and the enlarged view can copy the
    image to the clipboard or save it to a file. / **图片**:粘贴、拖入或点
    `+图片` 给便签附上图片;缩略图显示在条目里,点击放大;放大后可复制到剪贴板
    或保存到本地文件。
  - **Pushing a note that has images**: the text goes into the draft and the
    plugin first tries to hand the images to the composer itself (a synthetic
    paste into the composer editor, verified against the composer's own image
    list). When that is refused it copies the first image to the clipboard
    instead (re-encoded to PNG, because the async clipboard only accepts PNG) —
    press `Ctrl+V` to attach it. **Dragging a thumbnail straight into the
    composer** is the always-available manual route. / **带入含图便签**:文字进
    草稿,插件会先尝试**自动**把图片交给输入框(向编辑区派发一次合成粘贴,并用
    输入框自己的图片列表校验是否成功);被拒绝时退回复制首图到剪贴板(会转成
    PNG,因为异步剪贴板只接受 PNG)→ 按 `Ctrl+V` 即成附件。**把缩略图直接拖进
    输入框** 始终可用的手动通道。
  - **Search**: filter pending and history together (substring match). /
    **搜索**:一个输入框同时过滤待聊与历史。
  - **Export**: download every note of the session as Markdown
    (`park-notes-YYYY-MM-DD.md`). / **导出**:把本会话全部便签导出为 Markdown 文件。
  - **History**: pushed notes stay under a collapsed `已带入` section, tagged
    `已带入` / `已发送` (a note flips to `已发送` once the draft carrying it is
    actually submitted), with 重新带入 / 删除 / 清空. / **历史**:带入过的内容收进
    折叠的「已带入」区,标注「已带入 / 已发送」(真正把草稿发出去后自动标记),
    支持重新带入、删除、清空。
- Data lives in the browser `localStorage` per session (key
  `dsh-park-notes:v1:<sessionId>`); server restarts don't affect it. Notes
  written by the pre-rename `dsh-idea-note` build migrate automatically. /
  数据存浏览器 localStorage(按会话隔离),服务器重启不影响;旧版
  `dsh-idea-note` 的便签自动迁移。

## How it works / 原理

A DSH web plugin = one package with a host half and a browser half. /
DSH 网页插件 = 一个包,含 host 半边和浏览器半边。

- `lib/index.js` — host half: registers the `/note` slash command through the
  host `commands` service; the command runs directly against the agent and never
  creates a model message.
- `lib/client.js` — browser half: a `window.__ModuleLoader__.load(...)`
  bundle (same hand-written format as shipped `dsh-client-ui-*` packages, no
  build step). It declares `inject: ["slots", "locale"]` — the `inject`
  export is the Cordis dependency declaration; without it `apply` runs before
  the `slots` service exists and fails silently.
- The browser half also projects the host command run: a state-only
  conversation definition matches `command/run` with `name === "note"` and parks
  the text, deduplicated by command id so a replayed history cannot duplicate a
  note.
- `package.json` → `dsh.client` is how client-modules discovers and serves
  the bundle over `/plugins`; `dsh.bundle.patch` is what `dsh plugin add`
  uses to mount the row automatically.
- UI registers in `conversation.input.dock` (order 15), the same slot family
  as Todo / Goal / queue docks.

### Two traps worth knowing / 两个值得注意的坑

1. **Wait for services with `ctx.inject([name], cb)`, not `ctx.get(name)`.**
   A service provided by a later row (the command registry, the conversation
   UI) may not exist yet when `apply` runs; a plain `ctx.get` guard then returns
   silently and the contribution never happens. `ctx.inject` suspends the fiber
   until the service is available.
2. **A client bundle must export `inject`.** Without that dependency
   declaration the browser half applies before the `slots` service exists and
   disappears without an error — the classic "works after hot reload, gone after
   a refresh" symptom.

## Develop / edit / 开发

`lib/client.js` is plain JavaScript — edit it; a running dsh web picks the
change up via client HMR (or Ctrl+Shift+R). Syntax check: `node --check lib/client.js`.
/ `lib/client.js` 是纯 JS,直接编辑即可,开发热更新自动生效。

## Requirements / limits / 限制

- Web profile only (browser UI). / 仅 web 界面。
- Notes are per-session, per-browser (localStorage); images live in the browser's
  IndexedDB under the same per-session ownership and are never uploaded. /
  便签按会话、按浏览器隔离(localStorage);图片存在浏览器 IndexedDB,同样按会话
  归属,**不会上传到任何地方**。
- Images cannot be injected into the composer as attachments by a third-party
  plugin; the panel hands them over through the clipboard instead. / 图片无法由
  第三方插件直接注入输入框附件;面板改用剪贴板交接。
- **Image storage is managed, not left to grow**: the panel shows how much is
  stored and offers 清理历史图片; on every session load orphan images (no note
  references them) are deleted, and once the store passes an 80 MB budget the
  oldest images held only by archived notes are trimmed (text is kept). A single
  image above 12 MB is downscaled to 2560 px before it is stored. Pending notes
  are never trimmed. / **图片存储是被管理的**:面板显示占用并可一键「清理历史
  图片」;每次进入会话会删除孤儿图片(没有任何便签引用),总量超过 80MB 时自动
  清理最旧的归档图片(文字保留);单张超过 12MB 会先缩到 2560px 再存。**待聊
  便签的图片永不自动清理。**
- The Markdown export marks how many images a note has (blobs stay in the
  browser). / Markdown 导出会标注每条便签的图片数量(图片本体留在浏览器里)。
- Two browser tabs editing the same session's notes: last write wins. /
  同会话双标签页编辑时以最后写入为准。

## License

MIT

Install

dsh plugin --profile web add github:kevin-zx/dsh-park-notes

Profile: web

  • This source has no pinned commit, so a later push upstream changes what installs. Prefer pinning a commit.
Source