@particle-academy/agent-integrations 0.29.0 → 0.31.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 (146) hide show
  1. package/README.md +30 -1
  2. package/dist/bridges/files.d.cts +20 -1
  3. package/dist/bridges/files.d.ts +20 -1
  4. package/dist/bridges/forms.d.cts +22 -1
  5. package/dist/bridges/forms.d.ts +22 -1
  6. package/dist/bridges/git.d.cts +44 -0
  7. package/dist/bridges/git.d.ts +44 -0
  8. package/dist/bridges/terminal.d.cts +21 -1
  9. package/dist/bridges/terminal.d.ts +21 -1
  10. package/dist/bridges-artboard.cjs +1 -1
  11. package/dist/bridges-artboard.cjs.map +1 -1
  12. package/dist/bridges-artboard.js +1 -1
  13. package/dist/bridges-catalog.cjs +1 -1
  14. package/dist/bridges-catalog.cjs.map +1 -1
  15. package/dist/bridges-catalog.js +2 -2
  16. package/dist/bridges-charts.cjs +1 -1
  17. package/dist/bridges-charts.cjs.map +1 -1
  18. package/dist/bridges-charts.js +2 -2
  19. package/dist/bridges-cms.cjs +1 -1
  20. package/dist/bridges-cms.cjs.map +1 -1
  21. package/dist/bridges-cms.js +3 -3
  22. package/dist/bridges-code.cjs +38 -3
  23. package/dist/bridges-code.cjs.map +1 -1
  24. package/dist/bridges-code.js +2 -2
  25. package/dist/bridges-doc.cjs +1 -1
  26. package/dist/bridges-doc.cjs.map +1 -1
  27. package/dist/bridges-doc.js +2 -2
  28. package/dist/bridges-features.cjs +1 -1
  29. package/dist/bridges-features.cjs.map +1 -1
  30. package/dist/bridges-features.js +2 -2
  31. package/dist/bridges-files.cjs +29 -8
  32. package/dist/bridges-files.cjs.map +1 -1
  33. package/dist/bridges-files.js +2 -2
  34. package/dist/bridges-flow.cjs +1 -1
  35. package/dist/bridges-flow.cjs.map +1 -1
  36. package/dist/bridges-flow.js +1 -1
  37. package/dist/bridges-forms.cjs +12 -2
  38. package/dist/bridges-forms.cjs.map +1 -1
  39. package/dist/bridges-forms.js +2 -2
  40. package/dist/bridges-git.cjs +214 -0
  41. package/dist/bridges-git.cjs.map +1 -0
  42. package/dist/bridges-git.js +7 -0
  43. package/dist/bridges-git.js.map +1 -0
  44. package/dist/bridges-map.cjs +1 -1
  45. package/dist/bridges-map.cjs.map +1 -1
  46. package/dist/bridges-map.js +2 -2
  47. package/dist/bridges-scene.cjs +1 -1
  48. package/dist/bridges-scene.cjs.map +1 -1
  49. package/dist/bridges-scene.js +2 -2
  50. package/dist/bridges-screens.cjs +1 -1
  51. package/dist/bridges-screens.cjs.map +1 -1
  52. package/dist/bridges-screens.js +2 -2
  53. package/dist/bridges-sheets.cjs +1 -1
  54. package/dist/bridges-sheets.cjs.map +1 -1
  55. package/dist/bridges-sheets.js +2 -2
  56. package/dist/bridges-slides.cjs +1 -1
  57. package/dist/bridges-slides.cjs.map +1 -1
  58. package/dist/bridges-slides.js +2 -2
  59. package/dist/bridges-terminal.cjs +70 -45
  60. package/dist/bridges-terminal.cjs.map +1 -1
  61. package/dist/bridges-terminal.js +2 -2
  62. package/dist/bridges-tui.js +1 -1
  63. package/dist/bridges-whiteboard.cjs +1 -1
  64. package/dist/bridges-whiteboard.cjs.map +1 -1
  65. package/dist/bridges-whiteboard.js +2 -2
  66. package/dist/{chunk-OFCR6JY3.js → chunk-2U5JB6ZA.js} +3 -3
  67. package/dist/{chunk-OFCR6JY3.js.map → chunk-2U5JB6ZA.js.map} +1 -1
  68. package/dist/{chunk-ULJL53DL.js → chunk-2VENWGLZ.js} +3 -3
  69. package/dist/chunk-2VENWGLZ.js.map +1 -0
  70. package/dist/chunk-4D3II37O.js +94 -0
  71. package/dist/chunk-4D3II37O.js.map +1 -0
  72. package/dist/{chunk-BE2XS577.js → chunk-6YUBWQTS.js} +3 -3
  73. package/dist/{chunk-BE2XS577.js.map → chunk-6YUBWQTS.js.map} +1 -1
  74. package/dist/{chunk-OHUDEA6R.js → chunk-BHQJJ2YG.js} +3 -3
  75. package/dist/{chunk-OHUDEA6R.js.map → chunk-BHQJJ2YG.js.map} +1 -1
  76. package/dist/{chunk-LZJI7EKQ.js → chunk-CA7GIJJC.js} +3 -3
  77. package/dist/{chunk-LZJI7EKQ.js.map → chunk-CA7GIJJC.js.map} +1 -1
  78. package/dist/{chunk-7VBB2FJB.js → chunk-DKSR4R4O.js} +3 -3
  79. package/dist/{chunk-7VBB2FJB.js.map → chunk-DKSR4R4O.js.map} +1 -1
  80. package/dist/{chunk-2Y7Y5PTR.js → chunk-G5EZNWXJ.js} +3 -3
  81. package/dist/{chunk-2Y7Y5PTR.js.map → chunk-G5EZNWXJ.js.map} +1 -1
  82. package/dist/{chunk-OIX2ANFS.js → chunk-GRHPEK6M.js} +45 -9
  83. package/dist/chunk-GRHPEK6M.js.map +1 -0
  84. package/dist/{chunk-VMCG3PJD.js → chunk-HRHC5GM5.js} +31 -11
  85. package/dist/chunk-HRHC5GM5.js.map +1 -0
  86. package/dist/{chunk-5KLUYF4D.js → chunk-HSI5RVF4.js} +3 -3
  87. package/dist/{chunk-5KLUYF4D.js.map → chunk-HSI5RVF4.js.map} +1 -1
  88. package/dist/{chunk-AF454WRD.js → chunk-LQZKRBWR.js} +3 -3
  89. package/dist/{chunk-AF454WRD.js.map → chunk-LQZKRBWR.js.map} +1 -1
  90. package/dist/{chunk-KMSRG5KH.js → chunk-N6RLSLOF.js} +7 -7
  91. package/dist/chunk-N6RLSLOF.js.map +1 -0
  92. package/dist/{chunk-NSPL5TVF.js → chunk-OAFJ53X3.js} +3 -3
  93. package/dist/{chunk-NSPL5TVF.js.map → chunk-OAFJ53X3.js.map} +1 -1
  94. package/dist/{chunk-3PKHJ4IV.js → chunk-PR4SXFZH.js} +3 -3
  95. package/dist/{chunk-3PKHJ4IV.js.map → chunk-PR4SXFZH.js.map} +1 -1
  96. package/dist/{chunk-KYMEDV6E.js → chunk-RIXYCFDO.js} +41 -6
  97. package/dist/chunk-RIXYCFDO.js.map +1 -0
  98. package/dist/{chunk-TNU6AWUO.js → chunk-USQGA672.js} +14 -4
  99. package/dist/chunk-USQGA672.js.map +1 -0
  100. package/dist/{chunk-KKGC4ERF.js → chunk-UZHNKUER.js} +72 -47
  101. package/dist/chunk-UZHNKUER.js.map +1 -0
  102. package/dist/{chunk-UTUVN6HQ.js → chunk-WCKSDFTM.js} +3 -3
  103. package/dist/{chunk-UTUVN6HQ.js.map → chunk-WCKSDFTM.js.map} +1 -1
  104. package/dist/{chunk-HFLHLS2N.js → chunk-ZNGTC4CO.js} +3 -3
  105. package/dist/{chunk-HFLHLS2N.js.map → chunk-ZNGTC4CO.js.map} +1 -1
  106. package/dist/components/SharedWhiteboard/index.d.cts +1 -1
  107. package/dist/components/SharedWhiteboard/index.d.ts +1 -1
  108. package/dist/components-shared-whiteboard.cjs +2 -3
  109. package/dist/components-shared-whiteboard.cjs.map +1 -1
  110. package/dist/components-shared-whiteboard.js +4 -4
  111. package/dist/heuristics.js +1 -1
  112. package/dist/index.cjs +244 -60
  113. package/dist/index.cjs.map +1 -1
  114. package/dist/index.d.cts +3 -2
  115. package/dist/index.d.ts +3 -2
  116. package/dist/index.js +31 -24
  117. package/dist/index.js.map +1 -1
  118. package/dist/presence/index.d.cts +7 -0
  119. package/dist/presence/index.d.ts +7 -0
  120. package/dist/presence.cjs +1 -1
  121. package/dist/presence.cjs.map +1 -1
  122. package/dist/presence.js +1 -1
  123. package/dist/relay-server/index.d.cts +20 -0
  124. package/dist/relay-server/index.d.ts +20 -0
  125. package/dist/relay-server-cli.cjs +53 -9
  126. package/dist/relay-server-cli.cjs.map +1 -1
  127. package/dist/relay-server-cli.js +11 -3
  128. package/dist/relay-server-cli.js.map +1 -1
  129. package/dist/relay-server.cjs +43 -7
  130. package/dist/relay-server.cjs.map +1 -1
  131. package/dist/relay-server.js +1 -1
  132. package/dist/sharing/index.d.cts +1 -1
  133. package/dist/sharing/index.d.ts +1 -1
  134. package/dist/sharing.cjs +5 -5
  135. package/dist/sharing.cjs.map +1 -1
  136. package/dist/sharing.js +1 -1
  137. package/dist/{token-CrJF76oH.d.ts → token-BZ8doMam.d.cts} +15 -2
  138. package/dist/{token-CrJF76oH.d.cts → token-BZ8doMam.d.ts} +15 -2
  139. package/package.json +35 -7
  140. package/dist/chunk-KKGC4ERF.js.map +0 -1
  141. package/dist/chunk-KMSRG5KH.js.map +0 -1
  142. package/dist/chunk-KYMEDV6E.js.map +0 -1
  143. package/dist/chunk-OIX2ANFS.js.map +0 -1
  144. package/dist/chunk-TNU6AWUO.js.map +0 -1
  145. package/dist/chunk-ULJL53DL.js.map +0 -1
  146. package/dist/chunk-VMCG3PJD.js.map +0 -1
@@ -1,9 +1,25 @@
1
1
  import { ensureUndoToolsRegistered, pushUndoEntry } from './chunk-CT3LRNH7.js';
2
- import { wrapToolWithActivity } from './chunk-ULJL53DL.js';
2
+ import { wrapToolWithActivity } from './chunk-2VENWGLZ.js';
3
3
  import { textResult, errorResult } from './chunk-DF3PLL2E.js';
4
4
 
5
5
  // src/bridges/files.ts
6
6
  var DEFAULT_AGENT = { id: "agent", name: "Agent", color: "#a855f7" };
7
+ var MAX_SNAPSHOT_DEPTH = 8;
8
+ function assertPathWithinRoot(root, path) {
9
+ const segments = path.replace(/[\\/]+/g, "/").split("/");
10
+ if (segments.includes("..")) {
11
+ throw new Error(`Path may not contain '..': ${path}`);
12
+ }
13
+ const isAbsolute = /^([A-Za-z]:)?[\\/]/.test(path) || /^[A-Za-z]:/.test(path);
14
+ if (isAbsolute) {
15
+ const norm = (p2) => p2.replace(/[\\/]+/g, "/").replace(/\/+$/, "").toLowerCase();
16
+ const r = norm(root);
17
+ const p = norm(path);
18
+ if (p !== r && !p.startsWith(r + "/")) {
19
+ throw new Error(`Path escapes the configured root: ${path}`);
20
+ }
21
+ }
22
+ }
7
23
  var str = (v, fallback = "") => typeof v === "string" ? v : fallback;
8
24
  var num = (v, fallback) => typeof v === "number" && Number.isFinite(v) ? v : 0;
