@newrelic/preflight 1.67.3 → 1.69.0

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 (183) hide show
  1. package/README.md +2 -2
  2. package/dist/config.d.ts +75 -2
  3. package/dist/config.d.ts.map +1 -1
  4. package/dist/config.js +201 -22
  5. package/dist/config.js.map +1 -1
  6. package/dist/dashboard/routes/api-handler.d.ts +1 -0
  7. package/dist/dashboard/routes/api-handler.d.ts.map +1 -1
  8. package/dist/dashboard/routes/api-handler.js +120 -94
  9. package/dist/dashboard/routes/api-handler.js.map +1 -1
  10. package/dist/data/dashboards/ai-coding-assistant-adoption-cost.json +291 -1
  11. package/dist/data/dashboards/ai-coding-assistant-team-view.json +6 -6
  12. package/dist/hooks/billed-turn-ledger.d.ts +46 -0
  13. package/dist/hooks/billed-turn-ledger.d.ts.map +1 -0
  14. package/dist/hooks/billed-turn-ledger.js +274 -0
  15. package/dist/hooks/billed-turn-ledger.js.map +1 -0
  16. package/dist/hooks/collector-script.d.ts.map +1 -1
  17. package/dist/hooks/collector-script.js +5 -1
  18. package/dist/hooks/collector-script.js.map +1 -1
  19. package/dist/hooks/event-processor.d.ts +3 -7
  20. package/dist/hooks/event-processor.d.ts.map +1 -1
  21. package/dist/hooks/event-processor.js +21 -7
  22. package/dist/hooks/event-processor.js.map +1 -1
  23. package/dist/hooks/parent-transcript-watcher.d.ts +6 -5
  24. package/dist/hooks/parent-transcript-watcher.d.ts.map +1 -1
  25. package/dist/hooks/parent-transcript-watcher.js +64 -62
  26. package/dist/hooks/parent-transcript-watcher.js.map +1 -1
  27. package/dist/hooks/throttled-warning.d.ts +16 -0
  28. package/dist/hooks/throttled-warning.d.ts.map +1 -0
  29. package/dist/hooks/throttled-warning.js +32 -0
  30. package/dist/hooks/throttled-warning.js.map +1 -0
  31. package/dist/index.d.ts.map +1 -1
  32. package/dist/index.js +90 -83
  33. package/dist/index.js.map +1 -1
  34. package/dist/install/cli.d.ts.map +1 -1
  35. package/dist/install/cli.js +69 -1
  36. package/dist/install/cli.js.map +1 -1
  37. package/dist/install/dashboard-health.js +1 -1
  38. package/dist/install/dashboard-health.js.map +1 -1
  39. package/dist/install/diagnostics.d.ts +2 -0
  40. package/dist/install/diagnostics.d.ts.map +1 -1
  41. package/dist/install/diagnostics.js +132 -28
  42. package/dist/install/diagnostics.js.map +1 -1
  43. package/dist/install/headless-install.d.ts +26 -0
  44. package/dist/install/headless-install.d.ts.map +1 -1
  45. package/dist/install/headless-install.js +44 -1
  46. package/dist/install/headless-install.js.map +1 -1
  47. package/dist/install/install-helper.d.ts +2 -0
  48. package/dist/install/install-helper.d.ts.map +1 -1
  49. package/dist/install/install-helper.js +5 -0
  50. package/dist/install/install-helper.js.map +1 -1
  51. package/dist/install/keychain.d.ts +18 -0
  52. package/dist/install/keychain.d.ts.map +1 -0
  53. package/dist/install/keychain.js +60 -0
  54. package/dist/install/keychain.js.map +1 -0
  55. package/dist/install/kiro-install-helper.d.ts +27 -0
  56. package/dist/install/kiro-install-helper.d.ts.map +1 -0
  57. package/dist/install/kiro-install-helper.js +53 -0
  58. package/dist/install/kiro-install-helper.js.map +1 -0
  59. package/dist/install/setup-wizard.d.ts +4 -0
  60. package/dist/install/setup-wizard.d.ts.map +1 -1
  61. package/dist/install/setup-wizard.js +94 -9
  62. package/dist/install/setup-wizard.js.map +1 -1
  63. package/dist/lib/child-env.d.ts +11 -0
  64. package/dist/lib/child-env.d.ts.map +1 -0
  65. package/dist/lib/child-env.js +35 -0
  66. package/dist/lib/child-env.js.map +1 -0
  67. package/dist/lib/git-remote.d.ts +7 -0
  68. package/dist/lib/git-remote.d.ts.map +1 -1
  69. package/dist/lib/git-remote.js +13 -0
  70. package/dist/lib/git-remote.js.map +1 -1
  71. package/dist/metrics/cost-tracker-seed.d.ts +16 -0
  72. package/dist/metrics/cost-tracker-seed.d.ts.map +1 -1
  73. package/dist/metrics/cost-tracker-seed.js +42 -7
  74. package/dist/metrics/cost-tracker-seed.js.map +1 -1
  75. package/dist/metrics/cost-tracker.d.ts +11 -3
  76. package/dist/metrics/cost-tracker.d.ts.map +1 -1
  77. package/dist/metrics/cost-tracker.js +4 -1
  78. package/dist/metrics/cost-tracker.js.map +1 -1
  79. package/dist/metrics/git-activity-recorder.d.ts +3 -3
  80. package/dist/metrics/git-activity-recorder.d.ts.map +1 -1
  81. package/dist/metrics/git-activity-recorder.js +3 -3
  82. package/dist/metrics/git-activity-recorder.js.map +1 -1
  83. package/dist/metrics/git-workspace-identity.d.ts +6 -1
  84. package/dist/metrics/git-workspace-identity.d.ts.map +1 -1
  85. package/dist/metrics/git-workspace-identity.js +56 -32
  86. package/dist/metrics/git-workspace-identity.js.map +1 -1
  87. package/dist/metrics/git-workspace-reporter.d.ts +4 -3
  88. package/dist/metrics/git-workspace-reporter.d.ts.map +1 -1
  89. package/dist/metrics/git-workspace-reporter.js +4 -3
  90. package/dist/metrics/git-workspace-reporter.js.map +1 -1
  91. package/dist/metrics/pricing-init.d.ts +13 -0
  92. package/dist/metrics/pricing-init.d.ts.map +1 -0
  93. package/dist/metrics/pricing-init.js +19 -0
  94. package/dist/metrics/pricing-init.js.map +1 -0
  95. package/dist/metrics/skill-activation-tracker.d.ts +27 -0
  96. package/dist/metrics/skill-activation-tracker.d.ts.map +1 -0
  97. package/dist/metrics/skill-activation-tracker.js +92 -0
  98. package/dist/metrics/skill-activation-tracker.js.map +1 -0
  99. package/dist/metrics/turn-cost-attributor.d.ts +34 -16
  100. package/dist/metrics/turn-cost-attributor.d.ts.map +1 -1
  101. package/dist/metrics/turn-cost-attributor.js +95 -60
  102. package/dist/metrics/turn-cost-attributor.js.map +1 -1
  103. package/dist/proxy/proxy-manager.d.ts +3 -0
  104. package/dist/proxy/proxy-manager.d.ts.map +1 -1
  105. package/dist/proxy/proxy-manager.js +43 -3
  106. package/dist/proxy/proxy-manager.js.map +1 -1
  107. package/dist/proxy/types.d.ts +7 -0
  108. package/dist/proxy/types.d.ts.map +1 -1
  109. package/dist/proxy/types.js.map +1 -1
  110. package/dist/proxy/upstream-http.d.ts.map +1 -1
  111. package/dist/proxy/upstream-http.js +44 -1
  112. package/dist/proxy/upstream-http.js.map +1 -1
  113. package/dist/proxy/upstream-stdio.d.ts +0 -1
  114. package/dist/proxy/upstream-stdio.d.ts.map +1 -1
  115. package/dist/proxy/upstream-stdio.js +2 -26
  116. package/dist/proxy/upstream-stdio.js.map +1 -1
  117. package/dist/redaction-patterns.d.ts.map +1 -1
  118. package/dist/redaction-patterns.js +1 -0
  119. package/dist/redaction-patterns.js.map +1 -1
  120. package/dist/secret-command.d.ts +59 -0
  121. package/dist/secret-command.d.ts.map +1 -0
  122. package/dist/secret-command.js +123 -0
  123. package/dist/secret-command.js.map +1 -0
  124. package/dist/security/audit-trail.d.ts +7 -1
  125. package/dist/security/audit-trail.d.ts.map +1 -1
  126. package/dist/security/audit-trail.js +24 -0
  127. package/dist/security/audit-trail.js.map +1 -1
  128. package/dist/server.d.ts.map +1 -1
  129. package/dist/server.js +9 -4
  130. package/dist/server.js.map +1 -1
  131. package/dist/shared/pricing-data.d.ts.map +1 -1
  132. package/dist/shared/pricing-data.js +223 -32
  133. package/dist/shared/pricing-data.js.map +1 -1
  134. package/dist/shared/pricing.d.ts +25 -3
  135. package/dist/shared/pricing.d.ts.map +1 -1
  136. package/dist/shared/pricing.js +46 -9
  137. package/dist/shared/pricing.js.map +1 -1
  138. package/dist/shared/tokens.d.ts +16 -0
  139. package/dist/shared/tokens.d.ts.map +1 -1
  140. package/dist/shared/tokens.js +18 -0
  141. package/dist/shared/tokens.js.map +1 -1
  142. package/dist/shared/transport/otlp-shared.d.ts.map +1 -1
  143. package/dist/shared/transport/otlp-shared.js +7 -14
  144. package/dist/shared/transport/otlp-shared.js.map +1 -1
  145. package/dist/storage/local-store.d.ts +6 -4
  146. package/dist/storage/local-store.d.ts.map +1 -1
  147. package/dist/storage/local-store.js +21 -7
  148. package/dist/storage/local-store.js.map +1 -1
  149. package/dist/storage/session-store.d.ts +24 -1
  150. package/dist/storage/session-store.d.ts.map +1 -1
  151. package/dist/storage/session-store.js +38 -7
  152. package/dist/storage/session-store.js.map +1 -1
  153. package/dist/storage/types.d.ts +13 -0
  154. package/dist/storage/types.d.ts.map +1 -1
  155. package/dist/storage/types.js.map +1 -1
  156. package/dist/tools/cross-session-tools.d.ts +7 -1
  157. package/dist/tools/cross-session-tools.d.ts.map +1 -1
  158. package/dist/tools/cross-session-tools.js +47 -14
  159. package/dist/tools/cross-session-tools.js.map +1 -1
  160. package/dist/tools/session-stats.d.ts +6 -0
  161. package/dist/tools/session-stats.d.ts.map +1 -1
  162. package/dist/tools/session-stats.js +3 -2
  163. package/dist/tools/session-stats.js.map +1 -1
  164. package/dist/transport/audit-record-sender.d.ts +20 -0
  165. package/dist/transport/audit-record-sender.d.ts.map +1 -0
  166. package/dist/transport/audit-record-sender.js +54 -0
  167. package/dist/transport/audit-record-sender.js.map +1 -0
  168. package/dist/transport/nr-ingest.d.ts +7 -0
  169. package/dist/transport/nr-ingest.d.ts.map +1 -1
  170. package/dist/transport/nr-ingest.js +64 -27
  171. package/dist/transport/nr-ingest.js.map +1 -1
  172. package/dist/transport/tier-types.d.ts +11 -1
  173. package/dist/transport/tier-types.d.ts.map +1 -1
  174. package/dist/transport/tier-types.js +28 -6
  175. package/dist/transport/tier-types.js.map +1 -1
  176. package/dist/transport/unforwarded-session-monitor.d.ts +12 -6
  177. package/dist/transport/unforwarded-session-monitor.d.ts.map +1 -1
  178. package/dist/transport/unforwarded-session-monitor.js +24 -5
  179. package/dist/transport/unforwarded-session-monitor.js.map +1 -1
  180. package/dist/web/assets/{index-lvdXUntr.js → index-U9DPZ-Tb.js} +3 -3
  181. package/dist/web/index.html +1 -1
  182. package/examples/local-alert-rules.json +28 -0
  183. package/package.json +1 -1
