@particle-academy/agent-integrations 0.21.2 → 0.23.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.
@@ -0,0 +1,64 @@
1
+ import { T as ToolHost } from '../tool-host-BQuUygLF.cjs';
2
+ import { B as Bridge } from '../types-CCSBGW9T.cjs';
3
+ import '../types-aOQLTW0E.cjs';
4
+
5
+ type FileKind = "file" | "dir";
6
+ type FileEntry = {
7
+ path: string;
8
+ name: string;
9
+ kind: FileKind;
10
+ size?: number;
11
+ mtime?: string;
12
+ hasChildren?: boolean;
13
+ disabled?: boolean;
14
+ };
15
+ type FileSnapshotNode = FileEntry & {
16
+ children?: FileSnapshotNode[];
17
+ };
18
+
19
+ /**
20
+ * Adapter the host provides — getters/setters over the SAME controlled props it
21
+ * passes to react-fancy's `<FileBrowser>` (`value`/`path`/`expandedPaths`), plus
22
+ * `listChildren` (wire to your `provider.loadChildren` or the loaded cache) and,
23
+ * for snapshot mode, an optional `requestSnapshot`.
24
+ */
25
+ type FilesBridgeAdapter = {
26
+ /** Current directory (the `path` prop). */
27
+ getPath: () => string;
28
+ setPath: (path: string) => void;
29
+ /** Selected path(s) — normalize FileBrowser's `value` (string | string[] | null) to an array. */
30
+ getSelection: () => string[];
31
+ setSelection: (paths: string[]) => void;
32
+ /** Expanded folder paths (the `expandedPaths` prop). */
33
+ getExpanded: () => string[];
34
+ setExpanded: (next: string[] | ((prev: string[]) => string[])) => void;
35
+ /** Direct children of a path — wire to `provider.loadChildren` (async) or the loaded/snapshot cache. */
36
+ listChildren: (path: string) => Promise<FileEntry[]> | FileEntry[];
37
+ /** Optional (snapshot mode): fetch/refresh a snapshot subtree so an agent can pull remote state on demand. */
38
+ requestSnapshot?: (path: string, depth?: number) => Promise<FileSnapshotNode[]> | FileSnapshotNode[];
39
+ };
40
+ type FilesBridgeOptions = {
41
+ adapter: FilesBridgeAdapter;
42
+ /** Identity tagged onto agent-driven actions. */
43
+ agent?: {
44
+ id: string;
45
+ name?: string;
46
+ color?: string;
47
+ };
48
+ };
49
+ /**
50
+ * registerFilesBridge — an MCP tool set over a react-fancy `<FileBrowser>`'s
51
+ * controlled state, so a human and an agent share one file browser. The agent
52
+ * lists a folder's children, navigates, expands/collapses folders, selects
53
+ * entries, and (in snapshot mode) requests a fresh subtree — driving the same
54
+ * `value`/`path`/`expandedPaths` props, no DOM scraping. Every mutation
55
+ * broadcasts AgentActivity (presence) and pushes an undo entry. Mirrors the
56
+ * map / whiteboard / flow bridges in shape.
57
+ *
58
+ * Read-only browse in v1: no content preview (pair with fancy-code's
59
+ * FileViewer) and no write ops (rename/delete/upload) — those arrive later
60
+ * behind a pendingMode-gated iteration.
61
+ */
62
+ declare function registerFilesBridge(host: ToolHost, options: FilesBridgeOptions): Bridge;
63
+
64
+ export { type FilesBridgeAdapter, type FilesBridgeOptions, registerFilesBridge };
@@ -0,0 +1,64 @@
1
+ import { T as ToolHost } from '../tool-host-C8JMMGYq.js';
2
+ import { B as Bridge } from '../types-DIVNcIQO.js';
3
+ import '../types-aOQLTW0E.js';
4
+
5
+ type FileKind = "file" | "dir";
6
+ type FileEntry = {
7
+ path: string;
8
+ name: string;
9
+ kind: FileKind;
10
+ size?: number;
11
+ mtime?: string;
12
+ hasChildren?: boolean;
13
+ disabled?: boolean;
14
+ };
15
+ type FileSnapshotNode = FileEntry & {
16
+ children?: FileSnapshotNode[];
17
+ };
18
+
19
+ /**
20
+ * Adapter the host provides — getters/setters over the SAME controlled props it
21
+ * passes to react-fancy's `<FileBrowser>` (`value`/`path`/`expandedPaths`), plus
22
+ * `listChildren` (wire to your `provider.loadChildren` or the loaded cache) and,
23
+ * for snapshot mode, an optional `requestSnapshot`.
24
+ */
25
+ type FilesBridgeAdapter = {
26
+ /** Current directory (the `path` prop). */
27
+ getPath: () => string;
28
+ setPath: (path: string) => void;
29
+ /** Selected path(s) — normalize FileBrowser's `value` (string | string[] | null) to an array. */
30
+ getSelection: () => string[];
31
+ setSelection: (paths: string[]) => void;
32
+ /** Expanded folder paths (the `expandedPaths` prop). */
33
+ getExpanded: () => string[];
34
+ setExpanded: (next: string[] | ((prev: string[]) => string[])) => void;
35
+ /** Direct children of a path — wire to `provider.loadChildren` (async) or the loaded/snapshot cache. */
36
+ listChildren: (path: string) => Promise<FileEntry[]> | FileEntry[];
37
+ /** Optional (snapshot mode): fetch/refresh a snapshot subtree so an agent can pull remote state on demand. */
38
+ requestSnapshot?: (path: string, depth?: number) => Promise<FileSnapshotNode[]> | FileSnapshotNode[];
39
+ };
40
+ type FilesBridgeOptions = {
41
+ adapter: FilesBridgeAdapter;
42
+ /** Identity tagged onto agent-driven actions. */
43
+ agent?: {
44
+ id: string;
45
+ name?: string;
46
+ color?: string;
47
+ };
48
+ };
49
+ /**
50
+ * registerFilesBridge — an MCP tool set over a react-fancy `<FileBrowser>`'s
51
+ * controlled state, so a human and an agent share one file browser. The agent
52
+ * lists a folder's children, navigates, expands/collapses folders, selects
53
+ * entries, and (in snapshot mode) requests a fresh subtree — driving the same
54
+ * `value`/`path`/`expandedPaths` props, no DOM scraping. Every mutation
55
+ * broadcasts AgentActivity (presence) and pushes an undo entry. Mirrors the
56
+ * map / whiteboard / flow bridges in shape.
57
+ *
58
+ * Read-only browse in v1: no content preview (pair with fancy-code's
59
+ * FileViewer) and no write ops (rename/delete/upload) — those arrive later
60
+ * behind a pendingMode-gated iteration.
61
+ */
62
+ declare function registerFilesBridge(host: ToolHost, options: FilesBridgeOptions): Bridge;
63
+
64
+ export { type FilesBridgeAdapter, type FilesBridgeOptions, registerFilesBridge };
@@ -0,0 +1,62 @@
1
+ import { T as ToolHost } from '../tool-host-BQuUygLF.cjs';
2
+ import { B as Bridge } from '../types-CCSBGW9T.cjs';
3
+ import '../types-aOQLTW0E.cjs';
4
+
5
+ type LatLng = {
6
+ lat: number;
7
+ lng: number;
8
+ };
9
+ type MapView = {
10
+ center: LatLng;
11
+ zoom: number;
12
+ bearing?: number;
13
+ pitch?: number;
14
+ };
15
+ type MapMarker = {
16
+ id: string;
17
+ position: LatLng;
18
+ label?: string;
19
+ color?: string;
20
+ icon?: string;
21
+ draggable?: boolean;
22
+ data?: Record<string, unknown>;
23
+ };
24
+
25
+ /**
26
+ * Adapter the host provides — getters/setters over the SAME controlled state it
27
+ * passes to fancy-map's `<Map>` (view, markers, selection), plus optional
28
+ * `fitBounds` (from the map's onReady handle) and `setFollow` (drives the map's
29
+ * `follow` prop so an agent can make the camera track a moving marker).
30
+ */
31
+ type MapBridgeAdapter = {
32
+ getView: () => MapView;
33
+ setView: (next: MapView) => void;
34
+ getMarkers: () => MapMarker[];
35
+ setMarkers: (next: MapMarker[] | ((prev: MapMarker[]) => MapMarker[])) => void;
36
+ getSelected: () => string | null;
37
+ setSelected: (id: string | null) => void;
38
+ /** Fit the camera to points (wire to the `MapHandle.fitBounds` from `<Map onReady>`). */
39
+ fitBounds?: (points: LatLng[], padding?: number) => void;
40
+ /** Make the camera follow a marker as it moves (drives the map's `follow` prop). */
41
+ setFollow?: (id: string | null) => void;
42
+ };
43
+ type MapBridgeOptions = {
44
+ adapter: MapBridgeAdapter;
45
+ /** Identity tagged onto agent-authored markers. */
46
+ agent?: {
47
+ id: string;
48
+ name?: string;
49
+ color?: string;
50
+ };
51
+ };
52
+ /**
53
+ * registerMapBridge — an MCP tool set over a fancy-map `<Map>`'s controlled
54
+ * state, so a human and an agent cohabit one map. The agent moves the camera,
55
+ * drops/updates/removes markers, selects, fits bounds, and follows a live
56
+ * track; every mutation broadcasts AgentActivity (for presence) and pushes an
57
+ * undo entry (so the human can step the agent back). Mirrors the whiteboard /
58
+ * flow bridges in shape.
59
+ */
60
+ declare function registerMapBridge(host: ToolHost, options: MapBridgeOptions): Bridge;
61
+
62
+ export { type MapBridgeAdapter, type MapBridgeOptions, registerMapBridge };
@@ -0,0 +1,62 @@
1
+ import { T as ToolHost } from '../tool-host-C8JMMGYq.js';
2
+ import { B as Bridge } from '../types-DIVNcIQO.js';
3
+ import '../types-aOQLTW0E.js';
4
+
5
+ type LatLng = {
6
+ lat: number;
7
+ lng: number;
8
+ };
9
+ type MapView = {
10
+ center: LatLng;
11
+ zoom: number;
12
+ bearing?: number;
13
+ pitch?: number;
14
+ };
15
+ type MapMarker = {
16
+ id: string;
17
+ position: LatLng;
18
+ label?: string;
19
+ color?: string;
20
+ icon?: string;
21
+ draggable?: boolean;
22
+ data?: Record<string, unknown>;
23
+ };
24
+
25
+ /**
26
+ * Adapter the host provides — getters/setters over the SAME controlled state it
27
+ * passes to fancy-map's `<Map>` (view, markers, selection), plus optional
28
+ * `fitBounds` (from the map's onReady handle) and `setFollow` (drives the map's
29
+ * `follow` prop so an agent can make the camera track a moving marker).
30
+ */
31
+ type MapBridgeAdapter = {
32
+ getView: () => MapView;
33
+ setView: (next: MapView) => void;
34
+ getMarkers: () => MapMarker[];
35
+ setMarkers: (next: MapMarker[] | ((prev: MapMarker[]) => MapMarker[])) => void;
36
+ getSelected: () => string | null;
37
+ setSelected: (id: string | null) => void;
38
+ /** Fit the camera to points (wire to the `MapHandle.fitBounds` from `<Map onReady>`). */
39
+ fitBounds?: (points: LatLng[], padding?: number) => void;
40
+ /** Make the camera follow a marker as it moves (drives the map's `follow` prop). */
41
+ setFollow?: (id: string | null) => void;
42
+ };
43
+ type MapBridgeOptions = {
44
+ adapter: MapBridgeAdapter;
45
+ /** Identity tagged onto agent-authored markers. */
46
+ agent?: {
47
+ id: string;
48
+ name?: string;
49
+ color?: string;
50
+ };
51
+ };
52
+ /**
53
+ * registerMapBridge — an MCP tool set over a fancy-map `<Map>`'s controlled
54
+ * state, so a human and an agent cohabit one map. The agent moves the camera,
55
+ * drops/updates/removes markers, selects, fits bounds, and follows a live
56
+ * track; every mutation broadcasts AgentActivity (for presence) and pushes an
57
+ * undo entry (so the human can step the agent back). Mirrors the whiteboard /
58
+ * flow bridges in shape.
59
+ */
60
+ declare function registerMapBridge(host: ToolHost, options: MapBridgeOptions): Bridge;
61
+
62
+ export { type MapBridgeAdapter, type MapBridgeOptions, registerMapBridge };
@@ -0,0 +1,337 @@
1
+ 'use strict';
2
+
3
+ var fancyAutoCommon = require('@particle-academy/fancy-auto-common');
4
+
5
+ // src/mcp/server.ts
6
+ function textResult(text, structured) {
7
+ return {
8
+ content: [{ type: "text", text }],
9
+ ...structured !== void 0 ? { structuredContent: structured } : {}
10
+ };
11
+ }
12
+ function errorResult(text) {
13
+ return { content: [{ type: "text", text }], isError: true };
14
+ }
15
+
16
+ // src/presence/wrap-tool-with-activity.ts
17
+ function wrapToolWithActivity(handler, options) {
18
+ return async (args) => {
19
+ const result = await handler(args);
20
+ if (result.isError) return result;
21
+ let target;
22
+ if (options.resolveTarget) {
23
+ target = options.resolveTarget({ toolName: options.toolName, args, result });
24
+ } else {
25
+ target = { kind: options.kind, screenId: options.screenId };
26
+ }
27
+ if (!target) return result;
28
+ fancyAutoCommon.emitActivity({
29
+ agentId: options.agent.id,
30
+ agentName: options.agent.name,
31
+ agentColor: options.agent.color,
32
+ target: { ...target, kind: target.kind ?? options.kind, screenId: target.screenId ?? options.screenId },
33
+ action: options.toolName,
34
+ timestamp: Date.now(),
35
+ meta: extractMeta(result),
36
+ ttlMs: options.ttlMs
37
+ });
38
+ return result;
39
+ };
40
+ }
41
+ function extractMeta(result) {
42
+ const sc = result.structuredContent;
43
+ if (sc && typeof sc === "object" && !Array.isArray(sc)) {
44
+ return sc;
45
+ }
46
+ return void 0;
47
+ }
48
+
49
+ // src/undo/undo-tools.ts
50
+ var installedHosts = /* @__PURE__ */ new WeakSet();
51
+ function ensureUndoToolsRegistered(host, options = {}) {
52
+ if (installedHosts.has(host)) return;
53
+ installedHosts.add(host);
54
+ registerUndoTools(host, options);
55
+ }
56
+ function registerUndoTools(host, options = {}) {
57
+ const defaultAgent = options.defaultAgentId ?? "agent";
58
+ const disposers = [];
59
+ const agentOf = (args) => typeof args?.agentId === "string" ? args.agentId : defaultAgent;
60
+ disposers.push(
61
+ host.registerTool(
62
+ {
63
+ name: "agent_undo",
64
+ description: "Undo the most recent action on the agent's stack. Optional agentId targets a specific agent.",
65
+ inputSchema: {
66
+ type: "object",
67
+ properties: { agentId: { type: "string" } },
68
+ additionalProperties: false
69
+ }
70
+ },
71
+ async (args) => {
72
+ const entry = await fancyAutoCommon.undoOne(agentOf(args));
73
+ if (!entry) return errorResult("Nothing to undo.");
74
+ return textResult(`Undid: ${entry.label}`, { entry: serialize(entry) });
75
+ }
76
+ )
77
+ );
78
+ disposers.push(
79
+ host.registerTool(
80
+ {
81
+ name: "agent_redo",
82
+ description: "Redo the most recently undone action.",
83
+ inputSchema: {
84
+ type: "object",
85
+ properties: { agentId: { type: "string" } },
86
+ additionalProperties: false
87
+ }
88
+ },
89
+ async (args) => {
90
+ const entry = await fancyAutoCommon.redoOne(agentOf(args));
91
+ if (!entry) return errorResult("Nothing to redo.");
92
+ return textResult(`Redid: ${entry.label}`, { entry: serialize(entry) });
93
+ }
94
+ )
95
+ );
96
+ disposers.push(
97
+ host.registerTool(
98
+ {
99
+ name: "agent_history",
100
+ description: "List the agent's undo stack (oldest first). Useful for understanding what's reversible.",
101
+ inputSchema: {
102
+ type: "object",
103
+ properties: { agentId: { type: "string" } },
104
+ additionalProperties: false
105
+ }
106
+ },
107
+ async (args) => {
108
+ const history = fancyAutoCommon.readHistory(agentOf(args)).map(serialize);
109
+ const text = history.map((e) => `${new Date(e.timestamp).toISOString()} ${e.bridgeId} ${e.action}: ${e.label}`).join("\n");
110
+ return textResult(text || "(empty)", history);
111
+ }
112
+ )
113
+ );
114
+ return () => disposers.forEach((d) => d());
115
+ }
116
+ function serialize(entry) {
117
+ return {
118
+ timestamp: entry.timestamp,
119
+ bridgeId: entry.bridgeId,
120
+ action: entry.action,
121
+ label: entry.label
122
+ };
123
+ }
124
+
125
+ // src/bridges/files.ts
126
+ var DEFAULT_AGENT = { id: "agent", name: "Agent", color: "#0ea5e9" };
127
+ var str = (v, fallback = "") => typeof v === "string" ? v : fallback;
128
+ var num = (v, fallback) => typeof v === "number" && Number.isFinite(v) ? v : 0;
129
+ var asPaths = (v) => {
130
+ if (typeof v === "string") {
131
+ return [v];
132
+ }
133
+ if (Array.isArray(v)) {
134
+ return v.filter((x) => typeof x === "string");
135
+ }
136
+ return [];
137
+ };
138
+ function registerFilesBridge(host, options) {
139
+ const { adapter } = options;
140
+ const agent = { ...DEFAULT_AGENT, ...options.agent ?? {} };
141
+ const disposers = [];
142
+ ensureUndoToolsRegistered(host, { defaultAgentId: agent.id });
143
+ const fTarget = (args, _result) => ({
144
+ kind: "files",
145
+ elementId: args?.path ?? void 0
146
+ });
147
+ const reg = (name, description, properties, required, handler, resolveTarget) => {
148
+ const wrapped = async (args) => {
149
+ try {
150
+ return await handler(args);
151
+ } catch (e) {
152
+ return errorResult(e instanceof Error ? e.message : String(e));
153
+ }
154
+ };
155
+ const final = resolveTarget ? wrapToolWithActivity(wrapped, {
156
+ toolName: name,
157
+ agent: { id: agent.id, name: agent.name, color: agent.color },
158
+ kind: "files",
159
+ resolveTarget: ({ args, result }) => resolveTarget(args, result)
160
+ }) : wrapped;
161
+ disposers.push(
162
+ host.registerTool(
163
+ {
164
+ name,
165
+ description,
166
+ inputSchema: {
167
+ type: "object",
168
+ properties,
169
+ required,
170
+ additionalProperties: false
171
+ }
172
+ },
173
+ final
174
+ )
175
+ );
176
+ };
177
+ reg(
178
+ "files_get_state",
179
+ "Get the file browser's current directory, selected path(s), and expanded folders.",
180
+ {},
181
+ [],
182
+ () => {
183
+ const state = {
184
+ path: adapter.getPath(),
185
+ selected: adapter.getSelection(),
186
+ expanded: adapter.getExpanded()
187
+ };
188
+ return textResult(JSON.stringify(state, null, 2), state);
189
+ }
190
+ );
191
+ reg(
192
+ "files_list",
193
+ "List the direct children of a folder (files + subfolders). Omit `path` for the current directory. Loads lazily from the host's provider/snapshot \u2014 never an eager tree walk.",
194
+ { path: { type: "string", description: "Folder path to list; defaults to the current directory." } },
195
+ [],
196
+ async (args) => {
197
+ const path = args.path !== void 0 ? str(args.path) : adapter.getPath();
198
+ const entries = await adapter.listChildren(path);
199
+ const summary = entries.map((e) => ({
200
+ path: e.path,
201
+ name: e.name,
202
+ kind: e.kind,
203
+ ...e.size !== void 0 ? { size: e.size } : {},
204
+ ...e.mtime !== void 0 ? { mtime: e.mtime } : {}
205
+ }));
206
+ const text = summary.map((e) => `${e.kind === "dir" ? "\u{1F4C1}" : "\u{1F4C4}"} ${e.path}`).join("\n") || `(empty: ${path})`;
207
+ return textResult(text, { path, entries: summary });
208
+ }
209
+ );
210
+ reg(
211
+ "files_navigate",
212
+ "Set the current directory (as if the user clicked a breadcrumb or opened a folder).",
213
+ { path: { type: "string" } },
214
+ ["path"],
215
+ (args) => {
216
+ const path = str(args.path);
217
+ const prev = adapter.getPath();
218
+ adapter.setPath(path);
219
+ fancyAutoCommon.pushUndoEntry(agent.id, {
220
+ timestamp: Date.now(),
221
+ bridgeId: "files",
222
+ action: "files_navigate",
223
+ label: `Navigated to ${path}`,
224
+ undo: () => adapter.setPath(prev),
225
+ redo: () => adapter.setPath(path)
226
+ });
227
+ return textResult(`Current directory \u2192 ${path}`, { path });
228
+ },
229
+ fTarget
230
+ );
231
+ reg(
232
+ "files_expand",
233
+ "Expand a folder in the tree (loads its children if needed).",
234
+ { path: { type: "string" } },
235
+ ["path"],
236
+ (args) => {
237
+ const path = str(args.path);
238
+ if (adapter.getExpanded().includes(path)) {
239
+ return textResult(`${path} already expanded`, { path, expanded: true });
240
+ }
241
+ adapter.setExpanded((prev) => [...prev, path]);
242
+ fancyAutoCommon.pushUndoEntry(agent.id, {
243
+ timestamp: Date.now(),
244
+ bridgeId: "files",
245
+ action: "files_expand",
246
+ label: `Expanded ${path}`,
247
+ undo: () => adapter.setExpanded((prev) => prev.filter((p) => p !== path)),
248
+ redo: () => adapter.setExpanded((prev) => prev.includes(path) ? prev : [...prev, path])
249
+ });
250
+ return textResult(`Expanded ${path}`, { path, expanded: true });
251
+ },
252
+ fTarget
253
+ );
254
+ reg(
255
+ "files_collapse",
256
+ "Collapse a folder in the tree.",
257
+ { path: { type: "string" } },
258
+ ["path"],
259
+ (args) => {
260
+ const path = str(args.path);
261
+ if (!adapter.getExpanded().includes(path)) {
262
+ return textResult(`${path} already collapsed`, { path, expanded: false });
263
+ }
264
+ adapter.setExpanded((prev) => prev.filter((p) => p !== path));
265
+ fancyAutoCommon.pushUndoEntry(agent.id, {
266
+ timestamp: Date.now(),
267
+ bridgeId: "files",
268
+ action: "files_collapse",
269
+ label: `Collapsed ${path}`,
270
+ undo: () => adapter.setExpanded((prev) => prev.includes(path) ? prev : [...prev, path]),
271
+ redo: () => adapter.setExpanded((prev) => prev.filter((p) => p !== path))
272
+ });
273
+ return textResult(`Collapsed ${path}`, { path, expanded: false });
274
+ },
275
+ fTarget
276
+ );
277
+ reg(
278
+ "files_select",
279
+ "Set the selection to the given path(s). Pass a single `path`, or `paths` for a multi-select browser; either empty clears the selection.",
280
+ {
281
+ path: { type: "string", description: "A single path to select." },
282
+ paths: { type: "array", items: { type: "string" }, description: "Multiple paths (multi-select browsers)." }
283
+ },
284
+ [],
285
+ (args) => {
286
+ const next = args.paths !== void 0 ? asPaths(args.paths) : asPaths(args.path);
287
+ const prev = adapter.getSelection();
288
+ adapter.setSelection(next);
289
+ fancyAutoCommon.pushUndoEntry(agent.id, {
290
+ timestamp: Date.now(),
291
+ bridgeId: "files",
292
+ action: "files_select",
293
+ label: next.length ? `Selected ${next.join(", ")}` : "Cleared selection",
294
+ undo: () => adapter.setSelection(prev),
295
+ redo: () => adapter.setSelection(next)
296
+ });
297
+ return textResult(next.length ? `Selected ${next.join(", ")}` : "Cleared selection", {
298
+ selected: next
299
+ });
300
+ },
301
+ fTarget
302
+ );
303
+ reg(
304
+ "files_request_snapshot",
305
+ "Request a fresh snapshot subtree rooted at `path` (snapshot mode) \u2014 e.g. to pull a remote machine's current tree. Requires the host to wire requestSnapshot.",
306
+ {
307
+ path: { type: "string", description: "Root of the subtree; defaults to the current directory." },
308
+ depth: { type: "number", description: "How many levels deep to materialize (host-defined default)." }
309
+ },
310
+ [],
311
+ async (args) => {
312
+ if (!adapter.requestSnapshot) {
313
+ return errorResult("Host did not wire requestSnapshot (snapshot mode not enabled).");
314
+ }
315
+ const path = args.path !== void 0 ? str(args.path) : adapter.getPath();
316
+ const depth = args.depth !== void 0 ? num(args.depth) : void 0;
317
+ const tree = await adapter.requestSnapshot(path, depth);
318
+ const count = Array.isArray(tree) ? tree.length : 0;
319
+ return textResult(`Snapshot of ${path}: ${count} top-level entr${count === 1 ? "y" : "ies"}.`, {
320
+ path,
321
+ snapshot: tree
322
+ });
323
+ },
324
+ fTarget
325
+ );
326
+ return {
327
+ id: "files",
328
+ title: "Files",
329
+ dispose: () => {
330
+ for (const d of disposers) d();
331
+ }
332
+ };
333
+ }
334
+
335
+ exports.registerFilesBridge = registerFilesBridge;
336
+ //# sourceMappingURL=bridges-files.cjs.map
337
+ //# sourceMappingURL=bridges-files.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/mcp/server.ts","../src/presence/wrap-tool-with-activity.ts","../src/undo/undo-tools.ts","../src/bridges/files.ts"],"names":["emitActivity","undoOne","redoOne","readHistory","pushUndoEntry"],"mappings":"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","file":"bridges-files.cjs","sourcesContent":["import {\n type CallToolResult,\n type JsonObject,\n type JsonRpcMessage,\n type JsonRpcRequest,\n type JsonRpcId,\n type RegisteredTool,\n type ServerCapabilities,\n type ServerInfo,\n type ToolDefinition,\n type ToolHandler,\n JSONRPC_INTERNAL_ERROR,\n JSONRPC_INVALID_PARAMS,\n JSONRPC_METHOD_NOT_FOUND,\n MCP_PROTOCOL_VERSION,\n} from \"./types\";\nimport { ToolRegistry } from \"./tool-host\";\n\nexport type McpServerOptions = {\n info: ServerInfo;\n /** Defaults to { tools: { listChanged: true } } */\n capabilities?: ServerCapabilities;\n /** Free-text instructions surfaced to clients during initialize. */\n instructions?: string;\n};\n\nexport type Transport = {\n /** Called by the server when it has a message to deliver to the client. */\n send: (message: JsonRpcMessage) => void;\n /** Called by the server when it's torn down so the transport can clean up. */\n close?: () => void;\n};\n\n/**\n * MicroMcpServer — protocol-level MCP server, transport-agnostic.\n *\n * Use it like:\n *\n * const server = new MicroMcpServer({ info: { name: \"session\", version: \"0.1\" } });\n * server.registerTool({ name: \"...\", inputSchema: { type: \"object\" } }, async (args) => ({...}));\n * const transport = new InProcessTransport();\n * server.attach(transport);\n * transport.deliver({ ... }); // client → server frames\n *\n * The same server can serve multiple transports (e.g. an in-process agent\n * AND a relayed external client) by attaching each one.\n */\nexport class MicroMcpServer extends ToolRegistry {\n private transports = new Set<Transport>();\n private notifyListChangedScheduled = false;\n\n readonly info: ServerInfo;\n readonly capabilities: ServerCapabilities;\n readonly instructions?: string;\n\n constructor(options: McpServerOptions) {\n super();\n this.info = options.info;\n this.capabilities = options.capabilities ?? { tools: { listChanged: true } };\n this.instructions = options.instructions;\n }\n\n attach(transport: Transport): () => void {\n this.transports.add(transport);\n return () => this.detach(transport);\n }\n\n detach(transport: Transport): void {\n if (this.transports.delete(transport)) {\n transport.close?.();\n }\n }\n\n unregisterTool(name: string): void {\n if (this.tools.delete(name)) {\n this.scheduleListChangedNotification();\n }\n }\n\n protected onToolsChanged(): void {\n this.scheduleListChangedNotification();\n }\n\n /**\n * Receive a JSON-RPC frame from a client (called by the transport).\n * The transport is responsible for sending the response back.\n */\n async receive(transport: Transport, message: JsonRpcMessage): Promise<void> {\n if (!(\"method\" in message)) return; // It's a response, not a request — ignore.\n\n const isNotification = !(\"id\" in message);\n if (isNotification) {\n // Notifications are fire-and-forget. We ignore unknown methods.\n return;\n }\n\n const request = message as JsonRpcRequest;\n try {\n const result = await this.handle(request);\n transport.send({ jsonrpc: \"2.0\", id: request.id, result });\n } catch (err) {\n transport.send({\n jsonrpc: \"2.0\",\n id: request.id,\n error: this.toRpcError(err),\n });\n }\n }\n\n private async handle(request: JsonRpcRequest): Promise<any> {\n const { method, params } = request;\n switch (method) {\n case \"initialize\":\n return {\n protocolVersion: MCP_PROTOCOL_VERSION,\n capabilities: this.capabilities,\n serverInfo: this.info,\n ...(this.instructions ? { instructions: this.instructions } : {}),\n };\n\n case \"tools/list\":\n return { tools: this.listTools() };\n\n case \"tools/call\": {\n const name = params?.name;\n const args = (params?.arguments ?? {}) as JsonObject;\n if (typeof name !== \"string\") {\n throw rpcError(JSONRPC_INVALID_PARAMS, \"tools/call requires `name`\");\n }\n const tool = this.tools.get(name);\n if (!tool) {\n throw rpcError(JSONRPC_METHOD_NOT_FOUND, `Unknown tool: ${name}`);\n }\n const result = await tool.handler(args);\n return result satisfies CallToolResult;\n }\n\n case \"ping\":\n return {};\n\n default:\n throw rpcError(JSONRPC_METHOD_NOT_FOUND, `Unsupported method: ${method}`);\n }\n }\n\n private scheduleListChangedNotification(): void {\n if (this.notifyListChangedScheduled) return;\n this.notifyListChangedScheduled = true;\n queueMicrotask(() => {\n this.notifyListChangedScheduled = false;\n this.broadcast({ jsonrpc: \"2.0\", method: \"notifications/tools/list_changed\" });\n });\n }\n\n private broadcast(message: JsonRpcMessage): void {\n for (const t of this.transports) t.send(message);\n }\n\n private toRpcError(err: unknown): { code: number; message: string; data?: any } {\n if (err && typeof err === \"object\" && \"code\" in err && \"message\" in err) {\n return err as any;\n }\n return {\n code: JSONRPC_INTERNAL_ERROR,\n message: err instanceof Error ? err.message : String(err),\n };\n }\n}\n\nexport function rpcError(code: number, message: string, data?: any) {\n return { code, message, ...(data !== undefined ? { data } : {}) };\n}\n\n/**\n * Helper to build a CallToolResult from a string or structured value.\n */\nexport function textResult(text: string, structured?: any): CallToolResult {\n return {\n content: [{ type: \"text\", text }],\n ...(structured !== undefined ? { structuredContent: structured } : {}),\n };\n}\n\nexport function errorResult(text: string): CallToolResult {\n return { content: [{ type: \"text\", text }], isError: true };\n}\n\n// Internal helper so the JsonRpcId import isn't dropped by tsup\ntype _KeepIdImport = JsonRpcId;\n","import type { CallToolResult } from \"../mcp/types\";\nimport { emitActivity } from \"./registry\";\nimport type { AgentTarget } from \"./types\";\n\nexport type ActivityAgent = { id: string; name?: string; color?: string };\n\nexport type ActivityResolverContext<TArgs = Record<string, unknown>> = {\n /** Tool name as registered. */\n toolName: string;\n /** Arguments the tool was called with. */\n args: TArgs;\n /** The CallToolResult the underlying handler produced. */\n result: CallToolResult;\n};\n\n/**\n * Resolves an `AgentTarget` for an executed tool. Bridges declare one of\n * these per registration so the wrapper knows which surface / element /\n * screen the activity belongs to.\n *\n * The resolver runs AFTER the tool handler so it can inspect the result\n * (e.g. read a newly-created item id from `structuredContent`).\n */\nexport type ActivityTargetResolver<TArgs = Record<string, unknown>> = (\n ctx: ActivityResolverContext<TArgs>,\n) => AgentTarget | null;\n\nexport type ToolHandler<TArgs = Record<string, unknown>> = (\n args: TArgs,\n) => Promise<CallToolResult> | CallToolResult;\n\n/**\n * wrapToolWithActivity — decorate a bridge tool handler so every successful\n * call emits an `AgentActivityEvent`. Returns a new handler with the same shape.\n *\n * Usage in a bridge:\n *\n * server.registerTool(\n * definition,\n * wrapToolWithActivity(\n * handler,\n * { agent, kind: \"whiteboard\", resolveTarget: ({ args }) => ({\n * kind: \"whiteboard\", elementId: args.id as string,\n * }) },\n * ),\n * );\n */\nexport function wrapToolWithActivity<TArgs = Record<string, unknown>>(\n handler: ToolHandler<TArgs>,\n options: {\n toolName: string;\n agent: ActivityAgent;\n /** Optional fancy-screens screen id this bridge is scoped to. */\n screenId?: string;\n /** Default target kind if the resolver returns one without `kind`. */\n kind: AgentTarget[\"kind\"];\n /** Per-call resolver. Return `null` to skip emitting (e.g. for read-only tools). */\n resolveTarget?: ActivityTargetResolver<TArgs>;\n /** Optional ttl override. */\n ttlMs?: number;\n },\n): ToolHandler<TArgs> {\n return async (args) => {\n const result = await handler(args);\n if (result.isError) return result;\n\n let target: AgentTarget | null;\n if (options.resolveTarget) {\n target = options.resolveTarget({ toolName: options.toolName, args, result });\n } else {\n target = { kind: options.kind, screenId: options.screenId };\n }\n if (!target) return result;\n\n emitActivity({\n agentId: options.agent.id,\n agentName: options.agent.name,\n agentColor: options.agent.color,\n target: { ...target, kind: target.kind ?? options.kind, screenId: target.screenId ?? options.screenId },\n action: options.toolName,\n timestamp: Date.now(),\n meta: extractMeta(result),\n ttlMs: options.ttlMs,\n });\n return result;\n };\n}\n\nfunction extractMeta(result: CallToolResult): Record<string, unknown> | undefined {\n const sc = result.structuredContent;\n if (sc && typeof sc === \"object\" && !Array.isArray(sc)) {\n return sc as Record<string, unknown>;\n }\n return undefined;\n}\n","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 * 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 ),\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 ),\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 ),\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","// 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\nconst DEFAULT_AGENT = { id: \"agent\", name: \"Agent\", color: \"#0ea5e9\" };\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 // 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 = 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 = 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 = 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 = 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);\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 = args.path !== undefined ? str(args.path) : adapter.getPath();\n const depth = args.depth !== undefined ? 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"]}