@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.
Files changed (70) hide show
  1. package/codex-runtime.js +6 -2
  2. package/electron/main.cjs +56 -32
  3. package/electron/preload.cjs +178 -0
  4. package/electron/source-smoke.mjs +14 -1
  5. package/electron/windows-package-smoke.mjs +16 -0
  6. package/package.json +11 -10
  7. package/remote-fast/osx-arm64/mindexec-remote-fast.dll +0 -0
  8. package/remote-fast/osx-x64/mindexec-remote-fast.dll +0 -0
  9. package/remote-fast/win-x64/mindexec-remote-fast.dll +0 -0
  10. package/wwwroot/_content/MindExecution.Shared/css/app.css +1 -1
  11. package/wwwroot/_content/MindExecution.Shared/js/canvas-chat-task-switch.js +122 -0
  12. package/wwwroot/_content/MindExecution.Shared/js/mind-map-css3d-manager.js +161 -16
  13. package/wwwroot/_content/MindExecution.Shared/js/mind-map-interactions.js +68 -2
  14. package/wwwroot/_content/MindExecution.Shared/js/mind-map-lod-plan-worker.js +44 -8
  15. package/wwwroot/_content/MindExecution.Shared/js/mind-map-logic-workers.js +823 -111
  16. package/wwwroot/_content/MindExecution.Shared/js/mind-map-native-core-bridge.js +399 -0
  17. package/wwwroot/_content/MindExecution.Shared/js/mind-map-node-search-worker.js +53 -10
  18. package/wwwroot/_content/MindExecution.Shared/js/mind-map-visibility-worker.js +71 -11
  19. package/wwwroot/_content/MindExecution.Shared/native-core/mindexec-core-simd.js +18 -0
  20. package/wwwroot/_content/MindExecution.Shared/native-core/mindexec-core-simd.wasm +0 -0
  21. package/wwwroot/_content/MindExecution.Shared/native-core/mindexec-core.js +18 -0
  22. package/wwwroot/_content/MindExecution.Shared/native-core/mindexec-core.wasm +0 -0
  23. package/wwwroot/_content/MindExecution.Shared/native-core/mindexec-native-core-adapter.js +566 -0
  24. package/wwwroot/_content/MindExecution.Shared/native-core/mindexec-native-core-worker.js +89 -0
  25. package/wwwroot/_content/MindExecution.Shared/native-core/native-core-manifest.json +59 -0
  26. package/wwwroot/_framework/BenchmarkUtils.ytz7pn9azy.dll +0 -0
  27. package/wwwroot/_framework/Edgar.9yqq548b45.dll +0 -0
  28. package/wwwroot/_framework/GraphPlanarityTesting.lgk3vd0bh9.dll +0 -0
  29. package/wwwroot/_framework/Microsoft.Win32.SystemEvents.f8qhom7uq5.dll +0 -0
  30. package/wwwroot/_framework/{MindExecution.Core.zs4n1f9hjc.dll → MindExecution.Core.tre9kny2uo.dll} +0 -0
  31. package/wwwroot/_framework/{MindExecution.Kernel.l9idvg7mp7.dll → MindExecution.Kernel.lvfnhwdksf.dll} +0 -0
  32. package/wwwroot/_framework/{MindExecution.Plugins.Admin.l37qx5d8zi.dll → MindExecution.Plugins.Admin.k2vbe4lt64.dll} +0 -0
  33. package/wwwroot/_framework/{MindExecution.Plugins.Business.d7b282yazn.dll → MindExecution.Plugins.Business.u7i3r45xp5.dll} +0 -0
  34. package/wwwroot/_framework/{MindExecution.Plugins.Concept.iw98n0qz5k.dll → MindExecution.Plugins.Concept.7eoasvev17.dll} +0 -0
  35. package/wwwroot/_framework/{MindExecution.Plugins.Directory.cqgn6pa8di.dll → MindExecution.Plugins.Directory.rhh13u0z6c.dll} +0 -0
  36. package/wwwroot/_framework/{MindExecution.Plugins.PlanMaster.j8xoa8nl57.dll → MindExecution.Plugins.PlanMaster.xzl2x2cqk4.dll} +0 -0
  37. package/wwwroot/_framework/{MindExecution.Plugins.YouTube.zvpzk7om4z.dll → MindExecution.Plugins.YouTube.945tf0zc9m.dll} +0 -0
  38. package/wwwroot/_framework/{MindExecution.Shared.ovot7q606x.dll → MindExecution.Shared.e0w408b0ti.dll} +0 -0
  39. package/wwwroot/_framework/{MindExecution.Web.bzuaz35jv0.dll → MindExecution.Web.vc6ux7xjcw.dll} +0 -0
  40. package/wwwroot/_framework/RangeTree.iw8h1x5u2y.dll +0 -0
  41. package/wwwroot/_framework/System.Collections.Concurrent.jzwteolu29.dll +0 -0
  42. package/wwwroot/_framework/System.Collections.NonGeneric.uqtvwssxuq.dll +0 -0
  43. package/wwwroot/_framework/System.Collections.Specialized.85qtrfslgb.dll +0 -0
  44. package/wwwroot/_framework/System.Collections.xmhu72xgrp.dll +0 -0
  45. package/wwwroot/_framework/System.ComponentModel.Primitives.excbd02v5j.dll +0 -0
  46. package/wwwroot/_framework/System.ComponentModel.TypeConverter.ek2jcwibb9.dll +0 -0
  47. package/wwwroot/_framework/System.ComponentModel.wfe9zz2icv.dll +0 -0
  48. package/wwwroot/_framework/System.Console.5j283so6ps.dll +0 -0
  49. package/wwwroot/_framework/System.Drawing.Common.xzizafq144.dll +0 -0
  50. package/wwwroot/_framework/System.Private.CoreLib.7ouudb2fbl.dll +0 -0
  51. package/wwwroot/_framework/{System.Text.RegularExpressions.cvkox11l6l.dll → System.Text.RegularExpressions.b0vqxbob08.dll} +0 -0
  52. package/wwwroot/_framework/System.Threading.Tasks.Parallel.9tqazg1b0u.dll +0 -0
  53. package/wwwroot/_framework/System.Threading.Tasks.zl4yo3otxa.dll +0 -0
  54. package/wwwroot/_framework/YamlDotNet.dtey92juka.dll +0 -0
  55. package/wwwroot/_framework/blazor.boot.json +63 -45
  56. package/wwwroot/_framework/{dotnet.native.60hhmnxyoo.wasm → dotnet.native.58bvs6q392.wasm} +0 -0
  57. package/wwwroot/_framework/netstandard.he3m3p1s9q.dll +0 -0
  58. package/wwwroot/index.html +2 -1
  59. package/wwwroot/service-worker-assets.js +128 -56
  60. package/wwwroot/service-worker.js +1 -1
  61. package/wwwroot/_framework/System.Collections.3iuoxbe8my.dll +0 -0
  62. package/wwwroot/_framework/System.Collections.Concurrent.vow3rm1dku.dll +0 -0
  63. package/wwwroot/_framework/System.Collections.NonGeneric.npjkaz40oc.dll +0 -0
  64. package/wwwroot/_framework/System.Collections.Specialized.ugkjbs6p02.dll +0 -0
  65. package/wwwroot/_framework/System.ComponentModel.Primitives.end4v0xe2c.dll +0 -0
  66. package/wwwroot/_framework/System.ComponentModel.TypeConverter.tgtp5sm4iv.dll +0 -0
  67. package/wwwroot/_framework/System.ComponentModel.wupoltkk1t.dll +0 -0
  68. package/wwwroot/_framework/System.Console.9dik0wogo2.dll +0 -0
  69. package/wwwroot/_framework/System.Private.CoreLib.7s8wte759y.dll +0 -0
  70. 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 = aborted ? 'Codex turn was cancelled.' : (err?.message || String(err));
1186
- result.status = aborted ? 'cancelled' : 'failed';
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 appUrl = `http://127.0.0.1:${activeBridgePort}/mindcanvas`;
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();
@@ -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.match(mainSource, /Restart and update/, 'A downloaded update must ask before restarting active work.');
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.483",
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
  }