@mindexec/cli 0.2.464 → 0.2.466

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 (28) hide show
  1. package/README.md +1 -0
  2. package/codex-runtime.js +521 -15
  3. package/package.json +35 -33
  4. package/remote-fast/osx-arm64/mindexec-remote-fast.dll +0 -0
  5. package/remote-fast/osx-x64/mindexec-remote-fast.dll +0 -0
  6. package/remote-fast/win-x64/mindexec-remote-fast.dll +0 -0
  7. package/scripts/board-render-ownership-smoke.mjs +85 -0
  8. package/scripts/codex-sdk-image-runtime-smoke.mjs +121 -0
  9. package/server.js +17 -0
  10. package/wwwroot/_content/MindExecution.Shared/js/mind-map-board-render-ownership.js +81 -0
  11. package/wwwroot/_content/MindExecution.Shared/js/mind-map-core.js +110 -46
  12. package/wwwroot/_content/MindExecution.Shared/js/mind-map-render-plan.js +24 -1
  13. package/wwwroot/_framework/MindExecution.Core.psrddqi3mi.dll +0 -0
  14. package/wwwroot/_framework/{MindExecution.Kernel.s20qz1vf5c.dll → MindExecution.Kernel.emus4f6jja.dll} +0 -0
  15. package/wwwroot/_framework/{MindExecution.Plugins.Admin.th7yn9x0f6.dll → MindExecution.Plugins.Admin.q3gz9b4wp8.dll} +0 -0
  16. package/wwwroot/_framework/{MindExecution.Plugins.Business.5oxedy1s9k.dll → MindExecution.Plugins.Business.dr4m9mbnc5.dll} +0 -0
  17. package/wwwroot/_framework/{MindExecution.Plugins.Concept.3687y3dptp.dll → MindExecution.Plugins.Concept.xzrzi61p7e.dll} +0 -0
  18. package/wwwroot/_framework/{MindExecution.Plugins.Directory.9nttshvjo8.dll → MindExecution.Plugins.Directory.hcbtf3n8w7.dll} +0 -0
  19. package/wwwroot/_framework/{MindExecution.Plugins.PlanMaster.poo6g7knqo.dll → MindExecution.Plugins.PlanMaster.1w09epz56f.dll} +0 -0
  20. package/wwwroot/_framework/{MindExecution.Plugins.YouTube.fyved6pyst.dll → MindExecution.Plugins.YouTube.7vjbulgfo8.dll} +0 -0
  21. package/wwwroot/_framework/{MindExecution.Shared.pldp11njra.dll → MindExecution.Shared.zj2n1axexl.dll} +0 -0
  22. package/wwwroot/_framework/MindExecution.Web.z1np8j1qu6.dll +0 -0
  23. package/wwwroot/_framework/blazor.boot.json +21 -21
  24. package/wwwroot/index.html +2 -1
  25. package/wwwroot/service-worker-assets.js +29 -25
  26. package/wwwroot/service-worker.js +1 -1
  27. package/wwwroot/_framework/MindExecution.Core.8qo2jd7tuo.dll +0 -0
  28. package/wwwroot/_framework/MindExecution.Web.vldms1qzyf.dll +0 -0
