{"_id":"@dshworks/dsh-watch","_rev":"4-6eaefbeb5fb8bd19fd63fcb4e7713c05","name":"@dshworks/dsh-watch","dist-tags":{"latest":"0.2.3"},"versions":{"0.2.0":{"name":"@dshworks/dsh-watch","version":"0.2.0","keywords":["deepseek","deepseek-harness","dsh","dsh-plugin","monitor","watcher","daemon","background-jobs","notifications","tail"],"license":"MIT","_id":"@dshworks/dsh-watch@0.2.0","maintainers":[{"name":"lroolle","email":"reason-source6s@icloud.com"}],"homepage":"https://github.com/dshworks/dsh-watch#readme","bugs":{"url":"https://github.com/dshworks/dsh-watch/issues"},"dsh":{"bundle":{"patch":"./cordis.patch.yml"}},"dist":{"shasum":"82d4064ab63c24780c8812bb8464ad6ca56d4335","tarball":"https://registry.npmjs.org/@dshworks/dsh-watch/-/dsh-watch-0.2.0.tgz","fileCount":15,"integrity":"sha512-97l8oQle5xbLfW8Zv0oDREp60b17Q/BUPzD44+P7qh0T16LG64FlU+HZo+KqHxOvXNQczSLe+o01PYbHMgNh5w==","signatures":[{"sig":"MEUCIQCdpaKYiEFLRihwA+BnF3L0JBhygIoQRPM19PURxsx+AQIgMX5XRVBFCgsWRnf1F4T9aPLxha2haGYOO+OWIwvv2rA=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":82556},"main":"lib/index.js","type":"module","types":"lib/types/index.d.ts","engines":{"node":">=20"},"exports":{".":{"types":"./lib/types/index.d.ts","default":"./lib/index.js"},"./core":"./lib/core.js","./daemon":{"types":"./lib/types/daemon.d.ts","default":"./lib/daemon.js"},"./package.json":"./package.json"},"gitHead":"14744e2fe800844f17cd0875e345f4ff62179a77","scripts":{"test":"vitest run"},"_npmUser":{"name":"lroolle","email":"reason-source6s@icloud.com"},"repository":{"url":"git+https://github.com/dshworks/dsh-watch.git","type":"git"},"_npmVersion":"10.9.8","description":"Background stream listeners that wake the DeepSeek Harness agent — put a watch on a command or file and receive new lines as in-session notices. Ships a daemon host so a watcher can run unattended for weeks.","directories":{},"_nodeVersion":"22.23.2","dependencies":{"@deepseek-ai/schemastery":"^3.18.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vitest":"^3.2.4","@deepseek-ai/cordis":"^4.0.1","@deepseek-ai/dsh-llm":"^0.1.0-rc.6","@deepseek-ai/dsh-tools":"^0.1.0-rc.6"},"peerDependencies":{"@deepseek-ai/cordis":"^4.0.1","@deepseek-ai/dsh-llm":"^0.1.0-rc.6","@deepseek-ai/dsh-tools":"^0.1.0-rc.6"},"_npmOperationalInternal":{"tmp":"tmp/dsh-watch_0.2.0_1786811929404_0.7061122121819772","host":"s3://npm-registry-packages-npm-production"}},"0.2.1":{"name":"@dshworks/dsh-watch","version":"0.2.1","keywords":["deepseek","deepseek-harness","dsh","dsh-plugin","monitor","watcher","daemon","background-jobs","notifications","tail"],"license":"MIT","_id":"@dshworks/dsh-watch@0.2.1","maintainers":[{"name":"lroolle","email":"reason-source6s@icloud.com"}],"homepage":"https://github.com/dshworks/dsh-watch#readme","bugs":{"url":"https://github.com/dshworks/dsh-watch/issues"},"dsh":{"bundle":{"patch":"./cordis.patch.yml"}},"dist":{"shasum":"7fd07890eb56f91c02622f958f8888a3ae8c439a","tarball":"https://registry.npmjs.org/@dshworks/dsh-watch/-/dsh-watch-0.2.1.tgz","fileCount":15,"integrity":"sha512-/SJsO4KK5iXw81MeflCIYf9+wQEDSrhSE36bAnMLmrVsWoIu2yJ9lMet5jXJB5KaeYyCzUMeEd1F33LO9HyQOw==","signatures":[{"sig":"MEQCIDB+5BjfylpgZ23FSk14FHSyh4ruPcQ+XX6zZrv02hKEAiBOOXsVOjFT8wwYErVRzbF0Zoy39NhjXBxMoRFH6o3S4Q==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":84484},"main":"lib/index.js","type":"module","types":"lib/types/index.d.ts","engines":{"node":">=20"},"exports":{".":{"types":"./lib/types/index.d.ts","default":"./lib/index.js"},"./core":"./lib/core.js","./daemon":{"types":"./lib/types/daemon.d.ts","default":"./lib/daemon.js"},"./package.json":"./package.json"},"gitHead":"0b7850813db701af6d9b5681f401de22e052f43b","scripts":{"test":"vitest run"},"_npmUser":{"name":"lroolle","email":"reason-source6s@icloud.com"},"repository":{"url":"git+https://github.com/dshworks/dsh-watch.git","type":"git"},"_npmVersion":"10.9.8","description":"Background stream listeners that wake the DeepSeek Harness agent — put a watch on a command or file and receive new lines as in-session notices. Ships a daemon host so a watcher can run unattended for weeks.","directories":{},"_nodeVersion":"22.23.2","dependencies":{"@deepseek-ai/schemastery":"^3.18.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vitest":"^3.2.4","@deepseek-ai/cordis":"^4.0.1","@deepseek-ai/dsh-llm":"^0.1.0-rc.6 || ^0.1.1-rc.1 || ^0.1.2-rc.1","@deepseek-ai/dsh-tools":"^0.1.0-rc.6 || ^0.1.1-rc.1 || ^0.1.2-rc.1"},"peerDependencies":{"@deepseek-ai/cordis":"^4.0.1","@deepseek-ai/dsh-llm":"^0.1.0-rc.6 || ^0.1.1-rc.1 || ^0.1.2-rc.1","@deepseek-ai/dsh-tools":"^0.1.0-rc.6 || ^0.1.1-rc.1 || ^0.1.2-rc.1"},"_npmOperationalInternal":{"tmp":"tmp/dsh-watch_0.2.1_1788501358372_0.7367939372466783","host":"s3://npm-registry-packages-npm-production"}},"0.2.2":{"name":"@dshworks/dsh-watch","version":"0.2.2","keywords":["deepseek","deepseek-harness","dsh","dsh-plugin","monitor","watcher","daemon","background-jobs","notifications","tail"],"license":"MIT","_id":"@dshworks/dsh-watch@0.2.2","maintainers":[{"name":"lroolle","email":"reason-source6s@icloud.com"}],"homepage":"https://github.com/dshworks/dsh-watch#readme","bugs":{"url":"https://github.com/dshworks/dsh-watch/issues"},"dsh":{"bundle":{"patch":"./cordis.patch.yml"}},"dist":{"shasum":"5d3674304ad323071d5e5cf136fe21e84746612b","tarball":"https://registry.npmjs.org/@dshworks/dsh-watch/-/dsh-watch-0.2.2.tgz","fileCount":15,"integrity":"sha512-lmSQDzZ8r06NAa8DGbFDKNksGH3+k9MZB4g/o77MqZ7pgNzNGOHdMQGabqrwQxkwQTVeGd0hPHP6UFT6pV3mwQ==","signatures":[{"sig":"MEQCIChPtBr7sNFPe0Wa6lw2mXweL9j3m/nrFZ+WqsUD0wu8AiBcVY6WnovueagolKgN6L14GM9RVI5GqYQWjSkeeX4O4g==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCIQDV81FY97IzbmObFs2PK/e0ZELQZdj0HLOt0kwwoEhS3wIgT/VhUlBsZNcBYcCVl8o/lK0qua3Rp1BHR2Yzk0EVViQ=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":85809},"main":"lib/index.js","type":"module","types":"lib/types/index.d.ts","engines":{"node":">=20"},"exports":{".":{"types":"./lib/types/index.d.ts","default":"./lib/index.js"},"./core":"./lib/core.js","./daemon":{"types":"./lib/types/daemon.d.ts","default":"./lib/daemon.js"},"./package.json":"./package.json"},"gitHead":"3cdcf3f2f34d3f090faf54ddb26fd67b8977a66a","scripts":{"test":"vitest run"},"_npmUser":{"name":"lroolle","email":"reason-source6s@icloud.com"},"repository":{"url":"git+https://github.com/dshworks/dsh-watch.git","type":"git"},"_npmVersion":"10.9.8","description":"Background stream listeners that wake the DeepSeek Harness agent — put a watch on a command or file and receive new lines as in-session notices. Ships a daemon host so a watcher can run unattended for weeks.","directories":{},"_nodeVersion":"22.23.2","dependencies":{"@deepseek-ai/schemastery":"^3.18.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vitest":"^3.2.4","@deepseek-ai/cordis":"^4.0.1","@deepseek-ai/dsh-llm":"^0.1.0-rc.6 || ^0.1.1-rc.1 || ^0.1.2-rc.1 || ^0.1.5-rc.1","@deepseek-ai/dsh-tools":"^0.1.0-rc.6 || ^0.1.1-rc.1 || ^0.1.2-rc.1 || ^0.1.5-rc.1"},"peerDependencies":{"@deepseek-ai/cordis":"^4.0.1","@deepseek-ai/dsh-llm":"^0.1.0-rc.6 || ^0.1.1-rc.1 || ^0.1.2-rc.1 || ^0.1.5-rc.1","@deepseek-ai/dsh-tools":"^0.1.0-rc.6 || ^0.1.1-rc.1 || ^0.1.2-rc.1 || ^0.1.5-rc.1"},"_npmOperationalInternal":{"tmp":"tmp/dsh-watch_0.2.2_1789707868531_0.7569062041559067","host":"s3://npm-registry-packages-npm-production"}},"0.2.3":{"_id":"@dshworks/dsh-watch@0.2.3","dsh":{"bundle":{"patch":"./cordis.patch.yml"}},"bugs":{"url":"https://github.com/dshworks/dsh-watch/issues"},"dist":{"shasum":"d2010d2e58ce57c74e7d66e2cf81aedec06bc614","tarball":"https://registry.npmjs.org/@dshworks/dsh-watch/-/dsh-watch-0.2.3.tgz","fileCount":15,"integrity":"sha512-mR7t5lQfBcxkzgg0Gq5vza1AhNkYf42vbAfQaPh75O/SZl6oQf+sU2CF6Mv+vDXhd+T4c7hvogq/53blaSPlog==","signatures":[{"sig":"MEQCIG5vjjeBC7UbRleNgJlG81wngO6u2DFpftbTgg4wOS7uAiAUc9+Hzk+U653KEKudbmJD6XzHB/eHArEeRQt477R6aA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCICZOo0M5EHqE3iAqr9Z2a32KfYBswH4shhFQKqBDhpmBAiBAeuS73tibG06c356hLjQy6UQjS6JC+gdrGpiQEvuZpw=="}],"unpackedSize":90533},"main":"lib/index.js","name":"@dshworks/dsh-watch","type":"module","types":"lib/types/index.d.ts","engines":{"node":">=20"},"exports":{".":{"types":"./lib/types/index.d.ts","default":"./lib/index.js"},"./core":"./lib/core.js","./daemon":{"types":"./lib/types/daemon.d.ts","default":"./lib/daemon.js"},"./package.json":"./package.json"},"license":"MIT","scripts":{"test":"vitest run"},"version":"0.2.3","_npmUser":{"name":"lroolle","email":"reason-source6s@icloud.com"},"homepage":"https://github.com/dshworks/dsh-watch#readme","keywords":["deepseek","deepseek-harness","dsh","dsh-plugin","monitor","watcher","daemon","background-jobs","notifications","tail"],"repository":{"url":"git+https://github.com/dshworks/dsh-watch.git","type":"git"},"_npmVersion":"10.9.8","description":"Background stream listeners that wake the DeepSeek Harness agent — put a watch on a command or file and receive new lines as in-session notices. Ships a daemon host so a watcher can run unattended for weeks.","directories":{},"maintainers":[{"name":"lroolle","email":"reason-source6s@icloud.com"}],"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vitest":"^3.2.4","@deepseek-ai/cordis":"^4.0.4","@deepseek-ai/dsh-llm":"^0.1.7-rc.2","@deepseek-ai/dsh-tools":"^0.1.7-rc.2","@deepseek-ai/schemastery":"^3.18.4"},"peerDependencies":{"@deepseek-ai/cordis":"^4.0.1","@deepseek-ai/dsh-llm":"^0.1.7-alpha.1 || ^0.2.0-rc.1","@deepseek-ai/dsh-tools":"^0.1.7-alpha.1 || ^0.2.0-rc.1","@deepseek-ai/schemastery":"^3.18.1"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/dsh-watch_0.2.3_1790669888631_0.5182982424751572"}}},"time":{"created":"2026-08-15T16:38:49.298Z","modified":"2026-09-29T08:18:08.928Z","0.2.0":"2026-08-15T16:38:49.565Z","0.2.1":"2026-09-04T05:55:58.510Z","0.2.2":"2026-09-18T05:04:28.624Z","0.2.3":"2026-09-29T08:18:08.727Z"},"bugs":{"url":"https://github.com/dshworks/dsh-watch/issues"},"license":"MIT","homepage":"https://github.com/dshworks/dsh-watch#readme","keywords":["deepseek","deepseek-harness","dsh","dsh-plugin","monitor","watcher","daemon","background-jobs","notifications","tail"],"repository":{"url":"git+https://github.com/dshworks/dsh-watch.git","type":"git"},"description":"Background stream listeners that wake the DeepSeek Harness agent — put a watch on a command or file and receive new lines as in-session notices. Ships a daemon host so a watcher can run unattended for weeks.","maintainers":[{"name":"lroolle","email":"reason-source6s@icloud.com"}],"readme":"<table>\n<tr>\n<td width=\"40%\" valign=\"top\">\n\n# dsh-watch\n\n[English](README.md) | 中文\n\n### 给数据流挂一个监听。它说话，agent 就醒 —— 哪怕正在空闲，哪怕现场没有人。\n\n自带的 jobs 子系统只说任务**结束**了。`dsh-watch` 说有东西**开口**了：\n给长跑命令或持续增长的文件挂一个监听器，新出现的行经过滤、合批、字节封顶后，\n作为会话内通知送达。\n\n然后把人撤掉。把监听写进 profile 配置、挂上 daemon，agent 就会开机自启、\n空闲时零成本静默、连续数周被数据流唤醒。\n\n[![ci](https://github.com/dshworks/dsh-watch/actions/workflows/ci.yml/badge.svg)](https://github.com/dshworks/dsh-watch/actions/workflows/ci.yml)\n[![npm](https://img.shields.io/npm/v/@dshworks/dsh-watch?color=4D6BFE)](https://www.npmjs.com/package/@dshworks/dsh-watch)\n[![powered by dsh](https://img.shields.io/badge/powered__by-dsh-4D6BFE?logo=deepseek)](https://github.com/deepseek-ai/deepseek-harness)\n[![license: MIT](https://img.shields.io/badge/license-MIT-green)](LICENSE)\n\n</td>\n<td width=\"60%\" valign=\"top\">\n\n<img src=\"https://raw.githubusercontent.com/dshworks/dsh-watch/main/docs/watch-dark.png\" alt=\"终端里运行 dsh --profile watcher：daemon 启动、报告 Standing by、随后静默空闲不花一分钱，接着一次听到 53 个新发布的仓库，并记下留用的 11 个及各自归属的 dshworks 仓库\" width=\"100%\">\n\n</td>\n</tr>\n</table>\n\n## 安装\n\n```sh\ndsh plugin --profile web add @dshworks/dsh-watch\ndsh --profile web\n```\n\n`dsh plugin` 会转发给 pnpm，所以 PATH 里要有 pnpm。除此之外不需要配置 ——\n下一个会话里 `watch` 工具就可用了。\n\n需要 dsh 0.1.7 或更新（0.1.7 与 0.2.0 两条线）。dsh 在安装前会先检查插件的 harness\npeer 范围，所以更旧的宿主会直接拒装，而不是加载一个按另一套 API 写的插件。\n\n## 工具本体\n\n```text\nwatch(source: \"command\", command: \"npm run dev\", pattern: \"error|warn|Ready\", label: \"dev\")\n→ Watch armed (watch-1) on command: npm run dev.\n\n# …agent 继续干自己的活。当 dev server 打出 \"Ready in 130ms\"，\n# 一条通知把它唤醒：\n[watch dev · watch-1] 1 line:\nReady in 130ms\n```\n\n也可以盯文件：\n\n```text\nwatch(source: \"file\", path: \"/var/log/app.log\", pattern: \"ERROR|FATAL\")\n```\n\n每个监听都是**一等公民后台任务**（kind 为 `watch`），因此标准接口原样适用：\n`job_list` 列出已布防的监听，`job_output` 读出某个监听听到的行，`job_kill` 撤防，\n归属按会话隔离，结束时走普通的完成通知。这个插件只增加\"听\"这件事 ——\n没有第二套生命周期，也没有第二个注册表。\n\n| 行为 | 细节 |\n|---|---|\n| 数据源 | `command`（经 shell 能力启动一次，继承会话的沙箱策略与环境变量）· `file`（从当前末尾开始跟踪；已有内容一律不投递；被截断则从头重来；文件还不存在也可以先等着） |\n| 合批 | 一个 tick 内听到的所有行共用一条通知 —— 爆发式输出只花一次唤醒，而不是每行一次 |\n| 过滤 | 可选的 JavaScript 正则，只投递命中的行。**失败特征也要写进去 —— 没声音不等于没问题** |\n| 唤醒预算 | 每个 owner 一个令牌桶：先允许 `maxConsecutiveWakes` 次连发，之后每 `wakeRefillMs` 回一个额度。用户消息被领取时直接加满 |\n| 事件预算 | 每个监听在 `max_events` 条通知后自行撤防并以 `completed` 结束；填 `0` 表示一直听下去 |\n| 字节上限 | 每条完整通知按 UTF-8 安全截断（含包装文本）；听到的行同时写进任务的输出环，`job_output` 读的就是它 —— 保留多少由注册表限定，丢了字节的读取会被标记出来 |\n| 截断诚实 | 上游输出丢失（`lossy` 读）会作为标记行暴露出来，绝不吞掉 |\n| 生命周期 | 进程退出时先冲刷尾部再结算：`completed`（退出码 0）、`failed`（非零 —— 监听死了是一个发现，不是一段沉默）、`killed`（信号或撤防）。插件卸载会拆掉所有监听 |\n| 上限 | 每个 owner 的布防数量上限，超了就让这次调用**明确失败** |\n\n## 无人值守运行\n\n一个连续盯一个月生态的 agent，不是一场对话。有两件事必须改，而两件都已在包里。\n\n**它不能变聋。** 唤醒预算的存在，是为了不让一个失控的数据源把空闲 agent 无限循环唤醒。\n\"数连续唤醒次数、等下一条人类消息回血\"这条规则，对有人坐在旁边的会话是对的 ——\n对没人的会话就是一扇单向门：额度用完之后，每条通知都被注入到一个再也不会被唤醒的\n空闲 agent 里。所以预算改成了令牌桶：额度随时间回来（`wakeRefillMs`，默认 60 秒），\n而在桶空时到达的通知，会在额度回来的那一刻拿到一次补课唤醒。想要严格的\n`dsh-tool-jobs` 语义，把 `wakeRefillMs` 设为 `0`。\n\n**得有人去布防，也得有人让进程活着。** `dsh --profile headless` 跑完一个任务到静默\n就退出；`dsh --profile web` 常驻，但要等浏览器里的人。于是 `autoArm` 把监听声明进\nprofile 配置 —— 在 `agent/created` 时为根会话布防，并且走工具注册表，\n因此它要过的守卫、审批策略、沙箱和 shell 环境，跟模型自己发起的调用完全一致 ——\n而 `@dshworks/dsh-watch/daemon` 是一个约 90 行的宿主：创建一个 agent、注入一份常驻\n简报、把进程撑住，并把每个活动区间的收尾文本按 ISO 时间戳写到 stdout 作为运维日志。\n\n```yaml\n# ~/.dsh/profiles/watcher/cordis.patch.yml\n- id: dsh-watch\n  config:\n    wakeRefillMs: 300000\n    autoArm:\n      - source: command\n        command: node recipes/ecosystem-watcher/feed.mjs --topic dsh-plugin\n        pattern: '\"kind\":\"new-repo\"'\n        label: ecosystem\n        max_events: 0          # 会自己撤防的监听，算不上监听\n\n- insert:\n    - id: dsh-watch-daemon\n      name: '@dshworks/dsh-watch/daemon'\n      config:\n        brief: >-\n          You are the ecosystem watcher. A standing watch named \"ecosystem\"\n          is armed on a feed of newly published repositories. For each one,\n          decide whether there is an idea worth keeping, and append it to\n          data/ideas.ndjson.\n```\n\n```sh\ndsh plugin --profile watcher add @dshworks/dsh-watch\ndsh --profile watcher | tee -a watcher.log\n```\n\n[`recipes/ecosystem-watcher/`](recipes/ecosystem-watcher/) 里是完整的一套，\n包含一个按创建时间轮询 GitHub topic、对每个没见过的仓库输出一行 NDJSON 的 feed。\n\n### 实测\n\n2026-08-15 的一次真实运行，DeepSeek-V4-Pro，会话里没有人。feed 找到 53 个新发布的\ndsh 仓库；watcher 被唤醒、读完、留下 11 个，并说明了另外 42 个为什么被放掉：\n\n```text\n2026-08-15T16:21:23Z up — session 36041f74\n2026-08-15T16:25:11Z Batch of 53 repos processed. Appended 11 ideas to data/ideas.ndjson\n```\n\n```json\n{\"repo\":\"liustack/modlens\",\"why\":\"Pasting an image and receiving structured JSON evidence\n (OCR, layout, semantics) gives text-only DSH models vision without a vision model.\",\n \"for\":\"awesome-dsh-plugins\"}\n```\n\n这次运行还顺带换来一个 bug 修复：注入给**忙碌** owner 的通知会在它的下一步被领取，\n所以把它们算作\"欠一次补课唤醒\"，就会多出一次唤醒，而那次唤醒的全部内容是\n\"你有排队的通知\" —— 说的却是已经回答过的通知。改成在 `agent/inbox/claimed` 时清零，\n并补了一个回归测试守住。\n\n## 配置\n\n每一项边界都是经过校验的 `Config` 字段，不是写死的常量。\n\n| 字段 | 默认值 | 含义 |\n|---|---|---|\n| `pollIntervalMs` | `300` | 轮询节奏，同时也是合批窗口 |\n| `maxNoticeBytes` | `4096` | 单条完整通知（含头部）的 UTF-8 字节上限 |\n| `maxConsecutiveWakes` | `3` | 每个 owner 的唤醒额度桶容量 |\n| `wakeRefillMs` | `60000` | 回一个额度所需的毫秒数；`0` 表示不按时间回血 |\n| `defaultMaxEvents` | `50` | 每个监听的通知预算；`0` 表示不限 |\n| `maxListenersPerOwner` | `8` | 每个 agent 的布防数量上限 |\n| `autoArm` | `[]` | 启动时为根会话布防的常驻监听 |\n\ndaemon 自己的配置是 `brief`（必填）、`flushIntervalMs`（`300000`）和 `journal`（`true`）。\n\n## Model Experience\n\n### 系统提示词\n\n一段（order 107，排在后台任务指引之后）：\n\n```markdown\nYou can arm a watch on a stream with the watch tool: it listens in the background and wakes you when new matching lines arrive, so never busy-poll a source you already listen to. Listeners are background jobs — job_list shows them, job_output reads a listener's heard-line backlog, job_kill disarms one.\n```\n\n配置了 `autoArm` 时，会追加第二段（order 108）列出常驻监听的名字，\n免得模型把已经有的东西再布防一遍。\n\n### 工具\n\n只有一个工具 `watch`（source、command/path、workdir、pattern、max_events、label）。\n撤防、列表、读取都复用自带的 `job_kill` / `job_list` / `job_output`。\n\n### Token 影响\n\n安静的数据源不花 token —— 轮询发生在宿主侧。每条通知是一条有字节上限的消息\n（≤ `maxNoticeBytes`）；空闲唤醒还要额外付它开启的那次模型请求，\n这正是唤醒需要预算的原因。\n\n## 依赖要求\n\n- jobs 子系统：`@deepseek-ai/dsh-jobs`、`dsh-jobs-local`、`dsh-tool-jobs` ——\n  都在 `dsh-base` 里，因此 web 与 headless 标准 profile 都自带。\n  没有挂上 job 控制器时，布防会**明确失败**。\n- `source: command` 还需要 shell 能力（`@deepseek-ai/dsh-shell` 加一个 provider）。\n  文件源不需要。\n- daemon 另外需要 `agents`、`sessions`、`agentDefaultModel` —— 同样在 `dsh-base`。\n\n## 开发\n\n```sh\npnpm install && pnpm test    # 91 个测试\n```\n\n`lib/` 里是纯 ESM JavaScript —— 安装时不构建任何东西，所以用 git 装不会碰到\n`allowBuilds`。（**开发**安装会：vitest 会拉 esbuild，在 `pnpm-workspace.yaml` 里放行\n—— pnpm ≥ 11 从那里读构建设置，`package.json` 里的 `pnpm` 字段会被静默忽略。）\n\n除了测试套件，涉及 harness 的发布都会在真实 dsh 上跑一遍：用 `dsh plugin add` 装进一个\n临时 `DSH_HOME`，再作为无人值守的监听者启动。0.2.3（2026-09-29，`deepseek-flash`，\ndsh 0.1.7-rc.2 与 0.2.0-rc.1）验证了：\n\n- 常驻监听在 `agent/created` 时布防\n- 文件通知唤醒空闲 agent，`job_output` 读回那一行\n- 命令监听在布防 150 秒后才出声，越过了执行器默认两分钟的期限\n- `job_kill` 撤防\n- 每条通知都以 `dsh-watch` 来源 kind 写进 v4 会话日志\n\n`node scripts/check-dsh-release.mjs` 每天对 dsh `latest`（以及仅作提示的 `next`）重复\n安装这一半。dsh 的兼容性闸门拒装插件，或者插件把宿主已经提供的包带进 profile\n（它会为 profile 里的每个插件遮住宿主那一份）时，检查就会失败。\n\n测试替身按 peer 范围写明的 harness 版本建模，每次移植都做变异检查：把上一版的调用\n放回去，测试套件必须变红。在 0.1.7 上，为 0.1.5 写的替身在六处真实断裂下仍然全绿。\n\n## 与邻居的关系\n\n- **自带的 `dsh-tool-jobs`** 在任务**完成**时通知；dsh-watch 在**运行期间有输出**时通知。\n  同一套唤醒机制，互补的两个时刻。\n- **[yoke233/dsh-tool-monitor](https://github.com/yoke233/dsh-tool-monitor)**\n  通过分流输出来订阅**已经在跑**的 bash/pwsh 任务。想盯一个你已经启动的任务用它；\n  想布一个带合批和预算的专门监听（或盯文件）用 dsh-watch。\n- **[AbnerAI/dsh-monitor](https://github.com/AbnerAI/dsh-monitor)**\n  反复重跑一个命令、或轮询 NDJSON 收件箱，逐行唤醒 agent。dsh-watch 的不同在于：\n  命令只启动一次并按流处理、按 tick 合批、给唤醒和事件都上预算、每条通知都有字节上限、\n  活在 jobs 子系统内部，以及自带一个无人值守宿主。\n\n## 已知限制与未做的事\n\n- 是轮询，不是 `inotify`/`kqueue`：低于 `pollIntervalMs` 的延迟不在范围内，\n  tick 本身就是设计中的合批窗口。\n- 每个监听只有一个正则；多种特征用或来覆盖（`error|Traceback|FAILED`）。\n- 命令源的 `stderr` 混在 shell provider 的标记段落里，不是一条单独可过滤的通道。\n- 重启后不会自动恢复：监听与它的会话同生共死。重启后的 daemon 会开一个新会话并按\n  `autoArm` 重新布防，而不是接着上一个会话。\n- 补课扫描挂在监听的 tick 上，所以一个 owner 如果所有监听都被撤防了，\n  排队的通知会一直留到有别的东西唤醒它为止。\n\n## 许可\n\nMIT。与 DeepSeek 无隶属关系。已登记在\n[awesome-dsh-plugins](https://github.com/dshworks/awesome-dsh-plugins)。\n","readmeFilename":"README.zh.md"}