@newrelic/preflight 0.0.1-pre.1 → 1.0.1

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 (578) hide show
  1. package/LICENSE +183 -0
  2. package/README.md +498 -0
  3. package/dist/alerts/alert-log.d.ts +24 -0
  4. package/dist/alerts/alert-log.d.ts.map +1 -0
  5. package/dist/alerts/alert-log.js +159 -0
  6. package/dist/alerts/alert-log.js.map +1 -0
  7. package/dist/alerts/alert-snapshot-collector.d.ts +168 -0
  8. package/dist/alerts/alert-snapshot-collector.d.ts.map +1 -0
  9. package/dist/alerts/alert-snapshot-collector.js +243 -0
  10. package/dist/alerts/alert-snapshot-collector.js.map +1 -0
  11. package/dist/alerts/local-alert-engine.d.ts +86 -0
  12. package/dist/alerts/local-alert-engine.d.ts.map +1 -0
  13. package/dist/alerts/local-alert-engine.js +466 -0
  14. package/dist/alerts/local-alert-engine.js.map +1 -0
  15. package/dist/alerts/local-alert-rule.d.ts +439 -0
  16. package/dist/alerts/local-alert-rule.d.ts.map +1 -0
  17. package/dist/alerts/local-alert-rule.js +139 -0
  18. package/dist/alerts/local-alert-rule.js.map +1 -0
  19. package/dist/alerts/os-notifier.d.ts +39 -0
  20. package/dist/alerts/os-notifier.d.ts.map +1 -0
  21. package/dist/alerts/os-notifier.js +170 -0
  22. package/dist/alerts/os-notifier.js.map +1 -0
  23. package/dist/alerts/types.d.ts +35 -0
  24. package/dist/alerts/types.d.ts.map +1 -0
  25. package/dist/alerts/types.js +8 -0
  26. package/dist/alerts/types.js.map +1 -0
  27. package/dist/config.d.ts +169 -0
  28. package/dist/config.d.ts.map +1 -0
  29. package/dist/config.js +868 -0
  30. package/dist/config.js.map +1 -0
  31. package/dist/dashboard/dashboard-server.d.ts +38 -0
  32. package/dist/dashboard/dashboard-server.d.ts.map +1 -0
  33. package/dist/dashboard/dashboard-server.js +207 -0
  34. package/dist/dashboard/dashboard-server.js.map +1 -0
  35. package/dist/dashboard/index.d.ts +3 -0
  36. package/dist/dashboard/index.d.ts.map +1 -0
  37. package/dist/dashboard/index.js +2 -0
  38. package/dist/dashboard/index.js.map +1 -0
  39. package/dist/dashboard/live-event-bus.d.ts +99 -0
  40. package/dist/dashboard/live-event-bus.d.ts.map +1 -0
  41. package/dist/dashboard/live-event-bus.js +56 -0
  42. package/dist/dashboard/live-event-bus.js.map +1 -0
  43. package/dist/dashboard/routes/api-handler.d.ts +122 -0
  44. package/dist/dashboard/routes/api-handler.d.ts.map +1 -0
  45. package/dist/dashboard/routes/api-handler.js +1414 -0
  46. package/dist/dashboard/routes/api-handler.js.map +1 -0
  47. package/dist/dashboard/routes/replay-analyzer.d.ts +15 -0
  48. package/dist/dashboard/routes/replay-analyzer.d.ts.map +1 -0
  49. package/dist/dashboard/routes/replay-analyzer.js +227 -0
  50. package/dist/dashboard/routes/replay-analyzer.js.map +1 -0
  51. package/dist/dashboard/routes/sse-handler.d.ts +4 -0
  52. package/dist/dashboard/routes/sse-handler.d.ts.map +1 -0
  53. package/dist/dashboard/routes/sse-handler.js +122 -0
  54. package/dist/dashboard/routes/sse-handler.js.map +1 -0
  55. package/dist/dashboard/routes/static-handler.d.ts +3 -0
  56. package/dist/dashboard/routes/static-handler.d.ts.map +1 -0
  57. package/dist/dashboard/routes/static-handler.js +123 -0
  58. package/dist/dashboard/routes/static-handler.js.map +1 -0
  59. package/dist/data/alerts/conditions/01-daily-cost-spike.json +16 -0
  60. package/dist/data/alerts/conditions/02-low-efficiency-score.json +16 -0
  61. package/dist/data/alerts/conditions/03-stuck-loop-rate.json +16 -0
  62. package/dist/data/alerts/conditions/04-anti-pattern-rate.json +16 -0
  63. package/dist/data/alerts/conditions/05-session-cost-budget.json +16 -0
  64. package/dist/data/alerts/conditions-personal/01-personal-daily-cost.json +16 -0
  65. package/dist/data/alerts/conditions-personal/02-personal-session-cost.json +16 -0
  66. package/dist/data/alerts/conditions-personal/03-personal-low-efficiency.json +16 -0
  67. package/dist/data/alerts/conditions-personal/04-personal-anti-pattern-rate.json +16 -0
  68. package/dist/data/alerts/conditions-personal/05-personal-stuck-loop.json +16 -0
  69. package/dist/data/alerts/policy.json +4 -0
  70. package/dist/data/dashboards/ai-coding-assistant-manager-view.json +103 -0
  71. package/dist/data/dashboards/ai-coding-assistant-overview.json +239 -0
  72. package/dist/data/dashboards/ai-coding-assistant-personal.json +442 -0
  73. package/dist/data/dashboards/ai-coding-assistant-platform-comparison.json +320 -0
  74. package/dist/data/dashboards/ai-coding-assistant-security.json +275 -0
  75. package/dist/data/dashboards/ai-coding-assistant-session-detail.json +296 -0
  76. package/dist/data/dashboards/ai-coding-assistant-team-view.json +345 -0
  77. package/dist/deploy/data-paths.d.ts +22 -0
  78. package/dist/deploy/data-paths.d.ts.map +1 -0
  79. package/dist/deploy/data-paths.js +69 -0
  80. package/dist/deploy/data-paths.js.map +1 -0
  81. package/dist/deploy/deploy-alerts.d.ts +58 -0
  82. package/dist/deploy/deploy-alerts.d.ts.map +1 -0
  83. package/dist/deploy/deploy-alerts.js +371 -0
  84. package/dist/deploy/deploy-alerts.js.map +1 -0
  85. package/dist/deploy/deploy-dashboards.d.ts +92 -0
  86. package/dist/deploy/deploy-dashboards.d.ts.map +1 -0
  87. package/dist/deploy/deploy-dashboards.js +282 -0
  88. package/dist/deploy/deploy-dashboards.js.map +1 -0
  89. package/dist/digest/digest-formatter.d.ts +3 -0
  90. package/dist/digest/digest-formatter.d.ts.map +1 -0
  91. package/dist/digest/digest-formatter.js +37 -0
  92. package/dist/digest/digest-formatter.js.map +1 -0
  93. package/dist/digest/digest-sender.d.ts +2 -0
  94. package/dist/digest/digest-sender.d.ts.map +1 -0
  95. package/dist/digest/digest-sender.js +29 -0
  96. package/dist/digest/digest-sender.js.map +1 -0
  97. package/dist/hooks/bash-classifier.d.ts +26 -0
  98. package/dist/hooks/bash-classifier.d.ts.map +1 -0
  99. package/dist/hooks/bash-classifier.js +409 -0
  100. package/dist/hooks/bash-classifier.js.map +1 -0
  101. package/dist/hooks/collector-script.d.ts +47 -0
  102. package/dist/hooks/collector-script.d.ts.map +1 -0
  103. package/dist/hooks/collector-script.js +662 -0
  104. package/dist/hooks/collector-script.js.map +1 -0
  105. package/dist/hooks/event-processor.d.ts +65 -0
  106. package/dist/hooks/event-processor.d.ts.map +1 -0
  107. package/dist/hooks/event-processor.js +342 -0
  108. package/dist/hooks/event-processor.js.map +1 -0
  109. package/dist/hooks/index.d.ts +7 -0
  110. package/dist/hooks/index.d.ts.map +1 -0
  111. package/dist/hooks/index.js +5 -0
  112. package/dist/hooks/index.js.map +1 -0
  113. package/dist/hooks/session-resolver.d.ts +66 -0
  114. package/dist/hooks/session-resolver.d.ts.map +1 -0
  115. package/dist/hooks/session-resolver.js +196 -0
  116. package/dist/hooks/session-resolver.js.map +1 -0
  117. package/dist/hooks/tool-parsers.d.ts +19 -0
  118. package/dist/hooks/tool-parsers.d.ts.map +1 -0
  119. package/dist/hooks/tool-parsers.js +260 -0
  120. package/dist/hooks/tool-parsers.js.map +1 -0
  121. package/dist/index.d.ts +107 -0
  122. package/dist/index.d.ts.map +1 -0
  123. package/dist/index.js +1505 -0
  124. package/dist/index.js.map +1 -0
  125. package/dist/install/cli.d.ts +11 -0
  126. package/dist/install/cli.d.ts.map +1 -0
  127. package/dist/install/cli.js +365 -0
  128. package/dist/install/cli.js.map +1 -0
  129. package/dist/install/index.d.ts +4 -0
  130. package/dist/install/index.d.ts.map +1 -0
  131. package/dist/install/index.js +3 -0
  132. package/dist/install/index.js.map +1 -0
  133. package/dist/install/install-helper.d.ts +35 -0
  134. package/dist/install/install-helper.d.ts.map +1 -0
  135. package/dist/install/install-helper.js +227 -0
  136. package/dist/install/install-helper.js.map +1 -0
  137. package/dist/install/key-validator.d.ts +19 -0
  138. package/dist/install/key-validator.d.ts.map +1 -0
  139. package/dist/install/key-validator.js +122 -0
  140. package/dist/install/key-validator.js.map +1 -0
  141. package/dist/install/migrate.d.ts +12 -0
  142. package/dist/install/migrate.d.ts.map +1 -0
  143. package/dist/install/migrate.js +115 -0
  144. package/dist/install/migrate.js.map +1 -0
  145. package/dist/install/schedule.d.ts +11 -0
  146. package/dist/install/schedule.d.ts.map +1 -0
  147. package/dist/install/schedule.js +114 -0
  148. package/dist/install/schedule.js.map +1 -0
  149. package/dist/install/setup-wizard.d.ts +40 -0
  150. package/dist/install/setup-wizard.d.ts.map +1 -0
  151. package/dist/install/setup-wizard.js +489 -0
  152. package/dist/install/setup-wizard.js.map +1 -0
  153. package/dist/lib/date.d.ts +54 -0
  154. package/dist/lib/date.d.ts.map +1 -0
  155. package/dist/lib/date.js +85 -0
  156. package/dist/lib/date.js.map +1 -0
  157. package/dist/metrics/anti-patterns.d.ts +62 -0
  158. package/dist/metrics/anti-patterns.d.ts.map +1 -0
  159. package/dist/metrics/anti-patterns.js +301 -0
  160. package/dist/metrics/anti-patterns.js.map +1 -0
  161. package/dist/metrics/api-failure-tracker.d.ts +82 -0
  162. package/dist/metrics/api-failure-tracker.d.ts.map +1 -0
  163. package/dist/metrics/api-failure-tracker.js +202 -0
  164. package/dist/metrics/api-failure-tracker.js.map +1 -0
  165. package/dist/metrics/budget-tracker.d.ts +60 -0
  166. package/dist/metrics/budget-tracker.d.ts.map +1 -0
  167. package/dist/metrics/budget-tracker.js +130 -0
  168. package/dist/metrics/budget-tracker.js.map +1 -0
  169. package/dist/metrics/claudemd-tracker.d.ts +108 -0
  170. package/dist/metrics/claudemd-tracker.d.ts.map +1 -0
  171. package/dist/metrics/claudemd-tracker.js +337 -0
  172. package/dist/metrics/claudemd-tracker.js.map +1 -0
  173. package/dist/metrics/collaboration-profile.d.ts +65 -0
  174. package/dist/metrics/collaboration-profile.d.ts.map +1 -0
  175. package/dist/metrics/collaboration-profile.js +231 -0
  176. package/dist/metrics/collaboration-profile.js.map +1 -0
  177. package/dist/metrics/context-composition-tracker.d.ts +74 -0
  178. package/dist/metrics/context-composition-tracker.d.ts.map +1 -0
  179. package/dist/metrics/context-composition-tracker.js +202 -0
  180. package/dist/metrics/context-composition-tracker.js.map +1 -0
  181. package/dist/metrics/context-tracker.d.ts +78 -0
  182. package/dist/metrics/context-tracker.d.ts.map +1 -0
  183. package/dist/metrics/context-tracker.js +222 -0
  184. package/dist/metrics/context-tracker.js.map +1 -0
  185. package/dist/metrics/context-window-tracker.d.ts +18 -0
  186. package/dist/metrics/context-window-tracker.d.ts.map +1 -0
  187. package/dist/metrics/context-window-tracker.js +35 -0
  188. package/dist/metrics/context-window-tracker.js.map +1 -0
  189. package/dist/metrics/cost-forecast.d.ts +36 -0
  190. package/dist/metrics/cost-forecast.d.ts.map +1 -0
  191. package/dist/metrics/cost-forecast.js +91 -0
  192. package/dist/metrics/cost-forecast.js.map +1 -0
  193. package/dist/metrics/cost-per-outcome.d.ts +102 -0
  194. package/dist/metrics/cost-per-outcome.d.ts.map +1 -0
  195. package/dist/metrics/cost-per-outcome.js +266 -0
  196. package/dist/metrics/cost-per-outcome.js.map +1 -0
  197. package/dist/metrics/cost-tracker.d.ts +78 -0
  198. package/dist/metrics/cost-tracker.d.ts.map +1 -0
  199. package/dist/metrics/cost-tracker.js +169 -0
  200. package/dist/metrics/cost-tracker.js.map +1 -0
  201. package/dist/metrics/decision-tracker.d.ts +49 -0
  202. package/dist/metrics/decision-tracker.d.ts.map +1 -0
  203. package/dist/metrics/decision-tracker.js +161 -0
  204. package/dist/metrics/decision-tracker.js.map +1 -0
  205. package/dist/metrics/efficiency-score.d.ts +80 -0
  206. package/dist/metrics/efficiency-score.d.ts.map +1 -0
  207. package/dist/metrics/efficiency-score.js +219 -0
  208. package/dist/metrics/efficiency-score.js.map +1 -0
  209. package/dist/metrics/git-efficiency-tracker.d.ts +165 -0
  210. package/dist/metrics/git-efficiency-tracker.d.ts.map +1 -0
  211. package/dist/metrics/git-efficiency-tracker.js +1056 -0
  212. package/dist/metrics/git-efficiency-tracker.js.map +1 -0
  213. package/dist/metrics/index.d.ts +26 -0
  214. package/dist/metrics/index.d.ts.map +1 -0
  215. package/dist/metrics/index.js +14 -0
  216. package/dist/metrics/index.js.map +1 -0
  217. package/dist/metrics/instruction-drift-tracker.d.ts +69 -0
  218. package/dist/metrics/instruction-drift-tracker.d.ts.map +1 -0
  219. package/dist/metrics/instruction-drift-tracker.js +213 -0
  220. package/dist/metrics/instruction-drift-tracker.js.map +1 -0
  221. package/dist/metrics/latency-decomposition.d.ts +50 -0
  222. package/dist/metrics/latency-decomposition.d.ts.map +1 -0
  223. package/dist/metrics/latency-decomposition.js +112 -0
  224. package/dist/metrics/latency-decomposition.js.map +1 -0
  225. package/dist/metrics/latency-tracker.d.ts +33 -0
  226. package/dist/metrics/latency-tracker.d.ts.map +1 -0
  227. package/dist/metrics/latency-tracker.js +93 -0
  228. package/dist/metrics/latency-tracker.js.map +1 -0
  229. package/dist/metrics/live-session-registry.d.ts +29 -0
  230. package/dist/metrics/live-session-registry.d.ts.map +1 -0
  231. package/dist/metrics/live-session-registry.js +103 -0
  232. package/dist/metrics/live-session-registry.js.map +1 -0
  233. package/dist/metrics/model-usage-tracker.d.ts +21 -0
  234. package/dist/metrics/model-usage-tracker.d.ts.map +1 -0
  235. package/dist/metrics/model-usage-tracker.js +53 -0
  236. package/dist/metrics/model-usage-tracker.js.map +1 -0
  237. package/dist/metrics/percentile.d.ts +5 -0
  238. package/dist/metrics/percentile.d.ts.map +1 -0
  239. package/dist/metrics/percentile.js +10 -0
  240. package/dist/metrics/percentile.js.map +1 -0
  241. package/dist/metrics/personal-coach.d.ts +47 -0
  242. package/dist/metrics/personal-coach.d.ts.map +1 -0
  243. package/dist/metrics/personal-coach.js +241 -0
  244. package/dist/metrics/personal-coach.js.map +1 -0
  245. package/dist/metrics/prompt-feedback.d.ts +75 -0
  246. package/dist/metrics/prompt-feedback.d.ts.map +1 -0
  247. package/dist/metrics/prompt-feedback.js +286 -0
  248. package/dist/metrics/prompt-feedback.js.map +1 -0
  249. package/dist/metrics/proxy-metrics.d.ts +54 -0
  250. package/dist/metrics/proxy-metrics.d.ts.map +1 -0
  251. package/dist/metrics/proxy-metrics.js +228 -0
  252. package/dist/metrics/proxy-metrics.js.map +1 -0
  253. package/dist/metrics/quality-proxy-tracker.d.ts +51 -0
  254. package/dist/metrics/quality-proxy-tracker.d.ts.map +1 -0
  255. package/dist/metrics/quality-proxy-tracker.js +162 -0
  256. package/dist/metrics/quality-proxy-tracker.js.map +1 -0
  257. package/dist/metrics/recommendation-engine.d.ts +72 -0
  258. package/dist/metrics/recommendation-engine.d.ts.map +1 -0
  259. package/dist/metrics/recommendation-engine.js +207 -0
  260. package/dist/metrics/recommendation-engine.js.map +1 -0
  261. package/dist/metrics/retry-detector.d.ts +43 -0
  262. package/dist/metrics/retry-detector.d.ts.map +1 -0
  263. package/dist/metrics/retry-detector.js +179 -0
  264. package/dist/metrics/retry-detector.js.map +1 -0
  265. package/dist/metrics/session-tracker.d.ts +75 -0
  266. package/dist/metrics/session-tracker.d.ts.map +1 -0
  267. package/dist/metrics/session-tracker.js +249 -0
  268. package/dist/metrics/session-tracker.js.map +1 -0
  269. package/dist/metrics/task-completion-tracker.d.ts +15 -0
  270. package/dist/metrics/task-completion-tracker.d.ts.map +1 -0
  271. package/dist/metrics/task-completion-tracker.js +27 -0
  272. package/dist/metrics/task-completion-tracker.js.map +1 -0
  273. package/dist/metrics/task-detector.d.ts +84 -0
  274. package/dist/metrics/task-detector.d.ts.map +1 -0
  275. package/dist/metrics/task-detector.js +302 -0
  276. package/dist/metrics/task-detector.js.map +1 -0
  277. package/dist/metrics/tool-selection-scorer.d.ts +39 -0
  278. package/dist/metrics/tool-selection-scorer.d.ts.map +1 -0
  279. package/dist/metrics/tool-selection-scorer.js +193 -0
  280. package/dist/metrics/tool-selection-scorer.js.map +1 -0
  281. package/dist/metrics/trend-analyzer.d.ts +92 -0
  282. package/dist/metrics/trend-analyzer.d.ts.map +1 -0
  283. package/dist/metrics/trend-analyzer.js +293 -0
  284. package/dist/metrics/trend-analyzer.js.map +1 -0
  285. package/dist/metrics/turn-cost-attributor.d.ts +41 -0
  286. package/dist/metrics/turn-cost-attributor.d.ts.map +1 -0
  287. package/dist/metrics/turn-cost-attributor.js +118 -0
  288. package/dist/metrics/turn-cost-attributor.js.map +1 -0
  289. package/dist/metrics/turn-tracker.d.ts +49 -0
  290. package/dist/metrics/turn-tracker.d.ts.map +1 -0
  291. package/dist/metrics/turn-tracker.js +192 -0
  292. package/dist/metrics/turn-tracker.js.map +1 -0
  293. package/dist/platforms/amazon-q-adapter.d.ts +10 -0
  294. package/dist/platforms/amazon-q-adapter.d.ts.map +1 -0
  295. package/dist/platforms/amazon-q-adapter.js +75 -0
  296. package/dist/platforms/amazon-q-adapter.js.map +1 -0
  297. package/dist/platforms/claude-code-adapter.d.ts +10 -0
  298. package/dist/platforms/claude-code-adapter.d.ts.map +1 -0
  299. package/dist/platforms/claude-code-adapter.js +48 -0
  300. package/dist/platforms/claude-code-adapter.js.map +1 -0
  301. package/dist/platforms/continue-adapter.d.ts +10 -0
  302. package/dist/platforms/continue-adapter.d.ts.map +1 -0
  303. package/dist/platforms/continue-adapter.js +73 -0
  304. package/dist/platforms/continue-adapter.js.map +1 -0
  305. package/dist/platforms/copilot-adapter.d.ts +37 -0
  306. package/dist/platforms/copilot-adapter.d.ts.map +1 -0
  307. package/dist/platforms/copilot-adapter.js +66 -0
  308. package/dist/platforms/copilot-adapter.js.map +1 -0
  309. package/dist/platforms/cursor-adapter.d.ts +10 -0
  310. package/dist/platforms/cursor-adapter.d.ts.map +1 -0
  311. package/dist/platforms/cursor-adapter.js +60 -0
  312. package/dist/platforms/cursor-adapter.js.map +1 -0
  313. package/dist/platforms/generic-mcp-adapter.d.ts +113 -0
  314. package/dist/platforms/generic-mcp-adapter.d.ts.map +1 -0
  315. package/dist/platforms/generic-mcp-adapter.js +139 -0
  316. package/dist/platforms/generic-mcp-adapter.js.map +1 -0
  317. package/dist/platforms/index.d.ts +15 -0
  318. package/dist/platforms/index.d.ts.map +1 -0
  319. package/dist/platforms/index.js +12 -0
  320. package/dist/platforms/index.js.map +1 -0
  321. package/dist/platforms/platform-registry.d.ts +11 -0
  322. package/dist/platforms/platform-registry.d.ts.map +1 -0
  323. package/dist/platforms/platform-registry.js +54 -0
  324. package/dist/platforms/platform-registry.js.map +1 -0
  325. package/dist/platforms/types.d.ts +36 -0
  326. package/dist/platforms/types.d.ts.map +1 -0
  327. package/dist/platforms/types.js +2 -0
  328. package/dist/platforms/types.js.map +1 -0
  329. package/dist/platforms/windsurf-adapter.d.ts +10 -0
  330. package/dist/platforms/windsurf-adapter.d.ts.map +1 -0
  331. package/dist/platforms/windsurf-adapter.js +63 -0
  332. package/dist/platforms/windsurf-adapter.js.map +1 -0
  333. package/dist/platforms/zed-adapter.d.ts +10 -0
  334. package/dist/platforms/zed-adapter.d.ts.map +1 -0
  335. package/dist/platforms/zed-adapter.js +72 -0
  336. package/dist/platforms/zed-adapter.js.map +1 -0
  337. package/dist/proxy/index.d.ts +7 -0
  338. package/dist/proxy/index.d.ts.map +1 -0
  339. package/dist/proxy/index.js +5 -0
  340. package/dist/proxy/index.js.map +1 -0
  341. package/dist/proxy/otlp-receiver.d.ts +28 -0
  342. package/dist/proxy/otlp-receiver.d.ts.map +1 -0
  343. package/dist/proxy/otlp-receiver.js +319 -0
  344. package/dist/proxy/otlp-receiver.js.map +1 -0
  345. package/dist/proxy/proxy-manager.d.ts +47 -0
  346. package/dist/proxy/proxy-manager.d.ts.map +1 -0
  347. package/dist/proxy/proxy-manager.js +338 -0
  348. package/dist/proxy/proxy-manager.js.map +1 -0
  349. package/dist/proxy/types.d.ts +72 -0
  350. package/dist/proxy/types.d.ts.map +1 -0
  351. package/dist/proxy/types.js +33 -0
  352. package/dist/proxy/types.js.map +1 -0
  353. package/dist/proxy/upstream-http.d.ts +26 -0
  354. package/dist/proxy/upstream-http.d.ts.map +1 -0
  355. package/dist/proxy/upstream-http.js +209 -0
  356. package/dist/proxy/upstream-http.js.map +1 -0
  357. package/dist/proxy/upstream-stdio.d.ts +25 -0
  358. package/dist/proxy/upstream-stdio.d.ts.map +1 -0
  359. package/dist/proxy/upstream-stdio.js +256 -0
  360. package/dist/proxy/upstream-stdio.js.map +1 -0
  361. package/dist/security/audit-trail.d.ts +74 -0
  362. package/dist/security/audit-trail.d.ts.map +1 -0
  363. package/dist/security/audit-trail.js +338 -0
  364. package/dist/security/audit-trail.js.map +1 -0
  365. package/dist/security/index.d.ts +5 -0
  366. package/dist/security/index.d.ts.map +1 -0
  367. package/dist/security/index.js +4 -0
  368. package/dist/security/index.js.map +1 -0
  369. package/dist/security/ssrf.d.ts +2 -0
  370. package/dist/security/ssrf.d.ts.map +1 -0
  371. package/dist/security/ssrf.js +126 -0
  372. package/dist/security/ssrf.js.map +1 -0
  373. package/dist/server.d.ts +14 -0
  374. package/dist/server.d.ts.map +1 -0
  375. package/dist/server.js +117 -0
  376. package/dist/server.js.map +1 -0
  377. package/dist/shared/__test-utils__/log-output.d.ts +49 -0
  378. package/dist/shared/__test-utils__/log-output.d.ts.map +1 -0
  379. package/dist/shared/__test-utils__/log-output.js +38 -0
  380. package/dist/shared/__test-utils__/log-output.js.map +1 -0
  381. package/dist/shared/config.d.ts +56 -0
  382. package/dist/shared/config.d.ts.map +1 -0
  383. package/dist/shared/config.js +290 -0
  384. package/dist/shared/config.js.map +1 -0
  385. package/dist/shared/errors.d.ts +139 -0
  386. package/dist/shared/errors.d.ts.map +1 -0
  387. package/dist/shared/errors.js +406 -0
  388. package/dist/shared/errors.js.map +1 -0
  389. package/dist/shared/events/factory.d.ts +143 -0
  390. package/dist/shared/events/factory.d.ts.map +1 -0
  391. package/dist/shared/events/factory.js +351 -0
  392. package/dist/shared/events/factory.js.map +1 -0
  393. package/dist/shared/events/index.d.ts +6 -0
  394. package/dist/shared/events/index.d.ts.map +1 -0
  395. package/dist/shared/events/index.js +3 -0
  396. package/dist/shared/events/index.js.map +1 -0
  397. package/dist/shared/events/serialize.d.ts +87 -0
  398. package/dist/shared/events/serialize.d.ts.map +1 -0
  399. package/dist/shared/events/serialize.js +510 -0
  400. package/dist/shared/events/serialize.js.map +1 -0
  401. package/dist/shared/events/types.d.ts +139 -0
  402. package/dist/shared/events/types.d.ts.map +1 -0
  403. package/dist/shared/events/types.js +2 -0
  404. package/dist/shared/events/types.js.map +1 -0
  405. package/dist/shared/harvest/event-buffer.d.ts +59 -0
  406. package/dist/shared/harvest/event-buffer.d.ts.map +1 -0
  407. package/dist/shared/harvest/event-buffer.js +100 -0
  408. package/dist/shared/harvest/event-buffer.js.map +1 -0
  409. package/dist/shared/harvest/harvest-scheduler.d.ts +200 -0
  410. package/dist/shared/harvest/harvest-scheduler.d.ts.map +1 -0
  411. package/dist/shared/harvest/harvest-scheduler.js +647 -0
  412. package/dist/shared/harvest/harvest-scheduler.js.map +1 -0
  413. package/dist/shared/harvest/index.d.ts +7 -0
  414. package/dist/shared/harvest/index.d.ts.map +1 -0
  415. package/dist/shared/harvest/index.js +4 -0
  416. package/dist/shared/harvest/index.js.map +1 -0
  417. package/dist/shared/harvest/metric-aggregator.d.ts +115 -0
  418. package/dist/shared/harvest/metric-aggregator.d.ts.map +1 -0
  419. package/dist/shared/harvest/metric-aggregator.js +247 -0
  420. package/dist/shared/harvest/metric-aggregator.js.map +1 -0
  421. package/dist/shared/index.d.ts +22 -0
  422. package/dist/shared/index.d.ts.map +1 -0
  423. package/dist/shared/index.js +13 -0
  424. package/dist/shared/index.js.map +1 -0
  425. package/dist/shared/logger.d.ts +57 -0
  426. package/dist/shared/logger.d.ts.map +1 -0
  427. package/dist/shared/logger.js +166 -0
  428. package/dist/shared/logger.js.map +1 -0
  429. package/dist/shared/pricing-data.d.ts +4 -0
  430. package/dist/shared/pricing-data.d.ts.map +1 -0
  431. package/dist/shared/pricing-data.js +473 -0
  432. package/dist/shared/pricing-data.js.map +1 -0
  433. package/dist/shared/pricing.d.ts +148 -0
  434. package/dist/shared/pricing.d.ts.map +1 -0
  435. package/dist/shared/pricing.js +528 -0
  436. package/dist/shared/pricing.js.map +1 -0
  437. package/dist/shared/redact.d.ts +33 -0
  438. package/dist/shared/redact.d.ts.map +1 -0
  439. package/dist/shared/redact.js +110 -0
  440. package/dist/shared/redact.js.map +1 -0
  441. package/dist/shared/timing.d.ts +96 -0
  442. package/dist/shared/timing.d.ts.map +1 -0
  443. package/dist/shared/timing.js +173 -0
  444. package/dist/shared/timing.js.map +1 -0
  445. package/dist/shared/tokens.d.ts +145 -0
  446. package/dist/shared/tokens.d.ts.map +1 -0
  447. package/dist/shared/tokens.js +492 -0
  448. package/dist/shared/tokens.js.map +1 -0
  449. package/dist/shared/transport/events-api.d.ts +14 -0
  450. package/dist/shared/transport/events-api.d.ts.map +1 -0
  451. package/dist/shared/transport/events-api.js +29 -0
  452. package/dist/shared/transport/events-api.js.map +1 -0
  453. package/dist/shared/transport/http-client.d.ts +49 -0
  454. package/dist/shared/transport/http-client.d.ts.map +1 -0
  455. package/dist/shared/transport/http-client.js +381 -0
  456. package/dist/shared/transport/http-client.js.map +1 -0
  457. package/dist/shared/transport/index.d.ts +10 -0
  458. package/dist/shared/transport/index.d.ts.map +1 -0
  459. package/dist/shared/transport/index.js +6 -0
  460. package/dist/shared/transport/index.js.map +1 -0
  461. package/dist/shared/transport/logs-api.d.ts +29 -0
  462. package/dist/shared/transport/logs-api.d.ts.map +1 -0
  463. package/dist/shared/transport/logs-api.js +40 -0
  464. package/dist/shared/transport/logs-api.js.map +1 -0
  465. package/dist/shared/transport/metric-api.d.ts +9 -0
  466. package/dist/shared/transport/metric-api.d.ts.map +1 -0
  467. package/dist/shared/transport/metric-api.js +39 -0
  468. package/dist/shared/transport/metric-api.js.map +1 -0
  469. package/dist/shared/transport/otlp-event-bridge.d.ts +22 -0
  470. package/dist/shared/transport/otlp-event-bridge.d.ts.map +1 -0
  471. package/dist/shared/transport/otlp-event-bridge.js +50 -0
  472. package/dist/shared/transport/otlp-event-bridge.js.map +1 -0
  473. package/dist/shared/transport/otlp-shared.d.ts +14 -0
  474. package/dist/shared/transport/otlp-shared.d.ts.map +1 -0
  475. package/dist/shared/transport/otlp-shared.js +49 -0
  476. package/dist/shared/transport/otlp-shared.js.map +1 -0
  477. package/dist/shared/transport/otlp-transport.d.ts +58 -0
  478. package/dist/shared/transport/otlp-transport.d.ts.map +1 -0
  479. package/dist/shared/transport/otlp-transport.js +236 -0
  480. package/dist/shared/transport/otlp-transport.js.map +1 -0
  481. package/dist/shared/transport/types.d.ts +129 -0
  482. package/dist/shared/transport/types.d.ts.map +1 -0
  483. package/dist/shared/transport/types.js +2 -0
  484. package/dist/shared/transport/types.js.map +1 -0
  485. package/dist/shared/version.d.ts +2 -0
  486. package/dist/shared/version.d.ts.map +1 -0
  487. package/dist/shared/version.js +2 -0
  488. package/dist/shared/version.js.map +1 -0
  489. package/dist/storage/index.d.ts +7 -0
  490. package/dist/storage/index.d.ts.map +1 -0
  491. package/dist/storage/index.js +4 -0
  492. package/dist/storage/index.js.map +1 -0
  493. package/dist/storage/local-store.d.ts +153 -0
  494. package/dist/storage/local-store.d.ts.map +1 -0
  495. package/dist/storage/local-store.js +719 -0
  496. package/dist/storage/local-store.js.map +1 -0
  497. package/dist/storage/retention.d.ts +2 -0
  498. package/dist/storage/retention.d.ts.map +1 -0
  499. package/dist/storage/retention.js +53 -0
  500. package/dist/storage/retention.js.map +1 -0
  501. package/dist/storage/session-store.d.ts +97 -0
  502. package/dist/storage/session-store.d.ts.map +1 -0
  503. package/dist/storage/session-store.js +391 -0
  504. package/dist/storage/session-store.js.map +1 -0
  505. package/dist/storage/types.d.ts +64 -0
  506. package/dist/storage/types.d.ts.map +1 -0
  507. package/dist/storage/types.js +2 -0
  508. package/dist/storage/types.js.map +1 -0
  509. package/dist/storage/weekly-summary.d.ts +61 -0
  510. package/dist/storage/weekly-summary.d.ts.map +1 -0
  511. package/dist/storage/weekly-summary.js +243 -0
  512. package/dist/storage/weekly-summary.js.map +1 -0
  513. package/dist/tools/analytics-tools.d.ts +101 -0
  514. package/dist/tools/analytics-tools.d.ts.map +1 -0
  515. package/dist/tools/analytics-tools.js +71 -0
  516. package/dist/tools/analytics-tools.js.map +1 -0
  517. package/dist/tools/cost-tools.d.ts +121 -0
  518. package/dist/tools/cost-tools.d.ts.map +1 -0
  519. package/dist/tools/cost-tools.js +174 -0
  520. package/dist/tools/cost-tools.js.map +1 -0
  521. package/dist/tools/cross-session-tools.d.ts +376 -0
  522. package/dist/tools/cross-session-tools.d.ts.map +1 -0
  523. package/dist/tools/cross-session-tools.js +820 -0
  524. package/dist/tools/cross-session-tools.js.map +1 -0
  525. package/dist/tools/extended-analytics-tools.d.ts +164 -0
  526. package/dist/tools/extended-analytics-tools.d.ts.map +1 -0
  527. package/dist/tools/extended-analytics-tools.js +121 -0
  528. package/dist/tools/extended-analytics-tools.js.map +1 -0
  529. package/dist/tools/index.d.ts +7 -0
  530. package/dist/tools/index.d.ts.map +1 -0
  531. package/dist/tools/index.js +4 -0
  532. package/dist/tools/index.js.map +1 -0
  533. package/dist/tools/session-stats.d.ts +162 -0
  534. package/dist/tools/session-stats.d.ts.map +1 -0
  535. package/dist/tools/session-stats.js +1054 -0
  536. package/dist/tools/session-stats.js.map +1 -0
  537. package/dist/tools/workflow-tools.d.ts +126 -0
  538. package/dist/tools/workflow-tools.d.ts.map +1 -0
  539. package/dist/tools/workflow-tools.js +274 -0
  540. package/dist/tools/workflow-tools.js.map +1 -0
  541. package/dist/tracing/mcp-tracer.d.ts +4 -0
  542. package/dist/tracing/mcp-tracer.d.ts.map +1 -0
  543. package/dist/tracing/mcp-tracer.js +14 -0
  544. package/dist/tracing/mcp-tracer.js.map +1 -0
  545. package/dist/tracing/session-span.d.ts +14 -0
  546. package/dist/tracing/session-span.d.ts.map +1 -0
  547. package/dist/tracing/session-span.js +53 -0
  548. package/dist/tracing/session-span.js.map +1 -0
  549. package/dist/tracing/task-span-tracker.d.ts +11 -0
  550. package/dist/tracing/task-span-tracker.d.ts.map +1 -0
  551. package/dist/tracing/task-span-tracker.js +59 -0
  552. package/dist/tracing/task-span-tracker.js.map +1 -0
  553. package/dist/tracing/tool-call-span.d.ts +4 -0
  554. package/dist/tracing/tool-call-span.d.ts.map +1 -0
  555. package/dist/tracing/tool-call-span.js +60 -0
  556. package/dist/tracing/tool-call-span.js.map +1 -0
  557. package/dist/transport/index.d.ts +3 -0
  558. package/dist/transport/index.d.ts.map +1 -0
  559. package/dist/transport/index.js +2 -0
  560. package/dist/transport/index.js.map +1 -0
  561. package/dist/transport/log-ingest.d.ts +42 -0
  562. package/dist/transport/log-ingest.d.ts.map +1 -0
  563. package/dist/transport/log-ingest.js +151 -0
  564. package/dist/transport/log-ingest.js.map +1 -0
  565. package/dist/transport/nr-ingest.d.ts +171 -0
  566. package/dist/transport/nr-ingest.d.ts.map +1 -0
  567. package/dist/transport/nr-ingest.js +659 -0
  568. package/dist/transport/nr-ingest.js.map +1 -0
  569. package/dist/types.d.ts +45 -0
  570. package/dist/types.d.ts.map +1 -0
  571. package/dist/types.js +2 -0
  572. package/dist/types.js.map +1 -0
  573. package/dist/web/assets/index-BrL281N-.css +2 -0
  574. package/dist/web/assets/index-CcaYZzXm.js +42 -0
  575. package/dist/web/favicon.svg +15 -0
  576. package/dist/web/index.html +15 -0
  577. package/examples/local-alert-rules.json +106 -0
  578. package/package.json +129 -1
