mindexec-ai 0.2.385

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 (99) hide show
  1. package/README.md +354 -0
  2. package/codex-runtime.js +1339 -0
  3. package/launch-bridge.cjs +236 -0
  4. package/package.json +77 -0
  5. package/port-guard.cjs +232 -0
  6. package/remote-fast/osx-arm64/mindexec-remote-fast +0 -0
  7. package/remote-fast/osx-arm64/mindexec-remote-fast.deps.json +24 -0
  8. package/remote-fast/osx-arm64/mindexec-remote-fast.dll +0 -0
  9. package/remote-fast/osx-arm64/mindexec-remote-fast.runtimeconfig.json +13 -0
  10. package/remote-fast/osx-x64/mindexec-remote-fast +0 -0
  11. package/remote-fast/osx-x64/mindexec-remote-fast.deps.json +24 -0
  12. package/remote-fast/osx-x64/mindexec-remote-fast.dll +0 -0
  13. package/remote-fast/osx-x64/mindexec-remote-fast.runtimeconfig.json +13 -0
  14. package/remote-fast/win-x64/mindexec-remote-fast.deps.json +24 -0
  15. package/remote-fast/win-x64/mindexec-remote-fast.dll +0 -0
  16. package/remote-fast/win-x64/mindexec-remote-fast.exe +0 -0
  17. package/remote-fast/win-x64/mindexec-remote-fast.runtimeconfig.json +20 -0
  18. package/remote-hub.js +3106 -0
  19. package/scripts/auth-session-smoke.mjs +262 -0
  20. package/scripts/remote-agent-managed-smoke.mjs +291 -0
  21. package/scripts/remote-agent-package-smoke.mjs +64 -0
  22. package/scripts/remote-agent-ws-smoke.mjs +202 -0
  23. package/scripts/remote-fast-live-rate-smoke.mjs +355 -0
  24. package/scripts/remote-fast-mdm-browser-smoke.mjs +476 -0
  25. package/scripts/remote-fleet-render-smoke.mjs +1491 -0
  26. package/scripts/remote-frame-ws-smoke.mjs +234 -0
  27. package/scripts/remote-http-smoke.mjs +592 -0
  28. package/scripts/remote-hub-identity-smoke.mjs +146 -0
  29. package/scripts/remote-hub-scale-smoke.mjs +124 -0
  30. package/scripts/remote-hub-smoke.mjs +631 -0
  31. package/scripts/remote-input-ws-smoke.mjs +263 -0
  32. package/scripts/remote-registry-follower-smoke.mjs +752 -0
  33. package/scripts/setup-tree-sitter-grammars.mjs +80 -0
  34. package/server.js +15709 -0
  35. package/start-bridge.bat +32 -0
  36. package/start-bridge.sh +81 -0
  37. package/tree-sitter-grammars/README.md +18 -0
  38. package/tree-sitter-grammars/tree-sitter-c_sharp.wasm +0 -0
  39. package/tree-sitter-grammars/tree-sitter-go.wasm +0 -0
  40. package/tree-sitter-grammars/tree-sitter-java.wasm +0 -0
  41. package/tree-sitter-grammars/tree-sitter-javascript.wasm +0 -0
  42. package/tree-sitter-grammars/tree-sitter-python.wasm +0 -0
  43. package/tree-sitter-grammars/tree-sitter-rust.wasm +0 -0
  44. package/tree-sitter-grammars/tree-sitter-tsx.wasm +0 -0
  45. package/tree-sitter-grammars/tree-sitter-typescript.wasm +0 -0
  46. package/wwwroot/_headers +73 -0
  47. package/wwwroot/_redirects +1 -0
  48. package/wwwroot/appsettings.json +83 -0
  49. package/wwwroot/assets/AdminDashboardPage-B2vz2Px9.css +1 -0
  50. package/wwwroot/assets/AdminDashboardPage-DnuCHywn.js +1 -0
  51. package/wwwroot/assets/AppSidebar-DU2OgSiv.js +2 -0
  52. package/wwwroot/assets/AuthPages-BrH6kRcv.css +1 -0
  53. package/wwwroot/assets/AuthPages-Dgezl7Vj.js +1 -0
  54. package/wwwroot/assets/CodePage-7kgZlB3O.js +87 -0
  55. package/wwwroot/assets/CodePage-Bncc352E.css +1 -0
  56. package/wwwroot/assets/CompanyCorePage-ChBnq1ve.css +1 -0
  57. package/wwwroot/assets/CompanyCorePage-CzIZIIU_.js +13 -0
  58. package/wwwroot/assets/ExecutionModePage-B-etp_mc.js +18 -0
  59. package/wwwroot/assets/ExecutionModePage-TLuld9l3.css +1 -0
  60. package/wwwroot/assets/LaunchLeadCapture-Bx9LM0IX.js +1 -0
  61. package/wwwroot/assets/LaunchLeadCapture-CiRI1shz.css +1 -0
  62. package/wwwroot/assets/MarketingHome-BsyerRpe.js +1 -0
  63. package/wwwroot/assets/MarketingHome-DPzaYzA_.css +1 -0
  64. package/wwwroot/assets/MindCanvas-DtqOZnoW.css +1 -0
  65. package/wwwroot/assets/MindCanvas-zEDXzaxW.js +49 -0
  66. package/wwwroot/assets/PlanMasterPage-CJ36rep-.css +1 -0
  67. package/wwwroot/assets/PlanMasterPage-NZ_mPvaE.js +4 -0
  68. package/wwwroot/assets/PricingPage-Cg_0i_ZR.css +1 -0
  69. package/wwwroot/assets/PricingPage-Ylrn8l2g.js +1 -0
  70. package/wwwroot/assets/ToolPages-3M2KqA9k.js +28 -0
  71. package/wwwroot/assets/ToolPages-DIB187pZ.css +1 -0
  72. package/wwwroot/assets/YouTubeSearchPage-COv1oAA7.js +4 -0
  73. package/wwwroot/assets/YouTubeSearchPage-IPPa_BIH.css +1 -0
  74. package/wwwroot/assets/app-runtime-xD2Z3NdN.js +1 -0
  75. package/wwwroot/assets/canvas-runtime-BbicBcOj.js +44 -0
  76. package/wwwroot/assets/code-agent-runtime-B5PPZd1t.js +74 -0
  77. package/wwwroot/assets/executionModeSettings-NJqurj-o.js +1 -0
  78. package/wwwroot/assets/index-CQMKCp-t.js +2 -0
  79. package/wwwroot/assets/index-yNpEK-gp.css +1 -0
  80. package/wwwroot/assets/marketingTools-DN_rnHeB.js +4 -0
  81. package/wwwroot/assets/mindCanvasSearchWorker-BzPMsHOB.js +1 -0
  82. package/wwwroot/assets/mindexecution-mindcanvas.png +0 -0
  83. package/wwwroot/assets/mindexecution-prod-home-current.png +0 -0
  84. package/wwwroot/assets/mindexecution-prod-pricing-current.png +0 -0
  85. package/wwwroot/assets/pricingCheckoutShell-O-DnwmbU.js +1 -0
  86. package/wwwroot/assets/productionAdapterConfig-C5jfk6oG.js +1 -0
  87. package/wwwroot/assets/runtimeSettingsPersistenceProjection-BoNWmYjU.js +1 -0
  88. package/wwwroot/assets/storage-TM3YrWaj.js +1 -0
  89. package/wwwroot/assets/supabaseAuthAdapter-DA43DeSY.js +44 -0
  90. package/wwwroot/assets/toolHandoff-D5e5f7t5.js +4 -0
  91. package/wwwroot/assets/vendor-icons-DE3gIReG.js +681 -0
  92. package/wwwroot/assets/vendor-msgpack-BE8aAsr3.js +1 -0
  93. package/wwwroot/assets/vendor-react-BXzpOyCS.js +40 -0
  94. package/wwwroot/favicon.svg +7 -0
  95. package/wwwroot/index.html +22 -0
  96. package/wwwroot/manifest.webmanifest +19 -0
  97. package/wwwroot/robots.txt +4 -0
  98. package/wwwroot/service-worker.js +7 -0
  99. package/wwwroot/sitemap.xml +39 -0
