@indigoai-us/hq-cli 5.201.2 → 5.201.3

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/CHANGELOG.md CHANGED
@@ -2,6 +2,12 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [5.201.3] — 2026-09-25
6
+
7
+ ### Fixed
8
+
9
+ - A flag-registry worker whose startup fails because the working directory was deleted or its package files were being replaced no longer creates a Sentry issue. Other flag-registry worker errors remain visible with a worker tag.
10
+
5
11
  ## [5.201.2] — 2026-09-25
6
12
 
7
13
  ### Changed
@@ -6,6 +6,7 @@
6
6
  * keep a short-lived, offline CLI alive until the client's network deadline.
7
7
  */
8
8
  import { Worker } from "node:worker_threads";
9
+ import * as Sentry from "@sentry/node";
9
10
  import { isFlagSnapshot, readLocalOverride, resolveFlag, } from "@indigoai-us/hq-flags-client";
10
11
  import { readMachineCompanyBinding } from "./work-context/company.js";
11
12
  import { readSessionState } from "./work-context/state.js";
@@ -116,12 +117,19 @@ export function kickFlagRegistryReadiness(dependencies = {}) {
116
117
  const companyIdentifiers = [companyUid, company.companySlug].filter((value) => Boolean(value));
117
118
  processReader = processSnapshotReader(companyIdentifiers);
118
119
  try {
119
- const worker = (dependencies.createWorker ?? ((filename, options) => new Worker(filename, options)))(new URL("./flag-registry-worker.js", import.meta.url), {
120
- workerData: {
121
- endpoint,
122
- ...(companyUid ? { companyUid } : {}),
123
- ...(company.companySlug ? { companyIdentifiers: [company.companySlug] } : {}),
124
- },
120
+ // The SDK's child-process integration captures every Worker error unless
121
+ // its process-wide captureWorkerErrors option is disabled. Scope only this
122
+ // worker so the reporting boundary can classify its startup errors without
123
+ // changing capture for unrelated workers.
124
+ const worker = Sentry.withScope((scope) => {
125
+ scope.setTag("worker", "flag-registry");
126
+ return (dependencies.createWorker ?? ((filename, options) => new Worker(filename, options)))(new URL("./flag-registry-worker.js", import.meta.url), {
127
+ workerData: {
128
+ endpoint,
129
+ ...(companyUid ? { companyUid } : {}),
130
+ ...(company.companySlug ? { companyIdentifiers: [company.companySlug] } : {}),
131
+ },
132
+ });
125
133
  });
126
134
  worker.on("message", (value) => {
127
135
  if (isFlagSnapshot(value))
package/dist/sentry.js CHANGED
@@ -20,7 +20,14 @@ import { installTreeTornSentryTagsFor, sentryFingerprintFor, sentryMcpCollisionC
20
20
  * Consistent with the swallow-EPIPE posture established in #138.
21
21
  */
22
22
  export function epipeAwareBeforeSend(event, hint) {
23
- if (isEpipe(hint?.originalException))
23
+ const flagRegistryWorkerEvent = isFlagRegistryWorkerEvent(event);
24
+ if (flagRegistryWorkerEvent) {
25
+ if (isExpectedFlagRegistryWorkerStartupFailure(hint?.originalException))
26
+ return null;
27
+ event.level = "warning";
28
+ event.tags = { ...event.tags, worker: "flag-registry" };
29
+ }
30
+ if (!flagRegistryWorkerEvent && isEpipe(hint?.originalException))
24
31
  return null;
25
32
  // Path-independent belt for environmental filesystem failures (ENOSPC /
26
33
  // EDQUOT / EROFS — a full disk, exhausted quota, or read-only mount, e.g.
@@ -31,7 +38,7 @@ export function epipeAwareBeforeSend(event, hint) {
31
38
  // either. handleTopLevelError already prints an actionable message for the
32
39
  // boundary route; dropping the event here suppresses the fatal regardless of
33
40
  // route, while the CLI still exits non-zero. HQ-CLI-R (Sentry 7671416365).
34
- if (environmentalFsErrorMessage(hint?.originalException))
41
+ if (!flagRegistryWorkerEvent && environmentalFsErrorMessage(hint?.originalException))
35
42
  return null;
36
43
  // Path-independent belt for an IN-PROCESS incomplete-install module-load
37
44
  // failure — hq-cli's own globally installed tree is not intact at load time
@@ -50,7 +57,7 @@ export function epipeAwareBeforeSend(event, hint) {
50
57
  // node_modules, so an hq-cli packaging fault (a dist/ miss, or a bare miss the
51
58
  // requirer does NOT declare — a possible undeclared/peer dependency) and the
52
59
  // path-less unattributable shape are NOT dropped here and stay captured.
53
- if (incompleteInstallMessage(hint?.originalException))
60
+ if (!flagRegistryWorkerEvent && incompleteInstallMessage(hint?.originalException))
54
61
  return null;
55
62
  // An incomplete-install shape that is NOT suppressed (a bare miss the requirer
56
63
  // does not declare, or a path-less loader/resolver ENOENT) should still arrive
@@ -95,6 +102,27 @@ export function epipeAwareBeforeSend(event, hint) {
95
102
  }
96
103
  return beforeSend(event, hint);
97
104
  }
105
+ function isFlagRegistryWorkerEvent(event) {
106
+ return event.tags?.worker === "flag-registry" && Boolean(event.exception?.values?.some((value) => value.mechanism?.type === "auto.child_process.worker_thread"));
107
+ }
108
+ function isExpectedFlagRegistryWorkerStartupFailure(error) {
109
+ if (typeof error !== "object" || error === null)
110
+ return false;
111
+ const details = error;
112
+ if (details.code === "ENOENT" && details.syscall === "uv_cwd") {
113
+ const stack = typeof details.stack === "string" ? details.stack : "";
114
+ return stack.includes("node:internal/main/worker_thread") && /\bat process\.cwd \(/.test(stack);
115
+ }
116
+ if (details.code !== "MODULE_NOT_FOUND" && details.code !== "ERR_MODULE_NOT_FOUND") {
117
+ return false;
118
+ }
119
+ const message = typeof details.message === "string" ? details.message : "";
120
+ const missingModule = /Cannot find module\s+['"]([^'"]+)['"]/.exec(message)?.[1];
121
+ if (!missingModule)
122
+ return false;
123
+ return missingModule.replaceAll("\\", "/").endsWith("/flag-registry-worker.js") ||
124
+ missingModule === "flag-registry-worker.js";
125
+ }
98
126
  /**
99
127
  * Tests substitute only the transport so the real SDK lifecycle can be
100
128
  * exercised without an ingest request. Production callers pass nothing.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@indigoai-us/hq-cli",
3
- "version": "5.201.2",
3
+ "version": "5.201.3",
4
4
  "description": "HQ by Indigo management CLI — modules and cloud sync",
5
5
  "main": "dist/index.js",
6
6
  "bin": {