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.
- package/README.md +2 -2
- package/bin/src/engine/agentEngine.d.ts.map +1 -1
- package/bin/src/engine/agentEngine.js +4 -0
- package/bin/src/engine/agentEngine.js.map +1 -1
- package/bin/src/engine/appControl.d.ts.map +1 -1
- package/bin/src/engine/appControl.js +150 -57
- package/bin/src/engine/appControl.js.map +1 -1
- package/bin/src/engine/liveScreenEngine.js +2 -2
- package/bin/src/engine/liveScreenEngine.js.map +1 -1
- package/bin/src/index.js +4 -4
- package/bin/src/utils/branding.js +1 -1
- package/package.json +1 -1
- package/web/app.js +2 -2
- package/web/styles.css +2 -2
|
@@ -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
|
|
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
|
|
657
|
-
const
|
|
658
|
-
|
|
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 (
|
|
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,
|
|
671
|
-
const ksRes = await sendKeystrokes(name || 'browser',
|
|
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 "${
|
|
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="
|
|
1153
|
-
<Path x:Name="CornerTL" Data="M 0,
|
|
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="
|
|
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="
|
|
1162
|
-
<Path x:Name="CornerTR" Data="M 30,0 L
|
|
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="
|
|
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="
|
|
1171
|
-
<Path x:Name="CornerBL" Data="M 0,30 L 0,
|
|
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="
|
|
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="
|
|
1180
|
-
<Path x:Name="CornerBR" Data="M 30,
|
|
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="
|
|
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,
|
|
1189
|
-
Background="#EE03121F" BorderBrush="#00e5ff" BorderThickness="1.8" CornerRadius="24" Padding="
|
|
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="
|
|
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="
|
|
1200
|
-
<TextBlock Text="${safeSubtitle}" Foreground="#38bdf8" FontSize="13
|
|
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
|
-
$
|
|
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="
|
|
1353
|
-
<Path x:Name="CornerTL" Data="M 0,
|
|
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="
|
|
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="
|
|
1362
|
-
<Path x:Name="CornerTR" Data="M 30,0 L
|
|
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="
|
|
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="
|
|
1371
|
-
<Path x:Name="CornerBL" Data="M 0,30 L 0,
|
|
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="
|
|
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="
|
|
1380
|
-
<Path x:Name="CornerBR" Data="M 30,
|
|
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="
|
|
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,
|
|
1389
|
-
Background="#EE03121F" BorderBrush="#00e5ff" BorderThickness="1.8" CornerRadius="24" Padding="
|
|
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="
|
|
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="
|
|
1400
|
-
<TextBlock Text="${safeSubtitle}" Foreground="#38bdf8" FontSize="13
|
|
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
|
-
$
|
|
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 { }
|