diff --git a/bun.lock b/bun.lock index 63c3b491..81e6b499 100644 --- a/bun.lock +++ b/bun.lock @@ -7,23 +7,24 @@ "devDependencies": { "@changesets/changelog-github": "^0.6.0", "@changesets/cli": "^2.31.0", - "@types/bun": "^1.3.3", - "@types/node": "^20.0.0", + "@types/bun": "^1.3.14", + "@types/fs-extra": "^11.0.4", + "@types/node": "^20.19.41", "eslint": "^9.39.4", - "eslint-config-oclif": "^6.0.165", + "eslint-config-oclif": "^6.0.167", "eslint-config-prettier": "^10.1.8", "tsdown": "^0.21.10", - "typescript": "^5.7.2", + "typescript": "^5.9.3", }, }, "packages/cli": { "name": "@beeper/cli", - "version": "0.6.1", + "version": "0.6.2", "bin": { "beeper": "bin/run.js", }, "dependencies": { - "@beeper/desktop-api": "github:beeper/desktop-api-js#next", + "@beeper/desktop-api": "^5.0.0", "@oclif/core": "^4.11.2", "@oclif/plugin-autocomplete": "^3.2.49", "@oclif/plugin-help": "^6.2.48", @@ -59,9 +60,9 @@ }, "packages/npm": { "name": "beeper-cli", - "version": "0.6.1", + "version": "0.6.2", "bin": { - "beeper": "./bin/beeper.js", + "beeper": "bin/beeper.js", }, }, }, @@ -89,7 +90,7 @@ "@beeper/cli-plugin-cloudflare": ["@beeper/cli-plugin-cloudflare@workspace:packages/cli-plugin-cloudflare"], - "@beeper/desktop-api": ["@beeper/desktop-api@github:beeper/desktop-api-js#b9c1714", {}, "beeper-desktop-api-js-b9c1714", "sha512-Qlxz1R4ppJd6vPuzgKhJqEC2WpNPtdi6n9ONieX6S5mAC0wyWUjZP/SogeTcbDf8vQ2Sl+ET4lzRN4ZcKHkqww=="], + "@beeper/desktop-api": ["@beeper/desktop-api@5.0.0", "", {}, "sha512-f9GhxQw6E0VMiVJGcdkUPNc6qCypaQlgMgxG6yU2lLy9gzx8xEObYnJbuhmT+HBg2SaQzNB33fC5ZT4OL3GnQw=="], "@changesets/apply-release-plan": ["@changesets/apply-release-plan@7.1.1", "", { "dependencies": { "@changesets/config": "3.1.4", "@changesets/get-version-range-type": "0.4.0", "@changesets/git": "3.0.4", "@changesets/should-skip-package": "0.1.2", "@changesets/types": "6.1.0", "@manypkg/get-packages": "1.1.3", "detect-indent": "6.1.0", "fs-extra": "7.0.1", "lodash.startcase": "4.4.0", "outdent": "0.5.0", "prettier": "2.8.8", "resolve-from": "5.0.0", "semver": "7.8.0" } }, "sha512-9qPCm/rLx/xoOFXIHGB229+4GOL76S4MC+7tyOuTsR6+1jYlfFDQORdvwR5hDA6y4FL2BPt3qpbcQIS+dW85LA=="], @@ -293,13 +294,17 @@ "@types/estree": ["@types/estree@1.0.9", "", {}, "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg=="], + "@types/fs-extra": ["@types/fs-extra@11.0.4", "", { "dependencies": { "@types/jsonfile": "*", "@types/node": "*" } }, "sha512-yTbItCNreRooED33qjunPthRcSjERP1r4MqCZc7wv0u2sUkzTFp45tgUfS5+r7FrZPdmCCNflLhVSP/o+SemsQ=="], + "@types/jsesc": ["@types/jsesc@2.5.1", "", {}, "sha512-9VN+6yxLOPLOav+7PwjZbxiID2bVaeq0ED4qSQmdQTdjnXJSaCVKTR58t15oqH1H5t8Ng2ZX1SabJVoN9Q34bw=="], "@types/json-schema": ["@types/json-schema@7.0.15", "", {}, "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA=="], "@types/json5": ["@types/json5@0.0.29", "", {}, "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ=="], - "@types/node": ["@types/node@20.19.41", "", { "dependencies": { "undici-types": "6.21.0" } }, "sha512-ECymXOukMnOoVkC2bb1Vc/w/836DXncOg5m8Xj1RH7xSHZJWNYY6Zh7EH477vcnD5egKNNfy2RpNOmuChhFPgQ=="], + "@types/jsonfile": ["@types/jsonfile@6.1.4", "", { "dependencies": { "@types/node": "*" } }, "sha512-D5qGUYwjvnNNextdU59/+fI+spnwtTFmyQP0h+PfIOSkNfpU6AOICUOkm4i0OnSk+NyjdPJrxCDro0sJsWlRpQ=="], + + "@types/node": ["@types/node@20.19.42", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-5L7SUaFC1RyDraj2yRhyBzHTobyXHmohD100CChNtyPyleoq37Mqab5Gn8XEKI04dfN/oqPdpHk38MgcQWHbZg=="], "@types/normalize-package-data": ["@types/normalize-package-data@2.4.4", "", {}, "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA=="], @@ -565,7 +570,7 @@ "eslint-compat-utils": ["eslint-compat-utils@0.5.1", "", { "dependencies": { "semver": "7.8.0" }, "peerDependencies": { "eslint": "9.39.4" } }, "sha512-3z3vFexKIEnjHE3zCMRo6fn/e44U7T1khUjg+Hp0ZQMCigh28rALD0nPFBcGZuiLC5rLZa2ubQHDRln09JfU2Q=="], - "eslint-config-oclif": ["eslint-config-oclif@6.0.165", "", { "dependencies": { "@eslint/compat": "1.4.1", "@eslint/eslintrc": "3.3.5", "@eslint/js": "9.39.4", "@stylistic/eslint-plugin": "3.1.0", "@typescript-eslint/eslint-plugin": "8.59.3", "@typescript-eslint/parser": "8.59.3", "eslint-config-oclif": "5.2.2", "eslint-config-xo": "0.49.0", "eslint-config-xo-space": "0.35.0", "eslint-import-resolver-typescript": "3.10.1", "eslint-plugin-import": "2.32.0", "eslint-plugin-jsdoc": "50.8.0", "eslint-plugin-mocha": "10.5.0", "eslint-plugin-n": "17.24.0", "eslint-plugin-perfectionist": "4.15.1", "eslint-plugin-unicorn": "56.0.1", "typescript-eslint": "8.59.3" } }, "sha512-kbzxHAXEHKTY2X4UVVu4cPjjxP2YsVEsgYaXJDakpBEoAUEUSnYCKOOoxrIHl1egDM3q07kOZnBPkwYQ+nR4Og=="], + "eslint-config-oclif": ["eslint-config-oclif@6.0.167", "", { "dependencies": { "@eslint/compat": "^1.4.1", "@eslint/eslintrc": "^3.3.5", "@eslint/js": "^9.39.4", "@stylistic/eslint-plugin": "^3.1.0", "@typescript-eslint/eslint-plugin": "^8", "@typescript-eslint/parser": "^8", "eslint-config-oclif": "^5.2.2", "eslint-config-xo": "^0.49.0", "eslint-config-xo-space": "^0.35.0", "eslint-import-resolver-typescript": "^3.10.1", "eslint-plugin-import": "^2.32.0", "eslint-plugin-jsdoc": "^50.8.0", "eslint-plugin-mocha": "^10.5.0", "eslint-plugin-n": "^17.24.0", "eslint-plugin-perfectionist": "^4", "eslint-plugin-unicorn": "^56.0.1", "typescript-eslint": "^8.60.0" } }, "sha512-CdFBogd4GWq7apgGlU78nXVhVyQdj74kaB7jAuoV3Y2ue1vZ7YlNCb2p2879kGPp6WWIUHUHUX1wvnnVKReN8Q=="], "eslint-config-prettier": ["eslint-config-prettier@10.1.8", "", { "peerDependencies": { "eslint": "9.39.4" }, "bin": { "eslint-config-prettier": "bin/cli.js" } }, "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w=="], @@ -1143,7 +1148,7 @@ "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], - "typescript-eslint": ["typescript-eslint@8.59.3", "", { "dependencies": { "@typescript-eslint/eslint-plugin": "8.59.3", "@typescript-eslint/parser": "8.59.3", "@typescript-eslint/typescript-estree": "8.59.3", "@typescript-eslint/utils": "8.59.3" }, "peerDependencies": { "eslint": "9.39.4", "typescript": "5.9.3" } }, "sha512-KgusgyDgG4LI8Ih/sWaCtZ06tckLAS5CvT5A4D1Q7bYVoAAyzwiZvE4BmwDHkhRVkvhRBepKeASoFzQetha7Fg=="], + "typescript-eslint": ["typescript-eslint@8.60.1", "", { "dependencies": { "@typescript-eslint/eslint-plugin": "8.60.1", "@typescript-eslint/parser": "8.60.1", "@typescript-eslint/typescript-estree": "8.60.1", "@typescript-eslint/utils": "8.60.1" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-6m5hkkRAp8lKvhVpcprAIn5KkehQEh+47oHH2VGnExEh7dhNxXlg6GPAOIu6TxbVQxhebrJDvjl3020ooiWCMA=="], "unbox-primitive": ["unbox-primitive@1.1.0", "", { "dependencies": { "call-bound": "1.0.4", "has-bigints": "1.1.0", "has-symbols": "1.1.0", "which-boxed-primitive": "1.1.1" } }, "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw=="], @@ -1219,10 +1224,38 @@ "@eslint/json/@eslint/plugin-kit": ["@eslint/plugin-kit@0.3.5", "", { "dependencies": { "@eslint/core": "0.15.2", "levn": "0.4.1" } }, "sha512-Z5kJ+wU3oA7MMIqVR9tyZRtjYPr4OC004Q4Rw7pgOKUOKkJfZ3O24nz3WYfGRpMDNmcOi3TwQOmgm7B7Tpii0w=="], + "@inquirer/checkbox/@types/node": ["@types/node@20.19.41", "", { "dependencies": { "undici-types": "6.21.0" } }, "sha512-ECymXOukMnOoVkC2bb1Vc/w/836DXncOg5m8Xj1RH7xSHZJWNYY6Zh7EH477vcnD5egKNNfy2RpNOmuChhFPgQ=="], + + "@inquirer/confirm/@types/node": ["@types/node@20.19.41", "", { "dependencies": { "undici-types": "6.21.0" } }, "sha512-ECymXOukMnOoVkC2bb1Vc/w/836DXncOg5m8Xj1RH7xSHZJWNYY6Zh7EH477vcnD5egKNNfy2RpNOmuChhFPgQ=="], + + "@inquirer/core/@types/node": ["@types/node@20.19.41", "", { "dependencies": { "undici-types": "6.21.0" } }, "sha512-ECymXOukMnOoVkC2bb1Vc/w/836DXncOg5m8Xj1RH7xSHZJWNYY6Zh7EH477vcnD5egKNNfy2RpNOmuChhFPgQ=="], + "@inquirer/core/signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="], "@inquirer/core/wrap-ansi": ["wrap-ansi@6.2.0", "", { "dependencies": { "ansi-styles": "4.3.0", "string-width": "4.2.3", "strip-ansi": "6.0.1" } }, "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA=="], + "@inquirer/editor/@types/node": ["@types/node@20.19.41", "", { "dependencies": { "undici-types": "6.21.0" } }, "sha512-ECymXOukMnOoVkC2bb1Vc/w/836DXncOg5m8Xj1RH7xSHZJWNYY6Zh7EH477vcnD5egKNNfy2RpNOmuChhFPgQ=="], + + "@inquirer/expand/@types/node": ["@types/node@20.19.41", "", { "dependencies": { "undici-types": "6.21.0" } }, "sha512-ECymXOukMnOoVkC2bb1Vc/w/836DXncOg5m8Xj1RH7xSHZJWNYY6Zh7EH477vcnD5egKNNfy2RpNOmuChhFPgQ=="], + + "@inquirer/external-editor/@types/node": ["@types/node@20.19.41", "", { "dependencies": { "undici-types": "6.21.0" } }, "sha512-ECymXOukMnOoVkC2bb1Vc/w/836DXncOg5m8Xj1RH7xSHZJWNYY6Zh7EH477vcnD5egKNNfy2RpNOmuChhFPgQ=="], + + "@inquirer/input/@types/node": ["@types/node@20.19.41", "", { "dependencies": { "undici-types": "6.21.0" } }, "sha512-ECymXOukMnOoVkC2bb1Vc/w/836DXncOg5m8Xj1RH7xSHZJWNYY6Zh7EH477vcnD5egKNNfy2RpNOmuChhFPgQ=="], + + "@inquirer/number/@types/node": ["@types/node@20.19.41", "", { "dependencies": { "undici-types": "6.21.0" } }, "sha512-ECymXOukMnOoVkC2bb1Vc/w/836DXncOg5m8Xj1RH7xSHZJWNYY6Zh7EH477vcnD5egKNNfy2RpNOmuChhFPgQ=="], + + "@inquirer/password/@types/node": ["@types/node@20.19.41", "", { "dependencies": { "undici-types": "6.21.0" } }, "sha512-ECymXOukMnOoVkC2bb1Vc/w/836DXncOg5m8Xj1RH7xSHZJWNYY6Zh7EH477vcnD5egKNNfy2RpNOmuChhFPgQ=="], + + "@inquirer/prompts/@types/node": ["@types/node@20.19.41", "", { "dependencies": { "undici-types": "6.21.0" } }, "sha512-ECymXOukMnOoVkC2bb1Vc/w/836DXncOg5m8Xj1RH7xSHZJWNYY6Zh7EH477vcnD5egKNNfy2RpNOmuChhFPgQ=="], + + "@inquirer/rawlist/@types/node": ["@types/node@20.19.41", "", { "dependencies": { "undici-types": "6.21.0" } }, "sha512-ECymXOukMnOoVkC2bb1Vc/w/836DXncOg5m8Xj1RH7xSHZJWNYY6Zh7EH477vcnD5egKNNfy2RpNOmuChhFPgQ=="], + + "@inquirer/search/@types/node": ["@types/node@20.19.41", "", { "dependencies": { "undici-types": "6.21.0" } }, "sha512-ECymXOukMnOoVkC2bb1Vc/w/836DXncOg5m8Xj1RH7xSHZJWNYY6Zh7EH477vcnD5egKNNfy2RpNOmuChhFPgQ=="], + + "@inquirer/select/@types/node": ["@types/node@20.19.41", "", { "dependencies": { "undici-types": "6.21.0" } }, "sha512-ECymXOukMnOoVkC2bb1Vc/w/836DXncOg5m8Xj1RH7xSHZJWNYY6Zh7EH477vcnD5egKNNfy2RpNOmuChhFPgQ=="], + + "@inquirer/type/@types/node": ["@types/node@20.19.41", "", { "dependencies": { "undici-types": "6.21.0" } }, "sha512-ECymXOukMnOoVkC2bb1Vc/w/836DXncOg5m8Xj1RH7xSHZJWNYY6Zh7EH477vcnD5egKNNfy2RpNOmuChhFPgQ=="], + "@manypkg/find-root/@types/node": ["@types/node@12.20.55", "", {}, "sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ=="], "@manypkg/find-root/find-up": ["find-up@4.1.0", "", { "dependencies": { "locate-path": "5.0.0", "path-exists": "4.0.0" } }, "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw=="], @@ -1249,6 +1282,12 @@ "@quansync/fs/quansync": ["quansync@1.0.0", "", {}, "sha512-5xZacEEufv3HSTPQuchrvV6soaiACMFnq1H8wkVioctoH3TRha9Sz66lOxRwPK/qZj7HPiSveih9yAyh98gvqA=="], + "@types/fs-extra/@types/node": ["@types/node@20.19.41", "", { "dependencies": { "undici-types": "6.21.0" } }, "sha512-ECymXOukMnOoVkC2bb1Vc/w/836DXncOg5m8Xj1RH7xSHZJWNYY6Zh7EH477vcnD5egKNNfy2RpNOmuChhFPgQ=="], + + "@types/jsonfile/@types/node": ["@types/node@20.19.41", "", { "dependencies": { "undici-types": "6.21.0" } }, "sha512-ECymXOukMnOoVkC2bb1Vc/w/836DXncOg5m8Xj1RH7xSHZJWNYY6Zh7EH477vcnD5egKNNfy2RpNOmuChhFPgQ=="], + + "@types/ws/@types/node": ["@types/node@20.19.41", "", { "dependencies": { "undici-types": "6.21.0" } }, "sha512-ECymXOukMnOoVkC2bb1Vc/w/836DXncOg5m8Xj1RH7xSHZJWNYY6Zh7EH477vcnD5egKNNfy2RpNOmuChhFPgQ=="], + "@typescript-eslint/eslint-plugin/ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="], "@typescript-eslint/typescript-estree/minimatch": ["minimatch@10.2.5", "", { "dependencies": { "brace-expansion": "5.0.6" } }, "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg=="], @@ -1259,6 +1298,8 @@ "ansi-escapes/type-fest": ["type-fest@0.21.3", "", {}, "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w=="], + "bun-types/@types/node": ["@types/node@20.19.41", "", { "dependencies": { "undici-types": "6.21.0" } }, "sha512-ECymXOukMnOoVkC2bb1Vc/w/836DXncOg5m8Xj1RH7xSHZJWNYY6Zh7EH477vcnD5egKNNfy2RpNOmuChhFPgQ=="], + "chalk/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], "chalk/supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], @@ -1351,6 +1392,14 @@ "stack-utils/escape-string-regexp": ["escape-string-regexp@2.0.0", "", {}, "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w=="], + "typescript-eslint/@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.60.1", "", { "dependencies": { "@eslint-community/regexpp": "^4.12.2", "@typescript-eslint/scope-manager": "8.60.1", "@typescript-eslint/type-utils": "8.60.1", "@typescript-eslint/utils": "8.60.1", "@typescript-eslint/visitor-keys": "8.60.1", "ignore": "^7.0.5", "natural-compare": "^1.4.0", "ts-api-utils": "^2.5.0" }, "peerDependencies": { "@typescript-eslint/parser": "^8.60.1", "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-JQ4S5GB0tfjO8BuJ4fcX+HodkzJjYBV+7OJ+wLygaX7OGQ7FudyHL4NSCA6ob+w3Yn+5MkKIozOwQhXeM7opVg=="], + + "typescript-eslint/@typescript-eslint/parser": ["@typescript-eslint/parser@8.60.1", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.60.1", "@typescript-eslint/types": "8.60.1", "@typescript-eslint/typescript-estree": "8.60.1", "@typescript-eslint/visitor-keys": "8.60.1", "debug": "^4.4.3" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-A0M6ua6H252bVjPvvtSgl2QA4+ET9S5Mtkb2GDyTxIhH/C4qDItT7RQNO5PhMC6NXGYXOR9dIalcDDgBKT7oFA=="], + + "typescript-eslint/@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.60.1", "", { "dependencies": { "@typescript-eslint/project-service": "8.60.1", "@typescript-eslint/tsconfig-utils": "8.60.1", "@typescript-eslint/types": "8.60.1", "@typescript-eslint/visitor-keys": "8.60.1", "debug": "^4.4.3", "minimatch": "^10.2.2", "semver": "^7.7.3", "tinyglobby": "^0.2.15", "ts-api-utils": "^2.5.0" }, "peerDependencies": { "typescript": ">=4.8.4 <6.1.0" } }, "sha512-alpRkfG8hlVE5kdJW2GkfgDgXxold3e8e4l6EnmhRmRLbekgAPCCGDVD++sABy9FcgPFroq+uFcCSM1vR57Cew=="], + + "typescript-eslint/@typescript-eslint/utils": ["@typescript-eslint/utils@8.60.1", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", "@typescript-eslint/scope-manager": "8.60.1", "@typescript-eslint/types": "8.60.1", "@typescript-eslint/typescript-estree": "8.60.1" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-h2MPBLoNtjc3qZWfY3Tl51yPorQ2McHn8pJfcMNTcIvrrZrr90Ykffit0yjrPFWQcRcUxzH20+6OcVdW4yHtUg=="], + "unconfig-core/quansync": ["quansync@1.0.0", "", {}, "sha512-5xZacEEufv3HSTPQuchrvV6soaiACMFnq1H8wkVioctoH3TRha9Sz66lOxRwPK/qZj7HPiSveih9yAyh98gvqA=="], "validate-npm-package-license/spdx-expression-parse": ["spdx-expression-parse@3.0.1", "", { "dependencies": { "spdx-exceptions": "2.5.0", "spdx-license-ids": "3.0.23" } }, "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q=="], @@ -1393,6 +1442,34 @@ "read-yaml-file/js-yaml/argparse": ["argparse@1.0.10", "", { "dependencies": { "sprintf-js": "1.0.3" } }, "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg=="], + "typescript-eslint/@typescript-eslint/eslint-plugin/@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.60.1", "", { "dependencies": { "@typescript-eslint/types": "8.60.1", "@typescript-eslint/visitor-keys": "8.60.1" } }, "sha512-gvI5OQoptnxQnchOirukCuQ55svJSTuD/4k5+pC267xyBtYry748R9/c3tYUzb/iE6RZfllRz2lVulLCHkTm4w=="], + + "typescript-eslint/@typescript-eslint/eslint-plugin/@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.60.1", "", { "dependencies": { "@typescript-eslint/types": "8.60.1", "@typescript-eslint/typescript-estree": "8.60.1", "@typescript-eslint/utils": "8.60.1", "debug": "^4.4.3", "ts-api-utils": "^2.5.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-sdwTrpjosW7ANQYJ39ZBF1ZyEMEGVB2UsikrserVM/30a/F1dTLnu9bGxEdosugyu5caigjLrR2qiD11asjI1A=="], + + "typescript-eslint/@typescript-eslint/eslint-plugin/@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.60.1", "", { "dependencies": { "@typescript-eslint/types": "8.60.1", "eslint-visitor-keys": "^5.0.0" } }, "sha512-EbGRQg4FhrmwLodl+t3JNAnXHWVr9Vp+Zl1QBZVPY4ByfkzIT8cX3K6QWODHtkIZqqJVEWvhHSx3v5PDHsaQag=="], + + "typescript-eslint/@typescript-eslint/eslint-plugin/ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="], + + "typescript-eslint/@typescript-eslint/parser/@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.60.1", "", { "dependencies": { "@typescript-eslint/types": "8.60.1", "@typescript-eslint/visitor-keys": "8.60.1" } }, "sha512-gvI5OQoptnxQnchOirukCuQ55svJSTuD/4k5+pC267xyBtYry748R9/c3tYUzb/iE6RZfllRz2lVulLCHkTm4w=="], + + "typescript-eslint/@typescript-eslint/parser/@typescript-eslint/types": ["@typescript-eslint/types@8.60.1", "", {}, "sha512-4h0tY8ppCkdCzcrl2YM5M3my0xsE1Tf8om3owEu5oPWmXwkKRmk0j0LGDzYBGUcAlesEbxBhazqu/K4cu3Ug7w=="], + + "typescript-eslint/@typescript-eslint/parser/@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.60.1", "", { "dependencies": { "@typescript-eslint/types": "8.60.1", "eslint-visitor-keys": "^5.0.0" } }, "sha512-EbGRQg4FhrmwLodl+t3JNAnXHWVr9Vp+Zl1QBZVPY4ByfkzIT8cX3K6QWODHtkIZqqJVEWvhHSx3v5PDHsaQag=="], + + "typescript-eslint/@typescript-eslint/typescript-estree/@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.60.1", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.60.1", "@typescript-eslint/types": "^8.60.1", "debug": "^4.4.3" }, "peerDependencies": { "typescript": ">=4.8.4 <6.1.0" } }, "sha512-eXkTH2bxmXlqD1RnOPmLZ9ZM9D3VwSx04JOwBnP9RQ+yUA5a2Mu7SfW8uaV2Aon53NJzZlZYuX7tn91Izf+xaw=="], + + "typescript-eslint/@typescript-eslint/typescript-estree/@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.60.1", "", { "peerDependencies": { "typescript": ">=4.8.4 <6.1.0" } }, "sha512-nh8w4qAteiKuZu3pSSzG/yGKpw0OlkrKnzFmbVRenKaD4qc+7i1GrmZaLVkr8rk4uipiPGMOW4YsM6WmKZ5CvA=="], + + "typescript-eslint/@typescript-eslint/typescript-estree/@typescript-eslint/types": ["@typescript-eslint/types@8.60.1", "", {}, "sha512-4h0tY8ppCkdCzcrl2YM5M3my0xsE1Tf8om3owEu5oPWmXwkKRmk0j0LGDzYBGUcAlesEbxBhazqu/K4cu3Ug7w=="], + + "typescript-eslint/@typescript-eslint/typescript-estree/@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.60.1", "", { "dependencies": { "@typescript-eslint/types": "8.60.1", "eslint-visitor-keys": "^5.0.0" } }, "sha512-EbGRQg4FhrmwLodl+t3JNAnXHWVr9Vp+Zl1QBZVPY4ByfkzIT8cX3K6QWODHtkIZqqJVEWvhHSx3v5PDHsaQag=="], + + "typescript-eslint/@typescript-eslint/typescript-estree/minimatch": ["minimatch@10.2.5", "", { "dependencies": { "brace-expansion": "5.0.6" } }, "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg=="], + + "typescript-eslint/@typescript-eslint/utils/@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.60.1", "", { "dependencies": { "@typescript-eslint/types": "8.60.1", "@typescript-eslint/visitor-keys": "8.60.1" } }, "sha512-gvI5OQoptnxQnchOirukCuQ55svJSTuD/4k5+pC267xyBtYry748R9/c3tYUzb/iE6RZfllRz2lVulLCHkTm4w=="], + + "typescript-eslint/@typescript-eslint/utils/@typescript-eslint/types": ["@typescript-eslint/types@8.60.1", "", {}, "sha512-4h0tY8ppCkdCzcrl2YM5M3my0xsE1Tf8om3owEu5oPWmXwkKRmk0j0LGDzYBGUcAlesEbxBhazqu/K4cu3Ug7w=="], + "yargs/find-up/locate-path": ["locate-path@5.0.0", "", { "dependencies": { "p-locate": "4.1.0" } }, "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g=="], "@manypkg/find-root/find-up/locate-path/p-locate": ["p-locate@4.1.0", "", { "dependencies": { "p-limit": "2.3.0" } }, "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A=="], @@ -1411,12 +1488,32 @@ "read-pkg-up/find-up/locate-path/p-locate": ["p-locate@4.1.0", "", { "dependencies": { "p-limit": "2.3.0" } }, "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A=="], + "typescript-eslint/@typescript-eslint/eslint-plugin/@typescript-eslint/scope-manager/@typescript-eslint/types": ["@typescript-eslint/types@8.60.1", "", {}, "sha512-4h0tY8ppCkdCzcrl2YM5M3my0xsE1Tf8om3owEu5oPWmXwkKRmk0j0LGDzYBGUcAlesEbxBhazqu/K4cu3Ug7w=="], + + "typescript-eslint/@typescript-eslint/eslint-plugin/@typescript-eslint/type-utils/@typescript-eslint/types": ["@typescript-eslint/types@8.60.1", "", {}, "sha512-4h0tY8ppCkdCzcrl2YM5M3my0xsE1Tf8om3owEu5oPWmXwkKRmk0j0LGDzYBGUcAlesEbxBhazqu/K4cu3Ug7w=="], + + "typescript-eslint/@typescript-eslint/eslint-plugin/@typescript-eslint/visitor-keys/@typescript-eslint/types": ["@typescript-eslint/types@8.60.1", "", {}, "sha512-4h0tY8ppCkdCzcrl2YM5M3my0xsE1Tf8om3owEu5oPWmXwkKRmk0j0LGDzYBGUcAlesEbxBhazqu/K4cu3Ug7w=="], + + "typescript-eslint/@typescript-eslint/eslint-plugin/@typescript-eslint/visitor-keys/eslint-visitor-keys": ["eslint-visitor-keys@5.0.1", "", {}, "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA=="], + + "typescript-eslint/@typescript-eslint/parser/@typescript-eslint/visitor-keys/eslint-visitor-keys": ["eslint-visitor-keys@5.0.1", "", {}, "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA=="], + + "typescript-eslint/@typescript-eslint/typescript-estree/@typescript-eslint/visitor-keys/eslint-visitor-keys": ["eslint-visitor-keys@5.0.1", "", {}, "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA=="], + + "typescript-eslint/@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@5.0.6", "", { "dependencies": { "balanced-match": "4.0.4" } }, "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g=="], + + "typescript-eslint/@typescript-eslint/utils/@typescript-eslint/scope-manager/@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.60.1", "", { "dependencies": { "@typescript-eslint/types": "8.60.1", "eslint-visitor-keys": "^5.0.0" } }, "sha512-EbGRQg4FhrmwLodl+t3JNAnXHWVr9Vp+Zl1QBZVPY4ByfkzIT8cX3K6QWODHtkIZqqJVEWvhHSx3v5PDHsaQag=="], + "yargs/find-up/locate-path/p-locate": ["p-locate@4.1.0", "", { "dependencies": { "p-limit": "2.3.0" } }, "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A=="], "@manypkg/find-root/find-up/locate-path/p-locate/p-limit": ["p-limit@2.3.0", "", { "dependencies": { "p-try": "2.2.0" } }, "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w=="], "read-pkg-up/find-up/locate-path/p-locate/p-limit": ["p-limit@2.3.0", "", { "dependencies": { "p-try": "2.2.0" } }, "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w=="], + "typescript-eslint/@typescript-eslint/typescript-estree/minimatch/brace-expansion/balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="], + + "typescript-eslint/@typescript-eslint/utils/@typescript-eslint/scope-manager/@typescript-eslint/visitor-keys/eslint-visitor-keys": ["eslint-visitor-keys@5.0.1", "", {}, "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA=="], + "yargs/find-up/locate-path/p-locate/p-limit": ["p-limit@2.3.0", "", { "dependencies": { "p-try": "2.2.0" } }, "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w=="], } } diff --git a/package.json b/package.json index cbd382a8..306e8c2b 100644 --- a/package.json +++ b/package.json @@ -25,12 +25,13 @@ "devDependencies": { "@changesets/changelog-github": "^0.6.0", "@changesets/cli": "^2.31.0", - "@types/bun": "^1.3.3", - "@types/node": "^20.0.0", + "@types/bun": "^1.3.14", + "@types/fs-extra": "^11.0.4", + "@types/node": "^20.19.42", "eslint": "^9.39.4", - "eslint-config-oclif": "^6.0.165", + "eslint-config-oclif": "^6.0.167", "eslint-config-prettier": "^10.1.8", "tsdown": "^0.21.10", - "typescript": "^5.7.2" + "typescript": "^5.9.3" } -} +} \ No newline at end of file diff --git a/packages/cli/bin/run.js b/packages/cli/bin/run.js index de26bc2c..82aa4b46 100755 --- a/packages/cli/bin/run.js +++ b/packages/cli/bin/run.js @@ -1,7 +1,8 @@ #!/usr/bin/env node import { createHash } from 'node:crypto' import { createWriteStream, existsSync } from 'node:fs' -import { chmod, mkdir, readFile, rename, rm } from 'node:fs/promises' +import { chmod, mkdir, readFile, rm } from 'node:fs/promises' +import { move } from 'fs-extra' import { get } from 'node:https' import { homedir, tmpdir } from 'node:os' import { basename, dirname, join } from 'node:path' @@ -63,7 +64,7 @@ async function ensureExecutable() { if (platform !== 'windows') await chmod(extractedExecutable, 0o755) await rm(cacheDir, { recursive: true, force: true }) await mkdir(cacheDir, { recursive: true }) - await rename(extractedExecutable, cachedExecutable) + await move(extractedExecutable, cachedExecutable) await rm(tmpDir, { recursive: true, force: true }) return cachedExecutable } diff --git a/packages/cli/package.json b/packages/cli/package.json index f79ec98f..ece533ce 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -118,7 +118,7 @@ } }, "dependencies": { - "@beeper/desktop-api": "github:beeper/desktop-api-js#next", + "@beeper/desktop-api": "^5.0.0", "@oclif/core": "^4.11.2", "@oclif/plugin-autocomplete": "^3.2.49", "@oclif/plugin-help": "^6.2.48", @@ -139,4 +139,4 @@ "@types/ws": "^8.18.1", "typescript": "^5.7.2" } -} +} \ No newline at end of file diff --git a/packages/cli/src/commands/update.ts b/packages/cli/src/commands/update.ts index 587fda05..8fd36dae 100644 --- a/packages/cli/src/commands/update.ts +++ b/packages/cli/src/commands/update.ts @@ -4,6 +4,7 @@ import { checkInstallationUpdate, readInstallations, updateServerInstallation, + updateDesktopInstallation, type Installation, } from '../lib/installations.js' import { profileStatus, startProfile, stopProfile } from '../lib/profiles.js' @@ -33,7 +34,13 @@ export default class Update extends BeeperCommand { } if ((!selected || flags.desktop) && installations.desktop) { - results.push({ kind: 'desktop', ...(await checkDesktop(installations.desktop)) }) + const check = await checkInstallationUpdate(installations.desktop) + if (check.available && !flags.check) { + const updated = await updateDesktopInstallation(installations.desktop) + results.push({ kind: 'desktop', updated: true, previousVersion: installations.desktop.version, currentVersion: updated.version, path: updated.path, action: 'Restart the app to apply the update.' }) + } else { + results.push({ kind: 'desktop', ...check }) + } } else if ((!selected || flags.desktop) && !installations.desktop) { results.push({ kind: 'desktop', installed: false, action: 'Run: beeper install desktop' }) } @@ -71,14 +78,6 @@ async function runningServerProfiles(): Promise> { - const check = await checkInstallationUpdate(installation) - return { - ...check, - action: 'Update Beeper Desktop in the app.', - } -} - async function checkCLI(): Promise> { const currentVersion = pkg.version const installMethod = detectCLIInstallMethod() diff --git a/packages/cli/src/lib/installations.ts b/packages/cli/src/lib/installations.ts index 19abe049..ddfea349 100644 --- a/packages/cli/src/lib/installations.ts +++ b/packages/cli/src/lib/installations.ts @@ -1,6 +1,7 @@ import { createWriteStream } from 'node:fs' -import { chmod, cp, mkdir, readFile, rename, rm, symlink, writeFile } from 'node:fs/promises' -import { tmpdir } from 'node:os' +import { chmod, cp, mkdir, readFile, rm, symlink, writeFile } from 'node:fs/promises' +import { move } from 'fs-extra' +import { tmpdir, homedir } from 'node:os' import { basename, dirname, extname, join } from 'node:path' import { Readable } from 'node:stream' import { pipeline } from 'node:stream/promises' @@ -141,10 +142,7 @@ export async function checkInstallationUpdate(installation: Installation): Promi available, latestVersion, currentVersion: installation.version, - action: installation.kind === 'desktop' - ? 'Update Beeper Desktop in the app.' - : available ? 'Run: beeper update --server' : 'Beeper Server is up to date.', - feedURL: installation.feedURL, + action: available ? installation.kind === 'desktop' ? 'Run: beeper update --desktop' : 'Run: beeper update --server' : 'Installation is up to date.' } } @@ -206,6 +204,10 @@ export async function installServer(options: { channel?: InstallChannel; serverE }) } +export async function updateDesktopInstallation(installation: Installation): Promise { + return installDesktop({ channel: installation.channel, serverEnv: installation.serverEnv }) +} + export async function updateServerInstallation(installation: Installation): Promise { return installServer({ channel: installation.channel, serverEnv: installation.serverEnv }) } @@ -218,7 +220,7 @@ export async function downloadArtifact(url: string, destinationDir: string): Pro const finalPath = join(destinationDir, filename) const tmpPath = join(tmpdir(), `${filename}.${process.pid}.${Date.now()}.tmp`) await writeResponseToFile(response, tmpPath) - await rename(tmpPath, finalPath) + await move(tmpPath, finalPath) return finalPath } @@ -234,14 +236,14 @@ async function extractServerArtifact(artifactPath: string, destinationDir: strin else await execFileAsync('unzip', ['-q', artifactPath, '-d', extractDir]) } else { const executable = join(destinationDir, 'beeper-server') - await rename(artifactPath, executable) + await move(artifactPath, executable) await chmod(executable, 0o755) return executable } const executable = await findServerExecutable(extractDir) const finalPath = join(destinationDir, 'beeper-server') - await rename(executable, finalPath) + await move(executable, finalPath) await chmod(finalPath, 0o755) return finalPath } @@ -273,6 +275,14 @@ async function extractDesktopArtifact(artifactPath: string, destinationDir: stri return finalPath } + if (artifactPath.endsWith('.AppImage')) { + const finalPath = join(desktopInstallDir(), basename(artifactPath)); + await move(artifactPath, finalPath); + await chmod(finalPath, 0o755); + await createDesktopEntry(finalPath); + return finalPath; + } + return artifactPath } @@ -310,6 +320,27 @@ async function findAppBundle(dir: string): Promise { throw new Error('Downloaded Beeper Desktop artifact did not contain an app bundle.') } +async function createDesktopEntry(executablePath: string): Promise { + const iconPath = join(homedir(), '.local/share/icons/beeper.png') + const desktopEntry = `[Desktop Entry] +Name=Beeper +Exec=${executablePath} %u +Icon=${iconPath} +Type=Application +Terminal=false +Comment=The ultimate messaging app +Categories=Network;Chat; +MimeType=x-scheme-handler/beeper; +StartupWMClass=Beeper +StartupNotify=true +X-Desktop-File-Install-Version=0.28 +` + const desktopDir = join(homedir(), '.local/share/applications') + await mkdir(desktopDir, { recursive: true }) + const desktopFilePath = join(desktopDir, 'Beeper.desktop') + await writeFile(desktopFilePath, desktopEntry, { mode: 0o644 }) +} + async function findServerExecutable(dir: string): Promise { const { readdir, stat } = await import('node:fs/promises') const entries = await readdir(dir) diff --git a/packages/cli/src/lib/profiles.ts b/packages/cli/src/lib/profiles.ts index 6599bcad..7d38de83 100644 --- a/packages/cli/src/lib/profiles.ts +++ b/packages/cli/src/lib/profiles.ts @@ -1,7 +1,7 @@ import { spawn } from 'node:child_process' import { execFile } from 'node:child_process' -import { closeSync, openSync } from 'node:fs' -import { access, mkdir, readFile, rm, writeFile } from 'node:fs/promises' +import { closeSync, openSync, existsSync } from 'node:fs' +import { access, mkdir, readdir, readFile, rm, writeFile } from 'node:fs/promises' import { homedir } from 'node:os' import { join } from 'node:path' import { promisify } from 'node:util' @@ -54,23 +54,42 @@ export async function startProfile(target: Target): Promise { const installations = await readInstallations().catch(() => ({ desktop: undefined })) - const appPath = installations.desktop?.path ?? await findDesktopAppPath() - const args = appPath ? ['-n', appPath, '--args'] : ['-n', '-a', 'Beeper', '--args'] - args.push('--no-enforce-app-location') - if (target?.port) args.push(`--pas-port=${target.port}`) - if (target?.serverEnv) args.push(`--server-env=${target.serverEnv}`) - const env = target?.dataDir - ? { + + const appPath = installations.desktop?.path && existsSync(installations.desktop.path) ? installations.desktop.path : await findDesktopAppPath() + + if (process.platform === 'darwin') { + const args = appPath ? ['-n', appPath, '--args'] : ['-n', '-a', 'Beeper', '--args'] + args.push('--no-enforce-app-location') + if (target?.port) args.push(`--pas-port=${target.port}`) + if (target?.serverEnv) args.push(`--server-env=${target.serverEnv}`) + const env = target?.dataDir + ? { + ...process.env, + ALLOW_MULTIPLE_INSTANCES: 'true', + BEEPER_PROFILE: target.profile ?? target.id, + BEEPER_USER_DATA_DIR: target.dataDir, + } + : process.env + spawn('open', args, { detached: true, stdio: 'ignore', env }).unref() + } + + if (process.platform === 'linux' || process.platform === 'win32') { + if (!appPath) throw new Error("Beeper Desktop not found. Please install beeper using 'beeper install --desktop' or add Beeper Desktop to the PATH") + const args = ['--no-enforce-app-location'] + if (target?.port) args.push(`--pas-port=${target.port}`) + if (target?.serverEnv) args.push(`--server-env=${target.serverEnv}`) + const env = target?.dataDir + ? { ...process.env, ALLOW_MULTIPLE_INSTANCES: 'true', BEEPER_PROFILE: target.profile ?? target.id, BEEPER_USER_DATA_DIR: target.dataDir, } - : process.env - spawn('open', args, { detached: true, stdio: 'ignore', env }).unref() + : process.env + spawn(appPath, args, { detached: true, stdio: 'ignore', env }).unref() + } return { id: target?.id ?? 'desktop', startedAt: new Date().toISOString() } } - export async function findDesktopAppPath(): Promise { const installations = await readInstallations().catch(() => ({ desktop: undefined })) if (installations.desktop?.path && await isBeeperDesktopApp(installations.desktop.path)) return installations.desktop.path @@ -96,8 +115,68 @@ export async function findDesktopAppPath(): Promise { } if (process.platform === 'linux') { - for (const path of ['/usr/bin/beeper', '/usr/local/bin/beeper']) { - if (await pathExists(path)) return path + // 1. Check ~/.beeper/apps/desktop directory for AppImage first + const desktopAppDir = join(homedir(), '.beeper', 'apps', 'desktop'); + try { + const files = await readdir(desktopAppDir); + for (const file of files) { + const filePath = join(desktopAppDir, file); + if (file.match(/^Beeper-.*\.AppImage$/i) && await pathExists(filePath)) { + return filePath; + } + } + } catch { + // Directory doesn't exist or cannot be read, continue to next strategy + } + + // 2. Look for Beeper.desktop file and extract the executable from that + const desktopDirs = [ + join(homedir(), '.local', 'share', 'applications'), + '/usr/share/applications', + ]; + + for (const dir of desktopDirs) { + try { + const desktopFilePath = join(dir, 'Beeper.desktop'); + if (await pathExists(desktopFilePath)) { + const content = await readFile(desktopFilePath, 'utf8'); + const execLine = content + .split('\n') + .find(line => line.startsWith('Exec=')); + + if (execLine) { + const exec = execLine.slice(5).trim(); + const match = exec.match(/^"([^"]+)"|^([^\s]+)/); + const executable = match?.[1] ?? match?.[2]; + + if (executable && await pathExists(executable)) { + return executable; + } + } + } + } catch { + // Ignore unreadable files, continue to next strategy + } + } + + // 3. Search PATH environment variable for AppImage + const pathEnv = process.env.PATH || ''; + for (const dir of pathEnv.split(':')) { + if (dir) { + try { + const files = await readdir(dir); + for (const file of files) { + if (file.match(/^Beeper-.*\.AppImage$/i)) { + const filePath = join(dir, file); + if (await pathExists(filePath)) { + return filePath; + } + } + } + } catch { + // Directory doesn't exist or cannot be read, continue to next + } + } } }