@@ -0,0 +1,236 @@
1
+ #!/usr/bin/env node
2
+
3
+ const path = require('path');
4
+ const fs = require('fs');
5
+ const { spawn } = require('child_process');
6
+ const packageInfo = require('./package.json');
7
+ const { normalizePort, releaseBridgePort } = require('./port-guard.cjs');
8
+
9
+ const bridgeRoot = __dirname;
10
+ const serverPath = path.resolve(bridgeRoot, 'server.js');
11
+ const inheritedWorkspacePath = String(process.env.WORKSPACE_PATH || '').trim();
12
+ const rawArgs = process.argv.slice(2);
13
+ const parsedArgs = extractWorkspaceArg(rawArgs);
14
+ const cliArgs = parsedArgs.args;
15
+ const workspacePath = path.resolve(
16
+ parsedArgs.workspacePath || inheritedWorkspacePath || getDefaultWorkspacePath()
17
+ );
18
+ const appUrl = `http://localhost:${normalizePort(process.env.BRIDGE_PORT)}/mindcanvas`;
19
+ const statusUrl = `http://127.0.0.1:${normalizePort(process.env.BRIDGE_PORT)}/api/status`;
20
+
21
+ function isSamePath(left, right) {
22
+ return path.resolve(left).toLowerCase() === path.resolve(right).toLowerCase();
23
+ }
24
+
25
+ function pathExists(...segments) {
26
+ return fs.existsSync(path.join(...segments));
27
+ }
28
+
29
+ function looksLikeWorkspaceRoot(candidate) {
30
+ return pathExists(candidate, '.mindexec')
31
+ || pathExists(candidate, 'MindExecution.Web')
32
+ || pathExists(candidate, 'MindExecution.Shared')
33
+ || pathExists(candidate, 'LocalBridge');
34
+ }
35
+
36
+ function getDefaultWorkspacePath() {
37
+ const cwd = process.cwd();
38
+ const bridgeParent = path.resolve(bridgeRoot, '..');
39
+
40
+ if (isSamePath(cwd, bridgeRoot) && looksLikeWorkspaceRoot(bridgeParent)) {
41
+ return bridgeParent;
42
+ }
43
+
44
+ return cwd;
45
+ }
46
+
47
+ function extractWorkspaceArg(args) {
48
+ const filteredArgs = [];
49
+ let workspacePath = '';
50
+
51
+ for (let index = 0; index < args.length; index += 1) {
52
+ const arg = args[index];
53
+ if (arg === '--workspace' || arg === '--workspace-path') {
54
+ workspacePath = String(args[index + 1] || '').trim();
55
+ if (!workspacePath) {
56
+ console.error(`[MindExec CLI] ${arg} requires a path.`);
57
+ process.exit(1);
58
+ }
59
+
60
+ index += 1;
61
+ continue;
62
+ }
63
+
64
+ if (arg.startsWith('--workspace=')) {
65
+ workspacePath = arg.slice('--workspace='.length).trim();
66
+ continue;
67
+ }
68
+
69
+ if (arg.startsWith('--workspace-path=')) {
70
+ workspacePath = arg.slice('--workspace-path='.length).trim();
71
+ continue;
72
+ }
73
+
74
+ filteredArgs.push(arg);
75
+ }
76
+
77
+ return {
78
+ args: filteredArgs,
79
+ workspacePath
80
+ };
81
+ }
82
+
83
+ function printHelp() {
84
+ console.log(`MindExec CLI ${packageInfo.version}
85
+
86
+ Usage:
87
+ mindexec [start] [options] [node-options]
88
+ npx mindexec-ai [options]
89
+
90
+ Runs the MindExec local app and bridge on http://localhost:5147/mindcanvas by default.
91
+
92
+ Options:
93
+ --workspace <path>
94
+ Workspace root. Defaults to the current directory for npx/global runs
95
+ --no-open Do not open the local app in the default browser
96
+
97
+ Environment:
98
+ BRIDGE_PORT Local bridge port. Default: 5147
99
+ WORKSPACE_PATH Workspace root. Overridden by --workspace when both are set
100
+ BRIDGE_TOKEN Fixed token for protected REST APIs
101
+ MINDEXEC_WEB_ROOT Published MindCanvas wwwroot override. Default: package wwwroot
102
+ MINDEXEC_NO_OPEN=1
103
+ Do not open the local app in the default browser
104
+ BRIDGE_SKIP_PORT_REAP=1
105
+ Do not stop an existing MindExec bridge on the same port
106
+ BRIDGE_FORCE_KILL_PORT_OWNER=1
107
+ Stop any process that owns BRIDGE_PORT before starting
108
+
109
+ Examples:
110
+ mindexec
111
+ mindexec --no-open
112
+ mindexec --workspace /path/to/work
113
+ npx mindexec-ai --workspace /path/to/work
114
+ BRIDGE_PORT=8080 WORKSPACE_PATH=/path/to/work mindexec
115
+ mindexec --watch
116
+ `);
117
+ }
118
+
119
+ if (cliArgs.includes('--help') || cliArgs.includes('-h')) {
120
+ printHelp();
121
+ process.exit(0);
122
+ }
123
+
124
+ if (cliArgs.includes('--version') || cliArgs.includes('-v')) {
125
+ console.log(packageInfo.version);
126
+ process.exit(0);
127
+ }
128
+
129
+ const command = cliArgs[0];
130
+ const commandArgs = command === 'start' || command === 'bridge'
131
+ ? cliArgs.slice(1)
132
+ : cliArgs;
133
+ const shouldOpenApp = !commandArgs.some(arg => arg === '--no-open' || arg === '--no-browser')
134
+ && !/^(1|true|yes|on)$/i.test(String(process.env.MINDEXEC_NO_OPEN || '').trim())
135
+ && !/^(0|false|no|off)$/i.test(String(process.env.MINDEXEC_OPEN_APP || '').trim());
136
+ const runtimeArgs = commandArgs.filter(arg => arg !== '--no-open' && arg !== '--no-browser');
137
+ const childArgs = [...runtimeArgs, serverPath];
138
+ const port = normalizePort(process.env.BRIDGE_PORT);
139
+
140
+ function delay(ms) {
141
+ return new Promise(resolve => setTimeout(resolve, ms));
142
+ }
143
+
144
+ async function waitForBridgeReady(timeoutMs = 15000) {
145
+ const startedAt = Date.now();
146
+ while (Date.now() - startedAt < timeoutMs) {
147
+ try {
148
+ const response = await fetch(statusUrl, { cache: 'no-store' });
149
+ if (response.ok) {
150
+ return true;
151
+ }
152
+ } catch {
153
+ // Server is still booting.
154
+ }
155
+
156
+ await delay(300);
157
+ }
158
+
159
+ return false;
160
+ }
161
+
162
+ function openLocalApp() {
163
+ let child;
164
+ if (process.platform === 'win32') {
165
+ child = spawn('cmd', ['/c', 'start', '', appUrl], {
166
+ detached: true,
167
+ stdio: 'ignore',
168
+ windowsHide: true
169
+ });
170
+ } else if (process.platform === 'darwin') {
171
+ child = spawn('open', [appUrl], {
172
+ detached: true,
173
+ stdio: 'ignore'
174
+ });
175
+ } else {
176
+ child = spawn('xdg-open', [appUrl], {
177
+ detached: true,
178
+ stdio: 'ignore'
179
+ });
180
+ }
181
+
182
+ child.on('error', () => {
183
+ console.log(`[MindExec CLI] Open the app manually: ${appUrl}`);
184
+ });
185
+ child.unref();
186
+ }
187
+
188
+ async function main() {
189
+ await releaseBridgePort({
190
+ port,
191
+ bridgeRoot,
192
+ log: message => console.log(`[MindExec CLI] ${message}`)
193
+ });
194
+
195
+ const child = spawn(process.execPath, childArgs, {
196
+ cwd: bridgeRoot,
197
+ env: {
198
+ ...process.env,
199
+ WORKSPACE_PATH: workspacePath
200
+ },
201
+ stdio: 'inherit',
202
+ windowsHide: false
203
+ });
204
+
205
+ child.on('exit', (code, signal) => {
206
+ if (signal) {
207
+ process.kill(process.pid, signal);
208
+ return;
209
+ }
210
+
211
+ process.exit(code ?? 0);
212
+ });
213
+
214
+ child.on('error', (error) => {
215
+ console.error('[MindExec CLI] Failed to start local bridge:', error);
216
+ process.exit(1);
217
+ });
218
+
219
+ if (shouldOpenApp) {
220
+ void (async () => {
221
+ const ready = await waitForBridgeReady();
222
+ if (!ready || child.exitCode !== null) {
223
+ console.log(`[MindExec CLI] Open the app manually: ${appUrl}`);
224
+ return;
225
+ }
226
+
227
+ console.log(`[MindExec CLI] opening ${appUrl}`);
228
+ openLocalApp();
229
+ })();
230
+ }
231
+ }
232
+
233
+ main().catch(error => {
234
+ console.error('[MindExec CLI] Failed to prepare local bridge port:', error.message || error);
235
+ process.exit(1);
236
+ });
package/package.json ADDED
@@ -0,0 +1,77 @@
1
+ {
2
+ "name": "mindexec-ai",
3
+ "version": "0.2.385",
4
+ "description": "MindExec local runtime and bridge CLI",
5
+ "main": "server.js",
6
+ "type": "module",
7
+ "files": [
8
+ "start-bridge.bat",
9
+ "start-bridge.sh",
10
+ "launch-bridge.cjs",
11
+ "server.js",
12
+ "remote-hub.js",
13
+ "codex-runtime.js",
14
+ "port-guard.cjs",
15
+ "remote-fast/",
16
+ "wwwroot/",
17
+ "scripts/",
18
+ "tree-sitter-grammars/",
19
+ "README.md"
20
+ ],
21
+ "scripts": {
22
+ "start": "node launch-bridge.cjs",
23
+ "dev": "node launch-bridge.cjs --watch",
24
+ "test:syntax": "node --check server.js && node --check remote-hub.js && node --check codex-runtime.js && node --check launch-bridge.cjs && node --check port-guard.cjs && node --check scripts/setup-tree-sitter-grammars.mjs && node --check scripts/auth-session-smoke.mjs && node --check scripts/remote-hub-smoke.mjs && node --check scripts/remote-hub-scale-smoke.mjs && node --check scripts/remote-fleet-render-smoke.mjs && node --check scripts/remote-http-smoke.mjs && node --check scripts/remote-frame-ws-smoke.mjs && node --check scripts/remote-input-ws-smoke.mjs && node --check scripts/remote-agent-ws-smoke.mjs && node --check scripts/remote-agent-managed-smoke.mjs && node --check scripts/remote-registry-follower-smoke.mjs && node --check scripts/remote-agent-package-smoke.mjs && node --check scripts/remote-fast-live-rate-smoke.mjs && node --check scripts/remote-fast-mdm-browser-smoke.mjs",
25
+ "test:auth": "node scripts/auth-session-smoke.mjs",
26
+ "test:remote": "node scripts/remote-hub-smoke.mjs",
27
+ "test:remote:scale": "node scripts/remote-hub-scale-smoke.mjs",
28
+ "test:remote:render": "node scripts/remote-fleet-render-smoke.mjs",
29
+ "test:remote:http": "node scripts/remote-http-smoke.mjs",
30
+ "test:remote:frame-ws": "node scripts/remote-frame-ws-smoke.mjs",
31
+ "test:remote:input-ws": "node scripts/remote-input-ws-smoke.mjs",
32
+ "test:remote:agent-ws": "node scripts/remote-agent-ws-smoke.mjs",
33
+ "test:remote:managed": "node scripts/remote-agent-managed-smoke.mjs",
34
+ "test:remote:registry": "node scripts/remote-registry-follower-smoke.mjs",
35
+ "test:remote:package": "node scripts/remote-agent-package-smoke.mjs",
36
+ "test:remote:live-rate": "node scripts/remote-fast-live-rate-smoke.mjs",
37
+ "test:remote:mdm-browser": "node scripts/remote-fast-mdm-browser-smoke.mjs",
38
+ "pack:dry": "npm pack --dry-run",
39
+ "setup:grammars": "node scripts/setup-tree-sitter-grammars.mjs",
40
+ "postinstall": "npm run setup:grammars"
41
+ },
42
+ "keywords": [
43
+ "mindexec",
44
+ "mindcanvas",
45
+ "cli",
46
+ "bridge",
47
+ "local",
48
+ "ai"
49
+ ],
50
+ "author": "",
51
+ "license": "MIT",
52
+ "publishConfig": {
53
+ "access": "public"
54
+ },
55
+ "engines": {
56
+ "node": ">=20"
57
+ },
58
+ "dependencies": {
59
+ "@mindexec/remote": "^0.1.17",
60
+ "@openai/codex-sdk": "^0.137.0",
61
+ "chokidar": "^3.6.0",
62
+ "cors": "^2.8.5",
63
+ "express": "^4.18.2",
64
+ "multer": "^2.2.0",
65
+ "playwright-core": "^1.53.0",
66
+ "sharp": "^0.33.2",
67
+ "web-tree-sitter": "^0.22.6",
68
+ "ws": "^8.16.0"
69
+ },
70
+ "bin": {
71
+ "mindexec": "launch-bridge.cjs",
72
+ "mind-bridge": "launch-bridge.cjs"
73
+ },
74
+ "devDependencies": {
75
+ "tree-sitter-wasms": "^0.1.13"
76
+ }
77
+ }
package/port-guard.cjs ADDED
@@ -0,0 +1,232 @@
1
+ const { execFile } = require('child_process');
2
+ const path = require('path');
3
+ const { promisify } = require('util');
4
+
5
+ const execFileAsync = promisify(execFile);
6
+ const DEFAULT_WAIT_MS = 3500;
7
+
8
+ function normalizePort(value, fallback = 5147) {
9
+ const parsed = Number.parseInt(String(value || '').trim(), 10);
10
+ return Number.isInteger(parsed) && parsed > 0 && parsed <= 65535
11
+ ? parsed
12
+ : fallback;
13
+ }
14
+
15
+ function normalizePath(value) {
16
+ return String(value || '').replace(/\\/g, '/').toLowerCase();
17
+ }
18
+
19
+ function isTruthy(value) {
20
+ return /^(1|true|yes|on)$/i.test(String(value || '').trim());
21
+ }
22
+
23
+ function endpointUsesPort(endpoint, port) {
24
+ const text = String(endpoint || '').trim();
25
+ return text.endsWith(`:${port}`)
26
+ || text.endsWith(`.${port}`)
27
+ || text.includes(`:${port} `)
28
+ || text.includes(`]:${port}`);
29
+ }
30
+
31
+ async function getWindowsListeners(port) {
32
+ const { stdout } = await execFileAsync('netstat.exe', ['-ano', '-p', 'tcp'], {
33
+ windowsHide: true,
34
+ maxBuffer: 1024 * 1024
35
+ });
36
+
37
+ const pids = new Set();
38
+ for (const rawLine of String(stdout || '').split(/\r?\n/)) {
39
+ const line = rawLine.trim();
40
+ if (!line || !/\bLISTENING\b/i.test(line)) {
41
+ continue;
42
+ }
43
+
44
+ const parts = line.split(/\s+/);
45
+ if (parts.length < 5 || !endpointUsesPort(parts[1], port)) {
46
+ continue;
47
+ }
48
+
49
+ const pid = Number.parseInt(parts[parts.length - 1], 10);
50
+ if (Number.isInteger(pid) && pid > 0 && pid !== process.pid) {
51
+ pids.add(pid);
52
+ }
53
+ }
54
+
55
+ return [...pids];
56
+ }
57
+
58
+ async function getUnixListeners(port) {
59
+ try {
60
+ const { stdout } = await execFileAsync('lsof', ['-nP', `-iTCP:${port}`, '-sTCP:LISTEN', '-t'], {
61
+ maxBuffer: 256 * 1024
62
+ });
63
+ return String(stdout || '')
64
+ .split(/\r?\n/)
65
+ .map(line => Number.parseInt(line.trim(), 10))
66
+ .filter(pid => Number.isInteger(pid) && pid > 0 && pid !== process.pid);
67
+ } catch {
68
+ return [];
69
+ }
70
+ }
71
+
72
+ async function getPortListeners(port) {
73
+ try {
74
+ return process.platform === 'win32'
75
+ ? await getWindowsListeners(port)
76
+ : await getUnixListeners(port);
77
+ } catch {
78
+ return [];
79
+ }
80
+ }
81
+
82
+ async function getWindowsProcessDetails(pid) {
83
+ const script = [
84
+ '$ErrorActionPreference = "SilentlyContinue";',
85
+ `$p = Get-CimInstance Win32_Process -Filter "ProcessId=${pid}";`,
86
+ 'if ($p) {',
87
+ ' [pscustomobject]@{ ProcessId = $p.ProcessId; ExecutablePath = $p.ExecutablePath; CommandLine = $p.CommandLine } | ConvertTo-Json -Compress',
88
+ '}'
89
+ ].join(' ');
90
+ const { stdout } = await execFileAsync('powershell.exe', ['-NoProfile', '-Command', script], {
91
+ windowsHide: true,
92
+ maxBuffer: 256 * 1024
93
+ });
94
+ const parsed = JSON.parse(String(stdout || '{}').trim() || '{}');
95
+ return {
96
+ pid,
97
+ executablePath: parsed.ExecutablePath || '',
98
+ commandLine: parsed.CommandLine || ''
99
+ };
100
+ }
101
+
102
+ async function getUnixProcessDetails(pid) {
103
+ const { stdout } = await execFileAsync('ps', ['-p', String(pid), '-o', 'comm=', '-o', 'args='], {
104
+ maxBuffer: 256 * 1024
105
+ });
106
+ const text = String(stdout || '').trim();
107
+ return {
108
+ pid,
109
+ executablePath: text.split(/\s+/)[0] || '',
110
+ commandLine: text
111
+ };
112
+ }
113
+
114
+ async function getProcessDetails(pid) {
115
+ try {
116
+ return process.platform === 'win32'
117
+ ? await getWindowsProcessDetails(pid)
118
+ : await getUnixProcessDetails(pid);
119
+ } catch {
120
+ return {
121
+ pid,
122
+ executablePath: '',
123
+ commandLine: ''
124
+ };
125
+ }
126
+ }
127
+
128
+ function looksLikeMindExecBridge(details, bridgeRoot) {
129
+ const text = normalizePath(`${details.executablePath || ''} ${details.commandLine || ''}`);
130
+ const root = normalizePath(bridgeRoot);
131
+ const packageRoot = normalizePath(path.dirname(bridgeRoot));
132
+
133
+ return (root && text.includes(root))
134
+ || (packageRoot && text.includes(`${packageRoot}/localbridge/`))
135
+ || text.includes('localbridge/server.js')
136
+ || text.includes('localbridge/launch-bridge.cjs')
137
+ || text.includes('/localbridge/server.js')
138
+ || text.includes('/localbridge/launch-bridge.cjs')
139
+ || text.includes('mindexec-ai')
140
+ || text.includes('mind-bridge')
141
+ || /\bmindexec(\.cmd|\.ps1|\.exe)?\b/i.test(text);
142
+ }
143
+
144
+ async function waitForPortRelease(port, timeoutMs = DEFAULT_WAIT_MS) {
145
+ const started = Date.now();
146
+ while (Date.now() - started < timeoutMs) {
147
+ const listeners = await getPortListeners(port);
148
+ if (listeners.length === 0) {
149
+ return true;
150
+ }
151
+
152
+ await new Promise(resolve => setTimeout(resolve, 120));
153
+ }
154
+
155
+ return false;
156
+ }
157
+
158
+ function killPid(pid, signal) {
159
+ try {
160
+ process.kill(pid, signal);
161
+ return true;
162
+ } catch {
163
+ return false;
164
+ }
165
+ }
166
+
167
+ async function releaseBridgePort(options = {}) {
168
+ const port = normalizePort(options.port || process.env.BRIDGE_PORT);
169
+ const bridgeRoot = options.bridgeRoot || __dirname;
170
+ const log = typeof options.log === 'function' ? options.log : () => {};
171
+ const force = isTruthy(process.env.BRIDGE_FORCE_KILL_PORT_OWNER)
172
+ || isTruthy(process.env.BRIDGE_KILL_ANY_PORT_OWNER);
173
+ const disabled = isTruthy(process.env.BRIDGE_SKIP_PORT_REAP);
174
+
175
+ if (disabled) {
176
+ return { port, killed: [], skipped: [], disabled: true };
177
+ }
178
+
179
+ const pids = await getPortListeners(port);
180
+ const killed = [];
181
+ const skipped = [];
182
+
183
+ for (const pid of pids) {
184
+ const details = await getProcessDetails(pid);
185
+ const canKill = force || looksLikeMindExecBridge(details, bridgeRoot);
186
+ if (!canKill) {
187
+ skipped.push(details);
188
+ continue;
189
+ }
190
+
191
+ if (killPid(pid, 'SIGTERM')) {
192
+ killed.push(details);
193
+ log(`stopping existing LocalBridge listener on port ${port} (pid ${pid})`);
194
+ }
195
+ }
196
+
197
+ if (killed.length > 0) {
198
+ const released = await waitForPortRelease(port);
199
+ if (!released) {
200
+ const remaining = await getPortListeners(port);
201
+ for (const details of killed) {
202
+ if (remaining.includes(details.pid)) {
203
+ killPid(details.pid, 'SIGKILL');
204
+ log(`force-stopping LocalBridge listener on port ${port} (pid ${details.pid})`);
205
+ }
206
+ }
207
+
208
+ await waitForPortRelease(port, 1200);
209
+ }
210
+ }
211
+
212
+ if (skipped.length > 0) {
213
+ const owners = skipped
214
+ .map(item => `pid ${item.pid}${item.commandLine ? ` (${item.commandLine})` : ''}`)
215
+ .join('; ');
216
+ const error = new Error(
217
+ `Port ${port} is already in use by a non-MindExec process: ${owners}. ` +
218
+ 'Close it or set BRIDGE_FORCE_KILL_PORT_OWNER=1 to terminate any owner of this bridge port.'
219
+ );
220
+ error.code = 'BRIDGE_PORT_IN_USE';
221
+ error.port = port;
222
+ error.skipped = skipped;
223
+ throw error;
224
+ }
225
+
226
+ return { port, killed, skipped, disabled: false };
227
+ }
228
+
229
+ module.exports = {
230
+ normalizePort,
231
+ releaseBridgePort
232
+ };
@@ -0,0 +1,24 @@
1
+ {
2
+ "runtimeTarget": {
3
+ "name": ".NETCoreApp,Version=v9.0/osx-arm64",
4
+ "signature": ""
5
+ },
6
+ "compilationOptions": {},
7
+ "targets": {
8
+ ".NETCoreApp,Version=v9.0": {},
9
+ ".NETCoreApp,Version=v9.0/osx-arm64": {
10
+ "mindexec-remote-fast/1.0.0": {
11
+ "runtime": {
12
+ "mindexec-remote-fast.dll": {}
13
+ }
14
+ }
15
+ }
16
+ },
17
+ "libraries": {
18
+ "mindexec-remote-fast/1.0.0": {
19
+ "type": "project",
20
+ "serviceable": false,
21
+ "sha512": ""
22
+ }
23
+ }
24
+ }
@@ -0,0 +1,13 @@
1
+ {
2
+ "runtimeOptions": {
3
+ "tfm": "net9.0",
4
+ "framework": {
5
+ "name": "Microsoft.NETCore.App",
6
+ "version": "9.0.0"
7
+ },
8
+ "configProperties": {
9
+ "System.Reflection.Metadata.MetadataUpdater.IsSupported": false,
10
+ "System.Runtime.Serialization.EnableUnsafeBinaryFormatterSerialization": false
11
+ }
12
+ }
13
+ }
@@ -0,0 +1,24 @@
1
+ {
2
+ "runtimeTarget": {
3
+ "name": ".NETCoreApp,Version=v9.0/osx-x64",
4
+ "signature": ""
5
+ },
6
+ "compilationOptions": {},
7
+ "targets": {
8
+ ".NETCoreApp,Version=v9.0": {},
9
+ ".NETCoreApp,Version=v9.0/osx-x64": {
10
+ "mindexec-remote-fast/1.0.0": {
11
+ "runtime": {
12
+ "mindexec-remote-fast.dll": {}
13
+ }
14
+ }
15
+ }
16
+ },
17
+ "libraries": {
18
+ "mindexec-remote-fast/1.0.0": {
19
+ "type": "project",
20
+ "serviceable": false,
21
+ "sha512": ""
22
+ }
23
+ }
24
+ }
@@ -0,0 +1,13 @@
1
+ {
2
+ "runtimeOptions": {
3
+ "tfm": "net9.0",
4
+ "framework": {
5
+ "name": "Microsoft.NETCore.App",
6
+ "version": "9.0.0"
7
+ },
8
+ "configProperties": {
9
+ "System.Reflection.Metadata.MetadataUpdater.IsSupported": false,
10
+ "System.Runtime.Serialization.EnableUnsafeBinaryFormatterSerialization": false
11
+ }
12
+ }
13
+ }
@@ -0,0 +1,24 @@
1
+ {
2
+ "runtimeTarget": {
3
+ "name": ".NETCoreApp,Version=v9.0/win-x64",
4
+ "signature": ""
5
+ },
6
+ "compilationOptions": {},
7
+ "targets": {
8
+ ".NETCoreApp,Version=v9.0": {},
9
+ ".NETCoreApp,Version=v9.0/win-x64": {
10
+ "mindexec-remote-fast/1.0.0": {
11
+ "runtime": {
12
+ "mindexec-remote-fast.dll": {}
13
+ }
14
+ }
15
+ }
16
+ },
17
+ "libraries": {
18
+ "mindexec-remote-fast/1.0.0": {
19
+ "type": "project",
20
+ "serviceable": false,
21
+ "sha512": ""
22
+ }
23
+ }
24
+ }
@@ -0,0 +1,20 @@
1
+ {
2
+ "runtimeOptions": {
3
+ "tfm": "net9.0",
4
+ "frameworks": [
5
+ {
6
+ "name": "Microsoft.NETCore.App",
7
+ "version": "9.0.0"
8
+ },
9
+ {
10
+ "name": "Microsoft.WindowsDesktop.App",
11
+ "version": "9.0.0"
12
+ }
13
+ ],
14
+ "configProperties": {
15
+ "System.Reflection.Metadata.MetadataUpdater.IsSupported": false,
16
+ "System.Runtime.Serialization.EnableUnsafeBinaryFormatterSerialization": false,
17
+ "CSWINRT_USE_WINDOWS_UI_XAML_PROJECTIONS": false
18
+ }
19
+ }
20
+ }