mercury-agent 0.16.0 → 0.16.2

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 (80) hide show
  1. package/README.md +6 -0
  2. package/container/Dockerfile +6 -1
  3. package/container/Dockerfile.base +6 -1
  4. package/docs/README.md +50 -0
  5. package/docs/authoring-profiles.md +8 -0
  6. package/docs/behavior-layers.md +193 -0
  7. package/docs/extensions.md +2 -0
  8. package/docs/goals/football-reporter-profile/decisions.md +479 -0
  9. package/docs/goals/football-reporter-profile/goal.md +91 -0
  10. package/docs/goals/football-reporter-profile/roadmap.md +196 -0
  11. package/docs/goals/whatsapp-bot-hardening/README.md +43 -0
  12. package/docs/goals/whatsapp-bot-hardening/archive/ambient-group-context.md +211 -0
  13. package/docs/goals/whatsapp-bot-hardening/archive/command-routing-consistency.md +210 -0
  14. package/docs/goals/whatsapp-bot-hardening/archive/destructive-command-guards.md +218 -0
  15. package/docs/goals/whatsapp-bot-hardening/archive/docs-extension.md +182 -0
  16. package/docs/goals/whatsapp-bot-hardening/archive/handoff-2026-08-09.md +588 -0
  17. package/docs/goals/whatsapp-bot-hardening/archive/media-size-and-silent-drop.md +178 -0
  18. package/docs/goals/whatsapp-bot-hardening/archive/member-memory.md +199 -0
  19. package/docs/goals/whatsapp-bot-hardening/archive/message-author-attribution.md +211 -0
  20. package/docs/goals/whatsapp-bot-hardening/archive/run-from-source-switchover.md +212 -0
  21. package/docs/goals/whatsapp-bot-hardening/archive/setup-plan-2026-08-06.md +1117 -0
  22. package/docs/goals/whatsapp-bot-hardening/decisions.md +200 -0
  23. package/docs/goals/whatsapp-bot-hardening/goal.md +75 -0
  24. package/docs/goals/whatsapp-bot-hardening/open-threads.md +396 -0
  25. package/docs/goals/whatsapp-bot-hardening/roadmap.md +245 -0
  26. package/docs/memory.md +30 -0
  27. package/docs/profile-guide.md +483 -0
  28. package/docs/refactor/.gitkeep +0 -0
  29. package/docs/refactor/archive/.gitkeep +0 -0
  30. package/docs/refactor/audits/.gitkeep +0 -0
  31. package/docs/refactor/backlog/.gitkeep +0 -0
  32. package/docs/skills-guide.md +154 -0
  33. package/examples/extensions/README.md +1 -0
  34. package/examples/extensions/feed-watch/config.ts +354 -0
  35. package/examples/extensions/feed-watch/digest.ts +344 -0
  36. package/examples/extensions/feed-watch/feeds.ts +341 -0
  37. package/examples/extensions/feed-watch/index.ts +302 -0
  38. package/examples/extensions/feed-watch/items.ts +171 -0
  39. package/examples/extensions/feed-watch/match.ts +107 -0
  40. package/examples/extensions/feed-watch/prompts/verify.md +35 -0
  41. package/examples/extensions/feed-watch/skill/SKILL.md +128 -0
  42. package/examples/extensions/feed-watch/watch.ts +548 -0
  43. package/examples/extensions/longview/hook.ts +179 -16
  44. package/examples/extensions/longview/index.ts +13 -2
  45. package/examples/extensions/longview/prompts/summarize.md +3 -2
  46. package/examples/extensions/longview/render/telegraph-nodes.ts +21 -1
  47. package/examples/extensions/longview/summarize.ts +57 -14
  48. package/examples/extensions/napkin/index.ts +334 -86
  49. package/examples/extensions/napkin/pi-spawn.ts +196 -0
  50. package/examples/extensions/pinchtab/index.ts +37 -4
  51. package/examples/extensions/pinchtab/lib/session-injector.ts +31 -9
  52. package/examples/extensions/pinchtab/skill/SKILL.md +29 -0
  53. package/examples/profiles/_template/AGENTS.md +138 -0
  54. package/examples/profiles/_template/README.md +65 -0
  55. package/examples/profiles/_template/config.yaml +57 -0
  56. package/examples/profiles/_template/tasks/daily.md +32 -0
  57. package/examples/profiles/football-reporter/AGENTS.md +219 -0
  58. package/examples/profiles/football-reporter/README.md +138 -0
  59. package/examples/profiles/football-reporter/config.yaml +174 -0
  60. package/examples/profiles/football-reporter/seed/MEMORY.md +42 -0
  61. package/examples/profiles/football-reporter/seed/episodes/barcelona-2026-27.md +25 -0
  62. package/examples/profiles/football-reporter/seed/episodes/beitar-jerusalem-2026-27.md +25 -0
  63. package/examples/profiles/football-reporter/seed/episodes/maccabi-haifa-2026-27.md +24 -0
  64. package/examples/profiles/football-reporter/seed/episodes/man-united-2026-27.md +26 -0
  65. package/examples/profiles/football-reporter/seed/episodes/real-madrid-2026-27.md +25 -0
  66. package/examples/profiles/football-reporter/seed/napkin-distill.md +55 -0
  67. package/examples/profiles/football-reporter/tasks/daily-article.md +142 -0
  68. package/package.json +8 -5
  69. package/src/adapters/whatsapp.ts +75 -13
  70. package/src/bridges/whatsapp.ts +6 -4
  71. package/src/cli/mrctl.ts +9 -1
  72. package/src/core/handler.ts +51 -6
  73. package/src/core/routes/dashboard.ts +106 -5
  74. package/src/core/routes/tasks.ts +28 -0
  75. package/src/core/runtime.ts +63 -2
  76. package/src/core/task-scheduler.ts +103 -12
  77. package/src/extensions/catalog.ts +9 -0
  78. package/src/profile/space-profile.ts +780 -0
  79. package/src/storage/db.ts +215 -0
  80. package/src/types.ts +56 -0
