@particle-academy/agent-integrations 0.50.0 → 0.51.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 (226) hide show
  1. package/CHANGELOG.md +51 -0
  2. package/README.md +11 -0
  3. package/dist/bridges/artboard.d.cts +3 -3
  4. package/dist/bridges/artboard.d.ts +3 -3
  5. package/dist/bridges/catalog.d.cts +3 -3
  6. package/dist/bridges/catalog.d.ts +3 -3
  7. package/dist/bridges/charts.d.cts +3 -3
  8. package/dist/bridges/charts.d.ts +3 -3
  9. package/dist/bridges/cms.d.cts +3 -3
  10. package/dist/bridges/cms.d.ts +3 -3
  11. package/dist/bridges/code.d.cts +3 -3
  12. package/dist/bridges/code.d.ts +3 -3
  13. package/dist/bridges/doc.d.cts +3 -3
  14. package/dist/bridges/doc.d.ts +3 -3
  15. package/dist/bridges/features.d.cts +3 -3
  16. package/dist/bridges/features.d.ts +3 -3
  17. package/dist/bridges/files.d.cts +3 -3
  18. package/dist/bridges/files.d.ts +3 -3
  19. package/dist/bridges/flow.d.cts +3 -3
  20. package/dist/bridges/flow.d.ts +3 -3
  21. package/dist/bridges/forms.d.cts +3 -3
  22. package/dist/bridges/forms.d.ts +3 -3
  23. package/dist/bridges/git.d.cts +3 -3
  24. package/dist/bridges/git.d.ts +3 -3
  25. package/dist/bridges/grid.d.cts +3 -3
  26. package/dist/bridges/grid.d.ts +3 -3
  27. package/dist/bridges/map.d.cts +3 -3
  28. package/dist/bridges/map.d.ts +3 -3
  29. package/dist/bridges/navigation.d.cts +3 -3
  30. package/dist/bridges/navigation.d.ts +3 -3
  31. package/dist/bridges/passkeys.d.cts +3 -3
  32. package/dist/bridges/passkeys.d.ts +3 -3
  33. package/dist/bridges/scene.d.cts +3 -3
  34. package/dist/bridges/scene.d.ts +3 -3
  35. package/dist/bridges/screen-doc.d.cts +3 -3
  36. package/dist/bridges/screen-doc.d.ts +3 -3
  37. package/dist/bridges/screens.d.cts +3 -3
  38. package/dist/bridges/screens.d.ts +3 -3
  39. package/dist/bridges/sheets.d.cts +3 -3
  40. package/dist/bridges/sheets.d.ts +3 -3
  41. package/dist/bridges/slides.d.cts +3 -3
  42. package/dist/bridges/slides.d.ts +3 -3
  43. package/dist/bridges/terminal.d.cts +3 -3
  44. package/dist/bridges/terminal.d.ts +3 -3
  45. package/dist/bridges/tui.d.cts +2 -2
  46. package/dist/bridges/tui.d.ts +2 -2
  47. package/dist/bridges/whiteboard.d.cts +3 -3
  48. package/dist/bridges/whiteboard.d.ts +3 -3
  49. package/dist/bridges-artboard.cjs +11 -5
  50. package/dist/bridges-artboard.cjs.map +1 -1
  51. package/dist/bridges-artboard.js +6 -4
  52. package/dist/bridges-artboard.js.map +1 -1
  53. package/dist/bridges-catalog.cjs +11 -5
  54. package/dist/bridges-catalog.cjs.map +1 -1
  55. package/dist/bridges-catalog.js +3 -3
  56. package/dist/bridges-charts.cjs +11 -5
  57. package/dist/bridges-charts.cjs.map +1 -1
  58. package/dist/bridges-charts.js +3 -3
  59. package/dist/bridges-cms.cjs +11 -5
  60. package/dist/bridges-cms.cjs.map +1 -1
  61. package/dist/bridges-cms.js +4 -4
  62. package/dist/bridges-code.cjs +11 -5
  63. package/dist/bridges-code.cjs.map +1 -1
  64. package/dist/bridges-code.js +3 -3
  65. package/dist/bridges-doc.cjs +11 -5
  66. package/dist/bridges-doc.cjs.map +1 -1
  67. package/dist/bridges-doc.js +3 -3
  68. package/dist/bridges-features.cjs +11 -5
  69. package/dist/bridges-features.cjs.map +1 -1
  70. package/dist/bridges-features.js +3 -3
  71. package/dist/bridges-files.cjs +11 -5
  72. package/dist/bridges-files.cjs.map +1 -1
  73. package/dist/bridges-files.js +3 -3
  74. package/dist/bridges-flow.cjs +11 -5
  75. package/dist/bridges-flow.cjs.map +1 -1
  76. package/dist/bridges-flow.js +6 -4
  77. package/dist/bridges-flow.js.map +1 -1
  78. package/dist/bridges-forms.cjs +11 -5
  79. package/dist/bridges-forms.cjs.map +1 -1
  80. package/dist/bridges-forms.js +3 -3
  81. package/dist/bridges-git.cjs +10 -5
  82. package/dist/bridges-git.cjs.map +1 -1
  83. package/dist/bridges-git.js +3 -3
  84. package/dist/bridges-grid.cjs +11 -5
  85. package/dist/bridges-grid.cjs.map +1 -1
  86. package/dist/bridges-grid.js +3 -3
  87. package/dist/bridges-map.cjs +11 -5
  88. package/dist/bridges-map.cjs.map +1 -1
  89. package/dist/bridges-map.js +3 -3
  90. package/dist/bridges-navigation.cjs +11 -5
  91. package/dist/bridges-navigation.cjs.map +1 -1
  92. package/dist/bridges-navigation.js +3 -3
  93. package/dist/bridges-passkeys.cjs +11 -5
  94. package/dist/bridges-passkeys.cjs.map +1 -1
  95. package/dist/bridges-passkeys.js +3 -3
  96. package/dist/bridges-scene.cjs +11 -5
  97. package/dist/bridges-scene.cjs.map +1 -1
  98. package/dist/bridges-scene.js +3 -3
  99. package/dist/bridges-screen-doc.cjs +14 -6
  100. package/dist/bridges-screen-doc.cjs.map +1 -1
  101. package/dist/bridges-screen-doc.js +4 -4
  102. package/dist/bridges-screens.cjs +11 -5
  103. package/dist/bridges-screens.cjs.map +1 -1
  104. package/dist/bridges-screens.js +3 -3
  105. package/dist/bridges-sheets.cjs +11 -5
  106. package/dist/bridges-sheets.cjs.map +1 -1
  107. package/dist/bridges-sheets.js +3 -3
  108. package/dist/bridges-slides.cjs +11 -5
  109. package/dist/bridges-slides.cjs.map +1 -1
  110. package/dist/bridges-slides.js +3 -3
  111. package/dist/bridges-terminal.cjs +11 -5
  112. package/dist/bridges-terminal.cjs.map +1 -1
  113. package/dist/bridges-terminal.js +3 -3
  114. package/dist/bridges-tui.cjs +1 -1
  115. package/dist/bridges-tui.cjs.map +1 -1
  116. package/dist/bridges-tui.js +2 -2
  117. package/dist/bridges-whiteboard.cjs +11 -5
  118. package/dist/bridges-whiteboard.cjs.map +1 -1
  119. package/dist/bridges-whiteboard.js +3 -3
  120. package/dist/{chunk-CZV3WUW5.js → chunk-3GFKC6OK.js} +20 -7
  121. package/dist/chunk-3GFKC6OK.js.map +1 -0
  122. package/dist/{chunk-JLHVQWOV.js → chunk-6Q3PMT7K.js} +4 -4
  123. package/dist/chunk-6Q3PMT7K.js.map +1 -0
  124. package/dist/{chunk-AXWMWYH5.js → chunk-C4AQ2YBW.js} +7 -6
  125. package/dist/chunk-C4AQ2YBW.js.map +1 -0
  126. package/dist/{chunk-NH6HUVXQ.js → chunk-CI5ZVHDY.js} +8 -6
  127. package/dist/chunk-CI5ZVHDY.js.map +1 -0
  128. package/dist/{chunk-5ZWNCHZS.js → chunk-CKJL5C7A.js} +8 -6
  129. package/dist/chunk-CKJL5C7A.js.map +1 -0
  130. package/dist/{chunk-HOZCDDRA.js → chunk-CP3EHLZJ.js} +8 -6
  131. package/dist/chunk-CP3EHLZJ.js.map +1 -0
  132. package/dist/{chunk-VFWFT3OK.js → chunk-DNF3QVTW.js} +8 -6
  133. package/dist/chunk-DNF3QVTW.js.map +1 -0
  134. package/dist/{chunk-BG3QXNM6.js → chunk-HNVHAY4A.js} +8 -6
  135. package/dist/chunk-HNVHAY4A.js.map +1 -0
  136. package/dist/{chunk-5M5ELTHE.js → chunk-KAEPC6N4.js} +8 -6
  137. package/dist/chunk-KAEPC6N4.js.map +1 -0
  138. package/dist/{chunk-3WVXAB3D.js → chunk-M423JOQ3.js} +3 -3
  139. package/dist/{chunk-3WVXAB3D.js.map → chunk-M423JOQ3.js.map} +1 -1
  140. package/dist/{chunk-SWWJUOCY.js → chunk-MKC633WU.js} +3 -3
  141. package/dist/{chunk-SWWJUOCY.js.map → chunk-MKC633WU.js.map} +1 -1
  142. package/dist/{chunk-LQB42OSA.js → chunk-MKJE6V4Z.js} +8 -6
  143. package/dist/chunk-MKJE6V4Z.js.map +1 -0
  144. package/dist/{chunk-MIDZWKIF.js → chunk-NB5AQIR2.js} +8 -6
  145. package/dist/chunk-NB5AQIR2.js.map +1 -0
  146. package/dist/{chunk-VMRUW4B4.js → chunk-OUUHFR4N.js} +8 -6
  147. package/dist/chunk-OUUHFR4N.js.map +1 -0
  148. package/dist/{chunk-FCXSR7I5.js → chunk-P6SJBP5T.js} +8 -6
  149. package/dist/chunk-P6SJBP5T.js.map +1 -0
  150. package/dist/{chunk-5JLTXHX6.js → chunk-PMPBI6I3.js} +7 -5
  151. package/dist/chunk-PMPBI6I3.js.map +1 -0
  152. package/dist/{chunk-4WVLZ6YP.js → chunk-PV4FZDYX.js} +8 -6
  153. package/dist/chunk-PV4FZDYX.js.map +1 -0
  154. package/dist/{chunk-3UUF5KKZ.js → chunk-QEVSNDJW.js} +8 -6
  155. package/dist/chunk-QEVSNDJW.js.map +1 -0
  156. package/dist/{chunk-VOCUGTZB.js → chunk-S4DA2UTJ.js} +8 -6
  157. package/dist/chunk-S4DA2UTJ.js.map +1 -0
  158. package/dist/{chunk-RVMM4BHK.js → chunk-V6EHKHSF.js} +8 -6
  159. package/dist/chunk-V6EHKHSF.js.map +1 -0
  160. package/dist/{chunk-36MKPTVD.js → chunk-VE7TRWZR.js} +8 -6
  161. package/dist/chunk-VE7TRWZR.js.map +1 -0
  162. package/dist/{chunk-Z5NL5D4J.js → chunk-VFUKZ6UA.js} +8 -6
  163. package/dist/chunk-VFUKZ6UA.js.map +1 -0
  164. package/dist/{chunk-3HVYUMQF.js → chunk-VHB3VE53.js} +8 -6
  165. package/dist/chunk-VHB3VE53.js.map +1 -0
  166. package/dist/{chunk-R4XXOGQH.js → chunk-ZDKYKJFH.js} +10 -6
  167. package/dist/chunk-ZDKYKJFH.js.map +1 -0
  168. package/dist/components-shared-whiteboard.cjs +29 -10
  169. package/dist/components-shared-whiteboard.cjs.map +1 -1
  170. package/dist/components-shared-whiteboard.js +3 -3
  171. package/dist/dom-navigation/index.d.cts +3 -3
  172. package/dist/dom-navigation/index.d.ts +3 -3
  173. package/dist/index.cjs +96 -44
  174. package/dist/index.cjs.map +1 -1
  175. package/dist/index.d.cts +5 -5
  176. package/dist/index.d.ts +5 -5
  177. package/dist/index.js +26 -26
  178. package/dist/mcp/index.d.cts +5 -5
  179. package/dist/mcp/index.d.ts +5 -5
  180. package/dist/mcp/stdio.d.cts +3 -3
  181. package/dist/mcp/stdio.d.ts +3 -3
  182. package/dist/mcp.cjs +18 -5
  183. package/dist/mcp.cjs.map +1 -1
  184. package/dist/mcp.js +1 -1
  185. package/dist/presence/index.d.cts +1 -1
  186. package/dist/presence/index.d.ts +1 -1
  187. package/dist/{server-1y0n61R5.d.cts → server-DJJygNo1.d.cts} +2 -2
  188. package/dist/{server-vq6qVl3T.d.ts → server-Dwo9LOxh.d.ts} +2 -2
  189. package/dist/sharing/index.d.cts +3 -3
  190. package/dist/sharing/index.d.ts +3 -3
  191. package/dist/sheets-adapter.d.cts +3 -3
  192. package/dist/sheets-adapter.d.ts +3 -3
  193. package/dist/{tool-host-LYfdPE8u.d.ts → tool-host-BBSaU7IJ.d.cts} +10 -4
  194. package/dist/{tool-host-D67N2a2h.d.cts → tool-host-BqJRPr_T.d.ts} +10 -4
  195. package/dist/{types-DP5yQZQU.d.cts → types-D_H2f-wF.d.cts} +1 -1
  196. package/dist/{types-VX_9je7w.d.ts → types-D_TzdBsK.d.ts} +1 -1
  197. package/dist/{types-gzIpsUDE.d.cts → types-ITRQFAir.d.cts} +26 -1
  198. package/dist/{types-gzIpsUDE.d.ts → types-ITRQFAir.d.ts} +26 -1
  199. package/dist/undo/index.d.cts +2 -2
  200. package/dist/undo/index.d.ts +2 -2
  201. package/dist/undo.cjs +7 -3
  202. package/dist/undo.cjs.map +1 -1
  203. package/dist/undo.js +3 -3
  204. package/package.json +1 -1
  205. package/dist/chunk-36MKPTVD.js.map +0 -1
  206. package/dist/chunk-3HVYUMQF.js.map +0 -1
  207. package/dist/chunk-3UUF5KKZ.js.map +0 -1
  208. package/dist/chunk-4WVLZ6YP.js.map +0 -1
  209. package/dist/chunk-5JLTXHX6.js.map +0 -1
  210. package/dist/chunk-5M5ELTHE.js.map +0 -1
  211. package/dist/chunk-5ZWNCHZS.js.map +0 -1
  212. package/dist/chunk-AXWMWYH5.js.map +0 -1
  213. package/dist/chunk-BG3QXNM6.js.map +0 -1
  214. package/dist/chunk-CZV3WUW5.js.map +0 -1
  215. package/dist/chunk-FCXSR7I5.js.map +0 -1
  216. package/dist/chunk-HOZCDDRA.js.map +0 -1
  217. package/dist/chunk-JLHVQWOV.js.map +0 -1
  218. package/dist/chunk-LQB42OSA.js.map +0 -1
  219. package/dist/chunk-MIDZWKIF.js.map +0 -1
  220. package/dist/chunk-NH6HUVXQ.js.map +0 -1
  221. package/dist/chunk-R4XXOGQH.js.map +0 -1
  222. package/dist/chunk-RVMM4BHK.js.map +0 -1
  223. package/dist/chunk-VFWFT3OK.js.map +0 -1
  224. package/dist/chunk-VMRUW4B4.js.map +0 -1
  225. package/dist/chunk-VOCUGTZB.js.map +0 -1
  226. package/dist/chunk-Z5NL5D4J.js.map +0 -1
