dsh-idle-watchdog 1.1.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +13 -0
- package/README.md +35 -3
- package/docs/ERRORS.md +302 -0
- package/docs/TROUBLESHOOTING.md +444 -0
- package/lib/client.js +2 -2
- package/lib/doctor.js +148 -0
- package/lib/dual-settings.js +311 -0
- package/lib/errors.js +143 -0
- package/lib/index.js +200 -59
- package/lib/plugin-errors.js +207 -0
- package/lib/plugin-skills.js +118 -0
- package/package.json +10 -9
- package/skills/idle-watchdog-doctor/SKILL.md +68 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.2.0 (2026-11-01)
|
|
4
|
+
|
|
5
|
+
Runs on DSH 0.1.5 and on DSH 0.2.x (0.1.7 and later) with the same code:
|
|
6
|
+
|
|
7
|
+
* Settings: DSH 0.1.5 keeps the registered namespace `dsh-idle-watchdog` in `settings.yaml`. DSH 0.2.x has no registrable namespaces; the plugin now exports its settings schema as `Config` (every field live, no remount) and stores values in its profile row `idle-watchdog` in `cordis.patch.yml`. On the first 0.2.x boot it imports the old `dsh-idle-watchdog` section once from `settings.yaml.imported` (the core import cannot, because the section name is not the entry id), and never over a row that already has values.
|
|
8
|
+
* API secret: new version-independent home `$DSH_HOME/idle-watchdog/api-secret` (mode 0600, override with `DSH_IDLE_WATCHDOG_SECRET_FILE`). Precedence: env `DSH_IDLE_WATCHDOG_SECRET`, then the file, then the stored setting. `POST /secret` writes the file (and, on 0.1.5 only, the namespace copy as before); on 0.2.x the secret is never written into the profile patch, and the legacy import moves it into the file. Scripts should read the file instead of grepping `settings.yaml`, which no longer exists on 0.2.x.
|
|
9
|
+
* `/status` reports `secretSource` (env, file, settings or none, never the value), `secretFile` and `settingsEntry`; `settingsStore` can now also be `profile-row`.
|
|
10
|
+
* Schemastery is resolved from the running harness first, so live fields are wrapped the way the 0.2.x Loader commits them.
|
|
11
|
+
* New `GET /dsh-idle-watchdog/api/doctor`: read-only self-check (settings mode, `Config` visible, API secret configured and its source, secret file mode, watched chats, `sessionController`, next-nudge preview, last scan age, state file writable). It never shows a secret value or a path.
|
|
12
|
+
* The packaged skill `idle-watchdog-doctor` is registered with the skills service at start.
|
|
13
|
+
* A missing `settings.json` on a fresh install is logged as an info line (`init: no fallback settings.json yet ...`) instead of `WATCHDOG_INIT_FAILED`; other init failures keep the code.
|
|
14
|
+
* The module now also has a default export `{ name, inject, apply, Config }` (the named exports are unchanged), so the 0.2.x loader finds `Config` there.
|
|
15
|
+
|
|
3
16
|
## 1.1.0
|
|
4
17
|
|
|
5
18
|
New, all optional, all defaulting to the 1.0 behaviour:
|
package/README.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# DSH-Idle-Watchdog
|
|
2
2
|
|
|
3
|
+
[](https://www.npmjs.com/package/dsh-idle-watchdog)
|
|
4
|
+
|
|
3
5
|
A [DeepSeek Harness](https://www.deepseek.com) (DSH) web-profile plugin with two jobs:
|
|
4
6
|
|
|
5
7
|
1. **Idle nudges.** Chats you opt in are watched. When one goes quiet for longer than your idle window and its agent is idle, the watchdog posts a followup prompt into that same chat, up to a cap, until you reply.
|
|
@@ -17,7 +19,17 @@ POST /dsh-idle-watchdog/api/prompt
|
|
|
17
19
|
|
|
18
20
|
## Install (DSH web profile)
|
|
19
21
|
|
|
20
|
-
|
|
22
|
+
Install from npm: `dsh plugin --profile web add dsh-idle-watchdog`, or from GitHub: `dsh plugin --profile web add github:lucagiftzek/DSH-Idle-Watchdog`.
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
dsh plugin --profile web add dsh-idle-watchdog
|
|
26
|
+
# or from GitHub: dsh plugin --profile web add github:lucagiftzek/DSH-Idle-Watchdog
|
|
27
|
+
# then restart dsh-web: the host half is mounted at boot only
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
The package declares `dsh.bundle`, so `dsh plugin add` lists `dsh-idle-watchdog` in `dsh.profile.bundles`.
|
|
31
|
+
|
|
32
|
+
Or from a local checkout (linked, not copied: keep the checkout where it lives):
|
|
21
33
|
|
|
22
34
|
```bash
|
|
23
35
|
git clone https://github.com/lucagiftzek/DSH-Idle-Watchdog ~/plugins/DSH-Idle-Watchdog
|
|
@@ -31,13 +43,21 @@ pnpm install
|
|
|
31
43
|
# 2. restart dsh-web: the host half is mounted at boot only
|
|
32
44
|
```
|
|
33
45
|
|
|
34
|
-
The official installer also works: `dsh plugin --profile web add link:/absolute/path/to/DSH-Idle-Watchdog`.
|
|
46
|
+
The official installer also works with a checkout: `dsh plugin --profile web add link:/absolute/path/to/DSH-Idle-Watchdog`.
|
|
35
47
|
|
|
36
48
|
After the restart, reload the web UI. The **Idle Watchdog** section appears in Settings. The browser half hot-reloads; only the server half needs the restart. Requires Node 22.5 or newer and a DSH build with the `agents`, `settings` and `webServer` services.
|
|
37
49
|
|
|
38
50
|
## Configuration
|
|
39
51
|
|
|
40
|
-
Everything is in **Settings, Idle Watchdog**, and
|
|
52
|
+
Everything is in **Settings, Idle Watchdog**, and applies live. Where it is stored depends on the DSH line:
|
|
53
|
+
|
|
54
|
+
* **DSH 0.1.5 and older:** the `dsh-idle-watchdog` namespace of `~/.dsh/settings.yaml` (hand-editable).
|
|
55
|
+
* **DSH 0.1.7 / 0.2.x and newer:** the plugin row `idle-watchdog` in the profile patch, `~/.dsh/profiles/web/cordis.patch.yml` (`- id: idle-watchdog` / `config:`). On the first boot after an upgrade the old `dsh-idle-watchdog` section is imported once from `settings.yaml.imported`, never over a row that already has values.
|
|
56
|
+
* **No settings service:** `~/.dsh/idle-watchdog/settings.json`.
|
|
57
|
+
|
|
58
|
+
`/status` reports which store is active (`settingsStore`: `settings`, `profile-row` or `fallback-file`).
|
|
59
|
+
|
|
60
|
+
**API secret file.** The prompt API secret has a version-independent home: `~/.dsh/idle-watchdog/api-secret` (mode 0600; override the path with `DSH_IDLE_WATCHDOG_SECRET_FILE`). Precedence: env `DSH_IDLE_WATCHDOG_SECRET`, then the file, then the stored `api.secret` setting. Saving a secret in Settings writes the file; on 0.2.x the secret never goes into the profile patch, and the upgrade import moves an old `api.secret` into the file. Scripts read it with `IW_SECRET=${DSH_IDLE_WATCHDOG_SECRET:-$(cat ~/.dsh/idle-watchdog/api-secret)}`.
|
|
41
61
|
|
|
42
62
|
| Setting | Meaning | Default |
|
|
43
63
|
|---|---|---|
|
|
@@ -104,6 +124,7 @@ Auth, one of: `x-idle-watchdog-secret: <secret>` or `Authorization: Bearer <secr
|
|
|
104
124
|
|
|
105
125
|
```bash
|
|
106
126
|
# set the secret once in Settings (or export DSH_IDLE_WATCHDOG_SECRET for dsh-web), then:
|
|
127
|
+
IW_SECRET=${DSH_IDLE_WATCHDOG_SECRET:-$(cat ~/.dsh/idle-watchdog/api-secret)}
|
|
107
128
|
curl -sS -X POST http://127.0.0.1:3080/dsh-idle-watchdog/api/prompt \
|
|
108
129
|
-H 'content-type: application/json' \
|
|
109
130
|
-H "x-idle-watchdog-secret: $IW_SECRET" \
|
|
@@ -142,6 +163,17 @@ Other read-only routes: `GET /api/health`, `/api/status`, `/api/next`, `/api/log
|
|
|
142
163
|
* A browser cross-site JSON POST cannot work: the custom header forces a CORS preflight and no CORS headers are ever sent. UI-mutating routes also require `X-Requested-With: dsh-idle-watchdog` and a JSON content type. Bodies are capped at 64 KiB.
|
|
143
164
|
* Anything that can post to a chat can steer an agent that has tools. Treat the secret like shell access to that agent.
|
|
144
165
|
|
|
166
|
+
## When something goes wrong
|
|
167
|
+
|
|
168
|
+
* Ask your agent to load the **`idle-watchdog-doctor`** skill. It ships in `skills/idle-watchdog-doctor/` and the plugin registers it with the skills service at start (offered after `dsh web` restarts). If your DSH does not list it, install it by hand:
|
|
169
|
+
```bash
|
|
170
|
+
P=$(node -p "require('path').dirname(require.resolve('dsh-idle-watchdog/package.json',{paths:[(process.env.DSH_HOME||require('os').homedir()+'/.dsh')+'/profiles/web']}))")
|
|
171
|
+
mkdir -p "${DSH_HOME:-$HOME/.dsh}/skills" && cp -r "$P/skills/idle-watchdog-doctor" "${DSH_HOME:-$HOME/.dsh}/skills/"
|
|
172
|
+
```
|
|
173
|
+
The skills folder is watched, so it appears without a restart. Details: [docs/TROUBLESHOOTING.md](docs/TROUBLESHOOTING.md#start-here).
|
|
174
|
+
* One-call self-check: `GET /dsh-idle-watchdog/api/doctor` (read-only, same access as `/status`). It reports the settings mode, whether `Config` is visible to the loader, whether an API secret is configured (yes or no, plus its source: env, file or settings; never the value), the secret file mode (0600), the watched chats, `sessionController`, the next-nudge preview, the age of the last scan and whether the state file is writable. The read-only routes `/health`, `/status`, `/next` and `/logs` stay available (no secrets in the output).
|
|
175
|
+
* Every HTTP error carries a stable `code` (prefix `WATCHDOG_`) next to the short `error` string scripts already parse: [docs/ERRORS.md](docs/ERRORS.md).
|
|
176
|
+
|
|
145
177
|
## Troubleshooting
|
|
146
178
|
|
|
147
179
|
| Symptom | Likely cause |
|
package/docs/ERRORS.md
ADDED
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
# Error codes: Idle Watchdog
|
|
2
|
+
|
|
3
|
+
Every HTTP error body from `/dsh-idle-watchdog/api` has this shape:
|
|
4
|
+
|
|
5
|
+
```json
|
|
6
|
+
{ "ok": false, "error": "invalid-secret", "code": "WATCHDOG_SECRET_INVALID",
|
|
7
|
+
"message": "The presented secret does not match", "hint": "...", "docs": "docs/ERRORS.md#watchdog_secret_invalid" }
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
`error` keeps the short string that scripts already parse (it never changed when codes were added), `code` is the stable identifier, `docs` is relative to the package root. Some errors add fields: `retryAfterMs` (rate limits), `ref` (not found), `candidates` (ambiguous), `detail`. Log lines start with the code, so `grep WATCHDOG_` finds them. The plugin has no agent tools; the codes appear on HTTP routes and in the log.
|
|
11
|
+
|
|
12
|
+
Read-only diagnostics: `GET /dsh-idle-watchdog/api/health`, `/status`, `/next`, `/chats`, `/logs`. The one-call self-check is `GET /dsh-idle-watchdog/api/doctor`; its failing rows carry these codes.
|
|
13
|
+
|
|
14
|
+
Start here when you have a symptom instead of a code: [TROUBLESHOOTING.md](TROUBLESHOOTING.md#start-here).
|
|
15
|
+
|
|
16
|
+
| Code | HTTP | Where it appears | Meaning | Agent action |
|
|
17
|
+
|---|---|---|---|---|
|
|
18
|
+
| WATCHDOG_SECRET_NOT_CONFIGURED | 503 | route POST /dsh-idle-watchdog/api/prompt | The API has no secret from any source and fails closed. | `GET /dsh-idle-watchdog/api/status` and read `secretSource` (`none` confirms it), `envSecretPresent` and `secretFile`. ([details](#watchdog_secret_not_configured)) |
|
|
19
|
+
| WATCHDOG_SECRET_INVALID | 401 | route POST /dsh-idle-watchdog/api/prompt, log (ledger entry `prompt-rejected`, reason `bad-secret`) | The presented secret differs from the configured one. | `GET /status`: compare `secretSource` (env, file, settings) with what the caller uses. ([details](#watchdog_secret_invalid)) |
|
|
20
|
+
| WATCHDOG_AUTH_THROTTLED | 429 | route POST /dsh-idle-watchdog/api/prompt | Ten wrong secrets in a minute from one address; the address is paused. | Wait the seconds in the `retry-after` header (`retryAfterMs` in the body). ([details](#watchdog_auth_throttled)) |
|
|
21
|
+
| WATCHDOG_RATE_LIMITED | 429 | route POST /dsh-idle-watchdog/api/prompt | More prompt calls per minute from one address than `api.rateLimitPerMinute` (default 30). | Wait for `retry-after`; batch messages or add a delay in the caller. ([details](#watchdog_rate_limited)) |
|
|
22
|
+
| WATCHDOG_PROMPT_INVALID | 400 | route POST /dsh-idle-watchdog/api/prompt | `chat` or `message` is missing or empty after trimming. | Send `{"chat":"<id, prefix or title>","message":"text"}` with `content-type: application/json`. ([details](#watchdog_prompt_invalid)) |
|
|
23
|
+
| WATCHDOG_CHAT_NOT_FOUND | 404 | route POST /dsh-idle-watchdog/api/prompt | The reference matches no chat (also a cold id the host does not know). | `GET /dsh-idle-watchdog/api/chats?refresh` lists sessions with ids, titles and live flags. ([details](#watchdog_chat_not_found)) |
|
|
24
|
+
| WATCHDOG_CHAT_AMBIGUOUS | 409 | route POST /dsh-idle-watchdog/api/prompt | A prefix or title matches several chats; `candidates` lists up to 5. | Pick one id from `candidates` and send it in full. ([details](#watchdog_chat_ambiguous)) |
|
|
25
|
+
| WATCHDOG_CHAT_NOT_LIVE | 409 | route POST /dsh-idle-watchdog/api/prompt | The chat is not loaded and `wakeColdForApi` is off. | Enable `wakeColdForApi` in Settings (live), or open the chat in the web UI so it is loaded, then retry. ([details](#watchdog_chat_not_live)) |
|
|
26
|
+
| WATCHDOG_RESOLVER_UNAVAILABLE | 409 | route POST /dsh-idle-watchdog/api/prompt | The host has no session controller to wake a cold chat. Answered with the legacy string `chat-not-live`. | Open the chat in the UI so it is live, then retry. ([details](#watchdog_resolver_unavailable)) |
|
|
27
|
+
| WATCHDOG_CHAT_NOT_RESOLVABLE | 409 | route POST /dsh-idle-watchdog/api/prompt | The host knows the chat but could not load it; `detail` carries the host reason. | Open the chat in the web UI; if it does not load there either, the session itself is the problem. ([details](#watchdog_chat_not_resolvable)) |
|
|
28
|
+
| WATCHDOG_CHAT_SUBAGENT_OWNED | 403 | route POST /dsh-idle-watchdog/api/prompt | The chat is a child session owned by a subagent. | Address the parent chat. Child sessions are not addressable by design. ([details](#watchdog_chat_subagent_owned)) |
|
|
29
|
+
| WATCHDOG_RESOLVE_FAILED | 500 | route POST /dsh-idle-watchdog/api/prompt, ledger entry `prompt-resolve-failed` | The host threw an unexpected error while loading the chat. | `GET /logs` and find `prompt-resolve-failed` with its message. ([details](#watchdog_resolve_failed)) |
|
|
30
|
+
| WATCHDOG_FOLLOWUP_FAILED | 500 | route POST /dsh-idle-watchdog/api/prompt, ledger entry `prompt-failed` | The chat resolved but queueing the message threw. | `GET /logs` for `prompt-failed` and its message; retry once. ([details](#watchdog_followup_failed)) |
|
|
31
|
+
| WATCHDOG_CSRF_GUARD | 403 | route PUT /dsh-idle-watchdog/api/settings, route POST /dsh-idle-watchdog/api/secret | Browser-only routes need the UI request shape. | Send both headers (see the troubleshooting entry). The prompt route is for scripts and needs neither. ([details](#watchdog_csrf_guard)) |
|
|
32
|
+
| WATCHDOG_SETTINGS_EMPTY | 400 | route PUT /dsh-idle-watchdog/api/settings | After validation the patch has no setting left. | Send known keys within limits (README settings table); check spelling and types. ([details](#watchdog_settings_empty)) |
|
|
33
|
+
| WATCHDOG_SECRET_LENGTH | 400 | route POST /dsh-idle-watchdog/api/secret | The secret is shorter than 16 or longer than 256 characters. | Use 16 to 256 characters; a long random value is best. ([details](#watchdog_secret_length)) |
|
|
34
|
+
| WATCHDOG_ROUTE_NOT_FOUND | 404 | route any other path or method under /dsh-idle-watchdog/api | The plugin is loaded but does not serve that path and method. | Use GET `health`, `status`, `next`, `chats`, `logs`; PUT `settings`; POST `secret`, `prompt`. ([details](#watchdog_route_not_found)) |
|
|
35
|
+
| WATCHDOG_BODY_TOO_LARGE | 400 | route POST /prompt, PUT /settings, POST /secret | The body is above 64 KiB. | Shorten it; a prompt message is limited to 8000 characters anyway. ([details](#watchdog_body_too_large)) |
|
|
36
|
+
| WATCHDOG_BODY_INVALID | 400 | route POST /prompt, PUT /settings, POST /secret | The body is not valid JSON; `error` carries the parser message. | Build the body with a tool (`node -e`, `jq -n`) instead of hand quoting, and send `content-type: application/json`. ([details](#watchdog_body_invalid)) |
|
|
37
|
+
| WATCHDOG_INTERNAL | 400 | any route (answered with status 400 for compatibility), log | An unexpected exception inside a route. | Find the log line starting with `WATCHDOG_INTERNAL` in the `dsh web` log, and `GET /logs`. ([details](#watchdog_internal)) |
|
|
38
|
+
| WATCHDOG_INIT_FAILED | n/a | log | Loading saved state or the fallback settings file failed at start. | Read the file named in the line; a missing `settings.json` is no longer reported with this code. ([details](#watchdog_init_failed)) |
|
|
39
|
+
| WATCHDOG_TICK_FAILED | n/a | log | The idle scan or a session event handler threw; the next scan continues. | Read the line (it names the chat or handler). One occurrence is noise; a line on every scan means report a bug. ([details](#watchdog_tick_failed)) |
|
|
40
|
+
| WATCHDOG_STATE_WRITE_FAILED | n/a | log | Saving the nudge counters to `state.json` failed. | Check `df` and `ls -ld` on `${DSH_HOME:-$HOME/.dsh}/idle-watchdog`. Nudging continues; after a restart the counters start from zero. ([details](#watchdog_state_write_failed)) |
|
|
41
|
+
|
|
42
|
+
### WATCHDOG_SECRET_NOT_CONFIGURED
|
|
43
|
+
- **Meaning:** The API has no secret from any source and fails closed.
|
|
44
|
+
- **Where:** route POST /dsh-idle-watchdog/api/prompt. Legacy `error` string: `secret-not-configured`.
|
|
45
|
+
- **Likely causes:**
|
|
46
|
+
1. No secret was ever saved and env `DSH_IDLE_WATCHDOG_SECRET` is not set in the `dsh web` process.
|
|
47
|
+
2. The secret file is empty, missing, or its path override `DSH_IDLE_WATCHDOG_SECRET_FILE` points elsewhere.
|
|
48
|
+
3. After an upgrade to DSH 0.2.x the old secret only lived in `settings.yaml`, which was renamed to `settings.yaml.imported`, and it was never moved to the file.
|
|
49
|
+
- **Agent action:**
|
|
50
|
+
1. `GET /dsh-idle-watchdog/api/status` and read `secretSource` (`none` confirms it), `envSecretPresent` and `secretFile`.
|
|
51
|
+
2. Check the file exists with mode 0600: `ls -l "${DSH_HOME:-$HOME/.dsh}/idle-watchdog/api-secret"`.
|
|
52
|
+
3. Fix: save a secret in Settings, Idle Watchdog (writes the file), or create the file yourself (see the troubleshooting entry).
|
|
53
|
+
- **Needs the human:** Yes if a secret must be chosen or an environment variable of the `dsh web` service changed.
|
|
54
|
+
- **Troubleshooting:** [entry](TROUBLESHOOTING.md#t-secret)
|
|
55
|
+
|
|
56
|
+
### WATCHDOG_SECRET_INVALID
|
|
57
|
+
- **Meaning:** The presented secret differs from the configured one.
|
|
58
|
+
- **Where:** route POST /dsh-idle-watchdog/api/prompt, log (ledger entry `prompt-rejected`, reason `bad-secret`). Legacy `error` string: `invalid-secret`.
|
|
59
|
+
- **Likely causes:**
|
|
60
|
+
1. The caller reads an old source (for example `settings.yaml`, gone on DSH 0.2.x) or a stale copy.
|
|
61
|
+
2. Env `DSH_IDLE_WATCHDOG_SECRET` is set in the `dsh web` process and wins over the file, but the caller reads the file.
|
|
62
|
+
3. The secret was rotated; a file change is picked up within about 5 seconds, an env change needs a restart.
|
|
63
|
+
4. A trailing newline or quote ended up in the header value.
|
|
64
|
+
- **Agent action:**
|
|
65
|
+
1. `GET /status`: compare `secretSource` (env, file, settings) with what the caller uses.
|
|
66
|
+
2. Probe without sending a message: POST `{"chat":"","message":""}` with the secret; `400` (`WATCHDOG_PROMPT_INVALID`) means the secret was accepted.
|
|
67
|
+
3. Make the caller read the source that wins (see the troubleshooting entry). Never print the secret.
|
|
68
|
+
- **Needs the human:** No, unless the secret itself must be rotated or an environment variable changed.
|
|
69
|
+
- **Troubleshooting:** [entry](TROUBLESHOOTING.md#t-secret)
|
|
70
|
+
|
|
71
|
+
### WATCHDOG_AUTH_THROTTLED
|
|
72
|
+
- **Meaning:** Ten wrong secrets in a minute from one address; the address is paused.
|
|
73
|
+
- **Where:** route POST /dsh-idle-watchdog/api/prompt. Legacy `error` string: `rate-limited`.
|
|
74
|
+
- **Likely causes:**
|
|
75
|
+
1. A script or cron job keeps sending a wrong or missing secret.
|
|
76
|
+
2. Several scripts share one address and one of them is misconfigured.
|
|
77
|
+
- **Agent action:**
|
|
78
|
+
1. Wait the seconds in the `retry-after` header (`retryAfterMs` in the body).
|
|
79
|
+
2. Fix the caller first (code `WATCHDOG_SECRET_INVALID`), otherwise it throttles itself again.
|
|
80
|
+
3. The budget is per source address and fixed; it is not a setting.
|
|
81
|
+
- **Needs the human:** No.
|
|
82
|
+
- **Troubleshooting:** [entry](TROUBLESHOOTING.md#t-rate-limited)
|
|
83
|
+
|
|
84
|
+
### WATCHDOG_RATE_LIMITED
|
|
85
|
+
- **Meaning:** More prompt calls per minute from one address than `api.rateLimitPerMinute` (default 30).
|
|
86
|
+
- **Where:** route POST /dsh-idle-watchdog/api/prompt. Legacy `error` string: `rate-limited`.
|
|
87
|
+
- **Likely causes:**
|
|
88
|
+
1. A loop or burst of webhook deliveries.
|
|
89
|
+
2. The limit was lowered in Settings.
|
|
90
|
+
- **Agent action:**
|
|
91
|
+
1. Wait for `retry-after`; batch messages or add a delay in the caller.
|
|
92
|
+
2. To allow more: raise `api.rateLimitPerMinute` (1 to 600) in Settings.
|
|
93
|
+
- **Needs the human:** Only to raise the limit if the caller cannot slow down.
|
|
94
|
+
- **Troubleshooting:** [entry](TROUBLESHOOTING.md#t-rate-limited)
|
|
95
|
+
|
|
96
|
+
### WATCHDOG_PROMPT_INVALID
|
|
97
|
+
- **Meaning:** `chat` or `message` is missing or empty after trimming.
|
|
98
|
+
- **Where:** route POST /dsh-idle-watchdog/api/prompt. Legacy `error` string: `chat and non-empty message are required`.
|
|
99
|
+
- **Likely causes:**
|
|
100
|
+
1. The JSON field names are wrong (`chat`, `message`).
|
|
101
|
+
2. Shell quoting produced an empty value.
|
|
102
|
+
3. The message is empty or only whitespace.
|
|
103
|
+
- **Agent action:**
|
|
104
|
+
1. Send `{"chat":"<id, prefix or title>","message":"text"}` with `content-type: application/json`.
|
|
105
|
+
- **Needs the human:** No.
|
|
106
|
+
- **Troubleshooting:** [entry](TROUBLESHOOTING.md#t-prompt-chat)
|
|
107
|
+
|
|
108
|
+
### WATCHDOG_CHAT_NOT_FOUND
|
|
109
|
+
- **Meaning:** The reference matches no chat (also a cold id the host does not know).
|
|
110
|
+
- **Where:** route POST /dsh-idle-watchdog/api/prompt. Legacy `error` string: `chat-not-found`.
|
|
111
|
+
- **Likely causes:**
|
|
112
|
+
1. Typo, or a title that is not an exact match (case is ignored, spelling is not).
|
|
113
|
+
2. An id prefix shorter than 6 characters, or a prefix of a chat that is neither live nor in the watched list.
|
|
114
|
+
3. The chat title is not known to the plugin catalog yet (it refreshes about every 15 seconds).
|
|
115
|
+
4. The chat was deleted.
|
|
116
|
+
- **Agent action:**
|
|
117
|
+
1. `GET /dsh-idle-watchdog/api/chats?refresh` lists sessions with ids, titles and live flags.
|
|
118
|
+
2. Retry with the full session id.
|
|
119
|
+
- **Needs the human:** No.
|
|
120
|
+
- **Troubleshooting:** [entry](TROUBLESHOOTING.md#t-prompt-chat)
|
|
121
|
+
|
|
122
|
+
### WATCHDOG_CHAT_AMBIGUOUS
|
|
123
|
+
- **Meaning:** A prefix or title matches several chats; `candidates` lists up to 5.
|
|
124
|
+
- **Where:** route POST /dsh-idle-watchdog/api/prompt. Legacy `error` string: `ambiguous-chat`.
|
|
125
|
+
- **Likely causes:**
|
|
126
|
+
1. Two chats share a title, or an id prefix is too short.
|
|
127
|
+
- **Agent action:**
|
|
128
|
+
1. Pick one id from `candidates` and send it in full.
|
|
129
|
+
- **Needs the human:** No.
|
|
130
|
+
- **Troubleshooting:** [entry](TROUBLESHOOTING.md#t-prompt-chat)
|
|
131
|
+
|
|
132
|
+
### WATCHDOG_CHAT_NOT_LIVE
|
|
133
|
+
- **Meaning:** The chat is not loaded and `wakeColdForApi` is off.
|
|
134
|
+
- **Where:** route POST /dsh-idle-watchdog/api/prompt. Legacy `error` string: `chat-not-live`.
|
|
135
|
+
- **Likely causes:**
|
|
136
|
+
1. The setting `wakeColdForApi` was switched off (default is on).
|
|
137
|
+
- **Agent action:**
|
|
138
|
+
1. Enable `wakeColdForApi` in Settings (live), or open the chat in the web UI so it is loaded, then retry.
|
|
139
|
+
- **Needs the human:** Only the decision whether API calls may wake cold chats.
|
|
140
|
+
- **Troubleshooting:** [entry](TROUBLESHOOTING.md#t-prompt-chat)
|
|
141
|
+
|
|
142
|
+
### WATCHDOG_RESOLVER_UNAVAILABLE
|
|
143
|
+
- **Meaning:** The host has no session controller to wake a cold chat. Answered with the legacy string `chat-not-live`.
|
|
144
|
+
- **Where:** route POST /dsh-idle-watchdog/api/prompt. Legacy `error` string: `chat-not-live`.
|
|
145
|
+
- **Likely causes:**
|
|
146
|
+
1. The running `dsh web` is an older or different build without the session controller service.
|
|
147
|
+
2. The server half was updated but `dsh web` was not restarted.
|
|
148
|
+
- **Agent action:**
|
|
149
|
+
1. Open the chat in the UI so it is live, then retry.
|
|
150
|
+
2. Compare `GET /health` `version` with the installed package version; a mismatch means a restart is pending.
|
|
151
|
+
- **Needs the human:** Yes, a restart of `dsh web` if the build is current but the service is missing.
|
|
152
|
+
- **Troubleshooting:** [entry](TROUBLESHOOTING.md#t-prompt-chat)
|
|
153
|
+
|
|
154
|
+
### WATCHDOG_CHAT_NOT_RESOLVABLE
|
|
155
|
+
- **Meaning:** The host knows the chat but could not load it; `detail` carries the host reason.
|
|
156
|
+
- **Where:** route POST /dsh-idle-watchdog/api/prompt. Legacy `error` string: `chat-not-resolvable`.
|
|
157
|
+
- **Likely causes:**
|
|
158
|
+
1. The stored session cannot be opened (format, lock, or it is being deleted).
|
|
159
|
+
2. The host refused to resume it.
|
|
160
|
+
- **Agent action:**
|
|
161
|
+
1. Open the chat in the web UI; if it does not load there either, the session itself is the problem.
|
|
162
|
+
2. Retry through the API after it loads.
|
|
163
|
+
- **Needs the human:** Yes if the session is damaged.
|
|
164
|
+
- **Troubleshooting:** [entry](TROUBLESHOOTING.md#t-prompt-chat)
|
|
165
|
+
|
|
166
|
+
### WATCHDOG_CHAT_SUBAGENT_OWNED
|
|
167
|
+
- **Meaning:** The chat is a child session owned by a subagent.
|
|
168
|
+
- **Where:** route POST /dsh-idle-watchdog/api/prompt. Legacy `error` string: `subagent-owned`.
|
|
169
|
+
- **Likely causes:**
|
|
170
|
+
1. The id belongs to a subagent run, not to a top-level chat.
|
|
171
|
+
- **Agent action:**
|
|
172
|
+
1. Address the parent chat. Child sessions are not addressable by design.
|
|
173
|
+
- **Needs the human:** No.
|
|
174
|
+
- **Troubleshooting:** [entry](TROUBLESHOOTING.md#t-prompt-chat)
|
|
175
|
+
|
|
176
|
+
### WATCHDOG_RESOLVE_FAILED
|
|
177
|
+
- **Meaning:** The host threw an unexpected error while loading the chat.
|
|
178
|
+
- **Where:** route POST /dsh-idle-watchdog/api/prompt, ledger entry `prompt-resolve-failed`. Legacy `error` string: `resolve-failed`.
|
|
179
|
+
- **Likely causes:**
|
|
180
|
+
1. A host side failure while resuming the session.
|
|
181
|
+
- **Agent action:**
|
|
182
|
+
1. `GET /logs` and find `prompt-resolve-failed` with its message.
|
|
183
|
+
2. Retry once; if it repeats, collect the entry and report a bug.
|
|
184
|
+
- **Needs the human:** No.
|
|
185
|
+
- **Troubleshooting:** [entry](TROUBLESHOOTING.md#t-prompt-chat)
|
|
186
|
+
|
|
187
|
+
### WATCHDOG_FOLLOWUP_FAILED
|
|
188
|
+
- **Meaning:** The chat resolved but queueing the message threw.
|
|
189
|
+
- **Where:** route POST /dsh-idle-watchdog/api/prompt, ledger entry `prompt-failed`. Legacy `error` string: `followup-failed`.
|
|
190
|
+
- **Likely causes:**
|
|
191
|
+
1. The agent was disposed between resolve and delivery.
|
|
192
|
+
2. A host side error.
|
|
193
|
+
- **Agent action:**
|
|
194
|
+
1. `GET /logs` for `prompt-failed` and its message; retry once.
|
|
195
|
+
- **Needs the human:** No.
|
|
196
|
+
- **Troubleshooting:** [entry](TROUBLESHOOTING.md#t-prompt-chat)
|
|
197
|
+
|
|
198
|
+
### WATCHDOG_CSRF_GUARD
|
|
199
|
+
- **Meaning:** Browser-only routes need the UI request shape.
|
|
200
|
+
- **Where:** route PUT /dsh-idle-watchdog/api/settings, route POST /dsh-idle-watchdog/api/secret. Legacy `error` string: `csrf-guard`.
|
|
201
|
+
- **Likely causes:**
|
|
202
|
+
1. A script calls a settings route without header `X-Requested-With: dsh-idle-watchdog` or without `Content-Type: application/json`.
|
|
203
|
+
- **Agent action:**
|
|
204
|
+
1. Send both headers (see the troubleshooting entry). The prompt route is for scripts and needs neither.
|
|
205
|
+
- **Needs the human:** No.
|
|
206
|
+
- **Troubleshooting:** [entry](TROUBLESHOOTING.md#t-csrf-guard)
|
|
207
|
+
|
|
208
|
+
### WATCHDOG_SETTINGS_EMPTY
|
|
209
|
+
- **Meaning:** After validation the patch has no setting left.
|
|
210
|
+
- **Where:** route PUT /dsh-idle-watchdog/api/settings. Legacy `error` string: `no-valid-settings-in-body`.
|
|
211
|
+
- **Likely causes:**
|
|
212
|
+
1. Unknown key names, wrong types, or values out of range were all dropped.
|
|
213
|
+
- **Agent action:**
|
|
214
|
+
1. Send known keys within limits (README settings table); check spelling and types.
|
|
215
|
+
- **Needs the human:** No.
|
|
216
|
+
- **Troubleshooting:** [entry](TROUBLESHOOTING.md#t-settings-not-saved)
|
|
217
|
+
|
|
218
|
+
### WATCHDOG_SECRET_LENGTH
|
|
219
|
+
- **Meaning:** The secret is shorter than 16 or longer than 256 characters.
|
|
220
|
+
- **Where:** route POST /dsh-idle-watchdog/api/secret. Legacy `error` string: `secret must be 16..256 characters`.
|
|
221
|
+
- **Likely causes:**
|
|
222
|
+
1. Too short or too long a secret was submitted.
|
|
223
|
+
- **Agent action:**
|
|
224
|
+
1. Use 16 to 256 characters; a long random value is best.
|
|
225
|
+
- **Needs the human:** No.
|
|
226
|
+
- **Troubleshooting:** [entry](TROUBLESHOOTING.md#t-secret)
|
|
227
|
+
|
|
228
|
+
### WATCHDOG_ROUTE_NOT_FOUND
|
|
229
|
+
- **Meaning:** The plugin is loaded but does not serve that path and method.
|
|
230
|
+
- **Where:** route any other path or method under /dsh-idle-watchdog/api. Legacy `error` string: `not-found`.
|
|
231
|
+
- **Likely causes:**
|
|
232
|
+
1. Typo in the path, wrong method (for example GET on /prompt), or a feature of a newer version (the `/api/doctor` route needs plugin 1.2.0 with the doctor commit).
|
|
233
|
+
- **Agent action:**
|
|
234
|
+
1. Use GET `health`, `status`, `next`, `chats`, `logs`; PUT `settings`; POST `secret`, `prompt`.
|
|
235
|
+
2. A 404 on every path (no JSON body) means the plugin is not loaded: see the troubleshooting entry.
|
|
236
|
+
- **Needs the human:** No.
|
|
237
|
+
- **Troubleshooting:** [entry](TROUBLESHOOTING.md#t-route-404)
|
|
238
|
+
|
|
239
|
+
### WATCHDOG_BODY_TOO_LARGE
|
|
240
|
+
- **Meaning:** The body is above 64 KiB.
|
|
241
|
+
- **Where:** route POST /prompt, PUT /settings, POST /secret. Legacy `error` string: `request body too large`.
|
|
242
|
+
- **Likely causes:**
|
|
243
|
+
1. A very long message or a huge settings patch.
|
|
244
|
+
- **Agent action:**
|
|
245
|
+
1. Shorten it; a prompt message is limited to 8000 characters anyway.
|
|
246
|
+
- **Needs the human:** No.
|
|
247
|
+
- **Troubleshooting:** [entry](TROUBLESHOOTING.md#t-prompt-chat)
|
|
248
|
+
|
|
249
|
+
### WATCHDOG_BODY_INVALID
|
|
250
|
+
- **Meaning:** The body is not valid JSON; `error` carries the parser message.
|
|
251
|
+
- **Where:** route POST /prompt, PUT /settings, POST /secret.
|
|
252
|
+
- **Likely causes:**
|
|
253
|
+
1. Shell quoting broke the JSON.
|
|
254
|
+
2. Wrong content, for example form encoding.
|
|
255
|
+
- **Agent action:**
|
|
256
|
+
1. Build the body with a tool (`node -e`, `jq -n`) instead of hand quoting, and send `content-type: application/json`.
|
|
257
|
+
- **Needs the human:** No.
|
|
258
|
+
- **Troubleshooting:** [entry](TROUBLESHOOTING.md#t-prompt-chat)
|
|
259
|
+
|
|
260
|
+
### WATCHDOG_INTERNAL
|
|
261
|
+
- **Meaning:** An unexpected exception inside a route.
|
|
262
|
+
- **Where:** any route (answered with status 400 for compatibility), log.
|
|
263
|
+
- **Likely causes:**
|
|
264
|
+
1. A bug, or a disk error writing the secret file or the settings.
|
|
265
|
+
- **Agent action:**
|
|
266
|
+
1. Find the log line starting with `WATCHDOG_INTERNAL` in the `dsh web` log, and `GET /logs`.
|
|
267
|
+
2. Check disk space and the permissions of the plugin data directory, then retry once; report a bug with the line.
|
|
268
|
+
- **Needs the human:** Only to report the bug.
|
|
269
|
+
- **Troubleshooting:** [entry](TROUBLESHOOTING.md#t-start-here)
|
|
270
|
+
|
|
271
|
+
### WATCHDOG_INIT_FAILED
|
|
272
|
+
- **Meaning:** Loading saved state or the fallback settings file failed at start.
|
|
273
|
+
- **Where:** log.
|
|
274
|
+
- **Likely causes:**
|
|
275
|
+
1. A corrupt `state.json` or `settings.json`, or wrong file permissions.
|
|
276
|
+
2. An unexpected crash in the start-up loader (the line says `init crashed` and carries a stack).
|
|
277
|
+
A missing `settings.json` on a fresh install is not an error any more: the plugin logs the info line `init: no fallback settings.json yet (fresh install), nothing to load` without a code.
|
|
278
|
+
- **Agent action:**
|
|
279
|
+
1. If the line is the info line about a missing `settings.json`, it carries no code and needs no action.
|
|
280
|
+
2. Otherwise move the named file aside (`mv file file.bad-$(date +%Y%m%d)`), never delete, and restart when convenient.
|
|
281
|
+
- **Needs the human:** Yes for the restart.
|
|
282
|
+
- **Troubleshooting:** [entry](TROUBLESHOOTING.md#t-settings-not-saved)
|
|
283
|
+
|
|
284
|
+
### WATCHDOG_TICK_FAILED
|
|
285
|
+
- **Meaning:** The idle scan or a session event handler threw; the next scan continues.
|
|
286
|
+
- **Where:** log.
|
|
287
|
+
- **Likely causes:**
|
|
288
|
+
1. A host event had an unexpected shape, or one chat failed while being evaluated.
|
|
289
|
+
- **Agent action:**
|
|
290
|
+
1. Read the line (it names the chat or handler). One occurrence is noise; a line on every scan means report a bug.
|
|
291
|
+
- **Needs the human:** No.
|
|
292
|
+
- **Troubleshooting:** [entry](TROUBLESHOOTING.md#t-no-nudges)
|
|
293
|
+
|
|
294
|
+
### WATCHDOG_STATE_WRITE_FAILED
|
|
295
|
+
- **Meaning:** Saving the nudge counters to `state.json` failed.
|
|
296
|
+
- **Where:** log.
|
|
297
|
+
- **Likely causes:**
|
|
298
|
+
1. Disk full, or the data directory is not writable by the `dsh web` user.
|
|
299
|
+
- **Agent action:**
|
|
300
|
+
1. Check `df` and `ls -ld` on `${DSH_HOME:-$HOME/.dsh}/idle-watchdog`. Nudging continues; after a restart the counters start from zero.
|
|
301
|
+
- **Needs the human:** Yes if permissions or disk space need an administrator.
|
|
302
|
+
- **Troubleshooting:** [entry](TROUBLESHOOTING.md#t-start-here)
|