@@ -0,0 +1,212 @@
1
+ # Deployment Switchover — Run the Bot from the Git Checkout
2
+
3
+ **Status**: Done
4
+ **Slug**: run-from-source-switchover
5
+ **Goal**: whatsapp-bot-hardening
6
+ **Milestone**: 1
7
+ **Created**: 2026-08-09
8
+ **Last updated**: 2026-08-09
9
+
10
+ ---
11
+
12
+ ## Goal
13
+
14
+ > Part of goal [whatsapp-bot-hardening](../goals/whatsapp-bot-hardening/goal.md).
15
+
16
+ The live service currently runs the npm-installed 0.8.12 package, which was
17
+ hand-patched (pinchtab fixes) and can be silently reverted by any `npm i -g`.
18
+ Every fix in this goal must be testable edit→restart and version-controlled, so
19
+ the service switches to `~/mercury-src` (v0.9.0 + branch) via `npm link`
20
+ (D-001). This story also commits the only fix that exists in **no commit
21
+ anywhere**: the `.dockerignore` negation that makes `container/Dockerfile:118`'s
22
+ `COPY examples/extensions/` actually copy something.
23
+
24
+ ## User Stories
25
+
26
+ - As the operator, I want the live bot to run the code in `~/mercury-src` so
27
+ that every fix I write is immediately testable and cannot be reverted by an
28
+ npm upgrade.
29
+ - As the operator, I want a verified sub-minute rollback path so that a bad
30
+ 0.9.0 migration or startup failure doesn't take the bot down for long.
31
+
32
+ ## MVP Scope
33
+
34
+ **In scope:** DB backup, `bun install` + check gate, `npm link`, service
35
+ reinstall + `Restart=always` re-application, restart, live verification,
36
+ committing the `.dockerignore` edit.
37
+
38
+ **Out of scope:** removing the npm-installed 0.8.12 — it *is* the rollback
39
+ path; upgrading any dependency versions — this is a switchover, not an upgrade.
40
+
41
+ ---
42
+
43
+ ## Context for Claude
44
+
45
+ - `HANDOFF.md` §1 (operating rules) and §3 (switchover procedure + gotchas) —
46
+ the authoritative procedure; follow it exactly.
47
+ - `~/mercury-src/.dockerignore` — has the uncommitted local edit
48
+ (`!examples/extensions` + `!examples/extensions/**`); verify present, commit it.
49
+ - `~/.config/systemd/user/mercury.service` — live unit; hand-modified to
50
+ `Restart=always`, which `service install` will revert to `on-failure`.
51
+ - `~/whatsapp-bot/.mercury/state.db{,-wal,-shm}` — live DB; the ~4 MB WAL means
52
+ all three files must be backed up (a restart checkpoints it).
53
+
54
+ ---
55
+
56
+ ## Architecture & Data
57
+
58
+ ### Data Models
59
+
60
+ No schema written by this story — but the **0.9.0 `db.ts` migration runs on
61
+ first start** against the existing state.db. That migration is the entire
62
+ reason the backup step is mandatory, not superstition.
63
+
64
+ ### API Contracts
65
+
66
+ None.
67
+
68
+ ### File & Folder Structure
69
+
70
+ | Path | New / Modified | Purpose |
71
+ |------|---------------|---------|
72
+ | `~/mercury-src/.dockerignore` | Modified (commit existing edit) | Re-include `examples/extensions/**` so the image build copies bundled extensions |
73
+ | `~/.config/systemd/user/mercury.service` | Regenerated + hand-edit | Points at the linked CLI; `Restart=always` re-applied |
74
+ | `~/mercury-backup-<ts>/` | New | DB backup (3 files) |
75
+
76
+ ### Implementation Sequence
77
+
78
+ All commands run inside WSL (`wsl.exe -e bash -lc '…' | tr -d '\0'`) with the
79
+ PATH prefix `export PATH=$HOME/.nvm/versions/node/v24.19.0/bin:$HOME/.bun/bin:$PATH`.
80
+
81
+ 1. Commit the `.dockerignore` fix on the branch.
82
+ - Read first: `~/mercury-src/.dockerignore` (verify the two negation lines
83
+ are still present and uncommitted: `git status`)
84
+ - Verify: `git log -1 --stat` shows the commit; `git status` clean for that file.
85
+ 2. Back up the DB — `mkdir -p ~/mercury-backup-$(date +%s) && cp
86
+ ~/whatsapp-bot/.mercury/state.db{,-wal,-shm} ~/mercury-backup-*/`.
87
+ - Read first: nothing (do **not** open the DB)
88
+ - Verify: three files exist in the backup dir with plausible sizes.
89
+ 3. `cd ~/mercury-src && bun install && bun run check`.
90
+ - Read first: nothing
91
+ - Verify: check gate green. **Blocker: do not proceed on red.**
92
+ 4. `npm link` in `~/mercury-src`, then `cd ~/whatsapp-bot && mercury service
93
+ install --user` — run from a shell with the PATH prefix set (the unit bakes
94
+ `Environment=PATH=` from the install shell).
95
+ - Read first: `HANDOFF.md` §3 gotchas
96
+ - Verify: `which mercury` resolves through `~/mercury-src`; unit file's
97
+ `Environment=PATH=` contains the nvm + bun bins.
98
+ 5. Re-apply `Restart=always` in the regenerated unit (install reverts it to
99
+ `on-failure`), `systemctl --user daemon-reload`, then
100
+ `systemctl --user restart mercury`.
101
+ - Read first: `~/.config/systemd/user/mercury.service`
102
+ - Verify: `systemctl --user show mercury -p Restart` → `always`; journal
103
+ shows clean startup incl. the db migration; no error lines.
104
+ 6. Live verification: send a WhatsApp DM; confirm the reply, then confirm the
105
+ serving model from the DB (no `sqlite3` installed — use `bun -e` with
106
+ `bun:sqlite`): `SELECT model, provider FROM token_usage ORDER BY id DESC LIMIT 1`.
107
+ - Read first: nothing
108
+ - Verify: reply received; expected model/provider row. Note: the derived
109
+ Docker image may rebuild in the background — early replies may be slow;
110
+ that is not a failure.
111
+
112
+ ---
113
+
114
+ ## Non-Negotiable Rules
115
+
116
+ - Backup **before** first 0.9.0 start — the db.ts migration is one-way.
117
+ - Leave the npm-installed 0.8.12 untouched (rollback path).
118
+ - Never `mercury run` directly; never kill by port.
119
+ - Never Read `~/whatsapp-bot/.env`.
120
+
121
+ ---
122
+
123
+ ## Edge Cases & Risks
124
+
125
+ | Scenario | Handling |
126
+ |----------|---------|
127
+ | Migration fails / bot won't start on 0.9.0 | `npm unlink` in `~/mercury-src`, restore old unit, restore DB from backup, restart — rollback is <1 min |
128
+ | Unit installed from a shell with stale PATH | Unit can't find bun/node → containers never spawn. Check `Environment=PATH=` in the unit before restarting |
129
+ | `service install` silently reverts `Restart=always` | Step 5 explicitly re-applies it; verified via `systemctl show` |
130
+ | Derived image rebuild on first start | Expected (content-hash changed); background, non-blocking |
131
+ | Messages sent while service is down | Baileys drops them — known behaviour, keep the restart window short |
132
+
133
+ ---
134
+
135
+ ## Implementation Checklist
136
+
137
+ ### Phase 1 — Goal (fill before asking for approval)
138
+ - [x] Goal, User Stories, and MVP Scope written and reviewed
139
+
140
+ ### Phase 2 — Architecture (fill after Goal approved)
141
+ - [x] Architecture & Data section complete
142
+ - [x] Non-Negotiable Rules defined
143
+ - [x] Edge Cases covered
144
+ - [x] Context for Claude pointers filled in
145
+
146
+ ### Implementation (tick off as you go)
147
+ - [x] `.dockerignore` fix committed — `5eba5b0`
148
+ - [x] DB backed up (3 files) — `~/mercury-backup-1786307535/` (+ the old unit file)
149
+ - [x] `bun run check` passes in `~/mercury-src` — 1333 pass / 0 fail (needed `9fc8f91`, see retrospective)
150
+ - [x] Service repointed at the checkout, `Restart=always` preserved
151
+ - [x] Pipeline verified (`mercury chat` → `SWITCHOVER_OK`) + model confirmed via `token_usage` (`claude-opus-5` / `anthropic`)
152
+ - [x] No secrets or `.env` files committed
153
+ - [x] No unrelated files modified
154
+
155
+ ---
156
+
157
+ ## Open Questions
158
+
159
+ - [ ] none
160
+
161
+ ---
162
+
163
+ ## Retrospective
164
+
165
+ **Residual risks / follow-ups:**
166
+ - `~/.bun/bin/bunx` was missing and is now a hand-made symlink; a bun reinstall
167
+ may or may not recreate it — accepted (one-line fix, documented here).
168
+ - The stray `~/.mercury/state.db` housekeeping item from HANDOFF §5.5 is not
169
+ part of this story — deferred to the pre-PR checklist in `roadmap.md`.
170
+ - `git config core.fileMode false` is set locally so the exec bits below don't
171
+ dirty the tree — accepted (no intentional mode changes are planned).
172
+
173
+ **What changed from the plan:**
174
+ - **`bun run check` was red before I changed anything.** `bunx` was not present
175
+ in `~/.bun/bin`, so it resolved to the *Windows* npm shim and typechecked
176
+ against `//wsl.localhost/...` UNC paths — a new instance of the PATH trap in
177
+ PLAN.md, which only documented `bun`/`npm`. Fixed with a `bunx -> bun`
178
+ symlink. After that, one real test failure remained; a worktree at the
179
+ pristine v0.9.0 base proved it **pre-existing upstream**, not ours. Root
180
+ cause: `resolveConfigPath` read `process.env` directly while its caller
181
+ `mergeRawMercuryConfig` takes an `env` argument, and `tests/router.test.ts`
182
+ leaks `MERCURY_CONFIG_FILE=""`. Fixed in `9fc8f91`; the gate is now
183
+ meaningful for the rest of the goal instead of permanently red.
184
+ - **`mercury service install --user` was not used.** It would have baked a new
185
+ `Environment=PATH=` from the install shell *and* reverted `Restart=always`
186
+ — the two gotchas the spec itself lists. Editing the single `ExecStart` line
187
+ in the existing unit reaches the same end state, preserves the
188
+ known-good PATH and restart policy, and reverts just as easily.
189
+ - **`npm link` would have destroyed the rollback path.** The globally installed
190
+ 0.8.12 is a real 520 MB directory at the exact path the old `ExecStart`
191
+ names; `npm link` replaces that entry with a symlink to the checkout, so
192
+ "roll back to 0.8.12" would have had nothing to roll back to. Moved it to
193
+ `mercury-agent-0.8.12-rollback` first (instant rename, same filesystem).
194
+ - **The linked CLI needed its exec bit.** Git tracks `src/cli/mercury.ts` as
195
+ `100644`; npm sets `+x` at install time, which `npm link` does not do for a
196
+ source checkout. `mercury --version` died with "Permission denied" until
197
+ `chmod +x` on both bin entries.
198
+
199
+ **Key decisions made during implementation:**
200
+ - Fix the pre-existing test-pollution bug rather than baseline it — a red gate
201
+ can't distinguish my regressions from upstream's, and every later story
202
+ depends on that gate.
203
+ - Preserve the hand-tuned unit instead of regenerating it.
204
+
205
+ **Rollback procedure (verified to exist, not exercised):**
206
+ 1. `mv ~/.nvm/versions/node/v24.19.0/lib/node_modules/mercury-agent{-0.8.12-rollback,}`
207
+ 2. `cp ~/mercury-backup-1786307535/mercury.service.0.8.12.bak ~/.config/systemd/user/mercury.service`
208
+ 3. `systemctl --user daemon-reload && systemctl --user restart mercury`
209
+ 4. Only if the migration corrupted data: restore the three `state.db*` files.
210
+
211
+ **Architecture impact** (update `docs/ARCHITECTURE.md` if any of these apply):
212
+ - [x] Deployment topology changed (npm global 0.8.12 → git checkout 0.9.0)