diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000..a5aa07b --- /dev/null +++ b/.npmrc @@ -0,0 +1,2 @@ +//npm.xiongxiao.me/:_authToken=${ME_NPM_TOKEN} +//registry.npmjs.org/:_authToken=${NPM_TOKEN} diff --git a/bun.config.mjs b/bun.config.ts similarity index 61% rename from bun.config.mjs rename to bun.config.ts index 5abf321..5df3d42 100644 --- a/bun.config.mjs +++ b/bun.config.ts @@ -1,4 +1,3 @@ -// @ts-check import { resolvePath } from '@kevisual/use-config'; import { execSync } from 'node:child_process'; @@ -8,6 +7,17 @@ const external = ['pm2']; /** * @type {import('bun').BuildConfig} */ +// await Bun.build({ +// target: 'node', +// format: 'esm', +// entrypoints: [resolvePath(entry, { meta: import.meta })], +// outdir: resolvePath('./dist', { meta: import.meta }), +// naming: { +// entry: `${naming}.js`, +// }, +// external, +// }); + await Bun.build({ target: 'node', format: 'esm', @@ -16,6 +26,5 @@ await Bun.build({ naming: { entry: `${naming}.js`, }, - external, - env: 'KEVISUAL_*', + external }); \ No newline at end of file diff --git a/mod.ts b/mod.ts new file mode 100644 index 0000000..54460dc --- /dev/null +++ b/mod.ts @@ -0,0 +1,3 @@ +import { Hotkeys } from './src/hot-api/hotkeys/index'; + +export { Hotkeys } \ No newline at end of file diff --git a/package.json b/package.json index add9538..b397bbe 100644 --- a/package.json +++ b/package.json @@ -1,40 +1,37 @@ { - "name": "@kevisual/router-template-server", + "name": "@kevisual/hot-api", "version": "0.0.1", "description": "", - "main": "index.js", - "basename": "/root/router-template-server", + "main": "mod.ts", + "basename": "/root/hot-api", "app": { "type": "system-app", - "key": "router-template-server", "entry": "app.js", "runtime": [ - "server" + "client" ] }, "scripts": { "dev": "bun --watch src/main.ts ", - "build": "pnpm run clean && bun run bun.config.mjs", + "build": "pnpm run clean && bun run bun.config.ts", "postbuild": "ev pack", - "compile": "bun build --compile ./src/main.ts --outfile router-template", - "compile:win": "bun build --compile ./src/main.ts --target=bun-windows-x64 --outfile router-template.exe", "clean": "rm -rf dist && rimraf pack-dist", "pub": "envision pack -p -u" }, "files": [ - "dist" + "dist", + "src" ], "keywords": [], "author": "abearxiong (https://www.xiongxiao.me)", "license": "MIT", - "packageManager": "pnpm@10.22.0", + "packageManager": "pnpm@10.24.0", "type": "module", "dependencies": { - "@kevisual/ai": "^0.0.11", - "@kevisual/local-proxy": "^0.0.8", - "@kevisual/query": "^0.0.29", + "@kevisual/ai": "^0.0.16", + "@kevisual/query": "^0.0.30", "@kevisual/router": "0.0.33", - "@kevisual/use-config": "^1.0.19", + "@kevisual/use-config": "^1.0.21", "@nut-tree/nut-js": "^4.2.0", "archiver": "^7.0.1", "dayjs": "^1.11.19", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c621892..67386f7 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -9,20 +9,17 @@ importers: .: dependencies: '@kevisual/ai': - specifier: ^0.0.11 - version: 0.0.11 - '@kevisual/local-proxy': - specifier: ^0.0.8 - version: 0.0.8 + specifier: ^0.0.16 + version: 0.0.16 '@kevisual/query': - specifier: ^0.0.29 - version: 0.0.29 + specifier: ^0.0.30 + version: 0.0.30 '@kevisual/router': specifier: 0.0.33 version: 0.0.33 '@kevisual/use-config': - specifier: ^1.0.19 - version: 1.0.19(dotenv@16.6.1) + specifier: ^1.0.21 + version: 1.0.21(dotenv@16.6.1) '@nut-tree/nut-js': specifier: ^4.2.0 version: 4.2.0 @@ -223,20 +220,20 @@ packages: '@jimp/utils@0.22.12': resolution: {integrity: sha512-yJ5cWUknGnilBq97ZXOyOS0HhsHOyAyjHwYfHxGbSyMTohgQI6sVyE8KPgDwH8HHW/nMKXk8TrSwAE71zt716Q==} - '@kevisual/ai@0.0.11': - resolution: {integrity: sha512-SceIxodtjttLurZuXImZmJbimSt/NJW7N8vQArr0AaxqUam/WwcOTPYSVCleGhUW196Vew/FKC5k0vjyBMZZ5Q==} + '@kevisual/ai@0.0.16': + resolution: {integrity: sha512-K5KYm+dwHCnB61BhVFh9UcWiOS/FeS29ijvgwE/cQR8RonfPtX/oI7WhAu0jCGGSxTI6cel2LjrpU4JoVzWgnA==} '@kevisual/load@0.0.6': resolution: {integrity: sha512-+3YTFehRcZ1haGel5DKYMUwmi5i6f2psyaPZlfkKU/cOXgkpwoG9/BEqPCnPjicKqqnksEpixVRkyHJ+5bjLVA==} - '@kevisual/local-proxy@0.0.8': - resolution: {integrity: sha512-VX/P+6/Cc8ruqp34ag6gVX073BchUmf5VNZcTV/6MJtjrNE76G8V6TLpBE8bywLnrqyRtFLIspk4QlH8up9B5Q==} - '@kevisual/logger@0.0.4': resolution: {integrity: sha512-+fpr92eokSxoGOW1SIRl/27lPuO+zyY+feR5o2Q4YCNlAdt2x64NwC/w8r/3NEC5QenLgd4K0azyKTI2mHbARw==} - '@kevisual/query@0.0.29': - resolution: {integrity: sha512-rQZk0J073UuC1QGzuyq+pb4Y0hu8/Qx/xYHs9NbsmslM+RuMnd1zpXmvhXNj7Kn1MdYTH90ng2MlFLBkkQFaIg==} + '@kevisual/permission@0.0.3': + resolution: {integrity: sha512-8JsA/5O5Ax/z+M+MYpFYdlioHE6jNmWMuFSokBWYs9CCAHNiSKMR01YLkoVDoPvncfH/Y8F5K/IEXRCbptuMNA==} + + '@kevisual/query@0.0.30': + resolution: {integrity: sha512-mDPEaLX9LdTRgi9anmWQ4EJ491umsASu/gs6K85J5nJqtUN/kfnZ3x5IouUr6aNbgAhrNLv/vTqpQTBsQhEYHQ==} '@kevisual/router@0.0.33': resolution: {integrity: sha512-9z7TkSzCIGbXn9SuHPBdZpGwHlAuwA8iN5jNAZBUvbEvBRkBxlrbdCSe9fBYiAHueLm2AceFNrW74uulOiAkqA==} @@ -244,10 +241,10 @@ packages: '@kevisual/types@0.0.10': resolution: {integrity: sha512-Q73uzzjk9UidumnmCvOpgzqDDvQxsblz22bIFuoiioUFJWwaparx8bpd8ArRyFojicYL1YJoFDzDZ9j9NN8grA==} - '@kevisual/use-config@1.0.19': - resolution: {integrity: sha512-Q1IH4eMqUe5w6Bq8etoqOSls9FPIy0xwwD3wHf26EsQLZadhccI9qkDuFzP/rFWDa57mwFPEfwbGE5UlqWOCkw==} + '@kevisual/use-config@1.0.21': + resolution: {integrity: sha512-czgy4+tBDBJI6QTnKh2PCwswET6ZpZ4ZqBE/SPkkOivEtlrcPzLs5elwMLZ3goD1XMD4VB3yjumb5WuW/8H8MA==} peerDependencies: - dotenv: ^16.4.7 + dotenv: ^17 '@nut-tree/default-clipboard-provider@4.2.0': resolution: {integrity: sha512-O9EXd7F+iuHcm1XaIT1wNa34WYQDxriKYwUhyofvJpl0fJ0ou3u+nxHITmsr1zoBoERaOhG+PT3MSSNsQ+rTug==} @@ -278,10 +275,6 @@ packages: peerDependencies: '@nut-tree/nut-js': ^3 - '@nut-tree/node-mac-permissions@2.2.1': - resolution: {integrity: sha512-yoijwCqt2yS9UFTv7THGUwZgy2D2TorN703QpYNOergbTJ6vEmeG379pIZDfBuvf56n24RMzKJVoSqr9WIq/Yw==} - os: [darwin] - '@nut-tree/nut-js@4.2.0': resolution: {integrity: sha512-/xXsE7Z6+lOiltZgNWy6uPgiReSabgEYiTJFG2VqA9kRELtoiTyLM8ySds78zpPdTYYaL/Usi05+u54pIXnqQA==} engines: {node: '>=16'} @@ -666,9 +659,6 @@ packages: node-abort-controller@3.1.1: resolution: {integrity: sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==} - node-addon-api@5.0.0: - resolution: {integrity: sha512-CvkDw2OEnme7ybCykJpVcKH+uAOLV2qLqiyla128dN9TkEWfrYmxG6C2boDe5KcNQqZF3orkqzGgOMvZ/JNekA==} - node-fetch@2.7.0: resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} engines: {node: 4.x || >=6.0.0} @@ -700,18 +690,6 @@ packages: once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} - openai@5.23.2: - resolution: {integrity: sha512-MQBzmTulj+MM5O8SKEk/gL8a7s5mktS9zUtAkU257WjvobGc9nKcBuVwjyEEcb9SI8a8Y2G/mzn3vm9n1Jlleg==} - hasBin: true - peerDependencies: - ws: ^8.18.0 - zod: ^3.23.8 - peerDependenciesMeta: - ws: - optional: true - zod: - optional: true - p-finally@1.0.0: resolution: {integrity: sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==} engines: {node: '>=4'} @@ -1198,24 +1176,21 @@ snapshots: dependencies: regenerator-runtime: 0.13.11 - '@kevisual/ai@0.0.11': + '@kevisual/ai@0.0.16': dependencies: '@kevisual/logger': 0.0.4 + '@kevisual/permission': 0.0.3 + '@kevisual/query': 0.0.30 '@kevisual/load@0.0.6': dependencies: eventemitter3: 5.0.1 - '@kevisual/local-proxy@0.0.8': {} - '@kevisual/logger@0.0.4': {} - '@kevisual/query@0.0.29': - dependencies: - openai: 5.23.2 - transitivePeerDependencies: - - ws - - zod + '@kevisual/permission@0.0.3': {} + + '@kevisual/query@0.0.30': {} '@kevisual/router@0.0.33': dependencies: @@ -1227,7 +1202,7 @@ snapshots: '@kevisual/types@0.0.10': {} - '@kevisual/use-config@1.0.19(dotenv@16.6.1)': + '@kevisual/use-config@1.0.21(dotenv@16.6.1)': dependencies: '@kevisual/load': 0.0.6 dotenv: 16.6.1 @@ -1240,20 +1215,14 @@ snapshots: '@nut-tree/libnut-darwin@2.7.1': dependencies: bindings: 1.5.0 - optionalDependencies: - '@nut-tree/node-mac-permissions': 2.2.1 '@nut-tree/libnut-linux@2.7.1': dependencies: bindings: 1.5.0 - optionalDependencies: - '@nut-tree/node-mac-permissions': 2.2.1 '@nut-tree/libnut-win32@2.7.1': dependencies: bindings: 1.5.0 - optionalDependencies: - '@nut-tree/node-mac-permissions': 2.2.1 '@nut-tree/libnut@4.2.0(@nut-tree/nut-js@4.2.0)': dependencies: @@ -1262,12 +1231,6 @@ snapshots: '@nut-tree/libnut-win32': 2.7.1 '@nut-tree/nut-js': 4.2.0 - '@nut-tree/node-mac-permissions@2.2.1': - dependencies: - bindings: 1.5.0 - node-addon-api: 5.0.0 - optional: true - '@nut-tree/nut-js@4.2.0': dependencies: '@nut-tree/default-clipboard-provider': 4.2.0(@nut-tree/nut-js@4.2.0) @@ -1656,9 +1619,6 @@ snapshots: node-abort-controller@3.1.1: {} - node-addon-api@5.0.0: - optional: true - node-fetch@2.7.0: dependencies: whatwg-url: 5.0.0 @@ -1681,8 +1641,6 @@ snapshots: dependencies: wrappy: 1.0.2 - openai@5.23.2: {} - p-finally@1.0.0: {} package-json-from-dist@1.0.1: {} diff --git a/src/hot-api/hotkeys/index.ts b/src/hot-api/hotkeys/index.ts index e69de29..156c5be 100644 --- a/src/hot-api/hotkeys/index.ts +++ b/src/hot-api/hotkeys/index.ts @@ -0,0 +1,89 @@ +import { keyboard, Key } from "@nut-tree/nut-js"; + +/** + * 控制功能部分的案件映射 + */ +export const keyMap: Record = { + 'ctrl': Key.LeftControl, + 'leftctrl': Key.LeftControl, + 'rightctrl': Key.RightControl, + 'alt': Key.LeftAlt, + 'leftalt': Key.LeftAlt, + 'rightalt': Key.RightAlt, + 'shift': Key.LeftShift, + 'leftshift': Key.LeftShift, + 'rightshift': Key.RightShift, + 'meta': Key.LeftSuper, + 'cmd': Key.LeftCmd, + 'win': Key.LeftWin, + // 根据操作系统选择 Ctrl 或 Command 键 + 'ctrlorcommand': process.platform === 'darwin' ? Key.LeftCmd : Key.LeftControl, +}; + +/** + * 将快捷键字符串转换为 Key 枚举值 + * @param hotkey + * @returns + */ +export const parseHotkey = (hotkey: string): Key[] => { + return hotkey + .toLowerCase() + .split('+') + .map(key => { + const trimmed = key.trim().toLowerCase(); + // 如果是修饰键,从映射表中获取 + if (keyMap[trimmed]) { + return keyMap[trimmed]; + } + // 如果是字母,转换为大写并查找对应的 Key + if (trimmed.length === 1 && /[a-z]/.test(trimmed)) { + const upperKey = trimmed.toUpperCase(); + return Key[upperKey as keyof typeof Key] as Key; + } + // 其他情况直接查找 + return Key[trimmed as keyof typeof Key] as Key; + }) + .filter((key): key is Key => key !== undefined); +} + +type PressHostKeysOptions = { + hotkey: string; + durationMs?: number; +} +export const pressHotkey = async (opts: PressHostKeysOptions): Promise => { + const { hotkey, durationMs = 100 } = opts; + const keys = parseHotkey(hotkey); + + console.log('准备模拟按下快捷键:', hotkey); + // 同时按下所有键 + await keyboard.pressKey(...keys); + // 短暂延迟后释放 + await new Promise(resolve => setTimeout(resolve, durationMs)); + // 释放所有键 + await keyboard.releaseKey(...keys); + return true +} + +/** + * 模拟按下一组快捷键,支持逗号分隔的多个快捷键 + * @param opts + * @returns + */ +export const pressHotkeys = async (opts: PressHostKeysOptions): Promise => { + let { hotkey } = opts; + hotkey = hotkey.replace(/\s+/g, ''); // 去除所有空格 + const hotkeyList = hotkey.split(',').map(hk => hk.trim()); + if (hotkeyList.length === 0) { + return await pressHotkey({ ...opts, hotkey }); + } + for (const hk of hotkeyList) { + await pressHotkey({ ...opts, hotkey: hk }); + // 每个快捷键之间稍作延迟 + await new Promise(resolve => setTimeout(resolve, 200)); + } + return true; +} +export class Hotkeys { + pressHotkey = pressHotkey; + pressHotkeys = pressHotkeys; +} \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index f0a6d58..c9a8e5a 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,4 +1,4 @@ import { app } from './app.ts' -import './router/index.ts'; +import './routes/index.ts'; export { app } \ No newline at end of file diff --git a/src/main.ts b/src/main.ts index cf698ef..09bcf0a 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,17 +1,9 @@ import { app } from './app.ts' -import './router/index.ts'; +import './routes/index.ts'; import { HOME } from './module/config.ts'; -import { proxyRoute, initProxy } from '@kevisual/local-proxy/proxy.ts'; - export { app } if (require.main === module) { - initProxy({ - pagesDir: './public', - watch: true, - home: `/root/${HOME}` - }); app.listen(9000, () => { console.log('Server is running on http://localhost:9000'); }); - app.onServerRequest(proxyRoute); } \ No newline at end of file diff --git a/src/routes/index.ts b/src/routes/index.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/test/test-h.ts b/src/test/test-h.ts deleted file mode 100644 index 70f5f09..0000000 --- a/src/test/test-h.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { keyboard, Key } from "@nut-tree/nut-js"; - -// 将快捷键字符串转换为 Key 枚举值 -function parseHotkey(hotkey: string): Key[] { - const keyMap: Record = { - 'ctrl': Key.LeftControl, - 'leftctrl': Key.LeftControl, - 'rightctrl': Key.RightControl, - 'alt': Key.LeftAlt, - 'leftalt': Key.LeftAlt, - 'rightalt': Key.RightAlt, - 'shift': Key.LeftShift, - 'leftshift': Key.LeftShift, - 'rightshift': Key.RightShift, - 'meta': Key.LeftSuper, - 'cmd': Key.LeftCmd, - 'win': Key.LeftWin, - }; - - return hotkey - .toLowerCase() - .split('+') - .map(key => { - const trimmed = key.trim(); - // 如果是修饰键,从映射表中获取 - if (keyMap[trimmed]) { - return keyMap[trimmed]; - } - // 如果是字母,转换为大写并查找对应的 Key - if (trimmed.length === 1 && /[a-z]/.test(trimmed)) { - const upperKey = trimmed.toUpperCase(); - return Key[upperKey as keyof typeof Key] as Key; - } - // 其他情况直接查找 - return Key[trimmed as keyof typeof Key] as Key; - }) - .filter((key): key is Key => key !== undefined); -} - -const hotkey = 'ctrl+h'; -const keys = parseHotkey(hotkey); - -console.log('准备模拟按下快捷键:', hotkey); -console.log('解析后的键:', keys); - -// 同时按下所有键 -keyboard.pressKey(...keys) - .then(() => { - console.log('快捷键已按下'); - // 短暂延迟后释放 - return new Promise(resolve => setTimeout(resolve, 100)); - }) - .then(() => { - // 释放所有键 - return keyboard.releaseKey(...keys); - }) - .then(() => { - console.log('快捷键已释放'); - }) - .catch((error) => { - console.error('模拟快捷键失败:', error); - }); \ No newline at end of file