patchcord 0.5.104 → 0.5.105

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.
Files changed (2) hide show
  1. package/bin/patchcord.mjs +68 -1
  2. package/package.json +1 -1
package/bin/patchcord.mjs CHANGED
@@ -797,7 +797,7 @@ if (cmd === "subscribe") {
797
797
  // (docs/main-agent.md). The "main" is the managing agent of a team; its main
798
798
  // token is a user-scoped provisioning credential stored at ~/.patchcord/main.json
799
799
  // (legacy: master.json) or $PATCHCORD_MAIN_TOKEN (legacy: $PATCHCORD_MASTER_TOKEN).
800
- if (cmd === "main" || cmd === "master" || cmd === "provision" || cmd === "team") {
800
+ if (cmd === "main" || cmd === "master" || cmd === "provision" || cmd === "team" || cmd === "schedule") {
801
801
  const M = { cyan: "\x1b[36m", green: "\x1b[32m", dim: "\x1b[2m", rst: "\x1b[0m" };
802
802
  const MAIN_CONFIG = join(HOME, ".patchcord", "main.json");
803
803
  const LEGACY_CONFIG = join(HOME, ".patchcord", "master.json"); // pre-rename
@@ -1134,6 +1134,73 @@ if (cmd === "main" || cmd === "master" || cmd === "provision" || cmd === "team")
1134
1134
  console.error("Usage: patchcord team <init|list|launch|status>");
1135
1135
  process.exit(1);
1136
1136
  }
1137
+
1138
+ if (cmd === "schedule") {
1139
+ // User-level scheduled / recurring messages (server Plan 041). Authed by
1140
+ // the main token — the user can manage schedules in any namespace they own.
1141
+ const m = requireMain();
1142
+ const sub = process.argv[3];
1143
+ const BASE = `${m.baseUrl}/api/dashboard/scheduled`;
1144
+ const when = (s) => s.cron_expr ? `cron ${s.cron_expr}` : s.interval_sec ? `every ${s.interval_sec}s` : s.fire_at ? `once @ ${s.fire_at}` : s.schedule_kind;
1145
+ const fmt = (s) => `${s.id} ${M.green}${s.namespace_id}:${s.to_agent}${M.rst} ${s.active ? "" : M.dim + "[paused] " + M.rst}${s.name} ${M.dim}${when(s)}${s.next_fire_at ? ` → ${s.next_fire_at}` : ""}${M.rst}`;
1146
+
1147
+ if (sub === "list") {
1148
+ const ns = flagVal("namespace");
1149
+ const url = ns ? `${BASE}?namespace=${encodeURIComponent(ns)}` : BASE;
1150
+ const { status, json } = await _httpJSON("GET", url, m.token);
1151
+ if (status !== "200") { console.error(`list failed (HTTP ${status}): ${json?.error || ""}`); process.exit(1); }
1152
+ const items = json?.schedules || [];
1153
+ for (const s of items) console.log(" " + fmt(s));
1154
+ if (!items.length) console.log(" (no schedules)");
1155
+ process.exit(0);
1156
+ }
1157
+ if (sub === "create") {
1158
+ const name = process.argv[4];
1159
+ if (!name || name.startsWith("-")) { console.error('Usage: patchcord schedule create <name> --namespace <ns> --to <agent> --content "..." (--at <ISO> | --cron "<expr>" | --every <sec>) [--timezone <tz>] [--thread <slug>] [--max-runs N] [--expires <ISO>]'); process.exit(1); }
1160
+ const ns = flagVal("namespace"), to = flagVal("to"), content = flagVal("content");
1161
+ if (!ns || !to || !content) { console.error("--namespace, --to, and --content are required"); process.exit(1); }
1162
+ const at = flagVal("at"), cron = flagVal("cron"), every = flagVal("every");
1163
+ let schedule_kind, extra = {};
1164
+ if (cron) { schedule_kind = "cron"; extra.cron_expr = cron; }
1165
+ else if (every) { schedule_kind = "interval"; extra.interval_sec = parseInt(every, 10); }
1166
+ else if (at) { schedule_kind = "once"; extra.fire_at = at; }
1167
+ else { console.error('one of --at <ISO>, --cron "<expr>", or --every <seconds> is required'); process.exit(1); }
1168
+ const body = { namespace: ns, name, to_agent: to, content, schedule_kind, timezone: flagVal("timezone", "UTC"), ...extra };
1169
+ const thread = flagVal("thread"); if (thread) body.thread_slug = thread;
1170
+ const maxRuns = flagVal("max-runs"); if (maxRuns) body.max_runs = parseInt(maxRuns, 10);
1171
+ const expires = flagVal("expires"); if (expires) body.expires_at = expires;
1172
+ const { status, json } = await _httpJSON("POST", BASE, m.token, body);
1173
+ if (status !== "201" && status !== "200") { console.error(`create failed (HTTP ${status}): ${json?.error || ""}`); process.exit(1); }
1174
+ console.log(`✓ scheduled ${M.green}${ns}:${to}${M.rst} [${schedule_kind}] ${M.dim}${json?.schedule?.id || ""}${M.rst}`);
1175
+ process.exit(0);
1176
+ }
1177
+ if (sub === "cancel" || sub === "delete" || sub === "rm") {
1178
+ const id = process.argv[4];
1179
+ if (!id) { console.error("Usage: patchcord schedule cancel <id>"); process.exit(1); }
1180
+ const { status, json } = await _httpJSON("DELETE", `${BASE}/${id}`, m.token);
1181
+ if (status !== "200") { console.error(`cancel failed (HTTP ${status}): ${json?.error || ""}`); process.exit(1); }
1182
+ console.log(`✓ cancelled ${id}`);
1183
+ process.exit(0);
1184
+ }
1185
+ if (sub === "test" || sub === "fire") {
1186
+ const id = process.argv[4];
1187
+ if (!id) { console.error("Usage: patchcord schedule test <id>"); process.exit(1); }
1188
+ const { status, json } = await _httpJSON("POST", `${BASE}/${id}/test`, m.token, {});
1189
+ if (status !== "200") { console.error(`test failed (HTTP ${status}): ${json?.error || ""}`); process.exit(1); }
1190
+ console.log(`✓ fired ${id} once (does not consume max-runs)`);
1191
+ process.exit(0);
1192
+ }
1193
+ if (sub === "pause" || sub === "resume") {
1194
+ const id = process.argv[4];
1195
+ if (!id) { console.error(`Usage: patchcord schedule ${sub} <id>`); process.exit(1); }
1196
+ const { status, json } = await _httpJSON("PATCH", `${BASE}/${id}`, m.token, { active: sub === "resume" });
1197
+ if (status !== "200") { console.error(`${sub} failed (HTTP ${status}): ${json?.error || ""}`); process.exit(1); }
1198
+ console.log(`✓ ${sub === "resume" ? "resumed" : "paused"} ${id}`);
1199
+ process.exit(0);
1200
+ }
1201
+ console.error("Usage: patchcord schedule <create|list|cancel|test|pause|resume>");
1202
+ process.exit(1);
1203
+ }
1137
1204
  }
1138
1205
 
1139
1206
  if (cmd === "update" || cmd === "--update") {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "patchcord",
3
- "version": "0.5.104",
3
+ "version": "0.5.105",
4
4
  "description": "Cross-machine agent messaging for Claude Code and Codex",
5
5
  "author": "ppravdin",
6
6
  "license": "MIT",