trantor 0.17.17 → 0.17.18
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/package.json +1 -1
- package/ui.html +11 -7
|
@@ -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.18"
|
|
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, Gemini, 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.18",
|
|
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.18",
|
|
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/package.json
CHANGED
package/ui.html
CHANGED
|
@@ -470,25 +470,26 @@ function wireTimeline(el){
|
|
|
470
470
|
view.style.left = (100 * s.scrollLeft / w) + '%';
|
|
471
471
|
view.style.width = Math.min(100, 100 * s.clientWidth / w) + '%';
|
|
472
472
|
};
|
|
473
|
-
s.onscroll = () => { GSCROLL[proj] = s.scrollLeft; syncView(); };
|
|
473
|
+
s.onscroll = () => { GSCROLL[proj] = s.scrollLeft; flowBusy = Date.now(); syncView(); }; // flag busy so render() defers
|
|
474
474
|
requestAnimationFrame(syncView);
|
|
475
475
|
if (map) {
|
|
476
476
|
const scrubTo = (clientX) => { // map a pointer x onto a scroll position (centered)
|
|
477
477
|
const r = map.getBoundingClientRect();
|
|
478
478
|
const ratio = Math.max(0, Math.min(1, (clientX - r.left) / r.width));
|
|
479
|
+
flowBusy = Date.now(); // keep render() off the board WHILE scrubbing
|
|
479
480
|
s.scrollLeft = ratio * s.scrollWidth - s.clientWidth / 2;
|
|
480
481
|
};
|
|
481
|
-
let
|
|
482
|
+
let scrubbing = false;
|
|
482
483
|
map.addEventListener('pointerdown', e => {
|
|
483
|
-
|
|
484
|
+
scrubbing = true; flowBusy = Date.now();
|
|
484
485
|
try { map.setPointerCapture?.(e.pointerId); } catch {}
|
|
485
486
|
const seg = e.target.closest && e.target.closest('.gmapseg'); // click a phase segment → jump to that phase
|
|
486
487
|
if (seg && seg.dataset.cx != null) s.scrollLeft = +seg.dataset.cx - 40; else scrubTo(e.clientX);
|
|
487
488
|
e.preventDefault();
|
|
488
489
|
});
|
|
489
|
-
map.addEventListener('pointermove', e => { if (
|
|
490
|
-
const end = () => {
|
|
491
|
-
map.addEventListener('pointerup', end); map.addEventListener('pointercancel', end);
|
|
490
|
+
map.addEventListener('pointermove', e => { if (scrubbing) scrubTo(e.clientX); });
|
|
491
|
+
const end = () => { scrubbing = false; flowBusy = Date.now(); }; // freshen lock on release so the next render is deferred ~1s
|
|
492
|
+
map.addEventListener('pointerup', end); map.addEventListener('pointercancel', end); map.addEventListener('lostpointercapture', end);
|
|
492
493
|
}
|
|
493
494
|
});
|
|
494
495
|
el.querySelectorAll('.gnode[data-id]').forEach(n => n.onclick = () => openCard(+n.dataset.id));
|
|
@@ -526,6 +527,8 @@ async function openCard(id){
|
|
|
526
527
|
}
|
|
527
528
|
function closeCard(){ const el=$('#cardmodal'); el.style.display='none'; el.innerHTML=''; if(cardEsc){ document.removeEventListener('keydown', cardEsc); cardEsc=null; } }
|
|
528
529
|
let dragging = null; // suppresses re-render mid-gesture
|
|
530
|
+
let flowBusy = 0; // timestamp of the last FLOW scrub/scroll — render() defers while you interact
|
|
531
|
+
// (the 2.5s poll / SSE rebuild was replacing the scrubber DOM mid-drag → freeze)
|
|
529
532
|
function saveCam(proj, cam){ const c = JSON.parse(localStorage.getItem("abFlowCam") || "{}"); c[proj] = cam; localStorage.setItem("abFlowCam", JSON.stringify(c)); }
|
|
530
533
|
function wireFlow(el){
|
|
531
534
|
el.querySelectorAll(".flowwrap").forEach(w => {
|
|
@@ -671,7 +674,8 @@ async function render(){
|
|
|
671
674
|
return SEEN.indexOf(a.project)-SEEN.indexOf(b.project); // stable first-seen order
|
|
672
675
|
});
|
|
673
676
|
const el=$('#boards');
|
|
674
|
-
if(dragging)return; // never rebuild mid-gesture
|
|
677
|
+
if(dragging)return; // never rebuild mid-gesture (project drag / pan)
|
|
678
|
+
if(Date.now()-flowBusy < 1000){ clearTimeout(render._t); render._t=setTimeout(render,1100); return; } // ...nor mid-scrub/scroll; catch up shortly after
|
|
675
679
|
if(!projects.length){el.innerHTML='<div class="empty big">no projects yet — agents register a project on connect</div>';return;}
|
|
676
680
|
const idleOpen=new Set(JSON.parse(localStorage.getItem("abIdleOpen")||"[]"));
|
|
677
681
|
const projBlock=p=>{
|