package/README.md CHANGED
@@ -63,7 +63,7 @@ See cost breakdown, efficiency scoring, anti-patterns, and live session tracking
63
63
  - **Session Detail** — deep-dive into a single session's tool calls
64
64
  - **Team View** — aggregated cost and efficiency across developers
65
65
  - **Manager View** — high-level team metrics, no tool-call content
66
- - **Adoption & Cost** — adoption momentum, spend, MCP usage, and per-developer outcomes for engineering managers
66
+ - **Adoption & Cost** — adoption momentum, spend, skill and MCP usage, and per-developer outcomes for engineering managers
67
67
  - **Platform Comparison** — Claude Code vs. Cursor vs. Windsurf, etc.
68
68
  - **Security Audit** — audit trail of sensitive file access
69
69
 
@@ -77,7 +77,7 @@ See cost breakdown, efficiency scoring, anti-patterns, and live session tracking
77
77
  npm install -g @newrelic/preflight
78
78
  ```
79
79
 
80
- > **Using [Smithery](https://smithery.ai)?** Installing Preflight from the Smithery MCP registry wires up the MCP server for you, but Smithery has no mechanism to write Claude Code hooks. After install, ask Claude Code to call the `nr_observe_install_hooks` MCP tool (it will offer to do this automatically once `nr_observe_health` reports `setup_required: true`), then restart Claude Code to activate monitoring.
80
+ > **Using [Smithery](https://smithery.ai)?** Installing Preflight from the Smithery MCP registry wires up the MCP server for you, but Smithery has no mechanism to write Claude Code hooks. After install, either run `preflight install` in a terminal, or set `"allowHeadlessInstall": true` in your Preflight config (or `NEW_RELIC_AI_ALLOW_HEADLESS_INSTALL=true`) and ask Claude Code to call the `nr_observe_install_hooks` MCP tool. The tool refuses by default, because any connected MCP client can call it. With the flag on, it offers to do this automatically once `nr_observe_health` reports `setup_required: true`. Then restart Claude Code to activate monitoring.
81
81
 
82
82
  ### 2. Run setup
83
83
 
package/dist/config.d.ts CHANGED
@@ -4,6 +4,8 @@ import type { CliOptions } from './types.js';
4
4
  import type { UpstreamConfig } from './proxy/types.js';
5
5
  import type { PersonalAlertThresholds } from './alerts/types.js';
6
6
  import type { ResolvedTier } from './transport/tier-types.js';
7
+ import { SecretCommandError } from './secret-command.js';
8
+ import type { SecretSources } from './secret-command.js';
7
9
  export declare const VALID_MODES: readonly ["cloud", "local", "both"];
8
10
  export type Mode = (typeof VALID_MODES)[number];
9
11
  export type CompanionModeSource = 'env NR_AI_COMPANION_MODE' | 'config file' | 'detected Claude Code OTel export' | 'default';
@@ -11,6 +13,16 @@ export interface ResolvedCompanionMode {
11
13
  readonly value: boolean;
12
14
  readonly source: CompanionModeSource;
13
15
  }
16
+ /**
17
+ * Detects the setup where companion mode is off yet Claude Code's cost metrics
18
+ * reach New Relic through Preflight's receiver, so New Relic counts cost twice.
19
+ * Deliberately imprecise, and used only for a `preflight doctor` warning:
20
+ * auto-enabling companion mode on this signal would drop cost from New Relic
21
+ * whenever the proxy is not actually forwarding.
22
+ */
23
+ export declare function findReceiverDoubleCount(env: NodeJS.ProcessEnv, config: Pick<McpServerConfig, 'otlp' | 'companionMode'>): {
24
+ readonly grpc: boolean;
25
+ } | null;
14
26
  /**
15
27
  * Companion mode only prevents double-counting when Claude Code's own OTel
16
28
  * metrics also land in New Relic. Detection requires an nr-data.net endpoint:
@@ -43,6 +55,14 @@ export interface McpServerConfig {
43
55
  * (session_id === OTel's session.id). See docs/ADVANCED.md § Companion mode.
44
56
  */
45
57
  readonly companionMode: boolean;
58
+ /**
59
+ * Lets the `nr_observe_install_hooks` MCP tool rewrite ~/.claude/settings.json.
60
+ * Default false: any connected MCP client can call the tool, so it is opt-in.
61
+ * See docs/ADVANCED.md § allowHeadlessInstall.
62
+ */
63
+ readonly allowHeadlessInstall: boolean;
64
+ /** Source of the resolved companionMode value (env, config file, detected, or default). */
65
+ readonly companionModeSource: CompanionModeSource;
46
66
  readonly redactionPatterns: readonly RegExp[];
47
67
  readonly hookBufferPath: string;
48
68
  readonly storagePath: string;
@@ -58,6 +78,8 @@ export interface McpServerConfig {
58
78
  readonly collectorHost: string | null;
59
79
  readonly proxyUpstreams: readonly UpstreamConfig[];
60
80
  readonly nrApiKey: string | null;
81
+ /** Which source supplied each secret. Never the value. */
82
+ readonly secretSources: SecretSources;
61
83
  /** Path to a custom pricing JSON file, applied via `initPricing()`. See `NEW_RELIC_AI_CUSTOM_PRICING_FILE`. */
62
84
  readonly customPricingFile: string | null;
63
85
  /**
@@ -154,6 +176,7 @@ export interface McpServerConfig {
154
176
  }
155
177
  export declare const DEFAULT_STORAGE_PATH: string;
156
178
  export type PlatformTarget = 'native' | 'wsl-windows-cc' | 'wsl-linux-cc';
179
+ export declare const SecretCommandSchema: z.ZodArray<z.ZodString>;
157
180
  export declare const ConfigFileSchema: z.ZodObject<{
158
181
  configVersion: z.ZodOptional<z.ZodNumber>;
159
182
  licenseKey: z.ZodOptional<z.ZodString>;
@@ -171,6 +194,7 @@ export declare const ConfigFileSchema: z.ZodObject<{
171
194
  recordContent: z.ZodOptional<z.ZodBoolean>;
172
195
  pricingRefresh: z.ZodOptional<z.ZodBoolean>;
173
196
  companionMode: z.ZodOptional<z.ZodBoolean>;
197
+ allowHeadlessInstall: z.ZodOptional<z.ZodBoolean>;
174
198
  storagePath: z.ZodOptional<z.ZodString>;
175
199
  hookBufferPath: z.ZodOptional<z.ZodString>;
176
200
  harvestEventsMs: z.ZodOptional<z.ZodNumber>;
@@ -189,6 +213,9 @@ export declare const ConfigFileSchema: z.ZodObject<{
189
213
  proxyUpstreams: z.ZodOptional<z.ZodArray<z.ZodUnknown>>;
190
214
  tiers: z.ZodOptional<z.ZodArray<z.ZodUnknown>>;
191
215
  nrApiKey: z.ZodOptional<z.ZodNullable<z.ZodString>>;
216
+ licenseKeyCommand: z.ZodOptional<z.ZodArray<z.ZodString>>;
217
+ nrApiKeyCommand: z.ZodOptional<z.ZodArray<z.ZodString>>;
218
+ digestWebhookUrlCommand: z.ZodOptional<z.ZodArray<z.ZodString>>;
192
219
  customPricingFile: z.ZodOptional<z.ZodNullable<z.ZodString>>;
193
220
  costRateMultiplier: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
194
221
  dataResidencyPremium: z.ZodOptional<z.ZodBoolean>;
@@ -273,7 +300,40 @@ export declare class MissingCloudCredentialError extends Error {
273
300
  readonly mode: Mode;
274
301
  constructor(missingField: 'licenseKey' | 'accountId', mode: Mode, configFilePath: string);
275
302
  }
276
- export declare function loadMcpConfig(cliOptions?: Partial<CliOptions>): Readonly<McpServerConfig>;
303
+ /**
304
+ * A `SecretCommandError` raised while resolving a secret that cloud export
305
+ * needs. It keeps the helper's own message for stdio users and adds the mode
306
+ * the config asked for, so `--local` can tell a failing helper from a missing
307
+ * credential and still fall back to local mode.
308
+ */
309
+ export declare class CloudSecretCommandError extends SecretCommandError {
310
+ readonly mode: Mode;
311
+ constructor(original: SecretCommandError, mode: Mode);
312
+ }
313
+ /**
314
+ * The startup-resolved digest webhook URL when a source that outranks the
315
+ * file's `digestWebhookUrl` (env var or digestWebhookUrlCommand) supplied it.
316
+ * Undefined means "read the file at send time".
317
+ */
318
+ export declare function digestWebhookUrlOverride(config: Pick<McpServerConfig, 'digestWebhookUrl' | 'secretSources'>): string | undefined;
319
+ /** Which source is overriding the file's `digestWebhookUrl`, if any. */
320
+ export declare function digestWebhookUrlOverrideSource(config: Pick<McpServerConfig, 'digestWebhookUrl' | 'secretSources'>): 'env' | 'command' | undefined;
321
+ export interface LoadMcpConfigOptions {
322
+ /**
323
+ * Run the `*Command` secret helpers. Pass false from callers that poll or
324
+ * only read non-secret fields (dashboard diagnostics, host/port lookup):
325
+ * `secretSources` still reports `command`, but the secrets resolve to
326
+ * undefined/null and `tiers` stays empty unless explicit.
327
+ */
328
+ readonly resolveSecrets?: boolean;
329
+ /**
330
+ * Skip the `tiers` array entirely. The `--local` fallback sets this after a
331
+ * cloud credential failure: it reloads with `NR_AI_MODE=local`, and a
332
+ * `tiers` array under local mode is otherwise a config error.
333
+ */
334
+ readonly ignoreTiers?: boolean;
335
+ }
336
+ export declare function loadMcpConfig(cliOptions?: Partial<CliOptions>, loadOptions?: LoadMcpConfigOptions): Readonly<McpServerConfig>;
277
337
  export interface ConfigValidationResult {
278
338
  readonly filePath: string;
279
339
  readonly fileExists: boolean;
@@ -285,7 +345,7 @@ export interface ConfigValidationResult {
285
345
  readonly storagePath?: string;
286
346
  /** The `companionMode` field from the parsed config, if present and a boolean. */
287
347
  readonly companionMode?: boolean;
288
- /** True when a non-blank licenseKey is present in the parsed config. Raw value is intentionally not exposed. */
348
+ /** True when a non-blank licenseKey or a licenseKeyCommand is present in the parsed config. Raw value is intentionally not exposed. */
289
349
  readonly hasLicenseKey: boolean;
290
350
  /** Fatal problems that will prevent the MCP server from starting. */
291
351
  readonly errors: readonly string[];
@@ -299,4 +359,17 @@ export interface ConfigValidationResult {
299
359
  */
300
360
  export declare function validateConfigFile(filePath: string): ConfigValidationResult;
301
361
  export declare function redactSensitive(value: string, patterns?: readonly RegExp[]): string;
362
+ /**
363
+ * redactSensitive() for identifiers (project_id, repo_url, repo names), which
364
+ * carry a token only as a whole path segment or a segment's prefix. A match that
365
+ * starts right after a letter or digit is part of an ordinary name
366
+ * (`acme/risk-assessment-…` holds `sk-assessment-…`) and is left alone. The scan
367
+ * resumes one character later, so a token further into that span
368
+ * (`acme/risk-ghp_…`) is still caught.
369
+ *
370
+ * Free-form content keeps redactSensitive()'s plain matching: there a token
371
+ * routinely follows a letter or digit, after a JSON escape (`\nghp_…`), an ANSI
372
+ * colour code (`ESC[32m`) or `%3A`.
373
+ */
374
+ export declare function redactIdentifier(value: string): string;
302
375
  //# sourceMappingURL=config.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
package/dist/config.js CHANGED
@@ -9,6 +9,7 @@ import { REDACTION_PATTERNS as DEFAULT_REDACTION_PATTERNS } from './redaction-pa
9
9
  import { resolveRecordContent } from './record-content-gate.js';
10
10
  import { projectIdFromRemote, stripRemoteCredentials } from './lib/git-remote.js';
11
11
  import { validateTiers, DEFAULT_TIER_NAME, WILDCARD_EVENT_TYPE } from './transport/tier-types.js';
12
+ import { SecretCommandError, isSecretConfigured, resolveSecret, resolveSecretCommand, } from './secret-command.js';
12
13
  const logger = createLogger('mcp-config');
13
14
  export const VALID_MODES = ['cloud', 'local', 'both'];
14
15
  function otlpEndpointIsNewRelic(endpoint) {
@@ -22,6 +23,55 @@ function otlpEndpointIsNewRelic(endpoint) {
22
23
  return false;
23
24
  }
24
25
  }
26
+ const SDK_DEFAULT_OTLP_HTTP_ENDPOINT = 'http://localhost:4318';
27
+ const SDK_DEFAULT_OTLP_GRPC_ENDPOINT = 'http://localhost:4317';
28
+ const LOOPBACK_HOSTS = new Set(['127.0.0.1', 'localhost', '::1']);
29
+ const WILDCARD_HOSTS = new Set(['0.0.0.0', '::']);
30
+ function bareHost(host) {
31
+ return host.replace(/^\[|\]$/g, '');
32
+ }
33
+ function reachesReceiverHost(clientHost, bindAddress) {
34
+ const client = bareHost(clientHost);
35
+ const bind = bareHost(bindAddress);
36
+ if (client === bind)
37
+ return true;
38
+ return LOOPBACK_HOSTS.has(client) && (LOOPBACK_HOSTS.has(bind) || WILDCARD_HOSTS.has(bind));
39
+ }
40
+ /**
41
+ * Detects the setup where companion mode is off yet Claude Code's cost metrics
42
+ * reach New Relic through Preflight's receiver, so New Relic counts cost twice.
43
+ * Deliberately imprecise, and used only for a `preflight doctor` warning:
44
+ * auto-enabling companion mode on this signal would drop cost from New Relic
45
+ * whenever the proxy is not actually forwarding.
46
+ */
47
+ export function findReceiverDoubleCount(env, config) {
48
+ const { receiverEnabled, receiverPort, receiverBindAddress, forwardEndpoint } = config.otlp;
49
+ if (config.companionMode ||
50
+ !receiverEnabled ||
51
+ !otlpEndpointIsNewRelic(forwardEndpoint ?? undefined)) {
52
+ return null;
53
+ }
54
+ const exporters = (env.OTEL_METRICS_EXPORTER ?? '').split(',').map((e) => e.trim());
55
+ if (parseEnvBool(env.CLAUDE_CODE_ENABLE_TELEMETRY) !== true || !exporters.includes('otlp')) {
56
+ return null;
57
+ }
58
+ const protocol = env.OTEL_EXPORTER_OTLP_METRICS_PROTOCOL || env.OTEL_EXPORTER_OTLP_PROTOCOL;
59
+ const grpc = protocol === 'grpc';
60
+ const endpoint = env.OTEL_EXPORTER_OTLP_METRICS_ENDPOINT ||
61
+ env.OTEL_EXPORTER_OTLP_ENDPOINT ||
62
+ (grpc ? SDK_DEFAULT_OTLP_GRPC_ENDPOINT : SDK_DEFAULT_OTLP_HTTP_ENDPOINT);
63
+ try {
64
+ const url = new URL(endpoint.includes('://') ? endpoint : `http://${endpoint}`);
65
+ const port = Number(url.port || (url.protocol === 'https:' ? 443 : 80));
66
+ if (port !== receiverPort || !reachesReceiverHost(url.hostname, receiverBindAddress)) {
67
+ return null;
68
+ }
69
+ }
70
+ catch {
71
+ return null;
72
+ }
73
+ return { grpc };
74
+ }
25
75
  /**
26
76
  * Companion mode only prevents double-counting when Claude Code's own OTel
27
77
  * metrics also land in New Relic. Detection requires an nr-data.net endpoint:
@@ -59,6 +109,9 @@ const DEFAULT_RETAIN_SESSIONS_DAYS = 90;
59
109
  * rather than a breaking rename — so this has never moved past 1.
60
110
  */
