feat(clawbot): add native WeChat ClawBot protocol engine (clawbot.py) and WechatClawModal UI
This commit is contained in:
1 parent
07d2050c5f
commit
8fa46a2b8d
14 files changed
+1551
-201
No files matched your search
Generated
+331
@@ -14,10 +14,12 @@
|
|||||||
"@radix-ui/react-slot": "^1.5.0",
|
"@radix-ui/react-slot": "^1.5.0",
|
||||||
"@radix-ui/react-switch": "^1.4.1",
|
"@radix-ui/react-switch": "^1.4.1",
|
||||||
"@radix-ui/react-tabs": "^1.2.1",
|
"@radix-ui/react-tabs": "^1.2.1",
|
||||||
|
"@types/qrcode": "^1.5.6",
|
||||||
"class-variance-authority": "^0.7.1",
|
"class-variance-authority": "^0.7.1",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"cmdk": "^1.1.1",
|
"cmdk": "^1.1.1",
|
||||||
"lucide-react": "^0.475.0",
|
"lucide-react": "^0.475.0",
|
||||||
|
"qrcode": "^1.5.4",
|
||||||
"react": "^19.0.0",
|
"react": "^19.0.0",
|
||||||
"react-dom": "^19.0.0",
|
"react-dom": "^19.0.0",
|
||||||
"tailwind-merge": "^3.0.1",
|
"tailwind-merge": "^3.0.1",
|
||||||
@@ -2148,6 +2150,24 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/node": {
|
||||||
|
"version": "26.6.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-26.6.6.tgz",
|
||||||
|
"integrity": "sha512-MzQj+8Kx3XI40OmUAE6Qoh58ZMNstNNMwn2nfd3qWsfe7nDNSqJNzes4njhz6AHwrSHOffSLwXU6yb474Q4aog==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"undici-types": "~8.9.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@types/qrcode": {
|
||||||
|
"version": "1.5.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/qrcode/-/qrcode-1.5.6.tgz",
|
||||||
|
"integrity": "sha512-te7NQcV2BOvdj2b1hCAHzAoMNuj65kNBMz0KBaxM6c3VGBOhU0dURQKOtH8CFNI/dsKkwlv32p26qYQTWoB5bw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@types/react": {
|
"node_modules/@types/react": {
|
||||||
"version": "19.3.0",
|
"version": "19.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.3.0.tgz",
|
||||||
@@ -2189,6 +2209,30 @@
|
|||||||
"vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0"
|
"vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/ansi-regex": {
|
||||||
|
"version": "5.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
|
||||||
|
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/ansi-styles": {
|
||||||
|
"version": "4.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
|
||||||
|
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"color-convert": "^2.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/aria-hidden": {
|
"node_modules/aria-hidden": {
|
||||||
"version": "1.2.6",
|
"version": "1.2.6",
|
||||||
"resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.6.tgz",
|
"resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.6.tgz",
|
||||||
@@ -2248,6 +2292,15 @@
|
|||||||
"node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
|
"node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/camelcase": {
|
||||||
|
"version": "5.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
|
||||||
|
"integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/caniuse-lite": {
|
"node_modules/caniuse-lite": {
|
||||||
"version": "1.0.30001823",
|
"version": "1.0.30001823",
|
||||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001823.tgz",
|
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001823.tgz",
|
||||||
@@ -2281,6 +2334,17 @@
|
|||||||
"url": "https://polar.sh/cva"
|
"url": "https://polar.sh/cva"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/cliui": {
|
||||||
|
"version": "6.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz",
|
||||||
|
"integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"string-width": "^4.2.0",
|
||||||
|
"strip-ansi": "^6.0.0",
|
||||||
|
"wrap-ansi": "^6.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/clsx": {
|
"node_modules/clsx": {
|
||||||
"version": "2.1.1",
|
"version": "2.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz",
|
||||||
@@ -2306,6 +2370,24 @@
|
|||||||
"react-dom": "^18 || ^19 || ^19.0.0-rc"
|
"react-dom": "^18 || ^19 || ^19.0.0-rc"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/color-convert": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"color-name": "~1.1.4"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=7.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/color-name": {
|
||||||
|
"version": "1.1.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
||||||
|
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/convert-source-map": {
|
"node_modules/convert-source-map": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
|
||||||
@@ -2338,6 +2420,15 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/decamelize": {
|
||||||
|
"version": "1.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
|
||||||
|
"integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/detect-libc": {
|
"node_modules/detect-libc": {
|
||||||
"version": "2.1.2",
|
"version": "2.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
|
||||||
@@ -2354,6 +2445,12 @@
|
|||||||
"integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==",
|
"integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/dijkstrajs": {
|
||||||
|
"version": "1.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/dijkstrajs/-/dijkstrajs-1.0.3.tgz",
|
||||||
|
"integrity": "sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/electron-to-chromium": {
|
"node_modules/electron-to-chromium": {
|
||||||
"version": "1.5.478",
|
"version": "1.5.478",
|
||||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.478.tgz",
|
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.478.tgz",
|
||||||
@@ -2361,6 +2458,12 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
|
"node_modules/emoji-regex": {
|
||||||
|
"version": "8.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
|
||||||
|
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/enhanced-resolve": {
|
"node_modules/enhanced-resolve": {
|
||||||
"version": "5.26.1",
|
"version": "5.26.1",
|
||||||
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.26.1.tgz",
|
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.26.1.tgz",
|
||||||
@@ -2445,6 +2548,19 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/find-up": {
|
||||||
|
"version": "4.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
|
||||||
|
"integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"locate-path": "^5.0.0",
|
||||||
|
"path-exists": "^4.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/fsevents": {
|
"node_modules/fsevents": {
|
||||||
"version": "2.3.3",
|
"version": "2.3.3",
|
||||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
|
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
|
||||||
@@ -2470,6 +2586,15 @@
|
|||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/get-caller-file": {
|
||||||
|
"version": "2.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
|
||||||
|
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
|
||||||
|
"license": "ISC",
|
||||||
|
"engines": {
|
||||||
|
"node": "6.* || 8.* || >= 10.*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/get-nonce": {
|
"node_modules/get-nonce": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz",
|
||||||
@@ -2486,6 +2611,15 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
|
"node_modules/is-fullwidth-code-point": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/jiti": {
|
"node_modules/jiti": {
|
||||||
"version": "2.7.0",
|
"version": "2.7.0",
|
||||||
"resolved": "https://registry.npmjs.org/jiti/-/jiti-2.7.0.tgz",
|
"resolved": "https://registry.npmjs.org/jiti/-/jiti-2.7.0.tgz",
|
||||||
@@ -2802,6 +2936,18 @@
|
|||||||
"url": "https://opencollective.com/parcel"
|
"url": "https://opencollective.com/parcel"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/locate-path": {
|
||||||
|
"version": "5.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
|
||||||
|
"integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"p-locate": "^4.1.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/lru-cache": {
|
"node_modules/lru-cache": {
|
||||||
"version": "5.1.1",
|
"version": "5.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
|
||||||
@@ -2867,6 +3013,51 @@
|
|||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/p-limit": {
|
||||||
|
"version": "2.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
|
||||||
|
"integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"p-try": "^2.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/p-locate": {
|
||||||
|
"version": "4.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
|
||||||
|
"integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"p-limit": "^2.2.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/p-try": {
|
||||||
|
"version": "2.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
|
||||||
|
"integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/path-exists": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/picocolors": {
|
"node_modules/picocolors": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
|
||||||
@@ -2887,6 +3078,15 @@
|
|||||||
"url": "https://github.com/sponsors/jonschlinkert"
|
"url": "https://github.com/sponsors/jonschlinkert"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/pngjs": {
|
||||||
|
"version": "5.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/pngjs/-/pngjs-5.0.0.tgz",
|
||||||
|
"integrity": "sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10.13.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/postcss": {
|
"node_modules/postcss": {
|
||||||
"version": "8.5.32",
|
"version": "8.5.32",
|
||||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.32.tgz",
|
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.32.tgz",
|
||||||
@@ -2916,6 +3116,23 @@
|
|||||||
"node": "^10 || ^12 || >=14"
|
"node": "^10 || ^12 || >=14"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/qrcode": {
|
||||||
|
"version": "1.5.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/qrcode/-/qrcode-1.5.4.tgz",
|
||||||
|
"integrity": "sha512-1ca71Zgiu6ORjHqFBDpnSMTR2ReToX4l1Au1VFLyVeBTFavzQnv5JxMFr3ukHVKpSrSA2MCk0lNJSykjUfz7Zg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"dijkstrajs": "^1.0.1",
|
||||||
|
"pngjs": "^5.0.0",
|
||||||
|
"yargs": "^15.3.1"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"qrcode": "bin/qrcode"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10.13.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/react": {
|
"node_modules/react": {
|
||||||
"version": "19.3.1",
|
"version": "19.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/react/-/react-19.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/react/-/react-19.3.1.tgz",
|
||||||
@@ -3016,6 +3233,21 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/require-directory": {
|
||||||
|
"version": "2.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
|
||||||
|
"integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/require-main-filename": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==",
|
||||||
|
"license": "ISC"
|
||||||
|
},
|
||||||
"node_modules/rollup": {
|
"node_modules/rollup": {
|
||||||
"version": "4.67.5",
|
"version": "4.67.5",
|
||||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.67.5.tgz",
|
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.67.5.tgz",
|
||||||
@@ -3078,6 +3310,12 @@
|
|||||||
"semver": "bin/semver.js"
|
"semver": "bin/semver.js"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/set-blocking": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==",
|
||||||
|
"license": "ISC"
|
||||||
|
},
|
||||||
"node_modules/source-map-js": {
|
"node_modules/source-map-js": {
|
||||||
"version": "1.2.2",
|
"version": "1.2.2",
|
||||||
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.2.tgz",
|
||||||
@@ -3088,6 +3326,32 @@
|
|||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/string-width": {
|
||||||
|
"version": "4.2.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
|
||||||
|
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"emoji-regex": "^8.0.0",
|
||||||
|
"is-fullwidth-code-point": "^3.0.0",
|
||||||
|
"strip-ansi": "^6.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/strip-ansi": {
|
||||||
|
"version": "6.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
|
||||||
|
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"ansi-regex": "^5.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/tailwind-merge": {
|
"node_modules/tailwind-merge": {
|
||||||
"version": "3.7.0",
|
"version": "3.7.0",
|
||||||
"resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.7.0.tgz",
|
"resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.7.0.tgz",
|
||||||
@@ -3156,6 +3420,12 @@
|
|||||||
"node": ">=14.17"
|
"node": ">=14.17"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/undici-types": {
|
||||||
|
"version": "8.9.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-8.9.0.tgz",
|
||||||
|
"integrity": "sha512-KTDyRTYX8sWmKXAikPHHSyc63CRPETMctyjKFupcC6OBLXT3xsN0e9aF7m+mIXutFWpUXuedtowG7iLOzp0kQg==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/update-browserslist-db": {
|
"node_modules/update-browserslist-db": {
|
||||||
"version": "1.3.4",
|
"version": "1.3.4",
|
||||||
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.3.4.tgz",
|
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.3.4.tgz",
|
||||||
@@ -3305,6 +3575,32 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/which-module": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==",
|
||||||
|
"license": "ISC"
|
||||||
|
},
|
||||||
|
"node_modules/wrap-ansi": {
|
||||||
|
"version": "6.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
|
||||||
|
"integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"ansi-styles": "^4.0.0",
|
||||||
|
"string-width": "^4.1.0",
|
||||||
|
"strip-ansi": "^6.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/y18n": {
|
||||||
|
"version": "4.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz",
|
||||||
|
"integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==",
|
||||||
|
"license": "ISC"
|
||||||
|
},
|
||||||
"node_modules/yallist": {
|
"node_modules/yallist": {
|
||||||
"version": "3.1.1",
|
"version": "3.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
|
||||||
@@ -3312,6 +3608,41 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
|
"node_modules/yargs": {
|
||||||
|
"version": "15.4.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz",
|
||||||
|
"integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"cliui": "^6.0.0",
|
||||||
|
"decamelize": "^1.2.0",
|
||||||
|
"find-up": "^4.1.0",
|
||||||
|
"get-caller-file": "^2.0.1",
|
||||||
|
"require-directory": "^2.1.1",
|
||||||
|
"require-main-filename": "^2.0.0",
|
||||||
|
"set-blocking": "^2.0.0",
|
||||||
|
"string-width": "^4.2.0",
|
||||||
|
"which-module": "^2.0.0",
|
||||||
|
"y18n": "^4.0.0",
|
||||||
|
"yargs-parser": "^18.1.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/yargs-parser": {
|
||||||
|
"version": "18.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz",
|
||||||
|
"integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"camelcase": "^5.0.0",
|
||||||
|
"decamelize": "^1.2.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/zustand": {
|
"node_modules/zustand": {
|
||||||
"version": "5.1.0",
|
"version": "5.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/zustand/-/zustand-5.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/zustand/-/zustand-5.1.0.tgz",
|
||||||
|
|||||||
@@ -15,10 +15,12 @@
|
|||||||
"@radix-ui/react-slot": "^1.5.0",
|
"@radix-ui/react-slot": "^1.5.0",
|
||||||
"@radix-ui/react-switch": "^1.4.1",
|
"@radix-ui/react-switch": "^1.4.1",
|
||||||
"@radix-ui/react-tabs": "^1.2.1",
|
"@radix-ui/react-tabs": "^1.2.1",
|
||||||
|
"@types/qrcode": "^1.5.6",
|
||||||
"class-variance-authority": "^0.7.1",
|
"class-variance-authority": "^0.7.1",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"cmdk": "^1.1.1",
|
"cmdk": "^1.1.1",
|
||||||
"lucide-react": "^0.475.0",
|
"lucide-react": "^0.475.0",
|
||||||
|
"qrcode": "^1.5.4",
|
||||||
"react": "^19.0.0",
|
"react": "^19.0.0",
|
||||||
"react-dom": "^19.0.0",
|
"react-dom": "^19.0.0",
|
||||||
"tailwind-merge": "^3.0.1",
|
"tailwind-merge": "^3.0.1",
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { SshShelf } from './components/SshShelf';
|
|||||||
import { CommandPalette } from './components/CommandPalette';
|
import { CommandPalette } from './components/CommandPalette';
|
||||||
import { AgyTerminalModal } from './components/AgyTerminalModal';
|
import { AgyTerminalModal } from './components/AgyTerminalModal';
|
||||||
import { AuthGateCard } from './components/AuthGateModal';
|
import { AuthGateCard } from './components/AuthGateModal';
|
||||||
|
import { WechatClawModal } from './components/WechatClawModal';
|
||||||
import { StorybookWorkbench } from './components/StorybookWorkbench';
|
import { StorybookWorkbench } from './components/StorybookWorkbench';
|
||||||
import { LAYOUT_PRESETS } from './design-system/tokens';
|
import { LAYOUT_PRESETS } from './design-system/tokens';
|
||||||
import type { ServiceGroup } from './types/telemetry';
|
import type { ServiceGroup } from './types/telemetry';
|
||||||
@@ -244,6 +245,9 @@ export const App: React.FC = () => {
|
|||||||
{/* 5. Embedded AGY Cloud Terminal Modal */}
|
{/* 5. Embedded AGY Cloud Terminal Modal */}
|
||||||
<AgyTerminalModal />
|
<AgyTerminalModal />
|
||||||
|
|
||||||
|
{/* 5b. WeChat ClawBot QR Code & Live Status Modal */}
|
||||||
|
<WechatClawModal />
|
||||||
|
|
||||||
{/* 6. Custom SSO Auth Gate Modal (Replaces Browser Native Basic Auth Popup!) */}
|
{/* 6. Custom SSO Auth Gate Modal (Replaces Browser Native Basic Auth Popup!) */}
|
||||||
{authRedirect && (
|
{authRedirect && (
|
||||||
<div className="fixed inset-0 z-50 bg-black/75 backdrop-blur-sm flex items-center justify-center p-4">
|
<div className="fixed inset-0 z-50 bg-black/75 backdrop-blur-sm flex items-center justify-center p-4">
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { BookOpen, LayoutGrid, Moon, Search, Sun, Terminal } from 'lucide-react';
|
import { BookOpen, LayoutGrid, MessageSquare, Moon, Search, Sun, Terminal } from 'lucide-react';
|
||||||
import { usePortalStore } from '../store/usePortalStore';
|
import { usePortalStore } from '../store/usePortalStore';
|
||||||
import type { RouteModeId } from '../types/telemetry';
|
import type { RouteModeId } from '../types/telemetry';
|
||||||
import { Button } from './ui/button';
|
import { Button } from './ui/button';
|
||||||
@@ -24,6 +24,7 @@ export const TopRibbon: React.FC = () => {
|
|||||||
setRouteMode,
|
setRouteMode,
|
||||||
setViewMode,
|
setViewMode,
|
||||||
setShowAgyModal,
|
setShowAgyModal,
|
||||||
|
setShowWechatModal,
|
||||||
setShowCmdPalette,
|
setShowCmdPalette,
|
||||||
} = usePortalStore();
|
} = usePortalStore();
|
||||||
|
|
||||||
@@ -98,6 +99,21 @@ export const TopRibbon: React.FC = () => {
|
|||||||
</kbd>
|
</kbd>
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
onClick={() => setShowWechatModal(true)}
|
||||||
|
title="连接微信 ClawBot,在微信内直接收发消息与控制 Mac mini"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
className="w-2 h-2 rounded-full"
|
||||||
|
style={{
|
||||||
|
backgroundColor: telemetry.services.clawbot ? 'var(--success)' : 'var(--accent)',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<MessageSquare className="w-3.5 h-3.5" />
|
||||||
|
<span>微信 ClawBot</span>
|
||||||
|
</Button>
|
||||||
|
|
||||||
<Button onClick={() => setShowAgyModal(true)}>
|
<Button onClick={() => setShowAgyModal(true)}>
|
||||||
<Terminal className="w-3.5 h-3.5" />
|
<Terminal className="w-3.5 h-3.5" />
|
||||||
<span>AGY 终端</span>
|
<span>AGY 终端</span>
|
||||||
|
|||||||
@@ -0,0 +1,301 @@
|
|||||||
|
import React, { useEffect, useState } from 'react';
|
||||||
|
import QRCode from 'qrcode';
|
||||||
|
import {
|
||||||
|
CheckCircle2,
|
||||||
|
MessageSquare,
|
||||||
|
QrCode,
|
||||||
|
RefreshCw,
|
||||||
|
Send,
|
||||||
|
Smartphone,
|
||||||
|
Unplug,
|
||||||
|
} from 'lucide-react';
|
||||||
|
import { usePortalStore } from '../store/usePortalStore';
|
||||||
|
import type { ClawbotPublicStatus } from '../types/telemetry';
|
||||||
|
import { Badge } from './ui/badge';
|
||||||
|
import { Button } from './ui/button';
|
||||||
|
import { Dialog, DialogContent, DialogDescription, DialogTitle } from './ui/dialog';
|
||||||
|
import { Input } from './ui/input';
|
||||||
|
|
||||||
|
export const WechatClawModal: React.FC = () => {
|
||||||
|
const { showWechatModal, setShowWechatModal, showToast, fetchTelemetry } = usePortalStore();
|
||||||
|
const [statusData, setStatusData] = useState<ClawbotPublicStatus | null>(null);
|
||||||
|
const [qrDataUrl, setQrDataUrl] = useState<string>('');
|
||||||
|
const [loadingQr, setLoadingQr] = useState(false);
|
||||||
|
const [verifyCode, setVerifyCode] = useState('');
|
||||||
|
const [submittingCode, setSubmittingCode] = useState(false);
|
||||||
|
|
||||||
|
const generateNewQr = async () => {
|
||||||
|
setLoadingQr(true);
|
||||||
|
try {
|
||||||
|
const res = await fetch('/api/clawbot/qrcode', { method: 'POST' });
|
||||||
|
const data = await res.json();
|
||||||
|
setStatusData(data);
|
||||||
|
const url = data?.login?.qrcode_url;
|
||||||
|
if (url) {
|
||||||
|
const svgUrl = await QRCode.toDataURL(url, {
|
||||||
|
width: 240,
|
||||||
|
margin: 2,
|
||||||
|
color: { dark: '#09090b', light: '#ffffff' },
|
||||||
|
});
|
||||||
|
setQrDataUrl(svgUrl);
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
showToast('获取微信 ClawBot 二维码失败');
|
||||||
|
} finally {
|
||||||
|
setLoadingQr(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Initial load & polling while modal is open
|
||||||
|
useEffect(() => {
|
||||||
|
if (!showWechatModal) return;
|
||||||
|
|
||||||
|
let cancelled = false;
|
||||||
|
const init = async () => {
|
||||||
|
try {
|
||||||
|
const r = await fetch('/api/clawbot/status');
|
||||||
|
const d: ClawbotPublicStatus = await r.json();
|
||||||
|
if (cancelled) return;
|
||||||
|
setStatusData(d);
|
||||||
|
if (!d.connected && (!d.login?.active || !d.login?.qrcode_url)) {
|
||||||
|
await generateNewQr();
|
||||||
|
} else if (d.login?.qrcode_url) {
|
||||||
|
const svgUrl = await QRCode.toDataURL(d.login.qrcode_url, {
|
||||||
|
width: 240,
|
||||||
|
margin: 2,
|
||||||
|
color: { dark: '#09090b', light: '#ffffff' },
|
||||||
|
});
|
||||||
|
if (!cancelled) setQrDataUrl(svgUrl);
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
};
|
||||||
|
init();
|
||||||
|
|
||||||
|
const timer = setInterval(async () => {
|
||||||
|
try {
|
||||||
|
const r = await fetch('/api/clawbot/status');
|
||||||
|
if (!r.ok) return;
|
||||||
|
const d: ClawbotPublicStatus = await r.json();
|
||||||
|
if (cancelled) return;
|
||||||
|
setStatusData(d);
|
||||||
|
if (d.login?.qrcode_url) {
|
||||||
|
const svgUrl = await QRCode.toDataURL(d.login.qrcode_url, {
|
||||||
|
width: 240,
|
||||||
|
margin: 2,
|
||||||
|
color: { dark: '#09090b', light: '#ffffff' },
|
||||||
|
});
|
||||||
|
if (!cancelled) setQrDataUrl(svgUrl);
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
}, 1500);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
cancelled = true;
|
||||||
|
clearInterval(timer);
|
||||||
|
};
|
||||||
|
}, [showWechatModal]);
|
||||||
|
|
||||||
|
const handleVerifySubmit = async (e: React.FormEvent) => {
|
||||||
|
e.preventDefault();
|
||||||
|
if (!verifyCode.trim()) return;
|
||||||
|
setSubmittingCode(true);
|
||||||
|
try {
|
||||||
|
const res = await fetch('/api/clawbot/verify', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({ code: verifyCode.trim() }),
|
||||||
|
});
|
||||||
|
const data = await res.json();
|
||||||
|
setStatusData(data);
|
||||||
|
setVerifyCode('');
|
||||||
|
showToast('配对码已提交,正在等待微信验证...');
|
||||||
|
} catch {
|
||||||
|
showToast('配对码提交失败');
|
||||||
|
} finally {
|
||||||
|
setSubmittingCode(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleDisconnect = async () => {
|
||||||
|
try {
|
||||||
|
const res = await fetch('/api/clawbot/disconnect', { method: 'POST' });
|
||||||
|
const data = await res.json();
|
||||||
|
setStatusData(data);
|
||||||
|
setQrDataUrl('');
|
||||||
|
fetchTelemetry();
|
||||||
|
showToast('已断开微信 ClawBot 连接');
|
||||||
|
} catch {
|
||||||
|
showToast('断开失败');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const connected = Boolean(statusData?.connected);
|
||||||
|
const loginState = statusData?.login;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Dialog open={showWechatModal} onOpenChange={setShowWechatModal}>
|
||||||
|
<DialogContent className="max-w-lg p-6 space-y-5">
|
||||||
|
{/* Header */}
|
||||||
|
<div className="flex items-start justify-between gap-3 border-b hl-border pb-4">
|
||||||
|
<div className="flex items-center gap-3">
|
||||||
|
<div
|
||||||
|
className="w-10 h-10 rounded-xl flex items-center justify-center border hl-border shrink-0"
|
||||||
|
style={{ backgroundColor: 'rgba(16, 185, 129, 0.14)', color: 'var(--success)' }}
|
||||||
|
>
|
||||||
|
<MessageSquare className="w-5 h-5" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<DialogTitle className="text-sm font-bold">
|
||||||
|
微信 ClawBot · M6 Mac mini 直连通道
|
||||||
|
</DialogTitle>
|
||||||
|
<Badge variant={connected ? 'success' : 'accent'}>
|
||||||
|
{connected ? '已连接在线' : '扫码绑定'}
|
||||||
|
</Badge>
|
||||||
|
</div>
|
||||||
|
<DialogDescription className="text-xs font-mono-num mt-0.5">
|
||||||
|
@tencent-weixin/openclaw-weixin · ilinkai.weixin.qq.com
|
||||||
|
</DialogDescription>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Body: Connected vs QR Login */}
|
||||||
|
{connected ? (
|
||||||
|
<div className="space-y-4">
|
||||||
|
<div
|
||||||
|
className="p-4 rounded-xl border flex items-center justify-between"
|
||||||
|
style={{
|
||||||
|
backgroundColor: 'var(--success-soft)',
|
||||||
|
borderColor: 'rgba(16, 185, 129, 0.3)',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div className="flex items-center gap-3">
|
||||||
|
<CheckCircle2 className="w-5 h-5 shrink-0" style={{ color: 'var(--success)' }} />
|
||||||
|
<div>
|
||||||
|
<div className="text-xs font-bold">微信 ClawBot 长轮询守护线程运行中</div>
|
||||||
|
<div className="text-[11px] font-mono-num mt-0.5" style={{ color: 'var(--text-muted)' }}>
|
||||||
|
Bot ID: {statusData?.bot_id} · 累计收发: {statusData?.msg_count ?? 0} 条
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Button variant="outline" size="sm" onClick={handleDisconnect}>
|
||||||
|
<Unplug className="w-3.5 h-3.5" />
|
||||||
|
<span>重新绑定</span>
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="p-4 rounded-xl hl-muted border hl-border space-y-2.5 text-xs">
|
||||||
|
<div className="font-semibold">📱 现在打开手机微信「微信 ClawBot」可直接发送:</div>
|
||||||
|
<div className="grid grid-cols-1 sm:grid-cols-2 gap-2 font-mono-num text-[11px]">
|
||||||
|
<div className="p-2 rounded hl-card">
|
||||||
|
<span style={{ color: 'var(--accent)' }}>状态</span> · 查看 M6 & 极空间遥测
|
||||||
|
</div>
|
||||||
|
<div className="p-2 rounded hl-card">
|
||||||
|
<span style={{ color: 'var(--accent)' }}>备份</span> · 立即打包备份至 20TB NAS
|
||||||
|
</div>
|
||||||
|
<div className="p-2 rounded hl-card">
|
||||||
|
<span style={{ color: 'var(--accent)' }}>屏幕</span> · 截取 AGY 终端实时画面
|
||||||
|
</div>
|
||||||
|
<div className="p-2 rounded hl-card">
|
||||||
|
<span style={{ color: 'var(--accent)' }}>$ df -h</span> · 执行任意 Mac mini 命令
|
||||||
|
</div>
|
||||||
|
<div className="p-2 rounded hl-card sm:col-span-2">
|
||||||
|
<span style={{ color: 'var(--accent)' }}>> 你好</span> 或直接发任意问题 · 注入 AGY 终端或调用 AI 回答
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className="space-y-4">
|
||||||
|
<div className="flex flex-col items-center justify-center p-5 rounded-xl hl-muted border hl-border space-y-3">
|
||||||
|
{qrDataUrl ? (
|
||||||
|
<div className="p-3 bg-white rounded-xl shadow-md border">
|
||||||
|
<img
|
||||||
|
src={qrDataUrl}
|
||||||
|
alt="WeChat ClawBot QR Code"
|
||||||
|
className="w-48 h-48 block"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className="w-48 h-48 rounded-xl hl-card flex items-center justify-center text-xs font-mono-num">
|
||||||
|
{loadingQr ? '正在向微信申请二维码...' : '点击下方按钮生成二维码'}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<div className="flex items-center gap-2 text-xs font-medium text-center">
|
||||||
|
<Smartphone className="w-4 h-4 shrink-0" style={{ color: 'var(--accent)' }} />
|
||||||
|
<span>{loginState?.message || '请使用手机微信扫描上方二维码启用 ClawBot'}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
size="sm"
|
||||||
|
onClick={generateNewQr}
|
||||||
|
disabled={loadingQr}
|
||||||
|
>
|
||||||
|
<RefreshCw className="w-3.5 h-3.5" />
|
||||||
|
<span>{loadingQr ? '刷新中...' : '刷新二维码'}</span>
|
||||||
|
</Button>
|
||||||
|
{loginState?.qrcode_url && (
|
||||||
|
<Button variant="ghost" size="sm" asChild>
|
||||||
|
<a
|
||||||
|
href={loginState.qrcode_url}
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
className="font-mono-num"
|
||||||
|
>
|
||||||
|
<QrCode className="w-3.5 h-3.5" />
|
||||||
|
<span>打开备用链接 ↗</span>
|
||||||
|
</a>
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Verify Code Input (if WeChat prompts for pairing digits) */}
|
||||||
|
{loginState?.status === 'need_verifycode' && (
|
||||||
|
<form
|
||||||
|
onSubmit={handleVerifySubmit}
|
||||||
|
className="p-4 rounded-xl border space-y-2.5"
|
||||||
|
style={{
|
||||||
|
backgroundColor: 'var(--accent-soft)',
|
||||||
|
borderColor: 'var(--accent)',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<label className="block text-xs font-bold">
|
||||||
|
🔢 手机微信上显示了配对数字,请在下方输入:
|
||||||
|
</label>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<Input
|
||||||
|
type="text"
|
||||||
|
value={verifyCode}
|
||||||
|
onChange={(e) => setVerifyCode(e.target.value)}
|
||||||
|
placeholder="输入手机微信显示的 6 位数字..."
|
||||||
|
className="font-mono-num"
|
||||||
|
autoFocus
|
||||||
|
/>
|
||||||
|
<Button type="submit" disabled={submittingCode}>
|
||||||
|
<Send className="w-3.5 h-3.5" />
|
||||||
|
<span>验证</span>
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<div className="flex items-center justify-end pt-1">
|
||||||
|
<Button variant="outline" onClick={() => setShowWechatModal(false)}>
|
||||||
|
关闭窗口
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -9,6 +9,7 @@ interface PortalState {
|
|||||||
layoutPreset: LayoutPresetId;
|
layoutPreset: LayoutPresetId;
|
||||||
viewMode: 'dashboard' | 'storybook';
|
viewMode: 'dashboard' | 'storybook';
|
||||||
showAgyModal: boolean;
|
showAgyModal: boolean;
|
||||||
|
showWechatModal: boolean;
|
||||||
showCmdPalette: boolean;
|
showCmdPalette: boolean;
|
||||||
toast: string;
|
toast: string;
|
||||||
actionLoading: boolean;
|
actionLoading: boolean;
|
||||||
@@ -19,6 +20,7 @@ interface PortalState {
|
|||||||
setLayoutPreset: (preset: LayoutPresetId) => void;
|
setLayoutPreset: (preset: LayoutPresetId) => void;
|
||||||
setViewMode: (view: 'dashboard' | 'storybook') => void;
|
setViewMode: (view: 'dashboard' | 'storybook') => void;
|
||||||
setShowAgyModal: (open: boolean) => void;
|
setShowAgyModal: (open: boolean) => void;
|
||||||
|
setShowWechatModal: (open: boolean) => void;
|
||||||
setShowCmdPalette: (open: boolean) => void;
|
setShowCmdPalette: (open: boolean) => void;
|
||||||
showToast: (msg: string) => void;
|
showToast: (msg: string) => void;
|
||||||
fetchTelemetry: () => Promise<void>;
|
fetchTelemetry: () => Promise<void>;
|
||||||
@@ -34,11 +36,11 @@ const getSystemDark = () =>
|
|||||||
|
|
||||||
const applyDomTheme = (mode: ThemeId): 'light' | 'dark' => {
|
const applyDomTheme = (mode: ThemeId): 'light' | 'dark' => {
|
||||||
const isDark = mode === 'system' ? getSystemDark() : mode === 'dark';
|
const isDark = mode === 'system' ? getSystemDark() : mode === 'dark';
|
||||||
const domTheme = isDark ? 'catppuccin' : 'zinc-light';
|
const domTheme = isDark ? 'dark' : 'light';
|
||||||
if (typeof document !== 'undefined') {
|
if (typeof document !== 'undefined') {
|
||||||
document.documentElement.setAttribute('data-theme', domTheme);
|
document.documentElement.setAttribute('data-theme', domTheme);
|
||||||
}
|
}
|
||||||
return isDark ? 'dark' : 'light';
|
return domTheme;
|
||||||
};
|
};
|
||||||
|
|
||||||
const storedTheme = localStorage.getItem('hl_theme_v2') as ThemeId | null;
|
const storedTheme = localStorage.getItem('hl_theme_v2') as ThemeId | null;
|
||||||
@@ -62,6 +64,7 @@ export const usePortalStore = create<PortalState>((set, get) => ({
|
|||||||
layoutPreset: initialLayout,
|
layoutPreset: initialLayout,
|
||||||
viewMode: initialView,
|
viewMode: initialView,
|
||||||
showAgyModal: false,
|
showAgyModal: false,
|
||||||
|
showWechatModal: false,
|
||||||
showCmdPalette: false,
|
showCmdPalette: false,
|
||||||
toast: '',
|
toast: '',
|
||||||
actionLoading: false,
|
actionLoading: false,
|
||||||
@@ -105,6 +108,7 @@ export const usePortalStore = create<PortalState>((set, get) => ({
|
|||||||
clash: true,
|
clash: true,
|
||||||
router: true,
|
router: true,
|
||||||
uptime: true,
|
uptime: true,
|
||||||
|
clawbot: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -138,6 +142,7 @@ export const usePortalStore = create<PortalState>((set, get) => ({
|
|||||||
},
|
},
|
||||||
|
|
||||||
setShowAgyModal: (showAgyModal) => set({ showAgyModal }),
|
setShowAgyModal: (showAgyModal) => set({ showAgyModal }),
|
||||||
|
setShowWechatModal: (showWechatModal) => set({ showWechatModal }),
|
||||||
setShowCmdPalette: (showCmdPalette) => set({ showCmdPalette }),
|
setShowCmdPalette: (showCmdPalette) => set({ showCmdPalette }),
|
||||||
|
|
||||||
showToast: (msg) => {
|
showToast: (msg) => {
|
||||||
|
|||||||
@@ -1,6 +1,23 @@
|
|||||||
export type ThemeId = 'system' | 'light' | 'dark';
|
export type ThemeId = 'system' | 'light' | 'dark';
|
||||||
export type RouteModeId = 'auto' | 'edge443' | 'home10443' | 'lan';
|
export type RouteModeId = 'auto' | 'edge443' | 'home10443' | 'lan';
|
||||||
|
|
||||||
|
export interface ClawbotPublicStatus {
|
||||||
|
connected: boolean;
|
||||||
|
bot_id?: string;
|
||||||
|
user_id?: string;
|
||||||
|
base_url?: string;
|
||||||
|
connected_at?: string;
|
||||||
|
msg_count?: number;
|
||||||
|
last_inbound_text?: string;
|
||||||
|
last_reply_text?: string;
|
||||||
|
login?: {
|
||||||
|
active: boolean;
|
||||||
|
qrcode_url: string;
|
||||||
|
status: string;
|
||||||
|
message: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export interface TelemetryData {
|
export interface TelemetryData {
|
||||||
timestamp?: string;
|
timestamp?: string;
|
||||||
mini: {
|
mini: {
|
||||||
@@ -53,7 +70,9 @@ export interface TelemetryData {
|
|||||||
clash: boolean;
|
clash: boolean;
|
||||||
router: boolean;
|
router: boolean;
|
||||||
uptime: boolean;
|
uptime: boolean;
|
||||||
|
clawbot?: boolean;
|
||||||
};
|
};
|
||||||
|
clawbot?: ClawbotPublicStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface StatCell {
|
export interface StatCell {
|
||||||
@@ -68,7 +87,7 @@ export interface ServiceCardItem {
|
|||||||
subtitle: string;
|
subtitle: string;
|
||||||
iconUrl: string;
|
iconUrl: string;
|
||||||
online: boolean;
|
online: boolean;
|
||||||
actionType?: 'drawer' | 'backup';
|
actionType?: 'drawer' | 'backup' | 'clawbot';
|
||||||
desc: string;
|
desc: string;
|
||||||
edgeUrl: string;
|
edgeUrl: string;
|
||||||
homeUrl: string;
|
homeUrl: string;
|
||||||
|
|||||||
Reference in new issue
Block a user