nothumanallowed 13.5.7 → 13.5.8

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nothumanallowed",
3
- "version": "13.5.7",
3
+ "version": "13.5.8",
4
4
  "description": "NotHumanAllowed — 38 AI agents, 80 tools, Studio (visual agentic workflows). Email, calendar, browser automation, screen capture, canvas, cron/heartbeat, Alexandria E2E messaging, GitHub, Notion, Slack, voice chat, free AI (Liara), 28 languages. Zero-dependency CLI.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -3790,8 +3790,11 @@ ${writtenSoFar ? `## REPORT WRITTEN SO FAR (for consistency):\n${writtenSoFar.sl
3790
3790
  }
3791
3791
 
3792
3792
  // Estimate token usage (aprox: 1 token ≈ 4 chars)
3793
- const inTokens = Math.ceil((sysPrompt.length + userMsg.length) / 4);
3794
- const outTokens = Math.ceil(fullOutput.length / 4);
3793
+ // Include context + toolData in input estimate since they're sent in the prompt
3794
+ const contextLen = (context || '').length;
3795
+ const toolDataLen = (toolData || '').length;
3796
+ const inTokens = Math.ceil((sysPrompt.length + userMsg.length + contextLen + toolDataLen) / 4);
3797
+ const outTokens = Math.ceil(fullOutputClean.length / 4);
3795
3798
  clearInterval(keepalive);
3796
3799
  sendEvent({ usage: { input: inTokens, output: outTokens } });
3797
3800
  sendEvent({ done: true });
package/src/constants.mjs CHANGED
@@ -5,7 +5,7 @@ import { fileURLToPath } from 'url';
5
5
  const __filename = fileURLToPath(import.meta.url);
6
6
  const __dirname = path.dirname(__filename);
7
7
 
8
- export const VERSION = '13.5.7';
8
+ export const VERSION = '13.5.8';
9
9
  export const BASE_URL = 'https://nothumanallowed.com/cli';
10
10
  export const API_BASE = 'https://nothumanallowed.com/api/v1';
11
11
 
