trantor 0.18.4 → 0.18.6
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/.claude-plugin/plugin.json +1 -1
- package/bin/cli.mjs +31 -3
- package/bin/doctor.mjs +9 -1
- package/package.json +1 -1
- package/skills/crew/SKILL.md +5 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "trantor",
|
|
3
|
-
"version": "0.18.
|
|
3
|
+
"version": "0.18.6",
|
|
4
4
|
"description": "Trantor \u2014 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/cli.mjs
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
import { spawn } from "node:child_process";
|
|
5
5
|
import { join, dirname } from "node:path";
|
|
6
6
|
import { fileURLToPath } from "node:url";
|
|
7
|
-
import { readFileSync } from "node:fs";
|
|
7
|
+
import { readFileSync, existsSync } from "node:fs";
|
|
8
8
|
|
|
9
9
|
const ROOT = dirname(dirname(fileURLToPath(import.meta.url)));
|
|
10
10
|
const [, , cmd, ...args] = process.argv;
|
|
@@ -138,9 +138,37 @@ switch (cmd) {
|
|
|
138
138
|
else console.error(`Enrollment failed: ${j.error || r.statusText}`);
|
|
139
139
|
break;
|
|
140
140
|
}
|
|
141
|
+
// A BROWSER CANNOT READ AN ENFORCE-MODE HUB. The page itself is served (200), but every data
|
|
142
|
+
// endpoint answers 401 to an unsigned request — /projects, /tasks, /peers — because a browser has
|
|
143
|
+
// no keypair and nothing in a webview can safely hold one. So the dashboard renders as an empty
|
|
144
|
+
// shell with no projects, which reads as "the hub is broken" when the hub is fine and refusing
|
|
145
|
+
// correctly. That is exactly what happened to a crew launch on 2026-08-26.
|
|
146
|
+
//
|
|
147
|
+
// The desktop app is the surface that works: it signs every request in Rust, which is also why
|
|
148
|
+
// the webview never touches a key. Prefer it, and when it is missing say plainly why the browser
|
|
149
|
+
// will look empty rather than opening one and letting the operator draw the wrong conclusion.
|
|
141
150
|
case "ui": {
|
|
142
|
-
|
|
143
|
-
|
|
151
|
+
const { resolveHubInfo } = await import(join(ROOT, "lib/project.mjs"));
|
|
152
|
+
const { resolveProject } = await import(join(ROOT, "lib/project.mjs"));
|
|
153
|
+
const url = resolveHubInfo(resolveProject(process.cwd())).url;
|
|
154
|
+
|
|
155
|
+
let authMode = "";
|
|
156
|
+
try {
|
|
157
|
+
const r = await fetch(`${url}/health`, { signal: AbortSignal.timeout(5000) });
|
|
158
|
+
authMode = String((await r.json()).authMode || "");
|
|
159
|
+
} catch { /* hub unreachable — fall through and let the browser show that */ }
|
|
160
|
+
|
|
161
|
+
const hasApp = process.platform === "darwin" && existsSync("/Applications/Trantor.app");
|
|
162
|
+
if (authMode === "enforce" && hasApp) {
|
|
163
|
+
spawn("open", ["-a", "Trantor"], { stdio: "ignore", detached: true }).unref();
|
|
164
|
+
console.log(`dashboard → Trantor.app (${url} is auth:enforce — a browser cannot sign, so it would show an empty board)`);
|
|
165
|
+
break;
|
|
166
|
+
}
|
|
167
|
+
if (authMode === "enforce") {
|
|
168
|
+
console.log(`⚠ ${url} is auth:enforce. A browser cannot sign its requests, so the board will be EMPTY —`);
|
|
169
|
+
console.log(` every data endpoint returns 401. Install the desktop app instead: trantor app install`);
|
|
170
|
+
console.log(` Opening it anyway so you can see for yourself…`);
|
|
171
|
+
}
|
|
144
172
|
spawn(process.platform === "darwin" ? "open" : "xdg-open", [url], { stdio: "ignore", detached: true }).unref();
|
|
145
173
|
console.log(`dashboard → ${url}`);
|
|
146
174
|
break;
|
package/bin/doctor.mjs
CHANGED
|
@@ -152,7 +152,7 @@ if (!installed) warn("no crew CLIs found", "install at least one of: codex, gemi
|
|
|
152
152
|
// 2. ~/.agent-bus/.env — the CREW layer (seats: opencode/deepseek/openrouter/dsh)
|
|
153
153
|
// 3. ~/.token-scrooge/.env — the SCROOGE layer (cheap-model grunt routing)
|
|
154
154
|
section("provider keys (who spends on what)");
|
|
155
|
-
const KEY_VARS = ["DEEPSEEK_API_KEY", "OPENROUTER_API_KEY", "MOONSHOT_API_KEY", "ZAI_API_KEY", "OPENAI_API_KEY", "GEMINI_API_KEY", "XAI_API_KEY"];
|
|
155
|
+
const KEY_VARS = ["DEEPSEEK_API_KEY", "OPENROUTER_API_KEY", "MOONSHOT_API_KEY", "ZAI_API_KEY", "OPENAI_API_KEY", "GEMINI_API_KEY", "XAI_API_KEY", "INCEPTION_API_KEY"];
|
|
156
156
|
// Only some of these are a CREW credential. A seat that authenticates through its own config never
|
|
157
157
|
// reads the env var at all, so a shared value there costs nothing and flagging it is noise:
|
|
158
158
|
// glm → opencode.json provider["zai-coding-plan"].options.apiKey (and a coding plan is flat
|
|
@@ -164,7 +164,15 @@ const KEY_VARS = ["DEEPSEEK_API_KEY", "OPENROUTER_API_KEY", "MOONSHOT_API_KEY",
|
|
|
164
164
|
// which is how a doctor becomes something you skip.
|
|
165
165
|
const OPENCODE_CFG = read(join(H, ".config", "opencode", "opencode.json")) || {};
|
|
166
166
|
const SEAT_ENV_VARS = { DEEPSEEK_API_KEY: "deepseek", OPENROUTER_API_KEY: "openrouter" };
|
|
167
|
+
const ENV_TEMPLATE = /\{env:([A-Z0-9_]+)\}/;
|
|
168
|
+
// Every var any opencode provider resolves from the environment, read out of opencode's own config.
|
|
169
|
+
const opencodeEnvVars = new Set();
|
|
170
|
+
for (const cfg of Object.values(OPENCODE_CFG?.provider || {})) {
|
|
171
|
+
const m = ENV_TEMPLATE.exec(String(cfg?.options?.apiKey || ""));
|
|
172
|
+
if (m) opencodeEnvVars.add(m[1]);
|
|
173
|
+
}
|
|
167
174
|
const crewUsesVar = (v) => {
|
|
175
|
+
if (opencodeEnvVars.has(v)) return true; // a seat resolves this var at run time — stated by the config itself
|
|
168
176
|
const provider = SEAT_ENV_VARS[v];
|
|
169
177
|
if (!provider) return false;
|
|
170
178
|
const configured = OPENCODE_CFG?.provider?.[provider]?.options?.apiKey;
|
package/package.json
CHANGED
package/skills/crew/SKILL.md
CHANGED
|
@@ -36,7 +36,11 @@ explicit EVENT/INTERFACE CONTRACT — cross-agent bugs come from contract drift.
|
|
|
36
36
|
2. One card per package: `relay_task_add(title, assignee, difficulty, model)` — set `model`
|
|
37
37
|
to the advisor-routed model (or the CLI's default name); difficulty + model show as badges
|
|
38
38
|
on the card. Assignees: `codex:<project>` etc. Keep one for yourself.
|
|
39
|
-
3. Open the dashboard:
|
|
39
|
+
3. Open the dashboard: **`trantor ui`** — which opens the **desktop app**, not a browser.
|
|
40
|
+
Do NOT open the hub URL in a browser. A remote hub runs `auth:enforce`, and a browser cannot
|
|
41
|
+
sign its requests: the page loads but `/projects`, `/tasks` and `/peers` all return 401, so the
|
|
42
|
+
board renders EMPTY. That looks like a broken hub and is not one. The desktop app signs every
|
|
43
|
+
request natively, which is the whole reason it exists. If it is missing: `trantor app install`.
|
|
40
44
|
|
|
41
45
|
## Phase 2 — fire up the crew (with the Advisor's models)
|
|
42
46
|
**Each crew card from `relay_advise` carries a `launch` spec — run it VERBATIM; never invent a
|