agent-relay 3.2.22 → 4.0.1

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 (232) hide show
  1. package/README.md +5 -5
  2. package/bin/agent-relay-broker-darwin-arm64 +0 -0
  3. package/bin/agent-relay-broker-darwin-x64 +0 -0
  4. package/bin/agent-relay-broker-linux-arm64 +0 -0
  5. package/bin/agent-relay-broker-linux-x64 +0 -0
  6. package/dist/index.cjs +6564 -2100
  7. package/dist/src/cli/bootstrap.d.ts.map +1 -1
  8. package/dist/src/cli/bootstrap.js +2 -0
  9. package/dist/src/cli/bootstrap.js.map +1 -1
  10. package/dist/src/cli/commands/agent-management.d.ts.map +1 -1
  11. package/dist/src/cli/commands/agent-management.js +14 -4
  12. package/dist/src/cli/commands/agent-management.js.map +1 -1
  13. package/dist/src/cli/commands/core.d.ts +2 -6
  14. package/dist/src/cli/commands/core.d.ts.map +1 -1
  15. package/dist/src/cli/commands/core.js +31 -12
  16. package/dist/src/cli/commands/core.js.map +1 -1
  17. package/dist/src/cli/commands/messaging.d.ts.map +1 -1
  18. package/dist/src/cli/commands/messaging.js +10 -3
  19. package/dist/src/cli/commands/messaging.js.map +1 -1
  20. package/dist/src/cli/commands/monitoring.d.ts +2 -2
  21. package/dist/src/cli/commands/monitoring.d.ts.map +1 -1
  22. package/dist/src/cli/commands/monitoring.js +15 -6
  23. package/dist/src/cli/commands/monitoring.js.map +1 -1
  24. package/dist/src/cli/commands/on/dotfiles.d.ts +35 -0
  25. package/dist/src/cli/commands/on/dotfiles.d.ts.map +1 -0
  26. package/dist/src/cli/commands/on/dotfiles.js +157 -0
  27. package/dist/src/cli/commands/on/dotfiles.js.map +1 -0
  28. package/dist/src/cli/commands/on/prereqs.d.ts +15 -0
  29. package/dist/src/cli/commands/on/prereqs.d.ts.map +1 -0
  30. package/dist/src/cli/commands/on/prereqs.js +103 -0
  31. package/dist/src/cli/commands/on/prereqs.js.map +1 -0
  32. package/dist/src/cli/commands/on/provision.d.ts +22 -0
  33. package/dist/src/cli/commands/on/provision.d.ts.map +1 -0
  34. package/dist/src/cli/commands/on/provision.js +157 -0
  35. package/dist/src/cli/commands/on/provision.js.map +1 -0
  36. package/dist/src/cli/commands/on/relayfile-binary.d.ts +2 -0
  37. package/dist/src/cli/commands/on/relayfile-binary.d.ts.map +1 -0
  38. package/dist/src/cli/commands/on/relayfile-binary.js +208 -0
  39. package/dist/src/cli/commands/on/relayfile-binary.js.map +1 -0
  40. package/dist/src/cli/commands/on/scan.d.ts +8 -0
  41. package/dist/src/cli/commands/on/scan.d.ts.map +1 -0
  42. package/dist/src/cli/commands/on/scan.js +59 -0
  43. package/dist/src/cli/commands/on/scan.js.map +1 -0
  44. package/dist/src/cli/commands/on/services.d.ts +17 -0
  45. package/dist/src/cli/commands/on/services.d.ts.map +1 -0
  46. package/dist/src/cli/commands/on/services.js +328 -0
  47. package/dist/src/cli/commands/on/services.js.map +1 -0
  48. package/dist/src/cli/commands/on/start.d.ts +61 -0
  49. package/dist/src/cli/commands/on/start.d.ts.map +1 -0
  50. package/dist/src/cli/commands/on/start.js +1107 -0
  51. package/dist/src/cli/commands/on/start.js.map +1 -0
  52. package/dist/src/cli/commands/on/stop.d.ts +4 -0
  53. package/dist/src/cli/commands/on/stop.d.ts.map +1 -0
  54. package/dist/src/cli/commands/on/stop.js +11 -0
  55. package/dist/src/cli/commands/on/stop.js.map +1 -0
  56. package/dist/src/cli/commands/on/token.d.ts +8 -0
  57. package/dist/src/cli/commands/on/token.d.ts.map +1 -0
  58. package/dist/src/cli/commands/on/token.js +26 -0
  59. package/dist/src/cli/commands/on/token.js.map +1 -0
  60. package/dist/src/cli/commands/on/workspace.d.ts +4 -0
  61. package/dist/src/cli/commands/on/workspace.d.ts.map +1 -0
  62. package/dist/src/cli/commands/on/workspace.js +245 -0
  63. package/dist/src/cli/commands/on/workspace.js.map +1 -0
  64. package/dist/src/cli/commands/on.d.ts +10 -0
  65. package/dist/src/cli/commands/on.d.ts.map +1 -0
  66. package/dist/src/cli/commands/on.js +52 -0
  67. package/dist/src/cli/commands/on.js.map +1 -0
  68. package/dist/src/cli/commands/setup.d.ts.map +1 -1
  69. package/dist/src/cli/commands/setup.js +10 -21
  70. package/dist/src/cli/commands/setup.js.map +1 -1
  71. package/dist/src/cli/lib/bridge.js +1 -1
  72. package/dist/src/cli/lib/bridge.js.map +1 -1
  73. package/dist/src/cli/lib/broker-lifecycle.d.ts +14 -4
  74. package/dist/src/cli/lib/broker-lifecycle.d.ts.map +1 -1
  75. package/dist/src/cli/lib/broker-lifecycle.js +82 -120
  76. package/dist/src/cli/lib/broker-lifecycle.js.map +1 -1
  77. package/dist/src/cli/lib/client-factory.d.ts +4 -4
  78. package/dist/src/cli/lib/client-factory.d.ts.map +1 -1
  79. package/dist/src/cli/lib/client-factory.js +14 -11
  80. package/dist/src/cli/lib/client-factory.js.map +1 -1
  81. package/dist/src/cli/lib/core-maintenance.d.ts.map +1 -1
  82. package/dist/src/cli/lib/core-maintenance.js +11 -22
  83. package/dist/src/cli/lib/core-maintenance.js.map +1 -1
  84. package/dist/src/cost/pricing.d.ts +18 -0
  85. package/dist/src/cost/pricing.d.ts.map +1 -0
  86. package/dist/src/cost/pricing.js +111 -0
  87. package/dist/src/cost/pricing.js.map +1 -0
  88. package/dist/src/cost/tracker.d.ts +13 -0
  89. package/dist/src/cost/tracker.d.ts.map +1 -0
  90. package/dist/src/cost/tracker.js +152 -0
  91. package/dist/src/cost/tracker.js.map +1 -0
  92. package/dist/src/cost/types.d.ts +23 -0
  93. package/dist/src/cost/types.d.ts.map +1 -0
  94. package/dist/src/cost/types.js +2 -0
  95. package/dist/src/cost/types.js.map +1 -0
  96. package/package.json +15 -12
  97. package/packages/acp-bridge/package.json +2 -2
  98. package/packages/brand/package.json +1 -1
  99. package/packages/cloud/package.json +3 -3
  100. package/packages/config/package.json +1 -1
  101. package/packages/hooks/package.json +4 -4
  102. package/packages/memory/package.json +2 -2
  103. package/packages/openclaw/package.json +2 -2
  104. package/packages/policy/package.json +2 -2
  105. package/packages/sdk/README.md +10 -3
  106. package/packages/sdk/dist/broker-path.d.ts +3 -2
  107. package/packages/sdk/dist/broker-path.d.ts.map +1 -1
  108. package/packages/sdk/dist/broker-path.js +119 -32
  109. package/packages/sdk/dist/broker-path.js.map +1 -1
  110. package/packages/sdk/dist/client.d.ts +119 -197
  111. package/packages/sdk/dist/client.d.ts.map +1 -1
  112. package/packages/sdk/dist/client.js +354 -823
  113. package/packages/sdk/dist/client.js.map +1 -1
  114. package/packages/sdk/dist/examples/example.js +2 -5
  115. package/packages/sdk/dist/examples/example.js.map +1 -1
  116. package/packages/sdk/dist/index.d.ts +3 -1
  117. package/packages/sdk/dist/index.d.ts.map +1 -1
  118. package/packages/sdk/dist/index.js +3 -1
  119. package/packages/sdk/dist/index.js.map +1 -1
  120. package/packages/sdk/dist/relay-adapter.d.ts +9 -26
  121. package/packages/sdk/dist/relay-adapter.d.ts.map +1 -1
  122. package/packages/sdk/dist/relay-adapter.js +75 -47
  123. package/packages/sdk/dist/relay-adapter.js.map +1 -1
  124. package/packages/sdk/dist/relay.d.ts +26 -6
  125. package/packages/sdk/dist/relay.d.ts.map +1 -1
  126. package/packages/sdk/dist/relay.js +213 -43
  127. package/packages/sdk/dist/relay.js.map +1 -1
  128. package/packages/sdk/dist/transport.d.ts +58 -0
  129. package/packages/sdk/dist/transport.d.ts.map +1 -0
  130. package/packages/sdk/dist/transport.js +184 -0
  131. package/packages/sdk/dist/transport.js.map +1 -0
  132. package/packages/sdk/dist/types.d.ts +69 -0
  133. package/packages/sdk/dist/types.d.ts.map +1 -0
  134. package/packages/sdk/dist/types.js +5 -0
  135. package/packages/sdk/dist/types.js.map +1 -0
  136. package/packages/sdk/dist/workflows/__tests__/channel-messenger.test.d.ts +2 -0
  137. package/packages/sdk/dist/workflows/__tests__/channel-messenger.test.d.ts.map +1 -0
  138. package/packages/sdk/dist/workflows/__tests__/channel-messenger.test.js +117 -0
  139. package/packages/sdk/dist/workflows/__tests__/channel-messenger.test.js.map +1 -0
  140. package/packages/sdk/dist/workflows/__tests__/run-summary-table.test.js +4 -3
  141. package/packages/sdk/dist/workflows/__tests__/run-summary-table.test.js.map +1 -1
  142. package/packages/sdk/dist/workflows/__tests__/step-executor.test.d.ts +2 -0
  143. package/packages/sdk/dist/workflows/__tests__/step-executor.test.d.ts.map +1 -0
  144. package/packages/sdk/dist/workflows/__tests__/step-executor.test.js +378 -0
  145. package/packages/sdk/dist/workflows/__tests__/step-executor.test.js.map +1 -0
  146. package/packages/sdk/dist/workflows/__tests__/template-resolver.test.d.ts +2 -0
  147. package/packages/sdk/dist/workflows/__tests__/template-resolver.test.d.ts.map +1 -0
  148. package/packages/sdk/dist/workflows/__tests__/template-resolver.test.js +145 -0
  149. package/packages/sdk/dist/workflows/__tests__/template-resolver.test.js.map +1 -0
  150. package/packages/sdk/dist/workflows/__tests__/verification.test.d.ts +2 -0
  151. package/packages/sdk/dist/workflows/__tests__/verification.test.d.ts.map +1 -0
  152. package/packages/sdk/dist/workflows/__tests__/verification.test.js +170 -0
  153. package/packages/sdk/dist/workflows/__tests__/verification.test.js.map +1 -0
  154. package/packages/sdk/dist/workflows/builder.d.ts +3 -2
  155. package/packages/sdk/dist/workflows/builder.d.ts.map +1 -1
  156. package/packages/sdk/dist/workflows/builder.js +1 -3
  157. package/packages/sdk/dist/workflows/builder.js.map +1 -1
  158. package/packages/sdk/dist/workflows/channel-messenger.d.ts +28 -0
  159. package/packages/sdk/dist/workflows/channel-messenger.d.ts.map +1 -0
  160. package/packages/sdk/dist/workflows/channel-messenger.js +255 -0
  161. package/packages/sdk/dist/workflows/channel-messenger.js.map +1 -0
  162. package/packages/sdk/dist/workflows/index.d.ts +7 -0
  163. package/packages/sdk/dist/workflows/index.d.ts.map +1 -1
  164. package/packages/sdk/dist/workflows/index.js +7 -0
  165. package/packages/sdk/dist/workflows/index.js.map +1 -1
  166. package/packages/sdk/dist/workflows/process-spawner.d.ts +35 -0
  167. package/packages/sdk/dist/workflows/process-spawner.d.ts.map +1 -0
  168. package/packages/sdk/dist/workflows/process-spawner.js +141 -0
  169. package/packages/sdk/dist/workflows/process-spawner.js.map +1 -0
  170. package/packages/sdk/dist/workflows/run.d.ts +2 -1
  171. package/packages/sdk/dist/workflows/run.d.ts.map +1 -1
  172. package/packages/sdk/dist/workflows/run.js.map +1 -1
  173. package/packages/sdk/dist/workflows/runner.d.ts +6 -6
  174. package/packages/sdk/dist/workflows/runner.d.ts.map +1 -1
  175. package/packages/sdk/dist/workflows/runner.js +443 -719
  176. package/packages/sdk/dist/workflows/runner.js.map +1 -1
  177. package/packages/sdk/dist/workflows/step-executor.d.ts +95 -0
  178. package/packages/sdk/dist/workflows/step-executor.d.ts.map +1 -0
  179. package/packages/sdk/dist/workflows/step-executor.js +393 -0
  180. package/packages/sdk/dist/workflows/step-executor.js.map +1 -0
  181. package/packages/sdk/dist/workflows/template-resolver.d.ts +33 -0
  182. package/packages/sdk/dist/workflows/template-resolver.d.ts.map +1 -0
  183. package/packages/sdk/dist/workflows/template-resolver.js +144 -0
  184. package/packages/sdk/dist/workflows/template-resolver.js.map +1 -0
  185. package/packages/sdk/dist/workflows/validator.d.ts.map +1 -1
  186. package/packages/sdk/dist/workflows/validator.js +17 -2
  187. package/packages/sdk/dist/workflows/validator.js.map +1 -1
  188. package/packages/sdk/dist/workflows/verification.d.ts +33 -0
  189. package/packages/sdk/dist/workflows/verification.d.ts.map +1 -0
  190. package/packages/sdk/dist/workflows/verification.js +122 -0
  191. package/packages/sdk/dist/workflows/verification.js.map +1 -0
  192. package/packages/sdk/package.json +2 -2
  193. package/packages/sdk/src/__tests__/unit.test.ts +100 -1
  194. package/packages/sdk/src/broker-path.ts +136 -30
  195. package/packages/sdk/src/client.ts +453 -1069
  196. package/packages/sdk/src/examples/example.ts +2 -5
  197. package/packages/sdk/src/index.ts +9 -1
  198. package/packages/sdk/src/relay-adapter.ts +75 -55
  199. package/packages/sdk/src/relay.ts +262 -55
  200. package/packages/sdk/src/transport.ts +216 -0
  201. package/packages/sdk/src/types.ts +75 -0
  202. package/packages/sdk/src/workflows/__tests__/channel-messenger.test.ts +137 -0
  203. package/packages/sdk/src/workflows/__tests__/run-summary-table.test.ts +4 -3
  204. package/packages/sdk/src/workflows/__tests__/step-executor.test.ts +444 -0
  205. package/packages/sdk/src/workflows/__tests__/template-resolver.test.ts +162 -0
  206. package/packages/sdk/src/workflows/__tests__/verification.test.ts +229 -0
  207. package/packages/sdk/src/workflows/builder.ts +6 -6
  208. package/packages/sdk/src/workflows/channel-messenger.ts +314 -0
  209. package/packages/sdk/src/workflows/index.ts +12 -0
  210. package/packages/sdk/src/workflows/process-spawner.ts +201 -0
  211. package/packages/sdk/src/workflows/run.ts +2 -1
  212. package/packages/sdk/src/workflows/runner.ts +636 -951
  213. package/packages/sdk/src/workflows/step-executor.ts +579 -0
  214. package/packages/sdk/src/workflows/template-resolver.ts +180 -0
  215. package/packages/sdk/src/workflows/validator.ts +20 -2
  216. package/packages/sdk/src/workflows/verification.ts +184 -0
  217. package/packages/sdk-py/pyproject.toml +1 -1
  218. package/packages/sdk-py/src/agent_relay/__init__.py +0 -8
  219. package/packages/sdk-py/src/agent_relay/client.py +329 -522
  220. package/packages/sdk-py/src/agent_relay/protocol.py +2 -96
  221. package/packages/sdk-py/src/agent_relay/relay.py +1 -4
  222. package/packages/sdk-py/tests/test_wait_for_api_url.py +92 -0
  223. package/packages/sdk-py/uv.lock +5388 -0
  224. package/packages/telemetry/dist/client.d.ts.map +1 -1
  225. package/packages/telemetry/dist/client.js +1 -1
  226. package/packages/telemetry/dist/client.js.map +1 -1
  227. package/packages/telemetry/package.json +1 -1
  228. package/packages/telemetry/src/client.ts +3 -10
  229. package/packages/trajectory/package.json +2 -2
  230. package/packages/user-directory/package.json +2 -2
  231. package/packages/utils/package.json +2 -2
  232. package/scripts/postinstall.js +121 -1
