@burdenoff/microfe-vibecontrols 2026.601.8 → 2026.601.9

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 (273) hide show
  1. package/dist/_virtual/_rolldown/runtime.js +5 -2
  2. package/dist/components/graph/MeshAgentNode.js +74 -0
  3. package/dist/components/graph/MeshAgentNode.js.map +1 -0
  4. package/dist/components/graph/MeshDeployWizard.js +393 -0
  5. package/dist/components/graph/MeshDeployWizard.js.map +1 -0
  6. package/dist/components/graph/MeshGraphView.js +190 -0
  7. package/dist/components/graph/MeshGraphView.js.map +1 -0
  8. package/dist/components/graph/MeshNodeActions.js +70 -0
  9. package/dist/components/graph/MeshNodeActions.js.map +1 -0
  10. package/dist/components/graph/MeshRequestPanel.js +240 -0
  11. package/dist/components/graph/MeshRequestPanel.js.map +1 -0
  12. package/dist/components/graph/meshTypes.js +11 -0
  13. package/dist/components/graph/meshTypes.js.map +1 -0
  14. package/dist/components/graph/nodeIcons.js +31 -0
  15. package/dist/components/graph/nodeIcons.js.map +1 -0
  16. package/dist/components/sessions/TerminalPanel.js +483 -435
  17. package/dist/components/sessions/TerminalPanel.js.map +1 -1
  18. package/dist/generated/wspace-operations.js +1856 -1647
  19. package/dist/generated/wspace-operations.js.map +1 -1
  20. package/dist/generated/wspace-types.js +14 -12
  21. package/dist/generated/wspace-types.js.map +1 -1
  22. package/dist/index.js +10 -10
  23. package/dist/node_modules/dagre/index.js +24 -0
  24. package/dist/node_modules/dagre/index.js.map +1 -0
  25. package/dist/node_modules/dagre/lib/acyclic.js +47 -0
  26. package/dist/node_modules/dagre/lib/acyclic.js.map +1 -0
  27. package/dist/node_modules/dagre/lib/add-border-segments.js +32 -0
  28. package/dist/node_modules/dagre/lib/add-border-segments.js.map +1 -0
  29. package/dist/node_modules/dagre/lib/coordinate-system.js +57 -0
  30. package/dist/node_modules/dagre/lib/coordinate-system.js.map +1 -0
  31. package/dist/node_modules/dagre/lib/data/list.js +30 -0
  32. package/dist/node_modules/dagre/lib/data/list.js.map +1 -0
  33. package/dist/node_modules/dagre/lib/debug.js +31 -0
  34. package/dist/node_modules/dagre/lib/debug.js.map +1 -0
  35. package/dist/node_modules/dagre/lib/graphlib.js +15 -0
  36. package/dist/node_modules/dagre/lib/graphlib.js.map +1 -0
  37. package/dist/node_modules/dagre/lib/greedy-fas.js +74 -0
  38. package/dist/node_modules/dagre/lib/greedy-fas.js.map +1 -0
  39. package/dist/node_modules/dagre/lib/layout.js +305 -0
  40. package/dist/node_modules/dagre/lib/layout.js.map +1 -0
  41. package/dist/node_modules/dagre/lib/lodash.js +67 -0
  42. package/dist/node_modules/dagre/lib/lodash.js.map +1 -0
  43. package/dist/node_modules/dagre/lib/nesting-graph.js +76 -0
  44. package/dist/node_modules/dagre/lib/nesting-graph.js.map +1 -0
  45. package/dist/node_modules/dagre/lib/normalize.js +45 -0
  46. package/dist/node_modules/dagre/lib/normalize.js.map +1 -0
  47. package/dist/node_modules/dagre/lib/order/add-subgraph-constraints.js +24 -0
  48. package/dist/node_modules/dagre/lib/order/add-subgraph-constraints.js.map +1 -0
  49. package/dist/node_modules/dagre/lib/order/barycenter.js +34 -0
  50. package/dist/node_modules/dagre/lib/order/barycenter.js.map +1 -0
  51. package/dist/node_modules/dagre/lib/order/build-layer-graph.js +32 -0
  52. package/dist/node_modules/dagre/lib/order/build-layer-graph.js.map +1 -0
  53. package/dist/node_modules/dagre/lib/order/cross-count.js +39 -0
  54. package/dist/node_modules/dagre/lib/order/cross-count.js.map +1 -0
  55. package/dist/node_modules/dagre/lib/order/index.js +50 -0
  56. package/dist/node_modules/dagre/lib/order/index.js.map +1 -0
  57. package/dist/node_modules/dagre/lib/order/init-order.js +28 -0
  58. package/dist/node_modules/dagre/lib/order/init-order.js.map +1 -0
  59. package/dist/node_modules/dagre/lib/order/resolve-conflicts.js +61 -0
  60. package/dist/node_modules/dagre/lib/order/resolve-conflicts.js.map +1 -0
  61. package/dist/node_modules/dagre/lib/order/sort-subgraph.js +50 -0
  62. package/dist/node_modules/dagre/lib/order/sort-subgraph.js.map +1 -0
  63. package/dist/node_modules/dagre/lib/order/sort.js +34 -0
  64. package/dist/node_modules/dagre/lib/order/sort.js.map +1 -0
  65. package/dist/node_modules/dagre/lib/parent-dummy-chains.js +50 -0
  66. package/dist/node_modules/dagre/lib/parent-dummy-chains.js.map +1 -0
  67. package/dist/node_modules/dagre/lib/position/bk.js +212 -0
  68. package/dist/node_modules/dagre/lib/position/bk.js.map +1 -0
  69. package/dist/node_modules/dagre/lib/position/index.js +30 -0
  70. package/dist/node_modules/dagre/lib/position/index.js.map +1 -0
  71. package/dist/node_modules/dagre/lib/rank/feasible-tree.js +39 -0
  72. package/dist/node_modules/dagre/lib/rank/feasible-tree.js.map +1 -0
  73. package/dist/node_modules/dagre/lib/rank/index.js +35 -0
  74. package/dist/node_modules/dagre/lib/rank/index.js.map +1 -0
  75. package/dist/node_modules/dagre/lib/rank/network-simplex.js +90 -0
  76. package/dist/node_modules/dagre/lib/rank/network-simplex.js.map +1 -0
  77. package/dist/node_modules/dagre/lib/rank/util.js +31 -0
  78. package/dist/node_modules/dagre/lib/rank/util.js.map +1 -0
  79. package/dist/node_modules/dagre/lib/util.js +151 -0
  80. package/dist/node_modules/dagre/lib/util.js.map +1 -0
  81. package/dist/node_modules/dagre/lib/version.js +10 -0
  82. package/dist/node_modules/dagre/lib/version.js.map +1 -0
  83. package/dist/node_modules/graphlib/index.js +19 -0
  84. package/dist/node_modules/graphlib/index.js.map +1 -0
  85. package/dist/node_modules/graphlib/lib/alg/components.js +21 -0
  86. package/dist/node_modules/graphlib/lib/alg/components.js.map +1 -0
  87. package/dist/node_modules/graphlib/lib/alg/dfs.js +25 -0
  88. package/dist/node_modules/graphlib/lib/alg/dfs.js.map +1 -0
  89. package/dist/node_modules/graphlib/lib/alg/dijkstra-all.js +18 -0
  90. package/dist/node_modules/graphlib/lib/alg/dijkstra-all.js.map +1 -0
  91. package/dist/node_modules/graphlib/lib/alg/dijkstra.js +31 -0
  92. package/dist/node_modules/graphlib/lib/alg/dijkstra.js.map +1 -0
  93. package/dist/node_modules/graphlib/lib/alg/find-cycles.js +18 -0
  94. package/dist/node_modules/graphlib/lib/alg/find-cycles.js.map +1 -0
  95. package/dist/node_modules/graphlib/lib/alg/floyd-warshall.js +41 -0
  96. package/dist/node_modules/graphlib/lib/alg/floyd-warshall.js.map +1 -0
  97. package/dist/node_modules/graphlib/lib/alg/index.js +33 -0
  98. package/dist/node_modules/graphlib/lib/alg/index.js.map +1 -0
  99. package/dist/node_modules/graphlib/lib/alg/is-acyclic.js +21 -0
  100. package/dist/node_modules/graphlib/lib/alg/is-acyclic.js.map +1 -0
  101. package/dist/node_modules/graphlib/lib/alg/postorder.js +15 -0
  102. package/dist/node_modules/graphlib/lib/alg/postorder.js.map +1 -0
  103. package/dist/node_modules/graphlib/lib/alg/preorder.js +15 -0
  104. package/dist/node_modules/graphlib/lib/alg/preorder.js.map +1 -0
  105. package/dist/node_modules/graphlib/lib/alg/prim.js +35 -0
  106. package/dist/node_modules/graphlib/lib/alg/prim.js.map +1 -0
  107. package/dist/node_modules/graphlib/lib/alg/tarjan.js +34 -0
  108. package/dist/node_modules/graphlib/lib/alg/tarjan.js.map +1 -0
  109. package/dist/node_modules/graphlib/lib/alg/topsort.js +23 -0
  110. package/dist/node_modules/graphlib/lib/alg/topsort.js.map +1 -0
  111. package/dist/node_modules/graphlib/lib/data/priority-queue.js +56 -0
  112. package/dist/node_modules/graphlib/lib/data/priority-queue.js.map +1 -0
  113. package/dist/node_modules/graphlib/lib/graph.js +196 -0
  114. package/dist/node_modules/graphlib/lib/graph.js.map +1 -0
  115. package/dist/node_modules/graphlib/lib/index.js +15 -0
  116. package/dist/node_modules/graphlib/lib/index.js.map +1 -0
  117. package/dist/node_modules/graphlib/lib/json.js +55 -0
  118. package/dist/node_modules/graphlib/lib/json.js.map +1 -0
  119. package/dist/node_modules/graphlib/lib/lodash.js +47 -0
  120. package/dist/node_modules/graphlib/lib/lodash.js.map +1 -0
  121. package/dist/node_modules/graphlib/lib/version.js +10 -0
  122. package/dist/node_modules/graphlib/lib/version.js.map +1 -0
  123. package/dist/node_modules/lodash/_arrayEach.js +14 -0
  124. package/dist/node_modules/lodash/_arrayEach.js.map +1 -0
  125. package/dist/node_modules/lodash/_arrayReduce.js +15 -0
  126. package/dist/node_modules/lodash/_arrayReduce.js.map +1 -0
  127. package/dist/node_modules/lodash/_asciiSize.js +11 -0
  128. package/dist/node_modules/lodash/_asciiSize.js.map +1 -0
  129. package/dist/node_modules/lodash/_assignMergeValue.js +16 -0
  130. package/dist/node_modules/lodash/_assignMergeValue.js.map +1 -0
  131. package/dist/node_modules/lodash/_assignValue.js +17 -0
  132. package/dist/node_modules/lodash/_assignValue.js.map +1 -0
  133. package/dist/node_modules/lodash/_baseAssign.js +16 -0
  134. package/dist/node_modules/lodash/_baseAssign.js.map +1 -0
  135. package/dist/node_modules/lodash/_baseAssignIn.js +16 -0
  136. package/dist/node_modules/lodash/_baseAssignIn.js.map +1 -0
  137. package/dist/node_modules/lodash/_baseClone.js +64 -0
  138. package/dist/node_modules/lodash/_baseClone.js.map +1 -0
  139. package/dist/node_modules/lodash/_baseCreate.js +21 -0
  140. package/dist/node_modules/lodash/_baseCreate.js.map +1 -0
  141. package/dist/node_modules/lodash/_baseFilter.js +18 -0
  142. package/dist/node_modules/lodash/_baseFilter.js.map +1 -0
  143. package/dist/node_modules/lodash/_baseHas.js +14 -0
  144. package/dist/node_modules/lodash/_baseHas.js.map +1 -0
  145. package/dist/node_modules/lodash/_baseIsMap.js +16 -0
  146. package/dist/node_modules/lodash/_baseIsMap.js.map +1 -0
  147. package/dist/node_modules/lodash/_baseIsSet.js +16 -0
  148. package/dist/node_modules/lodash/_baseIsSet.js.map +1 -0
  149. package/dist/node_modules/lodash/_baseKeysIn.js +20 -0
  150. package/dist/node_modules/lodash/_baseKeysIn.js.map +1 -0
  151. package/dist/node_modules/lodash/_baseMerge.js +27 -0
  152. package/dist/node_modules/lodash/_baseMerge.js.map +1 -0
  153. package/dist/node_modules/lodash/_baseMergeDeep.js +39 -0
  154. package/dist/node_modules/lodash/_baseMergeDeep.js.map +1 -0
  155. package/dist/node_modules/lodash/_basePick.js +18 -0
  156. package/dist/node_modules/lodash/_basePick.js.map +1 -0
  157. package/dist/node_modules/lodash/_basePickBy.js +21 -0
  158. package/dist/node_modules/lodash/_basePickBy.js.map +1 -0
  159. package/dist/node_modules/lodash/_baseReduce.js +15 -0
  160. package/dist/node_modules/lodash/_baseReduce.js.map +1 -0
  161. package/dist/node_modules/lodash/_baseSet.js +30 -0
  162. package/dist/node_modules/lodash/_baseSet.js.map +1 -0
  163. package/dist/node_modules/lodash/_baseValues.js +17 -0
  164. package/dist/node_modules/lodash/_baseValues.js.map +1 -0
  165. package/dist/node_modules/lodash/_baseZipObject.js +17 -0
  166. package/dist/node_modules/lodash/_baseZipObject.js.map +1 -0
  167. package/dist/node_modules/lodash/_castFunction.js +15 -0
  168. package/dist/node_modules/lodash/_castFunction.js.map +1 -0
  169. package/dist/node_modules/lodash/_cloneArrayBuffer.js +16 -0
  170. package/dist/node_modules/lodash/_cloneArrayBuffer.js.map +1 -0
  171. package/dist/node_modules/lodash/_cloneBuffer.js +17 -0
  172. package/dist/node_modules/lodash/_cloneBuffer.js.map +1 -0
  173. package/dist/node_modules/lodash/_cloneDataView.js +16 -0
  174. package/dist/node_modules/lodash/_cloneDataView.js.map +1 -0
  175. package/dist/node_modules/lodash/_cloneRegExp.js +15 -0
  176. package/dist/node_modules/lodash/_cloneRegExp.js.map +1 -0
  177. package/dist/node_modules/lodash/_cloneSymbol.js +15 -0
  178. package/dist/node_modules/lodash/_cloneSymbol.js.map +1 -0
  179. package/dist/node_modules/lodash/_cloneTypedArray.js +16 -0
  180. package/dist/node_modules/lodash/_cloneTypedArray.js.map +1 -0
  181. package/dist/node_modules/lodash/_copyArray.js +15 -0
  182. package/dist/node_modules/lodash/_copyArray.js.map +1 -0
  183. package/dist/node_modules/lodash/_copyObject.js +22 -0
  184. package/dist/node_modules/lodash/_copyObject.js.map +1 -0
  185. package/dist/node_modules/lodash/_copySymbols.js +16 -0
  186. package/dist/node_modules/lodash/_copySymbols.js.map +1 -0
  187. package/dist/node_modules/lodash/_copySymbolsIn.js +16 -0
  188. package/dist/node_modules/lodash/_copySymbolsIn.js.map +1 -0
  189. package/dist/node_modules/lodash/_createAssigner.js +23 -0
  190. package/dist/node_modules/lodash/_createAssigner.js.map +1 -0
  191. package/dist/node_modules/lodash/_flatRest.js +17 -0
  192. package/dist/node_modules/lodash/_flatRest.js.map +1 -0
  193. package/dist/node_modules/lodash/_getAllKeysIn.js +17 -0
  194. package/dist/node_modules/lodash/_getAllKeysIn.js.map +1 -0
  195. package/dist/node_modules/lodash/_getSymbolsIn.js +18 -0
  196. package/dist/node_modules/lodash/_getSymbolsIn.js.map +1 -0
  197. package/dist/node_modules/lodash/_initCloneArray.js +15 -0
  198. package/dist/node_modules/lodash/_initCloneArray.js.map +1 -0
  199. package/dist/node_modules/lodash/_initCloneByTag.js +40 -0
  200. package/dist/node_modules/lodash/_initCloneByTag.js.map +1 -0
  201. package/dist/node_modules/lodash/_initCloneObject.js +17 -0
  202. package/dist/node_modules/lodash/_initCloneObject.js.map +1 -0
  203. package/dist/node_modules/lodash/_nativeKeysIn.js +15 -0
  204. package/dist/node_modules/lodash/_nativeKeysIn.js.map +1 -0
  205. package/dist/node_modules/lodash/_safeGet.js +13 -0
  206. package/dist/node_modules/lodash/_safeGet.js.map +1 -0
  207. package/dist/node_modules/lodash/_stringSize.js +17 -0
  208. package/dist/node_modules/lodash/_stringSize.js.map +1 -0
  209. package/dist/node_modules/lodash/_unicodeSize.js +25 -0
  210. package/dist/node_modules/lodash/_unicodeSize.js.map +1 -0
  211. package/dist/node_modules/lodash/clone.js +15 -0
  212. package/dist/node_modules/lodash/clone.js.map +1 -0
  213. package/dist/node_modules/lodash/cloneDeep.js +15 -0
  214. package/dist/node_modules/lodash/cloneDeep.js.map +1 -0
  215. package/dist/node_modules/lodash/defaults.js +23 -0
  216. package/dist/node_modules/lodash/defaults.js.map +1 -0
  217. package/dist/node_modules/lodash/each.js +11 -0
  218. package/dist/node_modules/lodash/each.js.map +1 -0
  219. package/dist/node_modules/lodash/filter.js +18 -0
  220. package/dist/node_modules/lodash/filter.js.map +1 -0
  221. package/dist/node_modules/lodash/flatten.js +15 -0
  222. package/dist/node_modules/lodash/flatten.js.map +1 -0
  223. package/dist/node_modules/lodash/forEach.js +18 -0
  224. package/dist/node_modules/lodash/forEach.js.map +1 -0
  225. package/dist/node_modules/lodash/forIn.js +17 -0
  226. package/dist/node_modules/lodash/forIn.js.map +1 -0
  227. package/dist/node_modules/lodash/has.js +16 -0
  228. package/dist/node_modules/lodash/has.js.map +1 -0
  229. package/dist/node_modules/lodash/isArrayLikeObject.js +16 -0
  230. package/dist/node_modules/lodash/isArrayLikeObject.js.map +1 -0
  231. package/dist/node_modules/lodash/isEmpty.js +28 -0
  232. package/dist/node_modules/lodash/isEmpty.js.map +1 -0
  233. package/dist/node_modules/lodash/isMap.js +14 -0
  234. package/dist/node_modules/lodash/isMap.js.map +1 -0
  235. package/dist/node_modules/lodash/isSet.js +14 -0
  236. package/dist/node_modules/lodash/isSet.js.map +1 -0
  237. package/dist/node_modules/lodash/isUndefined.js +13 -0
  238. package/dist/node_modules/lodash/isUndefined.js.map +1 -0
  239. package/dist/node_modules/lodash/keysIn.js +17 -0
  240. package/dist/node_modules/lodash/keysIn.js.map +1 -0
  241. package/dist/node_modules/lodash/merge.js +15 -0
  242. package/dist/node_modules/lodash/merge.js.map +1 -0
  243. package/dist/node_modules/lodash/pick.js +15 -0
  244. package/dist/node_modules/lodash/pick.js.map +1 -0
  245. package/dist/node_modules/lodash/reduce.js +20 -0
  246. package/dist/node_modules/lodash/reduce.js.map +1 -0
  247. package/dist/node_modules/lodash/size.js +22 -0
  248. package/dist/node_modules/lodash/size.js.map +1 -0
  249. package/dist/node_modules/lodash/toPlainObject.js +16 -0
  250. package/dist/node_modules/lodash/toPlainObject.js.map +1 -0
  251. package/dist/node_modules/lodash/transform.js +31 -0
  252. package/dist/node_modules/lodash/transform.js.map +1 -0
  253. package/dist/node_modules/lodash/union.js +17 -0
  254. package/dist/node_modules/lodash/union.js.map +1 -0
  255. package/dist/node_modules/lodash/uniqueId.js +16 -0
  256. package/dist/node_modules/lodash/uniqueId.js.map +1 -0
  257. package/dist/node_modules/lodash/values.js +16 -0
  258. package/dist/node_modules/lodash/values.js.map +1 -0
  259. package/dist/node_modules/lodash/zipObject.js +16 -0
  260. package/dist/node_modules/lodash/zipObject.js.map +1 -0
  261. package/dist/pages/AgentGraphPage.js +251 -118
  262. package/dist/pages/AgentGraphPage.js.map +1 -1
  263. package/dist/pages/SessionsPage.js +957 -918
  264. package/dist/pages/SessionsPage.js.map +1 -1
  265. package/dist/translations/en.js +7 -1
  266. package/dist/translations/en.js.map +1 -1
  267. package/package.json +3 -1
  268. package/dist/components/graph/AgentGraphView.js +0 -237
  269. package/dist/components/graph/AgentGraphView.js.map +0 -1
  270. package/dist/components/graph/AgentNode.js +0 -54
  271. package/dist/components/graph/AgentNode.js.map +0 -1
  272. package/dist/components/graph/TargetNode.js +0 -76
  273. package/dist/components/graph/TargetNode.js.map +0 -1
