@mindexec/cli 0.2.88 → 0.2.89
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/package.json +3 -2
- package/scripts/auth-session-smoke.mjs +218 -0
- package/server.js +213 -11
- package/wwwroot/_framework/MindExecution.Core.qprj2wqc9a.dll +0 -0
- package/wwwroot/_framework/{MindExecution.Kernel.mdo1lzjvvp.dll → MindExecution.Kernel.ksznt6ppyj.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Plugins.Admin.5fctwf65dx.dll → MindExecution.Plugins.Admin.ziclnsvcvi.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Plugins.Business.nwivpk9djf.dll → MindExecution.Plugins.Business.q32f5kgky1.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Plugins.Concept.d66vf951hc.dll → MindExecution.Plugins.Concept.vrmey2vv08.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Plugins.Directory.jnzcrwl049.dll → MindExecution.Plugins.Directory.3pet73jp0m.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Plugins.PlanMaster.3nmh4z5z35.dll → MindExecution.Plugins.PlanMaster.0pdulhmw15.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Plugins.YouTube.pk0nd21ct1.dll → MindExecution.Plugins.YouTube.ye6w0jn4v9.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Shared.kjl470mcqw.dll → MindExecution.Shared.oxf5h3gtl1.dll} +0 -0
- package/wwwroot/_framework/MindExecution.Web.s43m8j3bg0.dll +0 -0
- package/wwwroot/_framework/blazor.boot.json +21 -21
- package/wwwroot/index.html +3 -3
- package/wwwroot/service-worker-assets.js +23 -23
- package/wwwroot/service-worker.js +1 -1
- package/wwwroot/_framework/MindExecution.Core.csfu1xtj3l.dll +0 -0
- package/wwwroot/_framework/MindExecution.Web.w30rv8f29g.dll +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mindexec/cli",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.89",
|
|
4
4
|
"description": "MindExec local runtime and bridge CLI",
|
|
5
5
|
"main": "server.js",
|
|
6
6
|
"type": "module",
|
|
@@ -20,7 +20,8 @@
|
|
|
20
20
|
"scripts": {
|
|
21
21
|
"start": "node launch-bridge.cjs",
|
|
22
22
|
"dev": "node launch-bridge.cjs --watch",
|
|
23
|
-
"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/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",
|
|
23
|
+
"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",
|
|
24
|
+
"test:auth": "node scripts/auth-session-smoke.mjs",
|
|
24
25
|
"test:remote": "node scripts/remote-hub-smoke.mjs",
|
|
25
26
|
"test:remote:scale": "node scripts/remote-hub-scale-smoke.mjs",
|
|
26
27
|
"test:remote:render": "node scripts/remote-fleet-render-smoke.mjs",
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import assert from 'node:assert/strict';
|
|
4
|
+
import { spawn } from 'node:child_process';
|
|
5
|
+
import { mkdtemp, mkdir, rm, writeFile } from 'node:fs/promises';
|
|
6
|
+
import net from 'node:net';
|
|
7
|
+
import os from 'node:os';
|
|
8
|
+
import path from 'node:path';
|
|
9
|
+
import { fileURLToPath } from 'node:url';
|
|
10
|
+
|
|
11
|
+
const BRIDGE_TOKEN = 'auth-session-smoke-token';
|
|
12
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
13
|
+
const bridgeRoot = path.resolve(__dirname, '..');
|
|
14
|
+
|
|
15
|
+
function wait(ms) {
|
|
16
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
async function findFreePort() {
|
|
20
|
+
return await new Promise((resolve, reject) => {
|
|
21
|
+
const server = net.createServer();
|
|
22
|
+
server.unref();
|
|
23
|
+
server.once('error', reject);
|
|
24
|
+
server.listen(0, '127.0.0.1', () => {
|
|
25
|
+
const address = server.address();
|
|
26
|
+
const port = typeof address === 'object' && address ? address.port : 0;
|
|
27
|
+
server.close(() => resolve(port));
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async function fetchJson(url, options = {}) {
|
|
33
|
+
const response = await fetch(url, {
|
|
34
|
+
...options,
|
|
35
|
+
headers: {
|
|
36
|
+
...(options.body ? { 'Content-Type': 'application/json' } : {}),
|
|
37
|
+
...(options.token ? { 'X-Bridge-Token': options.token } : {}),
|
|
38
|
+
...(options.headers || {})
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
let payload = null;
|
|
43
|
+
try {
|
|
44
|
+
payload = await response.json();
|
|
45
|
+
} catch {
|
|
46
|
+
// Ignore non-JSON responses.
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return {
|
|
50
|
+
status: response.status,
|
|
51
|
+
ok: response.ok,
|
|
52
|
+
payload
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function spawnBridge({ bridgePort, workspacePath, authDataRoot }) {
|
|
57
|
+
const child = spawn(process.execPath, ['server.js'], {
|
|
58
|
+
cwd: bridgeRoot,
|
|
59
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
60
|
+
windowsHide: true,
|
|
61
|
+
env: {
|
|
62
|
+
...process.env,
|
|
63
|
+
BRIDGE_PORT: String(bridgePort),
|
|
64
|
+
BRIDGE_TOKEN,
|
|
65
|
+
BRIDGE_REQUIRE_TOKEN: '1',
|
|
66
|
+
WORKSPACE_PATH: workspacePath,
|
|
67
|
+
MINDEXEC_AUTH_DATA_ROOT: authDataRoot,
|
|
68
|
+
MINDEXEC_REMOTE_HUB: '0',
|
|
69
|
+
NO_COLOR: '1'
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
let stdout = '';
|
|
74
|
+
let stderr = '';
|
|
75
|
+
child.stdout.on('data', chunk => {
|
|
76
|
+
stdout += chunk.toString();
|
|
77
|
+
});
|
|
78
|
+
child.stderr.on('data', chunk => {
|
|
79
|
+
stderr += chunk.toString();
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
const details = () => `stdout=${stdout}\nstderr=${stderr}`;
|
|
83
|
+
const stop = async () => {
|
|
84
|
+
if (!child.killed) {
|
|
85
|
+
child.kill();
|
|
86
|
+
}
|
|
87
|
+
await Promise.race([
|
|
88
|
+
new Promise(resolve => child.once('exit', resolve)),
|
|
89
|
+
wait(3000)
|
|
90
|
+
]);
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
return {
|
|
94
|
+
child,
|
|
95
|
+
details,
|
|
96
|
+
stop
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
async function waitForBridge(baseUrl, details) {
|
|
101
|
+
const startedAt = Date.now();
|
|
102
|
+
while (Date.now() - startedAt < 30000) {
|
|
103
|
+
try {
|
|
104
|
+
const response = await fetchJson(`${baseUrl}/api/status`);
|
|
105
|
+
if (response.ok && response.payload?.status) {
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
} catch {
|
|
109
|
+
// Bridge is still starting.
|
|
110
|
+
}
|
|
111
|
+
await wait(100);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
throw new Error(`Timed out waiting for LocalBridge.\n${details()}`);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
async function withBridge({ workspacePath, authDataRoot }, action) {
|
|
118
|
+
const bridgePort = await findFreePort();
|
|
119
|
+
const bridge = spawnBridge({ bridgePort, workspacePath, authDataRoot });
|
|
120
|
+
const baseUrl = `http://127.0.0.1:${bridgePort}`;
|
|
121
|
+
try {
|
|
122
|
+
await waitForBridge(baseUrl, bridge.details);
|
|
123
|
+
await action(baseUrl);
|
|
124
|
+
} finally {
|
|
125
|
+
await bridge.stop();
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const tempRoot = await mkdtemp(path.join(os.tmpdir(), 'mindexec-auth-session-smoke-'));
|
|
130
|
+
try {
|
|
131
|
+
const authDataRoot = path.join(tempRoot, 'stable-auth');
|
|
132
|
+
const workspaceA = path.join(tempRoot, 'workspace-a');
|
|
133
|
+
const workspaceB = path.join(tempRoot, 'workspace-b');
|
|
134
|
+
await mkdir(workspaceA, { recursive: true });
|
|
135
|
+
await mkdir(workspaceB, { recursive: true });
|
|
136
|
+
|
|
137
|
+
const sessionPayload = JSON.stringify({
|
|
138
|
+
access_token: 'access-token-a',
|
|
139
|
+
refresh_token: 'refresh-token-a',
|
|
140
|
+
user: {
|
|
141
|
+
id: 'user-a',
|
|
142
|
+
email: 'auth-smoke@example.com'
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
await withBridge({ workspacePath: workspaceA, authDataRoot }, async (baseUrl) => {
|
|
147
|
+
const unauthorized = await fetchJson(`${baseUrl}/api/auth/session`);
|
|
148
|
+
assert.equal(unauthorized.status, 401);
|
|
149
|
+
|
|
150
|
+
const missing = await fetchJson(`${baseUrl}/api/auth/session`, { token: BRIDGE_TOKEN });
|
|
151
|
+
assert.equal(missing.status, 404);
|
|
152
|
+
|
|
153
|
+
const invalid = await fetchJson(`${baseUrl}/api/auth/session`, {
|
|
154
|
+
method: 'POST',
|
|
155
|
+
token: BRIDGE_TOKEN,
|
|
156
|
+
body: JSON.stringify({ content: 'not-json' })
|
|
157
|
+
});
|
|
158
|
+
assert.equal(invalid.status, 400);
|
|
159
|
+
|
|
160
|
+
const saved = await fetchJson(`${baseUrl}/api/auth/session`, {
|
|
161
|
+
method: 'POST',
|
|
162
|
+
token: BRIDGE_TOKEN,
|
|
163
|
+
body: JSON.stringify({ content: sessionPayload })
|
|
164
|
+
});
|
|
165
|
+
assert.equal(saved.status, 200);
|
|
166
|
+
assert.equal(saved.payload?.success, true);
|
|
167
|
+
|
|
168
|
+
const loaded = await fetchJson(`${baseUrl}/api/auth/session`, { token: BRIDGE_TOKEN });
|
|
169
|
+
assert.equal(loaded.status, 200);
|
|
170
|
+
assert.equal(loaded.payload?.content, sessionPayload);
|
|
171
|
+
assert.equal(loaded.payload?.source, 'stable');
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
await withBridge({ workspacePath: workspaceB, authDataRoot }, async (baseUrl) => {
|
|
175
|
+
const loaded = await fetchJson(`${baseUrl}/api/auth/session`, { token: BRIDGE_TOKEN });
|
|
176
|
+
assert.equal(loaded.status, 200);
|
|
177
|
+
assert.equal(loaded.payload?.content, sessionPayload);
|
|
178
|
+
assert.equal(loaded.payload?.source, 'stable');
|
|
179
|
+
|
|
180
|
+
const deleted = await fetchJson(`${baseUrl}/api/auth/session`, {
|
|
181
|
+
method: 'DELETE',
|
|
182
|
+
token: BRIDGE_TOKEN
|
|
183
|
+
});
|
|
184
|
+
assert.equal(deleted.status, 200);
|
|
185
|
+
assert.equal(deleted.payload?.success, true);
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
const legacyPayload = JSON.stringify({
|
|
189
|
+
access_token: 'legacy-access-token',
|
|
190
|
+
refresh_token: 'legacy-refresh-token',
|
|
191
|
+
user: {
|
|
192
|
+
id: 'legacy-user',
|
|
193
|
+
email: 'legacy-auth-smoke@example.com'
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
const legacyPath = path.join(workspaceB, '.mindexec', 'auth', 'supabase-session.json');
|
|
197
|
+
await mkdir(path.dirname(legacyPath), { recursive: true });
|
|
198
|
+
await writeFile(legacyPath, legacyPayload, 'utf8');
|
|
199
|
+
|
|
200
|
+
await withBridge({ workspacePath: workspaceB, authDataRoot }, async (baseUrl) => {
|
|
201
|
+
const migrated = await fetchJson(`${baseUrl}/api/auth/session`, { token: BRIDGE_TOKEN });
|
|
202
|
+
assert.equal(migrated.status, 200);
|
|
203
|
+
assert.equal(migrated.payload?.content, legacyPayload);
|
|
204
|
+
assert.equal(migrated.payload?.source, 'legacy-workspace');
|
|
205
|
+
assert.equal(migrated.payload?.migrated, true);
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
await withBridge({ workspacePath: workspaceA, authDataRoot }, async (baseUrl) => {
|
|
209
|
+
const loaded = await fetchJson(`${baseUrl}/api/auth/session`, { token: BRIDGE_TOKEN });
|
|
210
|
+
assert.equal(loaded.status, 200);
|
|
211
|
+
assert.equal(loaded.payload?.content, legacyPayload);
|
|
212
|
+
assert.equal(loaded.payload?.source, 'stable');
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
console.log('Auth session persistence smoke OK');
|
|
216
|
+
} finally {
|
|
217
|
+
await rm(tempRoot, { recursive: true, force: true });
|
|
218
|
+
}
|
package/server.js
CHANGED
|
@@ -424,10 +424,12 @@ let currentBrowserSessionId = null;
|
|
|
424
424
|
let browserSessionSequence = 0;
|
|
425
425
|
let playwrightModulePromise = null;
|
|
426
426
|
let playwrightBrowserPromise = null;
|
|
427
|
-
const DATA_ROOT_DIRNAME = '.mindexec';
|
|
428
|
-
const LEGACY_MIGRATION_MARKER = '.legacy_migrated_v1.json';
|
|
429
|
-
const DATA_GITIGNORE_FILE = '.gitignore';
|
|
430
|
-
const
|
|
427
|
+
const DATA_ROOT_DIRNAME = '.mindexec';
|
|
428
|
+
const LEGACY_MIGRATION_MARKER = '.legacy_migrated_v1.json';
|
|
429
|
+
const DATA_GITIGNORE_FILE = '.gitignore';
|
|
430
|
+
const AUTH_DATA_ROOT = resolveAuthDataRoot();
|
|
431
|
+
const AUTH_SESSION_FILE_NAME = 'supabase-session.json';
|
|
432
|
+
const DATA_GITIGNORE_CONTENT = [
|
|
431
433
|
'# MindExec managed data',
|
|
432
434
|
'# Keep boards/ and project.json for shared context by default.',
|
|
433
435
|
'/cache/',
|
|
@@ -470,13 +472,150 @@ const PLAYWRIGHT_BROWSER_CANDIDATES = process.platform === 'win32'
|
|
|
470
472
|
'/snap/bin/chromium'
|
|
471
473
|
];
|
|
472
474
|
|
|
473
|
-
function getDataRoot(basePath = workspacePath) {
|
|
474
|
-
return path.join(basePath, DATA_ROOT_DIRNAME);
|
|
475
|
-
}
|
|
476
|
-
|
|
477
|
-
function
|
|
478
|
-
|
|
479
|
-
|
|
475
|
+
function getDataRoot(basePath = workspacePath) {
|
|
476
|
+
return path.join(basePath, DATA_ROOT_DIRNAME);
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
function resolveAuthDataRoot() {
|
|
480
|
+
const configuredRoot = String(process.env.MINDEXEC_AUTH_DATA_ROOT || '').trim();
|
|
481
|
+
if (configuredRoot) {
|
|
482
|
+
return path.resolve(configuredRoot);
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
return path.join(os.homedir(), '.mindexec', 'auth');
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
function getStableSupabaseSessionPath() {
|
|
489
|
+
return path.join(AUTH_DATA_ROOT, AUTH_SESSION_FILE_NAME);
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
function getLegacyWorkspaceSupabaseSessionPath(basePath = workspacePath) {
|
|
493
|
+
return path.join(getDataRoot(basePath), 'auth', AUTH_SESSION_FILE_NAME);
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
function getLegacySupabaseSessionCandidatePaths() {
|
|
497
|
+
const candidates = [
|
|
498
|
+
getLegacyWorkspaceSupabaseSessionPath(workspacePath),
|
|
499
|
+
getLegacyWorkspaceSupabaseSessionPath(DEFAULT_WORKSPACE)
|
|
500
|
+
];
|
|
501
|
+
|
|
502
|
+
return Array.from(new Set(candidates.map(candidate => path.resolve(candidate))));
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
async function tryReadTextFile(filePath) {
|
|
506
|
+
try {
|
|
507
|
+
return await fs.readFile(filePath, 'utf8');
|
|
508
|
+
} catch (err) {
|
|
509
|
+
if (err?.code === 'ENOENT') {
|
|
510
|
+
return null;
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
throw err;
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
async function writePrivateTextFile(fullPath, content) {
|
|
518
|
+
await writeFileAtomically(fullPath, content, 'utf8');
|
|
519
|
+
try {
|
|
520
|
+
await fs.chmod(fullPath, 0o600);
|
|
521
|
+
} catch {
|
|
522
|
+
// Best effort only. Windows ACLs do not map cleanly to chmod.
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
function validateAuthSessionPayload(content) {
|
|
527
|
+
const payload = String(content || '');
|
|
528
|
+
if (!payload.trim()) {
|
|
529
|
+
const err = new Error('Session payload is required');
|
|
530
|
+
err.statusCode = 400;
|
|
531
|
+
throw err;
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
if (Buffer.byteLength(payload, 'utf8') > 512 * 1024) {
|
|
535
|
+
const err = new Error('Session payload is too large');
|
|
536
|
+
err.statusCode = 413;
|
|
537
|
+
throw err;
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
try {
|
|
541
|
+
JSON.parse(payload);
|
|
542
|
+
} catch {
|
|
543
|
+
const err = new Error('Session payload must be valid JSON');
|
|
544
|
+
err.statusCode = 400;
|
|
545
|
+
throw err;
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
return payload;
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
async function readStableAuthSessionPayload() {
|
|
552
|
+
const stablePath = getStableSupabaseSessionPath();
|
|
553
|
+
const stablePayload = await tryReadTextFile(stablePath);
|
|
554
|
+
if (stablePayload && stablePayload.trim()) {
|
|
555
|
+
return {
|
|
556
|
+
found: true,
|
|
557
|
+
content: stablePayload,
|
|
558
|
+
source: 'stable',
|
|
559
|
+
path: stablePath,
|
|
560
|
+
migrated: false
|
|
561
|
+
};
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
for (const legacyPath of getLegacySupabaseSessionCandidatePaths()) {
|
|
565
|
+
const legacyPayload = await tryReadTextFile(legacyPath);
|
|
566
|
+
if (!legacyPayload || !legacyPayload.trim()) {
|
|
567
|
+
continue;
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
await writePrivateTextFile(stablePath, legacyPayload);
|
|
571
|
+
return {
|
|
572
|
+
found: true,
|
|
573
|
+
content: legacyPayload,
|
|
574
|
+
source: 'legacy-workspace',
|
|
575
|
+
path: stablePath,
|
|
576
|
+
migrated: true,
|
|
577
|
+
legacyPath
|
|
578
|
+
};
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
return {
|
|
582
|
+
found: false,
|
|
583
|
+
content: null,
|
|
584
|
+
source: 'none',
|
|
585
|
+
path: stablePath,
|
|
586
|
+
migrated: false
|
|
587
|
+
};
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
async function writeStableAuthSessionPayload(content) {
|
|
591
|
+
const payload = validateAuthSessionPayload(content);
|
|
592
|
+
const stablePath = getStableSupabaseSessionPath();
|
|
593
|
+
await writePrivateTextFile(stablePath, payload);
|
|
594
|
+
return stablePath;
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
async function deleteStableAuthSessionPayload() {
|
|
598
|
+
const paths = [
|
|
599
|
+
getStableSupabaseSessionPath(),
|
|
600
|
+
...getLegacySupabaseSessionCandidatePaths()
|
|
601
|
+
];
|
|
602
|
+
|
|
603
|
+
const deleted = [];
|
|
604
|
+
for (const sessionPath of Array.from(new Set(paths.map(candidate => path.resolve(candidate))))) {
|
|
605
|
+
try {
|
|
606
|
+
await fs.rm(sessionPath, { force: true });
|
|
607
|
+
deleted.push(sessionPath);
|
|
608
|
+
} catch {
|
|
609
|
+
// Clearing auth should be best-effort across legacy mirrors.
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
return deleted;
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
function getBoardsPath(basePath = workspacePath) {
|
|
617
|
+
return path.join(getDataRoot(basePath), 'boards');
|
|
618
|
+
}
|
|
480
619
|
|
|
481
620
|
function getAssetsPath(basePath = workspacePath) {
|
|
482
621
|
return path.join(getDataRoot(basePath), 'assets');
|
|
@@ -1745,6 +1884,9 @@ const PROTECTED_BRIDGE_ROUTES = [
|
|
|
1745
1884
|
{ method: 'POST', exact: '/api/file/delete' },
|
|
1746
1885
|
{ method: 'POST', exact: '/api/file/copy' },
|
|
1747
1886
|
{ method: 'POST', exact: '/api/file/move' },
|
|
1887
|
+
{ method: 'GET', exact: '/api/auth/session' },
|
|
1888
|
+
{ method: 'POST', exact: '/api/auth/session' },
|
|
1889
|
+
{ method: 'DELETE', exact: '/api/auth/session' },
|
|
1748
1890
|
{ method: 'POST', exact: '/api/dir/create' },
|
|
1749
1891
|
{ method: 'POST', exact: '/api/dir/delete' },
|
|
1750
1892
|
{ method: 'POST', prefix: '/api/assets/' },
|
|
@@ -1869,6 +2011,66 @@ app.use((req, res, next) => {
|
|
|
1869
2011
|
requireBridgeToken(req, res, next);
|
|
1870
2012
|
});
|
|
1871
2013
|
|
|
2014
|
+
app.get('/api/auth/session', async (req, res) => {
|
|
2015
|
+
try {
|
|
2016
|
+
const result = await readStableAuthSessionPayload();
|
|
2017
|
+
if (!result.found) {
|
|
2018
|
+
return res.status(404).json({
|
|
2019
|
+
success: false,
|
|
2020
|
+
found: false
|
|
2021
|
+
});
|
|
2022
|
+
}
|
|
2023
|
+
|
|
2024
|
+
res.json({
|
|
2025
|
+
success: true,
|
|
2026
|
+
found: true,
|
|
2027
|
+
content: result.content,
|
|
2028
|
+
source: result.source,
|
|
2029
|
+
migrated: result.migrated === true
|
|
2030
|
+
});
|
|
2031
|
+
} catch (err) {
|
|
2032
|
+
logError('auth', 'failed to read persisted auth session.', err);
|
|
2033
|
+
const statusCode = Number(err?.statusCode || 500);
|
|
2034
|
+
res.status(statusCode >= 400 && statusCode < 600 ? statusCode : 500).json({
|
|
2035
|
+
success: false,
|
|
2036
|
+
error: err?.message || 'Failed to read auth session'
|
|
2037
|
+
});
|
|
2038
|
+
}
|
|
2039
|
+
});
|
|
2040
|
+
|
|
2041
|
+
app.post('/api/auth/session', async (req, res) => {
|
|
2042
|
+
try {
|
|
2043
|
+
const content = req.body?.content;
|
|
2044
|
+
await writeStableAuthSessionPayload(content);
|
|
2045
|
+
res.json({
|
|
2046
|
+
success: true
|
|
2047
|
+
});
|
|
2048
|
+
} catch (err) {
|
|
2049
|
+
logError('auth', 'failed to persist auth session.', err);
|
|
2050
|
+
const statusCode = Number(err?.statusCode || 500);
|
|
2051
|
+
res.status(statusCode >= 400 && statusCode < 600 ? statusCode : 500).json({
|
|
2052
|
+
success: false,
|
|
2053
|
+
error: err?.message || 'Failed to persist auth session'
|
|
2054
|
+
});
|
|
2055
|
+
}
|
|
2056
|
+
});
|
|
2057
|
+
|
|
2058
|
+
app.delete('/api/auth/session', async (req, res) => {
|
|
2059
|
+
try {
|
|
2060
|
+
await deleteStableAuthSessionPayload();
|
|
2061
|
+
res.json({
|
|
2062
|
+
success: true
|
|
2063
|
+
});
|
|
2064
|
+
} catch (err) {
|
|
2065
|
+
logError('auth', 'failed to clear auth session.', err);
|
|
2066
|
+
const statusCode = Number(err?.statusCode || 500);
|
|
2067
|
+
res.status(statusCode >= 400 && statusCode < 600 ? statusCode : 500).json({
|
|
2068
|
+
success: false,
|
|
2069
|
+
error: err?.message || 'Failed to clear auth session'
|
|
2070
|
+
});
|
|
2071
|
+
}
|
|
2072
|
+
});
|
|
2073
|
+
|
|
1872
2074
|
app.post('/api/local-files/register', async (req, res) => {
|
|
1873
2075
|
try {
|
|
1874
2076
|
const body = req.body || {};
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"mainAssemblyName": "MindExecution.Web",
|
|
3
3
|
"resources": {
|
|
4
|
-
"hash": "sha256-
|
|
4
|
+
"hash": "sha256-UYjWF1Jxof/7OQBXUWs4OE4sIOguU3A5k8CVb4Nnh/8=",
|
|
5
5
|
"fingerprinting": {
|
|
6
6
|
"Google.Protobuf.9h59ukbel7.dll": "Google.Protobuf.dll",
|
|
7
7
|
"Markdig.d1j7v41cl1.dll": "Markdig.dll",
|
|
@@ -123,16 +123,16 @@
|
|
|
123
123
|
"System.brmz7yk5qh.dll": "System.dll",
|
|
124
124
|
"netstandard.yvr3prsx0x.dll": "netstandard.dll",
|
|
125
125
|
"System.Private.CoreLib.c1dbswx1b2.dll": "System.Private.CoreLib.dll",
|
|
126
|
-
"MindExecution.Core.
|
|
127
|
-
"MindExecution.Kernel.
|
|
128
|
-
"MindExecution.Plugins.Admin.
|
|
129
|
-
"MindExecution.Plugins.Business.
|
|
130
|
-
"MindExecution.Plugins.Concept.
|
|
131
|
-
"MindExecution.Plugins.Directory.
|
|
132
|
-
"MindExecution.Plugins.PlanMaster.
|
|
133
|
-
"MindExecution.Plugins.YouTube.
|
|
134
|
-
"MindExecution.Shared.
|
|
135
|
-
"MindExecution.Web.
|
|
126
|
+
"MindExecution.Core.qprj2wqc9a.dll": "MindExecution.Core.dll",
|
|
127
|
+
"MindExecution.Kernel.ksznt6ppyj.dll": "MindExecution.Kernel.dll",
|
|
128
|
+
"MindExecution.Plugins.Admin.ziclnsvcvi.dll": "MindExecution.Plugins.Admin.dll",
|
|
129
|
+
"MindExecution.Plugins.Business.q32f5kgky1.dll": "MindExecution.Plugins.Business.dll",
|
|
130
|
+
"MindExecution.Plugins.Concept.vrmey2vv08.dll": "MindExecution.Plugins.Concept.dll",
|
|
131
|
+
"MindExecution.Plugins.Directory.3pet73jp0m.dll": "MindExecution.Plugins.Directory.dll",
|
|
132
|
+
"MindExecution.Plugins.PlanMaster.0pdulhmw15.dll": "MindExecution.Plugins.PlanMaster.dll",
|
|
133
|
+
"MindExecution.Plugins.YouTube.ye6w0jn4v9.dll": "MindExecution.Plugins.YouTube.dll",
|
|
134
|
+
"MindExecution.Shared.oxf5h3gtl1.dll": "MindExecution.Shared.dll",
|
|
135
|
+
"MindExecution.Web.s43m8j3bg0.dll": "MindExecution.Web.dll",
|
|
136
136
|
"dotnet.js": "dotnet.js",
|
|
137
137
|
"dotnet.native.qc8g39g30v.js": "dotnet.native.js",
|
|
138
138
|
"dotnet.native.boem75ye5i.wasm": "dotnet.native.wasm",
|
|
@@ -278,18 +278,18 @@
|
|
|
278
278
|
"System.Xml.XDocument.sn51jas17n.dll": "sha256-GNI2kFgFmPTwzuzwUn8gxK+AzGLUWRJFdg9JzIbrybQ=",
|
|
279
279
|
"System.brmz7yk5qh.dll": "sha256-CfM2miyj1KHApFmqMdLYWio3S/jrdON2pW9Xr2nTwlo=",
|
|
280
280
|
"netstandard.yvr3prsx0x.dll": "sha256-EksNn8Luo4bOWqJ6X7dIe9qG9oOqwOVzjH2xYyMNi+E=",
|
|
281
|
-
"MindExecution.Core.
|
|
282
|
-
"MindExecution.Kernel.
|
|
283
|
-
"MindExecution.Plugins.Concept.
|
|
284
|
-
"MindExecution.Plugins.PlanMaster.
|
|
285
|
-
"MindExecution.Shared.
|
|
286
|
-
"MindExecution.Web.
|
|
281
|
+
"MindExecution.Core.qprj2wqc9a.dll": "sha256-DnXZk8i9ukptBPjChSubsbWJIarYNileavZA4hihKJY=",
|
|
282
|
+
"MindExecution.Kernel.ksznt6ppyj.dll": "sha256-DAZ9Pzryh17vEhPOjVeFe+eCs/lgH5S0vxP9WFiTI2U=",
|
|
283
|
+
"MindExecution.Plugins.Concept.vrmey2vv08.dll": "sha256-y8SD/3+q7/5hBWFrizZ5w5QKJP8Nfz0NpV0XrT1eXxQ=",
|
|
284
|
+
"MindExecution.Plugins.PlanMaster.0pdulhmw15.dll": "sha256-LObinwzmz1i8etnhUMWcvdn6oZ7MSGkqfZnIcyakEFk=",
|
|
285
|
+
"MindExecution.Shared.oxf5h3gtl1.dll": "sha256-7Lze2YO8XmpwxtjLCUp/J9HND7AyKJyORksP8+XAua0=",
|
|
286
|
+
"MindExecution.Web.s43m8j3bg0.dll": "sha256-pCKvIt9SzRGSvNRSw/7lk7eG3RyzGrTZNolf1tx5T6A="
|
|
287
287
|
},
|
|
288
288
|
"lazyAssembly": {
|
|
289
|
-
"MindExecution.Plugins.Admin.
|
|
290
|
-
"MindExecution.Plugins.Business.
|
|
291
|
-
"MindExecution.Plugins.Directory.
|
|
292
|
-
"MindExecution.Plugins.YouTube.
|
|
289
|
+
"MindExecution.Plugins.Admin.ziclnsvcvi.dll": "sha256-VXbkR7uhooOS62ea02JNcfj2EpKxtIF4ZYRSvdO74kM=",
|
|
290
|
+
"MindExecution.Plugins.Business.q32f5kgky1.dll": "sha256-Zq3jwQKoz28lRtaqbPJgZenoBwrknjYBccYJhLOhYd4=",
|
|
291
|
+
"MindExecution.Plugins.Directory.3pet73jp0m.dll": "sha256-p7KSnHrHR4xFgP4WwKX0edQZgAhSsWqOcNRq4/oiH1I=",
|
|
292
|
+
"MindExecution.Plugins.YouTube.ye6w0jn4v9.dll": "sha256-eoQHQy2IbcBhJtbRR5HShNdMp7DJ4xOsFdwryQNoQrI="
|
|
293
293
|
}
|
|
294
294
|
},
|
|
295
295
|
"cacheBootResources": true,
|
package/wwwroot/index.html
CHANGED
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
<title>MindExec | Run your ideas as AI task graphs</title>
|
|
8
8
|
<meta name="description" content="MindExec is an AI execution canvas for solo builders, researchers, developers, and creators. Start with free browser tools, then move serious work into saved MindCanvas projects." />
|
|
9
9
|
<base href="/" />
|
|
10
|
-
<link rel="stylesheet" href="_content/MindExecution.Shared/css/app.css?v=20260615-
|
|
11
|
-
<link rel="stylesheet" href="_content/MindExecution.Shared/css/mind-map-overrides.css?v=20260615-
|
|
10
|
+
<link rel="stylesheet" href="_content/MindExecution.Shared/css/app.css?v=20260615-auth-session-v553" />
|
|
11
|
+
<link rel="stylesheet" href="_content/MindExecution.Shared/css/mind-map-overrides.css?v=20260615-auth-session-v553" />
|
|
12
12
|
<!-- ?쇄뼹??Font Awesome (local) ?쇄뼹??-->
|
|
13
13
|
<link rel="stylesheet" href="_content/MindExecution.Shared/lib/font-awesome/css/all.min.css" />
|
|
14
14
|
<!-- ?꿎뼯??-->
|
|
@@ -579,7 +579,7 @@
|
|
|
579
579
|
}
|
|
580
580
|
|
|
581
581
|
const base = '_content/MindExecution.Shared/js/';
|
|
582
|
-
const scriptVersion = '20260615-
|
|
582
|
+
const scriptVersion = '20260615-auth-session-v553';
|
|
583
583
|
const scriptUrl = (script) => `${base}${script}?v=${scriptVersion}`;
|
|
584
584
|
console.log(`[Script Loader] Shared JS version: ${scriptVersion}`);
|
|
585
585
|
const criticalScripts = [
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
self.assetsManifest = {
|
|
2
|
-
"version": "
|
|
2
|
+
"version": "mPvmdx5y",
|
|
3
3
|
"assets": [
|
|
4
4
|
{
|
|
5
5
|
"hash": "sha256-+CSYMcqLNTsq3VnH11jgYyOCCdxvHzL74CBmo4sCmMU=",
|
|
@@ -410,44 +410,44 @@
|
|
|
410
410
|
"url": "_framework/MimeMapping.og9ys58ylm.dll"
|
|
411
411
|
},
|
|
412
412
|
{
|
|
413
|
-
"hash": "sha256-
|
|
414
|
-
"url": "_framework/MindExecution.Core.
|
|
413
|
+
"hash": "sha256-DnXZk8i9ukptBPjChSubsbWJIarYNileavZA4hihKJY=",
|
|
414
|
+
"url": "_framework/MindExecution.Core.qprj2wqc9a.dll"
|
|
415
415
|
},
|
|
416
416
|
{
|
|
417
|
-
"hash": "sha256-
|
|
418
|
-
"url": "_framework/MindExecution.Kernel.
|
|
417
|
+
"hash": "sha256-DAZ9Pzryh17vEhPOjVeFe+eCs/lgH5S0vxP9WFiTI2U=",
|
|
418
|
+
"url": "_framework/MindExecution.Kernel.ksznt6ppyj.dll"
|
|
419
419
|
},
|
|
420
420
|
{
|
|
421
|
-
"hash": "sha256-
|
|
422
|
-
"url": "_framework/MindExecution.Plugins.Admin.
|
|
421
|
+
"hash": "sha256-VXbkR7uhooOS62ea02JNcfj2EpKxtIF4ZYRSvdO74kM=",
|
|
422
|
+
"url": "_framework/MindExecution.Plugins.Admin.ziclnsvcvi.dll"
|
|
423
423
|
},
|
|
424
424
|
{
|
|
425
|
-
"hash": "sha256-
|
|
426
|
-
"url": "_framework/MindExecution.Plugins.Business.
|
|
425
|
+
"hash": "sha256-Zq3jwQKoz28lRtaqbPJgZenoBwrknjYBccYJhLOhYd4=",
|
|
426
|
+
"url": "_framework/MindExecution.Plugins.Business.q32f5kgky1.dll"
|
|
427
427
|
},
|
|
428
428
|
{
|
|
429
|
-
"hash": "sha256-
|
|
430
|
-
"url": "_framework/MindExecution.Plugins.Concept.
|
|
429
|
+
"hash": "sha256-y8SD/3+q7/5hBWFrizZ5w5QKJP8Nfz0NpV0XrT1eXxQ=",
|
|
430
|
+
"url": "_framework/MindExecution.Plugins.Concept.vrmey2vv08.dll"
|
|
431
431
|
},
|
|
432
432
|
{
|
|
433
|
-
"hash": "sha256-
|
|
434
|
-
"url": "_framework/MindExecution.Plugins.Directory.
|
|
433
|
+
"hash": "sha256-p7KSnHrHR4xFgP4WwKX0edQZgAhSsWqOcNRq4/oiH1I=",
|
|
434
|
+
"url": "_framework/MindExecution.Plugins.Directory.3pet73jp0m.dll"
|
|
435
435
|
},
|
|
436
436
|
{
|
|
437
|
-
"hash": "sha256-
|
|
438
|
-
"url": "_framework/MindExecution.Plugins.PlanMaster.
|
|
437
|
+
"hash": "sha256-LObinwzmz1i8etnhUMWcvdn6oZ7MSGkqfZnIcyakEFk=",
|
|
438
|
+
"url": "_framework/MindExecution.Plugins.PlanMaster.0pdulhmw15.dll"
|
|
439
439
|
},
|
|
440
440
|
{
|
|
441
|
-
"hash": "sha256-
|
|
442
|
-
"url": "_framework/MindExecution.Plugins.YouTube.
|
|
441
|
+
"hash": "sha256-eoQHQy2IbcBhJtbRR5HShNdMp7DJ4xOsFdwryQNoQrI=",
|
|
442
|
+
"url": "_framework/MindExecution.Plugins.YouTube.ye6w0jn4v9.dll"
|
|
443
443
|
},
|
|
444
444
|
{
|
|
445
|
-
"hash": "sha256-
|
|
446
|
-
"url": "_framework/MindExecution.Shared.
|
|
445
|
+
"hash": "sha256-7Lze2YO8XmpwxtjLCUp/J9HND7AyKJyORksP8+XAua0=",
|
|
446
|
+
"url": "_framework/MindExecution.Shared.oxf5h3gtl1.dll"
|
|
447
447
|
},
|
|
448
448
|
{
|
|
449
|
-
"hash": "sha256-
|
|
450
|
-
"url": "_framework/MindExecution.Web.
|
|
449
|
+
"hash": "sha256-pCKvIt9SzRGSvNRSw/7lk7eG3RyzGrTZNolf1tx5T6A=",
|
|
450
|
+
"url": "_framework/MindExecution.Web.s43m8j3bg0.dll"
|
|
451
451
|
},
|
|
452
452
|
{
|
|
453
453
|
"hash": "sha256-IsZJ91/OW+fHzNqIgEc7Y072ns8z9dGritiSyvR9Wgc=",
|
|
@@ -770,7 +770,7 @@
|
|
|
770
770
|
"url": "_framework/Websocket.Client.vapounvmnl.dll"
|
|
771
771
|
},
|
|
772
772
|
{
|
|
773
|
-
"hash": "sha256-
|
|
773
|
+
"hash": "sha256-nFSI4H6aGg61G8/I7AXIvRFAlfAVhpij+EjRsJ4tctg=",
|
|
774
774
|
"url": "_framework/blazor.boot.json"
|
|
775
775
|
},
|
|
776
776
|
{
|
|
@@ -834,7 +834,7 @@
|
|
|
834
834
|
"url": "image-manifest.json"
|
|
835
835
|
},
|
|
836
836
|
{
|
|
837
|
-
"hash": "sha256-
|
|
837
|
+
"hash": "sha256-voojFCn8RinDrshRS7nUvpusiYKr/QFSZS0h4auGgOM=",
|
|
838
838
|
"url": "index.html"
|
|
839
839
|
},
|
|
840
840
|
{
|
|
Binary file
|
|
Binary file
|