@@ -7,64 +7,170 @@
7
7
  */
8
8
 
9
9
  import { existsSync } from 'node:fs';
10
- import { join, dirname } from 'node:path';
11
- import { execSync } from 'node:child_process';
10
+ import { join, dirname, resolve } from 'node:path';
11
+ import { execFileSync } from 'node:child_process';
12
12
  import { createRequire } from 'node:module';
13
13
  import { fileURLToPath } from 'node:url';
14
14
 
15
15
  const BROKER_NAME = 'agent-relay-broker';
16
16
 
17
+ function addUniquePath(paths: string[], candidate: string | null | undefined): void {
18
+ if (!candidate || paths.includes(candidate)) {
19
+ return;
20
+ }
21
+ paths.push(candidate);
22
+ }
23
+
24
+ function getImportMetaUrl(): string | null {
25
+ try {
26
+ return import.meta.url;
27
+ } catch {
28
+ return null;
29
+ }
30
+ }
31
+
32
+ function getCurrentModuleDir(): string | null {
33
+ if (typeof __dirname === 'string' && __dirname) {
34
+ return __dirname;
35
+ }
36
+ if (typeof __filename === 'string' && __filename) {
37
+ return dirname(__filename);
38
+ }
39
+
40
+ const importMetaUrl = getImportMetaUrl();
41
+ if (!importMetaUrl) {
42
+ return null;
43
+ }
44
+
45
+ try {
46
+ return dirname(fileURLToPath(importMetaUrl));
47
+ } catch {
48
+ return null;
49
+ }
50
+ }
51
+
52
+ function getCurrentModuleReference(): string | null {
53
+ if (typeof __filename === 'string' && __filename) {
54
+ return __filename;
55
+ }
56
+ if (typeof __dirname === 'string' && __dirname) {
57
+ return join(__dirname, 'broker-path.js');
58
+ }
59
+
60
+ return getImportMetaUrl();
61
+ }
62
+
63
+ function getSdkBinDirs(): string[] {
64
+ const binDirs: string[] = [];
65
+
66
+ const currentModuleDir = getCurrentModuleDir();
67
+ if (currentModuleDir) {
68
+ addUniquePath(binDirs, resolve(currentModuleDir, '..', 'bin'));
69
+ }
70
+
71
+ const currentModuleReference = getCurrentModuleReference();
72
+ if (currentModuleReference) {
73
+ try {
74
+ const sdkEntry = createRequire(currentModuleReference).resolve('@agent-relay/sdk');
75
+ addUniquePath(binDirs, resolve(dirname(sdkEntry), '..', 'bin'));
76
+ } catch {
77
+ // Continue with other resolution strategies.
78
+ }
79
+ }
80
+
81
+ const importMetaUrl = getImportMetaUrl();
82
+ if (importMetaUrl) {
83
+ try {
84
+ addUniquePath(binDirs, resolve(dirname(fileURLToPath(importMetaUrl)), '..', 'bin'));
85
+ } catch {
86
+ // Continue with other resolution strategies.
87
+ }
88
+ }
89
+
90
+ return binDirs;
91
+ }
92
+
93
+ function getDevelopmentBinaryPaths(ext: string, binDirs: string[]): string[] {
94
+ const binaryPaths: string[] = [];
95
+ const repoRoots = new Set<string>();
96
+
97
+ const addRepoRoot = (candidate: string | null | undefined): void => {
98
+ if (!candidate) {
99
+ return;
100
+ }
101
+
102
+ const repoRoot = resolve(candidate);
103
+ if (repoRoots.has(repoRoot)) {
104
+ return;
105
+ }
106
+ repoRoots.add(repoRoot);
107
+
108
+ addUniquePath(binaryPaths, join(repoRoot, 'target', 'release', `${BROKER_NAME}${ext}`));
109
+ addUniquePath(binaryPaths, join(repoRoot, 'target', 'debug', `${BROKER_NAME}${ext}`));
110
+ };
111
+
112
+ addRepoRoot(process.cwd());
113
+
114
+ const currentModuleDir = getCurrentModuleDir();
115
+ if (currentModuleDir) {
116
+ addRepoRoot(resolve(currentModuleDir, '..', '..', '..'));
117
+ }
118
+
119
+ for (const binDir of binDirs) {
120
+ addRepoRoot(resolve(binDir, '..', '..', '..'));
121
+ }
122
+
123
+ return binaryPaths;
124
+ }
125
+
17
126
  /**
18
127
  * Resolve the agent-relay-broker binary path.
19
128
  *
20
129
  * Search order:
21
- * 1. SDK's bin/ directory (resolved via createRequire or import.meta.url)
130
+ * 1. SDK's bin/ directory (resolved via CJS globals, createRequire, or import.meta.url)
22
131
  * 2. Platform-specific name (agent-relay-broker-{platform}-{arch}) in bin/
23
- * 3. PATH lookup via `which` / `where`
132
+ * 3. Common Cargo development paths (target/release and target/debug)
133
+ * 4. PATH lookup via `which` / `where`
24
134
  *
25
135
  * @returns Absolute path to the broker binary, or null if not found
26
136
  */
