arcane-os 0.5.1 → 0.5.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 CHANGED
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.5.2
4
+
5
+ - Forwarded each application's existing managed browser import map into
6
+ isolated `arcane test` and `arcane check` files so valid `arcane/*` imports
7
+ resolve from the selected workspace runtime while integrated-legacy apps
8
+ retain their established no-map path.
9
+
3
10
  ## 0.5.1
4
11
 
5
12
  - Separated the TWiN Cloud LLM access key from the legacy OpenAI speech
package/README.md CHANGED
@@ -19,7 +19,7 @@ version-locked SDK runtime, while an integrated Arcane checkout uses its live
19
19
  `arcane/` runtime. Both profiles preserve the same app URLs, theme, packaging,
20
20
  event, cancellation, and browser run contracts.
21
21
 
22
- This checkout defines the `0.5.1` SDK contract. Applications pin one exact npm
22
+ This checkout defines the `0.5.2` SDK contract. Applications pin one exact npm
23
23
  version and lockfile; registry state is deliberately not baked into application
24
24
  artifacts.
25
25
 
@@ -165,7 +165,7 @@ uses the same controller for automatic memory extraction.
165
165
  Create a new repository-shaped Arcane application with the exact stable SDK:
166
166
 
167
167
  ```bash
168
- npx arcane-os@0.5.1 new my-app --path ./my-app --target portable --git
168
+ npx arcane-os@0.5.2 new my-app --path ./my-app --target portable --git
169
169
  cd my-app
170
170
  npm install
171
171
  npm run check
@@ -176,7 +176,7 @@ To enroll an existing repository, install the exact SDK and initialize only
176
176
  missing Arcane files:
177
177
 
178
178
  ```bash
179
- npm install --save-dev --save-exact arcane-os@0.5.1
179
+ npm install --save-dev --save-exact arcane-os@0.5.2
180
180
  npm exec -- arcane init my-app --target portable
181
181
  ```
182
182
 
@@ -192,7 +192,7 @@ npm exec -- arcane-os targets
192
192
  No global SDK install or standalone Arcane CLI is required. The application
193
193
  repository's exact npm dependency and lockfile own the CLI and toolchain version.
194
194
 
195
- Use `npx arcane-os@0.5.1` for the initial bootstrap because it names this npm
195
+ Use `npx arcane-os@0.5.2` for the initial bootstrap because it names this npm
196
196
  package explicitly; bare `npx arcane` outside an installed project could resolve
197
197
  a different package. Both installed commands invoke the same headless toolchain.
198
198
  Project-local npm scripts use the SDK pinned by that app's `package-lock.json`,
@@ -213,7 +213,7 @@ node ./bin/arcane.mjs new local-app --path ../local-app --target portable --git
213
213
 
214
214
  # From the generated app repository
215
215
  cd ../local-app
216
- npm install --save-dev --save-exact ../arcane-os-sdk/arcane-os-0.5.1.tgz
216
+ npm install --save-dev --save-exact ../arcane-os-sdk/arcane-os-0.5.2.tgz
217
217
  npm run check
218
218
  npm ci
219
219
  ```
@@ -223,7 +223,7 @@ same location. The lockfile retains the selected package dependency while
223
223
  Arcane uses the installed package name and version. Local directory `file:` dependencies are not
224
224
  accepted because npm may install them as links; use a packed `.tgz`. A GitHub
225
225
  runner also needs that tarball at the locked path. After publication, replace
226
- the local declaration with the exact `arcane-os@0.5.1` registry package and
226
+ the local declaration with the exact `arcane-os@0.5.2` registry package and
227
227
  commit the regenerated lock.
228
228
 
229
229
  Generated repositories use `npm ci --ignore-scripts` in CI. Run dependency
@@ -361,7 +361,7 @@ package installation, or assertions.
361
361
 
362
362
  ## Current target support
363
363
 
364
- Version `0.5.1` exposes one browser target and five explicitly paired
364
+ Version `0.5.2` exposes one browser target and five explicitly paired
365
365
  native development targets: a non-runnable portable directory, a