@@ -0,0 +1,190 @@
1
+ import { __toESM as e } from "../../_virtual/_rolldown/runtime.js";
2
+ import { useTr as t } from "../../shared/hooks/useTr.js";
3
+ import { require_dagre as n } from "../../node_modules/dagre/index.js";
4
+ import { MeshAgentNode as r } from "./MeshAgentNode.js";
5
+ import { ConnectionPermissionsDialog as i } from "./ConnectionPermissionsDialog.js";
6
+ import { isMeshLinkLive as a, isSharedAgent as o } from "./meshTypes.js";
7
+ import { useCallback as s, useEffect as c, useMemo as l, useState as u } from "react";
8
+ import { CheckCircle as d } from "lucide-react";
9
+ import { Fragment as f, jsx as p, jsxs as m } from "react/jsx-runtime";
10
+ import { Background as h, BackgroundVariant as g, Controls as _, MarkerType as v, MiniMap as y, ReactFlow as b, useEdgesState as x, useNodesState as S } from "@xyflow/react";
11
+ import "@xyflow/react/dist/style.css";
12
+ //#region src/components/graph/MeshGraphView.tsx
13
+ var C = /* @__PURE__ */ e(n(), 1), w = 200, T = 72, E = { meshAgentNode: r };
14
+ function D(e, t, n) {
15
+ let r = new C.default.graphlib.Graph();
16
+ r.setGraph({
17
+ rankdir: "LR",
18
+ nodesep: 40,
19
+ ranksep: 90,
20
+ marginx: 16,
21
+ marginy: 16
22
+ }), r.setDefaultEdgeLabel(() => ({})), e.forEach((e) => {
23
+ r.setNode(`agent-${e.id}`, {
24
+ width: w,
25
+ height: T
26
+ });
27
+ });
28
+ let i = t.filter((t) => e.some((e) => e.id === t.sourceAgent.id) && e.some((e) => e.id === t.destinationAgent.id));
29
+ return i.forEach((e) => {
30
+ r.setEdge(`agent-${e.sourceAgent.id}`, `agent-${e.destinationAgent.id}`);
31
+ }), C.default.layout(r), {
32
+ nodes: e.map((e) => {
33
+ let t = r.node(`agent-${e.id}`), i = {
34
+ name: e.name,
35
+ version: e.version,
36
+ isActive: e.isActive,
37
+ isShared: o(e.ownerUserId),
38
+ hostType: e.target?.type ?? null,
39
+ hostLabel: e.target?.host ?? e.hostname,
40
+ onActivate: n ? () => n(e.id) : void 0
41
+ };
42
+ return {
43
+ id: `agent-${e.id}`,
44
+ type: "meshAgentNode",
45
+ position: {
46
+ x: (t?.x ?? 0) - w / 2,
47
+ y: (t?.y ?? 0) - T / 2
48
+ },
49
+ data: i,
50
+ className: n ? "cursor-pointer" : void 0
51
+ };
52
+ }),
53
+ edges: i.map((e) => {
54
+ let t = a(e.status);
55
+ return {
56
+ id: `mesh-${e.id}`,
57
+ source: `agent-${e.sourceAgent.id}`,
58
+ target: `agent-${e.destinationAgent.id}`,
59
+ label: e.label ?? void 0,
60
+ data: e,
61
+ type: "default",
62
+ animated: t,
63
+ markerEnd: { type: v.ArrowClosed },
64
+ style: {
65
+ stroke: t ? "var(--color-status-success-border)" : "var(--color-border-strong)",
66
+ strokeWidth: 2
67
+ },
68
+ labelStyle: {
69
+ fontSize: 10,
70
+ fontWeight: 600
71
+ },
72
+ labelBgStyle: { fill: "transparent" },
73
+ labelBgPadding: [4, 2]
74
+ };
75
+ })
76
+ };
77
+ }
78
+ function O({ agents: e, meshLinks: n, onUpdatePermissions: r, availablePermissions: a, availableScopes: o, onNodeClick: v, fullHeight: C }) {
79
+ let w = t(), { nodes: T, edges: O } = l(() => D(e, n, v), [
80
+ e,
81
+ n,
82
+ v
83
+ ]), [k, A, j] = S(T), [M, N, P] = x(O), [F, I] = u(null), [L, R] = u(!1);
84
+ c(() => {
85
+ let { nodes: t, edges: r } = D(e, n, v);
86
+ A(t), N(r);
87
+ }, [
88
+ e,
89
+ n,
90
+ v,
91
+ A,
92
+ N
93
+ ]);
94
+ let z = s((e, t) => {
95
+ if (!v) return;
96
+ let n = t.id.replace(/^agent-/, "");
97
+ n && v(n);
98
+ }, [v]), B = s((e, t) => {
99
+ let r = n.find((e) => `mesh-${e.id}` === t.id);
100
+ r && I(r);
101
+ }, [n]), V = s((e, t) => {
102
+ F && r && r(F.id, e, t), I(null), R(!0), setTimeout(() => R(!1), 3e3);
103
+ }, [F, r]);
104
+ return /* @__PURE__ */ m(f, { children: [
105
+ /* @__PURE__ */ p("div", {
106
+ className: "w-full rounded-lg border border-border-default overflow-hidden bg-bg-secondary",
107
+ style: { height: C ? "100%" : "500px" },
108
+ children: /* @__PURE__ */ m(b, {
109
+ nodes: k,
110
+ edges: M,
111
+ nodesDraggable: !1,
112
+ onNodesChange: j,
113
+ onEdgesChange: P,
114
+ onNodeClick: z,
115
+ onEdgeClick: B,
116
+ nodeTypes: E,
117
+ fitView: !0,
118
+ fitViewOptions: { padding: .2 },
119
+ minZoom: .2,
120
+ maxZoom: 2,
121
+ panOnDrag: !0,
122
+ proOptions: { hideAttribution: !0 },
123
+ children: [
124
+ /* @__PURE__ */ p(h, {
125
+ variant: g.Dots,
126
+ gap: 20,
127
+ size: 1,
128
+ className: "!fill-text-tertiary/10"
129
+ }),
130
+ /* @__PURE__ */ p(_, {
131
+ showInteractive: !1,
132
+ style: {
133
+ background: "var(--color-bg-primary)",
134
+ border: "1px solid var(--color-border-default)",
135
+ borderRadius: 8,
136
+ boxShadow: "0 1px 4px var(--color-border-default)"
137
+ },
138
+ className: "[&_button]:!bg-[var(--color-bg-primary)] [&_button]:!border-[var(--color-border-default)] [&_button]:!fill-[var(--color-text-secondary)] [&_button:hover]:!bg-[var(--color-bg-sunken)]"
139
+ }),
140
+ /* @__PURE__ */ p(y, {
141
+ zoomable: !0,
142
+ pannable: !0,
143
+ style: {
144
+ height: 80,
145
+ width: 120,
146
+ background: "var(--color-bg-primary)",
147
+ border: "1px solid var(--color-border-default)",
148
+ borderRadius: 8
149
+ },
150
+ maskColor: "var(--color-bg-default)"
151
+ })
152
+ ]
153
+ })
154
+ }),
155
+ F && /* @__PURE__ */ p(i, {
156
+ connection: {
157
+ id: F.id,
158
+ protocol: F.status,
159
+ permissions: F.permissions,
160
+ scopes: F.scopes,
161
+ label: F.label,
162
+ description: F.description,
163
+ sourceAgent: F.sourceAgent,
164
+ target: {
165
+ id: F.destinationAgent.id,
166
+ name: F.destinationAgent.name
167
+ }
168
+ },
169
+ availablePermissions: a,
170
+ availableScopes: o,
171
+ onSave: V,
172
+ onClose: () => I(null)
173
+ }),
174
+ L && /* @__PURE__ */ m("div", {
175
+ "data-testid": "mesh-save-toast",
176
+ className: "fixed bottom-4 right-4 z-[200] flex items-center gap-2 bg-bg-elevated border border-border-default rounded-lg shadow-lg px-4 py-2.5 text-sm",
177
+ children: [/* @__PURE__ */ p(d, {
178
+ size: 16,
179
+ className: "text-status-success-text flex-shrink-0"
180
+ }), /* @__PURE__ */ p("span", {
181
+ className: "text-text-primary",
182
+ children: w("vibecontrols.mesh.permissionsSaved", "Permissions saved")
183
+ })]
184
+ })
185
+ ] });
186
+ }
187
+ //#endregion
188
+ export { O as MeshGraphView };
189
+
190
+ //# sourceMappingURL=MeshGraphView.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MeshGraphView.js","names":[],"sources":["../../../src/components/graph/MeshGraphView.tsx"],"sourcesContent":["/**\n * MeshGraphView — React Flow visualization of the agent MESH topology.\n *\n * Agents are the nodes (MeshAgentNode); AgentMeshLinks are directed\n * agent->agent edges. Auto-layout is computed with dagre (rankdir LR).\n * Click an edge → edit its RBAC permissions/scopes. Click a node → fire the\n * supplied node-activate callback (used for quick-actions / navigation).\n *\n * Background / Controls / MiniMap styling + edge-stroke semantic tokens are\n * kept identical to AgentGraphView for visual consistency.\n */\n\nimport { useCallback, useEffect, useMemo, useState } from 'react';\nimport { CheckCircle } from 'lucide-react';\nimport dagre from 'dagre';\nimport { useTr } from '../../shared/hooks/useTr';\nimport {\n ReactFlow,\n Background,\n Controls,\n MiniMap,\n useNodesState,\n useEdgesState,\n type Node,\n type Edge,\n type NodeTypes,\n MarkerType,\n BackgroundVariant,\n} from '@xyflow/react';\nimport '@xyflow/react/dist/style.css';\nimport { MeshAgentNode, type MeshAgentNodeData } from './MeshAgentNode';\nimport { ConnectionPermissionsDialog } from './ConnectionPermissionsDialog';\nimport { isMeshLinkLive, isSharedAgent, type MeshAgentUi, type MeshLinkUi } from './meshTypes';\n\n// ---------------------------------------------------------------------------\n// Layout (dagre, rankdir LR)\n// ---------------------------------------------------------------------------\n\nconst NODE_WIDTH = 200;\nconst NODE_HEIGHT = 72;\n\nconst nodeTypes: NodeTypes = {\n meshAgentNode: MeshAgentNode,\n};\n\ninterface MeshGraphViewProps {\n agents: MeshAgentUi[];\n meshLinks: MeshLinkUi[];\n /** Current user id — used to flag personal vs shared agents on each node. */\n currentUserId?: string | null;\n onUpdatePermissions?: (meshLinkId: string, permissions: string[], scopes: string[]) => void;\n availablePermissions?: string[];\n availableScopes?: string[];\n onNodeClick?: (agentId: string) => void;\n fullHeight?: boolean;\n}\n\nfunction buildMeshElements(\n agents: MeshAgentUi[],\n meshLinks: MeshLinkUi[],\n onNodeClick?: (agentId: string) => void\n): { nodes: Node[]; edges: Edge[] } {\n const graph = new dagre.graphlib.Graph();\n graph.setGraph({ rankdir: 'LR', nodesep: 40, ranksep: 90, marginx: 16, marginy: 16 });\n graph.setDefaultEdgeLabel(() => ({}));\n\n agents.forEach((agent) => {\n graph.setNode(`agent-${agent.id}`, { width: NODE_WIDTH, height: NODE_HEIGHT });\n });\n\n const validLinks = meshLinks.filter(\n (link) =>\n agents.some((a) => a.id === link.sourceAgent.id) &&\n agents.some((a) => a.id === link.destinationAgent.id)\n );\n\n validLinks.forEach((link) => {\n graph.setEdge(`agent-${link.sourceAgent.id}`, `agent-${link.destinationAgent.id}`);\n });\n\n dagre.layout(graph);\n\n const nodes: Node[] = agents.map((agent) => {\n const layout = graph.node(`agent-${agent.id}`);\n const data: MeshAgentNodeData = {\n name: agent.name,\n version: agent.version,\n isActive: agent.isActive,\n isShared: isSharedAgent(agent.ownerUserId),\n hostType: agent.target?.type ?? null,\n hostLabel: agent.target?.host ?? agent.hostname,\n onActivate: onNodeClick ? () => onNodeClick(agent.id) : undefined,\n };\n return {\n id: `agent-${agent.id}`,\n type: 'meshAgentNode',\n // dagre positions node centers; React Flow expects top-left.\n position: {\n x: (layout?.x ?? 0) - NODE_WIDTH / 2,\n y: (layout?.y ?? 0) - NODE_HEIGHT / 2,\n },\n data: data as unknown as Record<string, unknown>,\n className: onNodeClick ? 'cursor-pointer' : undefined,\n };\n });\n\n const edges: Edge[] = validLinks.map((link) => {\n const live = isMeshLinkLive(link.status);\n return {\n id: `mesh-${link.id}`,\n source: `agent-${link.sourceAgent.id}`,\n target: `agent-${link.destinationAgent.id}`,\n label: link.label ?? undefined,\n data: link as unknown as Record<string, unknown>,\n type: 'default',\n animated: live,\n markerEnd: { type: MarkerType.ArrowClosed },\n style: {\n stroke: live ? 'var(--color-status-success-border)' : 'var(--color-border-strong)',\n strokeWidth: 2,\n },\n labelStyle: { fontSize: 10, fontWeight: 600 },\n labelBgStyle: { fill: 'transparent' },\n labelBgPadding: [4, 2] as [number, number],\n };\n });\n\n return { nodes, edges };\n}\n\n// ---------------------------------------------------------------------------\n// Component\n// ---------------------------------------------------------------------------\n\nexport function MeshGraphView({\n agents,\n meshLinks,\n onUpdatePermissions,\n availablePermissions,\n availableScopes,\n onNodeClick,\n fullHeight,\n}: MeshGraphViewProps) {\n const tr = useTr();\n\n const { nodes: initialNodes, edges: initialEdges } = useMemo(\n () => buildMeshElements(agents, meshLinks, onNodeClick),\n [agents, meshLinks, onNodeClick]\n );\n\n const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes);\n const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);\n const [selectedLink, setSelectedLink] = useState<MeshLinkUi | null>(null);\n const [permSaved, setPermSaved] = useState(false);\n\n // Re-sync nodes/edges when the data changes (e.g. root agent filter / refetch).\n useEffect(() => {\n const { nodes: newNodes, edges: newEdges } = buildMeshElements(agents, meshLinks, onNodeClick);\n setNodes(newNodes);\n setEdges(newEdges);\n }, [agents, meshLinks, onNodeClick, setNodes, setEdges]);\n\n const handleNodeClick = useCallback(\n (_event: React.MouseEvent, node: Node) => {\n if (!onNodeClick) return;\n const agentId = node.id.replace(/^agent-/, '');\n if (agentId) onNodeClick(agentId);\n },\n [onNodeClick]\n );\n\n const handleEdgeClick = useCallback(\n (_event: React.MouseEvent, edge: Edge) => {\n const link = meshLinks.find((l) => `mesh-${l.id}` === edge.id);\n if (link) setSelectedLink(link);\n },\n [meshLinks]\n );\n\n const handleSavePermissions = useCallback(\n (permissions: string[], scopes: string[]) => {\n if (selectedLink && onUpdatePermissions) {\n onUpdatePermissions(selectedLink.id, permissions, scopes);\n }\n setSelectedLink(null);\n setPermSaved(true);\n setTimeout(() => setPermSaved(false), 3000);\n },\n [selectedLink, onUpdatePermissions]\n );\n\n const height = fullHeight ? '100%' : '500px';\n\n return (\n <>\n <div\n className=\"w-full rounded-lg border border-border-default overflow-hidden bg-bg-secondary\"\n style={{ height }}\n >\n <ReactFlow\n nodes={nodes}\n edges={edges}\n nodesDraggable={false}\n onNodesChange={onNodesChange}\n onEdgesChange={onEdgesChange}\n onNodeClick={handleNodeClick}\n onEdgeClick={handleEdgeClick}\n nodeTypes={nodeTypes}\n fitView\n fitViewOptions={{ padding: 0.2 }}\n minZoom={0.2}\n maxZoom={2}\n panOnDrag={true}\n proOptions={{ hideAttribution: true }}\n >\n <Background\n variant={BackgroundVariant.Dots}\n gap={20}\n size={1}\n className=\"!fill-text-tertiary/10\"\n />\n <Controls\n showInteractive={false}\n style={{\n background: 'var(--color-bg-primary)',\n border: '1px solid var(--color-border-default)',\n borderRadius: 8,\n boxShadow: '0 1px 4px var(--color-border-default)',\n }}\n className=\"[&_button]:!bg-[var(--color-bg-primary)] [&_button]:!border-[var(--color-border-default)] [&_button]:!fill-[var(--color-text-secondary)] [&_button:hover]:!bg-[var(--color-bg-sunken)]\"\n />\n <MiniMap\n zoomable\n pannable\n style={{\n height: 80,\n width: 120,\n background: 'var(--color-bg-primary)',\n border: '1px solid var(--color-border-default)',\n borderRadius: 8,\n }}\n maskColor=\"var(--color-bg-default)\"\n />\n </ReactFlow>\n </div>\n\n {selectedLink && (\n <ConnectionPermissionsDialog\n connection={{\n id: selectedLink.id,\n protocol: selectedLink.status,\n permissions: selectedLink.permissions,\n scopes: selectedLink.scopes,\n label: selectedLink.label,\n description: selectedLink.description,\n sourceAgent: selectedLink.sourceAgent,\n target: {\n id: selectedLink.destinationAgent.id,\n name: selectedLink.destinationAgent.name,\n },\n }}\n availablePermissions={availablePermissions}\n availableScopes={availableScopes}\n onSave={handleSavePermissions}\n onClose={() => setSelectedLink(null)}\n />\n )}\n\n {permSaved && (\n <div\n data-testid=\"mesh-save-toast\"\n className=\"fixed bottom-4 right-4 z-[200] flex items-center gap-2 bg-bg-elevated border border-border-default rounded-lg shadow-lg px-4 py-2.5 text-sm\"\n >\n <CheckCircle size={16} className=\"text-status-success-text flex-shrink-0\" />\n <span className=\"text-text-primary\">\n {tr('vibecontrols.mesh.permissionsSaved', 'Permissions saved')}\n </span>\n </div>\n )}\n </>\n );\n}\n"],"mappings":"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"}
@@ -0,0 +1,70 @@
1
+ import { useTr as e } from "../../shared/hooks/useTr.js";
2
+ import { ExternalLink as t, Rocket as n, Send as r, Terminal as i, X as a } from "lucide-react";
3
+ import { jsx as o, jsxs as s } from "react/jsx-runtime";
4
+ //#region src/components/graph/MeshNodeActions.tsx
5
+ function c({ agent: c, onRunCommand: l, onStartTerminal: u, onDeployFromHere: d, onOpenAgent: f, onClose: p }) {
6
+ let m = e(), h = "w-full flex items-center gap-2 px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken text-left transition-colors";
7
+ return /* @__PURE__ */ s("div", {
8
+ className: "rounded-lg border border-border-default bg-bg-surface shadow-lg overflow-hidden w-56",
9
+ children: [/* @__PURE__ */ s("div", {
10
+ className: "flex items-center justify-between px-3 py-2 border-b border-border-default bg-bg-sunken",
11
+ children: [/* @__PURE__ */ o("span", {
12
+ className: "text-xs font-semibold text-text-primary truncate",
13
+ children: c.name
14
+ }), /* @__PURE__ */ o("button", {
15
+ type: "button",
16
+ onClick: p,
17
+ className: "p-0.5 rounded hover:bg-bg-elevated",
18
+ "aria-label": m("common.close", "Close"),
19
+ children: /* @__PURE__ */ o(a, {
20
+ size: 14,
21
+ className: "text-text-secondary"
22
+ })
23
+ })]
24
+ }), /* @__PURE__ */ s("div", {
25
+ className: "py-1",
26
+ children: [
27
+ /* @__PURE__ */ s("button", {
28
+ type: "button",
29
+ className: h,
30
+ onClick: () => l(c.id),
31
+ children: [/* @__PURE__ */ o(r, {
32
+ size: 14,
33
+ className: "text-text-secondary"
34
+ }), m("mesh.actions.runCommand", "Run command")]
35
+ }),
36
+ /* @__PURE__ */ s("button", {
37
+ type: "button",
38
+ className: h,
39
+ onClick: () => u(c.id),
40
+ children: [/* @__PURE__ */ o(i, {
41
+ size: 14,
42
+ className: "text-text-secondary"
43
+ }), m("mesh.actions.startTerminal", "Start terminal")]
44
+ }),
45
+ /* @__PURE__ */ s("button", {
46
+ type: "button",
47
+ className: h,
48
+ onClick: () => d(c.id),
49
+ children: [/* @__PURE__ */ o(n, {
50
+ size: 14,
51
+ className: "text-text-secondary"
52
+ }), m("mesh.actions.deployFromHere", "Deploy from here")]
53
+ }),
54
+ /* @__PURE__ */ s("button", {
55
+ type: "button",
56
+ className: h,
57
+ onClick: () => f(c.id),
58
+ children: [/* @__PURE__ */ o(t, {
59
+ size: 14,
60
+ className: "text-text-secondary"
61
+ }), m("mesh.actions.openAgent", "Open agent")]
62
+ })
63
+ ]
64
+ })]
65
+ });
66
+ }
67
+ //#endregion
68
+ export { c as MeshNodeActions };
69
+
70
+ //# sourceMappingURL=MeshNodeActions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MeshNodeActions.js","names":[],"sources":["../../../src/components/graph/MeshNodeActions.tsx"],"sourcesContent":["/**\n * MeshNodeActions — quick-action menu for a selected agent node in the mesh.\n *\n * Actions:\n * - Run command → opens the MeshRequestPanel targeting this node\n * - Start terminal → best-effort deep-terminal via startMeshAgentSession\n * - Deploy from here → opens the deploy wizard pre-seeded with this node\n * - Open agent → navigate to the agent details page\n *\n * Rendered as a lightweight popover anchored to the page; the parent owns the\n * open/close state and the action callbacks.\n */\n\nimport { Terminal, Send, Rocket, ExternalLink, X } from 'lucide-react';\nimport { useTr } from '../../shared/hooks/useTr';\nimport type { MeshAgentUi } from './meshTypes';\n\ninterface MeshNodeActionsProps {\n agent: MeshAgentUi;\n onRunCommand: (agentId: string) => void;\n onStartTerminal: (agentId: string) => void;\n onDeployFromHere: (agentId: string) => void;\n onOpenAgent: (agentId: string) => void;\n onClose: () => void;\n}\n\nexport function MeshNodeActions({\n agent,\n onRunCommand,\n onStartTerminal,\n onDeployFromHere,\n onOpenAgent,\n onClose,\n}: MeshNodeActionsProps) {\n const tr = useTr();\n\n const ITEM =\n 'w-full flex items-center gap-2 px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken text-left transition-colors';\n\n return (\n <div className=\"rounded-lg border border-border-default bg-bg-surface shadow-lg overflow-hidden w-56\">\n <div className=\"flex items-center justify-between px-3 py-2 border-b border-border-default bg-bg-sunken\">\n <span className=\"text-xs font-semibold text-text-primary truncate\">{agent.name}</span>\n <button\n type=\"button\"\n onClick={onClose}\n className=\"p-0.5 rounded hover:bg-bg-elevated\"\n aria-label={tr('common.close', 'Close')}\n >\n <X size={14} className=\"text-text-secondary\" />\n </button>\n </div>\n <div className=\"py-1\">\n <button type=\"button\" className={ITEM} onClick={() => onRunCommand(agent.id)}>\n <Send size={14} className=\"text-text-secondary\" />\n {tr('mesh.actions.runCommand', 'Run command')}\n </button>\n <button type=\"button\" className={ITEM} onClick={() => onStartTerminal(agent.id)}>\n <Terminal size={14} className=\"text-text-secondary\" />\n {tr('mesh.actions.startTerminal', 'Start terminal')}\n </button>\n <button type=\"button\" className={ITEM} onClick={() => onDeployFromHere(agent.id)}>\n <Rocket size={14} className=\"text-text-secondary\" />\n {tr('mesh.actions.deployFromHere', 'Deploy from here')}\n </button>\n <button type=\"button\" className={ITEM} onClick={() => onOpenAgent(agent.id)}>\n <ExternalLink size={14} className=\"text-text-secondary\" />\n {tr('mesh.actions.openAgent', 'Open agent')}\n </button>\n </div>\n </div>\n );\n}\n"],"mappings":";;;;AA0BA,SAAgB,EAAgB,EAC9B,UACA,iBACA,oBACA,qBACA,gBACA,cACuB;CACvB,IAAM,IAAK,GAAO,EAEZ,IACJ;AAEF,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf,CACE,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,QAAD;IAAM,WAAU;cAAoD,EAAM;IAAY,CAAA,EACtF,kBAAC,UAAD;IACE,MAAK;IACL,SAAS;IACT,WAAU;IACV,cAAY,EAAG,gBAAgB,QAAQ;cAEvC,kBAAC,GAAD;KAAG,MAAM;KAAI,WAAU;KAAwB,CAAA;IACxC,CAAA,CACL;MACN,kBAAC,OAAD;GAAK,WAAU;aAAf;IACE,kBAAC,UAAD;KAAQ,MAAK;KAAS,WAAW;KAAM,eAAe,EAAa,EAAM,GAAG;eAA5E,CACE,kBAAC,GAAD;MAAM,MAAM;MAAI,WAAU;MAAwB,CAAA,EACjD,EAAG,2BAA2B,cAAc,CACtC;;IACT,kBAAC,UAAD;KAAQ,MAAK;KAAS,WAAW;KAAM,eAAe,EAAgB,EAAM,GAAG;eAA/E,CACE,kBAAC,GAAD;MAAU,MAAM;MAAI,WAAU;MAAwB,CAAA,EACrD,EAAG,8BAA8B,iBAAiB,CAC5C;;IACT,kBAAC,UAAD;KAAQ,MAAK;KAAS,WAAW;KAAM,eAAe,EAAiB,EAAM,GAAG;eAAhF,CACE,kBAAC,GAAD;MAAQ,MAAM;MAAI,WAAU;MAAwB,CAAA,EACnD,EAAG,+BAA+B,mBAAmB,CAC/C;;IACT,kBAAC,UAAD;KAAQ,MAAK;KAAS,WAAW;KAAM,eAAe,EAAY,EAAM,GAAG;eAA3E,CACE,kBAAC,GAAD;MAAc,MAAM;MAAI,WAAU;MAAwB,CAAA,EACzD,EAAG,0BAA0B,aAAa,CACpC;;IACL;KACF"}
@@ -0,0 +1,240 @@
1
+ import { useExecuteAgentMeshRequestMutation as e } from "../../generated/wspace-operations.js";
2
+ import { useTr as t } from "../../shared/hooks/useTr.js";
3
+ import { useCallback as n, useMemo as r, useState as i } from "react";
4
+ import { ChevronRight as a, Loader2 as o, Network as s, Play as c } from "lucide-react";
5
+ import { jsx as l, jsxs as u } from "react/jsx-runtime";
6
+ //#region src/components/graph/MeshRequestPanel.tsx
7
+ function d(e) {
8
+ return e && typeof e == "object" && !Array.isArray(e) ? e : null;
9
+ }
10
+ function f(e, t) {
11
+ let n = e?.[t];
12
+ return typeof n == "string" ? n : null;
13
+ }
14
+ function p(e) {
15
+ if (!e) return [];
16
+ let t = e.hops ?? d(e.meta)?.hops;
17
+ return Array.isArray(t) ? t.filter((e) => typeof e == "string") : [];
18
+ }
19
+ var m = "px-3 py-2 text-sm rounded-md bg-bg-sunken border border-border-default text-text-primary focus:outline-none focus:ring-2 focus:ring-action-primary-bg/40";
20
+ function h({ rootAgentId: h, destinations: g, initialDestinationId: _, onClose: v }) {
21
+ let y = t(), [b, x] = i(_ ?? g[0]?.id ?? ""), [S, C] = i("command"), [w, T] = i("status"), [E, D] = i("GET"), [O, k] = i("/api/health"), [A, j] = i(""), [M, N] = i(null), [P, F] = i([]), [I, { loading: L }] = e(), R = n((e) => g.find((t) => t.id === e)?.name ?? e, [g]), z = r(() => !h || !b ? !1 : S === "command" ? w.trim().length > 0 : O.trim().length > 0, [
22
+ h,
23
+ b,
24
+ S,
25
+ w,
26
+ O
27
+ ]), B = n(async () => {
28
+ if (!h || !b) return;
29
+ N(null), F([]);
30
+ let e;
31
+ if (S === "command") e = {
32
+ method: "POST",
33
+ path: "/api/profiles/default/agent/commands/run",
34
+ body: { argv: w.trim().split(/\s+/).filter(Boolean) }
35
+ };
36
+ else {
37
+ let t;
38
+ if (A.trim().length > 0) try {
39
+ if (t = d(JSON.parse(A)) ?? void 0, !t) {
40
+ N({
41
+ body: y("mesh.request.bodyNotObject", "Body must be a JSON object."),
42
+ error: !0
43
+ });
44
+ return;
45
+ }
46
+ } catch {
47
+ N({
48
+ body: y("mesh.request.invalidJson", "Request body is not valid JSON."),
49
+ error: !0
50
+ });
51
+ return;
52
+ }
53
+ e = {
54
+ method: E,
55
+ path: O.trim(),
56
+ body: t
57
+ };
58
+ }
59
+ try {
60
+ let t = await I({ variables: {
61
+ rootAgentId: h,
62
+ destinationAgentId: b,
63
+ request: e
64
+ } }), n = t.data?.executeAgentMeshRequest, r = d(n?.data);
65
+ if (F(p(r)), t.error || n?.error || n?.ok === !1) {
66
+ N({
67
+ body: n?.error ?? t.error?.message ?? f(r, "error") ?? y("mesh.request.failed", "Request failed"),
68
+ error: !0
69
+ });
70
+ return;
71
+ }
72
+ let i = f(r, "stdout"), a = n?.text, o = r ? JSON.stringify(r, null, 2) : a ?? "(no output)";
73
+ N({ body: i || a || o });
74
+ } catch (e) {
75
+ N({
76
+ body: e instanceof Error ? e.message : String(e),
77
+ error: !0
78
+ });
79
+ }
80
+ }, [
81
+ h,
82
+ b,
83
+ S,
84
+ w,
85
+ E,
86
+ O,
87
+ A,
88
+ I,
89
+ y
90
+ ]);
91
+ return /* @__PURE__ */ u("div", {
92
+ className: "rounded-lg border border-border-default bg-bg-surface p-4 space-y-3",
93
+ children: [
94
+ /* @__PURE__ */ u("div", {
95
+ className: "flex items-center justify-between",
96
+ children: [/* @__PURE__ */ u("div", {
97
+ className: "flex items-center gap-2",
98
+ children: [/* @__PURE__ */ l(s, { className: "size-4 text-text-secondary" }), /* @__PURE__ */ l("h3", {
99
+ className: "text-sm font-semibold text-text-primary",
100
+ children: y("mesh.request.title", "Run mesh request")
101
+ })]
102
+ }), v && /* @__PURE__ */ l("button", {
103
+ type: "button",
104
+ onClick: v,
105
+ className: "text-xs text-text-muted hover:text-text-primary",
106
+ children: y("common.close", "Close")
107
+ })]
108
+ }),
109
+ !h && /* @__PURE__ */ l("p", {
110
+ className: "text-xs text-status-warning-text",
111
+ children: y("mesh.request.noRoot", "Select a reachable root agent to dispatch from.")
112
+ }),
113
+ /* @__PURE__ */ u("div", {
114
+ className: "flex flex-wrap items-end gap-2",
115
+ children: [/* @__PURE__ */ u("div", {
116
+ className: "flex flex-col gap-1",
117
+ children: [/* @__PURE__ */ l("label", {
118
+ className: "text-xs text-text-muted",
119
+ htmlFor: "mesh-dest",
120
+ children: y("mesh.request.destination", "Destination agent")
121
+ }), /* @__PURE__ */ u("select", {
122
+ id: "mesh-dest",
123
+ value: b,
124
+ onChange: (e) => x(e.target.value),
125
+ className: `${m} min-w-44`,
126
+ children: [g.length === 0 && /* @__PURE__ */ l("option", {
127
+ value: "",
128
+ children: y("mesh.request.noDest", "No agents")
129
+ }), g.map((e) => /* @__PURE__ */ u("option", {
130
+ value: e.id,
131
+ children: [
132
+ e.name,
133
+ " (",
134
+ e.hostname,
135
+ ")"
136
+ ]
137
+ }, e.id))]
138
+ })]
139
+ }), /* @__PURE__ */ u("div", {
140
+ className: "flex flex-col gap-1",
141
+ children: [/* @__PURE__ */ l("span", {
142
+ className: "text-xs text-text-muted",
143
+ children: y("mesh.request.mode", "Mode")
144
+ }), /* @__PURE__ */ u("div", {
145
+ className: "flex gap-1",
146
+ children: [/* @__PURE__ */ l("button", {
147
+ type: "button",
148
+ onClick: () => C("command"),
149
+ className: `px-3 py-2 text-sm rounded-md border transition-colors ${S === "command" ? "border-action-primary-bg bg-action-primary-bg/10 text-action-primary-bg" : "border-border-default text-text-secondary hover:bg-bg-sunken"}`,
150
+ children: y("mesh.request.command", "Command")
151
+ }), /* @__PURE__ */ l("button", {
152
+ type: "button",
153
+ onClick: () => C("api"),
154
+ className: `px-3 py-2 text-sm rounded-md border transition-colors ${S === "api" ? "border-action-primary-bg bg-action-primary-bg/10 text-action-primary-bg" : "border-border-default text-text-secondary hover:bg-bg-sunken"}`,
155
+ children: y("mesh.request.api", "API")
156
+ })]
157
+ })]
158
+ })]
159
+ }),
160
+ S === "command" ? /* @__PURE__ */ u("div", {
161
+ className: "flex flex-col gap-1",
162
+ children: [/* @__PURE__ */ l("label", {
163
+ className: "text-xs text-text-muted",
164
+ htmlFor: "mesh-argv",
165
+ children: y("mesh.request.argv", "Command (vibe …)")
166
+ }), /* @__PURE__ */ l("input", {
167
+ id: "mesh-argv",
168
+ type: "text",
169
+ value: w,
170
+ onChange: (e) => T(e.target.value),
171
+ placeholder: "status --json",
172
+ className: `${m} font-mono w-full`
173
+ })]
174
+ }) : /* @__PURE__ */ u("div", {
175
+ className: "space-y-2",
176
+ children: [/* @__PURE__ */ u("div", {
177
+ className: "flex gap-2",
178
+ children: [/* @__PURE__ */ l("select", {
179
+ value: E,
180
+ onChange: (e) => D(e.target.value),
181
+ className: `${m} w-28`,
182
+ "aria-label": y("mesh.request.method", "Method"),
183
+ children: [
184
+ "GET",
185
+ "POST",
186
+ "PUT",
187
+ "DELETE",
188
+ "PATCH"
189
+ ].map((e) => /* @__PURE__ */ l("option", {
190
+ value: e,
191
+ children: e
192
+ }, e))
193
+ }), /* @__PURE__ */ l("input", {
194
+ type: "text",
195
+ value: O,
196
+ onChange: (e) => k(e.target.value),
197
+ placeholder: "/api/health",
198
+ className: `${m} font-mono flex-1`,
199
+ "aria-label": y("mesh.request.path", "Path")
200
+ })]
201
+ }), /* @__PURE__ */ l("textarea", {
202
+ value: A,
203
+ onChange: (e) => j(e.target.value),
204
+ placeholder: y("mesh.request.bodyPlaceholder", "JSON body (optional)"),
205
+ rows: 3,
206
+ className: `${m} font-mono w-full resize-y`,
207
+ "aria-label": y("mesh.request.body", "Request body")
208
+ })]
209
+ }),
210
+ /* @__PURE__ */ u("button", {
211
+ type: "button",
212
+ onClick: () => void B(),
213
+ disabled: !z || L,
214
+ className: "inline-flex items-center gap-2 px-3 py-2 text-sm font-medium rounded-md bg-action-primary-bg text-action-primary-text hover:bg-action-primary-bg-hover transition-colors disabled:opacity-50",
215
+ children: [L ? /* @__PURE__ */ l(o, { className: "size-4 animate-spin" }) : /* @__PURE__ */ l(c, { className: "size-4" }), y("mesh.request.run", "Run")]
216
+ }),
217
+ P.length > 0 && /* @__PURE__ */ u("div", {
218
+ className: "flex flex-wrap items-center gap-1 text-xs text-text-tertiary",
219
+ children: [/* @__PURE__ */ l("span", {
220
+ className: "font-medium text-text-secondary",
221
+ children: y("mesh.request.hops", "Hops:")
222
+ }), P.map((e, t) => /* @__PURE__ */ u("span", {
223
+ className: "inline-flex items-center gap-1",
224
+ children: [/* @__PURE__ */ l("span", {
225
+ className: "rounded bg-bg-sunken px-1.5 py-0.5 text-text-primary",
226
+ children: R(e)
227
+ }), t < P.length - 1 && /* @__PURE__ */ l(a, { className: "size-3" })]
228
+ }, `${e}-${t}`))]
229
+ }),
230
+ M && /* @__PURE__ */ l("pre", {
231
+ className: `text-xs whitespace-pre-wrap break-words max-h-80 overflow-auto rounded-md p-3 ${M.error ? "bg-status-error-bg-subtle text-status-error-text" : "bg-bg-sunken text-text-primary"}`,
232
+ children: M.body
233
+ })
234
+ ]
235
+ });
236
+ }
237
+ //#endregion
238
+ export { h as MeshRequestPanel };
239
+
240
+ //# sourceMappingURL=MeshRequestPanel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MeshRequestPanel.js","names":[],"sources":["../../../src/components/graph/MeshRequestPanel.tsx"],"sourcesContent":["/**\n * MeshRequestPanel — run a request against a destination agent THROUGH the mesh.\n *\n * The backend computes the hop path from the chosen root (source) agent to the\n * destination, so the panel only supplies `rootAgentId` + `destinationAgentId`\n * + the request. Two request modes:\n * - COMMAND: type a `vibe` argv; we POST to\n * `/api/profiles/default/agent/commands/run` with body `{ argv }`.\n * - API: raw method + path + optional JSON body.\n *\n * The AgentProxyResponse is rendered like AgentMaintenanceTab's output pane,\n * and a hops breadcrumb is shown when the response surfaces hop info.\n */\n\nimport { useCallback, useMemo, useState } from 'react';\nimport { Loader2, Play, ChevronRight, Network } from 'lucide-react';\nimport { useTr } from '../../shared/hooks/useTr';\nimport { useExecuteAgentMeshRequestMutation } from '@/generated/wspace-operations';\nimport type { MeshAgentUi } from './meshTypes';\n\ntype RequestMode = 'command' | 'api';\ntype HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';\n\nfunction asRecord(v: unknown): Record<string, unknown> | null {\n return v && typeof v === 'object' && !Array.isArray(v) ? (v as Record<string, unknown>) : null;\n}\nfunction jstr(obj: Record<string, unknown> | null, key: string): string | null {\n const v = obj?.[key];\n return typeof v === 'string' ? v : null;\n}\n\nfunction extractHops(data: Record<string, unknown> | null): string[] {\n if (!data) return [];\n const raw = data.hops ?? asRecord(data.meta)?.hops;\n if (Array.isArray(raw)) return raw.filter((h): h is string => typeof h === 'string');\n return [];\n}\n\nconst INPUT_CLASS =\n 'px-3 py-2 text-sm rounded-md bg-bg-sunken border border-border-default text-text-primary focus:outline-none focus:ring-2 focus:ring-action-primary-bg/40';\n\ninterface MeshRequestPanelProps {\n /** The root/source agent the request is dispatched from. */\n rootAgentId: string | null;\n /** Candidate destination agents (typically the workspace mesh agents). */\n destinations: MeshAgentUi[];\n /** Pre-selected destination (e.g. clicked node). */\n initialDestinationId?: string | null;\n onClose?: () => void;\n}\n\nexport function MeshRequestPanel({\n rootAgentId,\n destinations,\n initialDestinationId,\n onClose,\n}: MeshRequestPanelProps) {\n const tr = useTr();\n\n const [destinationId, setDestinationId] = useState<string>(\n initialDestinationId ?? destinations[0]?.id ?? ''\n );\n const [mode, setMode] = useState<RequestMode>('command');\n const [argv, setArgv] = useState('status');\n const [method, setMethod] = useState<HttpMethod>('GET');\n const [path, setPath] = useState('/api/health');\n const [bodyText, setBodyText] = useState('');\n const [output, setOutput] = useState<{ body: string; error?: boolean } | null>(null);\n const [hops, setHops] = useState<string[]>([]);\n\n const [execute, { loading }] = useExecuteAgentMeshRequestMutation();\n\n const destName = useCallback(\n (id: string) => destinations.find((d) => d.id === id)?.name ?? id,\n [destinations]\n );\n\n const canRun = useMemo(() => {\n if (!rootAgentId || !destinationId) return false;\n if (mode === 'command') return argv.trim().length > 0;\n return path.trim().length > 0;\n }, [rootAgentId, destinationId, mode, argv, path]);\n\n const handleRun = useCallback(async () => {\n if (!rootAgentId || !destinationId) return;\n setOutput(null);\n setHops([]);\n\n let requestInput: {\n method: string;\n path: string;\n body?: Record<string, unknown>;\n };\n\n if (mode === 'command') {\n const parts = argv.trim().split(/\\s+/).filter(Boolean);\n requestInput = {\n method: 'POST',\n path: '/api/profiles/default/agent/commands/run',\n body: { argv: parts },\n };\n } else {\n let parsedBody: Record<string, unknown> | undefined;\n if (bodyText.trim().length > 0) {\n try {\n const parsed: unknown = JSON.parse(bodyText);\n parsedBody = asRecord(parsed) ?? undefined;\n if (!parsedBody) {\n setOutput({\n body: tr('mesh.request.bodyNotObject', 'Body must be a JSON object.'),\n error: true,\n });\n return;\n }\n } catch {\n setOutput({\n body: tr('mesh.request.invalidJson', 'Request body is not valid JSON.'),\n error: true,\n });\n return;\n }\n }\n requestInput = { method, path: path.trim(), body: parsedBody };\n }\n\n try {\n const res = await execute({\n variables: {\n rootAgentId,\n destinationAgentId: destinationId,\n request: requestInput,\n },\n });\n const proxy = res.data?.executeAgentMeshRequest;\n const data = asRecord(proxy?.data);\n setHops(extractHops(data));\n\n if (res.error || proxy?.error || proxy?.ok === false) {\n setOutput({\n body:\n proxy?.error ??\n res.error?.message ??\n jstr(data, 'error') ??\n tr('mesh.request.failed', 'Request failed'),\n error: true,\n });\n return;\n }\n\n const stdout = jstr(data, 'stdout');\n const text = proxy?.text;\n const pretty = data ? JSON.stringify(data, null, 2) : (text ?? '(no output)');\n setOutput({ body: stdout || text || pretty });\n } catch (err) {\n setOutput({ body: err instanceof Error ? err.message : String(err), error: true });\n }\n }, [rootAgentId, destinationId, mode, argv, method, path, bodyText, execute, tr]);\n\n return (\n <div className=\"rounded-lg border border-border-default bg-bg-surface p-4 space-y-3\">\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-2\">\n <Network className=\"size-4 text-text-secondary\" />\n <h3 className=\"text-sm font-semibold text-text-primary\">\n {tr('mesh.request.title', 'Run mesh request')}\n </h3>\n </div>\n {onClose && (\n <button\n type=\"button\"\n onClick={onClose}\n className=\"text-xs text-text-muted hover:text-text-primary\"\n >\n {tr('common.close', 'Close')}\n </button>\n )}\n </div>\n\n {!rootAgentId && (\n <p className=\"text-xs text-status-warning-text\">\n {tr('mesh.request.noRoot', 'Select a reachable root agent to dispatch from.')}\n </p>\n )}\n\n <div className=\"flex flex-wrap items-end gap-2\">\n <div className=\"flex flex-col gap-1\">\n <label className=\"text-xs text-text-muted\" htmlFor=\"mesh-dest\">\n {tr('mesh.request.destination', 'Destination agent')}\n </label>\n <select\n id=\"mesh-dest\"\n value={destinationId}\n onChange={(e) => setDestinationId(e.target.value)}\n className={`${INPUT_CLASS} min-w-44`}\n >\n {destinations.length === 0 && (\n <option value=\"\">{tr('mesh.request.noDest', 'No agents')}</option>\n )}\n {destinations.map((d) => (\n <option key={d.id} value={d.id}>\n {d.name} ({d.hostname})\n </option>\n ))}\n </select>\n </div>\n\n <div className=\"flex flex-col gap-1\">\n <span className=\"text-xs text-text-muted\">{tr('mesh.request.mode', 'Mode')}</span>\n <div className=\"flex gap-1\">\n <button\n type=\"button\"\n onClick={() => setMode('command')}\n className={`px-3 py-2 text-sm rounded-md border transition-colors ${\n mode === 'command'\n ? 'border-action-primary-bg bg-action-primary-bg/10 text-action-primary-bg'\n : 'border-border-default text-text-secondary hover:bg-bg-sunken'\n }`}\n >\n {tr('mesh.request.command', 'Command')}\n </button>\n <button\n type=\"button\"\n onClick={() => setMode('api')}\n className={`px-3 py-2 text-sm rounded-md border transition-colors ${\n mode === 'api'\n ? 'border-action-primary-bg bg-action-primary-bg/10 text-action-primary-bg'\n : 'border-border-default text-text-secondary hover:bg-bg-sunken'\n }`}\n >\n {tr('mesh.request.api', 'API')}\n </button>\n </div>\n </div>\n </div>\n\n {mode === 'command' ? (\n <div className=\"flex flex-col gap-1\">\n <label className=\"text-xs text-text-muted\" htmlFor=\"mesh-argv\">\n {tr('mesh.request.argv', 'Command (vibe …)')}\n </label>\n <input\n id=\"mesh-argv\"\n type=\"text\"\n value={argv}\n onChange={(e) => setArgv(e.target.value)}\n placeholder=\"status --json\"\n className={`${INPUT_CLASS} font-mono w-full`}\n />\n </div>\n ) : (\n <div className=\"space-y-2\">\n <div className=\"flex gap-2\">\n <select\n value={method}\n onChange={(e) => setMethod(e.target.value as HttpMethod)}\n className={`${INPUT_CLASS} w-28`}\n aria-label={tr('mesh.request.method', 'Method')}\n >\n {(['GET', 'POST', 'PUT', 'DELETE', 'PATCH'] as HttpMethod[]).map((m) => (\n <option key={m} value={m}>\n {m}\n </option>\n ))}\n </select>\n <input\n type=\"text\"\n value={path}\n onChange={(e) => setPath(e.target.value)}\n placeholder=\"/api/health\"\n className={`${INPUT_CLASS} font-mono flex-1`}\n aria-label={tr('mesh.request.path', 'Path')}\n />\n </div>\n <textarea\n value={bodyText}\n onChange={(e) => setBodyText(e.target.value)}\n placeholder={tr('mesh.request.bodyPlaceholder', 'JSON body (optional)')}\n rows={3}\n className={`${INPUT_CLASS} font-mono w-full resize-y`}\n aria-label={tr('mesh.request.body', 'Request body')}\n />\n </div>\n )}\n\n <button\n type=\"button\"\n onClick={() => void handleRun()}\n disabled={!canRun || loading}\n className=\"inline-flex items-center gap-2 px-3 py-2 text-sm font-medium rounded-md bg-action-primary-bg text-action-primary-text hover:bg-action-primary-bg-hover transition-colors disabled:opacity-50\"\n >\n {loading ? <Loader2 className=\"size-4 animate-spin\" /> : <Play className=\"size-4\" />}\n {tr('mesh.request.run', 'Run')}\n </button>\n\n {hops.length > 0 && (\n <div className=\"flex flex-wrap items-center gap-1 text-xs text-text-tertiary\">\n <span className=\"font-medium text-text-secondary\">\n {tr('mesh.request.hops', 'Hops:')}\n </span>\n {hops.map((hop, idx) => (\n <span key={`${hop}-${idx}`} className=\"inline-flex items-center gap-1\">\n <span className=\"rounded bg-bg-sunken px-1.5 py-0.5 text-text-primary\">\n {destName(hop)}\n </span>\n {idx < hops.length - 1 && <ChevronRight className=\"size-3\" />}\n </span>\n ))}\n </div>\n )}\n\n {output && (\n <pre\n className={`text-xs whitespace-pre-wrap break-words max-h-80 overflow-auto rounded-md p-3 ${\n output.error\n ? 'bg-status-error-bg-subtle text-status-error-text'\n : 'bg-bg-sunken text-text-primary'\n }`}\n >\n {output.body}\n </pre>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ //#region src/components/graph/meshTypes.ts
2
+ function e(e) {
3
+ return e === "active" || e === "connected";
4
+ }
5
+ function t(e) {
6
+ return e == null;
7
+ }
8
+ //#endregion
9
+ export { e as isMeshLinkLive, t as isSharedAgent };
10
+
11
+ //# sourceMappingURL=meshTypes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"meshTypes.js","names":[],"sources":["../../../src/components/graph/meshTypes.ts"],"sourcesContent":["/**\n * Shared UI types + small helpers for the agent-mesh graph.\n *\n * These narrow the generated fragment shapes into the plain props the mesh\n * graph components consume, so the components don't depend on the exact\n * generated type names.\n */\n\nexport interface MeshAgentUi {\n id: string;\n name: string;\n hostname: string;\n platform: string;\n version: string;\n isActive: boolean;\n ownerUserId?: string | null;\n targetId: string;\n tunnelStatus?: string | null;\n target?: {\n id: string;\n name: string;\n type: string;\n host?: string | null;\n } | null;\n}\n\nexport interface MeshLinkUi {\n id: string;\n workspaceId: string;\n status: string;\n permissions: string[];\n scopes: string[];\n label?: string | null;\n description?: string | null;\n createdAt: string;\n updatedAt: string;\n sourceAgent: { id: string; name: string };\n destinationAgent: {\n id: string;\n name: string;\n hostname: string;\n target?: { id: string; name: string; type: string; host?: string | null } | null;\n };\n}\n\n/** A mesh link is \"live\" (animated edge) when active/connected. */\nexport function isMeshLinkLive(status: string): boolean {\n return status === 'active' || status === 'connected';\n}\n\n/** NULL ownerUserId => shared workspace agent; non-null => personal agent. */\nexport function isSharedAgent(ownerUserId?: string | null): boolean {\n return ownerUserId == null;\n}\n"],"mappings":";AA8CA,SAAgB,EAAe,GAAyB;AACtD,QAAO,MAAW,YAAY,MAAW;;AAI3C,SAAgB,EAAc,GAAsC;AAClE,QAAO,KAAe"}
@@ -0,0 +1,31 @@
1
+ import { Laptop as e, Monitor as t, ScreenShare as n, Server as r } from "lucide-react";
2
+ //#region src/components/graph/nodeIcons.ts
3
+ var i = {
4
+ DIRECT: {
5
+ icon: e,
6
+ badge: "bg-accent-blue-subtle text-accent-blue",
7
+ border: "border-accent-blue/20 bg-accent-blue-subtle/50"
8
+ },
9
+ SSH: {
10
+ icon: r,
11
+ badge: "bg-status-success-bg-subtle text-status-success-text",
12
+ border: "border-status-success-border/20 bg-status-success-bg-subtle/50"
13
+ },
14
+ RDP: {
15
+ icon: t,
16
+ badge: "bg-status-warning-bg-subtle text-status-warning-text",
17
+ border: "border-status-warning-border/20 bg-status-warning-bg-subtle/50"
18
+ },
19
+ VNC: {
20
+ icon: n,
21
+ badge: "bg-accent-purple-subtle text-accent-purple",
22
+ border: "border-accent-purple/20 bg-accent-purple-subtle/50"
23
+ }
24
+ };
25
+ function a(e) {
26
+ return e && i[e] ? i[e] : i.DIRECT;
27
+ }
28
+ //#endregion
29
+ export { a as getNodeTypeConfig };
30
+
31
+ //# sourceMappingURL=nodeIcons.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nodeIcons.js","names":[],"sources":["../../../src/components/graph/nodeIcons.ts"],"sourcesContent":["/**\n * nodeIcons — shared icon + badge token map for target/host types.\n *\n * Lifted out of TargetNode so both the target-based graph and the agent-mesh\n * graph (MeshAgentNode host badge) render the same host-type glyphs and\n * semantic-token styling.\n */\n\nimport { Server, Monitor, ScreenShare, Laptop, type LucideIcon } from 'lucide-react';\n\nexport interface NodeTypeConfig {\n icon: LucideIcon;\n /** Badge background + text tokens. */\n badge: string;\n /** Group-container border + subtle background tokens. */\n border: string;\n}\n\nexport const NODE_TYPE_CONFIG: Record<string, NodeTypeConfig> = {\n DIRECT: {\n icon: Laptop,\n badge: 'bg-accent-blue-subtle text-accent-blue',\n border: 'border-accent-blue/20 bg-accent-blue-subtle/50',\n },\n SSH: {\n icon: Server,\n badge: 'bg-status-success-bg-subtle text-status-success-text',\n border: 'border-status-success-border/20 bg-status-success-bg-subtle/50',\n },\n RDP: {\n icon: Monitor,\n badge: 'bg-status-warning-bg-subtle text-status-warning-text',\n border: 'border-status-warning-border/20 bg-status-warning-bg-subtle/50',\n },\n VNC: {\n icon: ScreenShare,\n badge: 'bg-accent-purple-subtle text-accent-purple',\n border: 'border-accent-purple/20 bg-accent-purple-subtle/50',\n },\n};\n\nexport function getNodeTypeConfig(type?: string | null): NodeTypeConfig {\n if (type && NODE_TYPE_CONFIG[type]) return NODE_TYPE_CONFIG[type];\n return NODE_TYPE_CONFIG.DIRECT;\n}\n"],"mappings":";;AAkBA,IAAa,IAAmD;CAC9D,QAAQ;EACN,MAAM;EACN,OAAO;EACP,QAAQ;EACT;CACD,KAAK;EACH,MAAM;EACN,OAAO;EACP,QAAQ;EACT;CACD,KAAK;EACH,MAAM;EACN,OAAO;EACP,QAAQ;EACT;CACD,KAAK;EACH,MAAM;EACN,OAAO;EACP,QAAQ;EACT;CACF;AAED,SAAgB,EAAkB,GAAsC;AAEtE,QADI,KAAQ,EAAiB,KAAc,EAAiB,KACrD,EAAiB"}