snow-flow 10.0.201 → 10.0.203

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.201",
3
+ "version": "10.0.203",
4
4
  "name": "snow-flow",
5
5
  "description": "Snow-Flow - ServiceNow Multi-Agent Development Framework powered by AI",
6
6
  "license": "Elastic-2.0",
@@ -123,7 +123,12 @@ export class ServiceNowAuthManager {
123
123
  const accessToken = await this.getAccessToken(context)
124
124
 
125
125
  if (!accessToken) {
126
- throw new Error("Failed to obtain access token. Please verify ServiceNow credentials and run: snow-flow auth login")
126
+ throw new Error(
127
+ "Failed to obtain access token. This can happen when:\n" +
128
+ "• Your ServiceNow instance is hibernating — open it in a browser to wake it up\n" +
129
+ "• Your credentials have expired — run: snow-flow auth login\n" +
130
+ "• Your OAuth client ID/secret are incorrect"
131
+ )
127
132
  }
128
133
 
129
134
  // Determine correct Authorization header format
@@ -171,6 +176,19 @@ export class ServiceNowAuthManager {
171
176
  return response
172
177
  },
173
178
  async (error) => {
179
+ const status = error.response?.status
180
+
181
+ // Detect hibernating instance (502/503 from proxy or ServiceNow itself)
182
+ if (status === 502 || status === 503) {
183
+ const err = new Error(
184
+ `ServiceNow instance is hibernating or starting up (HTTP ${status}). ` +
185
+ `Open ${context.instanceUrl} in your browser to wake it up, then wait 1-2 minutes and try again.`
186
+ )
187
+ ;(err as any).response = error.response
188
+ ;(err as any).isHibernating = true
189
+ throw err
190
+ }
191
+
174
192
  // Check if the error response has ServiceNow error structure
175
193
  if (error.response?.data?.error) {
176
194
  const snowError = error.response.data.error
@@ -39,6 +39,37 @@ export async function execute(args: any, context: ServiceNowContext): Promise<To
39
39
  status: responseTime < 1000 ? "good" : responseTime < 3000 ? "fair" : "slow",
40
40
  })
41
41
  } catch (error: any) {
42
+ const msg = error.message || ""
43
+ const status = error.response?.status
44
+
45
+ // Detect hibernating instance
46
+ if (
47
+ status === 502 || status === 503
48
+ || msg.includes("ECONNREFUSED")
49
+ || msg.includes("ETIMEDOUT")
50
+ || msg.includes("socket hang up")
51
+ || (msg.includes("Failed to obtain access token") && !msg.includes("Invalid credentials"))
52
+ ) {
53
+ return createErrorResult(
54
+ `ServiceNow instance appears to be hibernating or starting up.\n\n` +
55
+ `Developer instances automatically hibernate after periods of inactivity. ` +
56
+ `To wake it up:\n` +
57
+ `1. Open your instance URL in a browser: ${context.instanceUrl}\n` +
58
+ `2. Wait 1-2 minutes for it to fully start\n` +
59
+ `3. Try this command again\n\n` +
60
+ `Technical detail: ${status ? `HTTP ${status}` : msg}`
61
+ )
62
+ }
63
+
64
+ // Detect auth issues separately
65
+ if (msg.includes("Failed to obtain access token") || status === 401) {
66
+ return createErrorResult(
67
+ `Authentication failed. Your access token may be expired.\n\n` +
68
+ `Run: snow-flow auth login\n\n` +
69
+ `If you've already logged in, check: snow-flow auth status`
70
+ )
71
+ }
72
+
42
73
  return createErrorResult(error.message)
43
74
  }
44
75
  }
@@ -77,6 +77,7 @@ export namespace AnonymousTelemetry {
77
77
 
78
78
  let messageCount = 0
79
79
  let exitReason: "normal" | "error" | "interrupt" = "normal"
80
+ let exitErrorMessage: string | undefined
80
81
  let configDisabled = false
81
82
  const startTime = Date.now()
82
83
  const sessionId = crypto.randomUUID()
@@ -89,8 +90,11 @@ export namespace AnonymousTelemetry {
89
90
  ]
90
91
 
91
92
  // Track exit reason via process signals
92
- const onError = () => {
93
+ const onError = (err: unknown) => {
93
94
  exitReason = "error"
95
+ if (err instanceof Error) exitErrorMessage = `${err.name}: ${err.message}`.slice(0, 500)
96
+ else if (typeof err === "string") exitErrorMessage = err.slice(0, 500)
97
+ else exitErrorMessage = String(err).slice(0, 500)
94
98
  }
95
99
  const onInterrupt = () => {
96
100
  exitReason = "interrupt"
@@ -142,6 +146,9 @@ export namespace AnonymousTelemetry {
142
146
  get exitReason() {
143
147
  return exitReason
144
148
  },
149
+ get exitErrorMessage() {
150
+ return exitErrorMessage
151
+ },
145
152
  get configDisabled() {
146
153
  return configDisabled
147
154
  },
@@ -165,6 +172,7 @@ export namespace AnonymousTelemetry {
165
172
  ...current.basePayload,
166
173
  type: "end",
167
174
  exitReason: current.exitReason,
175
+ exitErrorMessage: current.exitErrorMessage,
168
176
  sessionDurationSec,
169
177
  messageCount: current.messageCount,
170
178
  timestamp: Date.now(),