patchcord 0.5.4 → 0.5.6

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,7 +1,7 @@
1
1
  {
2
2
  "name": "patchcord",
3
3
  "description": "Cross-machine agent messaging with push delivery. Messages from other agents arrive as native channel notifications.",
4
- "version": "0.5.4",
4
+ "version": "0.5.6",
5
5
  "author": {
6
6
  "name": "ppravdin"
7
7
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "patchcord",
3
- "version": "0.5.4",
3
+ "version": "0.5.6",
4
4
  "description": "Cross-machine agent messaging for Claude Code and Codex",
5
5
  "author": "ppravdin",
6
6
  "license": "MIT",
@@ -70,7 +70,7 @@ if [ -n "$pc_url" ] && [ -n "$pc_token" ]; then
70
70
  fi
71
71
 
72
72
  if $needs_refresh; then
73
- http_code=$(curl -s -o /tmp/claude/patchcord-sl-resp.json -w "%{http_code}" --max-time 3 \
73
+ http_code=$(curl -s -o /tmp/claude/patchcord-sl-resp.json -w "%{http_code}" --max-time 5 \
74
74
  -H "Authorization: Bearer $pc_token" \
75
75
  "${pc_url}/api/inbox?status=pending&limit=50" 2>/dev/null || echo "000")
76
76
  if [ "$http_code" = "401" ] || [ "$http_code" = "403" ]; then
@@ -79,6 +79,14 @@ if [ -n "$pc_url" ] && [ -n "$pc_token" ]; then
79
79
  elif [ "$http_code" = "200" ]; then
80
80
  pc_data=$(cat /tmp/claude/patchcord-sl-resp.json 2>/dev/null)
81
81
  [ -n "$pc_data" ] && echo "$pc_data" > "$cache_file"
82
+ # Touch cache mtime even on success so the next miss starts fresh
83
+ else
84
+ # Refresh failed (timeout, 5xx, network blip). Fall back to the
85
+ # cached response if we have one, even if it's older than
86
+ # cache_max_age — better to show stale identity than nothing.
87
+ if [ -z "$pc_data" ] && [ -f "$cache_file" ]; then
88
+ pc_data=$(cat "$cache_file" 2>/dev/null)
89
+ fi
82
90
  fi
83
91
  rm -f /tmp/claude/patchcord-sl-resp.json
84
92
  fi
@@ -102,6 +102,27 @@ async function fetchTicket(baseUrl, token) {
102
102
  }
103
103
  }
104
104
 
105
+ // Check if there are messages already pending in the inbox at the moment
106
+ // we connect (or reconnect). Realtime only delivers FUTURE INSERTs, so
107
+ // anything queued before we joined is invisible until the agent calls
108
+ // inbox() manually. Emit a stdout line when there's a pending queue so
109
+ // Monitor wakes the agent the same way a real arrival does.
110
+ async function drainQueueOnce(baseUrl, token) {
111
+ const res = await httpJson(`${baseUrl}/api/inbox?count_only=1&limit=100`, {
112
+ headers: { Authorization: `Bearer ${token}` },
113
+ });
114
+ if (res.status !== 200) {
115
+ throw new Error(`inbox HTTP ${res.status}`);
116
+ }
117
+ let count = 0;
118
+ try {
119
+ count = JSON.parse(res.body).pending_count ?? 0;
120
+ } catch (_) {}
121
+ if (count > 0) {
122
+ process.stdout.write(`PATCHCORD: ${count} waiting in inbox\n`);
123
+ }
124
+ }
125
+
105
126
  function writePidfile(path) {
106
127
  try {
107
128
  writeFileSync(path, String(process.pid), { flag: "wx" });
@@ -233,6 +254,16 @@ function runOnce(ticket, baseUrl, token, refreshTicket) {
233
254
  })
234
255
  );
235
256
  }
257
+
258
+ // Drain any messages already in the queue when we connected.
259
+ // Realtime only delivers FUTURE INSERTs — anything pending before
260
+ // we joined (or that arrived during a reconnect gap) wouldn't
261
+ // otherwise wake the agent. Fire-and-forget: a transient HTTP
262
+ // failure here just means we miss queued messages this round;
263
+ // the next reconnect retries.
264
+ drainQueueOnce(baseUrl, token).catch((e) => {
265
+ process.stderr.write(`subscribe: queue check failed: ${e.message}\n`);
266
+ });
236
267
  heartbeatTimer = setInterval(() => {
237
268
  try {
238
269
  ws.send(