package/package.json CHANGED
@@ -1,15 +1,15 @@
1
1
  {
2
2
  "name": "@mindexec/cli",
3
- "version": "0.2.464",
3
+ "version": "0.2.466",
4
4
  "description": "MindExec local runtime and bridge CLI",
5
5
  "main": "server.js",
6
6
  "type": "module",
7
7
  "files": [
8
8
  "start-bridge.bat",
9
9
  "start-bridge.sh",
10
- "launch-bridge.cjs",
11
- "desktop-workspace-state.cjs",
12
- "server.js",
10
+ "launch-bridge.cjs",
11
+ "desktop-workspace-state.cjs",
12
+ "server.js",
13
13
  "remote-hub.js",
14
14
  "lzo1x.js",
15
15
  "mode4-atlas.js",
@@ -27,17 +27,19 @@
27
27
  "scripts": {
28
28
  "start": "node launch-bridge.cjs",
29
29
  "dev": "node launch-bridge.cjs --watch",
30
- "desktop:start": "electron electron/main.cjs",
31
- "desktop:build:win": "electron-builder --win --x64 --publish never",
32
- "desktop:inspect:update:dev": "node scripts/publish-mindexec-desktop-updates.mjs --channel dev --platform windows-x64 --dir ../artifacts/electron --allow-unsigned",
33
- "desktop:publish:update:dev": "node scripts/publish-mindexec-desktop-updates.mjs --channel dev --platform windows-x64 --dir ../artifacts/electron --allow-unsigned --publish",
34
- "desktop:deploy:update-worker": "node ../r2-auth-proxy/node_modules/wrangler/wrangler-dist/cli.js deploy --config ../workers/mindexec-desktop-updates/wrangler.jsonc",
35
- "desktop:check:update-worker": "node ../r2-auth-proxy/node_modules/wrangler/wrangler-dist/cli.js deploy --dry-run --config ../workers/mindexec-desktop-updates/wrangler.jsonc",
36
- "test:desktop:update": "node --test electron/update-manager-smoke.mjs electron/recurring-update-owner-smoke.mjs scripts/desktop-update-worker-smoke.mjs scripts/desktop-update-publisher-smoke.mjs",
37
- "test:desktop": "node electron/source-smoke.mjs && node scripts/desktop-workspace-state-smoke.mjs && npm run test:desktop:update",
30
+ "desktop:start": "electron electron/main.cjs",
31
+ "desktop:build:win": "electron-builder --win --x64 --publish never",
32
+ "desktop:inspect:update:dev": "node scripts/publish-mindexec-desktop-updates.mjs --channel dev --platform windows-x64 --dir ../artifacts/electron --allow-unsigned",
33
+ "desktop:publish:update:dev": "node scripts/publish-mindexec-desktop-updates.mjs --channel dev --platform windows-x64 --dir ../artifacts/electron --allow-unsigned --publish",
34
+ "desktop:deploy:update-worker": "node ../r2-auth-proxy/node_modules/wrangler/wrangler-dist/cli.js deploy --config ../workers/mindexec-desktop-updates/wrangler.jsonc",
35
+ "desktop:check:update-worker": "node ../r2-auth-proxy/node_modules/wrangler/wrangler-dist/cli.js deploy --dry-run --config ../workers/mindexec-desktop-updates/wrangler.jsonc",
36
+ "test:desktop:update": "node --test electron/update-manager-smoke.mjs electron/recurring-update-owner-smoke.mjs scripts/desktop-update-worker-smoke.mjs scripts/desktop-update-publisher-smoke.mjs",
37
+ "test:desktop": "node electron/source-smoke.mjs && node scripts/desktop-workspace-state-smoke.mjs && npm run test:desktop:update",
38
38
  "test:desktop:win": "node electron/windows-package-smoke.mjs",
39
- "test:syntax": "node --check server.js && node --check remote-hub.js && node --check lzo1x.js && node --check mode4-atlas.js && node --check mode4-atlas-worker.js && node --check codex-runtime.js && node --check codex-model-catalog.js && node --check launch-bridge.cjs && node --check port-guard.cjs && node --check desktop-workspace-state.cjs && node --check electron/main.cjs && node --check electron/preload.cjs && node --check electron/update-manager.cjs && node --check electron/update-feed-resolver.cjs && node --check electron/recurring-update-owner.cjs && node --check electron/source-smoke.mjs && node --check electron/windows-package-smoke.mjs && node --check electron/update-manager-smoke.mjs && node --check electron/recurring-update-owner-smoke.mjs && node --check scripts/desktop-workspace-state-smoke.mjs && node --check scripts/desktop-update-worker-smoke.mjs && node --check scripts/desktop-update-publisher-smoke.mjs && node --check scripts/publish-mindexec-desktop-updates.mjs && node --check ../workers/mindexec-desktop-updates/src/index.mjs && node --check scripts/setup-tree-sitter-grammars.mjs && node --check scripts/npm-fresh-install-smoke.mjs && node --check scripts/auth-session-smoke.mjs && node --check scripts/codex-model-catalog-smoke.mjs && node --check scripts/codex-sdk-runtime-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",
39
+ "test:syntax": "node --check server.js && node --check remote-hub.js && node --check lzo1x.js && node --check mode4-atlas.js && node --check mode4-atlas-worker.js && node --check codex-runtime.js && node --check codex-model-catalog.js && node --check launch-bridge.cjs && node --check port-guard.cjs && node --check desktop-workspace-state.cjs && node --check electron/main.cjs && node --check electron/preload.cjs && node --check electron/update-manager.cjs && node --check electron/update-feed-resolver.cjs && node --check electron/recurring-update-owner.cjs && node --check electron/source-smoke.mjs && node --check electron/windows-package-smoke.mjs && node --check electron/update-manager-smoke.mjs && node --check electron/recurring-update-owner-smoke.mjs && node --check scripts/desktop-workspace-state-smoke.mjs && node --check scripts/desktop-update-worker-smoke.mjs && node --check scripts/desktop-update-publisher-smoke.mjs && node --check scripts/board-render-ownership-smoke.mjs && node --check ../workers/mindexec-desktop-updates/src/index.mjs && node --check scripts/setup-tree-sitter-grammars.mjs && node --check scripts/npm-fresh-install-smoke.mjs && node --check scripts/auth-session-smoke.mjs && node --check scripts/codex-model-catalog-smoke.mjs && node --check scripts/codex-sdk-runtime-smoke.mjs && node --check scripts/codex-sdk-image-runtime-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",
40
+ "test:canvas:board-owner": "node scripts/board-render-ownership-smoke.mjs",
40
41
  "test:codex-sdk": "node scripts/codex-sdk-runtime-smoke.mjs",
42
+ "test:codex-sdk:image": "node scripts/codex-sdk-image-runtime-smoke.mjs",
41
43
  "test:codex-sdk:live": "node scripts/codex-sdk-runtime-smoke.mjs --live",
42
44
  "test:codex-sdk:live-tools": "node scripts/codex-sdk-runtime-smoke.mjs --live-tools",
43
45
  "test:codex-model-catalog": "node scripts/codex-model-catalog-smoke.mjs",
@@ -83,17 +85,17 @@
83
85
  "cors": "^2.8.5",
84
86
  "express": "^4.18.2",
85
87
  "ffmpeg-static": "^5.3.0",
86
- "multer": "^2.2.0",
87
- "electron-updater": "^6.8.9",
88
- "playwright-core": "^1.53.0",
88
+ "multer": "^2.2.0",
89
+ "electron-updater": "^6.8.9",
90
+ "playwright-core": "^1.53.0",
89
91
  "sharp": "^0.35.3",
90
92
  "web-tree-sitter": "^0.22.6",
91
93
  "ws": "^8.16.0"
92
94
  },
93
- "overrides": {
94
- "body-parser": "1.20.6",
95
- "js-yaml": "4.3.1"
96
- },
95
+ "overrides": {
96
+ "body-parser": "1.20.6",
97
+ "js-yaml": "4.3.1"
98
+ },
97
99
  "bin": {
98
100
  "mindexec": "launch-bridge.cjs",
99
101
  "mind-bridge": "launch-bridge.cjs"
@@ -108,9 +110,9 @@
108
110
  "productName": "MindExec",
109
111
  "copyright": "Copyright © 2026 lovecrdm77",
110
112
  "asar": false,
111
- "extraMetadata": {
112
- "main": "electron/main.cjs",
113
- "desktopUpdateChannel": "dev"
113
+ "extraMetadata": {
114
+ "main": "electron/main.cjs",
115
+ "desktopUpdateChannel": "dev"
114
116
  },
115
117
  "directories": {
116
118
  "output": "../artifacts/electron"
@@ -119,7 +121,7 @@
119
121
  "*.js",
120
122
  "*.cjs",
121
123
  "*.json",
122
- "electron/**/*",
124
+ "electron/**/*",
123
125
  "remote-fast/**/*",
124
126
  "scripts/**/*",
125
127
  "tree-sitter-grammars/**/*",
@@ -144,8 +146,8 @@
144
146
  }
145
147
  ]
146
148
  },
147
- "nsis": {
148
- "artifactName": "MindExec-${version}-dev-${arch}.${ext}",
149
+ "nsis": {
150
+ "artifactName": "MindExec-${version}-dev-${arch}.${ext}",
149
151
  "oneClick": false,
150
152
  "perMachine": false,
151
153
  "allowToChangeInstallationDirectory": true,
@@ -153,12 +155,12 @@
153
155
  "createStartMenuShortcut": true,
154
156
  "shortcutName": "MindExec"
155
157
  },
156
- "portable": {
157
- "artifactName": "MindExec-Portable-${version}-${arch}.${ext}"
158
- },
159
- "publish": {
160
- "provider": "generic",
161
- "url": "https://mindexec.lovecrdm.workers.dev/dev/windows/x64"
162
- }
158
+ "portable": {
159
+ "artifactName": "MindExec-Portable-${version}-${arch}.${ext}"
160
+ },
161
+ "publish": {
162
+ "provider": "generic",
163
+ "url": "https://mindexec.lovecrdm.workers.dev/dev/windows/x64"
164
+ }
163
165
  }
164
166
  }
@@ -0,0 +1,85 @@
1
+ import assert from 'node:assert/strict';
2
+ import fs from 'node:fs';
3
+ import path from 'node:path';
4
+ import vm from 'node:vm';
5
+ import { fileURLToPath } from 'node:url';
6
+
7
+ const scriptDir = path.dirname(fileURLToPath(import.meta.url));
8
+ const sourcePath = path.resolve(
9
+ scriptDir,
10
+ '..',
11
+ '..',
12
+ 'MindExecution.Shared',
13
+ 'wwwroot',
14
+ 'js',
15
+ 'mind-map-board-render-ownership.js');
16
+ const source = fs.readFileSync(sourcePath, 'utf8');
17
+ const traces = [];
18
+ const window = {
19
+ MindCanvasTrace: { emit: (type, data) => traces.push({ type, data }) },
20
+ MindCanvasBuildInfo: { registerPart: () => { } }
21
+ };
22
+
23
+ vm.runInNewContext(source, { window, Map, Object, Number, String, Math });
24
+
25
+ const makeMesh = (count = 8) => ({
26
+ visible: true,
27
+ geometry: {
28
+ instanceCount: count,
29
+ drawRange: { start: 0, count: count },
30
+ setDrawRange(start, nextCount) {
31
+ this.drawRange = { start, count: nextCount };
32
+ }
33
+ }
34
+ });
35
+ const renderer = {
36
+ resetCalls: 0,
37
+ resetState() { this.resetCalls++; },
38
+ pendingNodes: new Map([['stale-node', {}]]),
39
+ instancedHaloMesh: makeMesh(),
40
+ instancedMesh: makeMesh(),
41
+ instancedLineMesh: makeMesh(),
42
+ instancedBorderLineMesh: makeMesh(),
43
+ instancedConsoleMesh: makeMesh(),
44
+ instancedImageMesh: makeMesh(),
45
+ requestResidentPatch(reason) { this.patchReason = reason; }
46
+ };
47
+ const module = { _forceUpdateFrames: 0 };
48
+
49
+ assert.equal(window.MindMapBoardRenderOwnership.retireResidentBoard(renderer, module, {
50
+ fromBoardId: 'BOARD-B',
51
+ toBoardId: 'BOARD-A'
52
+ }), true);
53
+ assert.equal(renderer.resetCalls, 1);
54
+ assert.equal(renderer.pendingNodes.size, 0);
55
+ assert.equal(renderer._activeBoardRenderId, 'board-a');
56
+ assert.equal(renderer._residentBuilt, false);
57
+ assert.equal(renderer._residentBuildPhase, 'board-switch');
58
+ for (const mesh of [
59
+ renderer.instancedHaloMesh,
60
+ renderer.instancedMesh,
61
+ renderer.instancedLineMesh,
62
+ renderer.instancedBorderLineMesh,
63
+ renderer.instancedConsoleMesh,
64
+ renderer.instancedImageMesh
65
+ ]) {
66
+ assert.equal(mesh.visible, false);
67
+ assert.equal(mesh.geometry.instanceCount, 0);
68
+ }
69
+ assert.equal(renderer.instancedBorderLineMesh.geometry.drawRange.count, 0);
70
+ assert.equal(traces.at(-1)?.type, 'board.resident.retired');
71
+
72
+ const lineDataCache = new Map([['node-a', [1, 2, 3]]]);
73
+ assert.equal(window.MindMapBoardRenderOwnership.prepareCachedBoard(renderer, module, {
74
+ boardId: 'BOARD-A',
75
+ lineDataCache
76
+ }), true);
77
+ assert.equal(renderer.lineDataCache, lineDataCache);
78
+ assert.equal(renderer.patchReason, 'board-reload');
79
+
80
+ console.log(JSON.stringify({
81
+ ok: true,
82
+ retiredResidentCount: 0,
83
+ activeBoardRenderId: renderer._activeBoardRenderId,
84
+ patchReason: renderer.patchReason
85
+ }));
@@ -0,0 +1,121 @@
1
+ import assert from 'node:assert/strict';
2
+ import { promises as fs } from 'node:fs';
3
+ import os from 'node:os';
4
+ import path from 'node:path';
5
+ import { fileURLToPath } from 'node:url';
6
+ import { createCodexRuntime } from '../codex-runtime.js';
7
+
8
+ const scriptDir = path.dirname(fileURLToPath(import.meta.url));
9
+ const packageRoot = path.resolve(scriptDir, '..');
10
+ const workspaceRoot = path.resolve(packageRoot, '..');
11
+ const runtimeHome = await fs.mkdtemp(path.join(os.tmpdir(), 'mindexec-codex-sdk-image-'));
12
+ const tinyPngBase64 = 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/x8AAwMCAO+jX8kAAAAASUVORK5CYII=';
13
+
14
+ function imageEvents() {
15
+ return (async function* generateEvents() {
16
+ yield { type: 'thread.started', thread_id: 'thread-image-smoke' };
17
+ yield {
18
+ type: 'event_msg',
19
+ payload: {
20
+ type: 'image_generation_end',
21
+ result: `data:image/png;base64,${tinyPngBase64}`
22
+ }
23
+ };
24
+ yield { type: 'turn.completed' };
25
+ })();
26
+ }
27
+
28
+ function createFakeSdk(runStreamed, captures) {
29
+ return {
30
+ Codex: class FakeCodex {
31
+ constructor(options) {
32
+ captures.codexOptions.push(options);
33
+ }
34
+
35
+ startThread(options) {
36
+ captures.threadOptions.push(options);
37
+ return {
38
+ runStreamed: async input => {
39
+ captures.inputs.push(input);
40
+ return { events: runStreamed() };
41
+ }
42
+ };
43
+ }
44
+ }
45
+ };
46
+ }
47
+
48
+ function createRuntime(fakeSdk, loginCodex) {
49
+ return createCodexRuntime({
50
+ packageRoot,
51
+ resolveWorkingDirectory: async () => workspaceRoot,
52
+ getCurrentRuntime: () => ({}),
53
+ getModelCatalog: async () => ({ models: [], source: 'smoke', updatedAt: new Date().toISOString() }),
54
+ loadCodexSdk: async () => fakeSdk,
55
+ ensureCodexRuntimeHome: async () => {
56
+ await fs.mkdir(path.join(runtimeHome, 'generated_images'), { recursive: true });
57
+ return runtimeHome;
58
+ },
59
+ buildCodexChildEnv: () => ({ CODEX_HOME: runtimeHome }),
60
+ loginCodex,
61
+ log: () => {}
62
+ });
63
+ }
64
+
65
+ try {
66
+ const captures = { codexOptions: [], threadOptions: [], inputs: [] };
67
+ const runtime = createRuntime(createFakeSdk(imageEvents, captures), async () => {
68
+ throw new Error('Login must not run for an authenticated image request.');
69
+ });
70
+ const generated = await runtime.runImage({
71
+ prompt: 'Create a blue product icon.',
72
+ model: 'gpt-5.5',
73
+ size: '1024x1024',
74
+ quality: 'high',
75
+ referenceImages: [{ base64: tinyPngBase64, mimeType: 'image/png', fileName: 'source.png' }]
76
+ });
77
+
78
+ assert.equal(generated.success, true, generated.error);
79
+ assert.equal(generated.providerKind, 'TypeScriptSdk');
80
+ assert.equal(generated.imageBase64, tinyPngBase64);
81
+ assert.equal(generated.mimeType, 'image/png');
82
+ assert.equal(captures.codexOptions[0].config.features.image_generation, true);
83
+ assert.equal(captures.threadOptions[0].sandboxMode, 'read-only');
84
+ assert.equal(captures.inputs[0][0].type, 'text');
85
+ assert.equal(captures.inputs[0][1].type, 'local_image');
86
+ assert.equal(await fs.stat(captures.inputs[0][1].path).then(() => true).catch(() => false), false);
87
+
88
+ let attempts = 0;
89
+ let loginCount = 0;
90
+ const authCaptures = { codexOptions: [], threadOptions: [], inputs: [] };
91
+ const authSdk = createFakeSdk(() => {
92
+ attempts += 1;
93
+ if (attempts === 1) {
94
+ return (async function* invalidAuth() {
95
+ throw new Error('401 Unauthorized: invalid_refresh_token. Please log out and sign in again.');
96
+ })();
97
+ }
98
+ return imageEvents();
99
+ }, authCaptures);
100
+ const authRuntime = createRuntime(authSdk, async () => {
101
+ loginCount += 1;
102
+ return { success: true, exitCode: 0 };
103
+ });
104
+ const retried = await authRuntime.runImage({ prompt: 'Create one test image.' });
105
+
106
+ assert.equal(loginCount, 1);
107
+ assert.equal(attempts, 2);
108
+ assert.equal(retried.success, true, retried.error);
109
+ assert.equal(retried.loginOpened, true);
110
+ assert.equal(retried.authenticationRequired, false);
111
+ assert.equal(retried.providerKind, 'TypeScriptSdk');
112
+
113
+ console.log(JSON.stringify({
114
+ ok: true,
115
+ providerKind: generated.providerKind,
116
+ referenceAttachment: true,
117
+ browserLoginRetry: true
118
+ }));
119
+ } finally {
120
+ await fs.rm(runtimeHome, { recursive: true, force: true });
121
+ }
package/server.js CHANGED
@@ -13022,6 +13022,23 @@ app.post('/api/codex/thread/run', async (req, res) => {
13022
13022
  }
13023
13023
  });
