trantor 0.17.48 → 0.17.50
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 +115 -31
- package/bin/cli.mjs +2 -1
- package/bin/crew-runner.mjs +20 -0
- package/bin/crew.sh +427 -124
- package/bin/sweep.mjs +62 -0
- package/hooks/agent-notify.mjs +64 -0
- package/hooks/hooks.json +7 -1
- package/hooks/subagent-cost.mjs +5 -1
- package/hooks/subagent-start.mjs +50 -18
- package/hub.mjs +0 -0
- package/mcp.mjs +5 -3
- package/package.json +2 -2
- package/ui.html +25 -8
|
@@ -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.50"
|
|
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.50",
|
|
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.50",
|
|
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
|
@@ -12,14 +12,14 @@
|
|
|
12
12
|
### The hub-world for AI agent crews.
|
|
13
13
|
|
|
14
14
|
**One Advisor decides how your work runs — solo, cheap inline calls, or a live crew of
|
|
15
|
-
Claude Code, Codex, GLM, Kimi
|
|
16
|
-
actual plans, supervised on a live + historical board you can scroll
|
|
17
|
-
from every failure.**
|
|
15
|
+
Claude Code, Codex, GLM, Kimi, DeepSeek — or *any model you bring* — in their own terminal
|
|
16
|
+
windows, routed by your actual plans, supervised on a live + historical board you can scroll
|
|
17
|
+
back through, learning from every failure.**
|
|
18
18
|
|
|
19
19
|
[](./LICENSE)
|
|
20
20
|

|
|
21
|
-

|
|
22
|
+

