trantor 0.17.47 → 0.17.48
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/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +1 -1
- package/README.md +2 -2
- package/bin/advise.mjs +4 -4
- package/bin/cli.mjs +1 -1
- package/bin/crew.sh +3 -2
- package/bin/doctor.mjs +1 -1
- package/bin/provider.mjs +38 -6
- package/package.json +1 -1
- package/skills/crew/SKILL.md +3 -3
|
@@ -6,14 +6,14 @@
|
|
|
6
6
|
},
|
|
7
7
|
"metadata": {
|
|
8
8
|
"description": "Trantor — the hub-world for AI agent crews: live message bus, presence, project Kanban/flow board + context-handoff for independent AI coding agents (Claude, Codex, Gemini, …)",
|
|
9
|
-
"version": "0.17.
|
|
9
|
+
"version": "0.17.48"
|
|
10
10
|
},
|
|
11
11
|
"plugins": [
|
|
12
12
|
{
|
|
13
13
|
"name": "trantor",
|
|
14
14
|
"source": "./",
|
|
15
15
|
"description": "The hub-world for AI agent crews. Say \"fire up the crew\" and Claude becomes the architect: a plan-aware Advisor routes the work (solo / cheap inline calls / live crew of Codex, GLM, Kimi & DeepSeek in their own terminal windows), a Kanban/flow command center with a testing gate tracks it, and an economics brain (Scrooge) keeps the receipts. Includes the relay MCP, a SessionStart auto-discovery hook, and a PreCompact context-handoff so a fresh session can take over a full window instead of compacting.",
|
|
16
|
-
"version": "0.17.
|
|
16
|
+
"version": "0.17.48",
|
|
17
17
|
"author": {
|
|
18
18
|
"name": "Sasha Bogojevic"
|
|
19
19
|
},
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "trantor",
|
|
3
|
-
"version": "0.17.
|
|
3
|
+
"version": "0.17.48",
|
|
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/README.md
CHANGED
|
@@ -134,7 +134,7 @@ project takes over with a full window (and a PreCompact hook does this automatic
|
|
|
134
134
|
(`solo | scrooge | crew | hybrid`), a routing table with a **reason per package**, why
|
|
135
135
|
that many seats ("seats follow the work, not the install list"), and a real-money estimate
|
|
136
136
|
with quota-pool accounting. You say go.
|
|
137
|
-
2. **Windows open.** `trantor up codex kimi deepseek:deepseek
|
|
137
|
+
2. **Windows open.** `trantor up codex kimi deepseek:deepseek glm:zai-coding-plan` spawns one titled
|
|
138
138
|
terminal window per agent. `agent:model` pins a model; `agent:provider --difficulty hard`
|
|
139
139
|
picks the **best live model** for the work at spawn (capability × cost), enumerated from the
|
|
140
140
|
CLI itself — never a guessed endpoint. **Serialized and then verified on the bus** — the
|
|
@@ -236,7 +236,7 @@ trantor setup | doctor | connect | profile | up <agents…> | swap <old> <new> |
|
|
|
236
236
|
|
|
237
237
|
`trantor up` notes: `agent:model` pins a model (`deepseek:deepseek-v4-pro`); `agent:provider
|
|
238
238
|
--task <k> --difficulty <d>` picks the **best live model** for the work at spawn
|
|
239
|
-
(`
|
|
239
|
+
(`glm:zai-coding-plan --difficulty hard`); spawns are verified on the bus with one retry;
|
|
240
240
|
geometry auto-detects the screen you're working on (`CREW_RECT="X,Y,W,H"` to override). `trantor
|
|
241
241
|
swap <oldAgent> <newSpec>` replaces an exhausted agent with a live-selected one. `trantor down`
|
|
242
242
|
kills crew processes via their ttys and closes windows without macOS "Terminate?" dialogs.
|
package/bin/advise.mjs
CHANGED
|
@@ -36,7 +36,7 @@ export const BUILTIN_ROSTER = {
|
|
|
36
36
|
codex: { cli: "codex", launch: "codex", session: "codex", provider: "codex" },
|
|
37
37
|
kimi: { cli: "kimi", launch: "kimi", session: "kimi", provider: "kimi" },
|
|
38
38
|
deepseek: { cli: "opencode", launch: "deepseek:deepseek", session: "deepseek", provider: "deepseek", providerOc: "deepseek" },
|
|
39
|
-
glm: { cli: "opencode", launch: "
|
|
39
|
+
glm: { cli: "opencode", launch: "glm:zai-coding-plan", session: "glm", provider: "zai", providerOc: "zai-coding-plan" },
|
|
40
40
|
openrouter: { cli: "opencode", launch: "openrouter:openrouter", session: "openrouter", provider: "openrouter", providerOc: "openrouter" },
|
|
41
41
|
};
|
|
42
42
|
// opencode provider ids already claimed by a built-in (so discovery never duplicates them) + the
|
|
@@ -193,12 +193,12 @@ export function advise(input, world = loadWorld()) {
|
|
|
193
193
|
const seat = roster[r.executor];
|
|
194
194
|
return {
|
|
195
195
|
order: i + 1, title: r.title, difficulty: r.difficulty,
|
|
196
|
-
// bus identity = the
|
|
197
|
-
//
|
|
196
|
+
// bus identity = the seat's session label (every opencode-driven seat has its OWN label, so
|
|
197
|
+
// glm is `glm:<project>`, openrouter `openrouter:<project>`, a brought provider `<name>:<project>`).
|
|
198
198
|
assignee: r.executor === "scrooge" || r.executor === "orchestrator" ? undefined : `${seat?.session || r.executor}:<project>`,
|
|
199
199
|
// launch = the EXACT `trantor up` spec to spawn this seat; the orchestrator runs
|
|
200
200
|
// `trantor up <launch> --task <task> --difficulty <difficulty>`. Carrying it explicitly is
|
|
201
|
-
// what teaches the orchestrator the GLM path (`
|
|
201
|
+
// what teaches the orchestrator the GLM path (`glm:zai-coding-plan`) instead of guessing.
|
|
202
202
|
launch: ["scrooge", "orchestrator"].includes(r.executor) ? undefined : (seat?.launch || r.executor),
|
|
203
203
|
// "auto" = resolve a LIVE model at spawn (the launch spec already pins the provider; the
|
|
204
204
|
// runner picks the best live model for it). Was `<cli>-default` — a stale default.
|
package/bin/cli.mjs
CHANGED
|
@@ -53,7 +53,7 @@ switch (cmd) {
|
|
|
53
53
|
trantor profile declare your plans: trantor profile set claude=max codex=plus deepseek=api
|
|
54
54
|
trantor provider bring ANY model (BYOM): list seats · add <name> --key … · remove <name>
|
|
55
55
|
trantor models browse live models behind each seat + the router's pick per difficulty
|
|
56
|
-
trantor up … spawn a crew here: trantor up codex kimi deepseek:deepseek
|
|
56
|
+
trantor up … spawn a crew here: trantor up codex kimi deepseek:deepseek glm:zai-coding-plan
|
|
57
57
|
trantor down tear the crew down (kills processes, closes windows, no dialogs)
|
|
58
58
|
trantor ui open the live dashboard (board + flow views)
|
|
59
59
|
trantor catchup "where are we?" — the continuous board + git, with a synthesized brief
|
package/bin/crew.sh
CHANGED
|
@@ -52,8 +52,9 @@ down() {
|
|
|
52
52
|
case "$CMD" in up|swap) ;; *) echo "usage: crew.sh up <agent...> | crew.sh swap <oldAgent> <newAgent[:provider[/model]]> | crew.sh down"; exit 1 ;; esac
|
|
53
53
|
|
|
54
54
|
# --task/--difficulty drive LAZY live-model selection for provider-only specs (agent:provider).
|
|
55
|
-
# An agent spec is one of: `codex` (CLI default) · `
|
|
56
|
-
#
|
|
55
|
+
# An agent spec is one of: `codex` (CLI default) · `glm:zai-coding-plan` (provider only → pick the
|
|
56
|
+
# best live model now) · `glm:zai-coding-plan/glm-5.2` (full pin). The agent label is the bus
|
|
57
|
+
# identity; any non-native label runs via opencode (legacy `opencode:zai-coding-plan` still works).
|
|
57
58
|
TASK="code"; DIFF="medium"; _ARGS=()
|
|
58
59
|
while [ $# -gt 0 ]; do
|
|
59
60
|
case "$1" in
|
package/bin/doctor.mjs
CHANGED
|
@@ -60,7 +60,7 @@ const CLIS = [
|
|
|
60
60
|
{ name: "gemini (CLI retired 2026-06-18)", bin: "gemini", wired: () => !!read(join(H, ".gemini", "settings.json"))?.mcpServers?.relay, auth: () => existsSync(join(H, ".gemini", "oauth_creds.json")) || !!process.env.GEMINI_API_KEY || !!process.env.GOOGLE_API_KEY, login: "Gemini CLI retired 2026-06-18 (free/Pro/Ultra). Crew seat → GLM (opencode) or Antigravity `agy`. Gemini still serves as a Scrooge cheap-model via GEMINI_API_KEY." },
|
|
61
61
|
{ name: "kimi", bin: "kimi", wired: () => !!read(join(H, ".kimi", "mcp.json"))?.mcpServers?.relay, auth: () => existsSync(join(H, ".kimi", "credentials")), login: "kimi → /login (Kimi account or Moonshot API key)" },
|
|
62
62
|
{ name: "deepseek (via opencode)", bin: "opencode", wired: () => !!read(join(H, ".config", "opencode", "opencode.json"))?.mcp?.relay, auth: () => !!process.env.DEEPSEEK_API_KEY || (existsSync(join(H, ".agent-bus", ".env")) && readFileSync(join(H, ".agent-bus", ".env"), "utf8").includes("DEEPSEEK_API_KEY")) || !!read(join(H, ".local", "share", "opencode", "auth.json")), login: `get a key at platform.deepseek.com, then: echo 'DEEPSEEK_API_KEY=sk-…' >> ~/.agent-bus/.env` },
|
|
63
|
-
{ name: "glm (via opencode · coding plan)", bin: "opencode", wired: () => !!read(join(H, ".config", "opencode", "opencode.json"))?.mcp?.relay, auth: () => !!read(join(H, ".config", "opencode", "opencode.json"))?.provider?.["zai-coding-plan"]?.options?.apiKey, login: `put your Z.ai coding-plan key at ~/.config/opencode/opencode.json → provider["zai-coding-plan"].options.apiKey, then seat: trantor up
|
|
63
|
+
{ name: "glm (via opencode · coding plan)", bin: "opencode", wired: () => !!read(join(H, ".config", "opencode", "opencode.json"))?.mcp?.relay, auth: () => !!read(join(H, ".config", "opencode", "opencode.json"))?.provider?.["zai-coding-plan"]?.options?.apiKey, login: `put your Z.ai coding-plan key at ~/.config/opencode/opencode.json → provider["zai-coding-plan"].options.apiKey, then seat: trantor up glm:zai-coding-plan/glm-5.1` },
|
|
64
64
|
// OpenRouter — the BYOM on-ramp: ONE key fronts hundreds of models. Rides opencode; the same
|
|
65
65
|
// OPENROUTER_API_KEY Scrooge already uses authenticates the crew seat (the runner sources the
|
|
66
66
|
// .env files). Available the moment the key exists in env/opencode + declared `openrouter=api`.
|
package/bin/provider.mjs
CHANGED
|
@@ -4,11 +4,14 @@
|
|
|
4
4
|
//
|
|
5
5
|
// trantor provider # list seats: built-in + discovered, with availability + tier
|
|
6
6
|
// trantor provider add <name> [--key sk-…] [--plan api|coding-plan|max] [--label <bus-name>]
|
|
7
|
+
// [--base-url <url> [--models m1,m2]] # wire a CUSTOM OpenAI-compatible endpoint
|
|
7
8
|
// trantor provider remove <name> # drop it from your profile (leaves the key in place)
|
|
8
9
|
//
|
|
9
10
|
// `add` writes <NAME>_API_KEY to ~/.agent-bus/.env (if --key given), declares the plan in your
|
|
10
|
-
// quota profile, verifies opencode can see the provider's models, and prints the seat spec.
|
|
11
|
-
//
|
|
11
|
+
// quota profile, verifies opencode can see the provider's models, and prints the seat spec. For a
|
|
12
|
+
// provider opencode already knows (openrouter, groq, …) the key is enough; for a CUSTOM endpoint,
|
|
13
|
+
// pass --base-url and it writes the opencode.json provider block for you. The Advisor then routes
|
|
14
|
+
// to it automatically; run `scrooge-capabilities` so it routes well by difficulty.
|
|
12
15
|
import { readFileSync, writeFileSync, existsSync, mkdirSync, chmodSync, appendFileSync } from "node:fs";
|
|
13
16
|
import { join, dirname } from "node:path";
|
|
14
17
|
import { homedir } from "node:os";
|
|
@@ -23,6 +26,26 @@ const has = (c) => { try { execSync(`command -v ${c}`, { stdio: "ignore", shell:
|
|
|
23
26
|
const C = { dim: "\x1b[2m", grn: "\x1b[32m", red: "\x1b[31m", yel: "\x1b[33m", gold: "\x1b[38;5;208m", off: "\x1b[0m" };
|
|
24
27
|
const envKeyName = (p) => `${String(p).toUpperCase().replace(/[^A-Z0-9]/g, "_")}_API_KEY`;
|
|
25
28
|
|
|
29
|
+
const OC_CONFIG = join(H, ".config", "opencode", "opencode.json");
|
|
30
|
+
// Wire a CUSTOM OpenAI-compatible provider into opencode.json (matching opencode's schema +
|
|
31
|
+
// the existing providers' `options.apiKey` style). Merges, never clobbers other providers.
|
|
32
|
+
// `configPath` is injectable so it can be unit-tested against a temp file.
|
|
33
|
+
export function wireOpencodeProvider(name, baseUrl, models, configPath = OC_CONFIG) {
|
|
34
|
+
const cfg = existsSync(configPath) ? read(configPath, {}) : {};
|
|
35
|
+
cfg.$schema ||= "https://opencode.ai/config.json";
|
|
36
|
+
cfg.provider ||= {};
|
|
37
|
+
const block = {
|
|
38
|
+
npm: "@ai-sdk/openai-compatible",
|
|
39
|
+
name: name.charAt(0).toUpperCase() + name.slice(1),
|
|
40
|
+
options: { baseURL: baseUrl, apiKey: `{env:${envKeyName(name)}}` },
|
|
41
|
+
};
|
|
42
|
+
if (models && models.length) block.models = Object.fromEntries(models.map(m => [m, {}]));
|
|
43
|
+
cfg.provider[name] = { ...cfg.provider[name], ...block };
|
|
44
|
+
mkdirSync(dirname(configPath), { recursive: true });
|
|
45
|
+
writeFileSync(configPath, JSON.stringify(cfg, null, 2) + "\n");
|
|
46
|
+
return configPath;
|
|
47
|
+
}
|
|
48
|
+
|
|
26
49
|
function opencodeModelCount(providerOc) {
|
|
27
50
|
if (!has("opencode")) return null;
|
|
28
51
|
try { return execSync(`opencode models ${providerOc} 2>/dev/null`, { encoding: "utf8" }).split("\n").filter(Boolean).length; }
|
|
@@ -47,7 +70,7 @@ function listSeats() {
|
|
|
47
70
|
}
|
|
48
71
|
|
|
49
72
|
function addProvider(name, opts) {
|
|
50
|
-
if (!name) { console.error("usage: trantor provider add <name> [--key sk-…] [--plan api] [--label <bus-name>]"); process.exit(1); }
|
|
73
|
+
if (!name) { console.error("usage: trantor provider add <name> [--key sk-…] [--plan api] [--label <bus-name>] [--base-url <url> [--models m1,m2]]"); process.exit(1); }
|
|
51
74
|
const provider = name.toLowerCase();
|
|
52
75
|
const label = (opts.label || provider).toLowerCase().replace(/[^a-z0-9-]/g, "-");
|
|
53
76
|
const plan = (opts.plan || "api").toLowerCase();
|
|
@@ -73,13 +96,20 @@ function addProvider(name, opts) {
|
|
|
73
96
|
console.log(`${C.grn}✓${C.off} profile: ${provider}=${plan}`);
|
|
74
97
|
} catch (e) { console.log(`${C.yel}⚠${C.off} could not set profile (run: trantor profile set ${provider}=${plan})`); }
|
|
75
98
|
|
|
76
|
-
// 3)
|
|
99
|
+
// 3) custom endpoint → write the opencode.json provider block (known providers skip this)
|
|
100
|
+
if (opts.baseUrl) {
|
|
101
|
+
const models = (opts.models || "").split(",").map(s => s.trim()).filter(Boolean);
|
|
102
|
+
const where = wireOpencodeProvider(provider, opts.baseUrl, models);
|
|
103
|
+
console.log(`${C.grn}✓${C.off} wired custom provider '${provider}' → ${where.replace(H, "~")} (baseURL ${opts.baseUrl}${models.length ? `, ${models.length} models` : ""})`);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// 4) verify opencode can see the provider's models
|
|
77
107
|
const n = opencodeModelCount(provider);
|
|
78
108
|
if (n == null) console.log(`${C.yel}⚠${C.off} opencode not on PATH — install it to run this seat (it's the universal adapter)`);
|
|
79
|
-
else if (n === 0) console.log(`${C.yel}⚠${C.off} opencode lists 0 models for '${provider}'. If it's a known provider, the key above is enough; for a
|
|
109
|
+
else if (n === 0) console.log(`${C.yel}⚠${C.off} opencode lists 0 models for '${provider}'.${opts.baseUrl ? " Check the baseURL/key, or pass --models m1,m2 to declare them." : " If it's a known provider, the key above is enough; for a CUSTOM endpoint re-run with --base-url <url> [--models m1,m2]."} Re-check: trantor models ${provider}`);
|
|
80
110
|
else console.log(`${C.grn}✓${C.off} opencode sees ${n} models for '${provider}'`);
|
|
81
111
|
|
|
82
|
-
//
|
|
112
|
+
// 5) score it for difficulty-aware routing + show the seat
|
|
83
113
|
console.log(`\n${C.gold}Seat ready.${C.off} Launch it:`);
|
|
84
114
|
console.log(` trantor up ${label === provider ? label : `${label}:${provider}`} ${C.dim}# live-selects the best model for the work${C.off}`);
|
|
85
115
|
console.log(` trantor up ${label}:${provider}/<model> ${C.dim}# pin a specific model${C.off}`);
|
|
@@ -106,6 +136,8 @@ if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href)
|
|
|
106
136
|
if (rest[i] === "--key") opts.key = rest[++i];
|
|
107
137
|
else if (rest[i] === "--plan") opts.plan = rest[++i];
|
|
108
138
|
else if (rest[i] === "--label") opts.label = rest[++i];
|
|
139
|
+
else if (rest[i] === "--base-url" || rest[i] === "--baseurl") opts.baseUrl = rest[++i];
|
|
140
|
+
else if (rest[i] === "--models") opts.models = rest[++i];
|
|
109
141
|
else pos.push(rest[i]);
|
|
110
142
|
}
|
|
111
143
|
if (!sub || sub === "list") listSeats();
|
package/package.json
CHANGED
package/skills/crew/SKILL.md
CHANGED
|
@@ -49,11 +49,11 @@ EXACT launch spec per provider (do not improvise these):
|
|
|
49
49
|
| Codex | `codex` (or `codex:gpt-5.5` to pin) | OpenAI CLI |
|
|
50
50
|
| Kimi | `kimi` | Moonshot coding-plan |
|
|
51
51
|
| DeepSeek | `deepseek:deepseek` | runs via opencode; `deepseek` alone = CLI default |
|
|
52
|
-
| **GLM (Z.ai)** | **`
|
|
52
|
+
| **GLM (Z.ai)** | **`glm:zai-coding-plan`** | **runs via opencode, NOT a bare `glm`/`zai` terminal command.** `glm:zai-coding-plan/glm-5.2` pins a model; `glm:zai-coding-plan` live-selects. (Legacy `opencode:zai-coding-plan` still works.) |
|
|
53
53
|
| **OpenRouter (BYOM)** | **`openrouter`** | **the bring-your-own-model on-ramp — one key fronts hundreds of vendors (incl. ones with no CLI).** Bare `openrouter` live-selects the best OpenRouter model for the difficulty; pin one with `openrouter:openrouter/<vendor>/<model>`. Its own bus identity `openrouter:<project>` (never collides with the GLM `opencode` seat). |
|
|
54
54
|
|
|
55
55
|
`agent:provider` live-selects the best model now; `agent:provider/model` pins one. Example:
|
|
56
|
-
`trantor up codex kimi deepseek:deepseek
|
|
56
|
+
`trantor up codex kimi deepseek:deepseek glm:zai-coding-plan --task code --difficulty hard`.
|
|
57
57
|
**Whatever the advisor's `launch` field says, run that verbatim** — the roster above is just the
|
|
58
58
|
built-in menu, but the advisor picks the right seats/specs for THIS work (a user who's only brought
|
|
59
59
|
an OpenRouter key gets `openrouter` for everything; one who brought five providers gets a
|
|
@@ -66,7 +66,7 @@ advisor routes to a brought provider you don't recognize, that's expected — ru
|
|
|
66
66
|
|
|
67
67
|
⚠️ **Gemini CLI is RETIRED (Google killed the free seat 2026-06-18).** The advisor no longer
|
|
68
68
|
offers it and you must NOT fire up `gemini` — `gemini --yolo` exits 1 and crash-loops on the
|
|
69
|
-
bus. Its replacement seat is **GLM via `
|
|
69
|
+
bus. Its replacement seat is **GLM via `glm:zai-coding-plan`**. (Gemini still serves as a
|
|
70
70
|
Scrooge cheap-model via `GEMINI_API_KEY` — that's a separate, working path, not a crew seat.)
|
|
71
71
|
Only a holder of a paid Gemini enterprise key should ever `trantor up gemini`.
|
|
72
72
|
|