@particle-academy/agent-integrations 0.50.0 → 0.52.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 (230) hide show
  1. package/CHANGELOG.md +91 -0
  2. package/README.md +69 -0
  3. package/dist/bridges/artboard.d.cts +3 -3
  4. package/dist/bridges/artboard.d.ts +3 -3
  5. package/dist/bridges/catalog.d.cts +3 -3
  6. package/dist/bridges/catalog.d.ts +3 -3
  7. package/dist/bridges/charts.d.cts +3 -3
  8. package/dist/bridges/charts.d.ts +3 -3
  9. package/dist/bridges/cms.d.cts +3 -3
  10. package/dist/bridges/cms.d.ts +3 -3
  11. package/dist/bridges/code.d.cts +3 -3
  12. package/dist/bridges/code.d.ts +3 -3
  13. package/dist/bridges/doc.d.cts +3 -3
  14. package/dist/bridges/doc.d.ts +3 -3
  15. package/dist/bridges/features.d.cts +3 -3
  16. package/dist/bridges/features.d.ts +3 -3
  17. package/dist/bridges/files.d.cts +3 -3
  18. package/dist/bridges/files.d.ts +3 -3
  19. package/dist/bridges/flow.d.cts +3 -3
  20. package/dist/bridges/flow.d.ts +3 -3
  21. package/dist/bridges/forms.d.cts +55 -10
  22. package/dist/bridges/forms.d.ts +55 -10
  23. package/dist/bridges/git.d.cts +3 -3
  24. package/dist/bridges/git.d.ts +3 -3
  25. package/dist/bridges/grid.d.cts +3 -3
  26. package/dist/bridges/grid.d.ts +3 -3
  27. package/dist/bridges/map.d.cts +3 -3
  28. package/dist/bridges/map.d.ts +3 -3
  29. package/dist/bridges/navigation.d.cts +3 -3
  30. package/dist/bridges/navigation.d.ts +3 -3
  31. package/dist/bridges/passkeys.d.cts +3 -3
  32. package/dist/bridges/passkeys.d.ts +3 -3
  33. package/dist/bridges/scene.d.cts +3 -3
  34. package/dist/bridges/scene.d.ts +3 -3
  35. package/dist/bridges/screen-doc.d.cts +3 -3
  36. package/dist/bridges/screen-doc.d.ts +3 -3
  37. package/dist/bridges/screens.d.cts +3 -3
  38. package/dist/bridges/screens.d.ts +3 -3
  39. package/dist/bridges/sheets.d.cts +3 -3
  40. package/dist/bridges/sheets.d.ts +3 -3
  41. package/dist/bridges/slides.d.cts +3 -3
  42. package/dist/bridges/slides.d.ts +3 -3
  43. package/dist/bridges/terminal.d.cts +3 -3
  44. package/dist/bridges/terminal.d.ts +3 -3
  45. package/dist/bridges/tui.d.cts +2 -2
  46. package/dist/bridges/tui.d.ts +2 -2
  47. package/dist/bridges/whiteboard.d.cts +3 -3
  48. package/dist/bridges/whiteboard.d.ts +3 -3
  49. package/dist/bridges-artboard.cjs +11 -5
  50. package/dist/bridges-artboard.cjs.map +1 -1
  51. package/dist/bridges-artboard.js +6 -4
  52. package/dist/bridges-artboard.js.map +1 -1
  53. package/dist/bridges-catalog.cjs +11 -5
  54. package/dist/bridges-catalog.cjs.map +1 -1
  55. package/dist/bridges-catalog.js +3 -3
  56. package/dist/bridges-charts.cjs +11 -5
  57. package/dist/bridges-charts.cjs.map +1 -1
  58. package/dist/bridges-charts.js +3 -3
  59. package/dist/bridges-cms.cjs +11 -5
  60. package/dist/bridges-cms.cjs.map +1 -1
  61. package/dist/bridges-cms.js +4 -4
  62. package/dist/bridges-code.cjs +11 -5
  63. package/dist/bridges-code.cjs.map +1 -1
  64. package/dist/bridges-code.js +3 -3
  65. package/dist/bridges-doc.cjs +11 -5
  66. package/dist/bridges-doc.cjs.map +1 -1
  67. package/dist/bridges-doc.js +3 -3
  68. package/dist/bridges-features.cjs +11 -5
  69. package/dist/bridges-features.cjs.map +1 -1
  70. package/dist/bridges-features.js +3 -3
  71. package/dist/bridges-files.cjs +11 -5
  72. package/dist/bridges-files.cjs.map +1 -1
  73. package/dist/bridges-files.js +3 -3
  74. package/dist/bridges-flow.cjs +11 -5
  75. package/dist/bridges-flow.cjs.map +1 -1
  76. package/dist/bridges-flow.js +6 -4
  77. package/dist/bridges-flow.js.map +1 -1
  78. package/dist/bridges-forms.cjs +123 -16
  79. package/dist/bridges-forms.cjs.map +1 -1
  80. package/dist/bridges-forms.js +4 -3
  81. package/dist/bridges-git.cjs +10 -5
  82. package/dist/bridges-git.cjs.map +1 -1
  83. package/dist/bridges-git.js +3 -3
  84. package/dist/bridges-grid.cjs +11 -5
  85. package/dist/bridges-grid.cjs.map +1 -1
  86. package/dist/bridges-grid.js +3 -3
  87. package/dist/bridges-map.cjs +11 -5
  88. package/dist/bridges-map.cjs.map +1 -1
  89. package/dist/bridges-map.js +3 -3
  90. package/dist/bridges-navigation.cjs +11 -5
  91. package/dist/bridges-navigation.cjs.map +1 -1
  92. package/dist/bridges-navigation.js +3 -3
  93. package/dist/bridges-passkeys.cjs +11 -5
  94. package/dist/bridges-passkeys.cjs.map +1 -1
  95. package/dist/bridges-passkeys.js +3 -3
  96. package/dist/bridges-scene.cjs +11 -5
  97. package/dist/bridges-scene.cjs.map +1 -1
  98. package/dist/bridges-scene.js +3 -3
  99. package/dist/bridges-screen-doc.cjs +14 -6
  100. package/dist/bridges-screen-doc.cjs.map +1 -1
  101. package/dist/bridges-screen-doc.js +4 -4
  102. package/dist/bridges-screens.cjs +15 -7
  103. package/dist/bridges-screens.cjs.map +1 -1
  104. package/dist/bridges-screens.js +4 -3
  105. package/dist/bridges-sheets.cjs +11 -5
  106. package/dist/bridges-sheets.cjs.map +1 -1
  107. package/dist/bridges-sheets.js +3 -3
  108. package/dist/bridges-slides.cjs +11 -5
  109. package/dist/bridges-slides.cjs.map +1 -1
  110. package/dist/bridges-slides.js +3 -3
  111. package/dist/bridges-terminal.cjs +11 -5
  112. package/dist/bridges-terminal.cjs.map +1 -1
  113. package/dist/bridges-terminal.js +3 -3
  114. package/dist/bridges-tui.cjs +1 -1
  115. package/dist/bridges-tui.cjs.map +1 -1
  116. package/dist/bridges-tui.js +2 -2
  117. package/dist/bridges-whiteboard.cjs +11 -5
  118. package/dist/bridges-whiteboard.cjs.map +1 -1
  119. package/dist/bridges-whiteboard.js +3 -3
  120. package/dist/{chunk-CZV3WUW5.js → chunk-3GFKC6OK.js} +20 -7
  121. package/dist/chunk-3GFKC6OK.js.map +1 -0
  122. package/dist/{chunk-JLHVQWOV.js → chunk-6Q3PMT7K.js} +4 -4
  123. package/dist/chunk-6Q3PMT7K.js.map +1 -0
  124. package/dist/{chunk-HOZCDDRA.js → chunk-7HHZBPDE.js} +9 -29
  125. package/dist/chunk-7HHZBPDE.js.map +1 -0
  126. package/dist/{chunk-VFWFT3OK.js → chunk-AL77RO25.js} +97 -17
  127. package/dist/chunk-AL77RO25.js.map +1 -0
  128. package/dist/{chunk-AXWMWYH5.js → chunk-C4AQ2YBW.js} +7 -6
  129. package/dist/chunk-C4AQ2YBW.js.map +1 -0
  130. package/dist/{chunk-NH6HUVXQ.js → chunk-CI5ZVHDY.js} +8 -6
  131. package/dist/chunk-CI5ZVHDY.js.map +1 -0
  132. package/dist/{chunk-5ZWNCHZS.js → chunk-CKJL5C7A.js} +8 -6
  133. package/dist/chunk-CKJL5C7A.js.map +1 -0
  134. package/dist/chunk-DPBAEWB5.js +28 -0
  135. package/dist/chunk-DPBAEWB5.js.map +1 -0
  136. package/dist/{chunk-BG3QXNM6.js → chunk-HNVHAY4A.js} +8 -6
  137. package/dist/chunk-HNVHAY4A.js.map +1 -0
  138. package/dist/{chunk-5M5ELTHE.js → chunk-KAEPC6N4.js} +8 -6
  139. package/dist/chunk-KAEPC6N4.js.map +1 -0
  140. package/dist/{chunk-3WVXAB3D.js → chunk-M423JOQ3.js} +3 -3
  141. package/dist/{chunk-3WVXAB3D.js.map → chunk-M423JOQ3.js.map} +1 -1
  142. package/dist/{chunk-SWWJUOCY.js → chunk-MKC633WU.js} +3 -3
  143. package/dist/{chunk-SWWJUOCY.js.map → chunk-MKC633WU.js.map} +1 -1
  144. package/dist/{chunk-LQB42OSA.js → chunk-MKJE6V4Z.js} +8 -6
  145. package/dist/chunk-MKJE6V4Z.js.map +1 -0
  146. package/dist/{chunk-MIDZWKIF.js → chunk-NB5AQIR2.js} +8 -6
  147. package/dist/chunk-NB5AQIR2.js.map +1 -0
  148. package/dist/{chunk-VMRUW4B4.js → chunk-OUUHFR4N.js} +8 -6
  149. package/dist/chunk-OUUHFR4N.js.map +1 -0
  150. package/dist/{chunk-FCXSR7I5.js → chunk-P6SJBP5T.js} +8 -6
  151. package/dist/chunk-P6SJBP5T.js.map +1 -0
  152. package/dist/{chunk-5JLTXHX6.js → chunk-PMPBI6I3.js} +7 -5
  153. package/dist/chunk-PMPBI6I3.js.map +1 -0
  154. package/dist/{chunk-4WVLZ6YP.js → chunk-PV4FZDYX.js} +8 -6
  155. package/dist/chunk-PV4FZDYX.js.map +1 -0
  156. package/dist/{chunk-3UUF5KKZ.js → chunk-QEVSNDJW.js} +8 -6
  157. package/dist/chunk-QEVSNDJW.js.map +1 -0
  158. package/dist/{chunk-VOCUGTZB.js → chunk-S4DA2UTJ.js} +8 -6
  159. package/dist/chunk-S4DA2UTJ.js.map +1 -0
  160. package/dist/{chunk-RVMM4BHK.js → chunk-V6EHKHSF.js} +8 -6
  161. package/dist/chunk-V6EHKHSF.js.map +1 -0
  162. package/dist/{chunk-36MKPTVD.js → chunk-VE7TRWZR.js} +8 -6
  163. package/dist/chunk-VE7TRWZR.js.map +1 -0
  164. package/dist/{chunk-Z5NL5D4J.js → chunk-VFUKZ6UA.js} +8 -6
  165. package/dist/chunk-VFUKZ6UA.js.map +1 -0
  166. package/dist/{chunk-3HVYUMQF.js → chunk-VHB3VE53.js} +8 -6
  167. package/dist/chunk-VHB3VE53.js.map +1 -0
  168. package/dist/{chunk-R4XXOGQH.js → chunk-ZDKYKJFH.js} +10 -6
  169. package/dist/chunk-ZDKYKJFH.js.map +1 -0
  170. package/dist/components-shared-whiteboard.cjs +29 -10
  171. package/dist/components-shared-whiteboard.cjs.map +1 -1
  172. package/dist/components-shared-whiteboard.js +3 -3
  173. package/dist/dom-navigation/index.d.cts +3 -3
  174. package/dist/dom-navigation/index.d.ts +3 -3
  175. package/dist/index.cjs +211 -78
  176. package/dist/index.cjs.map +1 -1
  177. package/dist/index.d.cts +6 -6
  178. package/dist/index.d.ts +6 -6
  179. package/dist/index.js +27 -26
  180. package/dist/index.js.map +1 -1
  181. package/dist/mcp/index.d.cts +5 -5
  182. package/dist/mcp/index.d.ts +5 -5
  183. package/dist/mcp/stdio.d.cts +3 -3
  184. package/dist/mcp/stdio.d.ts +3 -3
  185. package/dist/mcp.cjs +18 -5
  186. package/dist/mcp.cjs.map +1 -1
  187. package/dist/mcp.js +1 -1
  188. package/dist/presence/index.d.cts +1 -1
  189. package/dist/presence/index.d.ts +1 -1
  190. package/dist/{server-1y0n61R5.d.cts → server-DJJygNo1.d.cts} +2 -2
  191. package/dist/{server-vq6qVl3T.d.ts → server-Dwo9LOxh.d.ts} +2 -2
  192. package/dist/sharing/index.d.cts +3 -3
  193. package/dist/sharing/index.d.ts +3 -3
  194. package/dist/sheets-adapter.d.cts +3 -3
  195. package/dist/sheets-adapter.d.ts +3 -3
  196. package/dist/{tool-host-LYfdPE8u.d.ts → tool-host-BBSaU7IJ.d.cts} +10 -4
  197. package/dist/{tool-host-D67N2a2h.d.cts → tool-host-BqJRPr_T.d.ts} +10 -4
  198. package/dist/{types-DP5yQZQU.d.cts → types-D_H2f-wF.d.cts} +1 -1
  199. package/dist/{types-VX_9je7w.d.ts → types-D_TzdBsK.d.ts} +1 -1
  200. package/dist/{types-gzIpsUDE.d.cts → types-ITRQFAir.d.cts} +26 -1
  201. package/dist/{types-gzIpsUDE.d.ts → types-ITRQFAir.d.ts} +26 -1
  202. package/dist/undo/index.d.cts +2 -2
  203. package/dist/undo/index.d.ts +2 -2
  204. package/dist/undo.cjs +7 -3
  205. package/dist/undo.cjs.map +1 -1
  206. package/dist/undo.js +3 -3
  207. package/docs/multi-form-hosts.md +97 -0
  208. package/package.json +1 -1
  209. package/dist/chunk-36MKPTVD.js.map +0 -1
  210. package/dist/chunk-3HVYUMQF.js.map +0 -1
  211. package/dist/chunk-3UUF5KKZ.js.map +0 -1
  212. package/dist/chunk-4WVLZ6YP.js.map +0 -1
  213. package/dist/chunk-5JLTXHX6.js.map +0 -1
  214. package/dist/chunk-5M5ELTHE.js.map +0 -1
  215. package/dist/chunk-5ZWNCHZS.js.map +0 -1
  216. package/dist/chunk-AXWMWYH5.js.map +0 -1
  217. package/dist/chunk-BG3QXNM6.js.map +0 -1
  218. package/dist/chunk-CZV3WUW5.js.map +0 -1
  219. package/dist/chunk-FCXSR7I5.js.map +0 -1
  220. package/dist/chunk-HOZCDDRA.js.map +0 -1
  221. package/dist/chunk-JLHVQWOV.js.map +0 -1
  222. package/dist/chunk-LQB42OSA.js.map +0 -1
  223. package/dist/chunk-MIDZWKIF.js.map +0 -1
  224. package/dist/chunk-NH6HUVXQ.js.map +0 -1
  225. package/dist/chunk-R4XXOGQH.js.map +0 -1
  226. package/dist/chunk-RVMM4BHK.js.map +0 -1
  227. package/dist/chunk-VFWFT3OK.js.map +0 -1
  228. package/dist/chunk-VMRUW4B4.js.map +0 -1
  229. package/dist/chunk-VOCUGTZB.js.map +0 -1
  230. package/dist/chunk-Z5NL5D4J.js.map +0 -1
@@ -0,0 +1,97 @@
1
+ # Several forms on one host — design note
2
+
3
+ **Status: proposal, not implemented. The choice is the owner's.** Written
4
+ 2026-10-30 against 0.51.0, prompted by a consumer asking for the supported model.
5
+
6
+ ## Where it stands
7
+
8
+ `registerFormBridge` registers `form_describe`, `form_get_value`,
9
+ `form_get_values`, `form_set_value`, `form_set_values`, `form_focus` and
10
+ `form_submit`. The names are not scoped to the form. Since 0.51.0 a tool name
11
+ held by a different registrant is refused, and each form bridge registers as
12
+ `form:<adapter.id>`, so a second form with a different id on the same host
13
+ throws. Before 0.51.0 it did not throw, but the second form silently took over
14
+ the first one's tools, so two forms on one host have never worked. 0.51.0 made
15
+ the existing failure visible.
16
+
17
+ The same limit applies to every bridge whose registrant id carries an adapter
18
+ id: charts, grids, code editors, scenes, catalogs, feature panels and passkey
19
+ surfaces. Whatever is chosen for forms should be the pattern for those too.
20
+ There is already one precedent for scoping: `registerScreenDocBridge` takes a
21
+ `surface` option that prefixes its tool names (`screen_checkout_add`).
22
+
23
+ Today's supported answer is **one form bridge per host**.
24
+
25
+ ## Options
26
+
27
+ ### A. One form bridge serving N forms: a `form` argument plus `form_list`
28
+
29
+ The first `registerFormBridge` on a host creates a per-host form router. Later
30
+ calls on the same host **join** it instead of throwing (the same per-host
31
+ pattern `ensureUndoToolsRegistered` uses for the undo tools). Each returned
32
+ `Bridge.dispose()` removes only its own form. Tools gain a `form` argument, and
33
+ a new `form_list` tool returns `{ id, title, screenId }` for each mounted form.
34
+
35
+ - With exactly one form mounted, `form` is optional, so every existing
36
+ single-form consumer and agent prompt keeps working unchanged.
37
+ - With two or more forms, a call without `form` is an error that lists the form
38
+ ids, so an agent that guessed corrects itself on the next call.
39
+ - Presence and activity already target `formId:field`, so nothing changes there.
40
+ Closing one form settles only that form's pending writes.
41
+
42
+ Pros: stable, short `tools/list` (7 + 1 tools however many forms); no
43
+ `tools/list_changed` churn when forms mount and unmount; forms come and go as
44
+ data, which is how an agent reasons about them ("which form?"); no consumer code
45
+ change, because the call that throws today starts working. The router can be a
46
+ shared helper, so charts and grids get the same model later.
47
+
48
+ Cons: the largest change of the three. Tool descriptions become generic (today
49
+ `form_describe` names its form in the description). Per-form options such as
50
+ `pendingMode` and `agent` must stay per form inside one router. A host that
51
+ *relied* on the 0.51.0 throw to detect a double mount loses that signal, though
52
+ nothing first-party does.
53
+
54
+ ### B. Instance-scoped tool names via an option
55
+
56
+ Add `toolPrefix` (or reuse the name `surface`, as screen-doc does):
57
+ `registerFormBridge(host, { adapter, surface: "form_billing" })` registers
58
+ `form_billing_set_value`, and so on. The default stays `form`, so existing
59
+ consumers are unaffected.
60
+
61
+ Pros: small, mirrors an existing option, fully backward compatible, and each
62
+ tool name says which form it drives.
63
+
64
+ Cons: `tools/list` grows by 7 per form, and some clients cap or truncate long
65
+ tool lists. Mounting and unmounting forms churns `tools/list`, and not every
66
+ client re-reads it. The agent must infer that `form_billing_*` and
67
+ `form_shipping_*` are the same tool family. MCP tool names are limited (64
68
+ characters, `[A-Za-z0-9_-]`), so the host must choose a valid prefix or the
69
+ bridge must sanitise one. Nothing stops two hosts from choosing different
70
+ conventions.
71
+
72
+ ### C. One MCP host per form
73
+
74
+ Already supported. No change.
75
+
76
+ Pros: zero work and no new surface; isolation is total.
77
+
78
+ Cons: the agent needs one connection per form, or the consumer builds its own
79
+ router. Cross-form work ("copy billing into shipping") spans connections. Undo
80
+ history and presence split per host. This does not scale to dynamic forms. It
81
+ is a workaround, not a model.
82
+
83
+ ## Recommendation
84
+
85
+ **A**, built as a small shared per-host router so the charts, grid and other
86
+ multi-instance bridges can adopt it later. It is the only option that keeps the
87
+ tool list stable while forms come and go, and it needs no consumer change: the
88
+ code that throws today starts working. Keep **B** as the escape hatch only if a
89
+ client turns out to need flat, self-describing tool names. Document **C** as the
90
+ interim answer until A ships.
91
+
92
+ Suggested acceptance tests for A: two forms on one host both drivable; a call
93
+ without `form` while two are mounted is refused with both ids listed; with one
94
+ form mounted every existing call shape still succeeds; disposing one form leaves
95
+ the other drivable and settles only the disposed form's pending writes; a remount
96
+ of the same id re-joins rather than duplicating; `form_list` reflects mounts and
97
+ unmounts.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@particle-academy/agent-integrations",
3
- "version": "0.50.0",
3
+ "version": "0.52.0",
4
4
  "description": "MCP-driven agent presence in collab sessions: per-session micro-MCP server, pluggable bridges to fancy-* packages, and agent UX components (panel + on-canvas cursor).",
