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,432 @@
1
+ import {createHash} from 'node:crypto';
2
+ import {constants as FS_CONSTANTS} from 'node:fs';
3
+ import {lstat,open,realpath} from 'node:fs/promises';
4
+ import path from 'node:path';
5
+ import {ArcaneError,ERROR_CODES,throwIfAborted} from './errors.mjs';
6
+ import {runProcess} from './process.mjs';
7
+
8
+ export const INTEGRATED_TOOLCHAIN_PROTOCOL='arcane-integrated-toolchain/1';
9
+ export const ARCANE_INTEGRATED_PROVIDER_RELATIVE_PATH=Object.freeze([
10
+ 'tools',
11
+ 'integrated-development-provider.mjs'
12
+ ]);
13
+
14
+ const PROVIDER_STATE=Symbol.for('arcane-os-sdk.integrated-provider-state.v1');
15
+ const PROVIDER_RESTART_CODE='ARCANE_INTEGRATED_PROVIDER_RESTART_REQUIRED';
16
+ const MAX_PROVIDER_BYTES=512*1024;
17
+ const READ_ONLY_NO_FOLLOW=FS_CONSTANTS.O_RDONLY|(FS_CONSTANTS.O_NOFOLLOW??0);
18
+ const REQUIRED_OPERATIONS=Object.freeze(['development-check','focused-test']);
19
+ const SAFE_NODE_IMPORT=/^import\s+(?:(?:[A-Za-z_$][\w$]*|\*\s+as\s+[A-Za-z_$][\w$]*|\{[\w$\s,]+\})\s+from\s+)?(['"])(node:[a-z0-9_./-]+)\1;$/u;
20
+
21
+ if(!globalThis[PROVIDER_STATE]){
22
+ Object.defineProperty(globalThis,PROVIDER_STATE,{
23
+ value:{records:new Map()},
24
+ configurable:false,
25
+ enumerable:false,
26
+ writable:false
27
+ });
28
+ }
29
+
30
+ const providerRecords=globalThis[PROVIDER_STATE].records;
31
+
32
+ function fail(message,code=ERROR_CODES.integrityFailed,details){
33
+ throw new ArcaneError(code,message,{details});
34
+ }
35
+
36
+ function pathKey(value){
37
+ const normalized=path.normalize(path.resolve(value));
38
+ return process.platform==='win32'?normalized.toLowerCase():normalized;
39
+ }
40
+
41
+ function fileIdentity(info){
42
+ return Object.freeze({
43
+ device:String(info.dev),
44
+ inode:String(info.ino),
45
+ bytes:Number(info.size),
46
+ modifiedNanoseconds:String(info.mtimeNs),
47
+ changedNanoseconds:String(info.ctimeNs),
48
+ links:String(info.nlink)
49
+ });
50
+ }
51
+
52
+ function identityMatches(info,identity){
53
+ return String(info.dev)===identity.device
54
+ &&String(info.ino)===identity.inode
55
+ &&Number(info.size)===identity.bytes
56
+ &&String(info.mtimeNs)===identity.modifiedNanoseconds
57
+ &&String(info.ctimeNs)===identity.changedNanoseconds
58
+ &&String(info.nlink)===identity.links;
59
+ }
60
+
61
+ function restartRequired(message,details){
62
+ fail(message,PROVIDER_RESTART_CODE,details);
63
+ }
64
+
65
+ async function emit(onEvent,event){
66
+ await onEvent?.(Object.freeze(event));
67
+ }
68
+
69
+ async function assertUnlinkedDirectoryAncestors(location){
70
+ const resolved=path.resolve(location);
71
+ const parsed=path.parse(resolved);
72
+ const relative=resolved.slice(parsed.root.length);
73
+ let current=parsed.root;
74
+ const components=relative.split(path.sep).filter(Boolean);
75
+ for(let index=0;index<components.length-1;index+=1){
76
+ current=path.join(current,components[index]);
77
+ const info=await lstat(current);
78
+ if(info.isSymbolicLink()||!info.isDirectory()){
79
+ fail(
80
+ 'The Arcane OS root must not use a linked or non-directory ancestor.',
81
+ ERROR_CODES.policyDenied,
82
+ {arcaneRoot:resolved,ancestor:current}
83
+ );
84
+ }
85
+ }
86
+ }
87
+
88
+ async function canonicalProviderRoot(arcaneRoot){
89
+ if(typeof arcaneRoot!=='string'||!arcaneRoot.trim()){
90
+ fail('An explicit Arcane OS root is required for shared development.',ERROR_CODES.usage);
91
+ }
92
+ const requested=path.resolve(arcaneRoot);
93
+ let rootInfo;
94
+ try{
95
+ rootInfo=await lstat(requested);
96
+ }catch(error){
97
+ if(error?.code==='ENOENT'){
98
+ fail(`The Arcane OS root does not exist: ${requested}.`,ERROR_CODES.workspaceInvalid);
99
+ }
100
+ throw error;
101
+ }
102
+ if(rootInfo.isSymbolicLink()||!rootInfo.isDirectory()){
103
+ fail('The Arcane OS root must be a real directory.',ERROR_CODES.policyDenied);
104
+ }
105
+ await assertUnlinkedDirectoryAncestors(requested);
106
+ const canonicalRoot=await realpath(requested);
107
+ const toolsRoot=path.join(canonicalRoot,'tools');
108
+ const toolsInfo=await lstat(toolsRoot);
109
+ if(toolsInfo.isSymbolicLink()||!toolsInfo.isDirectory()){
110
+ fail('The Arcane OS tools root must be a real directory.',ERROR_CODES.policyDenied);
111
+ }
112
+ return canonicalRoot;
113
+ }
114
+
115
+ function assertSingleModulePolicy(source){
116
+ for(const [index,line] of source.split(/\r?\n/u).entries()){
117
+ if(!/\b(?:from|import|require)\b/u.test(line))continue;
118
+ if(!SAFE_NODE_IMPORT.test(line.trim())){
119
+ fail(
120
+ `The integrated provider may contain only one-line static Node built-in imports (line ${index+1}).`
121
+ );
122
+ }
123
+ }
124
+ }
125
+
126
+ function waitForProviderInitialization(promise,signal){
127
+ throwIfAborted(signal);
128
+ if(!signal)return promise;
129
+ return new Promise(function observeInitialization(resolve,reject){
130
+ let settled=false;
131
+ function cleanup(){
132
+ signal.removeEventListener('abort',abortObservation);
133
+ }
134
+ function settle(callback,value){
135
+ if(settled)return;
136
+ settled=true;
137
+ cleanup();
138
+ callback(value);
139
+ }
140
+ function abortObservation(){
141
+ try{
142
+ throwIfAborted(signal);
143
+ }catch(error){
144
+ settle(reject,error);
145
+ }
146
+ }
147
+ signal.addEventListener('abort',abortObservation,{once:true});
148
+ promise.then(
149
+ value=>settle(resolve,value),
150
+ error=>settle(reject,error)
151
+ );
152
+ if(signal.aborted)abortObservation();
153
+ });
154
+ }
155
+
156
+ async function readGeneration(canonicalRoot){
157
+ const providerPath=path.join(canonicalRoot,...ARCANE_INTEGRATED_PROVIDER_RELATIVE_PATH);
158
+ let before;
159
+ try{
160
+ before=await lstat(providerPath,{bigint:true});
161
+ }catch(error){
162
+ if(error?.code==='ENOENT'){
163
+ fail(
164
+ `The Arcane OS checkout does not provide ${ARCANE_INTEGRATED_PROVIDER_RELATIVE_PATH.join('/')}.`,
165
+ ERROR_CODES.prerequisiteMissing
166
+ );
167
+ }
168
+ throw error;
169
+ }
170
+ if(before.isSymbolicLink()||!before.isFile()||before.nlink!==1n){
171
+ fail('The integrated provider must be a single-link regular file.',ERROR_CODES.policyDenied);
172
+ }
173
+ if(before.size<1n||before.size>BigInt(MAX_PROVIDER_BYTES)){
174
+ fail(`The integrated provider must contain 1 through ${MAX_PROVIDER_BYTES} bytes.`);
175
+ }
176
+
177
+ let handle;
178
+ try{
179
+ handle=await open(providerPath,READ_ONLY_NO_FOLLOW);
180
+ }catch(error){
181
+ if(error?.code==='ELOOP')fail('The integrated provider became a symbolic link.');
182
+ throw error;
183
+ }
184
+ let bytes;
185
+ let openedIdentity;
186
+ try{
187
+ const opened=await handle.stat({bigint:true});
188
+ const beforeIdentity=fileIdentity(before);
189
+ if(!opened.isFile()||!identityMatches(opened,beforeIdentity)){
190
+ fail('The integrated provider changed while it was opened.');
191
+ }
192
+ openedIdentity=fileIdentity(opened);
193
+ bytes=await handle.readFile();
194
+ const after=await handle.stat({bigint:true});
195
+ if(!identityMatches(after,openedIdentity)){
196
+ fail('The integrated provider changed while it was read.');
197
+ }
198
+ }finally{
199
+ await handle.close().catch(()=>{});
200
+ }
201
+ const pathAfter=await lstat(providerPath,{bigint:true});
202
+ if(pathAfter.isSymbolicLink()||!identityMatches(pathAfter,openedIdentity)){
203
+ fail('The integrated provider path changed after it was read.');
204
+ }
205
+ const source=bytes.toString('utf8');
206
+ assertSingleModulePolicy(source);
207
+ const sha256=createHash('sha256').update(bytes).digest('hex');
208
+ return Object.freeze({
209
+ canonicalRoot,
210
+ providerPath,
211
+ bytes:bytes.length,
212
+ sha256,
213
+ identity:openedIdentity,
214
+ source
215
+ });
216
+ }
217
+
218
+ async function authenticateGenerationIdentity(generation){
219
+ const before=await lstat(generation.providerPath,{bigint:true});
220
+ if(before.isSymbolicLink()||!before.isFile()||before.nlink!==1n
221
+ ||!identityMatches(before,generation.identity)){
222
+ fail('The integrated provider filesystem identity changed.');
223
+ }
224
+ const canonical=await realpath(generation.providerPath);
225
+ if(pathKey(canonical)!==pathKey(generation.providerPath)){
226
+ fail('The integrated provider path began traversing a link.');
227
+ }
228
+ const after=await lstat(generation.providerPath,{bigint:true});
229
+ if(after.isSymbolicLink()||!identityMatches(after,generation.identity)){
230
+ fail('The integrated provider filesystem identity changed during authentication.');
231
+ }
232
+ return generation;
233
+ }
234
+
235
+ function describedOperationIds(description){
236
+ const operations=description?.operations;
237
+ if(Array.isArray(operations)){
238
+ return operations.map(operation=>typeof operation==='string'?operation:operation?.id).sort();
239
+ }
240
+ if(operations&&typeof operations==='object'){
241
+ return Object.keys(operations).sort();
242
+ }
243
+ return [];
244
+ }
245
+
246
+ async function validateProvider(moduleNamespace){
247
+ const provider=moduleNamespace?.integratedDevelopmentProvider;
248
+ if(!provider||typeof provider!=='object'||provider.protocol!==INTEGRATED_TOOLCHAIN_PROTOCOL
249
+ ||typeof provider.describe!=='function'||typeof provider.prepare!=='function'
250
+ ||typeof provider.execute!=='function'){
251
+ fail(`The integrated provider must export integratedDevelopmentProvider for ${INTEGRATED_TOOLCHAIN_PROTOCOL}.`);
252
+ }
253
+ const description=await provider.describe();
254
+ if(description?.protocol!==INTEGRATED_TOOLCHAIN_PROTOCOL
255
+ ||JSON.stringify(describedOperationIds(description))!==JSON.stringify(REQUIRED_OPERATIONS)){
256
+ fail('The integrated provider must declare only focused-test and development-check.');
257
+ }
258
+ return provider;
259
+ }
260
+
261
+ function publicGeneration(generation){
262
+ return Object.freeze({
263
+ kind:'arcane-integrated-provider-generation',
264
+ protocol:INTEGRATED_TOOLCHAIN_PROTOCOL,
265
+ canonicalLocation:generation.providerPath,
266
+ contentSha256:generation.sha256,
267
+ bytes:generation.bytes,
268
+ identity:generation.identity,
269
+ moduleCount:1
270
+ });
271
+ }
272
+
273
+ async function importProvider(generation){
274
+ const encoded=Buffer.from(generation.source,'utf8').toString('base64');
275
+ const namespace=await import(`data:text/javascript;base64,${encoded}#${generation.sha256}`);
276
+ return validateProvider(namespace);
277
+ }
278
+
279
+ async function authenticateRecord(record){
280
+ if(record.poisoned){
281
+ restartRequired('The integrated provider generation changed; start a new Arcane CLI process.');
282
+ }
283
+ try{
284
+ await authenticateGenerationIdentity(record.generation);
285
+ }catch(error){
286
+ record.poisoned=true;
287
+ record.state='poisoned';
288
+ restartRequired(
289
+ 'The integrated provider generation became unavailable; start a new Arcane CLI process.',
290
+ {causeCode:error?.code??null}
291
+ );
292
+ }
293
+ return record;
294
+ }
295
+
296
+ async function initializeProviderRecord(record){
297
+ record.state='loading';
298
+ try{
299
+ const canonicalRoot=await canonicalProviderRoot(record.requestedRoot);
300
+ const generation=await readGeneration(canonicalRoot);
301
+ record.canonicalRoot=canonicalRoot;
302
+ record.generation=generation;
303
+ record.importAttempted=true;
304
+ const provider=await importProvider(generation);
305
+ try{
306
+ await authenticateGenerationIdentity(generation);
307
+ }catch(error){
308
+ record.poisoned=true;
309
+ record.state='poisoned';
310
+ restartRequired(
311
+ 'The integrated provider generation became unavailable while it was imported; start a new Arcane CLI process.',
312
+ {causeCode:error?.code??null}
313
+ );
314
+ }
315
+ record.provider=provider;
316
+ record.state='ready';
317
+ return record;
318
+ }catch(error){
319
+ if(!record.importAttempted){
320
+ record.state='invalid';
321
+ if(providerRecords.get(record.key)===record)providerRecords.delete(record.key);
322
+ }else if(record.state!=='poisoned'){
323
+ record.poisoned=true;
324
+ record.state='poisoned';
325
+ }
326
+ throw error;
327
+ }
328
+ }
329
+
330
+ function createProviderReservation({key,requestedRoot}){
331
+ const record={
332
+ key,
333
+ requestedRoot,
334
+ canonicalRoot:null,
335
+ generation:null,
336
+ provider:null,
337
+ importAttempted:false,
338
+ poisoned:false,
339
+ state:'reserved',
340
+ promise:null
341
+ };
342
+ record.promise=Promise.resolve().then(()=>initializeProviderRecord(record));
343
+ record.promise.catch(()=>{});
344
+ return record;
345
+ }
346
+
347
+ async function observeProviderRecord({record,stateAtInvocation,signal,onEvent,run}){
348
+ await emit(onEvent,{
349
+ type:'integrated.provider.loading',
350
+ message:'Loading the fixed Arcane integrated development provider.'
351
+ });
352
+ if(stateAtInvocation==='poisoned'){
353
+ restartRequired('The integrated provider generation changed; start a new Arcane CLI process.');
354
+ }
355
+ const ready=await waitForProviderInitialization(record.promise,signal);
356
+ throwIfAborted(signal);
357
+ await authenticateRecord(ready);
358
+ const generation=publicGeneration(ready.generation);
359
+ await emit(onEvent,{
360
+ type:'integrated.provider.verified',
361
+ message:'Verified the Arcane integrated development provider generation.',
362
+ data:{contentSha256:generation.contentSha256,moduleCount:1}
363
+ });
364
+
365
+ async function describe(){
366
+ await authenticateRecord(ready);
367
+ const description=await ready.provider.describe();
368
+ await authenticateRecord(ready);
369
+ return description;
370
+ }
371
+
372
+ async function execute(request={}){
373
+ throwIfAborted(request.signal);
374
+ if(!REQUIRED_OPERATIONS.includes(request.operation)){
375
+ fail(`Unsupported integrated operation: ${String(request.operation)}.`,ERROR_CODES.usage);
376
+ }
377
+ await authenticateRecord(ready);
378
+ let result;
379
+ let operationError;
380
+ try{
381
+ result=await ready.provider.execute({
382
+ operation:request.operation,
383
+ workspaceRoot:ready.canonicalRoot,
384
+ ...(request.testFile===undefined?{}:{testFile:request.testFile}),
385
+ signal:request.signal,
386
+ onEvent:request.onEvent,
387
+ run
388
+ });
389
+ }catch(error){
390
+ operationError=error;
391
+ }
392
+ await authenticateRecord(ready);
393
+ if(operationError)throw operationError;
394
+ return result;
395
+ }
396
+
397
+ return Object.freeze({
398
+ protocol:INTEGRATED_TOOLCHAIN_PROTOCOL,
399
+ toolchainRoot:ready.canonicalRoot,
400
+ providerGeneration:generation,
401
+ describe,
402
+ execute
403
+ });
404
+ }
405
+
406
+ export function loadArcaneIntegratedProvider({
407
+ arcaneRoot,
408
+ signal,
409
+ onEvent,
410
+ run=runProcess
411
+ }={}){
412
+ throwIfAborted(signal);
413
+ if(typeof run!=='function')fail('The integrated provider process runner must be a function.',ERROR_CODES.usage);
414
+ if(typeof arcaneRoot!=='string'||!arcaneRoot.trim()){
415
+ fail('An explicit Arcane OS root is required for shared development.',ERROR_CODES.usage);
416
+ }
417
+ const requestedRoot=path.resolve(arcaneRoot);
418
+ const key=pathKey(requestedRoot);
419
+ let record=providerRecords.get(key);
420
+ const stateAtInvocation=record?.state??'created';
421
+ if(!record){
422
+ record=createProviderReservation({key,requestedRoot});
423
+ providerRecords.set(key,record);
424
+ }
425
+ return observeProviderRecord({
426
+ record,
427
+ stateAtInvocation,
428
+ signal,
429
+ onEvent,
430
+ run
431
+ });
432
+ }