@jskit-ai/jskit-cli 0.2.26 → 0.2.28

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 (59) hide show
  1. package/package.json +3 -2
  2. package/src/server/cliRuntime/appState.js +226 -0
  3. package/src/server/cliRuntime/capabilitySupport.js +194 -0
  4. package/src/server/cliRuntime/descriptorValidation.js +150 -0
  5. package/src/server/cliRuntime/ioAndMigrations.js +381 -0
  6. package/src/server/cliRuntime/localPackageSupport.js +390 -0
  7. package/src/server/cliRuntime/mutationApplication.js +9 -0
  8. package/src/server/cliRuntime/mutationWhen.js +285 -0
  9. package/src/server/cliRuntime/mutations/fileMutations.js +247 -0
  10. package/src/server/cliRuntime/mutations/installMigrationMutation.js +213 -0
  11. package/src/server/cliRuntime/mutations/mutationPathUtils.js +12 -0
  12. package/src/server/cliRuntime/mutations/surfaceTargets.js +155 -0
  13. package/src/server/cliRuntime/mutations/templateContext.js +171 -0
  14. package/src/server/cliRuntime/mutations/textMutations.js +250 -0
  15. package/src/server/cliRuntime/packageInstallFlow.js +489 -0
  16. package/src/server/cliRuntime/packageIntrospection/exportEntries.js +259 -0
  17. package/src/server/cliRuntime/packageIntrospection/exportedSymbols.js +216 -0
  18. package/src/server/cliRuntime/packageIntrospection/placementNormalization.js +98 -0
  19. package/src/server/cliRuntime/packageIntrospection/providerBindingIntrospection.js +377 -0
  20. package/src/server/cliRuntime/packageIntrospection.js +137 -0
  21. package/src/server/cliRuntime/packageOptions.js +299 -0
  22. package/src/server/cliRuntime/packageRegistries.js +343 -0
  23. package/src/server/cliRuntime/packageTemplateResolution.js +131 -0
  24. package/src/server/cliRuntime/viteProxy.js +356 -0
  25. package/src/server/commandHandlers/health.js +292 -0
  26. package/src/server/commandHandlers/list.js +292 -0
  27. package/src/server/commandHandlers/package.js +23 -0
  28. package/src/server/commandHandlers/packageCommands/add.js +282 -0
  29. package/src/server/commandHandlers/packageCommands/create.js +155 -0
  30. package/src/server/commandHandlers/packageCommands/generate.js +116 -0
  31. package/src/server/commandHandlers/packageCommands/migrations.js +155 -0
  32. package/src/server/commandHandlers/packageCommands/position.js +103 -0
  33. package/src/server/commandHandlers/packageCommands/remove.js +181 -0
  34. package/src/server/commandHandlers/packageCommands/update.js +40 -0
  35. package/src/server/commandHandlers/shared.js +314 -0
  36. package/src/server/commandHandlers/show/payloads.js +92 -0
  37. package/src/server/commandHandlers/show/renderBundleText.js +16 -0
  38. package/src/server/commandHandlers/show/renderHelpers.js +82 -0
  39. package/src/server/commandHandlers/show/renderPackageCapabilities.js +124 -0
  40. package/src/server/commandHandlers/show/renderPackageExports.js +203 -0
  41. package/src/server/commandHandlers/show/renderPackageText.js +332 -0
  42. package/src/server/commandHandlers/show.js +114 -0
  43. package/src/server/core/argParser.js +144 -0
  44. package/src/server/{runtimeDeps.js → core/buildCommandDeps.js} +2 -1
  45. package/src/server/core/commandCatalog.js +47 -0
  46. package/src/server/core/createCliRunner.js +150 -0
  47. package/src/server/core/createCommandHandlers.js +43 -0
  48. package/src/server/{runCli.js → core/dispatchCli.js} +14 -1
  49. package/src/server/core/usageHelp.js +344 -0
  50. package/src/server/index.js +1 -1
  51. package/src/server/{optionInterpolation.js → shared/optionInterpolation.js} +12 -1
  52. package/src/server/{pathResolution.js → shared/pathResolution.js} +1 -1
  53. package/src/server/argParser.js +0 -206
  54. package/src/server/cliRuntime.js +0 -4853
  55. package/src/server/commandHandlers.js +0 -2109
  56. /package/src/server/{cliError.js → shared/cliError.js} +0 -0
  57. /package/src/server/{collectionUtils.js → shared/collectionUtils.js} +0 -0
  58. /package/src/server/{outputFormatting.js → shared/outputFormatting.js} +0 -0
  59. /package/src/server/{packageIdHelpers.js → shared/packageIdHelpers.js} +0 -0
