@quantiya/codevibe-claude-plugin 1.0.9 โ†’ 1.0.11

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.
Files changed (40) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/README.md +75 -237
  3. package/hooks/session-start.sh +186 -0
  4. package/package.json +6 -9
  5. package/dist/appsync-client.d.ts +0 -67
  6. package/dist/appsync-client.d.ts.map +0 -1
  7. package/dist/appsync-client.js.map +0 -1
  8. package/dist/auth-cli.d.ts +0 -18
  9. package/dist/auth-cli.d.ts.map +0 -1
  10. package/dist/auth-cli.js.map +0 -1
  11. package/dist/command-executor.d.ts +0 -20
  12. package/dist/command-executor.d.ts.map +0 -1
  13. package/dist/command-executor.js.map +0 -1
  14. package/dist/config.d.ts +0 -25
  15. package/dist/config.d.ts.map +0 -1
  16. package/dist/config.js.map +0 -1
  17. package/dist/crypto-service.d.ts +0 -115
  18. package/dist/crypto-service.d.ts.map +0 -1
  19. package/dist/crypto-service.js.map +0 -1
  20. package/dist/http-api.d.ts +0 -35
  21. package/dist/http-api.d.ts.map +0 -1
  22. package/dist/http-api.js.map +0 -1
  23. package/dist/key-manager.d.ts +0 -87
  24. package/dist/key-manager.d.ts.map +0 -1
  25. package/dist/key-manager.js.map +0 -1
  26. package/dist/logger.d.ts +0 -2
  27. package/dist/logger.d.ts.map +0 -1
  28. package/dist/logger.js.map +0 -1
  29. package/dist/prompt-responder.d.ts +0 -22
  30. package/dist/prompt-responder.d.ts.map +0 -1
  31. package/dist/prompt-responder.js.map +0 -1
  32. package/dist/server.d.ts +0 -9
  33. package/dist/server.d.ts.map +0 -1
  34. package/dist/server.js.map +0 -1
  35. package/dist/token-storage.d.ts +0 -39
  36. package/dist/token-storage.d.ts.map +0 -1
  37. package/dist/token-storage.js.map +0 -1
  38. package/dist/types.d.ts +0 -110
  39. package/dist/types.d.ts.map +0 -1
  40. package/dist/types.js.map +0 -1
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codevibe-claude",
3
- "version": "1.0.9",
3
+ "version": "1.0.11",
4
4
  "description": "Sync Claude Code sessions with iOS mobile app via AWS backend. Control Claude Code from your phone with real-time bidirectional synchronization.",
