@pcircle/memesh 4.8.3 → 4.9.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 (254) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +2 -1
  3. package/.codex-plugin/mcp.json +6 -4
  4. package/.codex-plugin/plugin.json +1 -1
  5. package/AGENTS.md +68 -17
  6. package/README.de.md +83 -555
  7. package/README.md +83 -581
  8. package/README.zh-TW.md +84 -572
  9. package/dashboard/dist/index.html +10 -10
  10. package/dist/cli/view-live.d.ts.map +1 -1
  11. package/dist/cli/view-live.js +154 -384
  12. package/dist/cli/view-live.js.map +1 -1
  13. package/dist/core/agent-message-inbox.d.ts +2 -1
  14. package/dist/core/agent-message-inbox.d.ts.map +1 -1
  15. package/dist/core/agent-message-inbox.js +23 -4
  16. package/dist/core/agent-message-inbox.js.map +1 -1
  17. package/dist/core/agent-messaging.d.ts.map +1 -1
  18. package/dist/core/agent-messaging.js +23 -15
  19. package/dist/core/agent-messaging.js.map +1 -1
  20. package/dist/core/agent-router.d.ts +11 -10
  21. package/dist/core/agent-router.d.ts.map +1 -1
  22. package/dist/core/agent-router.js +29 -14
  23. package/dist/core/agent-router.js.map +1 -1
  24. package/dist/core/agent-scope-id.d.ts +11 -0
  25. package/dist/core/agent-scope-id.d.ts.map +1 -0
  26. package/dist/core/agent-scope-id.js +40 -0
  27. package/dist/core/agent-scope-id.js.map +1 -0
  28. package/dist/core/analytics.d.ts.map +1 -1
  29. package/dist/core/analytics.js.map +1 -1
  30. package/dist/core/briefing.d.ts.map +1 -1
  31. package/dist/core/briefing.js +8 -2
  32. package/dist/core/briefing.js.map +1 -1
  33. package/dist/core/config.d.ts +4 -40
  34. package/dist/core/config.d.ts.map +1 -1
  35. package/dist/core/config.js +75 -141
  36. package/dist/core/config.js.map +1 -1
  37. package/dist/core/demo.d.ts.map +1 -1
  38. package/dist/core/demo.js +6 -6
  39. package/dist/core/demo.js.map +1 -1
  40. package/dist/core/doctor.d.ts +2 -6
  41. package/dist/core/doctor.d.ts.map +1 -1
  42. package/dist/core/doctor.js +120 -154
  43. package/dist/core/doctor.js.map +1 -1
  44. package/dist/core/dreamer.d.ts +32 -47
  45. package/dist/core/dreamer.d.ts.map +1 -1
  46. package/dist/core/dreamer.js +214 -704
  47. package/dist/core/dreamer.js.map +1 -1
  48. package/dist/core/install-channel.d.ts.map +1 -1
  49. package/dist/core/install-channel.js +4 -47
  50. package/dist/core/install-channel.js.map +1 -1
  51. package/dist/core/install-id.d.ts.map +1 -1
  52. package/dist/core/install-id.js.map +1 -1
  53. package/dist/core/kg-backfill.d.ts.map +1 -1
  54. package/dist/core/kg-backfill.js.map +1 -1
  55. package/dist/core/lesson-engine.d.ts +0 -5
  56. package/dist/core/lesson-engine.d.ts.map +1 -1
  57. package/dist/core/lesson-engine.js +0 -25
  58. package/dist/core/lesson-engine.js.map +1 -1
  59. package/dist/core/lifecycle.d.ts.map +1 -1
  60. package/dist/core/lifecycle.js +58 -49
  61. package/dist/core/lifecycle.js.map +1 -1
  62. package/dist/core/memory-tool.d.ts.map +1 -1
  63. package/dist/core/memory-tool.js +20 -18
  64. package/dist/core/memory-tool.js.map +1 -1
  65. package/dist/core/operations.d.ts +3 -27
  66. package/dist/core/operations.d.ts.map +1 -1
  67. package/dist/core/operations.js +10 -245
  68. package/dist/core/operations.js.map +1 -1
  69. package/dist/core/paths.d.ts +4 -1
  70. package/dist/core/paths.d.ts.map +1 -1
  71. package/dist/core/paths.js +88 -14
  72. package/dist/core/paths.js.map +1 -1
  73. package/dist/core/product-improvements.js +2 -2
  74. package/dist/core/product-improvements.js.map +1 -1
  75. package/dist/core/project-tags.d.ts +2 -0
  76. package/dist/core/project-tags.d.ts.map +1 -1
  77. package/dist/core/project-tags.js +29 -1
  78. package/dist/core/project-tags.js.map +1 -1
  79. package/dist/core/schema-export.d.ts.map +1 -1
  80. package/dist/core/schema-export.js +13 -3
  81. package/dist/core/schema-export.js.map +1 -1
  82. package/dist/core/semver.d.ts +7 -0
  83. package/dist/core/semver.d.ts.map +1 -0
  84. package/dist/core/semver.js +49 -0
  85. package/dist/core/semver.js.map +1 -0
  86. package/dist/core/serializer.d.ts.map +1 -1
  87. package/dist/core/serializer.js +69 -57
  88. package/dist/core/serializer.js.map +1 -1
  89. package/dist/core/signal-scorer.d.ts.map +1 -1
  90. package/dist/core/signal-scorer.js.map +1 -1
  91. package/dist/core/transcript-extractor.d.ts +1 -85
  92. package/dist/core/transcript-extractor.d.ts.map +1 -1
  93. package/dist/core/transcript-extractor.js +5 -364
  94. package/dist/core/transcript-extractor.js.map +1 -1
  95. package/dist/core/transcript-source.d.ts +22 -6
  96. package/dist/core/transcript-source.d.ts.map +1 -1
  97. package/dist/core/transcript-source.js +108 -69
  98. package/dist/core/transcript-source.js.map +1 -1
  99. package/dist/core/types.d.ts +1 -17
  100. package/dist/core/types.d.ts.map +1 -1
  101. package/dist/core/version-check.d.ts +1 -0
  102. package/dist/core/version-check.d.ts.map +1 -1
  103. package/dist/core/version-check.js +46 -1
  104. package/dist/core/version-check.js.map +1 -1
  105. package/dist/db.d.ts +0 -34
  106. package/dist/db.d.ts.map +1 -1
  107. package/dist/db.js +6 -287
  108. package/dist/db.js.map +1 -1
  109. package/dist/host-runtime/acp.d.ts.map +1 -1
  110. package/dist/host-runtime/acp.js +4 -3
  111. package/dist/host-runtime/acp.js.map +1 -1
  112. package/dist/host-runtime/claude.d.ts.map +1 -1
  113. package/dist/host-runtime/claude.js +11 -11
  114. package/dist/host-runtime/claude.js.map +1 -1
  115. package/dist/host-runtime/codex-session.d.ts +9 -1
  116. package/dist/host-runtime/codex-session.d.ts.map +1 -1
  117. package/dist/host-runtime/codex-session.js +474 -29
  118. package/dist/host-runtime/codex-session.js.map +1 -1
  119. package/dist/host-runtime/codex.d.ts.map +1 -1
  120. package/dist/host-runtime/codex.js +4 -3
  121. package/dist/host-runtime/codex.js.map +1 -1
  122. package/dist/host-runtime/config.d.ts +1 -0
  123. package/dist/host-runtime/config.d.ts.map +1 -1
  124. package/dist/host-runtime/config.js +4 -0
  125. package/dist/host-runtime/config.js.map +1 -1
  126. package/dist/host-runtime/entry.d.ts +5 -0
  127. package/dist/host-runtime/entry.d.ts.map +1 -0
  128. package/dist/host-runtime/entry.js +11 -0
  129. package/dist/host-runtime/entry.js.map +1 -0
  130. package/dist/host-runtime/router-client.d.ts.map +1 -1
  131. package/dist/host-runtime/router-client.js +62 -15
  132. package/dist/host-runtime/router-client.js.map +1 -1
  133. package/dist/host-runtime/router.js +2 -2
  134. package/dist/host-runtime/router.js.map +1 -1
  135. package/dist/knowledge-graph.d.ts +0 -1
  136. package/dist/knowledge-graph.d.ts.map +1 -1
  137. package/dist/knowledge-graph.js +77 -60
  138. package/dist/knowledge-graph.js.map +1 -1
  139. package/dist/mcp/THIRD_PARTY_NOTICES.txt +217 -0
  140. package/dist/mcp/server.js +30685 -38
  141. package/dist/mcp/server.js.map +6 -1
  142. package/dist/skills-manifest.json +39 -34
  143. package/dist/storage/entity-index.d.ts +3 -0
  144. package/dist/storage/entity-index.d.ts.map +1 -0
  145. package/dist/storage/entity-index.js +8 -0
  146. package/dist/storage/entity-index.js.map +1 -0
  147. package/dist/storage/fts-index.d.ts.map +1 -1
  148. package/dist/storage/fts-index.js +11 -7
  149. package/dist/storage/fts-index.js.map +1 -1
  150. package/dist/storage/graph-repairs.d.ts +7 -2
  151. package/dist/storage/graph-repairs.d.ts.map +1 -1
  152. package/dist/storage/graph-repairs.js +89 -13
  153. package/dist/storage/graph-repairs.js.map +1 -1
  154. package/dist/storage/schema.d.ts +1 -1
  155. package/dist/storage/schema.d.ts.map +1 -1
  156. package/dist/storage/schema.js +1 -2
  157. package/dist/storage/schema.js.map +1 -1
  158. package/dist/storage/sqlite.d.ts +0 -1
  159. package/dist/storage/sqlite.d.ts.map +1 -1
  160. package/dist/storage/sqlite.js.map +1 -1
  161. package/dist/transports/agent-messaging.d.ts.map +1 -1
  162. package/dist/transports/agent-messaging.js +5 -7
  163. package/dist/transports/agent-messaging.js.map +1 -1
  164. package/dist/transports/cli/cli.d.ts.map +1 -1
  165. package/dist/transports/cli/cli.js +75 -686
  166. package/dist/transports/cli/cli.js.map +1 -1
  167. package/dist/transports/http/retired-routes.js +1 -1
  168. package/dist/transports/http/retired-routes.js.map +1 -1
  169. package/dist/transports/http/server.d.ts.map +1 -1
  170. package/dist/transports/http/server.js +13 -232
  171. package/dist/transports/http/server.js.map +1 -1
  172. package/dist/transports/mcp/handlers.d.ts +130 -4
  173. package/dist/transports/mcp/handlers.d.ts.map +1 -1
  174. package/dist/transports/mcp/handlers.js +56 -7
  175. package/dist/transports/mcp/handlers.js.map +1 -1
  176. package/dist/transports/schemas.d.ts +71 -19
  177. package/dist/transports/schemas.d.ts.map +1 -1
  178. package/dist/transports/schemas.js +57 -11
  179. package/dist/transports/schemas.js.map +1 -1
  180. package/docs/platforms/README.md +6 -5
  181. package/docs/platforms/agent-messaging.md +241 -20
  182. package/hooks/hooks.json +23 -2
  183. package/llms-install.md +62 -30
  184. package/package.json +12 -9
  185. package/scripts/hooks/_generated/agent-message-inbox.js +23 -4
  186. package/scripts/hooks/_generated/core-paths.js +88 -14
  187. package/scripts/hooks/_generated/fts-index.js +11 -7
  188. package/scripts/hooks/_generated/schema.js +1 -2
  189. package/scripts/hooks/_shared.js +65 -23
  190. package/scripts/hooks/decision-nudge.js +152 -0
  191. package/scripts/hooks/post-commit.js +11 -0
  192. package/scripts/hooks/pre-compact.js +12 -4
  193. package/scripts/hooks/session-start.js +32 -9
  194. package/scripts/hooks/session-summary.js +19 -374
  195. package/scripts/upgrade-plugin.sh +71 -2
  196. package/skills/memesh/SKILL.md +24 -15
  197. package/skills/memesh-review/SKILL.md +7 -6
  198. package/dist/core/auto-tagger.d.ts +0 -10
  199. package/dist/core/auto-tagger.d.ts.map +0 -1
  200. package/dist/core/auto-tagger.js +0 -63
  201. package/dist/core/auto-tagger.js.map +0 -1
  202. package/dist/core/conflict-candidates.d.ts +0 -20
  203. package/dist/core/conflict-candidates.d.ts.map +0 -1
  204. package/dist/core/conflict-candidates.js +0 -71
  205. package/dist/core/conflict-candidates.js.map +0 -1
  206. package/dist/core/conflict-judge.d.ts +0 -58
  207. package/dist/core/conflict-judge.d.ts.map +0 -1
  208. package/dist/core/conflict-judge.js +0 -189
  209. package/dist/core/conflict-judge.js.map +0 -1
  210. package/dist/core/digest-validator.d.ts +0 -18
  211. package/dist/core/digest-validator.d.ts.map +0 -1
  212. package/dist/core/digest-validator.js +0 -85
  213. package/dist/core/digest-validator.js.map +0 -1
  214. package/dist/core/embedder.d.ts +0 -20
  215. package/dist/core/embedder.d.ts.map +0 -1
  216. package/dist/core/embedder.js +0 -242
  217. package/dist/core/embedder.js.map +0 -1
  218. package/dist/core/failure-analyzer.d.ts +0 -19
  219. package/dist/core/failure-analyzer.d.ts.map +0 -1
  220. package/dist/core/failure-analyzer.js +0 -83
  221. package/dist/core/failure-analyzer.js.map +0 -1
  222. package/dist/core/json-utils.d.ts +0 -3
  223. package/dist/core/json-utils.d.ts.map +0 -1
  224. package/dist/core/json-utils.js +0 -46
  225. package/dist/core/json-utils.js.map +0 -1
  226. package/dist/core/llm-client.d.ts +0 -22
  227. package/dist/core/llm-client.d.ts.map +0 -1
  228. package/dist/core/llm-client.js +0 -203
  229. package/dist/core/llm-client.js.map +0 -1
  230. package/dist/core/llm-telemetry.d.ts +0 -47
  231. package/dist/core/llm-telemetry.d.ts.map +0 -1
  232. package/dist/core/llm-telemetry.js +0 -117
  233. package/dist/core/llm-telemetry.js.map +0 -1
  234. package/dist/core/llm-validator.d.ts +0 -20
  235. package/dist/core/llm-validator.d.ts.map +0 -1
  236. package/dist/core/llm-validator.js +0 -231
  237. package/dist/core/llm-validator.js.map +0 -1
  238. package/dist/core/ollama-host.d.ts +0 -6
  239. package/dist/core/ollama-host.d.ts.map +0 -1
  240. package/dist/core/ollama-host.js +0 -30
  241. package/dist/core/ollama-host.js.map +0 -1
  242. package/dist/core/output-language.d.ts +0 -6
  243. package/dist/core/output-language.d.ts.map +0 -1
  244. package/dist/core/output-language.js +0 -25
  245. package/dist/core/output-language.js.map +0 -1
  246. package/dist/core/prompt-safety.d.ts +0 -4
  247. package/dist/core/prompt-safety.d.ts.map +0 -1
  248. package/dist/core/prompt-safety.js +0 -20
  249. package/dist/core/prompt-safety.js.map +0 -1
  250. package/dist/storage/vector-index.d.ts +0 -3
  251. package/dist/storage/vector-index.d.ts.map +0 -1
  252. package/dist/storage/vector-index.js +0 -13
  253. package/dist/storage/vector-index.js.map +0 -1
  254. /package/{.mcp.json → .claude-plugin/mcp.json} +0 -0
