@nocville/npc 0.0.0-stage → 0.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.
Files changed (210) hide show
  1. package/README.md +243 -2
  2. package/dist/cjs/cli.js +533 -0
  3. package/dist/cjs/core/api-key.js +69 -0
  4. package/dist/cjs/core/base-npc.js +160 -0
  5. package/dist/cjs/core/config.js +108 -0
  6. package/dist/cjs/core/event-npc.js +14 -0
  7. package/dist/cjs/core/logger.js +39 -0
  8. package/dist/cjs/core/polling-npc.js +65 -0
  9. package/dist/cjs/core/screen.js +28 -0
  10. package/dist/cjs/core/text.js +15 -0
  11. package/dist/cjs/core/thresholds.js +48 -0
  12. package/dist/cjs/core/types.js +10 -0
  13. package/dist/cjs/core/user-config.js +92 -0
  14. package/dist/cjs/doctor.js +130 -0
  15. package/dist/cjs/index.js +90 -0
  16. package/dist/cjs/npcs/agent-common/activity.js +291 -0
  17. package/dist/cjs/npcs/agent-common/git-stats.js +71 -0
  18. package/dist/cjs/npcs/agent-common/hook-runner.js +252 -0
  19. package/dist/cjs/npcs/agent-common/hook-settings.js +279 -0
  20. package/dist/cjs/npcs/agent-common/liveness.js +112 -0
  21. package/dist/cjs/npcs/agent-common/lock.js +99 -0
  22. package/dist/cjs/npcs/agent-common/runtime.js +154 -0
  23. package/dist/cjs/npcs/agent-common/session.js +390 -0
  24. package/dist/cjs/npcs/agent-common/shim.js +96 -0
  25. package/dist/cjs/npcs/agent-common/watchdog.js +149 -0
  26. package/dist/cjs/npcs/claude-code/defaults.js +20 -0
  27. package/dist/cjs/npcs/claude-code/hook-handler.js +139 -0
  28. package/dist/cjs/npcs/claude-code/index.js +104 -0
  29. package/dist/cjs/npcs/claude-code/setup.js +133 -0
  30. package/dist/cjs/npcs/claude-code/state-machine.js +130 -0
  31. package/dist/cjs/npcs/codex/defaults.js +32 -0
  32. package/dist/cjs/npcs/codex/hook-handler.js +116 -0
  33. package/dist/cjs/npcs/codex/index.js +92 -0
  34. package/dist/cjs/npcs/codex/rollout.js +246 -0
  35. package/dist/cjs/npcs/codex/setup.js +104 -0
  36. package/dist/cjs/npcs/codex/watcher.js +346 -0
  37. package/dist/cjs/npcs/cursor/defaults.js +15 -0
  38. package/dist/cjs/npcs/cursor/hook-handler.js +65 -0
  39. package/dist/cjs/npcs/cursor/index.js +72 -0
  40. package/dist/cjs/npcs/cursor/normalize.js +54 -0
  41. package/dist/cjs/npcs/cursor/setup.js +98 -0
  42. package/dist/cjs/npcs/gemini/defaults.js +15 -0
  43. package/dist/cjs/npcs/gemini/hook-handler.js +93 -0
  44. package/dist/cjs/npcs/gemini/index.js +69 -0
  45. package/dist/cjs/npcs/gemini/setup.js +98 -0
  46. package/dist/cjs/npcs/github-watcher/defaults.js +11 -0
  47. package/dist/cjs/npcs/github-watcher/format.js +21 -0
  48. package/dist/cjs/npcs/github-watcher/github-api.js +126 -0
  49. package/dist/cjs/npcs/github-watcher/index.js +148 -0
  50. package/dist/cjs/npcs/internet-connectivity/checks.js +92 -0
  51. package/dist/cjs/npcs/internet-connectivity/defaults.js +22 -0
  52. package/dist/cjs/npcs/internet-connectivity/index.js +251 -0
  53. package/dist/cjs/npcs/log-watcher/buffer.js +40 -0
  54. package/dist/cjs/npcs/log-watcher/defaults.js +12 -0
  55. package/dist/cjs/npcs/log-watcher/index.js +161 -0
  56. package/dist/cjs/npcs/log-watcher/tail.js +81 -0
  57. package/dist/cjs/npcs/process-watcher/defaults.js +9 -0
  58. package/dist/cjs/npcs/process-watcher/index.js +140 -0
  59. package/dist/cjs/npcs/process-watcher/process-scanner.js +114 -0
  60. package/dist/cjs/npcs/receptionist/defaults.js +9 -0
  61. package/dist/cjs/npcs/receptionist/index.js +120 -0
  62. package/dist/cjs/npcs/receptionist/weather.js +129 -0
  63. package/dist/cjs/npcs/system-monitor/collectors.js +68 -0
  64. package/dist/cjs/npcs/system-monitor/defaults.js +13 -0
  65. package/dist/cjs/npcs/system-monitor/index.js +105 -0
  66. package/dist/cjs/npcs/web-page-watcher/basic-mode.js +58 -0
  67. package/dist/cjs/npcs/web-page-watcher/capture.js +80 -0
  68. package/dist/cjs/npcs/web-page-watcher/defaults.js +31 -0
  69. package/dist/cjs/npcs/web-page-watcher/index.js +234 -0
  70. package/dist/cjs/npcs/web-page-watcher/pixelate.js +181 -0
  71. package/dist/cjs/package.json +1 -0
  72. package/dist/cli.d.ts +3 -0
  73. package/dist/cli.js +498 -0
  74. package/dist/core/api-key.d.ts +34 -0
  75. package/dist/core/api-key.js +64 -0
  76. package/dist/core/base-npc.d.ts +41 -0
  77. package/dist/core/base-npc.js +156 -0
  78. package/dist/core/config.d.ts +22 -0
  79. package/dist/core/config.js +101 -0
  80. package/dist/core/event-npc.d.ts +8 -0
  81. package/dist/core/event-npc.js +10 -0
  82. package/dist/core/logger.d.ts +11 -0
  83. package/dist/core/logger.js +35 -0
  84. package/dist/core/polling-npc.d.ts +18 -0
  85. package/dist/core/polling-npc.js +61 -0
  86. package/dist/core/screen.d.ts +11 -0
  87. package/dist/core/screen.js +24 -0
  88. package/dist/core/text.d.ts +6 -0
  89. package/dist/core/text.js +12 -0
  90. package/dist/core/thresholds.d.ts +10 -0
  91. package/dist/core/thresholds.js +44 -0
  92. package/dist/core/types.d.ts +60 -0
  93. package/dist/core/types.js +7 -0
  94. package/dist/core/user-config.d.ts +43 -0
  95. package/dist/core/user-config.js +85 -0
  96. package/dist/doctor.d.ts +8 -0
  97. package/dist/doctor.js +126 -0
  98. package/dist/index.d.ts +39 -0
  99. package/dist/index.js +25 -0
  100. package/dist/npcs/agent-common/activity.d.ts +42 -0
  101. package/dist/npcs/agent-common/activity.js +280 -0
  102. package/dist/npcs/agent-common/git-stats.d.ts +11 -0
  103. package/dist/npcs/agent-common/git-stats.js +67 -0
  104. package/dist/npcs/agent-common/hook-runner.d.ts +62 -0
  105. package/dist/npcs/agent-common/hook-runner.js +245 -0
  106. package/dist/npcs/agent-common/hook-settings.d.ts +75 -0
  107. package/dist/npcs/agent-common/hook-settings.js +265 -0
  108. package/dist/npcs/agent-common/liveness.d.ts +12 -0
  109. package/dist/npcs/agent-common/liveness.js +105 -0
  110. package/dist/npcs/agent-common/lock.d.ts +6 -0
  111. package/dist/npcs/agent-common/lock.js +95 -0
  112. package/dist/npcs/agent-common/runtime.d.ts +16 -0
  113. package/dist/npcs/agent-common/runtime.js +149 -0
  114. package/dist/npcs/agent-common/session.d.ts +184 -0
  115. package/dist/npcs/agent-common/session.js +368 -0
  116. package/dist/npcs/agent-common/shim.d.ts +4 -0
  117. package/dist/npcs/agent-common/shim.js +90 -0
  118. package/dist/npcs/agent-common/watchdog.d.ts +16 -0
  119. package/dist/npcs/agent-common/watchdog.js +144 -0
  120. package/dist/npcs/claude-code/defaults.d.ts +15 -0
  121. package/dist/npcs/claude-code/defaults.js +17 -0
  122. package/dist/npcs/claude-code/hook-handler.d.ts +40 -0
  123. package/dist/npcs/claude-code/hook-handler.js +131 -0
  124. package/dist/npcs/claude-code/index.d.ts +36 -0
  125. package/dist/npcs/claude-code/index.js +92 -0
  126. package/dist/npcs/claude-code/setup.d.ts +58 -0
  127. package/dist/npcs/claude-code/setup.js +121 -0
  128. package/dist/npcs/claude-code/state-machine.d.ts +28 -0
  129. package/dist/npcs/claude-code/state-machine.js +125 -0
  130. package/dist/npcs/codex/defaults.d.ts +24 -0
  131. package/dist/npcs/codex/defaults.js +28 -0
  132. package/dist/npcs/codex/hook-handler.d.ts +24 -0
  133. package/dist/npcs/codex/hook-handler.js +110 -0
  134. package/dist/npcs/codex/index.d.ts +21 -0
  135. package/dist/npcs/codex/index.js +76 -0
  136. package/dist/npcs/codex/rollout.d.ts +39 -0
  137. package/dist/npcs/codex/rollout.js +242 -0
  138. package/dist/npcs/codex/setup.d.ts +37 -0
  139. package/dist/npcs/codex/setup.js +96 -0
  140. package/dist/npcs/codex/watcher.d.ts +62 -0
  141. package/dist/npcs/codex/watcher.js +341 -0
  142. package/dist/npcs/cursor/defaults.d.ts +9 -0
  143. package/dist/npcs/cursor/defaults.js +11 -0
  144. package/dist/npcs/cursor/hook-handler.d.ts +8 -0
  145. package/dist/npcs/cursor/hook-handler.js +60 -0
  146. package/dist/npcs/cursor/index.d.ts +18 -0
  147. package/dist/npcs/cursor/index.js +57 -0
  148. package/dist/npcs/cursor/normalize.d.ts +6 -0
  149. package/dist/npcs/cursor/normalize.js +49 -0
  150. package/dist/npcs/cursor/setup.d.ts +29 -0
  151. package/dist/npcs/cursor/setup.js +90 -0
  152. package/dist/npcs/gemini/defaults.d.ts +9 -0
  153. package/dist/npcs/gemini/defaults.js +11 -0
  154. package/dist/npcs/gemini/hook-handler.d.ts +10 -0
  155. package/dist/npcs/gemini/hook-handler.js +87 -0
  156. package/dist/npcs/gemini/index.d.ts +17 -0
  157. package/dist/npcs/gemini/index.js +56 -0
  158. package/dist/npcs/gemini/setup.d.ts +29 -0
  159. package/dist/npcs/gemini/setup.js +90 -0
  160. package/dist/npcs/github-watcher/defaults.d.ts +8 -0
  161. package/dist/npcs/github-watcher/defaults.js +8 -0
  162. package/dist/npcs/github-watcher/format.d.ts +3 -0
  163. package/dist/npcs/github-watcher/format.js +18 -0
  164. package/dist/npcs/github-watcher/github-api.d.ts +55 -0
  165. package/dist/npcs/github-watcher/github-api.js +120 -0
  166. package/dist/npcs/github-watcher/index.d.ts +35 -0
  167. package/dist/npcs/github-watcher/index.js +144 -0
  168. package/dist/npcs/internet-connectivity/checks.d.ts +24 -0
  169. package/dist/npcs/internet-connectivity/checks.js +84 -0
  170. package/dist/npcs/internet-connectivity/defaults.d.ts +20 -0
  171. package/dist/npcs/internet-connectivity/defaults.js +19 -0
  172. package/dist/npcs/internet-connectivity/index.d.ts +55 -0
  173. package/dist/npcs/internet-connectivity/index.js +246 -0
  174. package/dist/npcs/log-watcher/buffer.d.ts +18 -0
  175. package/dist/npcs/log-watcher/buffer.js +34 -0
  176. package/dist/npcs/log-watcher/defaults.d.ts +9 -0
  177. package/dist/npcs/log-watcher/defaults.js +9 -0
  178. package/dist/npcs/log-watcher/index.d.ts +45 -0
  179. package/dist/npcs/log-watcher/index.js +157 -0
  180. package/dist/npcs/log-watcher/tail.d.ts +9 -0
  181. package/dist/npcs/log-watcher/tail.js +78 -0
  182. package/dist/npcs/process-watcher/defaults.d.ts +6 -0
  183. package/dist/npcs/process-watcher/defaults.js +6 -0
  184. package/dist/npcs/process-watcher/index.d.ts +26 -0
  185. package/dist/npcs/process-watcher/index.js +136 -0
  186. package/dist/npcs/process-watcher/process-scanner.d.ts +19 -0
  187. package/dist/npcs/process-watcher/process-scanner.js +110 -0
  188. package/dist/npcs/receptionist/defaults.d.ts +6 -0
  189. package/dist/npcs/receptionist/defaults.js +6 -0
  190. package/dist/npcs/receptionist/index.d.ts +29 -0
  191. package/dist/npcs/receptionist/index.js +116 -0
  192. package/dist/npcs/receptionist/weather.d.ts +37 -0
  193. package/dist/npcs/receptionist/weather.js +121 -0
  194. package/dist/npcs/system-monitor/collectors.d.ts +45 -0
  195. package/dist/npcs/system-monitor/collectors.js +60 -0
  196. package/dist/npcs/system-monitor/defaults.d.ts +7 -0
  197. package/dist/npcs/system-monitor/defaults.js +10 -0
  198. package/dist/npcs/system-monitor/index.d.ts +27 -0
  199. package/dist/npcs/system-monitor/index.js +101 -0
  200. package/dist/npcs/web-page-watcher/basic-mode.d.ts +16 -0
  201. package/dist/npcs/web-page-watcher/basic-mode.js +52 -0
  202. package/dist/npcs/web-page-watcher/capture.d.ts +49 -0
  203. package/dist/npcs/web-page-watcher/capture.js +75 -0
  204. package/dist/npcs/web-page-watcher/defaults.d.ts +19 -0
  205. package/dist/npcs/web-page-watcher/defaults.js +27 -0
  206. package/dist/npcs/web-page-watcher/index.d.ts +42 -0
  207. package/dist/npcs/web-page-watcher/index.js +230 -0
  208. package/dist/npcs/web-page-watcher/pixelate.d.ts +36 -0
  209. package/dist/npcs/web-page-watcher/pixelate.js +172 -0
  210. package/package.json +73 -3