@@ -1,6 +1,6 @@
1
- import { ensureUndoToolsRegistered, pushUndoEntry } from './chunk-R4XXOGQH.js';
1
+ import { ensureUndoToolsRegistered, pushUndoEntry } from './chunk-ZDKYKJFH.js';
2
2
  import { wrapToolWithActivity } from './chunk-2VENWGLZ.js';
3
- import { textResult, errorResult } from './chunk-CZV3WUW5.js';
3
+ import { textResult, errorResult } from './chunk-3GFKC6OK.js';
4
4
 
5
5
  // src/bridges/files.ts
6
6
  var DEFAULT_AGENT = { id: "agent", name: "Agent", color: "#a855f7" };
@@ -43,6 +43,7 @@ function registerFilesBridge(host, options) {
43
43
  const agent = { ...DEFAULT_AGENT, ...options.agent ?? {} };
44
44
  const pendingMode = options.pendingMode ?? true;
45
45
  const disposers = [];
46
+ const bridgeId = "files";
46
47
  const guard = (path) => {
47
48
  if (options.root !== void 0) assertPathWithinRoot(options.root, path);
48
49
  return path;
@@ -78,7 +79,8 @@ function registerFilesBridge(host, options) {
78
79
  additionalProperties: false
79
80
  }
80
81
  },
81
- final
82
+ final,
83
+ { owner: bridgeId }
82
84
  )
