@jskit-ai/jskit-cli 0.2.27 → 0.2.29
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 +3 -2
- package/src/server/cliRuntime/appState.js +226 -0
- package/src/server/cliRuntime/capabilitySupport.js +194 -0
- package/src/server/cliRuntime/descriptorValidation.js +150 -0
- package/src/server/cliRuntime/ioAndMigrations.js +381 -0
- package/src/server/cliRuntime/localPackageSupport.js +390 -0
- package/src/server/cliRuntime/mutationApplication.js +9 -0
- package/src/server/cliRuntime/mutationWhen.js +285 -0
- package/src/server/cliRuntime/mutations/fileMutations.js +247 -0
- package/src/server/cliRuntime/mutations/installMigrationMutation.js +213 -0
- package/src/server/cliRuntime/mutations/mutationPathUtils.js +12 -0
- package/src/server/cliRuntime/mutations/surfaceTargets.js +155 -0
- package/src/server/cliRuntime/mutations/templateContext.js +171 -0
- package/src/server/cliRuntime/mutations/textMutations.js +250 -0
- package/src/server/cliRuntime/packageInstallFlow.js +489 -0
- package/src/server/cliRuntime/packageIntrospection/exportEntries.js +259 -0
- package/src/server/cliRuntime/packageIntrospection/exportedSymbols.js +216 -0
- package/src/server/cliRuntime/packageIntrospection/placementNormalization.js +98 -0
- package/src/server/cliRuntime/packageIntrospection/providerBindingIntrospection.js +377 -0
- package/src/server/cliRuntime/packageIntrospection.js +137 -0
- package/src/server/cliRuntime/packageOptions.js +299 -0
- package/src/server/cliRuntime/packageRegistries.js +343 -0
- package/src/server/cliRuntime/packageTemplateResolution.js +131 -0
- package/src/server/cliRuntime/viteProxy.js +356 -0
- package/src/server/commandHandlers/health.js +292 -0
- package/src/server/commandHandlers/list.js +292 -0
- package/src/server/commandHandlers/package.js +23 -0
- package/src/server/commandHandlers/packageCommands/add.js +282 -0
- package/src/server/commandHandlers/packageCommands/create.js +155 -0
- package/src/server/commandHandlers/packageCommands/generate.js +116 -0
- package/src/server/commandHandlers/packageCommands/migrations.js +155 -0
- package/src/server/commandHandlers/packageCommands/position.js +103 -0
- package/src/server/commandHandlers/packageCommands/remove.js +181 -0
- package/src/server/commandHandlers/packageCommands/update.js +40 -0
- package/src/server/commandHandlers/shared.js +314 -0
- package/src/server/commandHandlers/show/payloads.js +92 -0
- package/src/server/commandHandlers/show/renderBundleText.js +16 -0
- package/src/server/commandHandlers/show/renderHelpers.js +82 -0
- package/src/server/commandHandlers/show/renderPackageCapabilities.js +124 -0
- package/src/server/commandHandlers/show/renderPackageExports.js +203 -0
- package/src/server/commandHandlers/show/renderPackageText.js +332 -0
- package/src/server/commandHandlers/show.js +114 -0
- package/src/server/core/argParser.js +144 -0
- package/src/server/{runtimeDeps.js → core/buildCommandDeps.js} +2 -1
- package/src/server/core/commandCatalog.js +47 -0
- package/src/server/core/createCliRunner.js +150 -0
- package/src/server/core/createCommandHandlers.js +43 -0
- package/src/server/{runCli.js → core/dispatchCli.js} +14 -1
- package/src/server/core/usageHelp.js +344 -0
- package/src/server/index.js +1 -1
- package/src/server/{optionInterpolation.js → shared/optionInterpolation.js} +12 -1
- package/src/server/{pathResolution.js → shared/pathResolution.js} +1 -1
- package/src/server/argParser.js +0 -206
- package/src/server/cliRuntime.js +0 -4956
- package/src/server/commandHandlers.js +0 -2109
- /package/src/server/{cliError.js → shared/cliError.js} +0 -0
- /package/src/server/{collectionUtils.js → shared/collectionUtils.js} +0 -0
- /package/src/server/{outputFormatting.js → shared/outputFormatting.js} +0 -0
- /package/src/server/{packageIdHelpers.js → shared/packageIdHelpers.js} +0 -0
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ensureArray,
|
|
3
|
+
ensureObject,
|
|
4
|
+
sortStrings
|
|
5
|
+
} from "../shared/collectionUtils.js";
|
|
6
|
+
|
|
7
|
+
function createHealthCommands(ctx = {}) {
|
|
8
|
+
const {
|
|
9
|
+
resolveAppRootFromCwd,
|
|
10
|
+
loadLockFile,
|
|
11
|
+
loadPackageRegistry,
|
|
12
|
+
loadBundleRegistry,
|
|
13
|
+
loadAppLocalPackageRegistry,
|
|
14
|
+
mergePackageRegistries,
|
|
15
|
+
hydratePackageRegistryFromInstalledNodeModules,
|
|
16
|
+
inspectPackageOfferings,
|
|
17
|
+
fileExists,
|
|
18
|
+
path
|
|
19
|
+
} = ctx;
|
|
20
|
+
|
|
21
|
+
function collectDescriptorContainerTokens({ packageId, side, values, issues }) {
|
|
22
|
+
const declaredTokens = new Set();
|
|
23
|
+
const duplicateTokens = new Set();
|
|
24
|
+
let invalidCount = 0;
|
|
25
|
+
|
|
26
|
+
for (const rawValue of ensureArray(values)) {
|
|
27
|
+
if (typeof rawValue !== "string") {
|
|
28
|
+
invalidCount += 1;
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
const token = rawValue.trim();
|
|
32
|
+
if (!token) {
|
|
33
|
+
invalidCount += 1;
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
if (declaredTokens.has(token)) {
|
|
37
|
+
duplicateTokens.add(token);
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
declaredTokens.add(token);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (invalidCount > 0) {
|
|
44
|
+
issues.push({
|
|
45
|
+
packageId,
|
|
46
|
+
side,
|
|
47
|
+
code: "descriptor-token-invalid",
|
|
48
|
+
message: `${packageId} (${side}): metadata.apiSummary.containerTokens includes ${invalidCount} non-string or empty token value(s).`
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
for (const token of sortStrings([...duplicateTokens])) {
|
|
52
|
+
issues.push({
|
|
53
|
+
packageId,
|
|
54
|
+
side,
|
|
55
|
+
code: "descriptor-token-duplicate",
|
|
56
|
+
token,
|
|
57
|
+
message: `${packageId} (${side}): descriptor token is declared more than once: ${token}.`
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return declaredTokens;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function collectUsedContainerTokens({ packageId, side, bindings, issues }) {
|
|
65
|
+
const usedTokens = new Set();
|
|
66
|
+
for (const rawBinding of ensureArray(bindings)) {
|
|
67
|
+
const binding = ensureObject(rawBinding);
|
|
68
|
+
const tokenExpression = String(binding.tokenExpression || "").trim();
|
|
69
|
+
const token = String(binding.token || "").trim();
|
|
70
|
+
const location = String(binding.location || "").trim();
|
|
71
|
+
if (binding.tokenResolved !== true || !token) {
|
|
72
|
+
const expressionLabel = tokenExpression || "<empty>";
|
|
73
|
+
const locationSuffix = location ? ` at ${location}` : "";
|
|
74
|
+
issues.push({
|
|
75
|
+
packageId,
|
|
76
|
+
side,
|
|
77
|
+
code: "binding-token-unresolved",
|
|
78
|
+
tokenExpression: expressionLabel,
|
|
79
|
+
location,
|
|
80
|
+
message: `${packageId} (${side}): unresolved DI token expression "${expressionLabel}"${locationSuffix}.`
|
|
81
|
+
});
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
usedTokens.add(token);
|
|
85
|
+
}
|
|
86
|
+
return usedTokens;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function collectProviderIntrospectionIssues({ packageId, packageInsights, issues }) {
|
|
90
|
+
const introspection = ensureObject(packageInsights);
|
|
91
|
+
if (!introspection.available) {
|
|
92
|
+
issues.push({
|
|
93
|
+
packageId,
|
|
94
|
+
side: "",
|
|
95
|
+
code: "provider-introspection-unavailable",
|
|
96
|
+
message: `${packageId}: provider source introspection is unavailable, so DI token parity cannot be verified.`
|
|
97
|
+
});
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const notes = ensureArray(introspection.notes).map((value) => String(value || "").trim()).filter(Boolean);
|
|
102
|
+
for (const note of notes) {
|
|
103
|
+
if (
|
|
104
|
+
note.startsWith("Skipped wildcard provider entrypoint during introspection:") ||
|
|
105
|
+
note.startsWith("Provider file missing during introspection:") ||
|
|
106
|
+
note.startsWith("Failed reading provider ")
|
|
107
|
+
) {
|
|
108
|
+
issues.push({
|
|
109
|
+
packageId,
|
|
110
|
+
side: "",
|
|
111
|
+
code: "provider-introspection-incomplete",
|
|
112
|
+
message: `${packageId}: ${note}`
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function collectDiLabelParityIssuesForPackage({ packageEntry, packageInsights }) {
|
|
119
|
+
const packageId = String(packageEntry?.packageId || "").trim();
|
|
120
|
+
const descriptor = ensureObject(packageEntry?.descriptor);
|
|
121
|
+
const metadataApiSummary = ensureObject(ensureObject(descriptor.metadata).apiSummary);
|
|
122
|
+
const descriptorTokenSummary = ensureObject(metadataApiSummary.containerTokens);
|
|
123
|
+
const bindingSections = ensureObject(ensureObject(packageInsights).containerBindings);
|
|
124
|
+
const issues = [];
|
|
125
|
+
const sides = ["server", "client"];
|
|
126
|
+
|
|
127
|
+
collectProviderIntrospectionIssues({ packageId, packageInsights, issues });
|
|
128
|
+
|
|
129
|
+
for (const side of sides) {
|
|
130
|
+
const declaredTokens = collectDescriptorContainerTokens({
|
|
131
|
+
packageId,
|
|
132
|
+
side,
|
|
133
|
+
values: descriptorTokenSummary[side],
|
|
134
|
+
issues
|
|
135
|
+
});
|
|
136
|
+
const usedTokens = collectUsedContainerTokens({
|
|
137
|
+
packageId,
|
|
138
|
+
side,
|
|
139
|
+
bindings: bindingSections[side],
|
|
140
|
+
issues
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
for (const token of sortStrings([...usedTokens])) {
|
|
144
|
+
if (!declaredTokens.has(token)) {
|
|
145
|
+
issues.push({
|
|
146
|
+
packageId,
|
|
147
|
+
side,
|
|
148
|
+
code: "binding-token-undeclared",
|
|
149
|
+
token,
|
|
150
|
+
message: `${packageId} (${side}): token is used by providers but missing from metadata.apiSummary.containerTokens.${side}: ${token}.`
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
for (const token of sortStrings([...declaredTokens])) {
|
|
155
|
+
if (!usedTokens.has(token)) {
|
|
156
|
+
issues.push({
|
|
157
|
+
packageId,
|
|
158
|
+
side,
|
|
159
|
+
code: "descriptor-token-unused",
|
|
160
|
+
token,
|
|
161
|
+
message: `${packageId} (${side}): token is declared in metadata.apiSummary.containerTokens.${side} but never bound by providers: ${token}.`
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
return issues;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
async function commandDoctor({ cwd, options, stdout }) {
|
|
171
|
+
const appRoot = await resolveAppRootFromCwd(cwd);
|
|
172
|
+
const { lock } = await loadLockFile(appRoot);
|
|
173
|
+
const packageRegistry = await loadPackageRegistry();
|
|
174
|
+
const appLocalRegistry = await loadAppLocalPackageRegistry(appRoot);
|
|
175
|
+
const combinedPackageRegistry = mergePackageRegistries(packageRegistry, appLocalRegistry);
|
|
176
|
+
const issues = [];
|
|
177
|
+
const installed = ensureObject(lock.installedPackages);
|
|
178
|
+
await hydratePackageRegistryFromInstalledNodeModules({
|
|
179
|
+
appRoot,
|
|
180
|
+
packageRegistry: combinedPackageRegistry,
|
|
181
|
+
seedPackageIds: Object.keys(installed)
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
for (const [packageId, lockEntryValue] of Object.entries(installed)) {
|
|
185
|
+
const lockEntry = ensureObject(lockEntryValue);
|
|
186
|
+
if (!combinedPackageRegistry.has(packageId)) {
|
|
187
|
+
issues.push(`Installed package not found in package registry: ${packageId}`);
|
|
188
|
+
continue;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
const managed = ensureObject(lockEntry.managed);
|
|
192
|
+
for (const fileChange of ensureArray(managed.files)) {
|
|
193
|
+
const changeRecord = ensureObject(fileChange);
|
|
194
|
+
const relativePath = String(changeRecord.path || "").trim();
|
|
195
|
+
const absolutePath = path.join(appRoot, relativePath);
|
|
196
|
+
if (!(await fileExists(absolutePath))) {
|
|
197
|
+
issues.push(`${packageId}: managed file missing: ${relativePath}`);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
const payload = {
|
|
203
|
+
appRoot,
|
|
204
|
+
lockVersion: lock.lockVersion,
|
|
205
|
+
installedPackages: sortStrings(Object.keys(installed)),
|
|
206
|
+
issues
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
if (options.json) {
|
|
210
|
+
stdout.write(`${JSON.stringify(payload, null, 2)}\n`);
|
|
211
|
+
} else {
|
|
212
|
+
stdout.write(`App root: ${appRoot}\n`);
|
|
213
|
+
stdout.write(`Installed packages: ${payload.installedPackages.length}\n`);
|
|
214
|
+
if (issues.length === 0) {
|
|
215
|
+
stdout.write("Doctor status: healthy\n");
|
|
216
|
+
} else {
|
|
217
|
+
stdout.write(`Doctor status: unhealthy (${issues.length} issue(s))\n`);
|
|
218
|
+
for (const issue of issues) {
|
|
219
|
+
stdout.write(`- ${issue}\n`);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
return issues.length === 0 ? 0 : 1;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
async function commandLintDescriptors({ options, stdout }) {
|
|
228
|
+
const packageRegistry = await loadPackageRegistry();
|
|
229
|
+
const bundleRegistry = await loadBundleRegistry();
|
|
230
|
+
const shouldCheckDiLabels = options.checkDiLabels === true;
|
|
231
|
+
let diLabelIssues = [];
|
|
232
|
+
if (shouldCheckDiLabels) {
|
|
233
|
+
const issues = [];
|
|
234
|
+
for (const packageId of sortStrings([...packageRegistry.keys()])) {
|
|
235
|
+
const packageEntry = packageRegistry.get(packageId);
|
|
236
|
+
if (!packageEntry) {
|
|
237
|
+
continue;
|
|
238
|
+
}
|
|
239
|
+
const packageInsights = await inspectPackageOfferings({ packageEntry });
|
|
240
|
+
issues.push(...collectDiLabelParityIssuesForPackage({ packageEntry, packageInsights }));
|
|
241
|
+
}
|
|
242
|
+
diLabelIssues = issues;
|
|
243
|
+
}
|
|
244
|
+
const payload = {
|
|
245
|
+
packageCount: packageRegistry.size,
|
|
246
|
+
bundleCount: bundleRegistry.size,
|
|
247
|
+
packages: sortStrings([...packageRegistry.keys()]),
|
|
248
|
+
bundles: sortStrings([...bundleRegistry.keys()]),
|
|
249
|
+
diLabelCheck: shouldCheckDiLabels
|
|
250
|
+
? {
|
|
251
|
+
enabled: true,
|
|
252
|
+
issueCount: diLabelIssues.length,
|
|
253
|
+
issues: diLabelIssues
|
|
254
|
+
}
|
|
255
|
+
: {
|
|
256
|
+
enabled: false
|
|
257
|
+
}
|
|
258
|
+
};
|
|
259
|
+
|
|
260
|
+
if (options.json) {
|
|
261
|
+
stdout.write(`${JSON.stringify(payload, null, 2)}\n`);
|
|
262
|
+
} else {
|
|
263
|
+
const descriptorStatus = shouldCheckDiLabels && diLabelIssues.length > 0 ? "failed" : "passed";
|
|
264
|
+
stdout.write(`Descriptor lint ${descriptorStatus}.\n`);
|
|
265
|
+
stdout.write(`Packages: ${payload.packageCount}\n`);
|
|
266
|
+
stdout.write(`Bundles: ${payload.bundleCount}\n`);
|
|
267
|
+
if (shouldCheckDiLabels) {
|
|
268
|
+
if (diLabelIssues.length === 0) {
|
|
269
|
+
stdout.write("DI label parity check passed.\n");
|
|
270
|
+
} else {
|
|
271
|
+
stdout.write(`DI label parity check failed (${diLabelIssues.length} issue(s)).\n`);
|
|
272
|
+
for (const issue of diLabelIssues) {
|
|
273
|
+
const code = String(issue?.code || "").trim();
|
|
274
|
+
const codeLabel = code ? `[${code}] ` : "";
|
|
275
|
+
stdout.write(`- ${codeLabel}${String(issue?.message || "").trim()}\n`);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
if (shouldCheckDiLabels && diLabelIssues.length > 0) {
|
|
281
|
+
return 1;
|
|
282
|
+
}
|
|
283
|
+
return 0;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
return {
|
|
287
|
+
commandDoctor,
|
|
288
|
+
commandLintDescriptors
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
export { createHealthCommands };
|
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ensureArray,
|
|
3
|
+
ensureObject,
|
|
4
|
+
sortStrings
|
|
5
|
+
} from "../shared/collectionUtils.js";
|
|
6
|
+
|
|
7
|
+
function createListCommands(ctx = {}) {
|
|
8
|
+
const {
|
|
9
|
+
createCliError,
|
|
10
|
+
createColorFormatter,
|
|
11
|
+
normalizeRelativePosixPath,
|
|
12
|
+
resolveAppRootFromCwd,
|
|
13
|
+
loadLockFile,
|
|
14
|
+
loadPackageRegistry,
|
|
15
|
+
loadBundleRegistry,
|
|
16
|
+
loadAppLocalPackageRegistry,
|
|
17
|
+
discoverShellOutletTargetsFromApp,
|
|
18
|
+
resolvePackageKind
|
|
19
|
+
} = ctx;
|
|
20
|
+
|
|
21
|
+
async function commandList({ positional, options, cwd, stdout }) {
|
|
22
|
+
const packageRegistry = await loadPackageRegistry();
|
|
23
|
+
const bundleRegistry = await loadBundleRegistry();
|
|
24
|
+
|
|
25
|
+
const appRoot = await resolveAppRootFromCwd(cwd);
|
|
26
|
+
const appLocalRegistry = await loadAppLocalPackageRegistry(appRoot);
|
|
27
|
+
const { lock } = await loadLockFile(appRoot);
|
|
28
|
+
const installedPackageEntries = ensureObject(lock.installedPackages);
|
|
29
|
+
const installedPackages = new Set(Object.keys(installedPackageEntries));
|
|
30
|
+
const installedUnknownPackageIds = sortStrings(
|
|
31
|
+
[...installedPackages].filter((packageId) => !packageRegistry.has(packageId))
|
|
32
|
+
);
|
|
33
|
+
const installedLocalPackageIds = sortStrings(
|
|
34
|
+
installedUnknownPackageIds.filter((packageId) => {
|
|
35
|
+
const lockEntry = ensureObject(installedPackageEntries[packageId]);
|
|
36
|
+
const sourceType = String(ensureObject(lockEntry.source).type || "").trim();
|
|
37
|
+
return sourceType === "local-package" || sourceType === "app-local-package" || appLocalRegistry.has(packageId);
|
|
38
|
+
})
|
|
39
|
+
);
|
|
40
|
+
const installedExternalPackageIds = sortStrings(
|
|
41
|
+
installedUnknownPackageIds.filter((packageId) => !installedLocalPackageIds.includes(packageId))
|
|
42
|
+
);
|
|
43
|
+
const availableLocalPackageIds = sortStrings(
|
|
44
|
+
[...appLocalRegistry.keys()].filter((packageId) => !installedPackages.has(packageId))
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
const mode = String(positional[0] || "").trim();
|
|
48
|
+
const shouldListBundles = !mode || mode === "bundles";
|
|
49
|
+
const shouldListPackages = !mode || mode === "packages";
|
|
50
|
+
const shouldListGenerators = !mode || mode === "generators";
|
|
51
|
+
if (mode === "placements") {
|
|
52
|
+
throw createCliError('list mode "placements" moved to a dedicated command: jskit list-placements.');
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (!shouldListBundles && !shouldListPackages && !shouldListGenerators) {
|
|
56
|
+
throw createCliError(`Unknown list mode: ${mode}`, { showUsage: true });
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const color = createColorFormatter(stdout);
|
|
60
|
+
const lines = [];
|
|
61
|
+
if (shouldListBundles) {
|
|
62
|
+
lines.push(color.heading("Available bundles:"));
|
|
63
|
+
const bundleIds = sortStrings([...bundleRegistry.keys()]);
|
|
64
|
+
for (const bundleId of bundleIds) {
|
|
65
|
+
const bundle = bundleRegistry.get(bundleId);
|
|
66
|
+
const packageIds = ensureArray(bundle.packages).map((value) => String(value));
|
|
67
|
+
const isInstalled = packageIds.length > 0 && packageIds.every((packageId) => installedPackages.has(packageId));
|
|
68
|
+
const providerLabel = Number(bundle.provider) === 1 ? " [provider]" : "";
|
|
69
|
+
const installedLabel = isInstalled ? " (installed)" : "";
|
|
70
|
+
lines.push(
|
|
71
|
+
`- ${color.item(bundle.bundleId)} ${color.version(`(${bundle.version})`)}${isInstalled ? color.installed(installedLabel) : installedLabel}${providerLabel ? color.provider(providerLabel) : providerLabel}: ${String(bundle.description || "")}`
|
|
72
|
+
);
|
|
73
|
+
if (options.full || options.expanded) {
|
|
74
|
+
for (const packageId of packageIds) {
|
|
75
|
+
lines.push(` - ${color.dim(packageId)}`);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (shouldListPackages) {
|
|
82
|
+
if (lines.length > 0) {
|
|
83
|
+
lines.push("");
|
|
84
|
+
}
|
|
85
|
+
lines.push(color.heading("Available runtime packages:"));
|
|
86
|
+
const packageIds = sortStrings([...packageRegistry.keys()].filter((packageId) => {
|
|
87
|
+
const packageEntry = packageRegistry.get(packageId);
|
|
88
|
+
return resolvePackageKind(packageEntry) === "runtime";
|
|
89
|
+
}));
|
|
90
|
+
for (const packageId of packageIds) {
|
|
91
|
+
const packageEntry = packageRegistry.get(packageId);
|
|
92
|
+
const installedLabel = installedPackages.has(packageId) ? " (installed)" : "";
|
|
93
|
+
lines.push(
|
|
94
|
+
`- ${color.item(packageId)} ${color.version(`(${packageEntry.version})`)}${installedLabel ? color.installed(installedLabel) : ""}`
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (installedLocalPackageIds.length > 0) {
|
|
99
|
+
lines.push("");
|
|
100
|
+
lines.push(color.heading("Installed local packages:"));
|
|
101
|
+
for (const packageId of installedLocalPackageIds) {
|
|
102
|
+
const lockEntry = ensureObject(installedPackageEntries[packageId]);
|
|
103
|
+
const version = String(lockEntry.version || "").trim();
|
|
104
|
+
const versionLabel = version ? ` ${color.version(`(${version})`)}` : "";
|
|
105
|
+
lines.push(`- ${color.item(packageId)}${versionLabel}${color.installed(" (installed)")}`);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (installedExternalPackageIds.length > 0) {
|
|
110
|
+
lines.push("");
|
|
111
|
+
lines.push(color.heading("Installed external packages:"));
|
|
112
|
+
for (const packageId of installedExternalPackageIds) {
|
|
113
|
+
const lockEntry = ensureObject(installedPackageEntries[packageId]);
|
|
114
|
+
const version = String(lockEntry.version || "").trim();
|
|
115
|
+
const versionLabel = version ? ` ${color.version(`(${version})`)}` : "";
|
|
116
|
+
lines.push(`- ${color.item(packageId)}${versionLabel}${color.installed(" (installed)")}`);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (availableLocalPackageIds.length > 0) {
|
|
121
|
+
lines.push("");
|
|
122
|
+
lines.push(color.heading("Available local packages (not installed):"));
|
|
123
|
+
for (const packageId of availableLocalPackageIds) {
|
|
124
|
+
const packageEntry = appLocalRegistry.get(packageId);
|
|
125
|
+
const version = String(packageEntry?.version || "").trim();
|
|
126
|
+
const versionLabel = version ? ` ${color.version(`(${version})`)}` : "";
|
|
127
|
+
lines.push(`- ${color.item(packageId)}${versionLabel}`);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if (shouldListGenerators) {
|
|
133
|
+
if (lines.length > 0) {
|
|
134
|
+
lines.push("");
|
|
135
|
+
}
|
|
136
|
+
lines.push(color.heading("Available generators:"));
|
|
137
|
+
const packageIds = sortStrings([...packageRegistry.keys()].filter((packageId) => {
|
|
138
|
+
const packageEntry = packageRegistry.get(packageId);
|
|
139
|
+
return resolvePackageKind(packageEntry) === "generator";
|
|
140
|
+
}));
|
|
141
|
+
for (const packageId of packageIds) {
|
|
142
|
+
const packageEntry = packageRegistry.get(packageId);
|
|
143
|
+
const installedLabel = installedPackages.has(packageId) ? " (installed)" : "";
|
|
144
|
+
lines.push(
|
|
145
|
+
`- ${color.item(packageId)} ${color.version(`(${packageEntry.version})`)}${installedLabel ? color.installed(installedLabel) : ""}`
|
|
146
|
+
);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (options.json) {
|
|
151
|
+
const payload = {
|
|
152
|
+
bundles: shouldListBundles
|
|
153
|
+
? sortStrings([...bundleRegistry.keys()]).map((bundleId) => {
|
|
154
|
+
const bundle = bundleRegistry.get(bundleId);
|
|
155
|
+
const packageIds = ensureArray(bundle.packages).map((value) => String(value));
|
|
156
|
+
return {
|
|
157
|
+
bundleId: bundle.bundleId,
|
|
158
|
+
version: bundle.version,
|
|
159
|
+
description: bundle.description || "",
|
|
160
|
+
provider: Number(bundle.provider) === 1,
|
|
161
|
+
installed: packageIds.length > 0 && packageIds.every((packageId) => installedPackages.has(packageId)),
|
|
162
|
+
packages: packageIds
|
|
163
|
+
};
|
|
164
|
+
})
|
|
165
|
+
: [],
|
|
166
|
+
packages: shouldListPackages
|
|
167
|
+
? sortStrings([...packageRegistry.keys()])
|
|
168
|
+
.filter((packageId) => resolvePackageKind(packageRegistry.get(packageId)) === "runtime")
|
|
169
|
+
.map((packageId) => {
|
|
170
|
+
const packageEntry = packageRegistry.get(packageId);
|
|
171
|
+
return {
|
|
172
|
+
packageId,
|
|
173
|
+
version: packageEntry.version,
|
|
174
|
+
installed: installedPackages.has(packageId)
|
|
175
|
+
};
|
|
176
|
+
})
|
|
177
|
+
: [],
|
|
178
|
+
runtimePackages: shouldListPackages
|
|
179
|
+
? sortStrings([...packageRegistry.keys()]).map((packageId) => {
|
|
180
|
+
const packageEntry = packageRegistry.get(packageId);
|
|
181
|
+
if (resolvePackageKind(packageEntry) !== "runtime") {
|
|
182
|
+
return null;
|
|
183
|
+
}
|
|
184
|
+
return {
|
|
185
|
+
packageId,
|
|
186
|
+
version: packageEntry.version,
|
|
187
|
+
installed: installedPackages.has(packageId)
|
|
188
|
+
};
|
|
189
|
+
}).filter(Boolean)
|
|
190
|
+
: [],
|
|
191
|
+
generators: shouldListGenerators
|
|
192
|
+
? sortStrings([...packageRegistry.keys()]).map((packageId) => {
|
|
193
|
+
const packageEntry = packageRegistry.get(packageId);
|
|
194
|
+
if (resolvePackageKind(packageEntry) !== "generator") {
|
|
195
|
+
return null;
|
|
196
|
+
}
|
|
197
|
+
return {
|
|
198
|
+
packageId,
|
|
199
|
+
version: packageEntry.version,
|
|
200
|
+
installed: installedPackages.has(packageId)
|
|
201
|
+
};
|
|
202
|
+
}).filter(Boolean)
|
|
203
|
+
: [],
|
|
204
|
+
installedLocalPackages: shouldListPackages
|
|
205
|
+
? installedLocalPackageIds.map((packageId) => {
|
|
206
|
+
const lockEntry = ensureObject(installedPackageEntries[packageId]);
|
|
207
|
+
return {
|
|
208
|
+
packageId,
|
|
209
|
+
version: String(lockEntry.version || "").trim()
|
|
210
|
+
};
|
|
211
|
+
})
|
|
212
|
+
: [],
|
|
213
|
+
installedExternalPackages: shouldListPackages
|
|
214
|
+
? installedExternalPackageIds.map((packageId) => {
|
|
215
|
+
const lockEntry = ensureObject(installedPackageEntries[packageId]);
|
|
216
|
+
return {
|
|
217
|
+
packageId,
|
|
218
|
+
version: String(lockEntry.version || "").trim(),
|
|
219
|
+
source: ensureObject(lockEntry.source)
|
|
220
|
+
};
|
|
221
|
+
})
|
|
222
|
+
: [],
|
|
223
|
+
availableLocalPackages: shouldListPackages
|
|
224
|
+
? availableLocalPackageIds.map((packageId) => {
|
|
225
|
+
const packageEntry = appLocalRegistry.get(packageId);
|
|
226
|
+
return {
|
|
227
|
+
packageId,
|
|
228
|
+
version: String(packageEntry?.version || "").trim(),
|
|
229
|
+
packagePath: normalizeRelativePosixPath(String(packageEntry?.relativeDir || ""))
|
|
230
|
+
};
|
|
231
|
+
})
|
|
232
|
+
: []
|
|
233
|
+
};
|
|
234
|
+
stdout.write(`${JSON.stringify(payload, null, 2)}\n`);
|
|
235
|
+
} else {
|
|
236
|
+
stdout.write(`${lines.join("\n")}\n`);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
return 0;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
async function commandListPlacements({ options, cwd, stdout }) {
|
|
243
|
+
const appRoot = await resolveAppRootFromCwd(cwd);
|
|
244
|
+
const discoveredPlacements = await discoverShellOutletTargetsFromApp({
|
|
245
|
+
appRoot,
|
|
246
|
+
sourceRoot: "src"
|
|
247
|
+
});
|
|
248
|
+
const placementTargets = ensureArray(discoveredPlacements.targets)
|
|
249
|
+
.map((entry) => ensureObject(entry))
|
|
250
|
+
.filter((entry) => String(entry.id || "").trim())
|
|
251
|
+
.sort((left, right) => String(left.id || "").localeCompare(String(right.id || "")));
|
|
252
|
+
|
|
253
|
+
if (options.json) {
|
|
254
|
+
const payload = {
|
|
255
|
+
placements: placementTargets.map((placementTarget) => ({
|
|
256
|
+
id: String(placementTarget.id || "").trim(),
|
|
257
|
+
host: String(placementTarget.host || "").trim(),
|
|
258
|
+
position: String(placementTarget.position || "").trim(),
|
|
259
|
+
default: placementTarget.default === true,
|
|
260
|
+
sourcePath: String(placementTarget.sourcePath || "").trim()
|
|
261
|
+
}))
|
|
262
|
+
};
|
|
263
|
+
stdout.write(`${JSON.stringify(payload, null, 2)}\n`);
|
|
264
|
+
return 0;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
const color = createColorFormatter(stdout);
|
|
268
|
+
const lines = [color.heading("Available placements:")];
|
|
269
|
+
if (placementTargets.length < 1) {
|
|
270
|
+
lines.push("- none");
|
|
271
|
+
} else {
|
|
272
|
+
for (const placementTarget of placementTargets) {
|
|
273
|
+
const placementId = String(placementTarget.id || "").trim();
|
|
274
|
+
const sourcePath = String(placementTarget.sourcePath || "").trim();
|
|
275
|
+
const isDefault = placementTarget.default === true;
|
|
276
|
+
const defaultLabel = isDefault ? color.installed(" (default)") : "";
|
|
277
|
+
const sourceLabel = sourcePath ? ` ${color.dim(`[${sourcePath}]`)}` : "";
|
|
278
|
+
lines.push(`- ${color.item(placementId)}${defaultLabel}${sourceLabel}`);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
stdout.write(`${lines.join("\n")}\n`);
|
|
283
|
+
return 0;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
return {
|
|
287
|
+
commandList,
|
|
288
|
+
commandListPlacements
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
export { createListCommands };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { runPackageCreateCommand } from "./packageCommands/create.js";
|
|
2
|
+
import { runPackageAddCommand } from "./packageCommands/add.js";
|
|
3
|
+
import { runPackageGenerateCommand } from "./packageCommands/generate.js";
|
|
4
|
+
import { runPackageUpdateCommand } from "./packageCommands/update.js";
|
|
5
|
+
import { runPackageMigrationsCommand } from "./packageCommands/migrations.js";
|
|
6
|
+
import { runPackagePositionCommand } from "./packageCommands/position.js";
|
|
7
|
+
import { runPackageRemoveCommand } from "./packageCommands/remove.js";
|
|
8
|
+
|
|
9
|
+
function createPackageCommands(ctx = {}) {
|
|
10
|
+
const commandAdd = async (args) => runPackageAddCommand(ctx, args);
|
|
11
|
+
|
|
12
|
+
return {
|
|
13
|
+
commandCreate: async (args) => runPackageCreateCommand(ctx, args),
|
|
14
|
+
commandAdd,
|
|
15
|
+
commandGenerate: async (args) => runPackageGenerateCommand(ctx, args, { runCommandAdd: commandAdd }),
|
|
16
|
+
commandUpdate: async (args) => runPackageUpdateCommand(ctx, args, { runCommandAdd: commandAdd }),
|
|
17
|
+
commandMigrations: async (args) => runPackageMigrationsCommand(ctx, args),
|
|
18
|
+
commandPosition: async (args) => runPackagePositionCommand(ctx, args),
|
|
19
|
+
commandRemove: async (args) => runPackageRemoveCommand(ctx, args)
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export { createPackageCommands };
|