61
111
  const CURRENT_CONFIG_VERSION = 1;
112
+ // argv array only: a single string would invite shell-style quoting that
113
+ // Preflight never interprets, since the command runs without a shell.
114
+ export const SecretCommandSchema = z.array(z.string().min(1)).min(1);
62
115
  export const ConfigFileSchema = z
63
116
  .object({
64
117
  configVersion: z.number().int().optional(),
@@ -77,6 +130,7 @@ export const ConfigFileSchema = z
77
130
  recordContent: z.boolean().optional(),
78
131
  pricingRefresh: z.boolean().optional(),
79
132
  companionMode: z.boolean().optional(),
133
+ allowHeadlessInstall: z.boolean().optional(),
80
134
  storagePath: z.string().optional(),
81
135
  hookBufferPath: z.string().optional(),
82
136
  harvestEventsMs: z.number().optional(),
@@ -94,6 +148,9 @@ export const ConfigFileSchema = z
94
148
  // generic union-mismatch issue.
95
149
  tiers: z.array(z.unknown()).optional(),
96
150
  nrApiKey: z.string().nullable().optional(),
151
+ licenseKeyCommand: SecretCommandSchema.optional(),
152
+ nrApiKeyCommand: SecretCommandSchema.optional(),
153
+ digestWebhookUrlCommand: SecretCommandSchema.optional(),
97
154
  customPricingFile: z.string().nullable().optional(),
98
155
  costRateMultiplier: z.number().nullable().optional(),
99
156
  dataResidencyPremium: z.boolean().optional(),
@@ -494,7 +551,40 @@ export class MissingCloudCredentialError extends Error {
494
551
  this.mode = mode;
495
552
  }
496
553
  }
497
- export function loadMcpConfig(cliOptions) {
554
+ /**
555
+ * A `SecretCommandError` raised while resolving a secret that cloud export
556
+ * needs. It keeps the helper's own message for stdio users and adds the mode
557
+ * the config asked for, so `--local` can tell a failing helper from a missing
558
+ * credential and still fall back to local mode.
559
+ */
560
+ export class CloudSecretCommandError extends SecretCommandError {
561
+ mode;
562
+ constructor(original, mode) {
563
+ super(original.field, original.failure);
564
+ this.message = original.message;
565
+ this.cause = original;
566
+ this.mode = mode;
567
+ }
568
+ }
569
+ /**
570
+ * The startup-resolved digest webhook URL when a source that outranks the
571
+ * file's `digestWebhookUrl` (env var or digestWebhookUrlCommand) supplied it.
572
+ * Undefined means "read the file at send time".
573
+ */
574
+ export function digestWebhookUrlOverride(config) {
575
+ return digestWebhookUrlOverrideSource(config)
576
+ ? (config.digestWebhookUrl ?? undefined)
577
+ : undefined;
578
+ }
579
+ /** Which source is overriding the file's `digestWebhookUrl`, if any. */
580
+ export function digestWebhookUrlOverrideSource(config) {
581
+ const source = config.secretSources.digestWebhookUrl;
582
+ return (source === 'env' || source === 'command') && config.digestWebhookUrl !== null
583
+ ? source
584
+ : undefined;
585
+ }
586
+ export function loadMcpConfig(cliOptions, loadOptions = {}) {
587
+ const skipCommand = loadOptions.resolveSecrets === false;
498
588
  const configFilePath = cliOptions?.config ?? resolve(DEFAULT_STORAGE_PATH, 'config.json');
499
589
  const file = loadConfigFile(configFilePath);
500
590
  // Warn (don't crash) when the user's config file contains keys we don't
@@ -578,11 +668,17 @@ export function loadMcpConfig(cliOptions) {
578
668
  });
579
669
  }
580
670
  }
