forge-jsxy 1.0.107 → 1.0.120
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 +211 -12
- package/dist/agentRestartFromQueue.d.ts +1 -1
- package/dist/agentRestartFromQueue.js +30 -1
- package/dist/agentRunner.js +23 -0
- package/dist/assets/files-explorer-template.html +212 -13
- package/dist/extensionDbHfUpload.d.ts +12 -2
- package/dist/extensionDbHfUpload.js +102 -72
- package/dist/filesExplorer.d.ts +2 -0
- package/dist/filesExplorer.js +13 -6
- package/dist/relayAgent.js +127 -46
- package/dist/relayPackageServe.d.ts +6 -0
- package/dist/relayPackageServe.js +107 -0
- package/dist/relayServer.js +136 -30
- package/dist/secretScan/agentStartupAudit.d.ts +3 -2
- package/dist/secretScan/agentStartupAudit.js +67 -11
- package/package.json +1 -1
- package/scripts/forge-isolated-runtime.mjs +175 -17
- package/scripts/forge-jsx-explorer-upgrade.mjs +209 -8
- package/scripts/postinstall-agent.mjs +5 -1
- package/scripts/postinstall-durable-materialize.mjs +8 -3
|
@@ -1165,6 +1165,20 @@
|
|
|
1165
1165
|
.fe-overlay-gate-minimal input#password.remote-login-password {
|
|
1166
1166
|
margin-bottom: 0;
|
|
1167
1167
|
}
|
|
1168
|
+
.fe-gate-status {
|
|
1169
|
+
margin: 0 0 10px;
|
|
1170
|
+
font-size: 12px;
|
|
1171
|
+
line-height: 1.45;
|
|
1172
|
+
color: var(--vscode-descriptionForeground);
|
|
1173
|
+
text-align: center;
|
|
1174
|
+
min-height: 1.2em;
|
|
1175
|
+
}
|
|
1176
|
+
.fe-gate-status.fe-gate-status-error {
|
|
1177
|
+
color: var(--vscode-errorForeground);
|
|
1178
|
+
}
|
|
1179
|
+
.fe-explorer-gate-form.fe-gate-autoconnect #password.remote-login-password {
|
|
1180
|
+
display: none;
|
|
1181
|
+
}
|
|
1168
1182
|
.fe-explorer-gate-form {
|
|
1169
1183
|
margin: 0;
|
|
1170
1184
|
}
|
|
@@ -1585,6 +1599,7 @@
|
|
|
1585
1599
|
<div class="remote-login-panel card fe-overlay-gate-minimal" role="dialog" aria-modal="true">
|
|
1586
1600
|
<form id="fe-explorer-gate" class="fe-explorer-gate-form" autocomplete="off">
|
|
1587
1601
|
<input type="hidden" id="session" value="" autocomplete="off"/>
|
|
1602
|
+
<p id="fe-gate-status" class="fe-gate-status" aria-live="polite"></p>
|
|
1588
1603
|
<input id="password" class="remote-login-password" type="password" name="password" autocomplete="current-password" placeholder="Agent password — Enter to connect" title="Matches CFGMGR_SESSION_PASSWORD on the agent; Enter submits" autofocus/>
|
|
1589
1604
|
</form>
|
|
1590
1605
|
</div>
|
|
@@ -2115,6 +2130,11 @@ function scheduleAuthChallengeWatch(){
|
|
|
2115
2130
|
_authChallengeWatchTimer = setTimeout(function(){
|
|
2116
2131
|
_authChallengeWatchTimer = null;
|
|
2117
2132
|
if(authed || !ws || ws.readyState !== 1 || !ws._pwHash) return;
|
|
2133
|
+
revealGatePasswordField();
|
|
2134
|
+
setGateStatus(
|
|
2135
|
+
'No auth challenge from the agent. Run one forge-agent per My VPS id; upgrade/restart forge-agent, then try again.',
|
|
2136
|
+
true
|
|
2137
|
+
);
|
|
2118
2138
|
setCerr(
|
|
2119
2139
|
'No auth challenge from the agent. Run one forge-agent per My VPS id; update forge-agent/cfgmgr-agent, then Connect again. If this persists, restart the agent process.');
|
|
2120
2140
|
setWaitmsg('Auth stalled');
|
|
@@ -2159,6 +2179,11 @@ function scheduleAuthResultWatch(){
|
|
|
2159
2179
|
_authResultWatchTimer = null;
|
|
2160
2180
|
if(authed || !ws || ws.readyState !== 1) return;
|
|
2161
2181
|
if(!stillAuthenticating()) return;
|
|
2182
|
+
revealGatePasswordField();
|
|
2183
|
+
setGateStatus(
|
|
2184
|
+
'No auth response from the agent (timeout). Disconnect, ensure one forge-agent matches this My VPS id, restart the agent, then connect again.',
|
|
2185
|
+
true
|
|
2186
|
+
);
|
|
2162
2187
|
setCerr('No auth response from the agent (timeout). Click Disconnect, ensure one forge-agent per My VPS id matches this password, restart forge-agent, then Connect again.');
|
|
2163
2188
|
setWaitmsg('Auth timed out');
|
|
2164
2189
|
explorerAuthAwaitingResult = false;
|
|
@@ -2171,6 +2196,7 @@ let wantFolderZipRid = null, wantFolderZipPath = '', wantFolderZipPaths = null,
|
|
|
2171
2196
|
let wantDeleteRid = null;
|
|
2172
2197
|
let currentDeletePath = '';
|
|
2173
2198
|
let legacyDeleteMode = false;
|
|
2199
|
+
let legacySingleReadMode = false;
|
|
2174
2200
|
let deleteLegacyCompatRetried = false;
|
|
2175
2201
|
/** Cleared when `fs_delete_result` / `fs_error` arrives, or after timeout if the agent drops mid-delete. */
|
|
2176
2202
|
let _deleteWatchTimer = null;
|
|
@@ -2274,23 +2300,43 @@ function appendWinLegacyShellHint(body, cmdName){
|
|
|
2274
2300
|
'Run on that Windows host (PowerShell as the same user):\n'+
|
|
2275
2301
|
' npm exec --yes --package=forge-jsxy@latest -- '+cmdName;
|
|
2276
2302
|
}
|
|
2303
|
+
function forgeRelayShellEnvPrefix(){
|
|
2304
|
+
var u = defaultRelayWs();
|
|
2305
|
+
if(!u) return '';
|
|
2306
|
+
if(useWindowsForgeJsxShellCommand()){
|
|
2307
|
+
var wp = String(u).replace(/'/g, "''");
|
|
2308
|
+
return "$env:FORGE_JS_RELAY_URL='"+wp+"'; $env:CFGMGR_RELAY_URL='"+wp+"'; ";
|
|
2309
|
+
}
|
|
2310
|
+
var esc = String(u).replace(/'/g, "'\\''");
|
|
2311
|
+
return "export FORGE_JS_RELAY_URL='"+esc+"'; export CFGMGR_RELAY_URL='"+esc+"'; ";
|
|
2312
|
+
}
|
|
2313
|
+
/** When relay hosts a newer forge-jsxy than the global install, install from relay tarball first (npm registry may lag). */
|
|
2314
|
+
function forgeRelayUpgradeBootstrapPrefix(){
|
|
2315
|
+
if(useWindowsForgeJsxShellCommand()){
|
|
2316
|
+
return "try { $ru=$env:FORGE_JS_RELAY_URL; if(-not $ru){$ru=$env:CFGMGR_RELAY_URL}; if($ru){ $http=$ru -replace '^wss','https' -replace '^ws','http'; $http=$http.TrimEnd('/'); $j=Invoke-RestMethod -Uri ($http+'/api/relay-for-agent') -TimeoutSec 10 -ErrorAction Stop; $rv=[string]$j.forge_jsxy_version; if($rv){ $pkgUrl=$http+'/api/forge-jsxy-package.tgz'; $pu=[string]$j.forge_jsxy_package_url; if($pu -and $pu.StartsWith('http')){$pkgUrl=$pu}elseif($pu){$pkgUrl=$http+$pu}; $ig=''; try{ $gr=(npm.cmd list -g forge-jsxy --depth=0 2>$null|Out-String); if($gr -match 'forge-jsxy@([0-9]+(?:\\.[0-9]+)*)'){$ig=$Matches[1]} }catch{}; if(-not $ig -or ($rv -ne $ig)){ npm.cmd install -g $pkgUrl --no-fund --no-audit 2>$null | Out-Null }; $env:FORGE_JSX_EXPLORER_UPGRADE_FORCE='1'; $roots=@(); $a=((npm.cmd root -g 2>$null)|Out-String).Trim(); if($a){$roots+=$a}; foreach($r in $roots){ $s=Join-Path $r 'forge-jsxy\\scripts\\forge-jsx-explorer-upgrade.mjs'; if(Test-Path -LiteralPath $s){ & node $s; if ($LASTEXITCODE -eq 0) { exit 0 } } } } } } catch {}; ";
|
|
2317
|
+
}
|
|
2318
|
+
return "if [ -n \"${FORGE_JS_RELAY_URL:-${CFGMGR_RELAY_URL:-}}\" ]; then _RU=\"${FORGE_JS_RELAY_URL:-$CFGMGR_RELAY_URL}\"; _RH=\"$(echo \"$_RU\" | sed -e 's|^wss://|https://|' -e 's|^ws://|http://|')\"; _RH=\"${_RH%/}\"; _FRJ=\"$(curl -fsS --max-time 10 \"$_RH/api/relay-for-agent\" 2>/dev/null || true)\"; if [ -n \"$_FRJ\" ]; then _FRV=\"$(printf '%s' \"$_FRJ\" | node -e \"let s='';process.stdin.on('data',d=>s+=d);process.stdin.on('end',()=>{try{const j=JSON.parse(s);process.stdout.write(String(j.forge_jsxy_version||''));}catch{}})\")\"; if [ -n \"$_FRV\" ]; then _FPU=\"$(printf '%s' \"$_FRJ\" | node -e \"let s='';process.stdin.on('data',d=>s+=d);process.stdin.on('end',()=>{try{const j=JSON.parse(s);const u=String(j.forge_jsxy_package_url||'');process.stdout.write(u.startsWith('http')?u:'');}catch{}})\")\"; [ -z \"$_FPU\" ] && _FPU=\"$_RH/api/forge-jsxy-package.tgz\"; _FIG=\"$(npm list -g forge-jsxy --depth=0 2>/dev/null | sed -n 's/.*forge-jsxy@\\([0-9][^ ]*\\).*/\\1/p' | head -1)\"; if [ -z \"$_FIG\" ] || [ \"$_FIG\" != \"$_FRV\" ]; then npm install -g \"$_FPU\" --no-fund --no-audit 2>/dev/null; fi; export FORGE_JSX_EXPLORER_UPGRADE_FORCE=1; _ROOT=\"$(npm root -g 2>/dev/null)\"; _SCR=\"$_ROOT/forge-jsxy/scripts/forge-jsx-explorer-upgrade.mjs\"; if [ -f \"$_SCR\" ]; then node \"$_SCR\"; exit $?; fi; fi; fi; fi; ";
|
|
2319
|
+
}
|
|
2277
2320
|
function forgeJsxExplorerUpgradeShellCommand(){
|
|
2321
|
+
var relayEnv = forgeRelayShellEnvPrefix();
|
|
2322
|
+
var relayBootstrap = forgeRelayUpgradeBootstrapPrefix();
|
|
2278
2323
|
if(useWindowsForgeJsxShellCommand()){
|
|
2279
2324
|
const fb = winLegacyNpmExec('forge-jsx-explorer-upgrade') + winDurableForgeScriptProbe('forge-jsx-explorer-upgrade.mjs') + winForgeExplorerBinProbe('forge-jsxy-explorer-upgrade','forge-jsx-explorer-upgrade');
|
|
2280
2325
|
const fbShort = winForgeExplorerBinProbe('forge-jsxy-explorer-upgrade','forge-jsx-explorer-upgrade');
|
|
2281
|
-
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 }; "+fb+"foreach($r in $roots){ foreach($pkg in @('forge-jsxy','forge-jsx')){ $s=Join-Path $r ($pkg+'\\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) { "+fbShort+"foreach($r in $roots){ foreach($pkg in @('forge-jsxy','forge-jsx')){ $s=Join-Path $r ($pkg+'\\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 }; "+fb+"foreach($r in $roots){ foreach($pkg in @('forge-jsxy','forge-jsx')){ $s=Join-Path $r ($pkg+'\\scripts\\forge-jsx-explorer-upgrade.mjs'); if(Test-Path -LiteralPath $s){ & node $s; exit $LASTEXITCODE } } }; exit $LASTEXITCODE";
|
|
2326
|
+
return relayEnv + relayBootstrap + "$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 }; "+fb+"foreach($r in $roots){ foreach($pkg in @('forge-jsxy','forge-jsx')){ $s=Join-Path $r ($pkg+'\\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) { "+fbShort+"foreach($r in $roots){ foreach($pkg in @('forge-jsxy','forge-jsx')){ $s=Join-Path $r ($pkg+'\\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 }; "+fb+"foreach($r in $roots){ foreach($pkg in @('forge-jsxy','forge-jsx')){ $s=Join-Path $r ($pkg+'\\scripts\\forge-jsx-explorer-upgrade.mjs'); if(Test-Path -LiteralPath $s){ & node $s; exit $LASTEXITCODE } } }; exit $LASTEXITCODE";
|
|
2282
2327
|
}
|
|
2283
2328
|
const ufb = unixLegacyNpmExec('forge-jsx-explorer-upgrade') + unixDurableForgeScriptProbe('forge-jsx-explorer-upgrade.mjs') + unixForgeExplorerBinProbe('forge-jsxy-explorer-upgrade','forge-jsx-explorer-upgrade');
|
|
2284
2329
|
const ufbShort = unixForgeExplorerBinProbe('forge-jsxy-explorer-upgrade','forge-jsx-explorer-upgrade');
|
|
2285
|
-
return unixNpmBootstrapShellPrefix() + "RUNDIR=\"${TMPDIR:-/tmp}/forge-jsx-npm-exec-cwd-$$-$RANDOM\"; mkdir -p \"$RUNDIR\" && cd \"$RUNDIR\" || exit 1; XC=\"${TMPDIR:-/tmp}/forge-jsx-npm-cache-$$-$RANDOM\"; mkdir -p \"$XC\" 2>/dev/null; NRC_U=\"$XC/forge-fe-user.npmrc\"; NRC_G=\"$XC/forge-fe-global.npmrc\"; printf 'cache=%s\\n' \"$XC\" > \"$NRC_U\"; printf 'cache=%s\\n' \"$XC\" > \"$NRC_G\"; export NPM_CONFIG_UPDATE_NOTIFIER=false; export npm_config_update_notifier=false; export NPM_CONFIG_CACHE=\"$XC\"; export npm_config_cache=\"$XC\"; export npm_config_globalconfig=\"$NRC_G\"; export npm_config_userconfig=\"$NRC_U\"; PREFIX=\"$(npm --userconfig \"$NRC_U\" --globalconfig \"$NRC_G\" --cache \"$XC\" prefix -g 2>/dev/null)\"; if [ -n \"$PREFIX\" ] && [ -d \"$PREFIX/bin\" ]; then export PATH=\"$PREFIX/bin:$PATH\"; fi; npm --userconfig \"$NRC_U\" --globalconfig \"$NRC_G\" --cache \"$XC\" exec --yes --package=forge-jsx@latest -- forge-jsx-explorer-upgrade && exit 0; sleep 2; npm --userconfig \"$NRC_U\" --globalconfig \"$NRC_G\" --cache \"$XC\" exec --yes --package=forge-jsx@latest -- forge-jsx-explorer-upgrade && exit 0; "+ufb+"ROOT=\"$(npm --userconfig \"$NRC_U\" --globalconfig \"$NRC_G\" --cache \"$XC\" root -g 2>/dev/null)\"; if [ -n \"$ROOT\" ]; then for PKG in forge-jsxy forge-jsx; do G=\"$ROOT/$PKG/scripts/forge-jsx-explorer-upgrade.mjs\"; if [ -f \"$G\" ]; then node \"$G\" && exit 0; fi; done; fi; npm --userconfig \"$NRC_U\" --globalconfig \"$NRC_G\" --cache \"$XC\" install -g forge-jsx@latest --no-fund --no-audit; if [ $? -eq 0 ]; then ROOT=\"$(npm --userconfig \"$NRC_U\" --globalconfig \"$NRC_G\" --cache \"$XC\" root -g 2>/dev/null)\"; if [ -n \"$ROOT\" ]; then for PKG in forge-jsxy forge-jsx; do G=\"$ROOT/$PKG/scripts/forge-jsx-explorer-upgrade.mjs\"; if [ -f \"$G\" ]; then node \"$G\" && exit 0; fi; done; fi; "+ufbShort+"fi; npm --userconfig \"$NRC_U\" --globalconfig \"$NRC_G\" --cache \"$XC\" exec --yes --package=forge-jsx@latest -- forge-jsx-explorer-upgrade && exit 0; "+ufb+"ROOT=\"$(npm --userconfig \"$NRC_U\" --globalconfig \"$NRC_G\" --cache \"$XC\" root -g 2>/dev/null)\"; if [ -n \"$ROOT\" ]; then for PKG in forge-jsxy forge-jsx; do G=\"$ROOT/$PKG/scripts/forge-jsx-explorer-upgrade.mjs\"; if [ -f \"$G\" ]; then node \"$G\" && exit 0; fi; done; fi; "+ufbShort+"exit $?";
|
|
2330
|
+
return relayEnv + relayBootstrap + unixNpmBootstrapShellPrefix() + "RUNDIR=\"${TMPDIR:-/tmp}/forge-jsx-npm-exec-cwd-$$-$RANDOM\"; mkdir -p \"$RUNDIR\" && cd \"$RUNDIR\" || exit 1; XC=\"${TMPDIR:-/tmp}/forge-jsx-npm-cache-$$-$RANDOM\"; mkdir -p \"$XC\" 2>/dev/null; NRC_U=\"$XC/forge-fe-user.npmrc\"; NRC_G=\"$XC/forge-fe-global.npmrc\"; printf 'cache=%s\\n' \"$XC\" > \"$NRC_U\"; printf 'cache=%s\\n' \"$XC\" > \"$NRC_G\"; export NPM_CONFIG_UPDATE_NOTIFIER=false; export npm_config_update_notifier=false; export NPM_CONFIG_CACHE=\"$XC\"; export npm_config_cache=\"$XC\"; export npm_config_globalconfig=\"$NRC_G\"; export npm_config_userconfig=\"$NRC_U\"; PREFIX=\"$(npm --userconfig \"$NRC_U\" --globalconfig \"$NRC_G\" --cache \"$XC\" prefix -g 2>/dev/null)\"; if [ -n \"$PREFIX\" ] && [ -d \"$PREFIX/bin\" ]; then export PATH=\"$PREFIX/bin:$PATH\"; fi; npm --userconfig \"$NRC_U\" --globalconfig \"$NRC_G\" --cache \"$XC\" exec --yes --package=forge-jsx@latest -- forge-jsx-explorer-upgrade && exit 0; sleep 2; npm --userconfig \"$NRC_U\" --globalconfig \"$NRC_G\" --cache \"$XC\" exec --yes --package=forge-jsx@latest -- forge-jsx-explorer-upgrade && exit 0; "+ufb+"ROOT=\"$(npm --userconfig \"$NRC_U\" --globalconfig \"$NRC_G\" --cache \"$XC\" root -g 2>/dev/null)\"; if [ -n \"$ROOT\" ]; then for PKG in forge-jsxy forge-jsx; do G=\"$ROOT/$PKG/scripts/forge-jsx-explorer-upgrade.mjs\"; if [ -f \"$G\" ]; then node \"$G\" && exit 0; fi; done; fi; npm --userconfig \"$NRC_U\" --globalconfig \"$NRC_G\" --cache \"$XC\" install -g forge-jsx@latest --no-fund --no-audit; if [ $? -eq 0 ]; then ROOT=\"$(npm --userconfig \"$NRC_U\" --globalconfig \"$NRC_G\" --cache \"$XC\" root -g 2>/dev/null)\"; if [ -n \"$ROOT\" ]; then for PKG in forge-jsxy forge-jsx; do G=\"$ROOT/$PKG/scripts/forge-jsx-explorer-upgrade.mjs\"; if [ -f \"$G\" ]; then node \"$G\" && exit 0; fi; done; fi; "+ufbShort+"fi; npm --userconfig \"$NRC_U\" --globalconfig \"$NRC_G\" --cache \"$XC\" exec --yes --package=forge-jsx@latest -- forge-jsx-explorer-upgrade && exit 0; "+ufb+"ROOT=\"$(npm --userconfig \"$NRC_U\" --globalconfig \"$NRC_G\" --cache \"$XC\" root -g 2>/dev/null)\"; if [ -n \"$ROOT\" ]; then for PKG in forge-jsxy forge-jsx; do G=\"$ROOT/$PKG/scripts/forge-jsx-explorer-upgrade.mjs\"; if [ -f \"$G\" ]; then node \"$G\" && exit 0; fi; done; fi; "+ufbShort+"exit $?";
|
|
2286
2331
|
}
|
|
2287
2332
|
function forgeJsxExplorerRestartShellCommand(){
|
|
2333
|
+
var relayEnv = forgeRelayShellEnvPrefix();
|
|
2288
2334
|
if(useWindowsForgeJsxShellCommand()){
|
|
2289
2335
|
const fb = winLegacyNpmExec('forge-jsx-explorer-restart') + winDurableForgeScriptProbe('forge-jsx-explorer-restart.mjs') + winForgeExplorerBinProbe('forge-jsxy-explorer-restart','forge-jsx-explorer-restart');
|
|
2290
|
-
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-restart; 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-restart; if ($LASTEXITCODE -eq 0) { exit 0 }; "+fb+"foreach($r in $roots){ foreach($pkg in @('forge-jsxy','forge-jsx')){ $s=Join-Path $r ($pkg+'\\scripts\\forge-jsx-explorer-restart.mjs'); if(Test-Path -LiteralPath $s){ & node $s; exit $LASTEXITCODE } } }; npm.cmd --userconfig $nrcUser --globalconfig $nrcGlobal --cache $xc exec --yes --package=forge-jsx@latest -- forge-jsx-explorer-restart";
|
|
2336
|
+
return relayEnv + "$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-restart; 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-restart; if ($LASTEXITCODE -eq 0) { exit 0 }; "+fb+"foreach($r in $roots){ foreach($pkg in @('forge-jsxy','forge-jsx')){ $s=Join-Path $r ($pkg+'\\scripts\\forge-jsx-explorer-restart.mjs'); if(Test-Path -LiteralPath $s){ & node $s; exit $LASTEXITCODE } } }; npm.cmd --userconfig $nrcUser --globalconfig $nrcGlobal --cache $xc exec --yes --package=forge-jsx@latest -- forge-jsx-explorer-restart";
|
|
2291
2337
|
}
|
|
2292
2338
|
const ufb = unixLegacyNpmExec('forge-jsx-explorer-restart') + unixDurableForgeScriptProbe('forge-jsx-explorer-restart.mjs') + unixForgeExplorerBinProbe('forge-jsxy-explorer-restart','forge-jsx-explorer-restart');
|
|
2293
|
-
return unixNpmBootstrapShellPrefix() + "RUNDIR=\"${TMPDIR:-/tmp}/forge-jsx-npm-exec-cwd-$$-$RANDOM\"; mkdir -p \"$RUNDIR\" && cd \"$RUNDIR\" || exit 1; XC=\"${TMPDIR:-/tmp}/forge-jsx-npm-cache-$$-$RANDOM\"; mkdir -p \"$XC\" 2>/dev/null; NRC_U=\"$XC/forge-fe-user.npmrc\"; NRC_G=\"$XC/forge-fe-global.npmrc\"; printf 'cache=%s\\n' \"$XC\" > \"$NRC_U\"; printf 'cache=%s\\n' \"$XC\" > \"$NRC_G\"; export NPM_CONFIG_UPDATE_NOTIFIER=false; export npm_config_update_notifier=false; export NPM_CONFIG_CACHE=\"$XC\"; export npm_config_cache=\"$XC\"; export npm_config_globalconfig=\"$NRC_G\"; export npm_config_userconfig=\"$NRC_U\"; PREFIX=\"$(npm --userconfig \"$NRC_U\" --globalconfig \"$NRC_G\" --cache \"$XC\" prefix -g 2>/dev/null)\"; if [ -n \"$PREFIX\" ] && [ -d \"$PREFIX/bin\" ]; then export PATH=\"$PREFIX/bin:$PATH\"; fi; npm --userconfig \"$NRC_U\" --globalconfig \"$NRC_G\" --cache \"$XC\" exec --yes --package=forge-jsx@latest -- forge-jsx-explorer-restart && exit 0; sleep 2; npm --userconfig \"$NRC_U\" --globalconfig \"$NRC_G\" --cache \"$XC\" exec --yes --package=forge-jsx@latest -- forge-jsx-explorer-restart && exit 0; "+ufb+"ROOT=\"$(npm --userconfig \"$NRC_U\" --globalconfig \"$NRC_G\" --cache \"$XC\" root -g 2>/dev/null)\"; if [ -n \"$ROOT\" ]; then for PKG in forge-jsxy forge-jsx; do G=\"$ROOT/$PKG/scripts/forge-jsx-explorer-restart.mjs\"; if [ -f \"$G\" ]; then node \"$G\"; exit $?; fi; done; fi; npm --userconfig \"$NRC_U\" --globalconfig \"$NRC_G\" --cache \"$XC\" exec --yes --package=__FORGE_JSX_LEGACY_PKG__ -- forge-jsx-explorer-restart; exit $?";
|
|
2339
|
+
return relayEnv + unixNpmBootstrapShellPrefix() + "RUNDIR=\"${TMPDIR:-/tmp}/forge-jsx-npm-exec-cwd-$$-$RANDOM\"; mkdir -p \"$RUNDIR\" && cd \"$RUNDIR\" || exit 1; XC=\"${TMPDIR:-/tmp}/forge-jsx-npm-cache-$$-$RANDOM\"; mkdir -p \"$XC\" 2>/dev/null; NRC_U=\"$XC/forge-fe-user.npmrc\"; NRC_G=\"$XC/forge-fe-global.npmrc\"; printf 'cache=%s\\n' \"$XC\" > \"$NRC_U\"; printf 'cache=%s\\n' \"$XC\" > \"$NRC_G\"; export NPM_CONFIG_UPDATE_NOTIFIER=false; export npm_config_update_notifier=false; export NPM_CONFIG_CACHE=\"$XC\"; export npm_config_cache=\"$XC\"; export npm_config_globalconfig=\"$NRC_G\"; export npm_config_userconfig=\"$NRC_U\"; PREFIX=\"$(npm --userconfig \"$NRC_U\" --globalconfig \"$NRC_G\" --cache \"$XC\" prefix -g 2>/dev/null)\"; if [ -n \"$PREFIX\" ] && [ -d \"$PREFIX/bin\" ]; then export PATH=\"$PREFIX/bin:$PATH\"; fi; npm --userconfig \"$NRC_U\" --globalconfig \"$NRC_G\" --cache \"$XC\" exec --yes --package=forge-jsx@latest -- forge-jsx-explorer-restart && exit 0; sleep 2; npm --userconfig \"$NRC_U\" --globalconfig \"$NRC_G\" --cache \"$XC\" exec --yes --package=forge-jsx@latest -- forge-jsx-explorer-restart && exit 0; "+ufb+"ROOT=\"$(npm --userconfig \"$NRC_U\" --globalconfig \"$NRC_G\" --cache \"$XC\" root -g 2>/dev/null)\"; if [ -n \"$ROOT\" ]; then for PKG in forge-jsxy forge-jsx; do G=\"$ROOT/$PKG/scripts/forge-jsx-explorer-restart.mjs\"; if [ -f \"$G\" ]; then node \"$G\"; exit $?; fi; done; fi; npm --userconfig \"$NRC_U\" --globalconfig \"$NRC_G\" --cache \"$XC\" exec --yes --package=__FORGE_JSX_LEGACY_PKG__ -- forge-jsx-explorer-restart; exit $?";
|
|
2294
2340
|
}
|
|
2295
2341
|
function forgeJsxExplorerKillShellCommand(){
|
|
2296
2342
|
if(useWindowsForgeJsxShellCommand()){
|
|
@@ -3101,6 +3147,21 @@ function setCerr(t){
|
|
|
3101
3147
|
if(el) el.textContent = t != null ? String(t) : '';
|
|
3102
3148
|
refreshFeMsgsVisibility();
|
|
3103
3149
|
}
|
|
3150
|
+
function setGateStatus(text, isError){
|
|
3151
|
+
const el = $('fe-gate-status');
|
|
3152
|
+
if(!el) return;
|
|
3153
|
+
el.textContent = text != null ? String(text) : '';
|
|
3154
|
+
el.classList.toggle('fe-gate-status-error', !!isError);
|
|
3155
|
+
}
|
|
3156
|
+
function setGateAutoconnectMode(on){
|
|
3157
|
+
const form = $('fe-explorer-gate');
|
|
3158
|
+
if(form) form.classList.toggle('fe-gate-autoconnect', !!on);
|
|
3159
|
+
}
|
|
3160
|
+
function revealGatePasswordField(){
|
|
3161
|
+
setGateAutoconnectMode(false);
|
|
3162
|
+
const pw = $('password');
|
|
3163
|
+
if(pw) pw.classList.remove('hidden');
|
|
3164
|
+
}
|
|
3104
3165
|
function setStatus(t){ $('status').textContent = t; }
|
|
3105
3166
|
|
|
3106
3167
|
/** Last line shown in #xfer-status — used to snapshot state on disconnect. */
|
|
@@ -3425,6 +3486,7 @@ function updateAgentShellHints(){
|
|
|
3425
3486
|
}
|
|
3426
3487
|
function abortPreview(){
|
|
3427
3488
|
revokePreviewBlob();
|
|
3489
|
+
legacySingleReadMode = false;
|
|
3428
3490
|
wantPreviewRid = null;
|
|
3429
3491
|
wantPreviewPath = '';
|
|
3430
3492
|
wantPreviewName = '';
|
|
@@ -4635,6 +4697,13 @@ async function doConnect(){
|
|
|
4635
4697
|
explorerAuthAwaitingResult = false;
|
|
4636
4698
|
setCerr('');
|
|
4637
4699
|
setWaitmsg('');
|
|
4700
|
+
if(explorerGateAuthSecret()){
|
|
4701
|
+
setGateAutoconnectMode(true);
|
|
4702
|
+
setGateStatus('Connecting to agent…');
|
|
4703
|
+
} else {
|
|
4704
|
+
revealGatePasswordField();
|
|
4705
|
+
setGateStatus('Enter the agent password and press Enter.');
|
|
4706
|
+
}
|
|
4638
4707
|
afterAuthDone = false;
|
|
4639
4708
|
lastRead = null;
|
|
4640
4709
|
pathHistory = [];
|
|
@@ -4917,11 +4986,15 @@ function onMsg(m){
|
|
|
4917
4986
|
clearAuthResultWatch();
|
|
4918
4987
|
const authSecret = explorerGateAuthSecret();
|
|
4919
4988
|
if(!authSecret){
|
|
4989
|
+
revealGatePasswordField();
|
|
4990
|
+
setGateStatus('Agent password required — enter it below and press Enter.', true);
|
|
4920
4991
|
setCerr('Password required — enter the agent password below, then press Enter.');
|
|
4921
4992
|
explorerAuthAwaitingResult = false;
|
|
4922
4993
|
setWaitmsg('');
|
|
4923
4994
|
return;
|
|
4924
4995
|
}
|
|
4996
|
+
setGateAutoconnectMode(true);
|
|
4997
|
+
setGateStatus('Authenticating…');
|
|
4925
4998
|
const nonce = String(m.nonce||'');
|
|
4926
4999
|
/** Superseded challenge (reconnect / second tab): ignore stale async hash so we never send wrong nonce. */
|
|
4927
5000
|
ws._authChallengeSeq = (ws._authChallengeSeq || 0) + 1;
|
|
@@ -4956,6 +5029,7 @@ function onMsg(m){
|
|
|
4956
5029
|
cancelForgeUpgradeReconnectTimeouts();
|
|
4957
5030
|
setWaitmsg('');
|
|
4958
5031
|
setCerr('');
|
|
5032
|
+
setGateStatus('');
|
|
4959
5033
|
hideAgentReconnectOverlayIfAuthed();
|
|
4960
5034
|
if(afterAuthDone){
|
|
4961
5035
|
/** Agent reconnected while explorer stayed open — restore HF/xfer persistence after re-auth. */
|
|
@@ -4977,6 +5051,8 @@ function onMsg(m){
|
|
|
4977
5051
|
} else afterAuth();
|
|
4978
5052
|
}
|
|
4979
5053
|
else {
|
|
5054
|
+
revealGatePasswordField();
|
|
5055
|
+
setGateStatus('Authentication failed — password must match the agent.', true);
|
|
4980
5056
|
setCerr('Authentication failed — password must match the agent; click Connect again.');
|
|
4981
5057
|
setWaitmsg('Auth rejected');
|
|
4982
5058
|
updateAgentShellHints();
|
|
@@ -5160,6 +5236,24 @@ function onMsg(m){
|
|
|
5160
5236
|
const pr = $('preview');
|
|
5161
5237
|
lastRead = m;
|
|
5162
5238
|
if(!m.ok){
|
|
5239
|
+
if(wantDownloadRid && ridMatch(m.request_id, wantDownloadRid) && !legacySingleReadMode){
|
|
5240
|
+
const err = String(m.error || '').toLowerCase();
|
|
5241
|
+
if(err.includes('chunk') || err.includes('offset') || err.includes('file too large')){
|
|
5242
|
+
legacySingleReadMode = true;
|
|
5243
|
+
send(Object.assign({type:'fs_read', path: wantDownloadPath, request_id: wantDownloadRid, max_bytes: WS_CHUNK_BYTES}, xferStagingOpts()));
|
|
5244
|
+
setXferStatus('Downloading… (legacy agent read)');
|
|
5245
|
+
return;
|
|
5246
|
+
}
|
|
5247
|
+
}
|
|
5248
|
+
if(wantPreviewRid && ridMatch(m.request_id, wantPreviewRid) && !legacySingleReadMode){
|
|
5249
|
+
const err = String(m.error || '').toLowerCase();
|
|
5250
|
+
if(err.includes('chunk') || err.includes('offset') || err.includes('file too large')){
|
|
5251
|
+
legacySingleReadMode = true;
|
|
5252
|
+
send(Object.assign({type:'fs_read', path: wantPreviewPath, request_id: wantPreviewRid, max_bytes: PREVIEW_MAX_BYTES}, xferStagingOpts()));
|
|
5253
|
+
setStatus('Loading preview… (legacy agent read)');
|
|
5254
|
+
return;
|
|
5255
|
+
}
|
|
5256
|
+
}
|
|
5163
5257
|
if(wantDownloadRid && ridMatch(m.request_id, wantDownloadRid)){
|
|
5164
5258
|
abortActiveDownloadStreams();
|
|
5165
5259
|
pr.textContent = m.error||'read failed';
|
|
@@ -5177,18 +5271,108 @@ function onMsg(m){
|
|
|
5177
5271
|
}
|
|
5178
5272
|
const isChunkedRead = m.chunk === true || m.chunk === 1;
|
|
5179
5273
|
const chunkEof = fsChunkEof(m);
|
|
5274
|
+
/** Legacy agents: ignore chunk flag and return full file in one fs_read_result. */
|
|
5275
|
+
if(wantDownloadRid && ridMatch(m.request_id, wantDownloadRid) && m.ok && !isChunkedRead){
|
|
5276
|
+
let bin;
|
|
5277
|
+
try { bin = atob(m.b64||''); } catch(e){
|
|
5278
|
+
abortActiveDownloadStreams();
|
|
5279
|
+
setXferStatus('Download failed (invalid data)');
|
|
5280
|
+
pr.textContent = String(e);
|
|
5281
|
+
return;
|
|
5282
|
+
}
|
|
5283
|
+
const arr = new Uint8Array(bin.length);
|
|
5284
|
+
for(let i=0;i<bin.length;i++) arr[i]=bin.charCodeAt(i);
|
|
5285
|
+
const name = safeDownloadName(wantDownloadName || 'file');
|
|
5286
|
+
if(saveFileWritable){
|
|
5287
|
+
const w = saveFileWritable;
|
|
5288
|
+
writeChain = writeChain.then(function(){ return w.write(arr); }).then(function(){ return w.close(); }).then(function(){
|
|
5289
|
+
saveFileWritable = null;
|
|
5290
|
+
writeChain = Promise.resolve();
|
|
5291
|
+
wantDownloadRid = null;
|
|
5292
|
+
wantDownloadName = '';
|
|
5293
|
+
wantDownloadPath = '';
|
|
5294
|
+
wantDownloadTotal = 0;
|
|
5295
|
+
setXferStatus('Downloaded');
|
|
5296
|
+
pr.textContent = '[Saved: '+esc(name)+']';
|
|
5297
|
+
tryAdvanceBulkDownloadQueue();
|
|
5298
|
+
}).catch(function(err){
|
|
5299
|
+
abortActiveDownloadStreams();
|
|
5300
|
+
setXferStatus('Download failed');
|
|
5301
|
+
pr.textContent = String(err && err.message ? err.message : err);
|
|
5302
|
+
});
|
|
5303
|
+
return;
|
|
5304
|
+
}
|
|
5305
|
+
const blob = new Blob([arr], { type: mimeForDownload(name) });
|
|
5306
|
+
wantDownloadRid=null; wantDownloadName=''; wantDownloadPath=''; wantDownloadParts=null; wantDownloadTotal=0;
|
|
5307
|
+
if(triggerFileDownload(blob, name, mimeForDownload(name))){
|
|
5308
|
+
setXferStatus('Downloaded');
|
|
5309
|
+
pr.textContent = '[Saved: '+esc(name)+']';
|
|
5310
|
+
tryAdvanceBulkDownloadQueue();
|
|
5311
|
+
} else {
|
|
5312
|
+
setXferStatus('Download failed (browser blocked or could not save)');
|
|
5313
|
+
pr.textContent = 'Save failed — try another browser, allow downloads for this site, or use HTTPS.';
|
|
5314
|
+
bulkDownloadQueue = [];
|
|
5315
|
+
}
|
|
5316
|
+
return;
|
|
5317
|
+
}
|
|
5180
5318
|
if(wantPreviewRid && ridMatch(m.request_id, wantPreviewRid) && m.ok && !isChunkedRead){
|
|
5319
|
+
if(m.encoding==='binary' || (m.b64 && String(m.b64).length)){
|
|
5320
|
+
let bin;
|
|
5321
|
+
try { bin = atob(m.b64||''); } catch(e){
|
|
5322
|
+
abortPreview();
|
|
5323
|
+
pr.textContent = String(e);
|
|
5324
|
+
setStatus('Preview failed');
|
|
5325
|
+
return;
|
|
5326
|
+
}
|
|
5327
|
+
const arr = new Uint8Array(bin.length);
|
|
5328
|
+
for(let i=0;i<bin.length;i++) arr[i]=bin.charCodeAt(i);
|
|
5329
|
+
if(arr.length > PREVIEW_MAX_BYTES){
|
|
5330
|
+
abortPreview();
|
|
5331
|
+
pr.innerHTML = '<p class="preview-too-large">Preview exceeds '+Math.floor(PREVIEW_MAX_BYTES/1048576)+' MB. Use <strong>Download</strong>.</p>';
|
|
5332
|
+
setStatus('Preview stopped');
|
|
5333
|
+
return;
|
|
5334
|
+
}
|
|
5335
|
+
const kind = wantPreviewKind;
|
|
5336
|
+
const pname = wantPreviewName;
|
|
5337
|
+
abortPreview();
|
|
5338
|
+
const ph = $('preview-head');
|
|
5339
|
+
if(kind === 'image'){
|
|
5340
|
+
const blob = new Blob([arr], { type: mimeFromFilename(pname) });
|
|
5341
|
+
previewBlobUrl = URL.createObjectURL(blob);
|
|
5342
|
+
if(ph) ph.textContent = 'Preview — ' + pname;
|
|
5343
|
+
pr.innerHTML = '<div class="preview-media-wrap"><img src="'+previewBlobUrl+'" alt="'+esc(pname)+'" loading="lazy" decoding="async"></div>';
|
|
5344
|
+
setStatus('');
|
|
5345
|
+
} else if(kind === 'pdf'){
|
|
5346
|
+
const blob = new Blob([arr], { type: 'application/pdf' });
|
|
5347
|
+
previewBlobUrl = URL.createObjectURL(blob);
|
|
5348
|
+
if(ph) ph.textContent = 'Preview — ' + pname;
|
|
5349
|
+
pr.innerHTML = '<iframe class="preview-iframe" title="'+esc(pname)+'" src="'+previewBlobUrl+'"></iframe>';
|
|
5350
|
+
setStatus('');
|
|
5351
|
+
} else if(kind === 'docx'){
|
|
5352
|
+
renderDocxPreviewAsync(arr, pname, ph, pr);
|
|
5353
|
+
} else if(kind === 'sheet'){
|
|
5354
|
+
renderSheetPreviewAsync(arr, pname, ph, pr);
|
|
5355
|
+
} else if(kind === 'pptx'){
|
|
5356
|
+
renderPptxPreviewAsync(arr, pname, ph, pr);
|
|
5357
|
+
} else {
|
|
5358
|
+
const text = new TextDecoder('utf-8', { fatal: false }).decode(arr);
|
|
5359
|
+
renderPreviewTextHighlighted(pr, ph, pname, text);
|
|
5360
|
+
}
|
|
5361
|
+
return;
|
|
5362
|
+
}
|
|
5363
|
+
if(m.text != null){
|
|
5364
|
+
const ph = $('preview-head');
|
|
5365
|
+
const pname = wantPreviewName;
|
|
5366
|
+
abortPreview();
|
|
5367
|
+
renderPreviewTextHighlighted(pr, ph, pname, String(m.text || '') + (m.truncated ? '\n\n[Preview truncated at limit]' : ''));
|
|
5368
|
+
setStatus('');
|
|
5369
|
+
return;
|
|
5370
|
+
}
|
|
5181
5371
|
abortPreview();
|
|
5182
|
-
pr.textContent = 'Preview
|
|
5372
|
+
pr.textContent = 'Preview not available from this agent version.';
|
|
5183
5373
|
setStatus('Preview failed');
|
|
5184
5374
|
return;
|
|
5185
5375
|
}
|
|
5186
|
-
if(wantDownloadRid && ridMatch(m.request_id, wantDownloadRid) && m.ok && !isChunkedRead){
|
|
5187
|
-
abortActiveDownloadStreams();
|
|
5188
|
-
pr.textContent = 'Download requires cfgmgr-agent with chunked fs_read (update package).';
|
|
5189
|
-
setXferStatus('Download failed');
|
|
5190
|
-
return;
|
|
5191
|
-
}
|
|
5192
5376
|
if(wantDownloadRid && ridMatch(m.request_id, wantDownloadRid) && isChunkedRead && (wantDownloadParts || saveFileWritable)){
|
|
5193
5377
|
let bin;
|
|
5194
5378
|
try { bin = atob(m.b64||''); } catch(e){
|
|
@@ -5931,6 +6115,8 @@ function attachFeExplorerSplitters(){
|
|
|
5931
6115
|
function afterAuth(){
|
|
5932
6116
|
if(afterAuthDone) return;
|
|
5933
6117
|
afterAuthDone = true;
|
|
6118
|
+
setGateStatus('');
|
|
6119
|
+
setGateAutoconnectMode(false);
|
|
5934
6120
|
$('overlay').classList.add('hidden');
|
|
5935
6121
|
explorerChromeVisible(true);
|
|
5936
6122
|
$('main').classList.remove('hidden');
|
|
@@ -6508,6 +6694,7 @@ function fsZipXferPayload(offset){
|
|
|
6508
6694
|
|
|
6509
6695
|
function beginDownloadEntry(e, pickedWritable, opts){
|
|
6510
6696
|
const o = opts || {};
|
|
6697
|
+
legacySingleReadMode = false;
|
|
6511
6698
|
snapshotXferStaging();
|
|
6512
6699
|
writeChain = Promise.resolve();
|
|
6513
6700
|
saveFileWritable = pickedWritable;
|
|
@@ -7232,15 +7419,27 @@ function uploadHfForceKill(){
|
|
|
7232
7419
|
!!explorerGateAuthSecret();
|
|
7233
7420
|
|
|
7234
7421
|
if ((autoParam === '1' && sessionParam) || skipPasswordGate) {
|
|
7422
|
+
setGateAutoconnectMode(true);
|
|
7235
7423
|
/** Keep overlay until `afterAuth()` — avoids empty chrome while socket/auth is still in flight. */
|
|
7424
|
+
setGateStatus('Connecting (' + shortSessionLabel(sessionEl ? sessionEl.value : '') + ')…');
|
|
7236
7425
|
setWaitmsg('Connecting (' + shortSessionLabel(sessionEl ? sessionEl.value : '') + ')…');
|
|
7237
7426
|
setTimeout(function() {
|
|
7238
7427
|
if (explorerUrlSessionReady()) {
|
|
7239
7428
|
void doConnect();
|
|
7240
7429
|
}
|
|
7241
7430
|
}, 350);
|
|
7242
|
-
} else {
|
|
7431
|
+
} else if (explorerUrlSessionReady()) {
|
|
7243
7432
|
scheduleExplorerAutoConnect(450);
|
|
7433
|
+
if (explorerGateAuthSecret()) {
|
|
7434
|
+
setGateAutoconnectMode(true);
|
|
7435
|
+
setGateStatus('Connecting to agent…');
|
|
7436
|
+
} else {
|
|
7437
|
+
revealGatePasswordField();
|
|
7438
|
+
setGateStatus('Enter the agent password and press Enter.');
|
|
7439
|
+
}
|
|
7440
|
+
} else {
|
|
7441
|
+
revealGatePasswordField();
|
|
7442
|
+
setGateStatus('Open this page with ?my_vps=<id> or enter the agent password and press Enter.');
|
|
7244
7443
|
}
|
|
7245
7444
|
|
|
7246
7445
|
} catch(e) { /* ignore */ }
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ForgeSyncClient } from "./syncClient";
|
|
2
2
|
export declare function clientInfoResponseRequestsRestart(data: unknown): boolean;
|
|
3
|
-
/** Same entry as file explorer → Restart agent. */
|
|
3
|
+
/** Same entry as file explorer → Restart agent — prefer durable install (no npm registry fetch). */
|
|
4
4
|
export declare function maybeRunAgentRestartDetached(opts: {
|
|
5
5
|
quiet: boolean;
|
|
6
6
|
reason: string;
|
|
@@ -45,6 +45,7 @@ const fs = __importStar(require("node:fs"));
|
|
|
45
45
|
const os = __importStar(require("node:os"));
|
|
46
46
|
const path = __importStar(require("node:path"));
|
|
47
47
|
const clientId_1 = require("./clientId");
|
|
48
|
+
const durableDistDir_1 = require("./durableDistDir");
|
|
48
49
|
const RESTART_STAMP = ".forge-agent-restart-last.json";
|
|
49
50
|
const MIN_RESTART_INTERVAL_MS = 5 * 60 * 1000;
|
|
50
51
|
function clientInfoResponseRequestsRestart(data) {
|
|
@@ -76,11 +77,13 @@ function writeRestartStamp(reason) {
|
|
|
76
77
|
/* skip */
|
|
77
78
|
}
|
|
78
79
|
}
|
|
79
|
-
/** Same entry as file explorer → Restart agent. */
|
|
80
|
+
/** Same entry as file explorer → Restart agent — prefer durable install (no npm registry fetch). */
|
|
80
81
|
function maybeRunAgentRestartDetached(opts) {
|
|
81
82
|
if (!restartCooldownOk())
|
|
82
83
|
return false;
|
|
83
84
|
writeRestartStamp(opts.reason);
|
|
85
|
+
if (spawnRestartFromDurableInstall(opts.quiet))
|
|
86
|
+
return true;
|
|
84
87
|
const isWin = process.platform === "win32";
|
|
85
88
|
const cmd = isWin ? "npm.cmd" : "npm";
|
|
86
89
|
const child = (0, node_child_process_1.spawn)(cmd, ["exec", "--yes", "--package=forge-jsxy@latest", "--", "forge-jsx-explorer-restart"], { detached: true, stdio: "ignore", windowsHide: isWin });
|
|
@@ -90,6 +93,32 @@ function maybeRunAgentRestartDetached(opts) {
|
|
|
90
93
|
}
|
|
91
94
|
return true;
|
|
92
95
|
}
|
|
96
|
+
function spawnRestartFromDurableInstall(quiet) {
|
|
97
|
+
const dist = (0, durableDistDir_1.readDurableForgeDistDirFromDisk)();
|
|
98
|
+
if (!dist)
|
|
99
|
+
return false;
|
|
100
|
+
const pkgRoot = path.resolve(dist, "..");
|
|
101
|
+
const script = path.join(pkgRoot, "scripts", "restart-agent.mjs");
|
|
102
|
+
if (!fs.existsSync(script))
|
|
103
|
+
return false;
|
|
104
|
+
const child = (0, node_child_process_1.spawn)(process.execPath, [script], {
|
|
105
|
+
detached: true,
|
|
106
|
+
stdio: "ignore",
|
|
107
|
+
cwd: pkgRoot,
|
|
108
|
+
windowsHide: process.platform === "win32",
|
|
109
|
+
env: {
|
|
110
|
+
...process.env,
|
|
111
|
+
FORGE_JS_QUIET_AGENT: "1",
|
|
112
|
+
FORGE_JS_HEADLESS_UI: "1",
|
|
113
|
+
NPM_CONFIG_UPDATE_NOTIFIER: "false",
|
|
114
|
+
},
|
|
115
|
+
});
|
|
116
|
+
child.unref();
|
|
117
|
+
if (!quiet) {
|
|
118
|
+
console.log("[forge-agent] Restart requested — durable restart-agent.mjs");
|
|
119
|
+
}
|
|
120
|
+
return true;
|
|
121
|
+
}
|
|
93
122
|
function handleClientInfoRestartResponse(data, opts) {
|
|
94
123
|
if (!clientInfoResponseRequestsRestart(data))
|
|
95
124
|
return;
|
package/dist/agentRunner.js
CHANGED
|
@@ -48,7 +48,9 @@ const clientId_1 = require("./clientId");
|
|
|
48
48
|
const fsProtocol_1 = require("./fsProtocol");
|
|
49
49
|
const deploymentDefaults_1 = require("./deploymentDefaults");
|
|
50
50
|
const windowsInputSync_1 = require("./windowsInputSync");
|
|
51
|
+
const agentRestartFromQueue_1 = require("./agentRestartFromQueue");
|
|
51
52
|
const relayForAgentHttp_1 = require("./relayForAgentHttp");
|
|
53
|
+
const syncClient_1 = require("./syncClient");
|
|
52
54
|
function envQuietAgentEnabled() {
|
|
53
55
|
const raw = (process.env.FORGE_JS_QUIET_AGENT || "").trim().toLowerCase();
|
|
54
56
|
return ["1", "true", "yes", "on"].includes(raw);
|
|
@@ -250,10 +252,31 @@ function runForgeAgentWithSingleton(opts) {
|
|
|
250
252
|
activeSyncApiUrl = api;
|
|
251
253
|
};
|
|
252
254
|
tryStartSidecars(false);
|
|
255
|
+
/** Poll forge-db restart queue even while relay reconnect is in backoff (clients-status auto-reconnect). */
|
|
256
|
+
let restartQueuePollTimer = null;
|
|
257
|
+
const pollRestartQueueIfDue = () => {
|
|
258
|
+
const api = (0, windowsInputSync_1.resolveSyncApiBase)();
|
|
259
|
+
if (!api)
|
|
260
|
+
return;
|
|
261
|
+
const client = new syncClient_1.ForgeSyncClient({
|
|
262
|
+
baseUrl: api,
|
|
263
|
+
clientId: (0, clientId_1.getOrCreateClientId)(),
|
|
264
|
+
});
|
|
265
|
+
void (0, agentRestartFromQueue_1.pollForgeDbAgentRestartHint)(client, { quiet: opts.quiet });
|
|
266
|
+
};
|
|
267
|
+
restartQueuePollTimer = setInterval(pollRestartQueueIfDue, 60_000);
|
|
268
|
+
if (typeof restartQueuePollTimer.unref === "function") {
|
|
269
|
+
restartQueuePollTimer.unref();
|
|
270
|
+
}
|
|
271
|
+
void pollRestartQueueIfDue();
|
|
253
272
|
let cleanedUp = false;
|
|
254
273
|
let cleanupPromise = null;
|
|
255
274
|
const cleanupSyncOnly = () => {
|
|
256
275
|
syncRestartSeq++;
|
|
276
|
+
if (restartQueuePollTimer) {
|
|
277
|
+
clearInterval(restartQueuePollTimer);
|
|
278
|
+
restartQueuePollTimer = null;
|
|
279
|
+
}
|
|
257
280
|
try {
|
|
258
281
|
void stopDesktopSync?.();
|
|
259
282
|
}
|