@mindexec/cli 0.2.478 → 0.2.480

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 (146) hide show
  1. package/README.md +323 -323
  2. package/codex-model-catalog.js +202 -202
  3. package/codex-runtime.js +1608 -1608
  4. package/desktop-workspace-state.cjs +120 -120
  5. package/electron/main.cjs +517 -517
  6. package/electron/preload.cjs +17 -17
  7. package/electron/recurring-update-owner-smoke.mjs +55 -55
  8. package/electron/recurring-update-owner.cjs +97 -97
  9. package/electron/source-smoke.mjs +108 -108
  10. package/electron/update-feed-resolver.cjs +79 -79
  11. package/electron/update-feed.json +10 -10
  12. package/electron/update-manager-smoke.mjs +146 -146
  13. package/electron/update-manager.cjs +297 -297
  14. package/electron/windows-package-smoke.mjs +156 -156
  15. package/launch-bridge.cjs +236 -236
  16. package/lzo1x.js +110 -110
  17. package/mode4-atlas-worker.js +440 -440
  18. package/mode4-atlas.js +130 -130
  19. package/package.json +1 -1
  20. package/port-guard.cjs +285 -285
  21. package/remote-fast/osx-arm64/MacScreenCaptureKitH264.swift +339 -339
  22. package/remote-fast/osx-arm64/MacSystemAudioCapture.swift +214 -214
  23. package/remote-fast/osx-arm64/UnixRawCaptureHelper.mjs +80 -80
  24. package/remote-fast/osx-arm64/livedesk-raw-capture-resampler.mjs +73 -73
  25. package/remote-fast/osx-arm64/mindexec-remote-fast.dll +0 -0
  26. package/remote-fast/osx-x64/MacScreenCaptureKitH264.swift +339 -339
  27. package/remote-fast/osx-x64/MacSystemAudioCapture.swift +214 -214
  28. package/remote-fast/osx-x64/UnixRawCaptureHelper.mjs +80 -80
  29. package/remote-fast/osx-x64/livedesk-raw-capture-resampler.mjs +73 -73
  30. package/remote-fast/osx-x64/mindexec-remote-fast.dll +0 -0
  31. package/remote-fast/win-x64/mindexec-remote-fast.dll +0 -0
  32. package/remote-hub.js +3698 -3698
  33. package/scripts/auth-session-smoke.mjs +262 -262
  34. package/scripts/board-render-ownership-smoke.mjs +85 -85
  35. package/scripts/codex-model-catalog-smoke.mjs +150 -150
  36. package/scripts/codex-runtime-home-smoke.mjs +58 -58
  37. package/scripts/codex-sdk-image-live-smoke.mjs +43 -43
  38. package/scripts/codex-sdk-image-runtime-smoke.mjs +122 -122
  39. package/scripts/codex-sdk-runtime-smoke.mjs +89 -89
  40. package/scripts/desktop-update-publisher-smoke.mjs +89 -89
  41. package/scripts/desktop-update-worker-smoke.mjs +72 -72
  42. package/scripts/desktop-workspace-state-smoke.mjs +81 -81
  43. package/scripts/drive-installed-update-smoke.mjs +67 -67
  44. package/scripts/npm-fresh-install-smoke.mjs +216 -216
  45. package/scripts/publish-mindexec-desktop-updates.mjs +224 -224
  46. package/scripts/remote-agent-managed-smoke.mjs +318 -318
  47. package/scripts/remote-agent-package-smoke.mjs +64 -64
  48. package/scripts/remote-agent-ws-smoke.mjs +269 -269
  49. package/scripts/remote-fast-live-rate-smoke.mjs +343 -343
  50. package/scripts/remote-fast-mdm-browser-smoke.mjs +453 -453
  51. package/scripts/remote-fleet-render-smoke.mjs +1350 -1350
  52. package/scripts/remote-frame-ws-smoke.mjs +234 -234
  53. package/scripts/remote-http-smoke.mjs +592 -592
  54. package/scripts/remote-hub-identity-smoke.mjs +146 -146
  55. package/scripts/remote-hub-scale-smoke.mjs +124 -124
  56. package/scripts/remote-hub-smoke.mjs +699 -699
  57. package/scripts/remote-input-ws-smoke.mjs +263 -263
  58. package/scripts/remote-registry-follower-smoke.mjs +815 -815
  59. package/scripts/setup-tree-sitter-grammars.mjs +59 -59
  60. package/server.js +7510 -7510
  61. package/start-bridge.bat +32 -32
  62. package/start-bridge.sh +81 -81
  63. package/tree-sitter-grammars/README.md +18 -0
  64. package/tree-sitter-grammars/tree-sitter-c_sharp.wasm +0 -0
  65. package/tree-sitter-grammars/tree-sitter-go.wasm +0 -0
  66. package/tree-sitter-grammars/tree-sitter-java.wasm +0 -0
  67. package/tree-sitter-grammars/tree-sitter-javascript.wasm +0 -0
  68. package/tree-sitter-grammars/tree-sitter-python.wasm +0 -0
  69. package/tree-sitter-grammars/tree-sitter-rust.wasm +0 -0
  70. package/tree-sitter-grammars/tree-sitter-tsx.wasm +0 -0
  71. package/tree-sitter-grammars/tree-sitter-typescript.wasm +0 -0
  72. package/wwwroot/_content/MindExecution.Plugins.Admin/css/admin-dashboard.css +546 -546
  73. package/wwwroot/_content/MindExecution.Plugins.Directory/background.png +0 -0
  74. package/wwwroot/_content/MindExecution.Plugins.YouTube/css/youtube-search.css +251 -251
  75. package/wwwroot/_content/MindExecution.Shared/css/mind-map-overrides.css +3789 -3789
  76. package/wwwroot/_content/MindExecution.Shared/fonts/NotoSansKR-Bold.ttf +0 -0
  77. package/wwwroot/_content/MindExecution.Shared/fonts/NotoSansKR-Regular.ttf +0 -0
  78. package/wwwroot/_content/MindExecution.Shared/js/agent-visualization.js +27 -27
  79. package/wwwroot/_content/MindExecution.Shared/js/background-themes.js +1449 -1449
  80. package/wwwroot/_content/MindExecution.Shared/js/code-master.js +8316 -8316
  81. package/wwwroot/_content/MindExecution.Shared/js/file-system-helper.js +338 -338
  82. package/wwwroot/_content/MindExecution.Shared/js/marked.min.js +69 -69
  83. package/wwwroot/_content/MindExecution.Shared/js/mind-map-animated-image-preview.js +270 -270
  84. package/wwwroot/_content/MindExecution.Shared/js/mind-map-automation-edge-motion.js +170 -170
  85. package/wwwroot/_content/MindExecution.Shared/js/mind-map-board-render-ownership.js +81 -81
  86. package/wwwroot/_content/MindExecution.Shared/js/mind-map-core.js +10528 -10506
  87. package/wwwroot/_content/MindExecution.Shared/js/mind-map-core.js.backup +1059 -0
  88. package/wwwroot/_content/MindExecution.Shared/js/mind-map-css3d-hotpath.js +902 -902
  89. package/wwwroot/_content/MindExecution.Shared/js/mind-map-css3d-manager.js +24637 -24637
  90. package/wwwroot/_content/MindExecution.Shared/js/mind-map-dev-guards.js +325 -325
  91. package/wwwroot/_content/MindExecution.Shared/js/mind-map-dnd.js +1491 -1491
  92. package/wwwroot/_content/MindExecution.Shared/js/mind-map-dnd.js.bak +434 -0
  93. package/wwwroot/_content/MindExecution.Shared/js/mind-map-glow-shader.js +70 -70
  94. package/wwwroot/_content/MindExecution.Shared/js/mind-map-image-policy.js +218 -218
  95. package/wwwroot/_content/MindExecution.Shared/js/mind-map-interactions.js +7081 -7087
  96. package/wwwroot/_content/MindExecution.Shared/js/mind-map-lod-plan-worker.js +160 -160
  97. package/wwwroot/_content/MindExecution.Shared/js/mind-map-lod-renderer.js +9960 -9958
  98. package/wwwroot/_content/MindExecution.Shared/js/mind-map-lod-video-placeholder.js +107 -107
  99. package/wwwroot/_content/MindExecution.Shared/js/mind-map-logic-workers.js +1004 -1004
  100. package/wwwroot/_content/MindExecution.Shared/js/mind-map-menu-manager.js +1351 -1351
  101. package/wwwroot/_content/MindExecution.Shared/js/mind-map-multi-select.js +865 -865
  102. package/wwwroot/_content/MindExecution.Shared/js/mind-map-node-search-worker.js +554 -554
  103. package/wwwroot/_content/MindExecution.Shared/js/mind-map-nodes.js +4771 -4744
  104. package/wwwroot/_content/MindExecution.Shared/js/mind-map-normal-boundary-optimizer.js +624 -624
  105. package/wwwroot/_content/MindExecution.Shared/js/mind-map-object-manager.js +241 -241
  106. package/wwwroot/_content/MindExecution.Shared/js/mind-map-object-manager.js.backup +372 -0
  107. package/wwwroot/_content/MindExecution.Shared/js/mind-map-pipeline.js +2290 -2290
  108. package/wwwroot/_content/MindExecution.Shared/js/mind-map-remote-codecs.js +202 -202
  109. package/wwwroot/_content/MindExecution.Shared/js/mind-map-render-plan.js +1971 -1971
  110. package/wwwroot/_content/MindExecution.Shared/js/mind-map-text-lod-system.js +93 -93
  111. package/wwwroot/_content/MindExecution.Shared/js/mind-map-texture-factory.js +2391 -2391
  112. package/wwwroot/_content/MindExecution.Shared/js/mind-map-texture-factory.js.backup +1258 -0
  113. package/wwwroot/_content/MindExecution.Shared/js/mind-map-video-playback-controls.js +95 -95
  114. package/wwwroot/_content/MindExecution.Shared/js/mind-map-visibility-worker.js +895 -895
  115. package/wwwroot/_content/MindExecution.Shared/js/mindmap-toolbar.js +636 -636
  116. package/wwwroot/_content/MindExecution.Shared/js/native-drop-handler.js +45 -45
  117. package/wwwroot/_content/MindExecution.Shared/js/plan-master.js +117 -117
  118. package/wwwroot/_content/MindExecution.Shared/js/renderers/CSS3DRenderer.js +114 -114
  119. package/wwwroot/_content/MindExecution.Shared/js/texture-worker-manager.js +10 -10
  120. package/wwwroot/_content/MindExecution.Shared/js/three.min.js +6 -6
  121. package/wwwroot/_content/MindExecution.Shared/js/token-manager.js +7 -7
  122. package/wwwroot/_content/MindExecution.Shared/js/troika-bundle.js +6 -6
  123. package/wwwroot/_content/MindExecution.Shared/js/troika-bundle.js.map +2 -2
  124. package/wwwroot/_content/MindExecution.Shared/lib/font-awesome/css/all.min.css +8 -8
  125. package/wwwroot/_content/MindExecution.Shared/models/vocab.txt +30522 -30522
  126. package/wwwroot/_framework/{Google.Protobuf.33g2gb5is0.dll → Google.Protobuf.9h59ukbel7.dll} +0 -0
  127. package/wwwroot/_framework/{MindExecution.Core.z100xo4mg0.dll → MindExecution.Core.gnj3fo0pr7.dll} +0 -0
  128. package/wwwroot/_framework/{MindExecution.Kernel.i9cldrx8yc.dll → MindExecution.Kernel.1qygzf8o02.dll} +0 -0
  129. package/wwwroot/_framework/{MindExecution.Plugins.Admin.48lzqddb0a.dll → MindExecution.Plugins.Admin.n3uxh144wo.dll} +0 -0
  130. package/wwwroot/_framework/{MindExecution.Plugins.Business.7m8u1q142p.dll → MindExecution.Plugins.Business.vl5dximn25.dll} +0 -0
  131. package/wwwroot/_framework/{MindExecution.Plugins.Concept.cl5wmr53od.dll → MindExecution.Plugins.Concept.rutru9qeoi.dll} +0 -0
  132. package/wwwroot/_framework/{MindExecution.Plugins.Directory.slipi39041.dll → MindExecution.Plugins.Directory.fqbmq85het.dll} +0 -0
  133. package/wwwroot/_framework/{MindExecution.Plugins.PlanMaster.qfge05l671.dll → MindExecution.Plugins.PlanMaster.ko11cc9pll.dll} +0 -0
  134. package/wwwroot/_framework/{MindExecution.Plugins.YouTube.tn7v29ut77.dll → MindExecution.Plugins.YouTube.mt39q0to2j.dll} +0 -0
  135. package/wwwroot/_framework/MindExecution.Shared.umgls362or.dll +0 -0
  136. package/wwwroot/_framework/{MindExecution.Web.rwawrxxk38.dll → MindExecution.Web.1dwoarj2hg.dll} +0 -0
  137. package/wwwroot/_framework/{System.Collections.23yxgetbju.dll → System.Collections.zyvbaq6mpd.dll} +0 -0
  138. package/wwwroot/_framework/blazor.boot.json +25 -25
  139. package/wwwroot/_headers +40 -40
  140. package/wwwroot/_redirects +1 -1
  141. package/wwwroot/index.html +772 -772
  142. package/wwwroot/js/marketing-tool.js +180 -180
  143. package/wwwroot/manifest.webmanifest +23 -23
  144. package/wwwroot/service-worker-assets.js +109 -81
  145. package/wwwroot/service-worker.js +33 -33
  146. package/wwwroot/_framework/MindExecution.Shared.rjqlf0umjn.dll +0 -0
