arcane-os 0.1.0-dev.5

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 (248) hide show
  1. package/CHANGELOG.md +154 -0
  2. package/COMMERCIAL-LICENSE.md +13 -0
  3. package/LICENSE +661 -0
  4. package/NOTICE +70 -0
  5. package/README.md +448 -0
  6. package/bin/arcane-test.mjs +741 -0
  7. package/bin/arcane.mjs +5 -0
  8. package/docs/architecture.md +234 -0
  9. package/docs/compatibility.md +36 -0
  10. package/docs/event-manager.md +166 -0
  11. package/docs/platform-targets.md +108 -0
  12. package/docs/publishing.md +203 -0
  13. package/docs/reference/README.md +117 -0
  14. package/docs/reference/arcane-ollama.md +288 -0
  15. package/docs/reference/availability-and-normalization.md +123 -0
  16. package/docs/reference/behavioral-testing.md +86 -0
  17. package/docs/reference/cli.md +569 -0
  18. package/docs/reference/core/README.md +62 -0
  19. package/docs/reference/core/arcane-ai-contracts.md +873 -0
  20. package/docs/reference/core/arcane-api.md +601 -0
  21. package/docs/reference/core/arcane-entities.md +65 -0
  22. package/docs/reference/core/arcane-events.md +134 -0
  23. package/docs/reference/core/ollama-module.md +181 -0
  24. package/docs/reference/core/reference/arcane-api/ai-and-ollama.md +1909 -0
  25. package/docs/reference/core/reference/arcane-api/applications-terminal-capabilities.md +1057 -0
  26. package/docs/reference/core/reference/arcane-api/core-and-events.md +320 -0
  27. package/docs/reference/core/reference/arcane-api/filesystem-storage-preferences-appearance.md +610 -0
  28. package/docs/reference/core/reference/arcane-api/namespaces.md +1157 -0
  29. package/docs/reference/core/reference/arcane-api/platform-installation-users-system.md +1423 -0
  30. package/docs/reference/core/reference/arcane-api/session-provisioning-diagnostics-development.md +315 -0
  31. package/docs/reference/event-manager.md +957 -0
  32. package/docs/reference/inventory/package-api.json +2632 -0
  33. package/docs/reference/inventory/runtime-components.json +934 -0
  34. package/docs/reference/inventory/runtime-entities.json +26 -0
  35. package/docs/reference/inventory/runtime-modules.json +1249 -0
  36. package/docs/reference/protocols.md +242 -0
  37. package/docs/reference/runtime-components.md +1098 -0
  38. package/docs/reference/runtime-entities.md +303 -0
  39. package/docs/reference/runtime-modules.md +2010 -0
  40. package/docs/reference/sdk-api.md +4901 -0
  41. package/docs/roadmap.md +79 -0
  42. package/docs/work-amplification.md +124 -0
  43. package/node_modules/event-pubsub/CHANGELOG.md +55 -0
  44. package/node_modules/event-pubsub/MIGRATION.md +70 -0
  45. package/node_modules/event-pubsub/README.md +363 -0
  46. package/node_modules/event-pubsub/SECURITY.md +37 -0
  47. package/node_modules/event-pubsub/index.js +141 -0
  48. package/node_modules/event-pubsub/licence +21 -0
  49. package/node_modules/event-pubsub/package.json +59 -0
  50. package/node_modules/strong-type/README.md +408 -0
  51. package/node_modules/strong-type/assets/strong-type-header.png +0 -0
  52. package/node_modules/strong-type/index.js +1151 -0
  53. package/node_modules/strong-type/licence +21 -0
  54. package/node_modules/strong-type/node.js +125 -0
  55. package/node_modules/strong-type/package.json +61 -0
  56. package/package.json +95 -0
  57. package/runtime/ARCANE_RUNTIME_RELEASE.json +791 -0
  58. package/runtime/arcane/components/app-bar.html +468 -0
  59. package/runtime/arcane/components/assistant-panel.html +715 -0
  60. package/runtime/arcane/components/calculator.html +8 -0
  61. package/runtime/arcane/components/chart.html +655 -0
  62. package/runtime/arcane/components/chat.html +1225 -0
  63. package/runtime/arcane/components/conversation-view.html +13 -0
  64. package/runtime/arcane/components/dashboard-config.html +341 -0
  65. package/runtime/arcane/components/data-maintenance.html +112 -0
  66. package/runtime/arcane/components/data-view.html +92 -0
  67. package/runtime/arcane/components/directory-picker.html +197 -0
  68. package/runtime/arcane/components/document-inspector.html +252 -0
  69. package/runtime/arcane/components/file-drop.html +264 -0
  70. package/runtime/arcane/components/file-inspector.html +293 -0
  71. package/runtime/arcane/components/file-manager.html +1715 -0
  72. package/runtime/arcane/components/header.html +142 -0
  73. package/runtime/arcane/components/integration-settings.html +14 -0
  74. package/runtime/arcane/components/local-ai-status.html +360 -0
  75. package/runtime/arcane/components/markdown-document.html +1048 -0
  76. package/runtime/arcane/components/markdown-editor.html +360 -0
  77. package/runtime/arcane/components/media-embed.html +8 -0
  78. package/runtime/arcane/components/modal.html +402 -0
  79. package/runtime/arcane/components/output-panel.html +259 -0
  80. package/runtime/arcane/components/preferences-form.html +135 -0
  81. package/runtime/arcane/components/record-timeline.html +105 -0
  82. package/runtime/arcane/components/relationship-board.html +116 -0
  83. package/runtime/arcane/components/screen-capture.html +8 -0
  84. package/runtime/arcane/components/source-code-viewer.html +441 -0
  85. package/runtime/arcane/components/source-explanation.html +124 -0
  86. package/runtime/arcane/components/speech.html +365 -0
  87. package/runtime/arcane/components/summary-strip.html +177 -0
  88. package/runtime/arcane/components/table.html +77 -0
  89. package/runtime/arcane/components/task-progress.html +282 -0
  90. package/runtime/arcane/components/terminal-workspace.html +65 -0
  91. package/runtime/arcane/components/theme-editor.html +41 -0
  92. package/runtime/arcane/components/theme-switcher.html +46 -0
  93. package/runtime/arcane/components/unified-inbox.html +20 -0
  94. package/runtime/arcane/components/voice-transcription.html +476 -0
  95. package/runtime/arcane/components/weather-widget.html +8 -0
  96. package/runtime/arcane/components/web-navigator.html +239 -0
  97. package/runtime/arcane/css/communications.css +1 -0
  98. package/runtime/arcane/css/dashboard-config.css +45 -0
  99. package/runtime/arcane/css/document-site.css +981 -0
  100. package/runtime/arcane/css/layout.css +438 -0
  101. package/runtime/arcane/css/primitives.css +321 -0
  102. package/runtime/arcane/css/theme.css +112 -0
  103. package/runtime/arcane/css/utility-workspace.css +1 -0
  104. package/runtime/arcane/entities/ApiModelRecord.js +20 -0
  105. package/runtime/arcane/entities/Calculation.js +13 -0
  106. package/runtime/arcane/entities/Chat.js +581 -0
  107. package/runtime/arcane/entities/CommunicationMessage.js +29 -0
  108. package/runtime/arcane/entities/CommunicationThread.js +21 -0
  109. package/runtime/arcane/entities/Document.js +10 -0
  110. package/runtime/arcane/entities/File.js +143 -0
  111. package/runtime/arcane/entities/Image.js +135 -0
  112. package/runtime/arcane/entities/IntentEnvelope.js +834 -0
  113. package/runtime/arcane/entities/Preference.js +83 -0
  114. package/runtime/arcane/entities/TWiNPolicyDecision.js +1092 -0
  115. package/runtime/arcane/entities/TerminalSession.js +46 -0
  116. package/runtime/arcane/entities/Theme.js +107 -0
  117. package/runtime/arcane/entities/User.js +1046 -0
  118. package/runtime/arcane/entities/Weather.js +23 -0
  119. package/runtime/arcane/img/arcane-os-everywhere.png +0 -0
  120. package/runtime/arcane/img/arrow-left.png +0 -0
  121. package/runtime/arcane/img/arrow-right.png +0 -0
  122. package/runtime/arcane/img/doc.svg +5 -0
  123. package/runtime/arcane/img/folder.svg +4 -0
  124. package/runtime/arcane/img/image.svg +5 -0
  125. package/runtime/arcane/img/refresh.png +0 -0
  126. package/runtime/arcane/img/send.svg +9 -0
  127. package/runtime/arcane/img/trash.svg +5 -0
  128. package/runtime/arcane/img/upload.svg +5 -0
  129. package/runtime/arcane/modules/AI.js +2048 -0
  130. package/runtime/arcane/modules/AIPreferenceRuntime.js +32 -0
  131. package/runtime/arcane/modules/AIPreferenceTuple.js +92 -0
  132. package/runtime/arcane/modules/AIResponseLength.js +42 -0
  133. package/runtime/arcane/modules/AIResponseURLPolicy.js +626 -0
  134. package/runtime/arcane/modules/AnsiText.js +53 -0
  135. package/runtime/arcane/modules/ApiModelDatabase.js +25 -0
  136. package/runtime/arcane/modules/AppDataScope.js +245 -0
  137. package/runtime/arcane/modules/AppearancePreferences.js +28 -0
  138. package/runtime/arcane/modules/ArcaneCommunicationBridge.js +22 -0
  139. package/runtime/arcane/modules/ArcaneNavigationPolicy.js +135 -0
  140. package/runtime/arcane/modules/ArcaneNetworkPolicy.js +255 -0
  141. package/runtime/arcane/modules/AsyncBoundary.js +161 -0
  142. package/runtime/arcane/modules/BrowserTestSuite.js +326 -0
  143. package/runtime/arcane/modules/CalculatorEngine.js +20 -0
  144. package/runtime/arcane/modules/CaseEvidenceIndexer.js +134 -0
  145. package/runtime/arcane/modules/ChartLibrary.js +35 -0
  146. package/runtime/arcane/modules/ChatRecords.js +13 -0
  147. package/runtime/arcane/modules/CommunicationAppController.js +43 -0
  148. package/runtime/arcane/modules/CommunicationHub.js +16 -0
  149. package/runtime/arcane/modules/CommunicationPreferences.js +13 -0
  150. package/runtime/arcane/modules/CommunicationProviderRegistry.js +16 -0
  151. package/runtime/arcane/modules/ComponentContracts.js +586 -0
  152. package/runtime/arcane/modules/ConfiguredAIChatSession.js +288 -0
  153. package/runtime/arcane/modules/ConversationActionItems.js +488 -0
  154. package/runtime/arcane/modules/ConversationClosingReport.js +274 -0
  155. package/runtime/arcane/modules/ConversationTimebox.js +527 -0
  156. package/runtime/arcane/modules/CoreLocalModelCatalog.js +255 -0
  157. package/runtime/arcane/modules/DBLS.js +171 -0
  158. package/runtime/arcane/modules/DBOPFS.js +1154 -0
  159. package/runtime/arcane/modules/DBOPFSWorker.js +116 -0
  160. package/runtime/arcane/modules/DataMaintenance.js +91 -0
  161. package/runtime/arcane/modules/DevelopmentWorkspace.js +74 -0
  162. package/runtime/arcane/modules/DirectoryPicker.js +109 -0
  163. package/runtime/arcane/modules/DocumentNavigation.js +223 -0
  164. package/runtime/arcane/modules/Errors.js +1025 -0
  165. package/runtime/arcane/modules/GifEncoder.js +29 -0
  166. package/runtime/arcane/modules/HTMLImport.js +114 -0
  167. package/runtime/arcane/modules/InMemoryCommunicationProvider.js +14 -0
  168. package/runtime/arcane/modules/IsolatedModelQuestionRunner.js +275 -0
  169. package/runtime/arcane/modules/LocalAIReadiness.js +870 -0
  170. package/runtime/arcane/modules/LocalAIReadinessController.js +156 -0
  171. package/runtime/arcane/modules/MD.js +111 -0
  172. package/runtime/arcane/modules/Mail.js +352 -0
  173. package/runtime/arcane/modules/MailTransport.mjs +180 -0
  174. package/runtime/arcane/modules/Marked.min.js +71 -0
  175. package/runtime/arcane/modules/MemoryRecords.js +44 -0
  176. package/runtime/arcane/modules/MessageAdvisory.js +38 -0
  177. package/runtime/arcane/modules/ModelDefinition.js +189 -0
  178. package/runtime/arcane/modules/Ollama.js +74 -0
  179. package/runtime/arcane/modules/OllamaModelIdentifier.js +21 -0
  180. package/runtime/arcane/modules/OllamaSettings.js +24 -0
  181. package/runtime/arcane/modules/OpenMeteoWeatherProvider.js +14 -0
  182. package/runtime/arcane/modules/PreferenceStore.js +109 -0
  183. package/runtime/arcane/modules/QRCode.min.js +1 -0
  184. package/runtime/arcane/modules/Questionnaire.js +61 -0
  185. package/runtime/arcane/modules/RecordLinkIndex.js +24 -0
  186. package/runtime/arcane/modules/RecordPassageIndex.js +222 -0
  187. package/runtime/arcane/modules/RecordReviewStore.js +94 -0
  188. package/runtime/arcane/modules/RevocableProjectionLedger.js +1623 -0
  189. package/runtime/arcane/modules/RiskSignalAnalyzer.js +37 -0
  190. package/runtime/arcane/modules/ScamRiskPolicy.js +62 -0
  191. package/runtime/arcane/modules/ScopedOPFSCache.js +183 -0
  192. package/runtime/arcane/modules/ScreenCapture.js +20 -0
  193. package/runtime/arcane/modules/SpeechPlayback.js +581 -0
  194. package/runtime/arcane/modules/StaticDocumentCatalog.js +1248 -0
  195. package/runtime/arcane/modules/SystemAppearance.js +20 -0
  196. package/runtime/arcane/modules/SystemPlatformPresentation.js +51 -0
  197. package/runtime/arcane/modules/SystemToolRegistry.js +28 -0
  198. package/runtime/arcane/modules/TerminalClient.js +52 -0
  199. package/runtime/arcane/modules/TerminalCommandRegistry.js +50 -0
  200. package/runtime/arcane/modules/ThemeBootstrap.js +26 -0
  201. package/runtime/arcane/modules/ThemeManager.js +131 -0
  202. package/runtime/arcane/modules/TimeGuard.js +149 -0
  203. package/runtime/arcane/modules/ToolCallRouter.js +83 -0
  204. package/runtime/arcane/modules/WaitForComponent.js +102 -0
  205. package/runtime/arcane/modules/YouTubeMedia.js +16 -0
  206. package/runtime/arcane/modules/uPlot.LICENSE.txt +21 -0
  207. package/runtime/arcane/modules/uPlot.iife.min.js +2 -0
  208. package/runtime/arcane/modules/uPlot.min.css +1 -0
  209. package/runtime/arcane/security/arcane-network-policy.json +6 -0
  210. package/runtime/strong-type/index.js +352 -0
  211. package/runtime/strong-type/licence +21 -0
  212. package/runtime/strong-type/package.json +45 -0
  213. package/schemas/arcane-app-bundle.schema.json +125 -0
  214. package/schemas/arcane-app.schema.json +329 -0
  215. package/schemas/arcane-lock.schema.json +86 -0
  216. package/schemas/arcane-package.schema.json +224 -0
  217. package/schemas/cli-event.schema.json +122 -0
  218. package/schemas/event-stack.schema.json +152 -0
  219. package/schemas/native-build-plan.schema.json +176 -0
  220. package/schemas/target-adapter.schema.json +117 -0
  221. package/src/app-descriptor.mjs +500 -0
  222. package/src/cli/main.mjs +561 -0
  223. package/src/constants.mjs +31 -0
  224. package/src/dev-server.mjs +718 -0
  225. package/src/doctor.mjs +315 -0
  226. package/src/dom-event-instrumentation.mjs +594 -0
  227. package/src/errors.mjs +75 -0
  228. package/src/event-manager.mjs +1342 -0
  229. package/src/event-queue.mjs +138 -0
  230. package/src/events.mjs +219 -0
  231. package/src/index.mjs +177 -0
  232. package/src/integrated-provider-loader.mjs +432 -0
  233. package/src/native-plan.mjs +698 -0
  234. package/src/native-provider-loader.mjs +1126 -0
  235. package/src/packager/core.mjs +2691 -0
  236. package/src/process.mjs +353 -0
  237. package/src/release-bundle.mjs +2523 -0
  238. package/src/repository.mjs +90 -0
  239. package/src/runtime.mjs +452 -0
  240. package/src/scaffold.mjs +380 -0
  241. package/src/targets/index.mjs +436 -0
  242. package/src/templates/assets/app-icon.png +0 -0
  243. package/src/templates/workspace-template.mjs +388 -0
  244. package/src/testing-loader.mjs +9 -0
  245. package/src/testing.mjs +427 -0
  246. package/src/toolchain.mjs +1335 -0
  247. package/src/update-check.mjs +307 -0
  248. package/src/workspace.mjs +449 -0
