@quantiya/codevibe-claude-plugin 2.0.20 → 2.0.21

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,6 +1,6 @@
1
1
  {
2
2
  "name": "codevibe-claude",
3
- "version": "2.0.20",
3
+ "version": "2.0.21",
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"
@@ -130,6 +130,47 @@ if [ "${CODEVIBE_COMPANION_DIAGNOSTIC:-}" = "version" ]; then
130
130
  exit 0
131
131
  fi
132
132
 
133
+ # Primary-handoff isolation contract (the codex launcher established the
134
+ # direct-path `env -u` and the pane-command `unset`; this launcher adds the
135
+ # fresh-server `env -u` and the server scrub).
136
+ # `codevibe --agent claude` reaches this launcher with core's subprocess
137
+ # markers exported — including QUORUM_REVIEWER_SUBPROCESS=1, the reviewer
138
+ # gate that makes every hook in hooks/common.sh exit 0. That gate is right
139
+ # for reviewer/implementor subprocesses and wrong for the user's primary
140
+ # Companion session: if it reaches `claude`, no hook fires, no daemon
141
+ # starts, and the session never syncs to mobile. A tmux server STARTED by
142
+ # this launcher inherits the launcher's environment into its global
143
+ # environment, so the marker would also reach every pane on that server
144
+ # for the server's lifetime (an existing server does not copy it —
145
+ # see `update-environment`). The launcher therefore removes QUORUM at the
146
+ # exact primary handoff on every path below: `env -u` in front of the
147
+ # direct `claude` runs and in front of `tmux new-session` (so a fresh
148
+ # server never sees it), `unset` inside the pane command (so a server
149
+ # that already carries it — e.g. one started by a pre-2.0.19 launcher —
150
+ # still hands `claude` a clean environment), and a bounded scrub of the
151
+ # server's global environment. Reviewers and implementors spawned later
152
+ # add the marker again themselves and stay gated.
153
+ _CV_QUORUM_MARKER="QUORUM_REVIEWER_SUBPROCESS"
154
+
155
+ # Remove the reviewer gate from the global environment of the tmux server
156
+ # the current client talks to, if that server carries it (started by a
157
+ # 2.0.14–2.0.18 launcher, or by any tool that inherited the marker). The
158
+ # pane command / `env -u` already protect the session being launched; this
159
+ # keeps the marker from reaching panes the user opens later on that
160
+ # server. Bounded: exactly one named variable, only when the server
161
+ # reports it set; the prior value is logged before removal and a failed
162
+ # removal is logged rather than hidden. Never aborts the launcher.
163
+ cv_scrub_server_env() {
164
+ local prev
165
+ prev="$(tmux show-environment -g "$_CV_QUORUM_MARKER" 2>/dev/null)" || return 0
166
+ if tmux set-environment -g -u "$_CV_QUORUM_MARKER"; then
167
+ log "Removed $_CV_QUORUM_MARKER from the tmux server global environment (was: $prev)"
168
+ else
169
+ log "WARNING: failed to remove $_CV_QUORUM_MARKER from the tmux server global environment (was: $prev)"
170
+ fi
171
+ return 0
172
+ }
173
+
133
174
  # Metadata commands are intentionally short-lived and do not create a
134
175
  # Companion session. Run them directly in the foreground so a TTY invocation
135
176
  # cannot race a detached tmux session that exits before attach. Arguments and
@@ -141,7 +182,7 @@ case "${1:-}" in
141
182
  echo "Install Claude Code from https://docs.anthropic.com/claude/docs/claude-code" >&2
142
183
  exit 127
143
184
  fi
144
- exec claude "$@"
185
+ exec env -u "$_CV_QUORUM_MARKER" claude "$@"
145
186
  ;;
146
187
  esac
147
188
 
@@ -310,6 +351,7 @@ log "Arguments: $*"
310
351
  # (claude remains the foreground process for the duration).
311
352
  if [ -n "$TMUX" ]; then
312
353
  log "Already inside tmux, running claude directly"
354
+ cv_scrub_server_env
313
355
  _CV_AGENT_INVOKED="true"
314
356
  _CV_AGENT_STARTED_AT="$(date +%s)"
315
357
  # `|| _CV_RC=$?` is load-bearing: with `set -e`, a non-zero exit
@@ -319,7 +361,7 @@ if [ -n "$TMUX" ]; then
319
361
  # 0 leaves _CV_RC at its 0 default. printf's `|| true` keeps a
320
362
  # disk-full failure from clobbering diagnostics.
321
363
  _CV_RC=0
322
- claude --append-system-prompt "$CODEVIBE_SYSTEM_PROMPT" "$@" || _CV_RC=$?
364
+ env -u "$_CV_QUORUM_MARKER" claude --append-system-prompt "$CODEVIBE_SYSTEM_PROMPT" "$@" || _CV_RC=$?
323
365
  printf '%s' "$_CV_RC" > "$_CV_CLAUDE_EXIT_FILE" 2>/dev/null || true
324
366
  exit "$_CV_RC"
325
367
  fi
@@ -330,7 +372,7 @@ if [ ! -t 0 ] || [ ! -t 1 ]; then
330
372
  _CV_AGENT_INVOKED="true"
331
373
  _CV_AGENT_STARTED_AT="$(date +%s)"
332
374
  _CV_RC=0
333
- claude --append-system-prompt "$CODEVIBE_SYSTEM_PROMPT" "$@" || _CV_RC=$?
375
+ env -u "$_CV_QUORUM_MARKER" claude --append-system-prompt "$CODEVIBE_SYSTEM_PROMPT" "$@" || _CV_RC=$?
334
376
  printf '%s' "$_CV_RC" > "$_CV_CLAUDE_EXIT_FILE" 2>/dev/null || true
335
377
  exit "$_CV_RC"
336
378
  fi
@@ -358,9 +400,14 @@ done
358
400
  # 2. Runs claude
359
401
  # 3. Exits the tmux session when claude exits
360
402
 
361
- tmux new-session -d -s "$SESSION_NAME" -x "$(tput cols)" -y "$(tput lines)" \
362
- "export CODEVIBE_TMUX_SESSION='$SESSION_NAME'; export ENVIRONMENT='$ENVIRONMENT'; $CLAUDE_CMD; printf '%s' \"\$?\" > '$_CV_CLAUDE_EXIT_FILE'; exit"
403
+ env -u "$_CV_QUORUM_MARKER" tmux new-session -d -s "$SESSION_NAME" -x "$(tput cols)" -y "$(tput lines)" \
404
+ "unset $_CV_QUORUM_MARKER; export CODEVIBE_TMUX_SESSION='$SESSION_NAME'; export ENVIRONMENT='$ENVIRONMENT'; $CLAUDE_CMD; printf '%s' \"\$?\" > '$_CV_CLAUDE_EXIT_FILE'; exit"
363
405
  _CV_TMUX_STARTED="true"
406
+
407
+ # A server that already carries the gate (pre-existing, contaminated by a
408
+ # 2.0.14–2.0.18 launcher) hands this pane a clean environment via the
409
+ # `unset` above; scrub its global environment for later panes too.
410
+ cv_scrub_server_env
364
411
  _CV_AGENT_INVOKED="true"
365
412
  _CV_AGENT_STARTED_AT="$(date +%s)"
366
413
 
@@ -332,7 +332,7 @@ endif
332
332
 
333
333
  quiet_cmd_regen_makefile = ACTION Regenerating $@
334
334
  cmd_regen_makefile = cd $(srcdir); /opt/homebrew/lib/node_modules/npm/node_modules/node-gyp/gyp/gyp_main.py -fmake --ignore-environment "-Dlibrary=shared_library" "-Dvisibility=default" "-Dnode_root_dir=/Users/hendryyeh/Library/Caches/node-gyp/24.4.0" "-Dnode_gyp_dir=/opt/homebrew/lib/node_modules/npm/node_modules/node-gyp" "-Dnode_lib_file=/Users/hendryyeh/Library/Caches/node-gyp/24.4.0/<(target_arch)/node.lib" "-Dmodule_root_dir=/Users/hendryyeh/Workspace/CodeVibe/codevibe-claude-plugin/node_modules/fs-ext" "-Dnode_engine=v8" "--depth=." "-Goutput_dir=." "--generator-output=build" -I/Users/hendryyeh/Workspace/CodeVibe/codevibe-claude-plugin/node_modules/fs-ext/build/config.gypi -I/opt/homebrew/lib/node_modules/npm/node_modules/node-gyp/addon.gypi -I/Users/hendryyeh/Library/Caches/node-gyp/24.4.0/include/node/common.gypi "--toplevel-dir=." binding.gyp
335
- Makefile: $(srcdir)/build/config.gypi $(srcdir)/binding.gyp $(srcdir)/../../../../../../../opt/homebrew/lib/node_modules/npm/node_modules/node-gyp/addon.gypi $(srcdir)/../../../../../Library/Caches/node-gyp/24.4.0/include/node/common.gypi
335
+ Makefile: $(srcdir)/build/config.gypi $(srcdir)/../../../../../Library/Caches/node-gyp/24.4.0/include/node/common.gypi $(srcdir)/binding.gyp $(srcdir)/../../../../../../../opt/homebrew/lib/node_modules/npm/node_modules/node-gyp/addon.gypi
336
336
  $(call do_cmd,regen_makefile)
337
337
 
338
338
  # "all" is a concatenation of the "all" targets from all the included
@@ -489,6 +489,7 @@
489
489
  "nodedir": "/Users/hendryyeh/Library/Caches/node-gyp/24.4.0",
490
490
  "python": "/opt/homebrew/opt/python@3.14/bin/python3.14",
491
491
  "standalone_static_library": 1,
492
+ "audit": "",
492
493
  "global_prefix": "/opt/homebrew",
493
494
  "local_prefix": "/Users/hendryyeh/Workspace/CodeVibe/codevibe-claude-plugin",
494
495
  "globalconfig": "/opt/homebrew/etc/npmrc",
@@ -497,6 +498,7 @@
497
498
  "npm_version": "11.4.2",
498
499
  "node_gyp": "/opt/homebrew/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js",
499
500
  "cache": "/Users/hendryyeh/.npm",
501
+ "fund": "",
500
502
  "user_agent": "npm/11.4.2 node/v24.4.0 darwin arm64 workspaces/false",
501
503
  "prefix": "/opt/homebrew"
502
504
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@quantiya/codevibe-claude-plugin",
3
- "version": "2.0.20",
3
+ "version": "2.0.21",
4
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
  "codevibe": {
@@ -22,7 +22,8 @@
22
22
  "postpack": "node scripts/restore-dev.js",
23
23
  "dev": "ts-node src/server.ts",
24
24
  "start": "node dist/server.js",
25
- "test": "jest --config jest.config.js --forceExit"
25
+ "test": "jest --config jest.config.js --forceExit",
26
+ "test:launcher": "jest test/companion-launcher-contract.test.ts test/companion-launcher-quorum-gate.test.ts"
26
27
  },
27
28
  "keywords": [
28
29
  "claude",