From dd4db5ab07c8e26d9ee6ee05c823ab9f1db49767 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Sat, 2 Aug 2025 17:48:31 +0200 Subject: [PATCH] Fix npm package issues and update dependencies for beta 15.2 (#494) --- .grok/settings.json | 3 + docs/npm-release.md | 191 ++++++++++++++++++ ios/VibeTunnel/version.xcconfig | 2 +- mac/VibeTunnel/version.xcconfig | 2 +- web/package.json | 8 +- web/package.npm.json | 10 +- web/pnpm-lock.yaml | 72 +++---- web/scripts/build-npm.js | 19 +- .../components/session-create-form.test.ts | 4 +- .../services/push-notification-service.ts | 2 +- web/src/server/routes/worktrees.test.ts | 47 ++--- web/src/server/socket-api-client.ts | 14 +- web/src/test/unit/multiplexer-manager.test.ts | 15 +- 13 files changed, 288 insertions(+), 101 deletions(-) create mode 100644 .grok/settings.json create mode 100644 docs/npm-release.md diff --git a/.grok/settings.json b/.grok/settings.json new file mode 100644 index 00000000..1dbc7db1 --- /dev/null +++ b/.grok/settings.json @@ -0,0 +1,3 @@ +{ + "model": "grok-4-latest" +} \ No newline at end of file diff --git a/docs/npm-release.md b/docs/npm-release.md new file mode 100644 index 00000000..be0858ca --- /dev/null +++ b/docs/npm-release.md @@ -0,0 +1,191 @@ +# NPM Release Checklist + +This checklist ensures a smooth and error-free npm release process for VibeTunnel. + +## Pre-Release Checklist + +### 1. Code Quality +- [ ] Run all tests: `pnpm test` +- [ ] Run linting: `pnpm run lint` +- [ ] Run type checking: `pnpm run typecheck` +- [ ] Run format check: `pnpm run format:check` +- [ ] Fix any issues found: `pnpm run check:fix` + +### 2. Dependency Updates +- [ ] Update all dependencies to latest versions +- [ ] Run `pnpm update --interactive --latest` +- [ ] Test thoroughly after updates +- [ ] Check for security vulnerabilities: `pnpm audit` + +### 3. Version Updates (CRITICAL - Must be synchronized!) +- [ ] Update version in `web/package.json` +- [ ] Update version in `web/package.npm.json` (must match!) +- [ ] Update version in `mac/VibeTunnel/version.xcconfig` (MARKETING_VERSION) +- [ ] Update version in `ios/VibeTunnel/version.xcconfig` (if applicable) +- [ ] Ensure all versions match exactly + +### 4. Changelog +- [ ] Update CHANGELOG.md with new features, fixes, and breaking changes +- [ ] Include migration guide for breaking changes +- [ ] Credit contributors + +## Build Process + +### 5. Clean Build +- [ ] Clean previous builds: `rm -rf dist-npm/ vibetunnel-*.tgz` +- [ ] Run build: `pnpm run build:npm` +- [ ] Verify build output shows all platforms built successfully +- [ ] Check for "✅ authenticate-pam listed as optional dependency" in output + +### 6. Package Verification (CRITICAL) +- [ ] Verify tarball exists: `ls -la vibetunnel-*.tgz` +- [ ] Extract package.json: `tar -xf vibetunnel-*.tgz package/package.json` +- [ ] Verify authenticate-pam is OPTIONAL: + ```bash + grep -A5 -B5 authenticate-pam package/package.json + # Must show under "optionalDependencies", NOT "dependencies" + ``` +- [ ] Clean up: `rm -rf package/` +- [ ] Check package size is reasonable (~8-15 MB) + +### 7. Package Contents Verification +- [ ] List package contents: `tar -tzf vibetunnel-*.tgz | head -50` +- [ ] Verify critical files are included: + - [ ] `package/lib/vibetunnel-cli` + - [ ] `package/lib/cli.js` + - [ ] `package/bin/vibetunnel` + - [ ] `package/bin/vt` + - [ ] `package/scripts/postinstall.js` + - [ ] `package/scripts/install-vt-command.js` + - [ ] `package/node-pty/` directory + - [ ] `package/prebuilds/` directory with .tar.gz files + - [ ] `package/public/` directory + +## Testing + +### 8. Local Installation Test +- [ ] Test installation: `npm install -g ./vibetunnel-*.tgz` +- [ ] Verify version: `vibetunnel --version` +- [ ] Start server: `vibetunnel` +- [ ] Access web UI: http://localhost:4020 +- [ ] Test vt command: `vt echo "test"` +- [ ] Uninstall: `npm uninstall -g vibetunnel` + +### 9. Docker Test (Linux Compatibility) +- [ ] Create test Dockerfile: + ```dockerfile + FROM node:20-slim + COPY vibetunnel-*.tgz /tmp/ + RUN npm install -g /tmp/vibetunnel-*.tgz + CMD ["vibetunnel", "--version"] + ``` +- [ ] Build: `docker build -t vt-test .` +- [ ] Run: `docker run --rm vt-test` +- [ ] Test without PAM headers (should succeed) +- [ ] Test with PAM: Add `RUN apt-get update && apt-get install -y libpam0g-dev` before install + +### 10. Cross-Platform Testing +- [ ] Test on macOS (if available) +- [ ] Test on Linux x64 +- [ ] Test on Linux ARM64 (if available) +- [ ] Verify prebuilds are used (no compilation during install) + +## Publishing + +### 11. Pre-Publish Checks +- [ ] Ensure you're logged in to npm: `npm whoami` +- [ ] Check current tags: `npm dist-tag ls vibetunnel` +- [ ] Verify no uncommitted changes: `git status` +- [ ] Create git tag: `git tag v1.0.0-beta.X` + +### 12. Publish (CRITICAL - Use tarball filename!) +- [ ] Publish beta: `npm publish vibetunnel-*.tgz --tag beta` +- [ ] Verify on npm: https://www.npmjs.com/package/vibetunnel +- [ ] Test installation from npm: `npm install -g vibetunnel@beta` + +### 13. Post-Publish Verification +- [ ] Check package page shows correct version +- [ ] Verify optional dependencies are displayed correctly +- [ ] Test installation on clean system +- [ ] Monitor npm downloads and issues + +### 14. Promotion to Latest (if stable) +- [ ] Wait for user feedback (at least 24 hours) +- [ ] If stable, promote: `npm dist-tag add vibetunnel@VERSION latest` +- [ ] Update documentation to reference new version + +## Post-Release + +### 15. Documentation Updates +- [ ] Update README.md with new version info +- [ ] Update installation instructions if needed +- [ ] Update web/docs/npm.md release history +- [ ] Create GitHub release with changelog + +### 16. Communication +- [ ] Announce release on relevant channels +- [ ] Notify users of breaking changes +- [ ] Thank contributors + +## Emergency Procedures + +### If Wrong package.json Was Used +1. **DO NOT PANIC** +2. Check if authenticate-pam is a regular dependency (bad) or optional (good) +3. If bad, deprecate immediately: + ```bash + npm deprecate vibetunnel@VERSION "Installation issues on Linux. Use next version." + ``` +4. Increment version and republish following this checklist + +### If Build Failed to Include Files +1. Check build logs for errors +2. Verify all copy operations in build-npm.js succeeded +3. Ensure no .gitignore or .npmignore is excluding files +4. Rebuild with verbose logging if needed + +## Common Issues to Avoid + +1. **NEVER use `npm publish` without tarball filename** - it may rebuild with wrong config +2. **ALWAYS verify authenticate-pam is optional** before publishing +3. **ALWAYS sync versions** across all config files +4. **NEVER skip the Docker test** - it catches Linux issues +5. **ALWAYS use beta tag first** - easier to fix issues before promoting to latest + +## Version Numbering + +- Beta releases: `1.0.0-beta.X` where X increments +- Patch releases: `1.0.0-beta.X.Y` where Y is patch number +- Stable releases: `1.0.0` (no beta suffix) + +## Quick Commands Reference + +```bash +# Update dependencies +pnpm update --interactive --latest + +# Build +pnpm run build:npm + +# Verify +tar -xf vibetunnel-*.tgz package/package.json && \ +grep -A5 optionalDependencies package/package.json && \ +rm -rf package/ + +# Publish +npm publish vibetunnel-*.tgz --tag beta + +# Promote to latest +npm dist-tag add vibetunnel@VERSION latest + +# Check tags +npm dist-tag ls vibetunnel +``` + +## Release Frequency + +- Beta releases: As needed for testing new features +- Stable releases: After thorough testing and user feedback +- Security patches: ASAP after discovery + +Remember: It's better to delay a release than to publish a broken package! \ No newline at end of file diff --git a/ios/VibeTunnel/version.xcconfig b/ios/VibeTunnel/version.xcconfig index a10fd612..0a93ea93 100644 --- a/ios/VibeTunnel/version.xcconfig +++ b/ios/VibeTunnel/version.xcconfig @@ -1,7 +1,7 @@ // VibeTunnel Version Configuration // This file contains the version and build number for the app -MARKETING_VERSION = 1.0.0-beta.7 +MARKETING_VERSION = 1.0.0-beta.15.2 CURRENT_PROJECT_VERSION = 160 // Domain and GitHub configuration diff --git a/mac/VibeTunnel/version.xcconfig b/mac/VibeTunnel/version.xcconfig index 370012b8..6957117d 100644 --- a/mac/VibeTunnel/version.xcconfig +++ b/mac/VibeTunnel/version.xcconfig @@ -1,7 +1,7 @@ // VibeTunnel Version Configuration // This file contains the version and build number for the app -MARKETING_VERSION = 1.0.0-beta.16 +MARKETING_VERSION = 1.0.0-beta.15.2 CURRENT_PROJECT_VERSION = 206 // Domain and GitHub configuration diff --git a/web/package.json b/web/package.json index 1a1fdd5c..af80c71b 100644 --- a/web/package.json +++ b/web/package.json @@ -1,6 +1,6 @@ { "name": "vibetunnel", - "version": "1.0.0-beta.15.1", + "version": "1.0.0-beta.15.2", "description": "Terminal sharing server with web interface - supports macOS, Linux, and headless environments", "main": "dist/server/server.js", "bin": { @@ -96,7 +96,7 @@ "@codemirror/lang-html": "^6.4.9", "@codemirror/lang-javascript": "^6.2.4", "@codemirror/lang-json": "^6.0.2", - "@codemirror/lang-markdown": "^6.3.3", + "@codemirror/lang-markdown": "^6.3.4", "@codemirror/lang-python": "^6.2.1", "@codemirror/state": "^6.5.2", "@codemirror/theme-one-dark": "^6.1.3", @@ -124,7 +124,7 @@ "devDependencies": { "@biomejs/biome": "^2.1.3", "@open-wc/testing": "^4.0.0", - "@playwright/test": "^1.54.1", + "@playwright/test": "^1.54.2", "@prettier/plugin-oxc": "^0.0.4", "@tailwindcss/postcss": "^4.1.11", "@testing-library/dom": "^10.4.1", @@ -156,7 +156,7 @@ "supertest": "^7.1.4", "tailwindcss": "^4.1.11", "tsx": "^4.20.3", - "typescript": "^5.8.3", + "typescript": "^5.9.2", "uuid": "^11.1.0", "vitest": "^3.2.4", "ws-mock": "^0.1.0" diff --git a/web/package.npm.json b/web/package.npm.json index c6114e1a..6b79c6d4 100644 --- a/web/package.npm.json +++ b/web/package.npm.json @@ -1,6 +1,6 @@ { "name": "vibetunnel", - "version": "1.0.0-beta.15.1", + "version": "1.0.0-beta.15.2", "description": "Terminal sharing server with web interface - supports macOS, Linux, and headless environments", "main": "lib/cli.js", "bin": { @@ -12,7 +12,6 @@ "bin/", "scripts/", "node-pty/", - "node_modules/authenticate-pam/", "prebuilds/", "README.md" ], @@ -41,11 +40,11 @@ "@codemirror/lang-html": "^6.4.9", "@codemirror/lang-javascript": "^6.2.4", "@codemirror/lang-json": "^6.0.2", - "@codemirror/lang-markdown": "^6.3.3", + "@codemirror/lang-markdown": "^6.3.4", "@codemirror/lang-python": "^6.2.1", "@codemirror/state": "^6.5.2", "@codemirror/theme-one-dark": "^6.1.3", - "@codemirror/view": "^6.38.0", + "@codemirror/view": "^6.38.1", "@xterm/headless": "^5.5.0", "bonjour-service": "^1.3.0", "chalk": "^5.4.1", @@ -61,7 +60,8 @@ "postject": "1.0.0-alpha.6", "signal-exit": "^4.1.0", "web-push": "^3.6.7", - "ws": "^8.18.3" + "ws": "^8.18.3", + "node-addon-api": "^7.1.0" }, "optionalDependencies": { "authenticate-pam": "^1.0.5" diff --git a/web/pnpm-lock.yaml b/web/pnpm-lock.yaml index 99b58a55..7f224735 100644 --- a/web/pnpm-lock.yaml +++ b/web/pnpm-lock.yaml @@ -24,8 +24,8 @@ importers: specifier: ^6.0.2 version: 6.0.2 '@codemirror/lang-markdown': - specifier: ^6.3.3 - version: 6.3.3 + specifier: ^6.3.4 + version: 6.3.4 '@codemirror/lang-python': specifier: ^6.2.1 version: 6.2.1 @@ -103,8 +103,8 @@ importers: specifier: ^4.0.0 version: 4.0.0 '@playwright/test': - specifier: ^1.54.1 - version: 1.54.1 + specifier: ^1.54.2 + version: 1.54.2 '@prettier/plugin-oxc': specifier: ^0.0.4 version: 0.0.4 @@ -188,7 +188,7 @@ importers: version: 3.6.2 puppeteer: specifier: ^24.15.0 - version: 24.15.0(typescript@5.8.3) + version: 24.15.0(typescript@5.9.2) supertest: specifier: ^7.1.4 version: 7.1.4 @@ -199,8 +199,8 @@ importers: specifier: ^4.20.3 version: 4.20.3 typescript: - specifier: ^5.8.3 - version: 5.8.3 + specifier: ^5.9.2 + version: 5.9.2 uuid: specifier: ^11.1.0 version: 11.1.0 @@ -321,8 +321,8 @@ packages: '@codemirror/lang-json@6.0.2': resolution: {integrity: sha512-x2OtO+AvwEHrEwR0FyyPtfDUiloG3rnVTSZV1W8UteaLL8/MajQd8DpvUb2YVzC+/T18aSDv0H9mu+xw0EStoQ==} - '@codemirror/lang-markdown@6.3.3': - resolution: {integrity: sha512-1fn1hQAPWlSSMCvnF810AkhWpNLkJpl66CRfIy3vVl20Sl4NwChkorCHqpMtNbXr1EuMJsrDnhEpjZxKZ2UX3A==} + '@codemirror/lang-markdown@6.3.4': + resolution: {integrity: sha512-fBm0BO03azXnTAsxhONDYHi/qWSI+uSEIpzKM7h/bkIc9fHnFp9y7KTMXKON0teNT97pFhc1a9DQTtWBYEZ7ug==} '@codemirror/lang-python@6.2.1': resolution: {integrity: sha512-IRjC8RUBhn9mGR9ywecNhB51yePWCGgvHfY1lWN/Mrp3cKuHr0isDKia+9HnvhiWNnMpbGhWrkhuWOc09exRyw==} @@ -710,8 +710,8 @@ packages: resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} - '@playwright/test@1.54.1': - resolution: {integrity: sha512-FS8hQ12acieG2dYSksmLOF7BNxnVf2afRJdCuM1eMSxj6QTSE6G4InGF7oApGgDb65MX7AwMVlIkpru0yZA4Xw==} + '@playwright/test@1.54.2': + resolution: {integrity: sha512-A+znathYxPf+72riFd1r1ovOLqsIIB0jKIoPjyK2kqEIe30/6jF6BC7QNluHuwUmsD2tv1XZVugN8GqfTMOxsA==} engines: {node: '>=18'} hasBin: true @@ -1653,8 +1653,8 @@ packages: ee-first@1.1.1: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} - electron-to-chromium@1.5.192: - resolution: {integrity: sha512-rP8Ez0w7UNw/9j5eSXCe10o1g/8B1P5SM90PCCMVkIRQn2R0LEHWz4Eh9RnxkniuDe1W0cTSOB3MLlkTGDcuCg==} + electron-to-chromium@1.5.194: + resolution: {integrity: sha512-SdnWJwSUot04UR51I2oPD8kuP2VI37/CADR1OHsFOUzZIvfWJBO6q11k5P/uKNyTT3cdOsnyjkrZ+DDShqYqJA==} emoji-regex@10.4.0: resolution: {integrity: sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==} @@ -1825,8 +1825,8 @@ packages: flatted@3.3.3: resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==} - follow-redirects@1.15.9: - resolution: {integrity: sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==} + follow-redirects@1.15.11: + resolution: {integrity: sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==} engines: {node: '>=4.0'} peerDependencies: debug: '*' @@ -2682,13 +2682,13 @@ packages: resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} engines: {node: '>=0.10.0'} - playwright-core@1.54.1: - resolution: {integrity: sha512-Nbjs2zjj0htNhzgiy5wu+3w09YetDx5pkrpI/kZotDlDUaYk0HVA5xrBVPdow4SAUIlhgKcJeJg4GRKW6xHusA==} + playwright-core@1.54.2: + resolution: {integrity: sha512-n5r4HFbMmWsB4twG7tJLDN9gmBUeSPcsBZiWSE4DnYz9mJMAFqr2ID7+eGC9kpEnxExJ1epttwR59LEWCk8mtA==} engines: {node: '>=18'} hasBin: true - playwright@1.54.1: - resolution: {integrity: sha512-peWpSwIBmSLi6aW2auvrUtf2DqY16YYcCMO8rTVx486jKmDTJg7UAhyrraP98GB8BoPURZP8+nxO7TSd4cPr5g==} + playwright@1.54.2: + resolution: {integrity: sha512-Hu/BMoA1NAdRUuulyvQC0pEqZ4vQbGfn8f7wPXcnqQmM+zct9UliKxsIkLNmz/ku7LElUNqmaiv1TG/aL5ACsw==} engines: {node: '>=18'} hasBin: true @@ -3165,8 +3165,8 @@ packages: typedarray@0.0.6: resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==} - typescript@5.8.3: - resolution: {integrity: sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==} + typescript@5.9.2: + resolution: {integrity: sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==} engines: {node: '>=14.17'} hasBin: true @@ -3516,7 +3516,7 @@ snapshots: '@codemirror/language': 6.11.2 '@lezer/json': 1.0.3 - '@codemirror/lang-markdown@6.3.3': + '@codemirror/lang-markdown@6.3.4': dependencies: '@codemirror/autocomplete': 6.18.6 '@codemirror/lang-html': 6.4.9 @@ -3863,9 +3863,9 @@ snapshots: '@pkgjs/parseargs@0.11.0': optional: true - '@playwright/test@1.54.1': + '@playwright/test@1.54.2': dependencies: - playwright: 1.54.1 + playwright: 1.54.2 '@polka/url@1.0.0-next.29': {} @@ -4537,7 +4537,7 @@ snapshots: browserslist@4.25.1: dependencies: caniuse-lite: 1.0.30001731 - electron-to-chromium: 1.5.192 + electron-to-chromium: 1.5.194 node-releases: 2.0.19 update-browserslist-db: 1.1.3(browserslist@4.25.1) @@ -4745,14 +4745,14 @@ snapshots: depd: 2.0.0 keygrip: 1.1.0 - cosmiconfig@9.0.0(typescript@5.8.3): + cosmiconfig@9.0.0(typescript@5.9.2): dependencies: env-paths: 2.2.1 import-fresh: 3.3.1 js-yaml: 4.1.0 parse-json: 5.2.0 optionalDependencies: - typescript: 5.8.3 + typescript: 5.9.2 crelt@1.0.6: {} @@ -4847,7 +4847,7 @@ snapshots: ee-first@1.1.1: {} - electron-to-chromium@1.5.192: {} + electron-to-chromium@1.5.194: {} emoji-regex@10.4.0: {} @@ -5064,7 +5064,7 @@ snapshots: flatted@3.3.3: {} - follow-redirects@1.15.9(debug@4.4.1): + follow-redirects@1.15.11(debug@4.4.1): optionalDependencies: debug: 4.4.1 @@ -5250,7 +5250,7 @@ snapshots: http-proxy@1.18.1(debug@4.4.1): dependencies: eventemitter3: 4.0.7 - follow-redirects: 1.15.9(debug@4.4.1) + follow-redirects: 1.15.11(debug@4.4.1) requires-port: 1.0.0 transitivePeerDependencies: - debug @@ -5916,11 +5916,11 @@ snapshots: pify@2.3.0: {} - playwright-core@1.54.1: {} + playwright-core@1.54.2: {} - playwright@1.54.1: + playwright@1.54.2: dependencies: - playwright-core: 1.54.1 + playwright-core: 1.54.2 optionalDependencies: fsevents: 2.3.2 @@ -6020,11 +6020,11 @@ snapshots: - supports-color - utf-8-validate - puppeteer@24.15.0(typescript@5.8.3): + puppeteer@24.15.0(typescript@5.9.2): dependencies: '@puppeteer/browsers': 2.10.6 chromium-bidi: 7.2.0(devtools-protocol@0.0.1464554) - cosmiconfig: 9.0.0(typescript@5.8.3) + cosmiconfig: 9.0.0(typescript@5.9.2) devtools-protocol: 0.0.1464554 puppeteer-core: 24.15.0 typed-query-selector: 2.12.0 @@ -6477,7 +6477,7 @@ snapshots: typedarray@0.0.6: {} - typescript@5.8.3: {} + typescript@5.9.2: {} undici-types@6.21.0: {} diff --git a/web/scripts/build-npm.js b/web/scripts/build-npm.js index 9a45867c..07499d87 100644 --- a/web/scripts/build-npm.js +++ b/web/scripts/build-npm.js @@ -525,19 +525,18 @@ function validatePackageHybrid() { console.log(' ⚠️ Prebuilds skipped in current-only mode'); } - // Check authenticate-pam (Linux support) - const authPamDir = path.join(DIST_DIR, 'node_modules', 'authenticate-pam'); - if (!fs.existsSync(authPamDir)) { - warnings.push('authenticate-pam module not included (Linux PAM auth will not work)'); - } else { - console.log(' ✅ authenticate-pam module included for Linux support'); - } - // Validate package.json const packageJsonPath = path.join(DIST_DIR, 'package.json'); if (fs.existsSync(packageJsonPath)) { const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8')); + // Check authenticate-pam is listed as optionalDependency + if (packageJson.optionalDependencies && packageJson.optionalDependencies['authenticate-pam']) { + console.log(' ✅ authenticate-pam listed as optional dependency'); + } else { + warnings.push('authenticate-pam not listed as optional dependency (Linux PAM auth may not work)'); + } + // Check postinstall script if (!packageJson.scripts || !packageJson.scripts.postinstall) { errors.push('Missing postinstall script in package.json'); @@ -667,8 +666,8 @@ async function main() { // Step 4: Bundle node-pty with dependencies bundleNodePty(); - // Step 5: Copy authenticate-pam module for Linux support (OUR ENHANCEMENT) - copyAuthenticatePam(); + // Step 5: Don't copy authenticate-pam - it's an optionalDependency that will be installed by npm + // copyAuthenticatePam(); // Step 6: Use package.npm.json if available, otherwise create clean package.json console.log('\n6️⃣ Creating package.json for npm...\n'); diff --git a/web/src/client/components/session-create-form.test.ts b/web/src/client/components/session-create-form.test.ts index cecfdf23..f3c27a4c 100644 --- a/web/src/client/components/session-create-form.test.ts +++ b/web/src/client/components/session-create-form.test.ts @@ -880,12 +880,12 @@ describe('SessionCreateForm', () => { // Set up working directory and command first element.workingDir = '/home/user/project'; element.command = 'vim'; - + // Trigger Git repository check which will load currentBranch and selectedBaseBranch // @ts-expect-error - accessing private method for testing await element.checkGitRepository(); await element.updateComplete; - + // The Git check should have loaded the repository info and set currentBranch to 'main' // and selectedBaseBranch should also be 'main' (current branch is selected by default) // This ensures the Git info will be included in the session creation request diff --git a/web/src/client/services/push-notification-service.ts b/web/src/client/services/push-notification-service.ts index 4b393921..8c3201e8 100644 --- a/web/src/client/services/push-notification-service.ts +++ b/web/src/client/services/push-notification-service.ts @@ -315,7 +315,7 @@ export class PushNotificationService { // Subscribe to push notifications this.pushSubscription = await this.serviceWorkerRegistration.pushManager.subscribe({ userVisibleOnly: true, - applicationServerKey: vapidKey, + applicationServerKey: vapidKey as BufferSource, }); // Convert to our interface format diff --git a/web/src/server/routes/worktrees.test.ts b/web/src/server/routes/worktrees.test.ts index 97036e04..69566a2c 100644 --- a/web/src/server/routes/worktrees.test.ts +++ b/web/src/server/routes/worktrees.test.ts @@ -300,42 +300,27 @@ branch refs/heads/feature }); }); - describe('POST /api/worktrees/switch', () => { - it('should switch branch and enable follow mode', async () => { - mockExecFile.mockResolvedValueOnce({ stdout: '', stderr: '' }); // status (no uncommitted changes) - mockExecFile.mockResolvedValueOnce({ stdout: '', stderr: '' }); // checkout - mockExecFile.mockResolvedValueOnce({ stdout: '', stderr: '' }); // config - - const response = await request(app).post('/api/worktrees/switch').send({ - repoPath: '/home/user/project', - branch: 'develop', - }); - - expect(response.status).toBe(200); - expect(response.body.currentBranch).toBe('develop'); - expect(mockExecFile).toHaveBeenCalledWith( - 'git', - ['checkout', 'develop'], - expect.objectContaining({ cwd: '/home/user/project' }) - ); - expect(mockExecFile).toHaveBeenCalledWith( - 'git', - ['config', '--local', 'vibetunnel.followWorktree', '/path/to/worktree'], - expect.objectContaining({ cwd: '/home/user/project' }) - ); - }); - - it('should handle missing parameters', async () => { - const response = await request(app).post('/api/worktrees/switch').send({}); - expect(response.status).toBe(400); - }); - }); - describe('POST /api/worktrees/follow', () => { it('should enable follow mode', async () => { + // Mock worktree list to find the path for the branch + mockExecFile.mockResolvedValueOnce({ + stdout: `worktree /home/user/project +HEAD abc123 +branch refs/heads/main + +`, + stderr: '', + }); + // Mock setting git config for follow branch mockExecFile.mockResolvedValueOnce({ stdout: '', stderr: '' }); // config set + // Mock branch list check + mockExecFile.mockResolvedValueOnce({ stdout: '* main\n', stderr: '' }); + + // Mock checkout + mockExecFile.mockResolvedValueOnce({ stdout: '', stderr: '' }); + const response = await request(app).post('/api/worktrees/follow').send({ repoPath: '/home/user/project', branch: 'main', diff --git a/web/src/server/socket-api-client.ts b/web/src/server/socket-api-client.ts index 364b0926..3bcc11cb 100644 --- a/web/src/server/socket-api-client.ts +++ b/web/src/server/socket-api-client.ts @@ -35,19 +35,27 @@ export interface ServerStatus { */ export class SocketApiClient { private readonly controlSocketPath: string; + private readonly controlDir: string; constructor() { // Use control directory from environment or default - const controlDir = process.env.VIBETUNNEL_CONTROL_DIR || path.join(os.homedir(), '.vibetunnel'); + this.controlDir = process.env.VIBETUNNEL_CONTROL_DIR || path.join(os.homedir(), '.vibetunnel'); // Use api.sock instead of control.sock to avoid conflicts with Mac app - this.controlSocketPath = path.join(controlDir, 'api.sock'); + this.controlSocketPath = path.join(this.controlDir, 'api.sock'); + + logger.debug(`SocketApiClient initialized with control directory: ${this.controlDir}`); + logger.debug(`Socket path: ${this.controlSocketPath}`); } /** * Check if the control socket exists */ private isSocketAvailable(): boolean { - return fs.existsSync(this.controlSocketPath); + const available = fs.existsSync(this.controlSocketPath); + logger.debug( + `Socket availability check: ${this.controlSocketPath} - ${available ? 'available' : 'not available'}` + ); + return available; } /** diff --git a/web/src/test/unit/multiplexer-manager.test.ts b/web/src/test/unit/multiplexer-manager.test.ts index 7e40ef6a..7f906b63 100644 --- a/web/src/test/unit/multiplexer-manager.test.ts +++ b/web/src/test/unit/multiplexer-manager.test.ts @@ -4,6 +4,7 @@ import { MultiplexerManager } from '../../server/services/multiplexer-manager.js import { ScreenManager } from '../../server/services/screen-manager.js'; import { TmuxManager } from '../../server/services/tmux-manager.js'; import { ZellijManager } from '../../server/services/zellij-manager.js'; +import type { MultiplexerType } from '../../shared/multiplexer-types.js'; import { TitleMode } from '../../shared/types.js'; // Mock the managers @@ -191,7 +192,7 @@ describe('MultiplexerManager', () => { it('should throw error for unknown multiplexer type', async () => { await expect( - multiplexerManager.createSession('unknown' as any, 'new-session') + multiplexerManager.createSession('unknown' as unknown as MultiplexerType, 'new-session') ).rejects.toThrow('Unknown multiplexer type: unknown'); }); }); @@ -250,9 +251,9 @@ describe('MultiplexerManager', () => { }); it('should throw error for unknown multiplexer type', async () => { - await expect(multiplexerManager.attachToSession('unknown' as any, 'main')).rejects.toThrow( - 'Unknown multiplexer type: unknown' - ); + await expect( + multiplexerManager.attachToSession('unknown' as unknown as MultiplexerType, 'main') + ).rejects.toThrow('Unknown multiplexer type: unknown'); }); }); @@ -280,9 +281,9 @@ describe('MultiplexerManager', () => { }); it('should throw error for unknown multiplexer type', async () => { - await expect(multiplexerManager.killSession('unknown' as any, 'old-session')).rejects.toThrow( - 'Unknown multiplexer type: unknown' - ); + await expect( + multiplexerManager.killSession('unknown' as unknown as MultiplexerType, 'old-session') + ).rejects.toThrow('Unknown multiplexer type: unknown'); }); });