|
|
23
23
|
|
|
24
24
|
</div>
|
|
25
25
|
|
|
@@ -42,6 +42,12 @@ claude plugin install trantor
|
|
|
42
42
|
That's it. (Prefer source? `git clone https://github.com/sashabogi/trantor && cd trantor &&
|
|
43
43
|
npm install && bash deploy/setup.sh` — identical result.)
|
|
44
44
|
|
|
45
|
+
**Recommended companion (macOS):** [**cmux**](https://cmux.com) — `brew install --cask cmux` — a
|
|
46
|
+
native terminal built for running multiple AI agents. Trantor groups each crew into one cmux workspace
|
|
47
|
+
with live per-seat status in the sidebar and project-scoped teardown. See
|
|
48
|
+
*[Grouped crews in cmux](#grouped-crews-in-cmux-recommended)*. Optional — crews also run in tmux or plain
|
|
49
|
+
Terminal windows.
|
|
50
|
+
|
|
45
51
|
## What gets installed — footprint & safety
|
|
46
52
|
|
|
47
53
|
Trantor is a **local-first multi-agent orchestrator with a built-in cost router** — not a cloud
|
|
@@ -65,9 +71,10 @@ on your machine, so you (or an agent installing it for you) can see the whole fo
|
|
|
65
71
|
**SubagentStop** (record each sub-agent's notional cost on the board).
|
|
66
72
|
|
|
67
73
|
**What it does *not* do:** no cloud, no accounts, no telemetry, nothing phones home; it never uploads
|
|
68
|
-
your code or keys; it doesn't touch other CLIs' credentials — Codex,
|
|
69
|
-
ones *you* already installed and signed into, and Trantor just coordinates
|
|
70
|
-
API keys in `~/.agent-bus/.env` are used only to call the
|
|
74
|
+
your code or keys; it doesn't touch other CLIs' credentials — Codex, Kimi, DeepSeek, GLM (and any
|
|
75
|
+
provider you bring) are ones *you* already installed and signed into, and Trantor just coordinates
|
|
76
|
+
them locally. The optional API keys in `~/.agent-bus/.env` are used only to call the models *you*
|
|
77
|
+
opted into for routing.
|
|
71
78
|
|
|
72
79
|
**Remove everything, anytime:**
|
|
73
80
|
```bash
|
|
@@ -134,12 +141,16 @@ project takes over with a full window (and a PreCompact hook does this automatic
|
|
|
134
141
|
(`solo | scrooge | crew | hybrid`), a routing table with a **reason per package**, why
|
|
135
142
|
that many seats ("seats follow the work, not the install list"), and a real-money estimate
|
|
136
143
|
with quota-pool accounting. You say go.
|
|
137
|
-
2. **Windows open.** `trantor up codex kimi deepseek:deepseek glm:zai-coding-plan` spawns
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
a
|
|
144
|
+
2. **Windows open.** `trantor up codex kimi deepseek:deepseek glm:zai-coding-plan` spawns the crew in
|
|
145
|
+
visible terminals — grouped into **one [cmux](https://cmux.com) workspace per project** when cmux is
|
|
146
|
+
installed (seats tiled, live status in the sidebar; see *[Grouped crews in cmux](#grouped-crews-in-cmux-recommended)*
|
|
147
|
+
below), else tmux, else one titled Terminal window per seat. The seats aren't a fixed list — they're **whatever you've got**:
|
|
148
|
+
the native CLIs (Codex, Kimi) plus *any* provider wired through OpenCode (DeepSeek, GLM, and
|
|
149
|
+
**OpenRouter's hundreds of models, or a custom endpoint you bring** — see *Bring your own
|
|
150
|
+
model* below). `agent:model` pins a model; `agent:provider --difficulty hard` picks the
|
|
151
|
+
**best live model** for the work at spawn (capability × cost), enumerated from the provider
|
|
152
|
+
itself — never a guessed endpoint. **Serialized and then verified on the bus** — the launcher
|
|
153
|
+
ends with "crew verified" or names the no-shows loudly. The orchestrator never gets a green lie.
|
|
143
154
|
3. **Work flows over the bus.** Contracts arrive as messages; each agent owns its own files;
|
|
144
155
|
coordination happens in <280-char messages you can read on the dashboard. Crew members
|
|
145
156
|
live under a **runner**: the CLI works one turn and exits, the runner long-polls the bus
|
|
@@ -156,6 +167,33 @@ project takes over with a full window (and a PreCompact hook does this automatic
|
|
|
156
167
|
6. **It learns.** Failures become lessons (`relay_lesson`), stored on the hub and **injected
|
|
157
168
|
into every future crew's prompts** — global or per-CLI. Your crew gets smarter every run.
|
|
158
169
|
|
|
170
|
+
### Grouped crews in cmux (recommended)
|
|
171
|
+
|
|
172
|
+
Trantor runs crews in visible terminals so nothing dies or fails silently. On macOS it prefers
|
|
173
|
+
**[cmux](https://cmux.com)** — a native, Ghostty-based terminal *built for managing multiple AI coding
|
|
174
|
+
agents* — and falls back to **tmux**, then plain Terminal windows.
|
|
175
|
+
|
|
176
|
+
With cmux, each crew becomes **one workspace tab per project**, its seats tiled inside, every pane
|
|
177
|
+
labeled `<agent> · <project>`, and each seat pushes its **live state into cmux's sidebar** —
|
|
178
|
+
`building` (blue) while a turn runs, `idle` when it's waiting, `error`/`down` (red) on a failed turn —
|
|
179
|
+
plus a per-crew progress pill. Teardown is **project-scoped**: `trantor down` closes only *this*
|
|
180
|
+
project's workspace, so when you run several sessions each driving its own crew, one session's teardown
|
|
181
|
+
can't nuke another's. `trantor down <agent>` drops a single seat; `trantor down --all --yes` tears down
|
|
182
|
+
every project's crew.
|
|
183
|
+
|
|
184
|
+
**One-time setup:**
|
|
185
|
+
- Install cmux — `brew install --cask cmux` (or grab it from **[cmux.com](https://cmux.com)**).
|
|
186
|
+
- Trantor drives cmux over its control socket, which is off to outside processes by default. Enable it in
|
|
187
|
+
`~/.config/cmux/cmux.json` (cmux auto-reloads):
|
|
188
|
+
```json
|
|
189
|
+
{ "automation": { "socketControlMode": "allowAll" } }
|
|
190
|
+
```
|
|
191
|
+
This lets local processes drive your terminals. Leave it on the default `cmuxOnly` and Trantor
|
|
192
|
+
automatically falls back to AppleScript (same grouped layout, minus the native sidebar status).
|
|
193
|
+
- The `cmux` CLI is symlinked onto your PATH on your first `trantor up`.
|
|
194
|
+
|
|
195
|
+
No cmux or tmux? Crews still work — one titled Terminal window per seat, still project-scoped teardown.
|
|
196
|
+
|
|
159
197
|
## The dashboard — `trantor ui`
|
|
160
198
|
|
|
161
199
|
A live command center at `http://127.0.0.1:4477`, grouped by **project** — and a *durable,
|
|
@@ -202,6 +240,39 @@ ledger; Trantor turns that into decisions:
|
|
|
202
240
|
- **Fractal delegation** (`relay_scrooge`): the architect *and* crew members push stateless
|
|
203
241
|
grunt work to cheap models, with ledger receipts.
|
|
204
242
|
|
|
243
|
+
## Bring your own model (BYOM)
|
|
244
|
+
|
|
245
|
+
The crew roster isn't a hardcoded list — it's **derived from what you've configured**. Trantor
|
|
246
|
+
ships built-in seats for Codex and Kimi (native CLIs) and DeepSeek + GLM (via OpenCode), but
|
|
247
|
+
**any** provider OpenCode can reach becomes a first-class seat with its own identity on the
|
|
248
|
+
board — no code change, no waiting for us to add it.
|
|
249
|
+
|
|
250
|
+
- **OpenRouter is the on-ramp.** One key fronts **hundreds of models** (incl. vendors that have
|
|
251
|
+
no CLI of their own). Drop `OPENROUTER_API_KEY` in `~/.agent-bus/.env` and `openrouter` is a
|
|
252
|
+
seat: `trantor up openrouter` live-selects the best model for the work, or
|
|
253
|
+
`trantor up openrouter:openrouter/<vendor>/<model>` pins one.
|
|
254
|
+
- **Add any provider in one command:**
|
|
255
|
+
```bash
|
|
256
|
+
trantor provider add <name> --key sk-… --plan api # a provider OpenCode already knows
|
|
257
|
+
trantor provider add acme --key sk-… --base-url https://api.acme.ai/v1 --models acme-lg,acme-sm
|
|
258
|
+
```
|
|
259
|
+
The second form wires a **custom OpenAI-compatible endpoint** into OpenCode for you (no
|
|
260
|
+
hand-editing config). Then `trantor provider` lists every seat with its availability + tier, and
|
|
261
|
+
`trantor models [<provider>]` browses the live models behind a seat — including the router's pick
|
|
262
|
+
per difficulty so you can see *hard → strong, easy → cheap* at a glance.
|
|
263
|
+
- **It routes by difficulty, not just price.** `scrooge-capabilities` scores a provider's whole
|
|
264
|
+
catalog (real Artificial-Analysis benchmarks where a model matches, a price-tier proxy for the
|
|
265
|
+
long tail) and the router weighs **capability × cost, gated by the work's difficulty** — so hard
|
|
266
|
+
work escalates to a genuinely strong model while easy work stays cheap. Run it once (a weekly
|
|
267
|
+
cron keeps it fresh): `scrooge-capabilities`.
|
|
268
|
+
- **Every seat is its own colleague.** Each opencode-driven provider gets a distinct bus label
|
|
269
|
+
(`glm:<project>`, `openrouter:<project>`, `acme:<project>`), so they never collide and each shows
|
|
270
|
+
up as its own agent on the dashboard.
|
|
271
|
+
|
|
272
|
+
> Brought a key for Inception, a new Japanese model, a niche fine-tune? `trantor provider add` it,
|
|
273
|
+
> `scrooge-capabilities` scores it, and the Advisor routes to it by difficulty — same as the
|
|
274
|
+
> built-ins.
|
|
275
|
+
|
|
205
276
|
## Context handoff — sessions that never hit the wall
|
|
206
277
|
|
|
207
278
|
A PreCompact hook writes a rich handoff before Claude Code compacts; a fresh session in the
|
|
@@ -231,29 +302,41 @@ rate, not work rate.
|
|
|
231
302
|
## The CLI
|
|
232
303
|
|
|
233
304
|
```
|
|
234
|
-
trantor setup | doctor | connect | profile |
|
|
305
|
+
trantor setup | doctor | connect | profile | provider | models
|
|
306
|
+
| up <agents…> | swap <old> <new> | down | ui | advise | hub | watch
|
|
235
307
|
```
|
|
236
308
|
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
309
|
+
- **`trantor provider`** — `list` every crew seat (built-in + brought) with availability + tier ·
|
|
310
|
+
`add <name> --key … [--plan api] [--base-url <url> --models a,b]` to bring any provider (custom
|
|
311
|
+
endpoints are wired into OpenCode for you) · `remove <name>`.
|
|
312
|
+
- **`trantor models [<provider>]`** — browse the live models behind each seat + the router's pick
|
|
313
|
+
per difficulty.
|
|
314
|
+
- **`trantor up`** — `agent:model` pins a model (`deepseek:deepseek-v4-pro`); `agent:provider
|
|
315
|
+
--task <k> --difficulty <d>` picks the **best live model** for the work at spawn
|
|
316
|
+
(`glm:zai-coding-plan --difficulty hard`); spawns are verified on the bus with one retry;
|
|
317
|
+
geometry auto-detects the screen you're working on (`CREW_RECT="X,Y,W,H"` to override).
|
|
318
|
+
- **`trantor swap <oldAgent> <newSpec>`** replaces an exhausted agent with a live-selected one.
|
|
319
|
+
- **`trantor down`** kills crew processes via their ttys and closes windows without macOS
|
|
320
|
+
"Terminate?" dialogs.
|
|
243
321
|
|
|
244
322
|
## Works with any MCP agent
|
|
245
323
|
|
|
246
|
-
Claude Code, Codex CLI,
|
|
247
|
-
`trantor connect` automatically (idempotent,
|
|
248
|
-
Anything else that speaks MCP: point it at
|
|
249
|
-
server auto-registers the session, so presence
|
|
324
|
+
Claude Code, Codex CLI, Kimi Code CLI, and **OpenCode** (the universal adapter — DeepSeek, GLM,
|
|
325
|
+
OpenRouter, and any provider you bring) are wired by `trantor connect` automatically (idempotent,
|
|
326
|
+
backed-up, never overwrites your customizations). Anything else that speaks MCP: point it at
|
|
327
|
+
`mcp.mjs` with `RELAY_AGENT=<brand>` — loading the server auto-registers the session, so presence
|
|
328
|
+
works before the model says a word.
|
|
329
|
+
|
|
330
|
+
*(Gemini CLI: Google retired the free seat in 2026, so it's no longer a default crew seat —
|
|
331
|
+
GLM via OpenCode is its replacement. Gemini still works as a Scrooge cheap-model via
|
|
332
|
+
`GEMINI_API_KEY`, and a paid-key holder can still run `trantor up gemini`.)*
|
|
250
333
|
|
|
251
334
|
## How it works
|
|
252
335
|
|
|
253
336
|
```
|
|
254
|
-
Claude (architect/plugin) codex ─ runner
|
|
337
|
+
Claude (architect/plugin) codex ─ runner kimi ─ runner opencode ─ runner (DeepSeek·GLM·OpenRouter·BYOM)
|
|
255
338
|
│ advise/contracts │ one turn, exit; runner long-polls (free) + resumes with context
|
|
256
|
-
|
|
339
|
+
└───────────┬─────────────┴──────────────┴───────────────────────────────────┘
|
|
257
340
|
▼
|
|
258
341
|
hub.mjs ←— plain HTTP + SSE · presence/messages/board/history/lessons/learning/economics
|
|
259
342
|
(Node built-ins only · state in ~/.agent-bus/bus.json · loopback by default)
|
|
@@ -286,10 +369,11 @@ The `relay_*` tool names and the `~/.agent-bus` state dir remain until a later r
|
|
|
286
369
|
## Tests
|
|
287
370
|
|
|
288
371
|
```bash
|
|
289
|
-
npm test #
|
|
290
|
-
# honest presence + TTL prune, spawn no-shows, the testing gate,
|
|
291
|
-
# /history + backfill, /learning shape, /todos sync, /card detail,
|
|
292
|
-
# plan tiers,
|
|
372
|
+
npm test # unit + 120+ protocol-level scenario drills + capability-routing, all with mock agents
|
|
373
|
+
# (no LLMs, seconds, $0): honest presence + TTL prune, spawn no-shows, the testing gate,
|
|
374
|
+
# bounce trails, lessons, /history + backfill, /learning shape, /todos sync, /card detail,
|
|
375
|
+
# advisor decisions across plan tiers, BYOM roster derivation + brought-provider routing,
|
|
376
|
+
# difficulty-aware model selection, deps validation, virgin-machine doctor, failure drills
|
|
293
377
|
```
|
|
294
378
|
|
|
295
379
|
## License
|
package/bin/cli.mjs
CHANGED
|
@@ -23,7 +23,7 @@ switch (cmd) {
|
|
|
23
23
|
case "advise": run("bin/advise.mjs"); break;
|
|
24
24
|
case "verify": run("bin/crew-verify.mjs"); break;
|
|
25
25
|
case "up": process.argv.splice(2, 1); spawn("/bin/bash", [join(ROOT, "bin/crew.sh"), "up", ...args], { stdio: "inherit", cwd: process.cwd() }).on("exit", c => process.exit(c ?? 0)); break;
|
|
26
|
-
case "down": spawn("/bin/bash", [join(ROOT, "bin/crew.sh"), "down"], { stdio: "inherit", cwd: process.cwd() }).on("exit", c => process.exit(c ?? 0)); break;
|
|
26
|
+
case "down": spawn("/bin/bash", [join(ROOT, "bin/crew.sh"), "down", ...args], { stdio: "inherit", cwd: process.cwd() }).on("exit", c => process.exit(c ?? 0)); break;
|
|
27
27
|
case "swap": spawn("/bin/bash", [join(ROOT, "bin/crew.sh"), "swap", ...args], { stdio: "inherit", cwd: process.cwd() }).on("exit", c => process.exit(c ?? 0)); break;
|
|
28
28
|
case "hub": run("hub.mjs"); break;
|
|
29
29
|
case "watch": run("bin/relay-watch.mjs"); break;
|
|
@@ -31,6 +31,7 @@ switch (cmd) {
|
|
|
31
31
|
case "agents": run("bin/agents.mjs"); break;
|
|
32
32
|
case "gates": run("bin/gates.mjs"); break;
|
|
33
33
|
case "backfill": run("bin/git-backfill.mjs"); break;
|
|
34
|
+
case "sweep": run("bin/sweep.mjs"); break;
|
|
34
35
|
case "init-hooks": run("bin/init-hooks.mjs"); break;
|
|
35
36
|
case "balances": case "balance": case "credits": run("bin/balances.mjs"); break;
|
|
36
37
|
case "recost": run("bin/recost.mjs"); break;
|
package/bin/crew-runner.mjs
CHANGED
|
@@ -50,6 +50,22 @@ async function api(path, body) {
|
|
|
50
50
|
return r.json();
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
+
// ---- cmux sidebar integration ----
|
|
54
|
+
// When this runner is inside a cmux surface (CMUX_SURFACE_ID is auto-set there), push its live state into
|
|
55
|
+
// cmux's sidebar for THIS seat. An inside process is allowed by cmux's default cmuxOnly socket mode — no
|
|
56
|
+
// allowAll needed. Fail-silent + short timeout; must never block or slow a turn.
|
|
57
|
+
const CMUX_BIN = process.env.CMUX_BIN
|
|
58
|
+
|| (existsSync("/Applications/cmux.app/Contents/Resources/bin/cmux") ? "/Applications/cmux.app/Contents/Resources/bin/cmux" : "cmux");
|
|
59
|
+
const inCmux = () => !!process.env.CMUX_SURFACE_ID;
|
|
60
|
+
function cmuxStatus(value, color, icon = "robot") {
|
|
61
|
+
if (!inCmux()) return;
|
|
62
|
+
try { spawnSync(CMUX_BIN, ["set-status", "trantor", value, "--color", color, "--icon", icon], { stdio: "ignore", timeout: 1500, env: { ...process.env, CMUX_QUIET: "1" } }); } catch {}
|
|
63
|
+
}
|
|
64
|
+
function cmuxLog(message, level = "info") {
|
|
65
|
+
if (!inCmux()) return;
|
|
66
|
+
try { spawnSync(CMUX_BIN, ["log", String(message).slice(0, 200), "--level", level], { stdio: "ignore", timeout: 1500, env: { ...process.env, CMUX_QUIET: "1" } }); } catch {}
|
|
67
|
+
}
|
|
68
|
+
|
|
53
69
|
// ---- per-CLI invocation (first turn vs resume turn). {P} = prompt file path ----
|
|
54
70
|
// CREW_MODEL env pins the model: each CLI gets its own flag via {M} (empty when unset).
|
|
55
71
|
let MODEL = process.env.CREW_MODEL || "";
|
|
@@ -119,6 +135,7 @@ async function reportFailure(exit, trigger) {
|
|
|
119
135
|
? `🛑 ${SESSION} DOWN — ${consecFails} consecutive failures (${reason}, exit ${exit})${hint}`
|
|
120
136
|
: `⚠️ ${SESSION} turn FAILED (${trigger}, exit ${exit} · ${reason})${hint}`;
|
|
121
137
|
await api("/send", { from: SESSION, to: "all", text, project: PROJ }).catch(() => {});
|
|
138
|
+
cmuxStatus(down ? "down" : "error", "#ef6a6a", "alert"); cmuxLog(`turn failed: ${reason} (exit ${exit})`, "error");
|
|
122
139
|
log(`\x1b[31mreported failure to bus: ${reason} (exit ${exit})\x1b[0m`);
|
|
123
140
|
}
|
|
124
141
|
|
|
@@ -127,6 +144,7 @@ async function reportHealthy() {
|
|
|
127
144
|
consecFails = 0;
|
|
128
145
|
await api("/register", { session: SESSION, project: PROJ, status: `active in ${PROJ}` }).catch(() => {});
|
|
129
146
|
await api("/send", { from: SESSION, to: "all", text: `✅ ${SESSION} recovered`, project: PROJ }).catch(() => {});
|
|
147
|
+
cmuxStatus("ok", "#14b8a6", "check");
|
|
130
148
|
}
|
|
131
149
|
|
|
132
150
|
let sid = "";
|
|
@@ -142,6 +160,7 @@ function runTurn(prompt, isFirst, trigger = "kickoff") {
|
|
|
142
160
|
const envs = [join(homedir(), ".agent-bus", ".env"), cli.env].filter(f => f && existsSync(f));
|
|
143
161
|
for (const f of envs.reverse()) cmd = `set -a; source ${f}; set +a; ${cmd}`; // ~/.agent-bus/.env wins
|
|
144
162
|
log(`turn starting (${isFirst ? "fresh session" : "resume"})${MODEL ? ` · model=${MODEL}` : ""}`);
|
|
163
|
+
cmuxStatus("building", "#4a90d9", "hammer");
|
|
145
164
|
// inherit stdio so the window shows the agent working live; also capture for sid-parsing.
|
|
146
165
|
// Tee stderr to ERRF (still shown live in the window) so a failed turn can be classified.
|
|
147
166
|
try { appendFileSync(ERRF, "", { flag: "w" }); } catch {}
|
|
@@ -155,6 +174,7 @@ function runTurn(prompt, isFirst, trigger = "kickoff") {
|
|
|
155
174
|
if (cli.sid && r.stdout) { const m = r.stdout.match(cli.sid); if (m) sid = m[1]; }
|
|
156
175
|
telemetry({ ts: Date.now(), agent: AGENT, project: PROJ, turn: TURN, trigger, model: MODEL || "default", duration_ms: Date.now() - t0, exit: r.status });
|
|
157
176
|
log(`turn ended (exit ${r.status}, ${((Date.now() - t0) / 1000).toFixed(0)}s)`);
|
|
177
|
+
if (r.status === 0) cmuxStatus("idle", "#8a94a6", "robot"); // finished this turn, waiting for the next
|
|
158
178
|
return r.status;
|
|
159
179
|
}
|
|
160
180
|
|