patchcord 0.5.57 → 0.5.59
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/bin/patchcord.mjs +62 -1
- package/package.json +1 -1
- package/per-project-skills/codex/SKILL.md +9 -12
- package/skills/inbox/SKILL.md +10 -13
package/bin/patchcord.mjs
CHANGED
|
@@ -78,6 +78,7 @@ Usage:
|
|
|
78
78
|
patchcord whoami --propose "<text>" Update your whoami (two-shot: first call asks you to show human, second call applies)
|
|
79
79
|
patchcord agents List every agent (with whoami)
|
|
80
80
|
patchcord agents <name> Show one agent's whoami
|
|
81
|
+
patchcord upload <file> [--mime <type>] [--as <name>] Upload a file as a patchcord attachment (prints the storage path)
|
|
81
82
|
patchcord subscribe Start the realtime listener
|
|
82
83
|
patchcord update Update to the latest version
|
|
83
84
|
patchcord --version Show installed version
|
|
@@ -390,6 +391,66 @@ if (cmd === "agents") {
|
|
|
390
391
|
process.exit(0);
|
|
391
392
|
}
|
|
392
393
|
|
|
394
|
+
// ── upload <file> [--mime <type>] [--as <filename>] ───────────
|
|
395
|
+
// Inline-upload an attachment to patchcord storage. Wraps what would
|
|
396
|
+
// otherwise be a base64-and-curl dance. Prints the storage path on
|
|
397
|
+
// success so the user can pipe it into send_message.
|
|
398
|
+
if (cmd === "upload") {
|
|
399
|
+
const args = process.argv.slice(3);
|
|
400
|
+
const filePath = (args[0] || "").trim();
|
|
401
|
+
if (!filePath) {
|
|
402
|
+
console.error("Usage: patchcord upload <file> [--mime <type>] [--as <filename>]");
|
|
403
|
+
process.exit(1);
|
|
404
|
+
}
|
|
405
|
+
if (!existsSync(filePath)) {
|
|
406
|
+
console.error(`file not found: ${filePath}`);
|
|
407
|
+
process.exit(1);
|
|
408
|
+
}
|
|
409
|
+
const mimeIdx = args.indexOf("--mime");
|
|
410
|
+
const mime = mimeIdx !== -1 ? (args[mimeIdx + 1] || "").trim() : "";
|
|
411
|
+
const asIdx = args.indexOf("--as");
|
|
412
|
+
const renameTo = asIdx !== -1 ? (args[asIdx + 1] || "").trim() : "";
|
|
413
|
+
|
|
414
|
+
const found = await _resolveBearer();
|
|
415
|
+
if (!found) {
|
|
416
|
+
console.error("No patchcord config found in current directory or any parent. Run `npx patchcord@latest` from a project directory first.");
|
|
417
|
+
process.exit(1);
|
|
418
|
+
}
|
|
419
|
+
const { token, baseUrl } = found;
|
|
420
|
+
if (!isSafeToken(token) || !isSafeUrl(baseUrl)) {
|
|
421
|
+
console.error(`Invalid patchcord URL or token in config.`);
|
|
422
|
+
process.exit(1);
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
const { readFileSync, statSync } = await import("fs");
|
|
426
|
+
const stats = statSync(filePath);
|
|
427
|
+
if (stats.size === 0) {
|
|
428
|
+
console.error(`file is empty: ${filePath}`);
|
|
429
|
+
process.exit(1);
|
|
430
|
+
}
|
|
431
|
+
if (stats.size > 25 * 1024 * 1024) {
|
|
432
|
+
console.error(`file is ${(stats.size / 1024 / 1024).toFixed(1)}MB; max is 25MB for inline upload.`);
|
|
433
|
+
process.exit(1);
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
const data = readFileSync(filePath);
|
|
437
|
+
const content_b64 = data.toString("base64");
|
|
438
|
+
const filename = renameTo || basename(filePath);
|
|
439
|
+
|
|
440
|
+
const body = { filename, content_b64 };
|
|
441
|
+
if (mime) body.mime_type = mime;
|
|
442
|
+
|
|
443
|
+
const { status, json, body: respBody } = await _httpJSON(
|
|
444
|
+
"POST", `${baseUrl}/api/agent/attachment/upload`, token, body
|
|
445
|
+
);
|
|
446
|
+
if (status !== "200") {
|
|
447
|
+
console.error(`✗ HTTP ${status}: ${(json && json.error) || respBody}`);
|
|
448
|
+
process.exit(1);
|
|
449
|
+
}
|
|
450
|
+
console.log(json.path);
|
|
451
|
+
process.exit(0);
|
|
452
|
+
}
|
|
453
|
+
|
|
393
454
|
// ── subscribe ─────────────────────────────────────────────────
|
|
394
455
|
// Thin wrapper around scripts/subscribe.mjs so users see a clean
|
|
395
456
|
// "npx patchcord subscribe" in their Claude Code tool log instead
|
|
@@ -1929,5 +1990,5 @@ if (cmd === "skill") {
|
|
|
1929
1990
|
process.exit(0);
|
|
1930
1991
|
}
|
|
1931
1992
|
|
|
1932
|
-
console.error(`Unknown command: ${cmd}. Available: whoami, agents, subscribe, update, --rename, --token, --agent-type, --version, --help`);
|
|
1993
|
+
console.error(`Unknown command: ${cmd}. Available: whoami, agents, upload, subscribe, update, --rename, --token, --agent-type, --version, --help`);
|
|
1933
1994
|
process.exit(1);
|
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/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
|
|