arcane-os 0.3.1 → 0.3.2

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 (153) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/README.md +86 -117
  3. package/bin/arcane-test.mjs +170 -46
  4. package/browser-runtime/ai/browser-speech-artifacts.mjs +855 -895
  5. package/browser-runtime/ai/browser-speech-providers.mjs +80 -204
  6. package/browser-runtime/ai/browser-wasm-llm-provider.mjs +627 -819
  7. package/browser-runtime/ai/browser-wasm.mjs +24 -35
  8. package/browser-runtime/ai/browser-wllama-runtime.mjs +64 -316
  9. package/browser-runtime/ai/model-controller.mjs +584 -181
  10. package/browser-runtime/ai/speech-worker-client.mjs +8 -148
  11. package/browser-runtime/ai/speech-worker-runtime.mjs +642 -374
  12. package/browser-runtime/dom-event-instrumentation.mjs +55 -147
  13. package/browser-runtime/event-manager.mjs +239 -624
  14. package/package.json +5 -6
  15. package/runtime/arcane/components/app-bar.html +3 -15
  16. package/runtime/arcane/components/assistant-panel.html +10 -10
  17. package/runtime/arcane/components/calculator.html +1 -1
  18. package/runtime/arcane/components/chat.html +1359 -135
  19. package/runtime/arcane/components/conversation-view.html +2 -2
  20. package/runtime/arcane/components/document-inspector.html +11 -17
  21. package/runtime/arcane/components/file-manager.html +13 -56
  22. package/runtime/arcane/components/markdown-document.html +82 -281
  23. package/runtime/arcane/components/markdown-editor.html +7 -10
  24. package/runtime/arcane/components/media-embed.html +6 -6
  25. package/runtime/arcane/components/screen-capture.html +4 -4
  26. package/runtime/arcane/components/source-explanation.html +2 -2
  27. package/runtime/arcane/components/speech.html +112 -68
  28. package/runtime/arcane/components/terminal-workspace.html +4 -4
  29. package/runtime/arcane/components/theme-editor.html +1 -1
  30. package/runtime/arcane/components/unified-inbox.html +2 -2
  31. package/runtime/arcane/components/voice-transcription.html +31 -21
  32. package/runtime/arcane/entities/Calculation.js +2 -3
  33. package/runtime/arcane/entities/Chat.js +228 -43
  34. package/runtime/arcane/entities/Preference.js +3 -5
  35. package/runtime/arcane/entities/Weather.js +5 -5
  36. package/runtime/arcane/modules/AI.js +1042 -427
  37. package/runtime/arcane/modules/AIProviderRuntime.js +618 -359
  38. package/runtime/arcane/modules/AIResponseLength.js +9 -19
  39. package/runtime/arcane/modules/AIRuntimeState.js +109 -72
  40. package/runtime/arcane/modules/ArcaneNavigationPolicy.js +45 -32
  41. package/runtime/arcane/modules/BrowserTestSuite.js +78 -122
  42. package/runtime/arcane/modules/CalculatorEngine.js +9 -9
  43. package/runtime/arcane/modules/CommunicationAppController.js +3 -7
  44. package/runtime/arcane/modules/ComponentContracts.js +30 -32
  45. package/runtime/arcane/modules/ConfiguredAIChatSession.js +281 -230
  46. package/runtime/arcane/modules/ConversationActionItems.js +26 -59
  47. package/runtime/arcane/modules/ConversationClosingReport.js +34 -61
  48. package/runtime/arcane/modules/ConversationTimebox.js +27 -15
  49. package/runtime/arcane/modules/DBOPFSDocumentLibrary.js +152 -344
  50. package/runtime/arcane/modules/DocumentLexicalSearch.js +25 -91
  51. package/runtime/arcane/modules/HTMLImport.js +54 -1
  52. package/runtime/arcane/modules/IsolatedModelQuestionRunner.js +40 -203
  53. package/runtime/arcane/modules/LocalAIReadiness.js +40 -60
  54. package/runtime/arcane/modules/LocalAIReadinessController.js +15 -13
  55. package/runtime/arcane/modules/MD.js +1 -45
  56. package/runtime/arcane/modules/Mail.js +51 -103
  57. package/runtime/arcane/modules/MailOutbox.mjs +95 -193
  58. package/runtime/arcane/modules/MailTransport.mjs +36 -57
  59. package/runtime/arcane/modules/ModelDefinition.js +22 -106
  60. package/runtime/arcane/modules/OpenMeteoWeatherProvider.js +39 -101
  61. package/runtime/arcane/modules/PersistentAIChatSession.js +281 -18
  62. package/runtime/arcane/modules/PreferenceStore.js +102 -30
  63. package/runtime/arcane/modules/RiskSignalAnalyzer.js +8 -9
  64. package/runtime/arcane/modules/ScopedOPFSCache.js +7 -42
  65. package/runtime/arcane/modules/ScreenCapture.js +175 -128
  66. package/runtime/arcane/modules/SpeechPlayback.js +46 -149
  67. package/runtime/arcane/modules/StaticDocumentCatalog.js +173 -407
  68. package/runtime/arcane/modules/ToolCallRouter.js +25 -12
  69. package/runtime/arcane/modules/YouTubeMedia.js +6 -5
  70. package/schemas/arcane-app-bundle.schema.json +13 -78
  71. package/schemas/arcane-app.schema.json +9 -25
  72. package/schemas/arcane-lock.schema.json +18 -151
  73. package/schemas/arcane-package.schema.json +2 -16
  74. package/schemas/native-build-plan.schema.json +119 -122
  75. package/src/app-descriptor.mjs +75 -132
  76. package/src/application-tests.mjs +200 -0
  77. package/src/cli/main.mjs +27 -46
  78. package/src/constants.mjs +3 -4
  79. package/src/dev-server.mjs +30 -324
  80. package/src/doctor.mjs +92 -154
  81. package/src/dom-event-instrumentation.mjs +55 -147
  82. package/src/errors.mjs +2 -3
  83. package/src/event-manager.mjs +239 -624
  84. package/src/event-queue.mjs +3 -3
  85. package/src/import-map.mjs +273 -1028
  86. package/src/index.mjs +14 -16
  87. package/src/installed-sdk-runtime.mjs +27 -67
  88. package/src/integrated-provider-loader.mjs +53 -382
  89. package/src/mail-api.mjs +0 -2
  90. package/src/mail-server.mjs +224 -580
  91. package/src/mail.mjs +4 -10
  92. package/src/native-plan.mjs +163 -598
  93. package/src/native-provider-loader.mjs +104 -1063
  94. package/src/packager/core.mjs +485 -3229
  95. package/src/process.mjs +5 -10
  96. package/src/release-bundle.mjs +292 -2405
  97. package/src/runtime.mjs +76 -396
  98. package/src/scaffold.mjs +30 -80
  99. package/src/sdk-browser-runtime.mjs +70 -626
  100. package/src/source-server.mjs +588 -0
  101. package/src/targets/index.mjs +78 -188
  102. package/src/templates/workspace-template.mjs +19 -135
  103. package/src/testing-loader.mjs +164 -0
  104. package/src/testing.mjs +1 -1
  105. package/src/toolchain.mjs +131 -544
  106. package/src/update-check.mjs +26 -64
  107. package/src/workspace-operation-lock.mjs +139 -430
  108. package/src/workspace-runtime.mjs +109 -1558
  109. package/src/workspace.mjs +40 -302
  110. package/browser-runtime/ARCANE_SDK_BROWSER_RELEASE.json +0 -218
  111. package/browser-runtime/ai/ARCANE_AI_BROWSER_SPEECH_COMPONENTS.json +0 -203
  112. package/browser-runtime/ai/ARCANE_AI_BROWSER_WASM_COMPONENTS.json +0 -80
  113. package/browser-runtime/ai/internal/sha256.mjs +0 -166
  114. package/docs/architecture.md +0 -344
  115. package/docs/compatibility.md +0 -36
  116. package/docs/event-manager.md +0 -294
  117. package/docs/platform-targets.md +0 -108
  118. package/docs/publishing.md +0 -201
  119. package/docs/reference/README.md +0 -185
  120. package/docs/reference/ai/browser-speech-package-authority.json +0 -835
  121. package/docs/reference/ai/browser-speech.md +0 -1295
  122. package/docs/reference/ai/browser-wasm.md +0 -530
  123. package/docs/reference/arcane-ollama.md +0 -288
  124. package/docs/reference/availability-and-normalization.md +0 -183
  125. package/docs/reference/behavioral-testing.md +0 -133
  126. package/docs/reference/cli.md +0 -779
  127. package/docs/reference/core/README.md +0 -62
  128. package/docs/reference/core/arcane-ai-contracts.md +0 -907
  129. package/docs/reference/core/arcane-api.md +0 -601
  130. package/docs/reference/core/arcane-entities.md +0 -65
  131. package/docs/reference/core/arcane-events.md +0 -134
  132. package/docs/reference/core/ollama-module.md +0 -181
  133. package/docs/reference/core/reference/arcane-api/ai-and-ollama.md +0 -1909
  134. package/docs/reference/core/reference/arcane-api/applications-terminal-capabilities.md +0 -1057
  135. package/docs/reference/core/reference/arcane-api/core-and-events.md +0 -320
  136. package/docs/reference/core/reference/arcane-api/filesystem-storage-preferences-appearance.md +0 -610
  137. package/docs/reference/core/reference/arcane-api/namespaces.md +0 -1157
  138. package/docs/reference/core/reference/arcane-api/platform-installation-users-system.md +0 -1423
  139. package/docs/reference/core/reference/arcane-api/session-provisioning-diagnostics-development.md +0 -315
  140. package/docs/reference/event-manager.md +0 -1511
  141. package/docs/reference/inventory/package-api.json +0 -3284
  142. package/docs/reference/inventory/runtime-components.json +0 -1011
  143. package/docs/reference/inventory/runtime-entities.json +0 -26
  144. package/docs/reference/inventory/runtime-modules.json +0 -1431
  145. package/docs/reference/mail.md +0 -316
  146. package/docs/reference/protocols.md +0 -719
  147. package/docs/reference/runtime-components.md +0 -1366
  148. package/docs/reference/runtime-entities.md +0 -303
  149. package/docs/reference/runtime-modules.md +0 -2965
  150. package/docs/reference/sdk-api.md +0 -6698
  151. package/docs/roadmap.md +0 -79
  152. package/docs/work-amplification.md +0 -129
  153. package/runtime/ARCANE_RUNTIME_RELEASE.json +0 -826
