@maolon/pi-watcher 0.0.0-stage → 0.1.1

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.
Files changed (72) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/LICENSE +21 -0
  3. package/README.md +255 -2
  4. package/dist/cli.d.ts +8 -0
  5. package/dist/cli.js +369 -0
  6. package/dist/contracts/interfaces.d.ts +262 -0
  7. package/dist/contracts/interfaces.js +1 -0
  8. package/dist/contracts/policy-defaults.json +61 -0
  9. package/dist/contracts/relay-next.interfaces.d.ts +160 -0
  10. package/dist/contracts/relay-next.interfaces.js +1 -0
  11. package/dist/engine/cards.d.ts +68 -0
  12. package/dist/engine/cards.js +76 -0
  13. package/dist/engine/engine.d.ts +178 -0
  14. package/dist/engine/engine.js +1162 -0
  15. package/dist/engine/hard-rules.d.ts +53 -0
  16. package/dist/engine/hard-rules.js +96 -0
  17. package/dist/engine/semantic.d.ts +49 -0
  18. package/dist/engine/semantic.js +125 -0
  19. package/dist/engine/service.d.ts +62 -0
  20. package/dist/engine/service.js +587 -0
  21. package/dist/engine/tool-actions.d.ts +35 -0
  22. package/dist/engine/tool-actions.js +348 -0
  23. package/dist/engine/widget.d.ts +29 -0
  24. package/dist/engine/widget.js +52 -0
  25. package/dist/ipc/client.d.ts +26 -0
  26. package/dist/ipc/client.js +106 -0
  27. package/dist/ipc/server.d.ts +78 -0
  28. package/dist/ipc/server.js +105 -0
  29. package/dist/jev/client.d.ts +38 -0
  30. package/dist/jev/client.js +239 -0
  31. package/dist/jev/consent.d.ts +12 -0
  32. package/dist/jev/consent.js +37 -0
  33. package/dist/jev/index.d.ts +9 -0
  34. package/dist/jev/index.js +9 -0
  35. package/dist/jev/mock.d.ts +30 -0
  36. package/dist/jev/mock.js +77 -0
  37. package/dist/jev/pi-registry.d.ts +66 -0
  38. package/dist/jev/pi-registry.js +127 -0
  39. package/dist/jev/questions.d.ts +15 -0
  40. package/dist/jev/questions.js +76 -0
  41. package/dist/jev/sanitizer.d.ts +10 -0
  42. package/dist/jev/sanitizer.js +59 -0
  43. package/dist/jev/types.d.ts +78 -0
  44. package/dist/jev/types.js +54 -0
  45. package/dist/pi-extension.d.ts +123 -0
  46. package/dist/pi-extension.js +687 -0
  47. package/dist/relay/managed.d.ts +120 -0
  48. package/dist/relay/managed.js +482 -0
  49. package/dist/relay/negotiate.d.ts +39 -0
  50. package/dist/relay/negotiate.js +112 -0
  51. package/dist/runtime.d.ts +74 -0
  52. package/dist/runtime.js +246 -0
  53. package/dist/source/agent-check/adapter.d.ts +57 -0
  54. package/dist/source/agent-check/adapter.js +224 -0
  55. package/dist/source/agent-file/adapter.d.ts +57 -0
  56. package/dist/source/agent-file/adapter.js +217 -0
  57. package/dist/source/task-status-v1/adapter.d.ts +36 -0
  58. package/dist/source/task-status-v1/adapter.js +263 -0
  59. package/dist/source/task-status-v1/producer.d.ts +81 -0
  60. package/dist/source/task-status-v1/producer.js +127 -0
  61. package/dist/storage/lock.d.ts +14 -0
  62. package/dist/storage/lock.js +66 -0
  63. package/dist/storage/schema.sql +166 -0
  64. package/dist/storage/store.d.ts +352 -0
  65. package/dist/storage/store.js +555 -0
  66. package/dist/util/clock.d.ts +23 -0
  67. package/dist/util/clock.js +34 -0
  68. package/dist/util/ids.d.ts +8 -0
  69. package/dist/util/ids.js +29 -0
  70. package/dist/util/result.d.ts +28 -0
  71. package/dist/util/result.js +54 -0
  72. package/package.json +101 -4
