patchcord 0.5.114 → 0.5.116
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
CHANGED
|
@@ -97,6 +97,9 @@ TEAMLEAD — set up the team-lead agent (the shepherd) in this folder
|
|
|
97
97
|
TEAM — the teamlead's tools (run from the project root)
|
|
98
98
|
patchcord provision <agent> --tool <X> --role <Y> --namespace <ns> [--dir <sub/>]
|
|
99
99
|
Create a worker agent (identity + config)
|
|
100
|
+
patchcord pull <agent> --tool <X> --namespace <ns> [--dir <sub/>]
|
|
101
|
+
Place an EXISTING agent into a folder
|
|
102
|
+
(same identity, new token; nothing overwritten)
|
|
100
103
|
patchcord provision revoke <agent> --namespace <ns>
|
|
101
104
|
patchcord team list [--namespace <ns>] Provisioned agents (server view, deduped)
|
|
102
105
|
patchcord team status Reconcile folder ↔ identity ↔ tmux ↔ token
|
|
@@ -829,7 +832,7 @@ if (cmd === "subscribe") {
|
|
|
829
832
|
// account token (user-level, tied to NO agent) lives at ~/.patchcord/auth.json
|
|
830
833
|
// (legacy: main.json / master.json) or $PATCHCORD_TOKEN (legacy: *_MAIN/MASTER).
|
|
831
834
|
// `patchcord login` authenticates; everything else logs in on demand.
|
|
832
|
-
if (cmd === "login" || cmd === "teamlead" || cmd === "provision" || cmd === "team" || cmd === "schedule") {
|
|
835
|
+
if (cmd === "login" || cmd === "teamlead" || cmd === "provision" || cmd === "pull" || cmd === "team" || cmd === "schedule") {
|
|
833
836
|
const M = { cyan: "\x1b[36m", green: "\x1b[32m", dim: "\x1b[2m", rst: "\x1b[0m" };
|
|
834
837
|
const AUTH_CONFIG = join(HOME, ".patchcord", "auth.json");
|
|
835
838
|
const LEGACY_CONFIGS = [join(HOME, ".patchcord", "main.json"), join(HOME, ".patchcord", "master.json")];
|
|
@@ -1010,6 +1013,39 @@ if (cmd === "login" || cmd === "teamlead" || cmd === "provision" || cmd === "tea
|
|
|
1010
1013
|
process.exit(0);
|
|
1011
1014
|
}
|
|
1012
1015
|
|
|
1016
|
+
if (cmd === "pull") {
|
|
1017
|
+
// Inverse of provision: place an EXISTING agent identity into a folder.
|
|
1018
|
+
// Mints another token bound to the same agent_id@namespace (its original
|
|
1019
|
+
// token is hashed server-side and unrecoverable, so we can't return the
|
|
1020
|
+
// literal one — but the identity is the same). Nothing is overwritten; the
|
|
1021
|
+
// agent can now run from this folder too.
|
|
1022
|
+
const arg = process.argv[3];
|
|
1023
|
+
if (!arg || arg.startsWith("-")) { console.error("Usage: patchcord pull <agent> --namespace ns --tool X [--dir sub/]"); process.exit(1); }
|
|
1024
|
+
const tool = flagVal("tool", "claude_code");
|
|
1025
|
+
const ns = flagVal("namespace");
|
|
1026
|
+
const subdir = flagVal("dir", arg);
|
|
1027
|
+
if (!ns) { console.error("--namespace <project-namespace> required"); process.exit(1); }
|
|
1028
|
+
const { status, json, m } = await accountCall("POST", "/api/provision", { namespace_id: ns, agent_id: arg, tool, require_existing: true, label: `pull:${tool}` });
|
|
1029
|
+
if (status === "404") { console.error(`no agent ${M.green}${ns}:${arg}${M.rst} to pull — create it with: patchcord provision ${arg} --tool ${tool} --namespace ${ns}`); process.exit(1); }
|
|
1030
|
+
if (status !== "200" || !json?.token) { console.error(`pull failed (HTTP ${status}): ${json?.error || ""}`); process.exit(1); }
|
|
1031
|
+
const base = String(json.url || `${m.baseUrl}/mcp`).replace(/\/mcp$/, "");
|
|
1032
|
+
const dir = join(process.cwd(), subdir);
|
|
1033
|
+
const hostname = run("hostname -s") || run("hostname") || "unknown";
|
|
1034
|
+
writeWorkerConfig(tool, dir, base, json.token, hostname);
|
|
1035
|
+
// Record in the local team manifest so `team launch` / `team status` see it.
|
|
1036
|
+
try {
|
|
1037
|
+
const tj = join(process.cwd(), ".patchcord", "team.json");
|
|
1038
|
+
if (existsSync(tj)) {
|
|
1039
|
+
const man = JSON.parse(readFileSync(tj, "utf-8"));
|
|
1040
|
+
man.agents = (man.agents || []).filter((a) => a.agent !== arg);
|
|
1041
|
+
man.agents.push({ agent: arg, tool, dir: subdir, namespace: ns });
|
|
1042
|
+
writeFileSync(tj, JSON.stringify(man, null, 2) + "\n");
|
|
1043
|
+
}
|
|
1044
|
+
} catch {}
|
|
1045
|
+
console.log(`✓ pulled ${M.green}${ns}:${arg}${M.rst} [${tool}] → ${dir}`);
|
|
1046
|
+
process.exit(0);
|
|
1047
|
+
}
|
|
1048
|
+
|
|
1013
1049
|
if (cmd === "teamlead") {
|
|
1014
1050
|
// Set up the TEAMLEAD agent in THIS folder. The teamlead is a distinct kind
|
|
1015
1051
|
// of agent — it shepherds a team: provisions, connects, and manages the
|
|
@@ -1628,6 +1664,27 @@ if (!cmd || cmd === "install" || cmd === "agent" || cmd?.startsWith("--")) {
|
|
|
1628
1664
|
}
|
|
1629
1665
|
}
|
|
1630
1666
|
|
|
1667
|
+
// Hermes — refresh patchcord skills to the current version on every run, so
|
|
1668
|
+
// skill fixes land via `patchcord update` (the interactive choice 13 only
|
|
1669
|
+
// installs them once). ~/.hermes/skills is Hermes-only, so no leak risk; only
|
|
1670
|
+
// refresh when the integrations dir already exists (Hermes was set up before).
|
|
1671
|
+
{
|
|
1672
|
+
const hermesSkillsSrc = join(pluginRoot, "per-project-skills", "hermes");
|
|
1673
|
+
const hermesSkillsDest = join(HOME, ".hermes", "skills", "integrations");
|
|
1674
|
+
if (existsSync(hermesSkillsDest) && existsSync(hermesSkillsSrc)) {
|
|
1675
|
+
let hermesChanged = false;
|
|
1676
|
+
for (const name of readdirSync(hermesSkillsSrc)) {
|
|
1677
|
+
const src = join(hermesSkillsSrc, name, "SKILL.md");
|
|
1678
|
+
if (!existsSync(src)) continue;
|
|
1679
|
+
const dest = join(hermesSkillsDest, name, "SKILL.md");
|
|
1680
|
+
const want = readFileSync(src, "utf-8");
|
|
1681
|
+
let cur = ""; try { cur = readFileSync(dest, "utf-8"); } catch {}
|
|
1682
|
+
if (cur !== want) { mkdirSync(dirname(dest), { recursive: true }); writeFileSync(dest, want); hermesChanged = true; }
|
|
1683
|
+
}
|
|
1684
|
+
if (hermesChanged) globalChanges.push("Hermes patchcord skills refreshed");
|
|
1685
|
+
}
|
|
1686
|
+
}
|
|
1687
|
+
|
|
1631
1688
|
// Kimi CLI
|
|
1632
1689
|
const hasKimi = run("which kimi");
|
|
1633
1690
|
if (hasKimi) {
|
|
@@ -2956,5 +3013,5 @@ if (cmd === "skill") {
|
|
|
2956
3013
|
process.exit(0);
|
|
2957
3014
|
}
|
|
2958
3015
|
|
|
2959
|
-
console.error(`Unknown command: ${cmd}. Available: install, whoami, agents, upload, subscribe, update, login, provision, teamlead, team, schedule, --rename, --token, --agent-type, --version, --help`);
|
|
3016
|
+
console.error(`Unknown command: ${cmd}. Available: install, whoami, agents, upload, subscribe, update, login, provision, pull, teamlead, team, schedule, --rename, --token, --agent-type, --version, --help`);
|
|
2960
3017
|
process.exit(1);
|
package/package.json
CHANGED
|
@@ -9,6 +9,8 @@ metadata:
|
|
|
9
9
|
---
|
|
10
10
|
# Patchcord — inbox
|
|
11
11
|
|
|
12
|
+
Applies only when the patchcord MCP tools (`mcp_patchcord_*`) are available this session. If they are not, do nothing — do not run the CLI as a substitute, do not read a bearer token from a config file, do not call the API directly, and do not web-search for setup. Just proceed with the user's request.
|
|
13
|
+
|
|
12
14
|
## When to use
|
|
13
15
|
The user mentions patchcord / other agents / checking messages, or a Patchcord webhook fired ("new Patchcord messages").
|
|
14
16
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: patchcord-subscribe
|
|
3
|
-
description:
|
|
4
|
-
version:
|
|
3
|
+
description: Real-time Patchcord delivery options for Hermes. Hermes has no in-session listener, so this starts nothing in-turn — it drains the inbox and tells the human the optional one-time push setup.
|
|
4
|
+
version: 2.0.0
|
|
5
5
|
platforms: [macos, linux]
|
|
6
6
|
metadata:
|
|
7
7
|
hermes:
|
|
@@ -10,21 +10,19 @@ metadata:
|
|
|
10
10
|
---
|
|
11
11
|
# Patchcord — subscribe (real-time)
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
gateway webhook plus the patchcord bridge: the bridge holds one realtime
|
|
15
|
-
connection and POSTs to a Hermes webhook on each new message, and the always-on
|
|
16
|
-
gateway injects a prompt that wakes the agent. No re-arm.
|
|
13
|
+
Applies only when the patchcord MCP tools (`mcp_patchcord_*`) are available this session. If they are not, do nothing — do not run the CLI, do not read tokens from config files, do not call the API directly.
|
|
17
14
|
|
|
18
|
-
|
|
19
|
-
1. Register a webhook route on the gateway:
|
|
20
|
-
`hermes webhook subscribe patchcord --prompt "You have new Patchcord messages. Run /patchcord-inbox now."`
|
|
21
|
-
Note the route URL it prints (e.g. `https://<gateway-host>/webhooks/patchcord`).
|
|
22
|
-
2. Start the bridge under the gateway/tmux/systemd:
|
|
23
|
-
`PATCHCORD_HERMES_WEBHOOK=<route-url> patchcord subscribe --hermes`
|
|
24
|
-
It self-reconnects and survives JWT cycles — leave it running.
|
|
15
|
+
**Hermes has no per-turn background-listener tool. There is nothing to start in this turn.** Do NOT web-search, do NOT fetch docs, do NOT guess or invent `hermes ...` commands.
|
|
25
16
|
|
|
26
|
-
|
|
27
|
-
|
|
17
|
+
When invoked, do exactly this and stop:
|
|
18
|
+
1. Run the **patchcord-inbox** skill now (drain anything pending).
|
|
19
|
+
2. Tell the human: "Hermes can't hold a live listener — I'll check the inbox at the start of each session. For push delivery there's a one-time bridge the human sets up; want the steps?"
|
|
20
|
+
3. Do not configure anything yourself.
|
|
28
21
|
|
|
29
|
-
##
|
|
30
|
-
|
|
22
|
+
## One-time push setup (the HUMAN runs this, only if they ask)
|
|
23
|
+
Real-time needs the patchcord bridge holding one realtime connection and POSTing to a Hermes webhook the human controls. Hand these to the human — never run them or invent command names yourself:
|
|
24
|
+
- In Hermes, create a webhook route that, when it fires, injects the prompt: `You have new Patchcord messages. Run /patchcord-inbox now.` (Use whatever the installed Hermes version calls this — the human knows their CLI.)
|
|
25
|
+
- Start the bridge pointed at that route URL and leave it running:
|
|
26
|
+
`PATCHCORD_HERMES_WEBHOOK=<route-url> patchcord subscribe --hermes`
|
|
27
|
+
|
|
28
|
+
Once the bridge runs, each new message fires the webhook → the gateway wakes the agent → run **patchcord-inbox**. If the human doesn't want the bridge, checking inbox at session start is the whole feature — that's fine.
|
|
@@ -9,6 +9,8 @@ metadata:
|
|
|
9
9
|
---
|
|
10
10
|
# Patchcord — wait
|
|
11
11
|
|
|
12
|
+
Applies only when the patchcord MCP tools (`mcp_patchcord_*`) are available this session. If they are not, do nothing — do not run the CLI, read tokens from config files, call the API directly, or web-search for setup. Proceed with the user's request.
|
|
13
|
+
|
|
12
14
|
## When to use
|
|
13
15
|
You sent a message and expect a reply, or the user asks you to wait for an incoming Patchcord message.
|
|
14
16
|
|