9
25
  var asPaths = (v) => {
@@ -19,6 +35,10 @@ function registerFilesBridge(host, options) {
19
35
  const { adapter } = options;
20
36
  const agent = { ...DEFAULT_AGENT, ...options.agent ?? {} };
21
37
  const disposers = [];
38
+ const guard = (path) => {
39
+ if (options.root !== void 0) assertPathWithinRoot(options.root, path);
40
+ return path;
41
+ };
22
42
  ensureUndoToolsRegistered(host, { defaultAgentId: agent.id });
23
43
  const fTarget = (args, _result) => ({
24
44
  kind: "files",
@@ -74,7 +94,7 @@ function registerFilesBridge(host, options) {
74
94
  { path: { type: "string", description: "Folder path to list; defaults to the current directory." } },
75
95
  [],
76
96
  async (args) => {
77
- const path = args.path !== void 0 ? str(args.path) : adapter.getPath();
97
+ const path = guard(args.path !== void 0 ? str(args.path) : adapter.getPath());
78
98
  const entries = await adapter.listChildren(path);
79
99
  const summary = entries.map((e) => ({
80
100
  path: e.path,
@@ -93,7 +113,7 @@ function registerFilesBridge(host, options) {
93
113
  { path: { type: "string" } },
94
114
  ["path"],
95
115
  (args) => {
96
- const path = str(args.path);
116
+ const path = guard(str(args.path));
97
117
  const prev = adapter.getPath();
98
118
  adapter.setPath(path);
99
119
  pushUndoEntry(agent.id, {
@@ -114,7 +134,7 @@ function registerFilesBridge(host, options) {
114
134
  { path: { type: "string" } },
115
135
  ["path"],
116
136
  (args) => {
117
- const path = str(args.path);
137
+ const path = guard(str(args.path));
118
138
  if (adapter.getExpanded().includes(path)) {
119
139
  return textResult(`${path} already expanded`, { path, expanded: true });
120
140
  }
@@ -137,7 +157,7 @@ function registerFilesBridge(host, options) {
137
157
  { path: { type: "string" } },
138
158
  ["path"],
139
159
  (args) => {
140
- const path = str(args.path);
160
+ const path = guard(str(args.path));
141
161
  if (!adapter.getExpanded().includes(path)) {
142
162
  return textResult(`${path} already collapsed`, { path, expanded: false });
143
163
  }
@@ -163,7 +183,7 @@ function registerFilesBridge(host, options) {
163
183
  },
164
184
  [],
165
185
  (args) => {
166
- const next = args.paths !== void 0 ? asPaths(args.paths) : asPaths(args.path);
186
+ const next = (args.paths !== void 0 ? asPaths(args.paths) : asPaths(args.path)).map(guard);
167
187
  const prev = adapter.getSelection();
168
188
  adapter.setSelection(next);
169
189
  pushUndoEntry(agent.id, {
@@ -192,8 +212,8 @@ function registerFilesBridge(host, options) {
192
212
  if (!adapter.requestSnapshot) {
193
213
  return errorResult("Host did not wire requestSnapshot (snapshot mode not enabled).");
194
214
  }
195
- const path = args.path !== void 0 ? str(args.path) : adapter.getPath();
196
- const depth = args.depth !== void 0 ? num(args.depth) : void 0;
215
+ const path = guard(args.path !== void 0 ? str(args.path) : adapter.getPath());
216
+ const depth = args.depth !== void 0 ? Math.max(0, Math.min(MAX_SNAPSHOT_DEPTH, num(args.depth))) : void 0;
197
217
  const tree = await adapter.requestSnapshot(path, depth);
198
218
  const count = Array.isArray(tree) ? tree.length : 0;
199
219
  return textResult(`Snapshot of ${path}: ${count} top-level entr${count === 1 ? "y" : "ies"}.`, {
@@ -212,6 +232,6 @@ function registerFilesBridge(host, options) {
212
232
  };
213
233
  }
214
234
 
215
- export { registerFilesBridge };
216
- //# sourceMappingURL=chunk-VMCG3PJD.js.map
217
- //# sourceMappingURL=chunk-VMCG3PJD.js.map
235
+ export { assertPathWithinRoot, registerFilesBridge };
236
+ //# sourceMappingURL=chunk-HRHC5GM5.js.map
237
+ //# sourceMappingURL=chunk-HRHC5GM5.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/bridges/files.ts"],"names":["p"],"mappings":";;;;;AAgEA,IAAM,gBAAgB,EAAE,EAAA,EAAI,SAAS,IAAA,EAAM,OAAA,EAAS,OAAO,SAAA,EAAU;AAIrE,IAAM,kBAAA,GAAqB,CAAA;AAQpB,SAAS,oBAAA,CAAqB,MAAc,IAAA,EAAoB;AACrE,EAAA,MAAM,WAAW,IAAA,CAAK,OAAA,CAAQ,WAAW,GAAG,CAAA,CAAE,MAAM,GAAG,CAAA;AACvD,EAAA,IAAI,QAAA,CAAS,QAAA,CAAS,IAAI,CAAA,EAAG;AAC3B,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,2BAAA,EAA8B,IAAI,CAAA,CAAE,CAAA;AAAA,EACtD;AACA,EAAA,MAAM,aAAa,oBAAA,CAAqB,IAAA,CAAK,IAAI,CAAA,IAAK,YAAA,CAAa,KAAK,IAAI,CAAA;AAC5E,EAAA,IAAI,UAAA,EAAY;AACd,IAAA,MAAM,IAAA,GAAO,CAACA,EAAAA,KAAsBA,EAAAA,CAAE,OAAA,CAAQ,SAAA,EAAW,GAAG,CAAA,CAAE,OAAA,CAAQ,MAAA,EAAQ,EAAE,CAAA,CAAE,WAAA,EAAY;AAC9F,IAAA,MAAM,CAAA,GAAI,KAAK,IAAI,CAAA;AACnB,IAAA,MAAM,CAAA,GAAI,KAAK,IAAI,CAAA;AACnB,IAAA,IAAI,MAAM,CAAA,IAAK,CAAC,EAAE,UAAA,CAAW,CAAA,GAAI,GAAG,CAAA,EAAG;AACrC,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,kCAAA,EAAqC,IAAI,CAAA,CAAE,CAAA;AAAA,IAC7D;AAAA,EACF;AACF;AAEA,IAAM,GAAA,GAAM,CAAC,CAAA,EAAY,QAAA,GAAW,OAAgB,OAAO,CAAA,KAAM,WAAW,CAAA,GAAI,QAAA;AAChF,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,OAAA,GAAU,CAAC,CAAA,KAAyB;AACxC,EAAA,IAAI,OAAO,MAAM,QAAA,EAAU;AACzB,IAAA,OAAO,CAAC,CAAC,CAAA;AAAA,EACX;AACA,EAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,CAAC,CAAA,EAAG;AACpB,IAAA,OAAO,EAAE,MAAA,CAAO,CAAC,CAAA,KAAmB,OAAO,MAAM,QAAQ,CAAA;AAAA,EAC3D;AACA,EAAA,OAAO,EAAC;AACV,CAAA;AAeO,SAAS,mBAAA,CAAoB,MAAgB,OAAA,EAAqC;AACvF,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;AAItC,EAAA,MAAM,KAAA,GAAQ,CAAC,IAAA,KAAyB;AACtC,IAAA,IAAI,QAAQ,IAAA,KAAS,MAAA,EAAW,oBAAA,CAAqB,OAAA,CAAQ,MAAM,IAAI,CAAA;AACvE,IAAA,OAAO,IAAA;AAAA,EACT,CAAA;AAGA,EAAA,yBAAA,CAA0B,IAAA,EAAM,EAAE,cAAA,EAAgB,KAAA,CAAM,IAAI,CAAA;AAE5D,EAAA,MAAM,OAAA,GAAU,CAAC,IAAA,EAAW,OAAA,MAAoC;AAAA,IAC9D,IAAA,EAAM,OAAA;AAAA,IACN,SAAA,EAAY,MAAM,IAAA,IAA+B;AAAA,GACnD,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,OAAA;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;AAAA,IACE,iBAAA;AAAA,IACA,mFAAA;AAAA,IACA,EAAC;AAAA,IACD,EAAC;AAAA,IACD,MAAM;AACJ,MAAA,MAAM,KAAA,GAAQ;AAAA,QACZ,IAAA,EAAM,QAAQ,OAAA,EAAQ;AAAA,QACtB,QAAA,EAAU,QAAQ,YAAA,EAAa;AAAA,QAC/B,QAAA,EAAU,QAAQ,WAAA;AAAY,OAChC;AACA,MAAA,OAAO,WAAW,IAAA,CAAK,SAAA,CAAU,OAAO,IAAA,EAAM,CAAC,GAAG,KAAK,CAAA;AAAA,IACzD;AAAA,GACF;AAEA,EAAA,GAAA;AAAA,IACE,YAAA;AAAA,IACA,mLAAA;AAAA,IACA,EAAE,IAAA,EAAM,EAAE,MAAM,QAAA,EAAU,WAAA,EAAa,2DAA0D,EAAE;AAAA,IACnG,EAAC;AAAA,IACD,OAAO,IAAA,KAAS;AACd,MAAA,MAAM,IAAA,GAAO,KAAA,CAAM,IAAA,CAAK,IAAA,KAAS,KAAA,CAAA,GAAY,GAAA,CAAI,IAAA,CAAK,IAAI,CAAA,GAAI,OAAA,CAAQ,OAAA,EAAS,CAAA;AAC/E,MAAA,MAAM,OAAA,GAAU,MAAM,OAAA,CAAQ,YAAA,CAAa,IAAI,CAAA;AAC/C,MAAA,MAAM,OAAA,GAAU,OAAA,CAAQ,GAAA,CAAI,CAAC,CAAA,MAAO;AAAA,QAClC,MAAM,CAAA,CAAE,IAAA;AAAA,QACR,MAAM,CAAA,CAAE,IAAA;AAAA,QACR,MAAM,CAAA,CAAE,IAAA;AAAA,QACR,GAAI,EAAE,IAAA,KAAS,KAAA,CAAA,GAAY,EAAE,IAAA,EAAM,CAAA,CAAE,IAAA,EAAK,GAAI,EAAC;AAAA,QAC/C,GAAI,EAAE,KAAA,KAAU,KAAA,CAAA,GAAY,EAAE,KAAA,EAAO,CAAA,CAAE,KAAA,EAAM,GAAI;AAAC,OACpD,CAAE,CAAA;AACF,MAAA,MAAM,IAAA,GACJ,QAAQ,GAAA,CAAI,CAAC,MAAM,CAAA,EAAG,CAAA,CAAE,SAAS,KAAA,GAAQ,WAAA,GAAO,WAAI,CAAA,CAAA,EAAI,CAAA,CAAE,IAAI,CAAA,CAAE,CAAA,CAAE,KAAK,IAAI,CAAA,IAC3E,WAAW,IAAI,CAAA,CAAA,CAAA;AACjB,MAAA,OAAO,WAAW,IAAA,EAAM,EAAE,IAAA,EAAM,OAAA,EAAS,SAAS,CAAA;AAAA,IACpD;AAAA,GACF;AAIA,EAAA,GAAA;AAAA,IACE,gBAAA;AAAA,IACA,qFAAA;AAAA,IACA,EAAE,IAAA,EAAM,EAAE,IAAA,EAAM,UAAS,EAAE;AAAA,IAC3B,CAAC,MAAM,CAAA;AAAA,IACP,CAAC,IAAA,KAAS;AACR,MAAA,MAAM,IAAA,GAAO,KAAA,CAAM,GAAA,CAAI,IAAA,CAAK,IAAI,CAAC,CAAA;AACjC,MAAA,MAAM,IAAA,GAAO,QAAQ,OAAA,EAAQ;AAC7B,MAAA,OAAA,CAAQ,QAAQ,IAAI,CAAA;AACpB,MAAA,aAAA,CAAc,MAAM,EAAA,EAAI;AAAA,QACtB,SAAA,EAAW,KAAK,GAAA,EAAI;AAAA,QACpB,QAAA,EAAU,OAAA;AAAA,QACV,MAAA,EAAQ,gBAAA;AAAA,QACR,KAAA,EAAO,gBAAgB,IAAI,CAAA,CAAA;AAAA,QAC3B,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,yBAAA,EAAuB,IAAI,CAAA,CAAA,EAAI,EAAE,MAAM,CAAA;AAAA,IAC3D,CAAA;AAAA,IACA;AAAA,GACF;AAIA,EAAA,GAAA;AAAA,IACE,cAAA;AAAA,IACA,6DAAA;AAAA,IACA,EAAE,IAAA,EAAM,EAAE,IAAA,EAAM,UAAS,EAAE;AAAA,IAC3B,CAAC,MAAM,CAAA;AAAA,IACP,CAAC,IAAA,KAAS;AACR,MAAA,MAAM,IAAA,GAAO,KAAA,CAAM,GAAA,CAAI,IAAA,CAAK,IAAI,CAAC,CAAA;AACjC,MAAA,IAAI,OAAA,CAAQ,WAAA,EAAY,CAAE,QAAA,CAAS,IAAI,CAAA,EAAG;AACxC,QAAA,OAAO,UAAA,CAAW,GAAG,IAAI,CAAA,iBAAA,CAAA,EAAqB,EAAE,IAAA,EAAM,QAAA,EAAU,MAAM,CAAA;AAAA,MACxE;AACA,MAAA,OAAA,CAAQ,YAAY,CAAC,IAAA,KAAS,CAAC,GAAG,IAAA,EAAM,IAAI,CAAC,CAAA;AAC7C,MAAA,aAAA,CAAc,MAAM,EAAA,EAAI;AAAA,QACtB,SAAA,EAAW,KAAK,GAAA,EAAI;AAAA,QACpB,QAAA,EAAU,OAAA;AAAA,QACV,MAAA,EAAQ,cAAA;AAAA,QACR,KAAA,EAAO,YAAY,IAAI,CAAA,CAAA;AAAA,QACvB,IAAA,EAAM,MAAM,OAAA,CAAQ,WAAA,CAAY,CAAC,IAAA,KAAS,IAAA,CAAK,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,KAAM,IAAI,CAAC,CAAA;AAAA,QACxE,IAAA,EAAM,MAAM,OAAA,CAAQ,WAAA,CAAY,CAAC,IAAA,KAAU,IAAA,CAAK,QAAA,CAAS,IAAI,IAAI,IAAA,GAAO,CAAC,GAAG,IAAA,EAAM,IAAI,CAAE;AAAA,OACzF,CAAA;AACD,MAAA,OAAO,UAAA,CAAW,YAAY,IAAI,CAAA,CAAA,EAAI,EAAE,IAAA,EAAM,QAAA,EAAU,MAAM,CAAA;AAAA,IAChE,CAAA;AAAA,IACA;AAAA,GACF;AAEA,EAAA,GAAA;AAAA,IACE,gBAAA;AAAA,IACA,gCAAA;AAAA,IACA,EAAE,IAAA,EAAM,EAAE,IAAA,EAAM,UAAS,EAAE;AAAA,IAC3B,CAAC,MAAM,CAAA;AAAA,IACP,CAAC,IAAA,KAAS;AACR,MAAA,MAAM,IAAA,GAAO,KAAA,CAAM,GAAA,CAAI,IAAA,CAAK,IAAI,CAAC,CAAA;AACjC,MAAA,IAAI,CAAC,OAAA,CAAQ,WAAA,EAAY,CAAE,QAAA,CAAS,IAAI,CAAA,EAAG;AACzC,QAAA,OAAO,UAAA,CAAW,GAAG,IAAI,CAAA,kBAAA,CAAA,EAAsB,EAAE,IAAA,EAAM,QAAA,EAAU,OAAO,CAAA;AAAA,MAC1E;AACA,MAAA,OAAA,CAAQ,WAAA,CAAY,CAAC,IAAA,KAAS,IAAA,CAAK,OAAO,CAAC,CAAA,KAAM,CAAA,KAAM,IAAI,CAAC,CAAA;AAC5D,MAAA,aAAA,CAAc,MAAM,EAAA,EAAI;AAAA,QACtB,SAAA,EAAW,KAAK,GAAA,EAAI;AAAA,QACpB,QAAA,EAAU,OAAA;AAAA,QACV,MAAA,EAAQ,gBAAA;AAAA,QACR,KAAA,EAAO,aAAa,IAAI,CAAA,CAAA;AAAA,QACxB,IAAA,EAAM,MAAM,OAAA,CAAQ,WAAA,CAAY,CAAC,IAAA,KAAU,IAAA,CAAK,QAAA,CAAS,IAAI,IAAI,IAAA,GAAO,CAAC,GAAG,IAAA,EAAM,IAAI,CAAE,CAAA;AAAA,QACxF,IAAA,EAAM,MAAM,OAAA,CAAQ,WAAA,CAAY,CAAC,IAAA,KAAS,IAAA,CAAK,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,KAAM,IAAI,CAAC;AAAA,OACzE,CAAA;AACD,MAAA,OAAO,UAAA,CAAW,aAAa,IAAI,CAAA,CAAA,EAAI,EAAE,IAAA,EAAM,QAAA,EAAU,OAAO,CAAA;AAAA,IAClE,CAAA;AAAA,IACA;AAAA,GACF;AAIA,EAAA,GAAA;AAAA,IACE,cAAA;AAAA,IACA,yIAAA;AAAA,IACA;AAAA,MACE,IAAA,EAAM,EAAE,IAAA,EAAM,QAAA,EAAU,aAAa,0BAAA,EAA2B;AAAA,MAChE,KAAA,EAAO,EAAE,IAAA,EAAM,OAAA,EAAS,KAAA,EAAO,EAAE,IAAA,EAAM,QAAA,EAAS,EAAG,WAAA,EAAa,yCAAA;AAA0C,KAC5G;AAAA,IACA,EAAC;AAAA,IACD,CAAC,IAAA,KAAS;AACR,MAAA,MAAM,IAAA,GAAA,CAAQ,IAAA,CAAK,KAAA,KAAU,MAAA,GAAY,OAAA,CAAQ,IAAA,CAAK,KAAK,CAAA,GAAI,OAAA,CAAQ,IAAA,CAAK,IAAI,CAAA,EAAG,IAAI,KAAK,CAAA;AAC5F,MAAA,MAAM,IAAA,GAAO,QAAQ,YAAA,EAAa;AAClC,MAAA,OAAA,CAAQ,aAAa,IAAI,CAAA;AACzB,MAAA,aAAA,CAAc,MAAM,EAAA,EAAI;AAAA,QACtB,SAAA,EAAW,KAAK,GAAA,EAAI;AAAA,QACpB,QAAA,EAAU,OAAA;AAAA,QACV,MAAA,EAAQ,cAAA;AAAA,QACR,KAAA,EAAO,KAAK,MAAA,GAAS,CAAA,SAAA,EAAY,KAAK,IAAA,CAAK,IAAI,CAAC,CAAA,CAAA,GAAK,mBAAA;AAAA,QACrD,IAAA,EAAM,MAAM,OAAA,CAAQ,YAAA,CAAa,IAAI,CAAA;AAAA,QACrC,IAAA,EAAM,MAAM,OAAA,CAAQ,YAAA,CAAa,IAAI;AAAA,OACtC,CAAA;AACD,MAAA,OAAO,UAAA,CAAW,KAAK,MAAA,GAAS,CAAA,SAAA,EAAY,KAAK,IAAA,CAAK,IAAI,CAAC,CAAA,CAAA,GAAK,mBAAA,EAAqB;AAAA,QACnF,QAAA,EAAU;AAAA,OACX,CAAA;AAAA,IACH,CAAA;AAAA,IACA;AAAA,GACF;AAIA,EAAA,GAAA;AAAA,IACE,wBAAA;AAAA,IACA,mKAAA;AAAA,IACA;AAAA,MACE,IAAA,EAAM,EAAE,IAAA,EAAM,QAAA,EAAU,aAAa,yDAAA,EAA0D;AAAA,MAC/F,KAAA,EAAO,EAAE,IAAA,EAAM,QAAA,EAAU,aAAa,6DAAA;AAA8D,KACtG;AAAA,IACA,EAAC;AAAA,IACD,OAAO,IAAA,KAAS;AACd,MAAA,IAAI,CAAC,QAAQ,eAAA,EAAiB;AAC5B,QAAA,OAAO,YAAY,gEAAgE,CAAA;AAAA,MACrF;AACA,MAAA,MAAM,IAAA,GAAO,KAAA,CAAM,IAAA,CAAK,IAAA,KAAS,MAAA,GAAY,GAAA,CAAI,IAAA,CAAK,IAAI,CAAA,GAAI,OAAA,CAAQ,OAAA,EAAS,CAAA;AAE/E,MAAA,MAAM,KAAA,GACJ,IAAA,CAAK,KAAA,KAAU,MAAA,GAAY,KAAK,GAAA,CAAI,CAAA,EAAG,IAAA,CAAK,GAAA,CAAI,oBAAoB,GAAA,CAAI,IAAA,CAAK,KAAK,CAAC,CAAC,CAAA,GAAI,MAAA;AAC1F,MAAA,MAAM,IAAA,GAAO,MAAM,OAAA,CAAQ,eAAA,CAAgB,MAAM,KAAK,CAAA;AACtD,MAAA,MAAM,QAAQ,KAAA,CAAM,OAAA,CAAQ,IAAI,CAAA,GAAI,KAAK,MAAA,GAAS,CAAA;AAClD,MAAA,OAAO,UAAA,CAAW,CAAA,YAAA,EAAe,IAAI,CAAA,EAAA,EAAK,KAAK,kBAAkB,KAAA,KAAU,CAAA,GAAI,GAAA,GAAM,KAAK,CAAA,CAAA,CAAA,EAAK;AAAA,QAC7F,IAAA;AAAA,QACA,QAAA,EAAU;AAAA,OACX,CAAA;AAAA,IACH,CAAA;AAAA,IACA;AAAA,GACF;AAEA,EAAA,OAAO;AAAA,IACL,EAAA,EAAI,OAAA;AAAA,IACJ,KAAA,EAAO,OAAA;AAAA,IACP,SAAS,MAAM;AACb,MAAA,KAAA,MAAW,CAAA,IAAK,WAAW,CAAA,EAAE;AAAA,IAC/B;AAAA,GACF;AACF","file":"chunk-HRHC5GM5.js","sourcesContent":["// Loose types so this bridge builds standalone without a hard dep on\n// @particle-academy/react-fancy. Hosts using FileBrowser pass its own\n// FileEntry / FileSnapshotNode values straight through — the shapes match.\ntype FileKind = \"file\" | \"dir\";\ntype FileEntry = {\n path: string;\n name: string;\n kind: FileKind;\n size?: number;\n mtime?: string;\n hasChildren?: boolean;\n disabled?: boolean;\n};\ntype FileSnapshotNode = FileEntry & { children?: FileSnapshotNode[] };\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 FilesAgentTarget } 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 props it\n * passes to react-fancy's `<FileBrowser>` (`value`/`path`/`expandedPaths`), plus\n * `listChildren` (wire to your `provider.loadChildren` or the loaded cache) and,\n * for snapshot mode, an optional `requestSnapshot`.\n */\nexport type FilesBridgeAdapter = {\n /** Current directory (the `path` prop). */\n getPath: () => string;\n setPath: (path: string) => void;\n /** Selected path(s) — normalize FileBrowser's `value` (string | string[] | null) to an array. */\n getSelection: () => string[];\n setSelection: (paths: string[]) => void;\n /** Expanded folder paths (the `expandedPaths` prop). */\n getExpanded: () => string[];\n setExpanded: (next: string[] | ((prev: string[]) => string[])) => void;\n /** Direct children of a path — wire to `provider.loadChildren` (async) or the loaded/snapshot cache. */\n listChildren: (path: string) => Promise<FileEntry[]> | FileEntry[];\n /** Optional (snapshot mode): fetch/refresh a snapshot subtree so an agent can pull remote state on demand. */\n requestSnapshot?: (path: string, depth?: number) => Promise<FileSnapshotNode[]> | FileSnapshotNode[];\n};\n\nexport type FilesBridgeOptions = {\n adapter: FilesBridgeAdapter;\n /** Identity tagged onto agent-driven actions. */\n agent?: { id: string; name?: string; color?: string };\n /**\n * Optional containment root. When set, every agent-supplied path is checked\n * with {@link assertPathWithinRoot} before it reaches the adapter: a `..`\n * segment or an absolute path outside `root` is rejected. This is a\n * fail-closed, string-level guard (no filesystem access — the bridge runs in\n * the browser). It is NOT sufficient on its own: a host over a real\n * filesystem MUST additionally resolve symlinks/junctions (realpath) and\n * enforce the root, because a link under `root` can still point outside it.\n * When `root` is unset the bridge does no containment and the adapter is\n * SOLELY responsible for sandboxing what `listChildren`/`requestSnapshot` expose.\n */\n root?: string;\n};\n\nconst DEFAULT_AGENT = { id: \"agent\", name: \"Agent\", color: \"#a855f7\" };\n\n/** Host default cap on snapshot recursion, so an agent can't request an\n * unbounded deep walk. */\nconst MAX_SNAPSHOT_DEPTH = 8;\n\n/**\n * Fail-closed, filesystem-free path containment. Throws when `path` contains a\n * `..` segment, or is absolute and not within `root`. Relative paths without\n * `..` pass (resolved within root by the host). String-level only — see the\n * `root` docs: hosts over a real fs must ALSO realpath to defeat symlinks.\n */\nexport function assertPathWithinRoot(root: string, path: string): void {\n const segments = path.replace(/[\\\\/]+/g, \"/\").split(\"/\");\n if (segments.includes(\"..\")) {\n throw new Error(`Path may not contain '..': ${path}`);\n }\n const isAbsolute = /^([A-Za-z]:)?[\\\\/]/.test(path) || /^[A-Za-z]:/.test(path);\n if (isAbsolute) {\n const norm = (p: string): string => p.replace(/[\\\\/]+/g, \"/\").replace(/\\/+$/, \"\").toLowerCase();\n const r = norm(root);\n const p = norm(path);\n if (p !== r && !p.startsWith(r + \"/\")) {\n throw new Error(`Path escapes the configured root: ${path}`);\n }\n }\n}\n\nconst str = (v: unknown, fallback = \"\"): string => (typeof v === \"string\" ? v : fallback);\nconst num = (v: unknown, fallback?: number): number =>\n typeof v === \"number\" && Number.isFinite(v) ? v : fallback ?? 0;\nconst asPaths = (v: unknown): string[] => {\n if (typeof v === \"string\") {\n return [v];\n }\n if (Array.isArray(v)) {\n return v.filter((x): x is string => typeof x === \"string\");\n }\n return [];\n};\n\n/**\n * registerFilesBridge — an MCP tool set over a react-fancy `<FileBrowser>`'s\n * controlled state, so a human and an agent share one file browser. The agent\n * lists a folder's children, navigates, expands/collapses folders, selects\n * entries, and (in snapshot mode) requests a fresh subtree — driving the same\n * `value`/`path`/`expandedPaths` props, no DOM scraping. Every mutation\n * broadcasts AgentActivity (presence) and pushes an undo entry. Mirrors the\n * map / whiteboard / flow bridges in shape.\n *\n * Read-only browse in v1: no content preview (pair with fancy-code's\n * FileViewer) and no write ops (rename/delete/upload) — those arrive later\n * behind a pendingMode-gated iteration.\n */\nexport function registerFilesBridge(host: ToolHost, options: FilesBridgeOptions): Bridge {\n const { adapter } = options;\n const agent = { ...DEFAULT_AGENT, ...(options.agent ?? {}) };\n const disposers: Array<() => void> = [];\n\n // Reject traversal / out-of-root paths before they reach the adapter (no-op\n // when no root is configured — the adapter is then responsible for sandboxing).\n const guard = (path: string): string => {\n if (options.root !== undefined) assertPathWithinRoot(options.root, path);\n return path;\n };\n\n // Register agent_undo / agent_redo / agent_history once per host. Idempotent.\n ensureUndoToolsRegistered(host, { defaultAgentId: agent.id });\n\n const fTarget = (args: any, _result: any): FilesAgentTarget => ({\n kind: \"files\",\n elementId: (args?.path as string | undefined) ?? 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) => FilesAgentTarget | 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: \"files\",\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(\n \"files_get_state\",\n \"Get the file browser's current directory, selected path(s), and expanded folders.\",\n {},\n [],\n () => {\n const state = {\n path: adapter.getPath(),\n selected: adapter.getSelection(),\n expanded: adapter.getExpanded(),\n };\n return textResult(JSON.stringify(state, null, 2), state);\n },\n );\n\n reg(\n \"files_list\",\n \"List the direct children of a folder (files + subfolders). Omit `path` for the current directory. Loads lazily from the host's provider/snapshot — never an eager tree walk.\",\n { path: { type: \"string\", description: \"Folder path to list; defaults to the current directory.\" } },\n [],\n async (args) => {\n const path = guard(args.path !== undefined ? str(args.path) : adapter.getPath());\n const entries = await adapter.listChildren(path);\n const summary = entries.map((e) => ({\n path: e.path,\n name: e.name,\n kind: e.kind,\n ...(e.size !== undefined ? { size: e.size } : {}),\n ...(e.mtime !== undefined ? { mtime: e.mtime } : {}),\n }));\n const text =\n summary.map((e) => `${e.kind === \"dir\" ? \"📁\" : \"📄\"} ${e.path}`).join(\"\\n\") ||\n `(empty: ${path})`;\n return textResult(text, { path, entries: summary });\n },\n );\n\n // ───────────── Navigation ─────────────\n\n reg(\n \"files_navigate\",\n \"Set the current directory (as if the user clicked a breadcrumb or opened a folder).\",\n { path: { type: \"string\" } },\n [\"path\"],\n (args) => {\n const path = guard(str(args.path));\n const prev = adapter.getPath();\n adapter.setPath(path);\n pushUndoEntry(agent.id, {\n timestamp: Date.now(),\n bridgeId: \"files\",\n action: \"files_navigate\",\n label: `Navigated to ${path}`,\n undo: () => adapter.setPath(prev),\n redo: () => adapter.setPath(path),\n });\n return textResult(`Current directory → ${path}`, { path });\n },\n fTarget,\n );\n\n // ───────────── Expansion ─────────────\n\n reg(\n \"files_expand\",\n \"Expand a folder in the tree (loads its children if needed).\",\n { path: { type: \"string\" } },\n [\"path\"],\n (args) => {\n const path = guard(str(args.path));\n if (adapter.getExpanded().includes(path)) {\n return textResult(`${path} already expanded`, { path, expanded: true });\n }\n adapter.setExpanded((prev) => [...prev, path]);\n pushUndoEntry(agent.id, {\n timestamp: Date.now(),\n bridgeId: \"files\",\n action: \"files_expand\",\n label: `Expanded ${path}`,\n undo: () => adapter.setExpanded((prev) => prev.filter((p) => p !== path)),\n redo: () => adapter.setExpanded((prev) => (prev.includes(path) ? prev : [...prev, path])),\n });\n return textResult(`Expanded ${path}`, { path, expanded: true });\n },\n fTarget,\n );\n\n reg(\n \"files_collapse\",\n \"Collapse a folder in the tree.\",\n { path: { type: \"string\" } },\n [\"path\"],\n (args) => {\n const path = guard(str(args.path));\n if (!adapter.getExpanded().includes(path)) {\n return textResult(`${path} already collapsed`, { path, expanded: false });\n }\n adapter.setExpanded((prev) => prev.filter((p) => p !== path));\n pushUndoEntry(agent.id, {\n timestamp: Date.now(),\n bridgeId: \"files\",\n action: \"files_collapse\",\n label: `Collapsed ${path}`,\n undo: () => adapter.setExpanded((prev) => (prev.includes(path) ? prev : [...prev, path])),\n redo: () => adapter.setExpanded((prev) => prev.filter((p) => p !== path)),\n });\n return textResult(`Collapsed ${path}`, { path, expanded: false });\n },\n fTarget,\n );\n\n // ───────────── Selection ─────────────\n\n reg(\n \"files_select\",\n \"Set the selection to the given path(s). Pass a single `path`, or `paths` for a multi-select browser; either empty clears the selection.\",\n {\n path: { type: \"string\", description: \"A single path to select.\" },\n paths: { type: \"array\", items: { type: \"string\" }, description: \"Multiple paths (multi-select browsers).\" },\n },\n [],\n (args) => {\n const next = (args.paths !== undefined ? asPaths(args.paths) : asPaths(args.path)).map(guard);\n const prev = adapter.getSelection();\n adapter.setSelection(next);\n pushUndoEntry(agent.id, {\n timestamp: Date.now(),\n bridgeId: \"files\",\n action: \"files_select\",\n label: next.length ? `Selected ${next.join(\", \")}` : \"Cleared selection\",\n undo: () => adapter.setSelection(prev),\n redo: () => adapter.setSelection(next),\n });\n return textResult(next.length ? `Selected ${next.join(\", \")}` : \"Cleared selection\", {\n selected: next,\n });\n },\n fTarget,\n );\n\n // ───────────── Snapshot (streamed remote trees) ─────────────\n\n reg(\n \"files_request_snapshot\",\n \"Request a fresh snapshot subtree rooted at `path` (snapshot mode) — e.g. to pull a remote machine's current tree. Requires the host to wire requestSnapshot.\",\n {\n path: { type: \"string\", description: \"Root of the subtree; defaults to the current directory.\" },\n depth: { type: \"number\", description: \"How many levels deep to materialize (host-defined default).\" },\n },\n [],\n async (args) => {\n if (!adapter.requestSnapshot) {\n return errorResult(\"Host did not wire requestSnapshot (snapshot mode not enabled).\");\n }\n const path = guard(args.path !== undefined ? str(args.path) : adapter.getPath());\n // Clamp depth so an agent can't demand an unbounded recursive walk.\n const depth =\n args.depth !== undefined ? Math.max(0, Math.min(MAX_SNAPSHOT_DEPTH, num(args.depth))) : undefined;\n const tree = await adapter.requestSnapshot(path, depth);\n const count = Array.isArray(tree) ? tree.length : 0;\n return textResult(`Snapshot of ${path}: ${count} top-level entr${count === 1 ? \"y\" : \"ies\"}.`, {\n path,\n snapshot: tree,\n });\n },\n fTarget,\n );\n\n return {\n id: \"files\",\n title: \"Files\",\n dispose: () => {\n for (const d of disposers) d();\n },\n };\n}\n"]}
@@ -1,4 +1,4 @@
1
- import { buildShareUrl, buildShareConfig } from './chunk-KMSRG5KH.js';
1
+ import { buildShareUrl, buildShareConfig } from './chunk-N6RLSLOF.js';
2
2
  import { useRef, useEffect, useState } from 'react';
3
3
  import { jsxs, jsx } from 'react/jsx-runtime';
4
4
 
@@ -326,5 +326,5 @@ function buildCurlRecipe(session) {
326
326
  }
327
327
 
328
328
  export { AgentActivityHighlight, AgentCursor, AgentPanel, ShareControls, buildAgentPrompt };
329
- //# sourceMappingURL=chunk-5KLUYF4D.js.map
330
- //# sourceMappingURL=chunk-5KLUYF4D.js.map
329
+ //# sourceMappingURL=chunk-HSI5RVF4.js.map
330
+ //# sourceMappingURL=chunk-HSI5RVF4.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/components/AgentPanel/AgentPanel.tsx","../src/components/AgentCursor/AgentCursor.tsx","../src/components/AgentActivityHighlight/AgentActivityHighlight.tsx","../src/components/ShareControls/ShareControls.tsx"],"names":["jsxs","jsx","useEffect","useState"],"mappings":"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","file":"chunk-5KLUYF4D.js","sourcesContent":["import { type CSSProperties, type ReactNode, useEffect, useRef } from \"react\";\n\nexport type AgentActivity = {\n id: string;\n /** Wall-clock timestamp; component formats it. */\n at: number;\n /** \"tool\" for MCP tool invocations, \"message\" for chat, \"info\" for status. */\n kind: \"tool\" | \"message\" | \"info\" | \"error\";\n /** Short label, e.g. \"whiteboard_add_sticky\" or \"Agent\". */\n source: string;\n /** Body text. */\n text: string;\n /** Optional structured payload, rendered as collapsed JSON. */\n detail?: unknown;\n};\n\nexport type AgentPanelProps = {\n /** The agent's identity (name + color appears in the header). */\n agent?: { name?: string; color?: string };\n /** Activity stream. Most recent at the end. */\n activity: AgentActivity[];\n /** Optional chat composer — pass an onSubmit to enable. */\n onSubmit?: (message: string) => void;\n /** Disabled while a request is in flight. */\n busy?: boolean;\n /** Right-rail header actions. */\n actions?: ReactNode;\n className?: string;\n style?: CSSProperties;\n};\n\n/**\n * AgentPanel — sidebar showing the agent's identity, a tool-and-chat log,\n * and an optional input composer. Pure presentational: hosts feed it the\n * activity stream from their own state (typically the MCP transport log).\n */\nexport function AgentPanel({ agent, activity, onSubmit, busy, actions, className, style }: AgentPanelProps) {\n const scrollRef = useRef<HTMLDivElement>(null);\n const inputRef = useRef<HTMLTextAreaElement>(null);\n\n useEffect(() => {\n const el = scrollRef.current;\n if (!el) return;\n el.scrollTop = el.scrollHeight;\n }, [activity.length]);\n\n const handleSubmit = (e: React.FormEvent) => {\n e.preventDefault();\n const value = inputRef.current?.value.trim();\n if (!value || !onSubmit) return;\n onSubmit(value);\n if (inputRef.current) inputRef.current.value = \"\";\n };\n\n const color = agent?.color ?? \"#a855f7\";\n const name = agent?.name ?? \"Agent\";\n\n return (\n <div className={[\"fai-panel\", className ?? \"\"].filter(Boolean).join(\" \")} style={style}>\n <header className=\"fai-panel__header\">\n <div\n className=\"fai-panel__avatar\"\n style={{ background: color }}\n aria-hidden\n >\n {name.slice(0, 1)}\n </div>\n <div className=\"fai-panel__title\">\n <strong>{name}</strong>\n <span className=\"fai-panel__subtitle\">\n {busy ? \"Working…\" : `${activity.length} event${activity.length === 1 ? \"\" : \"s\"}`}\n </span>\n </div>\n {actions && <div className=\"fai-panel__actions\">{actions}</div>}\n </header>\n\n <div ref={scrollRef} className=\"fai-panel__stream\">\n {activity.length === 0 ? (\n <p className=\"fai-panel__empty\">No activity yet.</p>\n ) : (\n activity.map((a) => <ActivityRow key={a.id} item={a} />)\n )}\n </div>\n\n {onSubmit && (\n <form className=\"fai-panel__composer\" onSubmit={handleSubmit}>\n <textarea\n ref={inputRef}\n className=\"fai-panel__input\"\n placeholder={busy ? \"Working…\" : \"Ask the agent…\"}\n disabled={busy}\n rows={2}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" && !e.shiftKey) {\n e.preventDefault();\n handleSubmit(e as unknown as React.FormEvent);\n }\n }}\n />\n <button type=\"submit\" className=\"fai-panel__send\" disabled={busy}>\n Send\n </button>\n </form>\n )}\n </div>\n );\n}\n\nfunction ActivityRow({ item }: { item: AgentActivity }) {\n const time = formatTime(item.at);\n return (\n <div className={`fai-row fai-row--${item.kind}`}>\n <div className=\"fai-row__meta\">\n <span className=\"fai-row__source\">{item.source}</span>\n <span className=\"fai-row__time\">{time}</span>\n </div>\n <div className=\"fai-row__text\">{item.text}</div>\n {item.detail !== undefined && (\n <details className=\"fai-row__detail\">\n <summary>details</summary>\n <pre>{safeJson(item.detail)}</pre>\n </details>\n )}\n </div>\n );\n}\n\nfunction formatTime(at: number): string {\n const d = new Date(at);\n const hh = d.getHours().toString().padStart(2, \"0\");\n const mm = d.getMinutes().toString().padStart(2, \"0\");\n const ss = d.getSeconds().toString().padStart(2, \"0\");\n return `${hh}:${mm}:${ss}`;\n}\n\nfunction safeJson(v: unknown): string {\n try {\n return JSON.stringify(v, null, 2);\n } catch {\n return String(v);\n }\n}\n","import type { CSSProperties } from \"react\";\n\nexport type AgentCursorProps = {\n x: number;\n y: number;\n name?: string;\n color?: string;\n /** Optional caption shown under the name (e.g. current tool). */\n status?: string;\n className?: string;\n style?: CSSProperties;\n};\n\n/**\n * AgentCursor — on-canvas presence marker for the agent. Drop it inside\n * (or alongside) a fancy-whiteboard <Board> at screen coords matching\n * the agent's reported position.\n */\nexport function AgentCursor({ x, y, name, color = \"#a855f7\", status, className, style }: AgentCursorProps) {\n return (\n <div\n className={[\"fai-cursor\", className ?? \"\"].filter(Boolean).join(\" \")}\n style={{\n position: \"absolute\",\n left: x,\n top: y,\n pointerEvents: \"none\",\n transform: \"translate(-2px, -2px)\",\n ...style,\n }}\n >\n <svg width=\"22\" height=\"22\" viewBox=\"0 0 22 22\" aria-hidden>\n <path\n d=\"M2 2 L2 17 L7 13 L10 19 L12 18 L9 12 L15 12 Z\"\n fill={color}\n stroke=\"white\"\n strokeWidth=\"1.2\"\n />\n </svg>\n {name && (\n <span\n className=\"fai-cursor__tag\"\n style={{ background: color }}\n >\n {name}\n {status ? <em className=\"fai-cursor__status\"> · {status}</em> : null}\n </span>\n )}\n </div>\n );\n}\n","import { type CSSProperties, useEffect, useState } from \"react\";\n\nexport type AgentActivityHighlightProps = {\n /** Bounds of the highlighted item in the parent's coord system. */\n x: number;\n y: number;\n width: number;\n height: number;\n /** Trigger token — change it (e.g. set to Date.now()) to re-fire the pulse. */\n pulseKey?: string | number;\n /** Highlight tint. */\n color?: string;\n /** Pulse duration in ms. Defaults 1200. */\n duration?: number;\n className?: string;\n style?: CSSProperties;\n};\n\n/**\n * AgentActivityHighlight — short pulsing outline that flashes around an\n * item the agent just touched. Position the parent so this can be placed\n * absolutely matching the item's bounds.\n */\nexport function AgentActivityHighlight({\n x,\n y,\n width,\n height,\n pulseKey,\n color = \"#a855f7\",\n duration = 1200,\n className,\n style,\n}: AgentActivityHighlightProps) {\n const [visible, setVisible] = useState(false);\n\n useEffect(() => {\n if (pulseKey === undefined) return;\n setVisible(true);\n const t = setTimeout(() => setVisible(false), duration);\n return () => clearTimeout(t);\n }, [pulseKey, duration]);\n\n if (!visible) return null;\n\n return (\n <div\n className={[\"fai-highlight\", className ?? \"\"].filter(Boolean).join(\" \")}\n style={{\n position: \"absolute\",\n left: x - 4,\n top: y - 4,\n width: width + 8,\n height: height + 8,\n borderRadius: 8,\n boxShadow: `0 0 0 2px ${color}, 0 0 16px ${color}66`,\n pointerEvents: \"none\",\n animation: `fai-pulse ${duration}ms ease-out forwards`,\n ...style,\n }}\n />\n );\n}\n","import { type CSSProperties, useState } from \"react\";\nimport type { SessionDescriptor } from \"../../sharing/token\";\nimport { buildShareConfig, buildShareUrl } from \"../../sharing/token\";\n\nexport type ShareControlsProps = {\n /** The active session, or null when not sharing yet. */\n session: SessionDescriptor | null;\n onStart: () => void;\n onStop: () => void;\n /** Optional connection-state badge text. */\n status?: string;\n /** Override the URL base used in the share URL. */\n shareBaseUrl?: string;\n className?: string;\n style?: CSSProperties;\n};\n\ntype Tab = \"prompt\" | \"url\" | \"json\" | \"curl\";\n\n/**\n * ShareControls — the host-facing UI for turning sharing on/off and\n * surfacing the resulting connection details (URL / JSON / cURL).\n */\nexport function ShareControls({\n session,\n onStart,\n onStop,\n status,\n shareBaseUrl,\n className,\n style,\n}: ShareControlsProps) {\n const [tab, setTab] = useState<Tab>(\"prompt\");\n\n if (!session) {\n return (\n <div className={[\"fai-share fai-share--idle\", className ?? \"\"].filter(Boolean).join(\" \")} style={style}>\n <button type=\"button\" className=\"fai-share__start\" onClick={onStart}>\n Start shared session\n </button>\n <p className=\"fai-share__hint\">\n Generates a session id + secret token. Hand the <strong>Agent prompt</strong> to an AI agent, share the URL with humans, or give the JSON config to an MCP-capable client.\n </p>\n </div>\n );\n }\n\n const url = buildShareUrl(session, shareBaseUrl);\n const config = buildShareConfig(session);\n const curl = buildCurlRecipe(session);\n const prompt = buildAgentPrompt(url);\n\n return (\n <div className={[\"fai-share fai-share--active\", className ?? \"\"].filter(Boolean).join(\" \")} style={style}>\n <div className=\"fai-share__header\">\n <div>\n <strong>Sharing</strong>\n <span className=\"fai-share__id\">\n session <code>{session.id}</code> · token <code>{session.display}…</code>\n </span>\n </div>\n <div className=\"fai-share__header-actions\">\n {status && <span className=\"fai-share__status\">{status}</span>}\n <button type=\"button\" className=\"fai-share__stop\" onClick={onStop}>\n Stop\n </button>\n </div>\n </div>\n\n <div className=\"fai-share__tabs\" role=\"tablist\">\n <TabButton tab=\"prompt\" active={tab} setTab={setTab}>Agent prompt</TabButton>\n <TabButton tab=\"url\" active={tab} setTab={setTab}>URL</TabButton>\n <TabButton tab=\"json\" active={tab} setTab={setTab}>JSON</TabButton>\n <TabButton tab=\"curl\" active={tab} setTab={setTab}>cURL recipe</TabButton>\n </div>\n\n <div className=\"fai-share__panel\">\n {tab === \"prompt\" && (\n <CopyBox\n label=\"Paste this straight into an AI agent — it connects over MCP, no browser\"\n value={prompt}\n multiline\n />\n )}\n {tab === \"url\" && <CopyBox label=\"Open this URL in another tab to join the session\" value={url} />}\n {tab === \"json\" && (\n <CopyBox\n label=\"Paste into Claude Desktop / Cline MCP server config\"\n value={JSON.stringify(config, null, 2)}\n />\n )}\n {tab === \"curl\" && (\n <CopyBox\n label=\"Connect from a terminal (verifies the relay is reachable)\"\n value={curl}\n multiline\n />\n )}\n </div>\n </div>\n );\n}\n\nfunction TabButton({ tab, active, setTab, children }: { tab: Tab; active: Tab; setTab: (t: Tab) => void; children: React.ReactNode }) {\n return (\n <button\n type=\"button\"\n role=\"tab\"\n aria-selected={tab === active}\n className={`fai-share__tab${tab === active ? \" is-active\" : \"\"}`}\n onClick={() => setTab(tab)}\n >\n {children}\n </button>\n );\n}\n\nfunction CopyBox({ label, value, multiline }: { label: string; value: string; multiline?: boolean }) {\n const [copied, setCopied] = useState(false);\n const copy = async () => {\n try {\n await navigator.clipboard.writeText(value);\n setCopied(true);\n setTimeout(() => setCopied(false), 1200);\n } catch {\n // ignore\n }\n };\n return (\n <div>\n <div className=\"fai-share__panel-label\">{label}</div>\n <div className=\"fai-share__copy\">\n <pre className={`fai-share__pre${multiline ? \" is-multi\" : \"\"}`}>{value}</pre>\n <button type=\"button\" className=\"fai-share__copy-btn\" onClick={copy}>\n {copied ? \"Copied\" : \"Copy\"}\n </button>\n </div>\n </div>\n );\n}\n\n/**\n * Build a copy-paste natural-language prompt to hand directly to an AI agent.\n * Agents handed a bare URL tend to try to *open it in a browser* — this spells\n * out that the link is a live MCP co-browsing session it should drive over MCP\n * tools (via the zero-install relay client), never visit.\n */\nexport function buildAgentPrompt(url: string): string {\n return [\n `You're joining a live Human+ co-browsing session on a web app. This is an MCP`,\n `(Model Context Protocol) session — NOT a website to visit. Do NOT open the URL`,\n `in a browser and do NOT use any browser/Playwright tool. You drive the real,`,\n `running app through MCP tools while a human watches and can take over.`,\n ``,\n `Session link (carries the session id + token — treat it as a secret):`,\n ` ${url}`,\n ``,\n `Connect by running the relay client as an MCP server (zero install):`,\n ` npx -y mcp-relay-client \"${url}\"`,\n ``,\n `That exposes the app's own tools (e.g. page_describe, page_read, nav_visit,`,\n `page_click, page_set_field, page_submit, plus surface tools like whiteboard_*).`,\n `Then:`,\n ` 1. Call page_describe first to see the current page and its interactive handles.`,\n ` 2. Act only on the STABLE HANDLES the tools return — never guess DOM selectors.`,\n ` 3. Navigate with nav_visit, type with page_set_field, click with page_click.`,\n ` Submits and destructive clicks are staged for the human to confirm.`,\n ``,\n `If you can't register an MCP server but can run a shell, drive it directly:`,\n ` curl -O https://raw.githubusercontent.com/Particle-Academy/mcp-relay-client/main/connect.sh`,\n ` bash connect.sh \"${url}\" tools`,\n ` bash connect.sh \"${url}\" call page_describe '{}'`,\n ].join(\"\\n\");\n}\n\n/** Build a copy-paste cURL recipe for connecting an external MCP client. */\nfunction buildCurlRecipe(session: SessionDescriptor): string {\n const base =\n typeof window !== \"undefined\"\n ? `${window.location.protocol}//${window.location.host}`\n : \"http://localhost\";\n const inbox = `${base}/agent-relay/${session.id}/inbox?token=${session.token}`;\n const events = `${base}/agent-relay/${session.id}/events?token=${session.token}`;\n return [\n `# 1) In one terminal, subscribe to server-pushed frames (SSE)`,\n `curl -N \"${events}\"`,\n ``,\n `# 2) In another terminal, send an initialize handshake`,\n `curl -X POST \"${inbox}\" \\\\`,\n ` -H 'content-type: application/json' \\\\`,\n ` -d '{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"initialize\",\"params\":{}}'`,\n ``,\n `# 3) List the tools the bridge exposes`,\n `curl -X POST \"${inbox}\" \\\\`,\n ` -H 'content-type: application/json' \\\\`,\n ` -d '{\"jsonrpc\":\"2.0\",\"id\":2,\"method\":\"tools/list\"}'`,\n ``,\n `# 4) Add a sticky note`,\n `curl -X POST \"${inbox}\" \\\\`,\n ` -H 'content-type: application/json' \\\\`,\n ` -d '{\"jsonrpc\":\"2.0\",\"id\":3,\"method\":\"tools/call\",\"params\":{\"name\":\"whiteboard_add_sticky\",\"arguments\":{\"x\":300,\"y\":300,\"text\":\"hello from curl\"}}}'`,\n ].join(\"\\n\");\n}\n"]}
1
+ {"version":3,"sources":["../src/components/AgentPanel/AgentPanel.tsx","../src/components/AgentCursor/AgentCursor.tsx","../src/components/AgentActivityHighlight/AgentActivityHighlight.tsx","../src/components/ShareControls/ShareControls.tsx"],"names":["jsxs","jsx","useEffect","useState"],"mappings":"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","file":"chunk-HSI5RVF4.js","sourcesContent":["import { type CSSProperties, type ReactNode, useEffect, useRef } from \"react\";\n\nexport type AgentActivity = {\n id: string;\n /** Wall-clock timestamp; component formats it. */\n at: number;\n /** \"tool\" for MCP tool invocations, \"message\" for chat, \"info\" for status. */\n kind: \"tool\" | \"message\" | \"info\" | \"error\";\n /** Short label, e.g. \"whiteboard_add_sticky\" or \"Agent\". */\n source: string;\n /** Body text. */\n text: string;\n /** Optional structured payload, rendered as collapsed JSON. */\n detail?: unknown;\n};\n\nexport type AgentPanelProps = {\n /** The agent's identity (name + color appears in the header). */\n agent?: { name?: string; color?: string };\n /** Activity stream. Most recent at the end. */\n activity: AgentActivity[];\n /** Optional chat composer — pass an onSubmit to enable. */\n onSubmit?: (message: string) => void;\n /** Disabled while a request is in flight. */\n busy?: boolean;\n /** Right-rail header actions. */\n actions?: ReactNode;\n className?: string;\n style?: CSSProperties;\n};\n\n/**\n * AgentPanel — sidebar showing the agent's identity, a tool-and-chat log,\n * and an optional input composer. Pure presentational: hosts feed it the\n * activity stream from their own state (typically the MCP transport log).\n */\nexport function AgentPanel({ agent, activity, onSubmit, busy, actions, className, style }: AgentPanelProps) {\n const scrollRef = useRef<HTMLDivElement>(null);\n const inputRef = useRef<HTMLTextAreaElement>(null);\n\n useEffect(() => {\n const el = scrollRef.current;\n if (!el) return;\n el.scrollTop = el.scrollHeight;\n }, [activity.length]);\n\n const handleSubmit = (e: React.FormEvent) => {\n e.preventDefault();\n const value = inputRef.current?.value.trim();\n if (!value || !onSubmit) return;\n onSubmit(value);\n if (inputRef.current) inputRef.current.value = \"\";\n };\n\n const color = agent?.color ?? \"#a855f7\";\n const name = agent?.name ?? \"Agent\";\n\n return (\n <div className={[\"fai-panel\", className ?? \"\"].filter(Boolean).join(\" \")} style={style}>\n <header className=\"fai-panel__header\">\n <div\n className=\"fai-panel__avatar\"\n style={{ background: color }}\n aria-hidden\n >\n {name.slice(0, 1)}\n </div>\n <div className=\"fai-panel__title\">\n <strong>{name}</strong>\n <span className=\"fai-panel__subtitle\">\n {busy ? \"Working…\" : `${activity.length} event${activity.length === 1 ? \"\" : \"s\"}`}\n </span>\n </div>\n {actions && <div className=\"fai-panel__actions\">{actions}</div>}\n </header>\n\n <div ref={scrollRef} className=\"fai-panel__stream\">\n {activity.length === 0 ? (\n <p className=\"fai-panel__empty\">No activity yet.</p>\n ) : (\n activity.map((a) => <ActivityRow key={a.id} item={a} />)\n )}\n </div>\n\n {onSubmit && (\n <form className=\"fai-panel__composer\" onSubmit={handleSubmit}>\n <textarea\n ref={inputRef}\n className=\"fai-panel__input\"\n placeholder={busy ? \"Working…\" : \"Ask the agent…\"}\n disabled={busy}\n rows={2}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" && !e.shiftKey) {\n e.preventDefault();\n handleSubmit(e as unknown as React.FormEvent);\n }\n }}\n />\n <button type=\"submit\" className=\"fai-panel__send\" disabled={busy}>\n Send\n </button>\n </form>\n )}\n </div>\n );\n}\n\nfunction ActivityRow({ item }: { item: AgentActivity }) {\n const time = formatTime(item.at);\n return (\n <div className={`fai-row fai-row--${item.kind}`}>\n <div className=\"fai-row__meta\">\n <span className=\"fai-row__source\">{item.source}</span>\n <span className=\"fai-row__time\">{time}</span>\n </div>\n <div className=\"fai-row__text\">{item.text}</div>\n {item.detail !== undefined && (\n <details className=\"fai-row__detail\">\n <summary>details</summary>\n <pre>{safeJson(item.detail)}</pre>\n </details>\n )}\n </div>\n );\n}\n\nfunction formatTime(at: number): string {\n const d = new Date(at);\n const hh = d.getHours().toString().padStart(2, \"0\");\n const mm = d.getMinutes().toString().padStart(2, \"0\");\n const ss = d.getSeconds().toString().padStart(2, \"0\");\n return `${hh}:${mm}:${ss}`;\n}\n\nfunction safeJson(v: unknown): string {\n try {\n return JSON.stringify(v, null, 2);\n } catch {\n return String(v);\n }\n}\n","import type { CSSProperties } from \"react\";\n\nexport type AgentCursorProps = {\n x: number;\n y: number;\n name?: string;\n color?: string;\n /** Optional caption shown under the name (e.g. current tool). */\n status?: string;\n className?: string;\n style?: CSSProperties;\n};\n\n/**\n * AgentCursor — on-canvas presence marker for the agent. Drop it inside\n * (or alongside) a fancy-whiteboard <Board> at screen coords matching\n * the agent's reported position.\n */\nexport function AgentCursor({ x, y, name, color = \"#a855f7\", status, className, style }: AgentCursorProps) {\n return (\n <div\n className={[\"fai-cursor\", className ?? \"\"].filter(Boolean).join(\" \")}\n style={{\n position: \"absolute\",\n left: x,\n top: y,\n pointerEvents: \"none\",\n transform: \"translate(-2px, -2px)\",\n ...style,\n }}\n >\n <svg width=\"22\" height=\"22\" viewBox=\"0 0 22 22\" aria-hidden>\n <path\n d=\"M2 2 L2 17 L7 13 L10 19 L12 18 L9 12 L15 12 Z\"\n fill={color}\n stroke=\"white\"\n strokeWidth=\"1.2\"\n />\n </svg>\n {name && (\n <span\n className=\"fai-cursor__tag\"\n style={{ background: color }}\n >\n {name}\n {status ? <em className=\"fai-cursor__status\"> · {status}</em> : null}\n </span>\n )}\n </div>\n );\n}\n","import { type CSSProperties, useEffect, useState } from \"react\";\n\nexport type AgentActivityHighlightProps = {\n /** Bounds of the highlighted item in the parent's coord system. */\n x: number;\n y: number;\n width: number;\n height: number;\n /** Trigger token — change it (e.g. set to Date.now()) to re-fire the pulse. */\n pulseKey?: string | number;\n /** Highlight tint. */\n color?: string;\n /** Pulse duration in ms. Defaults 1200. */\n duration?: number;\n className?: string;\n style?: CSSProperties;\n};\n\n/**\n * AgentActivityHighlight — short pulsing outline that flashes around an\n * item the agent just touched. Position the parent so this can be placed\n * absolutely matching the item's bounds.\n */\nexport function AgentActivityHighlight({\n x,\n y,\n width,\n height,\n pulseKey,\n color = \"#a855f7\",\n duration = 1200,\n className,\n style,\n}: AgentActivityHighlightProps) {\n const [visible, setVisible] = useState(false);\n\n useEffect(() => {\n if (pulseKey === undefined) return;\n setVisible(true);\n const t = setTimeout(() => setVisible(false), duration);\n return () => clearTimeout(t);\n }, [pulseKey, duration]);\n\n if (!visible) return null;\n\n return (\n <div\n className={[\"fai-highlight\", className ?? \"\"].filter(Boolean).join(\" \")}\n style={{\n position: \"absolute\",\n left: x - 4,\n top: y - 4,\n width: width + 8,\n height: height + 8,\n borderRadius: 8,\n boxShadow: `0 0 0 2px ${color}, 0 0 16px ${color}66`,\n pointerEvents: \"none\",\n animation: `fai-pulse ${duration}ms ease-out forwards`,\n ...style,\n }}\n />\n );\n}\n","import { type CSSProperties, useState } from \"react\";\nimport type { SessionDescriptor } from \"../../sharing/token\";\nimport { buildShareConfig, buildShareUrl } from \"../../sharing/token\";\n\nexport type ShareControlsProps = {\n /** The active session, or null when not sharing yet. */\n session: SessionDescriptor | null;\n onStart: () => void;\n onStop: () => void;\n /** Optional connection-state badge text. */\n status?: string;\n /** Override the URL base used in the share URL. */\n shareBaseUrl?: string;\n className?: string;\n style?: CSSProperties;\n};\n\ntype Tab = \"prompt\" | \"url\" | \"json\" | \"curl\";\n\n/**\n * ShareControls — the host-facing UI for turning sharing on/off and\n * surfacing the resulting connection details (URL / JSON / cURL).\n */\nexport function ShareControls({\n session,\n onStart,\n onStop,\n status,\n shareBaseUrl,\n className,\n style,\n}: ShareControlsProps) {\n const [tab, setTab] = useState<Tab>(\"prompt\");\n\n if (!session) {\n return (\n <div className={[\"fai-share fai-share--idle\", className ?? \"\"].filter(Boolean).join(\" \")} style={style}>\n <button type=\"button\" className=\"fai-share__start\" onClick={onStart}>\n Start shared session\n </button>\n <p className=\"fai-share__hint\">\n Generates a session id + secret token. Hand the <strong>Agent prompt</strong> to an AI agent, share the URL with humans, or give the JSON config to an MCP-capable client.\n </p>\n </div>\n );\n }\n\n const url = buildShareUrl(session, shareBaseUrl);\n const config = buildShareConfig(session);\n const curl = buildCurlRecipe(session);\n const prompt = buildAgentPrompt(url);\n\n return (\n <div className={[\"fai-share fai-share--active\", className ?? \"\"].filter(Boolean).join(\" \")} style={style}>\n <div className=\"fai-share__header\">\n <div>\n <strong>Sharing</strong>\n <span className=\"fai-share__id\">\n session <code>{session.id}</code> · token <code>{session.display}…</code>\n </span>\n </div>\n <div className=\"fai-share__header-actions\">\n {status && <span className=\"fai-share__status\">{status}</span>}\n <button type=\"button\" className=\"fai-share__stop\" onClick={onStop}>\n Stop\n </button>\n </div>\n </div>\n\n <div className=\"fai-share__tabs\" role=\"tablist\">\n <TabButton tab=\"prompt\" active={tab} setTab={setTab}>Agent prompt</TabButton>\n <TabButton tab=\"url\" active={tab} setTab={setTab}>URL</TabButton>\n <TabButton tab=\"json\" active={tab} setTab={setTab}>JSON</TabButton>\n <TabButton tab=\"curl\" active={tab} setTab={setTab}>cURL recipe</TabButton>\n </div>\n\n <div className=\"fai-share__panel\">\n {tab === \"prompt\" && (\n <CopyBox\n label=\"Paste this straight into an AI agent — it connects over MCP, no browser\"\n value={prompt}\n multiline\n />\n )}\n {tab === \"url\" && <CopyBox label=\"Open this URL in another tab to join the session\" value={url} />}\n {tab === \"json\" && (\n <CopyBox\n label=\"Paste into Claude Desktop / Cline MCP server config\"\n value={JSON.stringify(config, null, 2)}\n />\n )}\n {tab === \"curl\" && (\n <CopyBox\n label=\"Connect from a terminal (verifies the relay is reachable)\"\n value={curl}\n multiline\n />\n )}\n </div>\n </div>\n );\n}\n\nfunction TabButton({ tab, active, setTab, children }: { tab: Tab; active: Tab; setTab: (t: Tab) => void; children: React.ReactNode }) {\n return (\n <button\n type=\"button\"\n role=\"tab\"\n aria-selected={tab === active}\n className={`fai-share__tab${tab === active ? \" is-active\" : \"\"}`}\n onClick={() => setTab(tab)}\n >\n {children}\n </button>\n );\n}\n\nfunction CopyBox({ label, value, multiline }: { label: string; value: string; multiline?: boolean }) {\n const [copied, setCopied] = useState(false);\n const copy = async () => {\n try {\n await navigator.clipboard.writeText(value);\n setCopied(true);\n setTimeout(() => setCopied(false), 1200);\n } catch {\n // ignore\n }\n };\n return (\n <div>\n <div className=\"fai-share__panel-label\">{label}</div>\n <div className=\"fai-share__copy\">\n <pre className={`fai-share__pre${multiline ? \" is-multi\" : \"\"}`}>{value}</pre>\n <button type=\"button\" className=\"fai-share__copy-btn\" onClick={copy}>\n {copied ? \"Copied\" : \"Copy\"}\n </button>\n </div>\n </div>\n );\n}\n\n/**\n * Build a copy-paste natural-language prompt to hand directly to an AI agent.\n * Agents handed a bare URL tend to try to *open it in a browser* — this spells\n * out that the link is a live MCP co-browsing session it should drive over MCP\n * tools (via the zero-install relay client), never visit.\n */\nexport function buildAgentPrompt(url: string): string {\n return [\n `You're joining a live Human+ co-browsing session on a web app. This is an MCP`,\n `(Model Context Protocol) session — NOT a website to visit. Do NOT open the URL`,\n `in a browser and do NOT use any browser/Playwright tool. You drive the real,`,\n `running app through MCP tools while a human watches and can take over.`,\n ``,\n `Session link (carries the session id + token — treat it as a secret):`,\n ` ${url}`,\n ``,\n `Connect by running the relay client as an MCP server (zero install):`,\n ` npx -y mcp-relay-client \"${url}\"`,\n ``,\n `That exposes the app's own tools (e.g. page_describe, page_read, nav_visit,`,\n `page_click, page_set_field, page_submit, plus surface tools like whiteboard_*).`,\n `Then:`,\n ` 1. Call page_describe first to see the current page and its interactive handles.`,\n ` 2. Act only on the STABLE HANDLES the tools return — never guess DOM selectors.`,\n ` 3. Navigate with nav_visit, type with page_set_field, click with page_click.`,\n ` Submits and destructive clicks are staged for the human to confirm.`,\n ``,\n `If you can't register an MCP server but can run a shell, drive it directly:`,\n ` curl -O https://raw.githubusercontent.com/Particle-Academy/mcp-relay-client/main/connect.sh`,\n ` bash connect.sh \"${url}\" tools`,\n ` bash connect.sh \"${url}\" call page_describe '{}'`,\n ].join(\"\\n\");\n}\n\n/** Build a copy-paste cURL recipe for connecting an external MCP client. */\nfunction buildCurlRecipe(session: SessionDescriptor): string {\n const base =\n typeof window !== \"undefined\"\n ? `${window.location.protocol}//${window.location.host}`\n : \"http://localhost\";\n const inbox = `${base}/agent-relay/${session.id}/inbox?token=${session.token}`;\n const events = `${base}/agent-relay/${session.id}/events?token=${session.token}`;\n return [\n `# 1) In one terminal, subscribe to server-pushed frames (SSE)`,\n `curl -N \"${events}\"`,\n ``,\n `# 2) In another terminal, send an initialize handshake`,\n `curl -X POST \"${inbox}\" \\\\`,\n ` -H 'content-type: application/json' \\\\`,\n ` -d '{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"initialize\",\"params\":{}}'`,\n ``,\n `# 3) List the tools the bridge exposes`,\n `curl -X POST \"${inbox}\" \\\\`,\n ` -H 'content-type: application/json' \\\\`,\n ` -d '{\"jsonrpc\":\"2.0\",\"id\":2,\"method\":\"tools/list\"}'`,\n ``,\n `# 4) Add a sticky note`,\n `curl -X POST \"${inbox}\" \\\\`,\n ` -H 'content-type: application/json' \\\\`,\n ` -d '{\"jsonrpc\":\"2.0\",\"id\":3,\"method\":\"tools/call\",\"params\":{\"name\":\"whiteboard_add_sticky\",\"arguments\":{\"x\":300,\"y\":300,\"text\":\"hello from curl\"}}}'`,\n ].join(\"\\n\");\n}\n"]}
@@ -1,5 +1,5 @@
1
1
  import { ensureUndoToolsRegistered, pushUndoEntry } from './chunk-CT3LRNH7.js';
2
- import { wrapToolWithActivity } from './chunk-ULJL53DL.js';
2
+ import { wrapToolWithActivity } from './chunk-2VENWGLZ.js';
3
3
  import { textResult, errorResult } from './chunk-DF3PLL2E.js';
4
4
  import { treeReducer, autoApply, childrenOf, appendOrder, descendantsOf } from '@particle-academy/fancy-doc-commons';
5
5
 
@@ -241,5 +241,5 @@ function registerDocBridge(host, options) {
241
241
  }
242
242
 
243
243
  export { registerDocBridge };
244
- //# sourceMappingURL=chunk-AF454WRD.js.map
245
- //# sourceMappingURL=chunk-AF454WRD.js.map
244
+ //# sourceMappingURL=chunk-LQZKRBWR.js.map
245
+ //# sourceMappingURL=chunk-LQZKRBWR.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/bridges/doc.ts"],"names":[],"mappings":"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","file":"chunk-AF454WRD.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 const mintId = () => adapter.newId?.() ?? `${surface}-${(idSeq += 1)}`;\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 /** Auto-apply, or stage for confirmation per the stage policy. */\n function submit(op: TOp, label: string, targetId?: string): { staged: boolean; id?: string } {\n if (stage(op) === \"confirm\") {\n const id = `${surface}-pending-${(idSeq += 1)}`;\n pending.set(id, { op, label, targetId });\n options.onPending?.({ id, op, label });\n return { staged: true, id };\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 },\n [\"type\"],\n (args) => {\n const tree = adapter.get();\n const parent = typeof args.parent === \"string\" ? args.parent : null;\n const id = 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}` : `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}` : `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}` : `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}` : `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}` : 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 by its pending id (from a staged mutation).\",\n { id: { type: \"string\" } },\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 by its pending id.\",\n { id: { type: \"string\" } },\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
+ {"version":3,"sources":["../src/bridges/doc.ts"],"names":[],"mappings":"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","file":"chunk-LQZKRBWR.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 const mintId = () => adapter.newId?.() ?? `${surface}-${(idSeq += 1)}`;\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 /** Auto-apply, or stage for confirmation per the stage policy. */\n function submit(op: TOp, label: string, targetId?: string): { staged: boolean; id?: string } {\n if (stage(op) === \"confirm\") {\n const id = `${surface}-pending-${(idSeq += 1)}`;\n pending.set(id, { op, label, targetId });\n options.onPending?.({ id, op, label });\n return { staged: true, id };\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 },\n [\"type\"],\n (args) => {\n const tree = adapter.get();\n const parent = typeof args.parent === \"string\" ? args.parent : null;\n const id = 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}` : `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}` : `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}` : `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}` : `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}` : 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 by its pending id (from a staged mutation).\",\n { id: { type: \"string\" } },\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 by its pending id.\",\n { id: { type: \"string\" } },\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"]}
@@ -12,8 +12,7 @@ function describeSession(id, token) {
12
12
  }
13
13
  function buildShareUrl(descriptor, baseUrl = typeof window !== "undefined" ? window.location.href.split("?")[0] : "") {
14
14
  const u = new URL(baseUrl);
15
- u.searchParams.set("session", descriptor.id);
16
- u.searchParams.set("token", descriptor.token);
15
+ u.hash = new URLSearchParams({ session: descriptor.id, token: descriptor.token }).toString();
17
16
  return u.toString();
18
17
  }
19
18
  function buildShareConfig(descriptor, transport = "broadcast-channel") {
@@ -28,9 +27,10 @@ function buildShareConfig(descriptor, transport = "broadcast-channel") {
28
27
  }
29
28
  function readSessionFromUrl() {
30
29
  if (typeof window === "undefined") return null;
31
- const params = new URL(window.location.href).searchParams;
32
- const id = params.get("session");
33
- const token = params.get("token");
30
+ const url = new URL(window.location.href);
31
+ const frag = new URLSearchParams(url.hash.replace(/^#/, ""));
32
+ const id = frag.get("session") ?? url.searchParams.get("session");
33
+ const token = frag.get("token") ?? url.searchParams.get("token");
34
34
  if (!id || !token) return null;
35
35
  return describeSession(id, token);
36
36
  }
@@ -224,5 +224,5 @@ function attachSseRelay(server, options) {
224
224
  }
225
225
 
226
226
  export { SseRelayTransport, attachSseRelay, buildShareConfig, buildShareUrl, constantTimeEqual, createSessionDescriptor, describeSession, readSessionFromUrl };
227
- //# sourceMappingURL=chunk-KMSRG5KH.js.map
228
- //# sourceMappingURL=chunk-KMSRG5KH.js.map
227
+ //# sourceMappingURL=chunk-N6RLSLOF.js.map
228
+ //# sourceMappingURL=chunk-N6RLSLOF.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/sharing/token.ts","../src/sharing/sse-relay.ts"],"names":[],"mappings":"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","file":"chunk-N6RLSLOF.js","sourcesContent":["/**\n * Session-token utilities. The token is a high-entropy secret; possession\n * grants read/write on the session. We don't HMAC frames — frames carry\n * the token directly (which is fine for in-process / same-origin / TLS\n * transports). For lower-trust transports, host apps can layer signing\n * on top of the BroadcastChannelTransport.\n */\n\nconst TOKEN_BYTES = 24; // 192 bits, base64url-encoded → 32 chars\n\nexport type SessionDescriptor = {\n /** Stable session identifier. Channel name = `fai:share:${id}`. */\n id: string;\n /** Secret token. Treat as a password — anyone with it can read/write. */\n token: string;\n /** Pretty hash for display (first 8 chars of token). */\n display: string;\n};\n\nexport function createSessionDescriptor(): SessionDescriptor {\n const id = randomId(8);\n const token = randomToken();\n return { id, token, display: token.slice(0, 8) };\n}\n\nexport function describeSession(id: string, token: string): SessionDescriptor {\n return { id, token, display: token.slice(0, 8) };\n}\n\n/**\n * Build the shareable URL for the current page (preserves path, adds\n * session+token in the URL FRAGMENT).\n *\n * The token goes in the `#fragment`, never the `?query`: a fragment is never\n * transmitted to the server, so it can't leak through access/proxy logs or the\n * `Referer` header sent to third-party assets on the page. The recipient reads\n * it back with {@link readSessionFromUrl}. (The on-wire relay leg still sends\n * `?token=` today — moving that off the query is the larger transport change.)\n */\nexport function buildShareUrl(\n descriptor: SessionDescriptor,\n baseUrl: string = typeof window !== \"undefined\" ? window.location.href.split(\"?\")[0] : \"\",\n): string {\n const u = new URL(baseUrl);\n u.hash = new URLSearchParams({ session: descriptor.id, token: descriptor.token }).toString();\n return u.toString();\n}\n\n/** Build the JSON config form (suitable for Claude Desktop / Cline / etc.). */\nexport function buildShareConfig(descriptor: SessionDescriptor, transport = \"broadcast-channel\") {\n return {\n name: `whiteboard-${descriptor.id}`,\n transport,\n session: descriptor.id,\n token: descriptor.token,\n channel: `fai:share:${descriptor.id}`,\n protocol_version: \"2025-06-18\",\n };\n}\n\n/**\n * Read session descriptor from the current URL, or null if not a shared link.\n * Prefers the fragment (the non-leaking form {@link buildShareUrl} now emits),\n * falling back to the query string for links minted before that change.\n */\nexport function readSessionFromUrl(): SessionDescriptor | null {\n if (typeof window === \"undefined\") return null;\n const url = new URL(window.location.href);\n const frag = new URLSearchParams(url.hash.replace(/^#/, \"\"));\n const id = frag.get(\"session\") ?? url.searchParams.get(\"session\");\n const token = frag.get(\"token\") ?? url.searchParams.get(\"token\");\n if (!id || !token) return null;\n return describeSession(id, token);\n}\n\nfunction randomToken(): string {\n const bytes = new Uint8Array(TOKEN_BYTES);\n crypto.getRandomValues(bytes);\n return base64Url(bytes);\n}\n\nfunction randomId(len: number): string {\n const bytes = new Uint8Array(Math.ceil((len * 3) / 4));\n crypto.getRandomValues(bytes);\n return base64Url(bytes).slice(0, len);\n}\n\nfunction base64Url(bytes: Uint8Array): string {\n let s = \"\";\n for (const b of bytes) s += String.fromCharCode(b);\n return btoa(s).replace(/\\+/g, \"-\").replace(/\\//g, \"_\").replace(/=+$/, \"\");\n}\n\n/** Constant-time string compare so a mismatched token leaks no timing info. */\nexport function constantTimeEqual(a: string, b: string): boolean {\n if (a.length !== b.length) return false;\n let diff = 0;\n for (let i = 0; i < a.length; i++) diff |= a.charCodeAt(i) ^ b.charCodeAt(i);\n return diff === 0;\n}\n","import type { JsonRpcMessage } from \"../mcp/types\";\nimport type { Transport } from \"../mcp/server\";\nimport type { MicroMcpServer } from \"../mcp/server\";\nimport type { RelayChannelHandle } from \"@particle-academy/fancy-cf-relay\";\nimport { constantTimeEqual } from \"./token\";\nimport { emitActivity } from \"../presence/registry\";\n\n/**\n * SseRelayTransport — bridges the in-page MicroMcpServer to a host-app\n * relay broker over Server-Sent Events (inbound) + POST (outbound).\n *\n * Wire model:\n * - Browser opens an EventSource at `${baseUrl}/${sessionId}/events?token=…`.\n * Each `event: mcp` carries one JSON-RPC frame from a remote client.\n * - Browser POSTs JSON-RPC frames to `${baseUrl}/${sessionId}/outbox?token=…`\n * when the local server has a response/notification to send.\n *\n * The host provides the relay endpoint (any HTTP server). See the demo\n * `WhiteboardShareController` for the reference implementation.\n *\n * Token authentication is the host's job — this transport just carries the\n * token in the query string. For lower-trust deployments, layer signing on\n * top by wrapping `send` / `deliverFromRemote`.\n */\nexport type SseRelayOptions = {\n baseUrl: string;\n sessionId: string;\n token: string;\n /** Override fetch (testing / non-browser). Defaults to global fetch. */\n fetch?: typeof fetch;\n};\n\nexport class SseRelayTransport implements Transport {\n private server?: MicroMcpServer;\n private es?: EventSource;\n private channel?: RelayChannelHandle;\n private disposed = false;\n private opts: SseRelayOptions;\n private sendQueue: JsonRpcMessage[] = [];\n private connected = false;\n private listeners = new Set<(state: RelayState) => void>();\n private state: RelayState = \"idle\";\n private expectedToken: string;\n private peers = new Set<string>();\n\n constructor(options: SseRelayOptions) {\n this.opts = options;\n this.expectedToken = options.token;\n }\n\n bindServer(server: MicroMcpServer): void {\n this.server = server;\n }\n\n /** Open the receive channel. Idempotent. */\n start(): void {\n if (this.connected || this.disposed || typeof window === \"undefined\") return;\n this.setState(\"connecting\");\n // Prefer @particle-academy/fancy-cf-relay's adaptive channel (auto SSE↔\n // long-poll with Cloudflare detection) so the receive leg survives a\n // Cloudflare HTTP/3 (QUIC) edge that resets long-lived SSE streams. It's an\n // OPTIONAL peer: if it isn't installed, fall back to a plain EventSource.\n void import(\"@particle-academy/fancy-cf-relay\")\n .then(({ createRelayChannel }) => {\n if (this.connected || this.disposed) return;\n this.channel = createRelayChannel({\n baseUrl: this.opts.baseUrl,\n session: this.opts.sessionId,\n token: this.opts.token,\n transport: \"auto\",\n receiveDirection: \"inbound\",\n sendPath: \"outbox\",\n onFrame: (raw) => this.handleInbound(raw),\n onOpen: () => this.markOpen(),\n onError: () => this.setState(\"error\"),\n fetchImpl: this.opts.fetch,\n });\n this.channel.start();\n })\n .catch(() => {\n if (!this.disposed) this.startSse();\n });\n }\n\n /** Fallback receive leg: a plain EventSource (no fancy-cf-relay installed). */\n private startSse(): void {\n if (this.connected || this.disposed) return;\n const url = `${this.opts.baseUrl}/${encodeURIComponent(this.opts.sessionId)}/events?token=${encodeURIComponent(this.opts.token)}`;\n const es = new EventSource(url, { withCredentials: false });\n this.es = es;\n es.addEventListener(\"open\", () => this.markOpen());\n es.addEventListener(\"mcp\", (ev: MessageEvent) => this.handleInbound(ev.data));\n es.addEventListener(\"error\", () => this.setState(\"error\")); // EventSource auto-reconnects\n }\n\n /** Mark the channel live + flush any queued outbound frames. */\n private markOpen(): void {\n this.connected = true;\n this.setState(\"open\");\n const queued = this.sendQueue.splice(0);\n for (const msg of queued) this.postOut(msg);\n }\n\n send(message: JsonRpcMessage): void {\n if (!this.connected) {\n this.sendQueue.push(message);\n return;\n }\n this.postOut(message);\n }\n\n close(): void {\n this.disposed = true;\n this.channel?.stop();\n this.channel = undefined;\n this.es?.close();\n this.es = undefined;\n this.connected = false;\n this.setState(\"closed\");\n }\n\n onStateChange(listener: (state: RelayState) => void): () => void {\n this.listeners.add(listener);\n listener(this.state);\n return () => this.listeners.delete(listener);\n }\n\n /**\n * For relays that wrap each frame with auth metadata: hosts can call this\n * directly when a frame arrives via a non-SSE path. The transport will\n * dispatch it to the bound server.\n */\n async deliverFromRemote(payload: JsonRpcMessage | string, token?: string): Promise<void> {\n if (token !== undefined && !constantTimeEqual(token, this.expectedToken)) return;\n if (!this.server) throw new Error(\"SseRelayTransport has no bound server\");\n const message: JsonRpcMessage = typeof payload === \"string\" ? JSON.parse(payload) : payload;\n await this.server.receive(this, message);\n }\n\n private async postOut(message: JsonRpcMessage): Promise<void> {\n const url = `${this.opts.baseUrl}/${encodeURIComponent(this.opts.sessionId)}/outbox?token=${encodeURIComponent(this.opts.token)}`;\n const f = this.opts.fetch ?? fetch;\n try {\n await f(url, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\", \"accept\": \"application/json\" },\n body: JSON.stringify(message),\n });\n } catch {\n // Drop — relay errors are surfaced via state change separately.\n }\n }\n\n private async handleInbound(raw: string): Promise<void> {\n if (!this.server) return;\n let message: JsonRpcMessage;\n try {\n message = JSON.parse(raw);\n } catch {\n return;\n }\n if (\"method\" in message && message.method === \"notifications/peer_joined\") {\n const subscriberId = String((message.params as { subscriberId?: unknown } | undefined)?.subscriberId ?? \"peer\");\n this.peers.add(subscriberId);\n emitActivity({\n agentId: \"agent\",\n agentName: \"Agent\",\n agentColor: \"#a855f7\",\n action: \"agent_connected\",\n timestamp: Date.now(),\n target: { kind: \"navigation\", label: \"Agent connected\" },\n meta: { subscriberId },\n });\n return;\n }\n if (\"method\" in message && message.method === \"notifications/peer_left\") {\n const subscriberId = String((message.params as { subscriberId?: unknown } | undefined)?.subscriberId ?? \"peer\");\n this.peers.delete(subscriberId);\n if (this.peers.size === 0) {\n emitActivity({\n agentId: \"agent\",\n agentName: \"Agent\",\n agentColor: \"#a855f7\",\n action: \"agent_disconnected\",\n timestamp: Date.now(),\n target: { kind: \"navigation\", label: \"Agent disconnected\" },\n meta: { subscriberId },\n });\n }\n return;\n }\n await this.server.receive(this, message);\n }\n\n private setState(state: RelayState): void {\n this.state = state;\n for (const l of this.listeners) l(state);\n }\n}\n\nexport type RelayState = \"idle\" | \"connecting\" | \"open\" | \"closed\" | \"error\";\n\nexport function attachSseRelay(server: MicroMcpServer, options: SseRelayOptions): SseRelayTransport {\n const transport = new SseRelayTransport(options);\n transport.bindServer(server);\n server.attach(transport);\n transport.start();\n\n // Forward in-process agent activity events out over the relay so external\n // subscribers can render presence indicators in real time. Uses a dynamic\n // import so the relay doesn't hard-depend on the presence module if it's\n // tree-shaken out.\n import(\"../presence/registry\").then(({ onActivity }) => {\n const off = onActivity((event) => {\n transport.send({\n jsonrpc: \"2.0\",\n method: \"notifications/agent_activity\",\n params: event as any,\n });\n });\n // Tear down the subscription when the transport closes.\n const origClose = transport.close.bind(transport);\n transport.close = () => {\n off();\n origClose();\n };\n }).catch(() => {\n // Presence module unavailable — silently no-op (relay still works).\n });\n\n return transport;\n}\n"]}
@@ -1,5 +1,5 @@
1
1
  import { ensureUndoToolsRegistered, pushUndoEntry } from './chunk-CT3LRNH7.js';
2
- import { wrapToolWithActivity } from './chunk-ULJL53DL.js';
2
+ import { wrapToolWithActivity } from './chunk-2VENWGLZ.js';
3
3
  import { textResult, errorResult } from './chunk-DF3PLL2E.js';
4
4
 
5
5
  // src/bridges/catalog.ts
@@ -304,5 +304,5 @@ function registerCatalogBridge(host, options) {
304
304
  }
305
305
 
306
306
  export { registerCatalogBridge };
307
- //# sourceMappingURL=chunk-NSPL5TVF.js.map
308
- //# sourceMappingURL=chunk-NSPL5TVF.js.map
307
+ //# sourceMappingURL=chunk-OAFJ53X3.js.map
308
+ //# sourceMappingURL=chunk-OAFJ53X3.js.map