snow-flow 10.0.13 → 10.0.15

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/package.json",
3
- "version": "10.0.13",
3
+ "version": "10.0.15",
4
4
  "name": "snow-flow",
5
5
  "description": "Snow-Flow - ServiceNow Multi-Agent Development Framework powered by AI",
6
6
  "license": "Elastic-2.0",
@@ -938,10 +938,11 @@ function DialogAuthEnterprise() {
938
938
  const toast = useToast()
939
939
  const { theme } = useTheme()
940
940
 
941
- const [step, setStep] = createSignal<"subdomain" | "browser" | "code" | "verifying">("subdomain")
941
+ const [step, setStep] = createSignal<"subdomain" | "code" | "verifying">("subdomain")
942
942
  const [subdomain, setSubdomain] = createSignal("")
943
943
  const [sessionId, setSessionId] = createSignal("")
944
944
  const [authCode, setAuthCode] = createSignal("")
945
+ const [verificationUrl, setVerificationUrl] = createSignal("")
945
946
 
946
947
  let subdomainInput: TextareaRenderable
947
948
  let codeInput: TextareaRenderable
@@ -969,7 +970,7 @@ function DialogAuthEnterprise() {
969
970
  const currentStep = step()
970
971
  if (currentStep === "subdomain") {
971
972
  dialog.replace(() => <DialogAuth />)
972
- } else if (currentStep === "browser" || currentStep === "code") {
973
+ } else if (currentStep === "code") {
973
974
  setStep("subdomain")
974
975
  setSessionId("")
975
976
  setAuthCode("")
@@ -1020,24 +1021,16 @@ function DialogAuthEnterprise() {
1020
1021
 
1021
1022
  // Open browser with verification URL (works in Codespaces via xdg-open)
1022
1023
  const url = data.verificationUrl
1023
- const opened = await tryOpenBrowser(url)
1024
- if (opened) {
1025
- toast.show({ variant: "info", message: "Browser opened for verification", duration: 3000 })
1026
- } else {
1027
- toast.show({
1028
- variant: "info",
1029
- message: `Could not open browser. Open manually: ${url}`,
1030
- duration: 10000,
1031
- })
1032
- }
1033
-
1034
- setStep("browser")
1024
+ setVerificationUrl(url)
1025
+ tryOpenBrowser(url).then((opened) => {
1026
+ if (opened) {
1027
+ toast.show({ variant: "info", message: "Browser opened for verification", duration: 3000 })
1028
+ }
1029
+ })
1030
+ Clipboard.copy(url).catch(() => {})
1035
1031
 
1036
- // Auto-advance to code input after a moment
1037
- setTimeout(() => {
1038
- setStep("code")
1039
- setTimeout(() => codeInput?.focus(), 10)
1040
- }, 2000)
1032
+ setStep("code")
1033
+ setTimeout(() => codeInput?.focus(), 10)
1041
1034
  } catch (e) {
1042
1035
  toast.show({ variant: "error", message: e instanceof Error ? e.message : "Failed to start auth" })
1043
1036
  }
@@ -1256,22 +1249,21 @@ function DialogAuthEnterprise() {
1256
1249
  </box>
1257
1250
  </Show>
1258
1251
 
1259
- <Show when={step() === "browser"}>
1260
- <box gap={1}>
1261
- <text fg={theme.primary} attributes={TextAttributes.BOLD}>
1262
- Opening browser for verification...
1263
- </text>
1264
- <text fg={theme.textMuted}>URL: https://{subdomain()}.snow-flow.dev/device/authorize</text>
1265
- <box paddingTop={1}>
1266
- <text fg={theme.text}>After logging in on the portal:</text>
1267
- <text fg={theme.textMuted}> 1. Click "Approve" to authorize this device</text>
1268
- <text fg={theme.textMuted}> 2. Copy the authorization code shown</text>
1269
- </box>
1270
- </box>
1271
- </Show>
1272
-
1273
1252
  <Show when={step() === "code"}>
1274
1253
  <box gap={1}>
1254
+ <Show when={verificationUrl()}>
1255
+ <text fg={theme.primary} attributes={TextAttributes.BOLD}>
1256
+ Verify in your browser
1257
+ </text>
1258
+ <text fg={theme.text}>Open this URL to authorize this device:</text>
1259
+ <text fg={theme.primary}>{verificationUrl()}</text>
1260
+ <box paddingTop={1}>
1261
+ <text fg={theme.text}>After logging in on the portal:</text>
1262
+ <text fg={theme.textMuted}> 1. Click "Approve" to authorize this device</text>
1263
+ <text fg={theme.textMuted}> 2. Copy the authorization code shown</text>
1264
+ <text fg={theme.textMuted}> 3. Paste it below and press Enter</text>
1265
+ </box>
1266
+ </Show>
1275
1267
  <text fg={theme.textMuted}>Enter the authorization code from the portal</text>
1276
1268
  <textarea
1277
1269
  ref={(val: TextareaRenderable) => (codeInput = val)}
@@ -1318,7 +1310,6 @@ function DialogAuthEnterpriseCombined() {
1318
1310
 
1319
1311
  type CombinedStep =
1320
1312
  | "subdomain"
1321
- | "browser"
1322
1313
  | "code"
1323
1314
  | "verifying-enterprise"
1324
1315
  | "checking-portal-sn"
@@ -1334,6 +1325,7 @@ function DialogAuthEnterpriseCombined() {
1334
1325
  const [subdomain, setSubdomain] = createSignal("")
1335
1326
  const [sessionId, setSessionId] = createSignal("")
1336
1327
  const [authCode, setAuthCode] = createSignal("")
1328
+ const [verificationUrl, setVerificationUrl] = createSignal("")
1337
1329
  const [enterpriseData, setEnterpriseData] = createSignal<{
1338
1330
  token?: string
1339
1331
  user?: { username?: string; email?: string; role?: string }
@@ -1401,7 +1393,7 @@ function DialogAuthEnterpriseCombined() {
1401
1393
  if (evt.name === "escape") {
1402
1394
  if (currentStep === "subdomain") {
1403
1395
  dialog.replace(() => <DialogAuth />)
1404
- } else if (currentStep === "browser" || currentStep === "code") {
1396
+ } else if (currentStep === "code") {
1405
1397
  setStep("subdomain")
1406
1398
  setSessionId("")
1407
1399
  setAuthCode("")
@@ -1476,23 +1468,16 @@ function DialogAuthEnterpriseCombined() {
1476
1468
 
1477
1469
  // Open browser with verification URL (works in Codespaces via xdg-open)
1478
1470
  const url = data.verificationUrl
1479
- const opened = await tryOpenBrowser(url)
1480
- if (opened) {
1481
- toast.show({ variant: "info", message: "Browser opened for verification", duration: 3000 })
1482
- } else {
1483
- toast.show({
1484
- variant: "info",
1485
- message: `Could not open browser. Open manually: ${url}`,
1486
- duration: 10000,
1487
- })
1488
- }
1489
-
1490
- setStep("browser")
1471
+ setVerificationUrl(url)
1472
+ tryOpenBrowser(url).then((opened) => {
1473
+ if (opened) {
1474
+ toast.show({ variant: "info", message: "Browser opened for verification", duration: 3000 })
1475
+ }
1476
+ })
1477
+ Clipboard.copy(url).catch(() => {})
1491
1478
 
1492
- setTimeout(() => {
1493
- setStep("code")
1494
- setTimeout(() => codeInput?.focus(), 10)
1495
- }, 2000)
1479
+ setStep("code")
1480
+ setTimeout(() => codeInput?.focus(), 10)
1496
1481
  } catch (e) {
1497
1482
  toast.show({ variant: "error", message: e instanceof Error ? e.message : "Failed to start auth" })
1498
1483
  }
@@ -1915,28 +1900,22 @@ function DialogAuthEnterpriseCombined() {
1915
1900
  </box>
1916
1901
  </Show>
1917
1902
 
1918
- {/* Step 2: Browser opening */}
1919
- <Show when={step() === "browser"}>
1920
- <box gap={1}>
1921
- <text fg={theme.primary} attributes={TextAttributes.BOLD}>
1922
- Step 1 of 2: Enterprise Portal
1923
- </text>
1924
- <text fg={theme.text}>Opening browser for verification...</text>
1925
- <text fg={theme.textMuted}>URL: https://{subdomain()}.snow-flow.dev/device/authorize</text>
1926
- <box paddingTop={1}>
1927
- <text fg={theme.text}>After logging in on the portal:</text>
1928
- <text fg={theme.textMuted}> 1. Click "Approve" to authorize this device</text>
1929
- <text fg={theme.textMuted}> 2. Copy the authorization code shown</text>
1930
- </box>
1931
- </box>
1932
- </Show>
1933
-
1934
- {/* Step 3: Enter auth code */}
1903
+ {/* Step 2: Verify in browser + enter auth code */}
1935
1904
  <Show when={step() === "code"}>
1936
1905
  <box gap={1}>
1937
1906
  <text fg={theme.primary} attributes={TextAttributes.BOLD}>
1938
1907
  Step 1 of 2: Enterprise Portal
1939
1908
  </text>
1909
+ <Show when={verificationUrl()}>
1910
+ <text fg={theme.text}>Open this URL to authorize this device:</text>
1911
+ <text fg={theme.primary}>{verificationUrl()}</text>
1912
+ <box paddingTop={1}>
1913
+ <text fg={theme.text}>After logging in on the portal:</text>
1914
+ <text fg={theme.textMuted}> 1. Click "Approve" to authorize this device</text>
1915
+ <text fg={theme.textMuted}> 2. Copy the authorization code shown</text>
1916
+ <text fg={theme.textMuted}> 3. Paste it below and press Enter</text>
1917
+ </box>
1918
+ </Show>
1940
1919
  <text fg={theme.textMuted}>Enter the authorization code from the portal</text>
1941
1920
  <textarea
1942
1921
  ref={(val: TextareaRenderable) => (codeInput = val)}
@@ -26,6 +26,7 @@ import { BunProc } from "@/bun"
26
26
  import { Installation } from "@/installation"
27
27
  import { ConfigMarkdown } from "./markdown"
28
28
  import { existsSync } from "fs"
29
+ import { execSync } from "child_process"
29
30
  import { Bus } from "@/bus"
30
31
  import { GlobalBus } from "@/bus/global"
31
32
  import { Event } from "../server/event"
@@ -207,6 +208,26 @@ export namespace Config {
207
208
  }
208
209
  })
209
210
 
211
+ /**
212
+ * Detect the best available JS runtime command.
213
+ * Prefers bun if available, falls back to node.
214
+ */
215
+ function getRuntime(): string {
216
+ try {
217
+ execSync("bun --version", { stdio: "ignore" })
218
+ return "bun"
219
+ } catch {
220
+ return "node"
221
+ }
222
+ }
223
+
224
+ let _cachedRuntime: string | undefined
225
+
226
+ function runtime(): string {
227
+ if (_cachedRuntime === undefined) _cachedRuntime = getRuntime()
228
+ return _cachedRuntime
229
+ }
230
+
210
231
  /**
211
232
  * Get the MCP server command based on whether we're running bundled or in development
212
233
  */
@@ -269,9 +290,9 @@ export namespace Config {
269
290
  log.info("checking bundled path", { bundledPath, exists })
270
291
  if (exists) {
271
292
  log.info("found bundled MCP server", { serverName, path: bundledPath })
272
- // Use bun for bundled JS - it works with both bun-targeted and node-targeted builds
273
- // Node.js doesn't support import.meta.require used in bun-targeted builds
274
- return ["bun", "run", bundledPath]
293
+ const rt = runtime()
294
+ log.info("using runtime for MCP server", { runtime: rt })
295
+ return [rt, "run", bundledPath]
275
296
  }
276
297
  }
277
298
 
@@ -295,7 +316,7 @@ export namespace Config {
295
316
  })
296
317
  }
297
318
 
298
- return ["bun", "run", serverPath]
319
+ return [runtime(), "run", serverPath]
299
320
  }
300
321
 
301
322
  /**