orchestrating 0.1.35 → 0.1.37

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/bin/orch +33 -4
  2. package/package.json +1 -1
package/bin/orch CHANGED
@@ -448,10 +448,12 @@ async function handleDaemon(projectsDir) {
448
448
 
449
449
  const PING_INTERVAL_MS = 30_000;
450
450
  const PONG_TIMEOUT_MS = 10_000;
451
+ const HEARTBEAT_TIMEOUT_MS = 65_000; // expect server heartbeat every 30s, allow 2 missed + margin
451
452
  let ws = null;
452
453
  let pingTimer = null;
453
454
  let pongTimer = null;
454
455
  let reconnectTimer = null;
456
+ let heartbeatTimer = null;
455
457
 
456
458
  // Scan project directories
457
459
  const homeDir = os.homedir();
@@ -478,6 +480,14 @@ async function handleDaemon(projectsDir) {
478
480
  const recentRequests = new Set();
479
481
  const recentSpawns = new Map(); // "command:cwd" -> timestamp
480
482
 
483
+ function resetHeartbeatTimer(sock) {
484
+ if (heartbeatTimer) clearTimeout(heartbeatTimer);
485
+ heartbeatTimer = setTimeout(() => {
486
+ process.stderr.write(`${RED}${PREFIX} No server heartbeat — reconnecting${RESET}\n`);
487
+ if (sock && sock.readyState !== WebSocket.CLOSED) sock.terminate();
488
+ }, HEARTBEAT_TIMEOUT_MS);
489
+ }
490
+
481
491
  function scheduleReconnect(delaySec) {
482
492
  if (reconnecting) return;
483
493
  reconnecting = true;
@@ -530,6 +540,9 @@ async function handleDaemon(projectsDir) {
530
540
  }, PONG_TIMEOUT_MS);
531
541
  }
532
542
  }, PING_INTERVAL_MS);
543
+
544
+ // Start expecting server heartbeats (more reliable than WS pings through proxies)
545
+ resetHeartbeatTimer(sock);
533
546
  });
534
547
 
535
548
  sock.on("pong", () => {
@@ -540,6 +553,11 @@ async function handleDaemon(projectsDir) {
540
553
  let msg;
541
554
  try { msg = JSON.parse(raw.toString()); } catch { return; }
542
555
 
556
+ if (msg.type === "heartbeat") {
557
+ resetHeartbeatTimer(sock);
558
+ return;
559
+ }
560
+
543
561
  if (msg.type === "error") {
544
562
  process.stderr.write(`${RED}${PREFIX} Server: ${msg.error}${RESET}\n`);
545
563
  if (/unauthorized|auth|token/i.test(msg.error || "")) {
@@ -647,6 +665,7 @@ async function handleDaemon(projectsDir) {
647
665
  if (ws === sock) ws = null;
648
666
  if (pingTimer) { clearInterval(pingTimer); pingTimer = null; }
649
667
  if (pongTimer) { clearTimeout(pongTimer); pongTimer = null; }
668
+ if (heartbeatTimer) { clearTimeout(heartbeatTimer); heartbeatTimer = null; }
650
669
  process.stderr.write(`${DIM}${PREFIX} Disconnected — reconnecting in 2s${RESET}\n`);
651
670
  scheduleReconnect(2);
652
671
  });
@@ -663,6 +682,7 @@ async function handleDaemon(projectsDir) {
663
682
  process.stderr.write(`\n${DIM}${PREFIX} Shutting down${RESET}\n`);
664
683
  if (pingTimer) clearInterval(pingTimer);
665
684
  if (pongTimer) clearTimeout(pongTimer);
685
+ if (heartbeatTimer) clearTimeout(heartbeatTimer);
666
686
  if (reconnectTimer) clearTimeout(reconnectTimer);
667
687
  if (ws) ws.close();
668
688
  process.exit(0);
@@ -722,6 +742,11 @@ while (i < args.length) {
722
742
  console.error(" -y, --yolo Skip all permission prompts (auto-approve everything)");
723
743
  console.error("");
724
744
  console.error("Daemon options:");
745
+ console.error(" -b, --background Run daemon in background");
746
+ console.error(" --enable Start on boot (systemd/launchd)");
747
+ console.error(" --disable Remove boot startup");
748
+ console.error(" --stop Stop background daemon");
749
+ console.error(" --status Check if daemon is running");
725
750
  console.error(" --projects <path> Directory to scan for projects (default: ~/projects)");
726
751
  console.error(" -d <path> Short alias for --projects");
727
752
  console.error("");
@@ -731,7 +756,8 @@ while (i < args.length) {
731
756
  console.error(' orch -l "deploy fix" codex');
732
757
  console.error(" orch bash");
733
758
  console.error(" orch daemon");
734
- console.error(" orch daemon --projects ~/work");
759
+ console.error(" orch daemon -b");
760
+ console.error(" orch daemon --enable");
735
761
  console.error("");
736
762
  console.error("Environment:");
737
763
  console.error(" ORC_URL WebSocket server URL (default: wss://api.orchestrat.ing/ws)");
@@ -1082,10 +1108,13 @@ if (adapter) {
1082
1108
  } catch {}
1083
1109
  }
1084
1110
  if (historyEvents.length > 0) {
1085
- process.stderr.write(`${DIM}[orch] Forwarding ${historyEvents.length} history events to dashboard${RESET}\n`);
1111
+ // Only keep the most recent events from history
1112
+ const trimmedHistory = historyEvents.length > MAX_EVENT_HISTORY
1113
+ ? historyEvents.slice(-MAX_EVENT_HISTORY)
1114
+ : historyEvents;
1115
+ process.stderr.write(`${DIM}[orch] Forwarding ${trimmedHistory.length} history events to dashboard (${historyEvents.length} total)${RESET}\n`);
1086
1116
  // Prepend to eventHistory so they get replayed on reconnect too
1087
- eventHistory.unshift(...historyEvents);
1088
- while (eventHistory.length > MAX_EVENT_HISTORY) eventHistory.pop();
1117
+ eventHistory.unshift(...trimmedHistory);
1089
1118
  }
1090
1119
  }
1091
1120
  } catch (err) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "orchestrating",
3
- "version": "0.1.35",
3
+ "version": "0.1.37",
4
4
  "description": "Stream terminal sessions to the orchestrat.ing dashboard",
5
5
  "type": "module",
6
6
  "bin": {