arcane-os 0.1.2 → 0.2.0

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 (52) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/NOTICE +5 -3
  3. package/README.md +73 -24
  4. package/browser-runtime/ARCANE_SDK_BROWSER_RELEASE.json +67 -18
  5. package/browser-runtime/ai/ARCANE_AI_BROWSER_WASM_COMPONENTS.json +16 -5
  6. package/browser-runtime/ai/browser-kokoro-worker.mjs +3 -0
  7. package/browser-runtime/ai/browser-speech-artifacts.mjs +1108 -0
  8. package/browser-runtime/ai/browser-speech-providers.mjs +475 -0
  9. package/browser-runtime/ai/browser-speech.mjs +9 -0
  10. package/browser-runtime/ai/browser-wasm-llm-provider.mjs +1537 -167
  11. package/browser-runtime/ai/browser-wasm.mjs +46 -1
  12. package/browser-runtime/ai/browser-whisper-worker.mjs +3 -0
  13. package/browser-runtime/ai/browser-wllama-runtime.mjs +677 -132
  14. package/browser-runtime/ai/model-controller.mjs +138 -12
  15. package/browser-runtime/ai/speech-worker-client.mjs +207 -0
  16. package/browser-runtime/ai/speech-worker-runtime.mjs +516 -0
  17. package/browser-runtime/ai/wllama/index.mjs +389 -0
  18. package/docs/architecture.md +132 -22
  19. package/docs/reference/README.md +1 -1
  20. package/docs/reference/ai/browser-wasm.md +101 -42
  21. package/docs/reference/availability-and-normalization.md +19 -5
  22. package/docs/reference/behavioral-testing.md +18 -5
  23. package/docs/reference/cli.md +2 -2
  24. package/docs/reference/inventory/package-api.json +14 -14
  25. package/docs/reference/protocols.md +4 -4
  26. package/docs/reference/sdk-api.md +68 -38
  27. package/docs/work-amplification.md +8 -4
  28. package/package.json +7 -3
  29. package/runtime/ARCANE_RUNTIME_RELEASE.json +50 -20
  30. package/runtime/arcane/components/chat.html +280 -62
  31. package/runtime/arcane/components/speech.html +1113 -265
  32. package/runtime/arcane/entities/Chat.js +246 -43
  33. package/runtime/arcane/modules/AI.js +713 -162
  34. package/runtime/arcane/modules/AIProviderRuntime.js +2289 -0
  35. package/runtime/arcane/modules/AIRuntimeState.js +872 -0
  36. package/runtime/arcane/modules/ConfiguredAIChatSession.js +293 -27
  37. package/runtime/arcane/modules/DBOPFSDocumentLibrary.js +682 -0
  38. package/runtime/arcane/modules/DocumentLexicalSearch.js +292 -0
  39. package/runtime/arcane/modules/PersistentAIChatSession.js +268 -0
  40. package/runtime/arcane/modules/StaticDocumentCatalog.js +25 -206
  41. package/schemas/arcane-lock.schema.json +6 -4
  42. package/src/cli/main.mjs +14 -2
  43. package/src/constants.mjs +1 -1
  44. package/src/dev-server.mjs +244 -13
  45. package/src/import-map.mjs +59 -1
  46. package/src/packager/core.mjs +2 -2
  47. package/src/runtime.mjs +14 -4
  48. package/src/sdk-browser-runtime.mjs +28 -75
  49. package/src/templates/workspace-template.mjs +4 -4
  50. package/src/toolchain.mjs +3 -0
  51. package/src/workspace-runtime.mjs +1 -1
  52. package/src/workspace.mjs +1 -1
@@ -3476,6 +3476,395 @@ var Wllama = class {
3476
3476
  return workerResources;
3477
3477
  }
3478
3478
  };
