trantor 0.17.63 → 0.17.64

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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "trantor",
3
- "version": "0.17.63",
3
+ "version": "0.17.64",
4
4
  "description": "Trantor — the hub-world for AI agent crews: live message bus, presence, project Kanban/flow board + crew orchestration for independent AI coding agents (Claude, Codex, Gemini, Kimi, DeepSeek)",
5
5
  "mcpServers": {
6
6
  "relay": {
package/bin/app.mjs CHANGED
@@ -40,7 +40,10 @@ function installedVersion() {
40
40
  // Newest release carrying a Trantor DMG for this arch (falls back to any Trantor DMG — old
41
41
  // releases may predate multi-arch naming). GITHUB_TOKEN is honored but not required (public repo).
42
42
  async function latestAppRelease() {
43
- const headers = { accept: "application/vnd.github+json", "user-agent": "trantor-app" };
43
+ // cache-control: GitHub serves unauthenticated API responses through a shared ~60s cache — a
44
+ // release published seconds ago comes back MISSING and `app update` re-installs the previous
45
+ // version (observed live on the 0.2.0 release). no-cache punches through it.
46
+ const headers = { accept: "application/vnd.github+json", "user-agent": "trantor-app", "cache-control": "no-cache" };
44
47
  if (process.env.GITHUB_TOKEN) headers.authorization = `Bearer ${process.env.GITHUB_TOKEN}`;
45
48
  const r = await fetch(`https://api.github.com/repos/${REPO}/releases?per_page=30`, { headers, signal: AbortSignal.timeout(15000) });
46
49
  if (!r.ok) throw new Error(`GitHub API ${r.status} — ${(await r.text()).slice(0, 200)}`);
@@ -83,14 +83,23 @@ async function api(path, body) {
83
83
  const CMUX_BIN = process.env.CMUX_BIN
84
84
  || (existsSync("/Applications/cmux.app/Contents/Resources/bin/cmux") ? "/Applications/cmux.app/Contents/Resources/bin/cmux" : "cmux");
85
85
  const inCmux = () => !!process.env.CMUX_SURFACE_ID;
86
- function cmuxStatus(value, color, icon = "robot") {
86
+ // Brand colors — the SAME hexes the desktop app's Avatar.tsx uses, so a seat is the same color in
87
+ // the cmux sidebar and the Trantor app. cmux status icons are a fixed named set (no images), so an
88
+ // actual LLM logo in the pill is not possible — brand COLOR + the agent's name in the label is the
89
+ // closest cmux allows.
90
+ const BRAND_HEX = { claude: "#D97757", codex: "#e8e8ee", openai: "#e8e8ee", deepseek: "#5786FE",
91
+ kimi: "#8b8bf5", moonshot: "#8b8bf5", glm: "#5ea0f5", zai: "#5ea0f5", gemini: "#8E75B2", openrouter: "#94A3B8" };
92
+ function cmuxStatus(value, color, icon = "robot", opts = {}) {
87
93
  if (!inCmux()) return;
88
94
  // Label with the REAL seat identity, not a literal. This was hardcoded to "trantor", so every seat
89
95
  // in every project reported under one name — four different agents (and their duplicates) rendered
90
96
  // identically in the sidebar, which is why a runner leak looked like mystery sessions instead of
91
97
  // obvious duplicates. Note this is the DISPLAY path; two previous fixes to the crossed-label
92
98
  // symptom both landed on the *bus* identity and never touched this line.
93
- try { spawnSync(CMUX_BIN, ["set-status", SESSION, value, "--color", color, "--icon", icon], { stdio: "ignore", timeout: 1500, env: { ...process.env, CMUX_QUIET: "1" } }); } catch {}
99
+ // Pill = "<agent> · <state>" in the agent's BRAND color (alerts keep their alarm color — a red
100
+ // error must read as red at a glance); errors sort first via --priority.
101
+ const col = opts.alert ? color : (BRAND_HEX[AGENT.toLowerCase()] || color);
102
+ try { spawnSync(CMUX_BIN, ["set-status", SESSION, `${AGENT} · ${value}`, "--color", col, "--icon", icon, "--priority", String(opts.priority ?? 0)], { stdio: "ignore", timeout: 1500, env: { ...process.env, CMUX_QUIET: "1" } }); } catch {}
94
103
  }
95
104
  function cmuxLog(message, level = "info") {
96
105
  if (!inCmux()) return;
@@ -170,7 +179,7 @@ async function reportFailure(exit, trigger) {
170
179
  ? `🛑 ${SESSION} DOWN — ${consecFails} consecutive failures (${reason}, exit ${exit})${hint}`
171
180
  : `⚠️ ${SESSION} turn FAILED (${trigger}, exit ${exit} · ${reason})${hint}`;
172
181
  await api("/send", { from: SESSION, to: "all", text, project: PROJ }).catch(() => {});
173
- cmuxStatus(down ? "down" : "error", "#ef6a6a", "alert"); cmuxLog(`turn failed: ${reason} (exit ${exit})`, "error");
182
+ cmuxStatus(down ? "down" : "error", "#ef6a6a", "alert", { alert: true, priority: 90 }); cmuxLog(`turn failed: ${reason} (exit ${exit})`, "error");
174
183
  log(`\x1b[31mreported failure to bus: ${reason} (exit ${exit})\x1b[0m`);
175
184
  }
176
185
 
@@ -195,7 +204,7 @@ function runTurn(prompt, isFirst, trigger = "kickoff") {
195
204
  const envs = [join(homedir(), ".agent-bus", ".env"), cli.env].filter(f => f && existsSync(f));
196
205
  for (const f of envs.reverse()) cmd = `set -a; source ${f}; set +a; ${cmd}`; // ~/.agent-bus/.env wins
197
206
  log(`turn starting (${isFirst ? "fresh session" : "resume"})${MODEL ? ` · model=${MODEL}` : ""}`);
198
- cmuxStatus("building", "#4a90d9", "hammer");
207
+ cmuxStatus("building", "#4a90d9", "hammer", { priority: 50 });
199
208
  // inherit stdio so the window shows the agent working live; also capture for sid-parsing.
200
209
  // Tee stderr to ERRF (still shown live in the window) so a failed turn can be classified.
201
210
  try { appendFileSync(ERRF, "", { flag: "w" }); } catch {}
@@ -256,7 +265,14 @@ async function loadLessons() {
256
265
  try {
257
266
  const r = await api(`/poll?session=${encodeURIComponent(SESSION)}&since=${cursor}&wait=280`);
258
267
  msgs = r.messages || []; cursor = r.cursor ?? cursor;
259
- } catch (e) { log(`hub unreachable (${e.message}) — retrying in 5s`); await new Promise(s => setTimeout(s, 5000)); continue; }
268
+ } catch (e) {
269
+ // Deadline-abort on the LONG-POLL is not an outage — it means the hold expired with no hub
270
+ // response (stalled event loop, napped machine, dead socket). Reconnect immediately and say
271
+ // so calmly; reserve the scary "hub unreachable" + 5s backoff for real connection failures.
272
+ const expired = e && (e.name === "TimeoutError" || /abort/i.test(String(e.message)));
273
+ log(expired ? `long-poll hold expired with no hub response — reconnecting` : `hub unreachable (${e.message}) — retrying in 5s`);
274
+ await new Promise(s => setTimeout(s, expired ? 250 : 5000)); continue;
275
+ }
260
276
  if (!msgs.length) continue; // heartbeat tick, nothing for us
261
277
  const direct = msgs.filter(m => m.to === SESSION);
262
278
  const mentions = msgs.filter(m => m.to === "all" && (m.text.includes(`@${AGENT}`) || m.text.toLowerCase().includes(`${AGENT}:`)));
package/bin/crew.sh CHANGED
@@ -554,7 +554,8 @@ spawn_cmux() { # $@ = specs
554
554
  echo " → $AGENT seat in cmux workspace ($PROJ)"
555
555
  i=$(( i + 1 ))
556
556
  done
557
- [ "$DRY" = "1" ] || [ -z "$wsid" ] || _cmux set-status trantor "crew up" --icon rocket --color "#14b8a6" --workspace "$wsid" >/dev/null 2>&1
557
+ # (no workspace-level "crew up" pill — the per-seat pills the runners push carry all the signal;
558
+ # a fifth static pill just forced the sidebar into "Show more".)
558
559
  echo "— crew grouped in cmux: ONE workspace tab for $PROJ, seats tiled + sidebar status. Teardown (this project only): trantor down —"
559
560
  }
560
561
 
package/bin/duty.mjs CHANGED
@@ -66,7 +66,9 @@ async function ensureFleetIdentity(hub) {
66
66
  function alivePid() {
67
67
  try {
68
68
  const pid = Number(readFileSync(PIDF, "utf8"));
69
- if (pid && process.kill(pid, 0) === undefined) return pid;
69
+ // process.kill(pid, 0) returns TRUE on success (it throws when the pid is gone) — the original
70
+ // `=== undefined` comparison made alivePid always 0, so `duty status` reported NOT running forever.
71
+ if (pid) { process.kill(pid, 0); return pid; }
70
72
  } catch {}
71
73
  return 0;
72
74
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "trantor",
3
- "version": "0.17.63",
3
+ "version": "0.17.64",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "trantor": "bin/cli.mjs"