581
- // --- licenseKey: CLI has no flag for this, so env > file ---
582
- // Hoisted ahead of mode resolution: an ambiguous licenseKey-without-mode
583
- // config must fail closed instead of silently defaulting to 'cloud'.
584
- const licenseKeyRaw = process.env.NEW_RELIC_LICENSE_KEY ??
585
- (typeof file.licenseKey === 'string' ? file.licenseKey : undefined);
671
+ // --- licenseKey: CLI has no flag for this, so env > licenseKeyCommand > file ---
672
+ // Presence is checked ahead of mode resolution: an ambiguous
673
+ // licenseKey-without-mode config must fail closed instead of silently
674
+ // defaulting to 'cloud'. The command itself runs only after mode resolves,
675
+ // so a local-mode process never runs it.
676
+ const licenseKeySources = {
677
+ env: process.env.NEW_RELIC_LICENSE_KEY,
678
+ command: file.licenseKeyCommand,
679
+ file: typeof file.licenseKey === 'string' ? file.licenseKey : undefined,
680
+ };
681
+ const licenseKeyConfigured = isSecretConfigured(licenseKeySources);
586
682
  // --- Resolve mode early so we can gate licenseKey/accountId requirements ---
587
683
  // File mode is already validated by the zod schema in loadConfigFile.