3479
+ (function applyArcaneWllamaProjection() {
3480
+ const protocol = "arcane-wllama-webgpu-evidence/1";
3481
+ const emptyWorkerTelemetry = `{protocol:"${protocol}",adapter:null,bufferCount:0,bufferBytes:0,queueSubmissions:0,commandBuffers:0,queueFenceRequests:0,queueFenceCompletions:0,invalid:false}`;
3482
+
3483
+ function replaceSingle(source, search, replacement, label) {
3484
+ const first = source.indexOf(search);
3485
+ const last = source.lastIndexOf(search);
3486
+ if (first < 0 || first !== last) {
3487
+ throw new Error(`Pinned Wllama ${label} projection anchor must occur exactly once.`);
3488
+ }
3489
+ return `${source.slice(0, first)}${replacement}${source.slice(first + search.length)}`;
3490
+ }
3491
+
3492
+ const adapterAnchor = "if(adapter){WebGPU.Internals.jsObjectInsert(adapterPtr,adapter)";
3493
+ const adapterProjection = `if(adapter){(function arcaneRecordSelectedWebgpuAdapter(){const key="__arcaneWllamaWebgpuTelemetry";const previous=globalThis[key]??${emptyWorkerTelemetry};const info=adapter.info??{};const text=value=>typeof value==="string"?value.slice(0,256):"";const next={selected:true,vendorId:null,vendor:text(info.vendor),architecture:text(info.architecture),deviceId:null,name:text(info.device),description:text(info.description)};const conflicts=previous.adapter!==null&&JSON.stringify(previous.adapter)!==JSON.stringify(next);globalThis[key]={protocol:"${protocol}",adapter:previous.adapter??next,bufferCount:previous.bufferCount,bufferBytes:previous.bufferBytes,queueSubmissions:previous.queueSubmissions,commandBuffers:previous.commandBuffers,queueFenceRequests:previous.queueFenceRequests,queueFenceCompletions:previous.queueFenceCompletions,invalid:previous.invalid||conflicts}})();WebGPU.Internals.jsObjectInsert(adapterPtr,adapter)`;
3494
+ WLLAMA_EMSCRIPTEN_CODE = replaceSingle(
3495
+ WLLAMA_EMSCRIPTEN_CODE,
3496
+ adapterAnchor,
3497
+ adapterProjection,
3498
+ "WebGPU adapter selection",
3499
+ );
3500
+
3501
+ const bufferAnchor = "var buffer;try{buffer=device.createBuffer(desc)}catch(ex){return false}WebGPU.Internals.jsObjectInsert(bufferPtr,buffer)";
3502
+ const bufferProjection = `${bufferAnchor};(function arcaneRecordWebgpuBuffer(){const key="__arcaneWllamaWebgpuTelemetry";const previous=globalThis[key]??${emptyWorkerTelemetry};const size=desc.size;const bufferCount=previous.bufferCount+1;const bufferBytes=previous.bufferBytes+size;globalThis[key]={protocol:"${protocol}",adapter:previous.adapter,bufferCount:Number.isSafeInteger(bufferCount)?bufferCount:previous.bufferCount,bufferBytes:Number.isSafeInteger(size)&&size>0&&Number.isSafeInteger(bufferBytes)?bufferBytes:previous.bufferBytes,queueSubmissions:previous.queueSubmissions,commandBuffers:previous.commandBuffers,queueFenceRequests:previous.queueFenceRequests,queueFenceCompletions:previous.queueFenceCompletions,invalid:previous.invalid||!Number.isSafeInteger(size)||size<1||!Number.isSafeInteger(bufferCount)||!Number.isSafeInteger(bufferBytes)}})()`;
3503
+ WLLAMA_EMSCRIPTEN_CODE = replaceSingle(
3504
+ WLLAMA_EMSCRIPTEN_CODE,
3505
+ bufferAnchor,
3506
+ bufferProjection,
3507
+ "WebGPU buffer",
3508
+ );
3509
+
3510
+ const queueAnchor = "queue.submit(cmds)};function _wgpuQueueWriteBuffer";
3511
+ const queueProjection = `queue.submit(cmds);(function arcaneRecordWebgpuSubmission(){const key="__arcaneWllamaWebgpuTelemetry";const previous=globalThis[key]??${emptyWorkerTelemetry};const queueSubmissions=previous.queueSubmissions+1;const commandBuffers=previous.commandBuffers+cmds.length;globalThis[key]={protocol:"${protocol}",adapter:previous.adapter,bufferCount:previous.bufferCount,bufferBytes:previous.bufferBytes,queueSubmissions:Number.isSafeInteger(queueSubmissions)?queueSubmissions:previous.queueSubmissions,commandBuffers:Number.isSafeInteger(commandBuffers)?commandBuffers:previous.commandBuffers,queueFenceRequests:previous.queueFenceRequests,queueFenceCompletions:previous.queueFenceCompletions,invalid:previous.invalid||!Number.isSafeInteger(queueSubmissions)||!Number.isSafeInteger(commandBuffers)}})()};function _wgpuQueueWriteBuffer`;
3512
+ WLLAMA_EMSCRIPTEN_CODE = replaceSingle(
3513
+ WLLAMA_EMSCRIPTEN_CODE,
3514
+ queueAnchor,
3515
+ queueProjection,
3516
+ "WebGPU queue",
3517
+ );
3518
+
3519
+ const fenceAnchor = "runtimeKeepalivePush();WebGPU.Internals.futureInsert(futureId,queue.onSubmittedWorkDone().then(()=>{";
3520
+ const fenceProjection = `runtimeKeepalivePush();(function arcaneRecordWebgpuFenceRequest(){const key="__arcaneWllamaWebgpuTelemetry";const previous=globalThis[key]??${emptyWorkerTelemetry};const queueFenceRequests=previous.queueFenceRequests+1;globalThis[key]={protocol:"${protocol}",adapter:previous.adapter,bufferCount:previous.bufferCount,bufferBytes:previous.bufferBytes,queueSubmissions:previous.queueSubmissions,commandBuffers:previous.commandBuffers,queueFenceRequests:Number.isSafeInteger(queueFenceRequests)?queueFenceRequests:previous.queueFenceRequests,queueFenceCompletions:previous.queueFenceCompletions,invalid:previous.invalid||!Number.isSafeInteger(queueFenceRequests)}})();WebGPU.Internals.futureInsert(futureId,queue.onSubmittedWorkDone().then(function arcaneRecordWebgpuFenceCompletion(){(function arcaneCommitWebgpuFenceCompletion(){const key="__arcaneWllamaWebgpuTelemetry";const previous=globalThis[key]??${emptyWorkerTelemetry};const queueFenceCompletions=previous.queueFenceCompletions+1;globalThis[key]={protocol:"${protocol}",adapter:previous.adapter,bufferCount:previous.bufferCount,bufferBytes:previous.bufferBytes,queueSubmissions:previous.queueSubmissions,commandBuffers:previous.commandBuffers,queueFenceRequests:previous.queueFenceRequests,queueFenceCompletions:Number.isSafeInteger(queueFenceCompletions)?queueFenceCompletions:previous.queueFenceCompletions,invalid:previous.invalid||!Number.isSafeInteger(queueFenceCompletions)||queueFenceCompletions>previous.queueFenceRequests}})();`;
3521
+ WLLAMA_EMSCRIPTEN_CODE = replaceSingle(
3522
+ WLLAMA_EMSCRIPTEN_CODE,
3523
+ fenceAnchor,
3524
+ fenceProjection,
3525
+ "WebGPU submitted-work fence",
3526
+ );
3527
+
3528
+ const workerAnchor = " if (verb === 'module.init') {";
3529
+ const workerProjection = ` if (verb === 'arcane.telemetry') {\n const observed = globalThis.__arcaneWllamaWebgpuTelemetry;\n const adapter = observed?.adapter?.selected === true ? {\n selected: true,\n vendorId: null,\n vendor: typeof observed.adapter.vendor === 'string' ? observed.adapter.vendor.slice(0, 256) : '',\n architecture: typeof observed.adapter.architecture === 'string' ? observed.adapter.architecture.slice(0, 256) : '',\n deviceId: null,\n name: typeof observed.adapter.name === 'string' ? observed.adapter.name.slice(0, 256) : '',\n description: typeof observed.adapter.description === 'string' ? observed.adapter.description.slice(0, 256) : '',\n } : null;\n msg({\n callbackId,\n result: {\n protocol: '${protocol}',\n adapter,\n bufferCount: Number.isSafeInteger(observed?.bufferCount) ? observed.bufferCount : 0,\n bufferBytes: Number.isSafeInteger(observed?.bufferBytes) ? observed.bufferBytes : 0,\n queueSubmissions: Number.isSafeInteger(observed?.queueSubmissions) ? observed.queueSubmissions : 0,\n commandBuffers: Number.isSafeInteger(observed?.commandBuffers) ? observed.commandBuffers : 0,\n queueFenceRequests: Number.isSafeInteger(observed?.queueFenceRequests) ? observed.queueFenceRequests : 0,\n queueFenceCompletions: Number.isSafeInteger(observed?.queueFenceCompletions) ? observed.queueFenceCompletions : 0,\n invalid: observed?.invalid === true,\n },\n });\n return;\n }\n\n${workerAnchor}`;
3530
+ LLAMA_CPP_WORKER_CODE = replaceSingle(
3531
+ LLAMA_CPP_WORKER_CODE,
3532
+ workerAnchor,
3533
+ workerProjection,
3534
+ "Worker telemetry",
3535
+ );
3536
+
3537
+ function sanitizeWorkerTelemetry(value) {
3538
+ function nonNegativeCounter(candidate) {
3539
+ return Number.isSafeInteger(candidate) && candidate >= 0 ? candidate : 0;
3540
+ }
3541
+ function adapterText(candidate) {
3542
+ return typeof candidate === "string" && candidate.length <= 256 ? candidate : "";
3543
+ }
3544
+ const rawAdapter = value?.adapter;
3545
+ const adapterInvalid = rawAdapter !== undefined && rawAdapter !== null && (
3546
+ typeof rawAdapter !== "object"
3547
+ || rawAdapter.selected !== true
3548
+ || rawAdapter.vendorId !== null
3549
+ || typeof rawAdapter.vendor !== "string"
3550
+ || rawAdapter.vendor.length > 256
3551
+ || typeof rawAdapter.architecture !== "string"
3552
+ || rawAdapter.architecture.length > 256
3553
+ || rawAdapter.deviceId !== null
3554
+ || typeof rawAdapter.name !== "string"
3555
+ || rawAdapter.name.length > 256
3556
+ || typeof rawAdapter.description !== "string"
3557
+ || rawAdapter.description.length > 256
3558
+ );
3559
+ const adapter = rawAdapter?.selected === true ? Object.freeze({
3560
+ selected: true,
3561
+ vendorId: null,
3562
+ vendor: adapterText(rawAdapter.vendor),
3563
+ architecture: adapterText(rawAdapter.architecture),
3564
+ deviceId: null,
3565
+ name: adapterText(rawAdapter.name),
3566
+ description: adapterText(rawAdapter.description),
3567
+ }) : null;
3568
+ return Object.freeze({
3569
+ protocol,
3570
+ adapter,
3571
+ bufferCount: nonNegativeCounter(value?.bufferCount),
3572
+ bufferBytes: nonNegativeCounter(value?.bufferBytes),
3573
+ queueSubmissions: nonNegativeCounter(value?.queueSubmissions),
3574
+ commandBuffers: nonNegativeCounter(value?.commandBuffers),
3575
+ queueFenceRequests: nonNegativeCounter(value?.queueFenceRequests),
3576
+ queueFenceCompletions: nonNegativeCounter(value?.queueFenceCompletions),
3577
+ invalid: value?.invalid === true || value?.protocol !== protocol || adapterInvalid,
3578
+ });
3579
+ }
3580
+
3581
+ const proxyEvidence = new WeakMap();
3582
+ const sessionEvidence = new WeakMap();
3583
+
3584
+ function proxyRecord(proxy) {
3585
+ let record = proxyEvidence.get(proxy);
3586
+ if (!record) {
3587
+ record = {
3588
+ cancellationSequence: 0,
3589
+ cancellation: null,
3590
+ cleanupSequence: 0,
3591
+ cleanup: null,
3592
+ worker: sanitizeWorkerTelemetry(null),
3593
+ };
3594
+ proxyEvidence.set(proxy, record);
3595
+ }
3596
+ return record;
3597
+ }
3598
+
3599
+ function cancellationRecord(proxy, value) {
3600
+ const evidence = proxyRecord(proxy);
3601
+ const sequence = evidence.cancellationSequence + 1;
3602
+ evidence.cancellationSequence = sequence;
3603
+ const record = Object.freeze({
3604
+ sequence,
3605
+ requestId: typeof value.requestId === "number" || typeof value.requestId === "string"
3606
+ ? value.requestId
3607
+ : null,
3608
+ responseName: value.responseName === "cncl_res" ? value.responseName : null,
3609
+ acknowledged: value.acknowledged === true,
3610
+ failed: value.failed === true,
3611
+ });
3612
+ evidence.cancellation = record;
3613
+ return record;
3614
+ }
3615
+
3616
+ const originalAction = ProxyToWorker.prototype.wllamaAction;
3617
+ Object.defineProperty(ProxyToWorker.prototype, "wllamaAction", {
3618
+ configurable: false,
3619
+ writable: false,
3620
+ value: async function arcaneWllamaAction(name, body) {
3621
+ if (name !== "cancel") return originalAction.call(this, name, body);
3622
+ try {
3623
+ const result = await originalAction.call(this, name, body);
3624
+ cancellationRecord(this, {
3625
+ requestId: body?.req_id,
3626
+ responseName: result?._name,
3627
+ acknowledged: result?._name === "cncl_res" && result?.success === true,
3628
+ failed: false,
3629
+ });
3630
+ return result;
3631
+ } catch (error) {
3632
+ cancellationRecord(this, {
3633
+ requestId: body?.req_id,
3634
+ responseName: null,
3635
+ acknowledged: false,
3636
+ failed: true,
3637
+ });
3638
+ throw error;
3639
+ }
3640
+ },
3641
+ });
3642
+
3643
+ Object.defineProperty(ProxyToWorker.prototype, "arcaneTelemetry", {
3644
+ configurable: false,
3645
+ writable: false,
3646
+ value: async function arcaneTelemetry() {
3647
+ const value = await this.pushTask({
3648
+ verb: "arcane.telemetry",
3649
+ args: [],
3650
+ callbackId: this.taskId++,
3651
+ });
3652
+ const evidence = proxyRecord(this);
3653
+ evidence.worker = sanitizeWorkerTelemetry(value);
3654
+ return Object.freeze({
3655
+ protocol,
3656
+ worker: evidence.worker,
3657
+ cancellation: evidence.cancellation,
3658
+ cleanup: evidence.cleanup,
3659
+ });
3660
+ },
3661
+ });
3662
+
3663
+ const originalWorkerExit = ProxyToWorker.prototype.wllamaExit;
3664
+ Object.defineProperty(ProxyToWorker.prototype, "wllamaExit", {
3665
+ configurable: false,
3666
+ writable: false,
3667
+ value: async function arcaneWllamaExit(...args) {
3668
+ const hadWorker = Boolean(this.worker);
3669
+ const result = await originalWorkerExit.apply(this, args);
3670
+ if (hadWorker) {
3671
+ const evidence = proxyRecord(this);
3672
+ const sequence = evidence.cleanupSequence + 1;
3673
+ evidence.cleanupSequence = sequence;
3674
+ evidence.cleanup = Object.freeze({
3675
+ sequence,
3676
+ kind: "worker-terminated",
3677
+ nativeUnload: false,
3678
+ physicalVramReclamation: "not-observed",
3679
+ });
3680
+ }
3681
+ return result;
3682
+ },
3683
+ });
3684
+
3685
+ function projectionFailure(code, message, cause) {
3686
+ const error = new Error(message, cause === undefined ? undefined : { cause });
3687
+ error.name = "ArcaneWllamaProjectionError";
3688
+ error.code = code;
3689
+ return error;
3690
+ }
3691
+
3692
+ function cancellationError(reason) {
3693
+ if (reason instanceof Error) return reason;
3694
+ const error = new Error(reason ? String(reason) : "The Wllama operation was cancelled.");
3695
+ error.name = "AbortError";
3696
+ return error;
3697
+ }
3698
+
3699
+ function noWorkerCleanup() {
3700
+ return Object.freeze({
3701
+ sequence: 0,
3702
+ kind: "no-worker-observed-at-exit",
3703
+ nativeUnload: false,
3704
+ physicalVramReclamation: "not-applicable",
3705
+ });
3706
+ }
3707
+
3708
+ function proxySnapshot(proxy, cleanup = null) {
3709
+ const evidence = proxy ? proxyRecord(proxy) : null;
3710
+ return Object.freeze({
3711
+ protocol,
3712
+ worker: evidence?.worker ?? sanitizeWorkerTelemetry(null),
3713
+ cancellation: evidence?.cancellation ?? null,
3714
+ cleanup: evidence?.cleanup ?? cleanup,
3715
+ });
3716
+ }
3717
+
3718
+ Object.defineProperty(Wllama.prototype, "arcaneTelemetry", {
3719
+ configurable: false,
3720
+ writable: false,
3721
+ value: async function arcaneTelemetry() {
3722
+ const exited = sessionEvidence.get(this) ?? null;
3723
+ if (!this.proxy || exited?.cleanup) return exited ?? proxySnapshot(null);
3724
+ return this.proxy.arcaneTelemetry();
3725
+ },
3726
+ });
3727
+
3728
+ const originalExit = Wllama.prototype.exit;
3729
+ Object.defineProperty(Wllama.prototype, "exit", {
3730
+ configurable: false,
3731
+ writable: false,
3732
+ value: async function arcaneExit(...args) {
3733
+ const proxy = this.proxy;
3734
+ const hadWorker = Boolean(proxy?.worker);
3735
+ let result;
3736
+ try {
3737
+ result = await originalExit.apply(this, args);
3738
+ } catch (error) {
3739
+ throw projectionFailure(
3740
+ "ARCANE_AI_WORKER_TERMINATION_UNCONFIRMED",
3741
+ "Wllama exit failed before Worker termination could be confirmed.",
3742
+ error,
3743
+ );
3744
+ }
3745
+ let snapshot = proxySnapshot(proxy, hadWorker ? null : noWorkerCleanup());
3746
+ if (hadWorker && snapshot.cleanup?.kind !== "worker-terminated") {
3747
+ throw projectionFailure(
3748
+ "ARCANE_AI_WORKER_TERMINATION_UNCONFIRMED",
3749
+ "Wllama exit did not confirm Worker termination.",
3750
+ );
3751
+ }
3752
+ sessionEvidence.set(this, snapshot);
3753
+ return result;
3754
+ },
3755
+ });
3756
+
3757
+ Object.defineProperty(Wllama.prototype, "arcaneTerminate", {
3758
+ configurable: false,
3759
+ writable: false,
3760
+ value: async function arcaneTerminate() {
3761
+ const existing = sessionEvidence.get(this) ?? null;
3762
+ if (!this.proxy) {
3763
+ const snapshot = existing ?? proxySnapshot(null, noWorkerCleanup());
3764
+ sessionEvidence.set(this, snapshot);
3765
+ return snapshot;
3766
+ }
3767
+ await this.exit();
3768
+ const snapshot = await this.arcaneTelemetry();
3769
+ if (!["worker-terminated", "no-worker-observed-at-exit"].includes(snapshot.cleanup?.kind)) {
3770
+ throw projectionFailure(
3771
+ "ARCANE_AI_WORKER_TERMINATION_UNCONFIRMED",
3772
+ "Wllama cleanup did not confirm its Worker termination boundary.",
3773
+ );
3774
+ }
3775
+ return snapshot;
3776
+ },
3777
+ });
3778
+
3779
+ const originalLoadModel = Wllama.prototype.loadModel;
3780
+ Object.defineProperty(Wllama.prototype, "arcaneLoadModel", {
3781
+ configurable: false,
3782
+ writable: false,
3783
+ value: async function arcaneLoadModel(files, params = {}, signal = null) {
3784
+ if (signal !== null && typeof signal !== "object") {
3785
+ throw new TypeError("Arcane Wllama load cancellation requires an AbortSignal or null.");
3786
+ }
3787
+ if (signal?.aborted) throw cancellationError(signal.reason);
3788
+ const descriptor = Object.getOwnPropertyDescriptor(this, "proxy");
3789
+ if (!descriptor?.configurable || !("value" in descriptor) || descriptor.get || descriptor.set) {
3790
+ throw projectionFailure(
3791
+ "ARCANE_AI_WLLAMA_PROJECTION_INVALID",
3792
+ "Pinned Wllama proxy state is not an inspectable configurable data property.",
3793
+ );
3794
+ }
3795
+
3796
+ sessionEvidence.delete(this);
3797
+ const session = this;
3798
+ let proxy = descriptor.value;
3799
+ let resolveProxyAssigned;
3800
+ const proxyAssigned = new Promise(function captureAssignedProxy(resolve) {
3801
+ resolveProxyAssigned = resolve;
3802
+ });
3803
+ if (proxy) resolveProxyAssigned(proxy);
3804
+ Object.defineProperty(this, "proxy", {
3805
+ enumerable: descriptor.enumerable,
3806
+ configurable: true,
3807
+ get: function arcaneReadLoadingProxy() {
3808
+ return proxy;
3809
+ },
3810
+ set: function arcaneRecordLoadingProxy(value) {
3811
+ proxy = value;
3812
+ if (value) resolveProxyAssigned(value);
3813
+ },
3814
+ });
3815
+
3816
+ let restored = false;
3817
+ function restoreProxyProperty() {
3818
+ if (restored) return;
3819
+ restored = true;
3820
+ Object.defineProperty(session, "proxy", { ...descriptor, value: proxy });
3821
+ }
3822
+ const loadPromise = Promise.resolve().then(function beginProjectedModelLoad() {
3823
+ return originalLoadModel.call(session, files, params);
3824
+ });
3825
+ loadPromise.finally(restoreProxyProperty).catch(function ignoreObservedLoadSettlement() {});
3826
+ if (!signal) return loadPromise;
3827
+
3828
+ let onAbort;
3829
+ const aborted = new Promise(function captureProjectedLoadCancellation(resolve, reject) {
3830
+ onAbort = function terminateProjectedLoadAfterAbort() {
3831
+ const reason = cancellationError(signal.reason);
3832
+ const activeProxy = proxy
3833
+ ? Promise.resolve(proxy)
3834
+ : Promise.race([
3835
+ proxyAssigned,
3836
+ loadPromise.then(
3837
+ function projectedLoadFinishedWithoutProxy() { return null; },
3838
+ function projectedLoadFailedWithoutProxy() { return null; },
3839
+ ),
3840
+ ]);
3841
+ activeProxy.then(function terminateAssignedLoadProxy() {
3842
+ return session.arcaneTerminate();
3843
+ }).then(
3844
+ function rejectAfterConfirmedLoadTermination() { reject(reason); },
3845
+ function rejectWithLoadTerminationFailure(error) { reject(error); },
3846
+ );
3847
+ };
3848
+ });
3849
+ signal.addEventListener?.("abort", onAbort, { once: true });
3850
+ if (signal.aborted) onAbort();
3851
+ try {
3852
+ const result = await Promise.race([loadPromise, aborted]);
3853
+ if (signal.aborted) {
3854
+ await session.arcaneTerminate();
3855
+ throw cancellationError(signal.reason);
3856
+ }
3857
+ return result;
3858
+ } finally {
3859
+ signal.removeEventListener?.("abort", onAbort);
3860
+ }
3861
+ },
3862
+ });
3863
+
3864
+ Object.freeze(ProxyToWorker.prototype);
3865
+ Object.freeze(Wllama.prototype);
3866
+ })();
3867
+
3479
3868
  export {
3480
3869
  CacheManager,
3481
3870
  LogLevel,
@@ -7,37 +7,142 @@ same structured event stream; the GUI is not a second build system.
7
7
  ```text
8
8
  external app repository -----+
9
9
  |
10
- integrated Arcane checkout ---+-- CLI / future GUI / Codex / CI
10
+ Arcane OS consumer checkout --+-- CLI / future GUI / Codex / CI
11
11
  |
12
12
  shared toolchain API
13
13
  |
14
14
  browser package or explicit target adapter
15
15
  ```
16
16
 
17
+ ## Canonical ownership and portability boundary
18
+
19
+ The SDK repository is the canonical source for every mechanism that can be
20
+ reused by a portable Arcane application. That includes shared modules,
21
+ entities, components, themes, browser runtimes, providers, workers and assets;
22
+ protocol, state, startup, readiness, progress, cancellation, unload and dispose
23
+ machinery; public native contracts and adapters; the development source mount;
24
+ and the packaging, license, receipt and verification boundaries for those
25
+ portable bytes. In particular, shared AI selected-role hydration,
26
+ startup-settled state and events, fail-closed role readiness, lifecycle and
27
+ cancellation contracts, and the shared chat and speech components are
28
+ SDK-owned source and contracts rather than Arcane OS–owned snapshots.
29
+
30
+ Every portable application artifact materializes an immutable, locked and
31
+ verified projection of the SDK runtime bytes, assets, workers, licenses and
32
+ public contracts it uses. It remains self-contained whether it runs as plain
33
+ HTML or inside an executable wrapper. It has no runtime dependency on an
34
+ Arcane OS installation, source checkout or private Arcane OS import.
35
+
36
+ Arcane OS is an SDK consumer like other applications. Its orchestrator,
37
+ launcher, Shell, Provisioner, system AI application and internal tools use the
38
+ same SDK modules and components rather than maintaining private runtime copies.
39
+ Arcane OS and Core own the privileged host implementations, app/session
40
+ admission and authorization, native transport and lifecycle, launcher and
41
+ Shell orchestration, and system-AI policy specific to the Shell. The SDK may
42
+ publish the capability-neutral Core bridge contract and adapters, but it does
43
+ not embed Core or inherit another application's policy.
44
+
45
+ Each application owns its branding, prompts, data, tools, business policy,
46
+ model authorities and app-specific orchestration. Apply this decision order:
47
+
48
+ | Responsibility | Canonical owner |
49
+ |---|---|
50
+ | Reusable by any portable application | Arcane SDK |
51
+ | Host privilege, launcher, Shell or app/session admission | Arcane OS / Core |
52
+ | Behavior unique to one product | That application |
53
+
54
+ Do not copy a reusable implementation between the SDK, Arcane OS and an app,
55
+ and do not create a hidden Arcane OS source dependency. Extend one neutral SDK
56
+ contract and keep product policy in the consumer.
57
+
58
+ Development and distribution use different authority. The explicit
59
+ `arcane dev --sdk-runtime-source <sdk-root>` development-only live source mount
60
+ lets a refresh read the saved SDK source without copying it into the app.
61
+ Distribution never follows that mount. It embeds and verifies the application's
62
+ locked immutable SDK projection.
63
+
64
+ `tools/runtime-source.json` declares SDK-canonical authority for
65
+ `runtime/arcane/` and retains the prior Arcane OS source only as legacy
66
+ provenance for migrated compatibility bytes. The old OS-to-SDK synchronization
67
+ direction is retired and fails closed. Arcane OS must consume a locked SDK
68
+ projection through the same package/source-mount boundary as other apps; its
69
+ repository-side consumer cutover is coordinated separately and does not create
70
+ a co-equal source.
71
+
17
72
  ## Workspace profiles
18
73
 
19
74
  An external workspace maps the exact runtime shipped by its locked `arcane-os`
20
- dependency. An integrated workspace maps the live `arcane/` and
21
- `node_modules/strong-type` directories already owned by the Arcane checkout.
22
- The development server and packager consume the same route destinations in
23
- both cases, so app imports do not change. Integrated initialization creates
24
- only app-owned files and never rewrites Arcane root configuration.
75
+ dependency. An Arcane OS checkout is an integrated SDK consumer, not the owner
76
+ of portable runtime source. For live shared development, the explicit
77
+ development-only SDK source mount maps the canonical SDK runtime and dependency
78
+ paths into that consumer. Without the mount, the workspace uses its locked SDK
79
+ projection. The development server and packager consume the same route
80
+ destinations in both cases, so app imports do not change. Integrated
81
+ initialization creates only app-owned files and never rewrites Arcane OS or SDK
82
+ root configuration.
25
83
 
26
84
  The shared/Core development profile is a separate integrated-only scope selected
27
85
  with `--scope shared`. The SDK loads exactly
28
- `tools/integrated-development-provider.mjs` from the selected Arcane checkout as
29
- one process generation. That provider admits only one exact repository-relative
30
- focused `.test.mjs` through Arcane's canonical focused runner or Arcane's
31
- canonical development check. External workspaces cannot use the scope, and
32
- shared operations never enter app discovery, packaging, target planning, build,
33
- verification, or run paths. Provider bytes and filesystem identity are
34
- authenticated before and after the owned child operation; a generation change
35
- poisons that pairing and requires a new CLI process.
86
+ `tools/integrated-development-provider.mjs` from the selected Arcane OS checkout
87
+ as one process generation. This is a privileged host-development provider, not
88
+ a source of portable SDK runtime bytes. That provider admits only one exact
89
+ repository-relative focused `.test.mjs` through Arcane's canonical focused
90
+ runner or Arcane's canonical development check. External workspaces cannot use
91
+ the scope, and shared operations never enter app discovery, packaging, target
92
+ planning, build, verification, or run paths. Provider bytes and filesystem
93
+ identity are authenticated before and after the owned child operation; a
94
+ generation change poisons that pairing and requires a new CLI process.
36
95
  Integrated app testing remains isolated to the selected `apps/<id>/test/`
37
96
  tree; it cannot recursively select Arcane root tests or another app's tests.
38
97
  External repositories retain their existing workspace-root plus selected-app
39
98
  test layout.
40
99
 
100
+ ## Development and release serving boundary
101
+
102
+ Arcane applications keep one browser-first plain HTML, CSS, and JavaScript
103
+ baseline. A native target runs that same application and progressively enhances
104
+ it through capability-gated Arcane Core access. Browser operation must not
105
+ depend on Core being present. A feature that genuinely requires Core fails
106
+ closed and explains its unavailability without breaking unrelated browser
107
+ behavior or claiming that the capability exists.
108
+
109
+ Rapid development uses `arcane dev`. The development server maps the selected
110
+ application's canonical source tree and the live installed SDK/runtime routes.
111
+ Each request reads the current saved source into the existing bounded response
112
+ snapshot, so a browser refresh shows source changes without packaging, copying
113
+ files into `dist`, or restarting the server. Restarting is not a content
114
+ synchronization step; when a refresh is stale, first verify the command, URL,
115
+ workspace, selected app, and resolved source route.
116
+
117
+ Development is an intentionally fast feedback loop. Keep each increment small
118
+ and independently understandable so its effect has one clear cause and a
119
+ mistake can be isolated without untangling unrelated work. A development
120
+ operation does not implicitly run tests, checks, packaging, builds, or release
121
+ verification. The developer invokes a focused test or check deliberately at an
122
+ explicit checkpoint; merely refreshing source does not trigger one.
123
+
124
+ Executable development uses an Arcane-owned native development wrapper around
125
+ the same source-serving browser surface. The wrapper is an escalated browser,
126
+ not a packaged application: it loads current source files and adds only the
127
+ selected application's declared, capability-gated local Arcane Core access.
128
+ It preserves the browser behavior when Core is absent, fails closed for an
129
+ unavailable native-only capability, and never silently substitutes a release
130
+ tree. Starting or refreshing this wrapper does not package, copy to `dist`, or
131
+ run tests automatically. The SDK must not describe native source development as
132
+ available until this wrapper and its explicit capability boundary are actually
133
+ implemented.
134
+
135
+ Package and release verification use a separate explicit boundary. Run
136
+ `arcane package` to generate and verify `dist/<id>`, then use
137
+ `arcane run --target browser` to serve only that verified release. Distribution
138
+ automatically runs the selected application's required tests before accepting,
139
+ serving, or launching `dist` and fails closed on any test failure. The browser
140
+ run command does not substitute source files. If source changes after
141
+ packaging, the prior `dist` remains intentionally unchanged until the next
142
+ explicit package operation. Never use packaged `dist` as the everyday
143
+ development tree, and never treat source-serving behavior as evidence for the
144
+ release artifact.
145
+
41
146
  ## App and release contract
42
147
 
43
148
  The first SDK version deliberately preserves Arcane's current repository-shaped
@@ -55,11 +160,13 @@ exact schema-1 `arcane-package.json` for current consumers. Existing Arcane
55
160
  apps synthesize that descriptor from their schema-1 package plus the current
56
161
  native registry during migration.
57
162
 
58
- An external app's `arcane-packager.json` has three exact shared routes. They map the
59
- installed SDK runtime to `/arcane`, its vendored strong-type dependency to
163
+ An external app's `arcane-packager.json` has three exact shared routes. They map
164
+ the installed SDK runtime to `/arcane`, its vendored strong-type dependency to
60
165
  `/node_modules/strong-type`, and the SDK's `LICENSE`,
61
- `COMMERCIAL-LICENSE.md`, and `NOTICE` to `/licenses/arcane-os`. The app does not
62
- copy Arcane runtime source into its repository.
166
+ `COMMERCIAL-LICENSE.md`, and `NOTICE` to `/licenses/arcane-os`. Development does
167
+ not copy SDK runtime source into the app repository. Distribution materializes
168
+ those exact locked SDK routes inside the portable artifact and verifies their
169
+ immutable inventory, so the finished app has no Arcane OS runtime dependency.
63
170
 
64
171
  Release schema 1 and builder identity `arcane-app-packager-v1` remain unchanged
65
172
  because current Arcane native admission treats them as exact contracts. Native
@@ -93,7 +200,7 @@ length with an EOF growth probe, and rechecked by handle and pathname identity.
93
200
  Every cumulative path prefix has one case-folded spelling and one file/directory
94
201
  kind; prefix topology conflicts and the complete portable Windows device-name
95
202
  set fail before creation or admission.
96
- The current SDK admits only the explicitly compatible `0.1.0-dev.5` bundle
203
+ The current SDK admits only the explicitly compatible `0.2.0` bundle
97
204
  generation and rejects zero-byte payload releases.
98
205
 
99
206
  Promotion retains any prior output as an identity-bound backup until the new
@@ -150,8 +257,11 @@ failure propagation. No app or target loop exists in that scope.
150
257
 
151
258
  ## Verification receipts
152
259
 
153
- Runtime verification binds the exact SDK version, upstream Arcane commit,
154
- runtime inventory, byte counts, and SHA-256 hashes. Packaging writes the full
260
+ Runtime verification binds the exact SDK version, canonical SDK source
261
+ identity, runtime inventory, byte counts, and SHA-256 hashes. During the
262
+ source-ownership migration it may additionally record imported Arcane OS
263
+ provenance for compatibility bytes, but that field does not transfer canonical
264
+ ownership. Packaging writes the full
155
265
  schema-1 release inventory to `ARCANE_APP_RELEASE.json`; its operation result
156
266
  returns a deeply immutable, process-authenticated receipt that binds the
157
267
  canonical location, app policy, complete inventory, content digest, and verified
@@ -210,7 +320,7 @@ through SDK-bound verified readers rather than accepting a mutable source path
210
320
  as authority. Build completion requires provider verification, and later
211
321
  verify/run calls receive the exact artifact receipt.
212
322
 
213
- The SDK `0.1.0-dev.5` runtime requires Arcane `0.8.12` or newer. Compatibility
323
+ The SDK `0.2.0` runtime requires Arcane `0.8.12` or newer. Compatibility
214
324
  is contractual rather than exact-version pinning: the prepared Core must meet
215
325
  the highest minimum declared by the runtime, selected app, and bundled app
216
326
  dependencies; keep each app's Arcane protocol generation; and provide every
@@ -38,7 +38,7 @@ This repository contains two related, explicitly versioned surfaces:
38
38
 
39
39
  | Surface | Source identity | Meaning |
40
40
  | --- | --- | --- |
41
- | SDK and CLI | `arcane-os` `0.1.1` | The Node.js toolchain plus the browser-only `arcane-os/ai/browser-wasm` entrypoint in this checkout. |
41
+ | SDK and CLI | `arcane-os` `0.1.2` | The Node.js toolchain plus the browser-only `arcane-os/ai/browser-wasm` entrypoint in this checkout. |
42
42
  | Browser runtime | Arcane OS commit `567ad110bf57a1c2d4a3daa22ae93716cc5f4d7e`, bundle `0.8.12`, protocol `arcane/1` | The exact 155-file runtime snapshot shipped under `runtime/`. |
43
43
  | Core reference snapshot | Arcane OS commit `567ad110bf57a1c2d4a3daa22ae93716cc5f4d7e`, protocol `arcane/1` | The application-facing Core contract derived into `docs/reference/core/`. Canonical inventory and focused-member content was verified unchanged at Arcane OS `main` commit `13f3ce0ae34f77a3495331c8b4c30b1bb105f8ed`; SDK-local provenance, link, and package-boundary annotations are added explicitly. |
44
44