claude-ws 0.3.107 → 0.3.108

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-ws",
3
- "version": "0.3.107",
3
+ "version": "0.3.108",
4
4
  "private": false,
5
5
  "description": "A beautifully crafted workspace interface for Claude Code with real-time streaming and local SQLite database",
6
6
  "keywords": [
@@ -37,7 +37,21 @@
37
37
  "scripts",
38
38
  "src",
39
39
  "public",
40
- ".next",
40
+ ".next/build",
41
+ ".next/server",
42
+ ".next/static",
43
+ ".next/BUILD_ID",
44
+ ".next/build-manifest.json",
45
+ ".next/app-path-routes-manifest.json",
46
+ ".next/package.json",
47
+ ".next/required-server-files.json",
48
+ ".next/routes-manifest.json",
49
+ ".next/prerender-manifest.json",
50
+ ".next/export-marker.json",
51
+ ".next/images-manifest.json",
52
+ ".next/fallback-build-manifest.json",
53
+ ".next/next-minimal-server.js.nft.json",
54
+ ".next/next-server.js.nft.json",
41
55
  "server.ts",
42
56
  "next.config.ts",
43
57
  "tsconfig.json",
@@ -30,6 +30,8 @@ export function useBoardMobileSwipeGesture({
30
30
  onColumnChange,
31
31
  }: UseBoardMobileSwipeGestureProps): UseBoardMobileSwipeGestureReturn {
32
32
  const touchStartRef = useRef<{ x: number; y: number } | null>(null);
33
+ // Axis lock: null = undecided, 'horizontal' = swiping columns, 'vertical' = scrolling tasks
34
+ const axisLockRef = useRef<'horizontal' | 'vertical' | null>(null);
33
35
  const [swipeOffset, setSwipeOffset] = useState(0);
34
36
  const [isDragging, setIsDragging] = useState(false);
35
37
  const [isResetting, setIsResetting] = useState(false);
@@ -45,6 +47,7 @@ export function useBoardMobileSwipeGesture({
45
47
  }
46
48
 
47
49
  touchStartRef.current = { x: e.touches[0].clientX, y: e.touches[0].clientY };
50
+ axisLockRef.current = null;
48
51
  setSwipeOffset(0);
49
52
  setIsDragging(true);
50
53
  };
@@ -54,10 +57,20 @@ export function useBoardMobileSwipeGesture({
54
57
  if (!touchStartRef.current || !isDragging) return;
55
58
 
56
59
  const currentX = e.touches[0].clientX;
60
+ const currentY = e.touches[0].clientY;
57
61
  const dx = currentX - touchStartRef.current.x;
62
+ const dy = currentY - touchStartRef.current.y;
58
63
 
59
- // Calculate swipe offset with resistance
60
- // Limit the offset to simulate snap-back at edges
64
+ // Determine axis lock after a small movement threshold (8px)
65
+ if (axisLockRef.current === null) {
66
+ if (Math.abs(dx) < 8 && Math.abs(dy) < 8) return;
67
+ axisLockRef.current = Math.abs(dx) >= Math.abs(dy) ? 'horizontal' : 'vertical';
68
+ }
69
+
70
+ // Vertical scroll locked — let browser handle native scroll, skip horizontal swipe
71
+ if (axisLockRef.current === 'vertical') return;
72
+
73
+ // Horizontal swipe locked — calculate offset with resistance
61
74
  const maxOffset = window.innerWidth * 0.4;
62
75
  let newOffset = dx;
63
76
 
@@ -76,16 +89,22 @@ export function useBoardMobileSwipeGesture({
76
89
  return;
77
90
  }
78
91
  const dx = e.changedTouches[0].clientX - touchStartRef.current.x;
79
- const dy = e.changedTouches[0].clientY - touchStartRef.current.y;
92
+ const lockedAxis = axisLockRef.current;
80
93
  touchStartRef.current = null;
94
+ axisLockRef.current = null;
81
95
  setIsDragging(false);
82
96
 
97
+ // If gesture was vertical or undecided, just reset — no column transition
98
+ if (lockedAxis !== 'horizontal') {
99
+ setSwipeOffset(0);
100
+ return;
101
+ }
102
+
83
103
  const currentIndex = visibleColumnIds.indexOf(mobileActiveColumn);
84
104
  const threshold = window.innerWidth * 0.2; // 20% of screen width to trigger column change
85
105
 
86
- // Only trigger if horizontal swipe is dominant and exceeds threshold
87
- if (Math.abs(dx) < threshold || Math.abs(dy) > Math.abs(dx)) {
88
- // Animate back to original position
106
+ if (Math.abs(dx) < threshold) {
107
+ // Didn't swipe far enough animate back
89
108
  setSwipeOffset(0);
90
109
  return;
91
110
  }
@@ -9,17 +9,26 @@
9
9
  */
10
10
 
11
11
  import { EventEmitter } from 'events';
12
- import * as pty from '@homebridge/node-pty-prebuilt-multiarch';
13
12
  import { nanoid } from 'nanoid';
14
13
  import { detectShell } from './terminal-shell-detect';
15
14
  import { createLogger } from './logger';
16
15
 
17
16
  const log = createLogger('TerminalManager');
18
17
 
18
+ // Lazy-load node-pty — native module that may not compile on all platforms (e.g. Windows)
19
+ type NodePty = typeof import('@homebridge/node-pty-prebuilt-multiarch');
20
+ type IPty = import('@homebridge/node-pty-prebuilt-multiarch').IPty;
21
+ let pty: NodePty | null = null;
22
+ try {
23
+ pty = require('@homebridge/node-pty-prebuilt-multiarch');
24
+ } catch {
25
+ log.warn('node-pty not available — interactive terminal feature disabled');
26
+ }
27
+
19
28
  export interface TerminalSession {
20
29
  id: string;
21
30
  projectId: string;
22
- ptyProcess: pty.IPty;
31
+ ptyProcess: IPty;
23
32
  cols: number;
24
33
  rows: number;
25
34
  cwd: string;
@@ -47,7 +56,14 @@ class TerminalManager extends EventEmitter {
47
56
  process.on('exit', () => this.destroyAll());
48
57
  }
49
58
 
59
+ get isAvailable(): boolean {
60
+ return pty !== null;
61
+ }
62
+
50
63
  create(options: TerminalCreateOptions): string {
64
+ if (!pty) {
65
+ throw new Error('Interactive terminals unavailable — node-pty failed to load on this platform');
66
+ }
51
67
  const { projectId, cwd, cols = 80, rows = 24, shell } = options;
52
68
  const terminalId = nanoid();
53
69
 
@@ -1 +0,0 @@
1
- {"previewModeId":"3641d37f427d5227a0061def5f9f00ea","previewModeSigningKey":"107a6f903179eb48505a4b44be4e522d6b635f318c4d28b73ff38d3a83a4a578","previewModeEncryptionKey":"ed061d5be71683f347e59f91eacf67404caadbc7dc7c38a1dd156d033e6f36e4","expireAt":1774912358288}
@@ -1 +0,0 @@
1
- {"encryption.key":"Xy8lZ8znj271E22J2wI7ovhzG2IGRuiYBKxuwCxQiZk=","encryption.expire_at":1774912358171}