@@ -77,30 +77,58 @@ Linux. Windows remains supported for core MeMesh memory, durable message
77
77
  storage, and MCP tools, but host-native wakeup fails closed before creating
78
78
  credentials, configuration, IPC listeners, or managed child processes.
79
79
 
80
- Create one reusable owner-private config for each local path and principal.
81
- The stable principal is the logical recipient. Managed processes generate a
82
- fresh exact session identity; the ordinary Codex path instead uses the Codex
83
- thread identity supplied at SessionStart. No thread ID is copied by hand.
84
- Ordinary sessions outside the explicit `codex-session` workspace opt-in remain
85
- `presence-only/inbound-unavailable`.
80
+ The default local endpoint is versioned with the wire protocol
81
+ (`agent-router-v2.sock`). This lets a current router start beside an incompatible
82
+ legacy daemon after an upgrade instead of killing it or taking over its live
83
+ socket. Existing generated configs that name the former default are normalized
84
+ in memory; an explicit custom socket remains exact and reports
85
+ `router_version_mismatch` when it exposes the known legacy response shape.
86
+
87
+ Create one reusable owner-private config for each managed local host and
88
+ principal. The stable principal is the logical recipient. Managed processes
89
+ generate a fresh exact session identity. Ordinary Codex plugin sessions instead
90
+ register automatically from the Codex thread identity supplied at SessionStart,
91
+ using a distinct thread-scoped principal; no thread ID is copied by hand.
86
92
 