366
366
  Windows x64 unsigned-local-test EXE bundle, Linux x64 and Linux ARM64
367
367
  unsigned-local-test DEBs, and an Android development-signed APK. The
@@ -81,18 +81,30 @@ async function readManagedImportMapContext(source,signal,testFile){
81
81
  :context.boundary==='test'
82
82
  ?testCodeRoot
83
83
  :path.join(applicationRoot,'dist');
84
- let baseInfo;
85
- let canonicalBase;
86
- try{
87
- baseInfo=await lstat(expectedBase);
88
- canonicalBase=await realpath(expectedBase);
89
- }catch(error){
90
- importMapFailure(`Selected ${context.boundary} application directory is unavailable: ${error.message}`);
84
+ const workspaceRoot=path.resolve(process.cwd());
85
+ const requestedBases=context.boundary==='source'&&pathInside(workspaceRoot,applicationRoot)
86
+ ?[expectedBase,workspaceRoot]
87
+ :[expectedBase];
88
+ let canonicalBase=null;
89
+ for(const requestedBase of requestedBases){
90
+ let baseInfo;
91
+ let candidate;
92
+ try{
93
+ baseInfo=await lstat(requestedBase);
94
+ candidate=await realpath(requestedBase);
95
+ }catch{
96
+ continue;
97
+ }
98
+ if(!baseInfo.isSymbolicLink()&&baseInfo.isDirectory()
99
+ &&samePath(requestedBase,candidate)&&samePath(suppliedBase,candidate)){
100
+ canonicalBase=candidate;
101
+ break;
102
+ }
91
103
  }
92
- if(baseInfo.isSymbolicLink()||!baseInfo.isDirectory()
93
- ||!samePath(expectedBase,canonicalBase)||!samePath(suppliedBase,canonicalBase)){
104
+ if(canonicalBase===null){
94
105
  importMapFailure(
95
- `Managed import-map base URL must select this application's physical ${context.boundary} directory.`
106
+ `Managed import-map base URL must select this application's physical ${context.boundary} directory`
107
+ +(context.boundary==='source'?' or its physical workspace source directory.':'.')
96
108
  );
97
109
  }
98
110
  throwIfCancelled(signal);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "arcane-os",
3
- "version": "0.5.1",
3
+ "version": "0.5.2",
4
4
  "description": "Arcane OS JavaScript SDK, project-local CLI, browser runtime, and repository-portable application packager.",
5
5
  "type": "module",
6
6
  "main": "./src/index.mjs",
@@ -5,6 +5,7 @@ import {ArcaneError,ERROR_CODES,throwIfAborted} from './errors.mjs';
5
5
  import {runProcess} from './process.mjs';
6
6
 
7
7
  const TEST_RUNNER_PATH=fileURLToPath(new URL('../bin/arcane-test.mjs',import.meta.url));
8
+ const MANAGED_IMPORT_MAP_ENV='ARCANE_TEST_IMPORT_MAP_CONTEXT';
8
9
 
9
10
  function normalizedTestOutput(value){
10
11
  return typeof value==='string'?value:'';
@@ -129,6 +130,7 @@ export async function runApplicationTests({
129
130
  workspaceMode='packager',
130
131
  appId,
131
132
  appRoot,
133
+ managedImportMapContext=null,
132
134
  signal,
133
135
  onEvent
134
136
  }={}){
@@ -160,6 +162,11 @@ export async function runApplicationTests({
160
162
  [TEST_RUNNER_PATH,testFile],
161
163
  {
162
164
  cwd:workspaceRoot,
165
+ env:{
166
+ [MANAGED_IMPORT_MAP_ENV]:managedImportMapContext===null
167
+ ?''
168
+ :JSON.stringify(managedImportMapContext)
169
+ },
163
170
  signal,
164
171
  onEvent,
165
172
  allowNonzero:true
@@ -1602,6 +1602,55 @@ export async function createApplicationTestImportMapContext({
1602
1602
  };
1603
1603
  }
1604
1604
 
1605
+ export async function readApplicationTestImportMapContext({
1606
+ workspaceRoot,
1607
+ applicationRoot,
1608
+ signal
1609
+ }={}){
1610
+ if(typeof workspaceRoot!=='string'||workspaceRoot.trim()===''){
1611
+ throw new TypeError('workspaceRoot must be a nonempty string.');
1612
+ }
1613
+ if(typeof applicationRoot!=='string'||applicationRoot.trim()===''){
1614
+ throw new TypeError('applicationRoot must be a nonempty string.');
1615
+ }
1616
+ throwIfAborted(signal);
1617
+ const resolvedWorkspaceRoot=path.resolve(workspaceRoot);
1618
+ const resolvedApplicationRoot=path.resolve(applicationRoot);
1619
+ await physicalDirectory(resolvedWorkspaceRoot,resolvedApplicationRoot);
1620
+ const artifactPath=path.join(
1621
+ resolvedApplicationRoot,
1622
+ ...IMPORT_MAP_RELATIVE_PATH.split('/')
1623
+ );
1624
+ let source;
1625
+ try{
1626
+ source=await readPhysicalTextFile(
1627
+ resolvedApplicationRoot,
1628
+ artifactPath,
1629
+ 'Application test import-map artifact'
1630
+ );
1631
+ }catch(error){
1632
+ if(error?.code==='ENOENT')return null;
1633
+ throw error;
1634
+ }
1635
+ throwIfAborted(signal);
1636
+ let document;
1637
+ try{document=JSON.parse(source);}
1638
+ catch(error){
1639
+ fail(`Application test import-map artifact is not valid JSON: ${error.message}`);
1640
+ }
1641
+ if(document===null||typeof document!=='object'||Array.isArray(document)
1642
+ ||document.imports===null||typeof document.imports!=='object'
1643
+ ||Array.isArray(document.imports)){
1644
+ fail('Application test import-map artifact must contain an imports object.');
1645
+ }
1646
+ return createApplicationTestImportMapContext({
1647
+ applicationRoot:resolvedWorkspaceRoot,
1648
+ boundary:'source',
1649
+ imports:document.imports,
1650
+ signal
1651
+ });
1652
+ }
1653
+
1605
1654
  async function generateImportMapUnlocked({
1606
1655
  workspaceRoot,
1607
1656
  appId,
package/src/toolchain.mjs CHANGED
@@ -10,7 +10,7 @@ import {
10
10
  } from './workspace.mjs';
11
11
  import {loadArcaneIntegratedProvider} from './integrated-provider-loader.mjs';
12
12
  import {startDevServer} from './dev-server.mjs';
13
- import {generateImportMap} from './import-map.mjs';
13
+ import {generateImportMap,readApplicationTestImportMapContext} from './import-map.mjs';
14
14
  import {withWorkspaceOperationLock} from './workspace-operation-lock.mjs';
15
15
  import {
16
16
  inspectApp as inspectPackagedApp,
@@ -389,11 +389,21 @@ export async function doctorApplication(options={}){
389
389
 
390
390
  async function runPreparedApplicationTests(prepared,options={}){
391
391
  throwIfAborted(options.signal);
392
+ const integratedLegacy=prepared.workspaceMode==='integrated'
393
+ &&prepared.validation.config.browserRuntimeLayout==='integrated-legacy';
394
+ const managedImportMapContext=integratedLegacy
395
+ ?null
396
+ :await readApplicationTestImportMapContext({
397
+ workspaceRoot:prepared.workspaceRoot,
398
+ applicationRoot:prepared.appRoot,
399
+ signal:options.signal
400
+ });
392
401
  return runApplicationTests({
393
402
  workspaceRoot:prepared.workspaceRoot,
394
403
  workspaceMode:prepared.workspaceMode,
395
404
  appId:prepared.appId,
396
405
  appRoot:prepared.appRoot,
406
+ managedImportMapContext,
397
407
  signal:options.signal,
398
408
  onEvent:options.onEvent
399
409
  });