@@ -0,0 +1,610 @@
1
+ # Arcane API filesystem, storage, preferences, environment, and appearance guides
2
+
3
+ These authored notes explain the app-scoped persistence and user-controlled host
4
+ surfaces behind the canonical inventory in [`docs/arcane-api.md`](../../arcane-api.md).
5
+ The methods remain capability-gated by the application descriptor; feature-detect
6
+ the exact method before presenting a control.
7
+
8
+ ## Arcane.filesystem.selectDirectory()
9
+
10
+ ### Overview
11
+
12
+ Opens the operating system's folder picker after a user action and returns one
13
+ canonical existing directory. This is a selection capability, not general
14
+ filesystem access: it does not enumerate drives, read the directory, create a
15
+ folder, or grant permission to its contents.
16
+
17
+ Use it when an application needs the user to choose a local workspace or export
18
+ location. The application must still validate that the selected directory is
19
+ appropriate for its own workflow.
20
+
21
+ ### Options
22
+
23
+ Pass an object containing only these optional fields:
24
+
25
+ | Field | Contract |
26
+ |---|---|
27
+ | `title` | Plain-text dialog title. Defaults to `Choose a folder`; maximum 200 characters; control characters are rejected. |
28
+ | `initialPath` | Existing absolute directory path. It is canonicalized before the picker opens and may not exceed 4,096 characters. |
29
+
30
+ The promise resolves to `{cancelled:true,path:null}` when the user cancels, or
31
+ `{cancelled:false,path}` with the canonical absolute path. Cancellation is a
32
+ normal result, not an error.
33
+
34
+ ### Availability and errors
35
+
36
+ Requires `filesystem.directory.select`. Core-backed Microsoft NT uses the native
37
+ folder browser; Linux uses an installed Zenity or KDialog picker. Unsupported
38
+ hosts reject with `FILESYSTEM_DIRECTORY_SELECTION_UNSUPPORTED`. Invalid options,
39
+ an unavailable initial path, an invalid host response, or a selected directory
40
+ that disappears are rejected explicitly.
41
+
42
+ ### Example
43
+
44
+ ```js
45
+ async function chooseWorkspaceDirectory() {
46
+ const access = await Arcane.capabilities.list();
47
+ if (!access.methods.includes('filesystem.directory.select')) return null;
48
+
49
+ const selection = await Arcane.filesystem.selectDirectory({
50
+ title: 'Choose a development workspace'
51
+ });
52
+ return selection.cancelled ? null : selection.path;
53
+ }
54
+
55
+ document.querySelector('#choose-workspace')?.addEventListener(
56
+ 'click',
57
+ async function handleWorkspaceSelection() {
58
+ const path = await chooseWorkspaceDirectory();
59
+ if (path) document.querySelector('#workspace-path').textContent = path;
60
+ }
61
+ );
62
+ ```
63
+ ## Arcane.storage.list()
64
+
65
+ ### Overview
66
+
67
+ Reports the keys and quota use for the current application's native storage.
68
+ Storage is isolated by the application identity bound to the Core session; one
69
+ application cannot use this namespace to inspect another application's records.
70
+
71
+ ### Return value
72
+
73
+ Requires `storage.read` and resolves to:
74
+
75
+ ```text
76
+ { keys: string[], usedBytes: number, maximumBytes: 1048576 }
77
+ ```
78
+
79
+ Keys are sorted. `usedBytes` covers the complete persisted storage envelope, so
80
+ it can be larger than the sum of the individual JSON values.
81
+
82
+ ### Usage and failure behavior
83
+
84
+ Use the keys to build an index, then call `get()` only for records the current
85
+ view needs. An empty array is a valid new-app state. `METHOD_NOT_ALLOWED` means
86
+ the current application lacks `storage.read`; do not fall back to another
87
+ application's browser storage or retry until policy changes.
88
+
89
+ ### Example
90
+
91
+ ```js
92
+ async function showStorageBudget() {
93
+ const inventory = await Arcane.storage.list();
94
+ console.log(`${inventory.usedBytes} of ${inventory.maximumBytes} bytes used`);
95
+ for (const key of inventory.keys) console.log(key);
96
+ }
97
+
98
+ await showStorageBudget();
99
+ ```
100
+
101
+ ## Arcane.storage.get()
102
+
103
+ ### Overview
104
+
105
+ Reads one JSON-compatible value from the current application's native storage.
106
+ Use the explicit `found` flag to distinguish a missing key from a stored `null`.
107
+
108
+ ### Key and return value
109
+
110
+ The key must contain 1–128 letters, numbers, periods, underscores, colons, or
111
+ hyphens and begin with a letter or number. The promise resolves to
112
+ `{key,found,value}`; a missing key returns `found:false` and `value:null` rather
113
+ than rejecting.
114
+
115
+ Requires `storage.read`.
116
+
117
+ ### Errors and recovery
118
+
119
+ Invalid keys reject with `INVALID_STORAGE_KEY`; correct the key rather than
120
+ retrying. A capability rejection means this application cannot read native
121
+ storage. Treat a host or transport failure as an unavailable read, not as a
122
+ missing record, so the UI does not silently replace unknown data with defaults.
123
+
124
+ ### Example
125
+
126
+ ```js
127
+ async function loadDraft() {
128
+ const result = await Arcane.storage.get('editor.draft.current');
129
+ return result.found ? result.value : { text: '', updatedAt: null };
130
+ }
131
+
132
+ const draft = await loadDraft();
133
+ console.log(draft.updatedAt);
134
+ ```
135
+
136
+ ## Arcane.storage.set()
137
+
138
+ ### Overview
139
+
140
+ Atomically creates or replaces one app-scoped storage value. Use storage for
141
+ application data that is larger or more durable than a user preference, while
142
+ remaining within the intentionally small native quota.
143
+
144
+ ### Input and result
145
+
146
+ The key follows the storage-key rules above. `value` is normalized through a
147
+ JSON round-trip. Top-level `undefined`, functions, circular references, and
148
+ values that cannot produce JSON reject. Inside objects, `undefined` and function
149
+ properties are omitted; inside arrays, those slots become `null`. The receipt
150
+ returns the normalized value, so do not use storage for data whose meaning
151
+ depends on those values. One encoded value may use at most 131,072 bytes, and
152
+ the complete app storage envelope may use at most 1,048,576 bytes.
153
+
154
+ Requires `storage.write`. It resolves to
155
+ `{key,value,bytes,totalBytes,maximumBytes}` only after the atomic write completes.
156
+ Quota and validation failures leave the previous file unchanged.
157
+
158
+ ### Example
159
+
160
+ ```js
161
+ async function saveDraft(text) {
162
+ return Arcane.storage.set('editor.draft.current', {
163
+ text: String(text),
164
+ updatedAt: new Date().toISOString()
165
+ });
166
+ }
167
+
168
+ const receipt = await saveDraft('Synthetic example text');
169
+ console.log(`Saved ${receipt.bytes} bytes`);
170
+ ```
171
+
172
+ ## Arcane.storage.delete()
173
+
174
+ ### Overview
175
+
176
+ Deletes one key from the current application's native storage. Deleting a key
177
+ that is already absent is safe and resolves with `deleted:false`.
178
+
179
+ ### Return value and errors
180
+
181
+ Requires `storage.write` and resolves to
182
+ `{key,deleted,totalBytes,maximumBytes}`. Invalid keys reject before the storage
183
+ file is read. A successful `deleted:true` result means the updated storage
184
+ envelope was written atomically.
185
+
186
+ ### Side effects and recovery
187
+
188
+ Deletes are serialized with writes to the same app-owned document. If the
189
+ renderer loses its connection around a delete, call `get()` after reconnecting
190
+ to establish whether the key remains before offering another destructive
191
+ action; a missing response is not proof that the mutation failed.
192
+
193
+ ### Example
194
+
195
+ ```js
196
+ async function discardDraft() {
197
+ const result = await Arcane.storage.delete('editor.draft.current');
198
+ console.log(result.deleted ? 'Draft removed' : 'No draft was stored');
199
+ }
200
+
201
+ document.querySelector('#discard-draft')?.addEventListener(
202
+ 'click',
203
+ discardDraft
204
+ );
205
+ ```
206
+
207
+ ## Arcane.preferences.list()
208
+
209
+ ### Overview
210
+
211
+ Reports the current application's preference keys and quota use. Preferences
212
+ share the storage value and key validation rules but live in a separate
213
+ app-scoped preferences document.
214
+
215
+ ### Return value
216
+
217
+ Requires `preferences.read` and resolves to
218
+ `{keys,usedBytes,maximumBytes}`. Keys are sorted and `maximumBytes` is currently
219
+ 1,048,576 bytes for the complete preferences envelope.
220
+
221
+ ### Usage and failure behavior
222
+
223
+ Use this inventory to discover configured names, then read a needed preference
224
+ with `get()`. Apply an application default only when that result says
225
+ `found:false`. An empty list is valid. `METHOD_NOT_ALLOWED` means the application
226
+ lacks `preferences.read`; do not switch to an unreviewed persistence path.
227
+
228
+ ### Example
229
+
230
+ ```js
231
+ async function listPreferenceNames() {
232
+ const inventory = await Arcane.preferences.list();
233
+ return inventory.keys;
234
+ }
235
+
236
+ console.log(await listPreferenceNames());
237
+ ```
238
+
239
+ ## Arcane.preferences.get()
240
+
241
+ ### Overview
242
+
243
+ Reads one app-scoped preference. Use it for a user choice that the same
244
+ application should restore later; use shared Arcane services for system-wide
245
+ policy rather than copying a platform setting into app preferences.
246
+
247
+ ### Result
248
+
249
+ Requires `preferences.read`. The key uses the same 1–128 character contract as
250
+ storage keys. The promise resolves to `{key,found,value}` and returns
251
+ `found:false,value:null` for an absent preference.
252
+
253
+ ### Errors and recovery
254
+
255
+ Invalid names reject with `INVALID_STORAGE_KEY` because preferences share the
256
+ storage-key validator. A permission or host failure is not an absent preference:
257
+ keep the setting unresolved or retain its current in-memory value instead of
258
+ silently overwriting it with a default.
259
+
260
+ ### Example
261
+
262
+ ```js
263
+ async function preferredDensity() {
264
+ const result = await Arcane.preferences.get('layout.density');
265
+ return result.found ? result.value : 'comfortable';
266
+ }
267
+
268
+ document.documentElement.dataset.density = await preferredDensity();
269
+ ```
270
+
271
+ ## Arcane.preferences.set()
272
+
273
+ ### Overview
274
+
275
+ Atomically creates or replaces one app-scoped preference. The complete value is
276
+ validated before mutation, and the resolved receipt returns the JSON-normalized
277
+ value that was actually persisted.
278
+
279
+ ### Input, result, and errors
280
+
281
+ Requires `preferences.write`. Keys and values use the storage key, JSON, 128 KiB
282
+ per-value, and 1 MiB total-envelope limits. The promise resolves to
283
+ `{key,value,bytes,totalBytes,maximumBytes}`. Invalid JSON-compatible data or a
284
+ quota overflow rejects without replacing the prior preference document.
285
+
286
+ ### Example
287
+
288
+ ```js
289
+ async function saveDensity(density) {
290
+ if (!['compact', 'comfortable'].includes(density)) {
291
+ throw new TypeError('Unsupported density');
292
+ }
293
+ return Arcane.preferences.set('layout.density', density);
294
+ }
295
+
296
+ await saveDensity('compact');
297
+ ```
298
+
299
+ ## Arcane.preferences.setMany()
300
+
301
+ ### Overview
302
+
303
+ Validates and writes a related preference batch as one atomic mutation. Prefer
304
+ this method when several settings describe one UI state and must never be
305
+ observed half-updated.
306
+
307
+ ### Entries and result
308
+
309
+ Pass a plain object containing 1–32 entries. Every key and value is normalized
310
+ before any write begins. The entire request rejects when any member is invalid
311
+ or the merged document exceeds the 1 MiB quota.
312
+
313
+ Requires `preferences.write` and resolves to
314
+ `{keys,count,bytes,totalBytes,maximumBytes}`. `keys` is sorted, `bytes` is the sum
315
+ of the encoded values in this batch, and `totalBytes` covers the resulting full
316
+ preferences envelope.
317
+
318
+ ### Example
319
+
320
+ ```js
321
+ async function saveReadingPreferences() {
322
+ return Arcane.preferences.setMany({
323
+ 'reader.fontScale': 1.1,
324
+ 'reader.lineLength': 'medium',
325
+ 'reader.voice': 'onyx'
326
+ });
327
+ }
328
+
329
+ const receipt = await saveReadingPreferences();
330
+ console.log(`Updated ${receipt.count} preferences`);
331
+ ```
332
+
333
+ ## Arcane.preferences.delete()
334
+
335
+ ### Overview
336
+
337
+ Removes one app-scoped preference so the application can return to its default.
338
+ An absent key is not an error.
339
+
340
+ ### Return value
341
+
342
+ Requires `preferences.write` and resolves to
343
+ `{key,deleted,totalBytes,maximumBytes}`. The persisted document changes only
344
+ when `deleted` is `true`.
345
+
346
+ ### Side effects and recovery
347
+
348
+ Deletion is a serialized atomic preference mutation. If a transport failure
349
+ makes the response ambiguous, call `get()` after reconnecting and branch on
350
+ `found` before retrying. A missing key is already the desired default state and
351
+ resolves with `deleted:false` rather than rejecting.
352
+
353
+ ### Example
354
+
355
+ ```js
356
+ async function restoreDefaultDensity() {
357
+ const result = await Arcane.preferences.delete('layout.density');
358
+ return result.deleted;
359
+ }
360
+
361
+ document.querySelector('#restore-default-density')?.addEventListener(
362
+ 'click',
363
+ async function handleRestoreDefaultDensity() {
364
+ console.log(await restoreDefaultDensity());
365
+ }
366
+ );
367
+ ```
368
+
369
+ ## Arcane.environment.list()
370
+
371
+ ### Overview
372
+
373
+ Lists the Arcane-managed environment profile without exposing protected values.
374
+ Desktop hosts report the current user's Arcane-managed profile; Android reports
375
+ the calling application's private profile. Ordinary entries contain their
376
+ configured value; protected entries use the exact mask `•••••`.
377
+
378
+ This is a Vault-only administrative surface, not a general application
379
+ configuration mechanism. It requires `environment.read`, explicit app-id
380
+ admission, and a Core or Android host.
381
+
382
+ ### Return value
383
+
384
+ The promise resolves to
385
+ `{platform,pathSupported,maximumEntries,valueMaximumLength,persistence,entries}`.
386
+ At most 256 case-insensitively unique entries are returned in sorted order.
387
+ Desktop entries have `{name,value,configured:true,protected,scope:'user'}`;
388
+ Android entries use `scope:'app'`. Android also reports `pathSupported:false`,
389
+ because `PATH` is deliberately unavailable through this API there. Names use
390
+ 1–128 characters and ordinary values are bounded to 32,767 characters.
391
+
392
+ ### Example
393
+
394
+ ```js
395
+ async function renderEnvironmentInventory() {
396
+ const result = await Arcane.environment.list();
397
+ for (const entry of result.entries) {
398
+ console.log(entry.name, {
399
+ protected: entry.protected,
400
+ configured: entry.configured,
401
+ scope: entry.scope
402
+ });
403
+ }
404
+ }
405
+
406
+ await renderEnvironmentInventory();
407
+ ```
408
+
409
+ ## Arcane.environment.get()
410
+
411
+ ### Overview
412
+
413
+ Reads one configured environment entry, including the real value when the entry
414
+ is protected. This deliberate plaintext-reveal operation is restricted to the
415
+ Vault application with the separate `environment.protected.read` capability.
416
+ On Android the entry belongs to the calling application's private profile, and
417
+ requesting `PATH` rejects with `ENVIRONMENT_PATH_UNSUPPORTED`.
418
+
419
+ Do not log, persist, transmit, or place the returned value in diagnostics. Keep
420
+ it only for the immediate user-authorized workflow that required the reveal.
421
+
422
+ ### Input, result, and errors
423
+
424
+ Names must begin with a letter or underscore and then contain only letters,
425
+ numbers, underscores, periods, or hyphens, up to 128 characters. The promise
426
+ resolves to `{entry}` using the entry shape described above. Missing entries
427
+ reject with `ENVIRONMENT_ENTRY_NOT_FOUND`; invalid names reject before native
428
+ dispatch.
429
+
430
+ ### Example
431
+
432
+ ```js
433
+ async function revealEntryForCurrentInteraction(name) {
434
+ const { entry } = await Arcane.environment.get(name);
435
+ return entry.value;
436
+ }
437
+
438
+ const value = await revealEntryForCurrentInteraction('ARCANE_DEMO_VALUE');
439
+ document.querySelector('#environment-value').textContent = value;
440
+ ```
441
+
442
+ ## Arcane.environment.set()
443
+
444
+ ### Overview
445
+
446
+ Creates or replaces one Arcane-managed environment entry. It is an exclusive,
447
+ high-risk mutation available only to Vault with `environment.write`. Desktop
448
+ hosts persist a user-scoped entry for future processes; Android persists an
449
+ app-scoped entry in private storage. Already-running processes do not
450
+ retroactively receive a desktop change.
451
+
452
+ ### Input and protection
453
+
454
+ Call `set(name, value, options?)`. Values must be strings without null
455
+ characters and generally may not exceed 32,767 characters. On Linux, protected
456
+ Secret Service payloads have an additional 8,191-byte encoded ceiling (about
457
+ 6,126 ASCII value bytes after metadata). `options.protected` must be a Boolean
458
+ when supplied. The SDK defaults sensitive-looking names to protected storage,
459
+ and Core refuses to save such names unprotected. On desktop, `PATH` must remain
460
+ ordinary so future processes can use it; Android rejects any `PATH` mutation
461
+ with `ENVIRONMENT_PATH_UNSUPPORTED`.
462
+
463
+ The promise resolves to `{entry}`. Protected results contain the `•••••` mask,
464
+ never an echo of the submitted secret.
465
+
466
+ ### Mutation uncertainty and recovery
467
+
468
+ Environment writes are serialized. `ENVIRONMENT_OPERATION_BUSY`,
469
+ `ENVIRONMENT_RECOVERY_REQUIRED`, or `ENVIRONMENT_SERIALIZATION_RELEASE_FAILED`
470
+ means the profile cannot safely accept another mutation yet. Linux can also
471
+ report `ENVIRONMENT_PROTECTED_CLEANUP_FAILED` or
472
+ `ENVIRONMENT_METADATA_COMMIT_UNCERTAIN`; Android can report
473
+ `ANDROID_ENVIRONMENT_STORAGE_UNCERTAIN`. The renderer's normalized
474
+ `Arcane.Error` currently exposes the public error code but not the native
475
+ mutation-completion or cleanup-phase fields. Refresh the inventory after any of
476
+ these uncertainty codes before deciding how to recover, and never blindly retry.
477
+
478
+ ### Example
479
+
480
+ ```js
481
+ async function saveSyntheticProtectedValue() {
482
+ return Arcane.environment.set(
483
+ 'ARCANE_DEMO_TOKEN',
484
+ 'synthetic-development-value',
485
+ { protected: true }
486
+ );
487
+ }
488
+
489
+ document.querySelector('#confirm-environment-write')?.addEventListener(
490
+ 'click',
491
+ async function handleConfirmedEnvironmentWrite() {
492
+ const receipt = await saveSyntheticProtectedValue();
493
+ console.log(receipt.entry.name, receipt.entry.protected);
494
+ }
495
+ );
496
+ ```
497
+
498
+ ## Arcane.environment.remove()
499
+
500
+ ### Overview
501
+
502
+ Deletes one Arcane-managed environment entry: user-scoped on desktop and
503
+ app-scoped on Android. This exclusive Vault mutation is not reversible through
504
+ the API, so require a clear user confirmation and do not treat deletion as a way
505
+ to hide a value temporarily. Android rejects removal of `PATH` with
506
+ `ENVIRONMENT_PATH_UNSUPPORTED`.
507
+
508
+ ### Return value and errors
509
+
510
+ Requires `environment.write` and resolves to `{name,deleted:true}` only when the
511
+ native host removed the exact case-insensitive name requested. A missing entry
512
+ rejects with `ENVIRONMENT_ENTRY_NOT_FOUND`; response-identity mismatches fail
513
+ closed instead of reporting success.
514
+
515
+ ### Mutation uncertainty and recovery
516
+
517
+ Removal uses the same serialized mutation boundary as `set()`. Treat
518
+ `ENVIRONMENT_OPERATION_BUSY`, `ENVIRONMENT_RECOVERY_REQUIRED`,
519
+ `ENVIRONMENT_SERIALIZATION_RELEASE_FAILED`, platform cleanup/commit uncertainty,
520
+ and Android storage uncertainty as a recovery workflow—not permission to retry
521
+ immediately. Only the public error code survives renderer normalization today.
522
+ Refresh `list()` first and ask the user how to proceed if the resulting state
523
+ cannot be established safely.
524
+
525
+ ### Example
526
+
527
+ ```js
528
+ async function removeSyntheticEnvironmentEntry() {
529
+ return Arcane.environment.remove('ARCANE_DEMO_TOKEN');
530
+ }
531
+
532
+ document.querySelector('#remove-demo-entry')?.addEventListener(
533
+ 'click',
534
+ async function handleEnvironmentRemoval() {
535
+ const result = await removeSyntheticEnvironmentEntry();
536
+ console.log(`Removed ${result.name}`);
537
+ }
538
+ );
539
+ ```
540
+
541
+ ## Arcane.appearance.current()
542
+
543
+ ### Overview
544
+
545
+ Reads the native user-appearance state visible to the current host. This is
546
+ separate from an application's own CSS: Arcane applications should still load
547
+ the shared theme and `ThemeBootstrap.js` so saved appearance choices are applied
548
+ consistently.
549
+
550
+ ### Return value and platforms
551
+
552
+ Requires `appearance.read`. Microsoft NT returns
553
+ `{supported:true,platform:'windows',scheme,effectiveScheme,captionColor,textColor}`.
554
+ `scheme` is `system`, `light`, or `dark`; `effectiveScheme` is `light` or `dark`.
555
+ Linux currently reports an unsupported system appearance with null custom
556
+ colors rather than claiming that native settings were changed.
557
+
558
+ ### Example
559
+
560
+ ```js
561
+ async function reportNativeAppearance() {
562
+ const appearance = await Arcane.appearance.current();
563
+ console.log(appearance.supported, appearance.effectiveScheme);
564
+ return appearance;
565
+ }
566
+
567
+ await reportNativeAppearance();
568
+ ```
569
+
570
+ ## Arcane.appearance.apply()
571
+
572
+ ### Overview
573
+
574
+ Applies the supported native appearance for the current user and returns the
575
+ resulting state. On Microsoft NT it stores the Arcane choice, updates light/dark
576
+ system values, and broadcasts an appearance change. Choosing `system` restores
577
+ the captured baseline and removes Arcane custom caption colors.
578
+
579
+ ### Appearance contract
580
+
581
+ Requires `appearance.write`. Pass only `scheme`, `captionColor`, and
582
+ `textColor`. The scheme defaults to `system`. Custom colors apply only to
583
+ `light` or `dark` and must use `rgb(r, g, b)` with channels from 0 through 255.
584
+ Microsoft NT rejects unknown fields and malformed colors. Linux currently does
585
+ not validate the supplied appearance object; it resolves to its
586
+ `supported:false` status without claiming a native mutation. Always send the
587
+ portable contract instead of using an unsupported host as a validator.
588
+
589
+ Listen for [`appearance.changed`](../../arcane-events.md#event-inventory) when
590
+ the surrounding UI needs to react to a host-originated appearance update.
591
+
592
+ ### Example
593
+
594
+ ```js
595
+ async function applyDarkNativeAppearance() {
596
+ const result = await Arcane.appearance.apply({
597
+ scheme: 'dark',
598
+ captionColor: 'rgb(24, 27, 38)',
599
+ textColor: 'rgb(244, 246, 255)'
600
+ });
601
+ console.log(result.effectiveScheme);
602
+ }
603
+
604
+ document.querySelector('#use-dark-appearance')?.addEventListener(
605
+ 'click',
606
+ async function handleDarkAppearanceRequest() {
607
+ await applyDarkNativeAppearance();
608
+ }
609
+ );
610
+ ```