87
93
  ```bash
88
- memesh agent setup codex-session --project my-project --principal codex-reviewer --workspace "$PWD"
89
94
  memesh agent setup codex --project my-project --principal codex-reviewer --workspace "$PWD"
90
95
  memesh agent setup claude --project my-project --principal claude-reviewer
91
96
  ```
92
97
 
93
98
  Optional declarations can be persisted with `--model <id>` and
94
99
  `--work-summary <text>` (each is capped at 200 characters); no defaults are guessed.
100
+ For ordinary Codex only, `memesh agent setup codex-session ...` is an optional
101
+ workspace-specific stable-principal override, not an activation prerequisite.
102
+ When pairing Claude Channel with an automatically registered Codex session,
103
+ use the complete `project` field returned by `memesh briefing --json` in the
104
+ Claude setup command. A repository basename is not equivalent to the automatic
105
+ collision-resistant project identity, and different project strings cannot
106
+ discover or natively route to each other.
95
107
 
96
108
  ### Ordinary active Codex CLI session
97
109
 
98
- `codex-session` is the opt-in path for an ordinary local Codex session and
99
- requires the MeMesh Codex plugin to be installed and enabled so Codex loads
100
- the packaged SessionStart hook. Run
101
- the setup command from the exact workspace that Codex will use; it stores the
102
- configured real workspace and stable principal in the owner-private
103
- `codex-session.json` config. Restart Codex in that workspace after setup.
110
+ An ordinary local Codex session requires the MeMesh Codex plugin to be installed
111
+ and enabled so Codex loads the packaged SessionStart hook. Each startup or
112
+ resumed thread then registers automatically under the current project with a
113
+ thread-scoped principal. Use `message discover` to obtain the exact live session
114
+ ID. No manual `agent setup` is required.
115
+
116
+ The automatic project is a readable repo label plus a 32-hex identity suffix.
117
+ For a network Git remote, the suffix covers a password-free locator; otherwise
118
+ it covers the native real path. Standard GitHub HTTPS and SSH spellings
119
+ converge. Generic SSH locators keep the login and whether the repository path is
120
+ absolute or relative to that login's home, preventing distinct accounts or
121
+ paths from sharing one scope. This keeps the same repo together across
122
+ subdirectories, symlinks, remote-backed clones, and linked worktrees without
123
+ letting two unrelated repos named `shared` discover or receive each other's
124
+ messages. `memesh briefing` in that workspace reports the exact project value.
125
+
126
+ If one workspace needs a stable named principal across different threads, run
127
+ `memesh agent setup codex-session --project my-project --principal codex-reviewer
128
+ --workspace "$PWD"` there and restart Codex. The owner-private config overrides
129
+ project and principal only when its exact real workspace matches. Another
130
+ workspace still uses automatic identity; a malformed or insecure override fails
131
+ closed rather than silently downgrading.
104
132
 
105
133
  This guide's supported documented path is ordinary Codex CLI `SessionStart`.
106
134
  Codex Desktop or an unattached task is not user-visible native-delivery
@@ -108,23 +136,28 @@ evidence unless that exact live session registers with the router and the
108
136
  result is directly verified. This is a scope boundary for evidence, not a
109
137
  claim that Codex Desktop is universally unsupported.
110
138
 
