arcane-os 0.1.2 → 0.2.1
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 +35 -0
- package/NOTICE +5 -3
- package/README.md +73 -24
- package/browser-runtime/ARCANE_SDK_BROWSER_RELEASE.json +67 -18
- package/browser-runtime/ai/ARCANE_AI_BROWSER_WASM_COMPONENTS.json +16 -5
- package/browser-runtime/ai/browser-kokoro-worker.mjs +3 -0
- package/browser-runtime/ai/browser-speech-artifacts.mjs +1108 -0
- package/browser-runtime/ai/browser-speech-providers.mjs +780 -0
- package/browser-runtime/ai/browser-speech.mjs +9 -0
- package/browser-runtime/ai/browser-wasm-llm-provider.mjs +1537 -167
- package/browser-runtime/ai/browser-wasm.mjs +46 -1
- package/browser-runtime/ai/browser-whisper-worker.mjs +3 -0
- package/browser-runtime/ai/browser-wllama-runtime.mjs +677 -132
- package/browser-runtime/ai/model-controller.mjs +138 -12
- package/browser-runtime/ai/speech-worker-client.mjs +207 -0
- package/browser-runtime/ai/speech-worker-runtime.mjs +516 -0
- package/browser-runtime/ai/wllama/index.mjs +389 -0
- package/docs/architecture.md +132 -22
- package/docs/reference/README.md +1 -1
- package/docs/reference/ai/browser-wasm.md +101 -42
- package/docs/reference/availability-and-normalization.md +19 -5
- package/docs/reference/behavioral-testing.md +18 -5
- package/docs/reference/cli.md +2 -2
- package/docs/reference/inventory/package-api.json +14 -14
- package/docs/reference/protocols.md +4 -4
- package/docs/reference/sdk-api.md +68 -38
- package/docs/work-amplification.md +8 -4
- package/package.json +7 -3
- package/runtime/ARCANE_RUNTIME_RELEASE.json +50 -20
- package/runtime/arcane/components/chat.html +551 -62
- package/runtime/arcane/components/speech.html +1113 -265
- package/runtime/arcane/entities/Chat.js +246 -43
- package/runtime/arcane/modules/AI.js +1394 -162
- package/runtime/arcane/modules/AIProviderRuntime.js +2289 -0
- package/runtime/arcane/modules/AIRuntimeState.js +872 -0
- package/runtime/arcane/modules/ConfiguredAIChatSession.js +382 -31
- package/runtime/arcane/modules/DBOPFSDocumentLibrary.js +1106 -0
- package/runtime/arcane/modules/DocumentLexicalSearch.js +292 -0
- package/runtime/arcane/modules/PersistentAIChatSession.js +268 -0
- package/runtime/arcane/modules/StaticDocumentCatalog.js +25 -206
- package/schemas/arcane-lock.schema.json +10 -6
- package/src/cli/main.mjs +14 -2
- package/src/constants.mjs +1 -1
- package/src/dev-server.mjs +273 -26
- package/src/doctor.mjs +1 -3
- package/src/import-map.mjs +193 -84
- package/src/packager/core.mjs +313 -41
- package/src/runtime.mjs +14 -4
- package/src/scaffold.mjs +45 -17
- package/src/sdk-browser-runtime.mjs +28 -75
- package/src/templates/workspace-template.mjs +27 -8
- package/src/toolchain.mjs +13 -2
- package/src/workspace-runtime.mjs +1 -1
- package/src/workspace.mjs +178 -25
package/src/scaffold.mjs
CHANGED
|
@@ -7,12 +7,11 @@ import {materializeWorkspaceRuntime} from './workspace-runtime.mjs';
|
|
|
7
7
|
import {generateImportMap} from './import-map.mjs';
|
|
8
8
|
import {withWorkspaceOperationLock} from './workspace-operation-lock.mjs';
|
|
9
9
|
import {SDK_NAME,SDK_VERSION,workspaceTemplate} from './templates/workspace-template.mjs';
|
|
10
|
-
import {inspectWorkspaceProfile} from './workspace.mjs';
|
|
10
|
+
import {inspectWorkspaceProfile,resolveSdkPackageDeclaration} from './workspace.mjs';
|
|
11
11
|
import {parseSemver} from './packager/core.mjs';
|
|
12
12
|
|
|
13
13
|
const APP_ID_PATTERN=/^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/;
|
|
14
14
|
const DISPLAY_CONTROL_PATTERN=/[\x00-\x1f\x7f]/;
|
|
15
|
-
const LOCAL_TARBALL_PATTERN=/^file:.+\.tgz$/iu;
|
|
16
15
|
|
|
17
16
|
function fail(message,code='ARCANE_WORKSPACE_INVALID'){
|
|
18
17
|
const error=new Error(message);
|
|
@@ -152,31 +151,35 @@ async function assertNoLinkedAncestors(workspaceRoot,relative){
|
|
|
152
151
|
}
|
|
153
152
|
}
|
|
154
153
|
|
|
155
|
-
function
|
|
156
|
-
return value===SDK_VERSION||(typeof value==='string'&&LOCAL_TARBALL_PATTERN.test(value)
|
|
157
|
-
&&!DISPLAY_CONTROL_PATTERN.test(value));
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
async function prepareExistingPackage(workspaceRoot,files){
|
|
154
|
+
async function readExistingPackage(workspaceRoot){
|
|
161
155
|
const packagePath=path.join(workspaceRoot,'package.json');
|
|
162
156
|
let source;
|
|
163
157
|
try{source=await readFile(packagePath,'utf8');}
|
|
164
158
|
catch(error){
|
|
165
|
-
if(error?.code==='ENOENT')
|
|
159
|
+
if(error?.code==='ENOENT'){
|
|
160
|
+
return Object.freeze({exists:false,packagePath,source:null,document:null});
|
|
161
|
+
}
|
|
166
162
|
throw error;
|
|
167
163
|
}
|
|
168
164
|
let existing;
|
|
169
165
|
try{existing=JSON.parse(source);}
|
|
170
166
|
catch(error){fail(`Existing package.json is not valid JSON: ${error.message}.`);}
|
|
171
167
|
if(!existing||typeof existing!=='object'||Array.isArray(existing))fail('Existing package.json must be a JSON object.');
|
|
168
|
+
return Object.freeze({exists:true,packagePath,source,document:existing});
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function defaultSdkDeclaration(){
|
|
172
|
+
return resolveSdkPackageDeclaration({devDependencies:{[SDK_NAME]:SDK_VERSION}});
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
async function prepareExistingPackage(workspaceRoot,files,existingPackage,sdkDeclaration){
|
|
176
|
+
const packageState=existingPackage??await readExistingPackage(workspaceRoot);
|
|
177
|
+
if(!packageState.exists)return Object.freeze({exists:false,updated:false});
|
|
178
|
+
const {packagePath,source,document:existing}=packageState;
|
|
172
179
|
const generated=JSON.parse(files.get('package.json'));
|
|
173
180
|
const conflicts=[];
|
|
174
181
|
if(existing.private!==undefined&&existing.private!==true)conflicts.push('private must be true');
|
|
175
182
|
if(existing.type!==undefined&&existing.type!=='module')conflicts.push('type must be "module"');
|
|
176
|
-
const declared=existing.devDependencies?.[SDK_NAME]??existing.dependencies?.[SDK_NAME];
|
|
177
|
-
if(declared!==undefined&&!isSupportedSdkDeclaration(declared)){
|
|
178
|
-
conflicts.push(`${SDK_NAME} must be ${SDK_VERSION} or a local file: tarball`);
|
|
179
|
-
}
|
|
180
183
|
const appSelectionScripts=new Set(['build','run']);
|
|
181
184
|
for(const [name,command] of Object.entries(generated.scripts)){
|
|
182
185
|
if(appSelectionScripts.has(name))continue;
|
|
@@ -192,12 +195,15 @@ async function prepareExistingPackage(workspaceRoot,files){
|
|
|
192
195
|
private:true,
|
|
193
196
|
type:'module',
|
|
194
197
|
scripts:{...generated.scripts,...(existing.scripts||{})},
|
|
195
|
-
devDependencies:{
|
|
198
|
+
devDependencies:{
|
|
199
|
+
...(existing.devDependencies||{}),
|
|
200
|
+
[sdkDeclaration.dependencyName]:sdkDeclaration.specifier
|
|
201
|
+
},
|
|
196
202
|
engines:{...generated.engines,...(existing.engines||{})}
|
|
197
203
|
};
|
|
198
|
-
if(existing.dependencies?.[
|
|
204
|
+
if(existing.dependencies?.[sdkDeclaration.dependencyName]!==undefined){
|
|
199
205
|
merged.dependencies={...existing.dependencies};
|
|
200
|
-
delete merged.dependencies[
|
|
206
|
+
delete merged.dependencies[sdkDeclaration.dependencyName];
|
|
201
207
|
if(Object.keys(merged.dependencies).length===0)delete merged.dependencies;
|
|
202
208
|
}
|
|
203
209
|
if(JSON.stringify(existing)===JSON.stringify(merged)){
|
|
@@ -422,6 +428,20 @@ export async function initWorkspace({
|
|
|
422
428
|
const sdkBrowserRuntimeReceipt=workspaceMode==='external'
|
|
423
429
|
?await verifySdkBrowserRuntime({signal,onEvent})
|
|
424
430
|
:null;
|
|
431
|
+
const existingPackage=workspaceMode==='external'
|
|
432
|
+
?await readExistingPackage(resolvedRoot)
|
|
433
|
+
:null;
|
|
434
|
+
const sdkDeclaration=workspaceMode==='external'
|
|
435
|
+
?profile?.config.sdkPackageSource!==undefined
|
|
436
|
+
?resolveSdkPackageDeclaration(existingPackage.document??{}, {
|
|
437
|
+
allowMissing:true,
|
|
438
|
+
packageSource:profile.config.sdkPackageSource
|
|
439
|
+
})
|
|
440
|
+
:(existingPackage.exists
|
|
441
|
+
?resolveSdkPackageDeclaration(existingPackage.document,{allowMissing:true})
|
|
442
|
+
:null)
|
|
443
|
+
??defaultSdkDeclaration()
|
|
444
|
+
:null;
|
|
425
445
|
const template=workspaceMode==='integrated'
|
|
426
446
|
?workspaceTemplate({
|
|
427
447
|
appId,
|
|
@@ -437,12 +457,20 @@ export async function initWorkspace({
|
|
|
437
457
|
displayName,
|
|
438
458
|
runtimeRelease:runtimeReceipt,
|
|
439
459
|
sdkBrowserRuntimeRelease:sdkBrowserRuntimeReceipt,
|
|
460
|
+
sdkDependencyName:sdkDeclaration.dependencyName,
|
|
461
|
+
sdkDependencySpecifier:sdkDeclaration.specifier,
|
|
462
|
+
sdkPackageSource:sdkDeclaration.packageSource,
|
|
440
463
|
target,
|
|
441
464
|
appIcon:await scaffoldIcon(target)
|
|
442
465
|
});
|
|
443
466
|
const packagePlan=workspaceMode==='integrated'
|
|
444
467
|
?Object.freeze({exists:true,updated:false})
|
|
445
|
-
:await prepareExistingPackage(
|
|
468
|
+
:await prepareExistingPackage(
|
|
469
|
+
resolvedRoot,
|
|
470
|
+
template.files,
|
|
471
|
+
existingPackage,
|
|
472
|
+
sdkDeclaration
|
|
473
|
+
);
|
|
446
474
|
if(workspaceMode==='external'){
|
|
447
475
|
await assertExistingLockAdmission(resolvedRoot,template.files);
|
|
448
476
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {createHash} from 'node:crypto';
|
|
2
2
|
import {constants as FS_CONSTANTS} from 'node:fs';
|
|
3
|
-
import {lstat,open,readdir,realpath} from 'node:fs/promises';
|
|
3
|
+
import {lstat,open,readFile,readdir,realpath} from 'node:fs/promises';
|
|
4
4
|
import path from 'node:path';
|
|
5
5
|
import {fileURLToPath} from 'node:url';
|
|
6
6
|
import {SDK_VERSION} from './constants.mjs';
|
|
@@ -8,96 +8,49 @@ import {SDK_VERSION} from './constants.mjs';
|
|
|
8
8
|
const MANIFEST_NAME='ARCANE_SDK_BROWSER_RELEASE.json';
|
|
9
9
|
const BUILDER='arcane-sdk-browser-runtime-v1';
|
|
10
10
|
const PROTOCOL='arcane-sdk-browser-runtime/1';
|
|
11
|
-
export const SDK_BROWSER_RUNTIME_MANIFEST_SHA256=
|
|
12
|
-
'88395493b411fd5461fbb2bb065ae2b745f6d1672f796583fd248ec97f71f4f7';
|
|
13
|
-
export const SDK_BROWSER_RUNTIME_CONTENT_SHA256=
|
|
14
|
-
'5e03f45a732db51cb5a2b2193cc79ecda34501d07a9b2e82e794e5fa37d55d00';
|
|
15
11
|
const REPOSITORY='https://github.com/TheWizardNexus/arcane-os-sdk.git';
|
|
16
12
|
const SHA256_PATTERN=/^[a-f0-9]{64}$/u;
|
|
17
13
|
const READ_ONLY_NO_FOLLOW=FS_CONSTANTS.O_RDONLY|(FS_CONSTANTS.O_NOFOLLOW??0);
|
|
18
14
|
const MAX_VERIFIED_FILE_BYTES=64*1024*1024;
|
|
19
15
|
const packageRoot=path.resolve(path.dirname(fileURLToPath(import.meta.url)),'..');
|
|
20
16
|
const defaultRoot=path.join(packageRoot,'browser-runtime');
|
|
17
|
+
const canonicalManifestBytes=await readFile(path.join(defaultRoot,MANIFEST_NAME));
|
|
18
|
+
const canonicalRelease=JSON.parse(canonicalManifestBytes.toString('utf8'));
|
|
19
|
+
if(
|
|
20
|
+
canonicalRelease?.schemaVersion!==1
|
|
21
|
+
||canonicalRelease.builder!==BUILDER
|
|
22
|
+
||canonicalRelease.sdkVersion!==SDK_VERSION
|
|
23
|
+
||!SHA256_PATTERN.test(canonicalRelease.contentSha256)
|
|
24
|
+
){
|
|
25
|
+
throw new Error('The canonical SDK browser runtime receipt is invalid.');
|
|
26
|
+
}
|
|
27
|
+
export const SDK_BROWSER_RUNTIME_MANIFEST_SHA256=
|
|
28
|
+
createHash('sha256').update(canonicalManifestBytes).digest('hex');
|
|
29
|
+
export const SDK_BROWSER_RUNTIME_CONTENT_SHA256=canonicalRelease.contentSha256;
|
|
21
30
|
const issuedReceipts=new WeakSet();
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
runtimePolicy:{
|
|
29
|
-
modelAuthorities:'caller-supplied-exact-bytes-and-sha256',
|
|
30
|
-
modelWeightsPacked:false,
|
|
31
|
-
remoteModelHelpers:false,
|
|
32
|
-
compatibilityRuntime:false,
|
|
33
|
-
toolCalls:'structural-only-never-executed'
|
|
34
|
-
},
|
|
35
|
-
components:[
|
|
36
|
-
{
|
|
37
|
-
name:'@wllama/wllama',
|
|
38
|
-
version:'3.6.0',
|
|
39
|
-
licenseSpdx:'MIT',
|
|
40
|
-
sourceRepository:'https://github.com/ngxson/wllama.git',
|
|
41
|
-
sourceRevision:'f16050d8d51a00602c6a2a6b8ac9c09f490eea7f',
|
|
42
|
-
npm:{
|
|
43
|
-
resolved:'https://registry.npmjs.org/@wllama/wllama/-/wllama-3.6.0.tgz',
|
|
44
|
-
integrity:'sha512-NN3ZBXqaaUwGXTQubkNvsCaLPjN2XVa0bVS40OYCE8zquYmRc2W3oHYEgwvuSWWDB8aUqTLyMioySCXNkcnD1w==',
|
|
45
|
-
tarballBytes:5671369,
|
|
46
|
-
tarballSha256:'137c35ceccb4911a9b0ce9b427889f75991654ec6a6d1dd8fabd879b14b07a1b'
|
|
47
|
-
},
|
|
48
|
-
files:[
|
|
49
|
-
{
|
|
50
|
-
role:'runtime-module',
|
|
51
|
-
path:'ai/wllama/index.mjs',
|
|
52
|
-
sourcePath:'node_modules/@wllama/wllama/esm/index.js',
|
|
53
|
-
bytes:373519,
|
|
54
|
-
sha256:'4637e42d636010493a9b274fbbe70bfd8120365da726b1d9e589d85ca84a00d6'
|
|
55
|
-
},
|
|
56
|
-
{
|
|
57
|
-
role:'runtime-wasm',
|
|
58
|
-
path:'ai/wllama/wllama.wasm',
|
|
59
|
-
sourcePath:'node_modules/@wllama/wllama/esm/wasm/wllama.wasm',
|
|
60
|
-
bytes:8524865,
|
|
61
|
-
sha256:'95c6ff9ef2a03ff2c63bc91db132f0126a0bd0456b272cd8ae2e0f592fb059f6'
|
|
62
|
-
},
|
|
63
|
-
{
|
|
64
|
-
role:'license',
|
|
65
|
-
path:'ai/wllama/LICENCE',
|
|
66
|
-
sourcePath:'node_modules/@wllama/wllama/LICENCE',
|
|
67
|
-
bytes:1071,
|
|
68
|
-
sha256:'5866e3bd7e3cbd3f7c8bea6efd8a1e7fa7cc8de68c30f428aff7c6584a0fb720'
|
|
69
|
-
}
|
|
70
|
-
]
|
|
71
|
-
},
|
|
72
|
-
{
|
|
73
|
-
name:'llama.cpp',
|
|
74
|
-
version:'b10454',
|
|
75
|
-
licenseSpdx:'MIT',
|
|
76
|
-
sourceRepository:'https://github.com/ggerganov/llama.cpp.git',
|
|
77
|
-
sourceRevision:'4df29be4f4c3673f428170fda944a5b19f743bb8',
|
|
78
|
-
embeddedBy:'@wllama/wllama@3.6.0',
|
|
79
|
-
files:[
|
|
80
|
-
{
|
|
81
|
-
role:'license',
|
|
82
|
-
path:'ai/wllama/llama.cpp-LICENSE',
|
|
83
|
-
sourceUrl:'https://raw.githubusercontent.com/ggerganov/llama.cpp/4df29be4f4c3673f428170fda944a5b19f743bb8/LICENSE',
|
|
84
|
-
bytes:1078,
|
|
85
|
-
sha256:'94f29bbed6a22c35b992c5c6ebf0e7c92f13b836b90f36f461c9cf2f0f1d010d'
|
|
86
|
-
}
|
|
87
|
-
]
|
|
88
|
-
}
|
|
89
|
-
]
|
|
90
|
-
});
|
|
31
|
+
const canonicalAiComponentsBytes=await readFile(
|
|
32
|
+
path.join(defaultRoot,'ai','ARCANE_AI_BROWSER_WASM_COMPONENTS.json')
|
|
33
|
+
);
|
|
34
|
+
const expectedAiComponents=Object.freeze(
|
|
35
|
+
JSON.parse(canonicalAiComponentsBytes.toString('utf8'))
|
|
36
|
+
);
|
|
91
37
|
|
|
92
38
|
const expectedFiles=Object.freeze([
|
|
93
39
|
['ai/ARCANE_AI_BROWSER_WASM_COMPONENTS.json','browser-runtime/ai/ARCANE_AI_BROWSER_WASM_COMPONENTS.json','sdk-source-identity'],
|
|
40
|
+
['ai/browser-kokoro-worker.mjs','browser-runtime/ai/browser-kokoro-worker.mjs','sdk-source-identity'],
|
|
41
|
+
['ai/browser-speech-artifacts.mjs','browser-runtime/ai/browser-speech-artifacts.mjs','sdk-source-identity'],
|
|
42
|
+
['ai/browser-speech-providers.mjs','browser-runtime/ai/browser-speech-providers.mjs','sdk-source-identity'],
|
|
43
|
+
['ai/browser-speech.mjs','browser-runtime/ai/browser-speech.mjs','sdk-source-identity'],
|
|
94
44
|
['ai/browser-wasm-llm-provider.mjs','browser-runtime/ai/browser-wasm-llm-provider.mjs','sdk-source-identity'],
|
|
95
45
|
['ai/browser-wasm.mjs','browser-runtime/ai/browser-wasm.mjs','sdk-source-identity'],
|
|
46
|
+
['ai/browser-whisper-worker.mjs','browser-runtime/ai/browser-whisper-worker.mjs','sdk-source-identity'],
|
|
96
47
|
['ai/browser-wllama-runtime.mjs','browser-runtime/ai/browser-wllama-runtime.mjs','sdk-source-identity'],
|
|
97
48
|
['ai/internal/sha256.mjs','browser-runtime/ai/internal/sha256.mjs','sdk-source-identity'],
|
|
98
49
|
['ai/model-controller.mjs','browser-runtime/ai/model-controller.mjs','sdk-source-identity'],
|
|
50
|
+
['ai/speech-worker-client.mjs','browser-runtime/ai/speech-worker-client.mjs','sdk-source-identity'],
|
|
51
|
+
['ai/speech-worker-runtime.mjs','browser-runtime/ai/speech-worker-runtime.mjs','sdk-source-identity'],
|
|
99
52
|
['ai/wllama/LICENCE','node_modules/@wllama/wllama/LICENCE','vendor-package-identity'],
|
|
100
|
-
['ai/wllama/index.mjs','
|
|
53
|
+
['ai/wllama/index.mjs','browser-runtime/ai/wllama/index.mjs','deterministic-derived-vendor'],
|
|
101
54
|
['ai/wllama/llama.cpp-LICENSE','browser-runtime/ai/wllama/llama.cpp-LICENSE','vendor-source-identity'],
|
|
102
55
|
['ai/wllama/wllama.wasm','node_modules/@wllama/wllama/esm/wasm/wllama.wasm','vendor-package-identity'],
|
|
103
56
|
['dependencies/event-pubsub/index.js','node_modules/event-pubsub/index.js','vendor-package-identity'],
|
|
@@ -4,6 +4,9 @@ import {
|
|
|
4
4
|
SDK_BROWSER_RUNTIME_MANIFEST_SHA256
|
|
5
5
|
} from '../sdk-browser-runtime.mjs';
|
|
6
6
|
|
|
7
|
+
const NPM_PACKAGE_NAME_PATTERN=/^(?:@[a-z0-9][a-z0-9._-]*\/)?[a-z0-9][a-z0-9._-]*$/u;
|
|
8
|
+
const LOCAL_TARBALL_PATTERN=/^file:.+\.tgz$/iu;
|
|
9
|
+
|
|
7
10
|
function json(value){
|
|
8
11
|
return `${JSON.stringify(value,null,2)}\n`;
|
|
9
12
|
}
|
|
@@ -28,12 +31,28 @@ export function workspaceTemplate({
|
|
|
28
31
|
displayName,
|
|
29
32
|
runtimeRelease,
|
|
30
33
|
sdkBrowserRuntimeRelease,
|
|
34
|
+
sdkDependencyName=SDK_NAME,
|
|
35
|
+
sdkDependencySpecifier=SDK_VERSION,
|
|
36
|
+
sdkPackageSource=`node_modules/${sdkDependencyName}`,
|
|
31
37
|
appOnly=false,
|
|
32
38
|
namedImports=true,
|
|
33
39
|
minimumCoreVersion='0.8.12',
|
|
34
40
|
target='browser',
|
|
35
41
|
appIcon
|
|
36
42
|
}){
|
|
43
|
+
const canonicalSpecifier=sdkDependencyName===SDK_NAME
|
|
44
|
+
&&(sdkDependencySpecifier===SDK_VERSION
|
|
45
|
+
||(typeof sdkDependencySpecifier==='string'
|
|
46
|
+
&&LOCAL_TARBALL_PATTERN.test(sdkDependencySpecifier)
|
|
47
|
+
&&!/[\x00-\x1f\x7f]/.test(sdkDependencySpecifier)));
|
|
48
|
+
const aliasSpecifier=sdkDependencyName!==SDK_NAME
|
|
49
|
+
&&sdkDependencySpecifier===`npm:${SDK_NAME}@${SDK_VERSION}`;
|
|
50
|
+
if(typeof sdkDependencyName!=='string'||sdkDependencyName.length>214
|
|
51
|
+
||!NPM_PACKAGE_NAME_PATTERN.test(sdkDependencyName)
|
|
52
|
+
||sdkPackageSource!==`node_modules/${sdkDependencyName}`
|
|
53
|
+
||(!canonicalSpecifier&&!aliasSpecifier)){
|
|
54
|
+
throw new Error('Invalid scaffold SDK installation authority.');
|
|
55
|
+
}
|
|
37
56
|
const supportedTargets=['browser','portable','windows-x64','linux-x64','linux-arm64','android-arm64'];
|
|
38
57
|
if(!supportedTargets.includes(target)){
|
|
39
58
|
throw new Error(`Unsupported scaffold target: ${String(target)}.`);
|
|
@@ -47,7 +66,7 @@ export function workspaceTemplate({
|
|
|
47
66
|
const name=displayName||`Arcane ${titleCase(appId)}`;
|
|
48
67
|
const packageName=`arcane-${appId}`;
|
|
49
68
|
const runtimeContentSha256=runtimeRelease?.contentSha256;
|
|
50
|
-
const upstreamCommit=runtimeRelease?.source?.commit;
|
|
69
|
+
const upstreamCommit=runtimeRelease?.source?.legacyProjection?.commit;
|
|
51
70
|
const browserManifestSha256=sdkBrowserRuntimeRelease?.manifestSha256;
|
|
52
71
|
const browserContentSha256=sdkBrowserRuntimeRelease?.contentSha256;
|
|
53
72
|
const browserSource=sdkBrowserRuntimeRelease?.source;
|
|
@@ -153,15 +172,15 @@ appropriate.
|
|
|
153
172
|
files.set('AGENTS.md',`# ${name} development instructions
|
|
154
173
|
|
|
155
174
|
- Use plain JavaScript, HTML, and CSS; do not introduce TypeScript or TSX.
|
|
156
|
-
- Keep reusable mechanisms in Arcane
|
|
175
|
+
- Keep reusable portable mechanisms in the Arcane SDK and app-specific behavior under \`apps/${appId}/\`.
|
|
157
176
|
- Keep \`arcane/css/theme.css\` before app styles and import \`arcane/ThemeBootstrap\` before app code runs.
|
|
158
177
|
- Use \`rgb(...)\` or \`rgba(...)\` for new CSS colors.
|
|
159
178
|
- Build one named app and one explicit target at a time. Native targets may be unavailable until their adapters are installed.
|
|
160
|
-
- Run
|
|
179
|
+
- Run tests and checks only when the user explicitly selects verification or a distribution artifact requires it.
|
|
161
180
|
`);
|
|
162
181
|
files.set('README.md',`# ${name}
|
|
163
182
|
|
|
164
|
-
This repository contains the Arcane
|
|
183
|
+
This repository contains the portable Arcane application \`${appId}\`. It embeds immutable SDK runtime bytes for distribution and has no runtime dependency on an Arcane OS source checkout.
|
|
165
184
|
|
|
166
185
|
## Start
|
|
167
186
|
|
|
@@ -222,7 +241,7 @@ Every browser release also carries Arcane OS licensing material under \`licenses
|
|
|
222
241
|
}:{})
|
|
223
242
|
},
|
|
224
243
|
devDependencies:{
|
|
225
|
-
[
|
|
244
|
+
[sdkDependencyName]:sdkDependencySpecifier
|
|
226
245
|
},
|
|
227
246
|
engines:{node:'>=22.23.2'}
|
|
228
247
|
}));
|
|
@@ -239,7 +258,7 @@ Every browser release also carries Arcane OS licensing material under \`licenses
|
|
|
239
258
|
exclude:[]
|
|
240
259
|
},
|
|
241
260
|
{
|
|
242
|
-
source:
|
|
261
|
+
source:sdkPackageSource,
|
|
243
262
|
destination:'licenses/arcane-os',
|
|
244
263
|
include:['LICENSE','COMMERCIAL-LICENSE.md','NOTICE'],
|
|
245
264
|
exclude:[]
|
|
@@ -251,12 +270,12 @@ Every browser release also carries Arcane OS licensing material under \`licenses
|
|
|
251
270
|
schemaVersion:1,
|
|
252
271
|
sdk:{name:SDK_NAME,version:SDK_VERSION},
|
|
253
272
|
runtime:{
|
|
254
|
-
manifest
|
|
273
|
+
manifest:`${sdkPackageSource}/runtime/ARCANE_RUNTIME_RELEASE.json`,
|
|
255
274
|
contentSha256:runtimeContentSha256,
|
|
256
275
|
upstreamCommit
|
|
257
276
|
},
|
|
258
277
|
sdkBrowserRuntime:{
|
|
259
|
-
manifest
|
|
278
|
+
manifest:`${sdkPackageSource}/browser-runtime/ARCANE_SDK_BROWSER_RELEASE.json`,
|
|
260
279
|
manifestSha256:browserManifestSha256,
|
|
261
280
|
contentSha256:browserContentSha256,
|
|
262
281
|
builder:sdkBrowserRuntimeRelease?.builder,
|
package/src/toolchain.mjs
CHANGED
|
@@ -380,11 +380,19 @@ async function preparedWorkspace(options){
|
|
|
380
380
|
onEvent:options.onEvent
|
|
381
381
|
});
|
|
382
382
|
const external=workspace.workspaceMode==='external';
|
|
383
|
+
if(external&&(!workspace.sdkInstallation
|
|
384
|
+
||typeof workspace.sdkInstallation.runtimeRoot!=='string'
|
|
385
|
+
||typeof workspace.sdkInstallation.browserRuntimeRoot!=='string')){
|
|
386
|
+
throw new ArcaneError(
|
|
387
|
+
ERROR_CODES.workspaceInvalid,
|
|
388
|
+
'Validated external workspace is missing its bound SDK installation authority.'
|
|
389
|
+
);
|
|
390
|
+
}
|
|
383
391
|
const runtimeRoot=external
|
|
384
|
-
?
|
|
392
|
+
?workspace.sdkInstallation.runtimeRoot
|
|
385
393
|
:workspace.workspaceRoot;
|
|
386
394
|
const browserRuntimeRoot=external
|
|
387
|
-
?
|
|
395
|
+
?workspace.sdkInstallation.browserRuntimeRoot
|
|
388
396
|
:null;
|
|
389
397
|
const runtimeReceipt=external&&!options.deferRuntimeVerification
|
|
390
398
|
?await verifyRuntime({
|
|
@@ -791,6 +799,9 @@ export async function developApplication(options={}){
|
|
|
791
799
|
mode:'source',
|
|
792
800
|
workspaceRuntimeReceipt:prepared.workspaceRuntimeReceipt,
|
|
793
801
|
workspaceMode:prepared.workspaceMode,
|
|
802
|
+
...(options.sdkRuntimeSourceRoot===undefined?{}:{
|
|
803
|
+
sdkRuntimeSourceRoot:options.sdkRuntimeSourceRoot
|
|
804
|
+
}),
|
|
794
805
|
host:options.host,
|
|
795
806
|
port:options.port,
|
|
796
807
|
signal:options.signal,
|
|
@@ -543,7 +543,7 @@ export async function verifyWorkspaceRuntime({
|
|
|
543
543
|
sdkVersion:runtimeReceipt.sdkVersion,
|
|
544
544
|
sources:Object.freeze({
|
|
545
545
|
arcane:Object.freeze({
|
|
546
|
-
authority:'arcane-os-
|
|
546
|
+
authority:'arcane-os-sdk',
|
|
547
547
|
location:runtimeReceipt.canonicalLocation,
|
|
548
548
|
manifestSha256:runtimeReceipt.manifestSha256,
|
|
549
549
|
contentSha256:runtimeReceipt.contentSha256,
|