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.
- package/README.md +354 -0
- package/codex-runtime.js +1339 -0
- package/launch-bridge.cjs +236 -0
- package/package.json +77 -0
- package/port-guard.cjs +232 -0
- package/remote-fast/osx-arm64/mindexec-remote-fast +0 -0
- package/remote-fast/osx-arm64/mindexec-remote-fast.deps.json +24 -0
- package/remote-fast/osx-arm64/mindexec-remote-fast.dll +0 -0
- package/remote-fast/osx-arm64/mindexec-remote-fast.runtimeconfig.json +13 -0
- package/remote-fast/osx-x64/mindexec-remote-fast +0 -0
- package/remote-fast/osx-x64/mindexec-remote-fast.deps.json +24 -0
- package/remote-fast/osx-x64/mindexec-remote-fast.dll +0 -0
- package/remote-fast/osx-x64/mindexec-remote-fast.runtimeconfig.json +13 -0
- package/remote-fast/win-x64/mindexec-remote-fast.deps.json +24 -0
- package/remote-fast/win-x64/mindexec-remote-fast.dll +0 -0
- package/remote-fast/win-x64/mindexec-remote-fast.exe +0 -0
- package/remote-fast/win-x64/mindexec-remote-fast.runtimeconfig.json +20 -0
- package/remote-hub.js +3106 -0
- package/scripts/auth-session-smoke.mjs +262 -0
- package/scripts/remote-agent-managed-smoke.mjs +291 -0
- package/scripts/remote-agent-package-smoke.mjs +64 -0
- package/scripts/remote-agent-ws-smoke.mjs +202 -0
- package/scripts/remote-fast-live-rate-smoke.mjs +355 -0
- package/scripts/remote-fast-mdm-browser-smoke.mjs +476 -0
- package/scripts/remote-fleet-render-smoke.mjs +1491 -0
- package/scripts/remote-frame-ws-smoke.mjs +234 -0
- package/scripts/remote-http-smoke.mjs +592 -0
- package/scripts/remote-hub-identity-smoke.mjs +146 -0
- package/scripts/remote-hub-scale-smoke.mjs +124 -0
- package/scripts/remote-hub-smoke.mjs +631 -0
- package/scripts/remote-input-ws-smoke.mjs +263 -0
- package/scripts/remote-registry-follower-smoke.mjs +752 -0
- package/scripts/setup-tree-sitter-grammars.mjs +80 -0
- package/server.js +15709 -0
- package/start-bridge.bat +32 -0
- package/start-bridge.sh +81 -0
- package/tree-sitter-grammars/README.md +18 -0
- package/tree-sitter-grammars/tree-sitter-c_sharp.wasm +0 -0
- package/tree-sitter-grammars/tree-sitter-go.wasm +0 -0
- package/tree-sitter-grammars/tree-sitter-java.wasm +0 -0
- package/tree-sitter-grammars/tree-sitter-javascript.wasm +0 -0
- package/tree-sitter-grammars/tree-sitter-python.wasm +0 -0
- package/tree-sitter-grammars/tree-sitter-rust.wasm +0 -0
- package/tree-sitter-grammars/tree-sitter-tsx.wasm +0 -0
- package/tree-sitter-grammars/tree-sitter-typescript.wasm +0 -0
- package/wwwroot/_headers +73 -0
- package/wwwroot/_redirects +1 -0
- package/wwwroot/appsettings.json +83 -0
- package/wwwroot/assets/AdminDashboardPage-B2vz2Px9.css +1 -0
- package/wwwroot/assets/AdminDashboardPage-DnuCHywn.js +1 -0
- package/wwwroot/assets/AppSidebar-DU2OgSiv.js +2 -0
- package/wwwroot/assets/AuthPages-BrH6kRcv.css +1 -0
- package/wwwroot/assets/AuthPages-Dgezl7Vj.js +1 -0
- package/wwwroot/assets/CodePage-7kgZlB3O.js +87 -0
- package/wwwroot/assets/CodePage-Bncc352E.css +1 -0
- package/wwwroot/assets/CompanyCorePage-ChBnq1ve.css +1 -0
- package/wwwroot/assets/CompanyCorePage-CzIZIIU_.js +13 -0
- package/wwwroot/assets/ExecutionModePage-B-etp_mc.js +18 -0
- package/wwwroot/assets/ExecutionModePage-TLuld9l3.css +1 -0
- package/wwwroot/assets/LaunchLeadCapture-Bx9LM0IX.js +1 -0
- package/wwwroot/assets/LaunchLeadCapture-CiRI1shz.css +1 -0
- package/wwwroot/assets/MarketingHome-BsyerRpe.js +1 -0
- package/wwwroot/assets/MarketingHome-DPzaYzA_.css +1 -0
- package/wwwroot/assets/MindCanvas-DtqOZnoW.css +1 -0
- package/wwwroot/assets/MindCanvas-zEDXzaxW.js +49 -0
- package/wwwroot/assets/PlanMasterPage-CJ36rep-.css +1 -0
- package/wwwroot/assets/PlanMasterPage-NZ_mPvaE.js +4 -0
- package/wwwroot/assets/PricingPage-Cg_0i_ZR.css +1 -0
- package/wwwroot/assets/PricingPage-Ylrn8l2g.js +1 -0
- package/wwwroot/assets/ToolPages-3M2KqA9k.js +28 -0
- package/wwwroot/assets/ToolPages-DIB187pZ.css +1 -0
- package/wwwroot/assets/YouTubeSearchPage-COv1oAA7.js +4 -0
- package/wwwroot/assets/YouTubeSearchPage-IPPa_BIH.css +1 -0
- package/wwwroot/assets/app-runtime-xD2Z3NdN.js +1 -0
- package/wwwroot/assets/canvas-runtime-BbicBcOj.js +44 -0
- package/wwwroot/assets/code-agent-runtime-B5PPZd1t.js +74 -0
- package/wwwroot/assets/executionModeSettings-NJqurj-o.js +1 -0
- package/wwwroot/assets/index-CQMKCp-t.js +2 -0
- package/wwwroot/assets/index-yNpEK-gp.css +1 -0
- package/wwwroot/assets/marketingTools-DN_rnHeB.js +4 -0
- package/wwwroot/assets/mindCanvasSearchWorker-BzPMsHOB.js +1 -0
- package/wwwroot/assets/mindexecution-mindcanvas.png +0 -0
- package/wwwroot/assets/mindexecution-prod-home-current.png +0 -0
- package/wwwroot/assets/mindexecution-prod-pricing-current.png +0 -0
- package/wwwroot/assets/pricingCheckoutShell-O-DnwmbU.js +1 -0
- package/wwwroot/assets/productionAdapterConfig-C5jfk6oG.js +1 -0
- package/wwwroot/assets/runtimeSettingsPersistenceProjection-BoNWmYjU.js +1 -0
- package/wwwroot/assets/storage-TM3YrWaj.js +1 -0
- package/wwwroot/assets/supabaseAuthAdapter-DA43DeSY.js +44 -0
- package/wwwroot/assets/toolHandoff-D5e5f7t5.js +4 -0
- package/wwwroot/assets/vendor-icons-DE3gIReG.js +681 -0
- package/wwwroot/assets/vendor-msgpack-BE8aAsr3.js +1 -0
- package/wwwroot/assets/vendor-react-BXzpOyCS.js +40 -0
- package/wwwroot/favicon.svg +7 -0
- package/wwwroot/index.html +22 -0
- package/wwwroot/manifest.webmanifest +19 -0
- package/wwwroot/robots.txt +4 -0
- package/wwwroot/service-worker.js +7 -0
- 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
|
+
};
|
|
Binary file
|
|
@@ -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
|
+
}
|
|
Binary file
|
|
@@ -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
|
+
}
|
|
Binary file
|
|
@@ -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
|
+
}
|
|
Binary file
|
|
@@ -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
|
+
}
|
|
Binary file
|
|
Binary file
|
|
@@ -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
|
+
}
|