@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,46 @@
1
+ import { z } from 'zod';
2
+ import type { EventJournal } from '../event-journal.ts';
3
+ import { type LeaderCursors, type StateReader } from '../reconnect.ts';
4
+ /**
5
+ * `leader_events` (#251): the leader's PULL read of its project's significant events (F-21, A-15,
6
+ * A-21). A thin door over `reconnect.ts`, which owns every rule — this file only chooses the call
7
+ * and shapes the answer:
8
+ *
9
+ * - `read` is `reconnect()`: the outstanding rows strictly after the leader's acknowledged cursor
10
+ * (or after an explicit `cursor`, a rewind that never moves the ack), in `journalSeq` order, THEN
11
+ * the current state of the tasks they name. A cursor whose rows are gone is the journal's own
12
+ * `cursor_too_old` answer — stated as a gap with the current state beside it, never a partial
13
+ * replay that would read as "nothing happened in between".
14
+ * - `ack` is `LeaderCursors.ack()`: monotonic and idempotent, so a duplicate or an older cursor is
15
+ * a successful no-op, never a rewind.
16
+ *
17
+ * At-least-once, no repeated effect (N-10): a read before the ack returns the same rows again, each
18
+ * with its stable `eventId`, which is how the leader drops a duplicate.
19
+ *
20
+ * What this is NOT: push. One read when the leader connects, and a next page only because an answer
21
+ * said `hasMore` — no timer, no status poll, no subscription (N-06). Live delivery to a connected
22
+ * client (F-20, `LeaderFeed`) and a model reaction to an event (A-19) are Phase 6.
23
+ *
24
+ * F-15: rows are scrubbed with this host's secret list on the way out (the journal already scrubs a
25
+ * summary; a subject id is prose a writer chose too). Cursors are never touched: they are the
26
+ * journal's own opaque tokens. F-12 / N-01: a row and a task state carry no account identity, and
27
+ * the journal is the bound project's — a cursor from another project is refused outright.
28
+ */
29
+ /** The composed parts the tool reads — built once per project by `startMcpService`. */
30
+ export interface LeaderEventsPort {
31
+ readonly journal: EventJournal;
32
+ readonly cursors: LeaderCursors;
33
+ readonly readState: StateReader;
34
+ readonly secretValues: readonly string[];
35
+ }
36
+ export declare const leaderEventsInputSchema: z.ZodObject<{
37
+ action: z.ZodEnum<{
38
+ ack: "ack";
39
+ read: "read";
40
+ }>;
41
+ cursor: z.ZodOptional<z.ZodString>;
42
+ limit: z.ZodOptional<z.ZodNumber>;
43
+ operationId: z.ZodOptional<z.ZodString>;
44
+ }, z.core.$strict>;
45
+ export type LeaderEventsInput = z.output<typeof leaderEventsInputSchema>;
46
+ export declare const leaderEventsTool: import("../tool.ts").McpTool<z.ZodObject<z.core.$ZodLooseShape, z.core.$strip>>;
@@ -0,0 +1,126 @@
1
+ import { z } from 'zod';
2
+ import { MCP_JOURNAL_PAGE_ROWS, mcpJournalCursorSchema, operationIdSchema } from '../../contract/index.js';
3
+ import { redactDeep } from '../../core/secret-redaction.js';
4
+ import { McpJournalCursorError } from '../event-journal.js';
5
+ import { reconnect } from '../reconnect.js';
6
+ import { defineTool, errorResult, textResult } from '../tool.js';
7
+ export const leaderEventsInputSchema = z
8
+ .object({
9
+ action: z
10
+ .enum(['read', 'ack'])
11
+ .describe('read: the events outstanding since your last acknowledged position, then the current state of the tasks they name. ' +
12
+ 'ack: record that you have taken every event up to cursor into account.'),
13
+ cursor: mcpJournalCursorSchema
14
+ .optional()
15
+ .describe('read: replay after this cursor instead of your acknowledged position (optional; it never moves the acknowledgement). ' +
16
+ 'ack: required — the nextCursor of a page, or the resumeCursor of a gap.'),
17
+ limit: z.number().int().min(1).max(MCP_JOURNAL_PAGE_ROWS).optional().describe(`read: events per page, at most ${MCP_JOURNAL_PAGE_ROWS}.`),
18
+ operationId: operationIdSchema
19
+ .optional()
20
+ .describe('ack: required — a client-generated key for this acknowledgement (8–128 chars). Reuse it only to repeat the same acknowledgement. read: not accepted, because a read is meant to return the same events again until you ack them.'),
21
+ })
22
+ .strict()
23
+ .superRefine((args, ctx) => {
24
+ if (args.action === 'ack' && args.cursor === undefined) {
25
+ ctx.addIssue({ code: 'custom', path: ['cursor'], message: 'ack needs cursor' });
26
+ }
27
+ if (args.action === 'ack' && args.limit !== undefined) {
28
+ ctx.addIssue({ code: 'custom', path: ['limit'], message: 'limit does not apply to ack' });
29
+ }
30
+ // D-06 § 5.2 (#264). `ack` writes the leader's position, so it carries an operation id. `read`
31
+ // must NOT: at-least-once delivery means a repeated read deliberately returns the same rows
32
+ // again, and a receipt over it would answer the second read with the receipt instead.
33
+ if (args.action === 'ack' && args.operationId === undefined) {
34
+ ctx.addIssue({ code: 'custom', path: ['operationId'], message: 'ack needs operationId' });
35
+ }
36
+ if (args.action === 'read' && args.operationId !== undefined) {
37
+ ctx.addIssue({ code: 'custom', path: ['operationId'], message: 'operationId does not apply to read' });
38
+ }
39
+ });
40
+ const NOT_CONNECTED = "leader_events is not connected to this project's event journal; nothing was read or acknowledged.";
41
+ export const leaderEventsTool = defineTool({
42
+ name: 'leader_events',
43
+ title: 'Read and acknowledge project events',
44
+ description: [
45
+ "Read this project's significant events (task outcomes, questions, quality gates, human changes, executor availability) since you last acknowledged them, and acknowledge them.",
46
+ 'Call read when you connect or reconnect. It returns the outstanding events in order, each with a stable eventId and a standing (current, superseded or unjudged), then the current state of the tasks they name — the state is the authority, an event is history.',
47
+ 'When hasMore is true, read again at once; otherwise do not poll — call read again on your next connection.',
48
+ 'After you have taken a page into account, ack its nextCursor. Until you do, read returns the same events again, so drop any eventId you already handled. Acknowledging an older cursor changes nothing.',
49
+ 'status "gap" means events after your position are no longer retained: nothing is replayed, the current state is included, and you continue by acking resumeCursor.',
50
+ ].join('\n'),
51
+ inputSchema: leaderEventsInputSchema,
52
+ annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: false },
53
+ async call(args, ctx) {
54
+ const port = ctx.leaderEvents;
55
+ if (!port)
56
+ return errorResult(NOT_CONNECTED);
57
+ try {
58
+ return args.action === 'ack' ? ack(port, args.cursor) : read(port, args);
59
+ }
60
+ catch (err) {
61
+ if (err instanceof McpJournalCursorError) {
62
+ return errorResult(`${err.rejection.message}. Nothing was ${args.action === 'ack' ? 'acknowledged' : 'read'}.`, {
63
+ ...err.rejection,
64
+ });
65
+ }
66
+ throw err;
67
+ }
68
+ },
69
+ });
70
+ function read(port, args) {
71
+ const answer = reconnect({
72
+ journal: port.journal,
73
+ cursors: port.cursors,
74
+ readState: port.readState,
75
+ ...(args.cursor === undefined ? {} : { cursor: args.cursor }),
76
+ ...(args.limit === undefined ? {} : { limit: args.limit }),
77
+ });
78
+ // D-05 § 6.6: the rows are handed to the client now, so they count as delivered — not acked.
79
+ const last = answer.status === 'ok' ? answer.events.at(-1)?.row.journalSeq : undefined;
80
+ if (last !== undefined)
81
+ port.cursors.markDelivered(last);
82
+ const position = port.cursors.position();
83
+ const structured = shape(answer, position, port.secretValues);
84
+ return textResult(`${headline(answer)}\n${JSON.stringify(structured)}`, structured);
85
+ }
86
+ function ack(port, cursor) {
87
+ const result = port.cursors.ack(cursor);
88
+ const structured = { status: result.status, ackedSeq: result.ackedSeq, position: port.cursors.position() };
89
+ const text = result.status === 'acked'
90
+ ? `Acknowledged every event through #${result.ackedSeq}.`
91
+ : `Nothing changed: events through #${result.ackedSeq} were already acknowledged.`;
92
+ return textResult(`${text}\n${JSON.stringify(structured)}`, structured);
93
+ }
94
+ function shape(answer, position, secretValues) {
95
+ const common = { state: answer.state, position, fresh: answer.fresh, journalEpoch: answer.journalEpoch };
96
+ if (answer.status === 'cursor_too_old') {
97
+ const { gap } = answer;
98
+ return {
99
+ status: 'gap',
100
+ gap: { oldestSeq: gap.oldestSeq, latestSeq: gap.latestSeq, resumeCursor: gap.resumeCursor, recovery: gap.recovery },
101
+ ...common,
102
+ };
103
+ }
104
+ return {
105
+ status: 'ok',
106
+ events: answer.events.map(({ row, standing }) => ({ ...redactDeep(row, secretValues), standing })),
107
+ nextCursor: answer.nextCursor,
108
+ hasMore: answer.hasMore,
109
+ ...common,
110
+ };
111
+ }
112
+ /** The authoritative first line (D-05: the text block is what a client must be able to act on). */
113
+ function headline(answer) {
114
+ if (answer.status === 'cursor_too_old') {
115
+ const { oldestSeq, latestSeq } = answer.gap;
116
+ const retained = oldestSeq === null ? 'the journal holds no events' : `the journal holds #${oldestSeq}–#${latestSeq}`;
117
+ return `GAP: events after your position are no longer retained (${retained}). Nothing was replayed. Read the current state below, then ack resumeCursor.`;
118
+ }
119
+ if (answer.events.length === 0)
120
+ return 'No outstanding events.';
121
+ const first = answer.events[0].row.journalSeq;
122
+ const last = answer.events.at(-1).row.journalSeq;
123
+ const more = answer.hasMore ? ' More are retained: read again now.' : '';
124
+ return `${answer.events.length} outstanding event(s), #${first}–#${last}.${more} Ack nextCursor once you have taken them into account.`;
125
+ }
126
+ //# sourceMappingURL=leader-events.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"leader-events.js","sourceRoot":"","sources":["../../../src/mcp/tools/leader-events.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,qBAAqB,EAAE,sBAAsB,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAE1G,OAAO,EAAE,UAAU,EAAE,MAAM,gCAAgC,CAAC;AAE5D,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,SAAS,EAA8D,MAAM,iBAAiB,CAAC;AACxG,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,UAAU,EAA2C,MAAM,YAAY,CAAC;AAsC1G,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC;KACrC,MAAM,CAAC;IACN,MAAM,EAAE,CAAC;SACN,IAAI,CAAC,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;SACrB,QAAQ,CACP,qHAAqH;QACnH,wEAAwE,CAC3E;IACH,MAAM,EAAE,sBAAsB;SAC3B,QAAQ,EAAE;SACV,QAAQ,CACP,uHAAuH;QACrH,yEAAyE,CAC5E;IACH,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,qBAAqB,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,kCAAkC,qBAAqB,GAAG,CAAC;IACzI,WAAW,EAAE,iBAAiB;SAC3B,QAAQ,EAAE;SACV,QAAQ,CACP,kOAAkO,CACnO;CACJ,CAAC;KACD,MAAM,EAAE;KACR,WAAW,CAAC,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE;IACzB,IAAI,IAAI,CAAC,MAAM,KAAK,KAAK,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;QACvD,GAAG,CAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,QAAQ,CAAC,EAAE,OAAO,EAAE,kBAAkB,EAAE,CAAC,CAAC;IAClF,CAAC;IACD,IAAI,IAAI,CAAC,MAAM,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;QACtD,GAAG,CAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,6BAA6B,EAAE,CAAC,CAAC;IAC5F,CAAC;IACD,+FAA+F;IAC/F,4FAA4F;IAC5F,sFAAsF;IACtF,IAAI,IAAI,CAAC,MAAM,KAAK,KAAK,IAAI,IAAI,CAAC,WAAW,KAAK,SAAS,EAAE,CAAC;QAC5D,GAAG,CAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,aAAa,CAAC,EAAE,OAAO,EAAE,uBAAuB,EAAE,CAAC,CAAC;IAC5F,CAAC;IACD,IAAI,IAAI,CAAC,MAAM,KAAK,MAAM,IAAI,IAAI,CAAC,WAAW,KAAK,SAAS,EAAE,CAAC;QAC7D,GAAG,CAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,aAAa,CAAC,EAAE,OAAO,EAAE,oCAAoC,EAAE,CAAC,CAAC;IACzG,CAAC;AACH,CAAC,CAAC,CAAC;AAGL,MAAM,aAAa,GACjB,mGAAmG,CAAC;AAEtG,MAAM,CAAC,MAAM,gBAAgB,GAAG,UAAU,CAAC;IACzC,IAAI,EAAE,eAAe;IACrB,KAAK,EAAE,qCAAqC;IAC5C,WAAW,EAAE;QACX,gLAAgL;QAChL,oQAAoQ;QACpQ,4GAA4G;QAC5G,yMAAyM;QACzM,oKAAoK;KACrK,CAAC,IAAI,CAAC,IAAI,CAAC;IACZ,WAAW,EAAE,uBAAuB;IACpC,WAAW,EAAE,EAAE,YAAY,EAAE,KAAK,EAAE,eAAe,EAAE,KAAK,EAAE,cAAc,EAAE,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE;IACxG,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG;QAClB,MAAM,IAAI,GAAI,GAA2B,CAAC,YAAY,CAAC;QACvD,IAAI,CAAC,IAAI;YAAE,OAAO,WAAW,CAAC,aAAa,CAAC,CAAC;QAC7C,IAAI,CAAC;YACH,OAAO,IAAI,CAAC,MAAM,KAAK,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,MAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QAC5E,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,GAAG,YAAY,qBAAqB,EAAE,CAAC;gBACzC,OAAO,WAAW,CAAC,GAAG,GAAG,CAAC,SAAS,CAAC,OAAO,iBAAiB,IAAI,CAAC,MAAM,KAAK,KAAK,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,MAAM,GAAG,EAAE;oBAC9G,GAAG,GAAG,CAAC,SAAS;iBACjB,CAAC,CAAC;YACL,CAAC;YACD,MAAM,GAAG,CAAC;QACZ,CAAC;IACH,CAAC;CACF,CAAC,CAAC;AAEH,SAAS,IAAI,CAAC,IAAsB,EAAE,IAAuB;IAC3D,MAAM,MAAM,GAAG,SAAS,CAAC;QACvB,OAAO,EAAE,IAAI,CAAC,OAAO;QACrB,OAAO,EAAE,IAAI,CAAC,OAAO;QACrB,SAAS,EAAE,IAAI,CAAC,SAAS;QACzB,GAAG,CAAC,IAAI,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC;QAC7D,GAAG,CAAC,IAAI,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC;KAC3D,CAAC,CAAC;IACH,6FAA6F;IAC7F,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC;IACvF,IAAI,IAAI,KAAK,SAAS;QAAE,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;IACzD,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC;IACzC,MAAM,UAAU,GAAG,KAAK,CAAC,MAAM,EAAE,QAAQ,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC;IAC9D,OAAO,UAAU,CAAC,GAAG,QAAQ,CAAC,MAAM,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,EAAE,UAAU,CAAC,CAAC;AACtF,CAAC;AAED,SAAS,GAAG,CAAC,IAAsB,EAAE,MAAc;IACjD,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IACxC,MAAM,UAAU,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC;IAC3G,MAAM,IAAI,GACR,MAAM,CAAC,MAAM,KAAK,OAAO;QACvB,CAAC,CAAC,qCAAqC,MAAM,CAAC,QAAQ,GAAG;QACzD,CAAC,CAAC,oCAAoC,MAAM,CAAC,QAAQ,6BAA6B,CAAC;IACvF,OAAO,UAAU,CAAC,GAAG,IAAI,KAAK,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,EAAE,UAAU,CAAC,CAAC;AAC1E,CAAC;AAED,SAAS,KAAK,CAAC,MAAuB,EAAE,QAA+C,EAAE,YAA+B;IACtH,MAAM,MAAM,GAAG,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,YAAY,EAAE,MAAM,CAAC,YAAY,EAAE,CAAC;IACzG,IAAI,MAAM,CAAC,MAAM,KAAK,gBAAgB,EAAE,CAAC;QACvC,MAAM,EAAE,GAAG,EAAE,GAAG,MAAM,CAAC;QACvB,OAAO;YACL,MAAM,EAAE,KAAc;YACtB,GAAG,EAAE,EAAE,SAAS,EAAE,GAAG,CAAC,SAAS,EAAE,SAAS,EAAE,GAAG,CAAC,SAAS,EAAE,YAAY,EAAE,GAAG,CAAC,YAAY,EAAE,QAAQ,EAAE,GAAG,CAAC,QAAQ,EAAE;YACnH,GAAG,MAAM;SACV,CAAC;IACJ,CAAC;IACD,OAAO;QACL,MAAM,EAAE,IAAa;QACrB,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,UAAU,CAAC,GAAG,EAAE,YAAY,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC;QAClG,UAAU,EAAE,MAAM,CAAC,UAAU;QAC7B,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,GAAG,MAAM;KACV,CAAC;AACJ,CAAC;AAED,mGAAmG;AACnG,SAAS,QAAQ,CAAC,MAAuB;IACvC,IAAI,MAAM,CAAC,MAAM,KAAK,gBAAgB,EAAE,CAAC;QACvC,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,GAAG,MAAM,CAAC,GAAG,CAAC;QAC5C,MAAM,QAAQ,GAAG,SAAS,KAAK,IAAI,CAAC,CAAC,CAAC,6BAA6B,CAAC,CAAC,CAAC,sBAAsB,SAAS,KAAK,SAAS,EAAE,CAAC;QACtH,OAAO,2DAA2D,QAAQ,+EAA+E,CAAC;IAC5J,CAAC;IACD,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,wBAAwB,CAAC;IAChE,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC,GAAG,CAAC,UAAU,CAAC;IAC/C,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAE,CAAC,GAAG,CAAC,UAAU,CAAC;IAClD,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,qCAAqC,CAAC,CAAC,CAAC,EAAE,CAAC;IACzE,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,2BAA2B,KAAK,KAAK,IAAI,IAAI,IAAI,wDAAwD,CAAC;AAC1I,CAAC"}
@@ -0,0 +1,102 @@
1
+ import { z } from 'zod';
2
+ import { type ServiceDispatch } from '../service-adapter.ts';
3
+ import { type McpToolContext } from '../tool.ts';
4
+ /**
5
+ * `local_handoff` (#98): the cockpit's "Open in…" family — a task in a terminal, a task's
6
+ * worktree in a local app, the project folder in a local app, and the list of apps that can do it
7
+ * (I-044, I-114). Opening one image file by path is left out: see `Field` below.
8
+ *
9
+ * M-19 is the trap this module exists for. Every one of these routes launches an application on
10
+ * the machine that runs the xezar SERVICE. An MCP client is a separate process, possibly on
11
+ * another machine and possibly with no display at all, so nothing here may promise a window on
12
+ * the client's screen. Two rules follow, and the tests pin both:
13
+ *
14
+ * - With `capabilities.localHandoff` false (hosted mode: `XEZ_REMOTE=1` or a non-loopback bind),
15
+ * every action answers `unavailable` WITH A REASON and dispatches nothing — the same gate that
16
+ * hides the menu in the cockpit. The routes 409 on their own as well; this tool does not rely
17
+ * on that, because "the route refused" and "we never asked" must not read the same.
18
+ * - With it true, every answer names the machine it affects: the xezar host, not the client's.
19
+ *
20
+ * The capability is read from the service's own `GET /health`, through the same in-process entry
21
+ * every other call uses, so this tool and the cockpit read ONE answer (N-02) — including the
22
+ * `--bind-host` half, which this process cannot see from anywhere else.
23
+ *
24
+ * `open-in-cli` answers 409 with `error.command` when the host has no terminal emulator. The
25
+ * cockpit copies that command to the clipboard; a leader has no clipboard on the host, so the
26
+ * command is RETURNED as data (`fallbackCommand`), labelled as something to run on the host.
27
+ *
28
+ * D-08 / F-09 / F-22: opening an app is a project operation inside the approved goal, so there is
29
+ * no per-operation confirmation parameter. Goal and definition-of-done decisions stay with the
30
+ * human and are not offered here, and no parameter can waive a quality gate or an acceptance
31
+ * criterion — the strict schema turns an invented key into an argument error. The registry-wide
32
+ * test in `local-handoff.test.ts` asserts the last point for EVERY registered tool (A-22).
33
+ */
34
+ export declare const LOCAL_HANDOFF_ACTIONS: readonly ['list_apps', 'open_task_in_terminal', 'open_task_in_app', 'open_project_in_app'];
35
+ export type LocalHandoffAction = (typeof LOCAL_HANDOFF_ACTIONS)[number];
36
+ /** Where an answer's effect lands. There is deliberately no value for the client's machine. */
37
+ export declare const HANDOFF_MACHINE: 'xezar-host';
38
+ /** Said on every answer from a host that can hand off — the M-19 sentence. */
39
+ export declare const XEZAR_HOST_NOTICE = "This acts on the xezar host machine \u2013 the computer running the xezar service \u2013 not on the machine your MCP client runs on. Nothing opens on the client\u2019s screen.";
40
+ /** Said on every answer from a host that cannot. */
41
+ export declare const HOSTED_MODE_REASON = "desktop handoff is unavailable: this xezar runs in hosted mode (XEZ_REMOTE=1 or a non-loopback bind), so there is no desktop on the xezar host to open anything on, and xezar never opens anything on the MCP client\u2019s machine";
42
+ /** D-08 in the tool's own words, so a leader reads the boundary before it calls. */
43
+ export declare const DECISION_BOUNDARY = "No per-operation confirmation is needed: opening an app is a project operation inside the approved goal. Goal and definition-of-done decisions stay with the human and are not offered here, and no parameter can waive a quality gate or an acceptance criterion.";
44
+ /** The context this tool reads beyond `McpToolContext`: the running service's in-process entry. */
45
+ export type LocalHandoffContext = McpToolContext & {
46
+ readonly service?: ServiceDispatch;
47
+ };
48
+ export declare const localHandoffInputSchema: z.ZodObject<{
49
+ action: z.ZodEnum<{
50
+ list_apps: "list_apps";
51
+ open_project_in_app: "open_project_in_app";
52
+ open_task_in_app: "open_task_in_app";
53
+ open_task_in_terminal: "open_task_in_terminal";
54
+ }>;
55
+ runId: z.ZodOptional<z.ZodString>;
56
+ target: z.ZodOptional<z.ZodString>;
57
+ operationId: z.ZodOptional<z.ZodString>;
58
+ }, z.core.$strict>;
59
+ export type LocalHandoffInput = z.output<typeof localHandoffInputSchema>;
60
+ /** The result, text block and `structuredContent` alike (D-05: the text is authoritative). */
61
+ export declare const localHandoffResultSchema: z.ZodObject<{
62
+ action: z.ZodEnum<{
63
+ list_apps: "list_apps";
64
+ open_project_in_app: "open_project_in_app";
65
+ open_task_in_app: "open_task_in_app";
66
+ open_task_in_terminal: "open_task_in_terminal";
67
+ }>;
68
+ status: z.ZodEnum<{
69
+ conflict: "conflict";
70
+ done: "done";
71
+ failed: "failed";
72
+ }>;
73
+ outcome: z.ZodEnum<{
74
+ fallback: "fallback";
75
+ listed: "listed";
76
+ opened: "opened";
77
+ refused: "refused";
78
+ unavailable: "unavailable";
79
+ }>;
80
+ performed: z.ZodBoolean;
81
+ affects: z.ZodEnum<{
82
+ nothing: "nothing";
83
+ "xezar-host": "xezar-host";
84
+ }>;
85
+ notice: z.ZodString;
86
+ reason: z.ZodOptional<z.ZodString>;
87
+ nextAction: z.ZodOptional<z.ZodString>;
88
+ targets: z.ZodOptional<z.ZodArray<z.ZodObject<{
89
+ id: z.ZodString;
90
+ label: z.ZodString;
91
+ icon: z.ZodOptional<z.ZodString>;
92
+ }, z.core.$strip>>>;
93
+ path: z.ZodOptional<z.ZodString>;
94
+ command: z.ZodOptional<z.ZodString>;
95
+ fallbackCommand: z.ZodOptional<z.ZodString>;
96
+ httpStatus: z.ZodOptional<z.ZodNumber>;
97
+ origin: z.ZodLiteral<"mcp">;
98
+ }, z.core.$strip>;
99
+ export type LocalHandoffResult = z.infer<typeof localHandoffResultSchema>;
100
+ export declare const localHandoffTool: import("../tool.ts").McpTool<z.ZodObject<z.core.$ZodLooseShape, z.core.$strip>>;
101
+ /** One action against the bound project. Exported for tests; the tool is the only production caller. */
102
+ export declare function runLocalHandoff(args: LocalHandoffInput, projectId: string, service: ServiceDispatch): Promise<LocalHandoffResult>;
@@ -0,0 +1,306 @@
1
+ import { operationIdSchema, runIdParamSchema, openTargetSchema } from '../../contract/index.js';
2
+ import { hc } from 'hono/client';
3
+ import { z } from 'zod';
4
+ import { collectSecretValues, redactDeep } from '../../core/secret-redaction.js';
5
+ import { MCP_ORIGIN } from '../service-adapter.js';
6
+ import { defineTool, errorResult, textResult } from '../tool.js';
7
+ /**
8
+ * `local_handoff` (#98): the cockpit's "Open in…" family — a task in a terminal, a task's
9
+ * worktree in a local app, the project folder in a local app, and the list of apps that can do it
10
+ * (I-044, I-114). Opening one image file by path is left out: see `Field` below.
11
+ *
12
+ * M-19 is the trap this module exists for. Every one of these routes launches an application on
13
+ * the machine that runs the xezar SERVICE. An MCP client is a separate process, possibly on
14
+ * another machine and possibly with no display at all, so nothing here may promise a window on
15
+ * the client's screen. Two rules follow, and the tests pin both:
16
+ *
17
+ * - With `capabilities.localHandoff` false (hosted mode: `XEZ_REMOTE=1` or a non-loopback bind),
18
+ * every action answers `unavailable` WITH A REASON and dispatches nothing — the same gate that
19
+ * hides the menu in the cockpit. The routes 409 on their own as well; this tool does not rely
20
+ * on that, because "the route refused" and "we never asked" must not read the same.
21
+ * - With it true, every answer names the machine it affects: the xezar host, not the client's.
22
+ *
23
+ * The capability is read from the service's own `GET /health`, through the same in-process entry
24
+ * every other call uses, so this tool and the cockpit read ONE answer (N-02) — including the
25
+ * `--bind-host` half, which this process cannot see from anywhere else.
26
+ *
27
+ * `open-in-cli` answers 409 with `error.command` when the host has no terminal emulator. The
28
+ * cockpit copies that command to the clipboard; a leader has no clipboard on the host, so the
29
+ * command is RETURNED as data (`fallbackCommand`), labelled as something to run on the host.
30
+ *
31
+ * D-08 / F-09 / F-22: opening an app is a project operation inside the approved goal, so there is
32
+ * no per-operation confirmation parameter. Goal and definition-of-done decisions stay with the
33
+ * human and are not offered here, and no parameter can waive a quality gate or an acceptance
34
+ * criterion — the strict schema turns an invented key into an argument error. The registry-wide
35
+ * test in `local-handoff.test.ts` asserts the last point for EVERY registered tool (A-22).
36
+ */
37
+ export const LOCAL_HANDOFF_ACTIONS = ['list_apps', 'open_task_in_terminal', 'open_task_in_app', 'open_project_in_app'];
38
+ /** Where an answer's effect lands. There is deliberately no value for the client's machine. */
39
+ export const HANDOFF_MACHINE = 'xezar-host';
40
+ /** Said on every answer from a host that can hand off — the M-19 sentence. */
41
+ export const XEZAR_HOST_NOTICE = 'This acts on the xezar host machine – the computer running the xezar service – not on the machine your MCP client runs on. Nothing opens on the client’s screen.';
42
+ /** Said on every answer from a host that cannot. */
43
+ export const HOSTED_MODE_REASON = 'desktop handoff is unavailable: this xezar runs in hosted mode (XEZ_REMOTE=1 or a non-loopback bind), so there is no desktop on the xezar host to open anything on, and xezar never opens anything on the MCP client’s machine';
44
+ /** The next legitimate action when the capability is missing (UX-M05). */
45
+ const UNAVAILABLE_NEXT_ACTION = 'Ask the human to open it from a machine that has the checkout, or read the task, its diff and its files through the tools that return data.';
46
+ /** D-08 in the tool's own words, so a leader reads the boundary before it calls. */
47
+ export const DECISION_BOUNDARY = 'No per-operation confirmation is needed: opening an app is a project operation inside the approved goal. Goal and definition-of-done decisions stay with the human and are not offered here, and no parameter can waive a quality gate or an acceptance criterion.';
48
+ const NOT_CONNECTED = 'local_handoff is not connected to the xezar service in this process yet; nothing was opened.';
49
+ const FIELDS = ['runId', 'target', 'operationId'];
50
+ /** Which arguments each action takes. Anything else is refused rather than silently dropped.
51
+ * `operationId` (D-06 § 5.2, #264) is required by the three actions that open something on the
52
+ * host: launching an app twice is exactly the repeated effect a lost answer causes. `list_apps`
53
+ * reads the installed apps and takes none. */
54
+ const ACTION_FIELDS = {
55
+ list_apps: { required: [], optional: [] },
56
+ open_task_in_terminal: { required: ['runId', 'operationId'], optional: [] },
57
+ open_task_in_app: { required: ['runId', 'target', 'operationId'], optional: [] },
58
+ open_project_in_app: { required: ['target', 'operationId'], optional: [] },
59
+ };
60
+ export const localHandoffInputSchema = z
61
+ .object({
62
+ action: z
63
+ .enum(LOCAL_HANDOFF_ACTIONS)
64
+ .describe('list_apps: the apps installed on the xezar host. open_task_in_terminal: resume the task’s agent session in a terminal on the xezar host. ' +
65
+ 'open_task_in_app: open the task’s worktree in an app on the xezar host. ' +
66
+ 'open_project_in_app: open the project folder in an app on the xezar host.'),
67
+ runId: z.string().min(1).max(128).optional().describe("The task's run id, in the project this connection is bound to."),
68
+ target: z
69
+ .string()
70
+ .trim()
71
+ .min(1)
72
+ .max(200)
73
+ .optional()
74
+ .describe('An app id from list_apps (for example "finder", "terminal", "vscode", "cli:claude").'),
75
+ operationId: operationIdSchema
76
+ .optional()
77
+ .describe('Client-generated key for this operation (8–128 chars). Required by every open_ action; list_apps reads and takes none. Reuse it only to repeat the same operation: a repeat returns the first answer and opens nothing a second time.'),
78
+ })
79
+ .strict()
80
+ .superRefine((args, ctx) => {
81
+ const allowed = ACTION_FIELDS[args.action];
82
+ for (const field of FIELDS) {
83
+ const present = args[field] !== undefined;
84
+ if (allowed.required.includes(field) && !present) {
85
+ ctx.addIssue({ code: 'custom', path: [field], message: `${args.action} needs ${field}` });
86
+ }
87
+ if (present && !allowed.required.includes(field) && !allowed.optional.includes(field)) {
88
+ ctx.addIssue({ code: 'custom', path: [field], message: `${field} does not apply to ${args.action}` });
89
+ }
90
+ }
91
+ });
92
+ /** The result, text block and `structuredContent` alike (D-05: the text is authoritative). */
93
+ export const localHandoffResultSchema = z.object({
94
+ action: z.enum(LOCAL_HANDOFF_ACTIONS),
95
+ /** D-05's closed set (§ 6.8), narrowed to what a handoff can report. A 409 is a `conflict`. */
96
+ status: z.enum(['done', 'failed', 'conflict']),
97
+ /** What happened, in handoff terms. `unavailable`: the capability is missing and nothing was
98
+ * dispatched. `fallback`: nothing opened — run `fallbackCommand` on the xezar host instead. */
99
+ outcome: z.enum(['opened', 'listed', 'unavailable', 'fallback', 'refused']),
100
+ /** True only when the service reports it launched something. */
101
+ performed: z.boolean(),
102
+ /** Where the effect lands — the xezar host, or nowhere. Never the MCP client's machine. */
103
+ affects: z.enum([HANDOFF_MACHINE, 'nothing']),
104
+ notice: z.string(),
105
+ reason: z.string().optional(),
106
+ nextAction: z.string().optional(),
107
+ targets: z.array(openTargetSchema).optional(),
108
+ /** The host path that was opened. */
109
+ path: z.string().optional(),
110
+ /** The command the host terminal runs. */
111
+ command: z.string().optional(),
112
+ /** Run this in a terminal ON THE XEZAR HOST: the route found no terminal emulator to open. */
113
+ fallbackCommand: z.string().optional(),
114
+ httpStatus: z.number().int().optional(),
115
+ origin: z.literal(MCP_ORIGIN),
116
+ });
117
+ // ---- the service entry -------------------------------------------------------------------------
118
+ const IN_PROCESS_BASE = 'http://127.0.0.1';
119
+ const IN_PROCESS_HOST = '127.0.0.1';
120
+ /** The same in-process client the adapter builds (`service-adapter.ts`): loopback host, no Origin. */
121
+ const buildClient = (service) => hc(IN_PROCESS_BASE, {
122
+ fetch: async (input, init) => {
123
+ const headers = new Headers(init?.headers);
124
+ headers.set('host', IN_PROCESS_HOST);
125
+ headers.delete('origin');
126
+ const url = input instanceof Request ? input.url : String(input);
127
+ return service.request(url, { ...init, headers });
128
+ },
129
+ });
130
+ async function settle(pending) {
131
+ const res = await pending;
132
+ const body = await res.json().catch(() => undefined);
133
+ return { status: res.status, body: body && typeof body === 'object' ? body : undefined };
134
+ }
135
+ const str = (value) => (typeof value === 'string' ? value : undefined);
136
+ // ---- identity and secrets ----------------------------------------------------------------------
137
+ /** F-12: an account folder is user-named, and a folder named after an email address would put
138
+ * that address in a terminal command. Such a command is withheld rather than altered, because
139
+ * an edited command would resume the wrong account. */
140
+ const EMAIL_RE = /[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}/g;
141
+ const ACCOUNT_PLACEHOLDER = '[account]';
142
+ const hasEmail = (text) => new RegExp(EMAIL_RE.source).test(text);
143
+ const scrubEmail = (text) => text.replace(EMAIL_RE, ACCOUNT_PLACEHOLDER);
144
+ // ---- the tool ----------------------------------------------------------------------------------
145
+ export const localHandoffTool = defineTool({
146
+ name: 'local_handoff',
147
+ title: 'Open a task or the project in an app on the xezar host',
148
+ description: 'Hand a task or the project off to a desktop app — a terminal resuming the task’s agent session, an editor, the file manager. ' +
149
+ 'Every app opens on the XEZAR HOST MACHINE (the computer running the xezar service), never on the machine your MCP client runs on. ' +
150
+ 'When the xezar host has no desktop to hand off to (hosted mode), every action answers "unavailable" with the reason and opens nothing. ' +
151
+ 'When no terminal emulator is found, the answer carries fallbackCommand to run in a terminal on the xezar host. ' +
152
+ DECISION_BOUNDARY,
153
+ inputSchema: localHandoffInputSchema,
154
+ annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false },
155
+ async call(args, ctx) {
156
+ const service = ctx.service;
157
+ if (!service)
158
+ return errorResult(NOT_CONNECTED);
159
+ return render(await runLocalHandoff(args, ctx.project.id, service));
160
+ },
161
+ });
162
+ /** One action against the bound project. Exported for tests; the tool is the only production caller. */
163
+ export async function runLocalHandoff(args, projectId, service) {
164
+ const client = buildClient(service);
165
+ // The capability first, and nothing else until it says yes. An unreadable answer fails CLOSED:
166
+ // "we could not tell" must never read as "go ahead".
167
+ const health = await settle(client.api.v1.health.$get()).catch(() => undefined);
168
+ const capabilities = health?.body?.capabilities;
169
+ const localHandoff = health?.status === 200 && capabilities && typeof capabilities === 'object'
170
+ ? capabilities.localHandoff
171
+ : undefined;
172
+ if (localHandoff !== true) {
173
+ return unavailable(args.action, localHandoff === false ? HOSTED_MODE_REASON : 'xezar could not confirm that its host has a desktop to hand off to, so nothing was opened');
174
+ }
175
+ const scoped = client.api.v1.p[':projectId'];
176
+ const scope = { projectId };
177
+ if (args.action === 'list_apps') {
178
+ const answer = await settle(scoped['open-targets'].$get({ param: scope }));
179
+ if (answer.status !== 200)
180
+ return failed(args.action, answer);
181
+ const parsed = z.array(openTargetSchema).safeParse(answer.body?.targets);
182
+ if (!parsed.success)
183
+ return failed(args.action, { status: 502, body: { error: 'the service answered without a target list' } });
184
+ return { ...hostBase(args.action), status: 'done', outcome: 'listed', performed: false, targets: parsed.data };
185
+ }
186
+ if (args.action === 'open_project_in_app') {
187
+ const answer = await settle(scoped['open-in'].$post({ param: scope, json: { target: args.target } }));
188
+ if (answer.status !== 200)
189
+ return failed(args.action, answer);
190
+ return opened(args.action, answer);
191
+ }
192
+ const runId = args.runId;
193
+ // A dot segment would be resolved by the URL parser onto another route; refuse it undispatched.
194
+ if (runId === '.' || runId === '..' || !runIdParamSchema.safeParse({ id: runId }).success) {
195
+ return failed(args.action, { status: 400, body: { error: 'not a run id' } });
196
+ }
197
+ const param = { ...scope, id: runId };
198
+ if (args.action === 'open_task_in_terminal') {
199
+ const answer = await settle(scoped.runs[':id']['open-in-cli'].$post({ param }));
200
+ if (answer.status === 200)
201
+ return opened(args.action, answer);
202
+ return fallbackOrFailed(args.action, answer);
203
+ }
204
+ const answer = await settle(scoped.runs[':id']['open-in'].$post({ param, json: { target: args.target } }));
205
+ if (answer.status === 200)
206
+ return opened(args.action, answer);
207
+ return fallbackOrFailed(args.action, answer);
208
+ }
209
+ function hostBase(action) {
210
+ return { action, affects: HANDOFF_MACHINE, notice: XEZAR_HOST_NOTICE, origin: MCP_ORIGIN };
211
+ }
212
+ function unavailable(action, reason) {
213
+ return {
214
+ action,
215
+ status: 'failed',
216
+ outcome: 'unavailable',
217
+ performed: false,
218
+ affects: 'nothing',
219
+ notice: 'Nothing was opened – not on the xezar host and not on the machine your MCP client runs on.',
220
+ reason,
221
+ nextAction: UNAVAILABLE_NEXT_ACTION,
222
+ origin: MCP_ORIGIN,
223
+ };
224
+ }
225
+ function opened(action, answer) {
226
+ const path = str(answer.body?.path);
227
+ const command = str(answer.body?.command);
228
+ return {
229
+ ...hostBase(action),
230
+ status: 'done',
231
+ outcome: 'opened',
232
+ performed: true,
233
+ ...(path !== undefined ? { path } : {}),
234
+ ...(command !== undefined ? { command } : {}),
235
+ };
236
+ }
237
+ /** A 409 carrying `command` is the no-terminal fallback; every other refusal keeps the service's words. */
238
+ function fallbackOrFailed(action, answer) {
239
+ const fallback = answer.status === 409 ? str(answer.body?.command) : undefined;
240
+ if (fallback === undefined)
241
+ return failed(action, answer);
242
+ if (hasEmail(fallback)) {
243
+ return {
244
+ ...hostBase(action),
245
+ status: 'conflict',
246
+ outcome: 'refused',
247
+ performed: false,
248
+ httpStatus: answer.status,
249
+ reason: 'no terminal emulator was found on the xezar host, and the manual command names an account folder that looks like an email address, so it is not returned here',
250
+ nextAction: 'Ask the human to open the task from the cockpit on the xezar host, which copies the command there.',
251
+ };
252
+ }
253
+ return {
254
+ ...hostBase(action),
255
+ status: 'failed',
256
+ outcome: 'fallback',
257
+ performed: false,
258
+ httpStatus: answer.status,
259
+ reason: scrubEmail(str(answer.body?.error) ?? 'no terminal emulator found'),
260
+ fallbackCommand: fallback,
261
+ nextAction: 'Run fallbackCommand in a terminal on the xezar host. It will not work on the MCP client’s machine.',
262
+ };
263
+ }
264
+ function failed(action, answer) {
265
+ // The route re-checks hosted mode per request, so a capability that flipped between the two
266
+ // calls still reads as unavailable rather than as an ordinary failure.
267
+ const error = str(answer.body?.error) ?? `service answered ${answer.status}`;
268
+ if (answer.status === 409 && error.startsWith('local handoff is disabled'))
269
+ return unavailable(action, HOSTED_MODE_REASON);
270
+ return {
271
+ ...hostBase(action),
272
+ // D-05: a refusal the task or host state caused (409) is a business conflict, not a failure.
273
+ status: answer.status === 409 ? 'conflict' : 'failed',
274
+ outcome: 'refused',
275
+ performed: false,
276
+ httpStatus: answer.status,
277
+ reason: scrubEmail(error),
278
+ };
279
+ }
280
+ /** The text block says everything `structuredContent` says (D-05); secrets never leave (F-15). */
281
+ function render(result) {
282
+ const safe = redactDeep(result, collectSecretValues(process.env));
283
+ const lines = [`local_handoff ${safe.action}: ${safe.outcome} (status ${safe.status}).`, safe.notice];
284
+ if (safe.reason)
285
+ lines.push(`Reason: ${safe.reason}.`);
286
+ if (safe.targets) {
287
+ lines.push(safe.targets.length
288
+ ? `Apps on the xezar host: ${safe.targets.map((t) => `${t.id} (${t.label})`).join(', ')}.`
289
+ : 'No apps were detected on the xezar host.');
290
+ }
291
+ if (safe.path)
292
+ lines.push(`Opened on the xezar host: ${safe.path}`);
293
+ if (safe.command)
294
+ lines.push(`The xezar host terminal runs: ${safe.command}`);
295
+ if (safe.fallbackCommand)
296
+ lines.push(`Fallback command for a terminal on the xezar host: ${safe.fallbackCommand}`);
297
+ if (safe.nextAction)
298
+ lines.push(`Next: ${safe.nextAction}`);
299
+ const text = lines.join('\n');
300
+ const structured = safe;
301
+ // `unavailable` and `fallback` are degraded answers, not errors (AGENTS.md § Zero config), and a
302
+ // conflict is something to reason about (D-05). Only a refused call that failed outright is one.
303
+ const isError = safe.outcome === 'refused' && safe.status === 'failed';
304
+ return isError ? errorResult(text, structured) : textResult(text, structured);
305
+ }
306
+ //# sourceMappingURL=local-handoff.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"local-handoff.js","sourceRoot":"","sources":["../../../src/mcp/tools/local-handoff.ts"],"names":[],"mappings":"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"}