arcane-os 0.1.0-dev.5 → 0.1.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.
Files changed (44) hide show
  1. package/NOTICE +10 -0
  2. package/browser-runtime/ARCANE_SDK_BROWSER_RELEASE.json +162 -0
  3. package/browser-runtime/ai/ARCANE_AI_BROWSER_WASM_COMPONENTS.json +69 -0
  4. package/browser-runtime/ai/browser-wasm-llm-provider.mjs +1151 -0
  5. package/browser-runtime/ai/browser-wasm.mjs +44 -0
  6. package/browser-runtime/ai/browser-wllama-runtime.mjs +390 -0
  7. package/browser-runtime/ai/internal/sha256.mjs +166 -0
  8. package/browser-runtime/ai/model-controller.mjs +581 -0
  9. package/browser-runtime/ai/wllama/LICENCE +21 -0
  10. package/browser-runtime/ai/wllama/index.mjs +3494 -0
  11. package/browser-runtime/ai/wllama/llama.cpp-LICENSE +21 -0
  12. package/browser-runtime/ai/wllama/wllama.wasm +0 -0
  13. package/browser-runtime/dependencies/event-pubsub/index.js +141 -0
  14. package/browser-runtime/dependencies/event-pubsub/licence +21 -0
  15. package/browser-runtime/dependencies/event-pubsub/package.json +59 -0
  16. package/browser-runtime/dependencies/strong-type/index.js +1151 -0
  17. package/browser-runtime/dependencies/strong-type/licence +21 -0
  18. package/browser-runtime/dependencies/strong-type/package.json +61 -0
  19. package/browser-runtime/dom-event-instrumentation.mjs +594 -0
  20. package/browser-runtime/event-manager.mjs +1342 -0
  21. package/docs/publishing.md +65 -67
  22. package/docs/reference/README.md +2 -1
  23. package/docs/reference/cli.md +86 -3
  24. package/docs/reference/event-manager.md +20 -11
  25. package/docs/reference/inventory/package-api.json +1 -1
  26. package/docs/reference/protocols.md +112 -14
  27. package/docs/reference/sdk-api.md +40 -11
  28. package/docs/work-amplification.md +4 -3
  29. package/package.json +15 -8
  30. package/runtime/ARCANE_RUNTIME_RELEASE.json +1 -1
  31. package/schemas/arcane-lock.schema.json +97 -1
  32. package/src/cli/main.mjs +5 -0
  33. package/src/dev-server.mjs +78 -34
  34. package/src/doctor.mjs +77 -3
  35. package/src/import-map.mjs +2352 -0
  36. package/src/packager/core.mjs +607 -29
  37. package/src/scaffold.mjs +122 -5
  38. package/src/sdk-browser-runtime.mjs +702 -0
  39. package/src/targets/index.mjs +31 -4
  40. package/src/templates/workspace-template.mjs +141 -23
  41. package/src/toolchain.mjs +288 -55
  42. package/src/workspace-operation-lock.mjs +716 -0
  43. package/src/workspace-runtime.mjs +841 -0
  44. package/src/workspace.mjs +292 -37
@@ -163,6 +163,8 @@ const browserAdapter=Object.freeze({
163
163
  dryRun=false,
164
164
  signal,
165
165
  onEvent,
166
+ workspaceOperationLease,
167
+ runtimeVerificationState,
166
168
  validateSourceState
167
169
  }={}){
168
170
  await this.plan({workspaceRoot,appId,format,signing,signal});
@@ -173,17 +175,42 @@ const browserAdapter=Object.freeze({
173
175
  dryRun,
174
176
  signal,
175
177
  onEvent,
178
+ workspaceOperationLease,
179
+ runtimeVerificationState,
176
180
  validateSourceState
177
181
  });
178
182
  return {target:'browser',format,signing,release};
179
183
  },
