arcane-os 0.3.0 → 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.
- package/CHANGELOG.md +27 -0
- package/README.md +86 -117
- package/bin/arcane-test.mjs +170 -46
- package/browser-runtime/ai/browser-speech-artifacts.mjs +887 -909
- package/browser-runtime/ai/browser-speech-providers.mjs +96 -152
- package/browser-runtime/ai/browser-wasm-llm-provider.mjs +627 -819
- package/browser-runtime/ai/browser-wasm.mjs +24 -35
- package/browser-runtime/ai/browser-wllama-runtime.mjs +64 -316
- package/browser-runtime/ai/model-controller.mjs +584 -181
- package/browser-runtime/ai/speech-worker-client.mjs +8 -146
- package/browser-runtime/ai/speech-worker-runtime.mjs +643 -363
- package/browser-runtime/dom-event-instrumentation.mjs +55 -147
- package/browser-runtime/event-manager.mjs +239 -624
- package/package.json +5 -6
- package/runtime/arcane/components/app-bar.html +3 -15
- package/runtime/arcane/components/assistant-panel.html +10 -10
- package/runtime/arcane/components/calculator.html +1 -1
- package/runtime/arcane/components/chat.html +1359 -135
- package/runtime/arcane/components/conversation-view.html +2 -2
- package/runtime/arcane/components/document-inspector.html +11 -17
- package/runtime/arcane/components/file-manager.html +13 -56
- package/runtime/arcane/components/markdown-document.html +82 -281
- package/runtime/arcane/components/markdown-editor.html +7 -10
- package/runtime/arcane/components/media-embed.html +6 -6
- package/runtime/arcane/components/screen-capture.html +4 -4
- package/runtime/arcane/components/source-explanation.html +2 -2
- package/runtime/arcane/components/speech.html +112 -68
- package/runtime/arcane/components/terminal-workspace.html +4 -4
- package/runtime/arcane/components/theme-editor.html +1 -1
- package/runtime/arcane/components/unified-inbox.html +2 -2
- package/runtime/arcane/components/voice-transcription.html +31 -21
- package/runtime/arcane/entities/Calculation.js +2 -3
- package/runtime/arcane/entities/Chat.js +228 -43
- package/runtime/arcane/entities/Preference.js +3 -5
- package/runtime/arcane/entities/Weather.js +5 -5
- package/runtime/arcane/modules/AI.js +1050 -427
- package/runtime/arcane/modules/AIProviderRuntime.js +658 -363
- package/runtime/arcane/modules/AIResponseLength.js +9 -19
- package/runtime/arcane/modules/AIRuntimeState.js +109 -72
- package/runtime/arcane/modules/ArcaneNavigationPolicy.js +45 -32
- package/runtime/arcane/modules/BrowserTestSuite.js +78 -122
- package/runtime/arcane/modules/CalculatorEngine.js +9 -9
- package/runtime/arcane/modules/CommunicationAppController.js +3 -7
- package/runtime/arcane/modules/ComponentContracts.js +30 -32
- package/runtime/arcane/modules/ConfiguredAIChatSession.js +281 -230
- package/runtime/arcane/modules/ConversationActionItems.js +26 -59
- package/runtime/arcane/modules/ConversationClosingReport.js +34 -61
- package/runtime/arcane/modules/ConversationTimebox.js +27 -15
- package/runtime/arcane/modules/DBOPFSDocumentLibrary.js +152 -344
- package/runtime/arcane/modules/DocumentLexicalSearch.js +25 -91
- package/runtime/arcane/modules/HTMLImport.js +54 -1
- package/runtime/arcane/modules/IsolatedModelQuestionRunner.js +40 -203
- package/runtime/arcane/modules/LocalAIReadiness.js +40 -60
- package/runtime/arcane/modules/LocalAIReadinessController.js +15 -13
- package/runtime/arcane/modules/MD.js +1 -45
- package/runtime/arcane/modules/Mail.js +51 -103
- package/runtime/arcane/modules/MailOutbox.mjs +95 -193
- package/runtime/arcane/modules/MailTransport.mjs +36 -57
- package/runtime/arcane/modules/ModelDefinition.js +22 -106
- package/runtime/arcane/modules/OpenMeteoWeatherProvider.js +39 -101
- package/runtime/arcane/modules/PersistentAIChatSession.js +281 -18
- package/runtime/arcane/modules/PreferenceStore.js +102 -30
- package/runtime/arcane/modules/RiskSignalAnalyzer.js +8 -9
- package/runtime/arcane/modules/ScopedOPFSCache.js +7 -42
- package/runtime/arcane/modules/ScreenCapture.js +175 -128
- package/runtime/arcane/modules/SpeechPlayback.js +46 -149
- package/runtime/arcane/modules/StaticDocumentCatalog.js +173 -407
- package/runtime/arcane/modules/ToolCallRouter.js +25 -12
- package/runtime/arcane/modules/YouTubeMedia.js +6 -5
- package/schemas/arcane-app-bundle.schema.json +13 -78
- package/schemas/arcane-app.schema.json +9 -25
- package/schemas/arcane-lock.schema.json +18 -151
- package/schemas/arcane-package.schema.json +2 -16
- package/schemas/native-build-plan.schema.json +119 -122
- package/src/app-descriptor.mjs +75 -132
- package/src/application-tests.mjs +200 -0
- package/src/cli/main.mjs +27 -46
- package/src/constants.mjs +3 -4
- package/src/dev-server.mjs +30 -324
- package/src/doctor.mjs +92 -154
- package/src/dom-event-instrumentation.mjs +55 -147
- package/src/errors.mjs +2 -3
- package/src/event-manager.mjs +239 -624
- package/src/event-queue.mjs +3 -3
- package/src/import-map.mjs +273 -1028
- package/src/index.mjs +14 -16
- package/src/installed-sdk-runtime.mjs +40 -62
- package/src/integrated-provider-loader.mjs +53 -382
- package/src/mail-api.mjs +0 -2
- package/src/mail-server.mjs +224 -580
- package/src/mail.mjs +4 -10
- package/src/native-plan.mjs +163 -598
- package/src/native-provider-loader.mjs +104 -1063
- package/src/packager/core.mjs +485 -3229
- package/src/process.mjs +5 -10
- package/src/release-bundle.mjs +292 -2405
- package/src/runtime.mjs +76 -396
- package/src/scaffold.mjs +30 -80
- package/src/sdk-browser-runtime.mjs +70 -626
- package/src/source-server.mjs +588 -0
- package/src/targets/index.mjs +78 -188
- package/src/templates/workspace-template.mjs +19 -135
- package/src/testing-loader.mjs +164 -0
- package/src/testing.mjs +1 -1
- package/src/toolchain.mjs +131 -544
- package/src/update-check.mjs +26 -64
- package/src/workspace-operation-lock.mjs +139 -430
- package/src/workspace-runtime.mjs +112 -779
- package/src/workspace.mjs +40 -302
- package/browser-runtime/ARCANE_SDK_BROWSER_RELEASE.json +0 -218
- package/browser-runtime/ai/ARCANE_AI_BROWSER_SPEECH_COMPONENTS.json +0 -203
- package/browser-runtime/ai/ARCANE_AI_BROWSER_WASM_COMPONENTS.json +0 -80
- package/browser-runtime/ai/internal/sha256.mjs +0 -166
- package/docs/architecture.md +0 -344
- package/docs/compatibility.md +0 -36
- package/docs/event-manager.md +0 -294
- package/docs/platform-targets.md +0 -108
- package/docs/publishing.md +0 -201
- package/docs/reference/README.md +0 -187
- package/docs/reference/ai/browser-speech-package-authority.json +0 -835
- package/docs/reference/ai/browser-speech.md +0 -1252
- package/docs/reference/ai/browser-wasm.md +0 -530
- package/docs/reference/arcane-ollama.md +0 -288
- package/docs/reference/availability-and-normalization.md +0 -183
- package/docs/reference/behavioral-testing.md +0 -133
- package/docs/reference/cli.md +0 -779
- package/docs/reference/core/README.md +0 -62
- package/docs/reference/core/arcane-ai-contracts.md +0 -907
- package/docs/reference/core/arcane-api.md +0 -601
- package/docs/reference/core/arcane-entities.md +0 -65
- package/docs/reference/core/arcane-events.md +0 -134
- package/docs/reference/core/ollama-module.md +0 -181
- package/docs/reference/core/reference/arcane-api/ai-and-ollama.md +0 -1909
- package/docs/reference/core/reference/arcane-api/applications-terminal-capabilities.md +0 -1057
- package/docs/reference/core/reference/arcane-api/core-and-events.md +0 -320
- package/docs/reference/core/reference/arcane-api/filesystem-storage-preferences-appearance.md +0 -610
- package/docs/reference/core/reference/arcane-api/namespaces.md +0 -1157
- package/docs/reference/core/reference/arcane-api/platform-installation-users-system.md +0 -1423
- package/docs/reference/core/reference/arcane-api/session-provisioning-diagnostics-development.md +0 -315
- package/docs/reference/event-manager.md +0 -1511
- package/docs/reference/inventory/package-api.json +0 -3284
- package/docs/reference/inventory/runtime-components.json +0 -1011
- package/docs/reference/inventory/runtime-entities.json +0 -26
- package/docs/reference/inventory/runtime-modules.json +0 -1431
- package/docs/reference/mail.md +0 -316
- package/docs/reference/protocols.md +0 -677
- package/docs/reference/runtime-components.md +0 -1366
- package/docs/reference/runtime-entities.md +0 -303
- package/docs/reference/runtime-modules.md +0 -2960
- package/docs/reference/sdk-api.md +0 -6694
- package/docs/roadmap.md +0 -79
- package/docs/work-amplification.md +0 -129
- package/runtime/ARCANE_RUNTIME_RELEASE.json +0 -826
|
@@ -1,164 +1,43 @@
|
|
|
1
|
-
import {
|
|
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=
|
|
8
|
+
export const ARCANE_INTEGRATED_PROVIDER_RELATIVE_PATH=[
|
|
10
9
|
'tools',
|
|
11
10
|
'integrated-development-provider.mjs'
|
|
12
|
-
]
|
|
11
|
+
];
|
|
13
12
|
|
|
14
|
-
|
|
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?.(
|
|
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
|
|
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
|
|
25
|
+
const toolchainRoot=path.resolve(arcaneRoot);
|
|
93
26
|
let rootInfo;
|
|
94
|
-
try{
|
|
95
|
-
|
|
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: ${
|
|
30
|
+
fail(`The Arcane OS root does not exist: ${toolchainRoot}.`,ERROR_CODES.workspaceInvalid);
|
|
99
31
|
}
|
|
100
32
|
throw error;
|
|
101
33
|
}
|
|
102
|
-
if(rootInfo.
|
|
103
|
-
fail('The Arcane OS root must be a
|
|
34
|
+
if(!rootInfo.isDirectory()){
|
|
35
|
+
fail('The Arcane OS root must be a directory.',ERROR_CODES.workspaceInvalid);
|
|
104
36
|
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
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(
|
|
171
|
-
|
|
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
|
|
236
|
-
const
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
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(
|
|
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
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
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
|
|
77
|
+
message:'Loading the selected Arcane integrated development provider.'
|
|
351
78
|
});
|
|
352
|
-
|
|
353
|
-
|
|
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.
|
|
361
|
-
message:'
|
|
362
|
-
data:{
|
|
83
|
+
type:'integrated.provider.loaded',
|
|
84
|
+
message:'Loaded the selected Arcane integrated development provider.',
|
|
85
|
+
data:{location:selected.providerPath}
|
|
363
86
|
});
|
|
364
87
|
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
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
|
-
|
|
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,
|