83
85
  );
84
86
  };
@@ -268,7 +270,7 @@ function registerFilesBridge(host, options) {
268
270
  fTarget
269
271
  );
270
272
  return {
271
- id: "files",
273
+ id: bridgeId,
272
274
  title: "Files",
273
275
  dispose: () => {
274
276
  for (const d of disposers) d();
@@ -277,5 +279,5 @@ function registerFilesBridge(host, options) {
277
279
  }
278
280
 
279
281
  export { assertPathWithinRoot, invalidFolderName, registerFilesBridge };
280
- //# sourceMappingURL=chunk-Z5NL5D4J.js.map
281
- //# sourceMappingURL=chunk-Z5NL5D4J.js.map
282
+ //# sourceMappingURL=chunk-VFUKZ6UA.js.map
283
+ //# sourceMappingURL=chunk-VFUKZ6UA.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/bridges/files.ts"],"names":["p"],"mappings":"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","file":"chunk-VFUKZ6UA.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 * Create a folder. **Supplying this is the opt-in** — `files_create_folder`\n * is registered only when it is present, so an agent cannot be handed a write\n * a host never wired, and the advertised tool list tells the truth about what\n * is possible.\n *\n * Pairs with `FileBrowser`'s `onCreateFolder` (react-fancy 5.18+): the same\n * operation the human has, given to the agent.\n */\n createFolder?: (input: { parentPath: string; name: string }) => Promise<void> | void;\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 * Stage writes for human confirmation. Default **true**, matching the\n * catalog bridge's destructive ops.\n *\n * This bridge writes to a filesystem on the strength of a model's output, so\n * the safe mode is the default and turning it off is the deliberate act.\n */\n pendingMode?: boolean;\n /** Host confirm hook for staged writes. Resolves true to proceed. */\n confirm?: (req: { action: string; path: string; label: string }) => Promise<boolean> | boolean;\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 */\n/**\n * Why a folder NAME cannot be used, or `null`.\n *\n * `assertPathWithinRoot` inspects the parent path; the name is appended to it\n * afterwards, so `{ parentPath: \"/root\", name: \"../..\" }` clears that check and\n * still escapes. A name containing a separator is not a name.\n */\nexport function invalidFolderName(name: string): string | null {\n const trimmed = name.trim();\n if (trimmed === \"\") return \"A folder name is required.\";\n if (trimmed.includes(\"/\") || trimmed.includes(\"\\\\\")) return \"A folder name may not contain a path separator.\";\n if (trimmed === \".\" || trimmed === \"..\") return \"That folder name is reserved.\";\n return null;\n}\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 // Strip a trailing slash with `\\/$`, NOT `\\/+$`. The quantified `\\/+$`\n // is a polynomial-ReDoS on paths with many slashes (CodeQL js/polynomial-\n // redos), and the `+` is redundant here: the preceding\n // `.replace(/[\\\\/]+/g, \"/\")` has already collapsed every slash-run to a\n // single `/`, so at most one trailing slash can remain. Non-quantified\n // `\\/$` matches the same input in linear time.\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 pendingMode = options.pendingMode ?? true;\n const disposers: Array<() => void> = [];\n // The bridge id is also its registrant identity on the host: the same bridge\n // may re-register (a remount), a different one claiming a name is refused.\n const bridgeId = \"files\";\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 { owner: bridgeId },\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 // ───────────── Write (staged) ─────────────\n\n if (adapter.createFolder) {\n reg(\n \"files_create_folder\",\n \"Create a folder inside `parentPath`. Staged for human confirmation unless the host disabled pendingMode.\",\n {\n parentPath: { type: \"string\", description: \"Directory to create in; defaults to the current directory.\" },\n name: { type: \"string\", description: \"The new folder's name. A leaf name — no separators.\" },\n confirm: { type: \"boolean\", description: \"Acknowledge a staged write when the host wired no confirm hook.\" },\n },\n [\"name\"],\n async (args) => {\n const parentPath = guard(args.parentPath !== undefined ? str(args.parentPath) : adapter.getPath());\n const name = str(args.name).trim();\n\n const invalid = invalidFolderName(name);\n if (invalid) return errorResult(invalid);\n\n const label = `${parentPath}/${name}`;\n\n if (pendingMode) {\n if (options.confirm) {\n const ok = await options.confirm({ action: \"files_create_folder\", path: label, label });\n if (!ok) return errorResult(`Declined: create folder ${label} (human did not confirm).`);\n } else if (args.confirm !== true) {\n return errorResult(\n `Staged: create folder ${label}. Re-call with confirm:true to proceed.`,\n );\n }\n }\n\n try {\n await adapter.createFolder!({ parentPath, name });\n } catch (e) {\n // The host's filesystem is the authority on what is allowed —\n // permissions, name rules, a race with another writer. Reporting its\n // refusal as success would tell the agent a folder exists that does not.\n return errorResult(e instanceof Error ? e.message : String(e));\n }\n\n return textResult(`Created folder ${label}.`, { parentPath, name, path: label });\n },\n (args) => ({ kind: \"directory\", path: `${str(args.parentPath)}/${str(args.name)}`, label: str(args.name) }),\n );\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: bridgeId,\n title: \"Files\",\n dispose: () => {\n for (const d of disposers) d();\n },\n };\n}\n"]}
@@ -1,6 +1,6 @@
1
- import { ensureUndoToolsRegistered, pushUndoEntry } from './chunk-R4XXOGQH.js';
1
+ import { ensureUndoToolsRegistered, pushUndoEntry } from './chunk-ZDKYKJFH.js';
2
2
  import { wrapToolWithActivity } from './chunk-2VENWGLZ.js';
3
- import { textResult, errorResult } from './chunk-CZV3WUW5.js';
3
+ import { textResult, errorResult } from './chunk-3GFKC6OK.js';
4
4
  import { treeReducer, autoApply, childrenOf, appendOrder, descendantsOf } from '@particle-academy/fancy-doc-commons';
5
5
 
6
6
  var DEFAULT_AGENT = { id: "agent", name: "Agent", color: "#a855f7" };
@@ -12,6 +12,7 @@ function registerDocBridge(host, options) {
12
12
  const makeNode = options.makeNode ?? (({ id, type, parent, order }, props) => ({ id, type, parent, order, props }));
13
13
  const describeNode = options.describeNode ?? ((n) => ({ id: n.id, type: n.type, parent: n.parent, props: Object.keys(n.props ?? {}) }));
14
14
  const disposers = [];
15
+ const bridgeId = surface;
15
16
  ensureUndoToolsRegistered(host, { defaultAgentId: agent.id });
16
17
  let idSeq = 0;
17
18
  const mintId = () => {
@@ -72,7 +73,8 @@ function registerDocBridge(host, options) {
72
73
  disposers.push(
73
74
  host.registerTool(
74
75
  { name, description, inputSchema: { type: "object", properties, required, additionalProperties: false } },
75
- final
76
+ final,
77
+ { owner: bridgeId }
76
78
  )
77
79
  );
78
80
  };
@@ -247,7 +249,7 @@ function registerDocBridge(host, options) {
247
249
  false
248
250
  );
249
251
  return {
250
- id: surface,
252
+ id: bridgeId,
251
253
  title: surface,
252
254
  dispose: () => {
253
255
  for (const d of disposers) d();
@@ -257,5 +259,5 @@ function registerDocBridge(host, options) {
257
259
  }
258
260
 
259
261
  export { registerDocBridge };
260
- //# sourceMappingURL=chunk-3HVYUMQF.js.map
261
- //# sourceMappingURL=chunk-3HVYUMQF.js.map
262
+ //# sourceMappingURL=chunk-VHB3VE53.js.map
263
+ //# sourceMappingURL=chunk-VHB3VE53.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/bridges/doc.ts"],"names":[],"mappings":"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","file":"chunk-VHB3VE53.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 // The bridge id is also its registrant identity on the host: the same bridge\n // may re-register (a remount), a different one claiming a name is refused.\n const bridgeId = surface;\n\n // agent_undo / agent_redo / agent_history — always present (undo derives from\n // the reducer, so every doc surface gets working undo for free).\n ensureUndoToolsRegistered(host, { defaultAgentId: agent.id });\n\n let idSeq = 0;\n // The counter restarts with the bridge, so on a tree loaded from elsewhere\n // `surface-1` may well be taken. Skip past anything that already exists\n // rather than minting an id that silently overwrites a node.\n const mintId = () => {\n if (adapter.newId) return adapter.newId();\n const taken = adapter.get().nodes;\n let id: string;\n do id = `${surface}-${(idSeq += 1)}`;\n while (taken[id]);\n return id;\n };\n const target = (elementId?: string): AgentTarget => ({ kind: surface, screenId: adapter.screenId, elementId });\n\n // Staged ops awaiting confirmation.\n const pending = new Map<string, { op: TOp; label: string; targetId?: string }>();\n\n /** Apply an op immediately: reduce → set → push a snapshot-based undo entry. */\n function commit(op: TOp, label: string, targetId?: string): Record<string, unknown> {\n const prev = adapter.get();\n const next = reducer.reduce(prev, op);\n adapter.set(next);\n pushUndoEntry(agent.id, {\n timestamp: Date.now(),\n bridgeId: surface,\n action: label,\n label,\n undo: () => adapter.set(prev),\n redo: () => adapter.set(next),\n });\n return { ok: true, id: targetId };\n }\n\n /**\n * Auto-apply, or stage for confirmation per the stage policy.\n *\n * The staged case reports the pending id under its OWN key. Returning it as\n * `id` — as this used to — collided with the node id every mutation already\n * reports, so `update`/`remove`/`move` overwrote it and left the agent holding\n * a node id that `confirm` does not accept. The staged write was unconfirmable\n * for three of the four canonical ops, and looked fine from the outside.\n */\n function submit(op: TOp, label: string, targetId?: string): { staged: boolean; id?: string; pendingId?: string } {\n if (stage(op) === \"confirm\") {\n const pendingId = `${surface}-pending-${(idSeq += 1)}`;\n pending.set(pendingId, { op, label, targetId });\n options.onPending?.({ id: pendingId, op, label });\n return { staged: true, id: targetId, pendingId };\n }\n commit(op, label, targetId);\n return { staged: false, id: targetId };\n }\n\n const reg = (\n verb: string,\n description: string,\n properties: Record<string, unknown>,\n required: string[],\n handler: (args: JsonObject) => Record<string, unknown> | Promise<Record<string, unknown>>,\n isMutation: boolean,\n resolveTarget?: (args: JsonObject, result: Record<string, unknown>) => AgentTarget | null,\n ): void => {\n const name = `${surface}_${verb}`;\n const wrapped = async (args: JsonObject) => {\n try {\n // `_text` is the human-facing line; the rest is structuredContent.\n const { _text, ...structured } = await handler(args);\n return textResult(typeof _text === \"string\" ? _text : name, structured);\n } catch (e) {\n return errorResult(e instanceof Error ? e.message : String(e));\n }\n };\n const final = isMutation\n ? wrapToolWithActivity(wrapped, {\n toolName: name,\n agent,\n kind: surface,\n screenId: adapter.screenId,\n resolveTarget: ({ args, result }) => {\n if ((result.structuredContent as JsonObject | undefined)?.staged) return null;\n return resolveTarget?.(args, (result.structuredContent as JsonObject) ?? {}) ?? target();\n },\n })\n : wrapped;\n disposers.push(\n host.registerTool(\n { name, description, inputSchema: { type: \"object\", properties: properties as never, required, additionalProperties: false } },\n final as never,\n { owner: bridgeId },\n ),\n );\n };\n\n // ── Read tools ──────────────────────────────────────────────────────────\n reg(\n \"describe\",\n `Summarize the ${surface} document: node count, roots, and the active surface. Call before reading or writing.`,\n {},\n [],\n () => {\n const tree = adapter.get();\n const ids = Object.keys(tree.nodes);\n return { nodeCount: ids.length, roots: childrenOf(tree, null).map((n) => n.id), _text: `${ids.length} nodes` };\n },\n false,\n );\n reg(\n \"get\",\n `Get the whole ${surface} document tree as JSON.`,\n {},\n [],\n () => ({ tree: adapter.get(), _text: \"full tree\" }),\n false,\n );\n reg(\n \"list\",\n \"List nodes (optionally the children of `parent`), in order.\",\n { parent: { type: [\"string\", \"null\"], description: \"Parent id, or null/omitted for roots.\" } },\n [],\n (args) => {\n const tree = adapter.get();\n const parent = typeof args.parent === \"string\" ? args.parent : null;\n return { nodes: childrenOf(tree, parent).map(describeNode), _text: `children of ${parent ?? \"root\"}` };\n },\n false,\n );\n reg(\n \"get_node\",\n \"Get one node by id.\",\n { id: { type: \"string\" } },\n [\"id\"],\n (args) => {\n const node = adapter.get().nodes[String(args.id)];\n if (!node) throw new Error(`No node ${args.id}`);\n return { node, _text: `node ${node.id}` };\n },\n false,\n );\n\n // ── Canonical op tools ──────────────────────────────────────────────────\n reg(\n \"add\",\n \"Insert a node. Returns its id. Appends under `parent` (or roots) unless `order` is given.\",\n {\n type: { type: \"string\", description: \"Node type discriminant.\" },\n parent: { type: [\"string\", \"null\"], description: \"Parent id, or null for a root.\" },\n props: { type: \"object\", description: \"JSON props bag.\" },\n order: { type: \"string\", description: \"Fractional order key (default: append).\" },\n id: {\n type: \"string\",\n description:\n \"Id for the new node. Supply a meaningful one if you intend to address this node later; omitted means one is minted for you. Must not already exist.\",\n },\n },\n [\"type\"],\n (args) => {\n const tree = adapter.get();\n const parent = typeof args.parent === \"string\" ? args.parent : null;\n // An agent that names the node names the handle it will use afterwards.\n // Minted ids are addressable too, just less memorable.\n const requested = typeof args.id === \"string\" ? args.id : undefined;\n if (requested !== undefined && tree.nodes[requested]) {\n throw new Error(`Node ${requested} already exists — pick a different id or update it instead`);\n }\n const id = requested ?? mintId();\n const order = typeof args.order === \"string\" ? args.order : appendOrder(tree, parent);\n const props = (args.props && typeof args.props === \"object\" ? args.props : {}) as Record<string, unknown>;\n const node = makeNode({ id, type: String(args.type), parent, order }, props);\n const res = submit({ t: \"insert\", node } as unknown as TOp, `add ${args.type} ${id}`, id);\n return { ...res, _text: res.staged ? `staged add ${id} — confirm ${res.pendingId}` : `added ${id}` };\n },\n true,\n (_args, result) => target(result.id as string | undefined),\n );\n reg(\n \"update\",\n \"Merge a props patch into a node.\",\n { id: { type: \"string\" }, patch: { type: \"object\" } },\n [\"id\", \"patch\"],\n (args) => {\n const id = String(args.id);\n if (!adapter.get().nodes[id]) throw new Error(`No node ${id}`);\n const patch = (args.patch && typeof args.patch === \"object\" ? args.patch : {}) as Record<string, unknown>;\n const res = submit({ t: \"set_props\", id, patch } as unknown as TOp, `update ${id}`, id);\n return { ...res, id, _text: res.staged ? `staged update ${id} — confirm ${res.pendingId}` : `updated ${id}` };\n },\n true,\n (args) => target(String(args.id)),\n );\n reg(\n \"remove\",\n \"Remove a node and its subtree.\",\n { id: { type: \"string\" } },\n [\"id\"],\n (args) => {\n const id = String(args.id);\n const tree = adapter.get();\n if (!tree.nodes[id]) throw new Error(`No node ${id}`);\n const count = descendantsOf(tree, id).length + 1;\n const res = submit({ t: \"remove\", id } as unknown as TOp, `remove ${id} (${count} node${count === 1 ? \"\" : \"s\"})`, id);\n return { ...res, id, removed: count, _text: res.staged ? `staged remove ${id} — confirm ${res.pendingId}` : `removed ${id}` };\n },\n true,\n (args) => target(String(args.id)),\n );\n reg(\n \"move\",\n \"Reparent + reorder a node.\",\n { id: { type: \"string\" }, parent: { type: [\"string\", \"null\"] }, order: { type: \"string\", description: \"Fractional order key (default: append under the new parent).\" } },\n [\"id\"],\n (args) => {\n const id = String(args.id);\n const tree = adapter.get();\n if (!tree.nodes[id]) throw new Error(`No node ${id}`);\n const parent = args.parent === null ? null : typeof args.parent === \"string\" ? args.parent : tree.nodes[id]!.parent;\n const order = typeof args.order === \"string\" ? args.order : appendOrder(tree, parent);\n const res = submit({ t: \"move\", id, parent, order } as unknown as TOp, `move ${id}`, id);\n return { ...res, id, _text: res.staged ? `staged move ${id} — confirm ${res.pendingId}` : `moved ${id}` };\n },\n true,\n (args) => target(String(args.id)),\n );\n\n // ── Domain op tools ─────────────────────────────────────────────────────\n for (const t of options.opTools ?? []) {\n reg(\n t.verb,\n t.description,\n t.properties,\n t.required,\n (args) => {\n const built = t.build(args, adapter.get());\n if (built && typeof built === \"object\" && \"error\" in built) throw new Error((built as { error: string }).error);\n const tid = t.targetId?.(args);\n const res = submit(built as TOp, `${t.verb} ${tid ?? \"\"}`.trim(), tid);\n return { ...res, id: tid, _text: res.staged ? `staged ${t.verb} — confirm ${res.pendingId}` : t.verb };\n },\n true,\n (args) => target(t.targetId?.(args)),\n );\n }\n\n // ── Staged-write confirm / reject ───────────────────────────────────────\n reg(\n \"confirm\",\n \"Apply a staged op. Pass the `pendingId` a staged mutation returned — not the node `id` it also returns.\",\n { id: { type: \"string\", description: \"The `pendingId` from a staged mutation.\" } },\n [\"id\"],\n (args) => {\n const id = String(args.id);\n const p = pending.get(id);\n if (!p) throw new Error(`No pending op ${id}`);\n pending.delete(id);\n commit(p.op, p.label, p.targetId);\n return { ok: true, applied: p.label, id: p.targetId, _text: `applied ${p.label}` };\n },\n true,\n (_args, result) => target(result.id as string | undefined),\n );\n reg(\n \"reject\",\n \"Discard a staged op. Pass the `pendingId` a staged mutation returned — not the node `id` it also returns.\",\n { id: { type: \"string\", description: \"The `pendingId` from a staged mutation.\" } },\n [\"id\"],\n (args) => {\n const id = String(args.id);\n const p = pending.get(id);\n if (!p) throw new Error(`No pending op ${id}`);\n pending.delete(id);\n return { ok: true, rejected: p.label, _text: `rejected ${p.label}` };\n },\n false,\n );\n\n return {\n id: bridgeId,\n title: surface,\n dispose: () => {\n for (const d of disposers) d();\n pending.clear();\n },\n };\n}\n"]}
@@ -1,9 +1,10 @@
1
- import { errorResult, textResult } from './chunk-CZV3WUW5.js';
1
+ import { errorResult, textResult } from './chunk-3GFKC6OK.js';
2
2
  import { undoOne, redoOne, readHistory } from '@particle-academy/fancy-auto-common';
3
3
  export { clearStack, pushUndoEntry, readHistory, redoOne, resetAllUndoStacks, undoOne } from '@particle-academy/fancy-auto-common';
4
4
 
5
5
  // src/undo/undo-tools.ts
6
6
  var installedHosts = /* @__PURE__ */ new WeakSet();
7
+ var UNDO_TOOLS_OWNER = "agent-undo";
7
8
  function ensureUndoToolsRegistered(host, options = {}) {
8
9
  if (installedHosts.has(host)) return;
9
10
  installedHosts.add(host);
@@ -28,7 +29,8 @@ function registerUndoTools(host, options = {}) {
28
29
  const entry = await undoOne(agentOf(args));
29
30
  if (!entry) return errorResult("Nothing to undo.");
30
31
  return textResult(`Undid: ${entry.label}`, { entry: serialize(entry) });
31
- }
32
+ },
33
+ { owner: UNDO_TOOLS_OWNER }
32
34
  )
33
35
  );
34
36
  disposers.push(
@@ -46,7 +48,8 @@ function registerUndoTools(host, options = {}) {
46
48
  const entry = await redoOne(agentOf(args));
47
49
  if (!entry) return errorResult("Nothing to redo.");
48
50
  return textResult(`Redid: ${entry.label}`, { entry: serialize(entry) });
49
- }
51
+ },
52
+ { owner: UNDO_TOOLS_OWNER }
50
53
  )
51
54
  );
52
55
  disposers.push(
@@ -64,7 +67,8 @@ function registerUndoTools(host, options = {}) {
64
67
  const history = readHistory(agentOf(args)).map(serialize);
65
68
  const text = history.map((e) => `${new Date(e.timestamp).toISOString()} ${e.bridgeId} ${e.action}: ${e.label}`).join("\n");
66
69
  return textResult(text || "(empty)", history);
67
- }
70
+ },
71
+ { owner: UNDO_TOOLS_OWNER }
68
72
  )
69
73
  );
