@qodeca/xezar 0.13.0 → 0.14.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 (250) hide show
  1. package/README.md +72 -39
  2. package/dist/agent-config/account-identity.d.ts +2 -8
  3. package/dist/agent-config/account-identity.js +54 -10
  4. package/dist/agent-config/account-identity.js.map +1 -1
  5. package/dist/agent-config/catalog.d.ts +49 -7
  6. package/dist/agent-config/catalog.js +107 -0
  7. package/dist/agent-config/catalog.js.map +1 -1
  8. package/dist/agent-config/model-settings/pi.d.ts +12 -6
  9. package/dist/agent-config/model-settings/pi.js +12 -6
  10. package/dist/agent-config/model-settings/pi.js.map +1 -1
  11. package/dist/agent-config/seed.js +10 -0
  12. package/dist/agent-config/seed.js.map +1 -1
  13. package/dist/contract/github.d.ts +15 -0
  14. package/dist/contract/index.d.ts +9 -0
  15. package/dist/contract/index.js +1527 -895
  16. package/dist/contract/mcp-api-reference.d.ts +174 -0
  17. package/dist/contract/mcp-audit.d.ts +103 -0
  18. package/dist/contract/mcp-discovery.d.ts +257 -0
  19. package/dist/contract/mcp-event-catalog.d.ts +121 -0
  20. package/dist/contract/mcp-event-catalog.test.d.ts +1 -0
  21. package/dist/contract/mcp-idempotency.d.ts +200 -0
  22. package/dist/contract/mcp-journal.d.ts +268 -0
  23. package/dist/contract/mcp-leader.d.ts +88 -0
  24. package/dist/contract/mcp-ownership.d.ts +78 -0
  25. package/dist/contract/mcp-versioning.d.ts +139 -0
  26. package/dist/contract/runs.d.ts +81 -0
  27. package/dist/core/agent-profiles.d.ts +15 -4
  28. package/dist/core/agent-profiles.js +22 -8
  29. package/dist/core/agent-profiles.js.map +1 -1
  30. package/dist/core/opencode-server-runner.js +71 -11
  31. package/dist/core/opencode-server-runner.js.map +1 -1
  32. package/dist/core/secret-redaction.d.ts +7 -1
  33. package/dist/core/secret-redaction.js +44 -10
  34. package/dist/core/secret-redaction.js.map +1 -1
  35. package/dist/index.js +138 -27
  36. package/dist/index.js.map +1 -1
  37. package/dist/machine-identity.d.ts +66 -0
  38. package/dist/machine-identity.js +96 -0
  39. package/dist/machine-identity.js.map +1 -0
  40. package/dist/mcp/adapters/claude-code.d.ts +41 -0
  41. package/dist/mcp/adapters/claude-code.js +40 -0
  42. package/dist/mcp/adapters/claude-code.js.map +1 -0
  43. package/dist/mcp/adapters/codex.d.ts +140 -0
  44. package/dist/mcp/adapters/codex.js +323 -0
  45. package/dist/mcp/adapters/codex.js.map +1 -0
  46. package/dist/mcp/adapters/opencode.d.ts +148 -0
  47. package/dist/mcp/adapters/opencode.js +528 -0
  48. package/dist/mcp/adapters/opencode.js.map +1 -0
  49. package/dist/mcp/adapters/pi-link.d.ts +102 -0
  50. package/dist/mcp/adapters/pi-link.js +235 -0
  51. package/dist/mcp/adapters/pi-link.js.map +1 -0
  52. package/dist/mcp/adapters/pi.d.ts +188 -0
  53. package/dist/mcp/adapters/pi.js +418 -0
  54. package/dist/mcp/adapters/pi.js.map +1 -0
  55. package/dist/mcp/api-reference.d.ts +26 -0
  56. package/dist/mcp/api-reference.js +133 -0
  57. package/dist/mcp/api-reference.js.map +1 -0
  58. package/dist/mcp/audit-trail.d.ts +162 -0
  59. package/dist/mcp/audit-trail.js +306 -0
  60. package/dist/mcp/audit-trail.js.map +1 -0
  61. package/dist/mcp/bridge.d.ts +81 -0
  62. package/dist/mcp/bridge.js +407 -0
  63. package/dist/mcp/bridge.js.map +1 -0
  64. package/dist/mcp/connection-file.d.ts +49 -0
  65. package/dist/mcp/connection-file.js +63 -0
  66. package/dist/mcp/connection-file.js.map +1 -0
  67. package/dist/mcp/echo-guard.d.ts +94 -0
  68. package/dist/mcp/echo-guard.js +160 -0
  69. package/dist/mcp/echo-guard.js.map +1 -0
  70. package/dist/mcp/event-catalog.d.ts +120 -0
  71. package/dist/mcp/event-catalog.js +306 -0
  72. package/dist/mcp/event-catalog.js.map +1 -0
  73. package/dist/mcp/event-controller.d.ts +230 -0
  74. package/dist/mcp/event-controller.js +596 -0
  75. package/dist/mcp/event-controller.js.map +1 -0
  76. package/dist/mcp/event-journal.d.ts +57 -0
  77. package/dist/mcp/event-journal.js +423 -0
  78. package/dist/mcp/event-journal.js.map +1 -0
  79. package/dist/mcp/index.d.ts +63 -0
  80. package/dist/mcp/index.js +386 -0
  81. package/dist/mcp/index.js.map +1 -0
  82. package/dist/mcp/ipc.d.ts +202 -0
  83. package/dist/mcp/ipc.js +206 -0
  84. package/dist/mcp/ipc.js.map +1 -0
  85. package/dist/mcp/leader-delivery.d.ts +119 -0
  86. package/dist/mcp/leader-delivery.js +450 -0
  87. package/dist/mcp/leader-delivery.js.map +1 -0
  88. package/dist/mcp/operation-receipts.d.ts +210 -0
  89. package/dist/mcp/operation-receipts.js +723 -0
  90. package/dist/mcp/operation-receipts.js.map +1 -0
  91. package/dist/mcp/project-catalogs.d.ts +23 -0
  92. package/dist/mcp/project-catalogs.js +25 -0
  93. package/dist/mcp/project-catalogs.js.map +1 -0
  94. package/dist/mcp/project-leaders.d.ts +26 -0
  95. package/dist/mcp/project-leaders.js +17 -0
  96. package/dist/mcp/project-leaders.js.map +1 -0
  97. package/dist/mcp/protocol.d.ts +50 -0
  98. package/dist/mcp/protocol.js +47 -0
  99. package/dist/mcp/protocol.js.map +1 -0
  100. package/dist/mcp/reconnect.d.ts +297 -0
  101. package/dist/mcp/reconnect.js +465 -0
  102. package/dist/mcp/reconnect.js.map +1 -0
  103. package/dist/mcp/resource-ownership.d.ts +228 -0
  104. package/dist/mcp/resource-ownership.js +390 -0
  105. package/dist/mcp/resource-ownership.js.map +1 -0
  106. package/dist/mcp/service-adapter.d.ts +16488 -0
  107. package/dist/mcp/service-adapter.js +148 -0
  108. package/dist/mcp/service-adapter.js.map +1 -0
  109. package/dist/mcp/service.d.ts +83 -0
  110. package/dist/mcp/service.js +233 -0
  111. package/dist/mcp/service.js.map +1 -0
  112. package/dist/mcp/session-binding.d.ts +105 -0
  113. package/dist/mcp/session-binding.js +163 -0
  114. package/dist/mcp/session-binding.js.map +1 -0
  115. package/dist/mcp/stale-write.d.ts +145 -0
  116. package/dist/mcp/stale-write.js +219 -0
  117. package/dist/mcp/stale-write.js.map +1 -0
  118. package/dist/mcp/tool.d.ts +48 -0
  119. package/dist/mcp/tool.js +24 -0
  120. package/dist/mcp/tool.js.map +1 -0
  121. package/dist/mcp/tools/discovery.d.ts +40 -0
  122. package/dist/mcp/tools/discovery.js +232 -0
  123. package/dist/mcp/tools/discovery.js.map +1 -0
  124. package/dist/mcp/tools/execution-control.d.ts +171 -0
  125. package/dist/mcp/tools/execution-control.js +513 -0
  126. package/dist/mcp/tools/execution-control.js.map +1 -0
  127. package/dist/mcp/tools/handoff-git.d.ts +26 -0
  128. package/dist/mcp/tools/handoff-git.js +544 -0
  129. package/dist/mcp/tools/handoff-git.js.map +1 -0
  130. package/dist/mcp/tools/index.d.ts +2 -0
  131. package/dist/mcp/tools/index.js +23 -0
  132. package/dist/mcp/tools/index.js.map +1 -0
  133. package/dist/mcp/tools/leader-events.d.ts +46 -0
  134. package/dist/mcp/tools/leader-events.js +126 -0
  135. package/dist/mcp/tools/leader-events.js.map +1 -0
  136. package/dist/mcp/tools/local-handoff.d.ts +102 -0
  137. package/dist/mcp/tools/local-handoff.js +306 -0
  138. package/dist/mcp/tools/local-handoff.js.map +1 -0
  139. package/dist/mcp/tools/project-config.d.ts +340 -0
  140. package/dist/mcp/tools/project-config.js +1075 -0
  141. package/dist/mcp/tools/project-config.js.map +1 -0
  142. package/dist/mcp/tools/results-evidence.d.ts +112 -0
  143. package/dist/mcp/tools/results-evidence.js +1045 -0
  144. package/dist/mcp/tools/results-evidence.js.map +1 -0
  145. package/dist/mcp/tools/task-create.d.ts +70 -0
  146. package/dist/mcp/tools/task-create.js +473 -0
  147. package/dist/mcp/tools/task-create.js.map +1 -0
  148. package/dist/mcp/tools/task-reads.d.ts +102 -0
  149. package/dist/mcp/tools/task-reads.js +689 -0
  150. package/dist/mcp/tools/task-reads.js.map +1 -0
  151. package/dist/mcp/tools/work-organisation.d.ts +2 -0
  152. package/dist/mcp/tools/work-organisation.js +502 -0
  153. package/dist/mcp/tools/work-organisation.js.map +1 -0
  154. package/dist/paths.d.ts +17 -7
  155. package/dist/paths.js +18 -8
  156. package/dist/paths.js.map +1 -1
  157. package/dist/runs/project-writer.js +76 -11
  158. package/dist/runs/project-writer.js.map +1 -1
  159. package/dist/runs/retention.d.ts +25 -2
  160. package/dist/runs/retention.js +63 -2
  161. package/dist/runs/retention.js.map +1 -1
  162. package/dist/server/forge/github.js +44 -0
  163. package/dist/server/forge/github.js.map +1 -1
  164. package/dist/server/forge/types.d.ts +16 -0
  165. package/dist/server/project-context.d.ts +81 -8
  166. package/dist/server/project-context.js +143 -35
  167. package/dist/server/project-context.js.map +1 -1
  168. package/dist/server/server.d.ts +1050 -53
  169. package/dist/server/server.js +326 -120
  170. package/dist/server/server.js.map +1 -1
  171. package/dist/server/validators.d.ts +26 -6
  172. package/dist/server/validators.js +17 -0
  173. package/dist/server/validators.js.map +1 -1
  174. package/dist/skills-remote.js +64 -6
  175. package/dist/skills-remote.js.map +1 -1
  176. package/dist/workflows/run.d.ts +277 -12
  177. package/dist/workflows/run.js +599 -79
  178. package/dist/workflows/run.js.map +1 -1
  179. package/dist/workspace/agent-profiles.d.ts +30 -3
  180. package/dist/workspace/agent-profiles.js +39 -4
  181. package/dist/workspace/agent-profiles.js.map +1 -1
  182. package/dist/workspace/config.js +25 -4
  183. package/dist/workspace/config.js.map +1 -1
  184. package/dist/workspace/project-owner.d.ts +210 -0
  185. package/dist/workspace/project-owner.js +518 -0
  186. package/dist/workspace/project-owner.js.map +1 -0
  187. package/package.json +5 -3
  188. package/scripts/pi-leader-extension.ts +420 -0
  189. package/scripts/sync-readme.mjs +83 -2
  190. package/web/dist/assets/{alert-dialog-BVsVcbFy.js → alert-dialog-D6rP6d39.js} +1 -1
  191. package/web/dist/assets/arrow-down-DMOfFIzW.js +1 -0
  192. package/web/dist/assets/arrow-left-C4Ec2BUg.js +1 -0
  193. package/web/dist/assets/{centered-state-Djgly6Ni.js → centered-state-B0ZqrPaa.js} +12 -12
  194. package/web/dist/assets/chevron-right-mHJ-crvn.js +1 -0
  195. package/web/dist/assets/{collapsible-DZ4D-DHG.js → collapsible-DchEHgUM.js} +1 -1
  196. package/web/dist/assets/{commit-list-B-z1JL9G.js → commit-list-BpMim1Rv.js} +1 -1
  197. package/web/dist/assets/{compare-variants-CdS8r8E2.js → compare-variants-D5ItQbAq.js} +1 -1
  198. package/web/dist/assets/{diff-BKew9rQX.js → diff-HqqZ_WDR.js} +2 -2
  199. package/web/dist/assets/{diff-stat-D0mc5V6Z.js → diff-stat-NsU-3ecr.js} +1 -1
  200. package/web/dist/assets/{diff-view-xpIcuLIC.js → diff-view-B7c11Xux.js} +1 -1
  201. package/web/dist/assets/{dropdown-menu-CEQziH7X.js → dropdown-menu-CtTpnyod.js} +1 -1
  202. package/web/dist/assets/{editable-title-BCX3T2BY.js → editable-title-BXtuGQry.js} +1 -1
  203. package/web/dist/assets/{ellipsis-vertical-ByVdDc4z.js → ellipsis-vertical-MHtGZSH6.js} +1 -1
  204. package/web/dist/assets/{file-xBSB5hXO.js → file-DKLw5SOb.js} +1 -1
  205. package/web/dist/assets/{folder-CldgbZ5A.js → folder-Drw6-ufH.js} +1 -1
  206. package/web/dist/assets/{git-toolbar-BYlnf4qf.js → git-toolbar-BQH8bORV.js} +1 -1
  207. package/web/dist/assets/github-ynnpKFCJ.js +1 -0
  208. package/web/dist/assets/{image-preview-Cv5mZr0n.js → image-preview-DLhMN_R9.js} +1 -1
  209. package/web/dist/assets/index-BEsrNdXt.js +29 -0
  210. package/web/dist/assets/index-Da8DOBau.css +2 -0
  211. package/web/dist/assets/{markdown-CgEEE2ND.js → markdown-q365eN6Y.js} +1 -1
  212. package/web/dist/assets/{new-task-form-1r2bgsdD.js → new-task-form-CW-hNIWQ.js} +1 -1
  213. package/web/dist/assets/{pill-q-x22_ej.js → pill-B_TFulXa.js} +1 -1
  214. package/web/dist/assets/{project-router-VDN4jQM8.js → project-router-CLPc-ImZ.js} +1 -1
  215. package/web/dist/assets/{prompt-templates-BmZtCe-L.js → prompt-templates-CLc4RxyO.js} +1 -1
  216. package/web/dist/assets/{repo-git-C2On8SlI.js → repo-git-Is7R6-Tj.js} +1 -1
  217. package/web/dist/assets/{run-diff-vguEMJzh.js → run-diff-DHMvDlVo.js} +2 -2
  218. package/web/dist/assets/run-header-DvZJbQ8I.js +1 -0
  219. package/web/dist/assets/{search-x-QmhaAbg5.js → search-x-Ce2MMetu.js} +1 -1
  220. package/web/dist/assets/{skill-empty-hint-BrzUwByZ.js → skill-empty-hint-C_xCSvzB.js} +1 -1
  221. package/web/dist/assets/skills-CivqD4si.js +1 -0
  222. package/web/dist/assets/{sparkles-CP8QDOgX.js → sparkles-BCqPoj5g.js} +1 -1
  223. package/web/dist/assets/{square-terminal-CGypshSD.js → square-terminal-ikj5g-oK.js} +1 -1
  224. package/web/dist/assets/{tab-link-D4lFzzI1.js → tab-link-VsEjFV1Y.js} +1 -1
  225. package/web/dist/assets/{task-changes-6aopqAmV.js → task-changes-CH-E81-_.js} +1 -1
  226. package/web/dist/assets/{task-commits-u-dwaCyw.js → task-commits-DqfkMFxp.js} +1 -1
  227. package/web/dist/assets/{task-files-IMOZnIUK.js → task-files-D_nkHZ_a.js} +2 -2
  228. package/web/dist/assets/task-thread-bxQompxJ.js +9 -0
  229. package/web/dist/assets/{textarea-CyBCyKIk.js → textarea-xajuW1L_.js} +1 -1
  230. package/web/dist/assets/{thread-loading-Cuq2jchC.js → thread-loading-C3JQZbIE.js} +1 -1
  231. package/web/dist/assets/{trash-2-B6Dp3ZNs.js → trash-2-hJrBhpUD.js} +1 -1
  232. package/web/dist/assets/{triangle-alert-xBya8FUp.js → triangle-alert-D1u82y1a.js} +1 -1
  233. package/web/dist/assets/{upload-D6MXEB9p.js → upload-Bn6FBZ59.js} +1 -1
  234. package/web/dist/assets/{use-desktop-fLDKEJoB.js → use-desktop-DOIMfHfY.js} +1 -1
  235. package/web/dist/assets/{use-submit-shortcut-JTpNzU-u.js → use-submit-shortcut-Dj4DHTdE.js} +1 -1
  236. package/web/dist/assets/utils-YwBpOoRN.js +64 -0
  237. package/web/dist/assets/{workflows-BY3KTkFw.js → workflows-CTaAKz2m.js} +3 -3
  238. package/web/dist/assets/{zoomable-image-GTYwLtkS.js → zoomable-image-C1-6P3tg.js} +1 -1
  239. package/web/dist/index.html +23 -23
  240. package/web/dist/assets/arrow-down-CYgAlZtW.js +0 -1
  241. package/web/dist/assets/arrow-left-BOqE0a3k.js +0 -1
  242. package/web/dist/assets/chevron-right-Cc9BWnbN.js +0 -1
  243. package/web/dist/assets/github-CqGK62Lw.js +0 -1
  244. package/web/dist/assets/index-3nxVmdn5.css +0 -2
  245. package/web/dist/assets/index-qX7n11FX.js +0 -9
  246. package/web/dist/assets/refresh-cw-DcNCj2nu.js +0 -1
  247. package/web/dist/assets/run-header-DM7MiKj9.js +0 -1
  248. package/web/dist/assets/skills-Bj-uG_Hz.js +0 -1
  249. package/web/dist/assets/task-thread-CbMPmrWq.js +0 -9
  250. package/web/dist/assets/utils--z9hRtl3.js +0 -64
