@qodeca/xezar 0.13.1 → 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 +45 -15
  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 +24 -1
  160. package/dist/runs/retention.js +62 -1
  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 +554 -59
  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-D62m4j3B.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-DJANqg7Y.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-btG0sdbO.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-BtZId14z.js → task-changes-CH-E81-_.js} +1 -1
  226. package/web/dist/assets/{task-commits-BoeyJXrv.js → task-commits-DqfkMFxp.js} +1 -1
  227. package/web/dist/assets/{task-files-DIy2oUnj.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-CPBwzQ7M.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-DG115scU.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-D6vK0jFn.js +0 -1
  244. package/web/dist/assets/index-CkmR6h7s.css +0 -2
  245. package/web/dist/assets/index-DVDqF4bM.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-DMfxQtrD.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,407 @@
1
+ import { createConnection } from 'node:net';
2
+ import { MCP_PROJECT_OCCUPIED_REASON } from '../contract/index.js';
3
+ import { projectOccupiedError, sessionExpiredError } from '../workspace/project-owner.js';
4
+ import { IPC_PROTOCOL_VERSION, IPC_REQUEST_TIMEOUT_MS, IPC_SESSION_OPEN_TIMEOUT_MS, LineFramer, encodeFrame, healthResultSchema, ipcResponseSchema, sessionOpenResultSchema, toolCallParamsSchema, toolResultSchema, } from './ipc.js';
5
+ import { JSONRPC_ERRORS, SERVER_CAPABILITIES, incomingMessageSchema, initializeParamsSchema, negotiateProtocolVersion, } from './protocol.js';
6
+ import { errorResult, textResult, toolListing } from './tool.js';
7
+ /** Built into the bridge rather than the registry: it is how a client learns the service is down. */
8
+ export const HEALTH_TOOL = {
9
+ name: 'health',
10
+ title: 'xezar health',
11
+ description: 'Report whether the xezar cockpit is running for the project this session was started in, and which project that is.',
12
+ inputSchema: { type: 'object', properties: {}, additionalProperties: false },
13
+ annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: false },
14
+ };
15
+ const INSTRUCTIONS = 'xezar controls coding-agent tasks for the one project this session was started in. ' +
16
+ 'Call `health` to check that the xezar cockpit is running for it.';
17
+ /** Serve MCP until `input` ends. Resolves then; the session closes and in-flight answers are dropped. */
18
+ export function runBridge(opts) {
19
+ const inflight = new Set();
20
+ const session = new ServiceSession(opts);
21
+ let finished = false;
22
+ const write = (message) => {
23
+ if (!finished)
24
+ opts.output.write(encodeFrame(message));
25
+ };
26
+ const respond = (id, result) => write({ jsonrpc: '2.0', id, result });
27
+ const fail = (id, code, message) => write({ jsonrpc: '2.0', id, error: { code, message } });
28
+ const refuse = (id, error) => write({ jsonrpc: '2.0', id, error });
29
+ const framer = new LineFramer((line) => handle(line), () => fail(null, JSONRPC_ERRORS.invalidRequest, 'message too large'));
30
+ function handle(line) {
31
+ let json;
32
+ try {
33
+ json = JSON.parse(line);
34
+ }
35
+ catch {
36
+ fail(null, JSONRPC_ERRORS.parseError, 'parse error');
37
+ return;
38
+ }
39
+ const parsed = incomingMessageSchema.safeParse(json);
40
+ if (!parsed.success) {
41
+ // Batches were removed in 2025-06-18; neither supported revision has them.
42
+ fail(null, JSONRPC_ERRORS.invalidRequest, 'invalid request');
43
+ return;
44
+ }
45
+ const { id, method, params } = parsed.data;
46
+ // A notification (no id) or a response to us (no method): nothing to answer.
47
+ // `notifications/cancelled` lands here too — a call whose answer is already on
48
+ // its way is not unwound (D-05 § 3.1).
49
+ if (id === undefined || method === undefined)
50
+ return;
51
+ switch (method) {
52
+ case 'initialize': {
53
+ const init = initializeParamsSchema.safeParse(params);
54
+ if (!init.success) {
55
+ fail(id, JSONRPC_ERRORS.invalidParams, 'initialize needs a protocolVersion');
56
+ return;
57
+ }
58
+ // D-02.6: `initialize` is where a session acquires the project. Only a live competing
59
+ // owner turns it into an error; a service that is not running still gets a healthy
60
+ // handshake (N-07), and the first call tries again.
61
+ const handshake = () => respond(id, {
62
+ protocolVersion: negotiateProtocolVersion(init.data.protocolVersion),
63
+ capabilities: SERVER_CAPABILITIES,
64
+ serverInfo: { name: 'xezar', title: 'xezar', version: opts.version },
65
+ instructions: INSTRUCTIONS,
66
+ });
67
+ void session.initialize().then((refused) => (refused ? refuse(id, refused) : handshake()),
68
+ // A failure to even look for the service is not a competing owner: the handshake stays
69
+ // healthy (N-07) and the first call tries again, rather than `initialize` never answering.
70
+ handshake);
71
+ return;
72
+ }
73
+ case 'ping':
74
+ respond(id, {});
75
+ return;
76
+ case 'tools/list':
77
+ respond(id, { tools: [HEALTH_TOOL, ...opts.tools.map(toolListing)] });
78
+ return;
79
+ case 'tools/call': {
80
+ const call = toolCallParamsSchema.safeParse(params);
81
+ if (!call.success) {
82
+ fail(id, JSONRPC_ERRORS.invalidParams, 'tools/call needs a tool name');
83
+ return;
84
+ }
85
+ const { name } = call.data;
86
+ if (name !== HEALTH_TOOL.name && !opts.tools.some((t) => t.name === name)) {
87
+ fail(id, JSONRPC_ERRORS.invalidParams, `Unknown tool: ${name}`);
88
+ return;
89
+ }
90
+ const abort = new AbortController();
91
+ inflight.add(abort);
92
+ void callTool(call.data, abort.signal)
93
+ .then((answer) => {
94
+ if (abort.signal.aborted)
95
+ return;
96
+ if ('error' in answer)
97
+ refuse(id, answer.error);
98
+ else
99
+ respond(id, answer.result);
100
+ })
101
+ .finally(() => inflight.delete(abort));
102
+ return;
103
+ }
104
+ default:
105
+ fail(id, JSONRPC_ERRORS.methodNotFound, `Method not found: ${method}`);
106
+ }
107
+ }
108
+ async function callTool(call, signal) {
109
+ const health = call.name === HEALTH_TOOL.name;
110
+ const outcome = await session.call(health ? 'health' : 'tools/call', health ? undefined : call, signal);
111
+ if (outcome.kind !== 'response')
112
+ return outcome.kind === 'error' ? { error: outcome.error } : { result: outcome.result };
113
+ const response = outcome.response;
114
+ if (!response.ok)
115
+ return { result: refused(response, opts.version) };
116
+ if (health) {
117
+ const h = healthResultSchema.safeParse(response.result);
118
+ if (!h.success)
119
+ return { result: errorResult('xezar answered health with an unexpected shape.') };
120
+ return {
121
+ result: textResult(`xezar ${h.data.xezarVersion} is running for project ${h.data.project.name} (${h.data.project.id}).`, {
122
+ status: 'running',
123
+ ...h.data,
124
+ }),
125
+ };
126
+ }
127
+ const result = toolResultSchema.safeParse(response.result);
128
+ return { result: result.success ? result.data : errorResult(`xezar answered ${call.name} with an unexpected shape.`) };
129
+ }
130
+ return new Promise((resolve) => {
131
+ const finish = () => {
132
+ if (finished)
133
+ return;
134
+ finished = true;
135
+ for (const abort of inflight)
136
+ abort.abort();
137
+ // The client went away: closing the connection is how the service learns the session ended.
138
+ session.close();
139
+ resolve();
140
+ };
141
+ opts.input.on('data', (chunk) => framer.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk)));
142
+ opts.input.once('end', finish);
143
+ opts.input.once('close', finish);
144
+ // The client went away mid-write: there is nobody left to answer.
145
+ opts.output.on('error', finish);
146
+ });
147
+ }
148
+ class ServiceSession {
149
+ opts;
150
+ state = 'idle';
151
+ connection;
152
+ opening;
153
+ project;
154
+ closed = false;
155
+ constructor(opts) {
156
+ this.opts = opts;
157
+ }
158
+ /** Open the session for `initialize`. Answers the refusal to send, or nothing for a healthy handshake. */
159
+ async initialize() {
160
+ if (this.state === 'owner')
161
+ return undefined;
162
+ const opened = await this.open();
163
+ return opened.kind === 'occupied' ? opened.error : undefined;
164
+ }
165
+ async call(method, params, signal) {
166
+ const before = this.state;
167
+ if (before !== 'owner') {
168
+ const opened = await this.open();
169
+ if (opened.kind === 'unavailable')
170
+ return { kind: 'result', result: opened.result };
171
+ // The call was made under a session that does not own the project: it is answered as expired
172
+ // and never runs. A new session is already open (or refused) for the calls that follow.
173
+ if (before === 'lost' || before === 'refused')
174
+ return { kind: 'error', error: sessionExpiredError(this.projectId()) };
175
+ if (opened.kind === 'occupied')
176
+ return { kind: 'error', error: opened.error };
177
+ }
178
+ const connection = this.connection;
179
+ if (!connection)
180
+ return { kind: 'error', error: sessionExpiredError(this.projectId()) };
181
+ const outcome = await connection.request({ method, ...(params === undefined ? {} : { params }) }, this.opts.requestTimeoutMs ?? IPC_REQUEST_TIMEOUT_MS, signal);
182
+ if (outcome.kind !== 'response')
183
+ return { kind: 'result', result: unreachable(outcome, this.projectLabel(), this.opts.version) };
184
+ const response = outcome.response;
185
+ if (!response.ok && response.error.code === 'session-expired') {
186
+ // Fenced by the service. This session is over; the next call opens a new one.
187
+ this.drop('idle');
188
+ return { kind: 'error', error: response.rpcError ?? sessionExpiredError(this.projectId()) };
189
+ }
190
+ return { kind: 'response', response };
191
+ }
192
+ /** The client is gone. Closing the connection is what releases the project in the service. */
193
+ close() {
194
+ this.closed = true;
195
+ this.drop('idle');
196
+ }
197
+ open() {
198
+ this.opening ??= this.openOnce().finally(() => {
199
+ this.opening = undefined;
200
+ });
201
+ return this.opening;
202
+ }
203
+ async openOnce() {
204
+ this.dropConnection();
205
+ const target = await this.opts.resolveTarget();
206
+ if (target.kind === 'unavailable')
207
+ return { kind: 'unavailable', result: errorResult(target.message, { status: target.status }) };
208
+ if (this.closed)
209
+ return { kind: 'unavailable', result: errorResult('The MCP session ended before xezar answered.', { status: 'aborted' }) };
210
+ this.project = target.project;
211
+ const timeoutMs = Math.min(this.opts.requestTimeoutMs ?? IPC_REQUEST_TIMEOUT_MS, IPC_SESSION_OPEN_TIMEOUT_MS);
212
+ const started = Date.now();
213
+ const connected = await IpcConnection.connect(target.path, this.opts.version, timeoutMs, (connection) => this.onClosed(connection));
214
+ if (!(connected instanceof IpcConnection)) {
215
+ return { kind: 'unavailable', result: unreachable(connected, this.projectLabel(), this.opts.version) };
216
+ }
217
+ const answer = await connected.request({ method: 'session/open' }, Math.max(1, timeoutMs - (Date.now() - started)));
218
+ if (this.closed) {
219
+ connected.close();
220
+ return { kind: 'unavailable', result: errorResult('The MCP session ended before xezar answered.', { status: 'aborted' }) };
221
+ }
222
+ if (answer.kind !== 'response') {
223
+ connected.close();
224
+ return { kind: 'unavailable', result: unreachable(answer, this.projectLabel(), this.opts.version) };
225
+ }
226
+ const response = answer.response;
227
+ if (response.ok && sessionOpenResultSchema.safeParse(response.result).success) {
228
+ this.connection = connected;
229
+ this.state = 'owner';
230
+ return { kind: 'owner' };
231
+ }
232
+ connected.close();
233
+ if (!response.ok && response.error.code === 'project-occupied') {
234
+ this.state = 'refused';
235
+ const error = response.rpcError;
236
+ return {
237
+ kind: 'occupied',
238
+ error: error?.data.reason === MCP_PROJECT_OCCUPIED_REASON ? error : projectOccupiedError(target.project.id),
239
+ };
240
+ }
241
+ if (response.ok) {
242
+ return { kind: 'unavailable', result: errorResult('xezar answered session/open with an unexpected shape.', { status: 'version-mismatch' }) };
243
+ }
244
+ return { kind: 'unavailable', result: refused(response, this.opts.version) };
245
+ }
246
+ onClosed(connection) {
247
+ if (connection !== this.connection)
248
+ return;
249
+ this.connection = undefined;
250
+ if (this.state === 'owner')
251
+ this.state = 'lost';
252
+ }
253
+ drop(next) {
254
+ this.dropConnection();
255
+ this.state = next;
256
+ }
257
+ dropConnection() {
258
+ const connection = this.connection;
259
+ this.connection = undefined;
260
+ connection?.close();
261
+ }
262
+ projectId() {
263
+ return this.project?.id ?? 'unknown';
264
+ }
265
+ projectLabel() {
266
+ return this.project ?? { id: 'unknown', name: 'this project' };
267
+ }
268
+ }
269
+ // ---- the IPC connection ----------------------------------------------------------------------
270
+ /**
271
+ * One kept connection, many requests. Answers are matched by id; every request settles exactly
272
+ * once and never later than its own timeout, and none of that closes the connection — only the
273
+ * service, the OS or `close()` do.
274
+ */
275
+ class IpcConnection {
276
+ socket;
277
+ version;
278
+ pending = new Map();
279
+ nextId = 1;
280
+ ended = false;
281
+ constructor(socket, version) {
282
+ this.socket = socket;
283
+ this.version = version;
284
+ }
285
+ /** Connect, or answer why not. `onClose` fires once, when a connected socket closes for any reason. */
286
+ static connect(path, version, timeoutMs, onClose) {
287
+ return new Promise((resolve) => {
288
+ const socket = createConnection(path);
289
+ let settled = false;
290
+ const timer = setTimeout(() => {
291
+ if (settled)
292
+ return;
293
+ settled = true;
294
+ socket.destroy();
295
+ resolve({ kind: 'timeout' });
296
+ }, timeoutMs);
297
+ socket.once('error', (err) => {
298
+ if (settled)
299
+ return;
300
+ settled = true;
301
+ clearTimeout(timer);
302
+ socket.destroy();
303
+ resolve({ kind: 'error', code: err.code });
304
+ });
305
+ socket.once('connect', () => {
306
+ if (settled)
307
+ return;
308
+ settled = true;
309
+ clearTimeout(timer);
310
+ const connection = new IpcConnection(socket, version);
311
+ connection.attach(onClose);
312
+ resolve(connection);
313
+ });
314
+ });
315
+ }
316
+ request(body, timeoutMs, signal) {
317
+ if (this.ended)
318
+ return Promise.resolve({ kind: 'closed' });
319
+ const id = this.nextId++;
320
+ return new Promise((resolve) => {
321
+ const settle = (outcome) => {
322
+ if (!this.pending.delete(id))
323
+ return;
324
+ clearTimeout(timer);
325
+ signal?.removeEventListener('abort', onAbort);
326
+ resolve(outcome);
327
+ };
328
+ const onAbort = () => settle({ kind: 'aborted' });
329
+ // A slow answer is a timeout for THIS call only; the service was not told to cancel anything.
330
+ const timer = setTimeout(() => settle({ kind: 'timeout' }), timeoutMs);
331
+ this.pending.set(id, settle);
332
+ signal?.addEventListener('abort', onAbort);
333
+ this.socket.write(encodeFrame({ v: IPC_PROTOCOL_VERSION, id, bridgeVersion: this.version, ...body }));
334
+ });
335
+ }
336
+ close() {
337
+ this.socket.destroy();
338
+ }
339
+ attach(onClose) {
340
+ const framer = new LineFramer((line) => this.receive(line), () => this.failAll({ kind: 'bad-response' }));
341
+ this.socket.on('data', (chunk) => framer.push(chunk));
342
+ this.socket.on('error', () => {
343
+ // Always followed by `close`, which settles everything.
344
+ });
345
+ this.socket.once('close', () => {
346
+ this.ended = true;
347
+ this.failAll({ kind: 'closed' });
348
+ onClose(this);
349
+ });
350
+ }
351
+ receive(line) {
352
+ let json;
353
+ try {
354
+ json = JSON.parse(line);
355
+ }
356
+ catch {
357
+ this.failAll({ kind: 'bad-response' });
358
+ return;
359
+ }
360
+ const parsed = ipcResponseSchema.safeParse(json);
361
+ // An answer that names no request cannot be matched to one, so every call in flight is told
362
+ // the service answered in a way this bridge does not understand. The session itself stays.
363
+ if (!parsed.success || parsed.data.id === null) {
364
+ this.failAll({ kind: 'bad-response' });
365
+ return;
366
+ }
367
+ this.pending.get(parsed.data.id)?.({ kind: 'response', response: parsed.data });
368
+ }
369
+ failAll(outcome) {
370
+ for (const settle of [...this.pending.values()])
371
+ settle(outcome);
372
+ }
373
+ }
374
+ // ---- readable failures -------------------------------------------------------------
375
+ function unreachable(outcome, project, version) {
376
+ const label = `${project.name} (${project.id})`;
377
+ switch (outcome.kind) {
378
+ case 'error':
379
+ if (outcome.code === 'ENOENT' || outcome.code === 'ECONNREFUSED') {
380
+ return errorResult(`xezar is not running for project ${label}. Start the cockpit in the project's directory with \`xez\` (or \`npx @qodeca/xezar\`), then call this tool again.`, { status: 'not-running' });
381
+ }
382
+ if (outcome.code === 'EACCES' || outcome.code === 'EPERM') {
383
+ return errorResult(`xezar's socket for project ${label} refused this user (permission denied). The bridge must run as the same user as the cockpit.`, { status: 'refused' });
384
+ }
385
+ return errorResult(`Could not reach xezar for project ${label} (${outcome.code ?? 'unknown error'}).`, {
386
+ status: 'unreachable',
387
+ });
388
+ case 'timeout':
389
+ return errorResult(`xezar for project ${label} did not answer in time. It may be busy; the request was not cancelled in xezar. Call again to check.`, { status: 'timeout' });
390
+ case 'closed':
391
+ return errorResult(
392
+ // Not "call again": a write that passed the fence still finishes in the service, so a blind
393
+ // retry could do it twice (a fenced session's other calls in flight land here too).
394
+ `xezar for project ${label} closed the connection before answering, so whether this call ran is unknown — it may have stopped, or this session was fenced. Check the outcome before calling again.`, { status: 'unreachable' });
395
+ case 'bad-response':
396
+ return errorResult(`xezar for project ${label} answered in a format this bridge (xezar ${version}) does not understand. Run the bridge and the cockpit from the same xezar version.`, { status: 'version-mismatch' });
397
+ case 'aborted':
398
+ return errorResult('The MCP session ended before xezar answered.', { status: 'aborted' });
399
+ }
400
+ }
401
+ function refused(response, version) {
402
+ if (response.error.code === 'version-mismatch') {
403
+ return errorResult(`The running xezar (${response.serviceVersion ?? 'unknown version'}) and this bridge (xezar ${version}) speak different bridge protocols. Run both from the same xezar version.`, { status: 'version-mismatch' });
404
+ }
405
+ return errorResult(`xezar refused the request: ${response.error.message}`, { status: 'refused' });
406
+ }
407
+ //# sourceMappingURL=bridge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bridge.js","sourceRoot":"","sources":["../../src/mcp/bridge.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAe,MAAM,UAAU,CAAC;AACzD,OAAO,EAAE,2BAA2B,EAA6D,MAAM,wBAAwB,CAAC;AAChI,OAAO,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,+BAA+B,CAAC;AAC1F,OAAO,EACL,oBAAoB,EACpB,sBAAsB,EACtB,2BAA2B,EAC3B,UAAU,EACV,WAAW,EACX,kBAAkB,EAClB,iBAAiB,EACjB,uBAAuB,EACvB,oBAAoB,EACpB,gBAAgB,GAGjB,MAAM,UAAU,CAAC;AAClB,OAAO,EACL,cAAc,EACd,mBAAmB,EACnB,qBAAqB,EACrB,sBAAsB,EACtB,wBAAwB,GAEzB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,WAAW,EAAgB,MAAM,WAAW,CAAC;AA0D/E,qGAAqG;AACrG,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,IAAI,EAAE,QAAQ;IACd,KAAK,EAAE,cAAc;IACrB,WAAW,EACT,qHAAqH;IACvH,WAAW,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,EAAE,EAAE,oBAAoB,EAAE,KAAK,EAAE;IAC5E,WAAW,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE;CACvE,CAAC;AAEX,MAAM,YAAY,GAChB,qFAAqF;IACrF,kEAAkE,CAAC;AAKrE,yGAAyG;AACzG,MAAM,UAAU,SAAS,CAAC,IAAmB;IAC3C,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAmB,CAAC;IAC5C,MAAM,OAAO,GAAG,IAAI,cAAc,CAAC,IAAI,CAAC,CAAC;IACzC,IAAI,QAAQ,GAAG,KAAK,CAAC;IACrB,MAAM,KAAK,GAAG,CAAC,OAAgB,EAAQ,EAAE;QACvC,IAAI,CAAC,QAAQ;YAAE,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC;IACzD,CAAC,CAAC;IACF,MAAM,OAAO,GAAG,CAAC,EAAa,EAAE,MAAe,EAAQ,EAAE,CAAC,KAAK,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;IAChG,MAAM,IAAI,GAAG,CAAC,EAAoB,EAAE,IAAY,EAAE,OAAe,EAAQ,EAAE,CACzE,KAAK,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,CAAC,CAAC;IAC1D,MAAM,MAAM,GAAG,CAAC,EAAa,EAAE,KAAqB,EAAQ,EAAE,CAAC,KAAK,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;IAEpG,MAAM,MAAM,GAAG,IAAI,UAAU,CAC3B,CAAC,IAAI,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,EACtB,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,cAAc,CAAC,cAAc,EAAE,mBAAmB,CAAC,CACrE,CAAC;IAEF,SAAS,MAAM,CAAC,IAAY;QAC1B,IAAI,IAAa,CAAC;QAClB,IAAI,CAAC;YACH,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC1B,CAAC;QAAC,MAAM,CAAC;YACP,IAAI,CAAC,IAAI,EAAE,cAAc,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC;YACrD,OAAO;QACT,CAAC;QACD,MAAM,MAAM,GAAG,qBAAqB,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QACrD,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,2EAA2E;YAC3E,IAAI,CAAC,IAAI,EAAE,cAAc,CAAC,cAAc,EAAE,iBAAiB,CAAC,CAAC;YAC7D,OAAO;QACT,CAAC;QACD,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC;QAC3C,6EAA6E;QAC7E,+EAA+E;QAC/E,uCAAuC;QACvC,IAAI,EAAE,KAAK,SAAS,IAAI,MAAM,KAAK,SAAS;YAAE,OAAO;QACrD,QAAQ,MAAM,EAAE,CAAC;YACf,KAAK,YAAY,EAAE,CAAC;gBAClB,MAAM,IAAI,GAAG,sBAAsB,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;gBACtD,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;oBAClB,IAAI,CAAC,EAAE,EAAE,cAAc,CAAC,aAAa,EAAE,oCAAoC,CAAC,CAAC;oBAC7E,OAAO;gBACT,CAAC;gBACD,sFAAsF;gBACtF,mFAAmF;gBACnF,oDAAoD;gBACpD,MAAM,SAAS,GAAG,GAAS,EAAE,CAC3B,OAAO,CAAC,EAAE,EAAE;oBACV,eAAe,EAAE,wBAAwB,CAAC,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC;oBACpE,YAAY,EAAE,mBAAmB;oBACjC,UAAU,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE;oBACpE,YAAY,EAAE,YAAY;iBAC3B,CAAC,CAAC;gBACL,KAAK,OAAO,CAAC,UAAU,EAAE,CAAC,IAAI,CAC5B,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC;gBAC1D,uFAAuF;gBACvF,2FAA2F;gBAC3F,SAAS,CACV,CAAC;gBACF,OAAO;YACT,CAAC;YACD,KAAK,MAAM;gBACT,OAAO,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;gBAChB,OAAO;YACT,KAAK,YAAY;gBACf,OAAO,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,WAAW,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,EAAE,CAAC,CAAC;gBACtE,OAAO;YACT,KAAK,YAAY,EAAE,CAAC;gBAClB,MAAM,IAAI,GAAG,oBAAoB,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;gBACpD,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;oBAClB,IAAI,CAAC,EAAE,EAAE,cAAc,CAAC,aAAa,EAAE,8BAA8B,CAAC,CAAC;oBACvE,OAAO;gBACT,CAAC;gBACD,MAAM,EAAE,IAAI,EAAE,GAAG,IAAI,CAAC,IAAI,CAAC;gBAC3B,IAAI,IAAI,KAAK,WAAW,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,EAAE,CAAC;oBAC1E,IAAI,CAAC,EAAE,EAAE,cAAc,CAAC,aAAa,EAAE,iBAAiB,IAAI,EAAE,CAAC,CAAC;oBAChE,OAAO;gBACT,CAAC;gBACD,MAAM,KAAK,GAAG,IAAI,eAAe,EAAE,CAAC;gBACpC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;gBACpB,KAAK,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC;qBACnC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE;oBACf,IAAI,KAAK,CAAC,MAAM,CAAC,OAAO;wBAAE,OAAO;oBACjC,IAAI,OAAO,IAAI,MAAM;wBAAE,MAAM,CAAC,EAAE,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;;wBAC3C,OAAO,CAAC,EAAE,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;gBAClC,CAAC,CAAC;qBACD,OAAO,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;gBACzC,OAAO;YACT,CAAC;YACD;gBACE,IAAI,CAAC,EAAE,EAAE,cAAc,CAAC,cAAc,EAAE,qBAAqB,MAAM,EAAE,CAAC,CAAC;QAC3E,CAAC;IACH,CAAC;IAED,KAAK,UAAU,QAAQ,CAAC,IAA2D,EAAE,MAAmB;QACtG,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,KAAK,WAAW,CAAC,IAAI,CAAC;QAC9C,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QACxG,IAAI,OAAO,CAAC,IAAI,KAAK,UAAU;YAAE,OAAO,OAAO,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC;QACzH,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;QAClC,IAAI,CAAC,QAAQ,CAAC,EAAE;YAAE,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,QAAQ,EAAE,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QACrE,IAAI,MAAM,EAAE,CAAC;YACX,MAAM,CAAC,GAAG,kBAAkB,CAAC,SAAS,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;YACxD,IAAI,CAAC,CAAC,CAAC,OAAO;gBAAE,OAAO,EAAE,MAAM,EAAE,WAAW,CAAC,iDAAiD,CAAC,EAAE,CAAC;YAClG,OAAO;gBACL,MAAM,EAAE,UAAU,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,YAAY,2BAA2B,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,KAAK,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE;oBACvH,MAAM,EAAE,SAAS;oBACjB,GAAG,CAAC,CAAC,IAAI;iBACV,CAAC;aACH,CAAC;QACJ,CAAC;QACD,MAAM,MAAM,GAAG,gBAAgB,CAAC,SAAS,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QAC3D,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,WAAW,CAAC,kBAAkB,IAAI,CAAC,IAAI,4BAA4B,CAAC,EAAE,CAAC;IACzH,CAAC;IAED,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,MAAM,MAAM,GAAG,GAAS,EAAE;YACxB,IAAI,QAAQ;gBAAE,OAAO;YACrB,QAAQ,GAAG,IAAI,CAAC;YAChB,KAAK,MAAM,KAAK,IAAI,QAAQ;gBAAE,KAAK,CAAC,KAAK,EAAE,CAAC;YAC5C,4FAA4F;YAC5F,OAAO,CAAC,KAAK,EAAE,CAAC;YAChB,OAAO,EAAE,CAAC;QACZ,CAAC,CAAC;QACF,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAsB,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QACpH,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;QAC/B,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QACjC,kEAAkE;QAClE,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAClC,CAAC,CAAC,CAAC;AACL,CAAC;AA+BD,MAAM,cAAc;IAOW,IAAI;IANzB,KAAK,GAAiB,MAAM,CAAC;IAC7B,UAAU,CAA4B;IACtC,OAAO,CAAmC;IAC1C,OAAO,CAA2C;IAClD,MAAM,GAAG,KAAK,CAAC;IAEvB,YAA6B,IAA2E;oBAA3E,IAAI;IAA0E,CAAC;IAE5G,0GAA0G;IAC1G,KAAK,CAAC,UAAU;QACd,IAAI,IAAI,CAAC,KAAK,KAAK,OAAO;YAAE,OAAO,SAAS,CAAC;QAC7C,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC;QACjC,OAAO,MAAM,CAAC,IAAI,KAAK,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;IAC/D,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,MAA+B,EAAE,MAAe,EAAE,MAAmB;QAC9E,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC;QAC1B,IAAI,MAAM,KAAK,OAAO,EAAE,CAAC;YACvB,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC;YACjC,IAAI,MAAM,CAAC,IAAI,KAAK,aAAa;gBAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC;YACpF,6FAA6F;YAC7F,wFAAwF;YACxF,IAAI,MAAM,KAAK,MAAM,IAAI,MAAM,KAAK,SAAS;gBAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,mBAAmB,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,EAAE,CAAC;YACtH,IAAI,MAAM,CAAC,IAAI,KAAK,UAAU;gBAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC;QAChF,CAAC;QACD,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC;QACnC,IAAI,CAAC,UAAU;YAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,mBAAmB,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,EAAE,CAAC;QACxF,MAAM,OAAO,GAAG,MAAM,UAAU,CAAC,OAAO,CACtC,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,EACvD,IAAI,CAAC,IAAI,CAAC,gBAAgB,IAAI,sBAAsB,EACpD,MAAM,CACP,CAAC;QACF,IAAI,OAAO,CAAC,IAAI,KAAK,UAAU;YAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,WAAW,CAAC,OAAO,EAAE,IAAI,CAAC,YAAY,EAAE,EAAE,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QACjI,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;QAClC,IAAI,CAAC,QAAQ,CAAC,EAAE,IAAI,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,iBAAiB,EAAE,CAAC;YAC9D,8EAA8E;YAC9E,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YAClB,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,CAAC,QAAQ,IAAI,mBAAmB,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,EAAE,CAAC;QAC9F,CAAC;QACD,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAC;IACxC,CAAC;IAED,8FAA8F;IAC9F,KAAK;QACH,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;QACnB,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACpB,CAAC;IAEO,IAAI;QACV,IAAI,CAAC,OAAO,KAAK,IAAI,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE;YAC5C,IAAI,CAAC,OAAO,GAAG,SAAS,CAAC;QAC3B,CAAC,CAAC,CAAC;QACH,OAAO,IAAI,CAAC,OAAO,CAAC;IACtB,CAAC;IAEO,KAAK,CAAC,QAAQ;QACpB,IAAI,CAAC,cAAc,EAAE,CAAC;QACtB,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC;QAC/C,IAAI,MAAM,CAAC,IAAI,KAAK,aAAa;YAAE,OAAO,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,EAAE,WAAW,CAAC,MAAM,CAAC,OAAO,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC;QAClI,IAAI,IAAI,CAAC,MAAM;YAAE,OAAO,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,EAAE,WAAW,CAAC,8CAA8C,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,EAAE,CAAC;QAC5I,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC;QAC9B,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,gBAAgB,IAAI,sBAAsB,EAAE,2BAA2B,CAAC,CAAC;QAC9G,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC3B,MAAM,SAAS,GAAG,MAAM,aAAa,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,SAAS,EAAE,CAAC,UAAU,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC;QACpI,IAAI,CAAC,CAAC,SAAS,YAAY,aAAa,CAAC,EAAE,CAAC;YAC1C,OAAO,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,EAAE,WAAW,CAAC,SAAS,EAAE,IAAI,CAAC,YAAY,EAAE,EAAE,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QACzG,CAAC;QACD,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,cAAc,EAAE,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,SAAS,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;QACpH,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YAChB,SAAS,CAAC,KAAK,EAAE,CAAC;YAClB,OAAO,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,EAAE,WAAW,CAAC,8CAA8C,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,EAAE,CAAC;QAC7H,CAAC;QACD,IAAI,MAAM,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;YAC/B,SAAS,CAAC,KAAK,EAAE,CAAC;YAClB,OAAO,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,EAAE,WAAW,CAAC,MAAM,EAAE,IAAI,CAAC,YAAY,EAAE,EAAE,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QACtG,CAAC;QACD,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC;QACjC,IAAI,QAAQ,CAAC,EAAE,IAAI,uBAAuB,CAAC,SAAS,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,CAAC;YAC9E,IAAI,CAAC,UAAU,GAAG,SAAS,CAAC;YAC5B,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC;YACrB,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;QAC3B,CAAC;QACD,SAAS,CAAC,KAAK,EAAE,CAAC;QAClB,IAAI,CAAC,QAAQ,CAAC,EAAE,IAAI,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,kBAAkB,EAAE,CAAC;YAC/D,IAAI,CAAC,KAAK,GAAG,SAAS,CAAC;YACvB,MAAM,KAAK,GAAG,QAAQ,CAAC,QAAQ,CAAC;YAChC,OAAO;gBACL,IAAI,EAAE,UAAU;gBAChB,KAAK,EAAE,KAAK,EAAE,IAAI,CAAC,MAAM,KAAK,2BAA2B,CAAC,CAAC,CAAE,KAAiC,CAAC,CAAC,CAAC,oBAAoB,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC;aACzI,CAAC;QACJ,CAAC;QACD,IAAI,QAAQ,CAAC,EAAE,EAAE,CAAC;YAChB,OAAO,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,EAAE,WAAW,CAAC,uDAAuD,EAAE,EAAE,MAAM,EAAE,kBAAkB,EAAE,CAAC,EAAE,CAAC;QAC/I,CAAC;QACD,OAAO,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,EAAE,OAAO,CAAC,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;IAC/E,CAAC;IAEO,QAAQ,CAAC,UAAyB;QACxC,IAAI,UAAU,KAAK,IAAI,CAAC,UAAU;YAAE,OAAO;QAC3C,IAAI,CAAC,UAAU,GAAG,SAAS,CAAC;QAC5B,IAAI,IAAI,CAAC,KAAK,KAAK,OAAO;YAAE,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC;IAClD,CAAC;IAEO,IAAI,CAAC,IAAkB;QAC7B,IAAI,CAAC,cAAc,EAAE,CAAC;QACtB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;IACpB,CAAC;IAEO,cAAc;QACpB,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC;QACnC,IAAI,CAAC,UAAU,GAAG,SAAS,CAAC;QAC5B,UAAU,EAAE,KAAK,EAAE,CAAC;IACtB,CAAC;IAEO,SAAS;QACf,OAAO,IAAI,CAAC,OAAO,EAAE,EAAE,IAAI,SAAS,CAAC;IACvC,CAAC;IAEO,YAAY;QAClB,OAAO,IAAI,CAAC,OAAO,IAAI,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,cAAc,EAAE,CAAC;IACjE,CAAC;CACF;AAED,iGAAiG;AAEjG;;;;GAIG;AACH,MAAM,aAAa;IAME,MAAM;IACN,OAAO;IANT,OAAO,GAAG,IAAI,GAAG,EAAyC,CAAC;IACpE,MAAM,GAAG,CAAC,CAAC;IACX,KAAK,GAAG,KAAK,CAAC;IAEtB,YACmB,MAAc,EACd,OAAe;sBADf,MAAM;uBACN,OAAO;IACvB,CAAC;IAEJ,uGAAuG;IACvG,MAAM,CAAC,OAAO,CACZ,IAAY,EACZ,OAAe,EACf,SAAiB,EACjB,OAA4C;QAE5C,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;YAC7B,MAAM,MAAM,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC;YACtC,IAAI,OAAO,GAAG,KAAK,CAAC;YACpB,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;gBAC5B,IAAI,OAAO;oBAAE,OAAO;gBACpB,OAAO,GAAG,IAAI,CAAC;gBACf,MAAM,CAAC,OAAO,EAAE,CAAC;gBACjB,OAAO,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC;YAC/B,CAAC,EAAE,SAAS,CAAC,CAAC;YACd,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,GAA0B,EAAE,EAAE;gBAClD,IAAI,OAAO;oBAAE,OAAO;gBACpB,OAAO,GAAG,IAAI,CAAC;gBACf,YAAY,CAAC,KAAK,CAAC,CAAC;gBACpB,MAAM,CAAC,OAAO,EAAE,CAAC;gBACjB,OAAO,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;YAC7C,CAAC,CAAC,CAAC;YACH,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,EAAE;gBAC1B,IAAI,OAAO;oBAAE,OAAO;gBACpB,OAAO,GAAG,IAAI,CAAC;gBACf,YAAY,CAAC,KAAK,CAAC,CAAC;gBACpB,MAAM,UAAU,GAAG,IAAI,aAAa,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;gBACtD,UAAU,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;gBAC3B,OAAO,CAAC,UAAU,CAAC,CAAC;YACtB,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC;IAED,OAAO,CAAC,IAA0C,EAAE,SAAiB,EAAE,MAAoB;QACzF,IAAI,IAAI,CAAC,KAAK;YAAE,OAAO,OAAO,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC;QAC3D,MAAM,EAAE,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;QACzB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;YAC7B,MAAM,MAAM,GAAG,CAAC,OAAmB,EAAQ,EAAE;gBAC3C,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;oBAAE,OAAO;gBACrC,YAAY,CAAC,KAAK,CAAC,CAAC;gBACpB,MAAM,EAAE,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;gBAC9C,OAAO,CAAC,OAAO,CAAC,CAAC;YACnB,CAAC,CAAC;YACF,MAAM,OAAO,GAAG,GAAS,EAAE,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC;YACxD,8FAA8F;YAC9F,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,EAAE,SAAS,CAAC,CAAC;YACvE,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;YAC7B,MAAM,EAAE,gBAAgB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;YAC3C,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,EAAE,CAAC,EAAE,oBAAoB,EAAE,EAAE,EAAE,aAAa,EAAE,IAAI,CAAC,OAAO,EAAE,GAAG,IAAI,EAAE,CAAC,CAAC,CAAC;QACxG,CAAC,CAAC,CAAC;IACL,CAAC;IAED,KAAK;QACH,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;IACxB,CAAC;IAEO,MAAM,CAAC,OAA4C;QACzD,MAAM,MAAM,GAAG,IAAI,UAAU,CAC3B,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAC5B,GAAG,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,cAAc,EAAE,CAAC,CAC7C,CAAC;QACF,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;QAC9D,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;YAC3B,wDAAwD;QAC1D,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE;YAC7B,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;YAClB,IAAI,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC;YACjC,OAAO,CAAC,IAAI,CAAC,CAAC;QAChB,CAAC,CAAC,CAAC;IACL,CAAC;IAEO,OAAO,CAAC,IAAY;QAC1B,IAAI,IAAa,CAAC;QAClB,IAAI,CAAC;YACH,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC1B,CAAC;QAAC,MAAM,CAAC;YACP,IAAI,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,cAAc,EAAE,CAAC,CAAC;YACvC,OAAO;QACT,CAAC;QACD,MAAM,MAAM,GAAG,iBAAiB,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QACjD,4FAA4F;QAC5F,2FAA2F;QAC3F,IAAI,CAAC,MAAM,CAAC,OAAO,IAAI,MAAM,CAAC,IAAI,CAAC,EAAE,KAAK,IAAI,EAAE,CAAC;YAC/C,IAAI,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,cAAc,EAAE,CAAC,CAAC;YACvC,OAAO;QACT,CAAC;QACD,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;IAClF,CAAC;IAEO,OAAO,CAAC,OAAmB;QACjC,KAAK,MAAM,MAAM,IAAI,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;YAAE,MAAM,CAAC,OAAO,CAAC,CAAC;IACnE,CAAC;CACF;AAED,uFAAuF;AAEvF,SAAS,WAAW,CAClB,OAAkD,EAClD,OAAqC,EACrC,OAAe;IAEf,MAAM,KAAK,GAAG,GAAG,OAAO,CAAC,IAAI,KAAK,OAAO,CAAC,EAAE,GAAG,CAAC;IAChD,QAAQ,OAAO,CAAC,IAAI,EAAE,CAAC;QACrB,KAAK,OAAO;YACV,IAAI,OAAO,CAAC,IAAI,KAAK,QAAQ,IAAI,OAAO,CAAC,IAAI,KAAK,cAAc,EAAE,CAAC;gBACjE,OAAO,WAAW,CAChB,oCAAoC,KAAK,oHAAoH,EAC7J,EAAE,MAAM,EAAE,aAAa,EAAE,CAC1B,CAAC;YACJ,CAAC;YACD,IAAI,OAAO,CAAC,IAAI,KAAK,QAAQ,IAAI,OAAO,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;gBAC1D,OAAO,WAAW,CAChB,8BAA8B,KAAK,8FAA8F,EACjI,EAAE,MAAM,EAAE,SAAS,EAAE,CACtB,CAAC;YACJ,CAAC;YACD,OAAO,WAAW,CAAC,qCAAqC,KAAK,KAAK,OAAO,CAAC,IAAI,IAAI,eAAe,IAAI,EAAE;gBACrG,MAAM,EAAE,aAAa;aACtB,CAAC,CAAC;QACL,KAAK,SAAS;YACZ,OAAO,WAAW,CAChB,qBAAqB,KAAK,uGAAuG,EACjI,EAAE,MAAM,EAAE,SAAS,EAAE,CACtB,CAAC;QACJ,KAAK,QAAQ;YACX,OAAO,WAAW;YAChB,4FAA4F;YAC5F,oFAAoF;YACpF,qBAAqB,KAAK,yKAAyK,EACnM,EAAE,MAAM,EAAE,aAAa,EAAE,CAC1B,CAAC;QACJ,KAAK,cAAc;YACjB,OAAO,WAAW,CAChB,qBAAqB,KAAK,4CAA4C,OAAO,oFAAoF,EACjK,EAAE,MAAM,EAAE,kBAAkB,EAAE,CAC/B,CAAC;QACJ,KAAK,SAAS;YACZ,OAAO,WAAW,CAAC,8CAA8C,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC;IAC9F,CAAC;AACH,CAAC;AAED,SAAS,OAAO,CAAC,QAA6C,EAAE,OAAe;IAC7E,IAAI,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,kBAAkB,EAAE,CAAC;QAC/C,OAAO,WAAW,CAChB,sBAAsB,QAAQ,CAAC,cAAc,IAAI,iBAAiB,4BAA4B,OAAO,2EAA2E,EAChL,EAAE,MAAM,EAAE,kBAAkB,EAAE,CAC/B,CAAC;IACJ,CAAC;IACD,OAAO,WAAW,CAAC,8BAA8B,QAAQ,CAAC,KAAK,CAAC,OAAO,EAAE,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC;AACpG,CAAC"}
@@ -0,0 +1,49 @@
1
+ import { z } from 'zod';
2
+ /**
3
+ * D-04's connection descriptor (docs/features/mcp-server/mcp-d04-connection-file-decision.md):
4
+ * `<project root>/.local/xezar/mcp-connection.json`, written by the running service so nobody
5
+ * hand-authors connection data (F-14, A-01).
6
+ *
7
+ * The shape is D-04.2's with ONE deliberate omission: there is no `token`. D-04.5 put a token in
8
+ * the file only because the transport was still open; D-01 then chose a per-project Unix socket
9
+ * and made WHICH SOCKET the peer connected to the binding (D-01 § 6), so a token would be a
10
+ * secret nothing checks. F-15 is simplest to keep with no secret in the file at all. `endpoint`
11
+ * is D-01's socket, the one field the bridge could use; `project` and `service` are labels a
12
+ * human reads (D-04.5: never the identity the server trusts).
13
+ */
14
+ /** Additive changes keep version 1 (N-08); an incompatible one bumps it. */
15
+ export declare const MCP_CONNECTION_SCHEMA_VERSION = 1;
16
+ export declare const MCP_CONNECTION_FILE = "mcp-connection.json";
17
+ export declare const mcpConnectionDescriptorSchema: z.ZodObject<{
18
+ schemaVersion: z.ZodLiteral<1>;
19
+ project: z.ZodObject<{
20
+ id: z.ZodString;
21
+ root: z.ZodString;
22
+ dataDir: z.ZodString;
23
+ }, z.core.$strip>;
24
+ service: z.ZodObject<{
25
+ pid: z.ZodNumber;
26
+ startedAt: z.ZodString;
27
+ }, z.core.$strip>;
28
+ endpoint: z.ZodObject<{
29
+ socket: z.ZodString;
30
+ }, z.core.$strip>;
31
+ }, z.core.$strip>;
32
+ export type McpConnectionDescriptor = z.infer<typeof mcpConnectionDescriptorSchema>;
33
+ export declare function mcpConnectionPath(dataDir: string): string;
34
+ /**
35
+ * Write the descriptor atomically (tmp + rename) at mode 0600, overwriting whatever a previous
36
+ * service left: every field describes THIS process (D-04.3). The ignore file is ensured first, so
37
+ * there is no moment the descriptor is visible to `git add -A` (D-04.4). Throws on failure — the
38
+ * caller turns that into one warning (N-07).
39
+ */
40
+ export declare function writeMcpConnectionFile(input: {
41
+ project: {
42
+ id: string;
43
+ root: string;
44
+ };
45
+ dataDir: string;
46
+ socket: string;
47
+ pid?: number;
48
+ startedAt?: Date;
49
+ }): string;
@@ -0,0 +1,63 @@
1
+ import { chmodSync, mkdirSync, renameSync, rmSync, writeFileSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import { z } from 'zod';
4
+ import { ensureProjectDataIgnored } from '../project-data-paths.js';
5
+ /**
6
+ * D-04's connection descriptor (docs/features/mcp-server/mcp-d04-connection-file-decision.md):
7
+ * `<project root>/.local/xezar/mcp-connection.json`, written by the running service so nobody
8
+ * hand-authors connection data (F-14, A-01).
9
+ *
10
+ * The shape is D-04.2's with ONE deliberate omission: there is no `token`. D-04.5 put a token in
11
+ * the file only because the transport was still open; D-01 then chose a per-project Unix socket
12
+ * and made WHICH SOCKET the peer connected to the binding (D-01 § 6), so a token would be a
13
+ * secret nothing checks. F-15 is simplest to keep with no secret in the file at all. `endpoint`
14
+ * is D-01's socket, the one field the bridge could use; `project` and `service` are labels a
15
+ * human reads (D-04.5: never the identity the server trusts).
16
+ */
17
+ /** Additive changes keep version 1 (N-08); an incompatible one bumps it. */
18
+ export const MCP_CONNECTION_SCHEMA_VERSION = 1;
19
+ export const MCP_CONNECTION_FILE = 'mcp-connection.json';
20
+ export const mcpConnectionDescriptorSchema = z.object({
21
+ schemaVersion: z.literal(MCP_CONNECTION_SCHEMA_VERSION),
22
+ project: z.object({ id: z.string(), root: z.string(), dataDir: z.string() }),
23
+ service: z.object({ pid: z.number().int().positive(), startedAt: z.string() }),
24
+ endpoint: z.object({ socket: z.string() }),
25
+ });
26
+ export function mcpConnectionPath(dataDir) {
27
+ return join(dataDir, MCP_CONNECTION_FILE);
28
+ }
29
+ /**
30
+ * Write the descriptor atomically (tmp + rename) at mode 0600, overwriting whatever a previous
31
+ * service left: every field describes THIS process (D-04.3). The ignore file is ensured first, so
32
+ * there is no moment the descriptor is visible to `git add -A` (D-04.4). Throws on failure — the
33
+ * caller turns that into one warning (N-07).
34
+ */
35
+ export function writeMcpConnectionFile(input) {
36
+ const descriptor = {
37
+ schemaVersion: MCP_CONNECTION_SCHEMA_VERSION,
38
+ project: { id: input.project.id, root: input.project.root, dataDir: input.dataDir },
39
+ service: { pid: input.pid ?? process.pid, startedAt: (input.startedAt ?? new Date()).toISOString() },
40
+ endpoint: { socket: input.socket },
41
+ };
42
+ ensureProjectDataIgnored(input.dataDir);
43
+ mkdirSync(input.dataDir, { recursive: true });
44
+ const path = mcpConnectionPath(input.dataDir);
45
+ const tmp = `${path}.tmp`;
46
+ try {
47
+ writeFileSync(tmp, `${JSON.stringify(descriptor, null, 2)}\n`, { encoding: 'utf8', mode: 0o600 });
48
+ // The mode is ignored when a stale tmp already existed; the rename carries the tmp's mode.
49
+ chmodSync(tmp, 0o600);
50
+ renameSync(tmp, path);
51
+ }
52
+ catch (err) {
53
+ try {
54
+ rmSync(tmp, { force: true });
55
+ }
56
+ catch {
57
+ /* the write's own error is the one worth reporting */
58
+ }
59
+ throw err;
60
+ }
61
+ return path;
62
+ }
63
+ //# sourceMappingURL=connection-file.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connection-file.js","sourceRoot":"","sources":["../../src/mcp/connection-file.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,94 @@
1
+ import { type McpJournalRow } from '../contract/index.js';
2
+ import type { EventJournal } from './event-journal.ts';
3
+ /**
4
+ * The leader-side echo guard (#106, F-13): what stands between the project's event journal and a
5
+ * project-bound leader, so the leader sees human changes and new outcomes and never its own echoes.
6
+ *
7
+ * WHY IT EXISTS. A leader that reacts to every row would react to the row its OWN mutation
8
+ * produced, mutate again, and read that echo too — a loop that costs a model turn per lap and never
9
+ * ends. The compatibility report states the rule: do not react recursively to the leader's own
10
+ * operation acknowledgements; keep causal origin so real new outcomes stay actionable while echoes,
11
+ * duplicate delivery and presentation updates do not trigger loops.
12
+ *
13
+ * THE SOURCE. The same state source as the cockpit, after project filtering (requirements § 8):
14
+ * the per-project journal (#103), fed from the shared services an MCP write goes through. Never the
15
+ * workspace stream — `/api/v1/workspace/events` carries every project and the registry news, and an
16
+ * unfiltered workspace stream reaching MCP is exactly what § 8 prohibits (D-05 § 6.4).
17
+ *
18
+ * THE RULES, in the order `admit` applies them. A row is delivered only when it survives all six:
19
+ * 1. `invalid` — it does not parse as a journal row (`mcpJournalRowSchema`).
20
+ * 2. `foreign-project` — it names a project other than the one this session is bound to (N-01).
21
+ * 3. `workspace-only` — its `kind` is a workspace-only event name. `project-added`,
22
+ * `project-removed` and `checkout-progress` name OTHER projects; N-01 forbids a project-bound
23
+ * session ever receiving one, whatever category an emitter filed it under.
24
+ * 4. `presentation` — its `kind` is presentation, a log line or a counter: D-05 § 6.3's
25
+ * closed negative list plus the SSE stream's own `usage` and `ping`. The journal should never
26
+ * hold one (issue #104's catalog excludes them); this is the leader's own floor under that.
27
+ * 5. `own-echo` — `origin` is `leader` AND `causedBy` is an operation THIS guard issued.
28
+ * Exactly D-05 § 6.3's rule. Never "I recognise the run": a task the leader started still
29
+ * reports its completion (`origin: system`) and a human's edit to it (`origin: human`), and a
30
+ * `leader` row caused by an operation this guard never issued — another session's — is news.
31
+ * 6. `duplicate` — its `eventId` was already delivered. Delivery is at-least-once (D-05
32
+ * § 6.6), and a replay overlapping the live feed must not wake the leader twice.
33
+ *
34
+ * ORDERING IS THE WHOLE TRICK. The service writes the echo while the operation is still in flight:
35
+ * `PATCH /runs/:id` updates the store synchronously inside the route, so the row can reach the
36
+ * journal before the tool result reaches the leader. An operation id recorded on ACKNOWLEDGEMENT
37
+ * would therefore miss its own echo. `issue` records the id first and only then dispatches, so no
38
+ * interleaving can deliver an echo of an operation the guard does not yet know about.
39
+ *
40
+ * WHAT IT IS NOT. Not the journal (#103), not the catalog emitter (#104), not replay/reconnect
41
+ * (#105) and not the event controller (#107): those produce, page and dispatch rows, and each of
42
+ * them hands rows to `admit`. It grants nothing, persists nothing and opens no file.
43
+ */
44
+ /** The workspace-only names N-01 keeps away from a project-bound session: each names other projects. */
45
+ export declare const WORKSPACE_ONLY_EVENT_NAMES: readonly ['project-added', 'project-removed', 'checkout-progress'];
46
+ /**
47
+ * Presentation, log lines and counters (requirements § 6): D-05 § 6.3's decided-negative list, plus
48
+ * the two stream signals the brief names as the traffic that must not become leader events.
49
+ */
50
+ export declare const PRESENTATION_EVENT_KINDS: readonly ['item.started', 'item.completed', 'tool-call', 'tool-result', 'text', 'token-usage', 'cost', 'usage', 'ping'];
51
+ export type EchoDropReason = 'invalid' | 'foreign-project' | 'workspace-only' | 'presentation' | 'own-echo' | 'duplicate';
52
+ export type EchoVerdict = {
53
+ deliver: true;
54
+ row: McpJournalRow;
55
+ } | {
56
+ deliver: false;
57
+ reason: EchoDropReason;
58
+ };
59
+ export interface EchoGuardOptions {
60
+ /** The registry slug of the bound project, from the trusted binding — never from a tool argument. */
61
+ projectId: string;
62
+ }
63
+ export declare class EchoGuard {
64
+ #private;
65
+ readonly projectId: string;
66
+ constructor(options: EchoGuardOptions);
67
+ /**
68
+ * Record `operationId` as this leader's own, THEN run `dispatch`. The only way to issue an
69
+ * operation through the guard, so the id is always known before its echo can exist.
70
+ */
71
+ issue<T>(operationId: string, dispatch: () => T | Promise<T>): Promise<T>;
72
+ /** Whether `operationId` is one this guard issued. */
73
+ isOwn(operationId: string): boolean;
74
+ /** Decide one row. Pure apart from remembering what it delivered; never throws. */
75
+ admit(candidate: unknown): EchoVerdict;
76
+ /**
77
+ * Forget which rows were delivered — for a journal that was recreated (`cursor_too_old` after a
78
+ * new epoch restarts `journalSeq`, and therefore `eventId`, at 1). The operations this leader
79
+ * issued are kept: an echo of one is still an echo after the journal changed.
80
+ */
81
+ forgetDelivered(): void;
82
+ }
83
+ /**
84
+ * Attach a guarded leader feed to the bound project's journal. `deliver` sees only admitted rows;
85
+ * `onDrop`, when given, sees every refusal (for tests and diagnostics — never for the leader).
86
+ * Returns the unsubscribe, which the caller must keep: a feed nobody detaches is a listener the
87
+ * journal holds for ever.
88
+ */
89
+ export declare function attachLeaderFeed(options: {
90
+ journal: Pick<EventJournal, 'projectId' | 'subscribe'>;
91
+ guard: EchoGuard;
92
+ deliver: (row: McpJournalRow) => void;
93
+ onDrop?: (reason: EchoDropReason, row: McpJournalRow) => void;
94
+ }): () => void;