@jskit-ai/jskit-cli 0.2.23 → 0.2.25
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jskit-ai/jskit-cli",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.25",
|
|
4
4
|
"description": "Bundle and package orchestration CLI for JSKIT apps.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"test": "node --test"
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@jskit-ai/jskit-catalog": "0.1.
|
|
23
|
+
"@jskit-ai/jskit-catalog": "0.1.25"
|
|
24
24
|
},
|
|
25
25
|
"engines": {
|
|
26
26
|
"node": "20.x"
|
package/src/server/argParser.js
CHANGED
|
@@ -4,6 +4,7 @@ const KNOWN_COMMANDS = new Set([
|
|
|
4
4
|
"list",
|
|
5
5
|
"show",
|
|
6
6
|
"view",
|
|
7
|
+
"migrations",
|
|
7
8
|
"add",
|
|
8
9
|
"position",
|
|
9
10
|
"update",
|
|
@@ -165,6 +166,7 @@ function printUsage(stream = process.stderr) {
|
|
|
165
166
|
stream.write(" position element <packageId> Re-apply positioning mutations for one installed package\n");
|
|
166
167
|
stream.write(" show <id> Show details for bundle id or package id\n");
|
|
167
168
|
stream.write(" view <id> Alias of show <id>\n");
|
|
169
|
+
stream.write(" migrations <scope> Generate managed migrations only (scope: all | changed | package <packageId>)\n");
|
|
168
170
|
stream.write(" update package <packageId> Re-apply one installed package\n");
|
|
169
171
|
stream.write(" remove package <packageId> Remove one installed package\n");
|
|
170
172
|
stream.write(" doctor Validate lockfile + managed files\n");
|
package/src/server/cliRuntime.js
CHANGED
|
@@ -4298,6 +4298,79 @@ async function applyPackagePositioning({
|
|
|
4298
4298
|
return managedRecord;
|
|
4299
4299
|
}
|
|
4300
4300
|
|
|
4301
|
+
async function applyPackageMigrationsOnly({
|
|
4302
|
+
packageEntry,
|
|
4303
|
+
packageOptions,
|
|
4304
|
+
appRoot,
|
|
4305
|
+
lock,
|
|
4306
|
+
touchedFiles
|
|
4307
|
+
}) {
|
|
4308
|
+
const existingInstall = ensureObject(lock.installedPackages[packageEntry.packageId]);
|
|
4309
|
+
if (Object.keys(existingInstall).length < 1) {
|
|
4310
|
+
throw createCliError(`Package is not installed: ${packageEntry.packageId}`);
|
|
4311
|
+
}
|
|
4312
|
+
|
|
4313
|
+
const existingManaged = ensureObject(existingInstall.managed);
|
|
4314
|
+
const existingPackageJsonManaged = ensureObject(existingManaged.packageJson);
|
|
4315
|
+
const nextManaged = {
|
|
4316
|
+
packageJson: {
|
|
4317
|
+
dependencies: cloneManagedMap(existingPackageJsonManaged.dependencies),
|
|
4318
|
+
devDependencies: cloneManagedMap(existingPackageJsonManaged.devDependencies),
|
|
4319
|
+
scripts: cloneManagedMap(existingPackageJsonManaged.scripts)
|
|
4320
|
+
},
|
|
4321
|
+
text: cloneManagedMap(existingManaged.text),
|
|
4322
|
+
vite: cloneManagedMap(existingManaged.vite),
|
|
4323
|
+
files: cloneManagedArray(existingManaged.files),
|
|
4324
|
+
migrations: cloneManagedArray(existingManaged.migrations)
|
|
4325
|
+
};
|
|
4326
|
+
|
|
4327
|
+
const templateRoot = await resolvePackageTemplateRoot({ packageEntry, appRoot });
|
|
4328
|
+
const packageEntryForMutations =
|
|
4329
|
+
templateRoot === packageEntry.rootDir
|
|
4330
|
+
? packageEntry
|
|
4331
|
+
: {
|
|
4332
|
+
...packageEntry,
|
|
4333
|
+
rootDir: templateRoot
|
|
4334
|
+
};
|
|
4335
|
+
const mutations = ensureObject(packageEntry.descriptor.mutations);
|
|
4336
|
+
const migrationFileMutations = ensureArray(mutations.files).filter((mutationValue) => {
|
|
4337
|
+
const normalized = normalizeFileMutationRecord(mutationValue);
|
|
4338
|
+
const operation = String(normalized.op || "copy-file").trim();
|
|
4339
|
+
return operation === "install-migration";
|
|
4340
|
+
});
|
|
4341
|
+
const mutationWarnings = [];
|
|
4342
|
+
|
|
4343
|
+
if (migrationFileMutations.length > 0) {
|
|
4344
|
+
await applyFileMutations(
|
|
4345
|
+
packageEntryForMutations,
|
|
4346
|
+
packageOptions,
|
|
4347
|
+
appRoot,
|
|
4348
|
+
migrationFileMutations,
|
|
4349
|
+
[],
|
|
4350
|
+
nextManaged.migrations,
|
|
4351
|
+
touchedFiles,
|
|
4352
|
+
mutationWarnings
|
|
4353
|
+
);
|
|
4354
|
+
}
|
|
4355
|
+
|
|
4356
|
+
const managedRecord = {
|
|
4357
|
+
...existingInstall,
|
|
4358
|
+
packageId: packageEntry.packageId,
|
|
4359
|
+
source: resolveManagedSourceRecord(packageEntry, existingInstall),
|
|
4360
|
+
managed: nextManaged,
|
|
4361
|
+
options: {
|
|
4362
|
+
...ensureObject(packageOptions)
|
|
4363
|
+
},
|
|
4364
|
+
migrationSyncVersion: packageEntry.version,
|
|
4365
|
+
installedAt: String(existingInstall.installedAt || new Date().toISOString())
|
|
4366
|
+
};
|
|
4367
|
+
lock.installedPackages[packageEntry.packageId] = managedRecord;
|
|
4368
|
+
if (mutationWarnings.length > 0) {
|
|
4369
|
+
managedRecord.warnings = mutationWarnings;
|
|
4370
|
+
}
|
|
4371
|
+
return managedRecord;
|
|
4372
|
+
}
|
|
4373
|
+
|
|
4301
4374
|
async function applyPackageInstall({
|
|
4302
4375
|
packageEntry,
|
|
4303
4376
|
packageOptions,
|
|
@@ -4462,6 +4535,7 @@ async function applyPackageInstall({
|
|
|
4462
4535
|
if (cloneOnlyPackage) {
|
|
4463
4536
|
delete lock.installedPackages[packageEntry.packageId];
|
|
4464
4537
|
} else {
|
|
4538
|
+
managedRecord.migrationSyncVersion = packageEntry.version;
|
|
4465
4539
|
lock.installedPackages[packageEntry.packageId] = managedRecord;
|
|
4466
4540
|
}
|
|
4467
4541
|
if (mutationWarnings.length > 0) {
|
|
@@ -4522,6 +4596,7 @@ const commandHandlers = createCommandHandlers(
|
|
|
4522
4596
|
validatePlannedCapabilityClosure,
|
|
4523
4597
|
resolvePackageOptions,
|
|
4524
4598
|
applyPackageInstall,
|
|
4599
|
+
applyPackageMigrationsOnly,
|
|
4525
4600
|
applyPackagePositioning,
|
|
4526
4601
|
adoptAppLocalPackageDependencies,
|
|
4527
4602
|
loadAppPackageJson,
|
|
@@ -28,6 +28,7 @@ function createCommandHandlers(deps) {
|
|
|
28
28
|
validatePlannedCapabilityClosure,
|
|
29
29
|
resolvePackageOptions,
|
|
30
30
|
applyPackageInstall,
|
|
31
|
+
applyPackageMigrationsOnly,
|
|
31
32
|
applyPackagePositioning,
|
|
32
33
|
adoptAppLocalPackageDependencies,
|
|
33
34
|
loadAppPackageJson,
|
|
@@ -1336,6 +1337,138 @@ function createCommandHandlers(deps) {
|
|
|
1336
1337
|
});
|
|
1337
1338
|
}
|
|
1338
1339
|
|
|
1340
|
+
async function commandMigrations({ positional, options, cwd, io }) {
|
|
1341
|
+
const scope = String(positional[0] || "").trim().toLowerCase();
|
|
1342
|
+
const targetId = String(positional[1] || "").trim();
|
|
1343
|
+
if (!scope || (scope !== "all" && scope !== "changed" && scope !== "package")) {
|
|
1344
|
+
throw createCliError("migrations requires: migrations <all|changed|package <packageId>>", {
|
|
1345
|
+
showUsage: true
|
|
1346
|
+
});
|
|
1347
|
+
}
|
|
1348
|
+
if (scope === "package" && !targetId) {
|
|
1349
|
+
throw createCliError("migrations package requires a package id.", {
|
|
1350
|
+
showUsage: true
|
|
1351
|
+
});
|
|
1352
|
+
}
|
|
1353
|
+
if (scope !== "package" && Object.keys(ensureObject(options.inlineOptions)).length > 0) {
|
|
1354
|
+
throw createCliError("Inline options are only supported with: migrations package <packageId>.");
|
|
1355
|
+
}
|
|
1356
|
+
|
|
1357
|
+
const appRoot = await resolveAppRootFromCwd(cwd);
|
|
1358
|
+
const packageRegistry = await loadPackageRegistry();
|
|
1359
|
+
const appLocalRegistry = await loadAppLocalPackageRegistry(appRoot);
|
|
1360
|
+
const combinedPackageRegistry = mergePackageRegistries(packageRegistry, appLocalRegistry);
|
|
1361
|
+
const { lockPath, lock } = await loadLockFile(appRoot);
|
|
1362
|
+
const installedPackages = ensureObject(lock.installedPackages);
|
|
1363
|
+
const installedPackageIds = sortStrings(Object.keys(installedPackages));
|
|
1364
|
+
await hydratePackageRegistryFromInstalledNodeModules({
|
|
1365
|
+
appRoot,
|
|
1366
|
+
packageRegistry: combinedPackageRegistry,
|
|
1367
|
+
seedPackageIds: installedPackageIds
|
|
1368
|
+
});
|
|
1369
|
+
|
|
1370
|
+
let requestedPackageIds = [];
|
|
1371
|
+
if (scope === "all") {
|
|
1372
|
+
requestedPackageIds = installedPackageIds;
|
|
1373
|
+
} else if (scope === "package") {
|
|
1374
|
+
const resolvedTargetId = resolveInstalledPackageIdInput(targetId, installedPackages);
|
|
1375
|
+
if (!resolvedTargetId) {
|
|
1376
|
+
throw createCliError(`Package is not installed: ${targetId}`);
|
|
1377
|
+
}
|
|
1378
|
+
requestedPackageIds = [resolvedTargetId];
|
|
1379
|
+
} else {
|
|
1380
|
+
requestedPackageIds = installedPackageIds.filter((packageId) => {
|
|
1381
|
+
const packageEntry = combinedPackageRegistry.get(packageId);
|
|
1382
|
+
if (!packageEntry) {
|
|
1383
|
+
return true;
|
|
1384
|
+
}
|
|
1385
|
+
const lockEntry = ensureObject(installedPackages[packageId]);
|
|
1386
|
+
const migrationSyncVersion = String(lockEntry.migrationSyncVersion || "").trim();
|
|
1387
|
+
return migrationSyncVersion !== String(packageEntry.version || "").trim();
|
|
1388
|
+
});
|
|
1389
|
+
}
|
|
1390
|
+
|
|
1391
|
+
const touchedFiles = new Set();
|
|
1392
|
+
const migratedRecords = [];
|
|
1393
|
+
const migrationWarnings = [];
|
|
1394
|
+
for (const packageId of requestedPackageIds) {
|
|
1395
|
+
const packageEntry = combinedPackageRegistry.get(packageId);
|
|
1396
|
+
if (!packageEntry) {
|
|
1397
|
+
throw createCliError(
|
|
1398
|
+
`Installed package descriptor not found: ${packageId}. Ensure it is available in catalog, app packages/, or node_modules.`
|
|
1399
|
+
);
|
|
1400
|
+
}
|
|
1401
|
+
validateInlineOptionsForPackage(packageEntry, options.inlineOptions);
|
|
1402
|
+
const installedRecord = ensureObject(installedPackages[packageId]);
|
|
1403
|
+
const mergedInlineOptions = scope === "package" ? ensureObject(options.inlineOptions) : {};
|
|
1404
|
+
const resolvedOptions = await resolvePackageOptions(
|
|
1405
|
+
packageEntry,
|
|
1406
|
+
{
|
|
1407
|
+
...ensureObject(installedRecord.options),
|
|
1408
|
+
...mergedInlineOptions
|
|
1409
|
+
},
|
|
1410
|
+
io,
|
|
1411
|
+
{ appRoot }
|
|
1412
|
+
);
|
|
1413
|
+
|
|
1414
|
+
const managedRecord = await applyPackageMigrationsOnly({
|
|
1415
|
+
packageEntry,
|
|
1416
|
+
packageOptions: resolvedOptions,
|
|
1417
|
+
appRoot,
|
|
1418
|
+
lock,
|
|
1419
|
+
touchedFiles
|
|
1420
|
+
});
|
|
1421
|
+
migratedRecords.push(managedRecord);
|
|
1422
|
+
for (const warning of ensureArray(ensureObject(managedRecord).warnings)) {
|
|
1423
|
+
const normalizedWarning = String(warning || "").trim();
|
|
1424
|
+
if (!normalizedWarning) {
|
|
1425
|
+
continue;
|
|
1426
|
+
}
|
|
1427
|
+
migrationWarnings.push(normalizedWarning);
|
|
1428
|
+
}
|
|
1429
|
+
}
|
|
1430
|
+
|
|
1431
|
+
const touchedFileList = sortStrings([...touchedFiles]);
|
|
1432
|
+
if (!options.dryRun) {
|
|
1433
|
+
await writeJsonFile(lockPath, lock);
|
|
1434
|
+
}
|
|
1435
|
+
|
|
1436
|
+
if (options.json) {
|
|
1437
|
+
io.stdout.write(`${JSON.stringify({
|
|
1438
|
+
targetType: "migrations",
|
|
1439
|
+
scope,
|
|
1440
|
+
requestedPackages: requestedPackageIds,
|
|
1441
|
+
touchedFiles: touchedFileList,
|
|
1442
|
+
lockPath: normalizeRelativePath(appRoot, lockPath),
|
|
1443
|
+
dryRun: options.dryRun,
|
|
1444
|
+
migrated: migratedRecords,
|
|
1445
|
+
warnings: migrationWarnings
|
|
1446
|
+
}, null, 2)}\n`);
|
|
1447
|
+
} else {
|
|
1448
|
+
io.stdout.write(`Generated migrations (${scope}).\n`);
|
|
1449
|
+
io.stdout.write(`Resolved packages (${requestedPackageIds.length}):\n`);
|
|
1450
|
+
for (const packageId of requestedPackageIds) {
|
|
1451
|
+
io.stdout.write(`- ${packageId}\n`);
|
|
1452
|
+
}
|
|
1453
|
+
io.stdout.write(`Touched files (${touchedFileList.length}):\n`);
|
|
1454
|
+
for (const touchedFile of touchedFileList) {
|
|
1455
|
+
io.stdout.write(`- ${touchedFile}\n`);
|
|
1456
|
+
}
|
|
1457
|
+
io.stdout.write(`Lock file: ${normalizeRelativePath(appRoot, lockPath)}\n`);
|
|
1458
|
+
if (migrationWarnings.length > 0) {
|
|
1459
|
+
io.stdout.write(`Warnings (${migrationWarnings.length}):\n`);
|
|
1460
|
+
for (const warning of migrationWarnings) {
|
|
1461
|
+
io.stdout.write(`- ${warning}\n`);
|
|
1462
|
+
}
|
|
1463
|
+
}
|
|
1464
|
+
if (options.dryRun) {
|
|
1465
|
+
io.stdout.write("Dry run enabled: no files were written.\n");
|
|
1466
|
+
}
|
|
1467
|
+
}
|
|
1468
|
+
|
|
1469
|
+
return 0;
|
|
1470
|
+
}
|
|
1471
|
+
|
|
1339
1472
|
async function commandPosition({ positional, options, cwd, io }) {
|
|
1340
1473
|
const targetType = String(positional[0] || "").trim();
|
|
1341
1474
|
const targetId = String(positional[1] || "").trim();
|
|
@@ -1649,6 +1782,7 @@ function createCommandHandlers(deps) {
|
|
|
1649
1782
|
commandShow,
|
|
1650
1783
|
commandCreate,
|
|
1651
1784
|
commandAdd,
|
|
1785
|
+
commandMigrations,
|
|
1652
1786
|
commandPosition,
|
|
1653
1787
|
commandUpdate,
|
|
1654
1788
|
commandRemove,
|
package/src/server/runCli.js
CHANGED
|
@@ -48,6 +48,14 @@ function createRunCli({
|
|
|
48
48
|
if (command === "show") {
|
|
49
49
|
return await commandHandlers.commandShow({ positional, options, stdout });
|
|
50
50
|
}
|
|
51
|
+
if (command === "migrations") {
|
|
52
|
+
return await commandHandlers.commandMigrations({
|
|
53
|
+
positional,
|
|
54
|
+
options,
|
|
55
|
+
cwd,
|
|
56
|
+
io: { stdin, stdout, stderr }
|
|
57
|
+
});
|
|
58
|
+
}
|
|
51
59
|
if (command === "add") {
|
|
52
60
|
return await commandHandlers.commandAdd({
|
|
53
61
|
positional,
|
|
@@ -21,6 +21,7 @@ function createCommandHandlerDeps(deps = {}) {
|
|
|
21
21
|
validatePlannedCapabilityClosure: deps.validatePlannedCapabilityClosure,
|
|
22
22
|
resolvePackageOptions: deps.resolvePackageOptions,
|
|
23
23
|
applyPackageInstall: deps.applyPackageInstall,
|
|
24
|
+
applyPackageMigrationsOnly: deps.applyPackageMigrationsOnly,
|
|
24
25
|
applyPackagePositioning: deps.applyPackagePositioning,
|
|
25
26
|
adoptAppLocalPackageDependencies: deps.adoptAppLocalPackageDependencies,
|
|
26
27
|
loadAppPackageJson: deps.loadAppPackageJson,
|