arcane-os 0.5.17 → 0.5.18

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 (183) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/README.md +9 -9
  3. package/bin/arcane-test.mjs +16 -13
  4. package/browser-runtime/ai/browser-speech-artifacts.mjs +41 -38
  5. package/browser-runtime/ai/browser-speech-providers.mjs +46 -43
  6. package/browser-runtime/ai/browser-wasm-llm-provider.mjs +127 -124
  7. package/browser-runtime/ai/browser-wasm.mjs +6 -3
  8. package/browser-runtime/ai/browser-wllama-runtime.mjs +26 -23
  9. package/browser-runtime/ai/model-controller.mjs +94 -91
  10. package/browser-runtime/ai/speech-worker-client.mjs +12 -9
  11. package/browser-runtime/ai/speech-worker-runtime.mjs +56 -53
  12. package/browser-runtime/dependencies/strong-type/index.js +207 -82
  13. package/browser-runtime/dependencies/strong-type/package.json +15 -6
  14. package/browser-runtime/dom-event-instrumentation.mjs +24 -20
  15. package/browser-runtime/event-manager.mjs +111 -108
  16. package/browser-runtime/speech-text.mjs +5 -1
  17. package/docs/reference/ai/browser-speech.md +198 -5
  18. package/docs/reference/availability-and-normalization.md +40 -0
  19. package/docs/reference/inventory/package-api.json +1 -1
  20. package/docs/reference/inventory/runtime-components.json +1 -1
  21. package/docs/reference/inventory/runtime-modules.json +20 -24
  22. package/docs/reference/protocols.md +1 -1
  23. package/docs/reference/runtime-modules.md +125 -35
  24. package/docs/reference/sdk-api.md +23 -7
  25. package/examples/wasm-ai-demo/index.html +1 -0
  26. package/node_modules/event-pubsub/node_modules/strong-type/README.md +408 -0
  27. package/node_modules/event-pubsub/node_modules/strong-type/assets/strong-type-header.png +0 -0
  28. package/node_modules/event-pubsub/node_modules/strong-type/index.js +1151 -0
  29. package/node_modules/event-pubsub/node_modules/strong-type/licence +21 -0
  30. package/node_modules/event-pubsub/node_modules/strong-type/node.js +125 -0
  31. package/node_modules/event-pubsub/node_modules/strong-type/package.json +61 -0
  32. package/node_modules/strong-type/README.md +42 -24
  33. package/node_modules/strong-type/benchmark/core.js +324 -0
  34. package/node_modules/strong-type/index.js +207 -82
  35. package/node_modules/strong-type/package.json +14 -6
  36. package/package.json +3 -3
  37. package/runtime/arcane/components/app-bar.html +5 -2
  38. package/runtime/arcane/components/assistant-panel.html +5 -2
  39. package/runtime/arcane/components/chart.html +15 -12
  40. package/runtime/arcane/components/chat.html +117 -138
  41. package/runtime/arcane/components/dashboard-config.html +6 -3
  42. package/runtime/arcane/components/data-view.html +4 -1
  43. package/runtime/arcane/components/directory-picker.html +5 -2
  44. package/runtime/arcane/components/document-inspector.html +6 -3
  45. package/runtime/arcane/components/file-drop.html +5 -2
  46. package/runtime/arcane/components/file-inspector.html +9 -6
  47. package/runtime/arcane/components/file-manager.html +16 -13
  48. package/runtime/arcane/components/local-ai-status.html +5 -2
  49. package/runtime/arcane/components/markdown-document.html +14 -11
  50. package/runtime/arcane/components/markdown-editor.html +4 -1
  51. package/runtime/arcane/components/modal.html +4 -1
  52. package/runtime/arcane/components/output-panel.html +6 -3
  53. package/runtime/arcane/components/preferences-form.html +4 -1
  54. package/runtime/arcane/components/record-timeline.html +8 -5
  55. package/runtime/arcane/components/relationship-board.html +9 -6
  56. package/runtime/arcane/components/source-code-viewer.html +12 -9
  57. package/runtime/arcane/components/source-explanation.html +8 -5
  58. package/runtime/arcane/components/speech.html +24 -21
  59. package/runtime/arcane/components/summary-strip.html +4 -1
  60. package/runtime/arcane/components/task-progress.html +6 -3
  61. package/runtime/arcane/components/terminal-workspace.html +4 -1
  62. package/runtime/arcane/components/voice-transcription.html +11 -8
  63. package/runtime/arcane/components/web-navigator.html +5 -2
  64. package/runtime/arcane/entities/ApiModelRecord.js +5 -2
  65. package/runtime/arcane/entities/Calculation.js +5 -2
  66. package/runtime/arcane/entities/Chat.js +33 -33
  67. package/runtime/arcane/entities/CommunicationMessage.js +4 -1
  68. package/runtime/arcane/entities/CommunicationThread.js +4 -1
  69. package/runtime/arcane/entities/File.js +1 -1
  70. package/runtime/arcane/entities/Image.js +8 -5
  71. package/runtime/arcane/entities/IntentEnvelope.js +20 -17
  72. package/runtime/arcane/entities/Preference.js +9 -6
  73. package/runtime/arcane/entities/Theme.js +5 -2
  74. package/runtime/arcane/entities/User.js +11 -11
  75. package/runtime/arcane/entities/Weather.js +5 -2
  76. package/runtime/arcane/modules/AI.js +491 -165
  77. package/runtime/arcane/modules/AIPreferenceRuntime.js +5 -2
  78. package/runtime/arcane/modules/AIPreferenceTuple.js +9 -6
  79. package/runtime/arcane/modules/AIProviderRuntime.js +88 -85
  80. package/runtime/arcane/modules/AIResponseURLPolicy.js +148 -62
  81. package/runtime/arcane/modules/AIRuntimeState.js +29 -26
  82. package/runtime/arcane/modules/AnsiText.js +4 -1
  83. package/runtime/arcane/modules/ApiModelDatabase.js +22 -19
  84. package/runtime/arcane/modules/AppDataScope.js +8 -5
  85. package/runtime/arcane/modules/ArcaneCommunicationBridge.js +4 -1
  86. package/runtime/arcane/modules/ArcaneNavigationPolicy.js +8 -5
  87. package/runtime/arcane/modules/ArcaneNetworkPolicy.js +18 -15
  88. package/runtime/arcane/modules/AsyncBoundary.js +13 -10
  89. package/runtime/arcane/modules/BrowserTestSuite.js +19 -16
  90. package/runtime/arcane/modules/CalculatorEngine.js +5 -2
  91. package/runtime/arcane/modules/ChatRecords.js +18 -15
  92. package/runtime/arcane/modules/CommunicationAppController.js +9 -6
  93. package/runtime/arcane/modules/CommunicationHub.js +9 -6
  94. package/runtime/arcane/modules/CommunicationPreferences.js +4 -1
  95. package/runtime/arcane/modules/CommunicationProviderRegistry.js +4 -1
  96. package/runtime/arcane/modules/ComponentContracts.js +56 -53
  97. package/runtime/arcane/modules/ConfiguredAIChatSession.js +30 -27
  98. package/runtime/arcane/modules/ConversationActionItems.js +15 -12
  99. package/runtime/arcane/modules/ConversationClosingReport.js +11 -8
  100. package/runtime/arcane/modules/ConversationTimebox.js +28 -25
  101. package/runtime/arcane/modules/CoreLocalModelCatalog.js +17 -14
  102. package/runtime/arcane/modules/DBLS.js +7 -4
  103. package/runtime/arcane/modules/DBOPFS.js +7 -7
  104. package/runtime/arcane/modules/DBOPFSDocumentLibrary.js +34 -31
  105. package/runtime/arcane/modules/DevelopmentWorkspace.js +4 -1
  106. package/runtime/arcane/modules/DirectoryPicker.js +8 -5
  107. package/runtime/arcane/modules/DocumentLexicalSearch.js +11 -8
  108. package/runtime/arcane/modules/DocumentNavigation.js +7 -4
  109. package/runtime/arcane/modules/Errors.js +28 -25
  110. package/runtime/arcane/modules/HTMLImport.js +7 -4
  111. package/runtime/arcane/modules/IsolatedModelQuestionRunner.js +15 -12
  112. package/runtime/arcane/modules/LocalAIReadiness.js +21 -18
  113. package/runtime/arcane/modules/LocalAIReadinessController.js +6 -3
  114. package/runtime/arcane/modules/MD.js +1 -1
  115. package/runtime/arcane/modules/Mail.js +46 -43
  116. package/runtime/arcane/modules/MailOutbox.mjs +48 -45
  117. package/runtime/arcane/modules/MailTransport.mjs +29 -26
  118. package/runtime/arcane/modules/MemoryRecords.js +7 -4
  119. package/runtime/arcane/modules/MessageAdvisory.js +6 -3
  120. package/runtime/arcane/modules/ModelDefinition.js +7 -4
  121. package/runtime/arcane/modules/Ollama.js +6 -3
  122. package/runtime/arcane/modules/OllamaModelIdentifier.js +4 -1
  123. package/runtime/arcane/modules/OpenMeteoWeatherProvider.js +18 -15
  124. package/runtime/arcane/modules/PersistentAIChatSession.js +33 -30
  125. package/runtime/arcane/modules/PreferenceStore.js +20 -17
  126. package/runtime/arcane/modules/PreparedSpeech.js +485 -0
  127. package/runtime/arcane/modules/Questionnaire.js +6 -3
  128. package/runtime/arcane/modules/RecordLinkIndex.js +4 -1
  129. package/runtime/arcane/modules/RecordPassageIndex.js +9 -6
  130. package/runtime/arcane/modules/RecordReviewStore.js +12 -9
  131. package/runtime/arcane/modules/RiskSignalAnalyzer.js +4 -1
  132. package/runtime/arcane/modules/ScopedOPFSCache.js +6 -3
  133. package/runtime/arcane/modules/ScreenCapture.js +20 -17
  134. package/runtime/arcane/modules/SpeechPlayback.js +29 -26
  135. package/runtime/arcane/modules/StaticDocumentCatalog.js +33 -30
  136. package/runtime/arcane/modules/SystemAppearance.js +5 -2
  137. package/runtime/arcane/modules/SystemToolRegistry.js +6 -3
  138. package/runtime/arcane/modules/TerminalClient.js +14 -11
  139. package/runtime/arcane/modules/TerminalCommandRegistry.js +4 -1
  140. package/runtime/arcane/modules/ThemeBootstrap.js +9 -6
  141. package/runtime/arcane/modules/ThemeManager.js +5 -2
  142. package/runtime/arcane/modules/TimeGuard.js +1 -1
  143. package/runtime/arcane/modules/ToolCallRouter.js +11 -8
  144. package/runtime/arcane/modules/WaitForComponent.js +19 -16
  145. package/runtime/arcane/modules/YouTubeMedia.js +4 -1
  146. package/runtime/strong-type/index.js +1276 -352
  147. package/runtime/strong-type/package.json +69 -45
  148. package/src/app-descriptor.mjs +17 -14
  149. package/src/application-tests.mjs +4 -1
  150. package/src/cli/main.mjs +8 -5
  151. package/src/constants.mjs +4 -1
  152. package/src/dev-server.mjs +8 -5
  153. package/src/doctor.mjs +5 -2
  154. package/src/dom-event-instrumentation.mjs +24 -20
  155. package/src/errors.mjs +7 -3
  156. package/src/event-manager.mjs +111 -108
  157. package/src/event-queue.mjs +8 -5
  158. package/src/events.mjs +12 -9
  159. package/src/import-map.mjs +35 -27
  160. package/src/installed-sdk-runtime.mjs +4 -1
  161. package/src/integrated-provider-loader.mjs +9 -6
  162. package/src/mail-credentials.mjs +16 -13
  163. package/src/mail-server.mjs +53 -50
  164. package/src/mail.mjs +18 -15
  165. package/src/native-plan.mjs +12 -9
  166. package/src/native-provider-loader.mjs +7 -4
  167. package/src/packager/core.mjs +18 -15
  168. package/src/process.mjs +6 -3
  169. package/src/release-bundle.mjs +14 -11
  170. package/src/runtime.mjs +4 -1
  171. package/src/scaffold.mjs +9 -6
  172. package/src/sdk-browser-runtime.mjs +4 -1
  173. package/src/source-server.mjs +17 -14
  174. package/src/targets/index.mjs +5 -2
  175. package/src/templates/workspace-template.mjs +13 -6
  176. package/src/testing-loader.mjs +7 -4
  177. package/src/testing.mjs +10 -7
  178. package/src/toolchain.mjs +13 -10
  179. package/src/update-check.mjs +9 -6
  180. package/src/workspace-operation-lock.mjs +14 -11
  181. package/src/workspace-runtime.mjs +4 -1
  182. package/src/workspace.mjs +17 -14
  183. package/runtime/arcane/modules/AIResponseLength.js +0 -32