111
- On `SessionStart` for `startup` or `resume`, the asynchronous companion checks
112
- the Codex thread identity, hook session identity, and configured workspace
113
- realpath before it connects to the router. A missing identity, a different
114
- workspace, compact lifecycle input, or a failed/disconnected connection does
115
- not register a host and does not wake anything.
139
+ On `SessionStart` for `startup` or `resume`, a short hook validates the Codex
140
+ thread identity and cwd, then launches an owner-private detached companion.
141
+ Detachment is required because Codex reaps an async hook child when the CLI
142
+ process exits, while `codex queue` accepts the thread only after its active
143
+ writer is gone. `SessionEnd` leaves a bounded 45-second idle queue window;
144
+ resume replaces the prior exact generation through its private control socket,
145
+ and expiry removes the registration. A missing or malformed identity, invalid
146
+ cwd, insecure explicit override, or failed connection does not register a host.
116
147
 
117
148
  For a registered session, MeMesh invokes `codex queue` with one untrusted full
118
149
  envelope capped at 16,384 bytes (16 KiB), including routing metadata and payload.
119
150
  The separate durable JSON-encoded payload limit is 65,536 bytes (64 KiB). The exact-session sender returns
120
151
  `native_delivery.status: "native_accepted"` only after the queue accepts it;
121
152
  Codex does not need a second `message fetch` to inspect that native message.
153
+ For ordinary CLI, a message accepted in the idle window becomes model-visible
154
+ when that same thread resumes; it does not wake a stopped terminal or Desktop UI.
122
155
  The persisted `host_accept` is neither agent readback nor an `ack` or workflow
123
156
  disposition. Codex exposes message text only through its `--message` process
124
157
  argument, so same-user process inspection may observe it while the short-lived
125
158
  queue command runs; do not put secrets in native messages.
126
159
 
127
- If the configured Codex session is stopped, missing, disconnected, or no
160
+ If the target Codex session is stopped, missing, disconnected, or no
128
161
  longer matches its configured workspace, MeMesh does not start or replace it.
129
162
  An exact-session send reports `recipient_unavailable`; durable scoped recovery
130
163
  and receipt history remain available to fetch, cursor recovery, `poll`, or
@@ -203,6 +236,194 @@ for active Codex-session delivery.
203
236
  - `intake`, `ack`, `disposition`, and `activation` are explicit, separate, idempotent receipt facts. Inbox/MCP ACK is valid without a host-native acceptance; host-native ACK remains bound to its `host_accept`. `receipts` returns one ordered projection and identifies each underlying fact source. For example, `manual_resume_required` does not imply ACK, acceptance, rejection, cancellation, or completion.
204
237
  - The transport, rather than model-provided payload data, records sender-host provenance.
205
238
 
