snow-flow 10.0.68 → 10.0.70

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.68",
3
+ "version": "10.0.70",
4
4
  "name": "snow-flow",
5
5
  "description": "Snow-Flow - ServiceNow Multi-Agent Development Framework powered by AI",
6
6
  "license": "Elastic-2.0",
@@ -12,17 +12,11 @@ const log = Log.create({ service: "usage.anonymous-telemetry" })
12
12
  const PORTAL_URL = process.env.SNOW_FLOW_PORTAL_URL || "https://portal.snow-flow.dev"
13
13
 
14
14
  function isDisabled(): boolean {
15
- // 1. Standard DO_NOT_TRACK convention (consoledonottrack.com)
16
15
  const dnt = process.env.DO_NOT_TRACK?.toLowerCase()
17
16
  if (dnt === "1" || dnt === "true") return true
18
-
19
- // 2. Snow-Flow specific env vars
20
17
  if (Flag.OPENCODE_TELEMETRY_DISABLED) return true
21
-
22
- // 3. CI environments
23
18
  const ci = process.env.CI?.toLowerCase()
24
19
  if (ci === "true" || ci === "1") return true
25
-
26
20
  return false
27
21
  }
28
22
 
@@ -34,10 +28,23 @@ function getMachineId(): string | undefined {
34
28
  }
35
29
  }
36
30
 
31
+ async function sendPing(payload: Record<string, unknown>): Promise<void> {
32
+ try {
33
+ const response = await fetch(`${PORTAL_URL}/api/telemetry/ping`, {
34
+ method: "POST",
35
+ headers: { "Content-Type": "application/json" },
36
+ body: JSON.stringify(payload),
37
+ signal: AbortSignal.timeout(5_000),
38
+ })
39
+ log.info("telemetry ping sent", { status: response.status })
40
+ } catch (error) {
41
+ log.info("telemetry ping failed", { error: String(error) })
42
+ }
43
+ }
44
+
37
45
  export namespace AnonymousTelemetry {
38
46
  const state = Instance.state(
39
47
  () => {
40
- // Check env-based opt-out first (sync, before any subscriptions)
41
48
  if (isDisabled()) {
42
49
  log.info("anonymous telemetry disabled (env)")
43
50
  return { disabled: true as const, unsubs: [] as (() => void)[], startTime: 0, messageCount: 0 }
@@ -50,44 +57,69 @@ export namespace AnonymousTelemetry {
50
57
  }
51
58
 
52
59
  let messageCount = 0
60
+ let configDisabled = false
53
61
  const startTime = Date.now()
54
62
 
55
63
  const unsubs = [
56
64
  Bus.subscribe(MessageV2.Event.Updated, (event) => {
57
- if (event.properties.info.role === "user") {
58
- messageCount++
59
- }
65
+ if (event.properties.info.role === "user") messageCount++
60
66
  }),
61
67
  ]
62
68
 
63
- // Check config-based opt-out (async)
64
- Config.get().then((config) => {
65
- if (config.telemetry === false) {
66
- log.info("anonymous telemetry disabled (config)")
67
- for (const unsub of unsubs) unsub()
68
- unsubs.length = 0
69
- } else {
70
- log.info("anonymous telemetry active")
71
- }
72
- }).catch(() => {
73
- // Config not available yet — keep telemetry active
74
- log.info("anonymous telemetry active (config unavailable)")
75
- })
69
+ // Send start ping immediately, don't wait for Config
70
+ const startPayload = {
71
+ machineId,
72
+ version: Installation.VERSION,
73
+ channel: Installation.CHANNEL,
74
+ os: process.platform,
75
+ arch: process.arch,
76
+ sessionDurationSec: 0,
77
+ messageCount: 0,
78
+ timestamp: Date.now(),
79
+ }
76
80
 
77
- return { disabled: false as const, unsubs, startTime, machineId, get messageCount() { return messageCount } }
81
+ log.info("anonymous telemetry initializing", { machineId: machineId.slice(0, 8) + "..." })
82
+
83
+ // Check config opt-out in background, send start ping regardless
84
+ // (if config says disabled, we skip the dispose ping)
85
+ Config.get()
86
+ .then((config) => {
87
+ if (config.telemetry === false) {
88
+ configDisabled = true
89
+ log.info("anonymous telemetry disabled (config)")
90
+ for (const unsub of unsubs) unsub()
91
+ unsubs.length = 0
92
+ return
93
+ }
94
+ log.info("anonymous telemetry active, sending start ping")
95
+ sendPing(startPayload)
96
+ })
97
+ .catch(() => {
98
+ // Config unavailable — send ping anyway (opt-in by default)
99
+ log.info("anonymous telemetry active (config unavailable), sending start ping")
100
+ sendPing(startPayload)
101
+ })
102
+
103
+ return {
104
+ disabled: false as const,
105
+ unsubs,
106
+ startTime,
107
+ machineId,
108
+ get messageCount() { return messageCount },
109
+ get configDisabled() { return configDisabled },
110
+ }
78
111
  },
79
112
  async (current) => {
80
113
  for (const unsub of current.unsubs) unsub()
81
-
82
- if (current.disabled) return
114
+ if (current.disabled || current.configDisabled) return
83
115
 
84
116
  const sessionDurationSec = Math.round((Date.now() - current.startTime) / 1000)
85
117
 
86
- // Check config opt-out before sending
118
+ // Re-check config opt-out before sending dispose ping
87
119
  const config = await Config.get().catch(() => undefined)
88
120
  if (config?.telemetry === false) return
89
121
 
90
- const payload = {
122
+ await sendPing({
91
123
  machineId: current.machineId,
92
124
  version: Installation.VERSION,
93
125
  channel: Installation.CHANNEL,
@@ -96,22 +128,10 @@ export namespace AnonymousTelemetry {
96
128
  sessionDurationSec,
97
129
  messageCount: current.messageCount,
98
130
  timestamp: Date.now(),
99
- }
100
-
101
- try {
102
- await fetch(`${PORTAL_URL}/api/telemetry/ping`, {
103
- method: "POST",
104
- headers: { "Content-Type": "application/json" },
105
- body: JSON.stringify(payload),
106
- signal: AbortSignal.timeout(5_000),
107
- })
108
- } catch {
109
- // Fire-and-forget: network errors expected when offline
110
- }
131
+ })
111
132
  },
112
133
  )
113
134
 
114
- /** Initialize the anonymous telemetry reporter. Call once per Instance lifecycle. */
115
135
  export function init() {
116
136
  state()
117
137
  }