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 +7 -0
- package/README.md +7 -7
- package/bin/arcane-test.mjs +22 -10
- package/package.json +1 -1
- package/src/application-tests.mjs +7 -0
- package/src/import-map.mjs +49 -0
- package/src/toolchain.mjs +11 -1
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
package/bin/arcane-test.mjs
CHANGED
|
@@ -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
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
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(
|
|
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
|
@@ -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
|
package/src/import-map.mjs
CHANGED
|
@@ -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
|
});
|