mirror of
https://github.com/Gitlawb/openclaude.git
synced 2026-08-24 02:34:15 -05:00
Add optional Sentry error reporting (env-driven, opt-in) (#2139)
* Add optional Sentry error reporting (env-driven, opt-in) * Fix Sentry init to use dynamic import instead of require (ESM compatibility) * Document SENTRY_DSN setup in advanced-setup docs * Disable Sentry default integrations; document runtime install requirement * Wire reportErrorToSentry into top-level error handlers; add sentry.test.ts
This commit is contained in:
@@ -23,6 +23,7 @@
|
||||
"@grpc/grpc-js": "^1.14.3",
|
||||
"@grpc/proto-loader": "^0.8.0",
|
||||
"@modelcontextprotocol/sdk": "1.29.0",
|
||||
"@sentry/node": "^10.70.0",
|
||||
"@smithy/core": "3.24.3",
|
||||
"@smithy/node-http-handler": "4.7.3",
|
||||
"@types/bun": "1.3.11",
|
||||
@@ -117,6 +118,12 @@
|
||||
|
||||
"@anthropic-ai/sdk": ["@anthropic-ai/sdk@0.94.0", "", { "dependencies": { "json-schema-to-ts": "^3.1.1" }, "peerDependencies": { "zod": "^3.25.0 || ^4.0.0" }, "optionalPeers": ["zod"], "bin": { "anthropic-ai-sdk": "bin/cli" } }, "sha512-OVlCttk5MyeTGtrWX5+F3MJOfEMDuEjK8+rm9aQMDfRPWndVMbhk37QG8WLnVbcc7huyUGngVMjT7iMN2llySA=="],
|
||||
|
||||
"@apm-js-collab/code-transformer": ["@apm-js-collab/code-transformer@0.18.1", "", { "dependencies": { "@types/estree": "^1.0.8", "astring": "^1.9.0", "esquery": "^1.7.0", "meriyah": "^6.1.4", "semifies": "^1.0.0", "source-map": "^0.6.0" }, "bin": { "code-transformer": "cli.js" } }, "sha512-u1Hb6bHjWtkSpiprwVP6YaHC1DTN4RAU3zYkUDUe7WMnJwdyU1pwTL9dFKiSJB9IiLue/EQovmyx6xhU7FFtAQ=="],
|
||||
|
||||
"@apm-js-collab/code-transformer-bundler-plugins": ["@apm-js-collab/code-transformer-bundler-plugins@0.7.4", "", { "dependencies": { "@apm-js-collab/code-transformer": "^0.18.1", "es-module-lexer": "^2.1.0", "magic-string": "^0.30.21", "module-details-from-path": "^1.0.4" } }, "sha512-nAfOeZPSUAQvJa1iFT/5oCrTm5YQhMMrfCNthNnaXHZiOQhu1KGuLoIx7HtbAi3wfwaBYLaICPIeenIaEwcXIg=="],
|
||||
|
||||
"@apm-js-collab/tracing-hooks": ["@apm-js-collab/tracing-hooks@0.13.0", "", { "dependencies": { "@apm-js-collab/code-transformer": "^0.18.0", "debug": "^4.4.1", "module-details-from-path": "^1.0.4" } }, "sha512-mTvWz9rnQwx1U3h0XPTHaX7bgfkpipLLTQyjlC2cdhQpQEuoLT0AGzoydeoq2NxfEVv6fWOOETcSbb2nptleyw=="],
|
||||
|
||||
"@aws-crypto/crc32": ["@aws-crypto/crc32@5.2.0", "", { "dependencies": { "@aws-crypto/util": "^5.2.0", "@aws-sdk/types": "^3.222.0", "tslib": "^2.6.2" } }, "sha512-nLbCWqQNgUiwwtFsen1AdzAtvuLRsQS8rYgMuxCrdKf9kOssamGLuPwyTY9wyYblNr9+1XM8v6zoDTPPSIeANg=="],
|
||||
|
||||
"@aws-crypto/sha256-browser": ["@aws-crypto/sha256-browser@5.2.0", "", { "dependencies": { "@aws-crypto/sha256-js": "^5.2.0", "@aws-crypto/supports-web-crypto": "^5.2.0", "@aws-crypto/util": "^5.2.0", "@aws-sdk/types": "^3.222.0", "@aws-sdk/util-locate-window": "^3.0.0", "@smithy/util-utf8": "^2.0.0", "tslib": "^2.6.2" } }, "sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw=="],
|
||||
@@ -283,6 +290,8 @@
|
||||
|
||||
"@img/sharp-win32-x64": ["@img/sharp-win32-x64@0.34.5", "", { "os": "win32", "cpu": "x64" }, "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw=="],
|
||||
|
||||
"@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.5", "", {}, "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="],
|
||||
|
||||
"@js-sdsl/ordered-map": ["@js-sdsl/ordered-map@4.4.2", "", {}, "sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw=="],
|
||||
|
||||
"@mixmark-io/domino": ["@mixmark-io/domino@2.2.0", "", {}, "sha512-Y28PR25bHXUg88kCV7nivXrP2Nj2RueZ3/l/jdx6J9f8J4nsEGcgX0Qe6lt7Pa+J79+kPiJU3LguR6O/6zrLOw=="],
|
||||
@@ -295,6 +304,22 @@
|
||||
|
||||
"@nodable/entities": ["@nodable/entities@2.1.0", "", {}, "sha512-nyT7T3nbMyBI/lvr6L5TyWbFJAI9FTgVRakNoBqCD+PmID8DzFrrNdLLtHMwMszOtqZa8PAOV24ZqDnQrhQINA=="],
|
||||
|
||||
"@opentelemetry/api": ["@opentelemetry/api@1.9.1", "", {}, "sha512-gLyJlPHPZYdAk1JENA9LeHejZe1Ti77/pTeFm/nMXmQH/HFZlcS/O2XJB+L8fkbrNSqhdtlvjBVjxwUYanNH5Q=="],
|
||||
|
||||
"@opentelemetry/api-logs": ["@opentelemetry/api-logs@0.220.0", "", { "dependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-CmVa4ImJ+ynfrPMNaAXHET6Bhb44SwzmfyVJFq9ni2jgXJR/l7C6gfVFddNmHP+ZOkP9cf4f9DBe68qVLTHc9w=="],
|
||||
|
||||
"@opentelemetry/core": ["@opentelemetry/core@2.10.0", "", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-/wNZ8twnEQQA4HoHu22+vcsdru6pWPWxW+7w+FlxT6Id7PE/WIbZmVKkte+PF72e0F2dnImFeHD2syyE1Mw6MQ=="],
|
||||
|
||||
"@opentelemetry/instrumentation": ["@opentelemetry/instrumentation@0.220.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.220.0", "import-in-the-middle": "^3.0.0", "require-in-the-middle": "^8.0.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-xQx3E2WxP1mDvKzxLxX+CTCtNLa560YJZ3087qYHerl2YmiKpv7AH+dAy7vmx+eVrZ5BwhfWUAVoKOoxCNHcpw=="],
|
||||
|
||||
"@opentelemetry/resources": ["@opentelemetry/resources@2.10.0", "", { "dependencies": { "@opentelemetry/core": "2.10.0", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-q6MMm2zhggzsHVNbabYwut+a6nbuQQe3URUoxaojM/8K1IBfwwPzvxIjNi2/lI1TFe+fMHMW9MWhrtDLEXEnkA=="],
|
||||
|
||||
"@opentelemetry/sdk-trace": ["@opentelemetry/sdk-trace@2.10.0", "", { "dependencies": { "@opentelemetry/core": "2.10.0", "@opentelemetry/resources": "2.10.0", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-MfQGq3GRmTh5fM/y+OjaO0vj6+luCB1XO2gfXCalKCfgKw0eHL++sm75DNweC6ohlp+aFvACqeE0fYayqdRaoQ=="],
|
||||
|
||||
"@opentelemetry/sdk-trace-base": ["@opentelemetry/sdk-trace-base@2.10.0", "", { "dependencies": { "@opentelemetry/core": "2.10.0", "@opentelemetry/resources": "2.10.0", "@opentelemetry/sdk-trace": "2.10.0", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-GuYQQT7QD2EeO8lcZLRQzcbOyhqAzL+6WWTKTU9mSUBYBazkEDl+VrQcXQhbB08OWM9anD1aHleVadzulpOaUQ=="],
|
||||
|
||||
"@opentelemetry/semantic-conventions": ["@opentelemetry/semantic-conventions@1.43.0", "", {}, "sha512-eSYWTm620tTk45EKSedaUL8MFYI8hW164hIXsgIHyxu3VobUB3fFCu5t0hQby6OoWRPsG1KkKUG2M5UadiLiVg=="],
|
||||
|
||||
"@orama/orama": ["@orama/orama@3.1.18", "", {}, "sha512-a61ljmRVVyG5MC/698C8/FfFDw5a8LOIvyOLW5fztgUXqUpc1jOfQzOitSCbge657OgXXThmY3Tk8fpiDb4UcA=="],
|
||||
|
||||
"@orama/plugin-data-persistence": ["@orama/plugin-data-persistence@3.1.18", "", { "dependencies": { "@msgpack/msgpack": "^3.1.2", "@orama/orama": "3.1.18", "dpack": "^0.6.22", "seqproto": "^0.2.3" } }, "sha512-pfBbpK96VRW/7IkdMHn2HaW3/+4k2C9Uwyup0IONNuz5bG3L1orCNFZPBmu+zcokOU2YH+IAVuQz6MlvqOe3iw=="],
|
||||
@@ -403,6 +428,18 @@
|
||||
|
||||
"@sec-ant/readable-stream": ["@sec-ant/readable-stream@0.4.1", "", {}, "sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg=="],
|
||||
|
||||
"@sentry/conventions": ["@sentry/conventions@0.16.0", "", {}, "sha512-fO9PLmHdVURcSPUpWCItWAtgKiMwGdJHbovoSEyLplX5sxs2ugvI4CBPTrkkgqhObnZOD0CnWBKDzSVQYBKEyQ=="],
|
||||
|
||||
"@sentry/core": ["@sentry/core@10.70.0", "", { "dependencies": { "@sentry/conventions": "^0.16.0" } }, "sha512-ozhCTDqg89oB4XmWfAwuHshABpvT7AkRpaPnogopPfMAaI61G1t8EKCJ4W7aum8JSBonlfyjPCyW5oYZFm0KvA=="],
|
||||
|
||||
"@sentry/node": ["@sentry/node@10.70.0", "", { "dependencies": { "@opentelemetry/api": "^1.9.1", "@opentelemetry/instrumentation": "^0.220.0", "@opentelemetry/sdk-trace-base": "^2.9.0", "@sentry/conventions": "^0.16.0", "@sentry/core": "10.70.0", "@sentry/node-core": "10.70.0", "@sentry/opentelemetry": "10.70.0", "@sentry/server-utils": "10.70.0", "import-in-the-middle": "^3.0.0" } }, "sha512-SPOOVxmKTVIEtqvOKkQT163e/pOwucjS7OPsCHyRs8sFR4nfBNu0EThplyqnvqd5BWBMTPH6WTBQfo+QWHV+HA=="],
|
||||
|
||||
"@sentry/node-core": ["@sentry/node-core@10.70.0", "", { "dependencies": { "@sentry/conventions": "^0.16.0", "@sentry/core": "10.70.0", "@sentry/opentelemetry": "10.70.0", "import-in-the-middle": "^3.0.0" }, "peerDependencies": { "@opentelemetry/api": "^1.9.0", "@opentelemetry/core": "^1.30.1 || ^2.1.0", "@opentelemetry/exporter-trace-otlp-http": ">=0.57.0 <1", "@opentelemetry/instrumentation": ">=0.57.1 <1", "@opentelemetry/sdk-trace-base": "^1.30.1 || ^2.1.0" }, "optionalPeers": ["@opentelemetry/api", "@opentelemetry/core", "@opentelemetry/exporter-trace-otlp-http", "@opentelemetry/instrumentation", "@opentelemetry/sdk-trace-base"] }, "sha512-oPOEVVNxv5WHtckx2i06Wi9FLWyvOg/1DUeX732jZ4iqT2nupINaMH4nF4f4kSvUThFnxkFSRQxwqOxgzMKhKA=="],
|
||||
|
||||
"@sentry/opentelemetry": ["@sentry/opentelemetry@10.70.0", "", { "dependencies": { "@sentry/conventions": "^0.16.0", "@sentry/core": "10.70.0" }, "peerDependencies": { "@opentelemetry/api": "^1.9.0", "@opentelemetry/core": "^1.30.1 || ^2.1.0", "@opentelemetry/sdk-trace-base": "^1.30.1 || ^2.1.0" } }, "sha512-UNV/2tqypcUK6FDzerAsFJn1Km/c4VZCYkUZDNbnV5S0cwAq2BYKMo4M5vovaLDBQlxA+Wk9ovbxi5wYjjl9fw=="],
|
||||
|
||||
"@sentry/server-utils": ["@sentry/server-utils@10.70.0", "", { "dependencies": { "@apm-js-collab/code-transformer-bundler-plugins": "^0.7.3", "@apm-js-collab/tracing-hooks": "^0.13.0", "@sentry/conventions": "^0.16.0", "@sentry/core": "10.70.0", "meriyah": "^6.1.4" } }, "sha512-rzegZjMFFgCp3o+N8+XU13rfSvz4B+f8rU0ijBGrQcHdMNyfsFDTu1UTm262JofmrV2u+s+D0u0vFTnqtOGkbA=="],
|
||||
|
||||
"@sindresorhus/merge-streams": ["@sindresorhus/merge-streams@4.0.0", "", {}, "sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ=="],
|
||||
|
||||
"@smithy/abort-controller": ["@smithy/abort-controller@2.2.0", "", { "dependencies": { "@smithy/types": "^2.12.0", "tslib": "^2.6.2" } }, "sha512-wRlta7GuLWpTqtFfGo+nZyOO1vEvewdNR1R4rTxpC8XU6vG/NDyrFBhwLZsqg1NUoR1noVaXJPC/7ZK47QCySw=="],
|
||||
@@ -467,6 +504,8 @@
|
||||
|
||||
"@types/bun": ["@types/bun@1.3.11", "", { "dependencies": { "bun-types": "1.3.11" } }, "sha512-5vPne5QvtpjGpsGYXiFyycfpDF2ECyPcTSsFBMa0fraoxiQyMJ3SmuQIGhzPg2WJuWxVBoxWJ2kClYTcw/4fAg=="],
|
||||
|
||||
"@types/estree": ["@types/estree@1.0.9", "", {}, "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg=="],
|
||||
|
||||
"@types/node": ["@types/node@25.5.0", "", { "dependencies": { "undici-types": "~7.18.0" } }, "sha512-jp2P3tQMSxWugkCUKLRPVUpGaL5MVFwF8RDuSRztfwgN1wmqJeMSbKlnEtQqU8UrhTmzEmZdu2I6v2dpp7XIxw=="],
|
||||
|
||||
"@types/react": ["@types/react@19.2.14", "", { "dependencies": { "csstype": "^3.2.2" } }, "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w=="],
|
||||
@@ -515,6 +554,8 @@
|
||||
|
||||
"any-promise": ["any-promise@1.3.0", "", {}, "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A=="],
|
||||
|
||||
"astring": ["astring@1.9.0", "", { "bin": { "astring": "bin/astring" } }, "sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg=="],
|
||||
|
||||
"asynckit": ["asynckit@0.4.0", "", {}, "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="],
|
||||
|
||||
"auto-bind": ["auto-bind@5.0.1", "", {}, "sha512-ooviqdwwgfIfNmDwo94wlshcdzfO64XV0Cg6oDsDYBJfITDz1EngD2z7DkbvCWn+XIMsIqW27sEVF6qcpJrRcg=="],
|
||||
@@ -549,6 +590,8 @@
|
||||
|
||||
"chokidar": ["chokidar@4.0.3", "", { "dependencies": { "readdirp": "^4.0.1" } }, "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA=="],
|
||||
|
||||
"cjs-module-lexer": ["cjs-module-lexer@2.2.1", "", {}, "sha512-Ca8swihM+/4yKecYHY52kgJd300hi2lADU/a1RxNTRe+RJ9jvqQlESpbz9DnG9mowez8qwXHB8qYdIUw9e+F5Q=="],
|
||||
|
||||
"cli-boxes": ["cli-boxes@3.0.0", "", {}, "sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g=="],
|
||||
|
||||
"cli-highlight": ["cli-highlight@2.1.11", "", { "dependencies": { "chalk": "^4.0.0", "highlight.js": "^10.7.1", "mz": "^2.4.0", "parse5": "^5.1.1", "parse5-htmlparser2-tree-adapter": "^6.0.0", "yargs": "^16.0.0" }, "bin": { "highlight": "bin/highlight" } }, "sha512-9KDcoEVwyUXrjcJNvHD0NFc/hiwe/WPVYIleQh2O1N2Zro5gWJZ/K+3DGn8w8P/F6FxOgzyC5bxDyHIgCSPhGg=="],
|
||||
@@ -621,6 +664,8 @@
|
||||
|
||||
"es-errors": ["es-errors@1.3.0", "", {}, "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="],
|
||||
|
||||
"es-module-lexer": ["es-module-lexer@2.3.2", "", {}, "sha512-poHGpORABojJJucnV9KbOavETW8lBVnphkW77ER5/BQ5Fz7oXSoCNek7IH3vR5nRjdsEz926ibFYX8KtLQmdyw=="],
|
||||
|
||||
"es-object-atoms": ["es-object-atoms@1.1.1", "", { "dependencies": { "es-errors": "^1.3.0" } }, "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA=="],
|
||||
|
||||
"es-set-tostringtag": ["es-set-tostringtag@2.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "get-intrinsic": "^1.2.6", "has-tostringtag": "^1.0.2", "hasown": "^2.0.2" } }, "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA=="],
|
||||
@@ -629,6 +674,10 @@
|
||||
|
||||
"escape-html": ["escape-html@1.0.3", "", {}, "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="],
|
||||
|
||||
"esquery": ["esquery@1.7.0", "", { "dependencies": { "estraverse": "^5.1.0" } }, "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g=="],
|
||||
|
||||
"estraverse": ["estraverse@5.3.0", "", {}, "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA=="],
|
||||
|
||||
"etag": ["etag@1.8.1", "", {}, "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg=="],
|
||||
|
||||
"events": ["events@3.3.0", "", {}, "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q=="],
|
||||
@@ -745,6 +794,8 @@
|
||||
|
||||
"ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="],
|
||||
|
||||
"import-in-the-middle": ["import-in-the-middle@3.3.3", "", { "dependencies": { "cjs-module-lexer": "^2.2.0", "es-module-lexer": "^2.2.0", "module-details-from-path": "^1.0.4" } }, "sha512-AiohS3H80sXO6owEltjGX+glb7qXaDhBoJb9XcQVH4UI207xu/bDLUcadVKp7Qe576reg9yr/PXZjV5qx8gfbA=="],
|
||||
|
||||
"indent-string": ["indent-string@5.0.0", "", {}, "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg=="],
|
||||
|
||||
"inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="],
|
||||
@@ -821,6 +872,8 @@
|
||||
|
||||
"lru-cache": ["lru-cache@11.2.7", "", {}, "sha512-aY/R+aEsRelme17KGQa/1ZSIpLpNYYrhcrepKTZgE+W3WM16YMCaPwOHLHsmopZHELU0Ojin1lPVxKR0MihncA=="],
|
||||
|
||||
"magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="],
|
||||
|
||||
"marked": ["marked@15.0.12", "", { "bin": { "marked": "bin/marked.js" } }, "sha512-8dD6FusOQSrpv9Z1rdNMdlSgQOIP880DHqnohobOmYLElGEqAL/JvxvuxZO16r4HtjTlfPRDC1hbvxC9dPN2nA=="],
|
||||
|
||||
"math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="],
|
||||
@@ -829,12 +882,16 @@
|
||||
|
||||
"merge-descriptors": ["merge-descriptors@2.0.0", "", {}, "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g=="],
|
||||
|
||||
"meriyah": ["meriyah@6.1.4", "", {}, "sha512-Sz8FzjzI0kN13GK/6MVEsVzMZEPvOhnmmI1lU5+/1cGOiK3QUahntrNNtdVeihrO7t9JpoH75iMNXg6R6uWflQ=="],
|
||||
|
||||
"mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="],
|
||||
|
||||
"mime-types": ["mime-types@3.0.2", "", { "dependencies": { "mime-db": "^1.54.0" } }, "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A=="],
|
||||
|
||||
"mnemonist": ["mnemonist@0.39.8", "", { "dependencies": { "obliterator": "^2.0.1" } }, "sha512-vyWo2K3fjrUw8YeeZ1zF0fy6Mu59RHokURlld8ymdUPjMlD9EC9ov1/YPqTgqRvUN9nTr3Gqfz29LYAmu0PHPQ=="],
|
||||
|
||||
"module-details-from-path": ["module-details-from-path@1.0.4", "", {}, "sha512-EGWKgxALGMgzvxYF1UyGTy0HXX/2vHLkw6+NvDKW2jypWbHpjQuj4UMcqQWXHERJhVGKikolT06G3bcKe4fi7w=="],
|
||||
|
||||
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
|
||||
|
||||
"mz": ["mz@2.7.0", "", { "dependencies": { "any-promise": "^1.0.0", "object-assign": "^4.0.1", "thenify-all": "^1.0.0" } }, "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q=="],
|
||||
@@ -927,6 +984,8 @@
|
||||
|
||||
"require-from-string": ["require-from-string@2.0.2", "", {}, "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw=="],
|
||||
|
||||
"require-in-the-middle": ["require-in-the-middle@8.0.1", "", { "dependencies": { "debug": "^4.3.5", "module-details-from-path": "^1.0.3" } }, "sha512-QT7FVMXfWOYFbeRBF6nu+I6tr2Tf3u0q8RIEjNob/heKY/nh7drD/k7eeMFmSQgnTtCzLDcCu/XEnpW2wk4xCQ=="],
|
||||
|
||||
"require-main-filename": ["require-main-filename@2.0.0", "", {}, "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg=="],
|
||||
|
||||
"resolve-pkg-maps": ["resolve-pkg-maps@1.0.0", "", {}, "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw=="],
|
||||
@@ -945,6 +1004,8 @@
|
||||
|
||||
"scheduler": ["scheduler@0.27.0", "", {}, "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q=="],
|
||||
|
||||
"semifies": ["semifies@1.0.0", "", {}, "sha512-xXR3KGeoxTNWPD4aBvL5NUpMTT7WMANr3EWnaS190QVkY52lqqcVRD7Q05UVbBhiWDGWMlJEUam9m7uFFGVScw=="],
|
||||
|
||||
"semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="],
|
||||
|
||||
"send": ["send@1.2.1", "", { "dependencies": { "debug": "^4.4.3", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "fresh": "^2.0.0", "http-errors": "^2.0.1", "mime-types": "^3.0.2", "ms": "^2.1.3", "on-finished": "^2.4.1", "range-parser": "^1.2.1", "statuses": "^2.0.2" } }, "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ=="],
|
||||
@@ -977,6 +1038,8 @@
|
||||
|
||||
"smol-toml": ["smol-toml@1.6.1", "", {}, "sha512-dWUG8F5sIIARXih1DTaQAX4SsiTXhInKf1buxdY9DIg4ZYPZK5nGM1VRIYmEbDbsHt7USo99xSLFu5Q1IqTmsg=="],
|
||||
|
||||
"source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="],
|
||||
|
||||
"statuses": ["statuses@2.0.2", "", {}, "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw=="],
|
||||
|
||||
"string-width": ["string-width@7.2.0", "", { "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", "strip-ansi": "^7.1.0" } }, "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ=="],
|
||||
|
||||
@@ -403,6 +403,7 @@ missing. Install only what you need:
|
||||
| Azure Foundry | `CLAUDE_CODE_USE_FOUNDRY=1` | `npm i -g @anthropic-ai/foundry-sdk @azure/identity` |
|
||||
| Claude on Vertex AI / Gemini ADC | `CLAUDE_CODE_USE_VERTEX=1` / Gemini ADC auth | `npm i -g google-auth-library` |
|
||||
| Reading/processing images | reading an image file | `npm i -g sharp` |
|
||||
| Optional error reporting | `SENTRY_DSN` is set | `npm i -g @sentry/node`. Without this package installed, setting `SENTRY_DSN` has no effect and reporting is silently disabled. |
|
||||
|
||||
When installing OpenClaude from source (`bun install`), all of these are
|
||||
already present as dev dependencies, so source/dev builds need no extra steps.
|
||||
@@ -592,6 +593,37 @@ reject accidental absurd values. An invalid pricing map is ignored without
|
||||
discarding unrelated settings from the same file. `/config` does not currently
|
||||
edit record-valued settings, so edit the JSON file directly.
|
||||
|
||||
## Optional Error Reporting (Sentry)
|
||||
|
||||
OpenClaude can optionally report sanitized error events to Sentry. This is
|
||||
disabled by default and opt-in only.
|
||||
|
||||
```bash
|
||||
export SENTRY_DSN=https://your-key@your-org.ingest.sentry.io/your-project
|
||||
openclaude
|
||||
```
|
||||
|
||||
Notes:
|
||||
|
||||
- Reporting only activates when `SENTRY_DSN` is set. Unset, this is a no-op.
|
||||
- Reporting is skipped even when `SENTRY_DSN` is set if `DISABLE_TELEMETRY` or
|
||||
`CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC` is set, matching the same privacy
|
||||
levels used for existing telemetry (see [Runtime Hardening](#runtime-hardening)).
|
||||
- Only sanitized, telemetry-safe error messages are sent — never raw error
|
||||
messages, which may contain file paths or other identifying information.
|
||||
- `@sentry/node` is an optional dev dependency and is **not included** in the
|
||||
default `npm install -g @gitlawb/openclaude` install (see
|
||||
[Optional provider packages](#optional-provider-packages)). If you set
|
||||
`SENTRY_DSN` without installing it separately, reporting is silently
|
||||
disabled (no error, no crash). Install it explicitly with:
|
||||
|
||||
```bash
|
||||
npm i -g @sentry/node
|
||||
```
|
||||
|
||||
Source builds (`bun install`) already include it as a dev dependency, so no
|
||||
extra step is needed there.
|
||||
|
||||
## Safety strictness
|
||||
|
||||
OpenClaude runs several "safety" checks: a model-level refusal directive, bash
|
||||
|
||||
@@ -85,6 +85,7 @@
|
||||
"devDependencies": {
|
||||
"@alcalzone/ansi-tokenize": "0.3.0",
|
||||
"@anthropic-ai/bedrock-sdk": "0.29.1",
|
||||
"@sentry/node": "^10.70.0",
|
||||
"@anthropic-ai/foundry-sdk": "0.2.3",
|
||||
"@anthropic-ai/sandbox-runtime": "0.0.55",
|
||||
"@anthropic-ai/sdk": "0.94.0",
|
||||
|
||||
@@ -15,6 +15,10 @@
|
||||
export const COMMON_EXTERNALS: string[] = [
|
||||
// Native image processing
|
||||
'sharp',
|
||||
// Optional Sentry error reporting — dynamically required in utils/sentry.ts
|
||||
// only when SENTRY_DSN is set. Not shipped by default; kept external so
|
||||
// esbuild doesn't try to inline it.
|
||||
'@sentry/node',
|
||||
// Cloud provider SDKs
|
||||
'@aws-sdk/client-bedrock',
|
||||
'@aws-sdk/client-bedrock-runtime',
|
||||
@@ -88,6 +92,9 @@ export const OPTIONAL_RUNTIME_EXTERNALS: string[] = [
|
||||
// Optional: only image reads need it, and it carries a native install
|
||||
// script. Kept opt-in so default installs run no install scripts.
|
||||
'sharp',
|
||||
// Sentry error reporting — loaded via require() in utils/sentry.ts only
|
||||
// when SENTRY_DSN is set. Optional: most users never enable this.
|
||||
'@sentry/node',
|
||||
]
|
||||
|
||||
// OPTIONAL_RUNTIME_EXTERNALS that are loaded ONLY through the runtime importer
|
||||
|
||||
@@ -41,6 +41,7 @@ import {
|
||||
} from '../utils/permissions/filesystem.js'
|
||||
import { configureGlobalAgents } from '../utils/proxy.js'
|
||||
import { setShellIfWindows } from '../utils/windowsPaths.js'
|
||||
import { initializeSentry } from '../utils/sentry.js'
|
||||
|
||||
|
||||
export const init = memoize(async (): Promise<void> => {
|
||||
@@ -216,9 +217,10 @@ export const init = memoize(async (): Promise<void> => {
|
||||
})
|
||||
|
||||
/**
|
||||
* No-op — telemetry initialization has been removed.
|
||||
* Kept as an empty function for API compatibility with callers.
|
||||
* Initializes optional, env-driven Sentry error reporting after the user
|
||||
* has trusted the working directory. No-op unless SENTRY_DSN is set and
|
||||
* telemetry is not disabled.
|
||||
*/
|
||||
export function initializeTelemetryAfterTrust(): void {
|
||||
// Telemetry is no longer initialized; this is a no-op.
|
||||
void initializeSentry()
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ import {
|
||||
wrapForMultiplexer,
|
||||
} from '../ink/termio/osc.js'
|
||||
import { shutdownDatadog } from '../services/analytics/datadog.js'
|
||||
import { reportErrorToSentry } from './sentry.js'
|
||||
import {
|
||||
type AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
|
||||
logEvent,
|
||||
@@ -311,7 +312,7 @@ export const setupGracefulShutdown = memoize(() => {
|
||||
|
||||
// Log uncaught exceptions for container observability and analytics
|
||||
// Error names (e.g., "TypeError") are not sensitive - safe to log
|
||||
process.on('uncaughtException', error => {
|
||||
process.on('uncaughtException', error => {
|
||||
logForDiagnosticsNoPII('error', 'uncaught_exception', {
|
||||
error_name: error.name,
|
||||
error_message: error.message.slice(0, 2000),
|
||||
@@ -320,6 +321,10 @@ export const setupGracefulShutdown = memoize(() => {
|
||||
error_name:
|
||||
error.name as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
|
||||
})
|
||||
// Optional Sentry reporting (env-driven, opt-in). No-op unless
|
||||
// SENTRY_DSN is set; only sends the sanitized message for
|
||||
// TelemetrySafeError instances, never this raw error.
|
||||
reportErrorToSentry(error)
|
||||
})
|
||||
|
||||
// Log unhandled promise rejections for container observability and analytics
|
||||
@@ -343,6 +348,10 @@ export const setupGracefulShutdown = memoize(() => {
|
||||
error_name:
|
||||
errorName as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
|
||||
})
|
||||
// Optional Sentry reporting (env-driven, opt-in). No-op unless
|
||||
// SENTRY_DSN is set; only sends the sanitized message for
|
||||
// TelemetrySafeError instances, never this raw rejection reason.
|
||||
reportErrorToSentry(reason)
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
import { afterEach, beforeEach, expect, mock, test } from 'bun:test'
|
||||
|
||||
const ORIGINAL_SENTRY_DSN = process.env.SENTRY_DSN
|
||||
const ORIGINAL_DISABLE_TELEMETRY = process.env.DISABLE_TELEMETRY
|
||||
|
||||
beforeEach(() => {
|
||||
delete process.env.SENTRY_DSN
|
||||
delete process.env.DISABLE_TELEMETRY
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
if (ORIGINAL_SENTRY_DSN === undefined) {
|
||||
delete process.env.SENTRY_DSN
|
||||
} else {
|
||||
process.env.SENTRY_DSN = ORIGINAL_SENTRY_DSN
|
||||
}
|
||||
if (ORIGINAL_DISABLE_TELEMETRY === undefined) {
|
||||
delete process.env.DISABLE_TELEMETRY
|
||||
} else {
|
||||
process.env.DISABLE_TELEMETRY = ORIGINAL_DISABLE_TELEMETRY
|
||||
}
|
||||
mock.restore()
|
||||
})
|
||||
|
||||
test('isSentryEnabled is false when SENTRY_DSN is unset', async () => {
|
||||
const { isSentryEnabled } = await import('./sentry.js')
|
||||
expect(isSentryEnabled()).toBe(false)
|
||||
})
|
||||
|
||||
test('isSentryEnabled is true when SENTRY_DSN is set and telemetry is not disabled', async () => {
|
||||
process.env.SENTRY_DSN = 'https://example@o0.ingest.sentry.io/0'
|
||||
const { isSentryEnabled } = await import('./sentry.js')
|
||||
expect(isSentryEnabled()).toBe(true)
|
||||
})
|
||||
|
||||
test('isSentryEnabled is false when SENTRY_DSN is set but DISABLE_TELEMETRY is set', async () => {
|
||||
process.env.SENTRY_DSN = 'https://example@o0.ingest.sentry.io/0'
|
||||
process.env.DISABLE_TELEMETRY = '1'
|
||||
const { isSentryEnabled } = await import('./sentry.js')
|
||||
expect(isSentryEnabled()).toBe(false)
|
||||
})
|
||||
|
||||
test('reportErrorToSentry does not throw when Sentry is disabled', async () => {
|
||||
const { reportErrorToSentry } = await import('./sentry.js')
|
||||
const { TelemetrySafeError_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS: TelemetrySafeError } =
|
||||
await import('./errors.js')
|
||||
|
||||
expect(() =>
|
||||
reportErrorToSentry(
|
||||
new TelemetrySafeError('full message with /some/file/path', 'sanitized message'),
|
||||
),
|
||||
).not.toThrow()
|
||||
})
|
||||
|
||||
test('reportErrorToSentry does not throw for a plain (non-sanitized) Error', async () => {
|
||||
const { reportErrorToSentry } = await import('./sentry.js')
|
||||
|
||||
expect(() =>
|
||||
reportErrorToSentry(new Error('raw error with /some/file/path')),
|
||||
).not.toThrow()
|
||||
})
|
||||
|
||||
test('reportErrorToSentry only reports TelemetrySafeError, never a raw Error message', async () => {
|
||||
process.env.SENTRY_DSN = 'https://example@o0.ingest.sentry.io/0'
|
||||
|
||||
const captureMessage = mock(() => {})
|
||||
mock.module('@sentry/node', () => ({
|
||||
init: mock(() => {}),
|
||||
captureMessage,
|
||||
}))
|
||||
|
||||
const { initializeSentry, reportErrorToSentry } = await import('./sentry.js')
|
||||
const { TelemetrySafeError_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS: TelemetrySafeError } =
|
||||
await import('./errors.js')
|
||||
|
||||
await initializeSentry()
|
||||
|
||||
// A plain Error must never be reported — its message may contain file paths.
|
||||
reportErrorToSentry(new Error('raw error with /some/file/path'))
|
||||
expect(captureMessage).not.toHaveBeenCalled()
|
||||
|
||||
// A TelemetrySafeError reports only its sanitized telemetryMessage.
|
||||
reportErrorToSentry(
|
||||
new TelemetrySafeError('full message with /some/file/path', 'sanitized message'),
|
||||
)
|
||||
expect(captureMessage).toHaveBeenCalledWith('sanitized message', 'error')
|
||||
})
|
||||
@@ -0,0 +1,72 @@
|
||||
/**
|
||||
* Optional, env-driven Sentry error reporting.
|
||||
*
|
||||
* Disabled by default. Enabled only when SENTRY_DSN is set AND telemetry
|
||||
* is not disabled via DISABLE_TELEMETRY / CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC.
|
||||
*
|
||||
* Only TelemetrySafeError.telemetryMessage (never raw error.message) is sent,
|
||||
* to avoid leaking file paths or other PII into Sentry.
|
||||
*/
|
||||
import { isTelemetryDisabled } from './privacyLevel.js'
|
||||
import { TelemetrySafeError_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS as TelemetrySafeError } from './errors.js'
|
||||
|
||||
let sentryInitialized = false
|
||||
let sentryModule: typeof import('@sentry/node') | null = null
|
||||
|
||||
export function isSentryEnabled(): boolean {
|
||||
return Boolean(process.env.SENTRY_DSN) && !isTelemetryDisabled()
|
||||
}
|
||||
|
||||
/**
|
||||
* Lazily initializes Sentry. No-op if SENTRY_DSN is unset or telemetry is disabled.
|
||||
* Safe to call multiple times; only initializes once. Async because @sentry/node
|
||||
* is loaded via dynamic import — this bundle is ESM and does not define require().
|
||||
*/
|
||||
export async function initializeSentry(): Promise<void> {
|
||||
if (sentryInitialized || !isSentryEnabled()) {
|
||||
return
|
||||
}
|
||||
sentryInitialized = true
|
||||
|
||||
try {
|
||||
// Dynamic import so @sentry/node is never loaded (or its startup cost
|
||||
// paid) when the feature is off, and so it works under ESM where
|
||||
// require() is not defined.
|
||||
sentryModule = await import('@sentry/node')
|
||||
sentryModule.init({
|
||||
dsn: process.env.SENTRY_DSN,
|
||||
environment: process.env.NODE_ENV ?? 'production',
|
||||
tracesSampleRate: 0,
|
||||
// Disable Sentry's automatic uncaughtException/unhandledRejection
|
||||
// integrations. Those hooks report raw error content, bypassing the
|
||||
// TelemetrySafeError sanitization in reportErrorToSentry(). Only
|
||||
// explicit reportErrorToSentry() calls should ever send data.
|
||||
defaultIntegrations: false,
|
||||
})
|
||||
} catch {
|
||||
// Never let Sentry setup crash the CLI.
|
||||
sentryModule = null
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports an error to Sentry if enabled. Only sends the sanitized
|
||||
* telemetryMessage for TelemetrySafeError instances. Errors that are not
|
||||
* TelemetrySafeError are NOT reported, since their raw message may contain
|
||||
* file paths or other PII — never send an implicit raw error message.
|
||||
*/
|
||||
export function reportErrorToSentry(error: unknown): void {
|
||||
if (!sentryModule || !isSentryEnabled()) {
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
if (error instanceof TelemetrySafeError) {
|
||||
sentryModule.captureMessage(error.telemetryMessage, 'error')
|
||||
}
|
||||
// Non-TelemetrySafeError errors are intentionally not reported — their
|
||||
// message has not been vetted as safe to send.
|
||||
} catch {
|
||||
// Reporting must never throw.
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user