@jskit-ai/jskit-cli 0.2.41 → 0.2.43
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 +4 -3
- package/src/server/cliRuntime/completion.js +1177 -0
- package/src/server/cliRuntime/descriptorValidation.js +18 -3
- package/src/server/cliRuntime/ioAndMigrations.js +2 -2
- package/src/server/cliRuntime/mutationApplication.js +1 -1
- package/src/server/cliRuntime/mutationWhen.js +2 -0
- package/src/server/cliRuntime/mutations/fileMutations.js +188 -143
- package/src/server/cliRuntime/mutations/installMigrationMutation.js +11 -38
- package/src/server/cliRuntime/mutations/templateContext.js +8 -14
- package/src/server/cliRuntime/mutations/textMutations.js +11 -6
- package/src/server/cliRuntime/packageInstallFlow.js +36 -21
- package/src/server/cliRuntime/packageIntrospection/placementNormalization.js +13 -22
- package/src/server/cliRuntime/packageOptions.js +149 -3
- package/src/server/cliRuntime/packageRegistries.js +3 -2
- package/src/server/commandHandlers/completion.js +129 -0
- package/src/server/commandHandlers/list.js +4 -6
- package/src/server/commandHandlers/packageCommands/add.js +31 -11
- package/src/server/commandHandlers/packageCommands/discoverabilityHelp.js +10 -2
- package/src/server/commandHandlers/packageCommands/generate.js +29 -31
- package/src/server/commandHandlers/packageCommands/tabLinkItemProvisioning.js +123 -164
- package/src/server/commandHandlers/shared.js +23 -3
- package/src/server/commandHandlers/show/renderPackageText.js +3 -3
- package/src/server/core/argParser.js +12 -2
- package/src/server/core/commandCatalog.js +36 -13
- package/src/server/core/createCommandHandlers.js +3 -0
- package/src/server/shared/optionInterpolation.js +93 -0
|
@@ -30,9 +30,8 @@ function canDelegateAddInlineOptions(positional = []) {
|
|
|
30
30
|
function canDelegateGenerateInlineOptions(positional = []) {
|
|
31
31
|
const normalizedPositionals = Array.isArray(positional) ? positional : [];
|
|
32
32
|
const first = String(normalizedPositionals[0] || "").trim();
|
|
33
|
-
const second = String(normalizedPositionals[1] || "").trim();
|
|
34
33
|
const last = String(normalizedPositionals[normalizedPositionals.length - 1] || "").trim();
|
|
35
|
-
if (!first ||
|
|
34
|
+
if (!first || isHelpToken(first) || isHelpToken(last)) {
|
|
36
35
|
return false;
|
|
37
36
|
}
|
|
38
37
|
return true;
|
|
@@ -77,6 +76,31 @@ const COMMAND_DESCRIPTORS = Object.freeze({
|
|
|
77
76
|
inlineOptionMode: "none",
|
|
78
77
|
allowedValueOptionNames: Object.freeze([])
|
|
79
78
|
}),
|
|
79
|
+
completion: Object.freeze({
|
|
80
|
+
command: "completion",
|
|
81
|
+
aliases: Object.freeze([]),
|
|
82
|
+
showInOverview: true,
|
|
83
|
+
summary: "Print shell completion script support.",
|
|
84
|
+
minimalUse: "jskit completion bash",
|
|
85
|
+
parameters: Object.freeze([
|
|
86
|
+
Object.freeze({
|
|
87
|
+
name: "<shell>",
|
|
88
|
+
description: "Shell name. Currently only bash is supported."
|
|
89
|
+
})
|
|
90
|
+
]),
|
|
91
|
+
defaults: Object.freeze([
|
|
92
|
+
"Prints a shell completion script to stdout.",
|
|
93
|
+
"Use --install to write a small Bash loader file and wire ~/.bashrc automatically.",
|
|
94
|
+
"Use source <(npx jskit completion bash) to enable completion in the current shell.",
|
|
95
|
+
"The internal __complete__ mode is reserved for the generated shell function."
|
|
96
|
+
]),
|
|
97
|
+
fullUse: "jskit completion bash [--install]",
|
|
98
|
+
showHelpOnBareInvocation: true,
|
|
99
|
+
handlerName: "commandCompletion",
|
|
100
|
+
allowedFlagKeys: Object.freeze([]),
|
|
101
|
+
inlineOptionMode: "enumerated",
|
|
102
|
+
allowedValueOptionNames: Object.freeze(["install"])
|
|
103
|
+
}),
|
|
80
104
|
create: Object.freeze({
|
|
81
105
|
command: "create",
|
|
82
106
|
aliases: Object.freeze([]),
|
|
@@ -135,7 +159,7 @@ const COMMAND_DESCRIPTORS = Object.freeze({
|
|
|
135
159
|
}),
|
|
136
160
|
generate: Object.freeze({
|
|
137
161
|
command: "generate",
|
|
138
|
-
aliases: Object.freeze([
|
|
162
|
+
aliases: Object.freeze([]),
|
|
139
163
|
showInOverview: true,
|
|
140
164
|
summary: "Run a generator package (or generator subcommand).",
|
|
141
165
|
minimalUse: "jskit generate <generatorId>",
|
|
@@ -188,7 +212,7 @@ const COMMAND_DESCRIPTORS = Object.freeze({
|
|
|
188
212
|
}),
|
|
189
213
|
list: Object.freeze({
|
|
190
214
|
command: "list",
|
|
191
|
-
aliases: Object.freeze([
|
|
215
|
+
aliases: Object.freeze([]),
|
|
192
216
|
showInOverview: true,
|
|
193
217
|
summary: "List bundles, runtime packages, or generator packages.",
|
|
194
218
|
minimalUse: "jskit list",
|
|
@@ -212,7 +236,7 @@ const COMMAND_DESCRIPTORS = Object.freeze({
|
|
|
212
236
|
}),
|
|
213
237
|
"list-placements": Object.freeze({
|
|
214
238
|
command: "list-placements",
|
|
215
|
-
aliases: Object.freeze([
|
|
239
|
+
aliases: Object.freeze([]),
|
|
216
240
|
showInOverview: true,
|
|
217
241
|
summary: "List discovered UI placement targets.",
|
|
218
242
|
minimalUse: "jskit list-placements",
|
|
@@ -229,12 +253,12 @@ const COMMAND_DESCRIPTORS = Object.freeze({
|
|
|
229
253
|
inlineOptionMode: "none",
|
|
230
254
|
allowedValueOptionNames: Object.freeze([])
|
|
231
255
|
}),
|
|
232
|
-
"list-
|
|
233
|
-
command: "list-
|
|
234
|
-
aliases: Object.freeze([
|
|
256
|
+
"list-component-tokens": Object.freeze({
|
|
257
|
+
command: "list-component-tokens",
|
|
258
|
+
aliases: Object.freeze([]),
|
|
235
259
|
showInOverview: true,
|
|
236
|
-
summary: "List available placement
|
|
237
|
-
minimalUse: "jskit list-
|
|
260
|
+
summary: "List available placement component tokens.",
|
|
261
|
+
minimalUse: "jskit list-component-tokens",
|
|
238
262
|
parameters: Object.freeze([
|
|
239
263
|
Object.freeze({
|
|
240
264
|
name: "[--prefix <value>]",
|
|
@@ -252,7 +276,7 @@ const COMMAND_DESCRIPTORS = Object.freeze({
|
|
|
252
276
|
"Use --all when you want the full discovered token set.",
|
|
253
277
|
"Shows plain text by default; use --json for structured output."
|
|
254
278
|
]),
|
|
255
|
-
fullUse: "jskit list-
|
|
279
|
+
fullUse: "jskit list-component-tokens [--prefix <value>] [--all] [--json]",
|
|
256
280
|
showHelpOnBareInvocation: false,
|
|
257
281
|
handlerName: "commandListLinkItems",
|
|
258
282
|
allowedFlagKeys: Object.freeze(["json", "all"]),
|
|
@@ -261,7 +285,7 @@ const COMMAND_DESCRIPTORS = Object.freeze({
|
|
|
261
285
|
}),
|
|
262
286
|
show: Object.freeze({
|
|
263
287
|
command: "show",
|
|
264
|
-
aliases: Object.freeze([
|
|
288
|
+
aliases: Object.freeze([]),
|
|
265
289
|
showInOverview: true,
|
|
266
290
|
summary: "Show detailed metadata for a bundle or package.",
|
|
267
291
|
minimalUse: "jskit show <id>",
|
|
@@ -272,7 +296,6 @@ const COMMAND_DESCRIPTORS = Object.freeze({
|
|
|
272
296
|
})
|
|
273
297
|
]),
|
|
274
298
|
defaults: Object.freeze([
|
|
275
|
-
"view is an alias of show.",
|
|
276
299
|
"Basic output is compact; --details expands capability and runtime sections.",
|
|
277
300
|
"--debug-exports implies --details."
|
|
278
301
|
]),
|
|
@@ -3,6 +3,7 @@ import { createListCommands } from "../commandHandlers/list.js";
|
|
|
3
3
|
import { createShowCommand } from "../commandHandlers/show.js";
|
|
4
4
|
import { createPackageCommands } from "../commandHandlers/package.js";
|
|
5
5
|
import { createHealthCommands } from "../commandHandlers/health.js";
|
|
6
|
+
import { createCompletionCommands } from "../commandHandlers/completion.js";
|
|
6
7
|
|
|
7
8
|
function createCommandHandlers(deps = {}) {
|
|
8
9
|
const shared = createCommandHandlerShared(deps);
|
|
@@ -23,11 +24,13 @@ function createCommandHandlers(deps = {}) {
|
|
|
23
24
|
commandRemove
|
|
24
25
|
} = createPackageCommands(commandContext);
|
|
25
26
|
const { commandDoctor, commandLintDescriptors } = createHealthCommands(commandContext);
|
|
27
|
+
const { commandCompletion } = createCompletionCommands(commandContext);
|
|
26
28
|
|
|
27
29
|
return {
|
|
28
30
|
commandList,
|
|
29
31
|
commandListPlacements,
|
|
30
32
|
commandListLinkItems,
|
|
33
|
+
commandCompletion,
|
|
31
34
|
commandShow,
|
|
32
35
|
commandCreate,
|
|
33
36
|
commandAdd,
|
|
@@ -209,6 +209,80 @@ function normalizePathValue(value) {
|
|
|
209
209
|
.join("/");
|
|
210
210
|
}
|
|
211
211
|
|
|
212
|
+
function normalizePromptChoices(rawChoices = []) {
|
|
213
|
+
return ensureArray(rawChoices)
|
|
214
|
+
.map((entry) => {
|
|
215
|
+
if (!entry || typeof entry !== "object") {
|
|
216
|
+
return null;
|
|
217
|
+
}
|
|
218
|
+
const value = String(entry.value || "").trim();
|
|
219
|
+
const label = String(entry.label || value).trim();
|
|
220
|
+
if (!value || !label) {
|
|
221
|
+
return null;
|
|
222
|
+
}
|
|
223
|
+
return Object.freeze({ value, label });
|
|
224
|
+
})
|
|
225
|
+
.filter(Boolean);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
function findPromptChoice(promptChoices = [], answer = "") {
|
|
229
|
+
const normalizedAnswer = String(answer || "").trim();
|
|
230
|
+
if (!normalizedAnswer) {
|
|
231
|
+
return null;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
if (/^\d+$/.test(normalizedAnswer)) {
|
|
235
|
+
const index = Number.parseInt(normalizedAnswer, 10) - 1;
|
|
236
|
+
if (index >= 0 && index < promptChoices.length) {
|
|
237
|
+
return promptChoices[index];
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
return promptChoices.find((entry) => {
|
|
242
|
+
return entry.value === normalizedAnswer || entry.label === normalizedAnswer;
|
|
243
|
+
}) || null;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
async function promptForChoice({
|
|
247
|
+
promptText = "",
|
|
248
|
+
promptChoices = [],
|
|
249
|
+
stdin,
|
|
250
|
+
stdout,
|
|
251
|
+
required = false,
|
|
252
|
+
defaultValue = ""
|
|
253
|
+
}) {
|
|
254
|
+
const rl = createInterface({
|
|
255
|
+
input: stdin,
|
|
256
|
+
output: stdout
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
try {
|
|
260
|
+
while (true) {
|
|
261
|
+
const answer = String(await rl.question(promptText)).trim();
|
|
262
|
+
if (!answer && defaultValue) {
|
|
263
|
+
return defaultValue;
|
|
264
|
+
}
|
|
265
|
+
if (!answer && !required) {
|
|
266
|
+
return "";
|
|
267
|
+
}
|
|
268
|
+
if (!answer && required) {
|
|
269
|
+
throw createCliError("A selection is required.");
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
const matchedChoice = findPromptChoice(promptChoices, answer);
|
|
273
|
+
if (matchedChoice) {
|
|
274
|
+
return matchedChoice.value;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
const values = promptChoices.map((entry) => entry.value).join(", ");
|
|
278
|
+
stdout.write(`Invalid selection. Enter a number or one of: ${values}.
|
|
279
|
+
`);
|
|
280
|
+
}
|
|
281
|
+
} finally {
|
|
282
|
+
rl.close();
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
212
286
|
function parseTransformSpec(transform) {
|
|
213
287
|
const normalized = String(transform || "").trim();
|
|
214
288
|
if (!normalized) {
|
|
@@ -359,6 +433,7 @@ async function promptForRequiredOption({
|
|
|
359
433
|
ownerId,
|
|
360
434
|
optionName,
|
|
361
435
|
optionSchema,
|
|
436
|
+
promptChoices = [],
|
|
362
437
|
stdin = process.stdin,
|
|
363
438
|
stdout = process.stdout
|
|
364
439
|
}) {
|
|
@@ -387,6 +462,24 @@ async function promptForRequiredOption({
|
|
|
387
462
|
const defaultHint = defaultValue ? ` [default: ${defaultValue}]` : "";
|
|
388
463
|
const hintSuffix = promptHint ? ` ${promptHint}` : "";
|
|
389
464
|
const promptText = `${label}${defaultHint}${hintSuffix}: `;
|
|
465
|
+
const normalizedPromptChoices = normalizePromptChoices(promptChoices);
|
|
466
|
+
|
|
467
|
+
if (normalizedPromptChoices.length > 0) {
|
|
468
|
+
stdout.write(`${label}${defaultHint}${hintSuffix}
|
|
469
|
+
`);
|
|
470
|
+
normalizedPromptChoices.forEach((entry, index) => {
|
|
471
|
+
stdout.write(` ${index + 1}) ${entry.label}
|
|
472
|
+
`);
|
|
473
|
+
});
|
|
474
|
+
return promptForChoice({
|
|
475
|
+
promptText: "Select a surface by number or id: ",
|
|
476
|
+
promptChoices: normalizedPromptChoices,
|
|
477
|
+
stdin,
|
|
478
|
+
stdout,
|
|
479
|
+
required,
|
|
480
|
+
defaultValue
|
|
481
|
+
});
|
|
482
|
+
}
|
|
390
483
|
|
|
391
484
|
let answer = "";
|
|
392
485
|
|