@@ -1,164 +1,43 @@
1
- import {createHash} from 'node:crypto';
2
- import {constants as FS_CONSTANTS} from 'node:fs';
3
- import {lstat,open,realpath} from 'node:fs/promises';
1
+ import {stat} from 'node:fs/promises';
4
2
  import path from 'node:path';
3
+ import {pathToFileURL} from 'node:url';
5
4
  import {ArcaneError,ERROR_CODES,throwIfAborted} from './errors.mjs';
6
5
  import {runProcess} from './process.mjs';
7
6
 
8
7
  export const INTEGRATED_TOOLCHAIN_PROTOCOL='arcane-integrated-toolchain/1';
9
- export const ARCANE_INTEGRATED_PROVIDER_RELATIVE_PATH=Object.freeze([
8
+ export const ARCANE_INTEGRATED_PROVIDER_RELATIVE_PATH=[
10
9
  'tools',
11
10
  'integrated-development-provider.mjs'
12
- ]);
11
+ ];
13
12
 
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){
13
+ function fail(message,code=ERROR_CODES.operationFailed,details){
33
14
  throw new ArcaneError(code,message,{details});
34
15
  }
35
16
 
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
17
  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
- }
18
+ await onEvent?.(event);
86
19
  }
87
20
 
88
- async function canonicalProviderRoot(arcaneRoot){
21
+ async function selectedProvider(arcaneRoot){
89
22
  if(typeof arcaneRoot!=='string'||!arcaneRoot.trim()){
90
23
  fail('An explicit Arcane OS root is required for shared development.',ERROR_CODES.usage);
91
24
  }
92
- const requested=path.resolve(arcaneRoot);
25
+ const toolchainRoot=path.resolve(arcaneRoot);
93
26
  let rootInfo;
94
- try{
95
- rootInfo=await lstat(requested);
96
- }catch(error){
27
+ try{rootInfo=await stat(toolchainRoot);}
28
+ catch(error){
97
29
  if(error?.code==='ENOENT'){
98
- fail(`The Arcane OS root does not exist: ${requested}.`,ERROR_CODES.workspaceInvalid);
30
+ fail(`The Arcane OS root does not exist: ${toolchainRoot}.`,ERROR_CODES.workspaceInvalid);
99
31
  }
100
32
  throw error;
101
33
  }
102
- if(rootInfo.isSymbolicLink()||!rootInfo.isDirectory()){
103
- fail('The Arcane OS root must be a real directory.',ERROR_CODES.policyDenied);
34
+ if(!rootInfo.isDirectory()){
35
+ fail('The Arcane OS root must be a directory.',ERROR_CODES.workspaceInvalid);
104
36
  }
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){
37
+ const providerPath=path.join(toolchainRoot,...ARCANE_INTEGRATED_PROVIDER_RELATIVE_PATH);
38
+ let providerInfo;
39
+ try{providerInfo=await stat(providerPath);}
40
+ catch(error){
162
41
  if(error?.code==='ENOENT'){
163
42
  fail(
164
43
  `The Arcane OS checkout does not provide ${ARCANE_INTEGRATED_PROVIDER_RELATIVE_PATH.join('/')}.`,
@@ -167,266 +46,58 @@ async function readGeneration(canonicalRoot){
167
46
  }
168
47
  throw error;
169
48
  }
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;
49
+ if(!providerInfo.isFile())fail('The integrated provider must be a file.');
50
+ return {toolchainRoot,providerPath};
233
51
  }
234
52
 
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'
53
+ async function importedProvider(providerPath){
54
+ const namespace=await import(pathToFileURL(providerPath).href);
55
+ const provider=namespace?.integratedDevelopmentProvider;
56
+ if(!provider||typeof provider!=='object'
57
+ ||typeof provider.describe!=='function'
58
+ ||typeof provider.prepare!=='function'
250
59
  ||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.');
60
+ fail('The integrated provider must export integratedDevelopmentProvider.');
257
61
  }
258
62
  return provider;
259
63
  }
260
64
 
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;
65
+ export async function loadArcaneIntegratedProvider({
66
+ arcaneRoot,
67
+ signal,
68
+ onEvent,
69
+ run=runProcess
70
+ }={}){
71
+ throwIfAborted(signal);
72
+ if(typeof run!=='function'){
73
+ fail('The integrated provider process runner must be a function.',ERROR_CODES.usage);
327
74
  }
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
75
  await emit(onEvent,{
349
76
  type:'integrated.provider.loading',
350
- message:'Loading the fixed Arcane integrated development provider.'
77
+ message:'Loading the selected Arcane integrated development provider.'
351
78
  });
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);
79
+ const selected=await selectedProvider(arcaneRoot);
80
+ const provider=await importedProvider(selected.providerPath);
356
81
  throwIfAborted(signal);
357
- await authenticateRecord(ready);
358
- const generation=publicGeneration(ready.generation);
359
82
  await emit(onEvent,{
360
- type:'integrated.provider.verified',
361
- message:'Verified the Arcane integrated development provider generation.',
362
- data:{contentSha256:generation.contentSha256,moduleCount:1}
83
+ type:'integrated.provider.loaded',
84
+ message:'Loaded the selected Arcane integrated development provider.',
85
+ data:{location:selected.providerPath}
363
86
  });
364
87
 
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,
88
+ return {
89
+ protocol:provider.protocol??INTEGRATED_TOOLCHAIN_PROTOCOL,
90
+ toolchainRoot:selected.toolchainRoot,
91
+ describe(){
92
+ return provider.describe();
93
+ },
94
+ execute(request={}){
95
+ throwIfAborted(request.signal);
96
+ return provider.execute({
97
+ ...request,
98
+ workspaceRoot:selected.toolchainRoot,
387
99
  run
388
100
  });
389
- }catch(error){
390
- operationError=error;
391
101
  }
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
- });
102
+ };
432
103
  }
package/src/mail-api.mjs CHANGED
@@ -4,7 +4,6 @@ export {
4
4
  resolveMailConfig
5
5
  } from '../runtime/arcane/modules/Mail.js';
6
6
  export {
7
- MAIL_OUTBOX_ACCEPTANCE_AUTHORITIES,
8
7
  MAIL_OUTBOX_IDEMPOTENCY_WINDOW_MS,
9
8
  MAIL_OUTBOX_PROTOCOL,
10
9
  MAIL_OUTBOX_STATES,
@@ -14,7 +13,6 @@ export {
14
13
  } from '../runtime/arcane/modules/MailOutbox.mjs';
15
14
  export {
16
15
  DEFAULT_MAIL_REQUEST_TIMEOUT_MS,
17
- MAX_MAIL_RESPONSE_BYTES,
18
16
  MailTransportError,
19
17
  normalizeMailEndpoint,
20
18
  sendMailReport,