5
5
  "author": {
6
6
  "name": "CodeVibe Team"
package/README.md CHANGED
@@ -1,295 +1,133 @@
1
- # CodeVibe Claude Plugin
1
+ # CodeVibe for Claude Code
2
2
 
3
- Control Claude Code from your phone with real-time bidirectional synchronization. This plugin enables seamless communication between your desktop Claude Code sessions and the CodeVibe mobile app.
3
+ **Control Claude Code from your iPhone and Android.** See your agent's work, approve file edits, dictate prompts by voice โ€” all from your phone, anywhere you are.
4
4
 
5
- ## Features
5
+ ๐ŸŒ **[quantiya.ai/codevibe](https://quantiya.ai/codevibe)** โ€” landing page, demo video, and one-liner installer
6
6
 
7
- - **Real-time Sync** - See desktop conversations on mobile instantly (~100-500ms latency)
8
- - **Mobile Control** - Send prompts from your phone that execute in the correct desktop session
9
- - **Locked Screen Support** - Works even when your Mac screen is locked (via tmux)
10
- - **Interactive Prompts** - Answer permission dialogs with numbered options (1=Yes, 2=Yes for project, 3=Reject)
11
- - **Voice Input** - Dictate prompts using iOS speech-to-text
12
- - **Image Attachments** - Send screenshots and photos with your messages
13
- - **Markdown Rendering** - Code blocks and formatting displayed beautifully
14
- - **Secure** - Uses AWS AppSync with Cognito authentication (Sign in with Apple/Google)
15
- - **Complete Capture** - Syncs user prompts, assistant responses, tool usage, and file changes
16
- - **Session-Aware** - Multiple Claude Code sessions work independently
17
- - **Auto-execution** - Mobile prompts execute immediately (same trust model as desktop)
7
+ ๐Ÿ“ฑ **[Download on the App Store](https://apps.apple.com/app/id6756500217)** ยท **[Get it on Google Play](https://play.google.com/store/apps/details?id=ai.quantiya.app.codevibe)**
18
8
 
19
- ## Prerequisites
20
-
21
- - **macOS** (darwin platform)
22
- - **Node.js** 18.0.0 or higher
23
- - **tmux** (for locked screen support): `brew install tmux`
24
- - **Claude Code** with plugin system enabled
25
-
26
- ## Installation
27
-
28
- ### Step 1: Install Wrapper Command (One-time)
29
-
30
- Install the CodeVibe wrapper command via npm:
31
-
32
- ```bash
33
- npm install -g @quantiya/codevibe
34
- ```
35
-
36
- This puts `codevibe-claude` (and `codevibe-gemini`, `codevibe-codex`) in your PATH.
37
-
38
- ### Step 2: Register MCP Plugin (One-time)
39
-
40
- Claude Code also needs its MCP plugin registered. Inside a Claude Code session, run:
41
-
42
- ```
43
- /plugin marketplace add https://github.com/hendryyeh/quantiya-codevibe-marketplace
44
- ```
9
+ ---
45
10
 
46
- Then:
11
+ ## Why CodeVibe for Claude Code
47
12
 
48
- ```
49
- /plugin install codevibe-claude
50
- ```
13
+ - **๐Ÿš€ Real-time sync** โ€” every prompt, response, and file change shows up on your phone in 100โ€“500ms
14
+ - **โœ… Approve from anywhere** โ€” review full file diffs and approve or reject Edit/Write operations from your phone, with the same numbered options Claude Code shows in the terminal
15
+ - **๐ŸŽ™๏ธ Voice prompts** โ€” dictate your next prompt with speech-to-text, no keyboard required
16
+ - **๐Ÿ“ท Image attachments** โ€” send screenshots and photos directly to the agent
17
+ - **๐Ÿ”” Push notifications** โ€” get notified when your agent needs input so you never block on approvals
18
+ - **๐Ÿ”’ End-to-end encrypted** โ€” AES-256-GCM with ECDH key exchange; your prompts never pass through a server that can read them
19
+ - **๐Ÿ”“ Locked screen support** โ€” works even when your computer screen is locked (via tmux)
20
+ - **๐Ÿง  Session-aware** โ€” runs multiple concurrent Claude Code sessions independently
51
21
 
52
- ### Step 3: Authenticate (One-time)
22
+ ## Install in 30 seconds
53
23
 
54
- Login to your CodeVibe account:
24
+ The fastest path installs everything (Node, tmux, Claude Code, CodeVibe) in one command:
55
25
 
56
26
  ```bash
57
- codevibe-claude login
27
+ curl -fsSL https://quantiya.ai/codevibe/install.sh | bash
58
28
  ```
59
29
 
60
- This opens a browser for OAuth authentication (Sign in with Apple or Google). Your tokens are stored securely in `~/.codevibe-claude/`.
61
-
62
- Other auth commands:
63
- ```bash
64
- codevibe-claude status # Check authentication status
65
- codevibe-claude logout # Sign out and clear tokens
66
- ```
67
-
68
- ### Step 5: Start Claude Code with Mobile Support
69
-
70
- **Important:** You must use the `codevibe-claude` wrapper instead of `claude` directly:
30
+ Then download the **[iOS app](https://apps.apple.com/app/id6756500217)** or **[Android app](https://play.google.com/store/apps/details?id=ai.quantiya.app.codevibe)**, sign in with the same Apple or Google account, and start a session:
71
31
 
72
32
  ```bash
73
33
  codevibe-claude
74
34
  ```
75
35
 
76
- This wrapper:
77
- - Creates a tmux session for the Claude Code instance
78
- - Enables mobile prompts to work even when your Mac screen is locked
79
- - Supports multiple concurrent Claude Code sessions
80
-
81
- **Note:** Running `claude` directly without the wrapper will prevent mobile prompts from working when your screen is locked.
82
-
83
- ### Step 6: Download the iOS App
84
-
85
- Download "CodeVibe" from the App Store and sign in with the same account you used in Step 4.
86
-
87
- ## Usage
36
+ Your session appears on your phone automatically. That's it.
88
37
 
89
- ### Using the `codevibe-claude` Wrapper
38
+ ### Manual install (if you already have Claude Code)
90
39
 
91
40
  ```bash
92
- # Start a new session (same as running `claude`)
41
+ npm install -g @quantiya/codevibe
42
+ claude plugin marketplace add https://github.com/hendryyeh/quantiya-codevibe-marketplace
43
+ claude plugin install codevibe-claude@codevibe-marketplace
44
+ codevibe login
93
45
  codevibe-claude
94
-
95
- # Resume the last session
96
- codevibe-claude --resume
97
-
98
- # Start with a prompt
99
- codevibe-claude -p "fix the bug"
100
-
101
- # All other claude arguments work too
102
- codevibe-claude --model sonnet
103
46
  ```
104
47
 
105
- ### Benefits of `codevibe-claude`
106
-
107
- | Feature | `codevibe-claude` | Regular `claude` |
108
- |---------|-------------------|------------------|
109
- | Mobile prompts | Works always | Only when screen unlocked |
110
- | Screen locked support | Yes (via tmux) | No |
111
- | Mouse scrolling | Yes | Yes |
112
- | Same experience | Yes | Yes |
48
+ ## Requirements
113
49
 
114
- ### Desktop to Mobile Sync
50
+ - **macOS, Linux, or WSL Ubuntu** โ€” Windows without WSL is not supported
51
+ - **Node.js** 18.0.0+
52
+ - **tmux** โ€” `brew install tmux` on macOS, `apt install tmux` on Linux/WSL
53
+ - **Claude Code** with the plugin system enabled
115
54
 
116
- Everything you do in Claude Code is automatically synced to mobile:
55
+ ## How it works
117
56
 
118
- - **User Prompts** - Your questions and commands
119
- - **Assistant Responses** - Claude's complete responses
120
- - **Tool Usage** - File edits, reads, writes
121
- - **Interactive Prompts** - Y/n permission requests
122
- - **Notifications** - System messages
123
-
124
- ### Mobile to Desktop Control
125
-
126
- From the iOS app:
127
-
128
- 1. Open the CodeVibe app
129
- 2. Select your active session
130
- 3. Type a message or response
131
- 4. It executes immediately in your desktop Claude Code session
132
- 5. See the response on both desktop and mobile
133
-
134
- ### Responding to Permission Prompts from Mobile
135
-
136
- When Claude needs permission to edit or write files, you can respond directly from your phone.
137
-
138
- **Available Options:**
139
-
140
- | Reply | Description |
141
- |-------|-------------|
142
- | `1` | **Approve** - Allow this specific file operation |
143
- | `2` | **Always Allow** - Approve and skip future prompts for this project |
144
- | `3` | **Reject** - Decline the operation |
145
- | `3 <message>` | **Reject with Instructions** - Decline and tell Claude what to do instead |
146
-
147
- **Examples:**
148
57
  ```
149
- 1 -> Approves the edit
150
- 2 -> Approves and trusts this project
151
- 3 -> Rejects the edit
152
- 3 use a different approach -> Rejects and redirects Claude
58
+ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
59
+ โ”‚ Claude Code โ”‚ โ†’โ†’ โ”‚ CodeVibe โ”‚ โ†’โ†’ โ”‚ Your phone โ”‚
60
+ โ”‚ on desktop โ”‚ โ”‚ E2E encrypt โ”‚ โ”‚ (iOS/Android)โ”‚
61
+ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
62
+ โ†‘ โ”‚
63
+ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ mobile prompts โ†โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
153
64
  ```
154
65
 
155
- **Other Inputs:**
156
- - `Y` / `N` - For yes/no confirmation prompts
157
- - `exit`, `quit` - To cancel running operations
158
- - Any other text - Sent as a new prompt to Claude
66
+ Every prompt, response, tool call, and file edit in Claude Code gets encrypted and relayed to your phone in real time via AWS AppSync. Messages from your phone execute immediately in the correct desktop session via tmux โ€” no polling, no manual refresh.
159
67
 
160
- ## Troubleshooting
68
+ ## Responding to permission prompts from your phone
161
69
 
162
- ### "codevibe-claude: command not found"
70
+ When Claude asks for permission to edit a file, you see the **same numbered options on your phone** as in the terminal. Reply by typing or voice-inputting the option number:
163
71
 
164
- **Cause:** PATH not updated or shell not reloaded.
72
+ | Reply | What it does |
73
+ |---|---|
74
+ | `1` | Approve this specific file operation |
75
+ | `2` | Always allow for this project |
76
+ | `3` | Reject the operation |
77
+ | `3 use a different approach` | Reject and redirect Claude with new instructions |
165
78
 
166
- **Solution:**
167
- ```bash
168
- source ~/.zshrc # or ~/.bashrc
169
- ```
170
-
171
- Or check if PATH was added:
172
- ```bash
173
- grep "codevibe-claude" ~/.zshrc
174
- ```
175
-
176
- ### "Not authenticated" error
177
-
178
- **Cause:** User hasn't logged in or tokens expired.
179
-
180
- **Solution:**
181
- ```bash
182
- codevibe-claude login
183
- ```
184
-
185
- ### Mobile messages not executing
186
-
187
- **Cause:** Not using the codevibe-claude wrapper.
188
-
189
- **Solution:** Start Claude Code with:
190
- ```bash
191
- codevibe-claude
192
- ```
193
- Not just `claude`.
194
-
195
- ### Plugin hooks not firing
196
-
197
- **Cause:** Plugin not properly installed.
198
-
199
- **Solution:**
200
- ```
201
- # In Claude Code
202
- /plugin list # Check if installed
203
- /plugin uninstall codevibe-claude
204
- /plugin install codevibe-claude
205
- ```
79
+ You can also reply with any text to send a new prompt.
206
80
 
207
- ### Port already in use
81
+ ## Benefits of the `codevibe-claude` wrapper
208
82
 
209
- **Error:** `EADDRINUSE: address already in use :::3456`
83
+ | | `codevibe-claude` | plain `claude` |
84
+ |---|---|---|
85
+ | Mobile prompts | โœ… Always | โš ๏ธ Only when screen unlocked |
86
+ | Screen-locked support | โœ… Yes (via tmux) | โŒ No |
87
+ | Multiple concurrent sessions | โœ… Yes | โŒ No |
210
88
 
211
- **Solution:** Another MCP server is already running. Kill it:
89
+ Use `codevibe-claude` anywhere you'd use `claude` โ€” all the same flags (`--resume`, `-p`, `--model`, etc.) work identically.
212
90
 
213
- ```bash
214
- pkill -f "node dist/server.js"
215
- ```
216
-
217
- ## Mac Power Settings (for Locked Screen Support)
218
-
219
- To ensure mobile prompts work when your Mac screen is locked:
220
-
221
- 1. **System Settings** -> **Battery** (or **Energy**) -> Set "Computer sleep" to **Never** (when on power)
222
- 2. In Terminal:
223
- ```bash
224
- sudo pmset -a tcpkeepalive 1
225
- sudo pmset -a womp 1
226
- ```
227
-
228
- This keeps network connections alive during sleep.
229
-
230
- ## Architecture
231
-
232
- ```
233
- Desktop -> Mobile:
234
- +-------------+ +----------+ +---------+ +----------+ +--------+
235
- | Claude Code | -> | Hook | -> | MCP | -> | AppSync | -> | Mobile |
236
- | | | Scripts | | Server | | GraphQL | | App |
237
- +-------------+ +----------+ +---------+ +----------+ +--------+
238
-
239
- Mobile -> Desktop:
240
- +--------+ +----------+ +---------+ +-------------+
241
- | Mobile | -> | AppSync | -> | MCP | -> | Claude Code |
242
- | App | | GraphQL | | Server | | (tmux keys) |
243
- +--------+ +----------+ +---------+ +-------------+
244
- ```
91
+ ## Power settings for reliable locked-screen mode
245
92
 
246
- ## Development
247
-
248
- If you want to contribute or run from source:
249
-
250
- ### Clone and Build
93
+ For mobile prompts to keep working when your screen is locked, keep your computer awake on AC power:
251
94
 
95
+ **macOS:**
252
96
  ```bash
253
- git clone https://github.com/hendryyeh/quantiya-codevibe-claude-plugin.git
254
- cd quantiya-codevibe-claude-plugin
255
- npm install
256
- npm run build
97
+ sudo pmset -a tcpkeepalive 1
98
+ sudo pmset -a womp 1
257
99
  ```
100
+ Then set **System Settings โ†’ Battery โ†’ Computer sleep: Never** (when on power).
258
101
 
259
- ### Local Testing
260
-
261
- For local development and testing:
102
+ **Linux / WSL Ubuntu:** disable sleep in your desktop environment's power settings, or use `systemd-inhibit --what=sleep:idle sleep infinity &`. On WSL, configure Windows power settings on the host.
262
103
 
263
- ```bash
264
- ./install-local.sh
104
+ ## Troubleshooting
265
105
 
266
- # In Claude Code
267
- /plugin marketplace add ./dev-marketplace
268
- /plugin install codevibe-claude@codevibe-claude-dev
269
- ```
106
+ - **"command not found: codevibe-claude"** โ€” reload your shell: `source ~/.zshrc` (or `~/.bashrc`)
107
+ - **"not authenticated"** โ€” run `codevibe login`
108
+ - **Mobile messages not executing** โ€” make sure you launched via `codevibe-claude`, not plain `claude`
109
+ - **Plugin hooks not firing** โ€” `codevibe update`, then start a fresh session
270
110
 
271
- ### View Logs
111
+ ### View logs
272
112
 
273
113
  ```bash
274
- # MCP Server logs
275
114
  tail -f /tmp/codevibe-claude-mcp.log
276
-
277
- # Hook scripts logs
278
115
  tail -f /tmp/codevibe-claude-hooks.log
279
116
  ```
280
117
 
281
118
  ## Support
282
119
 
283
- - **Issues:** [GitHub Issues](https://github.com/hendryyeh/quantiya-codevibe-claude-plugin/issues)
120
+ - **Email:** support@quantiya.ai
121
+ - **Landing page:** [quantiya.ai/codevibe](https://quantiya.ai/codevibe)
122
+ - **Privacy policy:** [quantiya.ai/privacy](https://quantiya.ai/privacy)
284
123
 
285
- ## Related
124
+ ## Part of the CodeVibe family
286
125
 
287
- - **CodeVibe iOS App** - Available on the App Store
126
+ - **[@quantiya/codevibe](https://www.npmjs.com/package/@quantiya/codevibe)** โ€” meta-package with the `codevibe` CLI (install this, not this plugin directly)
127
+ - **[@quantiya/codevibe-core](https://www.npmjs.com/package/@quantiya/codevibe-core)** โ€” shared library used by all plugins
128
+ - **[@quantiya/codevibe-gemini-plugin](https://www.npmjs.com/package/@quantiya/codevibe-gemini-plugin)** โ€” Gemini CLI support
129
+ - **[@quantiya/codevibe-codex-plugin](https://www.npmjs.com/package/@quantiya/codevibe-codex-plugin)** โ€” OpenAI Codex CLI support
288
130
 
289
131
  ## License
290
132
 
291
- MIT License - see [LICENSE](LICENSE) file for details.
292
-
293
- ---
294
-
295
- **Made with care by the CodeVibe Team**
133
+ MIT
@@ -35,6 +35,192 @@ else
35
35
  MAPPING_FILE=""
36
36
  fi
37
37
 
38
+ # โ”€โ”€โ”€ Orphan daemon sweep โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
39
+ #
40
+ # When Claude Code terminates abnormally (crash, force-kill, window closed
41
+ # without /exit, network drop), the SessionEnd hook doesn't fire and the
42
+ # background daemon is never sent SIGTERM. Because the daemon is a PPID=1
43
+ # process (detached from the hook that launched it), nothing in the OS
44
+ # cleans it up โ€” it keeps holding its AppSync subscription, sending
45
+ # heartbeats, and showing the session as "desktop connected" on iOS forever.
46
+ #
47
+ # This sweep runs on every SessionStart and cleans up orphan daemons whose
48
+ # tmux session no longer exists. Daemons belonging to live tmux sessions
49
+ # (including our own) are left alone.
50
+ #
51
+ # Scope: the sweep only considers daemons that have an instance mapping file
52
+ # (i.e. were launched under a tmux session). Daemons launched without tmux
53
+ # have no mapping and cannot be safely identified as orphans, so we leave
54
+ # them alone.
55
+ #
56
+ # Safety guards:
57
+ #
58
+ # (A) PID reuse: before killing a PID, verify via `ps -o command=` that the
59
+ # process is actually a node + codevibe-claude + server.js invocation.
60
+ # PIDs are recyclable (macOS cycles through ~32K), so a stale mapping
61
+ # from weeks ago could end up pointing at an unrelated user process.
62
+ # Without identity verification, we'd kill random things.
63
+ #
64
+ # (B) tmux unavailable: if the `tmux` binary is missing or fails for a reason
65
+ # other than "session doesn't exist", we conservatively treat the session
66
+ # as alive and leave the daemon alone. This prevents a degraded-tmux
67
+ # environment from causing a sweep-induced mass kill.
68
+
69
+ # Check whether a PID is still identifiable as a codevibe-claude daemon.
70
+ # Returns 0 if yes, non-zero otherwise.
71
+ is_codevibe_daemon() {
72
+ local pid="$1"
73
+ local cmd
74
+ cmd=$(ps -o command= -p "$pid" 2>/dev/null)
75
+ # Pattern: "node" + "codevibe-claude" + "server.js" somewhere in the command line.
76
+ # Matches both the cache path (...codevibe-marketplace/codevibe-claude/X.Y.Z/dist/server.js)
77
+ # and the dev path (...codevibe-claude-plugin/dist/server.js).
78
+ case "$cmd" in
79
+ *node*codevibe-claude*server.js*) return 0 ;;
80
+ *) return 1 ;;
81
+ esac
82
+ }
83
+
84
+ # Return 0 if the tmux session is alive OR we can't tell.
85
+ # Return non-zero ONLY when we can prove the session is gone: tmux binary exists,
86
+ # tmux server is reachable, and the server says this specific session doesn't exist.
87
+ # Every other failure mode (no binary, server down, socket error, permission issue)
88
+ # returns 0 โ€” conservative, we'd rather leak a daemon than kill the wrong thing.
89
+ tmux_session_alive() {
90
+ local tmux_name="$1"
91
+ if ! command -v tmux >/dev/null 2>&1; then
92
+ return 0 # no tmux binary โ†’ can't verify โ†’ assume alive
93
+ fi
94
+ # Verify the tmux server itself is reachable before trusting has-session.
95
+ # `tmux ls` exits 0 when the server is running and has at least one session.
96
+ # If it fails (server not running, socket error, no sessions at all), we can't
97
+ # reliably distinguish "this session is gone" from "tmux is broken." Conservative
98
+ # choice: assume the session might still be alive (or recoverable when the server
99
+ # comes back).
100
+ if ! tmux ls >/dev/null 2>&1; then
101
+ return 0 # server unreachable or empty โ†’ can't verify โ†’ assume alive
102
+ fi
103
+ # Server is confirmed reachable and has sessions. has-session non-zero now
104
+ # reliably means "this specific session does not exist."
105
+ tmux has-session -t "$tmux_name" 2>/dev/null
106
+ }
107
+
108
+ sweep_orphan_daemons() {
109
+ local swept=0
110
+ local kept=0
111
+ local cleaned_stale=0
112
+
113
+ # Pass 1: walk mapping files, which are the source of truth for (tmux_session, pid) pairs
114
+ shopt -s nullglob
115
+ local map_file
116
+ for map_file in "${CODEVIBE_TMPDIR}"/codevibe-claude-instance-*.json; do
117
+ # Extract tmux session name from filename
118
+ local orphan_tmux
119
+ orphan_tmux=$(basename "$map_file" .json | sed 's/^codevibe-claude-instance-//')
120
+
121
+ # Skip our own tmux session โ€” we handle it in the existing reuse path below
122
+ if [ -n "$TMUX_SESSION" ] && [ "$orphan_tmux" = "$TMUX_SESSION" ]; then
123
+ continue
124
+ fi
125
+
126
+ local orphan_pid
127
+ orphan_pid=$(jq -r '.pid // empty' "$map_file" 2>/dev/null)
128
+
129
+ # Empty or missing PID in mapping โ€” clean up the mapping file
130
+ if [ -z "$orphan_pid" ]; then
131
+ log "INFO" "Orphan sweep: removing mapping with no PID: $map_file"
132
+ rm -f "$map_file"
133
+ cleaned_stale=$((cleaned_stale + 1))
134
+ continue
135
+ fi
136
+
137
+ # PID is no longer running โ€” clean up the stale mapping.
138
+ # NOTE: do NOT touch the pidfile or portfile by session UUID here. If /resume
139
+ # or a UUID collision caused a stale mapping to reference the same session
140
+ # UUID as a currently-live pidfile, we'd delete the live one. Pass 2 below
141
+ # handles pidfile cleanup by verifying each pidfile's content independently.
142
+ if ! ps -p "$orphan_pid" > /dev/null 2>&1; then
143
+ log "INFO" "Orphan sweep: removing stale mapping for dead PID $orphan_pid (tmux $orphan_tmux)"
144
+ rm -f "$map_file"
145
+ cleaned_stale=$((cleaned_stale + 1))
146
+ continue
147
+ fi
148
+
149
+ # PID is alive. Is its tmux session still alive (or unknowable)?
150
+ if tmux_session_alive "$orphan_tmux"; then
151
+ # Live other session โ€” or tmux is unavailable and we can't tell. Either
152
+ # way, the conservative choice is to leave the daemon alone.
153
+ log "DEBUG" "Orphan sweep: tmux $orphan_tmux is alive (or tmux unavailable), leaving daemon $orphan_pid"
154
+ kept=$((kept + 1))
155
+ continue
156
+ fi
157
+
158
+ # tmux is gone but the PID is alive โ€” looks like an orphan. But before
159
+ # killing, verify the PID actually belongs to a codevibe-claude daemon.
160
+ # If PID reuse has handed this PID to an unrelated process, we must not
161
+ # touch it. Just clean up the stale mapping and move on.
162
+ if ! is_codevibe_daemon "$orphan_pid"; then
163
+ log "INFO" "Orphan sweep: PID $orphan_pid is alive but is not a CodeVibe daemon (likely PID reused), removing stale mapping only"
164
+ rm -f "$map_file"
165
+ cleaned_stale=$((cleaned_stale + 1))
166
+ continue
167
+ fi
168
+
169
+ # Verified: this is our daemon and its tmux is gone. Kill it.
170
+ log "WARN" "Orphan sweep: killing orphan daemon PID $orphan_pid (tmux $orphan_tmux is gone)"
171
+
172
+ # SIGTERM first โ€” lets the daemon run its graceful shutdown (mark session INACTIVE, etc.)
173
+ kill "$orphan_pid" 2>/dev/null || true
174
+
175
+ # Give it a moment to exit cleanly, then SIGKILL if it's still alive
176
+ sleep 0.5
177
+ if ps -p "$orphan_pid" > /dev/null 2>&1; then
178
+ log "WARN" "Orphan sweep: daemon $orphan_pid did not exit from SIGTERM, sending SIGKILL"
179
+ kill -9 "$orphan_pid" 2>/dev/null || true
180
+ fi
181
+
182
+ # Remove the mapping file. Do NOT touch pidfile/portfile by session UUID โ€”
183
+ # Pass 2 below will pick up the now-dead PID and clean the pidfile (and its
184
+ # matching portfile) safely, based on PID content, not mapping contents.
185
+ rm -f "$map_file"
186
+ swept=$((swept + 1))
187
+ done
188
+
189
+ # Pass 2: defensive cleanup of stale pidfiles that have no mapping and are dead
190
+ # (e.g. daemons that died before writing a mapping file, or legacy non-tmux launches)
191
+ local pid_file
192
+ for pid_file in "${CODEVIBE_TMPDIR}"/codevibe-claude-*.pid; do
193
+ # Skip the instance-mapping files' PID files (they have 'instance' in the name and are .json not .pid,
194
+ # but be explicit in case the glob matches something unexpected)
195
+ local base
196
+ base=$(basename "$pid_file")
197
+ case "$base" in
198
+ codevibe-claude-instance-*) continue ;;
199
+ esac
200
+
201
+ local pid
202
+ pid=$(cat "$pid_file" 2>/dev/null)
203
+ if [ -z "$pid" ] || ! ps -p "$pid" > /dev/null 2>&1; then
204
+ log "INFO" "Orphan sweep: removing stale pidfile $pid_file (PID ${pid:-empty} not alive)"
205
+ rm -f "$pid_file"
206
+ # Also clean up the corresponding portfile
207
+ local port_file="${pid_file%.pid}.port"
208
+ rm -f "$port_file"
209
+ cleaned_stale=$((cleaned_stale + 1))
210
+ fi
211
+ done
212
+ shopt -u nullglob
213
+
214
+ if [ $swept -gt 0 ] || [ $cleaned_stale -gt 0 ]; then
215
+ log "INFO" "Orphan sweep: killed $swept orphan daemon(s), cleaned $cleaned_stale stale file(s), kept $kept live session(s)"
216
+ else
217
+ log "DEBUG" "Orphan sweep: nothing to clean (kept $kept live session(s))"
218
+ fi
219
+ }
220
+
221
+ # Run the sweep before touching the mapping file for our own session
222
+ sweep_orphan_daemons || log "WARN" "Orphan sweep failed (non-fatal, continuing)"
223
+
38
224
  # Check if there's an MCP server running for this Claude Code instance
39
225
  EXISTING_SERVER_PORT=""
40
226
  EXISTING_SERVER_PID=""
package/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "@quantiya/codevibe-claude-plugin",
3
- "version": "1.0.9",
4
- "description": "Mobile companion for Claude Code - monitor and control your Claude Code sessions from your phone with CodeVibe",
3
+ "version": "1.0.11",
4
+ "description": "Control Claude Code from your iPhone and Android โ€” real-time sync, approve file edits, send prompts by voice. Part of CodeVibe.",
5
5
  "main": "dist/server.js",
6
6
  "bin": {
7
7
  "codevibe-claude": "./bin/codevibe-claude"
8
8
  },
9
9
  "files": [
10
- "dist",
10
+ "dist/**/*.js",
11
11
  "bin",
12
12
  "hooks",
13
13
  ".claude-plugin",
@@ -24,10 +24,6 @@
24
24
  "watch": "tsc --watch",
25
25
  "test": "jest --config jest.config.js --forceExit"
26
26
  },
27
- "repository": {
28
- "type": "git",
29
- "url": "git+https://github.com/hendryyeh/quantiya-codevibe-claude-plugin.git"
30
- },
31
27
  "keywords": [
32
28
  "claude",
33
29
  "claude-code",
@@ -35,6 +31,7 @@
35
31
  "plugin",
36
32
  "mobile",
37
33
  "ios",
34
+ "android",
38
35
  "codevibe",
39
36
  "remote-control",
40
37
  "ai",
@@ -43,9 +40,9 @@
43
40
  "author": "Quantiya <support@quantiya.ai>",
44
41
  "license": "MIT",
45
42
  "bugs": {
46
- "url": "https://github.com/hendryyeh/quantiya-codevibe-claude-plugin/issues"
43
+ "email": "support@quantiya.ai"
47
44
  },
48
- "homepage": "https://github.com/hendryyeh/quantiya-codevibe-claude-plugin#readme",
45
+ "homepage": "https://quantiya.ai/codevibe",
49
46
  "engines": {
50
47
  "node": ">=18.0.0"
51
48
  },