@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.
package/dist/index.cjs CHANGED
@@ -1105,7 +1105,7 @@ function registerSceneBridge(host, options) {
1105
1105
  )
1106
1106
  );
1107
1107
  };
1108
- const newId = (kind) => `${kind}_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 6)}`;
1108
+ const newId2 = (kind) => `${kind}_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 6)}`;
1109
1109
  reg(
1110
1110
  "scene_describe",
1111
1111
  "Describe the scene \u2014 object count, kinds, camera position.",
@@ -1149,7 +1149,7 @@ function registerSceneBridge(host, options) {
1149
1149
  ["kind"],
1150
1150
  (args) => {
1151
1151
  const obj = {
1152
- id: newId(String(args.kind)),
1152
+ id: newId2(String(args.kind)),
1153
1153
  kind: String(args.kind),
1154
1154
  position: parseTriple(args.position),
1155
1155
  rotation: parseTriple(args.rotation),
@@ -1955,11 +1955,548 @@ function serialize(entry) {
1955
1955
  };
1956
1956
  }
1957
1957
 
1958
+ // src/bridges/map.ts
1959
+ var DEFAULT_AGENT8 = { id: "agent", name: "Agent", color: "#7c3aed" };
1960
+ var num2 = (v, fallback) => typeof v === "number" && Number.isFinite(v) ? v : 0;
1961
+ var str2 = (v, fallback = "") => typeof v === "string" ? v : fallback;
1962
+ var newId = (prefix) => `${prefix}_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 7)}`;
1963
+ function registerMapBridge(host, options) {
1964
+ const { adapter } = options;
1965
+ const agent = { ...DEFAULT_AGENT8, ...options.agent ?? {} };
1966
+ const disposers = [];
1967
+ ensureUndoToolsRegistered(host, { defaultAgentId: agent.id });
1968
+ const mTarget = (args, result) => ({
1969
+ kind: "map",
1970
+ elementId: result?.structuredContent?.id ?? args?.id
1971
+ });
1972
+ const reg = (name, description, properties, required, handler, resolveTarget) => {
1973
+ const wrapped = async (args) => {
1974
+ try {
1975
+ return await handler(args);
1976
+ } catch (e) {
1977
+ return errorResult(e instanceof Error ? e.message : String(e));
1978
+ }
1979
+ };
1980
+ const final = resolveTarget ? wrapToolWithActivity(wrapped, {
1981
+ toolName: name,
1982
+ agent: { id: agent.id, name: agent.name, color: agent.color },
1983
+ kind: "map",
1984
+ resolveTarget: ({ args, result }) => resolveTarget(args, result)
1985
+ }) : wrapped;
1986
+ disposers.push(
1987
+ host.registerTool(
1988
+ {
1989
+ name,
1990
+ description,
1991
+ inputSchema: {
1992
+ type: "object",
1993
+ properties,
1994
+ required,
1995
+ additionalProperties: false
1996
+ }
1997
+ },
1998
+ final
1999
+ )
2000
+ );
2001
+ };
2002
+ reg("map_get_state", "Get the map's camera, markers, and current selection.", {}, [], () => {
2003
+ const state = {
2004
+ view: adapter.getView(),
2005
+ markers: adapter.getMarkers(),
2006
+ selectedId: adapter.getSelected()
2007
+ };
2008
+ return textResult(JSON.stringify(state, null, 2), state);
2009
+ });
2010
+ reg(
2011
+ "map_set_view",
2012
+ "Move the camera to an absolute position. Any omitted field is left unchanged.",
2013
+ {
2014
+ lat: { type: "number", description: "New center latitude." },
2015
+ lng: { type: "number", description: "New center longitude." },
2016
+ zoom: { type: "number", description: "New zoom level (higher = closer)." }
2017
+ },
2018
+ [],
2019
+ (args) => {
2020
+ const prev = adapter.getView();
2021
+ const next = {
2022
+ center: {
2023
+ lat: args.lat !== void 0 ? num2(args.lat) : prev.center.lat,
2024
+ lng: args.lng !== void 0 ? num2(args.lng) : prev.center.lng
2025
+ },
2026
+ zoom: args.zoom !== void 0 ? num2(args.zoom) : prev.zoom
2027
+ };
2028
+ adapter.setView(next);
2029
+ fancyAutoCommon.pushUndoEntry(agent.id, {
2030
+ timestamp: Date.now(),
2031
+ bridgeId: "map",
2032
+ action: "map_set_view",
2033
+ label: `Moved camera to ${next.center.lat.toFixed(4)},${next.center.lng.toFixed(4)} z${next.zoom}`,
2034
+ undo: () => adapter.setView(prev),
2035
+ redo: () => adapter.setView(next)
2036
+ });
2037
+ return textResult(`Camera \u2192 ${next.center.lat.toFixed(4)},${next.center.lng.toFixed(4)} z${next.zoom}`, next);
2038
+ },
2039
+ mTarget
2040
+ );
2041
+ reg(
2042
+ "map_pan",
2043
+ "Pan the camera by a relative offset in degrees (positive dLat = north, positive dLng = east).",
2044
+ { dLat: { type: "number" }, dLng: { type: "number" } },
2045
+ [],
2046
+ (args) => {
2047
+ const prev = adapter.getView();
2048
+ const next = {
2049
+ ...prev,
2050
+ center: { lat: prev.center.lat + num2(args.dLat), lng: prev.center.lng + num2(args.dLng) }
2051
+ };
2052
+ adapter.setView(next);
2053
+ fancyAutoCommon.pushUndoEntry(agent.id, {
2054
+ timestamp: Date.now(),
2055
+ bridgeId: "map",
2056
+ action: "map_pan",
2057
+ label: "Panned camera",
2058
+ undo: () => adapter.setView(prev),
2059
+ redo: () => adapter.setView(next)
2060
+ });
2061
+ return textResult(`Panned to ${next.center.lat.toFixed(4)},${next.center.lng.toFixed(4)}`, next);
2062
+ },
2063
+ mTarget
2064
+ );
2065
+ reg(
2066
+ "map_zoom",
2067
+ "Zoom the camera by a relative delta (e.g. +1 zooms in one level, -2 out two).",
2068
+ { delta: { type: "number" } },
2069
+ ["delta"],
2070
+ (args) => {
2071
+ const prev = adapter.getView();
2072
+ const next = { ...prev, zoom: prev.zoom + num2(args.delta) };
2073
+ adapter.setView(next);
2074
+ fancyAutoCommon.pushUndoEntry(agent.id, {
2075
+ timestamp: Date.now(),
2076
+ bridgeId: "map",
2077
+ action: "map_zoom",
2078
+ label: `Zoom \u2192 ${next.zoom}`,
2079
+ undo: () => adapter.setView(prev),
2080
+ redo: () => adapter.setView(next)
2081
+ });
2082
+ return textResult(`Zoom \u2192 ${next.zoom}`, next);
2083
+ }
2084
+ );
2085
+ reg(
2086
+ "map_fit_bounds",
2087
+ "Fit the camera to enclose points. Pass `points`, or omit to fit all current markers.",
2088
+ {
2089
+ points: {
2090
+ type: "array",
2091
+ description: "Points to enclose, e.g. [{lat,lng},\u2026].",
2092
+ items: {
2093
+ type: "object",
2094
+ properties: { lat: { type: "number" }, lng: { type: "number" } },
2095
+ required: ["lat", "lng"]
2096
+ }
2097
+ },
2098
+ padding: { type: "number", description: "Padding in pixels (default 40)." }
2099
+ },
2100
+ [],
2101
+ (args) => {
2102
+ if (!adapter.fitBounds) {
2103
+ return errorResult("Host did not wire fitBounds (pass the <Map onReady> handle's fitBounds).");
2104
+ }
2105
+ const points = Array.isArray(args.points) ? args.points.map((p) => ({ lat: num2(p?.lat), lng: num2(p?.lng) })) : adapter.getMarkers().map((m) => m.position);
2106
+ if (!points.length) {
2107
+ return errorResult("No points to fit (map has no markers).");
2108
+ }
2109
+ adapter.fitBounds(points, args.padding !== void 0 ? num2(args.padding) : void 0);
2110
+ return textResult(`Fit camera to ${points.length} point(s).`);
2111
+ }
2112
+ );
2113
+ reg(
2114
+ "map_add_marker",
2115
+ "Drop a marker. `id` is optional (auto-generated); `icon` is an emoji or 1\u20132 chars.",
2116
+ {
2117
+ id: { type: "string" },
2118
+ lat: { type: "number" },
2119
+ lng: { type: "number" },
2120
+ label: { type: "string" },
2121
+ color: { type: "string", description: "CSS color, e.g. #2563eb." },
2122
+ icon: { type: "string", description: "Emoji / short text in the pin." },
2123
+ draggable: { type: "boolean" },
2124
+ data: { type: "object", description: "Arbitrary JSON payload carried with the marker." }
2125
+ },
2126
+ ["lat", "lng"],
2127
+ (args) => {
2128
+ const id = args.id ? str2(args.id) : newId("m");
2129
+ if (adapter.getMarkers().some((m) => m.id === id)) {
2130
+ return errorResult(`A marker with id ${id} already exists \u2014 use map_update_marker.`);
2131
+ }
2132
+ const marker = {
2133
+ id,
2134
+ position: { lat: num2(args.lat), lng: num2(args.lng) },
2135
+ ...args.label !== void 0 ? { label: str2(args.label) } : {},
2136
+ ...args.color !== void 0 ? { color: str2(args.color) } : {},
2137
+ ...args.icon !== void 0 ? { icon: str2(args.icon) } : {},
2138
+ ...args.draggable !== void 0 ? { draggable: !!args.draggable } : {},
2139
+ ...args.data && typeof args.data === "object" ? { data: args.data } : {}
2140
+ };
2141
+ adapter.setMarkers((all) => [...all, marker]);
2142
+ fancyAutoCommon.pushUndoEntry(agent.id, {
2143
+ timestamp: Date.now(),
2144
+ bridgeId: "map",
2145
+ action: "map_add_marker",
2146
+ label: `Added marker ${id}`,
2147
+ undo: () => adapter.setMarkers((all) => all.filter((m) => m.id !== id)),
2148
+ redo: () => adapter.setMarkers((all) => [...all, marker])
2149
+ });
2150
+ return textResult(`Added marker ${id} at ${marker.position.lat.toFixed(4)},${marker.position.lng.toFixed(4)}`, marker);
2151
+ },
2152
+ mTarget
2153
+ );
2154
+ reg(
2155
+ "map_update_marker",
2156
+ "Update a marker. Only provided fields change \u2014 update lat/lng repeatedly to drive a live track.",
2157
+ {
2158
+ id: { type: "string" },
2159
+ lat: { type: "number" },
2160
+ lng: { type: "number" },
2161
+ label: { type: "string" },
2162
+ color: { type: "string" },
2163
+ icon: { type: "string" },
2164
+ draggable: { type: "boolean" }
2165
+ },
2166
+ ["id"],
2167
+ (args) => {
2168
+ const id = str2(args.id);
2169
+ const prev = adapter.getMarkers().find((m) => m.id === id);
2170
+ if (!prev) {
2171
+ return errorResult(`No marker with id ${id}`);
2172
+ }
2173
+ const next = {
2174
+ ...prev,
2175
+ position: {
2176
+ lat: args.lat !== void 0 ? num2(args.lat) : prev.position.lat,
2177
+ lng: args.lng !== void 0 ? num2(args.lng) : prev.position.lng
2178
+ },
2179
+ ...args.label !== void 0 ? { label: str2(args.label) } : {},
2180
+ ...args.color !== void 0 ? { color: str2(args.color) } : {},
2181
+ ...args.icon !== void 0 ? { icon: str2(args.icon) } : {},
2182
+ ...args.draggable !== void 0 ? { draggable: !!args.draggable } : {}
2183
+ };
2184
+ adapter.setMarkers((all) => all.map((m) => m.id === id ? next : m));
2185
+ fancyAutoCommon.pushUndoEntry(agent.id, {
2186
+ timestamp: Date.now(),
2187
+ bridgeId: "map",
2188
+ action: "map_update_marker",
2189
+ label: `Updated marker ${id}`,
2190
+ undo: () => adapter.setMarkers((all) => all.map((m) => m.id === id ? prev : m)),
2191
+ redo: () => adapter.setMarkers((all) => all.map((m) => m.id === id ? next : m))
2192
+ });
2193
+ return textResult(`Updated marker ${id}`, next);
2194
+ },
2195
+ mTarget
2196
+ );
2197
+ reg(
2198
+ "map_remove_marker",
2199
+ "Remove a marker by id.",
2200
+ { id: { type: "string" } },
2201
+ ["id"],
2202
+ (args) => {
2203
+ const id = str2(args.id);
2204
+ const prev = adapter.getMarkers().find((m) => m.id === id);
2205
+ if (!prev) {
2206
+ return errorResult(`No marker with id ${id}`);
2207
+ }
2208
+ adapter.setMarkers((all) => all.filter((m) => m.id !== id));
2209
+ fancyAutoCommon.pushUndoEntry(agent.id, {
2210
+ timestamp: Date.now(),
2211
+ bridgeId: "map",
2212
+ action: "map_remove_marker",
2213
+ label: `Removed marker ${id}`,
2214
+ undo: () => adapter.setMarkers((all) => [...all, prev]),
2215
+ redo: () => adapter.setMarkers((all) => all.filter((m) => m.id !== id))
2216
+ });
2217
+ return textResult(`Removed marker ${id}`);
2218
+ },
2219
+ mTarget
2220
+ );
2221
+ reg(
2222
+ "map_select",
2223
+ "Select a marker (or pass no id / null to clear the selection).",
2224
+ { id: { type: "string" } },
2225
+ [],
2226
+ (args) => {
2227
+ const prev = adapter.getSelected();
2228
+ const id = args.id === void 0 || args.id === null ? null : str2(args.id);
2229
+ if (id !== null && !adapter.getMarkers().some((m) => m.id === id)) {
2230
+ return errorResult(`No marker with id ${id}`);
2231
+ }
2232
+ adapter.setSelected(id);
2233
+ fancyAutoCommon.pushUndoEntry(agent.id, {
2234
+ timestamp: Date.now(),
2235
+ bridgeId: "map",
2236
+ action: "map_select",
2237
+ label: id ? `Selected ${id}` : "Cleared selection",
2238
+ undo: () => adapter.setSelected(prev),
2239
+ redo: () => adapter.setSelected(id)
2240
+ });
2241
+ return textResult(id ? `Selected marker ${id}` : "Cleared selection", { selectedId: id });
2242
+ },
2243
+ mTarget
2244
+ );
2245
+ reg(
2246
+ "map_start_track",
2247
+ "Make the camera follow a marker as its position updates (live tracking). Requires the host to wire setFollow.",
2248
+ { id: { type: "string" } },
2249
+ ["id"],
2250
+ (args) => {
2251
+ if (!adapter.setFollow) {
2252
+ return errorResult("Host did not wire setFollow (pass the map's `follow` setter).");
2253
+ }
2254
+ const id = str2(args.id);
2255
+ if (!adapter.getMarkers().some((m) => m.id === id)) {
2256
+ return errorResult(`No marker with id ${id}`);
2257
+ }
2258
+ adapter.setFollow(id);
2259
+ return textResult(`Camera now following ${id}`, { follow: id });
2260
+ },
2261
+ mTarget
2262
+ );
2263
+ reg(
2264
+ "map_stop_track",
2265
+ "Stop following any marker (releases the camera). Requires the host to wire setFollow.",
2266
+ {},
2267
+ [],
2268
+ () => {
2269
+ if (!adapter.setFollow) {
2270
+ return errorResult("Host did not wire setFollow.");
2271
+ }
2272
+ adapter.setFollow(null);
2273
+ return textResult("Camera released (no longer following).", { follow: null });
2274
+ }
2275
+ );
2276
+ return {
2277
+ id: "map",
2278
+ title: "Map",
2279
+ dispose: () => {
2280
+ for (const d of disposers) d();
2281
+ }
2282
+ };
2283
+ }
2284
+
2285
+ // src/bridges/files.ts
2286
+ var DEFAULT_AGENT9 = { id: "agent", name: "Agent", color: "#0ea5e9" };
2287
+ var str3 = (v, fallback = "") => typeof v === "string" ? v : fallback;
2288
+ var num3 = (v, fallback) => typeof v === "number" && Number.isFinite(v) ? v : 0;
2289
+ var asPaths = (v) => {
2290
+ if (typeof v === "string") {
2291
+ return [v];
2292
+ }
2293
+ if (Array.isArray(v)) {
2294
+ return v.filter((x) => typeof x === "string");
2295
+ }
2296
+ return [];
2297
+ };
2298
+ function registerFilesBridge(host, options) {
2299
+ const { adapter } = options;
2300
+ const agent = { ...DEFAULT_AGENT9, ...options.agent ?? {} };
2301
+ const disposers = [];
2302
+ ensureUndoToolsRegistered(host, { defaultAgentId: agent.id });
2303
+ const fTarget = (args, _result) => ({
2304
+ kind: "files",
2305
+ elementId: args?.path ?? void 0
2306
+ });
2307
+ const reg = (name, description, properties, required, handler, resolveTarget) => {
2308
+ const wrapped = async (args) => {
2309
+ try {
2310
+ return await handler(args);
2311
+ } catch (e) {
2312
+ return errorResult(e instanceof Error ? e.message : String(e));
2313
+ }
2314
+ };
2315
+ const final = resolveTarget ? wrapToolWithActivity(wrapped, {
2316
+ toolName: name,
2317
+ agent: { id: agent.id, name: agent.name, color: agent.color },
2318
+ kind: "files",
2319
+ resolveTarget: ({ args, result }) => resolveTarget(args, result)
2320
+ }) : wrapped;
2321
+ disposers.push(
2322
+ host.registerTool(
2323
+ {
2324
+ name,
2325
+ description,
2326
+ inputSchema: {
2327
+ type: "object",
2328
+ properties,
2329
+ required,
2330
+ additionalProperties: false
2331
+ }
2332
+ },
2333
+ final
2334
+ )
2335
+ );
2336
+ };
2337
+ reg(
2338
+ "files_get_state",
2339
+ "Get the file browser's current directory, selected path(s), and expanded folders.",
2340
+ {},
2341
+ [],
2342
+ () => {
2343
+ const state = {
2344
+ path: adapter.getPath(),
2345
+ selected: adapter.getSelection(),
2346
+ expanded: adapter.getExpanded()
2347
+ };
2348
+ return textResult(JSON.stringify(state, null, 2), state);
2349
+ }
2350
+ );
2351
+ reg(
2352
+ "files_list",
2353
+ "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.",
2354
+ { path: { type: "string", description: "Folder path to list; defaults to the current directory." } },
2355
+ [],
2356
+ async (args) => {
2357
+ const path = args.path !== void 0 ? str3(args.path) : adapter.getPath();
2358
+ const entries = await adapter.listChildren(path);
2359
+ const summary = entries.map((e) => ({
2360
+ path: e.path,
2361
+ name: e.name,
2362
+ kind: e.kind,
2363
+ ...e.size !== void 0 ? { size: e.size } : {},
2364
+ ...e.mtime !== void 0 ? { mtime: e.mtime } : {}
2365
+ }));
2366
+ const text = summary.map((e) => `${e.kind === "dir" ? "\u{1F4C1}" : "\u{1F4C4}"} ${e.path}`).join("\n") || `(empty: ${path})`;
2367
+ return textResult(text, { path, entries: summary });
2368
+ }
2369
+ );
2370
+ reg(
2371
+ "files_navigate",
2372
+ "Set the current directory (as if the user clicked a breadcrumb or opened a folder).",
2373
+ { path: { type: "string" } },
2374
+ ["path"],
2375
+ (args) => {
2376
+ const path = str3(args.path);
2377
+ const prev = adapter.getPath();
2378
+ adapter.setPath(path);
2379
+ fancyAutoCommon.pushUndoEntry(agent.id, {
2380
+ timestamp: Date.now(),
2381
+ bridgeId: "files",
2382
+ action: "files_navigate",
2383
+ label: `Navigated to ${path}`,
2384
+ undo: () => adapter.setPath(prev),
2385
+ redo: () => adapter.setPath(path)
2386
+ });
2387
+ return textResult(`Current directory \u2192 ${path}`, { path });
2388
+ },
2389
+ fTarget
2390
+ );
2391
+ reg(
2392
+ "files_expand",
2393
+ "Expand a folder in the tree (loads its children if needed).",
2394
+ { path: { type: "string" } },
2395
+ ["path"],
2396
+ (args) => {
2397
+ const path = str3(args.path);
2398
+ if (adapter.getExpanded().includes(path)) {
2399
+ return textResult(`${path} already expanded`, { path, expanded: true });
2400
+ }
2401
+ adapter.setExpanded((prev) => [...prev, path]);
2402
+ fancyAutoCommon.pushUndoEntry(agent.id, {
2403
+ timestamp: Date.now(),
2404
+ bridgeId: "files",
2405
+ action: "files_expand",
2406
+ label: `Expanded ${path}`,
2407
+ undo: () => adapter.setExpanded((prev) => prev.filter((p) => p !== path)),
2408
+ redo: () => adapter.setExpanded((prev) => prev.includes(path) ? prev : [...prev, path])
2409
+ });
2410
+ return textResult(`Expanded ${path}`, { path, expanded: true });
2411
+ },
2412
+ fTarget
2413
+ );
2414
+ reg(
2415
+ "files_collapse",
2416
+ "Collapse a folder in the tree.",
2417
+ { path: { type: "string" } },
2418
+ ["path"],
2419
+ (args) => {
2420
+ const path = str3(args.path);
2421
+ if (!adapter.getExpanded().includes(path)) {
2422
+ return textResult(`${path} already collapsed`, { path, expanded: false });
2423
+ }
2424
+ adapter.setExpanded((prev) => prev.filter((p) => p !== path));
2425
+ fancyAutoCommon.pushUndoEntry(agent.id, {
2426
+ timestamp: Date.now(),
2427
+ bridgeId: "files",
2428
+ action: "files_collapse",
2429
+ label: `Collapsed ${path}`,
2430
+ undo: () => adapter.setExpanded((prev) => prev.includes(path) ? prev : [...prev, path]),
2431
+ redo: () => adapter.setExpanded((prev) => prev.filter((p) => p !== path))
2432
+ });
2433
+ return textResult(`Collapsed ${path}`, { path, expanded: false });
2434
+ },
2435
+ fTarget
2436
+ );
2437
+ reg(
2438
+ "files_select",
2439
+ "Set the selection to the given path(s). Pass a single `path`, or `paths` for a multi-select browser; either empty clears the selection.",
2440
+ {
2441
+ path: { type: "string", description: "A single path to select." },
2442
+ paths: { type: "array", items: { type: "string" }, description: "Multiple paths (multi-select browsers)." }
2443
+ },
2444
+ [],
2445
+ (args) => {
2446
+ const next = args.paths !== void 0 ? asPaths(args.paths) : asPaths(args.path);
2447
+ const prev = adapter.getSelection();
2448
+ adapter.setSelection(next);
2449
+ fancyAutoCommon.pushUndoEntry(agent.id, {
2450
+ timestamp: Date.now(),
2451
+ bridgeId: "files",
2452
+ action: "files_select",
2453
+ label: next.length ? `Selected ${next.join(", ")}` : "Cleared selection",
2454
+ undo: () => adapter.setSelection(prev),
2455
+ redo: () => adapter.setSelection(next)
2456
+ });
2457
+ return textResult(next.length ? `Selected ${next.join(", ")}` : "Cleared selection", {
2458
+ selected: next
2459
+ });
2460
+ },
2461
+ fTarget
2462
+ );
2463
+ reg(
2464
+ "files_request_snapshot",
2465
+ "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.",
2466
+ {
2467
+ path: { type: "string", description: "Root of the subtree; defaults to the current directory." },
2468
+ depth: { type: "number", description: "How many levels deep to materialize (host-defined default)." }
2469
+ },
2470
+ [],
2471
+ async (args) => {
2472
+ if (!adapter.requestSnapshot) {
2473
+ return errorResult("Host did not wire requestSnapshot (snapshot mode not enabled).");
2474
+ }
2475
+ const path = args.path !== void 0 ? str3(args.path) : adapter.getPath();
2476
+ const depth = args.depth !== void 0 ? num3(args.depth) : void 0;
2477
+ const tree = await adapter.requestSnapshot(path, depth);
2478
+ const count = Array.isArray(tree) ? tree.length : 0;
2479
+ return textResult(`Snapshot of ${path}: ${count} top-level entr${count === 1 ? "y" : "ies"}.`, {
2480
+ path,
2481
+ snapshot: tree
2482
+ });
2483
+ },
2484
+ fTarget
2485
+ );
2486
+ return {
2487
+ id: "files",
2488
+ title: "Files",
2489
+ dispose: () => {
2490
+ for (const d of disposers) d();
2491
+ }
2492
+ };
2493
+ }
2494
+
1958
2495
  // src/bridges/terminal.ts
1959
- var DEFAULT_AGENT8 = { id: "agent", name: "Agent", color: "#a855f7" };
2496
+ var DEFAULT_AGENT10 = { id: "agent", name: "Agent", color: "#a855f7" };
1960
2497
  var truncate = (s, n = 60) => s.length > n ? s.slice(0, n) + "\u2026" : s;
1961
2498
  function registerTerminalBridge(host, options) {
1962
- const agent = { ...DEFAULT_AGENT8, ...options.agent ?? {} };
2499
+ const agent = { ...DEFAULT_AGENT10, ...options.agent ?? {} };
1963
2500
  const pendingMode = options.pendingMode ?? false;
1964
2501
  const screenId = options.screenId ?? options.adapter?.screenId;
1965
2502
  const disposers = [];
@@ -2224,10 +2761,10 @@ function registerTerminalBridge(host, options) {
2224
2761
  }
2225
2762
 
2226
2763
  // src/bridges/navigation.ts
2227
- var DEFAULT_AGENT9 = { id: "agent", name: "Agent", color: "#a855f7" };
2764
+ var DEFAULT_AGENT11 = { id: "agent", name: "Agent", color: "#a855f7" };
2228
2765
  function registerNavigationBridge(host, options) {
2229
2766
  const { adapter } = options;
2230
- const agent = { ...DEFAULT_AGENT9, ...options.agent ?? {} };
2767
+ const agent = { ...DEFAULT_AGENT11, ...options.agent ?? {} };
2231
2768
  const pendingMode = options.pendingMode ?? true;
2232
2769
  const disposers = [];
2233
2770
  ensureUndoToolsRegistered(host, { defaultAgentId: agent.id });
@@ -2432,12 +2969,12 @@ function registerNavigationBridge(host, options) {
2432
2969
  }
2433
2970
 
2434
2971
  // src/bridges/catalog.ts
2435
- var DEFAULT_AGENT10 = { id: "agent", name: "Agent", color: "#a855f7" };
2436
- var str2 = (v, fallback = "") => typeof v === "string" ? v : fallback;
2437
- var num2 = (v, fallback = 0) => typeof v === "number" && Number.isFinite(v) ? v : fallback;
2972
+ var DEFAULT_AGENT12 = { id: "agent", name: "Agent", color: "#a855f7" };
2973
+ var str4 = (v, fallback = "") => typeof v === "string" ? v : fallback;
2974
+ var num4 = (v, fallback = 0) => typeof v === "number" && Number.isFinite(v) ? v : fallback;
2438
2975
  function registerCatalogBridge(host, options) {
2439
2976
  const { adapter } = options;
2440
- const agent = { ...DEFAULT_AGENT10, ...options.agent ?? {} };
2977
+ const agent = { ...DEFAULT_AGENT12, ...options.agent ?? {} };
2441
2978
  const pendingMode = options.pendingMode ?? true;
2442
2979
  const catalogId = adapter.id ?? "catalog";
2443
2980
  const disposers = [];
@@ -2507,7 +3044,7 @@ function registerCatalogBridge(host, options) {
2507
3044
  { id: { type: "string" }, withTrashed: { type: "boolean" } },
2508
3045
  ["id"],
2509
3046
  async (args) => {
2510
- const id = str2(args.id);
3047
+ const id = str4(args.id);
2511
3048
  const product = await adapter.products.find(id, { withTrashed: args.withTrashed === true });
2512
3049
  if (!product) return errorResult(`No product with id ${id}`);
2513
3050
  const prices = await adapter.prices.forProduct(id, { withTrashed: args.withTrashed === true });
@@ -2523,7 +3060,7 @@ function registerCatalogBridge(host, options) {
2523
3060
  [],
2524
3061
  async (args) => {
2525
3062
  const withTrashed = args.withTrashed === true;
2526
- const prices = args.productId !== void 0 ? await adapter.prices.forProduct(str2(args.productId), { withTrashed }) : await adapter.prices.all({ withTrashed });
3063
+ const prices = args.productId !== void 0 ? await adapter.prices.forProduct(str4(args.productId), { withTrashed }) : await adapter.prices.all({ withTrashed });
2527
3064
  const list = prices.map((p) => ({
2528
3065
  id: p.id,
2529
3066
  productId: p.productId,
@@ -2549,13 +3086,13 @@ function registerCatalogBridge(host, options) {
2549
3086
  },
2550
3087
  ["name"],
2551
3088
  async (args) => {
2552
- const name = str2(args.name);
3089
+ const name = str4(args.name);
2553
3090
  if (!name) return errorResult("name is required.");
2554
3091
  const product = await adapter.createProduct({
2555
3092
  name,
2556
- ...args.description !== void 0 ? { description: str2(args.description) } : {},
3093
+ ...args.description !== void 0 ? { description: str4(args.description) } : {},
2557
3094
  ...args.active !== void 0 ? { active: args.active === true } : {},
2558
- ...args.lookupKey !== void 0 ? { lookupKey: str2(args.lookupKey) } : {},
3095
+ ...args.lookupKey !== void 0 ? { lookupKey: str4(args.lookupKey) } : {},
2559
3096
  ...args.metadata && typeof args.metadata === "object" ? { metadata: args.metadata } : {}
2560
3097
  });
2561
3098
  fancyAutoCommon.pushUndoEntry(agent.id, {
@@ -2568,7 +3105,7 @@ function registerCatalogBridge(host, options) {
2568
3105
  });
2569
3106
  return textResult(`Created product ${product.id} (${product.name})`, product);
2570
3107
  },
2571
- (args) => target(void 0, `create product ${str2(args.name)}`)
3108
+ (args) => target(void 0, `create product ${str4(args.name)}`)
2572
3109
  );
2573
3110
  reg(
2574
3111
  "catalog_create_price",
@@ -2585,19 +3122,19 @@ function registerCatalogBridge(host, options) {
2585
3122
  },
2586
3123
  ["productId", "currency", "unitAmount", "type"],
2587
3124
  async (args) => {
2588
- const productId = str2(args.productId);
3125
+ const productId = str4(args.productId);
2589
3126
  const product = await adapter.products.find(productId);
2590
3127
  if (!product) return errorResult(`No product with id ${productId}`);
2591
- const type = str2(args.type);
3128
+ const type = str4(args.type);
2592
3129
  if (type !== "recurring" && type !== "one_time") return errorResult("type must be 'recurring' or 'one_time'.");
2593
3130
  const price = await adapter.createPrice({
2594
3131
  productId,
2595
- currency: str2(args.currency),
2596
- unitAmount: num2(args.unitAmount),
3132
+ currency: str4(args.currency),
3133
+ unitAmount: num4(args.unitAmount),
2597
3134
  type,
2598
- ...args.recurringInterval !== void 0 ? { recurringInterval: str2(args.recurringInterval) } : {},
2599
- ...args.nickname !== void 0 ? { nickname: str2(args.nickname) } : {},
2600
- ...args.lookupKey !== void 0 ? { lookupKey: str2(args.lookupKey) } : {},
3135
+ ...args.recurringInterval !== void 0 ? { recurringInterval: str4(args.recurringInterval) } : {},
3136
+ ...args.nickname !== void 0 ? { nickname: str4(args.nickname) } : {},
3137
+ ...args.lookupKey !== void 0 ? { lookupKey: str4(args.lookupKey) } : {},
2601
3138
  ...args.metadata && typeof args.metadata === "object" ? { metadata: args.metadata } : {}
2602
3139
  });
2603
3140
  fancyAutoCommon.pushUndoEntry(agent.id, {
@@ -2610,7 +3147,7 @@ function registerCatalogBridge(host, options) {
2610
3147
  });
2611
3148
  return textResult(`Created ${type} price ${price.id} on ${productId}`, price);
2612
3149
  },
2613
- (args) => target(str2(args.productId), `create price on ${str2(args.productId)}`)
3150
+ (args) => target(str4(args.productId), `create price on ${str4(args.productId)}`)
2614
3151
  );
2615
3152
  reg(
2616
3153
  "catalog_delete_product",
@@ -2618,7 +3155,7 @@ function registerCatalogBridge(host, options) {
2618
3155
  { id: { type: "string" }, confirm: { type: "boolean" } },
2619
3156
  ["id"],
2620
3157
  async (args) => {
2621
- const id = str2(args.id);
3158
+ const id = str4(args.id);
2622
3159
  const product = await adapter.products.find(id, { withTrashed: true });
2623
3160
  if (!product) return errorResult(`No product with id ${id}`);
2624
3161
  const blocked = await guardDestructive("catalog_delete_product", id, product.name, args.confirm === true);
@@ -2635,7 +3172,7 @@ function registerCatalogBridge(host, options) {
2635
3172
  });
2636
3173
  return textResult(`Deleted product ${id}`, { id });
2637
3174
  },
2638
- (args) => target(str2(args.id), `delete product ${str2(args.id)}`)
3175
+ (args) => target(str4(args.id), `delete product ${str4(args.id)}`)
2639
3176
  );
2640
3177
  reg(
2641
3178
  "catalog_delete_price",
@@ -2643,7 +3180,7 @@ function registerCatalogBridge(host, options) {
2643
3180
  { id: { type: "string" }, confirm: { type: "boolean" } },
2644
3181
  ["id"],
2645
3182
  async (args) => {
2646
- const id = str2(args.id);
3183
+ const id = str4(args.id);
2647
3184
  const price = await adapter.prices.find(id, { withTrashed: true });
2648
3185
  if (!price) return errorResult(`No price with id ${id}`);
2649
3186
  const blocked = await guardDestructive("catalog_delete_price", id, id, args.confirm === true);
@@ -2660,7 +3197,7 @@ function registerCatalogBridge(host, options) {
2660
3197
  });
2661
3198
  return textResult(`Deleted price ${id}`, { id });
2662
3199
  },
2663
- (args) => target(str2(args.id), `delete price ${str2(args.id)}`)
3200
+ (args) => target(str4(args.id), `delete price ${str4(args.id)}`)
2664
3201
  );
2665
3202
  reg(
2666
3203
  "catalog_sync_product",
@@ -2669,13 +3206,13 @@ function registerCatalogBridge(host, options) {
2669
3206
  ["id"],
2670
3207
  async (args) => {
2671
3208
  if (!adapter.syncProductAndPrices) return errorResult("Host did not wire Stripe sync.");
2672
- const id = str2(args.id);
3209
+ const id = str4(args.id);
2673
3210
  const product = await adapter.products.find(id);
2674
3211
  if (!product) return errorResult(`No product with id ${id}`);
2675
3212
  const synced = await adapter.syncProductAndPrices(product);
2676
3213
  return textResult(`Synced product ${id} to Stripe (${synced.externalId ?? "no external id"})`, synced);
2677
3214
  },
2678
- (args) => target(str2(args.id), `sync product ${str2(args.id)}`)
3215
+ (args) => target(str4(args.id), `sync product ${str4(args.id)}`)
2679
3216
  );
2680
3217
  reg(
2681
3218
  "catalog_test_connection",
@@ -2702,13 +3239,13 @@ function registerCatalogBridge(host, options) {
2702
3239
  },
2703
3240
  ["priceId", "successUrl", "cancelUrl"],
2704
3241
  async (args) => {
2705
- const priceId = str2(args.priceId);
3242
+ const priceId = str4(args.priceId);
2706
3243
  const price = await adapter.prices.find(priceId);
2707
3244
  if (!price) return errorResult(`No price with id ${priceId}`);
2708
3245
  const checkoutArgs = {
2709
- successUrl: str2(args.successUrl),
2710
- cancelUrl: str2(args.cancelUrl),
2711
- ...args.customer !== void 0 ? { customer: str2(args.customer) } : {},
3246
+ successUrl: str4(args.successUrl),
3247
+ cancelUrl: str4(args.cancelUrl),
3248
+ ...args.customer !== void 0 ? { customer: str4(args.customer) } : {},
2712
3249
  ...args.metadata && typeof args.metadata === "object" ? { metadata: args.metadata } : {}
2713
3250
  };
2714
3251
  let url;
@@ -2717,11 +3254,11 @@ function registerCatalogBridge(host, options) {
2717
3254
  url = await adapter.getSubscriptionCheckoutUrl(price, checkoutArgs);
2718
3255
  } else {
2719
3256
  if (!adapter.getOneTimeCheckoutUrl) return errorResult("Host did not wire one-time checkout.");
2720
- url = await adapter.getOneTimeCheckoutUrl(price, { ...checkoutArgs, quantity: num2(args.quantity, 1) });
3257
+ url = await adapter.getOneTimeCheckoutUrl(price, { ...checkoutArgs, quantity: num4(args.quantity, 1) });
2721
3258
  }
2722
3259
  return textResult(url || "(no url)", { priceId, type: price.type, url });
2723
3260
  },
2724
- (args) => target(str2(args.priceId), `checkout ${str2(args.priceId)}`)
3261
+ (args) => target(str4(args.priceId), `checkout ${str4(args.priceId)}`)
2725
3262
  );
2726
3263
  return {
2727
3264
  id: `catalog:${catalogId}`,
@@ -2733,12 +3270,12 @@ function registerCatalogBridge(host, options) {
2733
3270
  }
2734
3271
 
2735
3272
  // src/bridges/features.ts
2736
- var DEFAULT_AGENT11 = { id: "agent", name: "Agent", color: "#a855f7" };
2737
- var str3 = (v, fallback = "") => typeof v === "string" ? v : fallback;
2738
- var num3 = (v, fallback = 0) => typeof v === "number" && Number.isFinite(v) ? v : fallback;
3273
+ var DEFAULT_AGENT13 = { id: "agent", name: "Agent", color: "#a855f7" };
3274
+ var str5 = (v, fallback = "") => typeof v === "string" ? v : fallback;
3275
+ var num5 = (v, fallback = 0) => typeof v === "number" && Number.isFinite(v) ? v : fallback;
2739
3276
  function registerFeaturesBridge(host, options) {
2740
3277
  const { adapter } = options;
2741
- const agent = { ...DEFAULT_AGENT11, ...options.agent ?? {} };
3278
+ const agent = { ...DEFAULT_AGENT13, ...options.agent ?? {} };
2742
3279
  const pendingMode = options.pendingMode ?? true;
2743
3280
  const featuresId = adapter.id ?? "features";
2744
3281
  const disposers = [];
@@ -2799,7 +3336,7 @@ function registerFeaturesBridge(host, options) {
2799
3336
  { feature: { type: "string" }, subject: { description: "Opaque subject." }, context: { description: "Optional context." } },
2800
3337
  ["feature"],
2801
3338
  async (args) => {
2802
- const feature = str3(args.feature);
3339
+ const feature = str5(args.feature);
2803
3340
  const allowed = await adapter.canAccess(feature, args.subject, args.context);
2804
3341
  const remaining = await adapter.remaining(feature, args.subject, args.context);
2805
3342
  const out = { feature, allowed, remaining };
@@ -2814,7 +3351,7 @@ function registerFeaturesBridge(host, options) {
2814
3351
  ["feature"],
2815
3352
  async (args) => {
2816
3353
  if (!adapter.explain) return errorResult("Host did not wire explain().");
2817
- const result = await adapter.explain(str3(args.feature), args.subject, args.context);
3354
+ const result = await adapter.explain(str5(args.feature), args.subject, args.context);
2818
3355
  return textResult(JSON.stringify(result, null, 2), result);
2819
3356
  },
2820
3357
  false
@@ -2843,15 +3380,15 @@ function registerFeaturesBridge(host, options) {
2843
3380
  },
2844
3381
  ["key"],
2845
3382
  (args) => {
2846
- const key = str3(args.key);
3383
+ const key = str5(args.key);
2847
3384
  if (!key) return errorResult("key is required.");
2848
3385
  const existed = adapter.registryKeys().includes(key);
2849
3386
  const definition = {
2850
- ...args.name !== void 0 ? { name: str3(args.name) } : {},
2851
- ...args.description !== void 0 ? { description: str3(args.description) } : {},
2852
- ...args.type !== void 0 ? { type: str3(args.type) } : {},
3387
+ ...args.name !== void 0 ? { name: str5(args.name) } : {},
3388
+ ...args.description !== void 0 ? { description: str5(args.description) } : {},
3389
+ ...args.type !== void 0 ? { type: str5(args.type) } : {},
2853
3390
  ...args.enabled !== void 0 ? { enabled: args.enabled === true } : {},
2854
- ...args.limit !== void 0 ? { limit: num3(args.limit) } : {}
3391
+ ...args.limit !== void 0 ? { limit: num5(args.limit) } : {}
2855
3392
  };
2856
3393
  adapter.registerFeature(key, definition);
2857
3394
  fancyAutoCommon.pushUndoEntry(agent.id, {
@@ -2866,7 +3403,7 @@ function registerFeaturesBridge(host, options) {
2866
3403
  });
2867
3404
  return textResult(`${existed ? "Redefined" : "Defined"} feature ${key} (${definition.type ?? "boolean"})`, { key, definition });
2868
3405
  },
2869
- (args) => target(str3(args.key), `define ${str3(args.key)}`)
3406
+ (args) => target(str5(args.key), `define ${str5(args.key)}`)
2870
3407
  );
2871
3408
  reg(
2872
3409
  "features_grant",
@@ -2874,7 +3411,7 @@ function registerFeaturesBridge(host, options) {
2874
3411
  { subject: { description: "Opaque subject." }, group: { type: "string", description: "Feature group key." }, confirm: { type: "boolean" } },
2875
3412
  ["subject", "group"],
2876
3413
  async (args) => {
2877
- const groupKey = str3(args.group);
3414
+ const groupKey = str5(args.group);
2878
3415
  if (!groupKey) return errorResult("group is required.");
2879
3416
  const blocked = await guardGrant("features_grant", args.subject, groupKey, args.confirm === true);
2880
3417
  if (blocked) return blocked;
@@ -2893,7 +3430,7 @@ function registerFeaturesBridge(host, options) {
2893
3430
  });
2894
3431
  return textResult(`Granted group ${groupKey}`, { subject: args.subject, group: groupKey });
2895
3432
  },
2896
- (args) => target(str3(args.group), `grant ${str3(args.group)}`)
3433
+ (args) => target(str5(args.group), `grant ${str5(args.group)}`)
2897
3434
  );
2898
3435
  reg(
2899
3436
  "features_revoke",
@@ -2901,7 +3438,7 @@ function registerFeaturesBridge(host, options) {
2901
3438
  { subject: { description: "Opaque subject." }, group: { type: "string" }, confirm: { type: "boolean" } },
2902
3439
  ["subject", "group"],
2903
3440
  async (args) => {
2904
- const groupKey = str3(args.group);
3441
+ const groupKey = str5(args.group);
2905
3442
  if (!groupKey) return errorResult("group is required.");
2906
3443
  const blocked = await guardGrant("features_revoke", args.subject, groupKey, args.confirm === true);
2907
3444
  if (blocked) return blocked;
@@ -2919,7 +3456,7 @@ function registerFeaturesBridge(host, options) {
2919
3456
  });
2920
3457
  return textResult(`Revoked group ${groupKey}`, { subject: args.subject, group: groupKey });
2921
3458
  },
2922
- (args) => target(str3(args.group), `revoke ${str3(args.group)}`)
3459
+ (args) => target(str5(args.group), `revoke ${str5(args.group)}`)
2923
3460
  );
2924
3461
  reg(
2925
3462
  "features_consume",
@@ -2928,14 +3465,14 @@ function registerFeaturesBridge(host, options) {
2928
3465
  ["feature", "subject"],
2929
3466
  async (args) => {
2930
3467
  if (!adapter.tryConsume) return errorResult("Host did not wire usage metering (tryConsume).");
2931
- const feature = str3(args.feature);
2932
- const amount = num3(args.amount, 1);
3468
+ const feature = str5(args.feature);
3469
+ const amount = num5(args.amount, 1);
2933
3470
  const ok = await adapter.tryConsume(feature, args.subject, amount, args.context);
2934
3471
  const remaining = await adapter.remaining(feature, args.subject, args.context);
2935
3472
  const out = { feature, ok, amount, remaining };
2936
3473
  return textResult(JSON.stringify(out), out);
2937
3474
  },
2938
- (args) => target(str3(args.feature), `consume ${str3(args.feature)}`)
3475
+ (args) => target(str5(args.feature), `consume ${str5(args.feature)}`)
2939
3476
  );
2940
3477
  return {
2941
3478
  id: `features:${featuresId}`,
@@ -3140,11 +3677,11 @@ function attachSseRelay(server, options) {
3140
3677
 
3141
3678
  // src/sharing/use-co-browse-session.ts
3142
3679
  init_registry();
3143
- var DEFAULT_AGENT12 = { id: "agent", name: "Agent", color: "#a855f7" };
3680
+ var DEFAULT_AGENT14 = { id: "agent", name: "Agent", color: "#a855f7" };
3144
3681
  var USER = { id: "human", name: "You" };
3145
3682
  function useCoBrowseSession(options) {
3146
3683
  const { adapter, extraBridges } = options;
3147
- const agent = { ...DEFAULT_AGENT12, ...options.agent ?? {} };
3684
+ const agent = { ...DEFAULT_AGENT14, ...options.agent ?? {} };
3148
3685
  const relayBaseUrl = options.relayBaseUrl ?? "/agent-relay";
3149
3686
  const serverRef = react.useRef(null);
3150
3687
  const relayRef = react.useRef(null);
@@ -4370,7 +4907,9 @@ exports.registerCatalogBridge = registerCatalogBridge;
4370
4907
  exports.registerChartsBridge = registerChartsBridge;
4371
4908
  exports.registerCodeBridge = registerCodeBridge;
4372
4909
  exports.registerFeaturesBridge = registerFeaturesBridge;
4910
+ exports.registerFilesBridge = registerFilesBridge;
4373
4911
  exports.registerFormBridge = registerFormBridge;
4912
+ exports.registerMapBridge = registerMapBridge;
4374
4913
  exports.registerNavigationBridge = registerNavigationBridge;
4375
4914
  exports.registerSceneBridge = registerSceneBridge;
4376
4915
  exports.registerScreensBridge = registerScreensBridge;