239
+ ## Repeatable owner-run live checks
240
+
241
+ Everything above is checked by the test suite against stubs and fakes. That
242
+ proves the plumbing and nothing about a live model: a queue admission or a
243
+ `host_accept` is a statement about a frame, not about cognition. Two checks
244
+ close that gap by requiring evidence that could only have come out of a running
245
+ model.
246
+
247
+ ```bash
248
+ MEMESH_CODEX_QA_HOME="$(mktemp -d /private/tmp/memesh-codex-qa.XXXXXX)"
249
+ CODEX_HOME="$MEMESH_CODEX_QA_HOME" codex login
250
+ TMPDIR=/private/tmp npm run qa:live-journey -- --host codex --codex-home "$MEMESH_CODEX_QA_HOME" --out .qa/codex-report.json
251
+ TMPDIR=/private/tmp npm run qa:live-journey -- --host claude --out .qa/claude-report.json
252
+ ```
253
+
254
+ `.qa/` is where `npm run release:finish` looks for release receipts. Codex and
255
+ Claude are separate delivery claims, so **both** must PASS within 24 hours
256
+ against the exact clean commit being released, with current `dist/`, ordered
257
+ lifecycle steps, lease renewal, model-visible evidence, and the stopped-session
258
+ failure path. The installed Codex receipt also requires actual plugin
259
+ SessionStart loading and a resume that supersedes the prior generation.
260
+ One host can never satisfy the other host's gate. The commands above produce
261
+ `.qa/codex-report.json` and `.qa/claude-report.json`, respectively. The directory
262
+ is gitignored; reports are owner-machine evidence, never shipped.
263
+
264
+ `TMPDIR` is not decoration on macOS. The router's Unix socket lives beside the
265
+ database inside the temporary directory, and `AF_UNIX` caps a socket path at
266
+ 104 bytes; the platform default `os.tmpdir()` spends about half of that before
267
+ the check adds anything. The script measures its own socket path and refuses
268
+ with this hint rather than starting a router that cannot bind.
269
+
270
+ `scripts/qa/live-journey.mjs` is owner-run and refuses to start when `CI` is
271
+ set, because neither check can run unattended: one needs the owner's Codex
272
+ login, the other needs a person at an interactive Claude session. Its argument
273
+ parsing, its refusals, and every **pure** assertion it makes are unit-tested in
274
+ `tests/qa/live-journey.test.ts`, which does run in CI against recorded
275
+ fixtures; the orchestration around them is exercised only by a live run.
276
+
277
+ Everything MeMesh writes goes into a fresh `mktemp` MEMESH_DIR that is deleted
278
+ on exit (`--keep` retains it), against this repository's own `dist/`. The check
279
+ refuses to start if that directory would resolve inside `$HOME/.memesh` — the
280
+ comparison is made on **real** paths, before anything is created, so a
281
+ symlinked `TMPDIR` cannot get past it — or if `dist/` has not been built. It
282
+ reads no authentication file. Where that isolation stops is listed under
283
+ limitations below, and the report records whether the working tree was dirty
284
+ and whether `dist/` predates the newest file under `src/`.
285
+
286
+ Shutdown order is part of the design rather than an afterthought. A connected
287
+ host that sees the router socket disappear starts a **detached** packaged
288
+ router inheriting its own environment — including this check's `MEMESH_DIR` —
289
+ and the router recreates its data directory on start. The check therefore stops
290
+ the companion, waits for live sessions to disconnect, stops the router, and
291
+ only then removes the directory; if a session is still connected when the wait
292
+ expires it keeps the directory rather than racing that spawn. The same sequence
293
+ runs on failures and on `SIGINT`/`SIGTERM`.
294
+
295
+ **`--host codex`** installs the candidate plugin into the caller-prepared
296
+ authenticated `--codex-home`, verifies its cache, and creates a real Codex CLI
297
+ thread. The installed plugin's SessionStart hook registers the thread; the
298
+ runner never starts its companion. The check verifies lease renewal,
299
+ exact-session delivery, resume-generation supersession, renewed lease, and a
300
+ reply quoting the envelope's sentinel, `message_id`, and `delivery_id`.
301
+
302
+ The proof rejects other command/tool activity except the narrowly allowed
303
+ installed-skill read and failed work-package prepare probe; neither may contain
304
+ proof identifiers. After SessionEnd retirement, the next send must return
305
+ `recipient_unavailable` while the durable payload remains fetchable.
306
+ Its v3 report requires registration from `codex_plugin_session_start` with
307
+ `plugin_loader_verified: true`, including a renewed lease after resume supersedes
308
+ the startup generation. `release:finish` requires separate current-candidate
309
+ v3 receipts for both Codex and Claude; an old harness-injected v2 report does not
310
+ prove automatic installed-plugin registration and is rejected.
311
+
312
+ **`--host claude`** starts the router, runs `memesh agent setup claude`, writes
313
+ a temporary MCP config, and prints the exact interactive launch command — which
314
+ includes `--setting-sources ""` to request no user, project, or local settings
315
+ source. That option did not suppress all `[User]` hooks in a live Claude Code
316
+ 2.1.263 check, so it is not treated as plugin isolation. The operator runs
317
+ the command, checks `/mcp` and `/hooks` for any installed MeMesh plugin hook or
318
+ extra MeMesh MCP server, and types the exact isolation confirmation token in the
319
+ runner terminal. Other non-MeMesh hooks are outside this check. The token records
320
+ operator attestation, not programmatic inspection. The runner then prints one
321
+ trusted owner prompt: the operator submits it in Claude and confirms only after
322
+ Claude replies `READY_FOR_UNTRUSTED_INTAKE`. That second attestation must also
323
+ precede nonce generation. Only then does the runner wait for
324
+ `lease_expires_at_ms` to advance, send one inert exact-session payload containing
325
+ only its purpose and nonce, and wait for an
326
+ `intake` receipt on that message whose actor is that session — the model must
327
+ call `intake` exactly once under the prior trusted instruction, using the
328
+ documented `intake-<message_id>` idempotency key and only the six fields the
329
+ strict intake schema accepts (`action`, `project`, `recipient`, `message_id`,
330
+ `intake_state`, `idempotency_key`). This is what makes the proof
331
+ model-visible rather than transport-visible without treating the untrusted
332
+ payload as instructions. The operator is then asked to exit the session, and
333
+ the same fail-closed assertion runs. A reminder entered only after delivery is
334
+ diagnostic and cannot satisfy this release receipt.
335
+
336
+ Print mode (`claude -p`) is **not supported** and is deliberately not
337
+ exercised. A print-mode session does not surface `memesh-channel` notifications
338
+ to the model even when the channel host reports the frame accepted, so it can
339
+ never produce the receipt this check requires.
340
+
341
+ Each run writes a JSON report: the repository revision, every `message_id` and
342
+ `delivery_id`, the `native_delivery` receipts, the model-visible evidence, and
343
+ a `limitations` list. The exit code is 0 only when every required step passed.
344
+ The limitations these checks always declare:
345
+
346
+ - The Codex journey installs the candidate plugin into a caller-created
347
+ disposable authenticated `CODEX_HOME`, verifies the installed cache bytes,
348
+ and exercises that plugin's SessionStart and SessionEnd hooks through a real
349
+ Codex thread. It does not mutate the owner's normal Codex configuration. The
350
+ bounded `--codex-session-auto-registration` mode remains a narrower
351
+ account-free packaged router → native queue check and is not a substitute for
352
+ this installed-plugin journey.
353
+ - The interactive Claude session is **outside** this check's isolation.
354
+ `--setting-sources ""` is accepted by the CLI (an invalid source name is
355
+ rejected, an empty list is not), but it is not verified to exclude
356
+ plugin-provided hooks or MCP servers. A MeMesh plugin hook running in that
357
+ session inherits no `MEMESH_DIR` and would write the owner's real
358
+ `~/.memesh`. Before nonce generation or send, the runner requires the exact
359
+ confirmation token after the operator checks `/mcp` and `/hooks`. This is a
360
+ recorded human attestation, not a machine inspection; inability to identify
361
+ whether an entry comes from MeMesh means the operator must stop the run.
362
+ - `--host codex` creates one throwaway thread in the owner's Codex rollout
363
+ store and queues one message into it. That is session state, not
364
+ configuration; nothing outside the temporary directory is otherwise written.
365
+ - Before delivery, the Claude operator submits one exact trusted intake prompt
366
+ and attests that its READY reply was observed. The runner cannot inspect that
367
+ UI exchange. After delivery the operator is told to type nothing, but the
368
+ runner cannot observe whether that instruction was followed. The intake
369
+ receipt proves the model called `intake` in that session after native
370
+ notification; it does not prove the operator followed either instruction.
371
+ - The Claude intake receipt is matched on its `actor`, which `intake` sets from
372
+ the caller's `recipient`. The model must intake under its own session id; an
373
+ intake recorded against the principal id would not match, and the check would
374
+ report no model-visible proof.
375
+ - `recipient_unavailable` is a shared failure surface — the same string is
376
+ returned when the *sender* cannot reach the router. The fail-closed step
377
+ therefore also records that `message discover` still answered and that
378
+ `message fetch` still returned the payload. That pairing, not the string, is
379
+ what attributes the failure to the stopped recipient.
380
+
381
+ ## Scope identifiers
382
+
383
+ `project` and `recipient` together key one inbox, and `actor` is derived from
384
+ `recipient`, so how those three are spelled is part of the contract rather than
385
+ a formatting detail. Two spellings of one name are two inboxes: the recipient
386
+ that fetches under one never sees what was sent under the other, and a
387
+ `briefing` unread count is computed per spelling.
388
+
389
+ Every message action canonicalises them to Unicode NFC and trims surrounding
390
+ whitespace, on reads as well as writes, so a decomposed spelling reaches the
391
+ rows a composed one wrote.
392
+
393
+ A value spelled as an **absolute filesystem path is refused** — a POSIX path
394
+ (`/root`), a Windows drive path (`C:\work`), or a UNC path (`\\host\share`).
395
+ Project identity is derived from the working directory and can never take that
396
+ shape, so such a value is not an identity MeMesh produced; the error names the
397
+ field and a valid value. Callers that previously passed a home directory or a
398
+ checkout path where the agent's or project's NAME belonged must pass the name.
399
+ Nothing else is rewritten: identifiers are compared exactly, case included, and
400
+ an identifier that merely contains a separator (`team/reviewer`) is accepted.
401
+ MeMesh does not treat any prefix as a namespace, so `claude-code:reviewer` and
402
+ `reviewer` are two different recipients.
403
+
404
+ The same rule covers every surface that reads or writes that key, not only the
405
+ `message` tool: `briefing` counts unfetched deliveries for one exact
406
+ (`project`, `recipient`), and `memesh agent setup --project/--principal` writes
407
+ the identity a host will register under. A path-shaped value is refused there
408
+ too, at the moment the config is written, rather than surfacing later as an
409
+ error about some other agent's send.
410
+
411
+ `sender` is not covered by any of this. It is provenance rather than routing —
412
+ it keys no inbox, and it keys the send idempotency record — so it is stored
413
+ exactly as given, and the transport-bound provenance remains the field to trust.
414
+
415
+ Rows written before this rule are preserved byte-for-byte. MeMesh reports
416
+ path-shaped historical scope through its read-only memory invariant rather than
417
+ guessing that `/root`, `/tmp/root`, and `root` name one recipient. Such rows may
418
+ remain unreachable through the stricter public API until the owner supplies an
419
+ explicit mapping. For a confirmed project mapping, rename both its entity tags
420
+ and message scopes with the deliberate owner-run operation:
421
+
422
+ ```bash
423
+ memesh kg rename-project --from <old> --to <new> # dry run
424
+ memesh kg rename-project --from <old> --to <new> --apply # backs up first
425
+ ```
426
+
206
427
  ## Identity and lifecycle
