patchcord 0.5.58 → 0.5.60
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/package.json +1 -1
- package/per-project-skills/codex/SKILL.md +9 -12
- package/scripts/subscribe.mjs +21 -0
- package/skills/inbox/SKILL.md +10 -13
package/package.json
CHANGED
|
@@ -95,33 +95,30 @@ To message a user outside your namespace, use `@username` as the to_agent. Examp
|
|
|
95
95
|
|
|
96
96
|
## File sharing
|
|
97
97
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
**Relay from URL (preferred for public files):**
|
|
98
|
+
**Files on disk → `patchcord upload` (CLI, preferred):**
|
|
101
99
|
```
|
|
102
|
-
|
|
100
|
+
patchcord upload /path/to/report.md --mime text/markdown
|
|
103
101
|
```
|
|
104
|
-
|
|
102
|
+
Prints the storage path. Pass it to `send_message`. No curl, no base64 in chat. 25MB cap.
|
|
105
103
|
|
|
106
|
-
**
|
|
104
|
+
**Public URLs → `attachment(relay=true, ...)`:**
|
|
107
105
|
```
|
|
108
|
-
attachment(
|
|
109
|
-
curl -X PUT -H "Content-Type: text/markdown" --data-binary @/path/to/report.md "<url>"
|
|
106
|
+
attachment(relay=true, path_or_url="https://example.com/file.md", filename="file.md")
|
|
110
107
|
```
|
|
111
|
-
|
|
108
|
+
Server fetches and stores. Use when the file already lives at a public URL.
|
|
112
109
|
|
|
113
|
-
**Inline base64
|
|
110
|
+
**Inline base64 last resort:**
|
|
114
111
|
```
|
|
115
112
|
attachment(upload=true, filename="notes.txt", file_data="<base64>")
|
|
116
113
|
```
|
|
117
|
-
|
|
114
|
+
Only if you cannot run shell commands. Wastes context tokens.
|
|
118
115
|
|
|
119
116
|
**Downloading:**
|
|
120
117
|
```
|
|
121
118
|
attachment(path_or_url="namespace/agent/timestamp_file.md")
|
|
122
119
|
```
|
|
123
120
|
|
|
124
|
-
|
|
121
|
+
Always send the storage path (not file content) to the other agent.
|
|
125
122
|
|
|
126
123
|
## Rules
|
|
127
124
|
|
package/scripts/subscribe.mjs
CHANGED
|
@@ -22,6 +22,11 @@ const RECONNECT_BACKOFF_MS = [1000, 2000, 4000, 8000, 15_000, 30_000];
|
|
|
22
22
|
// gap means three missed heartbeats. Force a reconnect via the outer loop.
|
|
23
23
|
const FRESHNESS_CHECK_INTERVAL_MS = 30_000;
|
|
24
24
|
const FRESHNESS_STALE_MS = 90_000;
|
|
25
|
+
// Re-emit pending count every minute as a safety net. The Realtime push
|
|
26
|
+
// + Monitor pipeline can drop notifications when an agent is mid-tool-call
|
|
27
|
+
// (especially for long-running work like vector-DB searches). Re-emitting
|
|
28
|
+
// gives Monitor multiple chances to surface the line on a later idle tick.
|
|
29
|
+
const PENDING_HEARTBEAT_MS = 60_000;
|
|
25
30
|
|
|
26
31
|
// Short HH:MM:SS prefix so the Monitor output can be scanned at a glance.
|
|
27
32
|
// Local time — Monitor's reader is always a human looking at one machine.
|
|
@@ -243,6 +248,7 @@ function runOnce(ticket, baseUrl, token, refreshTicket) {
|
|
|
243
248
|
let heartbeatTimer = null;
|
|
244
249
|
let refreshTimer = null;
|
|
245
250
|
let freshnessTimer = null;
|
|
251
|
+
let pendingHeartbeatTimer = null;
|
|
246
252
|
let lastEventAt = Date.now();
|
|
247
253
|
let currentJwt = ticket.jwt;
|
|
248
254
|
let settled = false;
|
|
@@ -253,6 +259,7 @@ function runOnce(ticket, baseUrl, token, refreshTicket) {
|
|
|
253
259
|
if (heartbeatTimer) clearInterval(heartbeatTimer);
|
|
254
260
|
if (refreshTimer) clearTimeout(refreshTimer);
|
|
255
261
|
if (freshnessTimer) clearInterval(freshnessTimer);
|
|
262
|
+
if (pendingHeartbeatTimer) clearInterval(pendingHeartbeatTimer);
|
|
256
263
|
try {
|
|
257
264
|
ws.close();
|
|
258
265
|
} catch (_) {}
|
|
@@ -311,6 +318,20 @@ function runOnce(ticket, baseUrl, token, refreshTicket) {
|
|
|
311
318
|
}
|
|
312
319
|
}, FRESHNESS_CHECK_INTERVAL_MS);
|
|
313
320
|
|
|
321
|
+
// Pending-inbox heartbeat. The Realtime INSERT push that triggers the
|
|
322
|
+
// initial "PATCHCORD: 1 new from <sender>" notification can be lost
|
|
323
|
+
// by the Monitor → agent-context surface layer if the agent happens
|
|
324
|
+
// to be mid-tool-call when the line is emitted (heavy agents with
|
|
325
|
+
// long tool calls — vector-DB search, CrossRef lookups — are most
|
|
326
|
+
// exposed). Re-emit the pending count once a minute as long as the
|
|
327
|
+
// inbox is non-empty so a later idle tick has another chance to
|
|
328
|
+
// wake the agent. drainQueueOnce stays silent if pending_count == 0.
|
|
329
|
+
pendingHeartbeatTimer = setInterval(() => {
|
|
330
|
+
drainQueueOnce(baseUrl, token).catch((e) => {
|
|
331
|
+
logErr(`subscribe: pending heartbeat failed: ${e.message}`);
|
|
332
|
+
});
|
|
333
|
+
}, PENDING_HEARTBEAT_MS);
|
|
334
|
+
|
|
314
335
|
const scheduleRefresh = (ttlSec) => {
|
|
315
336
|
const refreshIn = Math.max((ttlSec - JWT_REFRESH_SAFETY_MARGIN_SEC) * 1000, 30_000);
|
|
316
337
|
refreshTimer = setTimeout(doRefresh, refreshIn);
|
package/skills/inbox/SKILL.md
CHANGED
|
@@ -83,34 +83,31 @@ To message a user outside your namespace, use `@username` as the to_agent. Examp
|
|
|
83
83
|
|
|
84
84
|
## File sharing
|
|
85
85
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
**Relay from URL (preferred for public files):**
|
|
86
|
+
**Files on disk → `patchcord upload` (CLI, preferred):**
|
|
89
87
|
```
|
|
90
|
-
|
|
88
|
+
patchcord upload /path/to/report.md --mime text/markdown
|
|
91
89
|
```
|
|
92
|
-
|
|
90
|
+
Prints the storage path. Pass that path to `send_message`. No curl, no base64 in chat, no presigned URLs. 25MB cap.
|
|
93
91
|
|
|
94
|
-
**
|
|
92
|
+
**Public URLs → `attachment(relay=true, ...)`:**
|
|
95
93
|
```
|
|
96
|
-
attachment(
|
|
97
|
-
curl -X PUT -H "Content-Type: text/markdown" --data-binary @/path/to/report.md "<url>"
|
|
94
|
+
attachment(relay=true, path_or_url="https://example.com/file.md", filename="file.md")
|
|
98
95
|
```
|
|
99
|
-
|
|
96
|
+
Server fetches the URL and stores it. Use when the file already lives at a public URL.
|
|
100
97
|
|
|
101
|
-
**
|
|
98
|
+
**Web agents (no shell) → inline base64 last resort:**
|
|
102
99
|
```
|
|
103
100
|
attachment(upload=true, filename="notes.txt", file_data="<base64>")
|
|
104
101
|
```
|
|
105
|
-
|
|
102
|
+
Only for agents that cannot run shell commands. Wastes context tokens. Never use if you can run `patchcord upload`.
|
|
106
103
|
|
|
107
104
|
**Downloading:**
|
|
108
105
|
```
|
|
109
106
|
attachment(path_or_url="namespace/agent/timestamp_file.md")
|
|
110
107
|
```
|
|
111
|
-
|
|
108
|
+
Pass the storage path from the sender's message.
|
|
112
109
|
|
|
113
|
-
|
|
110
|
+
Always send the storage path (not the file content) to the other agent.
|
|
114
111
|
|
|
115
112
|
## Identity (`patchcord whoami` / `patchcord agents`)
|
|
116
113
|
|