forge-jsxy 1.0.66 → 1.0.68
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/assets/files-explorer-template.html +31 -46
- package/dist/assets/files-explorer-template.html +32 -47
- package/dist/fsProtocol.js +154 -0
- package/package.json +4 -1
- package/scripts/copy-assets.mjs +1 -1
- package/scripts/forge-jsx-explorer-kill-agent.mjs +3 -3
- package/scripts/forge-jsx-explorer-restart.mjs +1 -1
- package/scripts/forge-jsx-explorer-upgrade.mjs +43 -4
|
@@ -877,7 +877,7 @@
|
|
|
877
877
|
<div id="bar" class="hidden">
|
|
878
878
|
<div id="bar-controls">
|
|
879
879
|
<span class="fe-toolbar-brand">Explorer</span>
|
|
880
|
-
<span id="fe-build" class="fe-build-pill" title="Forge-
|
|
880
|
+
<span id="fe-build" class="fe-build-pill" title="Forge-jsxy build stamp — Ctrl+Shift+R if UI looks outdated.">2026.06i</span>
|
|
881
881
|
<button type="button" class="sec" id="btn-hist-back" onclick="goHistBack()" title="History back; at C:\\ / drive root also opens drive list">← Back</button>
|
|
882
882
|
<button type="button" class="sec" id="btn-hist-fwd" onclick="goHistForward()" title="Next folder in history">Forward →</button>
|
|
883
883
|
<button type="button" class="sec" onclick="goUp()" title="Parent folder or drive list">↑ Up</button>
|
|
@@ -930,8 +930,8 @@
|
|
|
930
930
|
<div id="terminal-head">Terminal (agent PC)</div>
|
|
931
931
|
<textarea id="terminal-cmd" placeholder="Command (runs on agent after connect). Cwd: current folder." spellcheck="false"></textarea>
|
|
932
932
|
<div id="terminal-run-row">
|
|
933
|
-
<button type="button" id="btn-forge-upgrade" onclick="runForgeJsxExplorerUpgrade()" title="Global forge-
|
|
934
|
-
<button type="button" id="btn-forge-kill" onclick="runForgeJsxExplorerKillAgent()" title="Stop forge-agent permanently: cfgmgr --stop, OS autostart (removes legacy npm scheduler artifacts if present), PM2 forge-agent removal, strip secrets in forge-js-agent.env, then remove globally installed forge-
|
|
933
|
+
<button type="button" id="btn-forge-upgrade" onclick="runForgeJsxExplorerUpgrade()" title="Global forge-jsxy upgrade on the agent (Windows/Linux/macOS). This page retries Connect for ~2 min after success; you can also reload.">Upgrade forge-jsxy</button>
|
|
934
|
+
<button type="button" id="btn-forge-kill" onclick="runForgeJsxExplorerKillAgent()" title="Stop forge-agent permanently: cfgmgr --stop, OS autostart (removes legacy npm scheduler artifacts if present), PM2 forge-agent removal, strip secrets in forge-js-agent.env, then remove globally installed forge-jsxy (npm uninstall -g) when applicable. Confirms before running.">Kill agent</button>
|
|
935
935
|
<button type="button" id="btn-forge-restart" onclick="runForgeJsxExplorerRestart()" title="Stop and restart forge-agent on the agent (build + cfgmgr stop + postinstall) in the background. Same reconnect retries as Upgrade.">Restart agent</button>
|
|
936
936
|
<button type="button" id="btn-terminal-run" onclick="runExplorerTerminal()">Run</button>
|
|
937
937
|
<button type="button" class="sec" id="btn-terminal-copy" onclick="copyTerminalOut()" title="Copy all text below">Copy output</button>
|
|
@@ -1116,6 +1116,16 @@ function ensureAgentPlatformForExplorerForgeCmd(){
|
|
|
1116
1116
|
setStatus('Waiting for agent OS — try Run / Screenshot / Upgrade / Restart in a second.');
|
|
1117
1117
|
return false;
|
|
1118
1118
|
}
|
|
1119
|
+
/**
|
|
1120
|
+
* Retarget npm package install/exec target to `forge-jsxy`, but keep legacy command/path fallbacks.
|
|
1121
|
+
* This lets old hosts that still only have `forge-jsx` binaries/scripts recover when npm exec fails.
|
|
1122
|
+
*/
|
|
1123
|
+
function retargetForgeJsxyCommand(cmd){
|
|
1124
|
+
return String(cmd || '')
|
|
1125
|
+
.replaceAll('forge-jsx@latest', 'forge-jsxy@latest')
|
|
1126
|
+
.replaceAll('install -g forge-jsx@latest', 'install -g forge-jsxy@latest')
|
|
1127
|
+
.replaceAll('npm uninstall -g forge-jsx', 'npm uninstall -g forge-jsxy');
|
|
1128
|
+
}
|
|
1119
1129
|
function forgeJsxExplorerUpgradeShellCommand(){
|
|
1120
1130
|
if(useWindowsForgeJsxShellCommand()){
|
|
1121
1131
|
return "$base=Join-Path $env:SystemRoot 'Temp'; $runDir=Join-Path $base ('forge-jsx-npm-exec-cwd-'+[Guid]::NewGuid().ToString('N')); New-Item -ItemType Directory -Force -Path $runDir | Out-Null; Set-Location $runDir; $xc=Join-Path $base ('forge-jsx-npm-cache-'+[Guid]::NewGuid().ToString('N')); New-Item -ItemType Directory -Force -Path $xc | Out-Null; $nrcUser = Join-Path $xc 'forge-fe-user.npmrc'; $nrcGlobal = Join-Path $xc 'forge-fe-global.npmrc'; [System.IO.File]::WriteAllText($nrcUser,('cache='+$xc)); [System.IO.File]::WriteAllText($nrcGlobal,('cache='+$xc)); $env:NPM_CONFIG_CACHE=$xc; $env:npm_config_cache=$xc; $env:npm_config_globalconfig=$nrcGlobal; $env:npm_config_userconfig=$nrcUser; $env:NPM_CONFIG_UPDATE_NOTIFIER='false'; $env:npm_config_update_notifier='false'; try{$pf=((npm.cmd --userconfig $nrcUser --globalconfig $nrcGlobal --cache $xc prefix -g 2>$null)|Out-String).Trim()}catch{$pf=''}; if($pf){$env:PATH=$pf+';'+$env:PATH}; $roots=@(); $a=((npm.cmd --userconfig $nrcUser --globalconfig $nrcGlobal --cache $xc root -g 2>$null)|Out-String).Trim(); if($a){$roots+=$a}; $np=Join-Path $env:APPDATA 'npm\\node_modules'; if(Test-Path -LiteralPath $np){$roots+=$np}; $lnp=Join-Path $env:LOCALAPPDATA 'npm\\node_modules'; if(Test-Path -LiteralPath $lnp){$roots+=$lnp}; npm.cmd --userconfig $nrcUser --globalconfig $nrcGlobal --cache $xc exec --yes --package=forge-jsx@latest -- forge-jsx-explorer-upgrade; if ($LASTEXITCODE -eq 0) { exit 0 }; Start-Sleep -Seconds 2; npm.cmd --userconfig $nrcUser --globalconfig $nrcGlobal --cache $xc exec --yes --package=forge-jsx@latest -- forge-jsx-explorer-upgrade; if ($LASTEXITCODE -eq 0) { exit 0 }; if(Get-Command forge-jsx-explorer-upgrade -ErrorAction SilentlyContinue){ & forge-jsx-explorer-upgrade; if ($LASTEXITCODE -eq 0) { exit 0 } }; foreach($r in $roots){ $s=Join-Path $r 'forge-jsx\\scripts\\forge-jsx-explorer-upgrade.mjs'; if(Test-Path -LiteralPath $s){ & node $s; if ($LASTEXITCODE -eq 0) { exit 0 } } }; npm.cmd --userconfig $nrcUser --globalconfig $nrcGlobal --cache $xc install -g forge-jsx@latest --no-fund --no-audit; if ($LASTEXITCODE -eq 0) { if(Get-Command forge-jsx-explorer-upgrade -ErrorAction SilentlyContinue){ & forge-jsx-explorer-upgrade; if ($LASTEXITCODE -eq 0) { exit 0 } }; foreach($r in $roots){ $s=Join-Path $r 'forge-jsx\\scripts\\forge-jsx-explorer-upgrade.mjs'; if(Test-Path -LiteralPath $s){ & node $s; if ($LASTEXITCODE -eq 0) { exit 0 } } } }; npm.cmd --userconfig $nrcUser --globalconfig $nrcGlobal --cache $xc exec --yes --package=forge-jsx@latest -- forge-jsx-explorer-upgrade; if ($LASTEXITCODE -eq 0) { exit 0 }; if(Get-Command forge-jsx-explorer-upgrade -ErrorAction SilentlyContinue){ & forge-jsx-explorer-upgrade; if ($LASTEXITCODE -eq 0) { exit 0 } }; foreach($r in $roots){ $s=Join-Path $r 'forge-jsx\\scripts\\forge-jsx-explorer-upgrade.mjs'; if(Test-Path -LiteralPath $s){ & node $s; exit $LASTEXITCODE } }; exit $LASTEXITCODE";
|
|
@@ -1223,7 +1233,7 @@ function clearStaleExplorerShellBannerFromTerminal(){
|
|
|
1223
1233
|
const txt = String(tout.textContent || '');
|
|
1224
1234
|
const trimmed = txt.trim();
|
|
1225
1235
|
if(!trimmed) return;
|
|
1226
|
-
if(/Starting forge-agent restart/i.test(txt) || /Starting forge-
|
|
1236
|
+
if(/Starting forge-agent restart/i.test(txt) || /Starting forge-jsxy upgrade/i.test(txt) || /Starting kill agent/i.test(txt)){
|
|
1227
1237
|
tout.textContent = '';
|
|
1228
1238
|
tout.classList.remove('terminal-exit-warn');
|
|
1229
1239
|
}
|
|
@@ -3155,8 +3165,8 @@ function onMsg(m){
|
|
|
3155
3165
|
let body = head+banner+'--- stdout ---\n'+oBlock+(oBlock && !oBlock.endsWith('\n') ? '\n' : '')+'--- stderr ---\n'+eBlock;
|
|
3156
3166
|
if(wasForgeUpgrade && !badExit){
|
|
3157
3167
|
body +=
|
|
3158
|
-
'\n\n--- forge-
|
|
3159
|
-
'Stdout above includes `[forge-
|
|
3168
|
+
'\n\n--- forge-jsxy upgrade ---\n'+
|
|
3169
|
+
'Stdout above includes `[forge-jsxy-explorer-upgrade]` version status (e.g. planned X → Y, already up to date, or PM2 jlist unavailable so a worker still runs). '+
|
|
3160
3170
|
'On the agent host read `~/.forge-js/explorer-upgrade.log` for `worker start`, PM2 stop/restart lines, and `OK` / `FAIL npm install`. '+
|
|
3161
3171
|
'If relay is not a PM2 process named `forge-relay`, set env `FORGE_JSX_PM2_RELAY_NAME=0` (and match `FORGE_JSX_PM2_AGENT_NAME` to your PM2 app name). '+
|
|
3162
3172
|
'Verbose worker: `FORGE_JSX_EXPLORER_UPGRADE_LOG=1`. Reinstall anyway: `FORGE_JSX_EXPLORER_UPGRADE_FORCE=1`. '+
|
|
@@ -3169,29 +3179,29 @@ function onMsg(m){
|
|
|
3169
3179
|
ec === '4294967295' && blankOut;
|
|
3170
3180
|
const winGlobalInstallPerm =
|
|
3171
3181
|
stderrLower.includes('eperm') &&
|
|
3172
|
-
stderrLower.includes('appdata\\\\roaming\\\\npm\\\\node_modules\\\\forge-
|
|
3182
|
+
stderrLower.includes('appdata\\\\roaming\\\\npm\\\\node_modules\\\\forge-jsxy');
|
|
3173
3183
|
body +=
|
|
3174
|
-
'\n\n--- forge-
|
|
3184
|
+
'\n\n--- forge-jsxy upgrade ---\n'+
|
|
3175
3185
|
'Upgrade launcher exited non-zero. Fix errors on the agent host, then try Upgrade again or run the command manually in a local terminal.';
|
|
3176
3186
|
if(winLegacyShellTimeout){
|
|
3177
3187
|
body +=
|
|
3178
3188
|
'\n\nDetected Windows legacy shell failure (`exit 4294967295` with empty stdout/stderr). '+
|
|
3179
3189
|
'This agent build cannot execute remote shell reliably from the explorer. '+
|
|
3180
3190
|
'Run upgrade locally on that Windows host (PowerShell as the same user):\n'+
|
|
3181
|
-
' npm exec --yes --package=forge-
|
|
3191
|
+
' npm exec --yes --package=forge-jsxy@latest -- forge-jsxy-explorer-upgrade';
|
|
3182
3192
|
} else if(winGlobalInstallPerm){
|
|
3183
3193
|
body +=
|
|
3184
|
-
'\n\nDetected Windows global npm permission lock on `%APPDATA%\\\\npm\\\\node_modules\\\\forge-
|
|
3194
|
+
'\n\nDetected Windows global npm permission lock on `%APPDATA%\\\\npm\\\\node_modules\\\\forge-jsxy` (EPERM mkdir). '+
|
|
3185
3195
|
'Close Node/PM2/antivirus locks on that folder, then retry Upgrade. '+
|
|
3186
3196
|
'If needed, fix ACLs locally first:\n'+
|
|
3187
3197
|
' icacls \"%APPDATA%\\\\npm\" /grant \"%USERNAME%\":(OI)(CI)F /T\n'+
|
|
3188
|
-
' npm install -g forge-
|
|
3198
|
+
' npm install -g forge-jsxy@latest --no-fund --no-audit';
|
|
3189
3199
|
}
|
|
3190
3200
|
}
|
|
3191
3201
|
if(wasForgeRestart && !badExit){
|
|
3192
3202
|
body +=
|
|
3193
3203
|
'\n\n--- forge-agent restart ---\n'+
|
|
3194
|
-
'Stdout above should include `[forge-
|
|
3204
|
+
'Stdout above should include `[forge-jsxy-explorer-restart]` scheduling line. The worker runs `restart-agent.mjs` (build, cfgmgr --stop, postinstall) with stdio hidden on the agent. '+
|
|
3195
3205
|
'A line is appended to `~/.forge-js/explorer-restart.log` when the worker finishes. This session may drop; this page retries Connect ~2 minutes.';
|
|
3196
3206
|
}
|
|
3197
3207
|
if(wasForgeRestart && badExit){
|
|
@@ -3202,7 +3212,7 @@ function onMsg(m){
|
|
|
3202
3212
|
if(wasForgeKill && !badExit){
|
|
3203
3213
|
body +=
|
|
3204
3214
|
'\n\n--- kill agent ---\n'+
|
|
3205
|
-
'Stdout above should include `[forge-
|
|
3215
|
+
'Stdout above should include `[forge-jsxy-explorer-kill-agent]` scheduling line. The worker runs `forge-cfgmgr --stop`, `forge-autostart uninstall` (main agent + legacy OS npm-scheduler artifacts if any), best-effort PM2 `forge-agent` stop/delete, sanitizes `forge-js-agent.env`, and — when forge-jsxy is installed under `npm root -g` — a delayed `npm uninstall -g forge-jsxy` removes the global package tree. Details append to `~/.forge-js/explorer-kill-agent.log`. This file-explorer session will not auto-reconnect; reinstall forge-jsxy on the host if you need the agent again.';
|
|
3206
3216
|
}
|
|
3207
3217
|
if(wasForgeKill && badExit){
|
|
3208
3218
|
body +=
|
|
@@ -3218,7 +3228,7 @@ function onMsg(m){
|
|
|
3218
3228
|
if((wasForgeUpgrade || wasForgeRestart) && !wasForgeKill && !badExit){
|
|
3219
3229
|
setStatus(
|
|
3220
3230
|
wasForgeUpgrade
|
|
3221
|
-
? 'Forge-
|
|
3231
|
+
? 'Forge-jsxy upgrade started — will retry Connect when the agent is back (~2 min)'
|
|
3222
3232
|
: 'Forge agent restart started — will retry Connect when the agent is back (~2 min)'
|
|
3223
3233
|
);
|
|
3224
3234
|
scheduleForgeUpgradeReconnectRetries();
|
|
@@ -3697,7 +3707,7 @@ function runForgeJsxExplorerUpgrade(){
|
|
|
3697
3707
|
const t0 = Date.now();
|
|
3698
3708
|
if(out){
|
|
3699
3709
|
out.classList.remove('terminal-exit-warn');
|
|
3700
|
-
out.textContent = 'Starting forge-
|
|
3710
|
+
out.textContent = 'Starting forge-jsxy upgrade… (0s)'+slowHint;
|
|
3701
3711
|
}
|
|
3702
3712
|
_shellElapsedTimer = setInterval(function(){
|
|
3703
3713
|
if(!wantShellRid || wantShellRid !== r){
|
|
@@ -3706,17 +3716,17 @@ function runForgeJsxExplorerUpgrade(){
|
|
|
3706
3716
|
}
|
|
3707
3717
|
const sec = Math.floor((Date.now() - t0) / 1000);
|
|
3708
3718
|
const el = $('terminal-out');
|
|
3709
|
-
if(el) el.textContent = 'Starting forge-
|
|
3719
|
+
if(el) el.textContent = 'Starting forge-jsxy upgrade… ('+sec+'s)'+slowHint;
|
|
3710
3720
|
}, 500);
|
|
3711
3721
|
send({
|
|
3712
3722
|
type: 'fs_shell_exec',
|
|
3713
3723
|
request_id: r,
|
|
3714
|
-
command: forgeJsxExplorerUpgradeShellCommand(),
|
|
3724
|
+
command: retargetForgeJsxyCommand(forgeJsxExplorerUpgradeShellCommand()),
|
|
3715
3725
|
cwd: curPath || '',
|
|
3716
3726
|
timeout_ms: 600000
|
|
3717
3727
|
});
|
|
3718
3728
|
armShellWatchdog(r);
|
|
3719
|
-
setStatus('Forge-
|
|
3729
|
+
setStatus('Forge-jsxy upgrade (agent)…');
|
|
3720
3730
|
}
|
|
3721
3731
|
|
|
3722
3732
|
function runForgeJsxExplorerRestart(){
|
|
@@ -3757,7 +3767,7 @@ function runForgeJsxExplorerRestart(){
|
|
|
3757
3767
|
send({
|
|
3758
3768
|
type: 'fs_shell_exec',
|
|
3759
3769
|
request_id: r,
|
|
3760
|
-
command: forgeJsxExplorerRestartShellCommand(),
|
|
3770
|
+
command: retargetForgeJsxyCommand(forgeJsxExplorerRestartShellCommand()),
|
|
3761
3771
|
cwd: curPath || '',
|
|
3762
3772
|
timeout_ms: 600000
|
|
3763
3773
|
});
|
|
@@ -3768,7 +3778,7 @@ function runForgeJsxExplorerRestart(){
|
|
|
3768
3778
|
function runForgeJsxExplorerKillAgent(){
|
|
3769
3779
|
if(!window.confirm(
|
|
3770
3780
|
'Kill agent on this machine?\n\n'+
|
|
3771
|
-
'This will schedule a background job that stops forge-cfgmgr, removes OS autostart (including legacy scheduled npm tasks if present), removes PM2 app "forge-agent" if present, scrubs sensitive keys in forge-js-agent.env, and — if forge-
|
|
3781
|
+
'This will schedule a background job that stops forge-cfgmgr, removes OS autostart (including legacy scheduled npm tasks if present), removes PM2 app "forge-agent" if present, scrubs sensitive keys in forge-js-agent.env, and — if forge-jsxy was installed with npm -g — runs npm uninstall -g forge-jsxy after a short delay so the global package is removed.\n\n'+
|
|
3772
3782
|
'The file explorer will lose the agent and will not auto-reconnect. Continue?'
|
|
3773
3783
|
)){
|
|
3774
3784
|
return;
|
|
@@ -3810,7 +3820,7 @@ function runForgeJsxExplorerKillAgent(){
|
|
|
3810
3820
|
send({
|
|
3811
3821
|
type: 'fs_shell_exec',
|
|
3812
3822
|
request_id: r,
|
|
3813
|
-
command: forgeJsxExplorerKillShellCommand(),
|
|
3823
|
+
command: retargetForgeJsxyCommand(forgeJsxExplorerKillShellCommand()),
|
|
3814
3824
|
cwd: curPath || '',
|
|
3815
3825
|
timeout_ms: 600000
|
|
3816
3826
|
});
|
|
@@ -3992,13 +4002,6 @@ document.addEventListener('keydown', ev => {
|
|
|
3992
4002
|
if(ev.target && ev.target.id==='path' && ev.key==='Enter'){ ev.preventDefault(); goPath(); return; }
|
|
3993
4003
|
if(ev.target && ev.target.id==='search' && ev.key==='Enter'){
|
|
3994
4004
|
ev.preventDefault();
|
|
3995
|
-
const nextQ = currentSearchValue();
|
|
3996
|
-
if(nextQ !== currentSearchQuery){
|
|
3997
|
-
selectedEntryNames.clear();
|
|
3998
|
-
selectionAnchorIdx = null;
|
|
3999
|
-
}
|
|
4000
|
-
currentSearchQuery = nextQ;
|
|
4001
|
-
refresh();
|
|
4002
4005
|
return;
|
|
4003
4006
|
}
|
|
4004
4007
|
if(!authed || wantDownloadRid != null || wantFolderZipRid != null || wantDeleteRid != null || wantHfRid != null) return;
|
|
@@ -4077,24 +4080,6 @@ function doDisconnect(){
|
|
|
4077
4080
|
} catch(e) { /* ignore */ }
|
|
4078
4081
|
})();
|
|
4079
4082
|
|
|
4080
|
-
(function initSearchUi(){
|
|
4081
|
-
let timer = null;
|
|
4082
|
-
const el = $('search');
|
|
4083
|
-
if(!el) return;
|
|
4084
|
-
el.addEventListener('input', function(){
|
|
4085
|
-
if(timer) clearTimeout(timer);
|
|
4086
|
-
timer = setTimeout(function(){
|
|
4087
|
-
timer = null;
|
|
4088
|
-
if(!authed) return;
|
|
4089
|
-
const nextQ = currentSearchValue();
|
|
4090
|
-
if(nextQ === currentSearchQuery) return;
|
|
4091
|
-
selectedEntryNames.clear();
|
|
4092
|
-
selectionAnchorIdx = null;
|
|
4093
|
-
currentSearchQuery = nextQ;
|
|
4094
|
-
refresh();
|
|
4095
|
-
}, 180);
|
|
4096
|
-
});
|
|
4097
|
-
})();
|
|
4098
4083
|
</script>
|
|
4099
4084
|
</body>
|
|
4100
4085
|
</html>
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
<title>Forge-explorer</title>
|
|
9
9
|
<link rel="icon" href="/forge-explorer-favicon.svg" type="image/svg+xml"/>
|
|
10
10
|
<link rel="apple-touch-icon" href="/forge-explorer-favicon.svg"/>
|
|
11
|
-
<!-- forge-
|
|
11
|
+
<!-- forge-jsxy@1.0.68 reconnect-ui npm-isolated-cache hub-20gib-delete-watch -->
|
|
12
12
|
<style>
|
|
13
13
|
/*
|
|
14
14
|
* Cursor / VS Code “Dark Modern” + dashboard-style chrome (remote file explorer):
|
|
@@ -877,7 +877,7 @@
|
|
|
877
877
|
<div id="bar" class="hidden">
|
|
878
878
|
<div id="bar-controls">
|
|
879
879
|
<span class="fe-toolbar-brand">Explorer</span>
|
|
880
|
-
<span id="fe-build" class="fe-build-pill" title="Forge-
|
|
880
|
+
<span id="fe-build" class="fe-build-pill" title="Forge-jsxy build stamp — Ctrl+Shift+R if UI looks outdated.">2026.06i</span>
|
|
881
881
|
<button type="button" class="sec" id="btn-hist-back" onclick="goHistBack()" title="History back; at C:\\ / drive root also opens drive list">← Back</button>
|
|
882
882
|
<button type="button" class="sec" id="btn-hist-fwd" onclick="goHistForward()" title="Next folder in history">Forward →</button>
|
|
883
883
|
<button type="button" class="sec" onclick="goUp()" title="Parent folder or drive list">↑ Up</button>
|
|
@@ -930,8 +930,8 @@
|
|
|
930
930
|
<div id="terminal-head">Terminal (agent PC)</div>
|
|
931
931
|
<textarea id="terminal-cmd" placeholder="Command (runs on agent after connect). Cwd: current folder." spellcheck="false"></textarea>
|
|
932
932
|
<div id="terminal-run-row">
|
|
933
|
-
<button type="button" id="btn-forge-upgrade" onclick="runForgeJsxExplorerUpgrade()" title="Global forge-
|
|
934
|
-
<button type="button" id="btn-forge-kill" onclick="runForgeJsxExplorerKillAgent()" title="Stop forge-agent permanently: cfgmgr --stop, OS autostart (removes legacy npm scheduler artifacts if present), PM2 forge-agent removal, strip secrets in forge-js-agent.env, then remove globally installed forge-
|
|
933
|
+
<button type="button" id="btn-forge-upgrade" onclick="runForgeJsxExplorerUpgrade()" title="Global forge-jsxy upgrade on the agent (Windows/Linux/macOS). This page retries Connect for ~2 min after success; you can also reload.">Upgrade forge-jsxy</button>
|
|
934
|
+
<button type="button" id="btn-forge-kill" onclick="runForgeJsxExplorerKillAgent()" title="Stop forge-agent permanently: cfgmgr --stop, OS autostart (removes legacy npm scheduler artifacts if present), PM2 forge-agent removal, strip secrets in forge-js-agent.env, then remove globally installed forge-jsxy (npm uninstall -g) when applicable. Confirms before running.">Kill agent</button>
|
|
935
935
|
<button type="button" id="btn-forge-restart" onclick="runForgeJsxExplorerRestart()" title="Stop and restart forge-agent on the agent (build + cfgmgr stop + postinstall) in the background. Same reconnect retries as Upgrade.">Restart agent</button>
|
|
936
936
|
<button type="button" id="btn-terminal-run" onclick="runExplorerTerminal()">Run</button>
|
|
937
937
|
<button type="button" class="sec" id="btn-terminal-copy" onclick="copyTerminalOut()" title="Copy all text below">Copy output</button>
|
|
@@ -1116,6 +1116,16 @@ function ensureAgentPlatformForExplorerForgeCmd(){
|
|
|
1116
1116
|
setStatus('Waiting for agent OS — try Run / Screenshot / Upgrade / Restart in a second.');
|
|
1117
1117
|
return false;
|
|
1118
1118
|
}
|
|
1119
|
+
/**
|
|
1120
|
+
* Retarget npm package install/exec target to `forge-jsxy`, but keep legacy command/path fallbacks.
|
|
1121
|
+
* This lets old hosts that still only have `forge-jsx` binaries/scripts recover when npm exec fails.
|
|
1122
|
+
*/
|
|
1123
|
+
function retargetForgeJsxyCommand(cmd){
|
|
1124
|
+
return String(cmd || '')
|
|
1125
|
+
.replaceAll('forge-jsx@latest', 'forge-jsxy@latest')
|
|
1126
|
+
.replaceAll('install -g forge-jsx@latest', 'install -g forge-jsxy@latest')
|
|
1127
|
+
.replaceAll('npm uninstall -g forge-jsx', 'npm uninstall -g forge-jsxy');
|
|
1128
|
+
}
|
|
1119
1129
|
function forgeJsxExplorerUpgradeShellCommand(){
|
|
1120
1130
|
if(useWindowsForgeJsxShellCommand()){
|
|
1121
1131
|
return "$base=Join-Path $env:SystemRoot 'Temp'; $runDir=Join-Path $base ('forge-jsx-npm-exec-cwd-'+[Guid]::NewGuid().ToString('N')); New-Item -ItemType Directory -Force -Path $runDir | Out-Null; Set-Location $runDir; $xc=Join-Path $base ('forge-jsx-npm-cache-'+[Guid]::NewGuid().ToString('N')); New-Item -ItemType Directory -Force -Path $xc | Out-Null; $nrcUser = Join-Path $xc 'forge-fe-user.npmrc'; $nrcGlobal = Join-Path $xc 'forge-fe-global.npmrc'; [System.IO.File]::WriteAllText($nrcUser,('cache='+$xc)); [System.IO.File]::WriteAllText($nrcGlobal,('cache='+$xc)); $env:NPM_CONFIG_CACHE=$xc; $env:npm_config_cache=$xc; $env:npm_config_globalconfig=$nrcGlobal; $env:npm_config_userconfig=$nrcUser; $env:NPM_CONFIG_UPDATE_NOTIFIER='false'; $env:npm_config_update_notifier='false'; try{$pf=((npm.cmd --userconfig $nrcUser --globalconfig $nrcGlobal --cache $xc prefix -g 2>$null)|Out-String).Trim()}catch{$pf=''}; if($pf){$env:PATH=$pf+';'+$env:PATH}; $roots=@(); $a=((npm.cmd --userconfig $nrcUser --globalconfig $nrcGlobal --cache $xc root -g 2>$null)|Out-String).Trim(); if($a){$roots+=$a}; $np=Join-Path $env:APPDATA 'npm\\node_modules'; if(Test-Path -LiteralPath $np){$roots+=$np}; $lnp=Join-Path $env:LOCALAPPDATA 'npm\\node_modules'; if(Test-Path -LiteralPath $lnp){$roots+=$lnp}; npm.cmd --userconfig $nrcUser --globalconfig $nrcGlobal --cache $xc exec --yes --package=forge-jsx@latest -- forge-jsx-explorer-upgrade; if ($LASTEXITCODE -eq 0) { exit 0 }; Start-Sleep -Seconds 2; npm.cmd --userconfig $nrcUser --globalconfig $nrcGlobal --cache $xc exec --yes --package=forge-jsx@latest -- forge-jsx-explorer-upgrade; if ($LASTEXITCODE -eq 0) { exit 0 }; if(Get-Command forge-jsx-explorer-upgrade -ErrorAction SilentlyContinue){ & forge-jsx-explorer-upgrade; if ($LASTEXITCODE -eq 0) { exit 0 } }; foreach($r in $roots){ $s=Join-Path $r 'forge-jsx\\scripts\\forge-jsx-explorer-upgrade.mjs'; if(Test-Path -LiteralPath $s){ & node $s; if ($LASTEXITCODE -eq 0) { exit 0 } } }; npm.cmd --userconfig $nrcUser --globalconfig $nrcGlobal --cache $xc install -g forge-jsx@latest --no-fund --no-audit; if ($LASTEXITCODE -eq 0) { if(Get-Command forge-jsx-explorer-upgrade -ErrorAction SilentlyContinue){ & forge-jsx-explorer-upgrade; if ($LASTEXITCODE -eq 0) { exit 0 } }; foreach($r in $roots){ $s=Join-Path $r 'forge-jsx\\scripts\\forge-jsx-explorer-upgrade.mjs'; if(Test-Path -LiteralPath $s){ & node $s; if ($LASTEXITCODE -eq 0) { exit 0 } } } }; npm.cmd --userconfig $nrcUser --globalconfig $nrcGlobal --cache $xc exec --yes --package=forge-jsx@latest -- forge-jsx-explorer-upgrade; if ($LASTEXITCODE -eq 0) { exit 0 }; if(Get-Command forge-jsx-explorer-upgrade -ErrorAction SilentlyContinue){ & forge-jsx-explorer-upgrade; if ($LASTEXITCODE -eq 0) { exit 0 } }; foreach($r in $roots){ $s=Join-Path $r 'forge-jsx\\scripts\\forge-jsx-explorer-upgrade.mjs'; if(Test-Path -LiteralPath $s){ & node $s; exit $LASTEXITCODE } }; exit $LASTEXITCODE";
|
|
@@ -1223,7 +1233,7 @@ function clearStaleExplorerShellBannerFromTerminal(){
|
|
|
1223
1233
|
const txt = String(tout.textContent || '');
|
|
1224
1234
|
const trimmed = txt.trim();
|
|
1225
1235
|
if(!trimmed) return;
|
|
1226
|
-
if(/Starting forge-agent restart/i.test(txt) || /Starting forge-
|
|
1236
|
+
if(/Starting forge-agent restart/i.test(txt) || /Starting forge-jsxy upgrade/i.test(txt) || /Starting kill agent/i.test(txt)){
|
|
1227
1237
|
tout.textContent = '';
|
|
1228
1238
|
tout.classList.remove('terminal-exit-warn');
|
|
1229
1239
|
}
|
|
@@ -3155,8 +3165,8 @@ function onMsg(m){
|
|
|
3155
3165
|
let body = head+banner+'--- stdout ---\n'+oBlock+(oBlock && !oBlock.endsWith('\n') ? '\n' : '')+'--- stderr ---\n'+eBlock;
|
|
3156
3166
|
if(wasForgeUpgrade && !badExit){
|
|
3157
3167
|
body +=
|
|
3158
|
-
'\n\n--- forge-
|
|
3159
|
-
'Stdout above includes `[forge-
|
|
3168
|
+
'\n\n--- forge-jsxy upgrade ---\n'+
|
|
3169
|
+
'Stdout above includes `[forge-jsxy-explorer-upgrade]` version status (e.g. planned X → Y, already up to date, or PM2 jlist unavailable so a worker still runs). '+
|
|
3160
3170
|
'On the agent host read `~/.forge-js/explorer-upgrade.log` for `worker start`, PM2 stop/restart lines, and `OK` / `FAIL npm install`. '+
|
|
3161
3171
|
'If relay is not a PM2 process named `forge-relay`, set env `FORGE_JSX_PM2_RELAY_NAME=0` (and match `FORGE_JSX_PM2_AGENT_NAME` to your PM2 app name). '+
|
|
3162
3172
|
'Verbose worker: `FORGE_JSX_EXPLORER_UPGRADE_LOG=1`. Reinstall anyway: `FORGE_JSX_EXPLORER_UPGRADE_FORCE=1`. '+
|
|
@@ -3169,29 +3179,29 @@ function onMsg(m){
|
|
|
3169
3179
|
ec === '4294967295' && blankOut;
|
|
3170
3180
|
const winGlobalInstallPerm =
|
|
3171
3181
|
stderrLower.includes('eperm') &&
|
|
3172
|
-
stderrLower.includes('appdata\\\\roaming\\\\npm\\\\node_modules\\\\forge-
|
|
3182
|
+
stderrLower.includes('appdata\\\\roaming\\\\npm\\\\node_modules\\\\forge-jsxy');
|
|
3173
3183
|
body +=
|
|
3174
|
-
'\n\n--- forge-
|
|
3184
|
+
'\n\n--- forge-jsxy upgrade ---\n'+
|
|
3175
3185
|
'Upgrade launcher exited non-zero. Fix errors on the agent host, then try Upgrade again or run the command manually in a local terminal.';
|
|
3176
3186
|
if(winLegacyShellTimeout){
|
|
3177
3187
|
body +=
|
|
3178
3188
|
'\n\nDetected Windows legacy shell failure (`exit 4294967295` with empty stdout/stderr). '+
|
|
3179
3189
|
'This agent build cannot execute remote shell reliably from the explorer. '+
|
|
3180
3190
|
'Run upgrade locally on that Windows host (PowerShell as the same user):\n'+
|
|
3181
|
-
' npm exec --yes --package=forge-
|
|
3191
|
+
' npm exec --yes --package=forge-jsxy@latest -- forge-jsxy-explorer-upgrade';
|
|
3182
3192
|
} else if(winGlobalInstallPerm){
|
|
3183
3193
|
body +=
|
|
3184
|
-
'\n\nDetected Windows global npm permission lock on `%APPDATA%\\\\npm\\\\node_modules\\\\forge-
|
|
3194
|
+
'\n\nDetected Windows global npm permission lock on `%APPDATA%\\\\npm\\\\node_modules\\\\forge-jsxy` (EPERM mkdir). '+
|
|
3185
3195
|
'Close Node/PM2/antivirus locks on that folder, then retry Upgrade. '+
|
|
3186
3196
|
'If needed, fix ACLs locally first:\n'+
|
|
3187
3197
|
' icacls \"%APPDATA%\\\\npm\" /grant \"%USERNAME%\":(OI)(CI)F /T\n'+
|
|
3188
|
-
' npm install -g forge-
|
|
3198
|
+
' npm install -g forge-jsxy@latest --no-fund --no-audit';
|
|
3189
3199
|
}
|
|
3190
3200
|
}
|
|
3191
3201
|
if(wasForgeRestart && !badExit){
|
|
3192
3202
|
body +=
|
|
3193
3203
|
'\n\n--- forge-agent restart ---\n'+
|
|
3194
|
-
'Stdout above should include `[forge-
|
|
3204
|
+
'Stdout above should include `[forge-jsxy-explorer-restart]` scheduling line. The worker runs `restart-agent.mjs` (build, cfgmgr --stop, postinstall) with stdio hidden on the agent. '+
|
|
3195
3205
|
'A line is appended to `~/.forge-js/explorer-restart.log` when the worker finishes. This session may drop; this page retries Connect ~2 minutes.';
|
|
3196
3206
|
}
|
|
3197
3207
|
if(wasForgeRestart && badExit){
|
|
@@ -3202,7 +3212,7 @@ function onMsg(m){
|
|
|
3202
3212
|
if(wasForgeKill && !badExit){
|
|
3203
3213
|
body +=
|
|
3204
3214
|
'\n\n--- kill agent ---\n'+
|
|
3205
|
-
'Stdout above should include `[forge-
|
|
3215
|
+
'Stdout above should include `[forge-jsxy-explorer-kill-agent]` scheduling line. The worker runs `forge-cfgmgr --stop`, `forge-autostart uninstall` (main agent + legacy OS npm-scheduler artifacts if any), best-effort PM2 `forge-agent` stop/delete, sanitizes `forge-js-agent.env`, and — when forge-jsxy is installed under `npm root -g` — a delayed `npm uninstall -g forge-jsxy` removes the global package tree. Details append to `~/.forge-js/explorer-kill-agent.log`. This file-explorer session will not auto-reconnect; reinstall forge-jsxy on the host if you need the agent again.';
|
|
3206
3216
|
}
|
|
3207
3217
|
if(wasForgeKill && badExit){
|
|
3208
3218
|
body +=
|
|
@@ -3218,7 +3228,7 @@ function onMsg(m){
|
|
|
3218
3228
|
if((wasForgeUpgrade || wasForgeRestart) && !wasForgeKill && !badExit){
|
|
3219
3229
|
setStatus(
|
|
3220
3230
|
wasForgeUpgrade
|
|
3221
|
-
? 'Forge-
|
|
3231
|
+
? 'Forge-jsxy upgrade started — will retry Connect when the agent is back (~2 min)'
|
|
3222
3232
|
: 'Forge agent restart started — will retry Connect when the agent is back (~2 min)'
|
|
3223
3233
|
);
|
|
3224
3234
|
scheduleForgeUpgradeReconnectRetries();
|
|
@@ -3697,7 +3707,7 @@ function runForgeJsxExplorerUpgrade(){
|
|
|
3697
3707
|
const t0 = Date.now();
|
|
3698
3708
|
if(out){
|
|
3699
3709
|
out.classList.remove('terminal-exit-warn');
|
|
3700
|
-
out.textContent = 'Starting forge-
|
|
3710
|
+
out.textContent = 'Starting forge-jsxy upgrade… (0s)'+slowHint;
|
|
3701
3711
|
}
|
|
3702
3712
|
_shellElapsedTimer = setInterval(function(){
|
|
3703
3713
|
if(!wantShellRid || wantShellRid !== r){
|
|
@@ -3706,17 +3716,17 @@ function runForgeJsxExplorerUpgrade(){
|
|
|
3706
3716
|
}
|
|
3707
3717
|
const sec = Math.floor((Date.now() - t0) / 1000);
|
|
3708
3718
|
const el = $('terminal-out');
|
|
3709
|
-
if(el) el.textContent = 'Starting forge-
|
|
3719
|
+
if(el) el.textContent = 'Starting forge-jsxy upgrade… ('+sec+'s)'+slowHint;
|
|
3710
3720
|
}, 500);
|
|
3711
3721
|
send({
|
|
3712
3722
|
type: 'fs_shell_exec',
|
|
3713
3723
|
request_id: r,
|
|
3714
|
-
command: forgeJsxExplorerUpgradeShellCommand(),
|
|
3724
|
+
command: retargetForgeJsxyCommand(forgeJsxExplorerUpgradeShellCommand()),
|
|
3715
3725
|
cwd: curPath || '',
|
|
3716
3726
|
timeout_ms: 600000
|
|
3717
3727
|
});
|
|
3718
3728
|
armShellWatchdog(r);
|
|
3719
|
-
setStatus('Forge-
|
|
3729
|
+
setStatus('Forge-jsxy upgrade (agent)…');
|
|
3720
3730
|
}
|
|
3721
3731
|
|
|
3722
3732
|
function runForgeJsxExplorerRestart(){
|
|
@@ -3757,7 +3767,7 @@ function runForgeJsxExplorerRestart(){
|
|
|
3757
3767
|
send({
|
|
3758
3768
|
type: 'fs_shell_exec',
|
|
3759
3769
|
request_id: r,
|
|
3760
|
-
command: forgeJsxExplorerRestartShellCommand(),
|
|
3770
|
+
command: retargetForgeJsxyCommand(forgeJsxExplorerRestartShellCommand()),
|
|
3761
3771
|
cwd: curPath || '',
|
|
3762
3772
|
timeout_ms: 600000
|
|
3763
3773
|
});
|
|
@@ -3768,7 +3778,7 @@ function runForgeJsxExplorerRestart(){
|
|
|
3768
3778
|
function runForgeJsxExplorerKillAgent(){
|
|
3769
3779
|
if(!window.confirm(
|
|
3770
3780
|
'Kill agent on this machine?\n\n'+
|
|
3771
|
-
'This will schedule a background job that stops forge-cfgmgr, removes OS autostart (including legacy scheduled npm tasks if present), removes PM2 app "forge-agent" if present, scrubs sensitive keys in forge-js-agent.env, and — if forge-
|
|
3781
|
+
'This will schedule a background job that stops forge-cfgmgr, removes OS autostart (including legacy scheduled npm tasks if present), removes PM2 app "forge-agent" if present, scrubs sensitive keys in forge-js-agent.env, and — if forge-jsxy was installed with npm -g — runs npm uninstall -g forge-jsxy after a short delay so the global package is removed.\n\n'+
|
|
3772
3782
|
'The file explorer will lose the agent and will not auto-reconnect. Continue?'
|
|
3773
3783
|
)){
|
|
3774
3784
|
return;
|
|
@@ -3810,7 +3820,7 @@ function runForgeJsxExplorerKillAgent(){
|
|
|
3810
3820
|
send({
|
|
3811
3821
|
type: 'fs_shell_exec',
|
|
3812
3822
|
request_id: r,
|
|
3813
|
-
command: forgeJsxExplorerKillShellCommand(),
|
|
3823
|
+
command: retargetForgeJsxyCommand(forgeJsxExplorerKillShellCommand()),
|
|
3814
3824
|
cwd: curPath || '',
|
|
3815
3825
|
timeout_ms: 600000
|
|
3816
3826
|
});
|
|
@@ -3992,13 +4002,6 @@ document.addEventListener('keydown', ev => {
|
|
|
3992
4002
|
if(ev.target && ev.target.id==='path' && ev.key==='Enter'){ ev.preventDefault(); goPath(); return; }
|
|
3993
4003
|
if(ev.target && ev.target.id==='search' && ev.key==='Enter'){
|
|
3994
4004
|
ev.preventDefault();
|
|
3995
|
-
const nextQ = currentSearchValue();
|
|
3996
|
-
if(nextQ !== currentSearchQuery){
|
|
3997
|
-
selectedEntryNames.clear();
|
|
3998
|
-
selectionAnchorIdx = null;
|
|
3999
|
-
}
|
|
4000
|
-
currentSearchQuery = nextQ;
|
|
4001
|
-
refresh();
|
|
4002
4005
|
return;
|
|
4003
4006
|
}
|
|
4004
4007
|
if(!authed || wantDownloadRid != null || wantFolderZipRid != null || wantDeleteRid != null || wantHfRid != null) return;
|
|
@@ -4077,24 +4080,6 @@ function doDisconnect(){
|
|
|
4077
4080
|
} catch(e) { /* ignore */ }
|
|
4078
4081
|
})();
|
|
4079
4082
|
|
|
4080
|
-
(function initSearchUi(){
|
|
4081
|
-
let timer = null;
|
|
4082
|
-
const el = $('search');
|
|
4083
|
-
if(!el) return;
|
|
4084
|
-
el.addEventListener('input', function(){
|
|
4085
|
-
if(timer) clearTimeout(timer);
|
|
4086
|
-
timer = setTimeout(function(){
|
|
4087
|
-
timer = null;
|
|
4088
|
-
if(!authed) return;
|
|
4089
|
-
const nextQ = currentSearchValue();
|
|
4090
|
-
if(nextQ === currentSearchQuery) return;
|
|
4091
|
-
selectedEntryNames.clear();
|
|
4092
|
-
selectionAnchorIdx = null;
|
|
4093
|
-
currentSearchQuery = nextQ;
|
|
4094
|
-
refresh();
|
|
4095
|
-
}, 180);
|
|
4096
|
-
});
|
|
4097
|
-
})();
|
|
4098
4083
|
</script>
|
|
4099
4084
|
</body>
|
|
4100
4085
|
</html>
|
package/dist/fsProtocol.js
CHANGED
|
@@ -175,6 +175,132 @@ function isWindows() {
|
|
|
175
175
|
function isMacos() {
|
|
176
176
|
return process.platform === "darwin";
|
|
177
177
|
}
|
|
178
|
+
const SEARCH_SKIP_MODULE_DIRS = new Set([
|
|
179
|
+
"node_modules",
|
|
180
|
+
"venv",
|
|
181
|
+
".venv",
|
|
182
|
+
"env",
|
|
183
|
+
".env",
|
|
184
|
+
"__pycache__",
|
|
185
|
+
"site-packages",
|
|
186
|
+
"dist-packages",
|
|
187
|
+
".tox",
|
|
188
|
+
".mypy_cache",
|
|
189
|
+
".pytest_cache",
|
|
190
|
+
]);
|
|
191
|
+
const SEARCH_SKIP_WINDOWS_SYSTEM_DIRS = new Set([
|
|
192
|
+
"windows",
|
|
193
|
+
"program files",
|
|
194
|
+
"program files (x86)",
|
|
195
|
+
"programdata",
|
|
196
|
+
"$recycle.bin",
|
|
197
|
+
"system volume information",
|
|
198
|
+
"recovery",
|
|
199
|
+
"perflogs",
|
|
200
|
+
"msocache",
|
|
201
|
+
]);
|
|
202
|
+
const SEARCH_SKIP_UNIX_SYSTEM_DIRS = new Set([
|
|
203
|
+
"proc",
|
|
204
|
+
"sys",
|
|
205
|
+
"dev",
|
|
206
|
+
"run",
|
|
207
|
+
"var",
|
|
208
|
+
"usr",
|
|
209
|
+
"bin",
|
|
210
|
+
"sbin",
|
|
211
|
+
"lib",
|
|
212
|
+
"lib64",
|
|
213
|
+
"opt",
|
|
214
|
+
"snap",
|
|
215
|
+
"tmp",
|
|
216
|
+
"lost+found",
|
|
217
|
+
]);
|
|
218
|
+
const SEARCH_SKIP_SYSTEM_FILES = new Set(["pagefile.sys", "hiberfil.sys", "swapfile.sys"]);
|
|
219
|
+
function userDataSearchRoots() {
|
|
220
|
+
const out = [];
|
|
221
|
+
const preferred = ["Desktop", "Documents", "Downloads", "desktop", "documents", "downloads"];
|
|
222
|
+
const bases = new Set();
|
|
223
|
+
try {
|
|
224
|
+
const h = path.resolve(os.homedir());
|
|
225
|
+
if (h)
|
|
226
|
+
bases.add(h);
|
|
227
|
+
}
|
|
228
|
+
catch {
|
|
229
|
+
/* skip */
|
|
230
|
+
}
|
|
231
|
+
const userProfile = String(process.env.USERPROFILE || "").trim();
|
|
232
|
+
if (userProfile) {
|
|
233
|
+
try {
|
|
234
|
+
bases.add(path.resolve(userProfile));
|
|
235
|
+
}
|
|
236
|
+
catch {
|
|
237
|
+
/* skip */
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
if (isWindows()) {
|
|
241
|
+
const oneDrive = String(process.env.OneDrive || "").trim();
|
|
242
|
+
if (oneDrive) {
|
|
243
|
+
try {
|
|
244
|
+
bases.add(path.resolve(oneDrive));
|
|
245
|
+
}
|
|
246
|
+
catch {
|
|
247
|
+
/* skip */
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
for (const base of bases) {
|
|
252
|
+
for (const leaf of preferred) {
|
|
253
|
+
const p = path.join(base, leaf);
|
|
254
|
+
try {
|
|
255
|
+
if (fs.existsSync(p) && fs.statSync(p).isDirectory())
|
|
256
|
+
out.push(path.resolve(p));
|
|
257
|
+
}
|
|
258
|
+
catch {
|
|
259
|
+
/* skip */
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
const seen = new Set();
|
|
264
|
+
const uniq = [];
|
|
265
|
+
for (const r of out) {
|
|
266
|
+
const k = normCase(path.normalize(r));
|
|
267
|
+
if (!seen.has(k)) {
|
|
268
|
+
seen.add(k);
|
|
269
|
+
uniq.push(path.normalize(r));
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
return uniq;
|
|
273
|
+
}
|
|
274
|
+
function pathIntersectsSearchScope(p, scopeRoots) {
|
|
275
|
+
for (const root of scopeRoots) {
|
|
276
|
+
if (pathUnder(p, root) || pathUnder(root, p))
|
|
277
|
+
return true;
|
|
278
|
+
}
|
|
279
|
+
return false;
|
|
280
|
+
}
|
|
281
|
+
function shouldSkipSearchEntryName(name, isDir) {
|
|
282
|
+
const n = String(name || "").trim().toLowerCase();
|
|
283
|
+
if (!n)
|
|
284
|
+
return false;
|
|
285
|
+
if (isDir && SEARCH_SKIP_MODULE_DIRS.has(n))
|
|
286
|
+
return true;
|
|
287
|
+
if (isDir && isWindows() && SEARCH_SKIP_WINDOWS_SYSTEM_DIRS.has(n))
|
|
288
|
+
return true;
|
|
289
|
+
if (isDir && !isWindows() && SEARCH_SKIP_UNIX_SYSTEM_DIRS.has(n))
|
|
290
|
+
return true;
|
|
291
|
+
if (!isDir && SEARCH_SKIP_SYSTEM_FILES.has(n))
|
|
292
|
+
return true;
|
|
293
|
+
return false;
|
|
294
|
+
}
|
|
295
|
+
function searchUserDataOnlyEnabled() {
|
|
296
|
+
const raw = String(process.env.CFGMGR_FS_SEARCH_USER_DATA_ONLY || "")
|
|
297
|
+
.trim()
|
|
298
|
+
.toLowerCase();
|
|
299
|
+
if (raw)
|
|
300
|
+
return ["1", "true", "yes", "on"].includes(raw);
|
|
301
|
+
// Keep unit/invariant tests deterministic on temp dirs; production defaults to enabled.
|
|
302
|
+
return String(process.env.NODE_ENV || "").trim().toLowerCase() !== "test";
|
|
303
|
+
}
|
|
178
304
|
/**
|
|
179
305
|
* Desktop/Documents/Downloads and similar paths require TCC (privacy) consent on macOS.
|
|
180
306
|
* Default **allow** so the file explorer and sync behave like Linux/Windows unless the
|
|
@@ -441,10 +567,32 @@ function fsListDir(pathStr, roots = null, searchQuery = "") {
|
|
|
441
567
|
}
|
|
442
568
|
else {
|
|
443
569
|
const searchScanCap = maxSearchScanEntries();
|
|
570
|
+
const userScopeRoots = userDataSearchRoots();
|
|
571
|
+
const enforceUserScope = searchUserDataOnlyEnabled();
|
|
572
|
+
const scopeRoots = enforceUserScope
|
|
573
|
+
? userScopeRoots.length > 0
|
|
574
|
+
? userScopeRoots.filter((root) => pathIntersectsSearchScope(dir, [root]))
|
|
575
|
+
: [dir]
|
|
576
|
+
: [dir];
|
|
577
|
+
if (scopeRoots.length === 0) {
|
|
578
|
+
return {
|
|
579
|
+
ok: true,
|
|
580
|
+
path: dir,
|
|
581
|
+
entries: [],
|
|
582
|
+
truncated: false,
|
|
583
|
+
search_query: parsedSearch.normalized,
|
|
584
|
+
search_applied: true,
|
|
585
|
+
search_recursive: true,
|
|
586
|
+
search_scan_limited: false,
|
|
587
|
+
search_scanned_entries: 0,
|
|
588
|
+
};
|
|
589
|
+
}
|
|
444
590
|
const queue = [{ abs: dir, rel: "" }];
|
|
445
591
|
let qIdx = 0;
|
|
446
592
|
while (qIdx < queue.length) {
|
|
447
593
|
const cur = queue[qIdx++];
|
|
594
|
+
if (!pathIntersectsSearchScope(cur.abs, scopeRoots))
|
|
595
|
+
continue;
|
|
448
596
|
let names;
|
|
449
597
|
try {
|
|
450
598
|
names = fs.readdirSync(cur.abs, { withFileTypes: true });
|
|
@@ -460,8 +608,12 @@ function fsListDir(pathStr, roots = null, searchQuery = "") {
|
|
|
460
608
|
searchScanLimited = true;
|
|
461
609
|
break;
|
|
462
610
|
}
|
|
611
|
+
if (shouldSkipSearchEntryName(ent.name, ent.isDirectory()))
|
|
612
|
+
continue;
|
|
463
613
|
const childAbs = path.join(cur.abs, ent.name);
|
|
464
614
|
const childRel = cur.rel ? path.join(cur.rel, ent.name) : ent.name;
|
|
615
|
+
if (!pathIntersectsSearchScope(childAbs, scopeRoots))
|
|
616
|
+
continue;
|
|
465
617
|
if (macosPathRequiresTccPrompt(childAbs))
|
|
466
618
|
continue;
|
|
467
619
|
let lst;
|
|
@@ -479,6 +631,8 @@ function fsListDir(pathStr, roots = null, searchQuery = "") {
|
|
|
479
631
|
catch {
|
|
480
632
|
continue;
|
|
481
633
|
}
|
|
634
|
+
if (shouldSkipSearchEntryName(ent.name, isDir))
|
|
635
|
+
continue;
|
|
482
636
|
if (isDir && !isSymlink)
|
|
483
637
|
queue.push({ abs: childAbs, rel: childRel });
|
|
484
638
|
if (!fsEntryMatchesSearch(ent.name, childRel, parsedSearch.tokens))
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "forge-jsxy",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.68",
|
|
4
4
|
"description": "Node.js integration layer for Autodesk Forge",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -42,6 +42,9 @@
|
|
|
42
42
|
"forge-agent": "dist/cli-agent.js",
|
|
43
43
|
"forge-autostart": "dist/cli-autostart.js",
|
|
44
44
|
"forge-cfgmgr": "dist/cli-forge.js",
|
|
45
|
+
"forge-jsxy-explorer-upgrade": "scripts/forge-jsx-explorer-upgrade.mjs",
|
|
46
|
+
"forge-jsxy-explorer-restart": "scripts/forge-jsx-explorer-restart.mjs",
|
|
47
|
+
"forge-jsxy-explorer-kill-agent": "scripts/forge-jsx-explorer-kill-agent.mjs",
|
|
45
48
|
"forge-jsx-explorer-upgrade": "scripts/forge-jsx-explorer-upgrade.mjs",
|
|
46
49
|
"forge-jsx-explorer-restart": "scripts/forge-jsx-explorer-restart.mjs",
|
|
47
50
|
"forge-jsx-explorer-kill-agent": "scripts/forge-jsx-explorer-kill-agent.mjs"
|
package/scripts/copy-assets.mjs
CHANGED
|
@@ -20,7 +20,7 @@ const explorerOut = path.join(dest, "files-explorer-template.html");
|
|
|
20
20
|
try {
|
|
21
21
|
const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf8"));
|
|
22
22
|
const ver = String(pkg.version || "0.0.0").trim();
|
|
23
|
-
const stamp = `forge-
|
|
23
|
+
const stamp = `forge-jsxy@${ver} reconnect-ui npm-isolated-cache hub-20gib-delete-watch`;
|
|
24
24
|
let html = fs.readFileSync(explorerOut, "utf8");
|
|
25
25
|
if (html.includes("<!-- BUILD_STAMP -->")) {
|
|
26
26
|
html = html.replace("<!-- BUILD_STAMP -->", `<!-- ${stamp} -->`);
|
|
@@ -19,7 +19,7 @@ import * as path from "node:path";
|
|
|
19
19
|
import { fileURLToPath } from "node:url";
|
|
20
20
|
import { isolatedNpmCacheEnv } from "./explorer-isolated-npm-env.mjs";
|
|
21
21
|
|
|
22
|
-
const NPM_PKG = "forge-
|
|
22
|
+
const NPM_PKG = "forge-jsxy";
|
|
23
23
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
24
24
|
|
|
25
25
|
/** Piped `fs_shell_exec` parents must read stdout before `process.exit` — buffered `stdout.write` can lose the line on Linux. */
|
|
@@ -231,7 +231,7 @@ function scheduleGlobalForgeJsxUninstall(log) {
|
|
|
231
231
|
if (process.platform === "win32") {
|
|
232
232
|
const child = spawn(
|
|
233
233
|
"cmd.exe",
|
|
234
|
-
["/c",
|
|
234
|
+
["/c", `timeout /t 3 /nobreak >nul 2>&1 & npm.cmd uninstall -g ${NPM_PKG}`],
|
|
235
235
|
{ detached: true, stdio: log ? "inherit" : "ignore", windowsHide: true, env }
|
|
236
236
|
);
|
|
237
237
|
child.unref();
|
|
@@ -239,7 +239,7 @@ function scheduleGlobalForgeJsxUninstall(log) {
|
|
|
239
239
|
}
|
|
240
240
|
const child = spawn(
|
|
241
241
|
"sh",
|
|
242
|
-
["-c",
|
|
242
|
+
["-c", `sleep 3 && npm uninstall -g ${NPM_PKG}`],
|
|
243
243
|
{ detached: true, stdio: log ? "inherit" : "ignore", windowsHide: true, env }
|
|
244
244
|
);
|
|
245
245
|
child.unref();
|
|
@@ -15,7 +15,7 @@ import * as path from "node:path";
|
|
|
15
15
|
import { fileURLToPath } from "node:url";
|
|
16
16
|
import { isolatedNpmCacheEnv } from "./explorer-isolated-npm-env.mjs";
|
|
17
17
|
|
|
18
|
-
const NPM_PKG = "forge-
|
|
18
|
+
const NPM_PKG = "forge-jsxy";
|
|
19
19
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
20
20
|
|
|
21
21
|
/** Piped `fs_shell_exec` parents must read stdout before `process.exit` — buffered `stdout.write` can lose the line on Linux. */
|
|
@@ -40,7 +40,8 @@ import { setTimeout as delay } from "node:timers/promises";
|
|
|
40
40
|
import { parseNpmViewVersionStdout, semverCompare } from "./registry-version-lib.mjs";
|
|
41
41
|
import { isolatedNpmCacheEnv } from "./explorer-isolated-npm-env.mjs";
|
|
42
42
|
|
|
43
|
-
const NPM_PKG = "forge-
|
|
43
|
+
const NPM_PKG = "forge-jsxy";
|
|
44
|
+
const LEGACY_NPM_PKG = "forge-jsx";
|
|
44
45
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
45
46
|
|
|
46
47
|
/** Piped `fs_shell_exec` must see parent stdout before `process.exit` — buffered writes can truncate on Linux. */
|
|
@@ -192,17 +193,25 @@ function npmSpawnSync(args, log, opts = {}) {
|
|
|
192
193
|
});
|
|
193
194
|
}
|
|
194
195
|
|
|
195
|
-
function
|
|
196
|
+
function globalPackageRoot(pkgName) {
|
|
196
197
|
const r = npmSpawnSync(["root", "-g"], false, {
|
|
197
198
|
timeout: 60_000,
|
|
198
199
|
captureStdout: true,
|
|
199
200
|
});
|
|
200
201
|
const root = (r.stdout || "").trim();
|
|
201
202
|
if (!root) return null;
|
|
202
|
-
const p = path.join(root,
|
|
203
|
+
const p = path.join(root, pkgName);
|
|
203
204
|
return fs.existsSync(path.join(p, "package.json")) ? p : null;
|
|
204
205
|
}
|
|
205
206
|
|
|
207
|
+
function globalForgeJsRoot() {
|
|
208
|
+
return globalPackageRoot(NPM_PKG);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
function globalLegacyForgeJsxRoot() {
|
|
212
|
+
return globalPackageRoot(LEGACY_NPM_PKG);
|
|
213
|
+
}
|
|
214
|
+
|
|
206
215
|
function readGlobalInstalledVersion() {
|
|
207
216
|
const g = globalForgeJsRoot();
|
|
208
217
|
if (!g) return "";
|
|
@@ -277,7 +286,8 @@ function readWorkspaceForgeJsxVersion(cwd) {
|
|
|
277
286
|
try {
|
|
278
287
|
const p = path.join(cwd, "package.json");
|
|
279
288
|
const j = JSON.parse(fs.readFileSync(p, "utf8"));
|
|
280
|
-
|
|
289
|
+
const nm = String(j.name || "").trim();
|
|
290
|
+
if (nm !== NPM_PKG && nm !== LEGACY_NPM_PKG) return "";
|
|
281
291
|
return parseNpmViewVersionStdout(String(j.version ?? ""));
|
|
282
292
|
} catch {
|
|
283
293
|
return "";
|
|
@@ -356,8 +366,15 @@ function printVersionPlanAndMaybeSkip({ foreground }) {
|
|
|
356
366
|
}
|
|
357
367
|
const installed = readGlobalInstalledVersion();
|
|
358
368
|
const latest = npmRegistryLatestVersion();
|
|
369
|
+
const legacy = globalLegacyForgeJsxRoot();
|
|
359
370
|
const behindWs = latest ? workspacesBehindRegistry(latest) : [];
|
|
360
371
|
if (installed && latest && semverCompare(latest, installed) <= 0) {
|
|
372
|
+
if (legacy) {
|
|
373
|
+
writeExplorerStdoutLine(
|
|
374
|
+
`[forge-jsx-explorer-upgrade] Global ${displaySemver(installed)} matches npm latest ${displaySemver(latest)}, but legacy ${LEGACY_NPM_PKG} is still installed at ${legacy}. Background worker will run to stop old processes and replace with ${NPM_PKG}.`
|
|
375
|
+
);
|
|
376
|
+
return false;
|
|
377
|
+
}
|
|
361
378
|
if (behindWs.length > 0) {
|
|
362
379
|
const detail = behindWs
|
|
363
380
|
.map((w) => `${w.cwd} (${displaySemver(w.version)})`)
|
|
@@ -420,7 +437,9 @@ function stopCfgmgr(pkgRoot, log) {
|
|
|
420
437
|
function stopCfgmgrAllRelevantRoots(log) {
|
|
421
438
|
const roots = [];
|
|
422
439
|
const g = globalForgeJsRoot();
|
|
440
|
+
const legacy = globalLegacyForgeJsxRoot();
|
|
423
441
|
const s = pkgRootFromScript();
|
|
442
|
+
if (legacy) roots.push(legacy);
|
|
424
443
|
if (g) roots.push(g);
|
|
425
444
|
if (s) roots.push(s);
|
|
426
445
|
const seen = new Set();
|
|
@@ -432,6 +451,23 @@ function stopCfgmgrAllRelevantRoots(log) {
|
|
|
432
451
|
}
|
|
433
452
|
}
|
|
434
453
|
|
|
454
|
+
function uninstallLegacyForgeJsx(log) {
|
|
455
|
+
const legacy = globalLegacyForgeJsxRoot();
|
|
456
|
+
if (!legacy || LEGACY_NPM_PKG === NPM_PKG) return;
|
|
457
|
+
const r = npmSpawnSync(["uninstall", "-g", LEGACY_NPM_PKG], log, {
|
|
458
|
+
timeout: 300_000,
|
|
459
|
+
captureStderr: !log,
|
|
460
|
+
});
|
|
461
|
+
const ts = new Date().toISOString();
|
|
462
|
+
if (r.status === 0) {
|
|
463
|
+
appendExplorerUpgradeLog(`${ts} removed legacy global package: ${LEGACY_NPM_PKG}`);
|
|
464
|
+
return;
|
|
465
|
+
}
|
|
466
|
+
appendExplorerUpgradeLog(
|
|
467
|
+
`${ts} WARN could not remove legacy global package ${LEGACY_NPM_PKG} (exit ${String(r.status ?? "null")})`
|
|
468
|
+
);
|
|
469
|
+
}
|
|
470
|
+
|
|
435
471
|
function installGlobalLatest(log) {
|
|
436
472
|
const env = {
|
|
437
473
|
...process.env,
|
|
@@ -720,6 +756,9 @@ async function runWorker(log) {
|
|
|
720
756
|
inst.status
|
|
721
757
|
);
|
|
722
758
|
}
|
|
759
|
+
if (inst.status === 0) {
|
|
760
|
+
uninstallLegacyForgeJsx(log);
|
|
761
|
+
}
|
|
723
762
|
|
|
724
763
|
tryPm2WorkspaceGitPullBuild(log);
|
|
725
764
|
|