@jskit-ai/jskit-cli 0.2.27 → 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 -4956
  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,332 @@
1
+ import {
2
+ ensureArray,
3
+ ensureObject
4
+ } from "../../shared/collectionUtils.js";
5
+ import { createShowRenderHelpers } from "./renderHelpers.js";
6
+ import { writePackageExportsSection } from "./renderPackageExports.js";
7
+ import { writeCapabilitiesSections } from "./renderPackageCapabilities.js";
8
+
9
+ function renderPackagePayloadText({
10
+ payload,
11
+ provides,
12
+ requires,
13
+ capabilityDetails,
14
+ options,
15
+ stdout,
16
+ color,
17
+ resolveWrapWidth,
18
+ writeWrappedItems,
19
+ normalizeRelativePosixPath,
20
+ formatPackageSubpathImport,
21
+ normalizePlacementOutlets,
22
+ normalizePlacementContributions,
23
+ shouldShowPackageExportTarget,
24
+ classifyExportedSymbols,
25
+ deriveProviderDisplayName
26
+ } = {}) {
27
+ const wrapWidth = resolveWrapWidth(stdout, 80);
28
+ const {
29
+ writeBindingsSection,
30
+ writeField,
31
+ writeRuntimeProviders
32
+ } = createShowRenderHelpers({
33
+ stdout,
34
+ color,
35
+ options,
36
+ deriveProviderDisplayName
37
+ });
38
+
39
+ const runtimeMutations = ensureObject(ensureObject(payload.mutations).dependencies).runtime || {};
40
+ const devMutations = ensureObject(ensureObject(payload.mutations).dependencies).dev || {};
41
+ const scriptMutations = ensureObject(ensureObject(payload.mutations).packageJson).scripts || {};
42
+ const textMutations = ensureArray(ensureObject(payload.mutations).text);
43
+ const runtimeMutationEntries = Object.entries(ensureObject(runtimeMutations));
44
+ const devMutationEntries = Object.entries(ensureObject(devMutations));
45
+ const scriptMutationEntries = Object.entries(ensureObject(scriptMutations));
46
+
47
+ const introspection = ensureObject(payload.introspection);
48
+ const introspectionAvailable = introspection.available === true;
49
+ const introspectionNotes = ensureArray(introspection.notes)
50
+ .map((value) => String(value || "").trim())
51
+ .filter(Boolean);
52
+
53
+ const metadataApiSummary = ensureObject(ensureObject(payload.metadata).apiSummary);
54
+ const metadataUi = ensureObject(ensureObject(payload.metadata).ui);
55
+ const summarySurfaces = ensureArray(metadataApiSummary.surfaces)
56
+ .map((entry) => {
57
+ const record = ensureObject(entry);
58
+ return {
59
+ subpath: String(record.subpath || "").trim(),
60
+ summary: String(record.summary || "").trim()
61
+ };
62
+ })
63
+ .filter((entry) => entry.subpath && entry.summary);
64
+ const containerTokenSummary = ensureObject(metadataApiSummary.containerTokens);
65
+ const quickServerTokens = ensureArray(containerTokenSummary.server).map((value) => String(value || "").trim()).filter(Boolean);
66
+ const quickClientTokens = ensureArray(containerTokenSummary.client).map((value) => String(value || "").trim()).filter(Boolean);
67
+ const metadataUiPlacements = ensureObject(metadataUi.placements);
68
+ const placementOutlets = normalizePlacementOutlets(metadataUiPlacements.outlets);
69
+ const placementContributions = normalizePlacementContributions(metadataUiPlacements.contributions);
70
+ const bindingSections = ensureObject(payload.containerBindings);
71
+ const serverBindings = ensureArray(bindingSections.server);
72
+ const clientBindings = ensureArray(bindingSections.client);
73
+
74
+ stdout.write(`${color.heading("Information")}\n`);
75
+ writeField("Package", payload.packageId, color.item);
76
+ writeField("Version", payload.version, color.installed);
77
+ if (payload.description) {
78
+ writeField("Description", payload.description);
79
+ }
80
+ writeField("Descriptor", payload.descriptorPath, color.dim);
81
+
82
+ if (summarySurfaces.length > 0) {
83
+ stdout.write(`${color.heading("Summary:")}\n`);
84
+ for (const summaryEntry of summarySurfaces) {
85
+ const importPath = formatPackageSubpathImport(payload.packageId, summaryEntry.subpath);
86
+ stdout.write(`- ${color.item(`${importPath}:`)}\n`);
87
+ stdout.write(` ${summaryEntry.summary}\n`);
88
+ }
89
+ }
90
+
91
+ if (quickServerTokens.length > 0 || quickClientTokens.length > 0) {
92
+ stdout.write(`${color.heading("Container tokens")} ${color.dim("-- app.make('...'):")}\n`);
93
+ if (quickServerTokens.length > 0) {
94
+ stdout.write(`- ${color.installed("server")}: ${quickServerTokens.map((token) => color.item(token)).join(", ")}\n`);
95
+ }
96
+ if (quickClientTokens.length > 0) {
97
+ stdout.write(`- ${color.installed("client")}: ${quickClientTokens.map((token) => color.item(token)).join(", ")}\n`);
98
+ }
99
+ }
100
+
101
+ if (placementOutlets.length > 0) {
102
+ stdout.write(`${color.heading(`Placement outlets (accepted host/position pairs) (${placementOutlets.length}):`)}\n`);
103
+ for (const outlet of placementOutlets) {
104
+ const surfaces = ensureArray(outlet.surfaces).map((value) => String(value || "").trim()).filter(Boolean);
105
+ const surfacesLabel = surfaces.length > 0 ? ` ${color.installed(`[surfaces:${surfaces.join(", ")}]`)}` : "";
106
+ const description = String(outlet.description || "").trim();
107
+ const descriptionSuffix = description ? `: ${description}` : "";
108
+ stdout.write(`- ${color.item(`${outlet.host}.${outlet.position}`)}${surfacesLabel}${descriptionSuffix}\n`);
109
+ if (options.details) {
110
+ const sourceLabel = String(outlet.source || "").trim();
111
+ if (sourceLabel) {
112
+ stdout.write(` ${color.dim(`source: ${sourceLabel}`)}\n`);
113
+ }
114
+ }
115
+ }
116
+ }
117
+
118
+ if (placementContributions.length > 0) {
119
+ stdout.write(`${color.heading(`Placement contributions (default entries) (${placementContributions.length}):`)}\n`);
120
+ for (const contribution of placementContributions) {
121
+ const surfaces = ensureArray(contribution.surfaces).map((value) => String(value || "").trim()).filter(Boolean);
122
+ const surfacesLabel = surfaces.length > 0 ? surfaces.join(", ") : "*";
123
+ const orderSuffix = Number.isFinite(contribution.order) ? ` ${color.installed(`[order:${contribution.order}]`)}` : "";
124
+ const componentToken = String(contribution.componentToken || "").trim();
125
+ const componentSuffix = componentToken ? ` ${color.dim(`component:${componentToken}`)}` : "";
126
+ const description = String(contribution.description || "").trim();
127
+ const descriptionSuffix = description ? `: ${description}` : "";
128
+ stdout.write(
129
+ `- ${color.item(contribution.id)} ${color.dim("->")} ${color.item(`${contribution.host}.${contribution.position}`)} ${color.installed(`[surfaces:${surfacesLabel}]`)}${orderSuffix}${componentSuffix}${descriptionSuffix}\n`
130
+ );
131
+ if (options.details) {
132
+ const when = String(contribution.when || "").trim();
133
+ if (when) {
134
+ stdout.write(` ${color.dim(`when: ${when}`)}\n`);
135
+ }
136
+ const sourceLabel = String(contribution.source || "").trim();
137
+ if (sourceLabel) {
138
+ stdout.write(` ${color.dim(`source: ${sourceLabel}`)}\n`);
139
+ }
140
+ }
141
+ }
142
+ }
143
+
144
+ if (introspectionAvailable) {
145
+ writeBindingsSection("server", serverBindings);
146
+ writeBindingsSection("client", clientBindings);
147
+ }
148
+
149
+ writePackageExportsSection({
150
+ payload,
151
+ options,
152
+ stdout,
153
+ color,
154
+ wrapWidth,
155
+ normalizeRelativePosixPath,
156
+ shouldShowPackageExportTarget,
157
+ classifyExportedSymbols,
158
+ writeWrappedItems
159
+ });
160
+
161
+ if (payload.dependsOn.length > 0) {
162
+ writeWrappedItems({
163
+ stdout,
164
+ heading: `${color.heading("Depends on")} ${color.installed(`(${payload.dependsOn.length})`)}:`,
165
+ wrapWidth,
166
+ items: payload.dependsOn.map((dependencyId) => {
167
+ const text = String(dependencyId);
168
+ return {
169
+ text,
170
+ rendered: color.item(text)
171
+ };
172
+ })
173
+ });
174
+ }
175
+
176
+ if (runtimeMutationEntries.length > 0) {
177
+ writeWrappedItems({
178
+ stdout,
179
+ heading: color.heading(`Dependency mutations runtime (${runtimeMutationEntries.length}):`),
180
+ wrapWidth,
181
+ items: runtimeMutationEntries.map(([dependencyId, versionSpec]) => {
182
+ const dependencyText = String(dependencyId);
183
+ const versionText = String(versionSpec);
184
+ return {
185
+ text: `${dependencyText} ${versionText}`,
186
+ rendered: `${color.item(dependencyText)} ${color.installed(versionText)}`
187
+ };
188
+ })
189
+ });
190
+ }
191
+
192
+ writeCapabilitiesSections({
193
+ payload,
194
+ provides,
195
+ requires,
196
+ capabilityDetails,
197
+ stdout,
198
+ color,
199
+ wrapWidth,
200
+ writeWrappedItems
201
+ });
202
+
203
+ const uiRoutes = ensureArray(ensureObject(payload.metadata.ui).routes);
204
+ if (uiRoutes.length > 0) {
205
+ stdout.write(`${color.heading(`UI routes (${uiRoutes.length}):`)}\n`);
206
+ for (const route of uiRoutes) {
207
+ const record = ensureObject(route);
208
+ const routePath = String(record.path || "").trim();
209
+ const scope = String(record.scope || "").trim();
210
+ const routeId = String(record.id || record.name || "").trim();
211
+ const purpose = String(record.purpose || "").trim();
212
+ const modeLabel = record.autoRegister === false ? "advisory" : "auto";
213
+ const scopeLabel = scope ? ` (${scope})` : "";
214
+ const modePart = ` ${color.installed(`[${modeLabel}]`)}`;
215
+ const purposePart = purpose ? ` ${purpose}` : "";
216
+ const idPart = routeId ? ` ${color.installed(`(id:${routeId})`)}` : "";
217
+ stdout.write(`- ${color.item(routePath)}${color.installed(scopeLabel)}${modePart}${purposePart}${idPart}\n`);
218
+ }
219
+ }
220
+
221
+ const serverRoutes = ensureArray(ensureObject(payload.metadata.server).routes);
222
+ if (serverRoutes.length > 0) {
223
+ stdout.write(`${color.heading(`Server routes (${serverRoutes.length}):`)}\n`);
224
+ for (const route of serverRoutes) {
225
+ const record = ensureObject(route);
226
+ const method = String(record.method || "").trim().toUpperCase();
227
+ const routePath = String(record.path || "").trim();
228
+ const summary = String(record.summary || "").trim();
229
+ const routeLabel = `${method} ${routePath}`.trim();
230
+ const summarySuffix = summary ? `: ${summary}` : "";
231
+ stdout.write(`- ${color.item(routeLabel)}${summarySuffix}\n`);
232
+ }
233
+ }
234
+
235
+ const optionNames = Object.keys(ensureObject(payload.options));
236
+ if (optionNames.length > 0) {
237
+ stdout.write(`${color.heading(`Options (${optionNames.length}):`)}\n`);
238
+ for (const optionName of optionNames) {
239
+ const schema = ensureObject(payload.options[optionName]);
240
+ const required = schema.required ? "required" : "optional";
241
+ const defaultSuffix = schema.defaultValue ? ` (default: ${schema.defaultValue})` : "";
242
+ stdout.write(`- ${color.item(optionName)} ${color.installed(`[${required}]`)}${color.dim(defaultSuffix)}\n`);
243
+ }
244
+ }
245
+
246
+ if (devMutationEntries.length > 0) {
247
+ writeWrappedItems({
248
+ stdout,
249
+ heading: color.heading(`Dependency mutations dev (${devMutationEntries.length}):`),
250
+ wrapWidth,
251
+ items: devMutationEntries.map(([dependencyId, versionSpec]) => {
252
+ const dependencyText = String(dependencyId);
253
+ const versionText = String(versionSpec);
254
+ return {
255
+ text: `${dependencyText} ${versionText}`,
256
+ rendered: `${color.item(dependencyText)} ${color.installed(versionText)}`
257
+ };
258
+ })
259
+ });
260
+ }
261
+
262
+ if (scriptMutationEntries.length > 0) {
263
+ stdout.write(`${color.heading(`Script mutations (${scriptMutationEntries.length}):`)}\n`);
264
+ for (const [scriptName, scriptValue] of scriptMutationEntries) {
265
+ stdout.write(`- ${color.item(scriptName)}: ${String(scriptValue)}\n`);
266
+ }
267
+ }
268
+
269
+ if (textMutations.length > 0) {
270
+ stdout.write(`${color.heading(`Text mutations (${textMutations.length}):`)}\n`);
271
+ for (const mutation of textMutations) {
272
+ const record = ensureObject(mutation);
273
+ const op = String(record.op || "").trim();
274
+ const file = String(record.file || "").trim();
275
+ const key = String(record.key || "").trim();
276
+ const position = String(record.position || "").trim();
277
+ const reason = String(record.reason || "").trim();
278
+ const reasonSuffix = reason ? `: ${reason}` : "";
279
+ let mutationLabel = `${op} ${file} ${key}`.trim();
280
+ if (op === "append-text") {
281
+ mutationLabel = `${op} ${file}`;
282
+ if (position) {
283
+ mutationLabel = `${mutationLabel} [${position}]`;
284
+ }
285
+ }
286
+ stdout.write(`- ${color.item(mutationLabel)}${reasonSuffix}\n`);
287
+ }
288
+ }
289
+
290
+ if (payload.fileWritePlan.fileCount > 0) {
291
+ stdout.write(`${color.heading(`File writes (${payload.fileWritePlan.fileCount}):`)}\n`);
292
+ for (const group of payload.fileWritePlan.groups) {
293
+ const groupId = String(group.id || "").trim();
294
+ const category = String(group.category || "").trim();
295
+ const reason = String(group.reason || "").trim();
296
+ const files = ensureArray(group.files);
297
+ let marker = "";
298
+ if (groupId) {
299
+ marker = `id:${groupId}`;
300
+ } else if (category) {
301
+ marker = `category:${category}`;
302
+ }
303
+ const markerSuffix = marker ? ` (${marker})` : "";
304
+ for (const file of files) {
305
+ const targetPath = String(ensureObject(file).to || "").trim();
306
+ if (!targetPath) {
307
+ continue;
308
+ }
309
+ stdout.write(`- ${color.item(targetPath)}${color.installed(markerSuffix)}:\n`);
310
+ if (reason) {
311
+ stdout.write(` ${reason}\n`);
312
+ }
313
+ }
314
+ }
315
+ }
316
+
317
+ const serverProviders = ensureArray(ensureObject(payload.runtime.server).providers);
318
+ const clientProviders = ensureArray(ensureObject(payload.runtime.client).providers);
319
+ writeRuntimeProviders("server", serverProviders);
320
+ writeRuntimeProviders("client", clientProviders);
321
+
322
+ if (introspectionNotes.length > 0) {
323
+ stdout.write(`${color.heading(`Introspection notes (${introspectionNotes.length}):`)}\n`);
324
+ for (const note of introspectionNotes) {
325
+ stdout.write(`- ${color.dim(note)}\n`);
326
+ }
327
+ }
328
+ }
329
+
330
+ export {
331
+ renderPackagePayloadText
332
+ };
@@ -0,0 +1,114 @@
1
+ import { createShowRenderHelpers } from "./show/renderHelpers.js";
2
+ import {
3
+ buildBundleShowPayload,
4
+ buildPackageShowPayload
5
+ } from "./show/payloads.js";
6
+ import { renderBundlePayloadText } from "./show/renderBundleText.js";
7
+ import { renderPackagePayloadText } from "./show/renderPackageText.js";
8
+
9
+ function createShowCommand(ctx = {}) {
10
+ const {
11
+ createCliError,
12
+ createColorFormatter,
13
+ resolveWrapWidth,
14
+ writeWrappedItems,
15
+ normalizeRelativePosixPath,
16
+ resolvePackageIdInput,
17
+ loadPackageRegistry,
18
+ loadBundleRegistry,
19
+ inspectPackageOfferings,
20
+ buildFileWriteGroups,
21
+ listDeclaredCapabilities,
22
+ buildCapabilityDetailsForPackage,
23
+ formatPackageSubpathImport,
24
+ normalizePlacementOutlets,
25
+ normalizePlacementContributions,
26
+ shouldShowPackageExportTarget,
27
+ classifyExportedSymbols,
28
+ deriveProviderDisplayName
29
+ } = ctx;
30
+
31
+ async function commandShow({ positional, options, stdout }) {
32
+ const id = String(positional[0] || "").trim();
33
+ if (!id) {
34
+ throw createCliError("show requires an id.", { showUsage: true });
35
+ }
36
+
37
+ const packageRegistry = await loadPackageRegistry();
38
+ const bundleRegistry = await loadBundleRegistry();
39
+ const color = createColorFormatter(stdout);
40
+ const resolvedPackageId = resolvePackageIdInput(id, packageRegistry);
41
+
42
+ if (resolvedPackageId) {
43
+ const packageEntry = packageRegistry.get(resolvedPackageId);
44
+ const {
45
+ payload,
46
+ provides,
47
+ requires,
48
+ capabilityDetails
49
+ } = await buildPackageShowPayload({
50
+ packageRegistry,
51
+ packageEntry,
52
+ options,
53
+ inspectPackageOfferings,
54
+ buildFileWriteGroups,
55
+ listDeclaredCapabilities,
56
+ buildCapabilityDetailsForPackage
57
+ });
58
+
59
+ if (options.json) {
60
+ stdout.write(`${JSON.stringify(payload, null, 2)}\n`);
61
+ } else {
62
+ renderPackagePayloadText({
63
+ payload,
64
+ provides,
65
+ requires,
66
+ capabilityDetails,
67
+ options,
68
+ stdout,
69
+ color,
70
+ resolveWrapWidth,
71
+ writeWrappedItems,
72
+ normalizeRelativePosixPath,
73
+ formatPackageSubpathImport,
74
+ normalizePlacementOutlets,
75
+ normalizePlacementContributions,
76
+ shouldShowPackageExportTarget,
77
+ classifyExportedSymbols,
78
+ deriveProviderDisplayName
79
+ });
80
+ }
81
+ return 0;
82
+ }
83
+
84
+ if (bundleRegistry.has(id)) {
85
+ const bundle = bundleRegistry.get(id);
86
+ const payload = buildBundleShowPayload(bundle);
87
+ if (options.json) {
88
+ stdout.write(`${JSON.stringify(payload, null, 2)}\n`);
89
+ } else {
90
+ const { writeField } = createShowRenderHelpers({
91
+ stdout,
92
+ color,
93
+ options,
94
+ deriveProviderDisplayName
95
+ });
96
+ renderBundlePayloadText({
97
+ payload,
98
+ stdout,
99
+ color,
100
+ writeField
101
+ });
102
+ }
103
+ return 0;
104
+ }
105
+
106
+ throw createCliError(`Unknown package or bundle: ${id}`);
107
+ }
108
+
109
+ return {
110
+ commandShow
111
+ };
112
+ }
113
+
114
+ export { createShowCommand };
@@ -0,0 +1,144 @@
1
+ import { isKnownCommandName, resolveCommandAlias } from "./commandCatalog.js";
2
+
3
+ function parseArgs(argv, { createCliError } = {}) {
4
+ if (typeof createCliError !== "function") {
5
+ throw new TypeError("parseArgs requires createCliError.");
6
+ }
7
+
8
+ const args = Array.isArray(argv) ? [...argv] : [];
9
+ const firstToken = String(args[0] || "").trim();
10
+ if (firstToken === "--help" || firstToken === "-h") {
11
+ args.shift();
12
+ return {
13
+ command: "help",
14
+ options: {
15
+ dryRun: false,
16
+ runNpmInstall: false,
17
+ full: false,
18
+ expanded: false,
19
+ details: false,
20
+ debugExports: false,
21
+ checkDiLabels: false,
22
+ verbose: false,
23
+ json: false,
24
+ all: false,
25
+ help: true,
26
+ inlineOptions: {}
27
+ },
28
+ positional: []
29
+ };
30
+ }
31
+
32
+ const rawCommand = String(args.shift() || "help").trim() || "help";
33
+ const command = resolveCommandAlias(rawCommand);
34
+
35
+ if (!isKnownCommandName(command)) {
36
+ throw createCliError(`Unknown command: ${rawCommand}`, { showUsage: true });
37
+ }
38
+
39
+ const options = {
40
+ dryRun: false,
41
+ runNpmInstall: false,
42
+ full: false,
43
+ expanded: false,
44
+ details: false,
45
+ debugExports: false,
46
+ checkDiLabels: false,
47
+ verbose: false,
48
+ json: false,
49
+ all: false,
50
+ help: false,
51
+ inlineOptions: {}
52
+ };
53
+ const positional = [];
54
+
55
+ while (args.length > 0) {
56
+ const token = String(args.shift() || "");
57
+
58
+ if (token === "--dry-run") {
59
+ options.dryRun = true;
60
+ continue;
61
+ }
62
+ if (token === "--run-npm-install") {
63
+ options.runNpmInstall = true;
64
+ continue;
65
+ }
66
+ if (token === "--full") {
67
+ options.full = true;
68
+ continue;
69
+ }
70
+ if (token === "--expanded") {
71
+ options.expanded = true;
72
+ continue;
73
+ }
74
+ if (token === "--details") {
75
+ options.details = true;
76
+ continue;
77
+ }
78
+ if (token === "--debug-exports") {
79
+ options.debugExports = true;
80
+ continue;
81
+ }
82
+ if (token === "--check-di-labels") {
83
+ options.checkDiLabels = true;
84
+ continue;
85
+ }
86
+ if (token === "--verbose") {
87
+ options.verbose = true;
88
+ continue;
89
+ }
90
+ if (token === "--json") {
91
+ options.json = true;
92
+ continue;
93
+ }
94
+ if (token === "--all") {
95
+ options.all = true;
96
+ continue;
97
+ }
98
+ if (token === "--help" || token === "-h") {
99
+ options.help = true;
100
+ continue;
101
+ }
102
+
103
+ if (token.startsWith("--")) {
104
+ const withoutPrefix = token.slice(2);
105
+ const hasInlineValue = withoutPrefix.includes("=");
106
+ const optionName = hasInlineValue ? withoutPrefix.slice(0, withoutPrefix.indexOf("=")) : withoutPrefix;
107
+ const optionValueRaw = hasInlineValue
108
+ ? withoutPrefix.slice(withoutPrefix.indexOf("=") + 1)
109
+ : args.shift();
110
+
111
+ if (!/^[a-z][a-z0-9-]*$/.test(optionName)) {
112
+ throw createCliError(`Unknown option: ${token}`, { showUsage: true });
113
+ }
114
+ if (typeof optionValueRaw !== "string") {
115
+ throw createCliError(`--${optionName} requires a value.`, { showUsage: true });
116
+ }
117
+ const optionValue = optionValueRaw.trim();
118
+ if (!hasInlineValue && optionValue.startsWith("-")) {
119
+ throw createCliError(`--${optionName} requires a value.`, { showUsage: true });
120
+ }
121
+
122
+ options.inlineOptions[optionName] = optionValue;
123
+ continue;
124
+ }
125
+
126
+ if (token.startsWith("-")) {
127
+ throw createCliError(`Unknown option: ${token}`, { showUsage: true });
128
+ }
129
+
130
+ positional.push(token);
131
+ }
132
+
133
+ if (options.debugExports) {
134
+ options.details = true;
135
+ }
136
+
137
+ return {
138
+ command,
139
+ options,
140
+ positional
141
+ };
142
+ }
143
+
144
+ export { parseArgs };
@@ -49,7 +49,8 @@ function createCommandHandlerDeps(deps = {}) {
49
49
  removeEnvValue: deps.removeEnvValue,
50
50
  removeManagedViteProxyEntries: deps.removeManagedViteProxyEntries,
51
51
  hashBuffer: deps.hashBuffer,
52
- rm: deps.rm
52
+ rm: deps.rm,
53
+ discoverShellOutletTargetsFromApp: deps.discoverShellOutletTargetsFromApp
53
54
  };
