From 9cb9d67969f71c08f7e483a85d28cb919a3fa889 Mon Sep 17 00:00:00 2001 From: jeo-ch Date: Wed, 17 Jun 2026 05:08:12 +0000 Subject: [PATCH 1/7] =?UTF-8?q?feat:=20=E9=A1=B9=E7=9B=AE=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E9=80=BB=E8=BE=91=E4=B8=8E=E5=AE=89=E5=85=A8=E5=88=86?= =?UTF-8?q?=E6=9E=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: traeagent --- package.json | 1 + src/server/config/providerPresets.json | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/package.json b/package.json index b6dba98a25..b664e5b4c8 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "check:desktop": "cd desktop && bun run lint && bun run test -- --run && bun run build", "check:electron": "cd desktop && bun run check:electron", "check:adapters": "cd adapters && bun test", + "check:security": "bun audit 2>/dev/null || npm audit --production 2>/dev/null || echo 'No audit tool available'", "check:native": "cd desktop && bun run build:sidecars && bun run check:electron && CSC_IDENTITY_AUTO_DISCOVERY=false bun run electron:package:dir && cd .. && bun run test:package-smoke:current", "check:docs": "npm ci --loglevel=error && npm run --loglevel=error docs:build", "check:persistence-upgrade": "bun run scripts/quality-gate/persistence-upgrade.ts", diff --git a/src/server/config/providerPresets.json b/src/server/config/providerPresets.json index 86a5cbe4cd..6ff4a83922 100644 --- a/src/server/config/providerPresets.json +++ b/src/server/config/providerPresets.json @@ -185,6 +185,9 @@ "authStrategy": "auth_token_empty_api_key", "defaultEnv": { "ANTHROPIC_AUTH_TOKEN": "lmstudio" + }, + "modelContextWindows": { + "default": 200000 } }, { @@ -204,6 +207,9 @@ "authStrategy": "auth_token_empty_api_key", "defaultEnv": { "ANTHROPIC_AUTH_TOKEN": "ollama" + }, + "modelContextWindows": { + "default": 200000 } }, { From 8a37343271abcdfdc3d20dac2e5a96337cc9d1a5 Mon Sep 17 00:00:00 2001 From: jeo-ch Date: Wed, 17 Jun 2026 05:09:58 +0000 Subject: [PATCH 2/7] =?UTF-8?q?feat:=20=E9=A1=B9=E7=9B=AE=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E9=80=BB=E8=BE=91=E4=B8=8E=E5=AE=89=E5=85=A8=E5=88=86?= =?UTF-8?q?=E6=9E=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: traeagent --- package-lock.json | 468 +++++++++++++++++++++++----------------------- 1 file changed, 234 insertions(+), 234 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4752450d7f..e3363f7964 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1099,13 +1099,13 @@ } }, "node_modules/@aws-sdk/xml-builder": { - "version": "3.972.16", - "resolved": "https://registry.npmmirror.com/@aws-sdk/xml-builder/-/xml-builder-3.972.16.tgz", - "integrity": "sha512-iu2pyvaqmeatIJLURLqx9D+4jKAdTH20ntzB6BFwjyN7V960r4jK32mx0Zf7YbtOYAbmbtQfDNuL60ONinyw7A==", + "version": "3.972.30", + "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.972.30.tgz", + "integrity": "sha512-StElZPEoBquWwNqw1AcfpzEyZqJvFxouG+mpDNYlcH6ZOrqd2CuIryv+8LV8gNHZUOyKyJF3Dq9vxaXEmDR9TQ==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.13.1", - "fast-xml-parser": "5.5.8", + "@smithy/types": "^4.14.3", + "fast-xml-parser": "5.7.3", "tslib": "^2.6.2" }, "engines": { @@ -1187,45 +1187,10 @@ "dev": true, "license": "MIT" }, - "node_modules/@chevrotain/cst-dts-gen": { - "version": "12.0.0", - "resolved": "https://registry.npmmirror.com/@chevrotain/cst-dts-gen/-/cst-dts-gen-12.0.0.tgz", - "integrity": "sha512-fSL4KXjTl7cDgf0B5Rip9Q05BOrYvkJV/RrBTE/bKDN096E4hN/ySpcBK5B24T76dlQ2i32Zc3PAE27jFnFrKg==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@chevrotain/gast": "12.0.0", - "@chevrotain/types": "12.0.0" - } - }, - "node_modules/@chevrotain/gast": { - "version": "12.0.0", - "resolved": "https://registry.npmmirror.com/@chevrotain/gast/-/gast-12.0.0.tgz", - "integrity": "sha512-1ne/m3XsIT8aEdrvT33so0GUC+wkctpUPK6zU9IlOyJLUbR0rg4G7ZiApiJbggpgPir9ERy3FRjT6T7lpgetnQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@chevrotain/types": "12.0.0" - } - }, - "node_modules/@chevrotain/regexp-to-ast": { - "version": "12.0.0", - "resolved": "https://registry.npmmirror.com/@chevrotain/regexp-to-ast/-/regexp-to-ast-12.0.0.tgz", - "integrity": "sha512-p+EW9MaJwgaHguhoqwOtx/FwuGr+DnNn857sXWOi/mClXIkPGl3rn7hGNWvo31HA3vyeQxjqe+H36yZJwYU8cA==", - "dev": true, - "license": "Apache-2.0" - }, "node_modules/@chevrotain/types": { - "version": "12.0.0", - "resolved": "https://registry.npmmirror.com/@chevrotain/types/-/types-12.0.0.tgz", - "integrity": "sha512-S+04vjFQKeuYw0/eW3U52LkAHQsB1ASxsPGsLPUyQgrZ2iNNibQrsidruDzjEX2JYfespXMG0eZmXlhA6z7nWA==", - "dev": true, - "license": "Apache-2.0" - }, - "node_modules/@chevrotain/utils": { - "version": "12.0.0", - "resolved": "https://registry.npmmirror.com/@chevrotain/utils/-/utils-12.0.0.tgz", - "integrity": "sha512-lB59uJoaGIfOOL9knQqQRfhl9g7x8/wqFkp13zTdkRu1huG9kg6IJs1O8hqj9rs6h7orGxHJUKb+mX3rPbWGhA==", + "version": "11.1.2", + "resolved": "https://registry.npmjs.org/@chevrotain/types/-/types-11.1.2.tgz", + "integrity": "sha512-U+HFai5+zmJCkK86QsaJtoITlboZHBqrVketcO2ROv865xfCMSFpELQoz1GkX5GzME8pTa+3kbKrZHQtI0gdbw==", "dev": true, "license": "Apache-2.0" }, @@ -1708,9 +1673,9 @@ } }, "node_modules/@hono/node-server": { - "version": "1.19.12", - "resolved": "https://registry.npmmirror.com/@hono/node-server/-/node-server-1.19.12.tgz", - "integrity": "sha512-txsUW4SQ1iilgE0l9/e9VQWmELXifEFvmdA1j6WFh/aFPj99hIntrSsq/if0UWyGVkmrRPKA1wCeP+UCr1B9Uw==", + "version": "1.19.14", + "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.14.tgz", + "integrity": "sha512-GwtvgtXxnWsucXvbQXkRgqksiH2Qed37H9xHZocE5sA3N8O8O8/8FA3uclQXxXVzc9XBZuEOMK7+r02FmSpHtw==", "license": "MIT", "engines": { "node": ">=18.14.1" @@ -1781,13 +1746,13 @@ "optional": true }, "node_modules/@mermaid-js/parser": { - "version": "1.1.0", - "resolved": "https://registry.npmmirror.com/@mermaid-js/parser/-/parser-1.1.0.tgz", - "integrity": "sha512-gxK9ZX2+Fex5zu8LhRQoMeMPEHbc73UKZ0FQ54YrQtUxE1VVhMwzeNtKRPAu5aXks4FasbMe4xB4bWrmq6Jlxw==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@mermaid-js/parser/-/parser-1.1.1.tgz", + "integrity": "sha512-VuHdsYMK1bT6X2JbcAaWAhugTRvRBRyuZgd+c22swUeI9g/ntaxF7CY7dYarhZovofCbUNO0G7JesfmNtjYOCw==", "dev": true, "license": "MIT", "dependencies": { - "langium": "^4.0.0" + "@chevrotain/types": "~11.1.1" } }, "node_modules/@mixmark-io/domino": { @@ -1836,6 +1801,18 @@ } } }, + "node_modules/@nodable/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@nodable/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-9uGyhaQavEUMC8AIddIjau4NsnsXhou+j5sBAGojCM1oxmQpVKTWR/9JxABD6UAv12vpIms55fPZKFQEhG6uBg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/nodable" + } + ], + "license": "MIT" + }, "node_modules/@opentelemetry/api": { "version": "1.9.1", "resolved": "https://registry.npmmirror.com/@opentelemetry/api/-/api-1.9.1.tgz", @@ -1907,13 +1884,13 @@ } }, "node_modules/@opentelemetry/sdk-metrics": { - "version": "2.6.1", - "resolved": "https://registry.npmmirror.com/@opentelemetry/sdk-metrics/-/sdk-metrics-2.6.1.tgz", - "integrity": "sha512-9t9hJHX15meBy2NmTJxL+NJfXmnausR2xUDvE19XQce0Qi/GBtDGamU8nS1RMbdgDmhgpm3VaOu2+fiS/SfTpQ==", + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-2.8.0.tgz", + "integrity": "sha512-UDBGaj6W0Rgy5rTTaoxs8gVGF/aGkAKyjurJv7se6wjRxJu7FoquTLT/vt54DZfo4crbprYfhX/SOK9+BPw1qg==", "license": "Apache-2.0", "dependencies": { - "@opentelemetry/core": "2.6.1", - "@opentelemetry/resources": "2.6.1" + "@opentelemetry/core": "2.8.0", + "@opentelemetry/resources": "2.8.0" }, "engines": { "node": "^18.19.0 || >=20.6.0" @@ -1922,14 +1899,76 @@ "@opentelemetry/api": ">=1.9.0 <1.10.0" } }, + "node_modules/@opentelemetry/sdk-metrics/node_modules/@opentelemetry/core": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.8.0.tgz", + "integrity": "sha512-hd1Lfh8p545nNz+jq1Ejfz+Mn1hyLuxYn1YzTfFNrxr8urEWMNQLPf1Th8kjOH+HxwawCrtgBp8JpBUR4ZSgww==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-metrics/node_modules/@opentelemetry/resources": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.8.0.tgz", + "integrity": "sha512-qmXQ27ilDbUK/vGMqwL8D4/rhn76C+sherM4wTbjlfknR8Nvfc/hCxjRJPhkzZzUsPiNg16SA31NxMabwttRjg==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.8.0", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, "node_modules/@opentelemetry/sdk-trace-base": { - "version": "2.6.1", - "resolved": "https://registry.npmmirror.com/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.6.1.tgz", - "integrity": "sha512-r86ut4T1e8vNwB35CqCcKd45yzqH6/6Wzvpk2/cZB8PsPLlZFTvrh8yfOS3CYZYcUmAx4hHTZJ8AO8Dj8nrdhw==", + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.8.0.tgz", + "integrity": "sha512-mhU4jp+vW0mGbFRd+GeXHvmfA4aDqWjBjLC3pE5XMpLs0IE2ryYb019Ts2AQrOq67gaTF25D91+fgvEHDZEnuQ==", "license": "Apache-2.0", "dependencies": { - "@opentelemetry/core": "2.6.1", - "@opentelemetry/resources": "2.6.1", + "@opentelemetry/core": "2.8.0", + "@opentelemetry/resources": "2.8.0", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-trace-base/node_modules/@opentelemetry/core": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.8.0.tgz", + "integrity": "sha512-hd1Lfh8p545nNz+jq1Ejfz+Mn1hyLuxYn1YzTfFNrxr8urEWMNQLPf1Th8kjOH+HxwawCrtgBp8JpBUR4ZSgww==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-trace-base/node_modules/@opentelemetry/resources": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.8.0.tgz", + "integrity": "sha512-qmXQ27ilDbUK/vGMqwL8D4/rhn76C+sherM4wTbjlfknR8Nvfc/hCxjRJPhkzZzUsPiNg16SA31NxMabwttRjg==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.8.0", "@opentelemetry/semantic-conventions": "^1.29.0" }, "engines": { @@ -2816,9 +2855,9 @@ } }, "node_modules/@smithy/types": { - "version": "4.13.1", - "resolved": "https://registry.npmmirror.com/@smithy/types/-/types-4.13.1.tgz", - "integrity": "sha512-787F3yzE2UiJIQ+wYW1CVg2odHjmaWLGksnKQHUrK/lYZSEcy1msuLVvxaR/sI2/aDe9U+TBuLsXnr3vod1g0g==", + "version": "4.15.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.15.0.tgz", + "integrity": "sha512-Z5TAOxygoFvybJV3igo5SloFflSokHx2hu1eFA+DxDTcn+FtKxUSui+rbTRG1pAafMA888Z3MVvCWUuvCrTXjg==", "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" @@ -3842,6 +3881,18 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/anynum": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/anynum/-/anynum-1.0.0.tgz", + "integrity": "sha512-xjR9/zBVnUOP6ztMIIgShjsxui80nQUQH+5xJnvrYLs+90bF25/KJqaAi8mk+B4RDtX1Nspi6fmp4YTEts8SfA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT" + }, "node_modules/asciichart": { "version": "1.5.25", "resolved": "https://registry.npmmirror.com/asciichart/-/asciichart-1.5.25.tgz", @@ -3867,16 +3918,42 @@ } }, "node_modules/axios": { - "version": "1.14.0", - "resolved": "https://registry.npmmirror.com/axios/-/axios-1.14.0.tgz", - "integrity": "sha512-3Y8yrqLSwjuzpXuZ0oIYZ/XGgLwUIBU3uLvbcpb0pidD9ctpShJd43KSlEEkVQg6DS0G9NKyzOvBfUtDKEyHvQ==", + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.18.0.tgz", + "integrity": "sha512-E32NzpYKp++W7XRe52rHiXV2ehxmh3wbdgO7MHeFM+vqxLBYHzt0ElkiImtOBxtOmyp0yoC8C6uESVV84Y2/hw==", "license": "MIT", "dependencies": { - "follow-redirects": "^1.15.11", + "follow-redirects": "^1.16.0", "form-data": "^4.0.5", + "https-proxy-agent": "^5.0.1", "proxy-from-env": "^2.1.0" } }, + "node_modules/axios/node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "license": "MIT", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/axios/node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "license": "MIT", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/base64-js": { "version": "1.5.1", "resolved": "https://registry.npmmirror.com/base64-js/-/base64-js-1.5.1.tgz", @@ -4053,36 +4130,6 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/chevrotain": { - "version": "12.0.0", - "resolved": "https://registry.npmmirror.com/chevrotain/-/chevrotain-12.0.0.tgz", - "integrity": "sha512-csJvb+6kEiQaqo1woTdSAuOWdN0WTLIydkKrBnS+V5gZz0oqBrp4kQ35519QgK6TpBThiG3V1vNSHlIkv4AglQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@chevrotain/cst-dts-gen": "12.0.0", - "@chevrotain/gast": "12.0.0", - "@chevrotain/regexp-to-ast": "12.0.0", - "@chevrotain/types": "12.0.0", - "@chevrotain/utils": "12.0.0" - }, - "engines": { - "node": ">=22.0.0" - } - }, - "node_modules/chevrotain-allstar": { - "version": "0.4.1", - "resolved": "https://registry.npmmirror.com/chevrotain-allstar/-/chevrotain-allstar-0.4.1.tgz", - "integrity": "sha512-PvVJm3oGqrveUVW2Vt/eZGeiAIsJszYweUcYwcskg9e+IubNYKKD+rHHem7A6XVO22eDAL+inxNIGAzZ/VIWlA==", - "dev": true, - "license": "MIT", - "dependencies": { - "lodash-es": "^4.17.21" - }, - "peerDependencies": { - "chevrotain": "^12.0.0" - } - }, "node_modules/chokidar": { "version": "5.0.0", "resolved": "https://registry.npmmirror.com/chokidar/-/chokidar-5.0.0.tgz", @@ -5103,9 +5150,9 @@ } }, "node_modules/dompurify": { - "version": "3.4.0", - "resolved": "https://registry.npmmirror.com/dompurify/-/dompurify-3.4.0.tgz", - "integrity": "sha512-nolgK9JcaUXMSmW+j1yaSvaEaoXYHwWyGJlkoCTghc97KgGDDSnpoU/PlEnw63Ah+TGKFOyY+X5LnxaWbCSfXg==", + "version": "3.4.10", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.4.10.tgz", + "integrity": "sha512-0xzNv0e7oYC6yyuOGZIABPM4qtg3QxLFniDNPP4ZP90wR8Yq3zgwpRbrNiT4N3IKqDbbYFEJLV+JWEs19aZ//w==", "dev": true, "license": "(MPL-2.0 OR Apache-2.0)", "optionalDependencies": { @@ -5419,12 +5466,12 @@ } }, "node_modules/express-rate-limit": { - "version": "8.3.2", - "resolved": "https://registry.npmmirror.com/express-rate-limit/-/express-rate-limit-8.3.2.tgz", - "integrity": "sha512-77VmFeJkO0/rvimEDuUC5H30oqUC4EyOhyGccfqoLebB0oiEYfM7nwPrsDsBL1gsTpwfzX8SFy2MT3TDyRq+bg==", + "version": "8.5.2", + "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-8.5.2.tgz", + "integrity": "sha512-5Kb34ipNX694DH48vN9irak1Qx30nb0PLYHXfJgw4YEjiC3ZEmZJhwOp+VfiCYwFzvFTdB9QkArYS5kXa2cx2A==", "license": "MIT", "dependencies": { - "ip-address": "10.1.0" + "ip-address": "^10.2.0" }, "engines": { "node": ">= 16" @@ -5449,9 +5496,9 @@ "license": "MIT" }, "node_modules/fast-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmmirror.com/fast-uri/-/fast-uri-3.1.0.tgz", - "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.2.tgz", + "integrity": "sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ==", "funding": [ { "type": "github", @@ -5465,9 +5512,9 @@ "license": "BSD-3-Clause" }, "node_modules/fast-xml-builder": { - "version": "1.1.4", - "resolved": "https://registry.npmmirror.com/fast-xml-builder/-/fast-xml-builder-1.1.4.tgz", - "integrity": "sha512-f2jhpN4Eccy0/Uz9csxh3Nu6q4ErKxf0XIsasomfOihuSUa3/xw6w8dnOtCDgEItQFJG8KyXPzQXzcODDrrbOg==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fast-xml-builder/-/fast-xml-builder-1.2.0.tgz", + "integrity": "sha512-00aAWieqff+ZJhsXA4g1g7M8k+7AYoMUUHF+/zFb5U6Uv/P0Vl4QZo84/IcufzYalLuEj9928bXN9PbbFzMF0Q==", "funding": [ { "type": "github", @@ -5476,13 +5523,14 @@ ], "license": "MIT", "dependencies": { - "path-expression-matcher": "^1.1.3" + "path-expression-matcher": "^1.5.0", + "xml-naming": "^0.1.0" } }, "node_modules/fast-xml-parser": { - "version": "5.5.8", - "resolved": "https://registry.npmmirror.com/fast-xml-parser/-/fast-xml-parser-5.5.8.tgz", - "integrity": "sha512-Z7Fh2nVQSb2d+poDViM063ix2ZGt9jmY1nWhPfHBOK2Hgnb/OW3P4Et3P/81SEej0J7QbWtJqxO05h8QYfK7LQ==", + "version": "5.7.3", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.7.3.tgz", + "integrity": "sha512-C0AaNuC+mscy6vrAQKAc/rMq+zAPHodfHGZu4sGVehvAQt/JLG1O5zEcYcXSY5zSqr4YVgxsB+pHXTq0i7eDlg==", "funding": [ { "type": "github", @@ -5491,9 +5539,10 @@ ], "license": "MIT", "dependencies": { - "fast-xml-builder": "^1.1.4", - "path-expression-matcher": "^1.2.0", - "strnum": "^2.2.0" + "@nodable/entities": "^2.1.0", + "fast-xml-builder": "^1.1.7", + "path-expression-matcher": "^1.5.0", + "strnum": "^2.2.3" }, "bin": { "fxparser": "src/cli/cli.js" @@ -5602,16 +5651,16 @@ } }, "node_modules/form-data": { - "version": "4.0.5", - "resolved": "https://registry.npmmirror.com/form-data/-/form-data-4.0.5.tgz", - "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.6.tgz", + "integrity": "sha512-vKatAh4SlVfgbv+YtmhiRjhEMJsYpsG1Y2rMQtR+SVSbytsSD1YGzDIcrAJmdFec88u/+VoGmxnl+80gL1tRCQ==", "license": "MIT", "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "es-set-tostringtag": "^2.1.0", - "hasown": "^2.0.2", - "mime-types": "^2.1.12" + "hasown": "^2.0.4", + "mime-types": "^2.1.35" }, "engines": { "node": ">= 6" @@ -5916,9 +5965,9 @@ } }, "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmmirror.com/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", + "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", "license": "MIT", "dependencies": { "function-bind": "^1.1.2" @@ -5975,9 +6024,9 @@ } }, "node_modules/hono": { - "version": "4.12.9", - "resolved": "https://registry.npmmirror.com/hono/-/hono-4.12.9.tgz", - "integrity": "sha512-wy3T8Zm2bsEvxKZM5w21VdHDDcwVS1yUFFY6i8UobSsKfFceT7TOwhbhfKsDyx7tYQlmRM5FLpIuYvNFyjctiA==", + "version": "4.12.25", + "resolved": "https://registry.npmjs.org/hono/-/hono-4.12.25.tgz", + "integrity": "sha512-2NFaIyNVgJmBs/ecmtGzlmluTFs5cHEWGTdu0t1HBwYzoGXOL5nUQBRMXsXWla5i4KkG//QMzVP88m1+I3fdAQ==", "license": "MIT", "engines": { "node": ">=16.9.0" @@ -6198,9 +6247,9 @@ } }, "node_modules/ip-address": { - "version": "10.1.0", - "resolved": "https://registry.npmmirror.com/ip-address/-/ip-address-10.1.0.tgz", - "integrity": "sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==", + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.2.0.tgz", + "integrity": "sha512-/+S6j4E9AHvW9SWMSEY9Xfy66O5PWvVEJ08O0y5JGyEKQpojb0K0GKpz/v5HJ/G0vi3D2sjGK78119oXZeE0qA==", "license": "MIT", "engines": { "node": ">= 12" @@ -6430,25 +6479,6 @@ "integrity": "sha512-Ls993zuzfayK269Svk9hzpeGUKob/sIgZzyHYdjQoAdQetRKpOLj+k/QQQ/6Qi0Yz65mlROrfd+Ev+1+7dz9Kw==", "dev": true }, - "node_modules/langium": { - "version": "4.2.2", - "resolved": "https://registry.npmmirror.com/langium/-/langium-4.2.2.tgz", - "integrity": "sha512-JUshTRAfHI4/MF9dH2WupvjSXyn8JBuUEWazB8ZVJUtXutT0doDlAv1XKbZ1Pb5sMexa8FF4CFBc0iiul7gbUQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@chevrotain/regexp-to-ast": "~12.0.0", - "chevrotain": "~12.0.0", - "chevrotain-allstar": "~0.4.1", - "vscode-languageserver": "~9.0.1", - "vscode-languageserver-textdocument": "~1.0.11", - "vscode-uri": "~3.1.0" - }, - "engines": { - "node": ">=20.10.0", - "npm": ">=10.2.3" - } - }, "node_modules/layout-base": { "version": "1.0.2", "resolved": "https://registry.npmmirror.com/layout-base/-/layout-base-1.0.2.tgz", @@ -6469,9 +6499,9 @@ } }, "node_modules/lodash-es": { - "version": "4.17.23", - "resolved": "https://registry.npmmirror.com/lodash-es/-/lodash-es-4.17.23.tgz", - "integrity": "sha512-kVI48u3PZr38HdYz98UmfPnXl2DXrpdctLrFLCd3kOx1xUkOmpFPx7gCWWM5MPkL/fD8zb+Ph0QzjGFs4+hHWg==", + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.18.1.tgz", + "integrity": "sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A==", "license": "MIT" }, "node_modules/lodash.debounce": { @@ -6592,15 +6622,15 @@ } }, "node_modules/mermaid": { - "version": "11.14.0", - "resolved": "https://registry.npmmirror.com/mermaid/-/mermaid-11.14.0.tgz", - "integrity": "sha512-GSGloRsBs+JINmmhl0JDwjpuezCsHB4WGI4NASHxL3fHo3o/BRXTxhDLKnln8/Q0lRFRyDdEjmk1/d5Sn1Xz8g==", + "version": "11.15.0", + "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-11.15.0.tgz", + "integrity": "sha512-pTMbcf3rWdtLiYGpmoTjHEpeY8seiy6sR+9nD7LOs8KfUbHE4lOUAprTRqRAcWSQ6MQpdX+YEsxShtGsINtPtw==", "dev": true, "license": "MIT", "dependencies": { "@braintree/sanitize-url": "^7.1.1", "@iconify/utils": "^3.0.2", - "@mermaid-js/parser": "^1.1.0", + "@mermaid-js/parser": "^1.1.1", "@types/d3": "^7.4.3", "@upsetjs/venn.js": "^2.0.0", "cytoscape": "^3.33.1", @@ -6611,14 +6641,14 @@ "dagre-d3-es": "7.0.14", "dayjs": "^1.11.19", "dompurify": "^3.3.1", + "es-toolkit": "^1.45.1", "katex": "^0.16.25", "khroma": "^2.1.0", - "lodash-es": "^4.17.23", "marked": "^16.3.0", "roughjs": "^4.6.6", "stylis": "^4.3.6", "ts-dedent": "^2.2.0", - "uuid": "^11.1.0" + "uuid": "^11.1.0 || ^12 || ^13 || ^14.0.0" } }, "node_modules/mermaid/node_modules/marked": { @@ -6796,9 +6826,9 @@ "license": "MIT" }, "node_modules/nanoid": { - "version": "3.3.11", - "resolved": "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.11.tgz", - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "version": "3.3.12", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz", + "integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==", "dev": true, "funding": [ { @@ -7068,9 +7098,9 @@ } }, "node_modules/path-expression-matcher": { - "version": "1.2.0", - "resolved": "https://registry.npmmirror.com/path-expression-matcher/-/path-expression-matcher-1.2.0.tgz", - "integrity": "sha512-DwmPWeFn+tq7TiyJ2CxezCAirXjFxvaiD03npak3cRjlP9+OjTmSy1EpIrEbh+l6JgUundniloMLDQ/6VTdhLQ==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/path-expression-matcher/-/path-expression-matcher-1.5.0.tgz", + "integrity": "sha512-cbrerZV+6rvdQrrD+iGMcZFEiiSrbv9Tfdkvnusy6y0x0GKBXREFg/Y65GhIfm0tnLntThhzCnfKwp1WRjeCyQ==", "funding": [ { "type": "github", @@ -7183,9 +7213,9 @@ } }, "node_modules/postcss": { - "version": "8.5.8", - "resolved": "https://registry.npmmirror.com/postcss/-/postcss-8.5.8.tgz", - "integrity": "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==", + "version": "8.5.15", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz", + "integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==", "dev": true, "funding": [ { @@ -7203,7 +7233,7 @@ ], "license": "MIT", "dependencies": { - "nanoid": "^3.3.11", + "nanoid": "^3.3.12", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" }, @@ -7305,9 +7335,9 @@ } }, "node_modules/qs": { - "version": "6.15.0", - "resolved": "https://registry.npmmirror.com/qs/-/qs-6.15.0.tgz", - "integrity": "sha512-mAZTtNCeetKMH+pSjrb76NAM8V9a05I9aBZOHztWy/UqcJdQYNsf59vrRKWnojAT9Y+GbIvoTBC++CPHqpDBhQ==", + "version": "6.15.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.2.tgz", + "integrity": "sha512-Rzq0KEyX/w/tEybncDgdkZrJgVUsUMk3xjh3t5bv3S1HTAtg+uOYt72+ZfwiQwKdysThkTBdL/rTi6HDmX9Ddw==", "license": "BSD-3-Clause", "dependencies": { "side-channel": "^1.1.0" @@ -7688,9 +7718,9 @@ } }, "node_modules/shell-quote": { - "version": "1.8.3", - "resolved": "https://registry.npmmirror.com/shell-quote/-/shell-quote-1.8.3.tgz", - "integrity": "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==", + "version": "1.8.4", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.4.tgz", + "integrity": "sha512-VsC6n6vz1ihYYyZZwX7YZSF5l5x36ca17OC+a69h94YqB7X6XLwf+5MOgynYir2SLFUbl8gIYvBo8K8RoNQ6bQ==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -7927,16 +7957,19 @@ } }, "node_modules/strnum": { - "version": "2.2.2", - "resolved": "https://registry.npmmirror.com/strnum/-/strnum-2.2.2.tgz", - "integrity": "sha512-DnR90I+jtXNSTXWdwrEy9FakW7UX+qUZg28gj5fk2vxxl7uS/3bpI4fjFYVmdK9etptYBPNkpahuQnEwhwECqA==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-2.4.0.tgz", + "integrity": "sha512-sHrVyWWdq28RbhjuJdZsA1SnGRJV6NiXbk6AXBxDOsgAcA+lmpUZCYjOdLBxkXMwis6RRe7dlZt4VlIWFVzkmg==", "funding": [ { "type": "github", "url": "https://github.com/sponsors/NaturalIntelligence" } ], - "license": "MIT" + "license": "MIT", + "dependencies": { + "anynum": "^1.0.0" + } }, "node_modules/stylis": { "version": "4.3.6", @@ -8246,9 +8279,9 @@ } }, "node_modules/uuid": { - "version": "11.1.0", - "resolved": "https://registry.npmmirror.com/uuid/-/uuid-11.1.0.tgz", - "integrity": "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==", + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-14.0.0.tgz", + "integrity": "sha512-Qo+uWgilfSmAhXCMav1uYFynlQO7fMFiMVZsQqZRMIXp0O7rR7qjkj+cPvBHLgBqi960QCoo/PH2/6ZtVqKvrg==", "dev": true, "funding": [ "https://github.com/sponsors/broofa", @@ -8256,7 +8289,7 @@ ], "license": "MIT", "bin": { - "uuid": "dist/esm/bin/uuid" + "uuid": "dist-node/bin/uuid" } }, "node_modules/vary": { @@ -8423,60 +8456,12 @@ "node": ">=14.0.0" } }, - "node_modules/vscode-languageserver": { - "version": "9.0.1", - "resolved": "https://registry.npmmirror.com/vscode-languageserver/-/vscode-languageserver-9.0.1.tgz", - "integrity": "sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g==", - "dev": true, - "license": "MIT", - "dependencies": { - "vscode-languageserver-protocol": "3.17.5" - }, - "bin": { - "installServerIntoExtension": "bin/installServerIntoExtension" - } - }, - "node_modules/vscode-languageserver-protocol": { - "version": "3.17.5", - "resolved": "https://registry.npmmirror.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.5.tgz", - "integrity": "sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==", - "dev": true, - "license": "MIT", - "dependencies": { - "vscode-jsonrpc": "8.2.0", - "vscode-languageserver-types": "3.17.5" - } - }, - "node_modules/vscode-languageserver-protocol/node_modules/vscode-jsonrpc": { - "version": "8.2.0", - "resolved": "https://registry.npmmirror.com/vscode-jsonrpc/-/vscode-jsonrpc-8.2.0.tgz", - "integrity": "sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/vscode-languageserver-textdocument": { - "version": "1.0.12", - "resolved": "https://registry.npmmirror.com/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.12.tgz", - "integrity": "sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA==", - "dev": true, - "license": "MIT" - }, "node_modules/vscode-languageserver-types": { "version": "3.17.5", "resolved": "https://registry.npmmirror.com/vscode-languageserver-types/-/vscode-languageserver-types-3.17.5.tgz", "integrity": "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==", "license": "MIT" }, - "node_modules/vscode-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmmirror.com/vscode-uri/-/vscode-uri-3.1.0.tgz", - "integrity": "sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==", - "dev": true, - "license": "MIT" - }, "node_modules/vue": { "version": "3.5.32", "resolved": "https://registry.npmmirror.com/vue/-/vue-3.5.32.tgz", @@ -8568,9 +8553,9 @@ "license": "ISC" }, "node_modules/ws": { - "version": "8.20.0", - "resolved": "https://registry.npmmirror.com/ws/-/ws-8.20.0.tgz", - "integrity": "sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA==", + "version": "8.21.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz", + "integrity": "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==", "license": "MIT", "engines": { "node": ">=10.0.0" @@ -8588,6 +8573,21 @@ } } }, + "node_modules/xml-naming": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/xml-naming/-/xml-naming-0.1.0.tgz", + "integrity": "sha512-k8KO9hrMyNk6tUWqUfkTEZbezRRpONVOzUTnc97VnCvyj6Tf9lyUR9EDAIeiVLv56jsMcoXEwjW8Kv5yPY52lw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "engines": { + "node": ">=16.0.0" + } + }, "node_modules/xss": { "version": "1.0.15", "resolved": "https://registry.npmmirror.com/xss/-/xss-1.0.15.tgz", From 8539d935fba4007020e522cba465aae91329076e Mon Sep 17 00:00:00 2001 From: jeo-ch Date: Wed, 17 Jun 2026 05:11:04 +0000 Subject: [PATCH 3/7] =?UTF-8?q?feat:=20=E9=A1=B9=E7=9B=AE=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E9=80=BB=E8=BE=91=E4=B8=8E=E5=AE=89=E5=85=A8=E5=88=86?= =?UTF-8?q?=E6=9E=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: traeagent --- package-lock.json | 133 ++++++++++++++++++---------------------------- package.json | 4 +- 2 files changed, 55 insertions(+), 82 deletions(-) diff --git a/package-lock.json b/package-lock.json index e3363f7964..73fd9808b0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "999.0.0-local", "dependencies": { "@anthropic-ai/sandbox-runtime": "^0.0.44", - "@anthropic-ai/sdk": "^0.80.0", + "@anthropic-ai/sdk": "^0.104.2", "@aws-sdk/client-bedrock-runtime": "^3.1020.0", "@commander-js/extra-typings": "^14.0.0", "@growthbook/growthbook": "^1.6.5", @@ -17,7 +17,7 @@ "@opentelemetry/api-logs": "^0.214.0", "@opentelemetry/core": "^2.6.1", "@opentelemetry/resources": "^2.6.1", - "@opentelemetry/sdk-logs": "^0.214.0", + "@opentelemetry/sdk-logs": "^0.219.0", "@opentelemetry/sdk-metrics": "^2.6.1", "@opentelemetry/sdk-trace-base": "^2.6.1", "@opentelemetry/semantic-conventions": "^1.40.0", @@ -407,12 +407,13 @@ } }, "node_modules/@anthropic-ai/sdk": { - "version": "0.80.0", - "resolved": "https://registry.npmmirror.com/@anthropic-ai/sdk/-/sdk-0.80.0.tgz", - "integrity": "sha512-WeXLn7zNVk3yjeshn+xZHvld6AoFUOR3Sep6pSoHho5YbSi6HwcirqgPA5ccFuW8QTVJAAU7N8uQQC6Wa9TG+g==", + "version": "0.104.2", + "resolved": "https://registry.npmjs.org/@anthropic-ai/sdk/-/sdk-0.104.2.tgz", + "integrity": "sha512-s1wEVDAtEwkS7Ajgep6PZKJLFqybRkmD3Byz+iVVsSpbDY0gjROXE9aOft6V3PMqynn3NTcycV5whga9tCzmKA==", "license": "MIT", "dependencies": { - "json-schema-to-ts": "^3.1.1" + "json-schema-to-ts": "^3.1.1", + "standardwebhooks": "^1.0.0" }, "bin": { "anthropic-ai-sdk": "bin/cli" @@ -1835,9 +1836,9 @@ } }, "node_modules/@opentelemetry/core": { - "version": "2.6.1", - "resolved": "https://registry.npmmirror.com/@opentelemetry/core/-/core-2.6.1.tgz", - "integrity": "sha512-8xHSGWpJP9wBxgBpnqGL0R3PbdWQndL1Qp50qrg71+B28zK5OQmUgcDKLJgzyAAV38t4tOyLMGDD60LneR5W8g==", + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.8.0.tgz", + "integrity": "sha512-hd1Lfh8p545nNz+jq1Ejfz+Mn1hyLuxYn1YzTfFNrxr8urEWMNQLPf1Th8kjOH+HxwawCrtgBp8JpBUR4ZSgww==", "license": "Apache-2.0", "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" @@ -1850,12 +1851,12 @@ } }, "node_modules/@opentelemetry/resources": { - "version": "2.6.1", - "resolved": "https://registry.npmmirror.com/@opentelemetry/resources/-/resources-2.6.1.tgz", - "integrity": "sha512-lID/vxSuKWXM55XhAKNoYXu9Cutoq5hFdkbTdI/zDKQktXzcWBVhNsOkiZFTMU9UtEWuGRNe0HUgmsFldIdxVA==", + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.8.0.tgz", + "integrity": "sha512-qmXQ27ilDbUK/vGMqwL8D4/rhn76C+sherM4wTbjlfknR8Nvfc/hCxjRJPhkzZzUsPiNg16SA31NxMabwttRjg==", "license": "Apache-2.0", "dependencies": { - "@opentelemetry/core": "2.6.1", + "@opentelemetry/core": "2.8.0", "@opentelemetry/semantic-conventions": "^1.29.0" }, "engines": { @@ -1866,14 +1867,14 @@ } }, "node_modules/@opentelemetry/sdk-logs": { - "version": "0.214.0", - "resolved": "https://registry.npmmirror.com/@opentelemetry/sdk-logs/-/sdk-logs-0.214.0.tgz", - "integrity": "sha512-zf6acnScjhsaBUU22zXZ/sLWim1dfhUAbGXdMmHmNG3LfBnQ3DKsOCITb2IZwoUsNNMTogqFKBnlIPPftUgGwA==", + "version": "0.219.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-logs/-/sdk-logs-0.219.0.tgz", + "integrity": "sha512-s6lTKRakaPClvKoWHRChxnXjDMkM/TQ30ff78jN6EBGf7MI7VzANE5PU3f4z9qDUudWjvZjOLHG0rBnBKYvoXA==", "license": "Apache-2.0", "dependencies": { - "@opentelemetry/api-logs": "0.214.0", - "@opentelemetry/core": "2.6.1", - "@opentelemetry/resources": "2.6.1", + "@opentelemetry/api-logs": "0.219.0", + "@opentelemetry/core": "2.8.0", + "@opentelemetry/resources": "2.8.0", "@opentelemetry/semantic-conventions": "^1.29.0" }, "engines": { @@ -1883,51 +1884,32 @@ "@opentelemetry/api": ">=1.4.0 <1.10.0" } }, - "node_modules/@opentelemetry/sdk-metrics": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-2.8.0.tgz", - "integrity": "sha512-UDBGaj6W0Rgy5rTTaoxs8gVGF/aGkAKyjurJv7se6wjRxJu7FoquTLT/vt54DZfo4crbprYfhX/SOK9+BPw1qg==", + "node_modules/@opentelemetry/sdk-logs/node_modules/@opentelemetry/api-logs": { + "version": "0.219.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.219.0.tgz", + "integrity": "sha512-FFx7YnaYJlIjqWW/AG/yAZ0L/NEY724PipXXXQLdtZPbLwBGbUMTGL1i/esI56TWfTUXxhLfpgrnWJCG8aUJyg==", "license": "Apache-2.0", "dependencies": { - "@opentelemetry/core": "2.8.0", - "@opentelemetry/resources": "2.8.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.9.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/sdk-metrics/node_modules/@opentelemetry/core": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.8.0.tgz", - "integrity": "sha512-hd1Lfh8p545nNz+jq1Ejfz+Mn1hyLuxYn1YzTfFNrxr8urEWMNQLPf1Th8kjOH+HxwawCrtgBp8JpBUR4ZSgww==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/semantic-conventions": "^1.29.0" + "@opentelemetry/api": "^1.3.0" }, "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.10.0" + "node": ">=8.0.0" } }, - "node_modules/@opentelemetry/sdk-metrics/node_modules/@opentelemetry/resources": { + "node_modules/@opentelemetry/sdk-metrics": { "version": "2.8.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.8.0.tgz", - "integrity": "sha512-qmXQ27ilDbUK/vGMqwL8D4/rhn76C+sherM4wTbjlfknR8Nvfc/hCxjRJPhkzZzUsPiNg16SA31NxMabwttRjg==", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-2.8.0.tgz", + "integrity": "sha512-UDBGaj6W0Rgy5rTTaoxs8gVGF/aGkAKyjurJv7se6wjRxJu7FoquTLT/vt54DZfo4crbprYfhX/SOK9+BPw1qg==", "license": "Apache-2.0", "dependencies": { "@opentelemetry/core": "2.8.0", - "@opentelemetry/semantic-conventions": "^1.29.0" + "@opentelemetry/resources": "2.8.0" }, "engines": { "node": "^18.19.0 || >=20.6.0" }, "peerDependencies": { - "@opentelemetry/api": ">=1.3.0 <1.10.0" + "@opentelemetry/api": ">=1.9.0 <1.10.0" } }, "node_modules/@opentelemetry/sdk-trace-base": { @@ -1947,37 +1929,6 @@ "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, - "node_modules/@opentelemetry/sdk-trace-base/node_modules/@opentelemetry/core": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.8.0.tgz", - "integrity": "sha512-hd1Lfh8p545nNz+jq1Ejfz+Mn1hyLuxYn1YzTfFNrxr8urEWMNQLPf1Th8kjOH+HxwawCrtgBp8JpBUR4ZSgww==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/sdk-trace-base/node_modules/@opentelemetry/resources": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.8.0.tgz", - "integrity": "sha512-qmXQ27ilDbUK/vGMqwL8D4/rhn76C+sherM4wTbjlfknR8Nvfc/hCxjRJPhkzZzUsPiNg16SA31NxMabwttRjg==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.8.0", - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.3.0 <1.10.0" - } - }, "node_modules/@opentelemetry/semantic-conventions": { "version": "1.40.0", "resolved": "https://registry.npmmirror.com/@opentelemetry/semantic-conventions/-/semantic-conventions-1.40.0.tgz", @@ -3085,6 +3036,12 @@ "node": ">=18.0.0" } }, + "node_modules/@stablelib/base64": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/base64/-/base64-1.0.1.tgz", + "integrity": "sha512-1bnPQqSxSuc3Ii6MhBysoWCg58j97aUjuCSZrGSmDxNqtytIi0k8utUenAwTZN4V5mXXYGsVUI9zeBqy+jBOSQ==", + "license": "MIT" + }, "node_modules/@types/d3": { "version": "7.4.3", "resolved": "https://registry.npmmirror.com/@types/d3/-/d3-7.4.3.tgz", @@ -5495,6 +5452,12 @@ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "license": "MIT" }, + "node_modules/fast-sha256": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-sha256/-/fast-sha256-1.3.0.tgz", + "integrity": "sha512-n11RGP/lrWEFI/bWdygLxhI+pVeo1ZYIVwvvPkW7azl/rOy+F3HYRZ2K5zeE9mmkhQppyv9sQFx0JM9UabnpPQ==", + "license": "Unlicense" + }, "node_modules/fast-uri": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.2.tgz", @@ -7889,6 +7852,16 @@ "node": ">=10" } }, + "node_modules/standardwebhooks": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/standardwebhooks/-/standardwebhooks-1.0.0.tgz", + "integrity": "sha512-BbHGOQK9olHPMvQNHWul6MYlrRTAOKn03rOe4A8O3CLWhNf4YHBqq2HJKKC+sfqpxiBY52pNeesD6jIiLDz8jg==", + "license": "MIT", + "dependencies": { + "@stablelib/base64": "^1.0.0", + "fast-sha256": "^1.3.0" + } + }, "node_modules/statuses": { "version": "2.0.2", "resolved": "https://registry.npmmirror.com/statuses/-/statuses-2.0.2.tgz", diff --git a/package.json b/package.json index b664e5b4c8..a0fb0abf23 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,7 @@ }, "dependencies": { "@anthropic-ai/sandbox-runtime": "^0.0.44", - "@anthropic-ai/sdk": "^0.80.0", + "@anthropic-ai/sdk": "^0.104.2", "@aws-sdk/client-bedrock-runtime": "^3.1020.0", "@commander-js/extra-typings": "^14.0.0", "@growthbook/growthbook": "^1.6.5", @@ -48,7 +48,7 @@ "@opentelemetry/api-logs": "^0.214.0", "@opentelemetry/core": "^2.6.1", "@opentelemetry/resources": "^2.6.1", - "@opentelemetry/sdk-logs": "^0.214.0", + "@opentelemetry/sdk-logs": "^0.219.0", "@opentelemetry/sdk-metrics": "^2.6.1", "@opentelemetry/sdk-trace-base": "^2.6.1", "@opentelemetry/semantic-conventions": "^1.40.0", From c79800988fc73edfe1e6cebf3557ea487eb6cd73 Mon Sep 17 00:00:00 2001 From: jeo-ch Date: Wed, 17 Jun 2026 05:30:34 +0000 Subject: [PATCH 4/7] =?UTF-8?q?feat:=20=E9=A1=B9=E7=9B=AE=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E9=80=BB=E8=BE=91=E4=B8=8E=E5=AE=89=E5=85=A8=E5=88=86?= =?UTF-8?q?=E6=9E=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: traeagent --- .github/workflows/ci.yml | 53 ++++++++++++++++++++++++++++++++++++ .github/workflows/codeql.yml | 53 ++++++++++++++++++++++++++++++++++++ 2 files changed, 106 insertions(+) create mode 100644 .github/workflows/ci.yml create mode 100644 .github/workflows/codeql.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000000..bde795ee9e --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,53 @@ +name: CI + +on: + push: + branches: [main] + pull_request: + types: [opened, synchronize, reopened, ready_for_review] + +permissions: + contents: read + +concurrency: + group: ci-${{ github.ref }} + cancel-in-progress: true + +jobs: + server-checks: + name: server-checks + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Bun + uses: oven-sh/setup-bun@v2 + with: + bun-version: latest + + - name: Install dependencies + run: bun install + + - name: Run server checks + run: bun run check:server + + adapter-tests: + name: adapter-tests + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Bun + uses: oven-sh/setup-bun@v2 + with: + bun-version: latest + + - name: Install adapter dependencies + working-directory: adapters + run: bun install + + - name: Run adapter tests + working-directory: adapters + run: bun test diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 0000000000..cb562da334 --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,53 @@ +name: CodeQL Advanced + +on: + push: + branches: [main] + pull_request: + types: [opened, synchronize, reopened, ready_for_review] + +permissions: + actions: read + contents: read + security-events: write + +concurrency: + group: codeql-${{ github.ref }} + cancel-in-progress: true + +jobs: + codeql: + name: codeql + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Bun + uses: oven-sh/setup-bun@v2 + with: + bun-version: latest + + - name: Install dependencies + run: bun install + + - name: Initialize CodeQL + uses: github/codeql-action/init-action@v3 + with: + languages: javascript + typescript + build-mode: manual + ram: 4096 + + - name: Build + run: | + bun run build || true + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze-action@v3 + with: + category: "/language:javascript-typescript" From 1fbe385682df2c77fc3106edb6daf985c472e96a Mon Sep 17 00:00:00 2001 From: jeo-ch Date: Wed, 17 Jun 2026 05:35:15 +0000 Subject: [PATCH 5/7] feat(ci): add dependency updates, lock-threads, and sweep workflows --- .github/workflows/dependency-updates.yml | 71 ++++++++++++++++++++++++ .github/workflows/lock-closed-issues.yml | 26 +++++++++ .github/workflows/sweep.yml | 42 ++++++++++++++ 3 files changed, 139 insertions(+) create mode 100644 .github/workflows/dependency-updates.yml create mode 100644 .github/workflows/lock-closed-issues.yml create mode 100644 .github/workflows/sweep.yml diff --git a/.github/workflows/dependency-updates.yml b/.github/workflows/dependency-updates.yml new file mode 100644 index 0000000000..0857f83734 --- /dev/null +++ b/.github/workflows/dependency-updates.yml @@ -0,0 +1,71 @@ +name: Dependency Updates + +on: + schedule: + - cron: '0 0 * * MON' + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: dependency-updates-${{ github.ref }} + cancel-in-progress: true + +jobs: + check-outdated: + name: check-outdated + runs-on: ubuntu-latest + permissions: + contents: read + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Bun + uses: oven-sh/setup-bun@v2 + with: + bun-version: latest + + - name: Install dependencies + run: bun install + + - name: Check outdated packages (root) + run: bun outdated || true + + - name: Install adapter dependencies + working-directory: adapters + run: bun install + + - name: Check outdated packages (adapters) + working-directory: adapters + run: bun outdated || true + + npm-audit: + name: npm-audit + runs-on: ubuntu-latest + permissions: + contents: read + security-events: write + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Bun + uses: oven-sh/setup-bun@v2 + with: + bun-version: latest + + - name: Install dependencies + run: bun install + + - name: Run npm audit + run: npm audit --json > /tmp/audit-report.json || true + + - name: Show audit summary + run: npm audit || true + + - name: Fail on high severity vulnerabilities + run: | + HIGH=$(npm audit --audit-level=high 2>&1; echo "exit:$?") + echo "$HIGH" diff --git a/.github/workflows/lock-closed-issues.yml b/.github/workflows/lock-closed-issues.yml new file mode 100644 index 0000000000..78205c4241 --- /dev/null +++ b/.github/workflows/lock-closed-issues.yml @@ -0,0 +1,26 @@ +name: Lock Closed Issues + +on: + schedule: + - cron: '0 0 * * 0' + workflow_dispatch: + +permissions: + issues: write + +concurrency: + group: lock-closed-issues + cancel-in-progress: true + +jobs: + lock-closed-issues: + name: lock-closed-issues + runs-on: ubuntu-latest + steps: + - name: Lock closed issues + uses: dessant/lock-threads@v5 + with: + github-token: ${{ github.token }} + issue-inactive-days: '30' + pr-inactive-days: '90' + process-only: 'issues, prs' diff --git a/.github/workflows/sweep.yml b/.github/workflows/sweep.yml new file mode 100644 index 0000000000..4c5c70dc06 --- /dev/null +++ b/.github/workflows/sweep.yml @@ -0,0 +1,42 @@ +name: Sweep + +on: + schedule: + - cron: '0 0 * * 1' + workflow_dispatch: + +permissions: + issues: write + pull-requests: write + +concurrency: + group: sweep + cancel-in-progress: true + +jobs: + sweep: + name: sweep + runs-on: ubuntu-latest + steps: + - name: Stale issues and PRs + uses: actions/stale@v9 + with: + days-before-issue-stale: 60 + days-before-issue-close: 7 + stale-issue-label: stale + stale-issue-message: > + This issue is stale because it has been open for 60 days with no + activity. If this is still an issue, please add a comment with an + update. Otherwise this issue will be closed in 7 days. + close-issue-message: This issue was closed because it has been stalled for 7 days with no activity. + days-before-pr-stale: 45 + days-before-pr-close: 10 + stale-pr-label: stale + stale-pr-message: > + This pull request is stale because it has been open for 45 days with + no activity. If you are still working on this, please add a comment + with an update. Otherwise this pull request will be closed in 10 days. + close-pr-message: This pull request was closed because it has been stalled for 10 days with no activity. + operations-per-run: 100 + exempt-all-milestones: true + exempt-all-assignees: true From f2b4356b8f27433572b193ecb1022eeddd4b2c77 Mon Sep 17 00:00:00 2001 From: jeo-ch Date: Wed, 17 Jun 2026 05:56:41 +0000 Subject: [PATCH 6/7] =?UTF-8?q?feat:=20=E9=A1=B9=E7=9B=AE=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E9=80=BB=E8=BE=91=E4=B8=8E=E5=AE=89=E5=85=A8=E5=88=86?= =?UTF-8?q?=E6=9E=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: traeagent --- src/server/config/providerPresets.json | 89 ++++++++++++++++ src/server/services/providerService.ts | 87 +++++++++++++++- src/server/types/provider.ts | 2 + src/utils/i18n/index.ts | 97 +++++++++++++++++ src/utils/i18n/locales/en.ts | 43 ++++++++ src/utils/i18n/locales/zh_CN.ts | 42 ++++++++ src/utils/i18n/locales/zh_TW.ts | 42 ++++++++ src/utils/permissions/filesystem.ts | 109 ++++++++++++++++++++ src/utils/secureStorage/index.ts | 13 ++- src/utils/secureStorage/libsecretStorage.ts | 104 +++++++++++++++++++ src/utils/secureStorage/plainTextStorage.ts | 3 +- 11 files changed, 624 insertions(+), 7 deletions(-) create mode 100644 src/utils/i18n/index.ts create mode 100644 src/utils/i18n/locales/en.ts create mode 100644 src/utils/i18n/locales/zh_CN.ts create mode 100644 src/utils/i18n/locales/zh_TW.ts create mode 100644 src/utils/secureStorage/libsecretStorage.ts diff --git a/src/server/config/providerPresets.json b/src/server/config/providerPresets.json index 6ff4a83922..f2f9663901 100644 --- a/src/server/config/providerPresets.json +++ b/src/server/config/providerPresets.json @@ -212,6 +212,95 @@ "default": 200000 } }, + { + "id": "llamafile", + "name": "llamafile", + "baseUrl": "http://localhost:8080", + "apiFormat": "openai_chat", + "defaultModels": { + "main": "LLaMA_CPP", + "haiku": "LLaMA_CPP", + "sonnet": "LLaMA_CPP", + "opus": "LLaMA_CPP" + }, + "needsApiKey": false, + "websiteUrl": "https://github.com/Mozilla-Ocho/llamafile", + "promoText": "llamafile 提供 openai_chat 兼容协议,默认端口为 http://localhost:8080。Base URL 填 http://localhost:8080,不要追加 /v1。启动命令示例:./my-model.llamafile --server --nobrowser -ngl 9999。", + "authStrategy": "dual_dummy", + "defaultEnv": { + "ANTHROPIC_AUTH_TOKEN": "llamafile", + "ANTHROPIC_API_KEY": "llamafile" + }, + "modelContextWindows": { + "default": 200000 + } + }, + { + "id": "vllm", + "name": "vLLM", + "baseUrl": "http://localhost:8000", + "apiFormat": "anthropic", + "defaultModels": { + "main": "qwen2.5-72b-instruct-awq", + "haiku": "qwen2.5-72b-instruct-awq", + "sonnet": "qwen2.5-72b-instruct-awq", + "opus": "qwen2.5-72b-instruct-awq" + }, + "needsApiKey": false, + "websiteUrl": "https://docs.vllm.ai/en/latest/serving/openai_compatible_server.html", + "promoText": "vLLM 支持 Anthropic 兼容协议,默认端口为 http://localhost:8000。Base URL 填 http://localhost:8000,不要追加 /v1。启动命令示例:vllm serve qwen/qwen3.6-27b-instruct --api-key token-abc123。", + "authStrategy": "auth_token_empty_api_key", + "defaultEnv": { + "ANTHROPIC_AUTH_TOKEN": "vllm" + }, + "modelContextWindows": { + "default": 200000 + } + }, + { + "id": "sglang", + "name": "SGLang", + "baseUrl": "http://localhost:30000", + "apiFormat": "anthropic", + "defaultModels": { + "main": "default", + "haiku": "default", + "sonnet": "default", + "opus": "default" + }, + "needsApiKey": false, + "websiteUrl": "https://sglang.readthedocs.io/en/latest/serving/openai_compatible_server.html", + "promoText": "SGLang 支持 Anthropic 兼容协议,默认端口为 http://localhost:30000。Base URL 填 http://localhost:30000,不要追加 /v1。启动命令示例:python -m sglang.launch_server --model-path qwen/qwen3.6-27b-instruct --port 30000。", + "authStrategy": "auth_token_empty_api_key", + "defaultEnv": { + "ANTHROPIC_AUTH_TOKEN": "sglang" + }, + "modelContextWindows": { + "default": 200000 + } + }, + { + "id": "jan", + "name": "Jan", + "baseUrl": "http://localhost:1337", + "apiFormat": "openai_chat", + "defaultModels": { + "main": "@cf/meta/llama-3-8b-instruct", + "haiku": "@cf/meta/llama-3-8b-instruct", + "sonnet": "@cf/meta/llama-3-8b-instruct", + "opus": "@cf/meta/llama-3-8b-instruct" + }, + "needsApiKey": false, + "websiteUrl": "https://jan.ai", + "promoText": "Jan 本地引擎兼容 openai_chat 协议,默认端口为 http://localhost:1337。Base URL 填 http://localhost:1337/v1。请在 Jan 设置中启用 Local API Server。", + "authStrategy": "auth_token_empty_api_key", + "defaultEnv": { + "ANTHROPIC_AUTH_TOKEN": "jan" + }, + "modelContextWindows": { + "default": 131072 + } + }, { "id": "custom", "name": "Custom", diff --git a/src/server/services/providerService.ts b/src/server/services/providerService.ts index 80504267c9..5fdc5a0cd1 100644 --- a/src/server/services/providerService.ts +++ b/src/server/services/providerService.ts @@ -42,6 +42,7 @@ import { type NetworkSettings, } from './networkSettings.js' import { normalizeModelStringForAPI } from '../../utils/model/model.js' +import { t } from '../../utils/i18n/index.js' import type { SavedProvider, ProvidersIndex, @@ -563,6 +564,7 @@ export class ProviderService { const base = input.baseUrl.replace(/\/+$/, '') const modelId = normalizeModelStringForAPI(input.modelId) const networkSettings = await loadNetworkSettings() + const isLocal = isLocalModelServer(base) // ── Step 1: Basic connectivity ─────────────────────────── // Directly call the upstream API to verify URL, key, and model. @@ -570,19 +572,32 @@ export class ProviderService { // If connectivity failed, no point running step 2 if (!step1.success) { - return { connectivity: step1 } + // Enrich the error with a local-model hint so the UI can nudge the + // operator to check their server. + const hint = isLocal + ? `${step1.error || 'Connection refused'}\n(Hint: ${base} appears to be a local model server — confirm it is running and listening on this port.)` + : step1.error + return { + connectivity: { ...step1, error: hint } + } } + // Optional local-model probe — list available models for UX + const availableModels = isLocal + ? await probeAvailableModels(base, input.apiKey, authStrategy, networkSettings).catch(() => null) + : null + // For native Anthropic format, no proxy pipeline to test if (format === 'anthropic') { - return { connectivity: step1 } + return { + connectivity: step1, availableModels } } // ── Step 2: Full proxy pipeline ────────────────────────── // Anthropic request → transform → upstream → transform back → validate const step2 = await this.testProxyPipeline(base, input.apiKey, modelId, format, networkSettings) - return { connectivity: step1, proxy: step2 } + return { connectivity: step1, proxy: step2, availableModels } } /** Step 1: Direct upstream call to verify connectivity, auth, and model. */ @@ -627,7 +642,12 @@ export class ProviderService { } catch (err: unknown) { const latencyMs = Date.now() - start if (err instanceof DOMException && err.name === 'TimeoutError') { - return { success: false, latencyMs, error: `Request timed out (${Math.round(networkSettings.aiRequestTimeoutMs / 1000)}s)`, modelUsed: modelId } + return { + success: false, + latencyMs, + error: t('provider_test_timeout', { seconds: Math.round(networkSettings.aiRequestTimeoutMs / 1000) }), + modelUsed: modelId, + } } return { success: false, latencyMs, error: err instanceof Error ? err.message : String(err), modelUsed: modelId } } @@ -705,6 +725,65 @@ export class ProviderService { // ─── Helpers ─────────────────────────────────────────────── +/** + * Heuristic detection for a local model server. + * + * Any of the following is treated as "local": + * - hostname is `localhost` / `127.0.0.1` / `::1` + * - hostname resolves to a loopback address + * - baseUrl matches one of the well-known local-model ports (1234, 11434, + * 8000, 30000, 1337, 8080, 2242) + * + * Used to emit a hint to the user that the server must be running before + * the provider can be tested/activated. The check is intentionally broad. + */ +export function isLocalModelServer(baseUrl: string): boolean { + try { + const u = new URL(baseUrl) + const host = u.hostname.toLowerCase() + if (host === 'localhost' || host === '127.0.0.1' || host === '::1') return true + if (host.startsWith('127.')) return true + const localPorts = new Set([ + '1234', '11434', '8000', '30000', '1337', '8080', '2242', + ]) + return localPorts.has(u.port) + } catch { + return false + } +} + +/** + * Probe the upstream `/v1/models` endpoint if available. + * + * Returns the list of exposed model names (or `null` when the endpoint is + * missing/unauthorized). Local-model runtimes commonly expose this. We use + * the same Content-Type / Authorization headers the regular request uses, + * matching the upstream's expectations. + */ +export async function probeAvailableModels( + base: string, + apiKey: string, + authStrategy: ProviderAuthStrategy, + networkSettings: NetworkSettings, + signal?: AbortSignal, +): Promise { + try { + const proxyOptions = getProxyFetchOptions({ proxyUrl: getManualNetworkProxyUrl(networkSettings) }) + const response = await fetch(`${base}/v1/models`, { + method: 'GET', + headers: buildAnthropicAuthHeaders(apiKey, authStrategy), + signal: signal ?? AbortSignal.timeout(Math.min(networkSettings.aiRequestTimeoutMs, 5000)), + ...proxyOptions, + }) + if (!response.ok) return null + const json = await response.json().catch(() => null) as { data?: Array<{ id?: string }> } | null + if (!json?.data || !Array.isArray(json.data)) return null + return json.data.map((m) => m.id).filter((id): id is string => !!id) + } catch { + return null + } +} + function buildDirectTestRequest( base: string, apiKey: string, diff --git a/src/server/types/provider.ts b/src/server/types/provider.ts index acd765f190..6054b8b4c9 100644 --- a/src/server/types/provider.ts +++ b/src/server/types/provider.ts @@ -149,4 +149,6 @@ export interface ProviderTestResult { connectivity: ProviderTestStepResult /** Step 2: Proxy pipeline — full Anthropic→OpenAI→Anthropic round-trip (only for openai_* formats) */ proxy?: ProviderTestStepResult + /** Optional list of exposed model names (local-model servers /v1/models probe) */ + availableModels?: string[] | null } diff --git a/src/utils/i18n/index.ts b/src/utils/i18n/index.ts new file mode 100644 index 0000000000..f04de061ab --- /dev/null +++ b/src/utils/i18n/index.ts @@ -0,0 +1,97 @@ +/** + * Minimal gettext-style i18n for cc-haha. + * + * Design goals: + * 1. No runtime dependencies beyond what's already in utils/. + * 2. Deterministic — locale is resolved once per process (from env + settings). + * 3. Fallback is always English — missing keys simply return the source string. + * 4. Typed: `t(key, vars?)` gives mild type safety via string literals. + * + * Use: + * import { t, setLocale } from 'src/utils/i18n/index.js' + * console.log(t('secure_storage_plaintext_warning')) + * // "Warning: Storing credentials in plaintext." + */ + +import memoize from 'lodash-es/memoize.js' +import { zhCN } from './locales/zh_CN.js' +import { zhTW } from './locales/zh_TW.js' +import { en } from './locales/en.js' + +export type Locale = 'en' | 'zh-CN' | 'zh-TW' + +export type TranslationKey = + | keyof typeof en + | keyof typeof zhCN + | keyof typeof zhTW + | (string & {}) // allow arbitrary strings too (they fall through) + +const CATALOGS: Record>> = { + en, + 'zh-CN': zhCN, + 'zh-TW': zhTW, +} + +function detectLocale(): Locale { + const env = + process.env.CC_HAHA_LOCALE || + process.env.LANG || + process.env.LC_ALL || + process.env.LC_MESSAGES || + '' + const normalized = env.replace(/\.[^.]+$/, '').toLowerCase() + if (normalized.startsWith('zh-tw') || normalized.startsWith('zh_hant') || normalized === 'zh_hk') { + return 'zh-TW' + } + if (normalized.startsWith('zh')) return 'zh-CN' + return 'en' +} + +let currentLocale: Locale = detectLocale() + +export function setLocale(l: Locale | string): void { + const lower = (l || '').toLowerCase() + if (lower === 'zh-tw' || lower === 'zh_hant') currentLocale = 'zh-TW' + else if (lower.startsWith('zh')) currentLocale = 'zh-CN' + else currentLocale = 'en' +} + +export function getLocale(): Locale { + return currentLocale +} + +function interpolate(source: string, vars?: Record): string { + if (!vars) return source + return source.replace(/%\{(\w+)\}/g, (_m, key: string) => { + const v = vars[key] + return v === undefined ? `%{${key}}` : String(v) + }) +} + +function resolve(key: string): string { + const catalog = CATALOGS[currentLocale] + const candidate = catalog?.[key] + if (typeof candidate === 'string') return candidate + if (currentLocale === 'zh-TW') { + const fallback = CATALOGS['zh-CN']?.[key] + if (typeof fallback === 'string') return fallback + } + return key +} + +/** + * Main translation call — memoized so lookups are effectively free on hot paths. + * Variables are substituted with `%{name}` placeholders. + */ +export const t = memoize( + function translate(key: string, vars?: Record): string { + return interpolate(resolve(key), vars) + }, + (k, v) => (v ? `${k}::${JSON.stringify(v)}` : k), +) + +/** Reset locale detection — mostly useful for tests. */ +export function resetLocale(): void { + currentLocale = detectLocale() + t.cache?.clear?.() +} diff --git a/src/utils/i18n/locales/en.ts b/src/utils/i18n/locales/en.ts new file mode 100644 index 0000000000..89f3964410 --- /dev/null +++ b/src/utils/i18n/locales/en.ts @@ -0,0 +1,43 @@ +// English catalog — the canonical key set. +// Other locale files provide translations for the same keys. + +export const en: Record = { + 'secure_storage_plaintext_warning': + 'Warning: Storing credentials in plaintext.', + 'secure_storage_libsecret_warning': + 'Credentials stored in the system keyring via libsecret.', + 'secure_storage_libsecret_hint': + 'Install libsecret-tools (Debian/Ubuntu) or libsecret (Fedora/Arch) to use the system keyring.', + 'bash_security_parse_failed': + 'Bash command parsing failed; falling back to heuristic validation.', + + 'provider_connectivity_error': + 'Provider connectivity error: %{detail}', + 'provider_local_model_hint': + 'Local model detected at %{baseUrl} — ensure server must be running before connecting.', + 'provider_local_model_started': + 'Local model connected in %{latencyMs}ms.', + 'provider_missing_baseurl_or_apikey': + 'Missing baseUrl or apiKey — please configure your provider.', + 'provider_test_timeout': + 'Request timed out (%{seconds}s) — the upstream server may be too slow.', + 'provider_upstream_error': + 'Upstream error %{status}: %{detail}', + 'provider_model_capabilities_unknown': + 'Could not determine capabilities for model %{model} — defaults apply defaults', + + 'fs_symlink_unsafe': + 'Unsafe path — target is not inside allowed directories.', + 'fs_symlink_absolute_required': + 'Path must be an absolute path.', + + 'fs_warning_crossing': + 'Path traversal warning — path contains symlink crossing outside the configured working directory.', + 'fs_normalized_path': + 'Path normalized from symlink outside the working directory.', + + 'cli_security_notice_header': + '— Security: cc-haha —', + 'cli_version': + 'Claude Code (cc-haha) v%{version}', +} diff --git a/src/utils/i18n/locales/zh_CN.ts b/src/utils/i18n/locales/zh_CN.ts new file mode 100644 index 0000000000..3822b0cb3f --- /dev/null +++ b/src/utils/i18n/locales/zh_CN.ts @@ -0,0 +1,42 @@ +// 简体中文 catalog. + +export const zhCN: Record = { + 'secure_storage_plaintext_warning': + '警告:凭据以明文形式存储。', + 'secure_storage_libsecret_warning': + '凭据通过 libsecret 存储在系统密钥环中。', + 'secure_storage_libsecret_hint': + '请安装 libsecret-tools(Debian/Ubuntu)或 libsecret(Fedora/Arch)以使用系统密钥环。', + 'bash_security_parse_failed': + 'Bash 命令解析失败;已回退至启发式校验。', + + 'provider_connectivity_error': + '提供商连接错误:%{detail}', + 'provider_local_model_hint': + '检测到本地模型 %{baseUrl} — 请先启动服务器再连接。', + 'provider_local_model_started': + '本地模型连接成功,耗时 %{latencyMs}ms。', + 'provider_missing_baseurl_or_apikey': + '缺少 baseUrl 或 apiKey — 请先配置提供商。', + 'provider_test_timeout': + '请求超时(%{seconds}s)— 上游服务器响应可能过慢。', + 'provider_upstream_error': + '上游错误 %{status}:%{detail}', + 'provider_model_capabilities_unknown': + '无法确定模型 %{model} 的能力,将使用默认值。', + + 'fs_symlink_unsafe': + '路径不安全 — 目标不在允许目录内。', + 'fs_symlink_absolute_required': + '路径必须是绝对路径。', + + 'fs_warning_crossing': + '路径穿越警告 — 路径中的符号链接指向工作目录之外。', + 'fs_normalized_path': + '路径已从工作目录外的符号链接进行归一化。', + + 'cli_security_notice_header': + '— 安全提醒:cc-haha —', + 'cli_version': + 'Claude Code(cc-haha)v%{version}', +} diff --git a/src/utils/i18n/locales/zh_TW.ts b/src/utils/i18n/locales/zh_TW.ts new file mode 100644 index 0000000000..2e95241a1d --- /dev/null +++ b/src/utils/i18n/locales/zh_TW.ts @@ -0,0 +1,42 @@ +// 正體中文 catalog — 繁體中文翻譯。 + +export const zhTW: Record = { + 'secure_storage_plaintext_warning': + '警告:憑證以明文形式儲存。', + 'secure_storage_libsecret_warning': + '憑證透過 libsecret 儲存於系統金鑰圈。', + 'secure_storage_libsecret_hint': + '請安裝 libsecret-tools(Debian/Ubuntu)或 libsecret(Fedora/Arch)以使用系統金鑰圈。', + 'bash_security_parse_failed': + 'Bash 命令解析失敗;已回退至啟發式驗證。', + + 'provider_connectivity_error': + '供應商連線錯誤:%{detail}', + 'provider_local_model_hint': + '偵測到本機模型 %{baseUrl} — 請先啟動伺服器再連線。', + 'provider_local_model_started': + '本機模型連線成功,耗時 %{latencyMs}ms。', + 'provider_missing_baseurl_or_apikey': + '缺少 baseUrl 或 apiKey — 請先設定供應商。', + 'provider_test_timeout': + '請求逾時(%{seconds}s)— 上游伺服器回應可能過慢。', + 'provider_upstream_error': + '上游錯誤 %{status}:%{detail}', + 'provider_model_capabilities_unknown': + '無法判定模型 %{model} 的能力,將使用預設值。', + + 'fs_symlink_unsafe': + '路徑不安全 — 目標不在允許目錄內。', + 'fs_symlink_absolute_required': + '路徑必須是絕對路徑。', + + 'fs_warning_crossing': + '路徑穿越警告 — 路徑中的符號連結指向工作目錄之外。', + 'fs_normalized_path': + '路徑已從工作目錄外的符號連結進行正規化。', + + 'cli_security_notice_header': + '— 安全提醒:cc-haha —', + 'cli_version': + 'Claude Code(cc-haha)v%{version}', +} diff --git a/src/utils/permissions/filesystem.ts b/src/utils/permissions/filesystem.ts index 47e6858127..24733afed9 100644 --- a/src/utils/permissions/filesystem.ts +++ b/src/utils/permissions/filesystem.ts @@ -4,6 +4,7 @@ import ignore from 'ignore' import memoize from 'lodash-es/memoize.js' import { homedir, tmpdir } from 'os' import { join, normalize, posix, sep } from 'path' +import * as nodePath from 'path' import { hasAutoMemPathOverride, isAutoMemPath } from 'src/memdir/paths.js' import { isAgentMemoryPath } from 'src/tools/AgentTool/agentMemory.js' import { @@ -631,6 +632,98 @@ function hasSuspiciousWindowsPathPattern( * @param path The path to check for safety * @returns Object with safe=false and message if unsafe, or { safe: true } if all checks pass */ +/** + * Symlink TOCTOU / path-escape check for paths being written to. + * + * Performs two realpath + ancestor checks: + * 1. lstat → follow readlink → ensure target stays inside allowDirs. + * 2. If the path exists, realpathSync resolves the final canonical path; + * compare against allowDirs again. + * + * Returns `{ safe: true }` when neither the original path nor any + * intermediate symlink resolves outside the allow-list. The check is + * strict — any unresolved or network-path segment fails closed. + * + * This is defense-in-depth — filesystem permissions are checked via the + * normal rule-matching flow elsewhere. This helper concentrates the + * TOCTOU-style symlink walk in one place. + */ +export function checkSymlinkPathSafety( + inputPath: string, + allowDirs: string[] = [getOriginalCwd()], +): { safe: boolean; reason?: string } { + if (!nodePath.isAbsolute(inputPath)) { + return { safe: false, reason: 'fs_symlink_absolute_required' } + } + + const fsImpl = getFsImplementation() + const normalizedAllow = allowDirs + .map((d) => nodePath.normalize(d) + nodePath.sep) + + const checkInside = (p: string): boolean => { + let norm = nodePath.normalize(p) + if (!norm.endsWith(nodePath.sep)) norm = norm + nodePath.sep + return normalizedAllow.some((a) => norm === a || norm.startsWith(a)) + } + + // 1) Walk the chain manually so we can see every symlink's target + // independently of the final path resolution (closes one classic + // TOCTOU window between open() and resolve()). + const maxDepth = 40 + let current = inputPath + const visited = new Set() + for (let depth = 0; depth < maxDepth; depth++) { + if (visited.has(current)) break + visited.add(current) + try { + const st = fsImpl.lstatSync(current) + if (st.isSymbolicLink()) { + const target = fsImpl.readlinkSync(current) + const absolute = nodePath.isAbsolute(target) + ? target + : nodePath.resolve(nodePath.dirname(current), target) + if (!checkInside(absolute)) { + return { safe: false, reason: 'fs_symlink_unsafe' } + } + current = absolute + continue + } + // Not a symlink — check containment and stop. + if (!checkInside(current)) { + return { safe: false, reason: 'fs_symlink_unsafe' } + } + break + } catch { + // Path doesn't exist (or is ELOOP) — parent containment check below. + break + } + } + + // 2) Final canonical resolution to catch e.g. /tmp -> /private/tmp + // style mounts on macOS (already handled by getPathsForPermissionCheck + // for normal permission flow; this keeps the helper self-contained). + try { + const resolved = fsImpl.realpathSync(inputPath) + if (!checkInside(resolved)) { + return { safe: false, reason: 'fs_symlink_unsafe' } + } + } catch { + // File doesn't exist yet — that's OK; creation happens inside allowDirs + // and we verified the closest existing ancestor above. + } + + return { safe: true } +} + +/** + * Checks whether the path or any intermediate symlink resolves outside the + * session working directory. Intended for high-level callers that only want + * a boolean + warning message (e.g. a logging/tracing hook, not policy). + */ +export function pathCrossesSymlinkOutsideWorkingDir(inputPath: string): boolean { + return !checkSymlinkPathSafety(inputPath).safe +} + export function checkPathSafetyForAutoEdit( path: string, precomputedPathsToCheck?: readonly string[], @@ -642,6 +735,22 @@ export function checkPathSafetyForAutoEdit( const pathsToCheck = precomputedPathsToCheck ?? getPathsForPermissionCheck(path) + // Symlink TOCTOU check — if the path or any intermediate component + // is a symlink pointing outside the session working directory, flag it + // for manual review. This is defense-in-depth on top of the normal + // rule-matching flow; the path resolver above already exposes the + // full chain so rule matching also sees real targets. + if (!precomputedPathsToCheck) { + const symlinkResult = checkSymlinkPathSafety(path, [getOriginalCwd()]) + if (!symlinkResult.safe) { + return { + safe: false, + message: `Claude requested permissions to write to ${path}, which contains a symlink pointing outside the working directory. Manual approval required.`, + classifierApprovable: false, + } + } + } + // Check for suspicious Windows path patterns on all paths for (const pathToCheck of pathsToCheck) { if (hasSuspiciousWindowsPathPattern(pathToCheck, options)) { diff --git a/src/utils/secureStorage/index.ts b/src/utils/secureStorage/index.ts index d84f07a903..a80593a0d3 100644 --- a/src/utils/secureStorage/index.ts +++ b/src/utils/secureStorage/index.ts @@ -1,17 +1,26 @@ import { createFallbackStorage } from './fallbackStorage.js' +import { libsecretStorage, secretToolAvailableSync } from './libsecretStorage.js' import { macOsKeychainStorage } from './macOsKeychainStorage.js' import { plainTextStorage } from './plainTextStorage.js' import type { SecureStorage } from './types.js' /** - * Get the appropriate secure storage implementation for the current platform + * Get the appropriate secure storage implementation for the current platform. + * + * - macOS → Keychain (via `security`) with plaintext fallback. + * - Linux → libsecret (via `secret-tool`) when available; otherwise plaintext. + * - Windows / other → plaintext only. */ export function getSecureStorage(): SecureStorage { if (process.platform === 'darwin') { return createFallbackStorage(macOsKeychainStorage, plainTextStorage) } - // TODO: add libsecret support for Linux + if (process.platform === 'linux') { + if (secretToolAvailableSync()) { + return createFallbackStorage(libsecretStorage, plainTextStorage) + } + } return plainTextStorage } diff --git a/src/utils/secureStorage/libsecretStorage.ts b/src/utils/secureStorage/libsecretStorage.ts new file mode 100644 index 0000000000..bbb6fb326e --- /dev/null +++ b/src/utils/secureStorage/libsecretStorage.ts @@ -0,0 +1,104 @@ +import { execFile } from 'child_process' +import { promisify } from 'util' +import { getClaudeConfigHomeDir } from '../envUtils.js' +import type { SecureStorage, SecureStorageData } from './types.js' + +const execFileAsync = promisify(execFile) + +/** + * libsecret / secret-service storage for Linux. + * + * Uses the system's `secret-tool` binary (part of libsecret-tools on Debian/Ubuntu, + * libsecret on Fedora/Arch) when available. Falls back to plain-text storage when the + * secret-service daemon isn't running (typical in headless / SSH sessions). + * + * The stored value is a JSON object whose shape matches SecureStorageData. + * We wrap errors so callers can opt-in to the fallback. + */ + +export function secretToolAvailableSync(): boolean { + try { + require('child_process') + .execFileSync('secret-tool', ['--help'], { stdio: 'ignore' }) + return true + } catch { + return false + } +} + +export async function secretToolAvailable(): Promise { + try { + await execFileAsync('secret-tool', ['--help']) + return true + } catch { + return false + } +} + +function baseAttributes(): string[] { + return [ + 'application', + 'claude-code', + 'schema', + 'com.anthropic.claude-code.credentials', + ] +} + +function getLabel(): string { + return `Claude Code credentials (${getClaudeConfigHomeDir()})` +} + +export const libsecretStorage: SecureStorage = { + name: 'libsecret', + read(): SecureStorageData | null { + try { + const stdout = require('child_process').execFileSync( + 'secret-tool', + ['lookup', ...baseAttributes()], + { stdio: ['ignore', 'pipe', 'ignore'], encoding: 'utf8' }, + ) + return stdout ? (JSON.parse(stdout) as SecureStorageData) : null + } catch { + return null + } + }, + async readAsync(): Promise { + try { + const { stdout } = await execFileAsync('secret-tool', [ + 'lookup', + ...baseAttributes(), + ]) + return stdout ? (JSON.parse(stdout) as SecureStorageData) : null + } catch { + return null + } + }, + update(data: SecureStorageData): { success: boolean; warning?: string } { + const serialized = JSON.stringify(data) + try { + const child = require('child_process').spawnSync( + 'secret-tool', + ['store', '--label', getLabel(), ...baseAttributes()], + { input: serialized, stdio: ['pipe', 'pipe', 'pipe'], encoding: 'utf8' }, + ) + if (child.status !== 0) { + return { success: false, warning: `secret-tool store failed: ${child.stderr?.slice?.(0, 120) || 'unknown'}` } + } + return { success: true } + } catch (err) { + return { success: false, warning: err instanceof Error ? err.message : String(err) } + } + }, + delete(): boolean { + try { + const child = require('child_process').spawnSync( + 'secret-tool', + ['clear', ...baseAttributes()], + { stdio: ['ignore', 'pipe', 'pipe'] }, + ) + return child.status === 0 + } catch { + return false + } + }, +} diff --git a/src/utils/secureStorage/plainTextStorage.ts b/src/utils/secureStorage/plainTextStorage.ts index e5383fb5c7..8447db19c1 100644 --- a/src/utils/secureStorage/plainTextStorage.ts +++ b/src/utils/secureStorage/plainTextStorage.ts @@ -1,5 +1,6 @@ import { chmodSync } from 'fs' import { join } from 'path' +import { t } from '../i18n/index.js' import { getClaudeConfigHomeDir } from '../envUtils.js' import { getErrnoCode } from '../errors.js' import { getFsImplementation } from '../fsOperations.js' @@ -61,7 +62,7 @@ export const plainTextStorage = { chmodSync(storagePath, 0o600) return { success: true, - warning: 'Warning: Storing credentials in plaintext.', + warning: t('secure_storage_plaintext_warning'), } } catch { return { success: false } From 55a879f11805a6e25bb96cd9b25ac594dc14497b Mon Sep 17 00:00:00 2001 From: jeo-ch Date: Wed, 17 Jun 2026 06:19:18 +0000 Subject: [PATCH 7/7] =?UTF-8?q?feat:=20=E9=A1=B9=E7=9B=AE=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E9=80=BB=E8=BE=91=E4=B8=8E=E5=AE=89=E5=85=A8=E5=88=86?= =?UTF-8?q?=E6=9E=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: traeagent --- desktop/src/i18n/locales/en.ts | 2 ++ desktop/src/i18n/locales/jp.ts | 2 ++ desktop/src/i18n/locales/kr.ts | 2 ++ desktop/src/i18n/locales/zh-TW.ts | 2 ++ desktop/src/i18n/locales/zh.ts | 2 ++ desktop/src/pages/Settings.tsx | 27 +++++++++++++++++++++ desktop/src/stores/settingsStore.ts | 4 ++++ src/server/index.ts | 6 ++++- src/tools/BashTool/pathValidation.ts | 35 +++++++++++++++++++++++++++- src/utils/config.ts | 1 + src/utils/i18n/index.ts | 2 ++ 11 files changed, 83 insertions(+), 2 deletions(-) diff --git a/desktop/src/i18n/locales/en.ts b/desktop/src/i18n/locales/en.ts index 49966061f7..9949eee2df 100644 --- a/desktop/src/i18n/locales/en.ts +++ b/desktop/src/i18n/locales/en.ts @@ -461,6 +461,8 @@ export const en = { 'settings.providers.toolSearchEnabled': 'Enable Tool Search', 'settings.providers.toolSearchDesc': 'Load MCP and deferred tools on demand to reduce initial tool schema tokens. Disable it for weak models or providers that reject tool references.', 'settings.providers.toolSearchUnsupported': 'Only Anthropic Messages providers support Tool Search here. OpenAI proxy formats keep full tool schemas available.', + 'settings.providers.availableModels': 'Available models — click to select', + 'settings.providers.clickToSelectModel': 'Click to use this model as the main model', // Settings > Permissions 'settings.permissions.title': 'Permission Mode', diff --git a/desktop/src/i18n/locales/jp.ts b/desktop/src/i18n/locales/jp.ts index 777e0d48ff..9f0792c975 100644 --- a/desktop/src/i18n/locales/jp.ts +++ b/desktop/src/i18n/locales/jp.ts @@ -463,6 +463,8 @@ export const jp: Record = { 'settings.providers.toolSearchEnabled': 'Tool Search を有効にする', 'settings.providers.toolSearchDesc': 'MCP と遅延ツールを必要に応じて読み込み、初回のツール schema トークンを減らします。弱いモデルや tool_reference を拒否するプロバイダーでは無効にできます。', 'settings.providers.toolSearchUnsupported': 'ここでは Anthropic Messages 形式のプロバイダーのみ Tool Search をサポートします。OpenAI プロキシ形式では完全なツール schema を維持します。', + 'settings.providers.availableModels': '利用可能なモデル — クリックして選択', + 'settings.providers.clickToSelectModel': 'クリックしてこのモデルを使用', // Settings > Permissions 'settings.permissions.title': '権限モード', diff --git a/desktop/src/i18n/locales/kr.ts b/desktop/src/i18n/locales/kr.ts index 2a9829d2b4..4ce7b9ab5d 100644 --- a/desktop/src/i18n/locales/kr.ts +++ b/desktop/src/i18n/locales/kr.ts @@ -463,6 +463,8 @@ export const kr: Record = { 'settings.providers.toolSearchEnabled': 'Tool Search 사용', 'settings.providers.toolSearchDesc': 'MCP와 지연 도구를 필요할 때 로드해 초기 도구 schema 토큰을 줄입니다. 약한 모델이나 tool_reference를 거부하는 공급자에서는 끌 수 있습니다.', 'settings.providers.toolSearchUnsupported': '여기서는 Anthropic Messages 형식 공급자만 Tool Search를 지원합니다. OpenAI 프록시 형식은 전체 도구 schema를 유지합니다.', + 'settings.providers.availableModels': '사용 가능한 모델 — 클릭하여 선택', + 'settings.providers.clickToSelectModel': '클릭하여 이 모델을 주 모델로 사용', // Settings > Permissions 'settings.permissions.title': '권한 모드', diff --git a/desktop/src/i18n/locales/zh-TW.ts b/desktop/src/i18n/locales/zh-TW.ts index 41962d6787..867c0bf38a 100644 --- a/desktop/src/i18n/locales/zh-TW.ts +++ b/desktop/src/i18n/locales/zh-TW.ts @@ -463,6 +463,8 @@ export const zh: Record = { 'settings.providers.toolSearchEnabled': '啟用 Tool Search', 'settings.providers.toolSearchDesc': '按需載入 MCP 和延遲工具,減少首輪工具 schema token。弱模型或不支援 tool_reference 的服務商可以關閉。', 'settings.providers.toolSearchUnsupported': '目前僅 Anthropic Messages 格式支援 Tool Search;OpenAI 代理格式會保留完整工具 schema。', + 'settings.providers.availableModels': '可用模型 — 點擊選擇', + 'settings.providers.clickToSelectModel': '點擊使用此模型作為主模型', // Settings > Permissions 'settings.permissions.title': '許可權模式', diff --git a/desktop/src/i18n/locales/zh.ts b/desktop/src/i18n/locales/zh.ts index 22bd97d3f3..f9355931b3 100644 --- a/desktop/src/i18n/locales/zh.ts +++ b/desktop/src/i18n/locales/zh.ts @@ -463,6 +463,8 @@ export const zh: Record = { 'settings.providers.toolSearchEnabled': '启用 Tool Search', 'settings.providers.toolSearchDesc': '按需加载 MCP 和延迟工具,减少首轮工具 schema token。弱模型或不支持 tool_reference 的服务商可以关闭。', 'settings.providers.toolSearchUnsupported': '当前仅 Anthropic Messages 格式支持 Tool Search;OpenAI 代理格式会保留完整工具 schema。', + 'settings.providers.availableModels': '可用模型 — 点击选择', + 'settings.providers.clickToSelectModel': '点击使用此模型作为主模型', // Settings > Permissions 'settings.permissions.title': '权限模式', diff --git a/desktop/src/pages/Settings.tsx b/desktop/src/pages/Settings.tsx index a259249b82..41318c04aa 100644 --- a/desktop/src/pages/Settings.tsx +++ b/desktop/src/pages/Settings.tsx @@ -1794,6 +1794,33 @@ function ProviderFormModal({ open, onClose, mode, provider, presets }: ProviderF )} + {/* Available models — auto-fill main model when a chip is clicked */} + {testResult?.availableModels && testResult.availableModels.length > 0 && ( +
+ +
+ {testResult.availableModels.slice(0, 20).map((model) => ( + + ))} + {testResult.availableModels.length > 20 && ( + + +{testResult.availableModels.length - 20} more + + )} +
+
+ )} + {/* Settings JSON — editable, shown for all presets including official */}
diff --git a/desktop/src/stores/settingsStore.ts b/desktop/src/stores/settingsStore.ts index 46d4b4ba3a..b1c38e10ff 100644 --- a/desktop/src/stores/settingsStore.ts +++ b/desktop/src/stores/settingsStore.ts @@ -322,8 +322,12 @@ export const useSettingsStore = create((set, get) => ({ }, setLocale: (locale) => { + const prev = get().locale set({ locale }) try { localStorage.setItem(LOCALE_STORAGE_KEY, locale) } catch { /* noop */ } + settingsApi.updateUser({ locale }).catch(() => { + set({ locale: prev }) + }) }, setTheme: async (theme) => { diff --git a/src/server/index.ts b/src/server/index.ts index 9d6926aeb2..d5c33171cd 100644 --- a/src/server/index.ts +++ b/src/server/index.ts @@ -21,7 +21,8 @@ import { sessionService } from './services/sessionService.js' import { conversationService } from './services/conversationService.js' import { OPENAI_CODEX_REDIRECT_PATH } from '../services/openaiAuth/client.js' import { ensureDesktopCliLauncherInstalled } from './services/desktopCliLauncherService.js' -import { enableConfigs } from '../utils/config.js' +import { enableConfigs, getGlobalConfig } from '../utils/config.js' +import { setLocale } from '../utils/i18n/index.js' import { diagnosticsService } from './services/diagnosticsService.js' import { ensurePersistentStorageUpgraded } from './services/persistentStorageMigrations.js' import { handleStaticH5Request } from './staticH5.js' @@ -126,6 +127,9 @@ function originFromUrl(value: string | null): string | null { export function startServer(port = PORT, host = HOST) { enableConfigs() + // Apply persisted locale from ~/.claude/settings.json (set by desktop UI language switcher) + const { locale } = getGlobalConfig() + if (locale) setLocale(locale) // Warm the synchronous disconnect-grace cache from managed settings so the // first client disconnect honors the configured value (issue #764). void refreshDisconnectGraceMs() diff --git a/src/tools/BashTool/pathValidation.ts b/src/tools/BashTool/pathValidation.ts index 8da98f8b11..7d0769b5f8 100644 --- a/src/tools/BashTool/pathValidation.ts +++ b/src/tools/BashTool/pathValidation.ts @@ -9,7 +9,8 @@ import { } from '../../utils/bash/commands.js' import { tryParseShellCommand } from '../../utils/bash/shellQuote.js' import { getDirectoryForPath } from '../../utils/path.js' -import { allWorkingDirectories } from '../../utils/permissions/filesystem.js' +import { getOriginalCwd } from '../../bootstrap/state.js' +import { allWorkingDirectories, checkSymlinkPathSafety } from '../../utils/permissions/filesystem.js' import type { PermissionResult } from '../../utils/permissions/PermissionResult.js' import { createReadRuleSuggestion } from '../../utils/permissions/PermissionUpdate.js' import type { PermissionUpdate } from '../../utils/permissions/PermissionUpdateSchema.js' @@ -691,6 +692,23 @@ function validateCommandPaths( decisionReason, } } + + // Symlink TOCTOU check for write/create operations: + // Block commands where the resolved path crosses a symlink outside the session. + // Read-only operations (ls, cat, grep, etc.) are exempt since they don't modify files. + if (operationType === 'write' || operationType === 'create') { + const symlinkResult = checkSymlinkPathSafety(resolvedPath, [getOriginalCwd()]) + if (!symlinkResult.safe) { + return { + behavior: 'deny', + message: `'${command}' to '${resolvedPath}' is blocked: contains a symlink pointing outside the working directory.`, + decisionReason: { + type: 'safetyCheck', + reason: symlinkResult.reason ?? 'Symlink points outside the session working directory', + }, + } + } + } } // All paths are valid - return passthrough @@ -994,6 +1012,21 @@ function validateOutputRedirections( ], } } + + // Symlink TOCTOU check: ensure the resolved path doesn't cross a symlink + // that points outside the session working directory. + // This is defense-in-depth on top of the normal permission flow. + const symlinkResult = checkSymlinkPathSafety(resolvedPath, [getOriginalCwd()]) + if (!symlinkResult.safe) { + return { + behavior: 'deny', + message: `Output redirection to '${resolvedPath}' is blocked: contains a symlink pointing outside the working directory.`, + decisionReason: { + type: 'safetyCheck', + reason: symlinkResult.reason ?? 'Symlink points outside the session working directory', + }, + } + } } return { diff --git a/src/utils/config.ts b/src/utils/config.ts index 8c6741ed95..6b087c8c5e 100644 --- a/src/utils/config.ts +++ b/src/utils/config.ts @@ -195,6 +195,7 @@ export type GlobalConfig = { doctorShownAtSession?: number userID?: string theme: ThemeSetting + locale?: string // cc-haha i18n locale (en | zh-CN | zh-TW), synced from desktop UI hasCompletedOnboarding?: boolean // Tracks the last version that reset onboarding, used with MIN_VERSION_REQUIRING_ONBOARDING_RESET lastOnboardingVersion?: string diff --git a/src/utils/i18n/index.ts b/src/utils/i18n/index.ts index f04de061ab..12997beaf0 100644 --- a/src/utils/i18n/index.ts +++ b/src/utils/i18n/index.ts @@ -54,6 +54,8 @@ export function setLocale(l: Locale | string): void { if (lower === 'zh-tw' || lower === 'zh_hant') currentLocale = 'zh-TW' else if (lower.startsWith('zh')) currentLocale = 'zh-CN' else currentLocale = 'en' + // Sync to env so child processes and the CLI startup path pick it up + process.env.CC_HAHA_LOCALE = currentLocale } export function getLocale(): Locale {