@@ -0,0 +1,662 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Hook collector script for Claude Code PreToolUse / PostToolUse / PostToolUseFailure hooks.
4
+ *
5
+ * Called by Claude Code on every tool invocation. Reads the hook JSON from stdin,
6
+ * extracts key fields, and appends a single JSONL line to the buffer file.
7
+ *
8
+ * Design constraints:
9
+ * - <5ms execution budget — must never slow Claude Code
10
+ * - No heavy imports (no shared package, no commander, no zod)
11
+ * - All errors caught silently — always exits 0
12
+ * - Config via env vars only (no file reads for config)
13
+ */
14
+ import { readFileSync, readSync, writeFileSync, openSync, closeSync, mkdirSync, existsSync, constants as fsConstants, statSync, } from 'node:fs';
15
+ import { resolve, dirname } from 'node:path';
16
+ import { homedir } from 'node:os';
17
+ import { createHash } from 'node:crypto';
18
+ // ---------------------------------------------------------------------------
19
+ // Lightweight config (env vars only — no file reads)
20
+ // ---------------------------------------------------------------------------
21
+ const SESSION_ID_RE = /^[a-zA-Z0-9_-]{1,128}$/;
22
+ const DEFAULT_STORAGE_DIR = resolve(homedir(), '.newrelic-preflight');
23
+ /**
24
+ * Resolve the per-session buffer path. Validates sessionId against
25
+ * /^[a-zA-Z0-9_-]{1,128}$/ so a malicious session_id can't escape the storage
26
+ * dir. When sessionId is missing or fails validation, falls back to
27
+ * `buffer-unknown.jsonl` rather than the legacy shared `buffer.jsonl` — the
28
+ * MCP no longer reads the shared path.
29
+ *
30
+ * `NEW_RELIC_AI_MCP_BUFFER_PATH` is honored verbatim when set (used by tests
31
+ * and one-off configurations) and bypasses session-scoping.
32
+ */
33
+ function getBufferPath(sessionId) {
34
+ if (process.env.NEW_RELIC_AI_MCP_BUFFER_PATH !== undefined) {
35
+ return process.env.NEW_RELIC_AI_MCP_BUFFER_PATH;
36
+ }
37
+ const storageDir = process.env.NEW_RELIC_AI_MCP_STORAGE_PATH ?? DEFAULT_STORAGE_DIR;
38
+ const safeId = typeof sessionId === 'string' && SESSION_ID_RE.test(sessionId) ? sessionId : 'unknown';
39
+ return resolve(storageDir, `buffer-${safeId}.jsonl`);
40
+ }
41
+ // Cache only the file-read result to avoid repeated disk I/O on the hot path
42
+ // (<5ms budget per hook invocation) while keeping the env-var check dynamic
43
+ // so runtime changes in tests (and future dynamic config) are respected.
44
+ // This also eliminates the TOCTOU window between existsSync and readFileSync.
45
+ const HIGH_SECURITY_FROM_FILE = (() => {
46
+ // Check new path first; fall back to legacy path during the migration window
47
+ // (between upgrade and first server startup that runs migrateStoragePath).
48
+ for (const dir of ['.newrelic-preflight', '.nr-ai-observe']) {
49
+ try {
50
+ const configPath = resolve(homedir(), dir, 'config.json');
51
+ if (existsSync(configPath)) {
52
+ const config = JSON.parse(readFileSync(configPath, 'utf-8'));
53
+ return config.highSecurity === true;
54
+ }
55
+ }
56
+ catch {
57
+ // Silently ignore config read errors
58
+ }
59
+ }
60
+ return false;
61
+ })();
62
+ function getHighSecurity() {
63
+ // Accept both names — NEW_RELIC_AI_HIGH_SECURITY matches config.ts (preferred);
64
+ // NEW_RELIC_AI_MCP_HIGH_SECURITY is the legacy collector-only name.
65
+ return (process.env.NEW_RELIC_AI_HIGH_SECURITY === 'true' ||
66
+ process.env.NEW_RELIC_AI_MCP_HIGH_SECURITY === 'true' ||
67
+ HIGH_SECURITY_FROM_FILE);
68
+ }
69
+ function getRecordContent() {
70
+ const highSecurity = getHighSecurity();
71
+ if (highSecurity)
72
+ return false;
73
+ return process.env.NEW_RELIC_AI_MCP_RECORD_CONTENT === 'true';
74
+ }
75
+ function getMaxContentLength() {
76
+ const val = process.env.NEW_RELIC_AI_MCP_MAX_CONTENT_LENGTH;
77
+ if (val === undefined)
78
+ return 10_240;
79
+ const parsed = parseInt(val, 10);
80
+ return Number.isNaN(parsed) ? 10_240 : parsed;
81
+ }
82
+ // ---------------------------------------------------------------------------
83
+ // Inline redaction (mirrors config.ts DEFAULT_REDACTION_PATTERNS)
84
+ // ---------------------------------------------------------------------------
85
+ const REDACTION_PATTERNS = [
86
+ /(?<![a-zA-Z])(?:API_KEY|SECRET|TOKEN|PASSWORD|PASSPHRASE|PRIVATE_KEY)(?![a-zA-Z])[\s]*[=:]\s*\S+/gi,
87
+ /(?:sk-|ghp_|gho_|ghs_|github_pat_|xoxb-|xoxp-|Bearer\s+)[A-Za-z0-9_-]{20,200}/g,
88
+ /-----BEGIN[^-\n]{0,100}-----[A-Za-z0-9+/=\r\n. ]{0,65536}-----END[^-\n]{0,100}-----/g,
89
+ /\bAKIA[0-9A-Z]{16}\b/g,
90
+ /\bAIzaSy[0-9A-Za-z_-]{33}\b/g,
91
+ /\beyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}/g,
92
+ /\bnpm_[A-Za-z0-9]{36}\b/g,
93
+ /\bxox[a-z]-[0-9A-Za-z-]+/g,
94
+ ];
95
+ const MAX_REDACT_BYTES = 1_048_576; // 1 MB
96
+ function redact(value) {
97
+ // Truncate by byte count, not character count — 4-byte emoji chars would otherwise
98
+ // allow up to 4 MB of content through the regex pass.
99
+ let result = value;
100
+ if (Buffer.byteLength(value, 'utf8') > MAX_REDACT_BYTES) {
101
+ const buf = Buffer.from(value, 'utf8').subarray(0, MAX_REDACT_BYTES);
102
+ result = buf.toString('utf8').replace(/�$/, ''); // drop any partial surrogate at cut point
103
+ }
104
+ for (const pattern of REDACTION_PATTERNS) {
105
+ const re = new RegExp(pattern.source, pattern.flags);
106
+ result = result.replace(re, '[REDACTED]');
107
+ }
108
+ return result;
109
+ }
110
+ // ---------------------------------------------------------------------------
111
+ // Helpers
112
+ // ---------------------------------------------------------------------------
113
+ function hashInput(input) {
114
+ const str = JSON.stringify(input) ?? '';
115
+ return createHash('sha256').update(str).digest('hex').slice(0, 16);
116
+ }
117
+ function sizeOf(value) {
118
+ if (value === undefined || value === null)
119
+ return 0;
120
+ if (typeof value === 'string')
121
+ return value.length;
122
+ try {
123
+ return JSON.stringify(value).length;
124
+ }
125
+ catch {
126
+ return 0;
127
+ }
128
+ }
129
+ function truncate(value, maxLen) {
130
+ if (value.length <= maxLen)
131
+ return value;
132
+ return value.slice(0, maxLen) + '...[truncated]';
133
+ }
134
+ function countLines(text) {
135
+ if (text === '')
136
+ return 0;
137
+ return (text.match(/\n/g) || []).length + 1;
138
+ }
139
+ // ---------------------------------------------------------------------------
140
+ // Transcript token collection
141
+ // ---------------------------------------------------------------------------
142
+ const TRANSCRIPT_TAIL_BYTES = 16_384;
143
+ const DEFAULT_MODEL = 'claude-opus-4-6';
144
+ function getClaudeHome() {
145
+ return process.env.NR_AI_OBSERVE_CLAUDE_HOME ?? resolve(homedir(), '.claude');
146
+ }
147
+ function getTranscriptPath(cwd, sessionId) {
148
+ if (!sessionId)
149
+ return null;
150
+ const projectDir = cwd ? cwd.replace(/\//g, '-') : process.env.PWD?.replace(/\//g, '-');
151
+ if (!projectDir)
152
+ return null;
153
+ return resolve(getClaudeHome(), 'projects', projectDir, `${sessionId}.jsonl`);
154
+ }
155
+ function readLastAssistantUsage(transcriptPath) {
156
+ try {
157
+ const stat = statSync(transcriptPath);
158
+ if (stat.size === 0)
159
+ return null;
160
+ const fd = openSync(transcriptPath, fsConstants.O_RDONLY);
161
+ try {
162
+ const readSize = Math.min(stat.size, TRANSCRIPT_TAIL_BYTES);
163
+ const buffer = Buffer.alloc(readSize);
164
+ const bytesRead = readSync(fd, buffer, 0, readSize, stat.size - readSize);
165
+ const tail = buffer.toString('utf-8', 0, bytesRead);
166
+ const lines = tail.split('\n').filter(Boolean);
167
+ for (let i = lines.length - 1; i >= 0; i--) {
168
+ try {
169
+ const entry = JSON.parse(lines[i]);
170
+ if (entry.type === 'assistant' && entry.message && typeof entry.message === 'object') {
171
+ const msg = entry.message;
172
+ // Skip synthetic entries (Claude Code's internal injections —
173
+ // compaction summaries, system messages). They carry model:
174
+ // '<synthetic>' which doesn't match any pricing table entry.
175
+ if (msg.model === '<synthetic>')
176
+ continue;
177
+ if (msg.usage && typeof msg.usage === 'object') {
178
+ const usage = { ...msg.usage };
179
+ if (typeof msg.model === 'string' && msg.model.length > 0) {
180
+ usage.model = msg.model;
181
+ }
182
+ return usage;
183
+ }
184
+ }
185
+ }
186
+ catch {
187
+ continue;
188
+ }
189
+ }
190
+ }
191
+ finally {
192
+ closeSync(fd);
193
+ }
194
+ }
195
+ catch {
196
+ // Silently ignore — transcript may not exist yet
197
+ }
198
+ return null;
199
+ }
200
+ function getLastTranscriptSize(sessionId) {
201
+ if (!SESSION_ID_RE.test(sessionId))
202
+ return 0;
203
+ try {
204
+ const bufferDir = dirname(getBufferPath(sessionId));
205
+ const statePath = resolve(bufferDir, `.transcript-pos-${sessionId}`);
206
+ if (existsSync(statePath)) {
207
+ return parseInt(readFileSync(statePath, 'utf-8').trim(), 10) || 0;
208
+ }
209
+ }
210
+ catch {
211
+ // Ignore
212
+ }
213
+ return 0;
214
+ }
215
+ let _transcriptSizeWriteFailed = false;
216
+ function setLastTranscriptSize(sessionId, size) {
217
+ if (!SESSION_ID_RE.test(sessionId))
218
+ return;
219
+ try {
220
+ const bufferDir = dirname(getBufferPath(sessionId));
221
+ if (!existsSync(bufferDir)) {
222
+ mkdirSync(bufferDir, { recursive: true, mode: 0o700 });
223
+ }
224
+ const statePath = resolve(bufferDir, `.transcript-pos-${sessionId}`);
225
+ writeFileSync(statePath, String(size), { mode: 0o600 });
226
+ _transcriptSizeWriteFailed = false;
227
+ }
228
+ catch (err) {
229
+ if (!_transcriptSizeWriteFailed) {
230
+ process.stderr.write(`[preflight-collector] Warning: cannot persist transcript size: ${String(err)}\n`);
231
+ _transcriptSizeWriteFailed = true;
232
+ }
233
+ }
234
+ }
235
+ function collectTranscriptTokens(data) {
236
+ const sessionId = data.session_id;
237
+ // Prefer Claude Code's own transcript_path field — it's authoritative and
238
+ // works under git worktrees, where deriving the path from cwd produces a
239
+ // dashed directory that doesn't match the parent project's transcript dir.
240
+ const transcriptPath = typeof data.transcript_path === 'string' && data.transcript_path.length > 0
241
+ ? data.transcript_path
242
+ : getTranscriptPath(data.cwd, sessionId);
243
+ if (!transcriptPath || !sessionId)
244
+ return;
245
+ let currentSize;
246
+ try {
247
+ currentSize = statSync(transcriptPath).size;
248
+ }
249
+ catch {
250
+ return;
251
+ }
252
+ let lastSize = getLastTranscriptSize(sessionId);
253
+ if (currentSize < lastSize) {
254
+ // Transcript file was rotated — reset tracking so we read from offset 0
255
+ setLastTranscriptSize(sessionId, 0);
256
+ lastSize = 0;
257
+ }
258
+ if (currentSize <= lastSize)
259
+ return;
260
+ const usage = readLastAssistantUsage(transcriptPath);
261
+ if (!usage)
262
+ return;
263
+ const inputTokens = usage.input_tokens ?? 0;
264
+ const outputTokens = usage.output_tokens ?? 0;
265
+ if (inputTokens === 0 && outputTokens === 0)
266
+ return;
267
+ const tokenEvent = {
268
+ mode: 'token',
269
+ timestamp: Date.now(),
270
+ inputTokens,
271
+ outputTokens,
272
+ cacheReadTokens: usage.cache_read_input_tokens ?? 0,
273
+ cacheCreationTokens: usage.cache_creation_input_tokens ?? 0,
274
+ model: usage.model ?? DEFAULT_MODEL,
275
+ };
276
+ tokenEvent.sessionId = sessionId;
277
+ try {
278
+ const bufferPath = getBufferPath(sessionId);
279
+ const bufferDir = dirname(bufferPath);
280
+ if (!existsSync(bufferDir)) {
281
+ mkdirSync(bufferDir, { recursive: true, mode: 0o700 });
282
+ }
283
+ const line = JSON.stringify(tokenEvent) + '\n';
284
+ const fd = openSync(bufferPath, fsConstants.O_WRONLY | fsConstants.O_CREAT | fsConstants.O_APPEND, 0o600);
285
+ try {
286
+ writeFileSync(fd, line);
287
+ }
288
+ finally {
289
+ closeSync(fd);
290
+ }
291
+ // Persist the new size only after a successful buffer write so that a
292
+ // write failure doesn't silently drop the token event on the next invocation.
293
+ setLastTranscriptSize(sessionId, currentSize);
294
+ }
295
+ catch {
296
+ // Silent failure — never block Claude Code
297
+ }
298
+ }
299
+ // ---------------------------------------------------------------------------
300
+ // PPID breadcrumb — lets the MCP server learn the Claude Code session_id
301
+ //
302
+ // Claude Code spawns its MCP server and hook collector scripts as children of
303
+ // the same process; they share a PPID. The MCP can read its own process.ppid
304
+ // (= Claude Code's PID) and look up the matching session_id here.
305
+ //
306
+ // Hot-path: every PreToolUse / PostToolUse hook runs this. The
307
+ // existsSync + content-equality short-circuit makes the steady state a single
308
+ // stat() and one read — well under the <5ms budget.
309
+ // ---------------------------------------------------------------------------
310
+ let _breadcrumbWriteFailed = false;
311
+ function writePpidBreadcrumb(sessionId) {
312
+ if (!SESSION_ID_RE.test(sessionId))
313
+ return;
314
+ // process.ppid is undefined on a few exotic platforms; bail without writing.
315
+ const ppid = process.ppid;
316
+ if (typeof ppid !== 'number' || ppid <= 0)
317
+ return;
318
+ try {
319
+ const storageDir = process.env.NEW_RELIC_AI_MCP_STORAGE_PATH ?? DEFAULT_STORAGE_DIR;
320
+ const breadcrumbDir = resolve(storageDir, 'session-by-ppid');
321
+ const breadcrumbPath = resolve(breadcrumbDir, `${ppid}.txt`);
322
+ // Steady-state short-circuit: most hook fires after the first one are
323
+ // no-ops because the breadcrumb already contains the right session_id.
324
+ if (existsSync(breadcrumbPath)) {
325
+ try {
326
+ if (readFileSync(breadcrumbPath, 'utf-8').trim() === sessionId)
327
+ return;
328
+ }
329
+ catch {
330
+ // Fall through and rewrite if the read failed for any reason
331
+ }
332
+ }
333
+ mkdirSync(breadcrumbDir, { recursive: true, mode: 0o700 });
334
+ writeFileSync(breadcrumbPath, sessionId, { mode: 0o600 });
335
+ _breadcrumbWriteFailed = false;
336
+ }
337
+ catch (err) {
338
+ if (!_breadcrumbWriteFailed) {
339
+ process.stderr.write(`[preflight-collector] Warning: cannot write PPID breadcrumb: ${String(err)}\n`);
340
+ _breadcrumbWriteFailed = true;
341
+ }
342
+ }
343
+ }
344
+ /**
345
+ * Extract only the metadata fields from tool_input that the tool-specific
346
+ * parsers need. Full content strings are replaced with their lengths to
347
+ * avoid writing sensitive data to the JSONL buffer on disk.
348
+ */
349
+ function extractInputMeta(toolName, input) {
350
+ if (input === null || input === undefined || typeof input !== 'object')
351
+ return undefined;
352
+ const obj = input;
353
+ const meta = {};
354
+ // Common field: file_path (Read, Write, Edit)
355
+ if (typeof obj.file_path === 'string')
356
+ meta.file_path = obj.file_path;
357
+ switch (toolName) {
358
+ case 'Read':
359
+ if (typeof obj.offset === 'number')
360
+ meta.offset = obj.offset;
361
+ if (typeof obj.limit === 'number')
362
+ meta.limit = obj.limit;
363
+ break;
364
+ case 'Write':
365
+ if (typeof obj.content === 'string') {
366
+ meta.contentLength = obj.content.length;
367
+ meta.lineCount = obj.content.length > 0 ? countLines(obj.content) : 0;
368
+ }
369
+ break;
370
+ case 'Edit':
371
+ if (typeof obj.old_string === 'string') {
372
+ meta.oldStringLength = obj.old_string.length;
373
+ meta.oldLineCount = obj.old_string.length > 0 ? countLines(obj.old_string) : 0;
374
+ }
375
+ if (typeof obj.new_string === 'string') {
376
+ meta.newStringLength = obj.new_string.length;
377
+ meta.newLineCount = obj.new_string.length > 0 ? countLines(obj.new_string) : 0;
378
+ meta.isDelete = obj.new_string.length === 0;
379
+ }
380
+ if (typeof obj.replace_all === 'boolean')
381
+ meta.replace_all = obj.replace_all;
382
+ break;
383
+ case 'Bash':
384
+ if (typeof obj.command === 'string')
385
+ meta.command = redact(obj.command);
386
+ if (typeof obj.description === 'string')
387
+ meta.description = redact(obj.description);
388
+ if (typeof obj.timeout === 'number')
389
+ meta.timeout = obj.timeout;
390
+ if (typeof obj.run_in_background === 'boolean')
391
+ meta.run_in_background = obj.run_in_background;
392
+ break;
393
+ case 'Grep':
394
+ if (typeof obj.pattern === 'string')
395
+ meta.pattern = obj.pattern;
396
+ if (typeof obj.path === 'string')
397
+ meta.path = obj.path;
398
+ if (typeof obj.output_mode === 'string')
399
+ meta.output_mode = obj.output_mode;
400
+ break;
401
+ case 'Glob':
402
+ if (typeof obj.pattern === 'string')
403
+ meta.pattern = obj.pattern;
404
+ if (typeof obj.path === 'string')
405
+ meta.path = obj.path;
406
+ break;
407
+ case 'Agent':
408
+ if (typeof obj.description === 'string')
409
+ meta.description = obj.description;
410
+ if (typeof obj.subagent_type === 'string')
411
+ meta.subagent_type = obj.subagent_type;
412
+ if (typeof obj.prompt === 'string')
413
+ meta.promptLength = obj.prompt.length;
414
+ if (typeof obj.run_in_background === 'boolean')
415
+ meta.run_in_background = obj.run_in_background;
416
+ if (typeof obj.name === 'string')
417
+ meta.name = obj.name;
418
+ if (typeof obj.team_name === 'string')
419
+ meta.team_name = obj.team_name;
420
+ if (typeof obj.isolation === 'string')
421
+ meta.isolation = obj.isolation;
422
+ if (typeof obj.model === 'string')
423
+ meta.model = obj.model;
424
+ break;
425
+ case 'AskUserQuestion':
426
+ if (Array.isArray(obj.questions))
427
+ meta.questions = new Array(obj.questions.length);
428
+ break;
429
+ case 'TaskCreate':
430
+ if (typeof obj.subject === 'string')
431
+ meta.subject = obj.subject;
432
+ break;
433
+ case 'TaskUpdate':
434
+ if (typeof obj.taskId === 'string')
435
+ meta.taskId = obj.taskId;
436
+ if (typeof obj.status === 'string')
437
+ meta.status = obj.status;
438
+ if (typeof obj.subject === 'string')
439
+ meta.subject = obj.subject;
440
+ break;
441
+ }
442
+ return Object.keys(meta).length > 0 ? meta : undefined;
443
+ }
444
+ /**
445
+ * Extract only the metadata fields from tool_response that the tool-specific
446
+ * parsers need.
447
+ */
448
+ function extractOutputMeta(toolName, output) {
449
+ if (output === null || output === undefined || typeof output !== 'object')
450
+ return undefined;
451
+ const obj = output;
452
+ if (toolName === 'Bash') {
453
+ if (typeof obj.exitCode === 'number') {
454
+ return { exitCode: obj.exitCode };
455
+ }
456
+ if (typeof obj.exitCode === 'string') {
457
+ const parsed = Number(obj.exitCode);
458
+ if (!Number.isNaN(parsed))
459
+ return { exitCode: parsed };
460
+ }
461
+ }
462
+ if (toolName === 'Edit') {
463
+ const meta = {};
464
+ if (typeof obj.success === 'boolean')
465
+ meta.editSuccess = obj.success;
466
+ if (typeof obj.error === 'string')
467
+ meta.editError = obj.error.slice(0, 200);
468
+ if (typeof obj.matched === 'boolean')
469
+ meta.editMatched = obj.matched;
470
+ return Object.keys(meta).length > 0 ? meta : undefined;
471
+ }
472
+ if (toolName === 'Grep') {
473
+ const meta = {};
474
+ if (typeof obj.matchCount === 'number')
475
+ meta.grepMatchCount = obj.matchCount;
476
+ else if (Array.isArray(obj.matches))
477
+ meta.grepMatchCount = obj.matches.length;
478
+ else if (Array.isArray(obj.results))
479
+ meta.grepMatchCount = obj.results.length;
480
+ if (Array.isArray(obj.content)) {
481
+ let lineCount = 0;
482
+ for (const block of obj.content) {
483
+ if (block &&
484
+ typeof block === 'object' &&
485
+ 'text' in block &&
486
+ typeof block.text === 'string') {
487
+ lineCount += block.text.split('\n').length;
488
+ }
489
+ }
490
+ if (lineCount > 0)
491
+ meta.grepResultLines = lineCount;
492
+ }
493
+ return Object.keys(meta).length > 0 ? meta : undefined;
494
+ }
495
+ if (toolName === 'Agent') {
496
+ const meta = {};
497
+ if (typeof obj.completed === 'boolean')
498
+ meta.agentCompleted = obj.completed;
499
+ if (typeof obj.interrupted === 'boolean')
500
+ meta.agentInterrupted = obj.interrupted;
501
+ if (typeof obj.result === 'string')
502
+ meta.agentResultLength = obj.result.length;
503
+ else if (typeof obj.message === 'string')
504
+ meta.agentResultLength = obj.message.length;
505
+ else if (Array.isArray(obj.content)) {
506
+ let totalLen = 0;
507
+ for (const block of obj.content) {
508
+ if (block &&
509
+ typeof block === 'object' &&
510
+ 'text' in block &&
511
+ typeof block.text === 'string') {
512
+ totalLen += block.text.length;
513
+ }
514
+ }
515
+ if (totalLen > 0)
516
+ meta.agentResultLength = totalLen;
517
+ }
518
+ return Object.keys(meta).length > 0 ? meta : undefined;
519
+ }
520
+ return undefined;
521
+ }
522
+ function processHook(raw) {
523
+ let data;
524
+ try {
525
+ data = JSON.parse(raw);
526
+ }
527
+ catch {
528
+ return; // Malformed JSON — skip silently
529
+ }
530
+ // Drop a PPID breadcrumb at the very top so the MCP server can resolve its
531
+ // Claude Code session_id without an env-var or initialize-payload extension.
532
+ // The function itself is a no-op when sessionId is missing or invalid, and
533
+ // short-circuits if the breadcrumb is already current.
534
+ if (typeof data.session_id === 'string' && data.session_id.length > 0) {
535
+ writePpidBreadcrumb(data.session_id);
536
+ }
537
+ const eventName = data.hook_event_name;
538
+ const toolName = data.tool_name ?? 'unknown';
539
+ const timestamp = Date.now();
540
+ const recordContent = getRecordContent();
541
+ const maxContentLen = getMaxContentLength();
542
+ let event;
543
+ if (eventName === 'PreToolUse') {
544
+ event = {
545
+ mode: 'pre',
546
+ tool: toolName,
547
+ timestamp,
548
+ inputSize: sizeOf(data.tool_input),
549
+ inputHash: hashInput(data.tool_input),
550
+ };
551
+ // Store only the metadata fields needed for tool-specific parsing
552
+ const inputMeta = extractInputMeta(toolName, data.tool_input);
553
+ if (inputMeta !== undefined)
554
+ event.toolInput = inputMeta;
555
+ if (recordContent && data.tool_input !== undefined) {
556
+ const content = typeof data.tool_input === 'string' ? data.tool_input : JSON.stringify(data.tool_input);
557
+ event.inputContent = redact(truncate(content, maxContentLen));
558
+ }
559
+ }
560
+ else if (eventName === 'PostToolUse') {
561
+ event = {
562
+ mode: 'post',
563
+ tool: toolName,
564
+ timestamp,
565
+ outputSize: sizeOf(data.tool_response),
566
+ success: true,
567
+ };
568
+ // Store input metadata as fallback for orphaned-post pairing (pre-event may be missing)
569
+ const postInputMeta = extractInputMeta(toolName, data.tool_input);
570
+ if (postInputMeta !== undefined)
571
+ event.toolInput = postInputMeta;
572
+ // Store only the metadata fields needed for tool-specific parsing
573
+ const outputMeta = extractOutputMeta(toolName, data.tool_response);
574
+ if (outputMeta !== undefined)
575
+ event.toolOutput = outputMeta;
576
+ if (recordContent && data.tool_response !== undefined) {
577
+ const content = typeof data.tool_response === 'string'
578
+ ? data.tool_response
579
+ : JSON.stringify(data.tool_response);
580
+ event.outputContent = redact(truncate(content, maxContentLen));
581
+ }
582
+ }
583
+ else if (eventName === 'PostToolUseFailure') {
584
+ event = {
585
+ mode: 'post',
586
+ tool: toolName,
587
+ timestamp,
588
+ success: false,
589
+ error: redact(data.error ?? 'unknown error'),
590
+ isInterrupt: data.is_interrupt ?? false,
591
+ };
592
+ }
593
+ else {
594
+ // Unknown hook event — ignore silently
595
+ return;
596
+ }
597
+ // Attach session metadata
598
+ if (data.cwd)
599
+ event.cwd = data.cwd;
600
+ if (data.permission_mode)
601
+ event.permissionMode = data.permission_mode;
602
+ if (data.session_id)
603
+ event.sessionId = data.session_id;
604
+ if (data.tool_use_id)
605
+ event.toolUseId = data.tool_use_id;
606
+ // Write to buffer — wrapped in try/catch for resilience.
607
+ try {
608
+ const bufferPath = getBufferPath(data.session_id);
609
+ const bufferDir = dirname(bufferPath);
610
+ if (!existsSync(bufferDir)) {
611
+ mkdirSync(bufferDir, { recursive: true, mode: 0o700 });
612
+ }
613
+ const line = JSON.stringify(event) + '\n';
614
+ const fd = openSync(bufferPath, fsConstants.O_WRONLY | fsConstants.O_CREAT | fsConstants.O_APPEND, 0o600);
615
+ try {
616
+ writeFileSync(fd, line);
617
+ }
618
+ finally {
619
+ closeSync(fd);
620
+ }
621
+ }
622
+ catch {
623
+ // Silent failure — never block Claude Code
624
+ }
625
+ // After writing the tool event, collect token usage from the transcript.
626
+ // Only on PostToolUse — each assistant turn produces exactly one usage object.
627
+ if (eventName === 'PostToolUse') {
628
+ try {
629
+ collectTranscriptTokens(data);
630
+ }
631
+ catch {
632
+ // Silent failure — transcript reading is best-effort
633
+ }
634
+ }
635
+ }
636
+ // Exported for testing
637
+ export { processHook, redact, hashInput, sizeOf, truncate, getRecordContent, collectTranscriptTokens, readLastAssistantUsage, getTranscriptPath, getBufferPath, writePpidBreadcrumb, };
638
+ // ---------------------------------------------------------------------------
639
+ // Entry point — only when run directly (not when imported by the MCP server)
640
+ // ---------------------------------------------------------------------------
641
+ import { realpathSync } from 'node:fs';
642
+ const _resolvedScript = (() => {
643
+ try {
644
+ return realpathSync(process.argv[1]);
645
+ }
646
+ catch {
647
+ return process.argv[1];
648
+ }
649
+ })();
650
+ const _isDirectExecution = _resolvedScript != null && /collector-script\.[jt]s$/.test(_resolvedScript);
651
+ if (_isDirectExecution) {
652
+ try {
653
+ const stdin = readFileSync('/dev/stdin', 'utf-8');
654
+ if (stdin.trim()) {
655
+ processHook(stdin);
656
+ }
657
+ }
658
+ catch {
659
+ // Silent failure — never block Claude Code
660
+ }
661
+ }
662
+ //# sourceMappingURL=collector-script.js.map