207
428
 
208
429
  A **principal** is the stable logical recipient. A **session** is one live host connection for that principal. A **generation** changes when that session is replaced. An exact-session target never reroutes. A principal target can deliver only to an eligible active session after its activation checkpoint; it does not replay historical inbox contents into a first session.
@@ -276,7 +497,7 @@ reply, or a stopped-session wake-up.
276
497
 
277
498
  | Participant | Current path | Status today | Notes |
278
499
  |---|---|---|---|
279
- | Ordinary Codex CLI | `codex-session` owner-private opt-in | bounded full-message native delivery while active | Exact workspace, principal, and SessionStart identity must match; oversized envelopes return `native_message_too_large`, while stopped or disconnected sessions return `recipient_unavailable` |
500
+ | Ordinary Codex CLI | automatic plugin SessionStart registration; optional `codex-session` identity override | bounded full-message native delivery while active | Exact thread identity is discoverable; oversized envelopes return `native_message_too_large`, while stopped or disconnected sessions return `recipient_unavailable` |
280
501
  | MeMesh-managed Codex app-server | `memesh-host-codex` | separate managed path | It creates its own Codex thread; it does not attach to an ordinary session |
281
502
  | Claude channel | `memesh-host-claude` | separate channel path | Requires the documented Channel opt-in; no stopped-session resume |
282
503
  | Other local MCP clients | MCP, HTTP, or CLI message operations | durable messaging only | Use `poll`/`watch` and scoped fetch where their own host loop supports it; this guide makes no native-wakeup claim |
package/hooks/hooks.json CHANGED
@@ -39,8 +39,19 @@
39
39
  {
40
40
  "type": "command",
41
41
  "command": "${CLAUDE_PLUGIN_ROOT}/dist/host-runtime/codex-session.js",
42
- "async": true,
43
- "timeout": 31536000
42
+ "timeout": 10
43
+ }
44
+ ]
45
+ }
46
+ ],
47
+ "SessionEnd": [
48
+ {
49
+ "matcher": "*",
50
+ "hooks": [
51
+ {
52
+ "type": "command",
53
+ "command": "${CLAUDE_PLUGIN_ROOT}/dist/host-runtime/codex-session.js",
54
+ "timeout": 10
44
55
  }
45
56
  ]
46
57
  }
@@ -55,6 +66,16 @@
55
66
  "timeout": 5
56
67
  }
57
68
  ]
69
+ },
70
+ {
71
+ "matcher": "ExitPlanMode|AskUserQuestion",
72
+ "hooks": [
73
+ {
74
+ "type": "command",
75
+ "command": "${CLAUDE_PLUGIN_ROOT}/scripts/hooks/decision-nudge.js",
76
+ "timeout": 5
77
+ }
78
+ ]
58
79
  }
59
80
  ],
60
81
  "Stop": [
package/llms-install.md CHANGED
@@ -68,7 +68,7 @@ MEMESH_DOCTOR_PROBE_MESSAGE_CAPABILITY=1 memesh doctor
68
68
  ```
69
69
 
70
70
  This probe does not exercise a real host session and never wakes a stopped
71
- session. The ordinary Codex path below is the documented native local wakeup
71
+ session. The ordinary Codex path below is the documented bounded native queue
72
72
  path; `poll`/`watch` and cursor recovery remain available for compatibility and
73
73
  diagnosis.
74
74
 
@@ -104,8 +104,13 @@ umask 077
104
104
  memesh-router
105
105
  ```
106
106
 
107
- If you start it yourself, it creates `agent-router.sock` and `agent-router.token` beside the active
108
- MeMesh database (normally `~/.memesh/`) with owner-private permissions. Check
107
+ If you start it yourself, it creates the current protocol endpoint
108
+ `agent-router-v2.sock` and the shared `agent-router.token` beside the active
109
+ MeMesh database (normally `~/.memesh/`) with owner-private permissions. After
110
+ an upgrade, an older router may remain on its legacy socket until its old
111
+ sessions exit or the machine restarts. Current clients do not attach to it,
112
+ and MeMesh does not kill or unlink a live process without durable ownership
113
+ proof. Check
109
114
  the installed adapter imports and the live socket as distinct facts:
110
115
 
111
116
  ```bash
@@ -117,10 +122,20 @@ The router probe does not register a host, send content, or wake a stopped
117
122
  session. Generate reusable `0600` configs; session identities are not copied
118
123
  from an active ordinary session.
119
124
 
120
- For an ordinary active local Codex session, first install and enable the MeMesh
121
- Codex plugin (Option A), which supplies the packaged SessionStart hook. Then
122
- run this from the exact workspace you want to configure and restart Codex in
123
- that same workspace:
125
+ For an ordinary active local Codex session, install and enable the MeMesh
126
+ Codex plugin (Option A), which supplies the packaged SessionStart hook. On the
127
+ next startup or resume, that thread registers automatically under the current
128
+ project with a thread-scoped principal. First read the exact automatic project
129
+ value, then copy its `project` field into the discover command:
130
+
131
+ ```bash
132
+ memesh briefing --json
133
+ memesh message discover --project '<project from briefing>'
134
+ ```
135
+
136
+ No manual host setup is required. If one exact workspace needs a stable named
137
+ principal across different Codex threads, create this optional override and
138
+ restart Codex in that workspace:
124
139
 
125
140
  ```bash
126
141
  memesh agent setup codex-session --project my-project --principal codex-recipient --workspace "$PWD"
@@ -128,22 +143,34 @@ memesh agent setup codex-session --project my-project --principal codex-recipien
128
143
 
129
144
  This stores the configured workspace realpath and principal in
130
145
  `~/.memesh/hosts/codex-session.json`. On `SessionStart` (`startup` or
131
- `resume`), an asynchronous companion registers only when its Codex thread ID,
132
- hook session ID, and workspace realpath match that config. The authenticated
133
- router sends the active exact session one bounded full message through native
134
- `codex queue`; no second `message fetch` is required for that live delivery.
146
+ `resume`), a short hook validates the Codex thread ID and cwd, then launches an
147
+ owner-private detached companion. SessionEnd leaves a bounded 45-second idle
148
+ queue window; resume replaces the prior generation, and expiry removes it. A
149
+ matching valid override supplies its project and principal; another workspace
150
+ keeps automatic thread-scoped registration. A malformed or insecure override
151
+ fails closed. The authenticated router sends the exact registered thread one
152
+ bounded full message through native `codex queue`; no second `message fetch`
153
+ is required. A message accepted during the idle window becomes model-visible
154
+ when the same thread resumes; a stopped UI is not awakened.
135
155
 