@@ -0,0 +1,489 @@
1
+ import { createCliError } from "../shared/cliError.js";
2
+ import {
3
+ ensureArray,
4
+ ensureObject,
5
+ sortStrings
6
+ } from "../shared/collectionUtils.js";
7
+ import {
8
+ interpolateOptionValue
9
+ } from "../shared/optionInterpolation.js";
10
+ import {
11
+ normalizeFileMutationRecord
12
+ } from "./mutationWhen.js";
13
+ import {
14
+ applyViteMutations,
15
+ removeManagedViteProxyEntries
16
+ } from "./viteProxy.js";
17
+ import {
18
+ applyPackageJsonField,
19
+ removePackageJsonField
20
+ } from "./appState.js";
21
+ import {
22
+ isGeneratorPackageEntry,
23
+ loadAppLocalPackageRegistry
24
+ } from "./packageRegistries.js";
25
+ import {
26
+ resolvePackageDependencySpecifier,
27
+ normalizeJskitDependencySpecifier
28
+ } from "./localPackageSupport.js";
29
+ import {
30
+ resolvePackageTemplateRoot
31
+ } from "./packageTemplateResolution.js";
32
+ import {
33
+ applyFileMutations,
34
+ applyTextMutations,
35
+ preflightFileMutationTemplateContexts,
36
+ resolvePositioningMutations
37
+ } from "./mutationApplication.js";
38
+ function createManagedRecordBase(packageEntry, options) {
39
+ const sourceRecord = {
40
+ type: String(packageEntry?.sourceType || "packages-directory"),
41
+ ...ensureObject(packageEntry?.source)
42
+ };
43
+ if (!sourceRecord.descriptorPath && String(packageEntry?.descriptorRelativePath || "").trim()) {
44
+ sourceRecord.descriptorPath = String(packageEntry.descriptorRelativePath).trim();
45
+ }
46
+
47
+ return {
48
+ packageId: packageEntry.packageId,
49
+ version: packageEntry.version,
50
+ source: sourceRecord,
51
+ managed: {
52
+ packageJson: {
53
+ dependencies: {},
54
+ devDependencies: {},
55
+ scripts: {}
56
+ },
57
+ text: {},
58
+ vite: {},
59
+ files: [],
60
+ migrations: []
61
+ },
62
+ options,
63
+ installedAt: new Date().toISOString()
64
+ };
65
+ }
66
+
67
+
68
+ function cloneManagedMap(value = {}) {
69
+ const cloned = {};
70
+ for (const [key, entry] of Object.entries(ensureObject(value))) {
71
+ cloned[key] = {
72
+ ...ensureObject(entry)
73
+ };
74
+ }
75
+ return cloned;
76
+ }
77
+
78
+ function cloneManagedArray(value = []) {
79
+ return ensureArray(value).map((entry) => ({
80
+ ...ensureObject(entry)
81
+ }));
82
+ }
83
+
84
+ function resolveManagedSourceRecord(packageEntry, existingInstall = {}) {
85
+ const existingSource = ensureObject(existingInstall.source);
86
+ if (Object.keys(existingSource).length > 0) {
87
+ return {
88
+ ...existingSource
89
+ };
90
+ }
91
+
92
+ const sourceRecord = {
93
+ type: String(packageEntry?.sourceType || "packages-directory"),
94
+ ...ensureObject(packageEntry?.source)
95
+ };
96
+ if (!sourceRecord.descriptorPath && String(packageEntry?.descriptorRelativePath || "").trim()) {
97
+ sourceRecord.descriptorPath = String(packageEntry.descriptorRelativePath).trim();
98
+ }
99
+ return sourceRecord;
100
+ }
101
+
102
+ async function applyPackagePositioning({
103
+ packageEntry,
104
+ packageOptions,
105
+ appRoot,
106
+ lock,
107
+ touchedFiles
108
+ }) {
109
+ const existingInstall = ensureObject(lock.installedPackages[packageEntry.packageId]);
110
+ if (Object.keys(existingInstall).length < 1) {
111
+ throw createCliError(`Package is not installed: ${packageEntry.packageId}`);
112
+ }
113
+
114
+ const existingManaged = ensureObject(existingInstall.managed);
115
+ const existingPackageJsonManaged = ensureObject(existingManaged.packageJson);
116
+ const nextManaged = {
117
+ packageJson: {
118
+ dependencies: cloneManagedMap(existingPackageJsonManaged.dependencies),
119
+ devDependencies: cloneManagedMap(existingPackageJsonManaged.devDependencies),
120
+ scripts: cloneManagedMap(existingPackageJsonManaged.scripts)
121
+ },
122
+ text: cloneManagedMap(existingManaged.text),
123
+ vite: cloneManagedMap(existingManaged.vite),
124
+ files: cloneManagedArray(existingManaged.files),
125
+ migrations: cloneManagedArray(existingManaged.migrations)
126
+ };
127
+
128
+ const templateRoot = await resolvePackageTemplateRoot({ packageEntry, appRoot });
129
+ const packageEntryForMutations =
130
+ templateRoot === packageEntry.rootDir
131
+ ? packageEntry
132
+ : {
133
+ ...packageEntry,
134
+ rootDir: templateRoot
135
+ };
136
+
137
+ const mutations = ensureObject(packageEntry.descriptor.mutations);
138
+ const positioningMutations = resolvePositioningMutations(mutations);
139
+ const appliedManagedFiles = [];
140
+ const appliedManagedText = {};
141
+ if (positioningMutations.files.length > 0) {
142
+ await applyFileMutations(
143
+ packageEntryForMutations,
144
+ packageOptions,
145
+ appRoot,
146
+ positioningMutations.files,
147
+ appliedManagedFiles,
148
+ [],
149
+ touchedFiles
150
+ );
151
+ }
152
+ if (positioningMutations.text.length > 0) {
153
+ await applyTextMutations(
154
+ packageEntryForMutations,
155
+ appRoot,
156
+ positioningMutations.text,
157
+ packageOptions,
158
+ appliedManagedText,
159
+ touchedFiles
160
+ );
161
+ }
162
+
163
+ if (appliedManagedFiles.length > 0) {
164
+ const replacedPaths = new Set(
165
+ appliedManagedFiles
166
+ .map((entry) => String(ensureObject(entry).path || "").trim())
167
+ .filter(Boolean)
168
+ );
169
+ const retainedFiles = nextManaged.files.filter((entry) => {
170
+ const managedPath = String(ensureObject(entry).path || "").trim();
171
+ return !managedPath || !replacedPaths.has(managedPath);
172
+ });
173
+ nextManaged.files = [...retainedFiles, ...appliedManagedFiles];
174
+ }
175
+
176
+ if (Object.keys(appliedManagedText).length > 0) {
177
+ nextManaged.text = {
178
+ ...nextManaged.text,
179
+ ...appliedManagedText
180
+ };
181
+ }
182
+
183
+ const managedRecord = {
184
+ ...existingInstall,
185
+ packageId: packageEntry.packageId,
186
+ version: packageEntry.version,
187
+ source: resolveManagedSourceRecord(packageEntry, existingInstall),
188
+ managed: nextManaged,
189
+ options: {
190
+ ...ensureObject(packageOptions)
191
+ },
192
+ installedAt: String(existingInstall.installedAt || new Date().toISOString())
193
+ };
194
+ lock.installedPackages[packageEntry.packageId] = managedRecord;
195
+ return managedRecord;
196
+ }
197
+
198
+ async function applyPackageMigrationsOnly({
199
+ packageEntry,
200
+ packageOptions,
201
+ appRoot,
202
+ lock,
203
+ touchedFiles
204
+ }) {
205
+ const existingInstall = ensureObject(lock.installedPackages[packageEntry.packageId]);
206
+ if (Object.keys(existingInstall).length < 1) {
207
+ throw createCliError(`Package is not installed: ${packageEntry.packageId}`);
208
+ }
209
+
210
+ const existingManaged = ensureObject(existingInstall.managed);
211
+ const existingPackageJsonManaged = ensureObject(existingManaged.packageJson);
212
+ const nextManaged = {
213
+ packageJson: {
214
+ dependencies: cloneManagedMap(existingPackageJsonManaged.dependencies),
215
+ devDependencies: cloneManagedMap(existingPackageJsonManaged.devDependencies),
216
+ scripts: cloneManagedMap(existingPackageJsonManaged.scripts)
217
+ },
218
+ text: cloneManagedMap(existingManaged.text),
219
+ vite: cloneManagedMap(existingManaged.vite),
220
+ files: cloneManagedArray(existingManaged.files),
221
+ migrations: cloneManagedArray(existingManaged.migrations)
222
+ };
223
+
224
+ const templateRoot = await resolvePackageTemplateRoot({ packageEntry, appRoot });
225
+ const packageEntryForMutations =
226
+ templateRoot === packageEntry.rootDir
227
+ ? packageEntry
228
+ : {
229
+ ...packageEntry,
230
+ rootDir: templateRoot
231
+ };
232
+ const mutations = ensureObject(packageEntry.descriptor.mutations);
233
+ const migrationFileMutations = ensureArray(mutations.files).filter((mutationValue) => {
234
+ const normalized = normalizeFileMutationRecord(mutationValue);
235
+ const operation = String(normalized.op || "copy-file").trim();
236
+ return operation === "install-migration";
237
+ });
238
+ const mutationWarnings = [];
239
+
240
+ if (migrationFileMutations.length > 0) {
241
+ await applyFileMutations(
242
+ packageEntryForMutations,
243
+ packageOptions,
244
+ appRoot,
245
+ migrationFileMutations,
246
+ [],
247
+ nextManaged.migrations,
248
+ touchedFiles,
249
+ mutationWarnings
250
+ );
251
+ }
252
+
253
+ const managedRecord = {
254
+ ...existingInstall,
255
+ packageId: packageEntry.packageId,
256
+ source: resolveManagedSourceRecord(packageEntry, existingInstall),
257
+ managed: nextManaged,
258
+ options: {
259
+ ...ensureObject(packageOptions)
260
+ },
261
+ migrationSyncVersion: packageEntry.version,
262
+ installedAt: String(existingInstall.installedAt || new Date().toISOString())
263
+ };
264
+ lock.installedPackages[packageEntry.packageId] = managedRecord;
265
+ if (mutationWarnings.length > 0) {
266
+ managedRecord.warnings = mutationWarnings;
267
+ }
268
+ return managedRecord;
269
+ }
270
+
271
+ async function applyPackageInstall({
272
+ packageEntry,
273
+ packageOptions,
274
+ appRoot,
275
+ appPackageJson,
276
+ lock,
277
+ packageRegistry,
278
+ touchedFiles
279
+ }) {
280
+ const existingInstall = ensureObject(lock.installedPackages[packageEntry.packageId]);
281
+ const existingManaged = ensureObject(existingInstall.managed);
282
+ await removeManagedViteProxyEntries({
283
+ appRoot,
284
+ packageId: packageEntry.packageId,
285
+ managedViteChanges: ensureObject(existingManaged.vite),
286
+ touchedFiles
287
+ });
288
+
289
+ const managedRecord = createManagedRecordBase(packageEntry, packageOptions);
290
+ managedRecord.managed.migrations = cloneManagedArray(existingManaged.migrations);
291
+ const generatorPackage = isGeneratorPackageEntry(packageEntry);
292
+ const mutationWarnings = [];
293
+ const mutations = ensureObject(packageEntry.descriptor.mutations);
294
+ const fileMutations = ensureArray(mutations.files);
295
+ const templateRoot = await resolvePackageTemplateRoot({ packageEntry, appRoot });
296
+ const packageEntryForMutations =
297
+ templateRoot === packageEntry.rootDir
298
+ ? packageEntry
299
+ : {
300
+ ...packageEntry,
301
+ rootDir: templateRoot
302
+ };
303
+
304
+ const precomputedTemplateContextByMutationIndex = await preflightFileMutationTemplateContexts(
305
+ packageEntryForMutations,
306
+ packageOptions,
307
+ appRoot,
308
+ fileMutations
309
+ );
310
+
311
+ const mutationDependencies = ensureObject(mutations.dependencies);
312
+ const runtimeDependencies = ensureObject(mutationDependencies.runtime);
313
+ const devDependencies = ensureObject(mutationDependencies.dev);
314
+ const mutationScripts = ensureObject(ensureObject(mutations.packageJson).scripts);
315
+
316
+ for (const [rawDependencyId, rawDependencyVersion] of Object.entries(runtimeDependencies)) {
317
+ const dependencyId = interpolateOptionValue(
318
+ rawDependencyId,
319
+ packageOptions,
320
+ packageEntry.packageId,
321
+ `dependencies.runtime.${rawDependencyId}.id`
322
+ );
323
+ const dependencyVersion = interpolateOptionValue(
324
+ String(rawDependencyVersion || ""),
325
+ packageOptions,
326
+ packageEntry.packageId,
327
+ `dependencies.runtime.${rawDependencyId}.value`
328
+ );
329
+ if (!dependencyId) {
330
+ throw createCliError(
331
+ `Invalid runtime dependency key after option interpolation in ${packageEntry.packageId}: ${rawDependencyId}`
332
+ );
333
+ }
334
+
335
+ const localPackage = packageRegistry.get(dependencyId);
336
+ const existingRuntimeDependencyValue = String(ensureObject(appPackageJson.dependencies)[dependencyId] || "").trim();
337
+ const resolvedValue = localPackage
338
+ ? resolvePackageDependencySpecifier(localPackage, { existingValue: existingRuntimeDependencyValue })
339
+ : String(dependencyVersion);
340
+ const normalizedResolvedValue = normalizeJskitDependencySpecifier(dependencyId, resolvedValue);
341
+ const applied = applyPackageJsonField(appPackageJson, "dependencies", dependencyId, normalizedResolvedValue);
342
+ if (applied.changed) {
343
+ managedRecord.managed.packageJson.dependencies[dependencyId] = applied.managed;
344
+ touchedFiles.add("package.json");
345
+ }
346
+ }
347
+
348
+ for (const [rawDependencyId, rawDependencyVersion] of Object.entries(devDependencies)) {
349
+ const dependencyId = interpolateOptionValue(
350
+ rawDependencyId,
351
+ packageOptions,
352
+ packageEntry.packageId,
353
+ `dependencies.dev.${rawDependencyId}.id`
354
+ );
355
+ const dependencyVersion = interpolateOptionValue(
356
+ String(rawDependencyVersion || ""),
357
+ packageOptions,
358
+ packageEntry.packageId,
359
+ `dependencies.dev.${rawDependencyId}.value`
360
+ );
361
+ if (!dependencyId) {
362
+ throw createCliError(
363
+ `Invalid dev dependency key after option interpolation in ${packageEntry.packageId}: ${rawDependencyId}`
364
+ );
365
+ }
366
+
367
+ const localPackage = packageRegistry.get(dependencyId);
368
+ const existingDevDependencyValue = String(ensureObject(appPackageJson.devDependencies)[dependencyId] || "").trim();
369
+ const resolvedValue = localPackage
370
+ ? resolvePackageDependencySpecifier(localPackage, { existingValue: existingDevDependencyValue })
371
+ : String(dependencyVersion);
372
+ const normalizedResolvedValue = normalizeJskitDependencySpecifier(dependencyId, resolvedValue);
373
+ const applied = applyPackageJsonField(appPackageJson, "devDependencies", dependencyId, normalizedResolvedValue);
374
+ if (applied.changed) {
375
+ managedRecord.managed.packageJson.devDependencies[dependencyId] = applied.managed;
376
+ touchedFiles.add("package.json");
377
+ }
378
+ }
379
+
380
+ if (generatorPackage) {
381
+ const removedRuntimeDependency = removePackageJsonField(appPackageJson, "dependencies", packageEntry.packageId);
382
+ const removedDevDependency = removePackageJsonField(appPackageJson, "devDependencies", packageEntry.packageId);
383
+ if (removedRuntimeDependency || removedDevDependency) {
384
+ touchedFiles.add("package.json");
385
+ }
386
+ } else {
387
+ const existingSelfDependencyValue = String(ensureObject(appPackageJson.dependencies)[packageEntry.packageId] || "").trim();
388
+ const selfDependencyValue = resolvePackageDependencySpecifier(packageEntry, {
389
+ existingValue: existingSelfDependencyValue
390
+ });
391
+ const normalizedSelfDependencyValue = normalizeJskitDependencySpecifier(packageEntry.packageId, selfDependencyValue);
392
+ const selfApplied = applyPackageJsonField(
393
+ appPackageJson,
394
+ "dependencies",
395
+ packageEntry.packageId,
396
+ normalizedSelfDependencyValue
397
+ );
398
+ if (selfApplied.changed) {
399
+ managedRecord.managed.packageJson.dependencies[packageEntry.packageId] = selfApplied.managed;
400
+ touchedFiles.add("package.json");
401
+ }
402
+ }
403
+
404
+ for (const [scriptName, scriptValue] of Object.entries(mutationScripts)) {
405
+ const applied = applyPackageJsonField(appPackageJson, "scripts", scriptName, scriptValue);
406
+ if (applied.changed) {
407
+ managedRecord.managed.packageJson.scripts[scriptName] = applied.managed;
408
+ touchedFiles.add("package.json");
409
+ }
410
+ }
411
+
412
+ await applyFileMutations(
413
+ packageEntryForMutations,
414
+ packageOptions,
415
+ appRoot,
416
+ fileMutations,
417
+ managedRecord.managed.files,
418
+ managedRecord.managed.migrations,
419
+ touchedFiles,
420
+ mutationWarnings,
421
+ precomputedTemplateContextByMutationIndex
422
+ );
423
+
424
+ await applyTextMutations(
425
+ packageEntryForMutations,
426
+ appRoot,
427
+ ensureArray(mutations.text),
428
+ packageOptions,
429
+ managedRecord.managed.text,
430
+ touchedFiles
431
+ );
432
+
433
+ await applyViteMutations(
434
+ packageEntryForMutations,
435
+ appRoot,
436
+ ensureObject(mutations.vite),
437
+ packageOptions,
438
+ managedRecord.managed.vite,
439
+ touchedFiles
440
+ );
441
+
442
+ if (generatorPackage) {
443
+ delete lock.installedPackages[packageEntry.packageId];
444
+ } else {
445
+ managedRecord.migrationSyncVersion = packageEntry.version;
446
+ lock.installedPackages[packageEntry.packageId] = managedRecord;
447
+ }
448
+ if (mutationWarnings.length > 0) {
449
+ managedRecord.warnings = mutationWarnings;
450
+ }
451
+ return managedRecord;
452
+ }
453
+
454
+ async function adoptAppLocalPackageDependencies({
455
+ appRoot,
456
+ appPackageJson,
457
+ lock
458
+ }) {
459
+ const appLocalRegistry = await loadAppLocalPackageRegistry(appRoot);
460
+ const runtimeDependencies = ensureObject(appPackageJson.dependencies);
461
+ const adoptedPackageIds = [];
462
+
463
+ for (const dependencyId of sortStrings(Object.keys(runtimeDependencies))) {
464
+ if (lock.installedPackages[dependencyId]) {
465
+ continue;
466
+ }
467
+
468
+ const localPackageEntry = appLocalRegistry.get(dependencyId);
469
+ if (!localPackageEntry) {
470
+ continue;
471
+ }
472
+
473
+ lock.installedPackages[dependencyId] = createManagedRecordBase(localPackageEntry, {});
474
+ adoptedPackageIds.push(dependencyId);
475
+ }
476
+
477
+ return {
478
+ appLocalRegistry,
479
+ adoptedPackageIds: sortStrings(adoptedPackageIds)
480
+ };
481
+ }
482
+
483
+
484
+ export {
485
+ adoptAppLocalPackageDependencies,
486
+ applyPackageInstall,
487
+ applyPackageMigrationsOnly,
488
+ applyPackagePositioning
489
+ };