paneful 0.6.3 → 0.6.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,46 @@
1
- import { execFile } from 'node:child_process';
1
+ import { execFile, execSync } from 'node:child_process';
2
2
  import fs from 'node:fs';
3
+ /** Try to focus an existing Paneful browser window. Returns true if successful. */
4
+ export function focusBrowser(_port) {
5
+ if (process.platform !== 'darwin')
6
+ return false;
7
+ // App-mode Chrome windows don't have normal tabs — match by window title instead.
8
+ // The HTML <title> is "Paneful", so any app-mode or regular window showing the app
9
+ // will have "Paneful" in its title.
10
+ const browsers = ['Google Chrome', 'Chromium', 'Microsoft Edge', 'Brave Browser', 'Arc'];
11
+ for (const browser of browsers) {
12
+ const lines = [
13
+ `tell application "System Events"`,
14
+ ` if not (exists process "${browser}") then return false`,
15
+ `end tell`,
16
+ `tell application "${browser}"`,
17
+ ` repeat with w in windows`,
18
+ ` if title of w contains "Paneful" then`,
19
+ ` set index of w to 1`,
20
+ ` activate`,
21
+ ` return true`,
22
+ ` end if`,
23
+ ` end repeat`,
24
+ ` return false`,
25
+ `end tell`,
26
+ ];
27
+ const args = lines.flatMap((l) => ['-e', l]);
28
+ try {
29
+ const result = execSync(`osascript ${args.map((a) => JSON.stringify(a)).join(' ')}`, {
30
+ timeout: 3000,
31
+ encoding: 'utf-8',
32
+ }).trim();
33
+ if (result === 'true') {
34
+ console.log(`Focused existing Paneful window (${browser})`);
35
+ return true;
36
+ }
37
+ }
38
+ catch {
39
+ // This browser not running or doesn't have the window
40
+ }
41
+ }
42
+ return false;
43
+ }
3
44
  export function openBrowser(port) {
4
45
  const url = `http://localhost:${port}`;
5
46
  console.log(`Opening browser at ${url}`);
@@ -11,7 +11,7 @@ import { PtyManager } from './pty-manager.js';
11
11
  import { ProjectStore } from './project-store.js';
12
12
  import { WsHandler } from './ws-handler.js';
13
13
  import { startIpcListener, sendIpcCommand } from './ipc.js';
14
- import { openBrowser } from './browser.js';
14
+ import { openBrowser, focusBrowser } from './browser.js';
15
15
  // ── Version check ──
16
16
  const PKG_NAME = 'paneful';
17
17
  function findPackageJson() {
@@ -379,7 +379,9 @@ function startServer(devMode, port) {
379
379
  writeLockfile(process.pid, actualPort);
380
380
  console.log(`Paneful running on http://localhost:${actualPort}`);
381
381
  if (!devMode) {
382
- openBrowser(actualPort);
382
+ if (!focusBrowser(actualPort)) {
383
+ openBrowser(actualPort);
384
+ }
383
385
  }
384
386
  });
385
387
  // Graceful shutdown
@@ -420,7 +422,9 @@ program
420
422
  const lock = readLockfile();
421
423
  if (lock && isProcessAlive(lock.pid)) {
422
424
  console.log(`Paneful already running on port ${lock.port}`);
423
- openBrowser(lock.port);
425
+ if (!focusBrowser(lock.port)) {
426
+ openBrowser(lock.port);
427
+ }
424
428
  return;
425
429
  }
426
430
  if (lock) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "paneful",
3
- "version": "0.6.3",
3
+ "version": "0.6.4",
4
4
  "description": "Browser-based terminal multiplexer with tmux-style pane management",
5
5
  "type": "module",
6
6
  "bin": {