136
156
  `host_accept` records only that the local Codex queue accepted that message. It
137
157
  does not prove an agent read the payload, acknowledged it, or accepted the
138
158
  work. Codex exposes message text through its `--message` process argument, so
139
159
  same-user process inspection may observe it while the queue command runs; do
140
- not send secrets through the native path. If the session is stopped, missing, disconnected, or in another
141
- workspace, MeMesh neither starts nor replaces it; the durable inbox remains
160
+ not send secrets through the native path. If the session is stopped, missing,
161
+ or disconnected, MeMesh neither starts nor replaces it; the durable inbox remains
142
162
  available to scoped fetch, cursor recovery, `poll`, and `memesh message watch`
143
- for audit and diagnosis.
163
+ for audit and diagnosis. Failed exact-session native delivery is not replayed
164
+ automatically after a later registration; the sender must retry deliberately.
144
165
 
145
166
  The following are separate managed-host paths:
146
167
 
168
+ When pairing Claude Channel with an automatically registered Codex session,
169
+ copy the complete `project` value from `memesh briefing --json` into the Claude
170
+ setup command. Do not substitute the repository basename: automatic project
171
+ identities include a collision-resistant suffix, and different project strings
172
+ cannot discover or natively route to each other.
173
+
147
174
  ```bash
148
175
  memesh agent setup codex --project my-project --principal codex-recipient --workspace "$PWD"
149
176
  memesh-host-codex --config "$HOME/.memesh/hosts/codex.json"
@@ -192,13 +219,17 @@ memesh doctor
192
219
 
193
220
  ## 3. Codex CLI
194
221
 
195
- Prerequisite: section 2 `memesh-mcp` must resolve on PATH.
222
+ Install from the Codex plugin marketplace for zero-config MCP tools and the
223
+ SessionStart/SessionEnd companion lifecycle:
196
224
 
197
225
  ```
198
- codex mcp add memesh -- memesh-mcp
226
+ codex plugin marketplace add PCIRCLE-AI/memesh
227
+ codex plugin add memesh@pcircle-memesh
199
228
  ```
200
229
 
201
- Writes `[mcp_servers.memesh]` into `~/.codex/config.toml`.
230
+ The plugin manifest starts its bundled `dist/mcp/server.js` directly from the
231
+ plugin cache. It does not need a global `memesh-mcp` command or a manual
232
+ `codex mcp add` entry.
202
233
 
203
234
  **Verify**:
204
235
 
@@ -208,33 +239,34 @@ codex mcp list
208
239
 
209
240
  Expected: `memesh` is listed as enabled.
210
241
 
211
- ### Optional: Codex plugin marketplace
242
+ ### Manual npm-global alternative
212
243
 
213
- Current Codex CLI versions can install the repository's plugin marketplace
214
- directly. For a fresh install:
244
+ If you installed section 2 instead of the Codex plugin, register the global
245
+ stdio command manually:
215
246
 
216
247
  ```
217
- codex plugin marketplace add PCIRCLE-AI/memesh
218
- codex plugin add memesh@pcircle-memesh
248
+ codex mcp add memesh -- memesh-mcp
219
249
  ```
220
250
 
221
- If the configured marketplace snapshot is stale, refresh it and reinstall the
222
- plugin:
251
+ This writes `[mcp_servers.memesh]` into `~/.codex/config.toml`.
252
+
253
+ ### Refresh a stale plugin cache
254
+
255
+ If the configured marketplace snapshot is stale, refresh it and re-stage the
256
+ plugin. `codex plugin add` replaces the installed cache atomically, so do not
257
+ remove the working plugin first:
223
258
 
224
259
  ```
225
260
  codex plugin marketplace upgrade pcircle-memesh
226
- codex plugin remove memesh
227
261
  codex plugin add memesh@pcircle-memesh
