@remcp/runtime 0.2.150 → 0.2.152
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/CHANGELOG.md +8 -0
- package/package.json +1 -1
- package/src/catalog.mjs +5 -829
- package/src/core-catalog-part1.mjs +373 -0
- package/src/core-catalog-part2.mjs +374 -0
- package/src/core-catalog-shared.mjs +92 -0
- package/src/extended/catalog-rules.mjs +253 -0
- package/src/extended/catalog-schemas.mjs +252 -0
- package/src/extended/catalog.mjs +2 -505
- package/src/extended/desktop-macos-windows.mjs +66 -0
- package/src/extended/desktop-macos.mjs +2 -64
- package/src/extended/desktop-windows-msaa.mjs +104 -0
- package/src/extended/desktop-windows.mjs +1 -103
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { macWindowTargets, MAC_WINDOW_TARGET_TTL_MS, rememberMacWindowTarget, macWindowId, normalizeMacWindowTarget } from './desktop-macos-windows.mjs';
|
|
2
|
+
export { macWindowId, normalizeMacWindowTarget };
|
|
1
3
|
import path from 'node:path';
|
|
2
4
|
|
|
3
5
|
import { image, multi, text } from '../util.mjs';
|
|
@@ -23,72 +25,8 @@ function parseTsv(value, fields) {
|
|
|
23
25
|
});
|
|
24
26
|
}
|
|
25
27
|
|
|
26
|
-
const macWindowTargets = new Map();
|
|
27
|
-
const MAC_WINDOW_TARGET_TTL_MS = 5 * 60 * 1000;
|
|
28
28
|
let macWindowGeneration = 0;
|
|
29
29
|
|
|
30
|
-
function rememberMacWindowTarget(row) {
|
|
31
|
-
macWindowTargets.set(row.id, {
|
|
32
|
-
pid:row.pid,
|
|
33
|
-
app:row.app,
|
|
34
|
-
title:row.title,
|
|
35
|
-
x:row.x,
|
|
36
|
-
y:row.y,
|
|
37
|
-
width:row.width,
|
|
38
|
-
height:row.height,
|
|
39
|
-
at:Date.now(),
|
|
40
|
-
});
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
function cachedMacWindowTarget(id) {
|
|
44
|
-
const cached = macWindowTargets.get(id);
|
|
45
|
-
if (!cached) return null;
|
|
46
|
-
if ((Date.now() - cached.at) > MAC_WINDOW_TARGET_TTL_MS) {
|
|
47
|
-
macWindowTargets.delete(id);
|
|
48
|
-
return null;
|
|
49
|
-
}
|
|
50
|
-
return cached;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
export function macWindowId(pid, windowIndex, generation) {
|
|
54
|
-
const numericPid = Number(pid);
|
|
55
|
-
const numericIndex = Number(windowIndex);
|
|
56
|
-
const numericGeneration = Number(generation);
|
|
57
|
-
if (!Number.isInteger(numericPid) || numericPid <= 0
|
|
58
|
-
|| !Number.isInteger(numericIndex) || numericIndex < 0
|
|
59
|
-
|| !Number.isInteger(numericGeneration) || numericGeneration <= 0) {
|
|
60
|
-
throw new Error('Could not construct a macOS window id from invalid PID/index/generation');
|
|
61
|
-
}
|
|
62
|
-
return `mac:${numericPid}:w${numericIndex}:g${numericGeneration}`;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
export function normalizeMacWindowTarget(args = {}, { useWindowId = false } = {}) {
|
|
66
|
-
const explicitPid = Number.isInteger(Number(args.pid)) && Number(args.pid) > 0 ? Number(args.pid) : 0;
|
|
67
|
-
let idPid = 0;
|
|
68
|
-
let windowIndex = null;
|
|
69
|
-
const rawId = useWindowId ? optionalString(args.id) : '';
|
|
70
|
-
let cached = null;
|
|
71
|
-
if (rawId) {
|
|
72
|
-
const match = /^mac:(\d+):w(\d+):g(\d+)$/.exec(rawId);
|
|
73
|
-
if (!match) throw new Error('macOS window id is stale or unsupported; call list_windows again');
|
|
74
|
-
idPid = Number(match[1]);
|
|
75
|
-
windowIndex = Number(match[2]);
|
|
76
|
-
if (explicitPid && explicitPid !== idPid) throw new Error('macOS window id and pid refer to different processes');
|
|
77
|
-
cached = cachedMacWindowTarget(rawId);
|
|
78
|
-
}
|
|
79
|
-
return {
|
|
80
|
-
id:rawId,
|
|
81
|
-
idCached:Boolean(cached),
|
|
82
|
-
pid:idPid || explicitPid,
|
|
83
|
-
windowIndex,
|
|
84
|
-
app:optionalString(args.app) || '',
|
|
85
|
-
title:optionalString(args.window_title || args.windowTitle || args.title) || '',
|
|
86
|
-
expectedApp:cached?.app || '',
|
|
87
|
-
expectedTitle:cached?.title || '',
|
|
88
|
-
expectedBounds:cached ? [cached.x,cached.y,cached.width,cached.height] : null,
|
|
89
|
-
};
|
|
90
|
-
}
|
|
91
|
-
|
|
92
30
|
export async function listWindows() {
|
|
93
31
|
const script = `
|
|
94
32
|
set output to ""
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { clamp, runPowerShell, escapePowerShellSingle, optionalString } from './common.mjs';
|
|
2
|
+
|
|
3
|
+
export async function msaaBrowserSnapshot(args = {}) {
|
|
4
|
+
const maxNodes = clamp(args.max_nodes, 1200, 1, 5000);
|
|
5
|
+
const maxDepth = clamp(args.max_depth, 64, 1, 128);
|
|
6
|
+
const script = String.raw`
|
|
7
|
+
Add-Type -AssemblyName UIAutomationClient;Add-Type -AssemblyName UIAutomationTypes;Add-Type -AssemblyName Accessibility
|
|
8
|
+
${windowsUiRootScript(args)}
|
|
9
|
+
Add-Type @'
|
|
10
|
+
using System;
|
|
11
|
+
using System.Runtime.InteropServices;
|
|
12
|
+
public static class RMAcc {
|
|
13
|
+
[DllImport("oleacc.dll")]
|
|
14
|
+
public static extern int AccessibleObjectFromWindow(IntPtr hwnd,uint dwId,ref Guid riid,[MarshalAs(UnmanagedType.Interface)] out object ppvObject);
|
|
15
|
+
public static object FromWindow(IntPtr hwnd) {
|
|
16
|
+
Guid iid=new Guid("618736E0-3C3D-11CF-810C-00AA00389B71");
|
|
17
|
+
object value=null;
|
|
18
|
+
int hr=AccessibleObjectFromWindow(hwnd,0xFFFFFFFCu,ref iid,out value);
|
|
19
|
+
if(hr<0) Marshal.ThrowExceptionForHR(hr);
|
|
20
|
+
return value;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
'@
|
|
24
|
+
$rootAcc=[Accessibility.IAccessible][RMAcc]::FromWindow($h)
|
|
25
|
+
$nodes=New-Object System.Collections.ArrayList
|
|
26
|
+
$seen=0
|
|
27
|
+
$truncated=$false
|
|
28
|
+
$interactive=@(30,33,34,36,37,43,44,45,46,47,51,56,60,62)
|
|
29
|
+
$informative=@(15,20,22,24,31,32,40,41,42)
|
|
30
|
+
function Get-RoleName([int]$role){
|
|
31
|
+
switch($role){
|
|
32
|
+
15{'Document'};20{'Group'};22{'Toolbar'};24{'Table'};30{'Link'};33{'List'};34{'ListItem'};35{'Tree'};36{'TreeItem'};37{'TabItem'};40{'Graphic'};41{'Text'};42{'Edit'};43{'Button'};44{'CheckBox'};45{'RadioButton'};46{'ComboBox'};47{'DropList'};51{'Slider'};56{'Button'};60{'TabList'};62{'Button'};default{'Accessible'}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
function Walk-Acc($acc,[int]$depth,[string]$path,[bool]$inDocument,[string]$parentId){
|
|
36
|
+
if($null -eq $acc -or $depth -gt ${maxDepth} -or $script:seen -ge ${maxNodes}){if($script:seen -ge ${maxNodes}){$script:truncated=$true};return}
|
|
37
|
+
$script:seen++
|
|
38
|
+
try{$roleRaw=$acc.get_accRole(0);$role=[int]$roleRaw}catch{$role=-1}
|
|
39
|
+
try{$state=[int]$acc.get_accState(0)}catch{$state=0}
|
|
40
|
+
$invisible=(($state -band 0x8000) -ne 0) -or (($state -band 0x10000) -ne 0)
|
|
41
|
+
if($depth -gt 0 -and $invisible){return}
|
|
42
|
+
$isDocument=$role -eq 15
|
|
43
|
+
$inside=$inDocument -or $isDocument
|
|
44
|
+
$l=0;$t=0;$w=0;$hh=0;$hasRect=$true
|
|
45
|
+
try{$acc.accLocation([ref]$l,[ref]$t,[ref]$w,[ref]$hh,0)}catch{$hasRect=$false}
|
|
46
|
+
try{$name=[string]$acc.get_accName(0)}catch{$name=''}
|
|
47
|
+
try{$value=[string]$acc.get_accValue(0)}catch{$value=''}
|
|
48
|
+
$visible=$hasRect -and $w -gt 0 -and $hh -gt 0 -and -not $invisible
|
|
49
|
+
if($inside -and $visible -and (($interactive -contains $role) -or ($informative -contains $role) -or $name -or $value)){
|
|
50
|
+
$id='msaa:'+$rootPid+':'+$path
|
|
51
|
+
$patterns=New-Object System.Collections.ArrayList
|
|
52
|
+
if($role -in @(30,43,56,62)){[void]$patterns.Add('invoke')}
|
|
53
|
+
if($role -in @(42,46,47)){[void]$patterns.Add('value')}
|
|
54
|
+
if($role -in @(34,36,37,45)){[void]$patterns.Add('selection_item')}
|
|
55
|
+
if($role -eq 44){[void]$patterns.Add('toggle')}
|
|
56
|
+
if($role -eq 51){[void]$patterns.Add('range_value')}
|
|
57
|
+
[void]$nodes.Add([pscustomobject]@{
|
|
58
|
+
id=$id;parent_id=$parentId;depth=$depth;active=($depth -eq 0);pid=$rootPid;app=$rootApp;window=$windowName;
|
|
59
|
+
name=$name;role=(Get-RoleName $role);localized_role=(Get-RoleName $role);automationId='';className='';frameworkId='MSAA';
|
|
60
|
+
enabled=$true;offscreen=$false;focused=(($state -band 0x4) -ne 0);focusable=(($state -band 0x100000) -ne 0);password=$false;
|
|
61
|
+
value=$value;patterns=@($patterns);x=[int]$l;y=[int]$t;width=[int]$w;height=[int]$hh
|
|
62
|
+
})
|
|
63
|
+
$parentId=$id
|
|
64
|
+
}
|
|
65
|
+
try{$count=[int]$acc.accChildCount}catch{$count=0}
|
|
66
|
+
for($i=1;$i -le $count;$i++){
|
|
67
|
+
if($script:seen -ge ${maxNodes}){$script:truncated=$true;break}
|
|
68
|
+
try{$child=$acc.get_accChild($i)}catch{continue}
|
|
69
|
+
if($child -is [Accessibility.IAccessible]){
|
|
70
|
+
Walk-Acc $child ($depth+1) ($path+'.'+$i) $inside $parentId
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
Walk-Acc $rootAcc 0 'r' $false $null
|
|
75
|
+
[pscustomobject]@{platform='win32';count=$nodes.Count;nodes=@($nodes);truncated=$truncated;max_nodes=${maxNodes};browser_dom=[pscustomobject]@{requested=$true;available=($nodes.Count -gt 0);provider='msaa-iaccessible'}}|ConvertTo-Json -Compress -Depth 7`;
|
|
76
|
+
const { stdout } = await runPowerShell(script, { label:'MSAA browser accessibility snapshot', timeout:30_000 });
|
|
77
|
+
return stdout.trim() ? JSON.parse(stdout) : { platform:'win32', count:0, nodes:[], browser_dom:{ requested:true, available:false, provider:'msaa-iaccessible' } };
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export function windowsUiRootScript(args = {}) {
|
|
81
|
+
const pid = Number.isInteger(Number(args.pid)) ? Number(args.pid) : 0;
|
|
82
|
+
const app = escapePowerShellSingle(optionalString(args.app) || '');
|
|
83
|
+
const title = escapePowerShellSingle(optionalString(args.window_title || args.windowTitle) || '');
|
|
84
|
+
const scoped = pid > 0 || app || title;
|
|
85
|
+
const selector = scoped
|
|
86
|
+
? `$p=Get-Process|Where-Object{$_.MainWindowHandle -ne 0 -and (${pid} -eq 0 -or $_.Id -eq ${pid}) -and ('${app}' -eq '' -or $_.ProcessName -like '*${app}*') -and ('${title}' -eq '' -or $_.MainWindowTitle -like '*${title}*')}|Select-Object -First 1;if(-not $p){throw 'No matching UI window found'};$h=$p.MainWindowHandle`
|
|
87
|
+
: '$h=[RMFG]::GetForegroundWindow()';
|
|
88
|
+
return String.raw`
|
|
89
|
+
Add-Type @'
|
|
90
|
+
using System;using System.Runtime.InteropServices;
|
|
91
|
+
public static class RMFG{
|
|
92
|
+
[DllImport("user32.dll")]public static extern IntPtr GetForegroundWindow();
|
|
93
|
+
}
|
|
94
|
+
'@
|
|
95
|
+
$h=[IntPtr]::Zero
|
|
96
|
+
${selector}
|
|
97
|
+
if($h -eq [IntPtr]::Zero){throw 'No foreground UI window is available'}
|
|
98
|
+
$root=[System.Windows.Automation.AutomationElement]::FromHandle($h)
|
|
99
|
+
if(-not $root){throw 'Could not create UI Automation root'}
|
|
100
|
+
$windowName=$root.Current.Name
|
|
101
|
+
$rootPid=$root.Current.ProcessId
|
|
102
|
+
try{$rootApp=(Get-Process -Id $rootPid -ErrorAction Stop).ProcessName}catch{$rootApp=''}
|
|
103
|
+
`;
|
|
104
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { msaaBrowserSnapshot, windowsUiRootScript } from './desktop-windows-msaa.mjs';
|
|
1
2
|
import path from 'node:path';
|
|
2
3
|
import process from 'node:process';
|
|
3
4
|
|
|
@@ -100,109 +101,6 @@ switch('${action}'){
|
|
|
100
101
|
return text(`Window action ${action} completed.`);
|
|
101
102
|
}
|
|
102
103
|
|
|
103
|
-
async function msaaBrowserSnapshot(args = {}) {
|
|
104
|
-
const maxNodes = clamp(args.max_nodes, 1200, 1, 5000);
|
|
105
|
-
const maxDepth = clamp(args.max_depth, 64, 1, 128);
|
|
106
|
-
const script = String.raw`
|
|
107
|
-
Add-Type -AssemblyName UIAutomationClient;Add-Type -AssemblyName UIAutomationTypes;Add-Type -AssemblyName Accessibility
|
|
108
|
-
${windowsUiRootScript(args)}
|
|
109
|
-
Add-Type @'
|
|
110
|
-
using System;
|
|
111
|
-
using System.Runtime.InteropServices;
|
|
112
|
-
public static class RMAcc {
|
|
113
|
-
[DllImport("oleacc.dll")]
|
|
114
|
-
public static extern int AccessibleObjectFromWindow(IntPtr hwnd,uint dwId,ref Guid riid,[MarshalAs(UnmanagedType.Interface)] out object ppvObject);
|
|
115
|
-
public static object FromWindow(IntPtr hwnd) {
|
|
116
|
-
Guid iid=new Guid("618736E0-3C3D-11CF-810C-00AA00389B71");
|
|
117
|
-
object value=null;
|
|
118
|
-
int hr=AccessibleObjectFromWindow(hwnd,0xFFFFFFFCu,ref iid,out value);
|
|
119
|
-
if(hr<0) Marshal.ThrowExceptionForHR(hr);
|
|
120
|
-
return value;
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
'@
|
|
124
|
-
$rootAcc=[Accessibility.IAccessible][RMAcc]::FromWindow($h)
|
|
125
|
-
$nodes=New-Object System.Collections.ArrayList
|
|
126
|
-
$seen=0
|
|
127
|
-
$truncated=$false
|
|
128
|
-
$interactive=@(30,33,34,36,37,43,44,45,46,47,51,56,60,62)
|
|
129
|
-
$informative=@(15,20,22,24,31,32,40,41,42)
|
|
130
|
-
function Get-RoleName([int]$role){
|
|
131
|
-
switch($role){
|
|
132
|
-
15{'Document'};20{'Group'};22{'Toolbar'};24{'Table'};30{'Link'};33{'List'};34{'ListItem'};35{'Tree'};36{'TreeItem'};37{'TabItem'};40{'Graphic'};41{'Text'};42{'Edit'};43{'Button'};44{'CheckBox'};45{'RadioButton'};46{'ComboBox'};47{'DropList'};51{'Slider'};56{'Button'};60{'TabList'};62{'Button'};default{'Accessible'}
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
function Walk-Acc($acc,[int]$depth,[string]$path,[bool]$inDocument,[string]$parentId){
|
|
136
|
-
if($null -eq $acc -or $depth -gt ${maxDepth} -or $script:seen -ge ${maxNodes}){if($script:seen -ge ${maxNodes}){$script:truncated=$true};return}
|
|
137
|
-
$script:seen++
|
|
138
|
-
try{$roleRaw=$acc.get_accRole(0);$role=[int]$roleRaw}catch{$role=-1}
|
|
139
|
-
try{$state=[int]$acc.get_accState(0)}catch{$state=0}
|
|
140
|
-
$invisible=(($state -band 0x8000) -ne 0) -or (($state -band 0x10000) -ne 0)
|
|
141
|
-
if($depth -gt 0 -and $invisible){return}
|
|
142
|
-
$isDocument=$role -eq 15
|
|
143
|
-
$inside=$inDocument -or $isDocument
|
|
144
|
-
$l=0;$t=0;$w=0;$hh=0;$hasRect=$true
|
|
145
|
-
try{$acc.accLocation([ref]$l,[ref]$t,[ref]$w,[ref]$hh,0)}catch{$hasRect=$false}
|
|
146
|
-
try{$name=[string]$acc.get_accName(0)}catch{$name=''}
|
|
147
|
-
try{$value=[string]$acc.get_accValue(0)}catch{$value=''}
|
|
148
|
-
$visible=$hasRect -and $w -gt 0 -and $hh -gt 0 -and -not $invisible
|
|
149
|
-
if($inside -and $visible -and (($interactive -contains $role) -or ($informative -contains $role) -or $name -or $value)){
|
|
150
|
-
$id='msaa:'+$rootPid+':'+$path
|
|
151
|
-
$patterns=New-Object System.Collections.ArrayList
|
|
152
|
-
if($role -in @(30,43,56,62)){[void]$patterns.Add('invoke')}
|
|
153
|
-
if($role -in @(42,46,47)){[void]$patterns.Add('value')}
|
|
154
|
-
if($role -in @(34,36,37,45)){[void]$patterns.Add('selection_item')}
|
|
155
|
-
if($role -eq 44){[void]$patterns.Add('toggle')}
|
|
156
|
-
if($role -eq 51){[void]$patterns.Add('range_value')}
|
|
157
|
-
[void]$nodes.Add([pscustomobject]@{
|
|
158
|
-
id=$id;parent_id=$parentId;depth=$depth;active=($depth -eq 0);pid=$rootPid;app=$rootApp;window=$windowName;
|
|
159
|
-
name=$name;role=(Get-RoleName $role);localized_role=(Get-RoleName $role);automationId='';className='';frameworkId='MSAA';
|
|
160
|
-
enabled=$true;offscreen=$false;focused=(($state -band 0x4) -ne 0);focusable=(($state -band 0x100000) -ne 0);password=$false;
|
|
161
|
-
value=$value;patterns=@($patterns);x=[int]$l;y=[int]$t;width=[int]$w;height=[int]$hh
|
|
162
|
-
})
|
|
163
|
-
$parentId=$id
|
|
164
|
-
}
|
|
165
|
-
try{$count=[int]$acc.accChildCount}catch{$count=0}
|
|
166
|
-
for($i=1;$i -le $count;$i++){
|
|
167
|
-
if($script:seen -ge ${maxNodes}){$script:truncated=$true;break}
|
|
168
|
-
try{$child=$acc.get_accChild($i)}catch{continue}
|
|
169
|
-
if($child -is [Accessibility.IAccessible]){
|
|
170
|
-
Walk-Acc $child ($depth+1) ($path+'.'+$i) $inside $parentId
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
Walk-Acc $rootAcc 0 'r' $false $null
|
|
175
|
-
[pscustomobject]@{platform='win32';count=$nodes.Count;nodes=@($nodes);truncated=$truncated;max_nodes=${maxNodes};browser_dom=[pscustomobject]@{requested=$true;available=($nodes.Count -gt 0);provider='msaa-iaccessible'}}|ConvertTo-Json -Compress -Depth 7`;
|
|
176
|
-
const { stdout } = await runPowerShell(script, { label:'MSAA browser accessibility snapshot', timeout:30_000 });
|
|
177
|
-
return stdout.trim() ? JSON.parse(stdout) : { platform:'win32', count:0, nodes:[], browser_dom:{ requested:true, available:false, provider:'msaa-iaccessible' } };
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
function windowsUiRootScript(args = {}) {
|
|
181
|
-
const pid = Number.isInteger(Number(args.pid)) ? Number(args.pid) : 0;
|
|
182
|
-
const app = escapePowerShellSingle(optionalString(args.app) || '');
|
|
183
|
-
const title = escapePowerShellSingle(optionalString(args.window_title || args.windowTitle) || '');
|
|
184
|
-
const scoped = pid > 0 || app || title;
|
|
185
|
-
const selector = scoped
|
|
186
|
-
? `$p=Get-Process|Where-Object{$_.MainWindowHandle -ne 0 -and (${pid} -eq 0 -or $_.Id -eq ${pid}) -and ('${app}' -eq '' -or $_.ProcessName -like '*${app}*') -and ('${title}' -eq '' -or $_.MainWindowTitle -like '*${title}*')}|Select-Object -First 1;if(-not $p){throw 'No matching UI window found'};$h=$p.MainWindowHandle`
|
|
187
|
-
: '$h=[RMFG]::GetForegroundWindow()';
|
|
188
|
-
return String.raw`
|
|
189
|
-
Add-Type @'
|
|
190
|
-
using System;using System.Runtime.InteropServices;
|
|
191
|
-
public static class RMFG{
|
|
192
|
-
[DllImport("user32.dll")]public static extern IntPtr GetForegroundWindow();
|
|
193
|
-
}
|
|
194
|
-
'@
|
|
195
|
-
$h=[IntPtr]::Zero
|
|
196
|
-
${selector}
|
|
197
|
-
if($h -eq [IntPtr]::Zero){throw 'No foreground UI window is available'}
|
|
198
|
-
$root=[System.Windows.Automation.AutomationElement]::FromHandle($h)
|
|
199
|
-
if(-not $root){throw 'Could not create UI Automation root'}
|
|
200
|
-
$windowName=$root.Current.Name
|
|
201
|
-
$rootPid=$root.Current.ProcessId
|
|
202
|
-
try{$rootApp=(Get-Process -Id $rootPid -ErrorAction Stop).ProcessName}catch{$rootApp=''}
|
|
203
|
-
`;
|
|
204
|
-
}
|
|
205
|
-
|
|
206
104
|
export async function uiSnapshot(args = {}) {
|
|
207
105
|
const maxNodes = clamp(args.max_nodes, 500, 1, 5000);
|
|
208
106
|
const maxDepth = clamp(args.max_depth, 8, 1, 32);
|