nexting-cc-bridge 0.8.3
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/README.md +252 -0
- package/dist/attach-manager.js +259 -0
- package/dist/bridge.js +931 -0
- package/dist/cli-args.js +14 -0
- package/dist/cli.js +742 -0
- package/dist/codex-prompts.js +148 -0
- package/dist/codex-thread-source.js +495 -0
- package/dist/codex-transcript.js +415 -0
- package/dist/dev-server.js +126 -0
- package/dist/discovery.js +111 -0
- package/dist/e2e/codec.js +119 -0
- package/dist/e2e/crypto.js +127 -0
- package/dist/e2e/key-store.js +48 -0
- package/dist/e2e/keychain-identity.js +29 -0
- package/dist/engine/adapter.js +5 -0
- package/dist/engine/claude-adapter.js +77 -0
- package/dist/engine/codex-adapter.js +593 -0
- package/dist/file-preview.js +292 -0
- package/dist/hub-protocol.js +28 -0
- package/dist/hub-server.js +106 -0
- package/dist/hub.js +84 -0
- package/dist/install-util.js +33 -0
- package/dist/local-shell.js +32 -0
- package/dist/mcp-config.js +230 -0
- package/dist/mcp-device-proxy.js +501 -0
- package/dist/media-hydrator.js +222 -0
- package/dist/message-counter.js +79 -0
- package/dist/phone-probe.js +55 -0
- package/dist/prompt-detector.js +213 -0
- package/dist/protocol.js +3 -0
- package/dist/pty-mirror.js +80 -0
- package/dist/pty-spawn.js +53 -0
- package/dist/scanner.js +422 -0
- package/dist/self-update.js +122 -0
- package/dist/session-map.js +15 -0
- package/dist/session-runner.js +131 -0
- package/dist/shell.js +104 -0
- package/dist/skills-scanner.js +167 -0
- package/dist/stdin-encode.js +32 -0
- package/dist/stream-translate.js +122 -0
- package/dist/terminal-render.js +29 -0
- package/dist/transcript-watcher.js +138 -0
- package/dist/transcript.js +346 -0
- package/dist/turn-probe.js +152 -0
- package/dist/types.js +2 -0
- package/dist/watch-manager.js +77 -0
- package/install-cc.sh +90 -0
- package/install-codex.sh +97 -0
- package/package.json +39 -0
- package/shim/claude +55 -0
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
// Owns the set of transcript followers (one per phone-watched session).
|
|
2
|
+
// cc_watch is idempotent: a re-watch refreshes the TTL and re-sends
|
|
3
|
+
// watch_ok{entryCount} — the phone uses that count as a reconciliation
|
|
4
|
+
// heartbeat (mismatch → it refetches the full transcript anchor).
|
|
5
|
+
import { findSessionFile } from "./scanner.js";
|
|
6
|
+
import { createTranscriptFollower, } from "./transcript-watcher.js";
|
|
7
|
+
const WATCH_TTL_MS = 10 * 60 * 1000; // phone keepalive re-watches every 4 min
|
|
8
|
+
const SWEEP_MS = 60 * 1000;
|
|
9
|
+
export function createWatchManager(send, deps) {
|
|
10
|
+
const findFile = deps?.findFile ?? findSessionFile;
|
|
11
|
+
const log = deps?.log ?? (() => { });
|
|
12
|
+
const followers = new Map();
|
|
13
|
+
const sweep = setInterval(() => {
|
|
14
|
+
const now = Date.now();
|
|
15
|
+
for (const [id, w] of followers) {
|
|
16
|
+
if (now - w.lastTouch > WATCH_TTL_MS) {
|
|
17
|
+
w.f.stop();
|
|
18
|
+
followers.delete(id);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}, SWEEP_MS);
|
|
22
|
+
sweep.unref?.();
|
|
23
|
+
const ok = (sessionId, entryCount) => send({
|
|
24
|
+
type: "cc_event",
|
|
25
|
+
sessionId,
|
|
26
|
+
kind: "watch_ok",
|
|
27
|
+
payload: { entryCount },
|
|
28
|
+
});
|
|
29
|
+
return {
|
|
30
|
+
async watch(sessionId) {
|
|
31
|
+
const existing = followers.get(sessionId);
|
|
32
|
+
if (existing) {
|
|
33
|
+
existing.lastTouch = Date.now();
|
|
34
|
+
ok(sessionId, existing.f.entryCount());
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
const file = await findFile(sessionId);
|
|
38
|
+
if (!file) {
|
|
39
|
+
// No jsonl on this Mac (unknown id, or a codex bridge) — the phone
|
|
40
|
+
// falls back to slow polling on this signal.
|
|
41
|
+
log(`watch failed (no file): ${sessionId.slice(0, 8)}`);
|
|
42
|
+
send({
|
|
43
|
+
type: "cc_event",
|
|
44
|
+
sessionId,
|
|
45
|
+
kind: "watch_failed",
|
|
46
|
+
payload: { reason: "session_file_not_found" },
|
|
47
|
+
});
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
const f = createTranscriptFollower({
|
|
51
|
+
sessionId,
|
|
52
|
+
file,
|
|
53
|
+
emit: send,
|
|
54
|
+
parse: deps?.parse,
|
|
55
|
+
transform: deps?.transform,
|
|
56
|
+
});
|
|
57
|
+
await f.start();
|
|
58
|
+
followers.set(sessionId, { f, lastTouch: Date.now() });
|
|
59
|
+
log(`watch started: ${sessionId.slice(0, 8)} (${f.entryCount()} entries)`);
|
|
60
|
+
ok(sessionId, f.entryCount());
|
|
61
|
+
},
|
|
62
|
+
unwatch(sessionId) {
|
|
63
|
+
const w = followers.get(sessionId);
|
|
64
|
+
if (w) {
|
|
65
|
+
w.f.stop();
|
|
66
|
+
followers.delete(sessionId);
|
|
67
|
+
log(`watch stopped: ${sessionId.slice(0, 8)}`);
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
stopAll() {
|
|
71
|
+
clearInterval(sweep);
|
|
72
|
+
for (const w of followers.values())
|
|
73
|
+
w.f.stop();
|
|
74
|
+
followers.clear();
|
|
75
|
+
},
|
|
76
|
+
};
|
|
77
|
+
}
|
package/install-cc.sh
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Nexting Claude Code bridge installer.
|
|
3
|
+
# curl -fsSL https://nexting.ai/install-cc | bash
|
|
4
|
+
# Logs you in to Nexting in your browser, installs the bridge, and makes `claude`
|
|
5
|
+
# phone-controllable (claude shim + background hub). One step: log in = installed.
|
|
6
|
+
# Fully reversible: nexting-cc-bridge uninstall
|
|
7
|
+
set -euo pipefail
|
|
8
|
+
|
|
9
|
+
API="${NEXTING_API:-https://api.nexting.ai}"
|
|
10
|
+
WS_URL="${NEXTING_CC_URL:-wss://api.nexting.ai/cc-bridge/connect}"
|
|
11
|
+
CFG_DIR="$HOME/.nexting"
|
|
12
|
+
CFG="$CFG_DIR/cc-bridge.json"
|
|
13
|
+
|
|
14
|
+
echo "→ Nexting Claude Code bridge installer"
|
|
15
|
+
|
|
16
|
+
command -v node >/dev/null 2>&1 || { echo "✗ Node.js not found. Claude Code needs Node — install it first."; exit 1; }
|
|
17
|
+
|
|
18
|
+
# ── 1. log in to Nexting (device-code browser flow = the binding) ──
|
|
19
|
+
# Logging in IS the binding: the browser login authorizes this Mac for your
|
|
20
|
+
# account, no separate step. A token may be supplied out-of-band via
|
|
21
|
+
# NEXTING_CC_TOKEN to skip the browser login (e.g. an automated re-install).
|
|
22
|
+
if [ -n "${NEXTING_CC_TOKEN:-}" ]; then
|
|
23
|
+
TOKEN="$NEXTING_CC_TOKEN"
|
|
24
|
+
echo "✓ Using the Nexting account token provided."
|
|
25
|
+
else
|
|
26
|
+
echo "→ Logging you in to Nexting…"
|
|
27
|
+
START=$(curl -fsS -X POST "$API/api/v1/agent-bus/device/start")
|
|
28
|
+
DEVICE_CODE=$(echo "$START" | node -e 'process.stdin.once("data",d=>console.log(JSON.parse(d).device_code))')
|
|
29
|
+
VERIFY_URL=$(echo "$START" | node -e 'process.stdin.once("data",d=>console.log(JSON.parse(d).verify_url))')
|
|
30
|
+
INTERVAL=$(echo "$START" | node -e 'process.stdin.once("data",d=>console.log(JSON.parse(d).interval||3))')
|
|
31
|
+
|
|
32
|
+
echo "→ Opening your browser to log in:"
|
|
33
|
+
echo " $VERIFY_URL"
|
|
34
|
+
( command -v open >/dev/null 2>&1 && open "$VERIFY_URL" ) || echo " (open the URL above manually)"
|
|
35
|
+
|
|
36
|
+
echo "→ Waiting for you to log in & authorize…"
|
|
37
|
+
TOKEN=""
|
|
38
|
+
for _ in $(seq 1 100); do
|
|
39
|
+
sleep "$INTERVAL"
|
|
40
|
+
POLL=$(curl -fsS -X POST "$API/api/v1/agent-bus/device/poll" \
|
|
41
|
+
-H 'Content-Type: application/json' -d "{\"device_code\":\"$DEVICE_CODE\"}")
|
|
42
|
+
STATUS=$(echo "$POLL" | node -e 'process.stdin.once("data",d=>console.log(JSON.parse(d).status||""))')
|
|
43
|
+
if [ "$STATUS" = "approved" ]; then
|
|
44
|
+
TOKEN=$(echo "$POLL" | node -e 'process.stdin.once("data",d=>console.log(JSON.parse(d).token||""))')
|
|
45
|
+
break
|
|
46
|
+
fi
|
|
47
|
+
[ "$STATUS" = "expired" ] && { echo "✗ Login expired. Re-run the installer."; exit 1; }
|
|
48
|
+
done
|
|
49
|
+
[ -n "$TOKEN" ] || { echo "✗ Timed out waiting for login."; exit 1; }
|
|
50
|
+
echo "✓ Logged in."
|
|
51
|
+
fi
|
|
52
|
+
|
|
53
|
+
# ── 2. install the bridge ──
|
|
54
|
+
echo "→ Installing nexting-cc-bridge…"
|
|
55
|
+
npm install -g nexting-cc-bridge >/dev/null 2>&1 || {
|
|
56
|
+
echo " (npm global install unavailable — will run via npx instead)"
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
# ── 3. write config ──
|
|
60
|
+
mkdir -p "$CFG_DIR"
|
|
61
|
+
cat > "$CFG" <<EOF
|
|
62
|
+
{
|
|
63
|
+
"url": "$WS_URL",
|
|
64
|
+
"token": "$TOKEN"
|
|
65
|
+
}
|
|
66
|
+
EOF
|
|
67
|
+
chmod 600 "$CFG"
|
|
68
|
+
echo "✓ Config written to $CFG"
|
|
69
|
+
|
|
70
|
+
# ── 4. make `claude` phone-controllable (shim + PATH + hub daemon) ──
|
|
71
|
+
# Delegates to `nexting-cc-bridge install`: installs the `claude` shim (so the
|
|
72
|
+
# sessions you start are mirrored to + drivable from your phone), puts it on PATH,
|
|
73
|
+
# and keeps the hub daemon alive via launchd. Reversible: nexting-cc-bridge uninstall.
|
|
74
|
+
echo "→ Setting up the Claude Code manager…"
|
|
75
|
+
# `install` also gates Boss Mode: it verifies the superpowers/gstack Claude Code
|
|
76
|
+
# (Workflow tool + /loop) and exits non-zero if absent. Under `set -euo pipefail`
|
|
77
|
+
# that aborts this script before the `Done.` line — install the required Claude
|
|
78
|
+
# Code, then re-run this installer.
|
|
79
|
+
if command -v nexting-cc-bridge >/dev/null 2>&1; then
|
|
80
|
+
nexting-cc-bridge install
|
|
81
|
+
elif command -v npx >/dev/null 2>&1; then
|
|
82
|
+
npx -y nexting-cc-bridge install
|
|
83
|
+
else
|
|
84
|
+
echo "✗ Could not run nexting-cc-bridge install (no global bin / npx)."; exit 1
|
|
85
|
+
fi
|
|
86
|
+
|
|
87
|
+
echo
|
|
88
|
+
echo "Done. Run \`claude\` as usual — it now mirrors to your phone."
|
|
89
|
+
echo "Open Nexting on your phone → Claude Code to see and control your sessions."
|
|
90
|
+
echo "Bypass once with: NEXTING_CC_DISABLE=1 claude · Remove with: nexting-cc-bridge uninstall"
|
package/install-codex.sh
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Nexting Codex bridge installer.
|
|
3
|
+
# curl -fsSL https://nexting.ai/install-codex | bash
|
|
4
|
+
# Logs you in to Nexting in your browser, installs the bridge, and makes your
|
|
5
|
+
# Codex sessions visible and controllable from your phone. No shim needed —
|
|
6
|
+
# a background daemon (launchd) pushes session snapshots to the cloud.
|
|
7
|
+
# Fully reversible: nexting-cc-bridge codex-uninstall
|
|
8
|
+
set -euo pipefail
|
|
9
|
+
|
|
10
|
+
API="${NEXTING_API:-https://api.nexting.ai}"
|
|
11
|
+
WS_URL="${NEXTING_CODEX_URL:-wss://api.nexting.ai/codex-bridge/connect}"
|
|
12
|
+
CFG_DIR="$HOME/.nexting"
|
|
13
|
+
CFG="$CFG_DIR/codex-bridge.json"
|
|
14
|
+
|
|
15
|
+
echo "→ Nexting Codex bridge installer"
|
|
16
|
+
|
|
17
|
+
command -v node >/dev/null 2>&1 || { echo "✗ Node.js not found. Install it first (https://nodejs.org)."; exit 1; }
|
|
18
|
+
|
|
19
|
+
command -v codex >/dev/null 2>&1 || {
|
|
20
|
+
echo "✗ Codex CLI not found. Install it: npm install -g @openai/codex, then run: codex login"
|
|
21
|
+
exit 1
|
|
22
|
+
}
|
|
23
|
+
echo " (reminder: make sure you have run \`codex login\` before using Nexting Codex)"
|
|
24
|
+
|
|
25
|
+
# ── 1. log in to Nexting (device-code browser flow = the binding) ──
|
|
26
|
+
# Logging in IS the binding: the browser login authorizes this Mac for your
|
|
27
|
+
# account, no separate step. A token may be supplied out-of-band via
|
|
28
|
+
# NEXTING_CODEX_TOKEN to skip the browser login (e.g. an automated re-install).
|
|
29
|
+
if [ -n "${NEXTING_CODEX_TOKEN:-}" ]; then
|
|
30
|
+
TOKEN="$NEXTING_CODEX_TOKEN"
|
|
31
|
+
echo "✓ Using the Nexting account token provided."
|
|
32
|
+
else
|
|
33
|
+
echo "→ Logging you in to Nexting…"
|
|
34
|
+
START=$(curl -fsS -X POST "$API/api/v1/agent-bus/device/start")
|
|
35
|
+
DEVICE_CODE=$(echo "$START" | node -e 'process.stdin.once("data",d=>console.log(JSON.parse(d).device_code))')
|
|
36
|
+
VERIFY_URL=$(echo "$START" | node -e 'process.stdin.once("data",d=>console.log(JSON.parse(d).verify_url))')
|
|
37
|
+
INTERVAL=$(echo "$START" | node -e 'process.stdin.once("data",d=>console.log(JSON.parse(d).interval||3))')
|
|
38
|
+
|
|
39
|
+
echo "→ Opening your browser to log in:"
|
|
40
|
+
echo " $VERIFY_URL"
|
|
41
|
+
( command -v open >/dev/null 2>&1 && open "$VERIFY_URL" ) || echo " (open the URL above manually)"
|
|
42
|
+
|
|
43
|
+
echo "→ Waiting for you to log in & authorize…"
|
|
44
|
+
TOKEN=""
|
|
45
|
+
for _ in $(seq 1 100); do
|
|
46
|
+
sleep "$INTERVAL"
|
|
47
|
+
POLL=$(curl -fsS -X POST "$API/api/v1/agent-bus/device/poll" \
|
|
48
|
+
-H 'Content-Type: application/json' -d "{\"device_code\":\"$DEVICE_CODE\"}")
|
|
49
|
+
STATUS=$(echo "$POLL" | node -e 'process.stdin.once("data",d=>console.log(JSON.parse(d).status||""))')
|
|
50
|
+
if [ "$STATUS" = "approved" ]; then
|
|
51
|
+
TOKEN=$(echo "$POLL" | node -e 'process.stdin.once("data",d=>console.log(JSON.parse(d).token||""))')
|
|
52
|
+
break
|
|
53
|
+
fi
|
|
54
|
+
[ "$STATUS" = "expired" ] && { echo "✗ Login expired. Re-run the installer."; exit 1; }
|
|
55
|
+
done
|
|
56
|
+
[ -n "$TOKEN" ] || { echo "✗ Timed out waiting for login."; exit 1; }
|
|
57
|
+
echo "✓ Logged in."
|
|
58
|
+
fi
|
|
59
|
+
|
|
60
|
+
# ── 2. install the bridge ──
|
|
61
|
+
echo "→ Installing nexting-cc-bridge…"
|
|
62
|
+
npm install -g nexting-cc-bridge >/dev/null 2>&1 || {
|
|
63
|
+
echo " (npm global install unavailable — will run via npx instead)"
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
# ── 3. write config ──
|
|
67
|
+
mkdir -p "$CFG_DIR"
|
|
68
|
+
cat > "$CFG" <<EOF
|
|
69
|
+
{
|
|
70
|
+
"url": "$WS_URL",
|
|
71
|
+
"token": "$TOKEN"
|
|
72
|
+
}
|
|
73
|
+
EOF
|
|
74
|
+
chmod 600 "$CFG"
|
|
75
|
+
echo "✓ Config written to $CFG"
|
|
76
|
+
|
|
77
|
+
# ── 4. start the background daemon (launchd keeps it alive) ──
|
|
78
|
+
# Delegates to `nexting-cc-bridge codex-install`: writes a launchd plist that
|
|
79
|
+
# runs `nexting-cc-bridge codex-start` on login and keeps it alive. No shim,
|
|
80
|
+
# no PATH change. Reversible: nexting-cc-bridge codex-uninstall.
|
|
81
|
+
echo "→ Setting up the Codex bridge daemon…"
|
|
82
|
+
# `codex-install` also gates Boss Mode: it verifies the superpowers/gstack Claude
|
|
83
|
+
# Code (Workflow tool + /loop) and exits non-zero if absent. Under `set -euo
|
|
84
|
+
# pipefail` that aborts this script before the `Done.` line — install the required
|
|
85
|
+
# Claude Code, then re-run this installer.
|
|
86
|
+
if command -v nexting-cc-bridge >/dev/null 2>&1; then
|
|
87
|
+
nexting-cc-bridge codex-install
|
|
88
|
+
elif command -v npx >/dev/null 2>&1; then
|
|
89
|
+
npx -y nexting-cc-bridge codex-install
|
|
90
|
+
else
|
|
91
|
+
echo "✗ Could not run nexting-cc-bridge codex-install (no global bin / npx)."; exit 1
|
|
92
|
+
fi
|
|
93
|
+
|
|
94
|
+
echo
|
|
95
|
+
echo "Done. Your Codex sessions now appear on your phone."
|
|
96
|
+
echo "Open Nexting on your phone → Claude Code to see and co-control your sessions."
|
|
97
|
+
echo "Live co-control a folder: nexting-cc-bridge codex-run · Remove: nexting-cc-bridge codex-uninstall"
|
package/package.json
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "nexting-cc-bridge",
|
|
3
|
+
"version": "0.8.3",
|
|
4
|
+
"description": "Nexting Claude Code bridge \u2014 runs Claude Code through a local hub so your phone mirrors and controls your terminal sessions (two-way synced).",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"nexting-cc-bridge": "dist/cli.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist",
|
|
11
|
+
"assets",
|
|
12
|
+
"shim",
|
|
13
|
+
"install-cc.sh",
|
|
14
|
+
"install-codex.sh",
|
|
15
|
+
"README.md"
|
|
16
|
+
],
|
|
17
|
+
"scripts": {
|
|
18
|
+
"test": "vitest run",
|
|
19
|
+
"test:watch": "vitest",
|
|
20
|
+
"build": "tsc -p tsconfig.json && chmod +x dist/cli.js",
|
|
21
|
+
"prepublishOnly": "npm run build",
|
|
22
|
+
"dev": "node --import tsx src/cli.ts",
|
|
23
|
+
"devserver": "node --import tsx src/dev-server.ts"
|
|
24
|
+
},
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"@modelcontextprotocol/sdk": "^1.12.0",
|
|
27
|
+
"chokidar": "^3.6.0",
|
|
28
|
+
"https-proxy-agent": "^7.0.6",
|
|
29
|
+
"node-pty": "^1.1.0",
|
|
30
|
+
"ws": "^8.18.0"
|
|
31
|
+
},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"@types/node": "^22.0.0",
|
|
34
|
+
"@types/ws": "^8.5.12",
|
|
35
|
+
"tsx": "^4.19.0",
|
|
36
|
+
"typescript": "^5.6.0",
|
|
37
|
+
"vitest": "^2.1.0"
|
|
38
|
+
}
|
|
39
|
+
}
|
package/shim/claude
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Nexting Claude Code shim — installed to ~/.nexting/bin/claude and put first on
|
|
3
|
+
# PATH so `claude` transparently runs through the phone-controllable hub.
|
|
4
|
+
#
|
|
5
|
+
# Your terminal experience is unchanged (native Claude Code TUI); the hub just
|
|
6
|
+
# mirrors the session to your phone and lets the phone type into it.
|
|
7
|
+
#
|
|
8
|
+
# Escape hatch: NEXTING_CC_DISABLE=1 claude → runs claude normally, no hub.
|
|
9
|
+
# Uninstall: nexting-cc-bridge uninstall → removes this shim + PATH entry.
|
|
10
|
+
|
|
11
|
+
# Find the REAL claude (known install locations), never this shim.
|
|
12
|
+
REAL=""
|
|
13
|
+
for c in \
|
|
14
|
+
"$HOME/Library/pnpm/claude" \
|
|
15
|
+
"$HOME/.local/bin/claude" \
|
|
16
|
+
"$HOME/.npm-global/bin/claude" \
|
|
17
|
+
/opt/homebrew/bin/claude \
|
|
18
|
+
/usr/local/bin/claude; do
|
|
19
|
+
if [ -x "$c" ]; then REAL="$c"; break; fi
|
|
20
|
+
done
|
|
21
|
+
if [ -z "$REAL" ]; then
|
|
22
|
+
# Last resort: first `claude` on PATH that isn't this shim's dir.
|
|
23
|
+
REAL="$(command -v -a claude 2>/dev/null | grep -v "$HOME/.nexting/bin/claude" | head -1)"
|
|
24
|
+
fi
|
|
25
|
+
|
|
26
|
+
# Bypass when asked, or if we can't find the real claude or the bridge.
|
|
27
|
+
if [ -n "${NEXTING_CC_DISABLE:-}" ] || [ -z "$REAL" ] || ! command -v nexting-cc-bridge >/dev/null 2>&1; then
|
|
28
|
+
exec "${REAL:-claude}" "$@"
|
|
29
|
+
fi
|
|
30
|
+
|
|
31
|
+
# Bypass the phone-mirroring hub for NON-INTERACTIVE usage. The hub wraps claude in
|
|
32
|
+
# a pty so the phone can watch/drive it — wrong for scripted / piped / one-shot
|
|
33
|
+
# runs, which a pty would slow down, hang, or make claude think it's interactive.
|
|
34
|
+
# (a) stdin or stdout is not a TTY → piped / redirected / CI / script.
|
|
35
|
+
if [ ! -t 0 ] || [ ! -t 1 ]; then
|
|
36
|
+
exec "$REAL" "$@"
|
|
37
|
+
fi
|
|
38
|
+
# (b) print mode (-p / --print) anywhere in the args → one-shot, no TUI.
|
|
39
|
+
for arg in "$@"; do
|
|
40
|
+
case "$arg" in
|
|
41
|
+
-p | --print)
|
|
42
|
+
exec "$REAL" "$@"
|
|
43
|
+
;;
|
|
44
|
+
esac
|
|
45
|
+
done
|
|
46
|
+
# (c) non-interactive subcommands / info flags → don't need the hub.
|
|
47
|
+
case "${1:-}" in
|
|
48
|
+
mcp | config | doctor | update | install | --version | -v | --help | -h)
|
|
49
|
+
exec "$REAL" "$@"
|
|
50
|
+
;;
|
|
51
|
+
esac
|
|
52
|
+
|
|
53
|
+
# Tell the hub shell exactly which binary to run (absolute → no shim recursion).
|
|
54
|
+
export NEXTING_CC_CLAUDE_BIN="$REAL"
|
|
55
|
+
exec nexting-cc-bridge term -- "$@"
|