arcane-os 0.5.9 → 0.5.10

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/CHANGELOG.md CHANGED
@@ -1,5 +1,14 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.5.10
4
+
5
+ - Show one Windows performance-GPU flag advisory for the current Chromium
6
+ browser, including Edge, Brave, Opera, and Vivaldi. Browsers that conceal
7
+ their identity use their own flags page through the generic `about://` address.
8
+ - Make the notice conditional on having multiple GPUs, cover every observed
9
+ GPU vendor, and omit the notice on Firefox, Safari, mobile, and non-Windows
10
+ platforms. No additional GPU flags or automatic settings changes are included.
11
+
3
12
  ## 0.5.9
4
13
 
5
14
  - Renamed the built-in TWiN Cloud provider and default-model preference sentinel
package/README.md CHANGED
@@ -19,7 +19,7 @@ version-locked SDK runtime, while an integrated Arcane checkout uses its live
19
19
  `arcane/` runtime. Both profiles preserve the same app URLs, theme, packaging,
20
20
  event, cancellation, and browser run contracts.
21
21
 
22
- This checkout defines the `0.5.9` SDK contract. Applications pin one exact npm
22
+ This checkout defines the `0.5.10` SDK contract. Applications pin one exact npm
23
23
  version and lockfile; registry state is deliberately not baked into application
24
24
  artifacts.
25
25
 
@@ -204,7 +204,7 @@ uses the same controller for automatic memory extraction.
204
204
  Create a new repository-shaped Arcane application with the exact stable SDK:
205
205
 
206
206
  ```bash
207
- npx arcane-os@0.5.9 new my-app --path ./my-app --target portable --git
207
+ npx arcane-os@0.5.10 new my-app --path ./my-app --target portable --git
208
208
  cd my-app
209
209
  npm install
210
210
  npm run check
@@ -215,7 +215,7 @@ To enroll an existing repository, install the exact SDK and initialize only
215
215
  missing Arcane files:
216
216
 
217
217
  ```bash
218
- npm install --save-dev --save-exact arcane-os@0.5.9
218
+ npm install --save-dev --save-exact arcane-os@0.5.10
219
219
  npm exec -- arcane init my-app --target portable
220
220
  ```
221
221
 
@@ -231,7 +231,7 @@ npm exec -- arcane-os targets
231
231
  No global SDK install or standalone Arcane CLI is required. The application
232
232
  repository's exact npm dependency and lockfile own the CLI and toolchain version.
233
233
 
234
- Use `npx arcane-os@0.5.9` for the initial bootstrap because it names this npm
234
+ Use `npx arcane-os@0.5.10` for the initial bootstrap because it names this npm
235
235
  package explicitly; bare `npx arcane` outside an installed project could resolve
236
236
  a different package. Both installed commands invoke the same headless toolchain.
237
237
  Project-local npm scripts use the SDK pinned by that app's `package-lock.json`,
@@ -252,7 +252,7 @@ node ./bin/arcane.mjs new local-app --path ../local-app --target portable --git
252
252
 
253
253
  # From the generated app repository
254
254
  cd ../local-app
255
- npm install --save-dev --save-exact ../arcane-os-sdk/arcane-os-0.5.9.tgz
255
+ npm install --save-dev --save-exact ../arcane-os-sdk/arcane-os-0.5.10.tgz
256
256
  npm run check
257
257
  npm ci
258
258
  ```
@@ -262,7 +262,7 @@ same location. The lockfile retains the selected package dependency while
262
262
  Arcane uses the installed package name and version. Local directory `file:` dependencies are not
263
263
  accepted because npm may install them as links; use a packed `.tgz`. A GitHub
264
264
  runner also needs that tarball at the locked path. After publication, replace
265
- the local declaration with the exact `arcane-os@0.5.9` registry package and
265
+ the local declaration with the exact `arcane-os@0.5.10` registry package and
266
266
  commit the regenerated lock.
267
267
 
268
268
  Generated repositories use `npm ci --ignore-scripts` in CI. Run dependency
@@ -400,7 +400,7 @@ package installation, or assertions.
400
400
 
401
401
  ## Current target support
402
402
 
403
- Version `0.5.9` exposes one browser target and five explicitly paired
403
+ Version `0.5.10` exposes one browser target and five explicitly paired
404
404
  native development targets: a non-runnable portable directory, a
405
405
  Windows x64 unsigned-local-test EXE bundle, Linux x64 and Linux ARM64
406
406
  unsigned-local-test DEBs, and an Android development-signed APK. The
@@ -20,15 +20,12 @@ const AI_PROVIDER_PROTOCOL = "arcane-ai-provider/2";
20
20
  const AI_MODEL_AUTHORITY_PROTOCOL = "arcane-ai-model-authority/1";
21
21
  const WEBGPU_ADAPTER_SELECTED_EVENT = "arcane.ai.browser-wasm.webgpu.adapter.selected";
22
22
  const WEBGPU_ADAPTER_SELECTION_PROTOCOL = "arcane-ai-webgpu-adapter-selection/1";