@@ -0,0 +1,450 @@
1
+ import { projectDataDir } from '../project-data-paths.js';
2
+ import { OpenCodeReactionAdapter } from './adapters/opencode.js';
3
+ import { connectPiLeaderLink, readPiLeaderDescriptor } from './adapters/pi-link.js';
4
+ import { piReactionTarget } from './adapters/pi.js';
5
+ import { EventController } from './event-controller.js';
6
+ /**
7
+ * Push delivery, connected (#309, Phase 6 of #73). Until this module, `EventController` (#107) and
8
+ * the reaction adapters (#108–#110) were complete, tested — and constructed by nothing outside their
9
+ * own tests, so no event ever reached a client. This is the one place the running service builds
10
+ * the controller, composed once per project by `startMcpService`.
11
+ *
12
+ * WHAT IS ON BY DEFAULT. Every MCP session that becomes the project's owner (`session/open`,
13
+ * D-02.2) gets an event controller at once, with this object as its adapter; the controller ends
14
+ * when that session's connection closes (D-02.4). No flag, no setting: an owner session always has
15
+ * a dispatcher following the journal for it.
16
+ *
17
+ * WHO IT CAN REACH, AND WHY ONLY THEM. A dispatch must reach a MODEL, and generic MCP notifications
18
+ * start no turn in Claude Code, Codex, OpenCode or pi (D-05 § 4; #330 run A for pi; each adapter's
19
+ * evidence record). xezar NEVER starts an agent process for a leader (owner decision on #311): the
20
+ * person runs their own leader and connects it to xezar over MCP. So an event reaches a model only
21
+ * through a session the person runs AND tells xezar where to find — `attach`. Two clients can be
22
+ * told today:
23
+ *
24
+ * - **OpenCode** names an `opencode serve` session by URL and session id (#110).
25
+ * - **pi** names nothing, because it cannot: pi's RPC is stdio-only and spawn-only, so a pi the
26
+ * person started has no address. The address therefore comes from INSIDE it — xezar's pi leader
27
+ * extension opens a socket and announces it in the project's data directory, and `#piTarget()`
28
+ * dials that (#330 WP2, `adapters/pi-link.ts`). With no extension running there is no descriptor
29
+ * and the attach is refused with pi's own recoverable reason, which is exactly the behaviour that
30
+ * existed before the extension did.
31
+ *
32
+ * A Claude Code or Codex session in a terminal still has no address at all: for it the controller
33
+ * keeps the rows in the journal, reports `disconnected`, retries at its heartbeat, and
34
+ * `status().blocker` says so. Nothing is lost either way — such a leader reads its events with the
35
+ * `leader_events` tool (#251), and the next session resumes after its last acknowledgement.
36
+ *
37
+ * THE ECHO GUARD HOLDS HERE, FOR EVERY CLIENT. The door records each mutation's operation id as the
38
+ * leader's own before it runs (`EchoGuard.issue`, #106), including the ids it mints for tools that
39
+ * carry no `operationId`. A `leader` row caused by one of them is dropped before the adapter sees it,
40
+ * so a client's own guard — which knows only the ids it saw — cannot miss a door-minted one. Only the
41
+ * echo rule: the guard's `duplicate` rule must NOT be applied, because redelivery after a reconnect
42
+ * is at-least-once by contract.
43
+ *
44
+ * ## Every state this relies on, and who fires each exit
45
+ *
46
+ * Controller states (`EventControllerState`), as wired here:
47
+ *
48
+ * | State | Exit | Who fires it (on by default) |
49
+ * | --- | --- | --- |
50
+ * | inert | — | never entered: this object is always the adapter |
51
+ * | idle | → dispatching | a journal append, or the 30 s heartbeat tick |
52
+ * | dispatching | → idle / → recovering | `deliver` resolving / rejecting or timing out (one heartbeat) |
53
+ * | recovering | → idle / → disconnected | the bounded round itself (5 attempts) |
54
+ * | disconnected | → dispatching | the heartbeat tick, every 30 s; or `wake()`, which `attach` fires at once |
55
+ * | any | → ended | the session's connection closing (`sessionClosed`), another session taking the project (`sessionOpened`), the lease lapsing (found at the next tick), or the service closing |
56
+ *
57
+ * `disconnected` with nothing attached is the one state that waits on something outside xezar, and
58
+ * it does not wait on a human alone: the heartbeat retries it for as long as the session owns the
59
+ * project, at no model cost (N-06). It is the recoverable blocker the requirements ask for.
60
+ *
61
+ * Leader states: none → attached (`act` attach); attached → none (`act` stop, or the service
62
+ * closing). An attached OpenCode session that goes away is the adapter's own recoverable blocker,
63
+ * reported by `status()`; the controller retries it at the heartbeat. A pi leader that goes away
64
+ * takes its socket with it, which closes the link and reports the same way.
65
+ *
66
+ * What xezar OPENS to reach a leader is released on every one of those exits: `#detach` closes the
67
+ * adapter and then its `dispose` (pi's socket today), and `close()` goes through `#detach`.
68
+ *
69
+ * What reaches a terminal state BECAUSE of this module: its controllers. No process, run, lease,
70
+ * queue slot or worktree — it starts nothing and stops nothing but its own objects.
71
+ */
72
+ /** xezar's base role, sent with every event to an attached leader. Per-project customisation is not built yet. */
73
+ export const LEADER_ROLE_INSTRUCTION = [
74
+ 'You are the project leader for this xezar project.',
75
+ 'You plan and coordinate the work through the xezar MCP tools: start tasks, read their results, answer their questions and hand finished work off.',
76
+ 'You do not edit files yourself; tasks do the work in their own worktrees.',
77
+ ].join('\n');
78
+ const NO_LEADER = {
79
+ code: 'no-leader-session',
80
+ message: 'No leader session is attached to this project, so events are kept in the journal, not pushed. A Claude Code, Codex or pi session in a terminal has no address xezar can attach to, and MCP notifications start no turn — that leader reads its events with the leader_events tool.',
81
+ fix: 'Keep using leader_events from your own leader, or attach the OpenCode session you run with `opencode serve`.',
82
+ };
83
+ /**
84
+ * Every blocker about an ATTACHED leader is written in that leader's client's own words.
85
+ *
86
+ * It used to be written in OpenCode's, for all of them, so a pi user who hit one was told to check
87
+ * an `opencode serve` they are not running (QA on #358, finding 3) — at the exact moment they needed
88
+ * the right thing to check. The two clients are reached in completely different ways: OpenCode's
89
+ * leader is an HTTP server the person runs, pi's is a Unix socket xezar's leader extension opens
90
+ * from INSIDE the person's own pi, so "check the server" has no shared spelling.
91
+ *
92
+ * Only these two can be attached at all (`mcpLeaderAttachInputSchema` in the contract). A Claude Code
93
+ * or Codex leader has no address to attach, which is `NO_LEADER`'s case above and names all four
94
+ * clients itself. Typed `Record<McpLeaderSession['client'], …>` on purpose: a third attachable client
95
+ * is then a compile error here, rather than a message that quietly names the wrong server again.
96
+ */
97
+ const CLIENT_WORDS = {
98
+ opencode: {
99
+ name: 'OpenCode',
100
+ lazyMcp: ' OpenCode connects its xezar MCP server only when it first needs it.',
101
+ check: 'check that `opencode serve` is running and answering (a paused process still accepts connections)',
102
+ checkShort: 'check that `opencode serve` is running and answering',
103
+ reattach: 'attach the session again',
104
+ },
105
+ pi: {
106
+ // Nothing is claimed about WHEN pi opens its MCP connection, because nothing here measured it;
107
+ // the fix below works whenever it does.
108
+ name: 'pi',
109
+ lazyMcp: '',
110
+ check: 'check that the pi you attached is still running with xezar’s leader extension loaded (a paused process still holds its socket open)',
111
+ checkShort: 'check that the pi you attached is still running with xezar’s leader extension loaded',
112
+ reattach: 'attach it again',
113
+ },
114
+ };
115
+ /**
116
+ * #331: a leader is attached, but no MCP session owns the project, so no controller follows the
117
+ * journal and nothing is delivered. The ORDINARY first state: OpenCode connects its MCP servers
118
+ * lazily, so "attach first, MCP session later" is what a first user sees.
119
+ */
120
+ const noOwnerSession = (client) => {
121
+ const words = CLIENT_WORDS[client];
122
+ return {
123
+ code: 'no-owner-session',
124
+ message: `A ${words.name} leader is attached, but no MCP session owns this project yet, so nothing follows the event journal and nothing is delivered.${words.lazyMcp} Events are kept in the journal meanwhile.`,
125
+ fix: `Let the attached ${words.name} session call a xezar tool once (for example leader_events), so its MCP connection opens; it then receives every event it has not acknowledged.`,
126
+ };
127
+ };
128
+ /**
129
+ * Events are waiting and the last attempt to hand them to THIS leader did not get through — a
130
+ * refused request, a dropped connection, a server that accepts and never answers, or a leader busy
131
+ * in a long turn. xezar cannot tell those apart (the adapter waits for the session to be free, and a
132
+ * long turn looks exactly like silence), so the text names both and diagnoses neither (QA on #311,
133
+ * round five). The fact behind it is recorded against the LEADER, so it survives a session change and
134
+ * is never inherited by a leader that has just been attached.
135
+ */
136
+ const deliveryFailing = (client) => {
137
+ const words = CLIENT_WORDS[client];
138
+ return {
139
+ code: 'delivery-failing',
140
+ message: `Events are waiting, and the last attempt to hand them to the attached ${words.name} leader did not get through. It may be busy in a long turn, or it may have stopped answering — xezar cannot tell those apart, and keeps retrying while this MCP session owns the project. Nothing is lost: the events stay in the journal.`,
141
+ fix: `If the leader is working, nothing is needed: the events go as soon as it is free. Otherwise ${words.check}, or ${words.reattach}.`,
142
+ };
143
+ };
144
+ /** The same fact with nothing waiting: the leader did not answer xezar’s last liveness check. */
145
+ const leaderNotAnswering = (client) => {
146
+ const words = CLIENT_WORDS[client];
147
+ return {
148
+ code: 'leader-not-answering',
149
+ message: `The attached ${words.name} leader did not answer xezar’s last liveness check — it may be busy, or gone. Nothing is waiting right now; the next event would be retried until it answers.`,
150
+ fix: `If the leader is working, nothing is needed. Otherwise ${words.checkShort}, or ${words.reattach}.`,
151
+ };
152
+ };
153
+ /** #309 O-3: a journal that records nothing has nothing to deliver, so a leader would never hear a thing. */
154
+ const JOURNAL_UNWRITABLE = {
155
+ code: 'journal-unwritable',
156
+ message: 'xezar cannot write this project’s event journal, so no event is recorded and none can be delivered. The cockpit log names the file and the error.',
157
+ fix: 'Make the project’s .local/xezar/mcp folder writable, then restart xezar.',
158
+ };
159
+ export class LeaderDelivery {
160
+ projectId;
161
+ #opts;
162
+ /** Keyed by the transport's session key. At most one is live: the project has one owner. */
163
+ #controllers = new Map();
164
+ /** The attached OpenCode session and the facts observed against it. xezar never started it. */
165
+ #leader;
166
+ /** One `act` at a time: two concurrent attaches must not leave two adapters behind. */
167
+ #acting = Promise.resolve();
168
+ #closed = false;
169
+ constructor(opts) {
170
+ this.projectId = opts.projectId;
171
+ this.#opts = opts;
172
+ }
173
+ // ---- the transport's side: one controller per owner session ------------------------------
174
+ /** `session/open` made `sessionKey` the owner. Never throws into the transport (N-07). */
175
+ sessionOpened(sessionKey) {
176
+ if (this.#closed || this.#controllers.has(sessionKey))
177
+ return;
178
+ // Only one session owns the project, so any other controller serves a session that lost it —
179
+ // one whose lease lapsed while its connection stayed open. End it now rather than at its next
180
+ // tick: the journal allows one dispatcher, and it must be the owner's.
181
+ for (const [key, controller] of this.#controllers) {
182
+ controller.close();
183
+ this.#controllers.delete(key);
184
+ }
185
+ const started = EventController.start({
186
+ journal: this.#opts.journal,
187
+ ownership: this.#opts.ownership,
188
+ sessionKey,
189
+ adapter: this,
190
+ warn: this.#opts.warn,
191
+ ...(this.#opts.leaderRecord === undefined ? {} : { leaderRecord: this.#opts.leaderRecord }),
192
+ ...(this.#opts.heartbeatMs === undefined ? {} : { heartbeatMs: this.#opts.heartbeatMs }),
193
+ });
194
+ if (started.outcome === 'started')
195
+ this.#controllers.set(sessionKey, started.controller);
196
+ else if (started.outcome === 'refused')
197
+ this.#opts.warn(`[xez] MCP event delivery not started for project ${this.projectId}: ${started.error.message}`);
198
+ }
199
+ /** The session's connection closed (D-02.4): its controller ends. The journal keeps every row. */
200
+ sessionClosed(sessionKey) {
201
+ this.#controllers.get(sessionKey)?.close();
202
+ this.#controllers.delete(sessionKey);
203
+ }
204
+ // ---- the controller's side: `ReactionAdapter` ----------------------------------------------
205
+ async deliver(dispatch, signal) {
206
+ const leader = this.#leader;
207
+ if (leader === undefined)
208
+ throw new Error(NO_LEADER.message);
209
+ const events = dispatch.events.filter((row) => !this.#isEcho(row));
210
+ const last = dispatch.events.at(-1)?.journalSeq;
211
+ // Only the leader's own echoes: nothing to tell it, so nothing is handed over — and the receipt
212
+ // says so, so deliveredSeq never counts a row the leader was not sent (QA on #311). It is still
213
+ // settled, so nothing is waiting for it.
214
+ if (events.length === 0 && dispatch.recovery === undefined) {
215
+ if (last !== undefined)
216
+ leader.settledThrough = Math.max(leader.settledThrough, last);
217
+ return { handedThrough: null };
218
+ }
219
+ await this.#observed(leader, signal, () => leader.adapter.deliver({ ...dispatch, events }, signal));
220
+ if (last !== undefined)
221
+ leader.settledThrough = Math.max(leader.settledThrough, last);
222
+ return { handedThrough: events.at(-1)?.journalSeq ?? null };
223
+ }
224
+ async heartbeat(signal) {
225
+ const leader = this.#leader;
226
+ if (leader === undefined)
227
+ throw new Error(NO_LEADER.message);
228
+ await this.#observed(leader, signal, () => leader.adapter.heartbeat(signal));
229
+ }
230
+ /**
231
+ * Run one attempt against `leader` and record how it went, AGAINST THAT LEADER: the first failure
232
+ * with none succeeding since, cleared by the next success. An attempt the caller abandons (its
233
+ * signal aborts — a server that accepts and never answers) counts as a failure, and a late success
234
+ * after that abort does not clear it.
235
+ */
236
+ async #observed(leader, signal, call) {
237
+ let abandoned = signal.aborted;
238
+ const onAbort = () => {
239
+ abandoned = true;
240
+ leader.failingSince ??= Date.now();
241
+ };
242
+ signal.addEventListener('abort', onAbort, { once: true });
243
+ try {
244
+ const value = await call();
245
+ if (!abandoned)
246
+ leader.failingSince = null;
247
+ return value;
248
+ }
249
+ catch (err) {
250
+ leader.failingSince ??= Date.now();
251
+ throw err;
252
+ }
253
+ finally {
254
+ signal.removeEventListener('abort', onAbort);
255
+ }
256
+ }
257
+ /** Is a row waiting for the attached leader? Its own settled position, and what the leader acknowledged. */
258
+ #owed(leader) {
259
+ const owedAfter = this.#opts.leaderRecord?.owedAfter();
260
+ const acknowledged = owedAfter?.sameEpoch === true ? owedAfter.seq : 0;
261
+ return this.#opts.journal.latestSeq > Math.max(leader.settledThrough, acknowledged);
262
+ }
263
+ // ---- the cockpit's side: `ProjectLeaderPort` -----------------------------------------------
264
+ status() {
265
+ const controller = this.#liveController();
266
+ return {
267
+ available: true,
268
+ leader: this.#leaderSession(),
269
+ delivery: controller ? controller.status() : null,
270
+ blocker: this.#blocker(),
271
+ };
272
+ }
273
+ act(input) {
274
+ const next = this.#acting.then(() => this.#act(input));
275
+ this.#acting = next.catch(() => undefined);
276
+ return next;
277
+ }
278
+ /** The service is stopping: every controller ends and the attached session is let go. */
279
+ close() {
280
+ if (this.#closed)
281
+ return;
282
+ this.#closed = true;
283
+ for (const controller of this.#controllers.values())
284
+ controller.close();
285
+ this.#controllers.clear();
286
+ this.#detach();
287
+ }
288
+ // ---- internals ----------------------------------------------------------------------------
289
+ async #act(input) {
290
+ if (this.#closed)
291
+ return { ok: false, error: 'the MCP service for this project is stopping' };
292
+ if (input.action === 'stop') {
293
+ this.#detach();
294
+ return { ok: true, status: this.status() };
295
+ }
296
+ // Attaching a leader that can never receive an event would answer 200 with a blocker-free status
297
+ // for a path that delivers nothing (#309 O-3). Refuse, and say why.
298
+ if (!this.#opts.journal.writable)
299
+ return { ok: false, error: JOURNAL_UNWRITABLE.message };
300
+ if (input.client === 'pi') {
301
+ // pi's adapter (#330 WP2) is built the same way the OpenCode one is, and from the same kind of
302
+ // thing: an address the person's own leader offers. pi's RPC is stdio-only, so that address
303
+ // cannot be pi itself — it is the socket xezar's pi leader extension opens from INSIDE the
304
+ // person's pi and announces in this project's data directory (`adapters/pi-link.ts`). No
305
+ // extension running, no descriptor, no link: `piReactionTarget` answers with its own
306
+ // recoverable reason and the events stay in the journal, exactly as before this existed. The
307
+ // previous leader is kept either way — a refused attach must not detach one that is working.
308
+ const { target, dispose } = this.#piTarget();
309
+ if (target.kind === 'blocked') {
310
+ dispose?.();
311
+ return { ok: false, error: target.blocker.message };
312
+ }
313
+ this.#detach();
314
+ this.#leader = {
315
+ client: 'pi',
316
+ adapter: target.adapter,
317
+ failingSince: null,
318
+ settledThrough: 0,
319
+ ...(dispose ? { dispose } : {}),
320
+ };
321
+ this.#liveController()?.wake();
322
+ return { ok: true, status: this.status() };
323
+ }
324
+ // Re-attaching replaces the previous target; xezar owns no process, so nothing else changes.
325
+ this.#detach();
326
+ // A new leader with no history: whatever happened before it was attached was not about it.
327
+ this.#leader = {
328
+ client: 'opencode',
329
+ adapter: new OpenCodeReactionAdapter({
330
+ target: { baseUrl: input.baseUrl, sessionId: input.sessionId },
331
+ projectRoot: this.#opts.projectRoot,
332
+ roleInstruction: LEADER_ROLE_INSTRUCTION,
333
+ onReaction: (seq) => this.#recordReaction(seq),
334
+ ...this.#ownOperation(),
335
+ }),
336
+ failingSince: null,
337
+ settledThrough: 0,
338
+ };
339
+ // Deliver now, not at the next heartbeat.
340
+ this.#liveController()?.wake();
341
+ return { ok: true, status: this.status() };
342
+ }
343
+ /** Stop talking to the attached session. The OpenCode process and session are the person's. */
344
+ #detach() {
345
+ const leaving = this.#leader;
346
+ this.#leader = undefined;
347
+ leaving?.adapter.close();
348
+ // The transport last, and never skipped when `close()` throws: a socket xezar opened and then
349
+ // leaked would keep a pi process's peer alive with nothing reading it.
350
+ try {
351
+ leaving?.dispose?.();
352
+ }
353
+ catch (err) {
354
+ this.#opts.warn(`[xez] the pi leader link did not close cleanly (${err instanceof Error ? err.message : String(err)})`);
355
+ }
356
+ }
357
+ /**
358
+ * Build pi's target, and whatever has to be released with it. The ONE place a `PiRpcLink` is
359
+ * produced in this process — the answer to "who constructs the adapter", which for one round of
360
+ * review was nobody.
361
+ *
362
+ * Every failure is the blocker, never a throw: this is the `attach` path and the person reads the
363
+ * reason. A descriptor that names a dead socket is the ordinary case (a pi that exited), so it is
364
+ * reported as its own recoverable reason rather than as an error.
365
+ */
366
+ #piTarget() {
367
+ const base = {
368
+ projectId: this.projectId,
369
+ roleInstruction: LEADER_ROLE_INSTRUCTION,
370
+ onReaction: (seq) => this.#recordReaction(seq),
371
+ ...this.#ownOperation(),
372
+ };
373
+ const dataDir = this.#opts.dataDir ?? projectDataDir(this.#opts.projectRoot);
374
+ const read = this.#opts.piLeader?.read ?? readPiLeaderDescriptor;
375
+ const found = read(dataDir);
376
+ if (!found.ok)
377
+ return { target: piReactionTarget({ ...base, unreachable: found.reason }) };
378
+ const connect = this.#opts.piLeader?.connect ?? connectPiLeaderLink;
379
+ let link;
380
+ try {
381
+ link = connect(found.descriptor, { warn: this.#opts.warn });
382
+ }
383
+ catch (err) {
384
+ return {
385
+ target: piReactionTarget({
386
+ ...base,
387
+ unreachable: `its socket could not be reached: ${err instanceof Error ? err.message : String(err)}`,
388
+ }),
389
+ };
390
+ }
391
+ const target = piReactionTarget({ ...base, link });
392
+ // A link that was already closed gives a blocked target; do not leak the socket behind it.
393
+ if (target.kind === 'blocked') {
394
+ link.close();
395
+ return { target };
396
+ }
397
+ return { target, dispose: () => link.close() };
398
+ }
399
+ #ownOperation() {
400
+ const guard = this.#opts.guard;
401
+ return guard === undefined ? {} : { isOwnOperation: (operationId) => guard.isOwn(operationId) };
402
+ }
403
+ #isEcho(row) {
404
+ return row.origin === 'leader' && row.causedBy !== null && this.#opts.guard?.isOwn(row.causedBy) === true;
405
+ }
406
+ #liveController() {
407
+ for (const controller of this.#controllers.values())
408
+ if (controller.state !== 'ended')
409
+ return controller;
410
+ return undefined;
411
+ }
412
+ #recordReaction(seq) {
413
+ return this.#liveController()?.recordReaction(seq) ?? { status: 'inactive', seq: 0 };
414
+ }
415
+ #leaderSession() {
416
+ return this.#leader === undefined ? null : { client: this.#leader.client, state: 'attached' };
417
+ }
418
+ /**
419
+ * The blocker is a rule over FACTS, in order: the journal can be written; a leader is attached; a
420
+ * session owns the project; the adapter named no problem; no attempt has failed since the last
421
+ * success. It reads no controller state, so a state added later cannot slip past it.
422
+ */
423
+ #blocker() {
424
+ // Before anything about the leader: with no journal, even an attached leader hears nothing.
425
+ if (!this.#opts.journal.writable)
426
+ return JOURNAL_UNWRITABLE;
427
+ const leader = this.#leader;
428
+ if (leader === undefined)
429
+ return NO_LEADER;
430
+ // Attached, but nobody owns the project: no controller, so nothing is delivered (#331).
431
+ const controller = this.#liveController();
432
+ if (controller === undefined)
433
+ return noOwnerSession(leader.client);
434
+ const blocker = leader.adapter.status().blocker;
435
+ if (blocker) {
436
+ // The adapter's own `fix` when it has one (pi's does; `PiReactionAdapter.#block` always sets
437
+ // one, and `piReactionTarget`'s own blocker carries `PI_EXTENSION_FIX`), otherwise the
438
+ // OpenCode wording, which is the only adapter whose blockers name no remedy of their own.
439
+ const fix = blocker.fix ?? 'Check that `opencode serve` is running in this project and the session id is right, then attach it again.';
440
+ return { code: blocker.code, message: blocker.message, fix };
441
+ }
442
+ // From FACTS observed against THIS leader, never from the controller's state machine (rounds four
443
+ // and five): a failed attempt with no success since is a blocker in every state, it survives the
444
+ // session being replaced, and a leader just attached has none. `state` is shown, and decides nothing.
445
+ if (leader.failingSince !== null)
446
+ return this.#owed(leader) ? deliveryFailing(leader.client) : leaderNotAnswering(leader.client);
447
+ return null;
448
+ }
449
+ }
450
+ //# sourceMappingURL=leader-delivery.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"leader-delivery.js","sourceRoot":"","sources":["../../src/mcp/leader-delivery.ts"],"names":[],"mappings":"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"}