70
74
  return () => disposers.forEach((d) => d());
@@ -79,5 +83,5 @@ function serialize(entry) {
79
83
  }
80
84
 
81
85
  export { ensureUndoToolsRegistered, registerUndoTools };
82
- //# sourceMappingURL=chunk-R4XXOGQH.js.map
83
- //# sourceMappingURL=chunk-R4XXOGQH.js.map
86
+ //# sourceMappingURL=chunk-ZDKYKJFH.js.map
87
+ //# sourceMappingURL=chunk-ZDKYKJFH.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/undo/undo-tools.ts"],"names":[],"mappings":";;;;;AAaA,IAAM,cAAA,uBAAqB,OAAA,EAAkB;AAS7C,IAAM,gBAAA,GAAmB,YAAA;AAMlB,SAAS,yBAAA,CAA0B,IAAA,EAAgB,OAAA,GAA4B,EAAC,EAAS;AAC9F,EAAA,IAAI,cAAA,CAAe,GAAA,CAAI,IAAI,CAAA,EAAG;AAC9B,EAAA,cAAA,CAAe,IAAI,IAAI,CAAA;AACvB,EAAA,iBAAA,CAAkB,MAAM,OAAO,CAAA;AACjC;AAMO,SAAS,iBAAA,CAAkB,IAAA,EAAgB,OAAA,GAA4B,EAAC,EAAe;AAC5F,EAAA,MAAM,YAAA,GAAe,QAAQ,cAAA,IAAkB,OAAA;AAC/C,EAAA,MAAM,YAA+B,EAAC;AACtC,EAAA,MAAM,OAAA,GAAU,CAAC,IAAA,KACf,OAAO,MAAM,OAAA,KAAY,QAAA,GAAW,KAAK,OAAA,GAAU,YAAA;AAErD,EAAA,SAAA,CAAU,IAAA;AAAA,IACR,IAAA,CAAK,YAAA;AAAA,MACH;AAAA,QACE,IAAA,EAAM,YAAA;AAAA,QACN,WAAA,EAAa,8FAAA;AAAA,QACb,WAAA,EAAa;AAAA,UACX,IAAA,EAAM,QAAA;AAAA,UACN,YAAY,EAAE,OAAA,EAAS,EAAE,IAAA,EAAM,UAAS,EAAE;AAAA,UAC1C,oBAAA,EAAsB;AAAA;AACxB,OACF;AAAA,MACA,OAAO,IAAA,KAAS;AACd,QAAA,MAAM,KAAA,GAAQ,MAAM,OAAA,CAAQ,OAAA,CAAQ,IAAI,CAAC,CAAA;AACzC,QAAA,IAAI,CAAC,KAAA,EAAO,OAAO,WAAA,CAAY,kBAAkB,CAAA;AACjD,QAAA,OAAO,UAAA,CAAW,CAAA,OAAA,EAAU,KAAA,CAAM,KAAK,CAAA,CAAA,EAAI,EAAE,KAAA,EAAO,SAAA,CAAU,KAAK,CAAA,EAAG,CAAA;AAAA,MACxE,CAAA;AAAA,MACA,EAAE,OAAO,gBAAA;AAAiB;AAC5B,GACF;AAEA,EAAA,SAAA,CAAU,IAAA;AAAA,IACR,IAAA,CAAK,YAAA;AAAA,MACH;AAAA,QACE,IAAA,EAAM,YAAA;AAAA,QACN,WAAA,EAAa,uCAAA;AAAA,QACb,WAAA,EAAa;AAAA,UACX,IAAA,EAAM,QAAA;AAAA,UACN,YAAY,EAAE,OAAA,EAAS,EAAE,IAAA,EAAM,UAAS,EAAE;AAAA,UAC1C,oBAAA,EAAsB;AAAA;AACxB,OACF;AAAA,MACA,OAAO,IAAA,KAAS;AACd,QAAA,MAAM,KAAA,GAAQ,MAAM,OAAA,CAAQ,OAAA,CAAQ,IAAI,CAAC,CAAA;AACzC,QAAA,IAAI,CAAC,KAAA,EAAO,OAAO,WAAA,CAAY,kBAAkB,CAAA;AACjD,QAAA,OAAO,UAAA,CAAW,CAAA,OAAA,EAAU,KAAA,CAAM,KAAK,CAAA,CAAA,EAAI,EAAE,KAAA,EAAO,SAAA,CAAU,KAAK,CAAA,EAAG,CAAA;AAAA,MACxE,CAAA;AAAA,MACA,EAAE,OAAO,gBAAA;AAAiB;AAC5B,GACF;AAEA,EAAA,SAAA,CAAU,IAAA;AAAA,IACR,IAAA,CAAK,YAAA;AAAA,MACH;AAAA,QACE,IAAA,EAAM,eAAA;AAAA,QACN,WAAA,EAAa,yFAAA;AAAA,QACb,WAAA,EAAa;AAAA,UACX,IAAA,EAAM,QAAA;AAAA,UACN,YAAY,EAAE,OAAA,EAAS,EAAE,IAAA,EAAM,UAAS,EAAE;AAAA,UAC1C,oBAAA,EAAsB;AAAA;AACxB,OACF;AAAA,MACA,OAAO,IAAA,KAAS;AACd,QAAA,MAAM,UAAU,WAAA,CAAY,OAAA,CAAQ,IAAI,CAAC,CAAA,CAAE,IAAI,SAAS,CAAA;AACxD,QAAA,MAAM,IAAA,GAAO,OAAA,CAAQ,GAAA,CAAI,CAAC,CAAA,KAAM,GAAG,IAAI,IAAA,CAAK,CAAA,CAAE,SAAS,CAAA,CAAE,WAAA,EAAa,CAAA,CAAA,EAAI,CAAA,CAAE,QAAQ,CAAA,CAAA,EAAI,CAAA,CAAE,MAAM,CAAA,EAAA,EAAK,CAAA,CAAE,KAAK,CAAA,CAAE,CAAA,CAAE,IAAA,CAAK,IAAI,CAAA;AACzH,QAAA,OAAO,UAAA,CAAW,IAAA,IAAQ,SAAA,EAAW,OAAO,CAAA;AAAA,MAC9C,CAAA;AAAA,MACA,EAAE,OAAO,gBAAA;AAAiB;AAC5B,GACF;AAEA,EAAA,OAAO,MAAM,SAAA,CAAU,OAAA,CAAQ,CAAC,CAAA,KAAM,GAAG,CAAA;AAC3C;AAEA,SAAS,UAAU,KAAA,EAAyC;AAC1D,EAAA,OAAO;AAAA,IACL,WAAW,KAAA,CAAM,SAAA;AAAA,IACjB,UAAU,KAAA,CAAM,QAAA;AAAA,IAChB,QAAQ,KAAA,CAAM,MAAA;AAAA,IACd,OAAO,KAAA,CAAM;AAAA,GACf;AACF","file":"chunk-ZDKYKJFH.js","sourcesContent":["import { textResult, errorResult } from \"../mcp/server\";\nimport type { ToolHost } from \"../mcp/tool-host\";\nimport { readHistory, redoOne, undoOne } from \"./undo-stack\";\n\nexport type UndoToolsOptions = {\n /** Default agent id when the caller doesn't pass one. */\n defaultAgentId?: string;\n};\n\n/**\n * Idempotent tracker so multiple bridges on the same server only register\n * agent_undo / agent_redo / agent_history once.\n */\nconst installedHosts = new WeakSet<ToolHost>();\n\n/**\n * The one owner every copy of the undo tools registers under. They are SHARED\n * on purpose — every bridge ensures them, and a host may also call\n * `registerUndoTools` itself — so all of those are the same registrant, and a\n * second registration replaces the first instead of being refused as a\n * collision. Anything else claiming `agent_undo` is still refused.\n */\nconst UNDO_TOOLS_OWNER = \"agent-undo\";\n\n/**\n * ensureUndoToolsRegistered — bridges call this on construction. Safe to\n * call repeatedly with the same server; subsequent calls are no-ops.\n */\nexport function ensureUndoToolsRegistered(host: ToolHost, options: UndoToolsOptions = {}): void {\n if (installedHosts.has(host)) return;\n installedHosts.add(host);\n registerUndoTools(host, options);\n}\n\n/**\n * registerUndoTools — add agent_undo / agent_redo / agent_history to the\n * server. Returns a disposer that unregisters all three.\n */\nexport function registerUndoTools(host: ToolHost, options: UndoToolsOptions = {}): () => void {\n const defaultAgent = options.defaultAgentId ?? \"agent\";\n const disposers: Array<() => void> = [];\n const agentOf = (args: any): string =>\n typeof args?.agentId === \"string\" ? args.agentId : defaultAgent;\n\n disposers.push(\n host.registerTool(\n {\n name: \"agent_undo\",\n description: \"Undo the most recent action on the agent's stack. Optional agentId targets a specific agent.\",\n inputSchema: {\n type: \"object\",\n properties: { agentId: { type: \"string\" } },\n additionalProperties: false,\n },\n },\n async (args) => {\n const entry = await undoOne(agentOf(args));\n if (!entry) return errorResult(\"Nothing to undo.\");\n return textResult(`Undid: ${entry.label}`, { entry: serialize(entry) });\n },\n { owner: UNDO_TOOLS_OWNER },\n ),\n );\n\n disposers.push(\n host.registerTool(\n {\n name: \"agent_redo\",\n description: \"Redo the most recently undone action.\",\n inputSchema: {\n type: \"object\",\n properties: { agentId: { type: \"string\" } },\n additionalProperties: false,\n },\n },\n async (args) => {\n const entry = await redoOne(agentOf(args));\n if (!entry) return errorResult(\"Nothing to redo.\");\n return textResult(`Redid: ${entry.label}`, { entry: serialize(entry) });\n },\n { owner: UNDO_TOOLS_OWNER },\n ),\n );\n\n disposers.push(\n host.registerTool(\n {\n name: \"agent_history\",\n description: \"List the agent's undo stack (oldest first). Useful for understanding what's reversible.\",\n inputSchema: {\n type: \"object\",\n properties: { agentId: { type: \"string\" } },\n additionalProperties: false,\n },\n },\n async (args) => {\n const history = readHistory(agentOf(args)).map(serialize);\n const text = history.map((e) => `${new Date(e.timestamp).toISOString()} ${e.bridgeId} ${e.action}: ${e.label}`).join(\"\\n\");\n return textResult(text || \"(empty)\", history);\n },\n { owner: UNDO_TOOLS_OWNER },\n ),\n );\n\n return () => disposers.forEach((d) => d());\n}\n\nfunction serialize(entry: import(\"./undo-stack\").UndoEntry) {\n return {\n timestamp: entry.timestamp,\n bridgeId: entry.bridgeId,\n action: entry.action,\n label: entry.label,\n };\n}\n"]}
@@ -59,13 +59,23 @@ var ToolRegistry = class {
59
59
  */
60
60
  this.withdrawn = /* @__PURE__ */ new Set();
61
61
  }