@@ -1,17 +1,17 @@
1
- 'use strict';
2
-
3
- const { contextBridge, ipcRenderer } = require('electron');
4
-
5
- contextBridge.exposeInMainWorld('mindExecDesktop', {
6
- updates: {
7
- getStatus: () => ipcRenderer.invoke('updates:get-status'),
8
- check: () => ipcRenderer.invoke('updates:check'),
9
- install: () => ipcRenderer.invoke('updates:install'),
10
- onStatus: callback => {
11
- if (typeof callback !== 'function') return () => undefined;
12
- const listener = (_event, payload) => callback(payload);
13
- ipcRenderer.on('updates:status', listener);
14
- return () => ipcRenderer.removeListener('updates:status', listener);
15
- }
16
- }
17
- });
1
+ 'use strict';
2
+
3
+ const { contextBridge, ipcRenderer } = require('electron');
4
+
5
+ contextBridge.exposeInMainWorld('mindExecDesktop', {
6
+ updates: {
7
+ getStatus: () => ipcRenderer.invoke('updates:get-status'),
8
+ check: () => ipcRenderer.invoke('updates:check'),
9
+ install: () => ipcRenderer.invoke('updates:install'),
10
+ onStatus: callback => {
11
+ if (typeof callback !== 'function') return () => undefined;
12
+ const listener = (_event, payload) => callback(payload);
13
+ ipcRenderer.on('updates:status', listener);
14
+ return () => ipcRenderer.removeListener('updates:status', listener);
15
+ }
16
+ }
17
+ });
@@ -1,55 +1,55 @@
1
- import assert from 'node:assert/strict';
2
- import test from 'node:test';
3
- import recurringOwnerModule from './recurring-update-owner.cjs';
4
-
5
- const {
6
- DEFAULT_UPDATE_INTERVAL_MS,
7
- createRecurringProductUpdateOwner
8
- } = recurringOwnerModule;
9
-
10
- test('default recurring update cadence is one minute after the startup check', () => {
11
- const owner = createRecurringProductUpdateOwner({
12
- manager: { check: async () => ({ state: 'current' }) },
13
- setTimer: () => ({ unref() {} }),
14
- clearTimer: () => undefined
15
- });
16
-
17
- owner.start();
18
- assert.equal(DEFAULT_UPDATE_INTERVAL_MS, 60_000);
19
- assert.equal(owner.inspect().initialDelayMs, 60_000);
20
- assert.equal(owner.inspect().intervalMs, 60_000);
21
- owner.stop();
22
- });
23
-
24
- test('one recurring owner checks once and never installs without user approval', async () => {
25
- let checkCalls = 0;
26
- let installCalls = 0;
27
- let timerCallback = null;
28
- const manager = {
29
- getStatus: () => ({ state: 'downloaded', downloaded: true }),
30
- check: async () => {
31
- checkCalls += 1;
32
- await new Promise(resolve => setTimeout(resolve, 5));
33
- return { state: 'downloaded', downloaded: true };
34
- },
35
- install: async () => { installCalls += 1; }
36
- };
37
- const owner = createRecurringProductUpdateOwner({
38
- manager,
39
- initialDelayMs: 1_000,
40
- intervalMs: 1_000,
41
- setTimer: callback => { timerCallback = callback; return { unref() {} }; },
42
- clearTimer: () => { timerCallback = null; }
43
- });
44
-
45
- owner.start();
46
- assert.equal(owner.inspect().timerCount, 1);
47
- const [first, second] = await Promise.all([owner.runNow(), owner.runNow()]);
48
- assert.equal(first.downloaded, true);
49
- assert.equal(second.downloaded, true);
50
- assert.equal(checkCalls, 1);
51
- assert.equal(installCalls, 0);
52
- assert.ok(timerCallback, 'the single next check must be re-armed');
53
- owner.stop();
54
- assert.equal(owner.inspect().timerCount, 0);
55
- });
1
+ import assert from 'node:assert/strict';
2
+ import test from 'node:test';
3
+ import recurringOwnerModule from './recurring-update-owner.cjs';
4
+
5
+ const {
6
+ DEFAULT_UPDATE_INTERVAL_MS,
7
+ createRecurringProductUpdateOwner
8
+ } = recurringOwnerModule;
9
+
10
+ test('default recurring update cadence is one minute after the startup check', () => {
11
+ const owner = createRecurringProductUpdateOwner({
12
+ manager: { check: async () => ({ state: 'current' }) },
13
+ setTimer: () => ({ unref() {} }),
14
+ clearTimer: () => undefined
15
+ });
16
+
17
+ owner.start();
18
+ assert.equal(DEFAULT_UPDATE_INTERVAL_MS, 60_000);
19
+ assert.equal(owner.inspect().initialDelayMs, 60_000);
20
+ assert.equal(owner.inspect().intervalMs, 60_000);
21
+ owner.stop();
22
+ });
23
+
24
+ test('one recurring owner checks once and never installs without user approval', async () => {
25
+ let checkCalls = 0;
26
+ let installCalls = 0;
27
+ let timerCallback = null;
28
+ const manager = {
29
+ getStatus: () => ({ state: 'downloaded', downloaded: true }),
30
+ check: async () => {
31
+ checkCalls += 1;
32
+ await new Promise(resolve => setTimeout(resolve, 5));
33
+ return { state: 'downloaded', downloaded: true };
34
+ },
35
+ install: async () => { installCalls += 1; }
36
+ };
37
+ const owner = createRecurringProductUpdateOwner({
38
+ manager,
39
+ initialDelayMs: 1_000,
40
+ intervalMs: 1_000,
41
+ setTimer: callback => { timerCallback = callback; return { unref() {} }; },
42
+ clearTimer: () => { timerCallback = null; }
43
+ });
44
+
45
+ owner.start();
46
+ assert.equal(owner.inspect().timerCount, 1);
47
+ const [first, second] = await Promise.all([owner.runNow(), owner.runNow()]);
48
+ assert.equal(first.downloaded, true);
49
+ assert.equal(second.downloaded, true);
50
+ assert.equal(checkCalls, 1);
51
+ assert.equal(installCalls, 0);
52
+ assert.ok(timerCallback, 'the single next check must be re-armed');
53
+ owner.stop();
54
+ assert.equal(owner.inspect().timerCount, 0);
55
+ });
@@ -1,97 +1,97 @@
1
- 'use strict';
2
-
3
- const MINIMUM_UPDATE_DELAY_MS = 1_000;
4
- const DEFAULT_UPDATE_INTERVAL_MS = 60_000;
5
-
6
- function normalizeDelay(value, fallback) {
7
- const delay = Number(value);
8
- return Number.isFinite(delay) && delay >= MINIMUM_UPDATE_DELAY_MS
9
- ? Math.round(delay)
10
- : fallback;
11
- }
12
-
13
- function createRecurringProductUpdateOwner({
14
- manager,
15
- canRun = () => true,
16
- initialDelayMs = DEFAULT_UPDATE_INTERVAL_MS,
17
- intervalMs = DEFAULT_UPDATE_INTERVAL_MS,
18
- setTimer = setTimeout,
19
- clearTimer = clearTimeout,
20
- onError = () => undefined
21
- } = {}) {
22
- if (!manager || typeof manager.check !== 'function') {
23
- throw new TypeError('recurring-product-update-manager-required');
24
- }
25
-
26
- const initialDelay = normalizeDelay(initialDelayMs, DEFAULT_UPDATE_INTERVAL_MS);
27
- const interval = normalizeDelay(intervalMs, DEFAULT_UPDATE_INTERVAL_MS);
28
- let stopped = true;
29
- let generation = 0;
30
- let timer = null;
31
- let running = null;
32
-
33
- const clearOwnedTimer = () => {
34
- if (!timer) return;
35
- clearTimer(timer);
36
- timer = null;
37
- };
38
-
39
- const arm = (delay, ownerGeneration) => {
40
- if (stopped || ownerGeneration !== generation || !canRun()) return;
41
- clearOwnedTimer();
42
- timer = setTimer(() => {
43
- if (stopped || ownerGeneration !== generation) return;
44
- timer = null;
45
- void runCycle(ownerGeneration);
46
- }, delay);
47
- timer?.unref?.();
48
- };
49
-
50
- const runCycle = ownerGeneration => {
51
- if (stopped || ownerGeneration !== generation || !canRun()) {
52
- return Promise.resolve(manager.getStatus?.() || { state: 'stopped' });
53
- }
54
- if (running) return running;
55
-
56
- const operation = Promise.resolve(manager.check());
57
- running = operation;
58
- void operation.catch(error => onError(error)).finally(() => {
59
- if (running === operation) running = null;
60
- arm(interval, ownerGeneration);
61
- });
62
- return operation;
63
- };
64
-
65
- return {
66
- start() {
67
- if (!stopped) return;
68
- stopped = false;
69
- generation += 1;
70
- arm(initialDelay, generation);
71
- },
72
- stop() {
73
- stopped = true;
74
- generation += 1;
75
- clearOwnedTimer();
76
- },
77
- runNow() {
78
- clearOwnedTimer();
79
- return runCycle(generation);
80
- },
81
- inspect() {
82
- return {
83
- stopped,
84
- generation,
85
- timerCount: timer ? 1 : 0,
86
- running: Boolean(running),
87
- initialDelayMs: initialDelay,
88
- intervalMs: interval
89
- };
90
- }
91
- };
92
- }
93
-
94
- module.exports = {
95
- DEFAULT_UPDATE_INTERVAL_MS,
96
- createRecurringProductUpdateOwner
97
- };
1
+ 'use strict';
2
+
3
+ const MINIMUM_UPDATE_DELAY_MS = 1_000;
4
+ const DEFAULT_UPDATE_INTERVAL_MS = 60_000;
5
+
6
+ function normalizeDelay(value, fallback) {
7
+ const delay = Number(value);
8
+ return Number.isFinite(delay) && delay >= MINIMUM_UPDATE_DELAY_MS
9
+ ? Math.round(delay)
10
+ : fallback;
11
+ }
12
+
13
+ function createRecurringProductUpdateOwner({
14
+ manager,
15
+ canRun = () => true,
16
+ initialDelayMs = DEFAULT_UPDATE_INTERVAL_MS,
17
+ intervalMs = DEFAULT_UPDATE_INTERVAL_MS,
18
+ setTimer = setTimeout,
19
+ clearTimer = clearTimeout,
20
+ onError = () => undefined
21
+ } = {}) {
22
+ if (!manager || typeof manager.check !== 'function') {
23
+ throw new TypeError('recurring-product-update-manager-required');
24
+ }
25
+
26
+ const initialDelay = normalizeDelay(initialDelayMs, DEFAULT_UPDATE_INTERVAL_MS);
27
+ const interval = normalizeDelay(intervalMs, DEFAULT_UPDATE_INTERVAL_MS);
28
+ let stopped = true;
29
+ let generation = 0;
30
+ let timer = null;
31
+ let running = null;
32
+
33
+ const clearOwnedTimer = () => {
34
+ if (!timer) return;
35
+ clearTimer(timer);
36
+ timer = null;
37
+ };
38
+
39
+ const arm = (delay, ownerGeneration) => {
40
+ if (stopped || ownerGeneration !== generation || !canRun()) return;
41
+ clearOwnedTimer();
42
+ timer = setTimer(() => {
43
+ if (stopped || ownerGeneration !== generation) return;
44
+ timer = null;
45
+ void runCycle(ownerGeneration);
46
+ }, delay);
47
+ timer?.unref?.();
48
+ };
49
+
50
+ const runCycle = ownerGeneration => {
51
+ if (stopped || ownerGeneration !== generation || !canRun()) {
52
+ return Promise.resolve(manager.getStatus?.() || { state: 'stopped' });
53
+ }
54
+ if (running) return running;
55
+
56
+ const operation = Promise.resolve(manager.check());
57
+ running = operation;
58
+ void operation.catch(error => onError(error)).finally(() => {
59
+ if (running === operation) running = null;
60
+ arm(interval, ownerGeneration);
61
+ });
62
+ return operation;
63
+ };
64
+
65
+ return {
66
+ start() {
67
+ if (!stopped) return;
68
+ stopped = false;
69
+ generation += 1;
70
+ arm(initialDelay, generation);
71
+ },
72
+ stop() {
73
+ stopped = true;
74
+ generation += 1;
75
+ clearOwnedTimer();
76
+ },
77
+ runNow() {
78
+ clearOwnedTimer();
79
+ return runCycle(generation);
80
+ },
81
+ inspect() {
82
+ return {
83
+ stopped,
84
+ generation,
85
+ timerCount: timer ? 1 : 0,
86
+ running: Boolean(running),
87
+ initialDelayMs: initialDelay,
88
+ intervalMs: interval
89
+ };
90
+ }
91
+ };
92
+ }
93
+
94
+ module.exports = {
95
+ DEFAULT_UPDATE_INTERVAL_MS,
96
+ createRecurringProductUpdateOwner
97
+ };
@@ -1,108 +1,108 @@
1
- import assert from 'node:assert/strict';
2
- import fs from 'node:fs';
3
- import path from 'node:path';
4
- import { fileURLToPath } from 'node:url';
5
- import sharp from 'sharp';
6
-
7
- const electronDirectory = path.dirname(fileURLToPath(import.meta.url));
8
- const packageRoot = path.resolve(electronDirectory, '..');
9
- const packageJson = JSON.parse(fs.readFileSync(path.join(packageRoot, 'package.json'), 'utf8'));
10
- const mainSource = fs.readFileSync(path.join(electronDirectory, 'main.cjs'), 'utf8');
11
- const preloadSource = fs.readFileSync(path.join(electronDirectory, 'preload.cjs'), 'utf8');
12
- const updateManagerSource = fs.readFileSync(path.join(electronDirectory, 'update-manager.cjs'), 'utf8');
13
- const updateFeed = JSON.parse(fs.readFileSync(path.join(electronDirectory, 'update-feed.json'), 'utf8'));
14
- const serverSource = fs.readFileSync(path.join(packageRoot, 'server.js'), 'utf8');
15
-
16
- assert.equal(packageJson.build?.appId, 'com.mindexec.desktop', 'Stable desktop appId is required.');
17
- assert.equal(packageJson.build?.productName, 'MindExec', 'Desktop product name changed unexpectedly.');
18
- assert.match(mainSource, /title:\s*'MindExec'/, 'The Electron window title must use the MindExec app brand.');
19
- assert.equal(packageJson.build?.extraMetadata?.main, 'electron/main.cjs', 'Packaged Electron entry point is missing.');
20
- assert.equal(packageJson.build?.asar, false, 'Bundled runtime executables require an unpacked app directory.');
21
- assert.ok(packageJson.files?.includes('electron/'), 'The npm package must include the Electron source contract.');
22
- assert.ok(packageJson.files?.includes('desktop-workspace-state.cjs'), 'The npm package must include desktop workspace state.');
23
- assert.match(packageJson.scripts?.['desktop:build:win'] || '', /electron-builder/, 'Windows build script is missing.');
24
- assert.match(packageJson.scripts?.['test:desktop:win'] || '', /windows-package-smoke/, 'Packaged smoke test is missing.');
25
- assert.match(packageJson.scripts?.['desktop:publish:update:dev'] || '', /--channel dev[\s\S]*--allow-unsigned[\s\S]*--publish/,
26
- 'The explicit development update publishing command is missing.');
27
- assert.equal(packageJson.dependencies?.['electron-updater'], '^6.8.9', 'The packaged updater dependency is missing.');
28
- assert.equal(packageJson.build?.extraMetadata?.desktopUpdateChannel, 'dev', 'Development installers must stay on the dev feed.');
29
- assert.equal(packageJson.build?.publish?.provider, 'generic', 'Desktop updates must use the generic R2-backed provider.');
30
- assert.equal(
31
- packageJson.build?.publish?.url,
32
- 'https://mindexec.lovecrdm.workers.dev/dev/windows/x64',
33
- 'The packaged development update URL changed unexpectedly.'
34
- );
35
- assert.equal(updateFeed.baseUrl, 'https://mindexec.lovecrdm.workers.dev', 'MindExec update hostname has a typo.');
36
- assert.equal(updateFeed.channel, 'dev', 'The packaged update feed must default to the isolated dev channel.');
37
-
38
- assert.equal(
39
- packageJson.build?.win?.icon,
40
- '../MindExecution.Web/wwwroot/app-icon-1024.png',
41
- 'Electron must build from the canonical 1024px MindExec icon.'
42
- );
43
- const builderIconPath = path.resolve(packageRoot, packageJson.build.win.icon);
44
- assert.ok(fs.existsSync(builderIconPath), `Electron builder icon is missing: ${builderIconPath}`);
45
- const builderIconMetadata = await sharp(builderIconPath).metadata();
46
- assert.equal(builderIconMetadata.width, 1024, 'Electron builder icon must be 1024px wide.');
47
- assert.equal(builderIconMetadata.height, 1024, 'Electron builder icon must be 1024px tall.');
48
- assert.equal(builderIconMetadata.hasAlpha, true, 'Electron builder icon must preserve transparency.');
49
- const { data: builderIconPixels, info: builderIconInfo } = await sharp(builderIconPath)
50
- .ensureAlpha()
51
- .raw()
52
- .toBuffer({ resolveWithObject: true });
53
- const builderIconCornerAlpha = [
54
- builderIconPixels[3],
55
- builderIconPixels[(builderIconInfo.width - 1) * 4 + 3],
56
- builderIconPixels[(builderIconInfo.height - 1) * builderIconInfo.width * 4 + 3],
57
- builderIconPixels[(builderIconInfo.width * builderIconInfo.height - 1) * 4 + 3]
58
- ];
59
- assert.ok(
60
- builderIconCornerAlpha.every((alpha) => alpha === 0),
61
- 'Electron builder icon must have fully transparent corners.'
62
- );
63
-
64
- const targets = packageJson.build?.win?.target || [];
65
- assert.ok(targets.some((target) => target.target === 'nsis'), 'NSIS target is required.');
66
- assert.ok(targets.some((target) => target.target === 'portable'), 'Portable target is required.');
67
-
68
- assert.match(mainSource, /contextIsolation:\s*true/, 'Electron renderer isolation must remain enabled.');
69
- assert.match(mainSource, /nodeIntegration:\s*false/, 'Node integration must remain disabled.');
70
- assert.match(mainSource, /sandbox:\s*true/, 'Electron renderer sandbox must remain enabled.');
71
- assert.match(mainSource, /preload:\s*path\.join\(__dirname, 'preload\.cjs'\)/, 'The isolated updater preload is missing.');
72
- assert.match(mainSource, /runtimeMode:\s*'bundled'/, 'Packaged runtime must report bundled mode.');
73
- assert.match(mainSource, /spawnBundledBridge/, 'Electron must start its bundled LocalBridge.');
74
- assert.match(mainSource, /wwwroot.*index\.html/s, 'Electron must verify its bundled frontend.');
75
- assert.match(mainSource, /resolveDedicatedPort/, 'Electron must allocate dedicated local ports.');
76
- assert.doesNotMatch(mainSource, /adopted|probeBridge/, 'Electron must not adopt an external LocalBridge.');
77
- assert.match(mainSource, /MINDEXEC_DESKTOP_SMOKE_RESULT/, 'Packaged runtime smoke contract is missing.');
78
- assert.match(mainSource, /icon:\s*resolveDesktopIconPath\(\)/, 'Electron windows must use the packaged MindExec icon.');
79
- assert.match(mainSource, /app\.setAppUserModelId\(DESKTOP_APP_ID\)/, 'Windows taskbar identity must use the stable app id.');
80
- assert.match(mainSource, /resolveDesktopWorkspace/, 'Electron startup must restore the last desktop workspace.');
81
- assert.match(mainSource, /MINDEXEC_DESKTOP_WORKSPACE_STATE_PATH/, 'Electron must share its workspace state path with LocalBridge.');
82
- assert.match(mainSource, /resolveDesktopInstallKind/, 'Installed, portable, and unpacked update behavior must remain separate.');
83
- assert.match(mainSource, /createProductUpdateManager/, 'The Electron update manager is not wired into the app.');
84
- assert.match(mainSource, /updates:get-status/, 'The updater status IPC contract is missing.');
85
- assert.match(mainSource, /updates:check/, 'The manual updater check IPC contract is missing.');
86
- assert.match(mainSource, /updates:install/, 'The updater install IPC contract is missing.');
87
- assert.match(mainSource, /await stopBundledBridge\(\)[\s\S]{0,180}await waitForBundledRuntimePortsReleased\(\)/,
88
- 'The Bridge and RemoteHub ports must reach zero before the installer starts.');
89
- assert.match(mainSource, /Restart and update/, 'A downloaded update must ask before restarting active work.');
90
- assert.match(preloadSource, /mindExecDesktop/, 'The updater preload namespace changed unexpectedly.');
91
- assert.match(preloadSource, /updates:\s*\{/, 'The updater preload API is missing.');
92
- assert.match(updateManagerSource, /autoDownload\s*=\s*false/, 'Updates must not download through an unowned implicit path.');
93
- assert.match(updateManagerSource, /autoInstallOnAppQuit\s*=\s*false/, 'Updates must not restart without the explicit prompt path.');
94
- assert.match(updateManagerSource, /quitAndInstall\(true, true\)/, 'Downloaded updates must relaunch silently after approval.');
95
- assert.match(updateManagerSource, /desktop-updates-require-installed-windows-app/,
96
- 'Portable and unpacked builds must fail closed instead of replacing themselves.');
97
- assert.match(serverSource, /saveDesktopWorkspaceState\(DESKTOP_WORKSPACE_STATE_PATH, resolvedPath\)/,
98
- 'A successful desktop workspace switch must be saved for the next launch.');
99
-
100
- console.log(JSON.stringify({
101
- ok: true,
102
- appId: packageJson.build.appId,
103
- version: packageJson.version,
104
- runtimeMode: 'bundled',
105
- icon: packageJson.build.win.icon,
106
- updateFeed: `${updateFeed.baseUrl}/${updateFeed.channel}/windows/x64`,
107
- targets: targets.map((target) => `${target.target}:${target.arch.join(',')}`)
108
- }));
1
+ import assert from 'node:assert/strict';
2
+ import fs from 'node:fs';
3
+ import path from 'node:path';
4
+ import { fileURLToPath } from 'node:url';
5
+ import sharp from 'sharp';
6
+
7
+ const electronDirectory = path.dirname(fileURLToPath(import.meta.url));
8
+ const packageRoot = path.resolve(electronDirectory, '..');
9
+ const packageJson = JSON.parse(fs.readFileSync(path.join(packageRoot, 'package.json'), 'utf8'));
10
+ const mainSource = fs.readFileSync(path.join(electronDirectory, 'main.cjs'), 'utf8');
11
+ const preloadSource = fs.readFileSync(path.join(electronDirectory, 'preload.cjs'), 'utf8');
12
+ const updateManagerSource = fs.readFileSync(path.join(electronDirectory, 'update-manager.cjs'), 'utf8');
13
+ const updateFeed = JSON.parse(fs.readFileSync(path.join(electronDirectory, 'update-feed.json'), 'utf8'));
14
+ const serverSource = fs.readFileSync(path.join(packageRoot, 'server.js'), 'utf8');
15
+
16
+ assert.equal(packageJson.build?.appId, 'com.mindexec.desktop', 'Stable desktop appId is required.');
17
+ assert.equal(packageJson.build?.productName, 'MindExec', 'Desktop product name changed unexpectedly.');
18
+ assert.match(mainSource, /title:\s*'MindExec'/, 'The Electron window title must use the MindExec app brand.');
19
+ assert.equal(packageJson.build?.extraMetadata?.main, 'electron/main.cjs', 'Packaged Electron entry point is missing.');
20
+ assert.equal(packageJson.build?.asar, false, 'Bundled runtime executables require an unpacked app directory.');
21
+ assert.ok(packageJson.files?.includes('electron/'), 'The npm package must include the Electron source contract.');
22
+ assert.ok(packageJson.files?.includes('desktop-workspace-state.cjs'), 'The npm package must include desktop workspace state.');
23
+ assert.match(packageJson.scripts?.['desktop:build:win'] || '', /electron-builder/, 'Windows build script is missing.');
24
+ assert.match(packageJson.scripts?.['test:desktop:win'] || '', /windows-package-smoke/, 'Packaged smoke test is missing.');
25
+ assert.match(packageJson.scripts?.['desktop:publish:update:dev'] || '', /--channel dev[\s\S]*--allow-unsigned[\s\S]*--publish/,
26
+ 'The explicit development update publishing command is missing.');
27
+ assert.equal(packageJson.dependencies?.['electron-updater'], '^6.8.9', 'The packaged updater dependency is missing.');
28
+ assert.equal(packageJson.build?.extraMetadata?.desktopUpdateChannel, 'dev', 'Development installers must stay on the dev feed.');
29
+ assert.equal(packageJson.build?.publish?.provider, 'generic', 'Desktop updates must use the generic R2-backed provider.');
30
+ assert.equal(
31
+ packageJson.build?.publish?.url,
32
+ 'https://mindexec.lovecrdm.workers.dev/dev/windows/x64',
33
+ 'The packaged development update URL changed unexpectedly.'
34
+ );
35
+ assert.equal(updateFeed.baseUrl, 'https://mindexec.lovecrdm.workers.dev', 'MindExec update hostname has a typo.');
36
+ assert.equal(updateFeed.channel, 'dev', 'The packaged update feed must default to the isolated dev channel.');
37
+
38
+ assert.equal(
39
+ packageJson.build?.win?.icon,
40
+ '../MindExecution.Web/wwwroot/app-icon-1024.png',
41
+ 'Electron must build from the canonical 1024px MindExec icon.'
42
+ );
43
+ const builderIconPath = path.resolve(packageRoot, packageJson.build.win.icon);
44
+ assert.ok(fs.existsSync(builderIconPath), `Electron builder icon is missing: ${builderIconPath}`);
45
+ const builderIconMetadata = await sharp(builderIconPath).metadata();
46
+ assert.equal(builderIconMetadata.width, 1024, 'Electron builder icon must be 1024px wide.');
47
+ assert.equal(builderIconMetadata.height, 1024, 'Electron builder icon must be 1024px tall.');
48
+ assert.equal(builderIconMetadata.hasAlpha, true, 'Electron builder icon must preserve transparency.');
49
+ const { data: builderIconPixels, info: builderIconInfo } = await sharp(builderIconPath)
50
+ .ensureAlpha()
51
+ .raw()
52
+ .toBuffer({ resolveWithObject: true });
53
+ const builderIconCornerAlpha = [
54
+ builderIconPixels[3],
55
+ builderIconPixels[(builderIconInfo.width - 1) * 4 + 3],
56
+ builderIconPixels[(builderIconInfo.height - 1) * builderIconInfo.width * 4 + 3],
57
+ builderIconPixels[(builderIconInfo.width * builderIconInfo.height - 1) * 4 + 3]
58
+ ];
59
+ assert.ok(
60
+ builderIconCornerAlpha.every((alpha) => alpha === 0),
61
+ 'Electron builder icon must have fully transparent corners.'
62
+ );
63
+
64
+ const targets = packageJson.build?.win?.target || [];
65
+ assert.ok(targets.some((target) => target.target === 'nsis'), 'NSIS target is required.');
66
+ assert.ok(targets.some((target) => target.target === 'portable'), 'Portable target is required.');
67
+
68
+ assert.match(mainSource, /contextIsolation:\s*true/, 'Electron renderer isolation must remain enabled.');
69
+ assert.match(mainSource, /nodeIntegration:\s*false/, 'Node integration must remain disabled.');
70
+ assert.match(mainSource, /sandbox:\s*true/, 'Electron renderer sandbox must remain enabled.');
71
+ assert.match(mainSource, /preload:\s*path\.join\(__dirname, 'preload\.cjs'\)/, 'The isolated updater preload is missing.');
72
+ assert.match(mainSource, /runtimeMode:\s*'bundled'/, 'Packaged runtime must report bundled mode.');
73
+ assert.match(mainSource, /spawnBundledBridge/, 'Electron must start its bundled LocalBridge.');
74
+ assert.match(mainSource, /wwwroot.*index\.html/s, 'Electron must verify its bundled frontend.');
75
+ assert.match(mainSource, /resolveDedicatedPort/, 'Electron must allocate dedicated local ports.');
76
+ assert.doesNotMatch(mainSource, /adopted|probeBridge/, 'Electron must not adopt an external LocalBridge.');
77
+ assert.match(mainSource, /MINDEXEC_DESKTOP_SMOKE_RESULT/, 'Packaged runtime smoke contract is missing.');
78
+ assert.match(mainSource, /icon:\s*resolveDesktopIconPath\(\)/, 'Electron windows must use the packaged MindExec icon.');
79
+ assert.match(mainSource, /app\.setAppUserModelId\(DESKTOP_APP_ID\)/, 'Windows taskbar identity must use the stable app id.');
80
+ assert.match(mainSource, /resolveDesktopWorkspace/, 'Electron startup must restore the last desktop workspace.');
81
+ assert.match(mainSource, /MINDEXEC_DESKTOP_WORKSPACE_STATE_PATH/, 'Electron must share its workspace state path with LocalBridge.');
82
+ assert.match(mainSource, /resolveDesktopInstallKind/, 'Installed, portable, and unpacked update behavior must remain separate.');
83
+ assert.match(mainSource, /createProductUpdateManager/, 'The Electron update manager is not wired into the app.');
84
+ assert.match(mainSource, /updates:get-status/, 'The updater status IPC contract is missing.');
85
+ assert.match(mainSource, /updates:check/, 'The manual updater check IPC contract is missing.');
86
+ assert.match(mainSource, /updates:install/, 'The updater install IPC contract is missing.');
87
+ assert.match(mainSource, /await stopBundledBridge\(\)[\s\S]{0,180}await waitForBundledRuntimePortsReleased\(\)/,
88
+ 'The Bridge and RemoteHub ports must reach zero before the installer starts.');
89
+ assert.match(mainSource, /Restart and update/, 'A downloaded update must ask before restarting active work.');
90
+ assert.match(preloadSource, /mindExecDesktop/, 'The updater preload namespace changed unexpectedly.');
91
+ assert.match(preloadSource, /updates:\s*\{/, 'The updater preload API is missing.');
92
+ assert.match(updateManagerSource, /autoDownload\s*=\s*false/, 'Updates must not download through an unowned implicit path.');
93
+ assert.match(updateManagerSource, /autoInstallOnAppQuit\s*=\s*false/, 'Updates must not restart without the explicit prompt path.');
94
+ assert.match(updateManagerSource, /quitAndInstall\(true, true\)/, 'Downloaded updates must relaunch silently after approval.');
95
+ assert.match(updateManagerSource, /desktop-updates-require-installed-windows-app/,
96
+ 'Portable and unpacked builds must fail closed instead of replacing themselves.');
97
+ assert.match(serverSource, /saveDesktopWorkspaceState\(DESKTOP_WORKSPACE_STATE_PATH, resolvedPath\)/,
98
+ 'A successful desktop workspace switch must be saved for the next launch.');
99
+
100
+ console.log(JSON.stringify({
101
+ ok: true,
102
+ appId: packageJson.build.appId,
103
+ version: packageJson.version,
104
+ runtimeMode: 'bundled',
105
+ icon: packageJson.build.win.icon,
106
+ updateFeed: `${updateFeed.baseUrl}/${updateFeed.channel}/windows/x64`,
107
+ targets: targets.map((target) => `${target.target}:${target.arch.join(',')}`)
108
+ }));