claude-remote 0.2.0 → 0.2.1

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 (2) hide show
  1. package/package.json +1 -1
  2. package/server.js +36 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-remote",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "Remote control bridge for Claude Code REPL - drive from phone/WebUI",
5
5
  "main": "server.js",
6
6
  "bin": {
package/server.js CHANGED
@@ -120,6 +120,7 @@ let tailTimer = null;
120
120
  let switchWatcher = null;
121
121
  let expectingSwitch = false;
122
122
  let expectingSwitchTimer = null;
123
+ let pendingSwitchTarget = null;
123
124
  let tailRemainder = Buffer.alloc(0);
124
125
  let tailCatchingUp = false; // true while reading historical transcript content
125
126
  const isTTY = process.stdin.isTTY && process.stdout.isTTY;
@@ -214,6 +215,10 @@ function maybeAttachHookSession(data, source) {
214
215
  if (currentSessionId && !expectingSwitch) {
215
216
  const currentHasContent = transcriptPath && fileLooksLikeTranscript(transcriptPath);
216
217
  if (!targetHasContent || currentHasContent) {
218
+ if (currentSessionId !== target.sessionId) {
219
+ pendingSwitchTarget = { ...target, seenAt: Date.now(), source };
220
+ log(`Queued pending session-start: ${target.sessionId} (current=${currentSessionId} currentHasContent=${currentHasContent} targetHasContent=${targetHasContent})`);
221
+ }
217
222
  log(`Ignored session-start: ${target.sessionId} (current=${currentSessionId} currentHasContent=${currentHasContent} targetHasContent=${targetHasContent})`);
218
223
  return;
219
224
  }
@@ -238,6 +243,31 @@ function maybeAttachHookSession(data, source) {
238
243
  attachTranscript({ full: target.full }, 0);
239
244
  }
240
245
 
246
+ function maybeAttachPendingSwitchTarget(reason, requireReady = true) {
247
+ if (!pendingSwitchTarget) return false;
248
+ if ((Date.now() - pendingSwitchTarget.seenAt) > 15000) {
249
+ log(`Dropped stale pending switch target: ${pendingSwitchTarget.sessionId}`);
250
+ pendingSwitchTarget = null;
251
+ return false;
252
+ }
253
+ if (pendingSwitchTarget.sessionId === currentSessionId) {
254
+ pendingSwitchTarget = null;
255
+ return false;
256
+ }
257
+
258
+ if (requireReady && !fileLooksLikeTranscript(pendingSwitchTarget.full)) {
259
+ return false;
260
+ }
261
+
262
+ const target = pendingSwitchTarget;
263
+ pendingSwitchTarget = null;
264
+ log(`Attaching pending switch target from ${reason}: ${target.sessionId}`);
265
+ if (tailTimer) { clearInterval(tailTimer); tailTimer = null; }
266
+ if (switchWatcher) { clearInterval(switchWatcher); switchWatcher = null; }
267
+ attachTranscript({ full: target.full }, 0);
268
+ return true;
269
+ }
270
+
241
271
  // ============================================================
242
272
  // 1. Static file server
243
273
  // ============================================================
@@ -875,6 +905,9 @@ function extractSlashCommand(content) {
875
905
  function attachTranscript(target, startOffset = 0) {
876
906
  transcriptPath = target.full;
877
907
  currentSessionId = path.basename(transcriptPath, '.jsonl');
908
+ if (pendingSwitchTarget && pendingSwitchTarget.sessionId === currentSessionId) {
909
+ pendingSwitchTarget = null;
910
+ }
878
911
  transcriptOffset = Math.max(0, startOffset);
879
912
  tailRemainder = Buffer.alloc(0);
880
913
  eventBuffer = [];
@@ -915,6 +948,7 @@ function markExpectingSwitch() {
915
948
  log('Expecting-switch flag expired (no new transcript found)');
916
949
  }, 15000);
917
950
  log('Expecting session switch (/clear detected)');
951
+ if (maybeAttachPendingSwitchTarget('markExpectingSwitch')) return;
918
952
  }
919
953
 
920
954
  function startSwitchWatcher() {
@@ -952,6 +986,7 @@ function startSwitchWatcher() {
952
986
  function startTailing() {
953
987
  tailRemainder = Buffer.alloc(0);
954
988
  tailTimer = setInterval(() => {
989
+ if (maybeAttachPendingSwitchTarget('tail_pending_target')) return;
955
990
  if (!transcriptPath) return;
956
991
  try {
957
992
  const stat = fs.statSync(transcriptPath);
@@ -1039,6 +1074,7 @@ function stopTailing() {
1039
1074
  if (switchWatcher) { clearInterval(switchWatcher); switchWatcher = null; }
1040
1075
  if (expectingSwitchTimer) { clearTimeout(expectingSwitchTimer); expectingSwitchTimer = null; }
1041
1076
  expectingSwitch = false;
1077
+ pendingSwitchTarget = null;
1042
1078
  tailRemainder = Buffer.alloc(0);
1043
1079
  }
1044
1080