180
- async verify({workspaceRoot,appId,signal,onEvent}={}){
184
+ async verify({workspaceRoot,appId,runtimeVerificationState,signal,onEvent}={}){
181
185
  throwIfAborted(signal);
182
- return {target:'browser',release:await verifyApp({workspaceRoot,appId,signal,onEvent})};
186
+ return {
187
+ target:'browser',
188
+ release:await verifyApp({
189
+ workspaceRoot,
190
+ appId,
191
+ runtimeVerificationState,
192
+ signal,
193
+ onEvent
194
+ })
195
+ };
183
196
  },
184
- async run({workspaceRoot,appId,host='127.0.0.1',port=0,signal,onEvent}={}){
197
+ async run({
198
+ workspaceRoot,
199
+ appId,
200
+ runtimeVerificationState,
201
+ host='127.0.0.1',
202
+ port=0,
203
+ signal,
204
+ onEvent
205
+ }={}){
185
206
  throwIfAborted(signal);
186
- const verified=await verifyApp({workspaceRoot,appId,signal,onEvent});
207
+ const verified=await verifyApp({
208
+ workspaceRoot,
209
+ appId,
210
+ runtimeVerificationState,
211
+ signal,
212
+ onEvent
213
+ });
187
214
  const server=await startDevServer({
188
215
  workspaceRoot,
189
216
  appId,
@@ -1,4 +1,8 @@
1
1
  import {SDK_NAME,SDK_VERSION} from '../constants.mjs';
2
+ import {
3
+ SDK_BROWSER_RUNTIME_CONTENT_SHA256,
4
+ SDK_BROWSER_RUNTIME_MANIFEST_SHA256
5
+ } from '../sdk-browser-runtime.mjs';
2
6
 
3
7
  function json(value){
4
8
  return `${JSON.stringify(value,null,2)}\n`;
@@ -23,7 +27,9 @@ export function workspaceTemplate({
23
27
  appId,
24
28
  displayName,
25
29
  runtimeRelease,
30
+ sdkBrowserRuntimeRelease,
26
31
  appOnly=false,
32
+ namedImports=true,
27
33
  minimumCoreVersion='0.8.12',
28
34
  target='browser',
29
35
  appIcon
@@ -42,6 +48,29 @@ export function workspaceTemplate({
42
48
  const packageName=`arcane-${appId}`;
43
49
  const runtimeContentSha256=runtimeRelease?.contentSha256;
44
50
  const upstreamCommit=runtimeRelease?.source?.commit;
51
+ const browserManifestSha256=sdkBrowserRuntimeRelease?.manifestSha256;
52
+ const browserContentSha256=sdkBrowserRuntimeRelease?.contentSha256;
53
+ const browserSource=sdkBrowserRuntimeRelease?.source;
54
+ const expectedBrowserDependencies=[
55
+ {
56
+ name:'event-pubsub',
57
+ version:'6.1.0',
58
+ resolved:'https://registry.npmjs.org/event-pubsub/-/event-pubsub-6.1.0.tgz',
59
+ integrity:'sha512-FEMlhTxwqGM0hztTixG6FhVFXqp7Eq1ltk5mSreK6Mhy3xWWpLAzEUR6OMvMdNqT3jgSxA8JDhnhyAG3X4Xy7Q=='
60
+ },
61
+ {
62
+ name:'strong-type',
63
+ version:'2.0.0',
64
+ resolved:'https://registry.npmjs.org/strong-type/-/strong-type-2.0.0.tgz',
65
+ integrity:'sha512-HHrY9qYC7yn+5mlewiI3k9RQM9gZqGQsqbomZcd10Ks0h4RlX01nnkWbCe4AsVPCI6KaFvpkWm1nHMD+Ykup6g=='
66
+ },
67
+ {
68
+ name:'@wllama/wllama',
69
+ version:'3.6.0',
70
+ resolved:'https://registry.npmjs.org/@wllama/wllama/-/wllama-3.6.0.tgz',
71
+ integrity:'sha512-NN3ZBXqaaUwGXTQubkNvsCaLPjN2XVa0bVS40OYCE8zquYmRc2W3oHYEgwvuSWWDB8aUqTLyMioySCXNkcnD1w=='
72
+ }
73
+ ];
45
74
  const packageInclude=[`${appId}.css`,'index.html'];
46
75
  if(native)packageInclude.push('img/icon.png');
47
76
  packageInclude.push('manifest.json','modules');
@@ -72,7 +101,36 @@ appropriate.
72
101
  if(!appOnly&&(typeof upstreamCommit!=='string'||!/^[a-f0-9]{40}$/.test(upstreamCommit))){
73
102
  throw new Error('The SDK runtime release does not contain a valid upstream commit.');
74
103
  }
104
+ if(!appOnly&&(
105
+ browserManifestSha256!==SDK_BROWSER_RUNTIME_MANIFEST_SHA256
106
+ ||browserContentSha256!==SDK_BROWSER_RUNTIME_CONTENT_SHA256
107
+ ||sdkBrowserRuntimeRelease?.builder!=='arcane-sdk-browser-runtime-v1'
108
+ ||sdkBrowserRuntimeRelease?.sdkVersion!==SDK_VERSION
109
+ ||browserSource?.protocol!=='arcane-sdk-browser-runtime/1'
110
+ ||browserSource?.authority!=='arcane-os-sdk'
111
+ ||browserSource?.repository!=='https://github.com/TheWizardNexus/arcane-os-sdk.git'
112
+ ||browserSource?.browserEntry!=='arcane-os/event-manager'
113
+ ||!Array.isArray(browserSource?.dependencies)
114
+ ||browserSource.dependencies.length!==expectedBrowserDependencies.length
115
+ ||browserSource.dependencies.some((actual,index)=>{
116
+ const expected=expectedBrowserDependencies[index];
117
+ return !actual||Object.keys(actual).sort().join('\0')
118
+ !==['name','version','resolved','integrity'].sort().join('\0')
119
+ ||actual.name!==expected.name||actual.version!==expected.version
120
+ ||actual.resolved!==expected.resolved||actual.integrity!==expected.integrity;
121
+ })
122
+ )){
123
+ throw new Error('The SDK browser runtime release does not contain a valid trusted identity.');
124
+ }
75
125
 
126
+ const importMapMarkup=namedImports?` <script type="importmap" data-arcane-import-map>
127
+ {
128
+ "imports": {}
129
+ }
130
+ </script>
131
+ `:'';
132
+ const bootstrapMarkup=namedImports?'':
133
+ ' <script type="module" src="./arcane/modules/ThemeBootstrap.js?v=1"></script>\n';
76
134
  const files=new Map();
77
135
  files.set('.gitignore',[
78
136
  'node_modules/',
@@ -96,7 +154,7 @@ appropriate.
96
154
 
97
155
  - Use plain JavaScript, HTML, and CSS; do not introduce TypeScript or TSX.
98
156
  - Keep reusable mechanisms in Arcane OS and app-specific behavior under \`apps/${appId}/\`.
99
- - Keep \`arcane/css/theme.css\` and \`ThemeBootstrap.js\` loaded before app styles and modules.
157
+ - Keep \`arcane/css/theme.css\` before app styles and import \`arcane/ThemeBootstrap\` before app code runs.
100
158
  - Use \`rgb(...)\` or \`rgba(...)\` for new CSS colors.
101
159
  - Build one named app and one explicit target at a time. Native targets may be unavailable until their adapters are installed.
102
160
  - Run \`npm run check\` before committing.
@@ -113,20 +171,32 @@ npm run doctor
113
171
  npm run dev
114
172
  \`\`\`
115
173
 
116
- Open the loopback URL printed by the development server. The source server exposes this app and the SDK's browser runtime; it does not expose an Ollama HTTP endpoint.
174
+ Open the loopback URL printed by the development server. The source server exposes this app and its authenticated physical \`arcane/\` runtime; it does not expose an Ollama HTTP endpoint.
117
175
 
118
176
  Commit the generated \`package-lock.json\` after dependency installation. CI intentionally uses \`npm ci\` and therefore requires that lock. Before the SDK is published, install a locally packed \`${SDK_NAME}\` \`.tgz\` with \`npm install --save-dev --save-exact <path-to-tarball>\`; keep that tarball at the lock file's relative path for repeatable local \`npm ci\` runs.
119
177
 
120
- ## Check and package
178
+ ## Check and release the browser package
121
179
 
122
180
  \`\`\`sh
123
181
  npm run check
182
+ npm run import-map
124
183
  npm run package
184
+ npm run verify
185
+ npm run bundle
125
186
  npm run run
126
187
  \`\`\`
127
188
 
128
- The browser release is written to \`dist/${appId}\`. Native providers accept only
129
- explicit targets and fail honestly when their platform toolchain is unavailable.
189
+ The explicit \`import-map\` command refreshes
190
+ \`apps/${appId}/modules/arcane.importmap.json\` and the managed inline browser
191
+ import map in \`index.html\`. Development, package, and build refresh it
192
+ automatically. Named \`arcane/*\` imports resolve against the physical workspace
193
+ \`arcane/\` tree. Packaging copies the same authenticated bytes and specifier map
194
+ to \`dist/${appId}\`, \`verify\` authenticates that directory, \`bundle\` creates
195
+ its distributable archive, and \`run\` launches the verified packaged browser
196
+ release.
197
+
198
+ Native targets are provider-supplied and must be scaffolded and selected
199
+ explicitly; this browser workflow does not imply a standalone native executable.
130
200
  ${nativeGuide}
131
201
 
132
202
  Every browser release also carries Arcane OS licensing material under \`licenses/arcane-os/\`. Review those terms before distribution.
@@ -140,11 +210,16 @@ Every browser release also carries Arcane OS licensing material under \`licenses
140
210
  dev:'arcane dev',
141
211
  test:'arcane test',
142
212
  check:'arcane check',
213
+ 'import-map':'arcane import-map',
143
214
  package:'arcane package',
215
+ verify:'arcane verify',
216
+ bundle:'arcane bundle',
144
217
  build:`arcane build --target ${buildTarget}`,
145
218
  run:`arcane run --target ${runTarget}`,
146
- 'build:browser':'arcane build --target browser',
147
- 'run:browser':'arcane run --target browser'
219
+ ...(native?{
220
+ 'build:browser':'arcane build --target browser',
221
+ 'run:browser':'arcane run --target browser'
222
+ }:{})
148
223
  },
149
224
  devDependencies:{
150
225
  [SDK_NAME]:SDK_VERSION
@@ -158,15 +233,9 @@ Every browser release also carries Arcane OS licensing material under \`licenses
158
233
  sharedPayloads:{
159
234
  'browser-runtime':[
160
235
  {
161
- source:'node_modules/arcane-os/runtime/arcane',
236
+ source:'arcane',
162
237
  destination:'arcane',
163
- include:['components','css','entities','img','modules','security'],
164
- exclude:[]
165
- },
166
- {
167
- source:'node_modules/arcane-os/runtime/strong-type',
168
- destination:'node_modules/strong-type',
169
- include:['index.js','licence','package.json'],
238
+ include:['components','css','dependencies','entities','img','modules','sdk','security'],
170
239
  exclude:[]
171
240
  },
172
241
  {
@@ -186,6 +255,14 @@ Every browser release also carries Arcane OS licensing material under \`licenses
186
255
  contentSha256:runtimeContentSha256,
187
256
  upstreamCommit
188
257
  },
258
+ sdkBrowserRuntime:{
259
+ manifest:'node_modules/arcane-os/browser-runtime/ARCANE_SDK_BROWSER_RELEASE.json',
260
+ manifestSha256:browserManifestSha256,
261
+ contentSha256:browserContentSha256,
262
+ builder:sdkBrowserRuntimeRelease?.builder,
263
+ sdkVersion:sdkBrowserRuntimeRelease?.sdkVersion,
264
+ source:sdkBrowserRuntimeRelease?.source
265
+ },
189
266
  protocols:{
190
267
  arcane:'arcane/1',
191
268
  cliEvents:'arcane-cli-events/1',
@@ -288,15 +365,14 @@ jobs:
288
365
  <meta charset="utf-8">
289
366
  <meta name="arcane-app-id" content="${html(appId)}">
290
367
  <base href="../../">
291
- <meta name="viewport" content="width=device-width, initial-scale=1">
368
+ ${importMapMarkup} <meta name="viewport" content="width=device-width, initial-scale=1">
292
369
  <meta name="theme-color" content="rgb(23, 34, 56)">
293
370
  <title>${html(name)}</title>
294
371
  <link rel="manifest" href="./apps/${html(appId)}/manifest.json">
295
372
  <link rel="stylesheet" href="./arcane/css/theme.css?v=1">
296
373
  <link rel="stylesheet" href="./arcane/css/primitives.css?v=1">
297
374
  <link rel="stylesheet" href="./apps/${html(appId)}/${html(appId)}.css?v=1">
298
- <script type="module" src="./arcane/modules/ThemeBootstrap.js?v=1"></script>
299
- </head>
375
+ ${bootstrapMarkup}</head>
300
376
  <body>
301
377
  <main class="app-shell">
302
378
  <section class="arcane-card" aria-labelledby="app-title">
@@ -337,12 +413,49 @@ jobs:
337
413
  text-transform: uppercase;
338
414
  }
339
415
  `);
340
- files.set(`apps/${appId}/modules/App.js`,`const appName=${JSON.stringify(name)};
416
+ if(namedImports){
417
+ files.set(`apps/${appId}/modules/arcane.importmap.json`,json({imports:{}}));
418
+ }
419
+ const themeSpecifier=namedImports
420
+ ?'arcane/ThemeBootstrap':'../../../arcane/modules/ThemeBootstrap.js';
421
+ const appDataSpecifier=namedImports
422
+ ?'arcane/AppDataScope':'../../../arcane/modules/AppDataScope.js';
423
+ files.set(`apps/${appId}/modules/App.js`,`import arcaneThemeReady from '${themeSpecifier}';
424
+ import {
425
+ resolveApplicationId,
426
+ resolveApplicationLocalStorageKey
427
+ } from '${appDataSpecifier}';
428
+
429
+ const appName=${JSON.stringify(name)};
341
430
  const action=document.querySelector('#app-action');
342
431
  const status=document.querySelector('#app-status');
343
432
 
433
+ await arcaneThemeReady;
434
+
435
+ const appId=await resolveApplicationId();
436
+ const countKey=resolveApplicationLocalStorageKey('hello-count',{applicationId:appId});
437
+
438
+ function loadHelloCount(){
439
+ try{
440
+ const value=Number(globalThis.localStorage?.getItem(countKey)??0);
441
+ return Number.isSafeInteger(value)&&value>=0?value:0;
442
+ }catch{
443
+ return 0;
444
+ }
445
+ }
446
+
447
+ function saveHelloCount(value){
448
+ try{
449
+ globalThis.localStorage?.setItem(countKey,String(value));
450
+ }catch{
451
+ // The greeting still works when browser persistence is unavailable.
452
+ }
453
+ }
454
+
344
455
  action?.addEventListener('click',()=>{
345
- status.textContent=\`The \${appName} app is working.\`;
456
+ const count=loadHelloCount()+1;
457
+ saveHelloCount(count);
458
+ status.textContent=\`Hello from \${appName}! Greeting \${count}.\`;
346
459
  });
347
460
  `);
348
461
  if(native){
@@ -355,17 +468,22 @@ import test from '${SDK_NAME}/testing';
355
468
  const appRoot=new URL('../',import.meta.url);
356
469
 
357
470
  test('application shell uses the shared Arcane theme in order',async()=>{
358
- const source=await readFile(new URL('index.html',appRoot),'utf8');
471
+ const [source,appSource]=await Promise.all([
472
+ readFile(new URL('index.html',appRoot),'utf8'),
473
+ readFile(new URL('modules/App.js',appRoot),'utf8')
474
+ ]);
359
475
  const theme=source.indexOf('./arcane/css/theme.css');
360
476
  const primitives=source.indexOf('./arcane/css/primitives.css');
361
477
  const appStyle=source.indexOf('./apps/${appId}/${appId}.css');
362
- const bootstrap=source.indexOf('./arcane/modules/ThemeBootstrap.js');
478
+ const importMap=source.indexOf('${namedImports?'data-arcane-import-map':'./arcane/modules/ThemeBootstrap.js'}');
363
479
  const appModule=source.indexOf('./apps/${appId}/modules/App.js');
364
480
 
365
481
  assert.match(source,/<base href="\\.\\.\\/\\.\\.\\/">/);
366
482
  assert.match(source,/<meta name="arcane-app-id" content="${appId}">/);
367
483
  assert.ok(theme>=0&&primitives>theme&&appStyle>primitives);
368
- assert.ok(bootstrap>appStyle&&appModule>bootstrap);
484
+ assert.ok(importMap>=0&&appModule>importMap);
485
+ assert.ok(appSource.includes("from '${themeSpecifier}'"));
486
+ assert.ok(appSource.includes("from '${appDataSpecifier}'"));
369
487
  });
370
488
 
371
489
  test('application package identity matches its directory',async()=>{