27
137
  export function getBrokerBinaryPath(): string | null {
28
- let binDir: string | null = null;
29
- try {
30
- // Use createRequire for ESM-compatible require.resolve
31
- const esmRequire = createRequire(import.meta.url);
32
- const sdkEntry = esmRequire.resolve('@agent-relay/sdk');
33
- binDir = join(dirname(sdkEntry), '..', 'bin');
34
- } catch {
35
- try {
36
- // Fallback: derive from import.meta.url
37
- binDir = join(dirname(dirname(fileURLToPath(import.meta.url))), 'bin');
38
- } catch {
39
- // Neither method worked
40
- }
41
- }
42
- if (!binDir) return null;
43
-
44
138
  const ext = process.platform === 'win32' ? '.exe' : '';
139
+ const binDirs = getSdkBinDirs();
140
+ const platformSpecific = `${BROKER_NAME}-${process.platform}-${process.arch}${ext}`;
45
141
 
46
142
  // 1. Exact name in bin/
47
- const exactPath = join(binDir, `${BROKER_NAME}${ext}`);
48
- if (existsSync(exactPath)) {
49
- return exactPath;
143
+ for (const binDir of binDirs) {
144
+ const exactPath = join(binDir, `${BROKER_NAME}${ext}`);
145
+ if (existsSync(exactPath)) {
146
+ return exactPath;
147
+ }
50
148
  }
51
149
 
52
150
  // 2. Platform-specific name in bin/
53
- const platformSpecific = `${BROKER_NAME}-${process.platform}-${process.arch}${ext}`;
54
- const platformPath = join(binDir, platformSpecific);
55
- if (existsSync(platformPath)) {
56
- return platformPath;
151
+ for (const binDir of binDirs) {
152
+ const platformPath = join(binDir, platformSpecific);
153
+ if (existsSync(platformPath)) {
154
+ return platformPath;
155
+ }
156
+ }
157
+
158
+ // 3. Common development paths for local Cargo builds.
159
+ for (const developmentPath of getDevelopmentBinaryPaths(ext, binDirs)) {
160
+ if (existsSync(developmentPath)) {
161
+ return developmentPath;
162
+ }
57
163
  }
58
164
 
59
- // 3. PATH lookup
165
+ // 4. PATH lookup
60
166
  try {
61
167
  const cmd = process.platform === 'win32' ? 'where' : 'which';
62
- const result = execSync(`${cmd} ${BROKER_NAME}`, {
168
+ const result = execFileSync(cmd, [BROKER_NAME], {
63
169
  encoding: 'utf-8',
64
170
  stdio: ['pipe', 'pipe', 'pipe'],
65
171
  }).trim();
66
172
  if (result) {
67
- return result.split('\n')[0].trim();
173
+ return result.split(/\r?\n/u)[0].trim();
68
174
  }
69
175
  } catch {
70
176
  // Not found on PATH