23
- const CHROME_HIGH_PERFORMANCE_GPU_FLAG_URL =
24
- "chrome://flags/#force-high-performance-gpu";
25
23
  const MODEL_LOAD_HEARTBEAT_MS = 5_000;
26
24
  const DEFAULT_MODEL_DOWNLOAD_CONCURRENCY = 4;
27
25
  const MODEL_DOWNLOAD_PROGRESS_INTERVAL_MS = 250;
28
26
  const MODEL_DOWNLOAD_SPEED_WINDOW_MS = 5_000;
29
27
  const MODEL_DOWNLOAD_MAX_RANGE_PARTS = 4_096;
30
28
  const MODEL_DOWNLOAD_TARGET_RANGE_BYTES = 4_000_000;
31
- const INTEL_VENDOR_ID = 0x8086;
32
29
  const CAPABILITY_POLICY_PROTOCOL = "arcane-ai-browser-capability-policy/1";
33
30
  let highPerformanceGpuNoticeShown = false;
34
31
 
@@ -263,44 +260,71 @@ function publicDescriptor(source) {
263
260
  return modelDescriptor(source);
264
261
  }
265
262
 
266
- function isChromeBrowser() {
267
- const userAgent = String(globalThis.navigator?.userAgent ?? "");
268
- return /\b(?:Chrome|Chromium)\//u.test(userAgent)
269
- && !/\b(?:Edg|OPR)\//u.test(userAgent);
270
- }
263
+ function highPerformanceGpuBrowser() {
264
+ const navigatorObject = globalThis.navigator;
265
+ const userAgent = String(navigatorObject?.userAgent ?? "");
266
+ const clientHints = navigatorObject?.userAgentData;
267
+ const platform = String(clientHints?.platform || navigatorObject?.platform || userAgent);
268
+ if (
269
+ !/\b(?:Windows|Win32|Win64)\b/iu.test(platform)
270
+ || clientHints?.mobile === true
271
+ || /\b(?:Android|iPhone|iPad|iPod|Mobile)\b/iu.test(userAgent)
272
+ ) {
273
+ return null;
274
+ }
271
275
 
272
- function isLowerPowerIntelAdapter(adapter) {
273
- const identity = [
274
- adapter.vendor,
275
- adapter.architecture,
276
- adapter.name,
277
- adapter.description,
278
- ].filter(Boolean).join(" ");
279
- if (adapter?.vendorId !== INTEL_VENDOR_ID && !/\bintel\b/iu.test(identity)) return false;
280
- return /(?:intel|integrated|xe-lp)/iu.test(identity);
276
+ const brands = new Set();
277
+ for (const entry of clientHints?.brands ?? []) {
278
+ brands.add(entry.brand);
279
+ }
280
+ // Vivaldi can append its identity while also identifying as Edge or Chrome.
281
+ if (brands.has("Vivaldi") || /\bVivaldi\//u.test(userAgent)) {
282
+ return { name: "Vivaldi", url: "vivaldi://flags/#force-high-performance-gpu" };
283
+ }
284
+ if (brands.has("Brave") || typeof navigatorObject?.brave?.isBrave === "function") {
285
+ return { name: "Brave", url: "brave://flags/#force-high-performance-gpu" };
286
+ }
287
+ if (brands.has("Opera") || /\bOPR\//u.test(userAgent)) {
288
+ return { name: "Opera", url: "opera://flags/#force-high-performance-gpu" };
289
+ }
290
+ if (brands.has("Microsoft Edge") || /\bEdg\//u.test(userAgent)) {
291
+ return { name: "Microsoft Edge", url: "edge://flags/#force-high-performance-gpu" };
292
+ }
293
+ if (
294
+ brands.has("Chromium")
295
+ || brands.has("Google Chrome")
296
+ || /\b(?:Chrome|Chromium)\//u.test(userAgent)
297
+ ) {
298
+ // Some Chromium browsers mask their brand. about:// uses their own flags page.
299
+ return { name: "your browser", url: "about://flags/#force-high-performance-gpu" };
300
+ }
301
+ return null;
281
302
  }
282
303
 
283
- function notifyChromeHighPerformanceGpu(adapter) {
284
- if (
285
- highPerformanceGpuNoticeShown
286
- || !isChromeBrowser()
287
- || !isLowerPowerIntelAdapter(adapter)
288
- ) return;
289
- highPerformanceGpuNoticeShown = true;
290
- try {
291
- globalThis.open?.(CHROME_HIGH_PERFORMANCE_GPU_FLAG_URL, "_blank", "noopener,noreferrer");
292
- } catch {
293
- // Chrome may reject internal-page navigation from web content.
294
- }
295
- const adapterName = adapter.description || adapter.name
296
- || [adapter.vendor, adapter.architecture].filter(Boolean).join(" ")
297
- || "a lower-power Intel adapter";
298
- globalThis.alert?.(
299
- `Arcane selected the lower-power WebGPU adapter: ${adapterName}.\n\n`
300
- + "Enable “Force High Performance GPU” in the Chrome flags window. "
301
- + "Then completely close every Chrome window and reopen Chrome before loading the model again.\n\n"
302
- + `If the flags window did not open, paste ${CHROME_HIGH_PERFORMANCE_GPU_FLAG_URL} into Chrome.`,
303
- );
304
+ function notifyHighPerformanceGpu(adapter) {
305
+ if (highPerformanceGpuNoticeShown) {
306
+ return;
307
+ }
308
+ const browser = highPerformanceGpuBrowser();
309
+ if (!browser) {
310
+ return;
311
+ }
312
+ highPerformanceGpuNoticeShown = true;
313
+ try {
314
+ globalThis.open?.(browser.url, "_blank", "noopener,noreferrer");
315
+ } catch {
316
+ // Browsers may reject internal-page navigation from web content.
317
+ }
318
+ const adapterName = adapter.description || adapter.name
319
+ || [adapter.vendor, adapter.architecture].filter(Boolean).join(" ")
320
+ || "the available WebGPU adapter";
321
+ globalThis.alert?.(
322
+ `Selected WebGPU adapter: ${adapterName}.\n\n`
323
+ + `If this computer has multiple GPUs, enable “Force High Performance GPU” in ${browser.name} `
324
+ + "to request the high-performance GPU when available. "
325
+ + `Then completely close and reopen ${browser.name} before loading the model again.\n\n`
326
+ + `If the flags page did not open, paste ${browser.url} into the address bar.`,
327
+ );
304
328
  }
305
329
 
306
330
  function emitWebgpuAdapterSelection(source, runtime) {
@@ -322,7 +346,7 @@ function emitWebgpuAdapterSelection(source, runtime) {
322
346
  category: "capability",
323
347
  }));
324
348
  } finally {
325
- notifyChromeHighPerformanceGpu(webgpu.adapter);
349
+ notifyHighPerformanceGpu(webgpu.adapter);
326
350
  }