13024
13024
 
13025
+ app.post('/api/codex/image/run', async (req, res) => {
13026
+ try {
13027
+ res.json(await getCodexRuntime().runImage(req.body || {}));
13028
+ } catch (err) {
13029
+ console.error('[Codex/ImageRun] Error:', err);
13030
+ res.status(err.statusCode || 500).json({
13031
+ success: false,
13032
+ providerKind: 'Unavailable',
13033
+ imageBase64: '',
13034
+ mimeType: '',
13035
+ error: err?.message || String(err),
13036
+ authenticationRequired: false,
13037
+ loginOpened: false
13038
+ });
13039
+ }
13040
+ });
13041
+
13025
13042
  app.post('/api/codex/thread/resume', async (req, res) => {
13026
13043
  try {
13027
13044
  res.json(await getCodexRuntime().resumeThread(req.body || {}));
@@ -0,0 +1,81 @@
1
+ (function () {
2
+ 'use strict';
3
+
4
+ const BUILD_ID = '20260819-board-render-owner-v1';
5
+
6
+ function normalizeBoardId(value) {
7
+ return String(value || '').trim().toLowerCase();
8
+ }
9
+
10
+ function clearResidentGeometry(mesh, useDrawRange = false) {
11
+ if (!mesh) return;
12
+
13
+ mesh.visible = false;
14
+ const geometry = mesh.geometry;
15
+ if (!geometry) return;
16
+
17
+ if ('instanceCount' in geometry) {
18
+ geometry.instanceCount = 0;
19
+ }
20
+ if (useDrawRange && typeof geometry.setDrawRange === 'function') {
21
+ geometry.setDrawRange(0, 0);
22
+ }
23
+ }
24
+
25
+ function retireResidentBoard(renderer, module, details = {}) {
26
+ if (!renderer) return false;
27
+
28
+ renderer.resetState?.();
29
+ renderer.pendingNodes?.clear?.();
30
+
31
+ clearResidentGeometry(renderer.instancedHaloMesh);
32
+ clearResidentGeometry(renderer.instancedMesh);
33
+ clearResidentGeometry(renderer.instancedLineMesh);
34
+ clearResidentGeometry(renderer.instancedBorderLineMesh, true);
35
+ clearResidentGeometry(renderer.instancedConsoleMesh);
36
+ clearResidentGeometry(renderer.instancedImageMesh);
37
+
38
+ renderer._activeBoardRenderId = normalizeBoardId(details.toBoardId);
39
+ renderer._boardRenderEpoch = Math.max(0, Number(renderer._boardRenderEpoch || 0)) + 1;
40
+ renderer._residentBuilt = false;
41
+ renderer._residentBuildPhase = 'board-switch';
42
+
43
+ if (module) {
44
+ module._forceUpdateFrames = Math.max(Number(module._forceUpdateFrames || 0), 2);
45
+ }
46
+
47
+ window.MindCanvasTrace?.emit?.('board.resident.retired', {
48
+ fromBoardId: details.fromBoardId || null,
49
+ toBoardId: details.toBoardId || null,
50
+ reason: details.reason || 'board-switch',
51
+ epoch: renderer._boardRenderEpoch
52
+ });
53
+ return true;
54
+ }
55
+
56
+ function prepareCachedBoard(renderer, module, details = {}) {
57
+ if (!renderer) return false;
58
+
59
+ const boardId = normalizeBoardId(details.boardId);
60
+ renderer._activeBoardRenderId = boardId;
61
+ if (details.lineDataCache instanceof Map) {
62
+ renderer.lineDataCache = details.lineDataCache;
63
+ }
64
+ renderer.requestResidentPatch?.('board-reload');
65
+
66
+ if (module) {
67
+ module._forceUpdateFrames = Math.max(Number(module._forceUpdateFrames || 0), 2);
68
+ }
69
+ return true;
70
+ }
71
+
72
+ window.MindMapBoardRenderOwnership = Object.freeze({
73
+ BUILD_ID,
74
+ normalizeBoardId,
75
+ retireResidentBoard,
76
+ prepareCachedBoard
77
+ });
78
+ window.MindCanvasBuildInfo?.registerPart?.('boardRenderOwnership', BUILD_ID, {
79
+ file: 'mind-map-board-render-ownership.js'
80
+ });
81
+ })();