5
5
  "repository": {
6
6
  "type": "git",
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/bridges/charts.ts"],"names":[],"mappings":"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","file":"chunk-36MKPTVD.js","sourcesContent":["import { textResult, errorResult } from \"../mcp/server\";\nimport type { ToolHost } from \"../mcp/tool-host\";\nimport type { JsonObject } from \"../mcp/types\";\nimport type { Bridge } from \"./types\";\nimport { wrapToolWithActivity } from \"../presence/wrap-tool-with-activity\";\nimport { ensureUndoToolsRegistered } from \"../undo/undo-tools\";\nimport type { AgentTarget } from \"../presence/types\";\n\n/**\n * Adapter wires a single fancy-echarts chart to the bridge. Charts are\n * already prop-driven, so the adapter just exposes the data + option\n * setters and a way to read what's currently rendered.\n */\nexport type ChartsBridgeAdapter = {\n /** Stable id for this chart instance. */\n id: string;\n title?: string;\n screenId?: string;\n /** Read the current ECharts option object the chart is rendering. */\n getOption: () => Record<string, unknown>;\n /** Replace the entire option. */\n setOption: (option: Record<string, unknown>) => void;\n /** Convenience: shallow-merge a partial option update. */\n updateOption?: (partial: Record<string, unknown>) => void;\n /** Read just the data series (subset of option for quick agent reads). */\n getData?: () => unknown;\n /** Update only the data, leaving axes/colors/etc. alone. */\n updateData?: (data: unknown) => void;\n};\n\nexport type ChartsBridgeOptions = {\n adapter: ChartsBridgeAdapter;\n agent?: { id: string; name?: string; color?: string };\n};\n\nconst DEFAULT_AGENT = { id: \"agent\", name: \"Agent\", color: \"#a855f7\" };\n\n/**\n * registerChartsBridge — schema-aware MCP access to a single chart.\n */\nexport function registerChartsBridge(\n host: ToolHost,\n options: ChartsBridgeOptions,\n): Bridge {\n const { adapter } = options;\n const agent = { ...DEFAULT_AGENT, ...(options.agent ?? {}) };\n const disposers: Array<() => void> = [];\n\n // agent_undo / agent_redo / agent_history are registered whenever any bridge\n // mounts, so undo availability doesn't hinge on which bridges are co-present.\n ensureUndoToolsRegistered(host, { defaultAgentId: agent.id });\n\n const target: AgentTarget = {\n kind: \"chart\",\n screenId: adapter.screenId,\n elementId: adapter.id,\n label: adapter.title ?? adapter.id,\n };\n\n const reg = (\n name: string,\n description: string,\n properties: Record<string, unknown>,\n required: string[],\n handler: (args: JsonObject) => Promise<any> | any,\n isMutation: boolean,\n ) => {\n const wrapped = async (args: JsonObject) => {\n try { return await handler(args); }\n catch (e) { return errorResult(e instanceof Error ? e.message : String(e)); }\n };\n const final = isMutation\n ? wrapToolWithActivity(wrapped, {\n toolName: name, agent, kind: \"chart\", screenId: adapter.screenId,\n resolveTarget: () => target,\n })\n : wrapped;\n disposers.push(\n host.registerTool(\n { name, description, inputSchema: { type: \"object\", properties: properties as any, required, additionalProperties: false } },\n final as any,\n ),\n );\n };\n\n reg(\n \"chart_describe\",\n `Describe the chart \"${adapter.id}\" — series count, type guesses, axis info.`,\n {},\n [],\n () => {\n const opt = adapter.getOption();\n const series = Array.isArray(opt.series) ? opt.series : [];\n const summary = {\n id: adapter.id,\n title: adapter.title,\n seriesCount: series.length,\n seriesTypes: series.map((s: any) => s?.type ?? \"unknown\"),\n hasXAxis: !!opt.xAxis,\n hasYAxis: !!opt.yAxis,\n };\n return textResult(JSON.stringify(summary), summary);\n },\n false,\n );\n\n reg(\n \"chart_get_option\",\n \"Read the full ECharts option object the chart is rendering.\",\n {},\n [],\n () => {\n const opt = adapter.getOption();\n return textResult(JSON.stringify(opt, null, 2), opt);\n },\n false,\n );\n\n reg(\n \"chart_set_option\",\n \"Replace the entire ECharts option. Use chart_update_option for partial updates.\",\n { option: { type: \"object\" } },\n [\"option\"],\n (args) => {\n const opt = (args.option && typeof args.option === \"object\") ? args.option as Record<string, unknown> : {};\n adapter.setOption(opt);\n return textResult(\"Replaced chart option\", { });\n },\n true,\n );\n\n reg(\n \"chart_update_option\",\n \"Shallow-merge a partial option update — only the keys you provide change.\",\n { partial: { type: \"object\" } },\n [\"partial\"],\n (args) => {\n const partial = (args.partial && typeof args.partial === \"object\") ? args.partial as Record<string, unknown> : {};\n if (adapter.updateOption) {\n adapter.updateOption(partial);\n } else {\n adapter.setOption({ ...adapter.getOption(), ...partial });\n }\n return textResult(\"Merged chart option\", { keys: Object.keys(partial) });\n },\n true,\n );\n\n reg(\n \"chart_update_data\",\n \"Update only the data (typically the `series` field). Leaves layout / axes / colors alone.\",\n { data: { description: \"New series array (or whatever shape the host's adapter expects).\" } },\n [\"data\"],\n (args) => {\n if (!adapter.updateData) return errorResult(\"Host did not provide updateData.\");\n adapter.updateData(args.data);\n return textResult(\"Updated chart data\", { });\n },\n true,\n );\n\n return {\n id: `chart:${adapter.id}`,\n title: adapter.title ?? adapter.id,\n dispose: () => { for (const d of disposers) d(); },\n };\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/bridges/doc.ts"],"names":[],"mappings":"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","file":"chunk-3HVYUMQF.js","sourcesContent":["/**\n * registerDocBridge — a GENERIC MCP bridge over a `@particle-academy/fancy-doc-commons`\n * `DocTree`. Give it an adapter (`{ get, set }`) and it generates, from the shared\n * op-spine, a full Human+ surface: uniform read tools + the canonical node op tools\n * (add / update / remove / move) under one verb lexicon, with **undo derived from\n * the reducer**, agent-activity broadcasts, unconditional `agent_undo/redo/history`,\n * and an optional **staged-write** (confirm / reject) channel — replacing the ~500-line\n * bespoke bridges (whiteboard/flow/artboard/…) with one builder. A surface adds its\n * domain ops (e.g. cms `set_style`) via `opTools` + a matching reducer.\n */\nimport { textResult, errorResult } from \"../mcp/server\";\nimport type { ToolHost } from \"../mcp/tool-host\";\nimport type { JsonObject } from \"../mcp/types\";\nimport type { Bridge } from \"./types\";\nimport { wrapToolWithActivity } from \"../presence/wrap-tool-with-activity\";\nimport type { AgentTarget } from \"../presence/types\";\nimport { pushUndoEntry } from \"../undo/undo-stack\";\nimport { ensureUndoToolsRegistered } from \"../undo/undo-tools\";\nimport {\n treeReducer,\n childrenOf,\n descendantsOf,\n appendOrder,\n autoApply,\n type DocTree,\n type DocNode,\n type TreeOp,\n type DocReducer,\n type StagePolicy,\n} from \"@particle-academy/fancy-doc-commons\";\n\nconst DEFAULT_AGENT = { id: \"agent\", name: \"Agent\", color: \"#a855f7\" };\n\n/** Host-provided access to the document tree. */\nexport interface DocAdapter<N extends DocNode> {\n /** Read the current tree. */\n get(): DocTree<N>;\n /** Replace the tree — host wires this to its `onChange` / `setState`. */\n set(next: DocTree<N>): void;\n /** Optional fancy-screens screen id, for presence scoping. */\n screenId?: string;\n /** Mint a fresh, unique node id. Default: `<surface>-<n>`. */\n newId?(): string;\n}\n\n/**\n * A domain op tool beyond the built-in add/update/remove/move — lets a surface\n * expose its own ops (e.g. cms `set_style`) through the same undo + activity path.\n */\nexport interface DocOpTool<N extends DocNode, TOp> {\n /** Verb, prefixed with the surface (e.g. `set_style` → `cms_set_style`). */\n verb: string;\n description: string;\n properties: Record<string, unknown>;\n required: string[];\n /** Build the op from the args (or return `{ error }`). */\n build(args: JsonObject, tree: DocTree<N>): TOp | { error: string };\n /** Node id this op targets (for the activity target + undo label). */\n targetId?(args: JsonObject): string | undefined;\n}\n\nexport interface DocBridgeOptions<N extends DocNode, TOp = TreeOp<N>> {\n adapter: DocAdapter<N>;\n /** Tool-name prefix + activity kind (e.g. `\"cms\"` → `cms_add`, kind `\"cms\"`). */\n surface: string;\n agent?: { id: string; name?: string; color?: string };\n /** Reducer for reduce + invert. Default: the substrate `treeReducer<N>()`. */\n reducer?: DocReducer<DocTree<N>, TOp>;\n /** Build a full node from the core fields + props (fill surface defaults, e.g. `style`). */\n makeNode?: (core: { id: string; type: string; parent: string | null; order: string }, props: Record<string, unknown>) => N;\n /** Domain op tools beyond the built-ins. */\n opTools?: DocOpTool<N, TOp>[];\n /** Decide auto-apply vs. confirm per op. Default: everything auto-applies. */\n stagePolicy?: StagePolicy<TOp>;\n /** Fired when an op is staged pending human confirmation. */\n onPending?: (staged: { id: string; op: TOp; label: string }) => void;\n /** Summarize a node for describe/list. Default: id/type/parent + prop keys. */\n describeNode?: (node: N) => Record<string, unknown>;\n}\n\n/** Register the generic doc-surface bridge. Returns a {@link Bridge}. */\nexport function registerDocBridge<N extends DocNode, TOp = TreeOp<N>>(\n host: ToolHost,\n options: DocBridgeOptions<N, TOp>,\n): Bridge {\n const { adapter, surface } = options;\n const agent = { ...DEFAULT_AGENT, ...(options.agent ?? {}) };\n const reducer = (options.reducer ?? (treeReducer<N>() as unknown as DocReducer<DocTree<N>, TOp>));\n const stage = options.stagePolicy ?? (autoApply as StagePolicy<TOp>);\n const makeNode =\n options.makeNode ?? (({ id, type, parent, order }, props) => ({ id, type, parent, order, props }) as N);\n const describeNode =\n options.describeNode ?? ((n: N) => ({ id: n.id, type: n.type, parent: n.parent, props: Object.keys(n.props ?? {}) }));\n const disposers: Array<() => void> = [];\n\n // agent_undo / agent_redo / agent_history — always present (undo derives from\n // the reducer, so every doc surface gets working undo for free).\n ensureUndoToolsRegistered(host, { defaultAgentId: agent.id });\n\n let idSeq = 0;\n // The counter restarts with the bridge, so on a tree loaded from elsewhere\n // `surface-1` may well be taken. Skip past anything that already exists\n // rather than minting an id that silently overwrites a node.\n const mintId = () => {\n if (adapter.newId) return adapter.newId();\n const taken = adapter.get().nodes;\n let id: string;\n do id = `${surface}-${(idSeq += 1)}`;\n while (taken[id]);\n return id;\n };\n const target = (elementId?: string): AgentTarget => ({ kind: surface, screenId: adapter.screenId, elementId });\n\n // Staged ops awaiting confirmation.\n const pending = new Map<string, { op: TOp; label: string; targetId?: string }>();\n\n /** Apply an op immediately: reduce → set → push a snapshot-based undo entry. */\n function commit(op: TOp, label: string, targetId?: string): Record<string, unknown> {\n const prev = adapter.get();\n const next = reducer.reduce(prev, op);\n adapter.set(next);\n pushUndoEntry(agent.id, {\n timestamp: Date.now(),\n bridgeId: surface,\n action: label,\n label,\n undo: () => adapter.set(prev),\n redo: () => adapter.set(next),\n });\n return { ok: true, id: targetId };\n }\n\n /**\n * Auto-apply, or stage for confirmation per the stage policy.\n *\n * The staged case reports the pending id under its OWN key. Returning it as\n * `id` — as this used to — collided with the node id every mutation already\n * reports, so `update`/`remove`/`move` overwrote it and left the agent holding\n * a node id that `confirm` does not accept. The staged write was unconfirmable\n * for three of the four canonical ops, and looked fine from the outside.\n */\n function submit(op: TOp, label: string, targetId?: string): { staged: boolean; id?: string; pendingId?: string } {\n if (stage(op) === \"confirm\") {\n const pendingId = `${surface}-pending-${(idSeq += 1)}`;\n pending.set(pendingId, { op, label, targetId });\n options.onPending?.({ id: pendingId, op, label });\n return { staged: true, id: targetId, pendingId };\n }\n commit(op, label, targetId);\n return { staged: false, id: targetId };\n }\n\n const reg = (\n verb: string,\n description: string,\n properties: Record<string, unknown>,\n required: string[],\n handler: (args: JsonObject) => Record<string, unknown> | Promise<Record<string, unknown>>,\n isMutation: boolean,\n resolveTarget?: (args: JsonObject, result: Record<string, unknown>) => AgentTarget | null,\n ): void => {\n const name = `${surface}_${verb}`;\n const wrapped = async (args: JsonObject) => {\n try {\n // `_text` is the human-facing line; the rest is structuredContent.\n const { _text, ...structured } = await handler(args);\n return textResult(typeof _text === \"string\" ? _text : name, structured);\n } catch (e) {\n return errorResult(e instanceof Error ? e.message : String(e));\n }\n };\n const final = isMutation\n ? wrapToolWithActivity(wrapped, {\n toolName: name,\n agent,\n kind: surface,\n screenId: adapter.screenId,\n resolveTarget: ({ args, result }) => {\n if ((result.structuredContent as JsonObject | undefined)?.staged) return null;\n return resolveTarget?.(args, (result.structuredContent as JsonObject) ?? {}) ?? target();\n },\n })\n : wrapped;\n disposers.push(\n host.registerTool(\n { name, description, inputSchema: { type: \"object\", properties: properties as never, required, additionalProperties: false } },\n final as never,\n ),\n );\n };\n\n // ── Read tools ──────────────────────────────────────────────────────────\n reg(\n \"describe\",\n `Summarize the ${surface} document: node count, roots, and the active surface. Call before reading or writing.`,\n {},\n [],\n () => {\n const tree = adapter.get();\n const ids = Object.keys(tree.nodes);\n return { nodeCount: ids.length, roots: childrenOf(tree, null).map((n) => n.id), _text: `${ids.length} nodes` };\n },\n false,\n );\n reg(\n \"get\",\n `Get the whole ${surface} document tree as JSON.`,\n {},\n [],\n () => ({ tree: adapter.get(), _text: \"full tree\" }),\n false,\n );\n reg(\n \"list\",\n \"List nodes (optionally the children of `parent`), in order.\",\n { parent: { type: [\"string\", \"null\"], description: \"Parent id, or null/omitted for roots.\" } },\n [],\n (args) => {\n const tree = adapter.get();\n const parent = typeof args.parent === \"string\" ? args.parent : null;\n return { nodes: childrenOf(tree, parent).map(describeNode), _text: `children of ${parent ?? \"root\"}` };\n },\n false,\n );\n reg(\n \"get_node\",\n \"Get one node by id.\",\n { id: { type: \"string\" } },\n [\"id\"],\n (args) => {\n const node = adapter.get().nodes[String(args.id)];\n if (!node) throw new Error(`No node ${args.id}`);\n return { node, _text: `node ${node.id}` };\n },\n false,\n );\n\n // ── Canonical op tools ──────────────────────────────────────────────────\n reg(\n \"add\",\n \"Insert a node. Returns its id. Appends under `parent` (or roots) unless `order` is given.\",\n {\n type: { type: \"string\", description: \"Node type discriminant.\" },\n parent: { type: [\"string\", \"null\"], description: \"Parent id, or null for a root.\" },\n props: { type: \"object\", description: \"JSON props bag.\" },\n order: { type: \"string\", description: \"Fractional order key (default: append).\" },\n id: {\n type: \"string\",\n description:\n \"Id for the new node. Supply a meaningful one if you intend to address this node later; omitted means one is minted for you. Must not already exist.\",\n },\n },\n [\"type\"],\n (args) => {\n const tree = adapter.get();\n const parent = typeof args.parent === \"string\" ? args.parent : null;\n // An agent that names the node names the handle it will use afterwards.\n // Minted ids are addressable too, just less memorable.\n const requested = typeof args.id === \"string\" ? args.id : undefined;\n if (requested !== undefined && tree.nodes[requested]) {\n throw new Error(`Node ${requested} already exists — pick a different id or update it instead`);\n }\n const id = requested ?? mintId();\n const order = typeof args.order === \"string\" ? args.order : appendOrder(tree, parent);\n const props = (args.props && typeof args.props === \"object\" ? args.props : {}) as Record<string, unknown>;\n const node = makeNode({ id, type: String(args.type), parent, order }, props);\n const res = submit({ t: \"insert\", node } as unknown as TOp, `add ${args.type} ${id}`, id);\n return { ...res, _text: res.staged ? `staged add ${id} — confirm ${res.pendingId}` : `added ${id}` };\n },\n true,\n (_args, result) => target(result.id as string | undefined),\n );\n reg(\n \"update\",\n \"Merge a props patch into a node.\",\n { id: { type: \"string\" }, patch: { type: \"object\" } },\n [\"id\", \"patch\"],\n (args) => {\n const id = String(args.id);\n if (!adapter.get().nodes[id]) throw new Error(`No node ${id}`);\n const patch = (args.patch && typeof args.patch === \"object\" ? args.patch : {}) as Record<string, unknown>;\n const res = submit({ t: \"set_props\", id, patch } as unknown as TOp, `update ${id}`, id);\n return { ...res, id, _text: res.staged ? `staged update ${id} — confirm ${res.pendingId}` : `updated ${id}` };\n },\n true,\n (args) => target(String(args.id)),\n );\n reg(\n \"remove\",\n \"Remove a node and its subtree.\",\n { id: { type: \"string\" } },\n [\"id\"],\n (args) => {\n const id = String(args.id);\n const tree = adapter.get();\n if (!tree.nodes[id]) throw new Error(`No node ${id}`);\n const count = descendantsOf(tree, id).length + 1;\n const res = submit({ t: \"remove\", id } as unknown as TOp, `remove ${id} (${count} node${count === 1 ? \"\" : \"s\"})`, id);\n return { ...res, id, removed: count, _text: res.staged ? `staged remove ${id} — confirm ${res.pendingId}` : `removed ${id}` };\n },\n true,\n (args) => target(String(args.id)),\n );\n reg(\n \"move\",\n \"Reparent + reorder a node.\",\n { id: { type: \"string\" }, parent: { type: [\"string\", \"null\"] }, order: { type: \"string\", description: \"Fractional order key (default: append under the new parent).\" } },\n [\"id\"],\n (args) => {\n const id = String(args.id);\n const tree = adapter.get();\n if (!tree.nodes[id]) throw new Error(`No node ${id}`);\n const parent = args.parent === null ? null : typeof args.parent === \"string\" ? args.parent : tree.nodes[id]!.parent;\n const order = typeof args.order === \"string\" ? args.order : appendOrder(tree, parent);\n const res = submit({ t: \"move\", id, parent, order } as unknown as TOp, `move ${id}`, id);\n return { ...res, id, _text: res.staged ? `staged move ${id} — confirm ${res.pendingId}` : `moved ${id}` };\n },\n true,\n (args) => target(String(args.id)),\n );\n\n // ── Domain op tools ─────────────────────────────────────────────────────\n for (const t of options.opTools ?? []) {\n reg(\n t.verb,\n t.description,\n t.properties,\n t.required,\n (args) => {\n const built = t.build(args, adapter.get());\n if (built && typeof built === \"object\" && \"error\" in built) throw new Error((built as { error: string }).error);\n const tid = t.targetId?.(args);\n const res = submit(built as TOp, `${t.verb} ${tid ?? \"\"}`.trim(), tid);\n return { ...res, id: tid, _text: res.staged ? `staged ${t.verb} — confirm ${res.pendingId}` : t.verb };\n },\n true,\n (args) => target(t.targetId?.(args)),\n );\n }\n\n // ── Staged-write confirm / reject ───────────────────────────────────────\n reg(\n \"confirm\",\n \"Apply a staged op. Pass the `pendingId` a staged mutation returned — not the node `id` it also returns.\",\n { id: { type: \"string\", description: \"The `pendingId` from a staged mutation.\" } },\n [\"id\"],\n (args) => {\n const id = String(args.id);\n const p = pending.get(id);\n if (!p) throw new Error(`No pending op ${id}`);\n pending.delete(id);\n commit(p.op, p.label, p.targetId);\n return { ok: true, applied: p.label, id: p.targetId, _text: `applied ${p.label}` };\n },\n true,\n (_args, result) => target(result.id as string | undefined),\n );\n reg(\n \"reject\",\n \"Discard a staged op. Pass the `pendingId` a staged mutation returned — not the node `id` it also returns.\",\n { id: { type: \"string\", description: \"The `pendingId` from a staged mutation.\" } },\n [\"id\"],\n (args) => {\n const id = String(args.id);\n const p = pending.get(id);\n if (!p) throw new Error(`No pending op ${id}`);\n pending.delete(id);\n return { ok: true, rejected: p.label, _text: `rejected ${p.label}` };\n },\n false,\n );\n\n return {\n id: surface,\n title: surface,\n dispose: () => {\n for (const d of disposers) d();\n pending.clear();\n },\n };\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/bridges/map.ts"],"names":[],"mappings":";;;;;AAiDA,IAAM,gBAAgB,EAAE,EAAA,EAAI,SAAS,IAAA,EAAM,OAAA,EAAS,OAAO,SAAA,EAAU;AAErE,IAAM,GAAA,GAAM,CAAC,CAAA,EAAY,QAAA,KACvB,OAAO,CAAA,KAAM,QAAA,IAAY,MAAA,CAAO,QAAA,CAAS,CAAC,CAAA,GAAI,CAAA,GAAgB,CAAA;AAChE,IAAM,GAAA,GAAM,CAAC,CAAA,EAAY,QAAA,GAAW,OAAgB,OAAO,CAAA,KAAM,WAAW,CAAA,GAAI,QAAA;AAChF,IAAM,KAAA,GAAQ,CAAC,MAAA,KACb,CAAA,EAAG,MAAM,CAAA,CAAA,EAAI,IAAA,CAAK,GAAA,EAAI,CAAE,QAAA,CAAS,EAAE,CAAC,CAAA,CAAA,EAAI,IAAA,CAAK,QAAO,CAAE,QAAA,CAAS,EAAE,CAAA,CAAE,KAAA,CAAM,CAAA,EAAG,CAAC,CAAC,CAAA,CAAA;AAUzE,SAAS,iBAAA,CAAkB,MAAgB,OAAA,EAAmC;AACnF,EAAA,MAAM,EAAE,SAAQ,GAAI,OAAA;AACpB,EAAA,MAAM,KAAA,GAAQ,EAAE,GAAG,aAAA,EAAe,GAAI,OAAA,CAAQ,KAAA,IAAS,EAAC,EAAG;AAC3D,EAAA,MAAM,YAA+B,EAAC;AAGtC,EAAA,yBAAA,CAA0B,IAAA,EAAM,EAAE,cAAA,EAAgB,KAAA,CAAM,IAAI,CAAA;AAE5D,EAAA,MAAM,OAAA,GAAU,CAAC,IAAA,EAAW,MAAA,MAAiC;AAAA,IAC3D,IAAA,EAAM,KAAA;AAAA,IACN,SAAA,EACG,MAAA,EAAQ,iBAAA,EAAmB,EAAA,IAA8B,IAAA,EAAM;AAAA,GACpE,CAAA;AAEA,EAAA,MAAM,MAAM,CACV,IAAA,EACA,aACA,UAAA,EACA,QAAA,EACA,SACA,aAAA,KACG;AACH,IAAA,MAAM,OAAA,GAAU,OAAO,IAAA,KAAqB;AAC1C,MAAA,IAAI;AACF,QAAA,OAAO,MAAM,QAAQ,IAAI,CAAA;AAAA,MAC3B,SAAS,CAAA,EAAG;AACV,QAAA,OAAO,YAAY,CAAA,YAAa,KAAA,GAAQ,EAAE,OAAA,GAAU,MAAA,CAAO,CAAC,CAAC,CAAA;AAAA,MAC/D;AAAA,IACF,CAAA;AACA,IAAA,MAAM,KAAA,GAAQ,aAAA,GACV,oBAAA,CAAqB,OAAA,EAAS;AAAA,MAC5B,QAAA,EAAU,IAAA;AAAA,MACV,KAAA,EAAO,EAAE,EAAA,EAAI,KAAA,CAAM,EAAA,EAAI,MAAM,KAAA,CAAM,IAAA,EAAM,KAAA,EAAO,KAAA,CAAM,KAAA,EAAM;AAAA,MAC5D,IAAA,EAAM,KAAA;AAAA,MACN,aAAA,EAAe,CAAC,EAAE,IAAA,EAAM,QAAO,KAAM,aAAA,CAAc,MAAM,MAAM;AAAA,KAChE,CAAA,GACD,OAAA;AACJ,IAAA,SAAA,CAAU,IAAA;AAAA,MACR,IAAA,CAAK,YAAA;AAAA,QACH;AAAA,UACE,IAAA;AAAA,UACA,WAAA;AAAA,UACA,WAAA,EAAa;AAAA,YACX,IAAA,EAAM,QAAA;AAAA,YACN,UAAA;AAAA,YACA,QAAA;AAAA,YACA,oBAAA,EAAsB;AAAA;AACxB,SACF;AAAA,QACA;AAAA;AACF,KACF;AAAA,EACF,CAAA;AAIA,EAAA,GAAA,CAAI,iBAAiB,uDAAA,EAAyD,EAAC,EAAG,IAAI,MAAM;AAC1F,IAAA,MAAM,KAAA,GAAQ;AAAA,MACZ,IAAA,EAAM,QAAQ,OAAA,EAAQ;AAAA,MACtB,OAAA,EAAS,QAAQ,UAAA,EAAW;AAAA,MAC5B,UAAA,EAAY,QAAQ,WAAA;AAAY,KAClC;AACA,IAAA,OAAO,WAAW,IAAA,CAAK,SAAA,CAAU,OAAO,IAAA,EAAM,CAAC,GAAG,KAAK,CAAA;AAAA,EACzD,CAAC,CAAA;AAID,EAAA,GAAA;AAAA,IACE,cAAA;AAAA,IACA,+EAAA;AAAA,IACA;AAAA,MACE,GAAA,EAAK,EAAE,IAAA,EAAM,QAAA,EAAU,aAAa,sBAAA,EAAuB;AAAA,MAC3D,GAAA,EAAK,EAAE,IAAA,EAAM,QAAA,EAAU,aAAa,uBAAA,EAAwB;AAAA,MAC5D,IAAA,EAAM,EAAE,IAAA,EAAM,QAAA,EAAU,aAAa,mCAAA;AAAoC,KAC3E;AAAA,IACA,EAAC;AAAA,IACD,CAAC,IAAA,KAAS;AACR,MAAA,MAAM,IAAA,GAAO,QAAQ,OAAA,EAAQ;AAC7B,MAAA,MAAM,IAAA,GAAgB;AAAA,QACpB,MAAA,EAAQ;AAAA,UACN,GAAA,EAAK,KAAK,GAAA,KAAQ,MAAA,GAAY,IAAI,IAAA,CAAK,GAAG,CAAA,GAAI,IAAA,CAAK,MAAA,CAAO,GAAA;AAAA,UAC1D,GAAA,EAAK,KAAK,GAAA,KAAQ,MAAA,GAAY,IAAI,IAAA,CAAK,GAAG,CAAA,GAAI,IAAA,CAAK,MAAA,CAAO;AAAA,SAC5D;AAAA,QACA,IAAA,EAAM,KAAK,IAAA,KAAS,MAAA,GAAY,IAAI,IAAA,CAAK,IAAI,IAAI,IAAA,CAAK;AAAA,OACxD;AACA,MAAA,OAAA,CAAQ,QAAQ,IAAI,CAAA;AACpB,MAAA,aAAA,CAAc,MAAM,EAAA,EAAI;AAAA,QACtB,SAAA,EAAW,KAAK,GAAA,EAAI;AAAA,QACpB,QAAA,EAAU,KAAA;AAAA,QACV,MAAA,EAAQ,cAAA;AAAA,QACR,OAAO,CAAA,gBAAA,EAAmB,IAAA,CAAK,MAAA,CAAO,GAAA,CAAI,QAAQ,CAAC,CAAC,CAAA,CAAA,EAAI,IAAA,CAAK,OAAO,GAAA,CAAI,OAAA,CAAQ,CAAC,CAAC,CAAA,EAAA,EAAK,KAAK,IAAI,CAAA,CAAA;AAAA,QAChG,IAAA,EAAM,MAAM,OAAA,CAAQ,OAAA,CAAQ,IAAI,CAAA;AAAA,QAChC,IAAA,EAAM,MAAM,OAAA,CAAQ,OAAA,CAAQ,IAAI;AAAA,OACjC,CAAA;AACD,MAAA,OAAO,WAAW,CAAA,cAAA,EAAY,IAAA,CAAK,OAAO,GAAA,CAAI,OAAA,CAAQ,CAAC,CAAC,CAAA,CAAA,EAAI,KAAK,MAAA,CAAO,GAAA,CAAI,QAAQ,CAAC,CAAC,KAAK,IAAA,CAAK,IAAI,IAAI,IAAI,CAAA;AAAA,IAC9G,CAAA;AAAA,IACA;AAAA,GACF;AAEA,EAAA,GAAA;AAAA,IACE,SAAA;AAAA,IACA,+FAAA;AAAA,IACA,EAAE,IAAA,EAAM,EAAE,IAAA,EAAM,QAAA,IAAY,IAAA,EAAM,EAAE,IAAA,EAAM,QAAA,EAAS,EAAE;AAAA,IACrD,EAAC;AAAA,IACD,CAAC,IAAA,KAAS;AACR,MAAA,MAAM,IAAA,GAAO,QAAQ,OAAA,EAAQ;AAC7B,MAAA,MAAM,IAAA,GAAgB;AAAA,QACpB,GAAG,IAAA;AAAA,QACH,QAAQ,EAAE,GAAA,EAAK,IAAA,CAAK,MAAA,CAAO,MAAM,GAAA,CAAI,IAAA,CAAK,IAAI,CAAA,EAAG,KAAK,IAAA,CAAK,MAAA,CAAO,MAAM,GAAA,CAAI,IAAA,CAAK,IAAI,CAAA;AAAE,OACzF;AACA,MAAA,OAAA,CAAQ,QAAQ,IAAI,CAAA;AACpB,MAAA,aAAA,CAAc,MAAM,EAAA,EAAI;AAAA,QACtB,SAAA,EAAW,KAAK,GAAA,EAAI;AAAA,QACpB,QAAA,EAAU,KAAA;AAAA,QACV,MAAA,EAAQ,SAAA;AAAA,QACR,KAAA,EAAO,eAAA;AAAA,QACP,IAAA,EAAM,MAAM,OAAA,CAAQ,OAAA,CAAQ,IAAI,CAAA;AAAA,QAChC,IAAA,EAAM,MAAM,OAAA,CAAQ,OAAA,CAAQ,IAAI;AAAA,OACjC,CAAA;AACD,MAAA,OAAO,WAAW,CAAA,UAAA,EAAa,IAAA,CAAK,MAAA,CAAO,GAAA,CAAI,QAAQ,CAAC,CAAC,CAAA,CAAA,EAAI,IAAA,CAAK,OAAO,GAAA,CAAI,OAAA,CAAQ,CAAC,CAAC,IAAI,IAAI,CAAA;AAAA,IACjG,CAAA;AAAA,IACA;AAAA,GACF;AAEA,EAAA,GAAA;AAAA,IACE,UAAA;AAAA,IACA,+EAAA;AAAA,IACA,EAAE,KAAA,EAAO,EAAE,IAAA,EAAM,UAAS,EAAE;AAAA,IAC5B,CAAC,OAAO,CAAA;AAAA,IACR,CAAC,IAAA,KAAS;AACR,MAAA,MAAM,IAAA,GAAO,QAAQ,OAAA,EAAQ;AAC7B,MAAA,MAAM,IAAA,GAAgB,EAAE,GAAG,IAAA,EAAM,IAAA,EAAM,KAAK,IAAA,GAAO,GAAA,CAAI,IAAA,CAAK,KAAK,CAAA,EAAE;AACnE,MAAA,OAAA,CAAQ,QAAQ,IAAI,CAAA;AACpB,MAAA,aAAA,CAAc,MAAM,EAAA,EAAI;AAAA,QACtB,SAAA,EAAW,KAAK,GAAA,EAAI;AAAA,QACpB,QAAA,EAAU,KAAA;AAAA,QACV,MAAA,EAAQ,UAAA;AAAA,QACR,KAAA,EAAO,CAAA,YAAA,EAAU,IAAA,CAAK,IAAI,CAAA,CAAA;AAAA,QAC1B,IAAA,EAAM,MAAM,OAAA,CAAQ,OAAA,CAAQ,IAAI,CAAA;AAAA,QAChC,IAAA,EAAM,MAAM,OAAA,CAAQ,OAAA,CAAQ,IAAI;AAAA,OACjC,CAAA;AACD,MAAA,OAAO,UAAA,CAAW,CAAA,YAAA,EAAU,IAAA,CAAK,IAAI,IAAI,IAAI,CAAA;AAAA,IAC/C;AAAA,GACF;AAEA,EAAA,GAAA;AAAA,IACE,gBAAA;AAAA,IACA,sFAAA;AAAA,IACA;AAAA,MACE,MAAA,EAAQ;AAAA,QACN,IAAA,EAAM,OAAA;AAAA,QACN,WAAA,EAAa,6CAAA;AAAA,QACb,KAAA,EAAO;AAAA,UACL,IAAA,EAAM,QAAA;AAAA,UACN,UAAA,EAAY,EAAE,GAAA,EAAK,EAAE,IAAA,EAAM,QAAA,EAAS,EAAG,GAAA,EAAK,EAAE,IAAA,EAAM,QAAA,EAAS,EAAE;AAAA,UAC/D,QAAA,EAAU,CAAC,KAAA,EAAO,KAAK;AAAA;AACzB,OACF;AAAA,MACA,OAAA,EAAS,EAAE,IAAA,EAAM,QAAA,EAAU,aAAa,iCAAA;AAAkC,KAC5E;AAAA,IACA,EAAC;AAAA,IACD,CAAC,IAAA,KAAS;AACR,MAAA,IAAI,CAAC,QAAQ,SAAA,EAAW;AACtB,QAAA,OAAO,YAAY,0EAA0E,CAAA;AAAA,MAC/F;AACA,MAAA,MAAM,MAAA,GAAmB,KAAA,CAAM,OAAA,CAAQ,IAAA,CAAK,MAAM,CAAA,GAC7C,IAAA,CAAK,MAAA,CAAiB,GAAA,CAAI,CAAC,CAAA,MAAO,EAAE,KAAK,GAAA,CAAI,CAAA,EAAG,GAAG,CAAA,EAAG,GAAA,EAAK,GAAA,CAAI,CAAA,EAAG,GAAG,GAAE,CAAE,CAAA,GAC1E,OAAA,CAAQ,UAAA,EAAW,CAAE,GAAA,CAAI,CAAC,CAAA,KAAM,EAAE,QAAQ,CAAA;AAC9C,MAAA,IAAI,CAAC,OAAO,MAAA,EAAQ;AAClB,QAAA,OAAO,YAAY,wCAAwC,CAAA;AAAA,MAC7D;AACA,MAAA,OAAA,CAAQ,SAAA,CAAU,QAAQ,IAAA,CAAK,OAAA,KAAY,SAAY,GAAA,CAAI,IAAA,CAAK,OAAO,CAAA,GAAI,KAAA,CAAS,CAAA;AACpF,MAAA,OAAO,UAAA,CAAW,CAAA,cAAA,EAAiB,MAAA,CAAO,MAAM,CAAA,UAAA,CAAY,CAAA;AAAA,IAC9D;AAAA,GACF;AAIA,EAAA,GAAA;AAAA,IACE,gBAAA;AAAA,IACA,yFAAA;AAAA,IACA;AAAA,MACE,EAAA,EAAI,EAAE,IAAA,EAAM,QAAA,EAAS;AAAA,MACrB,GAAA,EAAK,EAAE,IAAA,EAAM,QAAA,EAAS;AAAA,MACtB,GAAA,EAAK,EAAE,IAAA,EAAM,QAAA,EAAS;AAAA,MACtB,KAAA,EAAO,EAAE,IAAA,EAAM,QAAA,EAAS;AAAA,MACxB,KAAA,EAAO,EAAE,IAAA,EAAM,QAAA,EAAU,aAAa,0BAAA,EAA2B;AAAA,MACjE,IAAA,EAAM,EAAE,IAAA,EAAM,QAAA,EAAU,aAAa,gCAAA,EAAiC;AAAA,MACtE,SAAA,EAAW,EAAE,IAAA,EAAM,SAAA,EAAU;AAAA,MAC7B,IAAA,EAAM,EAAE,IAAA,EAAM,QAAA,EAAU,aAAa,iDAAA;AAAkD,KACzF;AAAA,IACA,CAAC,OAAO,KAAK,CAAA;AAAA,IACb,CAAC,IAAA,KAAS;AACR,MAAA,MAAM,EAAA,GAAK,KAAK,EAAA,GAAK,GAAA,CAAI,KAAK,EAAE,CAAA,GAAI,MAAM,GAAG,CAAA;AAC7C,MAAA,IAAI,OAAA,CAAQ,YAAW,CAAE,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,EAAA,KAAO,EAAE,CAAA,EAAG;AACjD,QAAA,OAAO,WAAA,CAAY,CAAA,iBAAA,EAAoB,EAAE,CAAA,6CAAA,CAA0C,CAAA;AAAA,MACrF;AACA,MAAA,MAAM,MAAA,GAAoB;AAAA,QACxB,EAAA;AAAA,QACA,QAAA,EAAU,EAAE,GAAA,EAAK,GAAA,CAAI,IAAA,CAAK,GAAG,CAAA,EAAG,GAAA,EAAK,GAAA,CAAI,IAAA,CAAK,GAAG,CAAA,EAAE;AAAA,QACnD,GAAI,IAAA,CAAK,KAAA,KAAU,MAAA,GAAY,EAAE,KAAA,EAAO,GAAA,CAAI,IAAA,CAAK,KAAK,CAAA,EAAE,GAAI,EAAC;AAAA,QAC7D,GAAI,IAAA,CAAK,KAAA,KAAU,MAAA,GAAY,EAAE,KAAA,EAAO,GAAA,CAAI,IAAA,CAAK,KAAK,CAAA,EAAE,GAAI,EAAC;AAAA,QAC7D,GAAI,IAAA,CAAK,IAAA,KAAS,MAAA,GAAY,EAAE,IAAA,EAAM,GAAA,CAAI,IAAA,CAAK,IAAI,CAAA,EAAE,GAAI,EAAC;AAAA,QAC1D,GAAI,IAAA,CAAK,SAAA,KAAc,MAAA,GAAY,EAAE,SAAA,EAAW,CAAC,CAAC,IAAA,CAAK,SAAA,EAAU,GAAI,EAAC;AAAA,QACtE,GAAI,IAAA,CAAK,IAAA,IAAQ,OAAO,IAAA,CAAK,IAAA,KAAS,QAAA,GAClC,EAAE,IAAA,EAAM,IAAA,CAAK,IAAA,EAAgC,GAC7C;AAAC,OACP;AACA,MAAA,OAAA,CAAQ,WAAW,CAAC,GAAA,KAAQ,CAAC,GAAG,GAAA,EAAK,MAAM,CAAC,CAAA;AAC5C,MAAA,aAAA,CAAc,MAAM,EAAA,EAAI;AAAA,QACtB,SAAA,EAAW,KAAK,GAAA,EAAI;AAAA,QACpB,QAAA,EAAU,KAAA;AAAA,QACV,MAAA,EAAQ,gBAAA;AAAA,QACR,KAAA,EAAO,gBAAgB,EAAE,CAAA,CAAA;AAAA,QACzB,IAAA,EAAM,MAAM,OAAA,CAAQ,UAAA,CAAW,CAAC,GAAA,KAAQ,GAAA,CAAI,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,EAAA,KAAO,EAAE,CAAC,CAAA;AAAA,QACtE,IAAA,EAAM,MAAM,OAAA,CAAQ,UAAA,CAAW,CAAC,QAAQ,CAAC,GAAG,GAAA,EAAK,MAAM,CAAC;AAAA,OACzD,CAAA;AACD,MAAA,OAAO,WAAW,CAAA,aAAA,EAAgB,EAAE,OAAO,MAAA,CAAO,QAAA,CAAS,IAAI,OAAA,CAAQ,CAAC,CAAC,CAAA,CAAA,EAAI,OAAO,QAAA,CAAS,GAAA,CAAI,QAAQ,CAAC,CAAC,IAAI,MAAM,CAAA;AAAA,IACvH,CAAA;AAAA,IACA;AAAA,GACF;AAEA,EAAA,GAAA;AAAA,IACE,mBAAA;AAAA,IACA,sGAAA;AAAA,IACA;AAAA,MACE,EAAA,EAAI,EAAE,IAAA,EAAM,QAAA,EAAS;AAAA,MACrB,GAAA,EAAK,EAAE,IAAA,EAAM,QAAA,EAAS;AAAA,MACtB,GAAA,EAAK,EAAE,IAAA,EAAM,QAAA,EAAS;AAAA,MACtB,KAAA,EAAO,EAAE,IAAA,EAAM,QAAA,EAAS;AAAA,MACxB,KAAA,EAAO,EAAE,IAAA,EAAM,QAAA,EAAS;AAAA,MACxB,IAAA,EAAM,EAAE,IAAA,EAAM,QAAA,EAAS;AAAA,MACvB,SAAA,EAAW,EAAE,IAAA,EAAM,SAAA;AAAU,KAC/B;AAAA,IACA,CAAC,IAAI,CAAA;AAAA,IACL,CAAC,IAAA,KAAS;AACR,MAAA,MAAM,EAAA,GAAK,GAAA,CAAI,IAAA,CAAK,EAAE,CAAA;AACtB,MAAA,MAAM,IAAA,GAAO,QAAQ,UAAA,EAAW,CAAE,KAAK,CAAC,CAAA,KAAM,CAAA,CAAE,EAAA,KAAO,EAAE,CAAA;AACzD,MAAA,IAAI,CAAC,IAAA,EAAM;AACT,QAAA,OAAO,WAAA,CAAY,CAAA,kBAAA,EAAqB,EAAE,CAAA,CAAE,CAAA;AAAA,MAC9C;AACA,MAAA,MAAM,IAAA,GAAkB;AAAA,QACtB,GAAG,IAAA;AAAA,QACH,QAAA,EAAU;AAAA,UACR,GAAA,EAAK,KAAK,GAAA,KAAQ,MAAA,GAAY,IAAI,IAAA,CAAK,GAAG,CAAA,GAAI,IAAA,CAAK,QAAA,CAAS,GAAA;AAAA,UAC5D,GAAA,EAAK,KAAK,GAAA,KAAQ,MAAA,GAAY,IAAI,IAAA,CAAK,GAAG,CAAA,GAAI,IAAA,CAAK,QAAA,CAAS;AAAA,SAC9D;AAAA,QACA,GAAI,IAAA,CAAK,KAAA,KAAU,MAAA,GAAY,EAAE,KAAA,EAAO,GAAA,CAAI,IAAA,CAAK,KAAK,CAAA,EAAE,GAAI,EAAC;AAAA,QAC7D,GAAI,IAAA,CAAK,KAAA,KAAU,MAAA,GAAY,EAAE,KAAA,EAAO,GAAA,CAAI,IAAA,CAAK,KAAK,CAAA,EAAE,GAAI,EAAC;AAAA,QAC7D,GAAI,IAAA,CAAK,IAAA,KAAS,MAAA,GAAY,EAAE,IAAA,EAAM,GAAA,CAAI,IAAA,CAAK,IAAI,CAAA,EAAE,GAAI,EAAC;AAAA,QAC1D,GAAI,IAAA,CAAK,SAAA,KAAc,MAAA,GAAY,EAAE,SAAA,EAAW,CAAC,CAAC,IAAA,CAAK,SAAA,EAAU,GAAI;AAAC,OACxE;AACA,MAAA,OAAA,CAAQ,UAAA,CAAW,CAAC,GAAA,KAAQ,GAAA,CAAI,GAAA,CAAI,CAAC,CAAA,KAAO,CAAA,CAAE,EAAA,KAAO,EAAA,GAAK,IAAA,GAAO,CAAE,CAAC,CAAA;AACpE,MAAA,aAAA,CAAc,MAAM,EAAA,EAAI;AAAA,QACtB,SAAA,EAAW,KAAK,GAAA,EAAI;AAAA,QACpB,QAAA,EAAU,KAAA;AAAA,QACV,MAAA,EAAQ,mBAAA;AAAA,QACR,KAAA,EAAO,kBAAkB,EAAE,CAAA,CAAA;AAAA,QAC3B,IAAA,EAAM,MAAM,OAAA,CAAQ,UAAA,CAAW,CAAC,GAAA,KAAQ,GAAA,CAAI,GAAA,CAAI,CAAC,MAAO,CAAA,CAAE,EAAA,KAAO,EAAA,GAAK,IAAA,GAAO,CAAE,CAAC,CAAA;AAAA,QAChF,IAAA,EAAM,MAAM,OAAA,CAAQ,UAAA,CAAW,CAAC,GAAA,KAAQ,GAAA,CAAI,GAAA,CAAI,CAAC,MAAO,CAAA,CAAE,EAAA,KAAO,EAAA,GAAK,IAAA,GAAO,CAAE,CAAC;AAAA,OACjF,CAAA;AACD,MAAA,OAAO,UAAA,CAAW,CAAA,eAAA,EAAkB,EAAE,CAAA,CAAA,EAAI,IAAI,CAAA;AAAA,IAChD,CAAA;AAAA,IACA;AAAA,GACF;AAEA,EAAA,GAAA;AAAA,IACE,mBAAA;AAAA,IACA,wBAAA;AAAA,IACA,EAAE,EAAA,EAAI,EAAE,IAAA,EAAM,UAAS,EAAE;AAAA,IACzB,CAAC,IAAI,CAAA;AAAA,IACL,CAAC,IAAA,KAAS;AACR,MAAA,MAAM,EAAA,GAAK,GAAA,CAAI,IAAA,CAAK,EAAE,CAAA;AACtB,MAAA,MAAM,IAAA,GAAO,QAAQ,UAAA,EAAW,CAAE,KAAK,CAAC,CAAA,KAAM,CAAA,CAAE,EAAA,KAAO,EAAE,CAAA;AACzD,MAAA,IAAI,CAAC,IAAA,EAAM;AACT,QAAA,OAAO,WAAA,CAAY,CAAA,kBAAA,EAAqB,EAAE,CAAA,CAAE,CAAA;AAAA,MAC9C;AACA,MAAA,OAAA,CAAQ,UAAA,CAAW,CAAC,GAAA,KAAQ,GAAA,CAAI,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,EAAA,KAAO,EAAE,CAAC,CAAA;AAC1D,MAAA,aAAA,CAAc,MAAM,EAAA,EAAI;AAAA,QACtB,SAAA,EAAW,KAAK,GAAA,EAAI;AAAA,QACpB,QAAA,EAAU,KAAA;AAAA,QACV,MAAA,EAAQ,mBAAA;AAAA,QACR,KAAA,EAAO,kBAAkB,EAAE,CAAA,CAAA;AAAA,QAC3B,IAAA,EAAM,MAAM,OAAA,CAAQ,UAAA,CAAW,CAAC,QAAQ,CAAC,GAAG,GAAA,EAAK,IAAI,CAAC,CAAA;AAAA,QACtD,IAAA,EAAM,MAAM,OAAA,CAAQ,UAAA,CAAW,CAAC,GAAA,KAAQ,GAAA,CAAI,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,EAAA,KAAO,EAAE,CAAC;AAAA,OACvE,CAAA;AACD,MAAA,OAAO,UAAA,CAAW,CAAA,eAAA,EAAkB,EAAE,CAAA,CAAE,CAAA;AAAA,IAC1C,CAAA;AAAA,IACA;AAAA,GACF;AAEA,EAAA,GAAA;AAAA,IACE,YAAA;AAAA,IACA,gEAAA;AAAA,IACA,EAAE,EAAA,EAAI,EAAE,IAAA,EAAM,UAAS,EAAE;AAAA,IACzB,EAAC;AAAA,IACD,CAAC,IAAA,KAAS;AACR,MAAA,MAAM,IAAA,GAAO,QAAQ,WAAA,EAAY;AACjC,MAAA,MAAM,EAAA,GAAK,IAAA,CAAK,EAAA,KAAO,MAAA,IAAa,IAAA,CAAK,OAAO,IAAA,GAAO,IAAA,GAAO,GAAA,CAAI,IAAA,CAAK,EAAE,CAAA;AACzE,MAAA,IAAI,EAAA,KAAO,IAAA,IAAQ,CAAC,OAAA,CAAQ,UAAA,EAAW,CAAE,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,EAAA,KAAO,EAAE,CAAA,EAAG;AACjE,QAAA,OAAO,WAAA,CAAY,CAAA,kBAAA,EAAqB,EAAE,CAAA,CAAE,CAAA;AAAA,MAC9C;AACA,MAAA,OAAA,CAAQ,YAAY,EAAE,CAAA;AACtB,MAAA,aAAA,CAAc,MAAM,EAAA,EAAI;AAAA,QACtB,SAAA,EAAW,KAAK,GAAA,EAAI;AAAA,QACpB,QAAA,EAAU,KAAA;AAAA,QACV,MAAA,EAAQ,YAAA;AAAA,QACR,KAAA,EAAO,EAAA,GAAK,CAAA,SAAA,EAAY,EAAE,CAAA,CAAA,GAAK,mBAAA;AAAA,QAC/B,IAAA,EAAM,MAAM,OAAA,CAAQ,WAAA,CAAY,IAAI,CAAA;AAAA,QACpC,IAAA,EAAM,MAAM,OAAA,CAAQ,WAAA,CAAY,EAAE;AAAA,OACnC,CAAA;AACD,MAAA,OAAO,UAAA,CAAW,KAAK,CAAA,gBAAA,EAAmB,EAAE,KAAK,mBAAA,EAAqB,EAAE,UAAA,EAAY,EAAA,EAAI,CAAA;AAAA,IAC1F,CAAA;AAAA,IACA;AAAA,GACF;AAIA,EAAA,GAAA;AAAA,IACE,iBAAA;AAAA,IACA,+GAAA;AAAA,IACA,EAAE,EAAA,EAAI,EAAE,IAAA,EAAM,UAAS,EAAE;AAAA,IACzB,CAAC,IAAI,CAAA;AAAA,IACL,CAAC,IAAA,KAAS;AACR,MAAA,IAAI,CAAC,QAAQ,SAAA,EAAW;AACtB,QAAA,OAAO,YAAY,+DAA+D,CAAA;AAAA,MACpF;AACA,MAAA,MAAM,EAAA,GAAK,GAAA,CAAI,IAAA,CAAK,EAAE,CAAA;AACtB,MAAA,IAAI,CAAC,OAAA,CAAQ,UAAA,EAAW,CAAE,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,EAAA,KAAO,EAAE,CAAA,EAAG;AAClD,QAAA,OAAO,WAAA,CAAY,CAAA,kBAAA,EAAqB,EAAE,CAAA,CAAE,CAAA;AAAA,MAC9C;AACA,MAAA,OAAA,CAAQ,UAAU,EAAE,CAAA;AACpB,MAAA,OAAO,WAAW,CAAA,qBAAA,EAAwB,EAAE,IAAI,EAAE,MAAA,EAAQ,IAAI,CAAA;AAAA,IAChE,CAAA;AAAA,IACA;AAAA,GACF;AAEA,EAAA,GAAA;AAAA,IACE,gBAAA;AAAA,IACA,uFAAA;AAAA,IACA,EAAC;AAAA,IACD,EAAC;AAAA,IACD,MAAM;AACJ,MAAA,IAAI,CAAC,QAAQ,SAAA,EAAW;AACtB,QAAA,OAAO,YAAY,8BAA8B,CAAA;AAAA,MACnD;AACA,MAAA,OAAA,CAAQ,UAAU,IAAI,CAAA;AACtB,MAAA,OAAO,UAAA,CAAW,wCAAA,EAA0C,EAAE,MAAA,EAAQ,MAAM,CAAA;AAAA,IAC9E;AAAA,GACF;AAEA,EAAA,OAAO;AAAA,IACL,EAAA,EAAI,KAAA;AAAA,IACJ,KAAA,EAAO,KAAA;AAAA,IACP,SAAS,MAAM;AACb,MAAA,KAAA,MAAW,CAAA,IAAK,WAAW,CAAA,EAAE;AAAA,IAC/B;AAAA,GACF;AACF","file":"chunk-3UUF5KKZ.js","sourcesContent":["// Loose types so this bridge builds standalone without a hard dep on\n// @particle-academy/fancy-map. Hosts that use fancy-map pass its own\n// MapMarker / MapView values straight through — the shapes match.\ntype LatLng = { lat: number; lng: number };\ntype MapView = { center: LatLng; zoom: number; bearing?: number; pitch?: number };\ntype MapMarker = {\n id: string;\n position: LatLng;\n label?: string;\n color?: string;\n icon?: string;\n draggable?: boolean;\n data?: Record<string, unknown>;\n};\n\nimport { textResult, errorResult } from \"../mcp/server\";\nimport type { ToolHost } from \"../mcp/tool-host\";\nimport type { JsonObject } from \"../mcp/types\";\nimport type { Bridge } from \"./types\";\nimport { wrapToolWithActivity } from \"../presence/wrap-tool-with-activity\";\nimport type { AgentTarget as MapAgentTarget } from \"../presence/types\";\nimport { pushUndoEntry } from \"../undo/undo-stack\";\nimport { ensureUndoToolsRegistered } from \"../undo/undo-tools\";\n\n/**\n * Adapter the host provides — getters/setters over the SAME controlled state it\n * passes to fancy-map's `<Map>` (view, markers, selection), plus optional\n * `fitBounds` (from the map's onReady handle) and `setFollow` (drives the map's\n * `follow` prop so an agent can make the camera track a moving marker).\n */\nexport type MapBridgeAdapter = {\n getView: () => MapView;\n setView: (next: MapView) => void;\n getMarkers: () => MapMarker[];\n setMarkers: (next: MapMarker[] | ((prev: MapMarker[]) => MapMarker[])) => void;\n getSelected: () => string | null;\n setSelected: (id: string | null) => void;\n /** Fit the camera to points (wire to the `MapHandle.fitBounds` from `<Map onReady>`). */\n fitBounds?: (points: LatLng[], padding?: number) => void;\n /** Make the camera follow a marker as it moves (drives the map's `follow` prop). */\n setFollow?: (id: string | null) => void;\n};\n\nexport type MapBridgeOptions = {\n adapter: MapBridgeAdapter;\n /** Identity tagged onto agent-authored markers. */\n agent?: { id: string; name?: string; color?: string };\n};\n\nconst DEFAULT_AGENT = { id: \"agent\", name: \"Agent\", color: \"#a855f7\" };\n\nconst num = (v: unknown, fallback?: number): number =>\n typeof v === \"number\" && Number.isFinite(v) ? v : fallback ?? 0;\nconst str = (v: unknown, fallback = \"\"): string => (typeof v === \"string\" ? v : fallback);\nconst newId = (prefix: string) =>\n `${prefix}_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 7)}`;\n\n/**\n * registerMapBridge — an MCP tool set over a fancy-map `<Map>`'s controlled\n * state, so a human and an agent cohabit one map. The agent moves the camera,\n * drops/updates/removes markers, selects, fits bounds, and follows a live\n * track; every mutation broadcasts AgentActivity (for presence) and pushes an\n * undo entry (so the human can step the agent back). Mirrors the whiteboard /\n * flow bridges in shape.\n */\nexport function registerMapBridge(host: ToolHost, options: MapBridgeOptions): Bridge {\n const { adapter } = options;\n const agent = { ...DEFAULT_AGENT, ...(options.agent ?? {}) };\n const disposers: Array<() => void> = [];\n\n // Register agent_undo / agent_redo / agent_history once per host. Idempotent.\n ensureUndoToolsRegistered(host, { defaultAgentId: agent.id });\n\n const mTarget = (args: any, result: any): MapAgentTarget => ({\n kind: \"map\",\n elementId:\n (result?.structuredContent?.id as string | undefined) ?? (args?.id as string | undefined),\n });\n\n const reg = (\n name: string,\n description: string,\n properties: Record<string, unknown>,\n required: string[],\n handler: (args: JsonObject) => Promise<any> | any,\n resolveTarget?: (args: JsonObject, result: any) => MapAgentTarget | null,\n ) => {\n const wrapped = async (args: JsonObject) => {\n try {\n return await handler(args);\n } catch (e) {\n return errorResult(e instanceof Error ? e.message : String(e));\n }\n };\n const final = resolveTarget\n ? wrapToolWithActivity(wrapped, {\n toolName: name,\n agent: { id: agent.id, name: agent.name, color: agent.color },\n kind: \"map\",\n resolveTarget: ({ args, result }) => resolveTarget(args, result),\n })\n : wrapped;\n disposers.push(\n host.registerTool(\n {\n name,\n description,\n inputSchema: {\n type: \"object\",\n properties: properties as any,\n required,\n additionalProperties: false,\n },\n },\n final as any,\n ),\n );\n };\n\n // ───────────── Read ─────────────\n\n reg(\"map_get_state\", \"Get the map's camera, markers, and current selection.\", {}, [], () => {\n const state = {\n view: adapter.getView(),\n markers: adapter.getMarkers(),\n selectedId: adapter.getSelected(),\n };\n return textResult(JSON.stringify(state, null, 2), state);\n });\n\n // ───────────── Camera ─────────────\n\n reg(\n \"map_set_view\",\n \"Move the camera to an absolute position. Any omitted field is left unchanged.\",\n {\n lat: { type: \"number\", description: \"New center latitude.\" },\n lng: { type: \"number\", description: \"New center longitude.\" },\n zoom: { type: \"number\", description: \"New zoom level (higher = closer).\" },\n },\n [],\n (args) => {\n const prev = adapter.getView();\n const next: MapView = {\n center: {\n lat: args.lat !== undefined ? num(args.lat) : prev.center.lat,\n lng: args.lng !== undefined ? num(args.lng) : prev.center.lng,\n },\n zoom: args.zoom !== undefined ? num(args.zoom) : prev.zoom,\n };\n adapter.setView(next);\n pushUndoEntry(agent.id, {\n timestamp: Date.now(),\n bridgeId: \"map\",\n action: \"map_set_view\",\n label: `Moved camera to ${next.center.lat.toFixed(4)},${next.center.lng.toFixed(4)} z${next.zoom}`,\n undo: () => adapter.setView(prev),\n redo: () => adapter.setView(next),\n });\n return textResult(`Camera → ${next.center.lat.toFixed(4)},${next.center.lng.toFixed(4)} z${next.zoom}`, next);\n },\n mTarget,\n );\n\n reg(\n \"map_pan\",\n \"Pan the camera by a relative offset in degrees (positive dLat = north, positive dLng = east).\",\n { dLat: { type: \"number\" }, dLng: { type: \"number\" } },\n [],\n (args) => {\n const prev = adapter.getView();\n const next: MapView = {\n ...prev,\n center: { lat: prev.center.lat + num(args.dLat), lng: prev.center.lng + num(args.dLng) },\n };\n adapter.setView(next);\n pushUndoEntry(agent.id, {\n timestamp: Date.now(),\n bridgeId: \"map\",\n action: \"map_pan\",\n label: \"Panned camera\",\n undo: () => adapter.setView(prev),\n redo: () => adapter.setView(next),\n });\n return textResult(`Panned to ${next.center.lat.toFixed(4)},${next.center.lng.toFixed(4)}`, next);\n },\n mTarget,\n );\n\n reg(\n \"map_zoom\",\n \"Zoom the camera by a relative delta (e.g. +1 zooms in one level, -2 out two).\",\n { delta: { type: \"number\" } },\n [\"delta\"],\n (args) => {\n const prev = adapter.getView();\n const next: MapView = { ...prev, zoom: prev.zoom + num(args.delta) };\n adapter.setView(next);\n pushUndoEntry(agent.id, {\n timestamp: Date.now(),\n bridgeId: \"map\",\n action: \"map_zoom\",\n label: `Zoom → ${next.zoom}`,\n undo: () => adapter.setView(prev),\n redo: () => adapter.setView(next),\n });\n return textResult(`Zoom → ${next.zoom}`, next);\n },\n );\n\n reg(\n \"map_fit_bounds\",\n \"Fit the camera to enclose points. Pass `points`, or omit to fit all current markers.\",\n {\n points: {\n type: \"array\",\n description: \"Points to enclose, e.g. [{lat,lng},…].\",\n items: {\n type: \"object\",\n properties: { lat: { type: \"number\" }, lng: { type: \"number\" } },\n required: [\"lat\", \"lng\"],\n },\n },\n padding: { type: \"number\", description: \"Padding in pixels (default 40).\" },\n },\n [],\n (args) => {\n if (!adapter.fitBounds) {\n return errorResult(\"Host did not wire fitBounds (pass the <Map onReady> handle's fitBounds).\");\n }\n const points: LatLng[] = Array.isArray(args.points)\n ? (args.points as any[]).map((p) => ({ lat: num(p?.lat), lng: num(p?.lng) }))\n : adapter.getMarkers().map((m) => m.position);\n if (!points.length) {\n return errorResult(\"No points to fit (map has no markers).\");\n }\n adapter.fitBounds(points, args.padding !== undefined ? num(args.padding) : undefined);\n return textResult(`Fit camera to ${points.length} point(s).`);\n },\n );\n\n // ───────────── Markers ─────────────\n\n reg(\n \"map_add_marker\",\n \"Drop a marker. `id` is optional (auto-generated); `icon` is an emoji or 1–2 chars.\",\n {\n id: { type: \"string\" },\n lat: { type: \"number\" },\n lng: { type: \"number\" },\n label: { type: \"string\" },\n color: { type: \"string\", description: \"CSS color, e.g. #2563eb.\" },\n icon: { type: \"string\", description: \"Emoji / short text in the pin.\" },\n draggable: { type: \"boolean\" },\n data: { type: \"object\", description: \"Arbitrary JSON payload carried with the marker.\" },\n },\n [\"lat\", \"lng\"],\n (args) => {\n const id = args.id ? str(args.id) : newId(\"m\");\n if (adapter.getMarkers().some((m) => m.id === id)) {\n return errorResult(`A marker with id ${id} already exists — use map_update_marker.`);\n }\n const marker: MapMarker = {\n id,\n position: { lat: num(args.lat), lng: num(args.lng) },\n ...(args.label !== undefined ? { label: str(args.label) } : {}),\n ...(args.color !== undefined ? { color: str(args.color) } : {}),\n ...(args.icon !== undefined ? { icon: str(args.icon) } : {}),\n ...(args.draggable !== undefined ? { draggable: !!args.draggable } : {}),\n ...(args.data && typeof args.data === \"object\"\n ? { data: args.data as Record<string, unknown> }\n : {}),\n };\n adapter.setMarkers((all) => [...all, marker]);\n pushUndoEntry(agent.id, {\n timestamp: Date.now(),\n bridgeId: \"map\",\n action: \"map_add_marker\",\n label: `Added marker ${id}`,\n undo: () => adapter.setMarkers((all) => all.filter((m) => m.id !== id)),\n redo: () => adapter.setMarkers((all) => [...all, marker]),\n });\n return textResult(`Added marker ${id} at ${marker.position.lat.toFixed(4)},${marker.position.lng.toFixed(4)}`, marker);\n },\n mTarget,\n );\n\n reg(\n \"map_update_marker\",\n \"Update a marker. Only provided fields change — update lat/lng repeatedly to drive a live track.\",\n {\n id: { type: \"string\" },\n lat: { type: \"number\" },\n lng: { type: \"number\" },\n label: { type: \"string\" },\n color: { type: \"string\" },\n icon: { type: \"string\" },\n draggable: { type: \"boolean\" },\n },\n [\"id\"],\n (args) => {\n const id = str(args.id);\n const prev = adapter.getMarkers().find((m) => m.id === id);\n if (!prev) {\n return errorResult(`No marker with id ${id}`);\n }\n const next: MapMarker = {\n ...prev,\n position: {\n lat: args.lat !== undefined ? num(args.lat) : prev.position.lat,\n lng: args.lng !== undefined ? num(args.lng) : prev.position.lng,\n },\n ...(args.label !== undefined ? { label: str(args.label) } : {}),\n ...(args.color !== undefined ? { color: str(args.color) } : {}),\n ...(args.icon !== undefined ? { icon: str(args.icon) } : {}),\n ...(args.draggable !== undefined ? { draggable: !!args.draggable } : {}),\n };\n adapter.setMarkers((all) => all.map((m) => (m.id === id ? next : m)));\n pushUndoEntry(agent.id, {\n timestamp: Date.now(),\n bridgeId: \"map\",\n action: \"map_update_marker\",\n label: `Updated marker ${id}`,\n undo: () => adapter.setMarkers((all) => all.map((m) => (m.id === id ? prev : m))),\n redo: () => adapter.setMarkers((all) => all.map((m) => (m.id === id ? next : m))),\n });\n return textResult(`Updated marker ${id}`, next);\n },\n mTarget,\n );\n\n reg(\n \"map_remove_marker\",\n \"Remove a marker by id.\",\n { id: { type: \"string\" } },\n [\"id\"],\n (args) => {\n const id = str(args.id);\n const prev = adapter.getMarkers().find((m) => m.id === id);\n if (!prev) {\n return errorResult(`No marker with id ${id}`);\n }\n adapter.setMarkers((all) => all.filter((m) => m.id !== id));\n pushUndoEntry(agent.id, {\n timestamp: Date.now(),\n bridgeId: \"map\",\n action: \"map_remove_marker\",\n label: `Removed marker ${id}`,\n undo: () => adapter.setMarkers((all) => [...all, prev]),\n redo: () => adapter.setMarkers((all) => all.filter((m) => m.id !== id)),\n });\n return textResult(`Removed marker ${id}`);\n },\n mTarget,\n );\n\n reg(\n \"map_select\",\n \"Select a marker (or pass no id / null to clear the selection).\",\n { id: { type: \"string\" } },\n [],\n (args) => {\n const prev = adapter.getSelected();\n const id = args.id === undefined || args.id === null ? null : str(args.id);\n if (id !== null && !adapter.getMarkers().some((m) => m.id === id)) {\n return errorResult(`No marker with id ${id}`);\n }\n adapter.setSelected(id);\n pushUndoEntry(agent.id, {\n timestamp: Date.now(),\n bridgeId: \"map\",\n action: \"map_select\",\n label: id ? `Selected ${id}` : \"Cleared selection\",\n undo: () => adapter.setSelected(prev),\n redo: () => adapter.setSelected(id),\n });\n return textResult(id ? `Selected marker ${id}` : \"Cleared selection\", { selectedId: id });\n },\n mTarget,\n );\n\n // ───────────── Live tracking (camera follow) ─────────────\n\n reg(\n \"map_start_track\",\n \"Make the camera follow a marker as its position updates (live tracking). Requires the host to wire setFollow.\",\n { id: { type: \"string\" } },\n [\"id\"],\n (args) => {\n if (!adapter.setFollow) {\n return errorResult(\"Host did not wire setFollow (pass the map's `follow` setter).\");\n }\n const id = str(args.id);\n if (!adapter.getMarkers().some((m) => m.id === id)) {\n return errorResult(`No marker with id ${id}`);\n }\n adapter.setFollow(id);\n return textResult(`Camera now following ${id}`, { follow: id });\n },\n mTarget,\n );\n\n reg(\n \"map_stop_track\",\n \"Stop following any marker (releases the camera). Requires the host to wire setFollow.\",\n {},\n [],\n () => {\n if (!adapter.setFollow) {\n return errorResult(\"Host did not wire setFollow.\");\n }\n adapter.setFollow(null);\n return textResult(\"Camera released (no longer following).\", { follow: null });\n },\n );\n\n return {\n id: \"map\",\n title: \"Map\",\n dispose: () => {\n for (const d of disposers) d();\n },\n };\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/bridges/passkeys.ts"],"names":[],"mappings":"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","file":"chunk-4WVLZ6YP.js","sourcesContent":["import { textResult, errorResult } from \"../mcp/server\";\nimport type { ToolHost } from \"../mcp/tool-host\";\nimport type { JsonObject } from \"../mcp/types\";\nimport type { Bridge } from \"./types\";\nimport { wrapToolWithActivity } from \"../presence/wrap-tool-with-activity\";\nimport type { AgentTarget } from \"../presence/types\";\nimport { pushUndoEntry } from \"../undo/undo-stack\";\nimport { ensureUndoToolsRegistered } from \"../undo/undo-tools\";\n\n/**\n * Bridge for `@particle-academy/fancy-passkeys-ui` — the **management** half of\n * a passkey (WebAuthn) surface, and only that half.\n *\n * ## The absence is the design\n *\n * There is **no tool here that completes an authentication or registration\n * ceremony**, and there must never be one. Not `passkey_authenticate`, not\n * `passkey_sign_in`, not `passkey_complete`, not a \"headless\" variant behind a\n * flag.\n *\n * The reason is construction, not policy. `navigator.credentials.get()` requires\n * a user gesture and a biometric or PIN — both things only the person at the\n * keyboard has. An agent-drivable passkey login would be a bypass of the exact\n * property that makes a passkey worth more than a password: that possession of\n * the credential cannot be delegated, replayed, or phished. A bridge offering\n * one would quietly turn a phishing-resistant factor back into a bearer token.\n *\n * So the boundary sits where the cryptography already puts it, and the tool set\n * is drawn to match: **read the management surface, rename, propose, ask the\n * human to start a ceremony.** `bridges/__tests__/passkeys.test.ts` asserts the\n * registered tool names against a closed list, so \"finishing\" this bridge with a\n * sign-in tool fails CI rather than shipping.\n *\n * ## What it does do\n *\n * passkey_list the user's credentials (whitelisted fields only)\n * passkey_status browser support + what the surface currently shows\n * passkey_rename relabel one credential, by credential ID (undoable)\n * passkey_revoke **STAGES** a revoke for the human to confirm\n * passkey_begin_enrollment opens the enrollment prompt; returns immediately\n *\n * `passkey_revoke` never revokes. Revoking a passkey is destructive and revoking\n * the last one is a lockout, so the confirming click comes from the human at the\n * surface — there is deliberately **no `pendingMode: false`**, no `confirm: true`\n * argument, and no host hook that turns staging off. On this bridge staging is\n * not a mode.\n *\n * The adapter type is declared LOCALLY (like `features` / `catalog`) so the\n * bridge builds and type-checks with the sibling package absent. A host wiring a\n * live `PasskeyManager` satisfies it structurally, with no import.\n */\n\n/**\n * One credential as the bridge is willing to describe it — the `PasskeySummary`\n * shape both passkey backends already serialise.\n *\n * Everything the server stores that is NOT on this list — the COSE public key,\n * the user handle, the signature counter, the attestation statement and trust\n * path — is absent on purpose, and {@link toSummary} re-projects onto exactly\n * these keys rather than trusting the adapter to have withheld them. A host that\n * hands `list()` its raw ORM model (the obvious thing to do) therefore cannot\n * leak credential material through an MCP tool by accident.\n */\nexport type PasskeySummaryLike = {\n /** base64url credential ID — the handle every action here is keyed by. */\n id: string;\n /** Human-chosen label, or null when the user never named it. */\n name: string | null;\n /** ISO-8601. */\n createdAt: string;\n /** ISO-8601, or null when never used to sign in. */\n lastUsedAt: string | null;\n /** Transport hints (\"internal\", \"hybrid\", \"usb\", …). */\n transports: string[];\n /** True for a synced passkey (BE/BS flags); false means this device only. */\n backedUp: boolean;\n /** Authenticator model id. Stored, never a trust decision. */\n aaguid: string;\n /** ISO-8601 when the signature counter regressed — a suspected clone. */\n clonedAt: string | null;\n};\n\n/** What the browser can do, as the three `./client` predicates report it. */\nexport type PasskeySupport = {\n supported: boolean;\n /** Touch ID / Windows Hello present? `null` while unknown. */\n platformAuthenticator?: boolean | null;\n /** Can the browser offer a passkey from a username field? `null` while unknown. */\n conditionalUi?: boolean | null;\n};\n\n/** A read of what the management surface is currently showing. */\nexport type PasskeySurfaceState = {\n status?: \"idle\" | \"busy\" | \"error\";\n /** `{ code, message }` as carried in surface state — never an Error. */\n error?: { code: string; message: string } | null;\n /** The revoke awaiting a human's confirmation, if any. */\n pendingRevoke?: { id: string; isLastPasskey: boolean } | null;\n /** Credential ID currently being renamed, if any. */\n renamingId?: string | null;\n};\n\n/**\n * Host-provided access to the management surface. Mirrors the props a\n * `PasskeyManager` is already wired with, so a host usually passes the same four\n * callbacks it passed the component.\n */\nexport type PasskeyBridgeAdapter = {\n /** Stable id for this surface instance. Surfaces in activity logs. */\n id?: string;\n title?: string;\n screenId?: string;\n\n /** The signed-in user's credentials. */\n list(): PasskeySummaryLike[] | Promise<PasskeySummaryLike[]>;\n\n /** Relabel one credential. Cosmetic, reversible, and undoable here. */\n rename(input: { id: string; name: string }): void | Promise<void>;\n\n /**\n * **Stage** a revoke for human confirmation — the `pendingRevoke` the surface\n * renders a confirm/cancel dialog for. It must NOT revoke; a host that wires\n * this to a delete call has removed the human from the loop the bridge was\n * built around.\n */\n proposeRevoke(input: { id: string }): PasskeyProposal | Promise<PasskeyProposal>;\n\n /**\n * Open the enrollment prompt on the human's screen and return immediately.\n * The ceremony completes on their authenticator or not at all.\n */\n beginEnrollment?(input: { name?: string }): void | Promise<void>;\n\n /** Browser capability flags, if the host tracks them. */\n support?(): PasskeySupport | Promise<PasskeySupport>;\n\n /** What the surface currently shows. */\n state?(): PasskeySurfaceState | Promise<PasskeySurfaceState>;\n};\n\nexport type PasskeyProposal = { staged: true; isLastPasskey: boolean };\n\nexport type PasskeyBridgeOptions = {\n adapter: PasskeyBridgeAdapter;\n agent?: { id: string; name?: string; color?: string };\n /**\n * Also route `passkey_rename` through {@link confirm}. Off by default: a\n * rename is cosmetic, reversible and pushed onto the undo stack. Worth turning\n * on where the label itself carries trust — a rogue credential relabelled\n * \"Avery's iPhone\" survives a human's audit of the list.\n */\n confirmRename?: boolean;\n /**\n * Host confirmation hook for renames, when {@link confirmRename} is on.\n *\n * Note there is no revoke case: a revoke is staged into the surface and\n * confirmed there, never through a hook the agent's own host supplies.\n */\n confirm?: (req: { action: \"passkey_rename\"; id: string; name: string }) => boolean | Promise<boolean>;\n};\n\nconst DEFAULT_AGENT = { id: \"agent\", name: \"Agent\", color: \"#a855f7\" };\n\nconst str = (v: unknown, fallback = \"\"): string => (typeof v === \"string\" ? v : fallback);\n\n/**\n * Project an adapter record onto exactly the public summary fields.\n *\n * Deliberately a whitelist and not a `delete` of known-bad keys: a blacklist has\n * to be updated every time a backend grows a column, and the failure mode of\n * forgetting is silently publishing credential material to every agent in the\n * session.\n */\nfunction toSummary(record: PasskeySummaryLike): PasskeySummaryLike {\n return {\n id: str(record?.id),\n name: typeof record?.name === \"string\" ? record.name : null,\n createdAt: str(record?.createdAt),\n lastUsedAt: typeof record?.lastUsedAt === \"string\" ? record.lastUsedAt : null,\n transports: Array.isArray(record?.transports) ? record.transports.map((t) => String(t)) : [],\n backedUp: record?.backedUp === true,\n aaguid: str(record?.aaguid),\n clonedAt: typeof record?.clonedAt === \"string\" ? record.clonedAt : null,\n };\n}\n\n/**\n * The complete set of tools this bridge may ever register.\n *\n * Exported so the test suite — and anyone auditing what an agent can reach —\n * can assert the registered names against it rather than eyeballing the file.\n */\nexport const PASSKEY_BRIDGE_TOOLS = [\n \"passkey_list\",\n \"passkey_status\",\n \"passkey_rename\",\n \"passkey_revoke\",\n \"passkey_begin_enrollment\",\n] as const;\n\n/**\n * registerPasskeyBridge — MCP tools over a passkey **management** surface.\n *\n * Read the credential list, read browser support and surface state, rename a\n * credential, propose a revoke for the human to confirm, and ask for an\n * enrollment prompt. Nothing signs anyone in; see the file header for why that\n * is a property rather than a gap.\n */\nexport function registerPasskeyBridge(host: ToolHost, options: PasskeyBridgeOptions): Bridge {\n const { adapter } = options;\n const agent = { ...DEFAULT_AGENT, ...(options.agent ?? {}) };\n const surfaceId = adapter.id ?? \"passkeys\";\n const disposers: Array<() => void> = [];\n\n ensureUndoToolsRegistered(host, { defaultAgentId: agent.id });\n\n const target = (elementId?: string, label?: string): AgentTarget => ({\n kind: \"custom\",\n screenId: adapter.screenId,\n elementId,\n label: label ?? surfaceId,\n });\n\n const reg = (\n name: string,\n description: string,\n properties: Record<string, unknown>,\n required: string[],\n handler: (args: JsonObject) => Promise<unknown> | unknown,\n resolveTarget: false | ((args: JsonObject) => AgentTarget),\n ) => {\n const wrapped = async (args: JsonObject) => {\n try {\n return await handler(args);\n } catch (e) {\n return errorResult(e instanceof Error ? e.message : String(e));\n }\n };\n const final = resolveTarget\n ? wrapToolWithActivity(wrapped as never, {\n toolName: name,\n agent,\n kind: \"custom\",\n screenId: adapter.screenId,\n resolveTarget: ({ args }) => resolveTarget(args as JsonObject),\n })\n : wrapped;\n disposers.push(\n host.registerTool(\n {\n name,\n description,\n inputSchema: {\n type: \"object\",\n properties: properties as Record<string, never>,\n required,\n additionalProperties: false,\n },\n },\n final as never,\n ),\n );\n };\n\n const findById = async (id: string): Promise<PasskeySummaryLike | null> =>\n (await adapter.list()).map(toSummary).find((p) => p.id === id) ?? null;\n\n // ─── Read ────────────────────────────────────────────────────────────────\n\n reg(\n \"passkey_list\",\n \"List the signed-in user's passkeys: credential id, label, when it was added and last used, transports, whether it is a synced passkey, and whether the server flagged it as a possible clone. Read-only. Public keys, user handles and signature counters are never returned.\",\n {},\n [],\n async () => {\n const passkeys = (await adapter.list()).map(toSummary);\n return textResult(JSON.stringify(passkeys, null, 2), { passkeys, count: passkeys.length });\n },\n false,\n );\n\n reg(\n \"passkey_status\",\n \"Read what this browser can do (passkey support, a built-in authenticator, autofill sign-in) and what the management surface is currently showing (busy/error, a revoke awaiting confirmation, a rename in progress).\",\n {},\n [],\n async () => {\n const support = adapter.support ? await adapter.support() : null;\n const state = adapter.state ? await adapter.state() : null;\n const out = {\n support,\n state,\n // Said in the payload, not only in the docs: an agent reading this to\n // work out \"how do I sign the user in\" should find the answer here.\n canCompleteCeremony: false,\n note: \"A passkey ceremony needs a user gesture and a biometric or PIN. No tool on this bridge can perform one; ask the human to complete it on their device.\",\n };\n return textResult(JSON.stringify(out, null, 2), out);\n },\n false,\n );\n\n // ─── Rename (undoable) ───────────────────────────────────────────────────\n\n reg(\n \"passkey_rename\",\n \"Rename one passkey, by credential id (from passkey_list). Cosmetic and undoable with agent_undo.\",\n {\n id: { type: \"string\", description: \"base64url credential id.\" },\n name: { type: \"string\", description: \"New label, e.g. 'MacBook Touch ID'. Empty string clears it.\" },\n },\n [\"id\", \"name\"],\n async (args) => {\n const id = str(args.id);\n const name = str(args.name);\n if (!id) return errorResult(\"id is required.\");\n\n const existing = await findById(id);\n if (!existing) return errorResult(`No passkey with id ${id}.`);\n\n if (options.confirmRename) {\n if (!options.confirm) {\n return errorResult(\n \"passkey_rename requires confirmation (confirmRename), but the host wired no confirm hook.\",\n );\n }\n const ok = await options.confirm({ action: \"passkey_rename\", id, name });\n if (!ok) return errorResult(`Declined: rename ${id} (human did not confirm).`);\n }\n\n const previous = existing.name ?? \"\";\n await adapter.rename({ id, name });\n pushUndoEntry(agent.id, {\n timestamp: Date.now(),\n bridgeId: surfaceId,\n action: \"passkey_rename\",\n label: `Renamed passkey to ${name || \"(unnamed)\"}`,\n undo: async () => { await adapter.rename({ id, name: previous }); },\n redo: async () => { await adapter.rename({ id, name }); },\n });\n\n return textResult(`Renamed passkey ${id} to ${name || \"(unnamed)\"}`, { id, name, previous });\n },\n (args) => target(str(args.id), `rename ${str(args.id)}`),\n );\n\n // ─── Revoke — PROPOSAL ONLY ──────────────────────────────────────────────\n\n reg(\n \"passkey_revoke\",\n \"PROPOSE revoking one passkey. This does NOT revoke it: the request is staged on the surface and the human confirms or cancels there. Revoking the last passkey can lock the user out, and the response says when that is the case so you can tell them before they confirm.\",\n { id: { type: \"string\", description: \"base64url credential id.\" } },\n [\"id\"],\n async (args) => {\n const id = str(args.id);\n if (!id) return errorResult(\"id is required.\");\n\n const existing = await findById(id);\n if (!existing) return errorResult(`No passkey with id ${id}.`);\n\n const proposal = await adapter.proposeRevoke({ id });\n const isLastPasskey = proposal?.isLastPasskey === true;\n const out = {\n id,\n name: existing.name,\n staged: true as const,\n awaitingHuman: true as const,\n isLastPasskey,\n };\n\n return textResult(\n isLastPasskey\n ? `Staged a revoke of ${existing.name ?? id}. This is the account's LAST passkey — confirming it removes passkey sign-in entirely. Waiting for the human to confirm or cancel.`\n : `Staged a revoke of ${existing.name ?? id}. Waiting for the human to confirm or cancel on the surface.`,\n out,\n );\n },\n (args) => target(str(args.id), `propose revoke ${str(args.id)}`),\n );\n\n // ─── Enrollment — opens the prompt, never completes it ───────────────────\n\n reg(\n \"passkey_begin_enrollment\",\n \"Ask the surface to start enrolling a new passkey. This only opens the prompt: the ceremony completes on the human's authenticator (Touch ID, Windows Hello, phone, security key) or it does not complete at all. Returns immediately.\",\n { name: { type: \"string\", description: \"Optional label to pre-fill for the new passkey.\" } },\n [],\n async (args) => {\n if (!adapter.beginEnrollment) return errorResult(\"Host did not wire beginEnrollment().\");\n const name = args.name === undefined ? undefined : str(args.name);\n await adapter.beginEnrollment(name === undefined ? {} : { name });\n const out = { awaitingHuman: true as const, ...(name === undefined ? {} : { name }) };\n return textResult(\n \"Enrollment prompt opened. The human has to complete it on their authenticator — there is no tool that can finish it for them.\",\n out,\n );\n },\n (args) => target(undefined, `begin enrollment${args.name ? ` (${str(args.name)})` : \"\"}`),\n );\n\n // ── There is deliberately NO tool below that completes a ceremony. ────────\n // No passkey_authenticate, no passkey_sign_in, no passkey_complete, no\n // passkey_assert. Do not \"finish\" this bridge by adding one — see the header,\n // and see the closed-tool-list test that will fail if you do.\n\n return {\n id: `passkeys:${surfaceId}`,\n title: adapter.title ?? \"Passkeys\",\n dispose: () => {\n for (const d of disposers.splice(0)) d();\n },\n };\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/bridges/screen-doc.ts"],"names":[],"mappings":"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","file":"chunk-5JLTXHX6.js","sourcesContent":["/**\n * registerScreenDocBridge — an agent bridge over the CONTENT of one rendered\n * `<Screen doc={…}>` (fancy-screens ≥ 0.6), built on {@link registerDocBridge}.\n *\n * This is the other half of {@link registerScreensBridge}, and the halves are\n * not interchangeable. That one moves *between* screens and creates them from\n * host templates, treating a screen's contents as an opaque `config` blob. This\n * one addresses the nodes *inside* one screen: read them, patch a prop, retext a\n * label, reparent a card.\n *\n * Until fancy-screens 0.6 there was no way to do that at all — `ScreenSchema`\n * nodes had no `id`, so an agent could emit a whole surface and then not touch\n * anything in it. That was a standing violation of the component contract's\n * stable-handles requirement, on the one shipped \"agent emits a UI\" path.\n *\n * A screen document is a plain `DocTree`, so the generic bridge supplies\n * describe/get/list/get_node + add/update/remove/move + undo + agent activity +\n * staged writes for free. What this layer adds is everything that is specific to\n * a screen being a rendered React tree:\n *\n * - **Synthetic ids are reported as such.** fancy-screens mints a position-derived\n * id for any node the author left anonymous. It looks like a handle and is not\n * one: insert a sibling above it and it points at a different node, silently.\n * Every read here says which kind of id it handed back, and `screen_addressable`\n * lists only the durable ones.\n * - **Literal text is a node**, not a prop, so that a string and an element can be\n * siblings without losing their order. `screen_set_text` hides that from the\n * agent, which otherwise has to know the reserved `#text` type to change a label.\n *\n * No dependency on fancy-screens — the contract is the `DocTree`, mirroring how\n * `bridges/screens.ts` keeps its own snapshot types loose.\n */\nimport { textResult } from \"../mcp/server\";\nimport type { ToolHost } from \"../mcp/tool-host\";\nimport type { Bridge } from \"./types\";\nimport { registerDocBridge, type DocAdapter, type DocOpTool } from \"./doc\";\nexport type { DocAdapter } from \"./doc\";\nimport {\n childrenOf,\n appendOrder,\n type DocNode,\n type StagePolicy,\n type TreeOp,\n} from \"@particle-academy/fancy-doc-commons\";\n\n/**\n * Reserved node type for a literal string child. Must match fancy-screens'\n * `TEXT_NODE_TYPE`; duplicated rather than imported to keep this bridge free of\n * a fancy-screens dependency.\n */\nexport const SCREEN_TEXT_NODE_TYPE = \"#text\";\n\n/** A screen document node — a `DocNode` plus the minted-id flag. */\nexport interface ScreenDocNode extends DocNode {\n /**\n * True when fancy-screens minted this id because the author supplied none.\n * A synthetic id is derived from position, so it is not a durable handle.\n */\n synthetic?: boolean;\n}\n\nexport type ScreenDocOp = TreeOp<ScreenDocNode>;\n\nexport interface ScreenDocBridgeOptions {\n adapter: DocAdapter<ScreenDocNode>;\n /**\n * Tool-name prefix. Default `\"screen\"` → `screen_add`, `screen_set_text`, …\n *\n * Tool names are global, so a host wiring more than one doc-driven screen at\n * once must give each a distinct prefix (`\"screen_checkout\"`).\n */\n surface?: string;\n agent?: { id: string; name?: string; color?: string };\n /** Auto-apply vs. confirm per op (trust-but-verify). Default: auto. */\n stagePolicy?: StagePolicy<ScreenDocOp>;\n onPending?: (staged: { id: string; op: ScreenDocOp; label: string }) => void;\n}\n\n/** Register the screen-content bridge (prefix `screen_`) over a screen's `DocTree`. */\nexport function registerScreenDocBridge(host: ToolHost, options: ScreenDocBridgeOptions): Bridge {\n const { adapter } = options;\n const surface = options.surface ?? \"screen\";\n\n const setText: DocOpTool<ScreenDocNode, ScreenDocOp> = {\n verb: \"set_text\",\n description:\n \"Replace the literal text of an element node — the natural way to change a label, heading or paragraph. Pass the ELEMENT's id, not the text node's.\",\n properties: {\n id: { type: \"string\", description: \"Id of the element whose text to set.\" },\n text: { type: \"string\" },\n },\n required: [\"id\", \"text\"],\n build: (args, tree) => {\n const id = String(args.id);\n const node = tree.nodes[id];\n if (!node) return { error: `No node ${id}` };\n if (node.type === SCREEN_TEXT_NODE_TYPE) {\n return { t: \"set_props\", id, patch: { value: String(args.text) } };\n }\n\n const texts = childrenOf(tree, id).filter((c) => c.type === SCREEN_TEXT_NODE_TYPE);\n if (texts.length === 1) {\n return { t: \"set_props\", id: texts[0]!.id, patch: { value: String(args.text) } };\n }\n if (texts.length === 0) {\n // Nothing to retext, so give it text. The minted child is addressable in\n // its own right, which is what makes the follow-up edit possible.\n return {\n t: \"insert\",\n node: {\n id: `${id}-text`,\n type: SCREEN_TEXT_NODE_TYPE,\n parent: id,\n order: appendOrder(tree, id),\n props: { value: String(args.text) },\n },\n };\n }\n // Ambiguous on purpose: picking one would look like it worked.\n return {\n error: `Node ${id} has ${texts.length} text children (${texts.map((t) => t.id).join(\", \")}) — set_text on the one you mean`,\n };\n },\n targetId: (args) => String(args.id),\n };\n\n const bridge = registerDocBridge<ScreenDocNode, ScreenDocOp>(host, {\n adapter,\n surface,\n agent: options.agent,\n stagePolicy: options.stagePolicy,\n onPending: options.onPending,\n // Anything the AGENT adds is authored by definition — it chose or was given\n // the id — so it must not inherit the synthetic flag from its neighbours.\n makeNode: ({ id, type, parent, order }, props) => ({ id, type, parent, order, props }),\n describeNode: (n) => ({\n id: n.id,\n type: n.type,\n parent: n.parent,\n ...(n.synthetic ? { synthetic: true } : {}),\n ...(n.type === SCREEN_TEXT_NODE_TYPE ? { text: String(n.props?.value ?? \"\") } : { props: Object.keys(n.props ?? {}) }),\n }),\n opTools: [setText],\n });\n\n // A read tool, so it lives here rather than in `opTools` (which are mutations).\n const disposeAddressable = host.registerTool(\n {\n name: `${surface}_addressable`,\n description:\n \"List the node ids that are safe to remember and use later. Ids NOT listed here were minted from a node's position: they resolve today and silently point at a different node once a sibling is inserted above them. Address those in the same turn you read them, and never store one.\",\n inputSchema: { type: \"object\", properties: {} as never, required: [], additionalProperties: false },\n },\n (async () => {\n const nodes = Object.values(adapter.get().nodes);\n const authored = nodes.filter((n) => !n.synthetic).map((n) => ({ id: n.id, type: n.type }));\n const syntheticCount = nodes.length - authored.length;\n\n return textResult(\n authored.length\n ? `${authored.length} addressable, ${syntheticCount} positional`\n : `no addressable ids — all ${syntheticCount} nodes are positional`,\n { addressable: authored, syntheticCount },\n );\n }) as never,\n );\n\n return {\n id: surface,\n title: \"Screen content\",\n dispose: () => {\n disposeAddressable();\n bridge.dispose();\n },\n };\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/bridges/features.ts"],"names":[],"mappings":"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","file":"chunk-5M5ELTHE.js","sourcesContent":["import { textResult, errorResult } from \"../mcp/server\";\nimport type { ToolHost } from \"../mcp/tool-host\";\nimport type { JsonObject } from \"../mcp/types\";\nimport type { Bridge } from \"./types\";\nimport { wrapToolWithActivity } from \"../presence/wrap-tool-with-activity\";\nimport type { AgentTarget } from \"../presence/types\";\nimport { pushUndoEntry } from \"../undo/undo-stack\";\nimport { ensureUndoToolsRegistered } from \"../undo/undo-tools\";\n\n/**\n * Headless bridge for `@particle-academy/fancy-features` — feature management\n * with NO UI surface. The adapter is the `FeatureManager` (a `FeatureSource`\n * consumer): define features in the registry, check access for a subject,\n * grant/revoke via group assignment, and meter resource usage. Mutations\n * funnel through `wrapToolWithActivity` so presence + undo compose; `grant` /\n * `revoke` are `pendingMode`-gated (they change what a real user can do).\n *\n * The adapter shapes mirror fancy-features' public `FeatureManager` +\n * `FeatureRegistry` + `GroupStore`, defined LOCALLY so the bridge builds with\n * the sibling absent (optional peer). A live `FeatureManager` (plus its\n * `.registry` / `.groupStore`) satisfies this structurally with no import.\n *\n * SUBJECTS over the wire: `Subject` is opaque (`unknown`) in fancy-features.\n * Agents pass a JSON-serializable subject (string id or `{ id, … }` object);\n * the host's stores key on it via their `defaultSubjectKey`.\n */\n\nexport type FeatureGrant = {\n key: string;\n type: \"boolean\" | \"resource\";\n enabled: boolean;\n includedQuantity?: number | null;\n overageLimit?: number | null;\n source?: string;\n config?: Record<string, unknown>;\n};\n\n/** Normalized feature definition (mirror of fancy-features `FeatureDefinition`). */\nexport type FeatureDefinition = {\n key?: string;\n name?: string;\n description?: string;\n type?: \"boolean\" | \"resource\";\n enabled?: boolean;\n limit?: number;\n [k: string]: unknown;\n};\n\n/**\n * Adapter = the `FeatureManager` + its registry + group store. The bridge only\n * needs these members; a real manager exposes them directly.\n */\nexport type FeaturesBridgeAdapter = {\n /** Stable id for this feature manager instance. */\n id?: string;\n title?: string;\n screenId?: string;\n\n // ── Access checks (FeatureManager) ──\n /** Can the subject access the feature now? `manager.canAccess`. */\n canAccess(feature: string, subject?: unknown, context?: unknown): boolean | Promise<boolean>;\n /** Remaining quota for a resource feature (null = unlimited / n-a). `manager.remaining`. */\n remaining(feature: string, subject?: unknown, context?: unknown): number | null | Promise<number | null>;\n /** All enabled feature keys for the subject. `manager.enabled`. */\n enabled(subject?: unknown, context?: unknown): string[] | Promise<string[]>;\n /** Trace a feature's resolution to an AccessResult. `manager.explain`. */\n explain?(feature: string, subject?: unknown, context?: unknown): Promise<unknown> | unknown;\n\n // ── Registry (define) ──\n /** Register a programmatic feature. `manager.registerFeature` / `manager.registry.register`. */\n registerFeature(key: string, definition: FeatureDefinition): void;\n /** Registered feature keys. `manager.registry.keys`. */\n registryKeys(): string[];\n /** Resolve a registered definition (or null). `manager.registry.definition`. */\n definition?(key: string): FeatureDefinition | null | Promise<FeatureDefinition | null>;\n\n // ── Group store (grant / revoke) ──\n /** Assign a subject to a feature group (the grant primitive). `manager.groupStore.assign`. */\n assignGroup(subject: unknown, groupKey: string): void | Promise<void>;\n /** Detach a subject from a group (the revoke primitive). `manager.groupStore.detach`. */\n detachGroup(subject: unknown, groupKey: string): void | Promise<void>;\n /** Group keys assigned to a subject. `manager.groupStore.list`. */\n listGroups(subject: unknown): string[] | Promise<string[]>;\n\n // ── Usage / metering (resource features) ──\n /** Current usage for a resource feature. `manager.usageFor`. Optional. */\n usageFor?(feature: string, subject: unknown): number | Promise<number>;\n /** Atomic check-and-increment quota. `manager.tryConsume`. Optional. */\n tryConsume?(feature: string, subject: unknown, amount?: number, context?: unknown): boolean | Promise<boolean>;\n};\n\nexport type FeaturesBridgeOptions = {\n adapter: FeaturesBridgeAdapter;\n agent?: { id: string; name?: string; color?: string };\n /**\n * Trust-but-verify. When on (default), `features_grant` / `features_revoke`\n * (they change a real subject's entitlements) require `confirm:true` OR a\n * host `confirm` hook. Checks + define + usage are unaffected.\n */\n pendingMode?: boolean;\n confirm?: (req: { action: string; subject: unknown; groupKey: string }) => Promise<boolean> | boolean;\n};\n\nconst DEFAULT_AGENT = { id: \"agent\", name: \"Agent\", color: \"#a855f7\" };\n\nconst str = (v: unknown, fallback = \"\"): string => (typeof v === \"string\" ? v : fallback);\nconst num = (v: unknown, fallback = 0): number => (typeof v === \"number\" && Number.isFinite(v) ? v : fallback);\n\n/**\n * registerFeaturesBridge — full MCP tool set over a headless feature manager.\n *\n * features_list enabled feature keys for a subject\n * features_check can a subject access a feature? (+ remaining for resources)\n * features_explain trace why a feature is on/off for a subject\n * features_define register a feature definition (boolean / resource)\n * features_grant assign a subject to a group (pendingMode-gated, undoable)\n * features_revoke detach a subject from a group (pendingMode-gated, undoable)\n * features_groups list a subject's assigned groups\n * features_consume meter a resource feature (atomic check-and-increment)\n */\nexport function registerFeaturesBridge(host: ToolHost, options: FeaturesBridgeOptions): Bridge {\n const { adapter } = options;\n const agent = { ...DEFAULT_AGENT, ...(options.agent ?? {}) };\n const pendingMode = options.pendingMode ?? true;\n const featuresId = adapter.id ?? \"features\";\n const disposers: Array<() => void> = [];\n\n ensureUndoToolsRegistered(host, { defaultAgentId: agent.id });\n\n const target = (elementId?: string, label?: string): AgentTarget => ({\n kind: \"custom\",\n screenId: adapter.screenId,\n elementId,\n label: label ?? featuresId,\n });\n\n const reg = (\n name: string,\n description: string,\n properties: Record<string, unknown>,\n required: string[],\n handler: (args: JsonObject) => Promise<unknown> | unknown,\n resolveTarget: false | ((args: JsonObject) => AgentTarget),\n ) => {\n const wrapped = async (args: JsonObject) => {\n try {\n return await handler(args);\n } catch (e) {\n return errorResult(e instanceof Error ? e.message : String(e));\n }\n };\n const final = resolveTarget\n ? wrapToolWithActivity(wrapped as never, {\n toolName: name,\n agent,\n kind: \"custom\",\n screenId: adapter.screenId,\n resolveTarget: ({ args }) => resolveTarget(args as JsonObject),\n })\n : wrapped;\n disposers.push(\n host.registerTool(\n { name, description, inputSchema: { type: \"object\", properties: properties as Record<string, never>, required, additionalProperties: false } },\n final as never,\n ),\n );\n };\n\n const guardGrant = async (action: string, subject: unknown, groupKey: string, hasConfirmArg: boolean) => {\n if (!pendingMode) return null;\n if (options.confirm) {\n const ok = await options.confirm({ action, subject, groupKey });\n return ok ? null : errorResult(`Declined: ${action} ${groupKey} (human did not confirm).`);\n }\n if (!hasConfirmArg) {\n return errorResult(`${action} is staged (pendingMode). Re-call with confirm:true to apply, or wire a host confirm hook.`);\n }\n return null;\n };\n\n // ─── Read / check tools ──────────────────────────────────────────────────\n\n reg(\n \"features_list\",\n \"List the feature keys enabled for a subject. Pass `subject` (a string id or object).\",\n { subject: { description: \"Opaque subject — string id or { id, … } object.\" }, context: { description: \"Optional resolution context.\" } },\n [],\n async (args) => {\n const keys = await adapter.enabled(args.subject, args.context);\n return textResult(JSON.stringify(keys, null, 2), { subject: args.subject, enabled: keys });\n },\n false,\n );\n\n reg(\n \"features_check\",\n \"Check whether a subject can access a feature. For resource features also returns the remaining quota.\",\n { feature: { type: \"string\" }, subject: { description: \"Opaque subject.\" }, context: { description: \"Optional context.\" } },\n [\"feature\"],\n async (args) => {\n const feature = str(args.feature);\n const allowed = await adapter.canAccess(feature, args.subject, args.context);\n const remaining = await adapter.remaining(feature, args.subject, args.context);\n const out = { feature, allowed, remaining };\n return textResult(JSON.stringify(out), out);\n },\n false,\n );\n\n reg(\n \"features_explain\",\n \"Trace why a feature is on/off for a subject — returns the AccessResult (source, remaining, limit, used).\",\n { feature: { type: \"string\" }, subject: { description: \"Opaque subject.\" }, context: { description: \"Optional context.\" } },\n [\"feature\"],\n async (args) => {\n if (!adapter.explain) return errorResult(\"Host did not wire explain().\");\n const result = await adapter.explain(str(args.feature), args.subject, args.context);\n return textResult(JSON.stringify(result, null, 2), result as Record<string, unknown>);\n },\n false,\n );\n\n reg(\n \"features_groups\",\n \"List the feature groups a subject is assigned to.\",\n { subject: { description: \"Opaque subject.\" } },\n [\"subject\"],\n async (args) => {\n const groups = await adapter.listGroups(args.subject);\n return textResult(JSON.stringify(groups, null, 2), { subject: args.subject, groups });\n },\n false,\n );\n\n // ─── Define ──────────────────────────────────────────────────────────────\n\n reg(\n \"features_define\",\n \"Register a feature definition. type 'boolean' (on/off) or 'resource' (metered with a `limit`). `enabled` sets the default gate.\",\n {\n key: { type: \"string\" },\n name: { type: \"string\" },\n description: { type: \"string\" },\n type: { type: \"string\", enum: [\"boolean\", \"resource\"] },\n enabled: { type: \"boolean\" },\n limit: { type: \"number\", description: \"Resource quota per period (resource type).\" },\n },\n [\"key\"],\n (args) => {\n const key = str(args.key);\n if (!key) return errorResult(\"key is required.\");\n const existed = adapter.registryKeys().includes(key);\n const definition: FeatureDefinition = {\n ...(args.name !== undefined ? { name: str(args.name) } : {}),\n ...(args.description !== undefined ? { description: str(args.description) } : {}),\n ...(args.type !== undefined ? { type: str(args.type) as \"boolean\" | \"resource\" } : {}),\n ...(args.enabled !== undefined ? { enabled: args.enabled === true } : {}),\n ...(args.limit !== undefined ? { limit: num(args.limit) } : {}),\n };\n adapter.registerFeature(key, definition);\n pushUndoEntry(agent.id, {\n timestamp: Date.now(),\n bridgeId: featuresId,\n action: \"features_define\",\n // Registry has no unregister; undo re-registers the prior definition when we had one.\n label: existed ? `Redefined feature ${key}` : `Defined feature ${key}`,\n undo: () => {},\n redo: () => adapter.registerFeature(key, definition),\n });\n return textResult(`${existed ? \"Redefined\" : \"Defined\"} feature ${key} (${definition.type ?? \"boolean\"})`, { key, definition });\n },\n (args) => target(str(args.key), `define ${str(args.key)}`),\n );\n\n // ─── Grant / revoke (pendingMode-gated) ──────────────────────────────────\n\n reg(\n \"features_grant\",\n \"Grant a subject access by assigning it to a feature group. Staged in pendingMode — pass confirm:true or wire a host confirm hook.\",\n { subject: { description: \"Opaque subject.\" }, group: { type: \"string\", description: \"Feature group key.\" }, confirm: { type: \"boolean\" } },\n [\"subject\", \"group\"],\n async (args) => {\n const groupKey = str(args.group);\n if (!groupKey) return errorResult(\"group is required.\");\n const blocked = await guardGrant(\"features_grant\", args.subject, groupKey, args.confirm === true);\n if (blocked) return blocked;\n const already = (await adapter.listGroups(args.subject)).includes(groupKey);\n await adapter.assignGroup(args.subject, groupKey);\n pushUndoEntry(agent.id, {\n timestamp: Date.now(),\n bridgeId: featuresId,\n action: \"features_grant\",\n label: `Granted group ${groupKey}`,\n // Only reverse if WE added it (idempotent assign — don't revoke a pre-existing grant).\n undo: async () => { if (!already) await adapter.detachGroup(args.subject, groupKey); },\n redo: async () => { await adapter.assignGroup(args.subject, groupKey); },\n });\n return textResult(`Granted group ${groupKey}`, { subject: args.subject, group: groupKey });\n },\n (args) => target(str(args.group), `grant ${str(args.group)}`),\n );\n\n reg(\n \"features_revoke\",\n \"Revoke access by detaching a subject from a feature group. Staged in pendingMode — pass confirm:true or wire a host confirm hook.\",\n { subject: { description: \"Opaque subject.\" }, group: { type: \"string\" }, confirm: { type: \"boolean\" } },\n [\"subject\", \"group\"],\n async (args) => {\n const groupKey = str(args.group);\n if (!groupKey) return errorResult(\"group is required.\");\n const blocked = await guardGrant(\"features_revoke\", args.subject, groupKey, args.confirm === true);\n if (blocked) return blocked;\n const had = (await adapter.listGroups(args.subject)).includes(groupKey);\n await adapter.detachGroup(args.subject, groupKey);\n pushUndoEntry(agent.id, {\n timestamp: Date.now(),\n bridgeId: featuresId,\n action: \"features_revoke\",\n label: `Revoked group ${groupKey}`,\n undo: async () => { if (had) await adapter.assignGroup(args.subject, groupKey); },\n redo: async () => { await adapter.detachGroup(args.subject, groupKey); },\n });\n return textResult(`Revoked group ${groupKey}`, { subject: args.subject, group: groupKey });\n },\n (args) => target(str(args.group), `revoke ${str(args.group)}`),\n );\n\n // ─── Usage / metering ────────────────────────────────────────────────────\n\n reg(\n \"features_consume\",\n \"Meter a resource feature: atomic check-and-increment. Returns ok:false if the quota would be exceeded (nothing recorded).\",\n { feature: { type: \"string\" }, subject: { description: \"Opaque subject.\" }, amount: { type: \"number\", description: \"Units to consume. Default 1.\" }, context: { description: \"Optional context.\" } },\n [\"feature\", \"subject\"],\n async (args) => {\n if (!adapter.tryConsume) return errorResult(\"Host did not wire usage metering (tryConsume).\");\n const feature = str(args.feature);\n const amount = num(args.amount, 1);\n const ok = await adapter.tryConsume(feature, args.subject, amount, args.context);\n const remaining = await adapter.remaining(feature, args.subject, args.context);\n const out = { feature, ok, amount, remaining };\n return textResult(JSON.stringify(out), out);\n },\n (args) => target(str(args.feature), `consume ${str(args.feature)}`),\n );\n\n return {\n id: `features:${featuresId}`,\n title: adapter.title ?? \"Features\",\n dispose: () => {\n for (const d of disposers.splice(0)) d();\n },\n };\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/bridges/terminal.ts"],"names":[],"mappings":"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","file":"chunk-5ZWNCHZS.js","sourcesContent":["import { textResult, errorResult } from \"../mcp/server\";\nimport type { ToolHost } from \"../mcp/tool-host\";\nimport type { CallToolResult, JsonObject } from \"../mcp/types\";\nimport type { Bridge } from \"./types\";\nimport { wrapToolWithActivity } from \"../presence/wrap-tool-with-activity\";\nimport { ensureUndoToolsRegistered } from \"../undo/undo-tools\";\nimport type { AgentTarget } from \"../presence/types\";\n\n/**\n * A shell/profile an agent can switch a terminal to. Mirrors fancy-term's\n * `ShellProfile` (kept local so the bridge never imports fancy-term).\n */\nexport type TerminalShell = { id: string; label: string; icon?: string };\n\n/**\n * One terminal the bridge can drive. A Human+ app often hosts **several**\n * terminals on a screen (a build pane, a server pane, an agent scratch shell);\n * each is a `TerminalRef` with a stable `id` so an agent can read/write any of\n * them — not just \"its own\". Wire the function fields to that terminal's\n * fancy-term `TerminalHandle`.\n */\nexport type TerminalRef = {\n /** Stable id used to address this terminal (`terminal_list` enumerates them). */\n id: string;\n /** Human label, e.g. \"Build\", \"Server\". Defaults to the id. */\n label?: string;\n /** True for the focused terminal — the default target when no id is passed. */\n active?: boolean;\n /** Read the visible buffer as text (wire to `TerminalHandle.getBuffer`). */\n getBuffer: () => string;\n /** Write raw data / keystrokes (wire to `TerminalHandle.write`). */\n write: (data: string) => void;\n /** Run a command. Defaults to writing `${command}\\r`; override for a real runner. */\n runCommand?: (command: string) => void | Promise<void>;\n /** Clear the viewport (wire to `TerminalHandle.clear`). */\n clear?: () => void;\n /** Current text selection (wire to `TerminalHandle.getSelection`). */\n getSelection?: () => string;\n /** Shells this terminal offers (cmd, PowerShell, …). */\n listShells?: () => TerminalShell[];\n /** Switch this terminal's active shell by id. */\n setShell?: (id: string) => void | Promise<void>;\n /** This terminal's active shell id. */\n getShell?: () => string | undefined;\n};\n\n/**\n * Single-terminal adapter (back-compat). A `TerminalRef` without the\n * `id`/`label`/`active` bookkeeping — pass it as `{ adapter }` and the bridge\n * treats it as the one (active) terminal. Use `{ terminals }` for multiple.\n */\nexport type TerminalBridgeAdapter = Omit<TerminalRef, \"id\" | \"label\" | \"active\"> & {\n /** fancy-screens screen id (optional) so activity events know which screen the terminal lives in. */\n screenId?: string;\n};\n\ntype StagedKind = \"write\" | \"run\";\ntype Staged = { id: string; kind: StagedKind; data: string; terminalId: string };\n\nexport type TerminalBridgeOptions = {\n /** A single terminal (back-compat). Mutually exclusive with `terminals`. */\n adapter?: TerminalBridgeAdapter;\n /**\n * The live list of terminals on the screen. Use this when the app hosts more\n * than one terminal so an agent can `terminal_list` then target any of them by\n * id — i.e. reach into another terminal in the same screen.\n */\n terminals?: () => TerminalRef[];\n /** fancy-screens screen id for activity events (defaults to `adapter.screenId`). */\n screenId?: string;\n agent?: { id: string; name?: string; color?: string };\n /**\n * Trust-but-verify (Human+ contract for inhabited surfaces). When on,\n * `terminal_write` + `terminal_run` don't execute — they **stage** the command\n * (returning a pending id) and fire `onPending`. A human confirms via the\n * returned bridge's `confirm(id)` (wire it to a human-only control).\n *\n * **Default: ON.** The terminal is the most dangerous surface (arbitrary shell),\n * and possession of the relay session token = permission to call every tool, so\n * it must fail SAFE. Pass `false` only for a fully-trusted, non-shared terminal\n * where auto-execution is acceptable. A host that leaves this on MUST wire a\n * human confirm path (`onPending` + `bridge.confirm`), or staged commands never run.\n */\n pendingMode?: boolean;\n /** Notified when a command is staged (pendingMode) — show it + offer confirm / reject. */\n onPending?: (pending: Staged) => void;\n /**\n * Expose `terminal_confirm` / `terminal_reject` as agent-callable tools.\n * **Default: false** — otherwise the *same* agent that staged a command could\n * confirm it, defeating the human-in-the-loop. Leave off and confirm via the\n * returned `bridge.confirm(id)` wired to a human control.\n */\n allowAgentConfirm?: boolean;\n /**\n * Per-terminal authorization. Return false to hide a terminal id from this\n * agent entirely (it won't appear in `terminal_list` and can't be targeted).\n * Use it to scope an agent to its own pane(s); without it, `{ terminals }`\n * grants the agent full read/write over EVERY terminal in the list.\n */\n canAccess?: (terminalId: string) => boolean;\n};\n\nexport type TerminalBridge = Bridge & {\n /** Execute a staged command by id — wire a host confirm button to this. No-op if not pending. */\n confirm: (id: string) => void;\n /** Drop a staged command by id without executing. */\n reject: (id: string) => void;\n /** Commands currently awaiting confirmation. */\n pending: () => Staged[];\n};\n\nconst DEFAULT_AGENT = { id: \"agent\", name: \"Agent\", color: \"#a855f7\" };\n\nconst truncate = (s: string, n = 60): string => (s.length > n ? s.slice(0, n) + \"…\" : s);\n\n/**\n * registerTerminalBridge — MCP access to one **or many** terminal surfaces on a\n * screen. An agent reads the visible buffer (`terminal_read`), writes input\n * (`terminal_write`), and runs commands (`terminal_run`) through the host; every\n * mutation broadcasts an `AgentActivity` event. With `pendingMode`, destructive\n * actions are staged for human confirmation (`terminal_confirm` / `terminal_reject`\n * / `terminal_pending`).\n *\n * **Multi-terminal:** pass `{ terminals }` (vs a single `{ adapter }`) and every\n * tool takes an optional `terminal` id; `terminal_list` enumerates them. This is\n * how an agent **reaches into another terminal in the same screen** rather than\n * being stuck in one. When a terminal offers shells, the agent can also list\n * (`terminal_list_shells`) and switch (`terminal_set_shell`) its shell. Tool\n * prefix `terminal_*`.\n */\nexport function registerTerminalBridge(host: ToolHost, options: TerminalBridgeOptions): TerminalBridge {\n const agent = { ...DEFAULT_AGENT, ...(options.agent ?? {}) };\n // Safe-by-default: the terminal stages for human confirmation unless a host\n // explicitly opts a trusted, non-shared terminal into auto-exec (see the\n // pendingMode docs). Every other write bridge already defaults to staged.\n const pendingMode = options.pendingMode ?? true;\n const screenId = options.screenId ?? options.adapter?.screenId;\n const disposers: Array<() => void> = [];\n const staged = new Map<string, Staged>();\n let seq = 0;\n\n // Enables agent_history (a log of what agents did across every bridge).\n ensureUndoToolsRegistered(host);\n\n // The live terminal list — from `terminals()` (multi) or the single `adapter`\n // normalized to one active ref with the id \"terminal\".\n const listTerminals = (): TerminalRef[] => {\n const all = options.terminals\n ? options.terminals()\n : options.adapter\n ? [{ id: \"terminal\", label: \"Terminal\", active: true, ...options.adapter }]\n : [];\n // Per-terminal ACL: an agent can only see/target terminals it's allowed to.\n return options.canAccess ? all.filter((t) => options.canAccess!(t.id)) : all;\n };\n\n /** Resolve a terminal by id; with no id, the active one, else the first. */\n const resolve = (id?: unknown): TerminalRef | undefined => {\n const list = listTerminals();\n if (typeof id === \"string\" && id !== \"\") return list.find((t) => t.id === id);\n return list.find((t) => t.active) ?? list[0];\n };\n\n // Whether any host config can offer these capabilities (gates tool registration;\n // per-call we still check the *resolved* terminal supports it).\n const anyMulti = !!options.terminals;\n const canClear = anyMulti || !!options.adapter?.clear;\n const canShells = anyMulti || !!options.adapter?.listShells;\n const canSetShell = anyMulti || !!options.adapter?.setShell;\n\n const target = (label?: string, terminalId?: string): AgentTarget => ({\n kind: \"terminal\",\n screenId,\n elementId: terminalId ?? screenId ?? \"terminal\",\n label: label ?? \"terminal\",\n });\n\n // Broadcast meta for terminal mutations: shape only, never the raw command /\n // keystroke bytes (those may hold secrets, and the relay fans meta to every\n // peer). Full data stays local to the tool result + onPending / bridge.confirm.\n const redactMeta = (result: CallToolResult): Record<string, unknown> | undefined => {\n const sc = result.structuredContent as Record<string, unknown> | undefined;\n if (!sc || typeof sc !== \"object\") return undefined;\n return {\n terminal: sc.terminal,\n kind: sc.kind,\n length: typeof sc.data === \"string\" ? (sc.data as string).length : undefined,\n executed: sc.executed,\n pending: sc.pending,\n };\n };\n\n const TERMINAL_ARG = {\n terminal: {\n type: \"string\",\n description: \"Terminal id to target (call terminal_list for ids). Omit for the active / only terminal.\",\n },\n };\n\n const reg = (\n name: string,\n description: string,\n properties: Record<string, unknown>,\n required: string[],\n handler: (args: JsonObject) => Promise<any> | any,\n isMutation: boolean,\n resolveTarget?: (args: JsonObject, result: any) => AgentTarget | null,\n ) => {\n const wrapped = async (args: JsonObject) => {\n try {\n return await handler(args);\n } catch (e) {\n return errorResult(e instanceof Error ? e.message : String(e));\n }\n };\n const final = isMutation\n ? wrapToolWithActivity(wrapped, {\n toolName: name,\n agent,\n kind: \"terminal\",\n screenId,\n // A per-call resolver may return null to SKIP the broadcast (e.g. a\n // merely-staged command); only fall back to the default target when no\n // resolver was supplied.\n resolveTarget: ({ args, result }) => (resolveTarget ? resolveTarget(args, result) : target()),\n // Never fan raw command/keystroke bytes to peers — broadcast shape only.\n buildMeta: redactMeta,\n })\n : wrapped;\n disposers.push(\n host.registerTool(\n {\n name,\n description,\n inputSchema: { type: \"object\", properties: properties as any, required, additionalProperties: false },\n },\n final as any,\n ),\n );\n };\n\n /** Resolve the targeted terminal or throw a clear error for the agent. */\n const need = (args: JsonObject): TerminalRef => {\n const t = resolve(args.terminal);\n if (!t) {\n const ids = listTerminals().map((x) => x.id).join(\", \") || \"(none)\";\n throw new Error(\n typeof args.terminal === \"string\" && args.terminal\n ? `Unknown terminal '${args.terminal}'. Available: ${ids}. Use terminal_list.`\n : \"No terminal available.\",\n );\n }\n return t;\n };\n\n async function exec(t: TerminalRef, kind: StagedKind, data: string): Promise<void> {\n if (kind === \"run\") {\n if (t.runCommand) await t.runCommand(data);\n else t.write(data + \"\\r\");\n } else {\n t.write(data);\n }\n }\n\n async function stageOrExec(t: TerminalRef, kind: StagedKind, data: string) {\n // The human-facing summary truncates for readability, but the full payload\n // + its length ride in structuredContent / onPending so a confirm UI never\n // silently under-shows a long escape/injection payload.\n if (!pendingMode) {\n await exec(t, kind, data);\n return textResult(`${kind === \"run\" ? \"ran\" : \"wrote\"} on ${t.id}: ${truncate(data)}`, {\n kind,\n data,\n length: data.length,\n terminal: t.id,\n executed: true,\n });\n }\n const id = `t${++seq}`;\n const entry: Staged = { id, kind, data, terminalId: t.id };\n staged.set(id, entry);\n options.onPending?.(entry);\n return textResult(\n `Staged ${kind} on ${t.id} (id ${id}) — awaiting human confirmation: ${truncate(data)}`,\n { ...entry, length: data.length, pending: true },\n );\n }\n\n // ── List ──────────────────────────────────────────────────────────────────\n reg(\n \"terminal_list\",\n \"List the terminals on this screen (id, label, which is active) — so you can reach into another terminal, not just the active one. Pass the chosen id as `terminal` to the other tools.\",\n {},\n [],\n () => {\n const list = listTerminals().map((t) => ({ id: t.id, label: t.label ?? t.id, active: !!t.active }));\n const text = list.length\n ? list.map((t) => `${t.active ? \"* \" : \" \"}${t.id} — ${t.label}`).join(\"\\n\")\n : \"(no terminals)\";\n return textResult(text, { terminals: list });\n },\n false,\n );\n\n // ── Read ──────────────────────────────────────────────────────────────────\n reg(\n \"terminal_read\",\n \"Read a terminal's visible buffer as text — what the user sees. Pass `tail` for only the last N lines, `terminal` to read a specific one.\",\n { ...TERMINAL_ARG, tail: { type: \"number\", description: \"Return only the last N lines.\" } },\n [],\n (args) => {\n const t = need(args);\n let buf = t.getBuffer();\n const tail = typeof args.tail === \"number\" ? args.tail : undefined;\n if (tail && tail > 0) buf = buf.split(\"\\n\").slice(-tail).join(\"\\n\");\n return textResult(buf, { buffer: buf, terminal: t.id });\n },\n false,\n );\n\n reg(\n \"terminal_pending\",\n \"List commands staged for human confirmation (pendingMode).\",\n {},\n [],\n () => {\n const list = [...staged.values()];\n return textResult(\n list.length ? list.map((s) => `${s.id}: ${s.kind} on ${s.terminalId} ${truncate(s.data)}`).join(\"\\n\") : \"(none)\",\n { pending: list },\n );\n },\n false,\n );\n\n // ── Mutations ───────────────────────────────────────────────────────────────\n reg(\n \"terminal_write\",\n \"Write raw data / keystrokes to a terminal (input, control chars, ANSI). Pass `terminal` to target a specific one. In pendingMode this stages instead of executing. NOTE: bytes are written verbatim — an embedded CR runs a command, and ANSI/OSC sequences reach the terminal; treat this exactly like terminal_run for gating.\",\n { ...TERMINAL_ARG, data: { type: \"string\", description: \"Raw bytes to write.\" } },\n [\"data\"],\n (args) => stageOrExec(need(args), \"write\", String(args.data)),\n true,\n // Skip the peer broadcast while only staged; emit once it actually executes.\n (args, result) =>\n result?.structuredContent?.pending ? null : target(`write:${String(args.terminal ?? \"\")}`, resolve(args.terminal)?.id),\n );\n\n reg(\n \"terminal_run\",\n \"Run a shell command in a terminal — writes the command + Enter (or the host's runner). Pass `terminal` to target a specific one. In pendingMode this stages it for confirmation.\",\n { ...TERMINAL_ARG, command: { type: \"string\", description: \"The command line to run.\" } },\n [\"command\"],\n (args) => stageOrExec(need(args), \"run\", String(args.command)),\n true,\n (args, result) =>\n result?.structuredContent?.pending ? null : target(truncate(String(args.command ?? \"\")), resolve(args.terminal)?.id),\n );\n\n // Confirmation is HUMAN-driven by default: the acting agent must not be able to\n // confirm its own staged command (that would defeat pendingMode). Hosts confirm\n // via the returned `bridge.confirm(id)` wired to a human control. Only expose\n // the agent-callable tools when a host explicitly opts in.\n if (options.allowAgentConfirm) {\n reg(\n \"terminal_confirm\",\n \"Confirm + execute a staged command by id (pendingMode).\",\n { id: { type: \"string\" } },\n [\"id\"],\n async (args) => {\n const id = String(args.id);\n const entry = staged.get(id);\n if (!entry) return errorResult(`No staged command ${id}`);\n const t = resolve(entry.terminalId);\n if (!t) return errorResult(`Terminal '${entry.terminalId}' is gone — cannot run ${id}`);\n staged.delete(id);\n await exec(t, entry.kind, entry.data);\n return textResult(`Confirmed ${id}: ${entry.kind} on ${t.id} ${truncate(entry.data)}`, {\n ...entry,\n length: entry.data.length,\n executed: true,\n });\n },\n true,\n (args) => {\n const e = staged.get(String(args.id));\n return target(`confirm:${String(args.id ?? \"\")}`, e?.terminalId);\n },\n );\n\n reg(\n \"terminal_reject\",\n \"Drop a staged command by id without executing it.\",\n { id: { type: \"string\" } },\n [\"id\"],\n (args) => {\n const id = String(args.id);\n if (!staged.delete(id)) return errorResult(`No staged command ${id}`);\n return textResult(`Rejected ${id}`, { id, rejected: true });\n },\n false,\n );\n }\n\n if (canClear) {\n reg(\n \"terminal_clear\",\n \"Clear a terminal's viewport. Pass `terminal` to target a specific one.\",\n { ...TERMINAL_ARG },\n [],\n (args) => {\n const t = need(args);\n if (!t.clear) return errorResult(`Terminal '${t.id}' can't be cleared.`);\n t.clear();\n return textResult(`cleared ${t.id}`, { terminal: t.id });\n },\n true,\n (args) => target(`clear:${String(args.terminal ?? \"\")}`, resolve(args.terminal)?.id),\n );\n }\n\n // ── Shells ──────────────────────────────────────────────────────────────────\n if (canShells) {\n reg(\n \"terminal_list_shells\",\n \"List the shells a terminal can switch to (cmd, PowerShell, Git Bash, …) — id + label, active one marked. Pass `terminal` to target a specific one.\",\n { ...TERMINAL_ARG },\n [],\n (args) => {\n const t = need(args);\n if (!t.listShells) return errorResult(`Terminal '${t.id}' has no switchable shells.`);\n const shells = t.listShells();\n const active = t.getShell?.();\n const text = shells.length\n ? shells.map((s) => `${s.id === active ? \"* \" : \" \"}${s.id} — ${s.label}`).join(\"\\n\")\n : \"(none)\";\n return textResult(text, { shells, active, terminal: t.id });\n },\n false,\n );\n }\n\n if (canSetShell) {\n reg(\n \"terminal_set_shell\",\n \"Switch a terminal's active shell by id (e.g. 'powershell', 'git-bash'). Call terminal_list_shells first for valid ids. Pass `terminal` to target a specific one.\",\n { ...TERMINAL_ARG, id: { type: \"string\", description: \"Shell id to switch to.\" } },\n [\"id\"],\n async (args) => {\n const t = need(args);\n if (!t.setShell) return errorResult(`Terminal '${t.id}' can't switch shells.`);\n const id = String(args.id);\n // Fail closed: only allow a shell that is explicitly listed. A terminal\n // exposing setShell without listShells (or with an empty list) rejects\n // every id, so an unvalidated agent string can never reach setShell\n // (which a host may map to an executable = arbitrary-binary launch).\n const shells = t.listShells?.();\n if (!shells || !shells.some((s) => s.id === id)) {\n return errorResult(\n `Unknown or unlisted shell '${id}' for ${t.id}. Call terminal_list_shells for valid ids.`,\n );\n }\n await t.setShell(id);\n return textResult(`Switched ${t.id} shell to ${id}`, { shell: id, terminal: t.id });\n },\n true,\n (args) => target(`shell:${String(args.id ?? \"\")}`, resolve(args.terminal)?.id),\n );\n }\n\n return {\n id: \"terminal\",\n title: \"Terminal\",\n dispose: () => {\n disposers.forEach((d) => d());\n disposers.length = 0;\n staged.clear();\n },\n confirm: (id: string) => {\n const e = staged.get(id);\n if (e) {\n const t = resolve(e.terminalId);\n staged.delete(id);\n if (t) void exec(t, e.kind, e.data);\n }\n },\n reject: (id: string) => {\n staged.delete(id);\n },\n pending: () => [...staged.values()],\n };\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/bridges/git.ts"],"names":["mutation"],"mappings":"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","file":"chunk-AXWMWYH5.js","sourcesContent":["import { textResult, errorResult } from \"../mcp/server\";\nimport type { ToolHost } from \"../mcp/tool-host\";\nimport type { JsonObject } from \"../mcp/types\";\nimport type { Bridge } from \"./types\";\nimport { wrapToolWithActivity } from \"../presence/wrap-tool-with-activity\";\nimport { ensureUndoToolsRegistered } from \"../undo/undo-tools\";\n\nexport type GitProposal = {\n operation: string;\n arguments: Record<string, unknown>;\n summary: string;\n};\n\nexport type GitBridgeAdapter = {\n status: () => Promise<unknown>;\n log: (query: { ref?: string; limit?: number; skip?: number }) => Promise<unknown>;\n diff: (query: { from?: string; to?: string; staged?: boolean; paths?: string[] }) => Promise<unknown>;\n reviews?: (query: { state?: string; cursor?: string; limit?: number }) => Promise<unknown>;\n checks?: (revision: string) => Promise<unknown>;\n propose: (operation: string, args: Record<string, unknown>) => Promise<GitProposal>;\n applyProposal?: (proposal: GitProposal) => Promise<unknown>;\n};\n\nexport type GitBridgeOptions = {\n adapter: GitBridgeAdapter;\n agent?: { id: string; name?: string; color?: string };\n /** Defaults to proposal-only. Set true only when the host has its own confirmation policy. */\n allowApply?: boolean;\n};\n\nexport function registerGitBridge(host: ToolHost, options: GitBridgeOptions): Bridge {\n const agent = { id: \"agent\", name: \"Agent\", color: \"#a855f7\", ...(options.agent ?? {}) };\n const disposers: Array<() => void> = [];\n ensureUndoToolsRegistered(host, { defaultAgentId: agent.id });\n\n const reg = (\n name: string,\n description: string,\n properties: Record<string, unknown>,\n required: string[],\n handler: (args: JsonObject) => Promise<unknown>,\n mutation = false,\n ) => {\n const wrapped = async (args: JsonObject) => {\n try {\n return await handler(args);\n } catch (error) {\n return errorResult(error instanceof Error ? error.message : String(error));\n }\n };\n const final = mutation\n ? wrapToolWithActivity(wrapped as any, {\n toolName: name,\n agent,\n kind: \"git\",\n resolveTarget: ({ args }) => ({ kind: \"git\", elementId: typeof args.path === \"string\" ? args.path : undefined } as any),\n })\n : wrapped;\n disposers.push(host.registerTool({\n name,\n description,\n inputSchema: { type: \"object\", properties: properties as any, required, additionalProperties: false },\n }, final as any));\n };\n\n reg(\"git_status\", \"Read normalized working-tree and branch status.\", {}, [], async () => {\n const result = await options.adapter.status();\n return textResult(JSON.stringify(result, null, 2), result as any);\n });\n reg(\"git_log\", \"Read normalized commit history.\", {\n ref: { type: \"string\" }, limit: { type: \"number\" }, skip: { type: \"number\" },\n }, [], async (args) => {\n const result = await options.adapter.log(args as any);\n return textResult(JSON.stringify(result, null, 2), result as any);\n });\n reg(\"git_diff\", \"Read a normalized Git diff.\", {\n from: { type: \"string\" }, to: { type: \"string\" }, staged: { type: \"boolean\" },\n paths: { type: \"array\", items: { type: \"string\" } },\n }, [], async (args) => {\n const result = await options.adapter.diff(args as any);\n return textResult(JSON.stringify(result, null, 2), result as any);\n });\n if (options.adapter.reviews) reg(\"git_reviews_list\", \"List normalized pull/merge requests.\", {\n state: { type: \"string\" }, cursor: { type: \"string\" }, limit: { type: \"number\" },\n }, [], async (args) => {\n const result = await options.adapter.reviews!(args as any);\n return textResult(JSON.stringify(result, null, 2), result as any);\n });\n if (options.adapter.checks) reg(\"git_checks\", \"Read checks or pipeline summaries for a revision.\", {\n revision: { type: \"string\" },\n }, [\"revision\"], async (args) => {\n const result = await options.adapter.checks!(String(args.revision));\n return textResult(JSON.stringify(result, null, 2), result as any);\n });\n\n const mutation = (name: string, description: string, properties: Record<string, unknown>, required: string[]) =>\n reg(name, description, properties, required, async (args) => {\n const proposal = await options.adapter.propose(name.slice(4), args);\n if (args.apply === true) {\n if (!options.allowApply || !options.adapter.applyProposal) return errorResult(\"This host requires human confirmation before applying Git writes.\");\n const result = await options.adapter.applyProposal(proposal);\n return textResult(`Applied: ${proposal.summary}`, result as any);\n }\n return textResult(`Proposed: ${proposal.summary}`, proposal as any);\n }, true);\n\n mutation(\"git_stage\", \"Propose staging paths.\", { paths: { type: \"array\", items: { type: \"string\" } }, apply: { type: \"boolean\" } }, [\"paths\"]);\n mutation(\"git_unstage\", \"Propose unstaging paths.\", { paths: { type: \"array\", items: { type: \"string\" } }, apply: { type: \"boolean\" } }, [\"paths\"]);\n mutation(\"git_commit\", \"Propose committing staged changes.\", { message: { type: \"string\" }, apply: { type: \"boolean\" } }, [\"message\"]);\n mutation(\"git_checkout\", \"Propose checking out a ref.\", { target: { type: \"string\" }, apply: { type: \"boolean\" } }, [\"target\"]);\n mutation(\"git_fetch\", \"Propose fetching a remote.\", { remote: { type: \"string\" }, apply: { type: \"boolean\" } }, []);\n mutation(\"git_pull\", \"Propose a fast-forward-only pull.\", { remote: { type: \"string\" }, branch: { type: \"string\" }, apply: { type: \"boolean\" } }, []);\n mutation(\"git_push\", \"Propose pushing a branch.\", { remote: { type: \"string\" }, branch: { type: \"string\" }, apply: { type: \"boolean\" } }, []);\n mutation(\"git_review_create\", \"Propose creating a pull/merge request.\", {\n title: { type: \"string\" }, body: { type: \"string\" }, sourceBranch: { type: \"string\" }, targetBranch: { type: \"string\" }, draft: { type: \"boolean\" }, apply: { type: \"boolean\" },\n }, [\"title\", \"sourceBranch\", \"targetBranch\"]);\n\n return { id: \"git\", title: \"Git\", dispose: () => disposers.forEach((dispose) => dispose()) };\n}\n"]}