54
55
  }
55
56
 
@@ -0,0 +1,47 @@
1
+ const KNOWN_COMMAND_IDS = Object.freeze([
2
+ "help",
3
+ "create",
4
+ "generate",
5
+ "list",
6
+ "list-placements",
7
+ "show",
8
+ "view",
9
+ "migrations",
10
+ "add",
11
+ "position",
12
+ "update",
13
+ "remove",
14
+ "doctor",
15
+ "lint-descriptors"
16
+ ]);
17
+
18
+ const KNOWN_COMMANDS = new Set(KNOWN_COMMAND_IDS);
19
+
20
+ const COMMAND_ALIASES = Object.freeze({
21
+ view: "show",
22
+ ls: "list",
23
+ gen: "generate",
24
+ lp: "list-placements"
25
+ });
26
+
27
+ function resolveCommandAlias(rawCommand) {
28
+ const command = String(rawCommand || "").trim();
29
+ if (!command) {
30
+ return "";
31
+ }
32
+ return COMMAND_ALIASES[command] || command;
33
+ }
34
+
35
+ function isKnownCommandName(rawCommand) {
36
+ const command = resolveCommandAlias(rawCommand);
37
+ if (!command) {
38
+ return false;
39
+ }
40
+ return KNOWN_COMMANDS.has(command);
41
+ }
42
+
43
+ export {
44
+ KNOWN_COMMAND_IDS,
45
+ resolveCommandAlias,
46
+ isKnownCommandName
47
+ };