ft-scout 9.0.2 → 9.0.3

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.
@@ -62,7 +62,7 @@ export function buildSocialUrl(platformOrAppName, target, text) {
62
62
  const isLinkedIn = pLower.includes('linkedin') || cleanTarget.includes('linkedin.com');
63
63
  if (isInstagram) {
64
64
  if (handle && handle !== 'instagram' && !cleanTarget.includes('http')) {
65
- return `https://www.instagram.com/direct/i/`;
65
+ return `https://www.instagram.com/${handle}/`;
66
66
  }
67
67
  return `https://www.instagram.com/direct/inbox/`;
68
68
  }
@@ -653,9 +653,23 @@ export async function executeInApp(appName, action, payload) {
653
653
  if (!msgText && typeof payload === 'string' && payload.length > 0 && !payload.startsWith('@') && !payload.startsWith('http') && !payload.includes('@')) {
654
654
  msgText = payload;
655
655
  }
656
- const isEmail = ['send_mail', 'send_email', 'mail', 'email'].includes(actLower) || recipient.includes('@');
657
- const targetUrl = buildSocialUrl(isEmail ? 'gmail' : name, recipient, msgText);
658
- const openRes = await openApp('browser', targetUrl);
656
+ const cleanRecipient = String(recipient || '').trim();
657
+ const cleanMsg = String(msgText || '').trim();
658
+ if (!cleanRecipient && !cleanMsg) {
659
+ const targetPlatform = name || 'browser';
660
+ return {
661
+ success: false,
662
+ app: targetPlatform,
663
+ action: actLower,
664
+ output: `Missing recipient username/handle and message text for ${targetPlatform}. You MUST call the ask_user tool to ask: "Who would you like to message on ${targetPlatform}, and what message should I send?" before completing the task.`,
665
+ details: { platform: targetPlatform, recipient: '', msgText: '' },
666
+ };
667
+ }
668
+ const isEmail = ['send_mail', 'send_email', 'mail', 'email'].includes(actLower) || cleanRecipient.includes('@');
669
+ const targetUrl = buildSocialUrl(isEmail ? 'gmail' : name, cleanRecipient, cleanMsg);
670
+ await openApp('browser', targetUrl);
671
+ // Display aura HUD directly over the browser window
672
+ showScreenAuraOverlay(4500, `Scout is messaging on ${isEmail ? 'Gmail' : (name || 'browser')}...`, false, 'browser').catch(() => { });
659
673
  let keystrokeOutput = '';
660
674
  if (isEmail) {
661
675
  // For Gmail direct compose: wait 2.5s for page & compose dialog to render, then press Ctrl+Enter to send!
@@ -664,19 +678,38 @@ export async function executeInApp(appName, action, payload) {
664
678
  const ksRes = await sendKeystrokes('browser', '', false, 'ctrl+enter');
665
679
  keystrokeOutput = `\nAuto-Send Keystroke Dispatch (Ctrl+Enter): ${ksRes.output}`;
666
680
  }
667
- else if (msgText) {
681
+ else if (cleanRecipient && (name.toLowerCase().includes('instagram') || targetUrl.includes('instagram.com'))) {
682
+ // Real Instagram Web UI Automation:
683
+ // 1. Wait for profile / direct page to fully render
684
+ await new Promise((r) => setTimeout(r, 3500));
685
+ // 2. Focus browser window
686
+ await focusWindow('chrome');
687
+ await focusWindow('browser');
688
+ // 3. If message text is provided, click "Message" on profile and type text
689
+ if (cleanMsg) {
690
+ await new Promise((r) => setTimeout(r, 1000));
691
+ await findAndClickElement('Message', 'browser');
692
+ await new Promise((r) => setTimeout(r, 2200));
693
+ const ksRes = await sendKeystrokes('browser', cleanMsg, true);
694
+ keystrokeOutput = `\nInstagram Message Dispatched to ${cleanRecipient}: ${ksRes.output}`;
695
+ }
696
+ else {
697
+ keystrokeOutput = `\nNavigated to Instagram profile for ${cleanRecipient}. Message text was not specified. Call ask_user to get message content.`;
698
+ }
699
+ }
700
+ else if (cleanMsg) {
668
701
  // Lock user interruption during scratchpad keystroke dispatch so user clicks don't interrupt
669
702
  await lockAppInput(name || 'browser', 3000);
670
- await new Promise((r) => setTimeout(r, 1200));
671
- const ksRes = await sendKeystrokes(name || 'browser', msgText, true);
703
+ await new Promise((r) => setTimeout(r, 2000));
704
+ const ksRes = await sendKeystrokes(name || 'browser', cleanMsg, true);
672
705
  keystrokeOutput = `\nAuto-Keystroke Automated Dispatch: ${ksRes.output}`;
673
706
  }
674
707
  return {
675
708
  success: true,
676
709
  app: name,
677
710
  action: actLower,
678
- output: `Executed ${isEmail ? 'Gmail / Email Dispatch' : `${name} Direct Message`} for target recipient "${recipient}" at ${targetUrl}.${keystrokeOutput}`,
679
- details: { platform: isEmail ? 'gmail' : name, recipient, msgText, targetUrl },
711
+ output: `Executed ${isEmail ? 'Gmail / Email Dispatch' : `${name} Direct Message`} for target recipient "${cleanRecipient}" at ${targetUrl}.${keystrokeOutput}`,
712
+ details: { platform: isEmail ? 'gmail' : name, recipient: cleanRecipient, msgText: cleanMsg, targetUrl },
680
713
  };
681
714
  }
682
715
  }
@@ -1080,11 +1113,76 @@ function escapeXaml(text) {
1080
1113
  }
1081
1114
  let persistentAuraProcess = null;
1082
1115
  let persistentAuraFlagPath = null;
1116
+ function buildTargetWindowRectSnippet(targetApp) {
1117
+ const clean = (targetApp || '').trim().replace(/["'`$\\]/g, '');
1118
+ if (!clean || clean.toLowerCase() === 'desktop' || clean.toLowerCase() === 'system') {
1119
+ return `
1120
+ $window.Left = [System.Windows.SystemParameters]::VirtualScreenLeft
1121
+ $window.Top = [System.Windows.SystemParameters]::VirtualScreenTop
1122
+ $window.Width = [System.Windows.SystemParameters]::VirtualScreenWidth
1123
+ $window.Height = [System.Windows.SystemParameters]::VirtualScreenHeight
1124
+ `;
1125
+ }
1126
+ return `
1127
+ $targetApp = "${clean}"
1128
+ $winLeft = [System.Windows.SystemParameters]::VirtualScreenLeft
1129
+ $winTop = [System.Windows.SystemParameters]::VirtualScreenTop
1130
+ $winWidth = [System.Windows.SystemParameters]::VirtualScreenWidth
1131
+ $winHeight = [System.Windows.SystemParameters]::VirtualScreenHeight
1132
+
1133
+ $procNames = @($targetApp)
1134
+ if ($targetApp -match "browser|chrome|edge|web") {
1135
+ $procNames = @("chrome", "msedge", "brave", "firefox")
1136
+ } elseif ($targetApp -match "editor|code|vscode") {
1137
+ $procNames = @("Code", "cursor", "notepad")
1138
+ }
1139
+
1140
+ $proc = Get-Process -Name $procNames -ErrorAction SilentlyContinue | Where-Object { $_.MainWindowHandle -ne 0 } | Select-Object -First 1
1141
+ if (-not $proc) {
1142
+ $proc = Get-Process | Where-Object { ($_.MainWindowTitle -like "*$targetApp*" -or $_.ProcessName -like "*$targetApp*") -and $_.MainWindowHandle -ne 0 } | Select-Object -First 1
1143
+ }
1144
+
1145
+ if ($proc) {
1146
+ try {
1147
+ $sigRect = '[DllImport("user32.dll")] public static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect); public struct RECT { public int Left; public int Top; public int Right; public int Bottom; }'
1148
+ $wType = Add-Type -MemberDefinition $sigRect -Name ('WinRect_' + [Guid]::NewGuid().ToString('N').Substring(0,8)) -Namespace 'Win32' -PassThru
1149
+ $rc = [Activator]::CreateInstance($wType.GetNestedType('RECT'))
1150
+ [void]$wType::GetWindowRect($proc.MainWindowHandle, [ref]$rc)
1151
+ $calcW = $rc.Right - $rc.Left
1152
+ $calcH = $rc.Bottom - $rc.Top
1153
+ if ($calcW -gt 120 -and $calcH -gt 120) {
1154
+ $winLeft = [double]$rc.Left
1155
+ $winTop = [double]$rc.Top
1156
+ $winWidth = [double]$calcW
1157
+ $winHeight = [double]$calcH
1158
+ }
1159
+ } catch {
1160
+ try {
1161
+ Add-Type -AssemblyName UIAutomationClient
1162
+ $el = [System.Windows.Automation.AutomationElement]::FromHandle($proc.MainWindowHandle)
1163
+ $b = $el.Current.BoundingRectangle
1164
+ if ($b.Width -gt 120 -and $b.Height -gt 120) {
1165
+ $winLeft = [double]$b.X
1166
+ $winTop = [double]$b.Y
1167
+ $winWidth = [double]$b.Width
1168
+ $winHeight = [double]$b.Height
1169
+ }
1170
+ } catch {}
1171
+ }
1172
+ }
1173
+
1174
+ $window.Left = $winLeft
1175
+ $window.Top = $winTop
1176
+ $window.Width = $winWidth
1177
+ $window.Height = $winHeight
1178
+ `;
1179
+ }
1083
1180
  /**
1084
1181
  * Start persistent futuristic sky-blue aura overlay on screen borders and corners.
1085
1182
  * Stays continuously active and animating as long as live screen sharing is running.
1183
+ * When targetApp is specified, bounds strictly to that application window.
1086
1184
  */
1087
- export async function startScreenAuraOverlay(message = "Live Screen Share Active • Streaming to Model") {
1185
+ export async function startScreenAuraOverlay(message = "Live Screen Share Active • Streaming to Model", targetApp) {
1088
1186
  const platform = process.platform;
1089
1187
  if (platform !== 'win32')
1090
1188
  return;
@@ -1099,7 +1197,7 @@ export async function startScreenAuraOverlay(message = "Live Screen Share Active
1099
1197
  const flagFile = path.join(scriptsDir, 'aura_active.flag');
1100
1198
  fs.writeFileSync(flagFile, String(Date.now()), 'utf8');
1101
1199
  persistentAuraFlagPath = flagFile;
1102
- const subtitleText = " Perception Active";
1200
+ const subtitleText = targetApp ? ` • Focused: ${targetApp}` : " Perception Active";
1103
1201
  const safeMessage = escapeXaml(message);
1104
1202
  const safeSubtitle = escapeXaml(subtitleText);
1105
1203
  const parentPid = process.pid;
@@ -1149,55 +1247,55 @@ Add-Type -AssemblyName PresentationFramework, PresentationCore, WindowsBase
1149
1247
 
1150
1248
  <!-- Sky Blue Corner Brackets with Aura Glow -->
1151
1249
  <!-- Top Left Corner -->
1152
- <Canvas HorizontalAlignment="Left" VerticalAlignment="Top" Width="120" Height="120" Margin="6,6,0,0">
1153
- <Path x:Name="CornerTL" Data="M 0,90 L 0,0 L 90,0" Stroke="#00e5ff" StrokeThickness="6">
1250
+ <Canvas HorizontalAlignment="Left" VerticalAlignment="Top" Width="100" Height="100" Margin="4,4,0,0">
1251
+ <Path x:Name="CornerTL" Data="M 0,70 L 0,0 L 70,0" Stroke="#00e5ff" StrokeThickness="5">
1154
1252
  <Path.Effect>
1155
- <DropShadowEffect Color="#00e5ff" BlurRadius="30" ShadowDepth="0" Opacity="1"/>
1253
+ <DropShadowEffect Color="#00e5ff" BlurRadius="25" ShadowDepth="0" Opacity="1"/>
1156
1254
  </Path.Effect>
1157
1255
  </Path>
1158
1256
  </Canvas>
1159
1257
 
1160
1258
  <!-- Top Right Corner -->
1161
- <Canvas HorizontalAlignment="Right" VerticalAlignment="Top" Width="120" Height="120" Margin="0,6,6,0">
1162
- <Path x:Name="CornerTR" Data="M 30,0 L 120,0 L 120,90" Stroke="#00e5ff" StrokeThickness="6">
1259
+ <Canvas HorizontalAlignment="Right" VerticalAlignment="Top" Width="100" Height="100" Margin="0,4,4,0">
1260
+ <Path x:Name="CornerTR" Data="M 30,0 L 100,0 L 100,70" Stroke="#00e5ff" StrokeThickness="5">
1163
1261
  <Path.Effect>
1164
- <DropShadowEffect Color="#00e5ff" BlurRadius="30" ShadowDepth="0" Opacity="1"/>
1262
+ <DropShadowEffect Color="#00e5ff" BlurRadius="25" ShadowDepth="0" Opacity="1"/>
1165
1263
  </Path.Effect>
1166
1264
  </Path>
1167
1265
  </Canvas>
1168
1266
 
1169
1267
  <!-- Bottom Left Corner -->
1170
- <Canvas HorizontalAlignment="Left" VerticalAlignment="Bottom" Width="120" Height="120" Margin="6,0,0,6">
1171
- <Path x:Name="CornerBL" Data="M 0,30 L 0,120 L 90,120" Stroke="#00e5ff" StrokeThickness="6">
1268
+ <Canvas HorizontalAlignment="Left" VerticalAlignment="Bottom" Width="100" Height="100" Margin="4,0,0,4">
1269
+ <Path x:Name="CornerBL" Data="M 0,30 L 0,100 L 70,100" Stroke="#00e5ff" StrokeThickness="5">
1172
1270
  <Path.Effect>
1173
- <DropShadowEffect Color="#00e5ff" BlurRadius="30" ShadowDepth="0" Opacity="1"/>
1271
+ <DropShadowEffect Color="#00e5ff" BlurRadius="25" ShadowDepth="0" Opacity="1"/>
1174
1272
  </Path.Effect>
1175
1273
  </Path>
1176
1274
  </Canvas>
1177
1275
 
1178
1276
  <!-- Bottom Right Corner -->
1179
- <Canvas HorizontalAlignment="Right" VerticalAlignment="Bottom" Width="120" Height="120" Margin="0,0,6,6">
1180
- <Path x:Name="CornerBR" Data="M 30,120 L 120,120 L 120,30" Stroke="#00e5ff" StrokeThickness="6">
1277
+ <Canvas HorizontalAlignment="Right" VerticalAlignment="Bottom" Width="100" Height="100" Margin="0,0,4,4">
1278
+ <Path x:Name="CornerBR" Data="M 30,100 L 100,100 L 100,30" Stroke="#00e5ff" StrokeThickness="5">
1181
1279
  <Path.Effect>
1182
- <DropShadowEffect Color="#00e5ff" BlurRadius="30" ShadowDepth="0" Opacity="1"/>
1280
+ <DropShadowEffect Color="#00e5ff" BlurRadius="25" ShadowDepth="0" Opacity="1"/>
1183
1281
  </Path.Effect>
1184
1282
  </Path>
1185
1283
  </Canvas>
1186
1284
 
1187
1285
  <!-- Top Floating Status Badge -->
1188
- <Border HorizontalAlignment="Center" VerticalAlignment="Top" Margin="0,22,0,0"
1189
- Background="#EE03121F" BorderBrush="#00e5ff" BorderThickness="1.8" CornerRadius="24" Padding="26,10">
1286
+ <Border HorizontalAlignment="Center" VerticalAlignment="Top" Margin="0,16,0,0"
1287
+ Background="#EE03121F" BorderBrush="#00e5ff" BorderThickness="1.8" CornerRadius="24" Padding="22,8">
1190
1288
  <Border.Effect>
1191
1289
  <DropShadowEffect Color="#00e5ff" BlurRadius="25" ShadowDepth="0" Opacity="0.95"/>
1192
1290
  </Border.Effect>
1193
1291
  <StackPanel Orientation="Horizontal" VerticalAlignment="Center">
1194
- <Ellipse Width="12" Height="12" Fill="#00e5ff" Margin="0,0,12,0">
1292
+ <Ellipse Width="10" Height="10" Fill="#00e5ff" Margin="0,0,10,0">
1195
1293
  <Ellipse.Effect>
1196
1294
  <DropShadowEffect Color="#00e5ff" BlurRadius="12" ShadowDepth="0"/>
1197
1295
  </Ellipse.Effect>
1198
1296
  </Ellipse>
1199
- <TextBlock Text="${safeMessage}" Foreground="#ffffff" FontSize="16" FontWeight="Bold" VerticalAlignment="Center"/>
1200
- <TextBlock Text="${safeSubtitle}" Foreground="#38bdf8" FontSize="13.5" FontWeight="SemiBold" Margin="10,0,0,0" VerticalAlignment="Center"/>
1297
+ <TextBlock Text="${safeMessage}" Foreground="#ffffff" FontSize="15" FontWeight="Bold" VerticalAlignment="Center"/>
1298
+ <TextBlock Text="${safeSubtitle}" Foreground="#38bdf8" FontSize="13" FontWeight="SemiBold" Margin="8,0,0,0" VerticalAlignment="Center"/>
1201
1299
  </StackPanel>
1202
1300
  </Border>
1203
1301
  </Grid>
@@ -1207,10 +1305,7 @@ Add-Type -AssemblyName PresentationFramework, PresentationCore, WindowsBase
1207
1305
  $reader = (New-Object System.Xml.XmlNodeReader $xaml)
1208
1306
  $window = [System.Windows.Markup.XamlReader]::Load($reader)
1209
1307
 
1210
- $window.Left = [System.Windows.SystemParameters]::VirtualScreenLeft
1211
- $window.Top = [System.Windows.SystemParameters]::VirtualScreenTop
1212
- $window.Width = [System.Windows.SystemParameters]::VirtualScreenWidth
1213
- $window.Height = [System.Windows.SystemParameters]::VirtualScreenHeight
1308
+ ${buildTargetWindowRectSnippet(targetApp)}
1214
1309
  $window.Topmost = $true
1215
1310
  $window.ShowActivated = $false
1216
1311
 
@@ -1276,11 +1371,12 @@ export function stopScreenAuraOverlay() {
1276
1371
  /**
1277
1372
  * Display a futuristic sky-blue aura animation on screen borders and corners,
1278
1373
  * show the warning "Scout is on the screen.", and optionally block external inputs.
1374
+ * When targetApp is specified, bounds strictly to that application window.
1279
1375
  * If durationMs <= 0, aura stays on continuously until stopScreenAuraOverlay() is called.
1280
1376
  */
1281
- export async function showScreenAuraOverlay(durationMs = 2200, message = "Scout is viewing the screen.", blockInput = false) {
1377
+ export async function showScreenAuraOverlay(durationMs = 2200, message = "Scout is viewing the screen.", blockInput = false, targetApp) {
1282
1378
  if (durationMs <= 0) {
1283
- return await startScreenAuraOverlay(message);
1379
+ return await startScreenAuraOverlay(message, targetApp);
1284
1380
  }
1285
1381
  const platform = process.platform;
1286
1382
  if (platform !== 'win32')
@@ -1299,7 +1395,7 @@ try { [void]$b::BlockInput($true) } catch {}
1299
1395
  const unblockSnippet = blockInput ? `
1300
1396
  try { [void]$b::BlockInput($false) } catch {}
1301
1397
  ` : '';
1302
- const subtitleText = blockInput ? " • External Input Locked" : " Perception Active";
1398
+ const subtitleText = blockInput ? (targetApp ? ` • Controlling ${targetApp} (Input Locked)` : " • External Input Locked") : (targetApp ? ` • Focused: ${targetApp}` : " Perception Active");
1303
1399
  const safeMessage = escapeXaml(message);
1304
1400
  const safeSubtitle = escapeXaml(subtitleText);
1305
1401
  const overlayPs = `
@@ -1349,55 +1445,55 @@ ${blockInputSnippet}
1349
1445
 
1350
1446
  <!-- Sky Blue Corner Brackets with Aura Glow -->
1351
1447
  <!-- Top Left Corner -->
1352
- <Canvas HorizontalAlignment="Left" VerticalAlignment="Top" Width="120" Height="120" Margin="6,6,0,0">
1353
- <Path x:Name="CornerTL" Data="M 0,90 L 0,0 L 90,0" Stroke="#00e5ff" StrokeThickness="6">
1448
+ <Canvas HorizontalAlignment="Left" VerticalAlignment="Top" Width="100" Height="100" Margin="4,4,0,0">
1449
+ <Path x:Name="CornerTL" Data="M 0,70 L 0,0 L 70,0" Stroke="#00e5ff" StrokeThickness="5">
1354
1450
  <Path.Effect>
1355
- <DropShadowEffect Color="#00e5ff" BlurRadius="30" ShadowDepth="0" Opacity="1"/>
1451
+ <DropShadowEffect Color="#00e5ff" BlurRadius="25" ShadowDepth="0" Opacity="1"/>
1356
1452
  </Path.Effect>
1357
1453
  </Path>
1358
1454
  </Canvas>
1359
1455
 
1360
1456
  <!-- Top Right Corner -->
1361
- <Canvas HorizontalAlignment="Right" VerticalAlignment="Top" Width="120" Height="120" Margin="0,6,6,0">
1362
- <Path x:Name="CornerTR" Data="M 30,0 L 120,0 L 120,90" Stroke="#00e5ff" StrokeThickness="6">
1457
+ <Canvas HorizontalAlignment="Right" VerticalAlignment="Top" Width="100" Height="100" Margin="0,4,4,0">
1458
+ <Path x:Name="CornerTR" Data="M 30,0 L 100,0 L 100,70" Stroke="#00e5ff" StrokeThickness="5">
1363
1459
  <Path.Effect>
1364
- <DropShadowEffect Color="#00e5ff" BlurRadius="30" ShadowDepth="0" Opacity="1"/>
1460
+ <DropShadowEffect Color="#00e5ff" BlurRadius="25" ShadowDepth="0" Opacity="1"/>
1365
1461
  </Path.Effect>
1366
1462
  </Path>
1367
1463
  </Canvas>
1368
1464
 
1369
1465
  <!-- Bottom Left Corner -->
1370
- <Canvas HorizontalAlignment="Left" VerticalAlignment="Bottom" Width="120" Height="120" Margin="6,0,0,6">
1371
- <Path x:Name="CornerBL" Data="M 0,30 L 0,120 L 90,120" Stroke="#00e5ff" StrokeThickness="6">
1466
+ <Canvas HorizontalAlignment="Left" VerticalAlignment="Bottom" Width="100" Height="100" Margin="4,0,0,4">
1467
+ <Path x:Name="CornerBL" Data="M 0,30 L 0,100 L 70,100" Stroke="#00e5ff" StrokeThickness="5">
1372
1468
  <Path.Effect>
1373
- <DropShadowEffect Color="#00e5ff" BlurRadius="30" ShadowDepth="0" Opacity="1"/>
1469
+ <DropShadowEffect Color="#00e5ff" BlurRadius="25" ShadowDepth="0" Opacity="1"/>
1374
1470
  </Path.Effect>
1375
1471
  </Path>
1376
1472
  </Canvas>
1377
1473
 
1378
1474
  <!-- Bottom Right Corner -->
1379
- <Canvas HorizontalAlignment="Right" VerticalAlignment="Bottom" Width="120" Height="120" Margin="0,0,6,6">
1380
- <Path x:Name="CornerBR" Data="M 30,120 L 120,120 L 120,30" Stroke="#00e5ff" StrokeThickness="6">
1475
+ <Canvas HorizontalAlignment="Right" VerticalAlignment="Bottom" Width="100" Height="100" Margin="0,0,4,4">
1476
+ <Path x:Name="CornerBR" Data="M 30,100 L 100,100 L 100,30" Stroke="#00e5ff" StrokeThickness="5">
1381
1477
  <Path.Effect>
1382
- <DropShadowEffect Color="#00e5ff" BlurRadius="30" ShadowDepth="0" Opacity="1"/>
1478
+ <DropShadowEffect Color="#00e5ff" BlurRadius="25" ShadowDepth="0" Opacity="1"/>
1383
1479
  </Path.Effect>
1384
1480
  </Path>
1385
1481
  </Canvas>
1386
1482
 
1387
1483
  <!-- Top Floating Status Badge -->
1388
- <Border HorizontalAlignment="Center" VerticalAlignment="Top" Margin="0,22,0,0"
1389
- Background="#EE03121F" BorderBrush="#00e5ff" BorderThickness="1.8" CornerRadius="24" Padding="26,10">
1484
+ <Border HorizontalAlignment="Center" VerticalAlignment="Top" Margin="0,16,0,0"
1485
+ Background="#EE03121F" BorderBrush="#00e5ff" BorderThickness="1.8" CornerRadius="24" Padding="22,8">
1390
1486
  <Border.Effect>
1391
1487
  <DropShadowEffect Color="#00e5ff" BlurRadius="25" ShadowDepth="0" Opacity="0.95"/>
1392
1488
  </Border.Effect>
1393
1489
  <StackPanel Orientation="Horizontal" VerticalAlignment="Center">
1394
- <Ellipse Width="12" Height="12" Fill="#00e5ff" Margin="0,0,12,0">
1490
+ <Ellipse Width="10" Height="10" Fill="#00e5ff" Margin="0,0,10,0">
1395
1491
  <Ellipse.Effect>
1396
1492
  <DropShadowEffect Color="#00e5ff" BlurRadius="12" ShadowDepth="0"/>
1397
1493
  </Ellipse.Effect>
1398
1494
  </Ellipse>
1399
- <TextBlock Text="${safeMessage}" Foreground="#ffffff" FontSize="16" FontWeight="Bold" VerticalAlignment="Center"/>
1400
- <TextBlock Text="${safeSubtitle}" Foreground="#38bdf8" FontSize="13.5" FontWeight="SemiBold" Margin="10,0,0,0" VerticalAlignment="Center"/>
1495
+ <TextBlock Text="${safeMessage}" Foreground="#ffffff" FontSize="15" FontWeight="Bold" VerticalAlignment="Center"/>
1496
+ <TextBlock Text="${safeSubtitle}" Foreground="#38bdf8" FontSize="13" FontWeight="SemiBold" Margin="8,0,0,0" VerticalAlignment="Center"/>
1401
1497
  </StackPanel>
1402
1498
  </Border>
1403
1499
  </Grid>
@@ -1407,10 +1503,7 @@ ${blockInputSnippet}
1407
1503
  $reader = (New-Object System.Xml.XmlNodeReader $xaml)
1408
1504
  $window = [System.Windows.Markup.XamlReader]::Load($reader)
1409
1505
 
1410
- $window.Left = [System.Windows.SystemParameters]::VirtualScreenLeft
1411
- $window.Top = [System.Windows.SystemParameters]::VirtualScreenTop
1412
- $window.Width = [System.Windows.SystemParameters]::VirtualScreenWidth
1413
- $window.Height = [System.Windows.SystemParameters]::VirtualScreenHeight
1506
+ ${buildTargetWindowRectSnippet(targetApp)}
1414
1507
  $window.Topmost = $true
1415
1508
  $window.ShowActivated = $false
1416
1509
 
@@ -1715,7 +1808,7 @@ export async function takeoverControl(appName, durationMs = 3000, x, y) {
1715
1808
  // Trigger visual sky-blue aura overlay on screen borders & corners with warning badge & input block
1716
1809
  try {
1717
1810
  const auraLabel = targetApp ? `Scout is controlling ${targetApp}...` : "Scout is on the screen.";
1718
- await showScreenAuraOverlay(Math.min(5000, Math.max(800, durationMs)), auraLabel, true);
1811
+ await showScreenAuraOverlay(Math.min(5000, Math.max(800, durationMs)), auraLabel, true, targetApp);
1719
1812
  startLiveScreenShare({ targetApp }).catch(() => { });
1720
1813
  }
1721
1814
  catch { }