package/CHANGELOG.md ADDED
@@ -0,0 +1,23 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented here. The format follows
4
+ [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and the project uses
5
+ [Semantic Versioning](https://semver.org/). Before 1.0, minor versions may break.
6
+
7
+ ## [0.1.1] - 2026-10-08
8
+
9
+ ### Changed
10
+ - Released from CI through npm trusted publishing (OIDC), with provenance. No functional changes from 0.1.0.
11
+
12
+ ## [0.1.0] - 2026-10-08
13
+
14
+ First public release.
15
+
16
+ ### Added
17
+ - `watcher` tool with `watch-file`, `watch-check`, `register`, `list`, `inspect`, `check`, `pause` and `close`.
18
+ - `/watcher` command: status panel and local episode acknowledgement.
19
+ - Deterministic hard rules: explicit terminal states, business deadlines (raised once per checkpoint), silence detection and result cards.
20
+ - Optional semantic review via Jev (`semanticMode: shadow | active`). Credentials come from Pi's model registry (`/login` → TypeSafe, `TYPESAFE_API_KEY`, or another Jev provider) or `JEV_API_KEY`. Egress needs separate user consent: `/watcher jev consent on` or `JEV_CONSENT=1`.
21
+ - `/watcher jev` status command.
22
+ - Relay-delivered wakes through `@maolon/pi-relay` managed delivery: one scope per watch, durable control outbox, withdraw on pause/close with per-route results, and an idempotent host-response pump.
23
+ - `pi-watcher` CLI: `doctor`, `qualify`, `relay-setup`, plus `producer`/`demo` fixtures.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Maolon
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,256 @@
1
- # Temporary Holding Version
1
+ # pi-watcher
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Watch long-running work from [Pi](https://pi.dev) without babysitting it. pi-watcher tracks builds, test runs,
4
+ training jobs, CI pipelines and deadlines from durable evidence. It keeps the session quiet while things progress
5
+ and wakes the session (through [pi-relay](https://github.com/Maolon/pi-relay)) only when a fact needs a decision.
6
+
7
+ ```bash
8
+ pi install npm:@maolon/pi-relay # wake transport (recommended, see "pi-relay" below)
9
+ pi install npm:@maolon/pi-watcher
10
+ ```
11
+
12
+ ## Why
13
+
14
+ An agent that waits on a long task usually polls: `sleep`, re-run a status command, repeat. Each check spends a
15
+ model turn and grows the context just to learn "still running". pi-watcher moves that loop out of the model:
16
+
17
+ - **Facts first.** Explicit terminal states, exit markers, deadlines and silence are decided by code, not by a model.
18
+ - **Quiet by default.** Routine progress only updates a status widget. Nothing enters the conversation.
19
+ - **Wake on decisions.** Failure, a crossed deadline, a ready dependency or (optionally) a semantic blocker
20
+ becomes one episode and one wake. The host then inspects the fresh facts and responds.
21
+ - **Honest state.** Unknown stays unknown. Delivery, withdrawal and completion are reported only with evidence.
22
+
23
+ ## How it works
24
+
25
+ ```
26
+ exec log / build output / CI status Pi session
27
+ │ ▲
28
+ watch-file │ watch-check │ wake (managed delivery)
29
+ ▼ │
30
+ pi-watcher engine ──► SQLite truth store ──► pi-relay ──► relay_respond ──► watcher applies the response
31
+ hard rules, deadlines, silence,
32
+ optional Jev semantic review
33
+ ```
34
+
35
+ Each Pi session runs its own watcher runtime with state under `<cwd>/.pi-watcher/sessions/<session-id>/`.
36
+ The watcher never runs, retries, kills or fixes the task it watches.
37
+
38
+ ## Requirements
39
+
40
+ - Pi 1.0 or newer (`@earendil-works/pi-coding-agent`); Jev through Pi's `/login` needs Pi 1.1+
41
+ - Node.js 22.16 or newer
42
+ - macOS or Linux. Windows is not supported.
43
+ - A native build toolchain for `fs-ext` (Python 3, `make`, a C++ compiler; on macOS the Xcode Command Line
44
+ Tools). `better-sqlite3` ships prebuilt binaries for common platforms. pi-relay has the same requirements.
45
+
46
+ ## Install
47
+
48
+ ```bash
49
+ pi install npm:@maolon/pi-relay
50
+ pi install npm:@maolon/pi-watcher
51
+ ```
52
+
53
+ Use `-l` to install into the current project (`.pi/settings.json`) instead of your personal settings, or try it
54
+ for one run with `pi -e npm:@maolon/pi-watcher`. Pin versions with `npm:@maolon/pi-watcher@0.1.0`.
55
+
56
+ Add the watcher's state directories to your project's `.gitignore`:
57
+
58
+ ```gitignore
59
+ .pi-watcher/
60
+ .pi-watcher-sources/
61
+ ```
62
+
63
+ ## pi-relay
64
+
65
+ pi-watcher uses [`@maolon/pi-relay`](https://www.npmjs.com/package/@maolon/pi-relay) in two different roles:
66
+
67
+ | Role | What it is | How you get it |
68
+ |---|---|---|
69
+ | **Library** | The watcher publishes attentions, withdraws them on pause/close and reads host responses through pi-relay's managed-delivery source API (`@maolon/pi-relay/source`, `/consumer`, `/protocol`). | A regular npm dependency of pi-watcher, installed automatically. |
70
+ | **Pi extension** | Runs inside your Pi session as the delivery target: receives the wake, injects it when the session is idle, and gives the model the `relay_respond` tool. | Install it yourself: `pi install npm:@maolon/pi-relay`. |
71
+
72
+ **Compatibility.** pi-watcher 0.1.x requires pi-relay **0.2.x**: the `^0.2.0` dependency for the library, and
73
+ 0.2.x for the extension you install. Both sides share the relay home on disk (`~/.pi/relay`, or `PI_RELAY_HOME`),
74
+ so keep them on the same minor version.
75
+
76
+ **Without the pi-relay extension**, the watcher still works, but in *local display* mode:
77
+
78
+ | | with pi-relay | without pi-relay |
79
+ |---|---|---|
80
+ | Watches, hard rules, deadlines, silence | yes | yes |
81
+ | Status widget and toasts in the session | yes | yes |
82
+ | Result cards, `inspect`, `/watcher` panel | yes | yes |
83
+ | Wake an idle session when a fact needs a decision | **yes** | no: you or the model must look |
84
+ | Host response loop (`relay_respond` → applied) | yes | no (`ack` returns `NO_DELIVERY`; use `/watcher ack`) |
85
+ | Withdraw pending wakes on `pause`/`close` | yes (per-route result) | nothing is in flight |
86
+
87
+ **Setup is automatic.** When the relay home exists, the watcher enables relay delivery. On session start it asks the
88
+ pi-relay extension in the same session for a local binding over Pi's event bus, then provisions its audience and
89
+ scope. No invite or manual step is needed. The binding is *local trust*: same machine, same OS user, no interactive
90
+ consent prompt. To opt out:
91
+
92
+ - `PI_WATCHER_RELAY=0`: never use relay (local display only).
93
+ - `PI_WATCHER_AUTO_BIND=0`: keep relay, but do not bind automatically. Use `pi-watcher relay-setup` instead.
94
+
95
+ **When a wake arrives**, the model is instructed to run `watcher inspect` for that watch first, act on the fresh
96
+ facts, and then answer with `relay_respond` (`received`, `investigating`, `defer`, `resolved` or `dismiss`). The
97
+ watcher applies the response to the episode, confirms the application back to the relay, and closes finished
98
+ watches shortly afterwards.
99
+
100
+ ## Usage
101
+
102
+ You normally just ask: *"run the test suite and tell me when it's done"*, *"watch the training run"*, *"keep an eye
103
+ on the CI for this PR"*. The tool guidelines steer the model to the `watcher` tool instead of polling.
104
+
105
+ ### Watch a file
106
+
107
+ Typical use: the log of a long `exec_command` session.
108
+
109
+ ```json
110
+ { "action": "watch-file", "path": "/tmp/build.log",
111
+ "okPattern": "__EXEC_EXIT__:0", "failPattern": "__EXEC_EXIT__:-?[1-9]",
112
+ "objective": "release build", "deadlineAt": "2026-10-08T18:00:00Z" }
113
+ ```
114
+
115
+ A terminal state is decided only by the declared patterns (fail is checked first). End of file, a quiet log or a
116
+ line that merely says "done" never counts as completion.
117
+
118
+ ### Watch a command
119
+
120
+ Use this for state you cannot tail: CI, cloud resources, remote health.
121
+
122
+ ```json
123
+ { "action": "watch-check", "cmd": "gh run view 123456 --json conclusion -q .conclusion",
124
+ "okPattern": "^success$", "failPattern": "^(failure|cancelled)$", "intervalMs": 60000 }
125
+ ```
126
+
127
+ The command runs on a fixed interval with a timeout (1–30 s). Exit codes 126/127 and timeouts mark the *monitor* as
128
+ degraded; they never mark the task as failed. The command text is stored as evidence, so never put secrets in it.
129
+
130
+ ### Other actions
131
+
132
+ | Action | Purpose |
133
+ |---|---|
134
+ | `list` | Active and paused watches (`includeClosed: true` for history) |
135
+ | `inspect` | Authoritative facts for one watch: state, episodes, health, delivery |
136
+ | `check` | Schedule one bounded refresh now (needs `expectedControlRevision`) |
137
+ | `pause` / `close` | Stop watching. Pending wakes are withdrawn; the result is reported per route. |
138
+ | `register` | Full spec: `run`, `group` (up to 16 members) and `obligation` targets |
139
+
140
+ `/watcher` shows the panel; `/watcher ack <episodeId> <received|investigating|defer|resolved|dismiss> [until]`
141
+ handles an episode locally; `/watcher jev` manages the optional semantic review (see below).
142
+
143
+ ### Exit markers for `exec_command`
144
+
145
+ To make shell-session outcomes decidable, the watcher appends `echo __EXEC_EXIT__:$?` to every `exec_command`
146
+ call. It creates no watch on its own. Disable it with `PI_WATCHER_EXEC_MARKER=0`. To have every long-running exec
147
+ session watched automatically, set `PI_WATCHER_AUTO_EXEC=1` (off by default).
148
+
149
+ ## Semantic review (Jev, optional)
150
+
151
+ **Optional and off by default.** pi-watcher works fully without it: every watch is decided by facts (patterns,
152
+ exit markers, deadlines, silence). Semantic review is an extra layer you opt into per watch.
153
+
154
+ Some tasks cannot be judged by patterns alone: a training run that stalls, a fix loop that keeps repeating, a log
155
+ that claims success while showing errors. With `semanticMode` set on a watch, the watcher asks
156
+ [Jev](https://typesafe.ai), TypeSafe's fast discriminative classifier (not a chat model), six bounded questions
157
+ about a sanitized evidence window: progress, unresolved blocker, needs host decision, repeating without new
158
+ information, claim vs evidence conflict, and context sufficiency.
159
+
160
+ - `off` (default): facts only.
161
+ - `shadow`: record judgments and show them as toasts and widget hints; never wake.
162
+ - `active`: a confident blocker, decision request, repeating loop or claim conflict opens an episode and can wake the session.
163
+
164
+ Enabling it takes two separate steps, because authentication and permission to send data are different decisions.
165
+
166
+ **1. Authenticate Jev through Pi** (Pi 1.1+ ships Jev as a classifier model). Use any one of these:
167
+
168
+ - In Pi, run `/login`, choose **Sign in with an API key**, then pick **TypeSafe** (or another provider that serves
169
+ Jev, such as OpenRouter or OpenCode). The credential lands in Pi's `auth.json` and the watcher picks it up,
170
+ even mid-session.
171
+ - `export TYPESAFE_API_KEY=...` (Pi's standard variable for TypeSafe).
172
+ - `export JEV_API_KEY=...` uses the watcher's own direct client, pinned to `jev-1.13.0`. It takes precedence over Pi's registry.
173
+
174
+ When several Jev providers are configured, the watcher prefers TypeSafe direct, then OpenRouter, OpenCode,
175
+ Cloudflare Workers AI and Vercel AI Gateway. Force one with `PI_WATCHER_JEV_MODEL=<provider>/<model>`, for example
176
+ `openrouter/typesafe/jev-1.13`. The model that actually answered is recorded with every judgment.
177
+
178
+ **2. Grant egress consent** (user only; the model cannot grant it):
179
+
180
+ ```
181
+ /watcher jev consent on # stored in ~/.pi/agent/pi-watcher.json; `off` revokes it
182
+ /watcher jev # shows the active Jev source and the consent state
183
+ ```
184
+
185
+ Alternatively set `JEV_CONSENT=1` (or `0` to force it off); the environment overrides the stored setting.
186
+
187
+ Without credentials, a watch with `semanticMode` shows "semantic review unavailable" with the reason, and the facts
188
+ keep working. Before anything is sent, credentials and tokens are redacted. Requests are budgeted per watch and
189
+ per day, and hard facts always win over model scores. Redaction is best effort: for sensitive repositories, leave
190
+ `semanticMode` off.
191
+
192
+ ## Configuration
193
+
194
+ | Variable | Default | Effect |
195
+ |---|---|---|
196
+ | `PI_RELAY_HOME` | `~/.pi/relay` | Relay home shared with the pi-relay extension |
197
+ | `PI_WATCHER_RELAY` | auto | `0` disables relay delivery |
198
+ | `PI_WATCHER_AUTO_BIND` | on | `0` disables automatic local binding |
199
+ | `PI_WATCHER_EXEC_MARKER` | on | `0` disables `__EXEC_EXIT__` injection |
200
+ | `PI_WATCHER_AUTO_EXEC` | off | `1` auto-watches long-running exec sessions |
201
+ | `TYPESAFE_API_KEY` | unset | Pi's TypeSafe credential; enables Jev through Pi (same as `/login` → TypeSafe) |
202
+ | `JEV_API_KEY` | unset | Watcher's direct Jev client (`jev-1.13.0`); takes precedence over Pi's registry |
203
+ | `PI_WATCHER_JEV_MODEL` | auto | Force a Pi Jev model, e.g. `openrouter/typesafe/jev-1.13` |
204
+ | `JEV_CONSENT` | unset | `1`/`0` overrides the stored `/watcher jev consent` setting |
205
+ | `PI_WATCHER_CONFIG` | `~/.pi/agent/pi-watcher.json` | Where `/watcher jev consent` is stored |
206
+ | `JEV_BASE_URL` | `https://api.typesafe.ai` | Endpoint for the direct client |
207
+ | `JEV_TIMEOUT_MS` | `10000` | Per-request timeout for the direct client |
208
+
209
+ ## Data and privacy
210
+
211
+ - All watcher state stays on your machine: SQLite (WAL, `synchronous=FULL`) under `<cwd>/.pi-watcher/`.
212
+ - Wakes travel through pi-relay's store under the relay home on the same machine.
213
+ - Shadow-mode judgments are shown as session toasts and widget hints, never as conversation messages.
214
+ - Only with Jev credentials **and** egress consent (`/watcher jev consent on` or `JEV_CONSENT=1`) does a sanitized,
215
+ size-bounded evidence window leave the machine, and only for watches with `semanticMode` set.
216
+ - `watch-file` reads the paths you or the model declare. `watch-check` runs the declared command as your user.
217
+ Both are as powerful as the session itself; review what the model registers.
218
+
219
+ ## CLI
220
+
221
+ The package also installs `pi-watcher`:
222
+
223
+ ```bash
224
+ pi-watcher doctor --root .pi-watcher # local diagnostics
225
+ pi-watcher relay-setup [--finalize] # manual relay owner setup (when auto-bind is off)
226
+ pi-watcher qualify # native dependency / storage qualification report
227
+ ```
228
+
229
+ ## Status
230
+
231
+ 0.1 is an early release. What is solid and what is not:
232
+
233
+ - **Solid:** fact-driven watches (`watch-file`, `watch-check`, task-status), deadlines, silence, result cards,
234
+ per-session isolation, relay wakes with withdraw-on-pause, idempotent host-response handling. Covered by the
235
+ offline suite, including end-to-end tests against the real pi-relay libraries.
236
+ - **Experimental:** semantic review thresholds are initial values, not calibrated results. Use `shadow` before `active`.
237
+ - **Not yet:** a standalone watcher service (the watcher runs inside the Pi session), an interactive consent prompt
238
+ for relay binding (it is local trust today), fork/tree-navigation holds, artifact-digest binding for checks,
239
+ evidence retention limits, and the `update` action.
240
+
241
+ ## Development
242
+
243
+ ```bash
244
+ npm install
245
+ npm run typecheck
246
+ npm run test:unit # offline suite
247
+ npm run build # dist/
248
+ npm run test:package # pack + leak scan + install + load with plain Node
249
+ ```
250
+
251
+ To load your working copy in Pi: `pi -e ./` from this directory after `npm run build`. See [AGENTS.md](AGENTS.md)
252
+ for conventions.
253
+
254
+ ## License
255
+
256
+ [MIT](LICENSE)
package/dist/cli.d.ts ADDED
@@ -0,0 +1,8 @@
1
+ /**
2
+ * pi-watcher CLI (design 11.2 shell entry point).
3
+ * - qualify: V0 qualification check, produces qualification.json (distinguishes candidate platforms from measured platforms)
4
+ * - doctor: local diagnostics (lock/DB/relay negotiation/panel summary)
5
+ * - producer: runs a real async task-status-v1 fixture producer
6
+ * - demo: V1 display-only end-to-end demo
7
+ */
8
+ export {};