patchcord 0.3.71 → 0.3.73
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 +56 -2
- package/package.json +1 -1
- package/skills/codex/SKILL.md +6 -1
- package/skills/inbox/SKILL.md +6 -10
- package/skills/web/SKILL.md +7 -3
package/bin/patchcord.mjs
CHANGED
|
@@ -321,8 +321,61 @@ if (!cmd || cmd === "install" || cmd === "agent" || cmd === "--token" || cmd ===
|
|
|
321
321
|
}
|
|
322
322
|
rl.close();
|
|
323
323
|
} else {
|
|
324
|
+
// Check if patchcord is already configured — offer to update URL without re-auth
|
|
325
|
+
let existingToken = "";
|
|
326
|
+
let existingConfigFile = "";
|
|
327
|
+
const mcpJsonPath = join(cwd, ".mcp.json");
|
|
328
|
+
const codexTomlPath = join(cwd, ".codex", "config.toml");
|
|
329
|
+
if (existsSync(mcpJsonPath)) {
|
|
330
|
+
try {
|
|
331
|
+
const existing = JSON.parse(readFileSync(mcpJsonPath, "utf-8"));
|
|
332
|
+
const pt = existing?.mcpServers?.patchcord;
|
|
333
|
+
if (pt?.headers?.Authorization) {
|
|
334
|
+
existingToken = pt.headers.Authorization.replace(/^Bearer\s+/i, "");
|
|
335
|
+
existingConfigFile = mcpJsonPath;
|
|
336
|
+
}
|
|
337
|
+
} catch {}
|
|
338
|
+
}
|
|
339
|
+
if (!existingToken && existsSync(codexTomlPath)) {
|
|
340
|
+
try {
|
|
341
|
+
const content = readFileSync(codexTomlPath, "utf-8");
|
|
342
|
+
const match = content.match(/Bearer\s+([^\s"]+)/);
|
|
343
|
+
if (match) {
|
|
344
|
+
existingToken = match[1];
|
|
345
|
+
existingConfigFile = codexTomlPath;
|
|
346
|
+
}
|
|
347
|
+
} catch {}
|
|
348
|
+
}
|
|
349
|
+
if (existingToken) {
|
|
350
|
+
console.log(`\n ${dim}Existing patchcord token found in ${existingConfigFile}${r}`);
|
|
351
|
+
const { createInterface: createRLU } = await import("readline");
|
|
352
|
+
const rlU = createRLU({ input: process.stdin, output: process.stdout });
|
|
353
|
+
const askU = (q) => new Promise((resolve) => rlU.question(q, resolve));
|
|
354
|
+
const answer = (await askU(` ${bold}Update config and keep existing token? (Y/n):${r} `)).trim().toLowerCase();
|
|
355
|
+
rlU.close();
|
|
356
|
+
if (answer !== "n" && answer !== "no") {
|
|
357
|
+
token = existingToken;
|
|
358
|
+
// Validate existing token
|
|
359
|
+
const validateResp = run(`curl -sf --max-time 5 -H "Authorization: Bearer ${token}" "${serverUrl}/api/inbox?limit=0&count_only=1"`);
|
|
360
|
+
if (validateResp) {
|
|
361
|
+
try {
|
|
362
|
+
const data = JSON.parse(validateResp);
|
|
363
|
+
identity = `${data.agent_id}@${data.namespace_id}`;
|
|
364
|
+
clientType = data.client_type || "";
|
|
365
|
+
choice = CLIENT_TYPE_MAP[clientType] || "";
|
|
366
|
+
console.log(` ${green}✓${r} ${bold}${identity}${r} — token valid`);
|
|
367
|
+
} catch {}
|
|
368
|
+
}
|
|
369
|
+
if (!identity) {
|
|
370
|
+
console.log(` ${yellow}⚠${r} Token expired or invalid. Starting fresh setup.`);
|
|
371
|
+
token = "";
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
if (!token) {
|
|
324
377
|
// Browser connect flow
|
|
325
|
-
rl.close();
|
|
378
|
+
if (rl) rl.close();
|
|
326
379
|
|
|
327
380
|
function canOpenBrowser() {
|
|
328
381
|
if (process.env.SSH_CLIENT || process.env.SSH_TTY) return false;
|
|
@@ -475,7 +528,8 @@ if (!cmd || cmd === "install" || cmd === "agent" || cmd === "--token" || cmd ===
|
|
|
475
528
|
}
|
|
476
529
|
}
|
|
477
530
|
}
|
|
478
|
-
}
|
|
531
|
+
} // end connect flow
|
|
532
|
+
} // end if (!token)
|
|
479
533
|
|
|
480
534
|
const isCodex = choice === "2";
|
|
481
535
|
const isCursor = choice === "3";
|
package/package.json
CHANGED
package/skills/codex/SKILL.md
CHANGED
|
@@ -65,9 +65,14 @@ If send_message fails with a send gate error: call inbox(), reply to or resolve
|
|
|
65
65
|
|
|
66
66
|
1. Read the message from `inbox()` or `wait_for_message()`
|
|
67
67
|
2. Do the work - use real code, real files, real results from your project
|
|
68
|
-
3.
|
|
68
|
+
3. Reply with the right flag:
|
|
69
|
+
- `reply(message_id, "done: [details]")` — work done, sender might follow up
|
|
70
|
+
- `reply(message_id, "done: [details]", resolve=true)` — work done, conversation finished
|
|
71
|
+
- `reply(message_id, "ack, prioritizing [other task] first", defer=true)` — acknowledged but work not done yet. Message stays in your inbox as a reminder.
|
|
69
72
|
4. If sender is online: `wait_for_message()` for follow-ups
|
|
70
73
|
|
|
74
|
+
When you have multiple pending messages, prioritize by urgency. Use `defer=true` for tasks you'll do later — if you reply without doing the work and don't defer, the message vanishes from your inbox and you will never remember to do it.
|
|
75
|
+
|
|
71
76
|
## Cross-user messaging (Gate)
|
|
72
77
|
|
|
73
78
|
To message a user outside your namespace, use `@username` as the to_agent. Example: `send_message("@maria", "hello")`. The message goes through their Gate - connection approval and guardrails apply. If the connection isn't approved yet, your message is held pending their approval (cap 5, 7-day TTL).
|
package/skills/inbox/SKILL.md
CHANGED
|
@@ -52,23 +52,19 @@ If send_message fails with a send gate error: call inbox(), reply to or resolve
|
|
|
52
52
|
|
|
53
53
|
1. Read the message
|
|
54
54
|
2. Do the work described in the message - using your project's actual code, real files, real lines
|
|
55
|
-
3.
|
|
55
|
+
3. Reply with what you did, choosing the right flag:
|
|
56
|
+
- `reply(message_id, "done: [details]")` — work done, sender might follow up
|
|
57
|
+
- `reply(message_id, "done: [details]", resolve=true)` — work done, conversation finished. Notifies the sender.
|
|
58
|
+
- `reply(message_id, "ack, prioritizing [other task] first", defer=true)` — you acknowledged but haven't done the work yet. The message stays in your inbox as a reminder.
|
|
56
59
|
4. wait_for_message() if the sender is online - stay responsive for follow-ups
|
|
57
60
|
5. If you can't do the work, say specifically what's blocking you. Don't guess about another agent's code.
|
|
58
61
|
|
|
62
|
+
When you have multiple pending messages, prioritize by urgency. Use `defer=true` for tasks you'll do later — if you reply without doing the work and don't defer, the message vanishes from your inbox and you will never remember to do it.
|
|
63
|
+
|
|
59
64
|
## Cross-user messaging (Gate)
|
|
60
65
|
|
|
61
66
|
To message a user outside your namespace, use `@username` as the to_agent. Example: `send_message("@maria", "hello")`. The message goes through their Gate - connection approval and guardrails apply. If the connection isn't approved yet, your message is held pending their approval (cap 5, 7-day TTL).
|
|
62
67
|
|
|
63
|
-
## Deferred messages
|
|
64
|
-
|
|
65
|
-
reply(message_id, content, defer=true) sends a reply but keeps the original message visible in the inbox as "deferred". Use this when:
|
|
66
|
-
- The message needs attention from another agent or a later session
|
|
67
|
-
- You want to acknowledge receipt but can't fully handle it now
|
|
68
|
-
- The human says to mark/defer something for later
|
|
69
|
-
|
|
70
|
-
Deferred messages survive context compaction - the agent won't forget them.
|
|
71
|
-
|
|
72
68
|
## File sharing
|
|
73
69
|
|
|
74
70
|
Three modes, choose based on context:
|
package/skills/web/SKILL.md
CHANGED
|
@@ -73,10 +73,14 @@ After sending to an offline agent, tell the human: "Message sent. [agent] is not
|
|
|
73
73
|
|
|
74
74
|
1. Read messages from inbox()
|
|
75
75
|
2. Check the context tag - is this for your chat?
|
|
76
|
-
3. If yes:
|
|
76
|
+
3. If yes: do the work, then reply with the right flag:
|
|
77
|
+
- `reply(message_id, "[tag] done: [details]")` — work done, sender might follow up
|
|
78
|
+
- `reply(message_id, "[tag] done", resolve=true)` — work done, conversation finished
|
|
79
|
+
- `reply(message_id, "[tag] ack, will do after [other task]", defer=true)` — acknowledged but work not done yet. Message stays in inbox.
|
|
77
80
|
4. If no: reply(message_id, "For [other-tag] chat", defer=true)
|
|
78
|
-
5.
|
|
79
|
-
|
|
81
|
+
5. wait_for_message() - stay responsive for follow-ups
|
|
82
|
+
|
|
83
|
+
When you have multiple pending messages, prioritize by urgency. Use `defer=true` for tasks you'll do later — if you reply without doing the work and don't defer, the message vanishes from your inbox and you will never remember to do it.
|
|
80
84
|
|
|
81
85
|
## File sharing
|
|
82
86
|
|