package/README.md CHANGED
@@ -1,3 +1,244 @@
1
- # Temporary Holding Version
1
+ # @nocville/npc
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
+ Put your AI coding sessions and your infrastructure in the [Nocville](https://nocville.com)
4
+ office as live NPCs. Each Claude Code, Codex, Gemini CLI or Cursor session becomes a coworker named after its
5
+ project (`Claude · nocville`, `Codex · gridbreak`) who walks to a desk while working, raises
6
+ a hand when it needs you, dozes when idle, and shows what it's doing on its speech bubble and
7
+ desk sign: `Editing src/GameScene.ts`, `Running pnpm test`, `Searching for 'reconnect'`,
8
+ `Needs your approval`, `Thinking…`. It leaves the office when the session ends.
9
+
10
+ Requires Node.js 20+. Your team API key is in your Nocville team settings.
11
+
12
+ ## Quick start: AI coworkers
13
+
14
+ ```bash
15
+ npx @nocville/npc setup
16
+ ```
17
+
18
+ Paste your key at the prompt (input is hidden, so the key never lands in your shell history).
19
+ For scripts, pass `--api-key=<your team key>` or set `NOCVILLE_API_KEY` instead. That's it. The command saves your key to `~/.config/nocville/config.json` (mode 0600), then
20
+ hooks up whichever agents you have installed:
21
+
22
+ - **Claude Code**: adds hooks to `~/.claude/settings.json`. New sessions show up right away;
23
+ restart sessions that are already running.
24
+ - **Codex**: adds hooks to `~/.codex/hooks.json`. Codex won't run a new hook until you've
25
+ approved it, so start Codex once and run **`/hooks`** to trust the Nocville hooks.
26
+
27
+ - **Gemini CLI**: adds eight telemetry hooks to `~/.gemini/settings.json`, preserving your
28
+ settings and existing hooks. Start a new session after setup. Hooks return only `{}`.
29
+
30
+ - **Cursor**: adds native hooks to `~/.cursor/hooks.json`. Existing Nocville Claude hooks
31
+ also detect Cursor when its third-party hook imports are enabled. Both installations share
32
+ one coworker and deduplicate matching events. No permission decisions or model output are sent.
33
+
34
+ Self-hosting or developing locally? Add `--api-url=http://localhost:3601`. To send sessions to
35
+ a map other than your team's default, add `--map="Trading Floor"`.
36
+
37
+ Prefer a global install? Run `npm i -g @nocville/npc`, then `nocville-npc setup --api-key=…`.
38
+ When setup runs through `npx`, it copies itself to `~/.config/nocville/runtime/` so the hooks
39
+ keep working after npm clears its cache.
40
+
41
+ ### Per-agent commands
42
+
43
+ | Claude Code | Codex |
44
+ | ------------------------------------ | ---------------------------------------------- |
45
+ | `nocville-npc claude-code setup` | `nocville-npc codex setup` (then `/hooks`) |
46
+ | `nocville-npc claude-code uninstall` | `nocville-npc codex uninstall` |
47
+ | | `nocville-npc codex watch` (no-hooks fallback) |
48
+
49
+ `nocville-npc gemini setup` and `nocville-npc gemini uninstall` manage Gemini alone.
50
+ Gemini uses a 5000 ms hook timeout; pushes and end-of-turn git summaries are detached.
51
+ Its Node process is identified by the Gemini executable path, not an unrelated Node parent.
52
+
53
+ `nocville-npc cursor setup` and `nocville-npc cursor uninstall` manage native Cursor hooks.
54
+ Native commands use 10-second timeouts. Setup installs only sessionStart/sessionEnd,
55
+ beforeSubmitPrompt, postToolUse/postToolUseFailure, afterFileEdit, stop, subagentStop and
56
+ preCompact; it removes older Nocville permission hooks while preserving other hooks.
57
+ Activity comes from completed tools. Native and imported Cursor invocations return exactly
58
+ `{}` with no decision fields. Payload fields identify imported Cursor; `CURSOR_VERSION`
59
+ alone never reclassifies Claude launched inside its terminal. The launcher suppresses child
60
+ stdout for every agent, including debug logs, and emits only the appropriate neutral response.
61
+ Cursor does not watch the editor process or start a watchdog: an abandoned conversation uses
62
+ the one-hour fallback heartbeat interval (unknown after two hours, despawn ten minutes later).
63
+ Uninstall intentionally leaves `{"version":1}` when no other settings remain.
64
+
65
+ Cursor's [documented tool names](https://cursor.com/docs/hooks#configuration) include Grep,
66
+ Delete, Task and MCP tools. Their summaries use the shared redaction/path handling; MCP names
67
+ are normalized to the shared MCP format. Real Cursor Shell/Read/Write verification with both
68
+ Claude-imported-only and native hooks is still required before a public support claim.
69
+
70
+ `nocville-npc uninstall` removes every Nocville hook. `nocville-npc init` only saves
71
+ credentials. Every setup command takes the key from `--api-key`, then `NOCVILLE_API_KEY`, then
72
+ the saved config, and otherwise prompts for it (in a terminal) or exits with an error. `nocville-npc doctor` checks connectivity and sends a test push.
73
+
74
+ ### What you'll see
75
+
76
+ | Agent state | NPC | Desk sign / bubble |
77
+ | -------------------------------- | ------------------------------------- | ---------------------------------------------- |
78
+ | Prompt submitted | walks to a desk, sits | `Thinking…` |
79
+ | Using a tool | stays at the desk | `Editing apps/web/x.ts`, `Running pnpm test` … |
80
+ | Permission prompt / question | stands up and raises a hand | `Needs your approval: Running rm -rf dist` |
81
+ | Turn finished, or at the prompt | dozes at the desk | `Done — waiting for next task` |
82
+ | Session ends (exit, `/clear`, …) | leaves the office (immediate despawn) | |
83
+
84
+ **Privacy:** prompts, file contents, edit text, and command output are never sent. Commands
85
+ are shortened to their first line, and anything that looks like a secret is redacted first:
86
+ env assignments, `--token=`/`--password` flags, bearer headers, URL credentials, and long
87
+ key-like strings. Paths are shown relative to the project.
88
+
89
+ **Lifecycle and overhead:** normal hooks run asynchronously, update a locked local state file,
90
+ and hand HTTP delivery to a detached process. Same-phase bursts coalesce at 1.5 seconds.
91
+ SessionEnd stays synchronous with a short timeout to deliver the offline update; failures
92
+ remain pending for retry. Hooks never output instructions or permission decisions.
93
+
94
+ A watchdog checks a known agent process every 15 seconds and heartbeats once a minute.
95
+ A killed process leaves the office on the next check. If the machine sleeps or loses power,
96
+ the NPC becomes unknown after three minutes and disappears after thirteen. Hosts where
97
+ process liveness cannot be established retain the legacy one-hour heartbeat fallback.
98
+ Claude subagent activity appears below the parent's current activity and disappears when
99
+ the subagent stops (or after ten minutes without activity).
100
+
101
+ Setup installs a stable `~/.config/nocville/bin/nocville-hook` launcher (respecting
102
+ `XDG_CONFIG_HOME` and `NOCVILLE_CONFIG`) and an immutable runtime copy when needed.
103
+ Re-running setup updates the runtime pointer without changing the hook command or Codex's
104
+ command trust. Old snapshots remain available to running watchdogs. Windows uses the sibling
105
+ `nocville-hook.cmd` launcher, which resolves the saved Node path and runs the same bootstrap.
106
+ Windows setup writes plain commands, never `-EncodedCommand` or an execution-policy override.
107
+ Re-running setup replaces the former encoded commands; uninstall still recognizes them.
108
+
109
+ | Agent | Windows command host and verification |
110
+ | ----------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
111
+ | Claude Code | Explicit per-hook `shell: "powershell"`; invokes `& '<shim>.cmd' claude-code hook`. Claude selects PowerShell 7 or falls back to 5.1. CI exercises both. [Claude hook shell reference](https://code.claude.com/docs/en/hooks#windows-powershell-tool). |
112
+ | Gemini | Its hook runner selects PowerShell 7 or 5.1. The saved `cmd.exe /d /s /c --% ...` preserves cmd quoting, with a terminating newline before Gemini's appended exit check. CI exercises both hosts with that check. [Hook reference](https://geminicli.com/docs/hooks/reference/), [runner](https://github.com/google-gemini/gemini-cli/blob/main/packages/core/src/hooks/hookRunner.ts), [shell selection](https://github.com/google-gemini/gemini-cli/blob/main/packages/core/src/utils/shell-utils.ts). |
113
+ | Cursor | Explicit `cmd.exe /d /s /c` launcher; CI executes the saved string under cmd. The [published hook contract](https://cursor.com/docs/hooks) does not specify the Windows outer shell; real Windows Cursor verification remains required. |
114
+ | Codex | Explicit `cmd.exe /d /s /c` launcher; CI executes the saved string under cmd. The [published hook contract](https://learn.chatgpt.com/docs/hooks) does not identify the Windows outer shell; real Windows Codex verification remains required. |
115
+
116
+ PowerShell's [stop-parsing token](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_parsing#the-stop-parsing-token)
117
+ ends at a newline, not a semicolon. Keep Gemini's saved newline: its runner appends PowerShell
118
+ code to the command. No event input is interpolated into shell commands. Windows support remains
119
+ unverified until the Windows CI job and real-agent checks pass; macOS tests cannot establish it.
120
+ **Windows Cursor users:** install native hooks with `nocville-npc cursor setup`; do not rely on
121
+ Cursor importing Claude Code hooks. Claude's saved hook uses PowerShell syntax and an explicit
122
+ `shell` field. If Cursor's import path ignores that field and uses cmd, the imported command can
123
+ fail before the shim runs and produce hook errors. Nocville cannot control Cursor's import path.
124
+
125
+ Windows real-agent owner checklist (required before support claims):
126
+
127
+ - Run the native Windows CI job, including PowerShell 5.1/7 and a spaced `O’Neil` profile path.
128
+ - Verify native Cursor Shell/Read/Write events after `nocville-npc cursor setup`.
129
+ - With Claude hooks also installed, check whether Cursor imports them and honors their `shell`
130
+ field. Record agent versions and any duplicate/error events; verify native Cursor hooks work
131
+ independently. Do not count an imported Claude hook as proof of native Cursor support.
132
+ - Verify the actual Claude, Gemini and Codex hosts using their installed saved commands.
133
+
134
+ Claude's single-quoted path doubles straight and curly apostrophes according to
135
+ [PowerShell quoting rules](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_quoting_rules#including-quote-characters-in-a-string).
136
+
137
+ Both launchers discard child stdout and preserve stderr; all SDK logger levels use stderr.
138
+ If Node is unavailable, the shim drains stdin and returns neutral `{}` for Cursor/Gemini
139
+ and Claude hooks (which may have been imported by Cursor); Codex stays silent. Session records are local, including terminal
140
+ records that prevent late events from reviving an ended NPC; `cleanup` removes old records.
141
+
142
+ ### How the Codex integration works
143
+
144
+ Codex supports Claude-style lifecycle hooks (`SessionStart`, `UserPromptSubmit`,
145
+ `PreToolUse`, `PermissionRequest`, `Stop`, `SessionEnd`, …) configured in
146
+ `~/.codex/hooks.json`. Setup merges a Nocville entry into each event, keeps your existing
147
+ hooks, makes a one-time `hooks.json.nocville-backup`, and is safe to run again.
148
+
149
+ `nocville-npc codex watch` is a deprecated, best-effort fallback for builds without hooks. It
150
+ reads the rollout logs Codex writes to `~/.codex/sessions/YYYY/MM/DD/rollout-*.jsonl`. It
151
+ shows one NPC per interactive session (subagent and reviewer threads are skipped; add
152
+ `--include-exec` to include `codex exec` runs). A session leaves the office after 30 minutes
153
+ without log activity (`--idle-timeout=<minutes>`) or when you press Ctrl-C. If hooks are
154
+ installed for a session (any hook state file, including an old terminal record), the watcher
155
+ leaves that session to them. `doctor` warns when both modes are running.
156
+
157
+ ## Monitoring NPCs
158
+
159
+ Long-running processes that each collect from one source and push status. Their NPC spawns
160
+ on your map automatically and despawns when you press Ctrl-C. Once you've run
161
+ `nocville-npc init`, no `--api-key` is needed.
162
+
163
+ ```bash
164
+ # Common options:
165
+ # --api-key=<key> Team API key (or NOCVILLE_API_KEY, or saved via `init`)
166
+ # --api-url=<url> Default https://nocville.com (or NOCVILLE_API_URL)
167
+ # --service-id=<id> Service ID (or NOCVILLE_SERVICE_ID)
168
+ # --name=<banner name> Friendly NPC name (or NOCVILLE_NAME)
169
+ # --map=<id-or-name> Target map (or NOCVILLE_MAP). Default: the team's default map
170
+ # --debug Verbose logging
171
+ ```
172
+
173
+ | NPC | What it does | Example |
174
+ | ----------------------- | -------------------------------------------------- | ------------------------------------------------------ |
175
+ | `system-monitor` | CPU / memory / disk / load with sparklines | `nocville-npc system-monitor --cpu-warn=75` |
176
+ | `internet-connectivity` | DNS, HTTP and TCP latency checks | `nocville-npc internet-connectivity` |
177
+ | `process-watcher` | Watches named processes, calls out deaths | `nocville-npc process-watcher --processes=nginx,redis` |
178
+ | `log-watcher` | Error bursts in log files, last lines on a monitor | `nocville-npc log-watcher --files=/var/log/app.log` |
179
+ | `receptionist` | Time and weather at the entrance, greets players | `nocville-npc receptionist --location="Berlin"` |
180
+ | `github-watcher` | New commits on a commit board | `nocville-npc github-watcher --repo=owner/name` |
181
+ | `web-page-watcher` | A web page rendered as a pixel-art TV | `nocville-npc web-page-watcher --url=https://…` |
182
+
183
+ Run `nocville-npc --help` to see every flag. A few notes:
184
+
185
+ - **log-watcher**: `--error-pattern="ERROR|FATAL" --window=300 --error-warn=5 --error-crit=20`.
186
+ - **receptionist**: weather comes from the keyless open-meteo API. Set the place with
187
+ `--lat=52.5 --lon=13.4` or `--location=…` (otherwise it uses IP geolocation). Add
188
+ `--fahrenheit` for °F.
189
+ - **github-watcher**: uses ETag polling. Pass `--token=$GITHUB_TOKEN` for a higher rate limit.
190
+ - **web-page-watcher**: the pixel-art TV needs `npm i puppeteer-core` and a local
191
+ Chrome/Chromium (`--chrome-path` or `CHROME_PATH`). Without them it falls back to a
192
+ title/status ticker. Other options: `--mode=auto|screenshot|basic` and `--screen=160x120`.
193
+
194
+ ## Programmatic use
195
+
196
+ ```typescript
197
+ import { SystemMonitorNPC, PollingNPC } from '@nocville/npc';
198
+ import type { CollectedMetrics } from '@nocville/npc';
199
+
200
+ await new SystemMonitorNPC({
201
+ apiUrl: 'https://nocville.com',
202
+ apiKey: 'noc_…',
203
+ serviceId: 'web-1',
204
+ }).start();
205
+
206
+ class MyNPC extends PollingNPC {
207
+ get name() {
208
+ return 'my-npc';
209
+ }
210
+ async collect(): Promise<CollectedMetrics> {
211
+ return { status: 'healthy', mood: 'happy', message: 'All good', metrics: { qps: 42 } };
212
+ }
213
+ }
214
+ ```
215
+
216
+ ## Developing in the monorepo
217
+
218
+ ```bash
219
+ pnpm install
220
+ pnpm --filter @nocville/npc build
221
+ pnpm --filter @nocville/npc test
222
+ node libs/nocville-npc-library/dist/cli.js --help
223
+ SMOKE_STUB=1 pnpm --filter @nocville/npc smoke # every payload shape, no server needed
224
+ ```
225
+
226
+ **Watch an AI-coworker NPC without running an agent.** `simulate` plays a scripted session
227
+ (start → prompt → Read → Edit → `pnpm test` → approval wait → idle → end) through the real
228
+ built hook handlers. It works in a throwaway HOME, so your `~/.claude` and `~/.codex` are
229
+ untouched, and the NPC appears as "Claude · demo" (or "Codex · demo"):
230
+
231
+ ```bash
232
+ pnpm --filter @nocville/npc simulate claude --api-key=<key> --api-url=http://localhost:3601
233
+ pnpm --filter @nocville/npc simulate codex --api-key=<key> --project=gridbreak --fast
234
+ # --hold stay idle after Stop until Ctrl-C, then end the session
235
+ # --fast 5x shorter pauses (CI)
236
+ ```
237
+
238
+ **Real hooks against your local checkout.** This writes real hooks into `~/.claude` and
239
+ `~/.codex` that run your working copy's `dist/cli.js`:
240
+
241
+ ```bash
242
+ node libs/nocville-npc-library/dist/cli.js setup --api-key=<key> --api-url=http://localhost:3601
243
+ node libs/nocville-npc-library/dist/cli.js uninstall # remove them again
244
+ ```