327
351
  }
328
352
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "arcane-os",
3
- "version": "0.5.9",
3
+ "version": "0.5.10",
4
4
  "description": "Arcane OS JavaScript SDK, project-local CLI, browser runtime, and repository-portable application packager.",
5
5
  "type": "module",
6
6
  "main": "./src/index.mjs",
@@ -54,7 +54,7 @@
54
54
  "test": "npm run test:unit && npm run test:functional && npm run test:integration && npm run test:regression",
55
55
  "test:release": "node ./bin/arcane-test.mjs test/npm-release.test.mjs",
56
56
  "test:unit": "node ./bin/arcane-test.mjs test/app-descriptor.test.mjs test/app-schema.test.mjs test/contracts.test.mjs test/doctor.test.mjs test/mail-credentials.test.mjs test/mail-outbox.test.mjs test/mail-public-api.test.mjs test/mail-send.test.mjs test/mail-transport.test.mjs test/targets.test.mjs test/workspace-operation-lock.test.mjs",
57
- "test:functional": "node ./bin/arcane-test.mjs test/browser-speech-providers.test.mjs test/browser-wasm-download-resume.test.mjs test/cli.test.mjs test/dbopfs-document-library.test.mjs test/dev-server.test.mjs test/dom-event-instrumentation.test.mjs test/event-manager.test.mjs test/events.test.mjs test/import-map.test.mjs test/mail-cli.test.mjs test/mail-runtime.test.mjs test/mail-server.test.mjs test/packaging.test.mjs test/persistent-ai-chat-session.test.mjs test/reference-completeness.test.mjs test/runtime-api-behavior.test.mjs test/runtime.test.mjs test/scaffold.test.mjs test/site.test.mjs test/update-check.test.mjs",
57
+ "test:functional": "node ./bin/arcane-test.mjs test/browser-speech-providers.test.mjs test/browser-wasm-gpu-notice.test.mjs test/browser-wasm-download-resume.test.mjs test/cli.test.mjs test/dbopfs-document-library.test.mjs test/dev-server.test.mjs test/dom-event-instrumentation.test.mjs test/event-manager.test.mjs test/events.test.mjs test/import-map.test.mjs test/mail-cli.test.mjs test/mail-runtime.test.mjs test/mail-server.test.mjs test/packaging.test.mjs test/persistent-ai-chat-session.test.mjs test/reference-completeness.test.mjs test/runtime-api-behavior.test.mjs test/runtime.test.mjs test/scaffold.test.mjs test/site.test.mjs test/update-check.test.mjs",
58
58
  "test:integration": "node ./bin/arcane-test.mjs test/integrated-shared.test.mjs test/integrated-workspace.test.mjs test/mail-browser.test.mjs test/native-plan.test.mjs test/native-provider-loader.test.mjs test/npm-release.test.mjs test/release-bundle.test.mjs test/release-capability-smoke.test.mjs test/shared-payload-batch.test.mjs test/tarball.test.mjs test/wllama-webgpu-runtime.test.mjs",
59
59
  "test:regression": "node ./bin/arcane-test.mjs test/channel-workflows.test.mjs test/native-provider-generation.test.mjs test/testing.test.mjs test/test-sets.test.mjs",
60
60
  "check": "node tools/check-source.mjs && npm test",