228
262
  ```
229
263
 
230
- These commands are separate from the MCP registration above; keep the MCP
231
- path when a host needs `memesh-mcp` directly.
232
-
233
264
  | Failure | Remedy |
234
265
  |---|---|
235
266
  | `command not found: codex` | Codex CLI itself is not installed — out of scope here; install it first, then re-run the add. |
236
- | `memesh` absent from the list | The add did not persist. Re-run `codex mcp add memesh -- memesh-mcp` and re-check. |
237
- | Listed, but tool calls fail | Run `command -v memesh-mcp`. Empty output means section 2 is incomplete or PATH is wrong — fix per section 2's table. |
267
+ | Plugin-installed `memesh` is absent | Refresh and reinstall the plugin using the commands above, then restart Codex. |
268
+ | Manually registered `memesh` is absent | Re-run `codex mcp add memesh -- memesh-mcp` and re-check. |
269
+ | Manual registration is listed, but tool calls fail | Run `command -v memesh-mcp`. Empty output means section 2 is incomplete or PATH is wrong — fix per section 2's table. |
238
270
 
239
271
  ## 4. Cursor
240
272
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@pcircle/memesh",
3
- "version": "4.8.3",
4
- "description": "MeMesh \u2014 agentic memory for coding agents. Captured from the agent's real work via hooks, recalled when it acts. One SQLite file, zero cloud required.",
3
+ "version": "4.9.0",
4
+ "description": "MeMesh agentic memory for coding agents. Captured from the agent's real work via hooks, recalled when it acts. One SQLite file, zero cloud required.",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",
7
7
  "bin": {
@@ -17,7 +17,6 @@
17
17
  "files": [
18
18
  "dist/",
19
19
  "dashboard/dist/",
20
- ".mcp.json",
21
20
  "hooks/hooks.json",
22
21
  "scripts/hooks/",
23
22
  "scripts/upgrade-plugin.sh",
@@ -31,13 +30,11 @@
31
30
  "AGENTS.md"
32
31
  ],
33
32
  "scripts": {
34
- "build": "node scripts/check-schema-drift.mjs && tsc && node scripts/generate-hook-core.mjs && node scripts/copy-cli-assets.mjs && node scripts/set-executable-bits.mjs && node scripts/generate-skills-manifest.mjs && npm run build:dashboard && node scripts/smoke-test.mjs",
33
+ "build": "node scripts/check-schema-drift.mjs && tsc && node scripts/build-mcp-bundle.mjs && node scripts/generate-hook-core.mjs && node scripts/copy-cli-assets.mjs && node scripts/set-executable-bits.mjs && node scripts/generate-skills-manifest.mjs && npm run build:dashboard && node scripts/smoke-test.mjs",
35
34
  "build:dashboard": "node scripts/build-dashboard.mjs",
36
35
  "test": "vitest",
37
36
  "test:e2e-dashboard": "node scripts/dashboard-e2e-smoke.mjs",
38
37
  "test:issue-224": "vitest run tests/dashboard/issue-224-data-refresh.test.tsx --maxWorkers=1",
39
- "test:issue-225": "vitest run tests/dashboard/issue-225-language-persistence.test.tsx --maxWorkers=1",
40
- "test:issue-226": "vitest run tests/dashboard/SettingsTab-primary-llm.test.tsx tests/transports/http.test.ts --maxWorkers=1",
41
38
  "test:issue-227": "vitest run tests/dashboard/ProjectRoadmap.test.tsx --maxWorkers=1",
42
39
  "test:issue-228": "vitest run tests/dashboard/FeedbackWidget.test.tsx --maxWorkers=1",
43
40
  "test:issue-229": "vitest run tests/dashboard/OnboardingBanner.test.tsx tests/dashboard-i18n.test.ts --maxWorkers=1",
@@ -51,14 +48,20 @@
51
48
  "check:surface-parity": "node scripts/check-readme-tool-parity.mjs && node scripts/check-codemap-parity.mjs",
52
49
  "audit:prod": "node scripts/check-consumer-audit.mjs",
53
50
  "audit:memory": "node scripts/audit/memory-invariants.mjs",
54
- "verify:release": "npm run lint && npm run typecheck && node scripts/check-version-coherence.mjs && node scripts/check-generated-mirror.mjs && node scripts/check-agent-message-sync.mjs && npm run check:surface-parity && node scripts/check-doc-claims.mjs && node scripts/audit/verification-audit.mjs && npm run audit:prod",
51
+ "check:entry-points-start": "node scripts/check-entry-points-start.mjs",
52
+ "verify:release": "npm run lint && npm run typecheck && node scripts/check-version-coherence.mjs && node scripts/check-generated-mirror.mjs && node scripts/check-agent-message-sync.mjs && npm run check:surface-parity && node scripts/check-doc-claims.mjs && node scripts/audit/verification-audit.mjs && npm run audit:prod && npm run check:entry-points-start",
55
53
  "release:finish": "node scripts/finish-release.mjs",
56
- "prepublishOnly": "npm run build && npm run verify:release && npm run test:isolated && npm run test:packaged && npm run test:packaged:upgrade",
54
+ "verify:artifact": "npm run verify:release && npm run test:isolated && npm run test:packaged && npm run test:packaged:upgrade",
55
+ "prepublishOnly": "npm run build && npm run verify:artifact",
57
56
  "typecheck": "tsc -p tsconfig.check.json && tsc -p tsconfig.check-dashboard.json",
58
57
  "lint": "eslint src/ scripts/ tests/ dashboard/src/ --max-warnings 0",
59
58
  "lint:fix": "eslint src/ scripts/ tests/ dashboard/src/ --fix",
60
59
  "start": "node dist/mcp/server.js",
61
60
  "bench:longmemeval": "node benchmarks/longmemeval/run.mjs --mode A --dataset /tmp/longmemeval_s.json",
61
+ "qa:live-journey": "node scripts/qa/live-journey.mjs",
62
+ "qa:pre-release": "node scripts/qa/pre-release.mjs",
63
+ "qa:ui-review": "node scripts/qa/ui-review.mjs",
64
+ "qa:post-release": "node scripts/qa/post-release.mjs",
62
65
  "test:isolated": "node scripts/run-tests-isolated.mjs",
63
66
  "test:coverage": "node scripts/run-tests-isolated.mjs --coverage"
64
67
  },
@@ -89,7 +92,6 @@
89
92
  "commander": "^14.0.3",
90
93
  "express": "^5.2.1",
91
94
  "express-rate-limit": "8.5.1",
92
- "sqlite-vec": "^0.1.9",
93
95
  "ws": "^8.21.3",
94
96
  "zod": "4.4.3"
95
97
  },
@@ -117,6 +119,7 @@
117
119
  "@types/node": "25.6.2",
118
120
  "@types/ws": "^8.18.1",
119
121
  "@vitest/coverage-v8": "4.1.5",
122
+ "esbuild": "0.28.1",
120
123
  "eslint": "^10.3.0",
121
124
  "happy-dom": "^20.9.0",
122
125
  "playwright": "^1.59.1",
@@ -28,11 +28,30 @@ export function unreadDeliveryCount(db, project, recipient) {
28
28
  return 0;
29
29
  }
30
30
  }
31
- export function unreadInboxLines(count, project, recipient) {
32
- if (count <= 0 || !recipient)
31
+ export function recipientEverSeen(db, project, recipient) {
32
+ try {
33
+ const row = db.prepare(`SELECT (
34
+ EXISTS(SELECT 1 FROM agent_principals WHERE project = ? AND principal_id = ?)
35
+ OR EXISTS(SELECT 1 FROM agent_message_deliveries WHERE project = ? AND recipient = ?)
36
+ OR EXISTS(SELECT 1 FROM agent_session_instances WHERE project = ? AND session_instance_id = ?)
37
+ ) AS seen`).get(project, recipient, project, recipient, project, recipient);
38
+ return row?.seen === undefined ? undefined : Boolean(row.seen);
39
+ }
40
+ catch {
41
+ return undefined;
42
+ }
43
+ }
44
+ export function unreadInboxLines(count, project, recipient, everSeen) {
45
+ if (!recipient)
33
46
  return [];
34
- const noun = count === 1 ? 'message' : 'messages';
35
47
  const displayProject = JSON.stringify(project);
36
48
  const displayRecipient = JSON.stringify(recipient);
37
- return [`${count} ${noun} waiting for ${displayRecipient} in project ${displayProject} — poll the message tool with project ${displayProject} and recipient ${displayRecipient}, then fetch each message_id; fetching does not acknowledge.`];
49
+ if (count > 0) {
50
+ const noun = count === 1 ? 'message' : 'messages';
51
+ return [`${count} ${noun} waiting for ${displayRecipient} in project ${displayProject} — poll the message tool with project ${displayProject} and recipient ${displayRecipient}, then fetch each message_id; fetching does not acknowledge.`];
52
+ }
53
+ if (everSeen === false) {
54
+ return [`No messages waiting for ${displayRecipient} in project ${displayProject} — and this recipient id has never been seen in this project (check for a typo).`];
55
+ }
56
+ return [];
38
57
  }