@@ -4,6 +4,13 @@ Every file shipped under `runtime/arcane/modules/` appears here. Start with the
4
4
 
5
5
  Apps import renderer ESM from `/arcane/modules/<file>`. Classic scripts, the OPFS worker, uPlot stylesheet, and vendor license are called out explicitly. Importing a module does not grant a native capability.
6
6
 
7
+ Applications own response-detail preferences, their saved values, and any
8
+ verbosity instruction appended to the system prompt. The former
9
+ `AIResponseLength.js` module and its exports have been removed. Before adopting
10
+ this source change, consumers must normalize preferences in their application
11
+ and pass their complete system prompt directly instead of calling the former
12
+ no-op `applyAIResponseLength()` helper. Existing saved preferences are unchanged.
13
+
7
14
  ## Availability shorthand
8
15
 
9
16
  - **Cross-host** means in-process logic built from standard JavaScript/Web APIs.
@@ -44,8 +51,7 @@ own asynchronous work, cancellation, and backpressure.
44
51
  | [`AIPreferenceRuntime.js`](#aipreferenceruntimejs) | esm | Applies and reads non-persistent per-user AI preference overrides. | Cross-host | Normalized six-slot preference state. |
45
52
  | [`AIPreferenceTuple.js`](#aipreferencetuplejs) | esm | Normalizes and compares the six provider/model preference slots. | Cross-host | Fully normalized frozen tuple. |
46
53
  | [`AIProviderRuntime.js`](#aiproviderruntimejs) | esm | Owns provider-neutral selection, lifecycle, routing, startup, requests, streaming, cancellation, and independent LLM/STT/TTS state. | Cross-host runtime; provider-specific availability | Normalized required provider members plus route/status contracts, with explicit local-only selection and no implicit fallback. |
47
- | [`AIResponseLength.js`](#airesponselengthjs) | esm | Normalizes current low/medium/high response-preference selectors while preserving complete prompts. | Cross-host | Current selector normalization; prompt content remains unchanged. |
48
- | [`AIResponseURLPolicy.js`](#airesponseurlpolicyjs) | esm | Extracts and audits links from AI Markdown, rendered HTML, CSS, srcset, bare URLs, and email text. | Cross-host | Normalized frozen allowlist audit. |
54
+ | [`AIResponseURLPolicy.js`](#airesponseurlpolicyjs) | esm | Extracts and audits links from AI Markdown, rendered HTML, CSS, srcset, bare URLs, and email text. | Cross-host | Mutable audit with exact link comparison after renderer-level decoding. |
49
55
  | [`AIRuntimeState.js`](#airuntimestatejs) | esm | Publishes sticky mutable role snapshots, lifecycle intents, and startup-settlement barriers. | Cross-host state contract | Closed monotonic state records; events report state but grant no authority. |
50
56
  | [`AnsiText.js`](#ansitextjs) | esm | Parses terminal ANSI sequences into display spans or strips them to plain text. | Cross-host | Normalized text/span output. |
51
57
  | [`ApiModelDatabase.js`](#apimodeldatabasejs) | esm | Fetches an injectable HTTP JSON model with parser, cache, redacted public endpoint records, and request lifecycle events. | Browser / native WebView / server with fetch | Request records are normalized; fetch/provider failures remain mixed. |
@@ -100,6 +106,7 @@ own asynchronous work, cancellation, and backpressure.
100
106
  | [`OpenMeteoWeatherProvider.js`](#openmeteoweatherproviderjs) | esm | Searches and loads Open-Meteo data into complete mutable Arcane weather entities. | Browser / native WebView / server with fetch + cloud | Provider data normalized to mutable entities; transport errors mixed. |
101
107
  | [`PersistentAIChatSession.js`](#persistentaichatsessionjs) | esm | Adds explicit retained-history/memory policy to complete configured chat without changing DBOPFS or ChatEntity semantics. | Browser / native WebView with DBOPFS and configured chat | Retained context commits atomically; `persist:false` turns are one-operation-only. |
102
108
  | [`PreferenceStore.js`](#preferencestorejs) | esm | Loads and updates schema-defined app preferences through native storage with a narrow browser fallback. | Browser/native hybrid | Complete ordinary values remain mutable; setAll uses one optional atomic adapter batch for every selected value when advertised, otherwise performs complete ordered serial writes, and only exact unsupported native capability changes future operations to the browser fallback. |
109
+ | [`PreparedSpeech.js`](#preparedspeechjs) | esm | Owns detached ordered preparation, semantic audio reuse, and per-caller cancellation behind AI.prepareTTS. | Browser / native WebView with injected synthesis and optional DBOPFS | Complete original inputs, ordered audio metadata, durable reuse, and observable preparation results. |
103
110
  | [`QRCode.min.js`](#qrcodeminjs) | classic-script | Vendored QRCode generator for DOM, canvas, SVG, and image output. | Browser vendor script | Vendor-native. |
104
111
  | [`Questionnaire.js`](#questionnairejs) | esm | Evaluates whether a one-time questionnaire prompt is due without performing the prompt. | Cross-host | Normalized conservative boolean. |
105
112
  | [`RecordLinkIndex.js`](#recordlinkindexjs) | esm | Parses record links and builds their normalized index. | Cross-host | Fully normalized. |
@@ -144,6 +151,8 @@ default `AI`; read-only `providerRuntime`, `browserSpeechConfiguration`, and
144
151
  `streamRequest()`, `streamMessage()`, `fetchRequest()`, `fetch()`,
145
152
  read-only `ttsSegmentation`, `configureTTSSegmentation()`,
146
153
  `streamTTS(text='',end=false,options={})`,
154
+ `prepareTTS({parts,storage,identity,signal,onState})`,
155
+ `playPreparedTTS(prepared,{signal,onState})`,
147
156
  `finishTTS()`, `fetchTTS()`, `fetchSTT()`, `stopAudio()`, `resumeAudio()`,
148
157
  `playAudio()`; consumes `user-entity-loaded` and `arcane-ollama-ready`,
149
158
  installs `window.ai`, and emits `ai-ready` and `ai-tts-failure`.
@@ -312,13 +321,63 @@ flush, not a queue-wide playback barrier. A muted call resolves `false`.
312
321
  Playback completion stays pending while the browser waits for an audio-unlock
313
322
  gesture or a recoverable resume attempt. If resuming a closed `AudioContext`
314
323
  fails, the affected jobs terminate and their playback results settle `false`.
315
- `stopAudio()` cancels all speech owned
316
- by this AI instance and settles pending playback promises `false`. A trailing
324
+ `stopAudio()` cancels streamed speech and prepared playback owned
325
+ by this AI instance and settles pending playback promises `false`; detached
326
+ preparation retains its own cancellation lifetime. A trailing
317
327
  pause delays the next queued audio; the preceding promise resolves when its
318
328
  last audio buffer ends, without waiting out that pause. Completion describes
319
329
  the playback lifecycle, not proof that a listener heard the sound. See the
320
330
  [complete-passage example](ai/browser-speech.md#queue-complete-passages-and-wait-for-playback).
321
331
 
332
+ `prepareTTS({parts,storage,identity,signal,onState})` returns an immediate
333
+ `{segments,state,ready,getAudio(index),cancel()}` handle for detached complete
334
+ speech preparation. Parts are strings or `{input,voice?,speed?,pauseAfterMs?}`
335
+ records. It retains the full source for semantic matching, snapshots the
336
+ selected speech configuration and segmentation, and applies automatic
337
+ formatting cleanup once to the speech copy. Generation uses the existing
338
+ bounded provider queue without adding playback. Optional
339
+ `storage:{db,table,key}` saves complete audio files and their MIME metadata in
340
+ the caller's ready DBOPFS instance; the separate JSON-compatible `identity`
341
+ adds application-owned semantic context. Reuse compares complete inputs rather
342
+ than an SDK version alone.
343
+
344
+ `state` is `queued`, `preparing`, `ready`, `error`, or `cancelled`.
345
+ `onState({state,completed,total,segments,error})` synchronously observes
346
+ preparation progress. `ready` resolves the complete record after every segment
347
+ is ready and, when storage is selected, durably saved. `getAudio(index)` waits
348
+ for the corresponding ordered segment and returns its complete `Blob` with
349
+ the retained MIME type. Preparation failure rejects; cancellation rejects as
350
+ `AbortError` and preserves successfully stored segments. Matching pending
351
+ requests share synthesis only on the same AI instance and storage group;
352
+ cancelling one handle does not cancel another active matching caller.
353
+ Preparation cancellation prevents later synthesis, but an already-started
354
+ shared provider load/unmute has no per-preparation signal and may finish.
355
+
356
+ `playPreparedTTS(prepared,{signal,onState})` can attach immediately. Its returned
357
+ `{state,error,finished,pause(),resume(),stop()}` handle schedules segments in
358
+ their original order using the existing AI audio clock. `finished` resolves `true` after
359
+ natural completion and `false` after stop, cancellation, or failure; genuine
360
+ failures also use the existing complete diagnostics and `ai-tts-failure` event.
361
+ Part pauses separate adjacent audio; the final trailing pause does not delay
362
+ `finished` after the final audio buffer ends. State/error getters and the
363
+ optional synchronous `onState({state,error})` callback expose `waiting`,
364
+ `waiting-for-gesture`, `scheduled`, `paused`, `complete`, `stopped`, or `error`.
365
+ Use `waiting-for-gesture` for audio-unlock UI; a `false` result from `resume()`
366
+ alone is not a first-segment-ready signal.
367
+ Pause and resume are asynchronous boolean controls scoped to that handle's
368
+ audio context; stop is synchronous. Playback completion and these controls do
369
+ not cancel independent preparation. One AI has one playback lane: attaching
370
+ prepared playback replaces its preceding streamed or prepared audio, and
371
+ `streamTTS()` interrupts active prepared playback. `stopAudio()` stops all
372
+ this AI's playback but keeps detached preparation running; `setSpeechMuted(true)` also cancels
373
+ provider TTS work and unloads it. Replacing the selected speech configuration
374
+ cancels missing generation for that earlier selection. Completed stored audio
375
+ remains in application storage.
376
+ Fully stored replay enables playback without loading the selected speech
377
+ model even when the AI starts muted. Missing audio alone requests the shared
378
+ TTS readiness path. See [prepared narration](ai/browser-speech.md#prepare-narration-once-and-replay-stored-audio)
379
+ for full record shapes, storage ownership, and a complete example.
380
+
322
381
  Streaming speech retains sentence
323
382
  segmentation by default. `configureTTSSegmentation({punctuation,wordCadence})`
324
383
  accepts `punctuation:'sentence'|'any'|'none'` and a `wordCadence` that is either
@@ -809,35 +868,6 @@ const runtime = getAIProviderRuntime();
809
868
  console.log(runtime.protocol, runtime.status());
810
869
  ```
811
870
 
812
- ## AIResponseLength.js
813
-
814
- ### Overview
815
-
816
- Normalizes current low/medium/high response-preference selectors while
817
- preserving complete prompts unchanged.
818
-
819
- ### Public surface
820
-
821
- Response-preference constants plus `normalizeAIResponseLength()`,
822
- `aiResponseLengthInstruction()`, and `applyAIResponseLength()`. Every option is
823
- labeled `Complete`, the instruction helper returns an empty string, and the
824
- application helper returns its complete `systemPrompt` unchanged.
825
-
826
- Exact exports: `AI_RESPONSE_LENGTH_DEFAULT`, `AI_RESPONSE_LENGTH_OPTIONS`, `aiResponseLengthInstruction`, `applyAIResponseLength`, `normalizeAIResponseLength`.
827
-
828
- ### Availability and normalization
829
-
830
- **Cross-host.** Current selector normalization with no prompt transformation.
831
- Transport: In-process only. [Deep protocol details](protocols.md).
832
-
833
- ### Example
834
-
835
- ```javascript
836
- import * as module from '/arcane/modules/AIResponseLength.js';
837
-
838
- console.log(Object.keys(module));
839
- ```
840
-
841
871
  ## AIResponseURLPolicy.js
842
872
 
843
873
  ### Overview
@@ -852,7 +882,19 @@ Exact exports: `auditAIResponseLinks`, `decodeHTMLCharacterReferences`, `extract
852
882
 
853
883
  ### Availability and normalization
854
884
 
855
- **Cross-host.** Normalized frozen allowlist audit. Transport: In-process; bundled Marked parser. [Deep protocol details](protocols.md).
885
+ **Cross-host.** Returns a mutable `{ok, links, unsupportedLinks, allowedLinks}`
886
+ audit. Browsers use detached native HTML elements to parse rendered markup and
887
+ decode character references. Hosts without a document retain lexical extraction
888
+ and the existing limited entity decoder. Rendered values are decoded only once.
889
+ Markdown destinations, CSS URLs, srcset candidates, and authored source positions
890
+ remain part of the audit; DOM-only attribute links use document order after
891
+ authored links because the DOM does not expose source offsets.
892
+
893
+ Comparison uses exact values after entity and Markdown escape decoding. URI
894
+ encoding, decoding, or URL canonicalization would change those values and is
895
+ not applied. The audit neither changes the response content nor fetches or
896
+ navigates to links. Transport: In-process; bundled Marked parser.
897
+ [Deep protocol details](protocols.md).
856
898
 
857
899
  ### Example
858
900
 
@@ -2292,7 +2334,7 @@ Exact exports: `MarkdownSpeech`.
2292
2334
  ### Availability and normalization
2293
2335
 
2294
2336
  **Cross-host.** The runtime projection and public package entrypoint share the
2295
- same dependency-free implementation. `append()` returns only
2337
+ same implementation. `append()` returns only
2296
2338
  the newly available narration. Only a trailing candidate marker and whether
2297
2339
  it repeats are retained; ordinary text is emitted immediately. Terminal
2298
2340
  `append(text,true)` flushes a single pending mark and resets state. `reset()`
@@ -2690,6 +2732,54 @@ import * as module from '/arcane/modules/PreferenceStore.js';
2690
2732
  console.log(Object.keys(module));
2691
2733
  ```
2692
2734
 
2735
+ ## PreparedSpeech.js
2736
+
2737
+ ### Overview
2738
+
2739
+ Shared preparation mechanism used by `AI.prepareTTS()`. It owns ordered
2740
+ generation admission, same-owner request sharing, complete audio storage and
2741
+ semantic reuse, and each caller's preparation lifetime. It does not construct
2742
+ an audio context, play speech, or select application content.
2743
+
2744
+ ### Public surface
2745
+
2746
+ Named `prepareSpeech({owner,parts,originalParts=parts,selection=null,
2747
+ segmentation=null,storage=null,identity=null,signal=null,onState,synthesize})`.
2748
+ The owning AI supplies already segmented speech parts, complete original parts,
2749
+ its selection snapshot, and its synthesis callback. The returned handle is
2750
+ `{segments,state,ready,getAudio(index),cancel()}`. Applications use
2751
+ `AI.prepareTTS()` and `AI.playPreparedTTS()` so the existing AI owner retains
2752
+ automatic formatting cleanup, segmentation, provider readiness/capacity, and
2753
+ ordered playback. See the [complete preparation contract](ai/browser-speech.md#prepare-narration-once-and-replay-stored-audio).
2754
+
2755
+ `storage:{db,table,key}` is optional; the ready DBOPFS instance supplies
2756
+ `get`, `set`, `readFile`, and `writeFile`. JSON-compatible semantic inputs stay
2757
+ complete in the version-1 manifest. Raw audio is persisted separately and its
2758
+ MIME type is retained in metadata. Storage mutation serializes by database,
2759
+ table, and key within the realm. Synthesis sharing is scoped to the same owner
2760
+ and matching semantic inputs/storage; playback remains outside this module.
2761
+
2762
+ Exact exports: `prepareSpeech`.
2763
+
2764
+ ### Availability and normalization
2765
+
2766
+ **Browser or native WebView with Blob, AbortController, an injected synthesis
2767
+ callback, and optional ready DBOPFS.** Import creates no provider or
2768
+ playback. Calling the preparation function starts owned asynchronous work.
2769
+ `ready` rejects complete synthesis/storage failures or `AbortError` after
2770
+ cancellation; successful audio remains available for reuse. Malformed part,
2771
+ storage, or semantic metadata inputs throw `TypeError`; an invalid segment
2772
+ index rejects with `RangeError`. No Core capability is selected here.
2773
+
2774
+ ### Example
2775
+
2776
+ ```javascript
2777
+ import {prepareSpeech} from '/arcane/modules/PreparedSpeech.js';
2778
+
2779
+ // Applications use AI.prepareTTS; this import only exposes the SDK mechanism.
2780
+ console.log(typeof prepareSpeech); // function
2781
+ ```
2782
+
2693
2783
  ## QRCode.min.js
2694
2784
 
2695
2785
  ### Overview
@@ -19,7 +19,7 @@ This table is the Node `package.json#exports` map: it defines package
19
19
  entrypoints for SDK/tooling code. It is distinct from the generated browser
20
20
  import map that resolves application-facing `arcane/*` modules and the focused
21
21
  EventManager entry. See [browser runtime delivery](protocols.md#browser-runtime-delivery)
22
- for the installed-inventory-derived physical-runtime contract in SDK `0.5.17`.
22
+ for the installed-inventory-derived physical-runtime contract in SDK `0.5.18`.
23
23
 
24
24
  | Specifier | Purpose |
25
25
  | --- | --- |
@@ -37,13 +37,29 @@ for the installed-inventory-derived physical-runtime contract in SDK `0.5.17`.
37
37
  | `arcane-os/logging` | Shared console diagnostics controlled by the existing `user.developer` preference. |
38
38
  | `arcane-os/preference-store` | Portable preference records and injected storage adapters. |
39
39
  | `arcane-os/speech-playback` | Portable speech preparation, playback state, and injected media adapters. |
40
- | `arcane-os/speech-text` | Dependency-free speech-input formatting cleanup for complete text and streamed chunks. |
40
+ | `arcane-os/speech-text` | Speech-input formatting cleanup for complete text and streamed chunks. |
41
41
  | `arcane-os/ai/browser-wasm` | Caller-selected browser-local Wllama inference, complete DBOPFS model storage, streaming, cancellation, and structural tool-call results. |
42
42
  | `arcane-os/ai/browser-speech` | Caller-selected browser-local Whisper STT and Kokoro TTS provider mechanisms, ordinary upstream assets, materialized/native routing, Workers, and cancellation. |
43
43
  | `arcane-os/mail` | Portable Mail runtime, durable outbox, complete transport responses, and provider-neutral acceptance contracts. |
44
44
 
45
45
  Eight JSON schemas and `package.json` are data-only export subpaths. In Node ESM, import JSON with `with {type: 'json'}`, or resolve and read it explicitly.
46
46
 
47
+ ### Managed AI narration
48
+
49
+ Applications import `AI` through `arcane/AI` in the managed browser map.
50
+ `ai.prepareTTS({parts,storage,identity,signal,onState})` prepares complete
51
+ punctuation segments without playing them and optionally saves/reuses their
52
+ audio through application-owned DBOPFS. Its immediate handle exposes ordered
53
+ segments, preparation state, `ready`, `getAudio(index)`, and `cancel()`.
54
+ `ai.playPreparedTTS(prepared,{signal,onState})` attaches ordered playback and
55
+ returns `state`, `error`, `finished`, `pause()`, `resume()`, and `stop()`.
56
+ Each AI has one playback lane; replacing playback preserves independent
57
+ preparation. Fully cached replay does not load the speech
58
+ model. See [prepared narration](ai/browser-speech.md#prepare-narration-once-and-replay-stored-audio)
59
+ for complete inputs, storage ownership, progress, errors, and cancellation,
60
+ and [AI.js](runtime-modules.md#aijs) for the managed runtime contract.
61
+ These are AI instance methods, not new npm export names.
62
+
47
63
  ## Shared operation contract
48
64
 
49
65
  High-level operations accept one options object. Common fields are `workspaceRoot`, `appId`, `target`, `signal`, and `onEvent`; only fields meaningful to that operation are consumed. Long work acknowledges first, owns its child tasks, keeps event delivery ordered and backpressured, emits progress or heartbeats, observes cancellation where safe, and rejects with `ArcaneError` on failure.
@@ -757,7 +773,7 @@ deterministic map. The package root also contains the public
757
773
  {
758
774
  schemaVersion: 1,
759
775
  kind: 'arcane-app-runtime-projection',
760
- sdkVersion: '0.5.17',
776
+ sdkVersion: '0.5.18',
761
777
  pathPrefix: 'arcane/',
762
778
  files: [{path}]
763
779
  }
@@ -1719,7 +1735,7 @@ console.log(splitSpeechText('Hello world.'));
1719
1735
 
1720
1736
  ### Overview
1721
1737
 
1722
- Streams the SDK's dependency-free speech formatting cleanup across input chunk
1738
+ Streams the SDK's speech formatting cleanup across input chunk
1723
1739
  boundaries. `append()` removes runs of two or more identical `*`, `#`, `_`,
1724
1740
  backtick, or `~` marks while retaining single marks and every other character.
1725
1741
  It is a narrow speech filter, not a Markdown parser. Normal SDK TTS calls use
@@ -3633,7 +3649,7 @@ workspace it additionally returns the exact installed package authority:
3633
3649
  packageSource,
3634
3650
  canonicalPackageRoot,
3635
3651
  packageName: 'arcane-os',
3636
- packageVersion: '0.5.17',
3652
+ packageVersion: '0.5.18',
3637
3653
  runtimeRoot,
3638
3654
  browserRuntimeRoot
3639
3655
  }
@@ -3641,9 +3657,9 @@ workspace it additionally returns the exact installed package authority:
3641
3657
  ```
3642
3658
 
3643
3659
  The dependency can be named `arcane-os` or be one exact npm alias for
3644
- `npm:arcane-os@0.5.17`. The selected installation must still be one direct,
3660
+ `npm:arcane-os@0.5.18`. The selected installation must still be one direct,
3645
3661
  physical, non-link package directory whose manifest identifies exactly as
3646
- `arcane-os@0.5.17`; duplicate canonical/alias declarations reject.
3662
+ `arcane-os@0.5.18`; duplicate canonical/alias declarations reject.
3647
3663
  `allowMissingManagedImportMap` is an internal packaging/development seam. An
3648
3664
  ordinary caller should leave it `false`.
3649
3665
 
@@ -319,6 +319,7 @@
319
319
  "arcane-os/event-manager": "/src/event-manager.mjs",
320
320
  "arcane-os/dom-event-instrumentation": "/src/dom-event-instrumentation.mjs",
321
321
  "event-pubsub": "/browser-runtime/dependencies/event-pubsub/index.js",
322
+ "strong-type": "/runtime/strong-type/index.js",
322
323
  "arcane-os/ai/browser-wasm": "/browser-runtime/ai/browser-wasm.mjs",
323
324
  "arcane-os/ai/browser-speech": "/browser-runtime/ai/browser-speech.mjs",
324
325
  "arcane-os/preference-store": "/runtime/arcane/modules/PreferenceStore.js",