trantor 0.17.27 → 0.17.29

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.27",
3
+ "version": "0.17.29",
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": {
@@ -11,7 +11,7 @@ import { join, basename } from "node:path";
11
11
  import { homedir, hostname } from "node:os";
12
12
  import { execSync } from "node:child_process";
13
13
  import { resolveProject, hostId } from "../lib/project.mjs";
14
- import { updateAvailable, maybeNotifyDesktop } from "./lib/update-check.mjs";
14
+ import { updateAvailable, maybeNotifyDesktop, readConfig } from "./lib/update-check.mjs";
15
15
 
16
16
  // Load the most recent UNCONSUMED handoff for this project (written by precompact.mjs
17
17
  // / the heartbeat early-warning). `claim` marks it consumed so exactly one session
@@ -93,6 +93,7 @@ function sanitize(s) {
93
93
  }
94
94
 
95
95
  let additionalContext = "";
96
+ let userBanner = ""; // shown to the USER in-terminal via the hook's `systemMessage` (not model-only context)
96
97
  try {
97
98
  let source = "", stdinObj = {};
98
99
  try { stdinObj = JSON.parse((await readStdin()) || "{}"); source = stdinObj.source || ""; } catch {}
@@ -158,14 +159,23 @@ try {
158
159
  }
159
160
  } catch {}
160
161
 
161
- // Update available? Like a desktop app's "an update is ready"surface it two ways: a one-time
162
- // native desktop notification (once per new version, not per session) AND an in-session context
163
- // block so the running model can tell the user the exact update commands. Throttled + fail-silent;
164
- // most starts do zero network (6h TTL cache). Disable: TRANTOR_NO_UPDATE_CHECK / _NOTIFY.
162
+ // Update available? Surface it the way a terminal tool shouldan in-terminal `systemMessage`
163
+ // line the USER sees at session start (NOT a macOS desktop popup, which macOS misattributes to
164
+ // Script Editor and which fires off-screen). It shows every session while an update is pending and
165
+ // auto-clears the moment they update (updateAvailable() flips false) a persistent-until-resolved
166
+ // reminder, like the built-in MCP-disconnected indicator. The model also gets the <trantor-update>
167
+ // context block so it can give the exact commands on request. Desktop notification is now OPT-IN
168
+ // (config.updateDesktopNotify:true) for anyone who genuinely wants the OS-level ping.
169
+ // Throttled + fail-silent; most starts do zero network (6h TTL cache). Disable: TRANTOR_NO_UPDATE_CHECK.
165
170
  try {
166
171
  const upd = await updateAvailable();
167
172
  if (upd.available) {
168
- maybeNotifyDesktop(upd);
173
+ if (readConfig().updateDesktopNotify === true) maybeNotifyDesktop(upd); // opt-in only
174
+ // Bold-orange ANSI so it's not lost in Claude Code's dim systemMessage styling; a leading
175
+ // 🟠 emoji anchor keeps it visibly colored even on a terminal that ignores the ANSI (so it
176
+ // can never silently fall back to low-contrast gray). \x1b[1;38;5;208m = bold orange, \x1b[0m resets.
177
+ const O = "\x1b[1;38;5;208m", R = "\x1b[0m";
178
+ userBanner = `🟠 ${O}Trantor update available: ${upd.installed} → ${upd.latest}${R} · update with: ${O}claude plugin update trantor@trantor${R}`;
169
179
  additionalContext += `<trantor-update installed="${sanitize(upd.installed)}" latest="${sanitize(upd.latest)}">\n`;
170
180
  additionalContext += `⬆️ **A newer Trantor is available — ${sanitize(upd.installed)} → ${sanitize(upd.latest)}.** Tell the user, and offer the update: \`claude plugin update trantor@trantor\` (plugin) + \`npm i -g trantor@${sanitize(upd.latest)}\` (CLI), then restart to apply.\n`;
171
181
  additionalContext += `</trantor-update>\n`;
@@ -195,13 +205,21 @@ try {
195
205
  process.stderr.write(`[trantor] sessionstart error: ${err?.message || err}\n`);
196
206
  }
197
207
 
198
- // Hook protocol: emit additionalContext via stdout JSON. Self-validate so we never
199
- // emit something Claude Code can't parse fall back to sanitized, then to {}.
200
- function emit(ctx) {
201
- const obj = ctx ? { hookSpecificOutput: { hookEventName: "SessionStart", additionalContext: ctx } } : {};
208
+ // Hook protocol: emit additionalContext (model-facing) via stdout JSON, plus an optional
209
+ // `systemMessage` (USER-facing rendered as a line in the terminal, our update indicator).
210
+ // Self-validate so we never emit something Claude Code can't parse — fall back to sanitized, then {}.
211
+ function emit(ctx, sysMsg) {
212
+ const obj = {};
213
+ if (ctx) obj.hookSpecificOutput = { hookEventName: "SessionStart", additionalContext: ctx };
214
+ if (sysMsg) obj.systemMessage = sysMsg;
202
215
  const out = JSON.stringify(obj);
203
216
  try { JSON.parse(out); return out; } catch { /* fall through */ }
204
- try { return JSON.stringify({ hookSpecificOutput: { hookEventName: "SessionStart", additionalContext: sanitize(ctx) } }); } catch { return "{}"; }
217
+ try {
218
+ const safe = {};
219
+ if (ctx) safe.hookSpecificOutput = { hookEventName: "SessionStart", additionalContext: sanitize(ctx) };
220
+ if (sysMsg) safe.systemMessage = sanitize(sysMsg);
221
+ return JSON.stringify(safe);
222
+ } catch { return "{}"; }
205
223
  }
206
- process.stdout.write(emit(additionalContext));
224
+ process.stdout.write(emit(additionalContext, userBanner));
207
225
  process.exit(0);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "trantor",
3
- "version": "0.17.27",
3
+ "version": "0.17.29",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "trantor": "bin/cli.mjs"
@@ -12,7 +12,7 @@
12
12
  "scripts": {
13
13
  "test": "node test.mjs && node test-scenarios.mjs && node test-failure.mjs && node test-handoff.mjs && node test-update.mjs"
14
14
  },
15
- "description": "The hub-world for AI agent crews \u2014 orchestrate Claude Code, Codex, Gemini, Kimi & DeepSeek as live crews with a plan-aware Advisor, a Kanban/flow command center, a testing gate, and an economics brain (Scrooge).",
15
+ "description": "The hub-world for AI agent crews orchestrate Claude Code, Codex, Gemini, Kimi & DeepSeek as live crews with a plan-aware Advisor, a Kanban/flow command center, a testing gate, and an economics brain (Scrooge).",
16
16
  "files": [
17
17
  "hub.mjs",
18
18
  "mcp.mjs",