588
684
  const isValidMode = (v) => v !== undefined && VALID_MODES.includes(v);
@@ -598,7 +694,7 @@ export function loadMcpConfig(cliOptions) {
598
694
  else if (fileMode !== undefined) {
599
695
  mode = fileMode;
600
696
  }
601
- else if (licenseKeyRaw) {
697
+ else if (licenseKeyConfigured) {
602
698
  // Local-first default (README): telemetry export is opt-in, so a config
603
699
  // with credentials but no explicit mode must not silently export.
604
700
  throw new Error('Config has a licenseKey but no explicit mode. Telemetry export is opt-in: set "mode": "cloud" (or "both") in the config file, set NR_AI_MODE, or remove the credentials for local-only use. Previous versions implicitly defaulted to cloud.');
@@ -606,7 +702,19 @@ export function loadMcpConfig(cliOptions) {
606
702
  else {
607
703
  mode = 'local';
608
704
  }
609
- if (mode !== 'local' && !licenseKeyRaw) {
705
+ let licenseKeySecret;
706
+ try {
707
+ licenseKeySecret = resolveSecret('licenseKey', mode === 'local' ? { ...licenseKeySources, command: undefined } : licenseKeySources, { skipCommand });
708
+ }
709
+ catch (err) {
710
+ if (err instanceof SecretCommandError)
711
+ throw new CloudSecretCommandError(err, mode);
712
+ throw err;
713
+ }
714
+ const licenseKeyRaw = licenseKeySecret.value;
715
+ if (mode !== 'local' &&
716
+ !licenseKeyRaw &&
717
+ !(skipCommand && licenseKeySecret.source === 'command')) {
610
718
  throw new MissingCloudCredentialError('licenseKey', mode, configFilePath);
611
719
  }
612
720
  // Reject the literal string "null" — it's truthy but not a valid key
@@ -617,8 +725,8 @@ export function loadMcpConfig(cliOptions) {
617
725
  }
618
726
  // In local mode, undefined if licenseKey is missing (NR transport won't be used)
619
727
  const licenseKey = licenseKeyRaw;
620
- // --- accountId: env > file ---
621
- const accountIdRaw = process.env.NEW_RELIC_ACCOUNT_ID ??
728
+ // --- accountId: env > file; a blank env var counts as unset, as for the secrets ---
729
+ const accountIdRaw = (process.env.NEW_RELIC_ACCOUNT_ID?.trim() ? process.env.NEW_RELIC_ACCOUNT_ID : undefined) ??
622
730
  (typeof file.accountId === 'string' ? file.accountId : undefined);
623
731
  if (mode !== 'local' && !accountIdRaw) {
624
732
  throw new MissingCloudCredentialError('accountId', mode, configFilePath);
@@ -632,9 +740,7 @@ export function loadMcpConfig(cliOptions) {
632
740
  // --- tiers: config file only (no env var / CLI flag equivalent exists) ---
633
741
  // Fail closed on tiers-under-local BEFORE validating tier shape, so the
634
742
  // mode conflict is always the reported error even for a malformed array.
635
- const rawTiers = Array.isArray(file.tiers)
636
- ? file.tiers
637
- : undefined;
743
+ const rawTiers = Array.isArray(file.tiers) && !loadOptions.ignoreTiers ? file.tiers : undefined;
638
744
  let resolvedTiers;
639
745
  if (rawTiers !== undefined) {
640
746
  if (mode === 'local') {
@@ -642,7 +748,24 @@ export function loadMcpConfig(cliOptions) {
642
748
  'Multi-tier telemetry routing fans out the cloud export path, so it requires ' +
643
749
  "mode='cloud' or mode='both'. Remove the tiers array for local-only use, or set the mode.");
644
750
  }
645
- resolvedTiers = validateTiers(rawTiers);
751
+ try {
752
+ resolvedTiers = validateTiers(rawTiers, {
753
+ resolveLicenseKey: skipCommand
754
+ ? undefined
755
+ : (tier, argv) => resolveSecretCommand('licenseKey', argv, undefined, tier),
756
+ });
757
+ }
758
+ catch (err) {
759
+ if (err instanceof SecretCommandError)
760
+ throw new CloudSecretCommandError(err, mode);
761
+ throw err;
762
+ }
763
+ // A tier whose key was never read has no usable destination, so none are
764
+ // reported; the caller asked not to run helpers.
765
+ if (skipCommand &&
766
+ resolvedTiers.some((t) => t.destination.type === 'nr' && t.destination.licenseKey === '')) {
767
+ resolvedTiers = [];
768
+ }
646
769
  }
647
770
  else if (mode !== 'local' && licenseKey !== undefined && accountId !== undefined) {
648
771
  // Implicit single tier — byte-identical to the existing single-tier default.
@@ -662,8 +785,9 @@ export function loadMcpConfig(cliOptions) {
662
785
  (typeof file.storagePath === 'string' ? file.storagePath : DEFAULT_STORAGE_PATH);
663
786
  // highSecurity must be resolved before recordContent so it can override it
664
787
  const highSecurity = envBool('NEW_RELIC_AI_HIGH_SECURITY', typeof file.highSecurity === 'boolean' ? file.highSecurity : false);
665
- const resolvedProjectId = sanitizeOrgField(process.env.NEW_RELIC_AI_PROJECT_ID ??
666
- (typeof file.projectId === 'string' ? file.projectId : inferProjectId()));
788
+ const rawProjectId = process.env.NEW_RELIC_AI_PROJECT_ID ??
789
+ (typeof file.projectId === 'string' ? file.projectId : inferProjectId());
790
+ const resolvedProjectId = sanitizeOrgField(rawProjectId === null ? null : redactIdentifier(rawProjectId));
667
791
  // Dedicated opt-out, independent of projectId's — repo_url can carry an
668
792
  // internal git host that org/repo alone doesn't, so it gets its own toggle
669
793
  // rather than riding along on projectId's. Defaults on; the setup wizard
@@ -677,17 +801,32 @@ export function loadMcpConfig(cliOptions) {
677
801
  const rawRepoUrl = process.env.NEW_RELIC_AI_REPO_URL ??
678
802
  (typeof file.repoUrl === 'string' ? file.repoUrl : getGitRemoteUrl());
679
803
  // stripRemoteCredentials drops URL userinfo and query strings;
680
- // redactSensitive then catches any token elsewhere in the value.
804
+ // redactIdentifier then catches any token elsewhere in the value.
681
805
  const strippedRepoUrl = stripRemoteCredentials(rawRepoUrl);
682
- const resolvedRepoUrl = sanitizeOrgField(strippedRepoUrl === null ? null : redactSensitive(strippedRepoUrl));
806
+ const resolvedRepoUrl = sanitizeOrgField(strippedRepoUrl === null ? null : redactIdentifier(strippedRepoUrl));
683
807
  const resolvedCompanionMode = resolveCompanionMode(process.env, typeof file.companionMode === 'boolean' ? file.companionMode : undefined);
684
808
  logger.info('Companion mode resolved', {
685
809
  value: resolvedCompanionMode.value,
686
810
  source: resolvedCompanionMode.source,
687
811
  });
812
+ const nrApiKeySecret = resolveSecret('nrApiKey', {
813
+ env: process.env.NEW_RELIC_API_KEY,
814
+ command: mode === 'local' ? undefined : file.nrApiKeyCommand,
815
+ file: typeof file.nrApiKey === 'string' ? file.nrApiKey : undefined,
816
+ }, { optional: true, skipCommand });
817
+ const digestWebhookUrlSecret = resolveSecret('digestWebhookUrl', {
818
+ env: process.env.NEW_RELIC_AI_DIGEST_WEBHOOK_URL,
819
+ command: file.digestWebhookUrlCommand,
820
+ file: typeof file.digestWebhookUrl === 'string' ? file.digestWebhookUrl : undefined,
821
+ }, { optional: true, skipCommand });
688
822
  const config = {
689
823
  licenseKey,
690
824
  accountId,
825
+ secretSources: {
826
+ licenseKey: licenseKeySecret.source,
827
+ nrApiKey: nrApiKeySecret.source,
828
+ digestWebhookUrl: digestWebhookUrlSecret.source,
829
+ },
691
830
  configVersion: typeof file.configVersion === 'number' ? file.configVersion : CURRENT_CONFIG_VERSION,
692
831
  appName: process.env.NEW_RELIC_AI_MCP_APP_NAME ??
693
832
  (typeof file.appName === 'string' ? file.appName : 'preflight'),
@@ -707,6 +846,10 @@ export function loadMcpConfig(cliOptions) {
707
846
  ? false
708
847
  : envBool('NEW_RELIC_AI_PRICING_REFRESH', typeof file.pricingRefresh === 'boolean' ? file.pricingRefresh : true),
709
848
  companionMode: resolvedCompanionMode.value,
849
+ companionModeSource: resolvedCompanionMode.source,
850
+ allowHeadlessInstall: highSecurity
851
+ ? false
852
+ : envBool('NEW_RELIC_AI_ALLOW_HEADLESS_INSTALL', typeof file.allowHeadlessInstall === 'boolean' ? file.allowHeadlessInstall : false),
710
853
  redactionPatterns: DEFAULT_REDACTION_PATTERNS,
711
854
  hookBufferPath: process.env.NEW_RELIC_AI_MCP_BUFFER_PATH ??
712
855
  (typeof file.hookBufferPath === 'string'
@@ -772,7 +915,7 @@ export function loadMcpConfig(cliOptions) {
772
915
  collectorHost: resolveCollectorHost(licenseKey, process.env.NEW_RELIC_HOST ??
773
916
  (typeof file.collectorHost === 'string' ? file.collectorHost : null)),
774
917
  proxyUpstreams: parseProxyUpstreams(process.env.NEW_RELIC_AI_MCP_PROXY_UPSTREAMS, file.proxyUpstreams),
775
- nrApiKey: process.env.NEW_RELIC_API_KEY ?? (typeof file.nrApiKey === 'string' ? file.nrApiKey : null),
918
+ nrApiKey: nrApiKeySecret.value ?? null,
776
919
  customPricingFile: process.env.NEW_RELIC_AI_CUSTOM_PRICING_FILE ??
777
920
  (typeof file.customPricingFile === 'string' ? file.customPricingFile : null),
778
921
  costRateMultiplier: (() => {
@@ -789,8 +932,7 @@ export function loadMcpConfig(cliOptions) {
789
932
  : null;
790
933
  })(),
791
934
  dataResidencyPremium: envBool('NEW_RELIC_AI_DATA_RESIDENCY_PREMIUM', typeof file.dataResidencyPremium === 'boolean' ? file.dataResidencyPremium : false),
792
- digestWebhookUrl: process.env.NEW_RELIC_AI_DIGEST_WEBHOOK_URL ??
793
- (typeof file.digestWebhookUrl === 'string' ? file.digestWebhookUrl : null),
935
+ digestWebhookUrl: digestWebhookUrlSecret.value ?? null,
794
936
  digestSchedule: process.env.NEW_RELIC_AI_DIGEST_SCHEDULE ??
795
937
  (typeof file.digestSchedule === 'string' ? file.digestSchedule : '0 9 * * 1'),
796
938
  retainSessionsDays: (() => {
@@ -1177,7 +1319,8 @@ export function validateConfigFile(filePath) {
1177
1319
  mode: typeof file.mode === 'string' ? file.mode : undefined,
1178
1320
  storagePath: typeof file.storagePath === 'string' ? file.storagePath : undefined,
1179
1321
  companionMode: typeof file.companionMode === 'boolean' ? file.companionMode : undefined,
1180
- hasLicenseKey: typeof file.licenseKey === 'string' && file.licenseKey.trim().length > 0,
1322
+ hasLicenseKey: (typeof file.licenseKey === 'string' && file.licenseKey.trim().length > 0) ||
1323
+ Array.isArray(file.licenseKeyCommand),
1181
1324
  errors,
1182
1325
  warnings,
1183
1326
  };
@@ -1224,4 +1367,40 @@ export function redactSensitive(value, patterns) {
1224
1367
  }
1225
1368
  return result;
1226
1369
  }
1370
+ const WORD_CHAR_RE = /[A-Za-z0-9]/;
1371
+ /**
1372
+ * redactSensitive() for identifiers (project_id, repo_url, repo names), which
1373
+ * carry a token only as a whole path segment or a segment's prefix. A match that
1374
+ * starts right after a letter or digit is part of an ordinary name
1375
+ * (`acme/risk-assessment-…` holds `sk-assessment-…`) and is left alone. The scan
1376
+ * resumes one character later, so a token further into that span
1377
+ * (`acme/risk-ghp_…`) is still caught.
1378
+ *
1379
+ * Free-form content keeps redactSensitive()'s plain matching: there a token
1380
+ * routinely follows a letter or digit, after a JSON escape (`\nghp_…`), an ANSI
1381
+ * colour code (`ESC[32m`) or `%3A`.
1382
+ */
1383
+ export function redactIdentifier(value) {
1384
+ let result = value;
1385
+ for (const pattern of DEFAULT_REDACTION_PATTERNS) {
1386
+ const re = new RegExp(pattern.source, pattern.flags.includes('g') ? pattern.flags : `${pattern.flags}g`);
1387
+ let out = '';
1388
+ let last = 0;
1389
+ let match;
1390
+ while ((match = re.exec(result)) !== null) {
1391
+ if (match[0] === '') {
1392
+ re.lastIndex++;
1393
+ continue;
1394
+ }
1395
+ if (match.index > 0 && WORD_CHAR_RE.test(result[match.index - 1])) {
1396
+ re.lastIndex = match.index + 1;
1397
+ continue;
1398
+ }
1399
+ out += `${result.slice(last, match.index)}[REDACTED]`;
1400
+ last = re.lastIndex;
1401
+ }
1402
+ result = out + result.slice(last);
1403
+ }
1404
+ return result;
1405
+ }
1227
1406
  //# sourceMappingURL=config.js.map