arcane-os 0.5.16 → 0.5.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +44 -0
- package/README.md +42 -19
- package/bin/arcane-test.mjs +16 -13
- package/browser-runtime/ai/browser-speech-artifacts.mjs +41 -38
- package/browser-runtime/ai/browser-speech-providers.mjs +53 -46
- package/browser-runtime/ai/browser-wasm-llm-provider.mjs +127 -124
- package/browser-runtime/ai/browser-wasm.mjs +6 -3
- package/browser-runtime/ai/browser-wllama-runtime.mjs +26 -23
- package/browser-runtime/ai/model-controller.mjs +94 -91
- package/browser-runtime/ai/speech-worker-client.mjs +12 -9
- package/browser-runtime/ai/speech-worker-runtime.mjs +56 -53
- package/browser-runtime/dependencies/strong-type/index.js +207 -82
- package/browser-runtime/dependencies/strong-type/package.json +15 -6
- package/browser-runtime/dom-event-instrumentation.mjs +24 -20
- package/browser-runtime/event-manager.mjs +111 -108
- package/browser-runtime/speech-text.mjs +35 -0
- package/docs/architecture.md +1 -1
- package/docs/reference/README.md +8 -8
- package/docs/reference/ai/browser-speech.md +230 -16
- package/docs/reference/ai/twin-cloud.md +1 -1
- package/docs/reference/availability-and-normalization.md +42 -1
- package/docs/reference/cli.md +1 -1
- package/docs/reference/core/arcane-ai-contracts.md +1 -1
- package/docs/reference/inventory/package-api.json +60 -4
- package/docs/reference/inventory/runtime-components.json +2 -2
- package/docs/reference/inventory/runtime-modules.json +29 -31
- package/docs/reference/protocols.md +17 -13
- package/docs/reference/runtime-components.md +6 -5
- package/docs/reference/runtime-modules.md +212 -70
- package/docs/reference/sdk-api.md +197 -11
- package/examples/wasm-ai-demo/index.html +1 -0
- package/node_modules/event-pubsub/node_modules/strong-type/README.md +408 -0
- package/node_modules/event-pubsub/node_modules/strong-type/assets/strong-type-header.png +0 -0
- package/node_modules/event-pubsub/node_modules/strong-type/index.js +1151 -0
- package/node_modules/event-pubsub/node_modules/strong-type/licence +21 -0
- package/node_modules/event-pubsub/node_modules/strong-type/node.js +125 -0
- package/node_modules/event-pubsub/node_modules/strong-type/package.json +61 -0
- package/node_modules/strong-type/README.md +42 -24
- package/node_modules/strong-type/benchmark/core.js +324 -0
- package/node_modules/strong-type/index.js +207 -82
- package/node_modules/strong-type/package.json +14 -6
- package/package.json +4 -3
- package/runtime/arcane/components/app-bar.html +5 -2
- package/runtime/arcane/components/assistant-panel.html +5 -2
- package/runtime/arcane/components/chart.html +15 -12
- package/runtime/arcane/components/chat.html +118 -141
- package/runtime/arcane/components/dashboard-config.html +6 -3
- package/runtime/arcane/components/data-view.html +4 -1
- package/runtime/arcane/components/directory-picker.html +5 -2
- package/runtime/arcane/components/document-inspector.html +6 -3
- package/runtime/arcane/components/file-drop.html +5 -2
- package/runtime/arcane/components/file-inspector.html +9 -6
- package/runtime/arcane/components/file-manager.html +16 -13
- package/runtime/arcane/components/local-ai-status.html +5 -2
- package/runtime/arcane/components/markdown-document.html +14 -11
- package/runtime/arcane/components/markdown-editor.html +4 -1
- package/runtime/arcane/components/modal.html +4 -1
- package/runtime/arcane/components/output-panel.html +6 -3
- package/runtime/arcane/components/preferences-form.html +4 -1
- package/runtime/arcane/components/record-timeline.html +8 -5
- package/runtime/arcane/components/relationship-board.html +9 -6
- package/runtime/arcane/components/source-code-viewer.html +12 -9
- package/runtime/arcane/components/source-explanation.html +8 -5
- package/runtime/arcane/components/speech.html +24 -21
- package/runtime/arcane/components/summary-strip.html +4 -1
- package/runtime/arcane/components/task-progress.html +6 -3
- package/runtime/arcane/components/terminal-workspace.html +4 -1
- package/runtime/arcane/components/voice-transcription.html +11 -8
- package/runtime/arcane/components/web-navigator.html +5 -2
- package/runtime/arcane/entities/ApiModelRecord.js +5 -2
- package/runtime/arcane/entities/Calculation.js +5 -2
- package/runtime/arcane/entities/Chat.js +33 -33
- package/runtime/arcane/entities/CommunicationMessage.js +4 -1
- package/runtime/arcane/entities/CommunicationThread.js +4 -1
- package/runtime/arcane/entities/File.js +1 -1
- package/runtime/arcane/entities/Image.js +8 -5
- package/runtime/arcane/entities/IntentEnvelope.js +20 -17
- package/runtime/arcane/entities/Preference.js +9 -6
- package/runtime/arcane/entities/Theme.js +5 -2
- package/runtime/arcane/entities/User.js +11 -11
- package/runtime/arcane/entities/Weather.js +5 -2
- package/runtime/arcane/modules/AI.js +503 -187
- package/runtime/arcane/modules/AIPreferenceRuntime.js +5 -2
- package/runtime/arcane/modules/AIPreferenceTuple.js +9 -6
- package/runtime/arcane/modules/AIProviderRuntime.js +117 -92
- package/runtime/arcane/modules/AIResponseURLPolicy.js +148 -62
- package/runtime/arcane/modules/AIRuntimeState.js +29 -26
- package/runtime/arcane/modules/AnsiText.js +4 -1
- package/runtime/arcane/modules/ApiModelDatabase.js +22 -19
- package/runtime/arcane/modules/AppDataScope.js +8 -5
- package/runtime/arcane/modules/ArcaneCommunicationBridge.js +4 -1
- package/runtime/arcane/modules/ArcaneNavigationPolicy.js +8 -5
- package/runtime/arcane/modules/ArcaneNetworkPolicy.js +18 -15
- package/runtime/arcane/modules/AsyncBoundary.js +13 -10
- package/runtime/arcane/modules/BrowserTestSuite.js +19 -16
- package/runtime/arcane/modules/CalculatorEngine.js +5 -2
- package/runtime/arcane/modules/ChatRecords.js +18 -15
- package/runtime/arcane/modules/CommunicationAppController.js +9 -6
- package/runtime/arcane/modules/CommunicationHub.js +9 -6
- package/runtime/arcane/modules/CommunicationPreferences.js +4 -1
- package/runtime/arcane/modules/CommunicationProviderRegistry.js +4 -1
- package/runtime/arcane/modules/ComponentContracts.js +56 -53
- package/runtime/arcane/modules/ConfiguredAIChatSession.js +30 -27
- package/runtime/arcane/modules/ConversationActionItems.js +15 -12
- package/runtime/arcane/modules/ConversationClosingReport.js +11 -8
- package/runtime/arcane/modules/ConversationTimebox.js +28 -25
- package/runtime/arcane/modules/CoreLocalModelCatalog.js +17 -14
- package/runtime/arcane/modules/DBLS.js +7 -4
- package/runtime/arcane/modules/DBOPFS.js +7 -7
- package/runtime/arcane/modules/DBOPFSDocumentLibrary.js +34 -31
- package/runtime/arcane/modules/DevelopmentWorkspace.js +4 -1
- package/runtime/arcane/modules/DirectoryPicker.js +8 -5
- package/runtime/arcane/modules/DocumentLexicalSearch.js +11 -8
- package/runtime/arcane/modules/DocumentNavigation.js +7 -4
- package/runtime/arcane/modules/Errors.js +28 -25
- package/runtime/arcane/modules/HTMLImport.js +7 -4
- package/runtime/arcane/modules/IsolatedModelQuestionRunner.js +15 -12
- package/runtime/arcane/modules/LocalAIReadiness.js +21 -18
- package/runtime/arcane/modules/LocalAIReadinessController.js +6 -3
- package/runtime/arcane/modules/MD.js +1 -1
- package/runtime/arcane/modules/Mail.js +46 -43
- package/runtime/arcane/modules/MailOutbox.mjs +48 -45
- package/runtime/arcane/modules/MailTransport.mjs +29 -26
- package/runtime/arcane/modules/MarkdownSpeech.js +1 -50
- package/runtime/arcane/modules/MemoryRecords.js +7 -4
- package/runtime/arcane/modules/MessageAdvisory.js +6 -3
- package/runtime/arcane/modules/ModelDefinition.js +7 -4
- package/runtime/arcane/modules/Ollama.js +6 -3
- package/runtime/arcane/modules/OllamaModelIdentifier.js +4 -1
- package/runtime/arcane/modules/OpenMeteoWeatherProvider.js +18 -15
- package/runtime/arcane/modules/PersistentAIChatSession.js +33 -30
- package/runtime/arcane/modules/PreferenceStore.js +20 -17
- package/runtime/arcane/modules/PreparedSpeech.js +485 -0
- package/runtime/arcane/modules/Questionnaire.js +6 -3
- package/runtime/arcane/modules/RecordLinkIndex.js +4 -1
- package/runtime/arcane/modules/RecordPassageIndex.js +9 -6
- package/runtime/arcane/modules/RecordReviewStore.js +12 -9
- package/runtime/arcane/modules/RiskSignalAnalyzer.js +4 -1
- package/runtime/arcane/modules/ScopedOPFSCache.js +6 -3
- package/runtime/arcane/modules/ScreenCapture.js +20 -17
- package/runtime/arcane/modules/SpeechPlayback.js +61 -28
- package/runtime/arcane/modules/StaticDocumentCatalog.js +33 -30
- package/runtime/arcane/modules/SystemAppearance.js +5 -2
- package/runtime/arcane/modules/SystemToolRegistry.js +6 -3
- package/runtime/arcane/modules/TerminalClient.js +14 -11
- package/runtime/arcane/modules/TerminalCommandRegistry.js +4 -1
- package/runtime/arcane/modules/ThemeBootstrap.js +9 -6
- package/runtime/arcane/modules/ThemeManager.js +5 -2
- package/runtime/arcane/modules/TimeGuard.js +1 -1
- package/runtime/arcane/modules/ToolCallRouter.js +11 -8
- package/runtime/arcane/modules/WaitForComponent.js +19 -16
- package/runtime/arcane/modules/YouTubeMedia.js +4 -1
- package/runtime/strong-type/index.js +1276 -352
- package/runtime/strong-type/package.json +69 -45
- package/src/app-descriptor.mjs +17 -14
- package/src/application-tests.mjs +4 -1
- package/src/cli/main.mjs +8 -5
- package/src/constants.mjs +4 -1
- package/src/dev-server.mjs +8 -5
- package/src/doctor.mjs +5 -2
- package/src/dom-event-instrumentation.mjs +24 -20
- package/src/errors.mjs +7 -3
- package/src/event-manager.mjs +111 -108
- package/src/event-queue.mjs +8 -5
- package/src/events.mjs +12 -9
- package/src/import-map.mjs +36 -27
- package/src/installed-sdk-runtime.mjs +4 -1
- package/src/integrated-provider-loader.mjs +9 -6
- package/src/mail-credentials.mjs +16 -13
- package/src/mail-server.mjs +53 -50
- package/src/mail.mjs +18 -15
- package/src/native-plan.mjs +12 -9
- package/src/native-provider-loader.mjs +7 -4
- package/src/packager/core.mjs +18 -15
- package/src/process.mjs +6 -3
- package/src/release-bundle.mjs +14 -11
- package/src/runtime.mjs +4 -1
- package/src/scaffold.mjs +9 -6
- package/src/sdk-browser-runtime.mjs +4 -1
- package/src/source-server.mjs +17 -14
- package/src/targets/index.mjs +5 -2
- package/src/templates/workspace-template.mjs +13 -6
- package/src/testing-loader.mjs +7 -4
- package/src/testing.mjs +10 -7
- package/src/toolchain.mjs +13 -10
- package/src/update-check.mjs +9 -6
- package/src/workspace-operation-lock.mjs +14 -11
- package/src/workspace-runtime.mjs +4 -1
- package/src/workspace.mjs +17 -14
- package/runtime/arcane/modules/AIResponseLength.js +0 -32
package/src/testing.mjs
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
|
+
import Is from 'strong-type';
|
|
1
2
|
import VanillaTest from 'vanilla-test';
|
|
2
3
|
|
|
4
|
+
const is = new Is(false);
|
|
5
|
+
|
|
3
6
|
export const DEFAULT_TEST_TIMEOUT_MS=30_000;
|
|
4
7
|
|
|
5
8
|
const MAX_TEST_TIMEOUT_MS=3_600_000;
|
|
@@ -26,14 +29,14 @@ class TestCancellationError extends Error{
|
|
|
26
29
|
}
|
|
27
30
|
|
|
28
31
|
function assertName(name){
|
|
29
|
-
if(
|
|
32
|
+
if(!is.string(name)||name.trim()===''){
|
|
30
33
|
throw new TypeError('A test name must be a nonempty string.');
|
|
31
34
|
}
|
|
32
35
|
}
|
|
33
36
|
|
|
34
37
|
function testTimeout(options){
|
|
35
38
|
const timeout=options.timeout??DEFAULT_TEST_TIMEOUT_MS;
|
|
36
|
-
if(!
|
|
39
|
+
if(!is.safeInteger(timeout)||timeout<1||timeout>MAX_TEST_TIMEOUT_MS){
|
|
37
40
|
throw new TypeError(
|
|
38
41
|
`Test timeout must be an integer from 1 through ${String(MAX_TEST_TIMEOUT_MS)} milliseconds.`
|
|
39
42
|
);
|
|
@@ -43,13 +46,13 @@ function testTimeout(options){
|
|
|
43
46
|
|
|
44
47
|
function definition(name,optionsOrCallback,maybeCallback){
|
|
45
48
|
assertName(name);
|
|
46
|
-
const hasOptions
|
|
49
|
+
const hasOptions=!is.function(optionsOrCallback);
|
|
47
50
|
const options=hasOptions?optionsOrCallback:{};
|
|
48
51
|
const callback=hasOptions?maybeCallback:optionsOrCallback;
|
|
49
|
-
if(options===null
|
|
52
|
+
if(options===null||!is.object(options)||is.array(options)){
|
|
50
53
|
throw new TypeError('Test options must be an object.');
|
|
51
54
|
}
|
|
52
|
-
if(
|
|
55
|
+
if(!is.function(callback)){
|
|
53
56
|
throw new TypeError(`Test "${name}" requires a callback function.`);
|
|
54
57
|
}
|
|
55
58
|
return {name,timeoutMs:testTimeout(options),callback};
|
|
@@ -226,7 +229,7 @@ async function executeDefinition(current,path,outcomes,{parentSignal,state,onPha
|
|
|
226
229
|
if(state.cancelled||state.fatalError||controller.signal.aborted){
|
|
227
230
|
throw state.fatalError??cancellationError(controller.signal);
|
|
228
231
|
}
|
|
229
|
-
if(
|
|
232
|
+
if(!is.function(callback)){
|
|
230
233
|
throw new TypeError('t.after() requires a callback function.');
|
|
231
234
|
}
|
|
232
235
|
cleanups.push(callback);
|
|
@@ -365,7 +368,7 @@ export async function runRegisteredTests({signal,requireTests=true,onPhase}={}){
|
|
|
365
368
|
if(lifecycle!=='collecting'){
|
|
366
369
|
throw new ReferenceError('The registered test suite can run only once.');
|
|
367
370
|
}
|
|
368
|
-
if(onPhase!==undefined
|
|
371
|
+
if(onPhase!==undefined&&!is.function(onPhase)){
|
|
369
372
|
throw new TypeError('onPhase must be a function when provided.');
|
|
370
373
|
}
|
|
371
374
|
lifecycle='running';
|
package/src/toolchain.mjs
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import Is from 'strong-type';
|
|
1
2
|
import path from 'node:path';
|
|
2
3
|
import {readdir,lstat,realpath} from 'node:fs/promises';
|
|
3
4
|
import {createWorkspace,initWorkspace} from './scaffold.mjs';
|
|
@@ -39,6 +40,8 @@ import {
|
|
|
39
40
|
verifyAppReleaseBundle
|
|
40
41
|
} from './release-bundle.mjs';
|
|
41
42
|
|
|
43
|
+
const is = new Is(false);
|
|
44
|
+
|
|
42
45
|
async function emit(onEvent,event){
|
|
43
46
|
await onEvent?.(event);
|
|
44
47
|
}
|
|
@@ -63,10 +66,10 @@ function isOuterCommitEvent(label,event){
|
|
|
63
66
|
|
|
64
67
|
function hasCommittedOuterResult(label,result){
|
|
65
68
|
if(label==='import-map')return result?.committed===true;
|
|
66
|
-
if(label==='package')return
|
|
67
|
-
if(label==='bundle')return
|
|
69
|
+
if(label==='package')return is.string(result?.outputRoot);
|
|
70
|
+
if(label==='bundle')return is.string(result?.bundlePath);
|
|
68
71
|
if(label!=='build')return false;
|
|
69
|
-
return result?.artifact!=null||
|
|
72
|
+
return result?.artifact!=null||is.string(result?.release?.outputRoot);
|
|
70
73
|
}
|
|
71
74
|
|
|
72
75
|
async function ownedWork(label,work,{
|
|
@@ -245,8 +248,8 @@ async function preparedWorkspace(options){
|
|
|
245
248
|
});
|
|
246
249
|
const external=workspace.workspaceMode==='external';
|
|
247
250
|
if(external&&(!workspace.sdkInstallation
|
|
248
|
-
|
|
249
|
-
|
|
251
|
+
||!is.string(workspace.sdkInstallation.runtimeRoot)
|
|
252
|
+
||!is.string(workspace.sdkInstallation.browserRuntimeRoot))){
|
|
250
253
|
throw new ArcaneError(
|
|
251
254
|
ERROR_CODES.workspaceInvalid,
|
|
252
255
|
'Validated external workspace is missing its SDK runtime directories.'
|
|
@@ -397,7 +400,7 @@ async function runPreparedApplicationTests(prepared,options={}){
|
|
|
397
400
|
export async function testApplication(options={}){
|
|
398
401
|
throwIfAborted(options.signal);
|
|
399
402
|
if(operationScope(options)==='shared'){
|
|
400
|
-
if(
|
|
403
|
+
if(!is.string(options.testFile)||!options.testFile){
|
|
401
404
|
throw new ArcaneError(
|
|
402
405
|
ERROR_CODES.usage,
|
|
403
406
|
'Shared testing requires one exact repo-relative .test.mjs file.'
|
|
@@ -521,7 +524,7 @@ export async function verifyApplication(options={}){
|
|
|
521
524
|
|
|
522
525
|
export async function bundleApplication(options={}){
|
|
523
526
|
assertApplicationScope(options,'Release bundling');
|
|
524
|
-
if(options.overwrite!==undefined
|
|
527
|
+
if(options.overwrite!==undefined&&!is.boolean(options.overwrite)){
|
|
525
528
|
throw new ArcaneError(ERROR_CODES.usage,'overwrite must be a literal boolean.');
|
|
526
529
|
}
|
|
527
530
|
const prepared=await preparedWorkspace(options);
|
|
@@ -658,7 +661,7 @@ function sameOrDescendant(parent,candidate){
|
|
|
658
661
|
}
|
|
659
662
|
|
|
660
663
|
export function resolveNativeBuildOutputRoot({target,workspaceMode,workspaceRoot,outputRoot}={}){
|
|
661
|
-
if(
|
|
664
|
+
if(!is.string(target)||!target||target==='browser'){
|
|
662
665
|
throw new ArcaneError(ERROR_CODES.usage,'A native output root requires one explicit native target.');
|
|
663
666
|
}
|
|
664
667
|
if(workspaceMode==='integrated'&&!outputRoot){
|
|
@@ -696,7 +699,7 @@ function sameCanonicalPath(left,right){
|
|
|
696
699
|
|
|
697
700
|
export function assertIntegratedNativeToolchain({workspaceMode,workspaceRoot,toolchainRoot,target}={}){
|
|
698
701
|
if(workspaceMode!=='integrated')return;
|
|
699
|
-
if(
|
|
702
|
+
if(!is.string(toolchainRoot)||!sameCanonicalPath(workspaceRoot,toolchainRoot)){
|
|
700
703
|
throw new ArcaneError(
|
|
701
704
|
ERROR_CODES.policyDenied,
|
|
702
705
|
`An integrated ${target??'native'} build must use the same Arcane OS checkout for --workspace and --arcane-root.`
|
|
@@ -972,7 +975,7 @@ function nativeBuildResult(assembly){
|
|
|
972
975
|
|
|
973
976
|
function usesWorkspaceNativeAssembly(options){
|
|
974
977
|
return options.nativeBuilder!=null
|
|
975
|
-
&&
|
|
978
|
+
&&is.string(options.workspaceRoot)
|
|
976
979
|
&&options.release==null
|
|
977
980
|
&&options.appReleaseRoot==null
|
|
978
981
|
&&options.appDescriptor==null;
|
package/src/update-check.mjs
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
|
+
import Is from 'strong-type';
|
|
1
2
|
import {ArcaneError,ERROR_CODES,throwIfAborted} from './errors.mjs';
|
|
2
3
|
import {parseSemver} from './packager/core.mjs';
|
|
3
4
|
import {SDK_NAME,SDK_VERSION} from './constants.mjs';
|
|
4
5
|
|
|
6
|
+
const is = new Is(false);
|
|
7
|
+
|
|
5
8
|
export const SDK_UPDATE_REGISTRY='https://registry.npmjs.org/';
|
|
6
9
|
export const SDK_UPDATE_TIMEOUT_MS=2500;
|
|
7
10
|
|
|
@@ -13,7 +16,7 @@ function updateFailure(message,{cause,details}={}){
|
|
|
13
16
|
}
|
|
14
17
|
|
|
15
18
|
function plainObject(value){
|
|
16
|
-
return value!==null&&
|
|
19
|
+
return value!==null&&is.object(value)&&!is.array(value);
|
|
17
20
|
}
|
|
18
21
|
|
|
19
22
|
function canonicalPackageName(value){
|
|
@@ -41,7 +44,7 @@ function registryEndpoint(registry,packageName){
|
|
|
41
44
|
}
|
|
42
45
|
|
|
43
46
|
function validateTimeout(value){
|
|
44
|
-
if(!
|
|
47
|
+
if(!is.safeInteger(value)||value<1){
|
|
45
48
|
throw updateFailure('The SDK update timeout must be a positive integer of milliseconds.');
|
|
46
49
|
}
|
|
47
50
|
return value;
|
|
@@ -76,7 +79,7 @@ async function responseText(response){
|
|
|
76
79
|
if(!/^(?:application\/json|application\/[A-Za-z0-9.+-]+\+json)(?:\s*;|$)/iu.test(contentType)){
|
|
77
80
|
throw updateFailure('The npm registry returned a non-JSON update response.');
|
|
78
81
|
}
|
|
79
|
-
if(!response.body
|
|
82
|
+
if(!response.body||!is.function(response.body.getReader)){
|
|
80
83
|
throw updateFailure('The npm registry returned no readable update response.');
|
|
81
84
|
}
|
|
82
85
|
const reader=response.body.getReader();
|
|
@@ -113,7 +116,7 @@ function canonicalDistTags(value){
|
|
|
113
116
|
const tags=Object.create(null);
|
|
114
117
|
for(const [tag,version] of entries){
|
|
115
118
|
if(!DIST_TAG_PATTERN.test(tag)||FORBIDDEN_DIST_TAG_KEYS.has(tag)
|
|
116
|
-
|
|
119
|
+
||!is.string(version)){
|
|
117
120
|
throw updateFailure('The npm registry update response contained an invalid dist-tag.');
|
|
118
121
|
}
|
|
119
122
|
try{
|
|
@@ -180,7 +183,7 @@ export async function checkForSdkUpdate({
|
|
|
180
183
|
const selectedPackage=canonicalPackageName(packageName);
|
|
181
184
|
const selectedRegistry=validateUpdateRegistry(registry);
|
|
182
185
|
const selectedTimeout=validateTimeout(timeoutMs);
|
|
183
|
-
if(
|
|
186
|
+
if(!is.function(fetchImpl)){
|
|
184
187
|
throw updateFailure('The SDK update HTTP client is unavailable.');
|
|
185
188
|
}
|
|
186
189
|
const tag=updateTagForVersion(currentVersion);
|
|
@@ -198,7 +201,7 @@ export async function checkForSdkUpdate({
|
|
|
198
201
|
signal:linked.signal
|
|
199
202
|
});
|
|
200
203
|
throwIfAborted(signal);
|
|
201
|
-
if(!response
|
|
204
|
+
if(!response||!is.number(response.status)){
|
|
202
205
|
throw updateFailure('The npm registry update response is unavailable.');
|
|
203
206
|
}
|
|
204
207
|
if(response.status!==200){
|
|
@@ -1,8 +1,11 @@
|
|
|
1
|
+
import Is from 'strong-type';
|
|
1
2
|
import {randomUUID} from 'node:crypto';
|
|
2
3
|
import {constants as FS_CONSTANTS} from 'node:fs';
|
|
3
4
|
import {lstat,mkdir,open,readFile,realpath,rm} from 'node:fs/promises';
|
|
4
5
|
import path from 'node:path';
|
|
5
6
|
|
|
7
|
+
const is = new Is(false);
|
|
8
|
+
|
|
6
9
|
const LOCK_DIRECTORY='.arcane';
|
|
7
10
|
const LOCK_NAME='workspace-operation.lock.json';
|
|
8
11
|
const LOCK_TTL_MILLISECONDS=6*60*60*1000;
|
|
@@ -44,7 +47,7 @@ function samePath(left,right){
|
|
|
44
47
|
}
|
|
45
48
|
|
|
46
49
|
function validOperation(value){
|
|
47
|
-
return
|
|
50
|
+
return is.string(value)&&/^[a-z][a-z0-9._-]*$/u.test(value);
|
|
48
51
|
}
|
|
49
52
|
|
|
50
53
|
function trackedLeaseState(fields){
|
|
@@ -96,7 +99,7 @@ async function ensureLockDirectory(workspace){
|
|
|
96
99
|
}
|
|
97
100
|
|
|
98
101
|
function ownerIsAlive(pid){
|
|
99
|
-
if(!
|
|
102
|
+
if(!is.safeInteger(pid)||pid<1)return false;
|
|
100
103
|
try{
|
|
101
104
|
process.kill(pid,0);
|
|
102
105
|
return true;
|
|
@@ -106,21 +109,21 @@ function ownerIsAlive(pid){
|
|
|
106
109
|
}
|
|
107
110
|
|
|
108
111
|
function lockDocument(value,{workspaceRoot,now=Date.now()}={}){
|
|
109
|
-
if(!value
|
|
112
|
+
if(!value||!is.object(value)||is.array(value)
|
|
110
113
|
||value.schemaVersion!==1
|
|
111
114
|
||value.kind!=='arcane-workspace-operation-lock'
|
|
112
115
|
||!validOperation(value.operation)
|
|
113
|
-
|
|
114
|
-
||!value.owner||!
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
116
|
+
||!is.string(value.nonce)||!value.nonce
|
|
117
|
+
||!value.owner||!is.safeInteger(value.owner.pid)
|
|
118
|
+
||!is.string(value.scope)||!samePath(value.scope,workspaceRoot)
|
|
119
|
+
||!is.string(value.acquiredAt)
|
|
120
|
+
||!is.string(value.expiresAt)
|
|
118
121
|
||value.releaseProcedure!==RELEASE_PROCEDURE
|
|
119
122
|
||value.staleRecovery!==STALE_RECOVERY){
|
|
120
123
|
return null;
|
|
121
124
|
}
|
|
122
125
|
const expiresAt=Date.parse(value.expiresAt);
|
|
123
|
-
if(!
|
|
126
|
+
if(!is.finite(expiresAt))return null;
|
|
124
127
|
return {...value,expired:expiresAt<=now};
|
|
125
128
|
}
|
|
126
129
|
|
|
@@ -227,7 +230,7 @@ async function acquire({
|
|
|
227
230
|
onEvent
|
|
228
231
|
}){
|
|
229
232
|
throwIfAborted(signal);
|
|
230
|
-
if(
|
|
233
|
+
if(!is.string(workspaceRoot)||!workspaceRoot.trim()){
|
|
231
234
|
throw new TypeError('workspaceRoot is required for an Arcane workspace operation lock.');
|
|
232
235
|
}
|
|
233
236
|
if(!validOperation(operation)){
|
|
@@ -404,7 +407,7 @@ function attachReleaseError(workError,releaseError){
|
|
|
404
407
|
}
|
|
405
408
|
|
|
406
409
|
export async function withWorkspaceOperationLock(options,work){
|
|
407
|
-
if(
|
|
410
|
+
if(!is.function(work))throw new TypeError('Workspace operation lock work must be a function.');
|
|
408
411
|
const acquired=await acquire(options);
|
|
409
412
|
let result;
|
|
410
413
|
let workError;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import Is from 'strong-type';
|
|
1
2
|
import {randomUUID} from 'node:crypto';
|
|
2
3
|
import {copyFile,lstat,mkdir,readFile,readdir,realpath,rename,rm,writeFile} from 'node:fs/promises';
|
|
3
4
|
import path from 'node:path';
|
|
@@ -6,6 +7,8 @@ import {rewriteAssetReferences} from './import-map.mjs';
|
|
|
6
7
|
import {getSdkRoot} from './runtime.mjs';
|
|
7
8
|
import {getSdkBrowserRuntimeRoot} from './sdk-browser-runtime.mjs';
|
|
8
9
|
|
|
10
|
+
const is = new Is(false);
|
|
11
|
+
|
|
9
12
|
const STAGING_PREFIX='.arcane-runtime-content-staging-';
|
|
10
13
|
const BACKUP_PREFIX='.arcane-runtime-content-backup-';
|
|
11
14
|
|
|
@@ -23,7 +26,7 @@ function throwIfAborted(signal){
|
|
|
23
26
|
}
|
|
24
27
|
|
|
25
28
|
async function emit(onEvent,event){
|
|
26
|
-
if(
|
|
29
|
+
if(is.function(onEvent))await onEvent(event);
|
|
27
30
|
}
|
|
28
31
|
|
|
29
32
|
function compareText(left,right){
|
package/src/workspace.mjs
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import Is from 'strong-type';
|
|
1
2
|
import {readFile,readdir,realpath,stat} from 'node:fs/promises';
|
|
2
3
|
import path from 'node:path';
|
|
3
4
|
import {
|
|
@@ -9,6 +10,8 @@ import {loadAppDescriptor} from './app-descriptor.mjs';
|
|
|
9
10
|
import {SDK_NAME as EXPECTED_SDK_NAME} from './constants.mjs';
|
|
10
11
|
import {inspectImportMapHtml} from './import-map.mjs';
|
|
11
12
|
|
|
13
|
+
const is = new Is(false);
|
|
14
|
+
|
|
12
15
|
const APP_ID_PATTERN=/^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/;
|
|
13
16
|
const NPM_PACKAGE_NAME_PATTERN=/^(?:@[a-z0-9][a-z0-9._-]*\/)?[a-z0-9][a-z0-9._-]*$/u;
|
|
14
17
|
const ROOT_CONFIG_NAME='arcane-packager.json';
|
|
@@ -22,7 +25,7 @@ function fail(message,code='ARCANE_WORKSPACE_INVALID'){
|
|
|
22
25
|
}
|
|
23
26
|
|
|
24
27
|
function isObject(value){
|
|
25
|
-
return value!==null&&
|
|
28
|
+
return value!==null&&is.object(value)&&!is.array(value);
|
|
26
29
|
}
|
|
27
30
|
|
|
28
31
|
function ordinal(left,right){
|
|
@@ -37,7 +40,7 @@ function throwIfAborted(signal){
|
|
|
37
40
|
}
|
|
38
41
|
|
|
39
42
|
async function emit(onEvent,event){
|
|
40
|
-
if(
|
|
43
|
+
if(is.function(onEvent))await onEvent(event);
|
|
41
44
|
}
|
|
42
45
|
|
|
43
46
|
async function readJson(filePath,label){
|
|
@@ -71,7 +74,7 @@ function sameDirectoryPath(left,right){
|
|
|
71
74
|
}
|
|
72
75
|
|
|
73
76
|
function sdkPackageSourceForDependency(dependencyName){
|
|
74
|
-
if(
|
|
77
|
+
if(!is.string(dependencyName)||dependencyName.length>214
|
|
75
78
|
||!NPM_PACKAGE_NAME_PATTERN.test(dependencyName)){
|
|
76
79
|
fail(`Invalid installed SDK dependency name: ${String(dependencyName)}.`);
|
|
77
80
|
}
|
|
@@ -85,7 +88,7 @@ function sdkPackageSourceForDependency(dependencyName){
|
|
|
85
88
|
}
|
|
86
89
|
|
|
87
90
|
function dependencyNameForSdkPackageSource(source){
|
|
88
|
-
if(
|
|
91
|
+
if(!is.string(source)||!source.startsWith('node_modules/'))return null;
|
|
89
92
|
const dependencyName=source.slice('node_modules/'.length);
|
|
90
93
|
try{
|
|
91
94
|
return sdkPackageSourceForDependency(dependencyName)===source?dependencyName:null;
|
|
@@ -95,7 +98,7 @@ function dependencyNameForSdkPackageSource(source){
|
|
|
95
98
|
}
|
|
96
99
|
|
|
97
100
|
function routeIncludeMatches(actual,wanted,optionalSecurity){
|
|
98
|
-
if(!
|
|
101
|
+
if(!is.array(actual)||!is.array(wanted))return false;
|
|
99
102
|
if(actual.length===wanted.length
|
|
100
103
|
&&actual.every(function sameIncludedPath(value,index){return value===wanted[index];})){
|
|
101
104
|
return true;
|
|
@@ -118,11 +121,11 @@ export function resolveSdkPackageDeclaration(rootPackage,{
|
|
|
118
121
|
if(!isObject(group))fail(`package.json ${groupName} must be a JSON object.`);
|
|
119
122
|
for(const [dependencyName,specifier] of Object.entries(group)){
|
|
120
123
|
const canonicalName=dependencyName===EXPECTED_SDK_NAME;
|
|
121
|
-
const aliasTarget=
|
|
124
|
+
const aliasTarget=is.string(specifier)
|
|
122
125
|
&&(specifier===`npm:${EXPECTED_SDK_NAME}`
|
|
123
126
|
||specifier.startsWith(`npm:${EXPECTED_SDK_NAME}@`));
|
|
124
127
|
if(!canonicalName&&!aliasTarget)continue;
|
|
125
|
-
if(
|
|
128
|
+
if(!is.string(specifier)||!specifier.trim()){
|
|
126
129
|
fail(`package.json ${groupName}.${dependencyName} must declare an SDK package version or source.`);
|
|
127
130
|
}
|
|
128
131
|
candidates.push(completeValue({
|
|
@@ -155,7 +158,7 @@ export function resolveSdkPackageDeclaration(rootPackage,{
|
|
|
155
158
|
function classifyRootConfig(config){
|
|
156
159
|
const validated=validatePackagerRootConfig(config,ROOT_CONFIG_NAME);
|
|
157
160
|
const routes=validated.sharedPayloads['browser-runtime'];
|
|
158
|
-
if(!
|
|
161
|
+
if(!is.array(routes))fail(`${ROOT_CONFIG_NAME} must define browser-runtime routes.`);
|
|
159
162
|
const externalPackageSource=routes.length===2
|
|
160
163
|
&&dependencyNameForSdkPackageSource(routes[1]?.source)!==null
|
|
161
164
|
?routes[1].source
|
|
@@ -194,7 +197,7 @@ function classifyRootConfig(config){
|
|
|
194
197
|
optionalArcaneSecurity&&index===0
|
|
195
198
|
&&wanted.source==='arcane'&&wanted.destination==='arcane'
|
|
196
199
|
)
|
|
197
|
-
&&
|
|
200
|
+
&&is.array(route.exclude)&&route.exclude.length===0;
|
|
198
201
|
});
|
|
199
202
|
};
|
|
200
203
|
let workspaceMode;
|
|
@@ -272,7 +275,7 @@ export async function inspectWorkspaceProfile(workspaceRoot=process.cwd()){
|
|
|
272
275
|
|
|
273
276
|
export async function selectApp(workspaceRoot=process.cwd(),appId){
|
|
274
277
|
const apps=await discoverApps(workspaceRoot);
|
|
275
|
-
if(appId!==undefined&&(
|
|
278
|
+
if(appId!==undefined&&(!is.string(appId)||!APP_ID_PATTERN.test(appId))){
|
|
276
279
|
fail(`Invalid app id: ${String(appId)}.`,'ARCANE_USAGE');
|
|
277
280
|
}
|
|
278
281
|
if(appId){
|
|
@@ -292,7 +295,7 @@ export async function resolveWorkspace({workspaceRoot=process.cwd(),appId}={}){
|
|
|
292
295
|
const canonicalRoot=profile.workspaceRoot;
|
|
293
296
|
const config=profile.config;
|
|
294
297
|
const apps=await discoverAppsInRoot(canonicalRoot,config);
|
|
295
|
-
if(appId!==undefined&&(
|
|
298
|
+
if(appId!==undefined&&(!is.string(appId)||!APP_ID_PATTERN.test(appId))){
|
|
296
299
|
fail(`Invalid app id: ${String(appId)}.`,'ARCANE_USAGE');
|
|
297
300
|
}
|
|
298
301
|
let app;
|
|
@@ -330,7 +333,7 @@ export async function resolveInstalledSdkInstallation(workspaceRoot,declaration)
|
|
|
330
333
|
path.join(canonicalPackageRoot,'package.json'),
|
|
331
334
|
'installed SDK package manifest'
|
|
332
335
|
);
|
|
333
|
-
if(installedPackage.name!==EXPECTED_SDK_NAME
|
|
336
|
+
if(installedPackage.name!==EXPECTED_SDK_NAME||!is.string(installedPackage.version)){
|
|
334
337
|
fail(`Installed SDK package must identify as ${EXPECTED_SDK_NAME}.`);
|
|
335
338
|
}
|
|
336
339
|
const runtimeRoot=path.join(canonicalPackageRoot,'runtime');
|
|
@@ -427,8 +430,8 @@ export async function validateDiscoveredApplication({
|
|
|
427
430
|
onEvent
|
|
428
431
|
}={}){
|
|
429
432
|
throwIfAborted(signal);
|
|
430
|
-
if(!app
|
|
431
|
-
|
|
433
|
+
if(!app||!is.string(app.appId)||!APP_ID_PATTERN.test(app.appId)
|
|
434
|
+
||!is.string(app.appRoot)
|
|
432
435
|
||!app.manifest||!app.descriptor){
|
|
433
436
|
fail('A discovered Arcane application is required for focused validation.');
|
|
434
437
|
}
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
export const AI_RESPONSE_LENGTH_DEFAULT='medium';
|
|
2
|
-
|
|
3
|
-
export const AI_RESPONSE_LENGTH_OPTIONS=[
|
|
4
|
-
{value:'low',label:'Complete'},
|
|
5
|
-
{value:'medium',label:'Complete'},
|
|
6
|
-
{value:'high',label:'Complete'}
|
|
7
|
-
];
|
|
8
|
-
|
|
9
|
-
const RESPONSE_LENGTH_BY_VALUE=new Map(
|
|
10
|
-
AI_RESPONSE_LENGTH_OPTIONS.map(option=>[option.value,option])
|
|
11
|
-
);
|
|
12
|
-
|
|
13
|
-
export function normalizeAIResponseLength(value){
|
|
14
|
-
const normalized=typeof value==='string'?value.trim().toLowerCase():'';
|
|
15
|
-
return RESPONSE_LENGTH_BY_VALUE.has(normalized)
|
|
16
|
-
?normalized
|
|
17
|
-
:AI_RESPONSE_LENGTH_DEFAULT;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export function aiResponseLengthInstruction(value){
|
|
21
|
-
normalizeAIResponseLength(value);
|
|
22
|
-
return '';
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export function applyAIResponseLength(systemPrompt,value){
|
|
26
|
-
if(typeof systemPrompt!=='string'){
|
|
27
|
-
throw new TypeError('systemPrompt must be a string');
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
normalizeAIResponseLength(value);
|
|
31
|
-
return systemPrompt;
|
|
32
|
-
}
|