@mindexec/cli 0.2.483 → 0.2.494
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/codex-runtime.js +6 -2
- package/electron/main.cjs +56 -32
- package/electron/preload.cjs +178 -0
- package/electron/source-smoke.mjs +14 -1
- package/electron/windows-package-smoke.mjs +16 -0
- package/package.json +11 -10
- package/remote-fast/osx-arm64/mindexec-remote-fast.dll +0 -0
- package/remote-fast/osx-x64/mindexec-remote-fast.dll +0 -0
- package/remote-fast/win-x64/mindexec-remote-fast.dll +0 -0
- package/wwwroot/_content/MindExecution.Shared/css/app.css +1 -1
- package/wwwroot/_content/MindExecution.Shared/js/canvas-chat-task-switch.js +122 -0
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-css3d-manager.js +161 -16
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-interactions.js +68 -2
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-lod-plan-worker.js +44 -8
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-logic-workers.js +823 -111
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-native-core-bridge.js +399 -0
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-node-search-worker.js +53 -10
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-visibility-worker.js +71 -11
- package/wwwroot/_content/MindExecution.Shared/native-core/mindexec-core-simd.js +18 -0
- package/wwwroot/_content/MindExecution.Shared/native-core/mindexec-core-simd.wasm +0 -0
- package/wwwroot/_content/MindExecution.Shared/native-core/mindexec-core.js +18 -0
- package/wwwroot/_content/MindExecution.Shared/native-core/mindexec-core.wasm +0 -0
- package/wwwroot/_content/MindExecution.Shared/native-core/mindexec-native-core-adapter.js +566 -0
- package/wwwroot/_content/MindExecution.Shared/native-core/mindexec-native-core-worker.js +89 -0
- package/wwwroot/_content/MindExecution.Shared/native-core/native-core-manifest.json +59 -0
- package/wwwroot/_framework/BenchmarkUtils.ytz7pn9azy.dll +0 -0
- package/wwwroot/_framework/Edgar.9yqq548b45.dll +0 -0
- package/wwwroot/_framework/GraphPlanarityTesting.lgk3vd0bh9.dll +0 -0
- package/wwwroot/_framework/Microsoft.Win32.SystemEvents.f8qhom7uq5.dll +0 -0
- package/wwwroot/_framework/{MindExecution.Core.zs4n1f9hjc.dll → MindExecution.Core.tre9kny2uo.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Kernel.l9idvg7mp7.dll → MindExecution.Kernel.lvfnhwdksf.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Plugins.Admin.l37qx5d8zi.dll → MindExecution.Plugins.Admin.k2vbe4lt64.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Plugins.Business.d7b282yazn.dll → MindExecution.Plugins.Business.u7i3r45xp5.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Plugins.Concept.iw98n0qz5k.dll → MindExecution.Plugins.Concept.7eoasvev17.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Plugins.Directory.cqgn6pa8di.dll → MindExecution.Plugins.Directory.rhh13u0z6c.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Plugins.PlanMaster.j8xoa8nl57.dll → MindExecution.Plugins.PlanMaster.xzl2x2cqk4.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Plugins.YouTube.zvpzk7om4z.dll → MindExecution.Plugins.YouTube.945tf0zc9m.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Shared.ovot7q606x.dll → MindExecution.Shared.e0w408b0ti.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Web.bzuaz35jv0.dll → MindExecution.Web.vc6ux7xjcw.dll} +0 -0
- package/wwwroot/_framework/RangeTree.iw8h1x5u2y.dll +0 -0
- package/wwwroot/_framework/System.Collections.Concurrent.jzwteolu29.dll +0 -0
- package/wwwroot/_framework/System.Collections.NonGeneric.uqtvwssxuq.dll +0 -0
- package/wwwroot/_framework/System.Collections.Specialized.85qtrfslgb.dll +0 -0
- package/wwwroot/_framework/System.Collections.xmhu72xgrp.dll +0 -0
- package/wwwroot/_framework/System.ComponentModel.Primitives.excbd02v5j.dll +0 -0
- package/wwwroot/_framework/System.ComponentModel.TypeConverter.ek2jcwibb9.dll +0 -0
- package/wwwroot/_framework/System.ComponentModel.wfe9zz2icv.dll +0 -0
- package/wwwroot/_framework/System.Console.5j283so6ps.dll +0 -0
- package/wwwroot/_framework/System.Drawing.Common.xzizafq144.dll +0 -0
- package/wwwroot/_framework/System.Private.CoreLib.7ouudb2fbl.dll +0 -0
- package/wwwroot/_framework/{System.Text.RegularExpressions.cvkox11l6l.dll → System.Text.RegularExpressions.b0vqxbob08.dll} +0 -0
- package/wwwroot/_framework/System.Threading.Tasks.Parallel.9tqazg1b0u.dll +0 -0
- package/wwwroot/_framework/System.Threading.Tasks.zl4yo3otxa.dll +0 -0
- package/wwwroot/_framework/YamlDotNet.dtey92juka.dll +0 -0
- package/wwwroot/_framework/blazor.boot.json +63 -45
- package/wwwroot/_framework/{dotnet.native.60hhmnxyoo.wasm → dotnet.native.58bvs6q392.wasm} +0 -0
- package/wwwroot/_framework/netstandard.he3m3p1s9q.dll +0 -0
- package/wwwroot/index.html +2 -1
- package/wwwroot/service-worker-assets.js +128 -56
- package/wwwroot/service-worker.js +1 -1
- package/wwwroot/_framework/System.Collections.3iuoxbe8my.dll +0 -0
- package/wwwroot/_framework/System.Collections.Concurrent.vow3rm1dku.dll +0 -0
- package/wwwroot/_framework/System.Collections.NonGeneric.npjkaz40oc.dll +0 -0
- package/wwwroot/_framework/System.Collections.Specialized.ugkjbs6p02.dll +0 -0
- package/wwwroot/_framework/System.ComponentModel.Primitives.end4v0xe2c.dll +0 -0
- package/wwwroot/_framework/System.ComponentModel.TypeConverter.tgtp5sm4iv.dll +0 -0
- package/wwwroot/_framework/System.ComponentModel.wupoltkk1t.dll +0 -0
- package/wwwroot/_framework/System.Console.9dik0wogo2.dll +0 -0
- package/wwwroot/_framework/System.Private.CoreLib.7s8wte759y.dll +0 -0
- package/wwwroot/_framework/netstandard.b50t77veor.dll +0 -0
package/codex-runtime.js
CHANGED
|
@@ -1120,9 +1120,11 @@ export function createCodexRuntime(options) {
|
|
|
1120
1120
|
sandboxMode: API_SANDBOX_BY_SDK_VALUE[threadOptions.sandboxMode] || threadOptions.sandboxMode
|
|
1121
1121
|
});
|
|
1122
1122
|
let timeout = null;
|
|
1123
|
+
let timedOut = false;
|
|
1123
1124
|
|
|
1124
1125
|
try {
|
|
1125
1126
|
timeout = setTimeout(() => {
|
|
1127
|
+
timedOut = true;
|
|
1126
1128
|
try {
|
|
1127
1129
|
abortController.abort();
|
|
1128
1130
|
} catch {
|
|
@@ -1182,8 +1184,10 @@ export function createCodexRuntime(options) {
|
|
|
1182
1184
|
}
|
|
1183
1185
|
} catch (err) {
|
|
1184
1186
|
const aborted = abortController.signal.aborted;
|
|
1185
|
-
result.error =
|
|
1186
|
-
|
|
1187
|
+
result.error = timedOut
|
|
1188
|
+
? 'Codex turn timed out.'
|
|
1189
|
+
: (aborted ? 'Codex turn was cancelled.' : (err?.message || String(err)));
|
|
1190
|
+
result.status = timedOut ? 'timed-out' : (aborted ? 'cancelled' : 'failed');
|
|
1187
1191
|
result.success = false;
|
|
1188
1192
|
} finally {
|
|
1189
1193
|
if (timeout) {
|
package/electron/main.cjs
CHANGED
|
@@ -33,8 +33,6 @@ let desktopWorkspaceStatePath = '';
|
|
|
33
33
|
let productUpdates = null;
|
|
34
34
|
let recurringProductUpdates = null;
|
|
35
35
|
let updateInstallSequenceStarted = false;
|
|
36
|
-
let updatePromptPromise = null;
|
|
37
|
-
let updatePromptedVersion = '';
|
|
38
36
|
|
|
39
37
|
function resolveDesktopIconPath() {
|
|
40
38
|
const iconPath = path.resolve(__dirname, '..', 'wwwroot', 'icon-512.png');
|
|
@@ -48,6 +46,21 @@ function resolveDesktopInstallKind() {
|
|
|
48
46
|
return process.platform === 'win32' ? 'installed' : 'unsupported-platform';
|
|
49
47
|
}
|
|
50
48
|
|
|
49
|
+
function resolveNativeCoreMode() {
|
|
50
|
+
const validModes = new Set(['off', 'compare', 'native']);
|
|
51
|
+
const environmentMode = String(process.env.MINDEXEC_NATIVE_CORE_MODE || '').trim().toLowerCase();
|
|
52
|
+
if (validModes.has(environmentMode)) return environmentMode;
|
|
53
|
+
if (!app.isPackaged) return 'off';
|
|
54
|
+
|
|
55
|
+
try {
|
|
56
|
+
const packageInfo = JSON.parse(fs.readFileSync(path.join(app.getAppPath(), 'package.json'), 'utf8'));
|
|
57
|
+
const packagedMode = String(packageInfo.nativeCoreMode || '').trim().toLowerCase();
|
|
58
|
+
return validModes.has(packagedMode) ? packagedMode : 'off';
|
|
59
|
+
} catch {
|
|
60
|
+
return 'off';
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
51
64
|
function parsePort(value) {
|
|
52
65
|
const parsed = Number.parseInt(String(value ?? ''), 10);
|
|
53
66
|
return Number.isInteger(parsed) && parsed > 0 && parsed <= 65_535 ? parsed : 0;
|
|
@@ -259,34 +272,6 @@ function sendUpdateStatus(status) {
|
|
|
259
272
|
if (mainWindow && !mainWindow.isDestroyed() && !mainWindow.webContents.isDestroyed()) {
|
|
260
273
|
mainWindow.webContents.send('updates:status', status);
|
|
261
274
|
}
|
|
262
|
-
if (status.state === 'downloaded') void promptForDownloadedUpdate(status);
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
async function promptForDownloadedUpdate(status = productUpdates?.getStatus()) {
|
|
266
|
-
if (!status?.downloaded || !status.availableVersion || !mainWindow || mainWindow.isDestroyed()) return;
|
|
267
|
-
if (process.env.MINDEXEC_DESKTOP_SMOKE === '1') return;
|
|
268
|
-
if (updatePromptedVersion === status.availableVersion || updatePromptPromise) return updatePromptPromise;
|
|
269
|
-
|
|
270
|
-
updatePromptedVersion = status.availableVersion;
|
|
271
|
-
updatePromptPromise = dialog.showMessageBox(mainWindow, {
|
|
272
|
-
type: 'info',
|
|
273
|
-
title: 'MindExec update ready',
|
|
274
|
-
message: `MindExec ${status.availableVersion} is ready.`,
|
|
275
|
-
detail: 'Restart now to use the new development build. Your project folder and saved data stay unchanged.',
|
|
276
|
-
buttons: ['Restart and update', 'Later'],
|
|
277
|
-
defaultId: 0,
|
|
278
|
-
cancelId: 1,
|
|
279
|
-
noLink: true
|
|
280
|
-
}).then(result => {
|
|
281
|
-
if (result.response === 0) return productUpdates?.install();
|
|
282
|
-
return productUpdates?.getStatus();
|
|
283
|
-
}).catch(error => {
|
|
284
|
-
appendDesktopLog(`[update:prompt-error] ${error?.stack || error}`);
|
|
285
|
-
return productUpdates?.getStatus();
|
|
286
|
-
}).finally(() => {
|
|
287
|
-
updatePromptPromise = null;
|
|
288
|
-
});
|
|
289
|
-
return updatePromptPromise;
|
|
290
275
|
}
|
|
291
276
|
|
|
292
277
|
function initializeProductUpdates() {
|
|
@@ -370,6 +355,40 @@ function writeSmokeResult(payload) {
|
|
|
370
355
|
fs.writeFileSync(resultPath, `${JSON.stringify(payload, null, 2)}\n`, 'utf8');
|
|
371
356
|
}
|
|
372
357
|
|
|
358
|
+
async function waitForNativeCoreSmoke(browserWindow, expectedMode) {
|
|
359
|
+
if (expectedMode === 'off') return null;
|
|
360
|
+
const deadline = Date.now() + 30_000;
|
|
361
|
+
let lastSnapshot = null;
|
|
362
|
+
while (Date.now() < deadline) {
|
|
363
|
+
lastSnapshot = await browserWindow.webContents.executeJavaScript(`(() => {
|
|
364
|
+
const value = window.__mindExecutionNativeCoreStatus;
|
|
365
|
+
if (!value) return null;
|
|
366
|
+
return {
|
|
367
|
+
mode: String(value.mode || ''),
|
|
368
|
+
ready: value.ready === true,
|
|
369
|
+
backend: String(value.backend || ''),
|
|
370
|
+
buildId: String(value.buildId || ''),
|
|
371
|
+
lastError: String(value.lastError || ''),
|
|
372
|
+
fallbackActive: value.fallbackActive === true,
|
|
373
|
+
fallbackReason: String(value.fallbackReason || ''),
|
|
374
|
+
primaryResults: Number(value.primaryResults || 0),
|
|
375
|
+
lastPrimaryResultType: String(value.lastPrimaryResultType || ''),
|
|
376
|
+
lastPrimaryDurationMs: Number(value.lastPrimaryDurationMs || 0),
|
|
377
|
+
lastPrimaryRoundTripMs: Number(value.lastPrimaryRoundTripMs || 0)
|
|
378
|
+
};
|
|
379
|
+
})()`);
|
|
380
|
+
if (lastSnapshot?.lastError || lastSnapshot?.fallbackActive === true) {
|
|
381
|
+
throw new Error(`Native core smoke initialization failed: ${lastSnapshot.lastError}`);
|
|
382
|
+
}
|
|
383
|
+
const acceptedNativeResult = expectedMode !== 'native' || Number(lastSnapshot?.primaryResults || 0) > 0;
|
|
384
|
+
if (lastSnapshot?.ready === true && lastSnapshot.mode === expectedMode && acceptedNativeResult) {
|
|
385
|
+
return lastSnapshot;
|
|
386
|
+
}
|
|
387
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
388
|
+
}
|
|
389
|
+
throw new Error(`Native core did not become ready in ${expectedMode} mode: ${JSON.stringify(lastSnapshot)}`);
|
|
390
|
+
}
|
|
391
|
+
|
|
373
392
|
async function stopBundledBridge() {
|
|
374
393
|
const child = bridgeChild;
|
|
375
394
|
bridgeChild = null;
|
|
@@ -447,11 +466,15 @@ async function recoverRuntimeAfterUpdateInstallError(error) {
|
|
|
447
466
|
async function launchDesktop() {
|
|
448
467
|
const status = await prepareBundledRuntime();
|
|
449
468
|
const window = createMainWindow();
|
|
450
|
-
const
|
|
469
|
+
const nativeCoreMode = resolveNativeCoreMode();
|
|
470
|
+
const nativeCoreQuery = nativeCoreMode === 'off'
|
|
471
|
+
? ''
|
|
472
|
+
: `?nativeCore=${encodeURIComponent(nativeCoreMode)}`;
|
|
473
|
+
const appUrl = `http://127.0.0.1:${activeBridgePort}/mindcanvas${nativeCoreQuery}`;
|
|
451
474
|
await window.loadURL(appUrl);
|
|
452
|
-
void promptForDownloadedUpdate();
|
|
453
475
|
|
|
454
476
|
if (process.env.MINDEXEC_DESKTOP_SMOKE === '1') {
|
|
477
|
+
const nativeCore = await waitForNativeCoreSmoke(window, nativeCoreMode);
|
|
455
478
|
writeSmokeResult({
|
|
456
479
|
ok: true,
|
|
457
480
|
appVersion: app.getVersion(),
|
|
@@ -462,6 +485,7 @@ async function launchDesktop() {
|
|
|
462
485
|
remoteHubPort: activeRemoteHubPort,
|
|
463
486
|
workspace: activeWorkspace,
|
|
464
487
|
url: appUrl,
|
|
488
|
+
nativeCore,
|
|
465
489
|
desktopUpdate: productUpdates?.getStatus() || null
|
|
466
490
|
});
|
|
467
491
|
setTimeout(() => app.quit(), 250).unref();
|
package/electron/preload.cjs
CHANGED
|
@@ -2,6 +2,184 @@
|
|
|
2
2
|
|
|
3
3
|
const { contextBridge, ipcRenderer } = require('electron');
|
|
4
4
|
|
|
5
|
+
const UPDATE_INDICATOR_ID = 'mindexec-desktop-update-indicator';
|
|
6
|
+
const UPDATE_STYLE_ID = 'mindexec-desktop-update-indicator-style';
|
|
7
|
+
let latestUpdateStatus = null;
|
|
8
|
+
let updateInstallBusy = false;
|
|
9
|
+
|
|
10
|
+
function updateVersion(status) {
|
|
11
|
+
return String(status?.availableVersion || '').trim();
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function shouldShowUpdateIndicator(status) {
|
|
15
|
+
const version = updateVersion(status);
|
|
16
|
+
if (!version) return false;
|
|
17
|
+
return ['available', 'downloading', 'downloaded', 'error'].includes(String(status?.state || '').toLowerCase());
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function buildUpdateTooltip(status) {
|
|
21
|
+
const version = updateVersion(status) || 'new version';
|
|
22
|
+
const state = String(status?.state || '').toLowerCase();
|
|
23
|
+
if (state === 'downloading') {
|
|
24
|
+
const progress = Math.max(0, Math.min(100, Math.round(Number(status?.progress || 0))));
|
|
25
|
+
return `Update available · ${version} · downloading ${progress}%`;
|
|
26
|
+
}
|
|
27
|
+
if (state === 'downloaded') return `Update available · ${version} · ready to install`;
|
|
28
|
+
if (state === 'error') return `Update available · ${version} · click to retry`;
|
|
29
|
+
return `Update available · ${version}`;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function ensureUpdateIndicatorStyle() {
|
|
33
|
+
if (document.getElementById(UPDATE_STYLE_ID)) return;
|
|
34
|
+
const style = document.createElement('style');
|
|
35
|
+
style.id = UPDATE_STYLE_ID;
|
|
36
|
+
style.textContent = `
|
|
37
|
+
#${UPDATE_INDICATOR_ID} {
|
|
38
|
+
position: fixed;
|
|
39
|
+
left: 16px;
|
|
40
|
+
bottom: 16px;
|
|
41
|
+
z-index: 2147483000;
|
|
42
|
+
width: 32px;
|
|
43
|
+
height: 32px;
|
|
44
|
+
box-sizing: border-box;
|
|
45
|
+
display: none;
|
|
46
|
+
align-items: center;
|
|
47
|
+
justify-content: center;
|
|
48
|
+
border: 0;
|
|
49
|
+
border-radius: 50%;
|
|
50
|
+
background: #3b82f6;
|
|
51
|
+
color: #fff;
|
|
52
|
+
box-shadow: 0 1px 3px rgba(15, 23, 42, 0.16);
|
|
53
|
+
cursor: pointer;
|
|
54
|
+
padding: 0;
|
|
55
|
+
font: inherit;
|
|
56
|
+
line-height: 0;
|
|
57
|
+
appearance: none;
|
|
58
|
+
-webkit-app-region: no-drag;
|
|
59
|
+
transition: background 120ms ease, box-shadow 120ms ease, opacity 120ms ease;
|
|
60
|
+
}
|
|
61
|
+
#${UPDATE_INDICATOR_ID}:hover {
|
|
62
|
+
background: #2563eb;
|
|
63
|
+
box-shadow: 0 2px 6px rgba(37, 99, 235, 0.28);
|
|
64
|
+
}
|
|
65
|
+
#${UPDATE_INDICATOR_ID}:focus-visible {
|
|
66
|
+
outline: 2px solid #60a5fa;
|
|
67
|
+
outline-offset: 2px;
|
|
68
|
+
}
|
|
69
|
+
#${UPDATE_INDICATOR_ID}[data-busy="true"] {
|
|
70
|
+
cursor: progress;
|
|
71
|
+
opacity: 0.72;
|
|
72
|
+
}
|
|
73
|
+
#${UPDATE_INDICATOR_ID} svg {
|
|
74
|
+
width: 20px;
|
|
75
|
+
height: 20px;
|
|
76
|
+
flex: 0 0 20px;
|
|
77
|
+
display: block;
|
|
78
|
+
pointer-events: none;
|
|
79
|
+
}
|
|
80
|
+
#${UPDATE_INDICATOR_ID} .mindexec-update-tooltip {
|
|
81
|
+
position: absolute;
|
|
82
|
+
left: 40px;
|
|
83
|
+
bottom: 50%;
|
|
84
|
+
transform: translateY(50%) translateX(-2px);
|
|
85
|
+
opacity: 0;
|
|
86
|
+
visibility: hidden;
|
|
87
|
+
pointer-events: none;
|
|
88
|
+
white-space: nowrap;
|
|
89
|
+
padding: 6px 9px;
|
|
90
|
+
border-radius: 7px;
|
|
91
|
+
background: rgba(15, 23, 42, 0.96);
|
|
92
|
+
color: #f8fafc;
|
|
93
|
+
font-size: 12px;
|
|
94
|
+
font-weight: 600;
|
|
95
|
+
line-height: 1.2;
|
|
96
|
+
letter-spacing: 0.01em;
|
|
97
|
+
box-shadow: 0 6px 20px rgba(15, 23, 42, 0.18);
|
|
98
|
+
transition: opacity 100ms ease, transform 100ms ease, visibility 100ms ease;
|
|
99
|
+
}
|
|
100
|
+
#${UPDATE_INDICATOR_ID}:hover .mindexec-update-tooltip,
|
|
101
|
+
#${UPDATE_INDICATOR_ID}:focus-visible .mindexec-update-tooltip {
|
|
102
|
+
opacity: 1;
|
|
103
|
+
visibility: visible;
|
|
104
|
+
transform: translateY(50%) translateX(0);
|
|
105
|
+
}
|
|
106
|
+
`;
|
|
107
|
+
(document.head || document.documentElement).appendChild(style);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function ensureUpdateIndicator() {
|
|
111
|
+
if (!document.body) return null;
|
|
112
|
+
ensureUpdateIndicatorStyle();
|
|
113
|
+
let button = document.getElementById(UPDATE_INDICATOR_ID);
|
|
114
|
+
if (button) return button;
|
|
115
|
+
|
|
116
|
+
button = document.createElement('button');
|
|
117
|
+
button.id = UPDATE_INDICATOR_ID;
|
|
118
|
+
button.type = 'button';
|
|
119
|
+
button.setAttribute('aria-live', 'polite');
|
|
120
|
+
button.innerHTML = `
|
|
121
|
+
<svg viewBox="0 0 24 24" fill="none" aria-hidden="true">
|
|
122
|
+
<path d="M12 3.5v10.75m0 0 4.25-4.25M12 14.25 7.75 10M5 19.5h14" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
|
123
|
+
</svg>
|
|
124
|
+
<span class="mindexec-update-tooltip" role="tooltip"></span>
|
|
125
|
+
`;
|
|
126
|
+
button.addEventListener('click', async () => {
|
|
127
|
+
if (updateInstallBusy) return;
|
|
128
|
+
updateInstallBusy = true;
|
|
129
|
+
button.dataset.busy = 'true';
|
|
130
|
+
const tooltip = button.querySelector('.mindexec-update-tooltip');
|
|
131
|
+
if (tooltip) tooltip.textContent = `Updating MindExec · ${updateVersion(latestUpdateStatus) || ''}`.trim();
|
|
132
|
+
try {
|
|
133
|
+
const result = await ipcRenderer.invoke('updates:install');
|
|
134
|
+
renderUpdateIndicator(result);
|
|
135
|
+
} catch (error) {
|
|
136
|
+
renderUpdateIndicator({
|
|
137
|
+
...(latestUpdateStatus || {}),
|
|
138
|
+
state: 'error',
|
|
139
|
+
error: String(error?.message || error)
|
|
140
|
+
});
|
|
141
|
+
} finally {
|
|
142
|
+
updateInstallBusy = false;
|
|
143
|
+
button.dataset.busy = 'false';
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
document.body.appendChild(button);
|
|
147
|
+
return button;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function renderUpdateIndicator(status) {
|
|
151
|
+
latestUpdateStatus = status || latestUpdateStatus || { state: 'unavailable' };
|
|
152
|
+
const button = ensureUpdateIndicator();
|
|
153
|
+
if (!button) return;
|
|
154
|
+
|
|
155
|
+
if (!shouldShowUpdateIndicator(latestUpdateStatus)) {
|
|
156
|
+
button.style.display = 'none';
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const tooltipText = buildUpdateTooltip(latestUpdateStatus);
|
|
161
|
+
button.style.display = 'flex';
|
|
162
|
+
button.dataset.state = String(latestUpdateStatus.state || 'available');
|
|
163
|
+
button.setAttribute('aria-label', `${tooltipText}. Click to update MindExec.`);
|
|
164
|
+
const tooltip = button.querySelector('.mindexec-update-tooltip');
|
|
165
|
+
if (tooltip && updateInstallBusy !== true) tooltip.textContent = tooltipText;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
async function bootstrapUpdateIndicator() {
|
|
169
|
+
try {
|
|
170
|
+
renderUpdateIndicator(await ipcRenderer.invoke('updates:get-status'));
|
|
171
|
+
} catch {
|
|
172
|
+
renderUpdateIndicator({ state: 'unavailable' });
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
ipcRenderer.on('updates:status', (_event, payload) => renderUpdateIndicator(payload));
|
|
177
|
+
if (document.readyState === 'loading') {
|
|
178
|
+
window.addEventListener('DOMContentLoaded', () => void bootstrapUpdateIndicator(), { once: true });
|
|
179
|
+
} else {
|
|
180
|
+
void bootstrapUpdateIndicator();
|
|
181
|
+
}
|
|
182
|
+
|
|
5
183
|
contextBridge.exposeInMainWorld('mindExecDesktop', {
|
|
6
184
|
updates: {
|
|
7
185
|
getStatus: () => ipcRenderer.invoke('updates:get-status'),
|
|
@@ -33,6 +33,9 @@ assert.match(packageJson.scripts?.['desktop:publish:update:dev'] || '', /--chann
|
|
|
33
33
|
'The explicit development update publishing command is missing.');
|
|
34
34
|
assert.equal(packageJson.dependencies?.['electron-updater'], '^6.8.9', 'The packaged updater dependency is missing.');
|
|
35
35
|
assert.equal(packageJson.build?.extraMetadata?.desktopUpdateChannel, 'dev', 'Development installers must stay on the dev feed.');
|
|
36
|
+
assert.equal(packageJson.build?.extraMetadata?.nativeCoreMode, 'native',
|
|
37
|
+
'Packaged development builds must use the validated native-primary core with bounded JS fallback.');
|
|
38
|
+
assert.match(mainSource, /waitForNativeCoreSmoke/, 'Packaged smoke must verify the native Wasm runtime, not only its URL mode.');
|
|
36
39
|
assert.equal(packageJson.build?.publish?.provider, 'generic', 'Desktop updates must use the generic R2-backed provider.');
|
|
37
40
|
assert.equal(packageJson.build?.publish?.useMultipleRangeRequest, false,
|
|
38
41
|
'Packaged differential downloads must use one byte range per request.');
|
|
@@ -95,7 +98,17 @@ assert.match(mainSource, /updates:check/, 'The manual updater check IPC contract
|
|
|
95
98
|
assert.match(mainSource, /updates:install/, 'The updater install IPC contract is missing.');
|
|
96
99
|
assert.match(mainSource, /await stopBundledBridge\(\)[\s\S]{0,180}await waitForBundledRuntimePortsReleased\(\)/,
|
|
97
100
|
'The Bridge and RemoteHub ports must reach zero before the installer starts.');
|
|
98
|
-
assert.
|
|
101
|
+
assert.doesNotMatch(mainSource, /Restart and update|promptForDownloadedUpdate|showMessageBox\(mainWindow/, 'Update availability must not open a restart modal.');
|
|
102
|
+
assert.match(preloadSource, /mindexec-desktop-update-indicator/, 'The bottom-left update indicator is missing.');
|
|
103
|
+
assert.match(preloadSource, /Update available ·/, 'The update indicator tooltip must include the available version.');
|
|
104
|
+
assert.match(preloadSource, /left:\s*16px[\s\S]*bottom:\s*16px/, 'The update indicator must stay at the bottom-left.');
|
|
105
|
+
assert.match(preloadSource, /width:\s*32px[\s\S]{0,80}height:\s*32px/,
|
|
106
|
+
'The update indicator must keep the compact circular-button dimensions.');
|
|
107
|
+
assert.match(preloadSource, /align-items:\s*center[\s\S]{0,80}justify-content:\s*center/,
|
|
108
|
+
'The update indicator icon must stay centered in both directions.');
|
|
109
|
+
assert.match(preloadSource, /border:\s*0[\s\S]{0,80}border-radius:\s*50%[\s\S]{0,100}background:\s*#3b82f6[\s\S]{0,60}color:\s*#fff/,
|
|
110
|
+
'The update indicator must keep the filled blue circle and white icon style.');
|
|
111
|
+
assert.match(preloadSource, /ipcRenderer\.invoke\('updates:install'\)/, 'Clicking the update indicator must use the owned install IPC path.');
|
|
99
112
|
assert.match(preloadSource, /mindExecDesktop/, 'The updater preload namespace changed unexpectedly.');
|
|
100
113
|
assert.match(preloadSource, /updates:\s*\{/, 'The updater preload API is missing.');
|
|
101
114
|
assert.match(updateManagerSource, /autoDownload\s*=\s*false/, 'Updates must not download through an unowned implicit path.');
|
|
@@ -126,6 +126,22 @@ try {
|
|
|
126
126
|
assert.equal(result.appVersion, packageJson.version, 'Electron app version does not match the npm package version.');
|
|
127
127
|
assert.equal(result.bridgeVersion, packageJson.version, 'Bundled LocalBridge version does not match Electron.');
|
|
128
128
|
assert.equal(result.runtimeMode, 'bundled', 'Electron did not use its bundled runtime.');
|
|
129
|
+
assert.equal(
|
|
130
|
+
result.url,
|
|
131
|
+
`http://127.0.0.1:${bridgePort}/mindcanvas?nativeCore=native`,
|
|
132
|
+
'Packaged Electron did not enable the validated native-primary core.'
|
|
133
|
+
);
|
|
134
|
+
assert.equal(result.nativeCore?.mode, 'native', 'Packaged Electron native core mode did not reach the page runtime.');
|
|
135
|
+
assert.equal(result.nativeCore?.ready, true, 'Packaged Electron native core worker did not become ready.');
|
|
136
|
+
assert.match(result.nativeCore?.backend || '', /^wasm-(?:simd|scalar)$/,
|
|
137
|
+
'Packaged Electron native core did not load a scalar or SIMD Wasm backend.');
|
|
138
|
+
assert.equal(result.nativeCore?.fallbackActive, false,
|
|
139
|
+
`Packaged Electron fell back from its native primary: ${result.nativeCore?.fallbackReason || 'unknown reason'}`);
|
|
140
|
+
assert.ok(Number(result.nativeCore?.primaryResults || 0) > 0,
|
|
141
|
+
'Packaged Electron became ready but did not apply a native-core result.');
|
|
142
|
+
assert.match(result.nativeCore?.lastPrimaryResultType || '', /^(?:VISIBILITY|HIT_TEST|SELECTION_QUERY)_RESULT$/,
|
|
143
|
+
'Packaged Electron did not report the accepted native-core result type.');
|
|
144
|
+
assert.equal(result.nativeCore?.lastError, '', 'Packaged Electron native core reported an initialization error.');
|
|
129
145
|
assert.equal(result.windowTitle, `MindExec ${packageJson.version}`,
|
|
130
146
|
'Packaged Electron did not keep the version visible in the title bar.');
|
|
131
147
|
assert.equal(result.bridgePort, bridgePort, 'Packaged shell did not use the requested Bridge port.');
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mindexec/cli",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.494",
|
|
4
4
|
"description": "MindExec local runtime and bridge CLI",
|
|
5
5
|
"main": "server.js",
|
|
6
6
|
"type": "module",
|
|
@@ -112,10 +112,11 @@
|
|
|
112
112
|
"productName": "MindExec",
|
|
113
113
|
"copyright": "Copyright © 2026 lovecrdm77",
|
|
114
114
|
"asar": false,
|
|
115
|
-
"extraMetadata": {
|
|
116
|
-
"main": "electron/main.cjs",
|
|
117
|
-
"desktopUpdateChannel": "dev"
|
|
118
|
-
|
|
115
|
+
"extraMetadata": {
|
|
116
|
+
"main": "electron/main.cjs",
|
|
117
|
+
"desktopUpdateChannel": "dev",
|
|
118
|
+
"nativeCoreMode": "native"
|
|
119
|
+
},
|
|
119
120
|
"directories": {
|
|
120
121
|
"output": "../artifacts/electron"
|
|
121
122
|
},
|
|
@@ -160,10 +161,10 @@
|
|
|
160
161
|
"portable": {
|
|
161
162
|
"artifactName": "MindExec-Portable-${version}-${arch}.${ext}"
|
|
162
163
|
},
|
|
163
|
-
"publish": {
|
|
164
|
-
"provider": "generic",
|
|
165
|
-
"url": "https://mindexec.lovecrdm.workers.dev/dev/windows/x64",
|
|
166
|
-
"useMultipleRangeRequest": false
|
|
167
|
-
}
|
|
164
|
+
"publish": {
|
|
165
|
+
"provider": "generic",
|
|
166
|
+
"url": "https://mindexec.lovecrdm.workers.dev/dev/windows/x64",
|
|
167
|
+
"useMultipleRangeRequest": false
|
|
168
|
+
}
|
|
168
169
|
}
|
|
169
170
|
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|