From 2cbbda613fe57c8b665434d52ace65ed7cf8f5a9 Mon Sep 17 00:00:00 2001 From: LloydAsp Date: Tue, 19 May 2026 15:37:07 +0800 Subject: [PATCH 1/8] chore: remove axios dependency --- package.json | 1 - pnpm-lock.yaml | 190 ------------------------------------------------- 2 files changed, 191 deletions(-) diff --git a/package.json b/package.json index ea1b6e0f..e3549e6a 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,6 @@ "@vueuse/core": "^14.2.0", "@xterm/addon-fit": "^0.11.0", "@xterm/xterm": "^6.0.0", - "axios": "^1.13.5", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "codemirror": "^6.0.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c0009e9d..716f9303 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -47,9 +47,6 @@ importers: '@xterm/xterm': specifier: ^6.0.0 version: 6.0.0 - axios: - specifier: ^1.13.5 - version: 1.13.5 class-variance-authority: specifier: ^0.7.1 version: 0.7.1 @@ -1314,12 +1311,6 @@ packages: resolution: {integrity: sha512-cbdCP0PGOBq0ASG+sjnKIoYkWMKhhz+F/h9pRexUdX2Hd38+WOlBkRKlqkGOSm0YQpcFMQBJeK4WspUAkwsEdg==} engines: {node: '>=20.19.0'} - asynckit@0.4.0: - resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} - - axios@1.13.5: - resolution: {integrity: sha512-cz4ur7Vb0xS4/KUN0tPWe44eqxrIu31me+fbang3ijiNscE129POzipJJA6zniq2C/Z6sJCjMimjS8Lc/GAs8Q==} - balanced-match@4.0.2: resolution: {integrity: sha512-x0K50QvKQ97fdEz2kPehIerj+YTeptKF9hyYkKf6egnwmMWAkADiO0QCzSp0R5xN8FTZgYaBfSaue46Ej62nMg==} engines: {node: 20 || >=22} @@ -1351,10 +1342,6 @@ packages: resolution: {integrity: sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==} engines: {node: '>=18'} - call-bind-apply-helpers@1.0.2: - resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} - engines: {node: '>= 0.4'} - camelcase@5.3.1: resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} engines: {node: '>=6'} @@ -1397,10 +1384,6 @@ packages: colorette@2.0.20: resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} - combined-stream@1.0.8: - resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} - engines: {node: '>= 0.8'} - commander@14.0.3: resolution: {integrity: sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==} engines: {node: '>=20'} @@ -1467,10 +1450,6 @@ packages: defu@6.1.4: resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==} - delayed-stream@1.0.0: - resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} - engines: {node: '>=0.4.0'} - detect-libc@2.1.2: resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} engines: {node: '>=8'} @@ -1482,10 +1461,6 @@ packages: dijkstrajs@1.0.3: resolution: {integrity: sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==} - dunder-proto@1.0.1: - resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} - engines: {node: '>= 0.4'} - echarts@6.0.0: resolution: {integrity: sha512-Tte/grDQRiETQP4xz3iZWSvoHrkCQtwqd6hs+mifXcjrCuo2iKWbajFObuLJVBlDIJlOzgQPd1hsaKt/3+OMkQ==} @@ -1517,22 +1492,6 @@ packages: error-stack-parser-es@1.0.5: resolution: {integrity: sha512-5qucVt2XcuGMcEGgWI7i+yZpmpByQ8J1lHhcL7PwqCwu9FPP3VUXzT4ltHe5i2z9dePwEHcDVOAfSnHsOlCXRA==} - es-define-property@1.0.1: - resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} - engines: {node: '>= 0.4'} - - es-errors@1.3.0: - resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} - engines: {node: '>= 0.4'} - - es-object-atoms@1.1.1: - resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} - engines: {node: '>= 0.4'} - - es-set-tostringtag@2.1.0: - resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} - engines: {node: '>= 0.4'} - esbuild@0.27.2: resolution: {integrity: sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==} engines: {node: '>=18'} @@ -1689,27 +1648,11 @@ packages: flatted@3.3.3: resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==} - follow-redirects@1.15.11: - resolution: {integrity: sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==} - engines: {node: '>=4.0'} - peerDependencies: - debug: '*' - peerDependenciesMeta: - debug: - optional: true - - form-data@4.0.5: - resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==} - engines: {node: '>= 6'} - fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} os: [darwin] - function-bind@1.1.2: - resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} - gensync@1.0.0-beta.2: resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} engines: {node: '>=6.9.0'} @@ -1722,14 +1665,6 @@ packages: resolution: {integrity: sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q==} engines: {node: '>=18'} - get-intrinsic@1.3.0: - resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} - engines: {node: '>= 0.4'} - - get-proto@1.0.1: - resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} - engines: {node: '>= 0.4'} - glob-parent@5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} @@ -1738,10 +1673,6 @@ packages: resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} engines: {node: '>=10.13.0'} - gopd@1.2.0: - resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} - engines: {node: '>= 0.4'} - graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} @@ -1749,18 +1680,6 @@ packages: resolution: {integrity: sha512-6ABGa9CR7WR/0pAJicBy5SJkiikbFM6kf/JjykwX7x+t+s8ORWVnlbi6FkHeFFb36yWsjUpHqSYrygd7ofEUqA==} engines: {node: '>=0.10.0'} - has-symbols@1.1.0: - resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} - engines: {node: '>= 0.4'} - - has-tostringtag@1.0.2: - resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} - engines: {node: '>= 0.4'} - - hasown@2.0.2: - resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} - engines: {node: '>= 0.4'} - hookable@5.5.3: resolution: {integrity: sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==} @@ -1998,10 +1917,6 @@ packages: resolution: {integrity: sha512-BuU2qnTti9YKgK5N+IeMubp14ZUKUUw7yeJbkjtosvHiP0AZ5c8IAgEMk79D0eC8F23r4Ac/q8cAIFdm2FtyoA==} hasBin: true - math-intrinsics@1.1.0: - resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} - engines: {node: '>= 0.4'} - mdurl@2.0.0: resolution: {integrity: sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==} @@ -2020,14 +1935,6 @@ packages: resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} engines: {node: '>=8.6'} - mime-db@1.52.0: - resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} - engines: {node: '>= 0.6'} - - mime-types@2.1.35: - resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} - engines: {node: '>= 0.6'} - mimic-function@5.0.1: resolution: {integrity: sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==} engines: {node: '>=18'} @@ -2220,9 +2127,6 @@ packages: engines: {node: '>=14'} hasBin: true - proxy-from-env@1.1.0: - resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} - punycode.js@2.3.1: resolution: {integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==} engines: {node: '>=6'} @@ -3870,16 +3774,6 @@ snapshots: '@babel/parser': 7.28.6 ast-kit: 2.2.0 - asynckit@0.4.0: {} - - axios@1.13.5: - dependencies: - follow-redirects: 1.15.11 - form-data: 4.0.5 - proxy-from-env: 1.1.0 - transitivePeerDependencies: - - debug - balanced-match@4.0.2: dependencies: jackspeak: 4.2.3 @@ -3910,11 +3804,6 @@ snapshots: dependencies: run-applescript: 7.1.0 - call-bind-apply-helpers@1.0.2: - dependencies: - es-errors: 1.3.0 - function-bind: 1.1.2 - camelcase@5.3.1: {} caniuse-lite@1.0.30001766: {} @@ -3962,10 +3851,6 @@ snapshots: colorette@2.0.20: {} - combined-stream@1.0.8: - dependencies: - delayed-stream: 1.0.0 - commander@14.0.3: {} compare-versions@6.1.1: {} @@ -4011,20 +3896,12 @@ snapshots: defu@6.1.4: {} - delayed-stream@1.0.0: {} - detect-libc@2.1.2: {} diff@8.0.4: {} dijkstrajs@1.0.3: {} - dunder-proto@1.0.1: - dependencies: - call-bind-apply-helpers: 1.0.2 - es-errors: 1.3.0 - gopd: 1.2.0 - echarts@6.0.0: dependencies: tslib: 2.3.0 @@ -4049,21 +3926,6 @@ snapshots: error-stack-parser-es@1.0.5: {} - es-define-property@1.0.1: {} - - es-errors@1.3.0: {} - - es-object-atoms@1.1.1: - dependencies: - es-errors: 1.3.0 - - es-set-tostringtag@2.1.0: - dependencies: - es-errors: 1.3.0 - get-intrinsic: 1.3.0 - has-tostringtag: 1.0.2 - hasown: 2.0.2 - esbuild@0.27.2: optionalDependencies: '@esbuild/aix-ppc64': 0.27.2 @@ -4248,45 +4110,15 @@ snapshots: flatted@3.3.3: {} - follow-redirects@1.15.11: {} - - form-data@4.0.5: - dependencies: - asynckit: 0.4.0 - combined-stream: 1.0.8 - es-set-tostringtag: 2.1.0 - hasown: 2.0.2 - mime-types: 2.1.35 - fsevents@2.3.3: optional: true - function-bind@1.1.2: {} - gensync@1.0.0-beta.2: {} get-caller-file@2.0.5: {} get-east-asian-width@1.4.0: {} - get-intrinsic@1.3.0: - dependencies: - call-bind-apply-helpers: 1.0.2 - es-define-property: 1.0.1 - es-errors: 1.3.0 - es-object-atoms: 1.1.1 - function-bind: 1.1.2 - get-proto: 1.0.1 - gopd: 1.2.0 - has-symbols: 1.1.0 - hasown: 2.0.2 - math-intrinsics: 1.1.0 - - get-proto@1.0.1: - dependencies: - dunder-proto: 1.0.1 - es-object-atoms: 1.1.1 - glob-parent@5.1.2: dependencies: is-glob: 4.0.3 @@ -4295,22 +4127,10 @@ snapshots: dependencies: is-glob: 4.0.3 - gopd@1.2.0: {} - graceful-fs@4.2.11: {} gradient-parser@1.2.0: {} - has-symbols@1.1.0: {} - - has-tostringtag@1.0.2: - dependencies: - has-symbols: 1.1.0 - - hasown@2.0.2: - dependencies: - function-bind: 1.1.2 - hookable@5.5.3: {} husky@9.1.7: {} @@ -4505,8 +4325,6 @@ snapshots: punycode.js: 2.3.1 uc.micro: 2.1.0 - math-intrinsics@1.1.0: {} - mdurl@2.0.0: {} memorystream@0.3.1: {} @@ -4520,12 +4338,6 @@ snapshots: braces: 3.0.3 picomatch: 2.3.1 - mime-db@1.52.0: {} - - mime-types@2.1.35: - dependencies: - mime-db: 1.52.0 - mimic-function@5.0.1: {} minimatch@10.2.0: @@ -4691,8 +4503,6 @@ snapshots: prettier@3.8.1: {} - proxy-from-env@1.1.0: {} - punycode.js@2.3.1: {} punycode@2.3.1: {} From 796f4c595fa5f88848d43f71412b0f844f73862c Mon Sep 17 00:00:00 2001 From: LloydAsp Date: Tue, 19 May 2026 18:18:02 +0800 Subject: [PATCH 2/8] feat(input): add contenteditable input --- src/components/BackendSwitcher.vue | 8 +++ src/components/misc/mockInput.vue | 108 +++++++++++++++++++++++++++++ 2 files changed, 116 insertions(+) create mode 100644 src/components/misc/mockInput.vue diff --git a/src/components/BackendSwitcher.vue b/src/components/BackendSwitcher.vue index fd703d61..1510195a 100644 --- a/src/components/BackendSwitcher.vue +++ b/src/components/BackendSwitcher.vue @@ -18,6 +18,7 @@ import { useLifecycle } from "@/composables/useLifecycle"; import { delay } from "@/lib/delay"; import { useBackendExtra } from "@/composables/useBackendExtra"; import { useRouter } from "vue-router"; +import mockInput from "@/components/misc/mockInput.vue"; import { Select, SelectTrigger, @@ -334,6 +335,13 @@ watch( type="password" placeholder="key:secret username|password" /> + + +// 这个组件是为了在某些场景下替代原生 input,提供更好的样式控制和用户体验 +// 比如iOS上原生 input 在输入token时会有奇怪的大小写问题 + +import { computed, onMounted, ref, watch } from "vue"; + +interface Props { + modelValue?: string; + placeholder?: string; + disabled?: boolean; + autofocus?: boolean; +} + +const props = withDefaults(defineProps(), { + modelValue: "", + placeholder: "", + disabled: false, + autofocus: false, +}); + +const emit = defineEmits<{ + "update:modelValue": [value: string]; + input: [value: string]; + focus: [event: FocusEvent]; + blur: [event: FocusEvent]; +}>(); + +const elRef = ref(); + +const editable = computed(() => !props.disabled); + +function syncFromProps() { + const el = elRef.value; + if (!el) return; + + if (el.innerText !== props.modelValue) { + el.innerText = props.modelValue; + } +} + +function handleInput() { + const el = elRef.value; + if (!el) return; + + const value = el.innerText; + + emit("update:modelValue", value); + emit("input", value); +} + +function handlePaste(e: ClipboardEvent) { + // 纯文本粘贴,避免富文本污染 + e.preventDefault(); + + const text = e.clipboardData?.getData("text/plain") ?? ""; + + document.execCommand("insertText", false, text); +} + +function handleKeydown(e: KeyboardEvent) { + // 单行 input 风格 + if (e.key === "Enter") { + e.preventDefault(); + } +} + +watch( + () => props.modelValue, + () => { + syncFromProps(); + }, +); + +onMounted(() => { + syncFromProps(); + + if (props.autofocus) { + elRef.value?.focus(); + } +}); + + + From a8d9f364b225d6979397372e0afaabd603129029 Mon Sep 17 00:00:00 2001 From: LloydAsp Date: Tue, 19 May 2026 23:52:21 +0800 Subject: [PATCH 3/8] refactor: add new upstream config, optimize useTask --- src/composables/useAgentConfig.ts | 56 ++++++++- src/composables/useTask.ts | 203 ++++++++++++++++++++---------- 2 files changed, 192 insertions(+), 67 deletions(-) diff --git a/src/composables/useAgentConfig.ts b/src/composables/useAgentConfig.ts index d6234ee1..83681e88 100644 --- a/src/composables/useAgentConfig.ts +++ b/src/composables/useAgentConfig.ts @@ -9,6 +9,8 @@ Handles functionalities related to agent configuration, such as import { ref, computed } from "vue"; import { useBackendStore } from "@/composables/useBackendStore"; import { useBackendExtra } from "@/composables/useBackendExtra"; +import { type TaskString, allTaskStrings } from "@/composables/useTask"; +import { compareVersions } from "compare-versions"; import { useTask, @@ -38,6 +40,7 @@ export interface UpstreamServer { allow_self_update?: boolean; allow_ip?: boolean; allow_version?: boolean; + allow_task_type?: TaskString[]; [key: string]: any; } @@ -116,6 +119,35 @@ function parseToml(tomlStr: string): AgentConfig { } } +function oldUpstream2New(upstream: UpstreamServer) { + const upstream2: UpstreamServer = JSON.parse(JSON.stringify(upstream)); + const allow_task_type: Array = []; + allTaskStrings.forEach((t) => { + if (upstream2["allow_" + t]) { + allow_task_type.push(t as TaskString); + delete upstream2["allow_" + t]; + } + }); + delete upstream2.allow_task; + upstream2.allow_task_type = allow_task_type; + return upstream2; +} + +function newUpstream2Old(upstream: UpstreamServer) { + const upstream2: UpstreamServer = JSON.parse(JSON.stringify(upstream)); + if (!Array.isArray(upstream2.allow_task_type)) { + throw "not new upstream"; + } + const allow_task_type: Array = []; + const att = new Set(upstream2.allow_task_type); + allTaskStrings.forEach((t) => { + upstream2["allow_" + t] = att.has(t); + }); + delete upstream2.allow_task_type; + upstream2.allow_task = allow_task_type.length !== 0; + return upstream2; +} + /** * 使用标准TOML库序列化配置 */ @@ -134,7 +166,15 @@ function getAgentConfig( timeoutMs: number = 5000, ): Promise { return getRawAgentConfig(agentUuid, timeoutMs).then((tomlStr) => { - return parseToml(tomlStr); + const config = parseToml(tomlStr); + config.server = config.server.map((v) => { + if (Array.isArray(v.allow_task_type)) { + return v; + } + return oldUpstream2New(v); + }); + // return new config format + return config; }); } @@ -189,11 +229,23 @@ function writeRawAgentConfig( ); } -function writeAgentConfig( +async function writeAgentConfig( agentUuid: string, config: AgentConfig, timeoutMs: number = 5000, ): Promise { + const { createVersionTask } = useTask(currentBackend); + + const versonResult = await createVersionTask(agentUuid, true); + const version = versonResult.task_event_result?.version; + + if (!version) { + throw "failed to get agent version"; + } + if (compareVersions(version.cargo_version, "0.3.0") < 0) { + config.server = config.server.map((v) => newUpstream2Old(v)); + } + const tomlContent = serializeToml(config); return writeRawAgentConfig(agentUuid, tomlContent, timeoutMs); } diff --git a/src/composables/useTask.ts b/src/composables/useTask.ts index c791b779..d808aaeb 100644 --- a/src/composables/useTask.ts +++ b/src/composables/useTask.ts @@ -67,6 +67,23 @@ export type TaskEventType = | IpTask | VersionTask; +export const allTaskStrings = [ + "icmp_ping", + "tcp_ping", + "http_ping", + "web_shell", + "edit_config", + "read_config", + "execute", + "http_request", + "self_update", + "ip", + "version", + "dns", +] as const; + +export type TaskString = (typeof allTaskStrings)[number]; + // Task Event Results export interface PingResult { ping: number; // 延迟 ms @@ -176,14 +193,14 @@ export interface CreateTaskResponse { } // Create Task Blocking Response -export interface CreateTaskBlockingResponse { +export interface CreateTaskBlockingResponse { task_id: number; agent_uuid: string; task_token: string; timestamp: number; success: boolean; error_message: string | null; - task_event_result: TaskEventResult | null; + task_event_result: T | null; } // Delete Task Response @@ -221,12 +238,12 @@ export function useTask(backend = useBackendStore().currentBackend) { /** * 创建任务并阻塞等待 Agent 返回结果 */ - const createTaskBlocking = async ( + const createTaskBlocking = async ( targetUuid: string, taskType: TaskEventType, timeoutMs: number = 5000, - ): Promise => { - return rpc( + ) => { + return rpc>( "task_create_task_blocking", { token: backendToken.value, @@ -316,43 +333,59 @@ export function useTask(backend = useBackendStore().currentBackend) { }; // Convenience methods for creating specific task types - const createPingTask = async ( + const createPingTask = async ( targetUuid: string, target: string, - blocking: boolean = false, + blocking: T = false as T, timeoutMs?: number, - ): Promise => { + ): Promise< + T extends true ? CreateTaskBlockingResponse : CreateTaskResponse + > => { const taskType: PingTask = { ping: target }; - return blocking - ? createTaskBlocking(targetUuid, taskType, timeoutMs) - : createTask(targetUuid, taskType); + return ( + blocking + ? createTaskBlocking(targetUuid, taskType, timeoutMs) + : createTask(targetUuid, taskType) + ) as any; }; - const createTcpPingTask = async ( + const createTcpPingTask = async ( targetUuid: string, target: string, - blocking: boolean = false, + blocking: T = false as T, timeoutMs?: number, - ): Promise => { + ): Promise< + T extends true + ? CreateTaskBlockingResponse + : CreateTaskResponse + > => { const taskType: TcpPingTask = { tcp_ping: target }; - return blocking - ? createTaskBlocking(targetUuid, taskType, timeoutMs) - : createTask(targetUuid, taskType); + return ( + blocking + ? createTaskBlocking(targetUuid, taskType, timeoutMs) + : createTask(targetUuid, taskType) + ) as any; }; - const createHttpPingTask = async ( + const createHttpPingTask = async ( targetUuid: string, url: string, - blocking: boolean = false, + blocking: T = false as T, timeoutMs?: number, - ): Promise => { + ): Promise< + T extends true + ? CreateTaskBlockingResponse + : CreateTaskResponse + > => { const taskType: HttpPingTask = { http_ping: url }; - return blocking - ? createTaskBlocking(targetUuid, taskType, timeoutMs) - : createTask(targetUuid, taskType); + return ( + blocking + ? createTaskBlocking(targetUuid, taskType, timeoutMs) + : createTask(targetUuid, taskType) + ) as any; }; - const createHttpRequestTask = async ( + const createHttpRequestTask = async ( targetUuid: string, config: { url: string; @@ -362,38 +395,56 @@ export function useTask(backend = useBackendStore().currentBackend) { body_base64?: string; ip?: string; }, - blocking: boolean = false, + blocking: T = false as T, timeoutMs?: number, - ): Promise => { + ): Promise< + T extends true + ? CreateTaskBlockingResponse + : CreateTaskResponse + > => { const taskType: HttpRequestTask = { http_request: config }; - return blocking - ? createTaskBlocking(targetUuid, taskType, timeoutMs) - : createTask(targetUuid, taskType); + return ( + blocking + ? createTaskBlocking(targetUuid, taskType, timeoutMs) + : createTask(targetUuid, taskType) + ) as any; }; - const createSelfUpdateTask = async ( + const createSelfUpdateTask = async ( targetUuid: string, version: string, - blocking: boolean = false, + blocking: T = false as T, timeoutMs?: number, - ): Promise => { + ): Promise< + T extends true + ? CreateTaskBlockingResponse + : CreateTaskResponse + > => { const taskType: SelfUpdateTask = { self_update: version }; - return blocking - ? createTaskBlocking(targetUuid, taskType, timeoutMs) - : createTask(targetUuid, taskType); + return ( + blocking + ? createTaskBlocking(targetUuid, taskType, timeoutMs) + : createTask(targetUuid, taskType) + ) as any; }; - const createExecuteTask = async ( + const createExecuteTask = async ( targetUuid: string, cmd: string, args: string[] = [], - blocking: boolean = false, + blocking: T = false as T, timeoutMs?: number, - ): Promise => { + ): Promise< + T extends true + ? CreateTaskBlockingResponse + : CreateTaskResponse + > => { const taskType: ExecuteTask = { execute: { cmd, args } }; - return blocking - ? createTaskBlocking(targetUuid, taskType, timeoutMs) - : createTask(targetUuid, taskType); + return ( + blocking + ? createTaskBlocking(targetUuid, taskType, timeoutMs) + : createTask(targetUuid, taskType) + ) as any; }; const createWebShellTask = async ( @@ -407,49 +458,71 @@ export function useTask(backend = useBackendStore().currentBackend) { return createTask(targetUuid, taskType); }; - const createReadConfigTask = async ( + const createReadConfigTask = async ( targetUuid: string, - blocking: boolean = false, + blocking: T = false as T, timeoutMs?: number, - ): Promise => { + ): Promise< + T extends true + ? CreateTaskBlockingResponse + : CreateTaskResponse + > => { const taskType: ReadConfigTask = "read_config"; - return blocking - ? createTaskBlocking(targetUuid, taskType, timeoutMs) - : createTask(targetUuid, taskType); + return ( + blocking + ? createTaskBlocking(targetUuid, taskType, timeoutMs) + : createTask(targetUuid, taskType) + ) as any; }; - const createEditConfigTask = async ( + const createEditConfigTask = async ( targetUuid: string, configContent: string, - blocking: boolean = false, + blocking: T = false as T, timeoutMs?: number, - ): Promise => { + ): Promise< + T extends true + ? CreateTaskBlockingResponse + : CreateTaskResponse + > => { const taskType: EditConfigTask = { edit_config: configContent }; - return blocking - ? createTaskBlocking(targetUuid, taskType, timeoutMs) - : createTask(targetUuid, taskType); + return ( + blocking + ? createTaskBlocking(targetUuid, taskType, timeoutMs) + : createTask(targetUuid, taskType) + ) as any; }; - const createIpTask = async ( + const createIpTask = async ( targetUuid: string, - blocking: boolean = false, + blocking: T = false as T, timeoutMs?: number, - ): Promise => { + ): Promise< + T extends true ? CreateTaskBlockingResponse : CreateTaskResponse + > => { const taskType: IpTask = "ip"; - return blocking - ? createTaskBlocking(targetUuid, taskType, timeoutMs) - : createTask(targetUuid, taskType); + return ( + blocking + ? createTaskBlocking(targetUuid, taskType, timeoutMs) + : createTask(targetUuid, taskType) + ) as any; }; - const createVersionTask = async ( + const createVersionTask = async ( targetUuid: string, - blocking: boolean = false, + blocking: T, timeoutMs?: number, - ): Promise => { + ): Promise< + T extends true + ? CreateTaskBlockingResponse + : CreateTaskResponse + > => { const taskType: VersionTask = "version"; - return blocking - ? createTaskBlocking(targetUuid, taskType, timeoutMs) - : createTask(targetUuid, taskType); + return ( + blocking + ? createTaskBlocking(targetUuid, taskType, timeoutMs) + : createTask(targetUuid, taskType) + ) as any; }; return { From caa7c940bb0420e71734dde82310a845ab1e08ee Mon Sep 17 00:00:00 2001 From: LloydAsp Date: Wed, 20 May 2026 01:02:40 +0800 Subject: [PATCH 4/8] feat(agent-config): support allow_task_type format --- .../node/setting/NodeSettingTabConfig.vue | 179 +++++++++++------- src/composables/useAgentConfig.ts | 43 +++-- src/composables/useTask.ts | 2 +- 3 files changed, 142 insertions(+), 82 deletions(-) diff --git a/src/components/node/setting/NodeSettingTabConfig.vue b/src/components/node/setting/NodeSettingTabConfig.vue index aca73095..51c2e34a 100644 --- a/src/components/node/setting/NodeSettingTabConfig.vue +++ b/src/components/node/setting/NodeSettingTabConfig.vue @@ -8,6 +8,7 @@ import { Label } from "@/components/ui/label"; import { NumberField } from "@/components/ui/number-field"; import { Switch } from "@/components/ui/switch"; import { PopConfirm } from "@/components/ui/pop-confirm"; +import { type TaskString } from "@/composables/useTask"; import { useAgentConfig, type AgentConfig, @@ -46,7 +47,7 @@ const execMaxCharacter = ref(undefined); const connectTimeout = ref(undefined); // 特性开关 (server config中的allow_*属性) -const allowTask = ref(false); +const allowTaskType = ref(new Set()); const allowIcmpPing = ref(false); const allowTcpPing = ref(false); const allowHttpPing = ref(false); @@ -77,18 +78,7 @@ function syncFromConfig(config: splitConfig) { // 从 server 配置中提取第一个 server 的 allow_* 属性 if (currentUpstream) { - allowTask.value = currentUpstream.allow_task === true; - allowIcmpPing.value = currentUpstream.allow_icmp_ping === true; - allowTcpPing.value = currentUpstream.allow_tcp_ping === true; - allowHttpPing.value = currentUpstream.allow_http_ping === true; - allowHttpRequest.value = currentUpstream.allow_http_request === true; - ((allowSelfUpdate.value = currentUpstream.allow_self_update === true), - (allowWebShell.value = currentUpstream.allow_web_shell === true)); - allowExecute.value = currentUpstream.allow_execute === true; - allowReadConfig.value = currentUpstream.allow_read_config === true; - allowEditConfig.value = currentUpstream.allow_edit_config === true; - allowIp.value = currentUpstream.allow_edit_config === true; - allowVersion.value = currentUpstream.allow_version === true; + allowTaskType.value = new Set(currentUpstream.allow_task_type || []); } } @@ -132,18 +122,7 @@ function buildConfig(): AgentConfig { const currentUpstreamNew: UpstreamServer = { ...agentConfig.value.currentUpstream, - allow_task: allowTask.value, - allow_icmp_ping: allowIcmpPing.value, - allow_tcp_ping: allowTcpPing.value, - allow_http_ping: allowHttpPing.value, - allow_http_request: allowHttpRequest.value, - allow_self_update: allowSelfUpdate.value, - allow_web_shell: allowWebShell.value, - allow_execute: allowExecute.value, - allow_read_config: allowReadConfig.value, - allow_edit_config: allowEditConfig.value, - allow_ip: !!allowIp.value, - allow_version: !!allowVersion.value, + allow_task_type: Array.from(allowTaskType.value), }; return { @@ -181,9 +160,9 @@ async function handleSave() { const success = await writeAgentConfig(props.uuid, config); if (success) { - toast.success(t("dashboard.saveSuccess")); await delay(1000); agentConfig.value = await getAgentConfigExtra(props.uuid); + toast.success(t("dashboard.saveSuccess")); } else { toast.error(t("dashboard.saveFailed")); } @@ -195,22 +174,6 @@ async function handleSave() { saveLoading.value = false; } } - -/** - * 处理禁用 allow_edit_config - */ -function handleEditConfigToggle(checked: boolean) { - if (!checked) { - // 触发确认弹窗 - // 这里通过 PopConfirm 组件处理 - } else { - allowEditConfig.value = true; - } -} - -function confirmDisableEditConfig() { - allowEditConfig.value = false; -}