@@ -3626,70 +3626,127 @@ function officeRoomDecor() {
3626
3626
  // Characters are positioned with position:absolute, scale by row for depth.
3627
3627
  var ISO_TILE_W = 72;
3628
3628
  var ISO_TILE_H = 36;
3629
- var ISO_ORIGIN_X = 260; // center-left of scene
3630
- var ISO_ORIGIN_Y = 40; // top of scene
3629
+ var ISO_ORIGIN_X = 300;
3630
+ var ISO_ORIGIN_Y = 60;
3631
3631
  function isoProject(col, row) {
3632
3632
  return {
3633
3633
  x: ISO_ORIGIN_X + (col - row) * (ISO_TILE_W / 2),
3634
3634
  y: ISO_ORIGIN_Y + (col + row) * (ISO_TILE_H / 2)
3635
3635
  };
3636
3636
  }
3637
- // Draw isometric floor tiles as SVG
3637
+
3638
+ // Full bright office scene SVG background
3638
3639
  function isoFloorSvg(cols, rows) {
3639
- var w = 600; var h = 240;
3640
+ var w = 640; var h = 320;
3640
3641
  var out = \x27<svg viewBox="0 0 \x27+w+\x27 \x27+h+\x27" width="\x27+w+\x27" height="\x27+h+\x27" xmlns="http://www.w3.org/2000/svg" style="position:absolute;top:0;left:0;pointer-events:none;z-index:0">\x27;
3641
- // Back wall — two side walls
3642
- out += \x27<polygon points="0,80 300,20 300,100 0,160" fill="#1a1535" opacity=".7"/>\x27;
3643
- out += \x27<polygon points="300,20 600,80 600,160 300,100" fill="#141030" opacity=".7"/>\x27;
3644
- // Wall top edge
3645
- out += \x27<line x1="0" y1="80" x2="300" y2="20" stroke="#3a3060" stroke-width="1.5"/>\x27;
3646
- out += \x27<line x1="300" y1="20" x2="600" y2="80" stroke="#3a3060" stroke-width="1.5"/>\x27;
3647
- // Wall window left
3648
- out += \x27<polygon points="60,82 130,62 130,102 60,122" fill="#1a2840" stroke="#2a4060" stroke-width="1"/>\x27;
3649
- out += \x27<polygon points="65,85 125,66 125,98 65,117" fill="#7ecfff" opacity=".15" stroke="#4a90c0" stroke-width=".5"/>\x27;
3650
- // Wall window right
3651
- out += \x27<polygon points="470,82 540,62 540,102 470,122" fill="#1a2840" stroke="#2a4060" stroke-width="1"/>\x27;
3652
- out += \x27<polygon points="475,85 535,66 535,98 475,117" fill="#7ecfff" opacity=".15" stroke="#4a90c0" stroke-width=".5"/>\x27;
3653
- // Sunlight shafts
3654
- out += \x27<polygon points="80,102 120,90 125,160 85,175" fill="rgba(200,230,255,.04)"/>\x27;
3655
- out += \x27<polygon points="490,90 530,102 535,175 495,160" fill="rgba(200,230,255,.04)"/>\x27;
3656
- // Ceiling lamp
3657
- out += \x27<ellipse cx="300" cy="22" rx="20" ry="6" fill="#2a2050" stroke="#4a3080" stroke-width="1"/>\x27;
3658
- out += \x27<ellipse cx="300" cy="24" rx="18" ry="10" fill="rgba(255,220,100,.12)"/>\x27;
3659
- out += \x27<line x1="300" y1="0" x2="300" y2="22" stroke="#3a3060" stroke-width="1.5"/>\x27;
3660
- // Floor tiles iso grid
3661
- for (var r = 0; r < rows; r++) {
3662
- for (var c = 0; c < cols; c++) {
3663
- var p = isoProject(c, r);
3664
- var tx = p.x; var ty = p.y + 80;
3665
- // Diamond tile
3666
- var pts = (tx)+\x27,\x27+(ty) + \x27 \x27+(tx+ISO_TILE_W/2)+\x27,\x27+(ty+ISO_TILE_H/2) + \x27 \x27+tx+\x27,\x27+(ty+ISO_TILE_H) + \x27 \x27+(tx-ISO_TILE_W/2)+\x27,\x27+(ty+ISO_TILE_H/2);
3667
- var tileEven = (r+c) % 2 === 0;
3668
- out += \x27<polygon points="\x27+pts+\x27" fill="\x27+(tileEven?\x27#1e1840\x27:\x27#1a1535\x27)+\x27" stroke="#2a2050" stroke-width=".8"/>\x27;
3669
- // Tile highlight (top-left edge)
3670
- out += \x27<line x1="\x27+(tx-ISO_TILE_W/2)+\x27" y1="\x27+(ty+ISO_TILE_H/2)+\x27" x2="\x27+tx+\x27" y2="\x27+ty+\x27" stroke="rgba(255,255,255,.04)" stroke-width=".6"/>\x27;
3642
+
3643
+ // ── BACK WALL (white/cream) ──────────────────────────────────────────
3644
+ out += \x27<polygon points="0,100 320,20 320,120 0,200" fill="#f5f3ee"/>\x27;
3645
+ out += \x27<polygon points="320,20 640,100 640,200 320,120" fill="#edeae3"/>\x27;
3646
+ out += \x27<line x1="0" y1="100" x2="320" y2="20" stroke="#ccc" stroke-width="1.5"/>\x27;
3647
+ out += \x27<line x1="320" y1="20" x2="640" y2="100" stroke="#bbb" stroke-width="1.5"/>\x27;
3648
+ // Wall corner vertical line
3649
+ out += \x27<line x1="320" y1="20" x2="320" y2="120" stroke="#c8c4bc" stroke-width="1"/>\x27;
3650
+
3651
+ // ── WINDOWS — 3 centered on left wall ────────────────────────────────
3652
+ // Win L1
3653
+ out += \x27<polygon points="30,122 90,102 90,155 30,175" fill="#d0eeff" stroke="#aac8e8" stroke-width="1"/>\x27;
3654
+ out += \x27<line x1="60,112" y1="60" x2="60" y2="130" stroke="#aac8e8" stroke-width=".8"/>\x27;
3655
+ out += \x27<line x1="30,148" y1="148" x2="90" y2="128" stroke="#aac8e8" stroke-width=".8"/>\x27;
3656
+ out += \x27<polygon points="30,122 90,102 90,108 30,128" fill="#b8ddf8" opacity=".4"/>\x27;
3657
+ out += \x27<polygon points="30,122 90,102 90,155 30,175" fill="rgba(200,230,255,.12)"/>\x27;
3658
+ // Win L2 (center-left)
3659
+ out += \x27<polygon points="110,102 175,80 175,132 110,154" fill="#d0eeff" stroke="#aac8e8" stroke-width="1"/>\x27;
3660
+ out += \x27<polygon points="110,102 175,80 175,88 110,110" fill="#b8ddf8" opacity=".4"/>\x27;
3661
+ out += \x27<line x1="142" y1="91" x2="142" y2="143" stroke="#aac8e8" stroke-width=".8"/>\x27;
3662
+ out += \x27<line x1="110" y1="128" x2="175" y2="106" stroke="#aac8e8" stroke-width=".8"/>\x27;
3663
+ out += \x27<polygon points="110,102 175,80 175,132 110,154" fill="rgba(200,230,255,.10)"/>\x27;
3664
+ // Win L3 (center)
3665
+ out += \x27<polygon points="195,88 255,68 255,118 195,138" fill="#d0eeff" stroke="#aac8e8" stroke-width="1"/>\x27;
3666
+ out += \x27<polygon points="195,88 255,68 255,76 195,96" fill="#b8ddf8" opacity=".4"/>\x27;
3667
+ out += \x27<line x1="225" y1="78" x2="225" y2="128" stroke="#aac8e8" stroke-width=".8"/>\x27;
3668
+ out += \x27<line x1="195" y1="113" x2="255" y2="93" stroke="#aac8e8" stroke-width=".8"/>\x27;
3669
+ // Sunlight shafts from windows
3670
+ out += \x27<polygon points="50,155 90,140 120,260 80,275" fill="rgba(255,250,220,.06)"/>\x27;
3671
+ out += \x27<polygon points="130,132 175,116 200,260 155,275" fill="rgba(255,250,220,.05)"/>\x27;
3672
+ out += \x27<polygon points="210,116 255,100 270,260 225,275" fill="rgba(255,250,220,.04)"/>\x27;
3673
+
3674
+ // ── ART on left wall ────────────────────────────────────────────────
3675
+ // Frame 1 (small painting near top-right of left wall)
3676
+ out += \x27<polygon points="275,72 310,60 310,90 275,102" fill="#e8e4dc" stroke="#bbb" stroke-width="1"/>\x27;
3677
+ out += \x27<polygon points="278,74 307,63 307,88 278,99" fill="#7a9ed4"/>\x27;
3678
+ out += \x27<polygon points="285,77 303,70 303,84 285,91" fill="#a8c4e8"/>\x27;
3679
+ out += \x27<ellipse cx="294" cy="80" rx="5" ry="4" fill="#fff" opacity=".5"/>\x27;
3680
+
3681
+ // ── PLANT (bottom-left corner) ───────────────────────────────────────
3682
+ out += \x27<ellipse cx="30" cy="188" rx="10" ry="5" fill="#2d4a1e" opacity=".7"/>\x27;
3683
+ out += \x27<rect x="25" y="178" width="10" height="10" rx="2" fill="#5a3a1a"/>\x27;
3684
+ out += \x27<path d="M30 178 C25 165 18 155 22 148 C26 142 30 148 30 178" fill="#3a7a1e"/>\x27;
3685
+ out += \x27<path d="M30 178 C35 162 42 155 38 148 C34 142 30 150 30 178" fill="#4a8a26"/>\x27;
3686
+ out += \x27<path d="M30 175 C22 168 16 160 18 153" stroke="#3a7a1e" stroke-width="2" fill="none" stroke-linecap="round"/>\x27;
3687
+ out += \x27<path d="M30 170 C38 165 44 158 42 151" stroke="#4a8a26" stroke-width="2" fill="none" stroke-linecap="round"/>\x27;
3688
+
3689
+ // ── CEILING CHANDELIER with glow ─────────────────────────────────────
3690
+ out += \x27<line x1="320" y1="0" x2="320" y2="18" stroke="#999" stroke-width="2"/>\x27;
3691
+ // Chandelier body
3692
+ out += \x27<ellipse cx="320" cy="18" rx="24" ry="7" fill="#d4c88a" stroke="#b8a860" stroke-width="1.5"/>\x27;
3693
+ out += \x27<ellipse cx="320" cy="22" rx="20" ry="5" fill="#e8d898"/>\x27;
3694
+ // Bulbs hanging down
3695
+ out += \x27<circle cx="305" cy="28" r="5" fill="#fffbe8" filter="url(#glow)"/>\x27;
3696
+ out += \x27<circle cx="320" cy="26" r="6" fill="#fffbe8" filter="url(#glow)"/>\x27;
3697
+ out += \x27<circle cx="335" cy="28" r="5" fill="#fffbe8" filter="url(#glow)"/>\x27;
3698
+ out += \x27<line x1="305" y1="22" x2="305" y2="28" stroke="#aaa" stroke-width=".8"/>\x27;
3699
+ out += \x27<line x1="320" y1="22" x2="320" y2="26" stroke="#aaa" stroke-width=".8"/>\x27;
3700
+ out += \x27<line x1="335" y1="22" x2="335" y2="28" stroke="#aaa" stroke-width=".8"/>\x27;
3701
+ // Light cone glow on floor/walls
3702
+ out += \x27<radialGradient id="chandelierGlow" cx="50%" cy="0%" r="60%"><stop offset="0%" stop-color="rgba(255,245,180,.22)"/><stop offset="100%" stop-color="rgba(255,245,180,0)"/></radialGradient>\x27;
3703
+ out += \x27<filter id="glow"><feGaussianBlur stdDeviation="3" result="blur"/><feMerge><feMergeNode in="blur"/><feMergeNode in="SourceGraphic"/></feMerge></filter>\x27;
3704
+ out += \x27<ellipse cx="320" cy="180" rx="200" ry="120" fill="url(#chandelierGlow)"/>\x27;
3705
+
3706
+ // ── PARQUET FLOOR — long narrow planks ───────────────────────────────
3707
+ // Draw rectangular plank tiles in iso projection
3708
+ var PLANK_W = ISO_TILE_W; var PLANK_H = ISO_TILE_H;
3709
+ var plankColors = [\x27#b5854a\x27,\x27#a8783c\x27,\x27#bf9055\x27,\x27#c49a60\x27,\x27#a07234\x27];
3710
+ for (var r2 = 0; r2 < rows; r2++) {
3711
+ for (var c2 = 0; c2 < cols; c2++) {
3712
+ var pp = isoProject(c2, r2);
3713
+ var ptx = pp.x; var pty = pp.y + 110;
3714
+ var pIdx = (r2 * 3 + c2) % plankColors.length;
3715
+ var pFill = plankColors[pIdx];
3716
+ var ppts = ptx+\x27,\x27+pty+\x27 \x27+(ptx+PLANK_W/2)+\x27,\x27+(pty+PLANK_H/2)+\x27 \x27+ptx+\x27,\x27+(pty+PLANK_H)+\x27 \x27+(ptx-PLANK_W/2)+\x27,\x27+(pty+PLANK_H/2);
3717
+ out += \x27<polygon points="\x27+ppts+\x27" fill="\x27+pFill+\x27" stroke="#8a6028" stroke-width=".7" opacity=".95"/>\x27;
3718
+ // Plank grain lines (long horizontal across plank)
3719
+ out += \x27<line x1="\x27+(ptx-PLANK_W/2+4)+\x27" y1="\x27+(pty+PLANK_H/2)+\x27" x2="\x27+(ptx+PLANK_W/2-4)+\x27" y2="\x27+(pty+PLANK_H/2)+\x27" stroke="rgba(0,0,0,.06)" stroke-width=".5"/>\x27;
3671
3720
  }
3672
3721
  }
3722
+ // Floor highlight (lamp reflection)
3723
+ out += \x27<ellipse cx="320" cy="220" rx="90" ry="30" fill="rgba(255,250,200,.08)"/>\x27;
3724
+
3673
3725
  out += \x27</svg>\x27;
3674
3726
  return out;
3675
3727
  }
3676
- // Small isometric desk object at iso position
3728
+ // Small isometric desk object at iso position — bright wood
3677
3729
  function isoDeskSvg(x, y, accentColor) {
3678
- var ac = accentColor || \x27#3a3060\x27;
3679
- return \x27<svg viewBox="0 0 64 40" width="64" height="40" xmlns="http://www.w3.org/2000/svg" style="position:absolute;left:\x27+(x-32)+\x27px;top:\x27+(y+10)+\x27px;z-index:\x27+(Math.round(y))+\x27;pointer-events:none">\x27+
3680
- // Desk top face
3681
- \x27<polygon points="32,4 56,16 32,28 8,16" fill="#1e1840" stroke="\x27+ac+\x27" stroke-width="1.2"/>\x27+
3730
+ var ac = accentColor || \x27#888\x27;
3731
+ var doneDesk = ac === \x27#22c55e\x27;
3732
+ return \x27<svg viewBox="0 0 72 44" width="72" height="44" xmlns="http://www.w3.org/2000/svg" style="position:absolute;left:\x27+(x-36)+\x27px;top:\x27+(y+8)+\x27px;z-index:\x27+(Math.round(y))+\x27;pointer-events:none">\x27+
3733
+ // Desk top face warm wood
3734
+ \x27<polygon points="36,4 62,18 36,32 10,18" fill="#d4a855" stroke="#b8893a" stroke-width="1"/>\x27+
3735
+ \x27<polygon points="36,4 62,18 36,32 10,18" fill="rgba(255,255,255,.08)"/>\x27+
3736
+ // Grain lines on top
3737
+ \x27<line x1="22" y1="18" x2="50" y2="10" stroke="rgba(0,0,0,.1)" stroke-width=".8"/>\x27+
3738
+ \x27<line x1="22" y1="22" x2="50" y2="14" stroke="rgba(0,0,0,.07)" stroke-width=".8"/>\x27+
3682
3739
  // Desk right face
3683
- \x27<polygon points="56,16 56,32 32,44 32,28" fill="#120e28" stroke="\x27+ac+\x2788" stroke-width=".8"/>\x27+
3740
+ \x27<polygon points="62,18 62,36 36,50 36,32" fill="#a8783c" stroke="#8a5c28" stroke-width=".8"/>\x27+
3684
3741
  // Desk left face
3685
- \x27<polygon points="8,16 32,28 32,44 8,32" fill="#161230" stroke="\x27+ac+\x2766" stroke-width=".8"/>\x27+
3686
- // Monitor on desk
3687
- \x27<polygon points="24,8 38,14 38,22 24,16" fill="\x27+(ac===\x27#22c55e\x27?\x27#0a2010\x27:\x27#0d0d1e\x27)+\x27" stroke="\x27+ac+\x27" stroke-width="1"/>\x27+
3688
- \x27<polygon points="24,10 36,15 36,20 24,15" fill="\x27+(ac===\x27#22c55e\x27?\x27#0a2810\x27:\x27#111128\x27)+\x27"/>\x27+
3689
- // Screen lines
3690
- \x27<line x1="26" y1="12" x2="34" y2="15" stroke="\x27+ac+\x27" stroke-width=".8" opacity=".8"/>\x27+
3691
- \x27<line x1="26" y1="14" x2="33" y2="17" stroke="\x27+ac+\x27" stroke-width=".8" opacity=".5"/>\x27+
3692
- \x27<line x1="26" y1="16" x2="32" y2="18" stroke="\x27+ac+\x27" stroke-width=".8" opacity=".3"/>\x27+
3742
+ \x27<polygon points="10,18 36,32 36,50 10,36" fill="#c49050" stroke="#9e7234" stroke-width=".8"/>\x27+
3743
+ // Monitor on desk — light screen
3744
+ \x27<polygon points="28,10 44,16 44,26 28,20" fill="#1e2840" stroke="\x27+ac+\x27" stroke-width="1.2"/>\x27+
3745
+ \x27<polygon points="29,11 43,17 43,25 29,19" fill="\x27+(doneDesk?\x27#0d2010\x27:\x27#0d1a2e\x27)+\x27"/>\x27+
3746
+ // Screen glow lines
3747
+ \x27<line x1="31" y1="14" x2="41" y2="18" stroke="\x27+ac+\x27" stroke-width=".9" opacity=".8"/>\x27+
3748
+ \x27<line x1="31" y1="17" x2="40" y2="20" stroke="\x27+ac+\x27" stroke-width=".9" opacity=".5"/>\x27+
3749
+ \x27<line x1="31" y1="20" x2="39" y2="23" stroke="\x27+ac+\x27" stroke-width=".9" opacity=".3"/>\x27+
3693
3750
  \x27</svg>\x27;
3694
3751
  }
3695
3752
  // Isometric JRPG sprite character — top-down 3/4 perspective, Pokemon-style
@@ -3835,10 +3892,8 @@ function renderStudioNodes() {
3835
3892
 
3836
3893
  // ── ISO scene dimensions ───────────────────────────────────────────────────
3837
3894
  var ISO_COLS = Math.max(nodes.length, 1);
3838
- var SCENE_W = 600; var SCENE_H = 260;
3895
+ var SCENE_W = 640; var SCENE_H = 420;
3839
3896
 
3840
- // Distribute agents along row=1 of the iso grid, spaced evenly
3841
- // Orchestrator walks on row=0 (further back = smaller)
3842
3897
  var agentsHtml = \x27\x27;
3843
3898
  nodes.forEach(function(n, idx) {
3844
3899
  var isActive = n.status === \x27running\x27;
@@ -3846,39 +3901,34 @@ function renderStudioNodes() {
3846
3901
  var isErr = n.status === \x27error\x27;
3847
3902
  var lbl = n.label || n.agent;
3848
3903
  var pal = agentPalette(lbl);
3849
- var accentColor = isActive ? \x27#6366f1\x27 : (isDone ? \x27#22c55e\x27 : (isErr ? \x27#ef4444\x27 : \x27#3a3060\x27));
3904
+ var accentColor = isActive ? \x27#6366f1\x27 : (isDone ? \x27#22c55e\x27 : (isErr ? \x27#ef4444\x27 : \x27#999\x27));
3850
3905
 
3851
- // Iso position: spread across columns, agents sit at row=2 (front row)
3852
- var col = (idx + 0.5) * (ISO_COLS > 1 ? (ISO_COLS - 1) / ISO_COLS : 1) + 0.5;
3853
- col = (idx * (ISO_COLS <= 1 ? 2 : (4 / ISO_COLS))) + 1;
3854
- var row = 2.5;
3906
+ // Spread agents evenly across front rows
3907
+ var colStep = ISO_COLS > 1 ? 5 / (ISO_COLS - 1) : 2;
3908
+ var col = (ISO_COLS === 1) ? 2.5 : idx * colStep;
3909
+ var row = 3.5;
3855
3910
  var pos = isoProject(col, row);
3856
- var px = pos.x; var py = pos.y + 40;
3857
- // scale: row 2.5 = 1.0, background rows smaller
3858
- var charScale = 0.9 + row * 0.08;
3911
+ var px = pos.x; var py = pos.y + 80;
3912
+ var charScale = 1.1;
3859
3913
  var zIdx = Math.round(py + 100);
3860
3914
 
3861
- // Speech bubble content
3862
- var bubbleText = \x27\x27;
3863
- var bubbleColor = \x27#6366f1\x27;
3864
- if (isActive) { bubbleText = \x27...lavora\x27; bubbleColor = \x27#6366f1\x27; }
3865
- else if (isDone) { bubbleText = \x27\u2714 fatto\x27; bubbleColor = \x27#22c55e\x27; }
3866
- else if (isErr) { bubbleText = \x27\u2715 errore\x27; bubbleColor = \x27#ef4444\x27; }
3867
- else { bubbleText = \x27in attesa\x27; bubbleColor = \x27#4a4a6a\x27; }
3868
-
3915
+ // Bubble: only show when active (live text) or done (checkmark)
3916
+ var bubbleText = isActive ? \x27...lavora\x27 : (isDone ? \x27\u2714 fatto\x27 : (isErr ? \x27\u2715 errore\x27 : \x27\x27));
3917
+ var bubbleColor = isActive ? \x27#6366f1\x27 : (isDone ? \x27#22c55e\x27 : \x27#ef4444\x27);
3869
3918
  var charSvg = isoCharSvg({skin: pal.skin, shirt: pal.shirt, hair: pal.hair,
3870
3919
  isActive: isActive, isDone: isDone, scale: charScale, accentColor: accentColor});
3920
+ var charW = Math.round(48 * charScale); var charH = Math.round(64 * charScale);
3871
3921
 
3872
- var charW = Math.round(48 * charScale);
3873
- var charH = Math.round(64 * charScale);
3874
-
3875
- agentsHtml += \x27<div class="iso-agent" data-agent-label="\x27+esc(lbl)+\x27" style="position:absolute;left:\x27+(px - charW/2)+\x27px;top:\x27+(py - charH)+\x27px;z-index:\x27+zIdx+\x27;display:flex;flex-direction:column;align-items:center;gap:2px;cursor:pointer" onclick="studioScrollToAgent(this.getAttribute(String.fromCharCode(100,97,116,97,45,97,103,101,110,116,45,108,97,98,101,108)))">\x27;
3876
- // Thought bubble above head
3877
- agentsHtml += \x27<div class="iso-bubble\x27+(isActive?\x27 iso-bubble--active\x27:\x27\x27)+\x27" id="isobubble_\x27+idx+\x27" style="border-color:\x27+bubbleColor+\x27;color:\x27+bubbleColor+\x27">\x27+esc(bubbleText)+\x27</div>\x27;
3922
+ agentsHtml += \x27<div class="iso-agent" data-agent-label="\x27+esc(lbl)+\x27" style="position:absolute;left:\x27+(px-charW/2)+\x27px;top:\x27+(py-charH)+\x27px;z-index:\x27+zIdx+\x27;display:flex;flex-direction:column;align-items:center;gap:3px;cursor:pointer" onclick="studioScrollToAgent(this.getAttribute(String.fromCharCode(100,97,116,97,45,97,103,101,110,116,45,108,97,98,101,108)))">\x27;
3923
+ // Bubble bigger, left-aligned (no mirror issue)
3924
+ if (bubbleText || isActive) {
3925
+ agentsHtml += \x27<div class="iso-bubble\x27+(isActive?\x27 iso-bubble--active\x27:\x27\x27)+\x27" id="isobubble_\x27+idx+\x27" style="border-color:\x27+bubbleColor+\x27;color:\x27+bubbleColor+\x27;min-width:80px;max-width:140px;font-size:10px;padding:4px 10px;text-align:left">\x27+esc(bubbleText)+\x27</div>\x27;
3926
+ } else {
3927
+ agentsHtml += \x27<div class="iso-bubble" id="isobubble_\x27+idx+\x27" style="visibility:hidden;min-width:80px"></div>\x27;
3928
+ }
3878
3929
  agentsHtml += charSvg;
3879
- // Name tag
3880
- agentsHtml += \x27<div class="iso-name" style="color:\x27+(isDone?\x27#4ade80\x27:(isActive?\x27#a5b4fc\x27:(isErr?\x27#f87171\x27:\x27#6b7280\x27)))+\x27">\x27+esc(lbl)+\x27</div>\x27;
3881
- // Iso desk below character
3930
+ agentsHtml += \x27<div class="iso-name" style="font-size:10px;font-weight:700;color:\x27+(isDone?\x27#22c55e\x27:(isActive?\x27#818cf8\x27:(isErr?\x27#ef4444\x27:\x27#555\x27)))+\x27;text-shadow:0 1px 3px rgba(255,255,255,.8)">\x27+esc(lbl)+\x27</div>\x27;
3931
+ // Desk lighter wood color for bright office
3882
3932
  agentsHtml += isoDeskSvg(px, py - charH/2, accentColor);
3883
3933
  agentsHtml += \x27</div>\x27;
3884
3934
  });
@@ -3886,17 +3936,16 @@ function renderStudioNodes() {
3886
3936
  // ── Orchestrator ──────────────────────────────────────────────────────────
3887
3937
  var orchHtml = \x27\x27;
3888
3938
  if (showMaster) {
3889
- var oPh = isoProject(ISO_COLS / 2, 0.5);
3890
- var orchPhrase = [\x27Analizzo il progresso...\x27, \x27Verifico gli step...\x27, \x27Coordinamento...\x27, \x27Supervisione in corso\x27][Math.floor(Date.now()/3000)%4];
3939
+ var oPh = isoProject(ISO_COLS / 2 + 0.5, 1.2);
3891
3940
  var orchDone = !hasActive && doneCount === totalCount;
3892
3941
  var orchAnim = hasActive ? \x27prl-master-walk\x27 : (orchDone ? \x27prl-master-done\x27 : \x27\x27);
3893
3942
  var orchStatus = hasActive
3894
- ? (\x27Eseguiti \x27+doneCount+\x27/\x27+totalCount)
3895
- : (orchDone ? \x27Workflow completato!\x27 : \x27In pianificazione\x27);
3896
- orchHtml = \x27<div class="prl-master \x27+orchAnim+\x27" id="wfOrch" style="position:absolute;left:\x27+(oPh.x+30)+\x27px;top:\x27+(oPh.y-10)+\x27px;z-index:50;display:flex;flex-direction:column;align-items:center;gap:2px">\x27+
3897
- \x27<div class="iso-bubble iso-bubble--orch" id="wfOrchBubble" style="border-color:#818cf8;color:#a5b4fc;max-width:120px">\x27+esc(orchStatus)+\x27</div>\x27+
3943
+ ? (\x27Step \x27+doneCount+\x27/\x27+totalCount)
3944
+ : (orchDone ? \x27Completato!\x27 : \x27Pianificazione\x27);
3945
+ orchHtml = \x27<div class="prl-master \x27+orchAnim+\x27" id="wfOrch" style="position:absolute;left:\x27+(oPh.x-28)+\x27px;top:\x27+(oPh.y+60)+\x27px;z-index:50;display:flex;flex-direction:column;align-items:center;gap:3px">\x27+
3946
+ \x27<div class="iso-bubble iso-bubble--orch" id="wfOrchBubble" style="border-color:#6366f1;color:#6366f1;max-width:140px;font-size:10px;padding:4px 10px">\x27+esc(orchStatus)+\x27</div>\x27+
3898
3947
  isoOrchSvg(hasActive, doneCount / Math.max(totalCount,1))+
3899
- \x27<div class="prl-master-label" style="color:#818cf8;font-size:8px">Orchestratore</div>\x27+
3948
+ \x27<div class="prl-master-label" style="color:#6366f1;font-size:9px;font-weight:700;text-shadow:0 1px 3px rgba(255,255,255,.8)">Orchestratore</div>\x27+
3900
3949
  \x27</div>\x27;
3901
3950
  }
3902
3951
 
@@ -3909,8 +3958,8 @@ function renderStudioNodes() {
3909
3958
  \x27<div class="prl-wrap" style="border-color:\x27+phaseColor2+\x2744;padding-bottom:8px">\x27+
3910
3959
  \x27<div class="prl-header"><span class="prl-phase-chip" style="--pc:\x27+phaseColor2+\x27">\x27+phaseLabel2+\x27</span></div>\x27+
3911
3960
  \x27<div style="display:flex;justify-content:center;width:100%;overflow-x:auto">\x27+
3912
- \x27<div class="iso-scene" style="position:relative;width:\x27+SCENE_W+\x27px;min-width:\x27+SCENE_W+\x27px;height:\x27+SCENE_H+\x27px;overflow:hidden;border-radius:10px">\x27+
3913
- isoFloorSvg(ISO_COLS + 2, 4)+
3961
+ \x27<div class="iso-scene" style="position:relative;width:\x27+SCENE_W+\x27px;min-width:\x27+SCENE_W+\x27px;height:\x27+SCENE_H+\x27px;overflow:hidden;border-radius:12px;background:#f0ede6">\x27+
3962
+ isoFloorSvg(ISO_COLS + 2, 5)+
3914
3963
  agentsHtml+
3915
3964
  orchHtml+
3916
3965
  \x27</div>\x27+
@@ -5611,13 +5660,16 @@ function runStudioStep(idx, node, task, context, stepDef, signal) {
5611
5660
  if (tb) {
5612
5661
  if (isStatus) {
5613
5662
  var st = ev.token.replace(new RegExp(\x27[\\\\r\\\\n]+\x27,\x27g\x27), \x27 \x27);
5614
- // Render [Searching: "query"] as a styled search chip
5615
- var srchM = st.match(/^\\[Searching:\\s*"([^"]+)"\\]\\s*$/);
5663
+ // Strip surrounding brackets for display
5664
+ var stLabel = st.replace(new RegExp(\x27^\\\\[\x27), \x27\x27).replace(new RegExp(\x27\\\\]\\\\s*$\x27), \x27\x27).trim();
5665
+ // Special chip for Searching
5666
+ var srchM = st.match(new RegExp(\x27^\\\\[Searching:\\\\s*"([^"]+)"\\\\]\\\\s*$\x27));
5616
5667
  if (srchM) {
5617
5668
  var qEsc = srchM[1].replace(/&/g,\x27&amp;\x27).replace(/</g,\x27&lt;\x27).replace(/>/g,\x27&gt;\x27);
5618
- tb.innerHTML = \x27<span style="display:inline-flex;align-items:center;gap:6px;background:#1c1c28;border:1px solid #6366f133;border-radius:20px;padding:3px 10px 3px 8px;font-size:11px;font-family:var(--mono)"><span style="color:#6366f1">&#128269;</span><span style="color:var(--dim)">Cercando</span><strong style="color:#a5b4fc">\x27 + qEsc + \x27</strong><span style="color:#6366f1;animation:pulse 1s infinite">&#183;&#183;&#183;</span></span>\x27;
5669
+ tb.innerHTML = \x27<span class="iso-status-chip"><span class="iso-status-dot"></span>&#128269; <span style="color:var(--dim)">Cercando</span> <strong style="color:#a5b4fc">\x27+qEsc+\x27</strong></span>\x27;
5619
5670
  } else {
5620
- tb.textContent = st;
5671
+ var stEsc = stLabel.replace(/&/g,\x27&amp;\x27).replace(/</g,\x27&lt;\x27).replace(/>/g,\x27&gt;\x27);
5672
+ tb.innerHTML = \x27<span class="iso-status-chip"><span class="iso-status-dot"></span>\x27+stEsc+\x27</span>\x27;
5621
5673
  }
5622
5674
  } else {
5623
5675
  // Word-by-word streaming: APPEND new chars, never overwrite
@@ -5704,9 +5756,14 @@ function runStudioStep(idx, node, task, context, stepDef, signal) {
5704
5756
  }
5705
5757
  }
5706
5758
  if (ev.usage) {
5759
+ // Backend sends accurate usage at end: add input, replace out estimate with real value
5707
5760
  var uIn = ev.usage.input||0; var uOut = ev.usage.output||0;
5708
- stepTokensIn += uIn; stepTokensOut += uOut;
5709
- studioAddTokens(uIn, uOut);
5761
+ // Correct output: remove per-token estimate already added, replace with real count
5762
+ var outDiff = uOut - stepTokensOut;
5763
+ studioTokens.out = Math.max(0, studioTokens.out + outDiff);
5764
+ stepTokensIn += uIn; stepTokensOut = uOut;
5765
+ studioTokens.in += uIn;
5766
+ studioUpdateTokenBar();
5710
5767
  } else if (ev.token && !isStatus) {
5711
5768
  var est = Math.ceil(ev.token.length/4);
5712
5769
  stepTokensOut += est; studioTokens.out += est; studioUpdateTokenBar();
@@ -5870,7 +5927,6 @@ function renderStudio(el) {
5870
5927
  '<div class="studio-log" id="studioLog" style="display:none"></div>' +
5871
5928
  '<div id="studioParliamentBlock" style="display:none;margin-bottom:12px"></div>' +
5872
5929
  '<div id="studioResult"></div>' +
5873
- '<div id="studioSessionsBar" style="margin-top:16px;display:none"></div>' +
5874
5930
  '</div>' +
5875
5931
 
5876
5932
  // ── AGENT SIDEBAR ──
@@ -5883,6 +5939,7 @@ function renderStudio(el) {
5883
5939
  '<div style="font-size:9px;color:var(--dim);margin-bottom:8px">Click to add to pipeline</div>' +
5884
5940
  '<div id="sideToolsList">'+toolsHtml+'</div>' +
5885
5941
  '<div id="sideAgentsList" style="display:none">'+specialistHtml+'</div>' +
5942
+ '<div id="studioSessionsBar" style="margin-top:16px;display:none"></div>' +
5886
5943
  '</div>' +
5887
5944
  '</div>';
5888
5945
 
@@ -6378,10 +6435,10 @@ input:focus,textarea:focus{border-color:var(--green3)}
6378
6435
  .studio-header{margin-bottom:20px}
6379
6436
  .studio-header h2{font-size:15px;color:var(--green);margin-bottom:4px}
6380
6437
  .studio-header p{font-size:11px;color:var(--dim);line-height:1.5}
6381
- .studio-input-row{display:flex;gap:8px;margin-bottom:20px}
6382
- .studio-input-row textarea{flex:1;resize:none;height:60px;padding:10px 14px;font-size:13px;border-radius:var(--r);border:1px solid var(--border2)}
6438
+ .studio-input-row{display:flex;gap:8px;margin-bottom:16px;align-items:flex-start}
6439
+ .studio-input-row textarea{flex:1;resize:vertical;min-height:90px;max-height:200px;padding:10px 14px;font-size:13px;border-radius:var(--r);border:1px solid var(--border2);line-height:1.5}
6383
6440
  .studio-input-row textarea:focus{border-color:var(--green3)}
6384
- .studio-run-btn{background:var(--green3);color:var(--bg);padding:0 20px;border-radius:var(--r);font-weight:700;font-size:13px;white-space:nowrap;align-self:stretch;min-width:90px}
6441
+ .studio-run-btn{background:var(--green3);color:var(--bg);padding:0 16px;border-radius:var(--r);font-weight:600;font-size:12px;white-space:nowrap;align-self:stretch;min-width:80px;letter-spacing:.2px}
6385
6442
  .studio-run-btn:disabled{opacity:.4}
6386
6443
  .studio-canvas{position:relative;width:100%;min-height:220px;background:var(--bg2);border:1px solid var(--border);border-radius:8px;margin-bottom:20px;overflow:hidden}
6387
6444
  .studio-canvas__empty{display:flex;align-items:center;justify-content:center;height:180px;color:var(--dim);font-size:11px;flex-direction:column;gap:8px}
@@ -6538,7 +6595,11 @@ input:focus,textarea:focus{border-color:var(--green3)}
6538
6595
  /* Plant right */
6539
6596
  .prl-office-plant2{position:absolute;bottom:14px;right:8px;width:22px;height:42px;z-index:2;pointer-events:none}
6540
6597
  /* ── ISOMETRIC JRPG SCENE ── */
6541
- .iso-scene{background:#0d0b1e;box-shadow:inset 0 0 40px rgba(0,0,0,.6);cursor:default;max-width:100%;overflow-x:auto}
6598
+ .iso-scene{background:#f0ede6;cursor:default;max-width:100%;overflow-x:auto;box-shadow:0 4px 24px rgba(0,0,0,.18)}
6599
+ /* Animated status chip for [bracket tokens] */
6600
+ .iso-status-chip{display:inline-flex;align-items:center;gap:6px;background:rgba(99,102,241,.1);border:1px solid rgba(99,102,241,.3);border-radius:20px;padding:3px 10px;font-size:11px;font-family:var(--mono);color:#818cf8;animation:statusPulse 2s ease-in-out infinite}
6601
+ @keyframes statusPulse{0%,100%{opacity:.7;border-color:rgba(99,102,241,.3)}50%{opacity:1;border-color:rgba(99,102,241,.7);box-shadow:0 0 8px rgba(99,102,241,.3)}}
6602
+ .iso-status-dot{width:6px;height:6px;border-radius:50%;background:#6366f1;animation:dotBounce 1s ease-in-out infinite}
6542
6603
  .iso-agent{transition:filter .3s}
6543
6604
  .iso-agent:hover{filter:brightness(1.15)}
6544
6605
  /* Thought bubble / speech bubble above character */
@@ -6608,7 +6669,7 @@ input:focus,textarea:focus{border-color:var(--green3)}
6608
6669
  .prl-conv-bar-inner{height:100%;background:linear-gradient(90deg,#22c55e,#4ade80);border-radius:4px;transition:width .8s ease}
6609
6670
  .prl-conv-text{font-size:9px;color:#86efac;line-height:1.55}
6610
6671
  .studio-log{background:var(--bg2);border:1px solid var(--border);border-radius:10px;padding:16px;max-height:380px;overflow-y:auto;font-size:11.5px;line-height:1.65}
6611
- .studio-log-entry{margin-bottom:12px;padding:10px 12px;border-radius:8px;background:var(--bg3);border:1px solid var(--border)}
6672
+ .studio-log-entry{margin-bottom:10px;padding:14px 16px;border-radius:10px;background:var(--bg3);border:1px solid var(--border);min-height:80px}
6612
6673
  .studio-log-entry:last-child{margin-bottom:0}
6613
6674
  .studio-log-entry__header{display:flex;align-items:center;gap:8px;margin-bottom:6px}
6614
6675
  .studio-log-entry__icon{font-size:15px}
@@ -6622,7 +6683,7 @@ input:focus,textarea:focus{border-color:var(--green3)}
6622
6683
  .studio-result__body{font-size:13px;color:var(--text);word-wrap:break-word;line-height:1.7}
6623
6684
  .studio-example-btn{display:inline-block;padding:5px 12px;border:1px solid var(--border2);border-radius:20px;font-size:10px;color:var(--dim);cursor:pointer;background:none;margin:0 4px 6px 0;transition:all .15s}
6624
6685
  .studio-example-btn:hover{border-color:var(--green3);color:var(--green);background:var(--greendim)}
6625
- .studio-tools-panel{width:220px;flex-shrink:0;border:1px solid var(--border);border-radius:10px;padding:12px;background:var(--bg2);max-height:600px;overflow-y:auto}
6686
+ .studio-tools-panel{width:220px;flex-shrink:0;border:1px solid var(--border);border-radius:10px;padding:12px;background:var(--bg2);max-height:calc(100vh - 120px);overflow-y:auto;position:sticky;top:16px}
6626
6687
  .studio-tool-item{display:flex;align-items:flex-start;gap:8px;padding:8px;border-radius:6px;cursor:pointer;transition:background .15s;margin-bottom:4px}
6627
6688
  .studio-tool-item:hover{background:var(--bg3);border-radius:6px}
6628
6689
  .studio-tool-icon{font-size:16px;flex-shrink:0;margin-top:1px}