62
- registerTool(definition, handler) {
63
- this.tools.set(definition.name, { definition, handler });
64
- this.withdrawn.delete(definition.name);
62
+ registerTool(definition, handler, options = {}) {
63
+ const name = definition.name;
64
+ const { owner, replace = false } = options;
65
+ const held = this.tools.get(name);
66
+ if (held && !replace && (owner === void 0 || held.owner !== owner)) {
67
+ throw new Error(
68
+ `Tool "${name}" is already registered by ${describeOwner(held.owner)}; ${describeOwner(owner)} cannot register it too. Two registrants for one name would leave the first one listed but unreachable. Give one of them a different tool name, dispose the first registration, or pass { replace: true } to take the name over deliberately.`
69
+ );
70
+ }
71
+ const record = owner === void 0 ? { definition, handler } : { definition, handler, owner };
72
+ this.tools.set(name, record);
73
+ this.withdrawn.delete(name);
65
74
  this.onToolsChanged();
66
75
  return () => {
67
- if (this.tools.delete(definition.name)) {
68
- this.withdrawn.add(definition.name);
76
+ if (this.tools.get(name) === record) {
77
+ this.tools.delete(name);
78
+ this.withdrawn.add(name);
69
79
  this.onToolsChanged();
70
80
  }
71
81
  };
@@ -94,6 +104,9 @@ var ToolRegistry = class {
94
104
  onToolsChanged() {
95
105
  }
96
106
  };
107
+ function describeOwner(owner) {
108
+ return owner === void 0 ? "an unnamed registrant (pass { owner } to registerTool to identify it)" : `"${owner}"`;
109
+ }
97
110
 
98
111
  // src/mcp/server.ts
99
112
  var MicroMcpServer = class extends ToolRegistry {
@@ -559,6 +572,7 @@ function extractMeta(result) {
559
572
 
560
573
  // src/undo/undo-tools.ts
561
574
  var installedHosts = /* @__PURE__ */ new WeakSet();
575
+ var UNDO_TOOLS_OWNER = "agent-undo";
562
576
  function ensureUndoToolsRegistered(host, options = {}) {
563
577
  if (installedHosts.has(host)) return;
564
578
  installedHosts.add(host);
@@ -583,7 +597,8 @@ function registerUndoTools(host, options = {}) {
583
597
  const entry = await fancyAutoCommon.undoOne(agentOf(args));
584
598
  if (!entry) return errorResult("Nothing to undo.");
585
599
  return textResult(`Undid: ${entry.label}`, { entry: serialize(entry) });
586
- }
600
+ },
601
+ { owner: UNDO_TOOLS_OWNER }
587
602
  )
588
603
  );
589
604
  disposers.push(
@@ -601,7 +616,8 @@ function registerUndoTools(host, options = {}) {
601
616
  const entry = await fancyAutoCommon.redoOne(agentOf(args));
602
617
  if (!entry) return errorResult("Nothing to redo.");
603
618
  return textResult(`Redid: ${entry.label}`, { entry: serialize(entry) });
604
- }
619
+ },
620
+ { owner: UNDO_TOOLS_OWNER }
605
621
  )
606
622
  );
607
623
  disposers.push(
@@ -619,7 +635,8 @@ function registerUndoTools(host, options = {}) {
619
635
  const history = fancyAutoCommon.readHistory(agentOf(args)).map(serialize);
620
636
  const text = history.map((e) => `${new Date(e.timestamp).toISOString()} ${e.bridgeId} ${e.action}: ${e.label}`).join("\n");
621
637
  return textResult(text || "(empty)", history);
622
- }
638
+ },
639
+ { owner: UNDO_TOOLS_OWNER }
623
640
  )
624
641
  );
625
642
  return () => disposers.forEach((d) => d());
@@ -644,6 +661,7 @@ function registerWhiteboardBridge(host, options) {
644
661
  const { adapter } = options;
645
662
  const agent = { ...DEFAULT_AGENT, ...options.agent ?? {} };
646
663
  const disposers = [];
664
+ const bridgeId = "whiteboard";
647
665
  ensureUndoToolsRegistered(host, { defaultAgentId: agent.id });
648
666
  const wbTarget = (args, result) => ({
649
667
  kind: "whiteboard",
@@ -675,7 +693,8 @@ function registerWhiteboardBridge(host, options) {
675
693
  additionalProperties: false
676
694
  }
677
695
  },
678
- final
696
+ final,
697
+ { owner: bridgeId }
679
698
  )
680
699
  );
681
700
  };
@@ -1053,7 +1072,7 @@ function registerWhiteboardBridge(host, options) {
1053
1072
  wbTarget
1054
1073
  );
1055
1074
  return {
1056
- id: "whiteboard",
1075
+ id: bridgeId,
1057
1076
  title: "Whiteboard",
1058
1077
  dispose: () => {
1059
1078
  for (const d of disposers) d();