@kora-platform/cli 0.8.2-rc4 → 0.9.0-rc2
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/dist/api-client.d.ts +29 -36
- package/dist/api-client.js +12 -15
- package/dist/api-types.d.ts +64 -15
- package/dist/command-registry.js +95 -60
- package/dist/commands.js +3 -4
- package/dist/extension-commands.js +185 -111
- package/dist/files.d.ts +1 -0
- package/dist/files.js +33 -17
- package/dist/schema-registry-data.d.ts +240 -18
- package/dist/schema-registry-data.js +329 -24
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { readOptionalStringFlag, readRequiredStringFlag } from "./command-flags.js";
|
|
1
|
+
import { readOptionalNumberFlag, readOptionalStringFlag, readRequiredStringFlag } from "./command-flags.js";
|
|
2
2
|
import { genericProblem, usageProblem } from "./cli-errors.js";
|
|
3
|
-
import { isZipArchivePath, readArchiveBytes, readJsonInputSpecifier, readPackageFileEntries, readWorkspaceExportMetadata, writeArchiveExport, writePackageExport } from "./files.js";
|
|
3
|
+
import { isZipArchivePath, readArchiveBytes, readJsonInputSpecifier, readJsonValueInputSpecifier, readPackageFileEntries, readWorkspaceExportMetadata, writeArchiveExport, writePackageExport } from "./files.js";
|
|
4
4
|
import { renderKeyValue, renderPrettyJson, renderSuccess, renderTable } from "./format.js";
|
|
5
5
|
import { confirmDestructive } from "./interaction.js";
|
|
6
6
|
import { readCliEnvironmentFlag, readRequiredCliEnvironmentFlag } from "./environment-context.js";
|
|
@@ -73,7 +73,7 @@ export async function executeExtensions(parsed, context, api, resolveOrgScope) {
|
|
|
73
73
|
: await api.publishExtensionPackage(session, org.id, { files: await readPackageFileEntries(path, parsed.definition.id) });
|
|
74
74
|
return {
|
|
75
75
|
data,
|
|
76
|
-
human: renderSuccess(`Published extension ${data.package.name}
|
|
76
|
+
human: renderSuccess(`Published extension package ${data.package.name}.`),
|
|
77
77
|
kind: "extensions_publish",
|
|
78
78
|
meta: withExtensionSummary({ command: parsed.definition.path.join(" "), mutated: true, orgId: org.id }, "Extension published.")
|
|
79
79
|
};
|
|
@@ -85,8 +85,8 @@ export async function executeExtensions(parsed, context, api, resolveOrgScope) {
|
|
|
85
85
|
const data = await api.installExtension(session, org.id, {
|
|
86
86
|
environment,
|
|
87
87
|
...(permissions ? { grantedPermissions: permissions } : {}),
|
|
88
|
-
|
|
89
|
-
slug: readRequiredArg(parsed, "
|
|
88
|
+
packageArtifactId: readRequiredArg(parsed, "published-package"),
|
|
89
|
+
slug: readRequiredArg(parsed, "name")
|
|
90
90
|
});
|
|
91
91
|
return {
|
|
92
92
|
data,
|
|
@@ -98,7 +98,7 @@ export async function executeExtensions(parsed, context, api, resolveOrgScope) {
|
|
|
98
98
|
case "extensions.grant": {
|
|
99
99
|
const environment = readRequiredCliEnvironmentFlag(parsed);
|
|
100
100
|
const permissions = await readRequiredPermissions(parsed, context);
|
|
101
|
-
const installRef = readRequiredArg(parsed, "
|
|
101
|
+
const installRef = readRequiredArg(parsed, "name");
|
|
102
102
|
announceResolvedEnvironment(parsed, context, environment);
|
|
103
103
|
const data = await api.grantExtensionPermissions(session, org.id, installRef, {
|
|
104
104
|
environment,
|
|
@@ -112,34 +112,6 @@ export async function executeExtensions(parsed, context, api, resolveOrgScope) {
|
|
|
112
112
|
meta: withExtensionSummary({ command: parsed.definition.path.join(" "), environment, mutated: true, orgId: org.id }, "Extension grants updated.")
|
|
113
113
|
};
|
|
114
114
|
}
|
|
115
|
-
case "extensions.update": {
|
|
116
|
-
const environment = readRequiredCliEnvironmentFlag(parsed);
|
|
117
|
-
const installRef = readRequiredArg(parsed, "install");
|
|
118
|
-
const input = {
|
|
119
|
-
environment,
|
|
120
|
-
...await readInstallPreconditions(parsed, context, installRef),
|
|
121
|
-
packageRevisionId: readRequiredStringFlag(parsed, "revision")
|
|
122
|
-
};
|
|
123
|
-
if (parsed.flags["dry-run"] === true) {
|
|
124
|
-
const data = await api.planExtensionInstallUpdate(session, org.id, installRef, input);
|
|
125
|
-
const plan = data.plan;
|
|
126
|
-
return {
|
|
127
|
-
data,
|
|
128
|
-
exitCode: plan.updateAllowed === false ? 1 : 0,
|
|
129
|
-
human: renderPrettyJson(data.plan),
|
|
130
|
-
kind: "extensions_update_plan",
|
|
131
|
-
meta: withExtensionSummary({ command: parsed.definition.path.join(" "), dryRun: true, environment, mutated: false, orgId: org.id }, summarizeExtensionUpdatePlan(plan))
|
|
132
|
-
};
|
|
133
|
-
}
|
|
134
|
-
announceResolvedEnvironment(parsed, context, environment);
|
|
135
|
-
const data = await api.updateExtensionInstall(session, org.id, installRef, input);
|
|
136
|
-
return {
|
|
137
|
-
data,
|
|
138
|
-
human: renderSuccess(`Updated extension ${data.install.slug} to ${data.install.packageRevisionId} in ${environment}.`),
|
|
139
|
-
kind: "extensions_update",
|
|
140
|
-
meta: withExtensionSummary({ command: parsed.definition.path.join(" "), environment, mutated: true, orgId: org.id }, "Extension updated.")
|
|
141
|
-
};
|
|
142
|
-
}
|
|
143
115
|
case "extensions.built-ins.list": {
|
|
144
116
|
const environment = readCliEnvironmentFlag(parsed);
|
|
145
117
|
const data = await api.listBuiltInExtensions(session, org.id, {
|
|
@@ -155,12 +127,12 @@ export async function executeExtensions(parsed, context, api, resolveOrgScope) {
|
|
|
155
127
|
case "extensions.built-ins.install": {
|
|
156
128
|
const environment = readRequiredCliEnvironmentFlag(parsed);
|
|
157
129
|
const permissions = await readOptionalPermissions(parsed, context);
|
|
158
|
-
const
|
|
130
|
+
const name = readOptionalStringFlag(parsed, "name");
|
|
159
131
|
announceResolvedEnvironment(parsed, context, environment);
|
|
160
132
|
const data = await api.installBuiltInExtension(session, org.id, readRequiredArg(parsed, "built-in"), {
|
|
161
133
|
environment,
|
|
162
134
|
...(permissions ? { grantedPermissions: permissions } : {}),
|
|
163
|
-
...(
|
|
135
|
+
...(name ? { slug: name } : {})
|
|
164
136
|
});
|
|
165
137
|
return {
|
|
166
138
|
data,
|
|
@@ -169,45 +141,79 @@ export async function executeExtensions(parsed, context, api, resolveOrgScope) {
|
|
|
169
141
|
meta: withExtensionSummary({ command: parsed.definition.path.join(" "), environment, mutated: true, orgId: org.id }, "Built-in extension installed.")
|
|
170
142
|
};
|
|
171
143
|
}
|
|
172
|
-
case "extensions.
|
|
144
|
+
case "extensions.search": {
|
|
173
145
|
const environment = readCliEnvironmentFlag(parsed);
|
|
174
|
-
const
|
|
175
|
-
|
|
146
|
+
const extensionRef = readOptionalArg(parsed, "extension");
|
|
147
|
+
if (extensionRef) {
|
|
148
|
+
const effectiveEnvironment = readRequiredCliEnvironmentFlag(parsed);
|
|
149
|
+
const data = await api.searchExtensionCapabilities(session, org.id, extensionRef, {
|
|
150
|
+
environment: effectiveEnvironment,
|
|
151
|
+
...readExtensionSearchFilters(parsed, { capabilities: true })
|
|
152
|
+
});
|
|
153
|
+
return {
|
|
154
|
+
data,
|
|
155
|
+
human: renderCapabilitySearchHuman(data.matches, data),
|
|
156
|
+
kind: "extensions_search",
|
|
157
|
+
meta: withExtensionSummary({ command: parsed.definition.path.join(" "), environment: effectiveEnvironment, orgId: org.id }, summarizeSearchResult(data))
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
const data = await api.searchExtensions(session, org.id, {
|
|
161
|
+
...(environment ? { environment } : {}),
|
|
162
|
+
...readExtensionSearchFilters(parsed, { capabilities: false })
|
|
176
163
|
});
|
|
177
164
|
return {
|
|
178
165
|
data,
|
|
179
|
-
human:
|
|
180
|
-
kind: "
|
|
181
|
-
meta: { command: parsed.definition.path.join(" "), ...(environment ? { environment } : {}), orgId: org.id }
|
|
166
|
+
human: renderExtensionSearchHuman(data.matches, data),
|
|
167
|
+
kind: "extensions_search",
|
|
168
|
+
meta: withExtensionSummary({ command: parsed.definition.path.join(" "), ...(environment ? { environment } : {}), orgId: org.id }, summarizeSearchResult(data))
|
|
182
169
|
};
|
|
183
170
|
}
|
|
184
|
-
case "extensions.
|
|
171
|
+
case "extensions.get": {
|
|
185
172
|
const environment = readRequiredCliEnvironmentFlag(parsed);
|
|
186
|
-
const
|
|
187
|
-
|
|
188
|
-
|
|
173
|
+
const extensionRef = readRequiredArg(parsed, "extension");
|
|
174
|
+
const selectedCapability = readSelectedCapability(parsed);
|
|
175
|
+
if (selectedCapability) {
|
|
176
|
+
const data = await api.getExtensionCapability(session, org.id, extensionRef, selectedCapability.kind, selectedCapability.name, { environment });
|
|
177
|
+
return {
|
|
178
|
+
data,
|
|
179
|
+
human: renderPrettyJson(data.capability),
|
|
180
|
+
kind: "extensions_get",
|
|
181
|
+
meta: withExtensionSummary({ command: parsed.definition.path.join(" "), environment, orgId: org.id }, `${selectedCapability.kind} ${selectedCapability.name} loaded.`)
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
const data = await api.getExtensionDiscovery(session, org.id, extensionRef, { environment });
|
|
189
185
|
return {
|
|
190
186
|
data,
|
|
191
|
-
human: renderPrettyJson(data.
|
|
192
|
-
kind: "
|
|
187
|
+
human: renderPrettyJson(data.extension),
|
|
188
|
+
kind: "extensions_get",
|
|
193
189
|
meta: { command: parsed.definition.path.join(" "), environment, orgId: org.id }
|
|
194
190
|
};
|
|
195
191
|
}
|
|
196
|
-
case "extensions.
|
|
192
|
+
case "extensions.invoke": {
|
|
197
193
|
const environment = readRequiredCliEnvironmentFlag(parsed);
|
|
198
|
-
const
|
|
199
|
-
|
|
194
|
+
const extensionRef = readRequiredArg(parsed, "extension");
|
|
195
|
+
const functionName = readRequiredArg(parsed, "function");
|
|
196
|
+
const invocationInput = await readOptionalInvocationInput(parsed, context);
|
|
197
|
+
await confirmDestructive(parsed, context, `Invoke extension function ${extensionRef}.${functionName} in ${environment}?`);
|
|
198
|
+
const data = await api.invokeExtensionFunction(session, org.id, extensionRef, functionName, {
|
|
199
|
+
environment,
|
|
200
|
+
...(invocationInput.provided ? { input: invocationInput.value } : {})
|
|
200
201
|
});
|
|
201
202
|
return {
|
|
202
203
|
data,
|
|
203
|
-
human:
|
|
204
|
-
kind: "
|
|
205
|
-
meta: {
|
|
204
|
+
human: renderExtensionInvocationHuman(data),
|
|
205
|
+
kind: "extensions_invoke",
|
|
206
|
+
meta: withExtensionSummary({
|
|
207
|
+
command: parsed.definition.path.join(" "),
|
|
208
|
+
environment,
|
|
209
|
+
executionId: data.invocation.executionId,
|
|
210
|
+
orgId: org.id
|
|
211
|
+
}, `Extension function ${functionName} invoked.`)
|
|
206
212
|
};
|
|
207
213
|
}
|
|
208
214
|
case "extensions.disable": {
|
|
209
215
|
const environment = readRequiredCliEnvironmentFlag(parsed);
|
|
210
|
-
const installRef = readRequiredArg(parsed, "
|
|
216
|
+
const installRef = readRequiredArg(parsed, "name");
|
|
211
217
|
announceResolvedEnvironment(parsed, context, environment);
|
|
212
218
|
const data = await api.disableExtensionInstall(session, org.id, installRef, {
|
|
213
219
|
environment
|
|
@@ -221,7 +227,7 @@ export async function executeExtensions(parsed, context, api, resolveOrgScope) {
|
|
|
221
227
|
}
|
|
222
228
|
case "extensions.enable": {
|
|
223
229
|
const environment = readRequiredCliEnvironmentFlag(parsed);
|
|
224
|
-
const installRef = readRequiredArg(parsed, "
|
|
230
|
+
const installRef = readRequiredArg(parsed, "name");
|
|
225
231
|
announceResolvedEnvironment(parsed, context, environment);
|
|
226
232
|
const data = await api.enableExtensionInstall(session, org.id, installRef, {
|
|
227
233
|
environment
|
|
@@ -235,15 +241,15 @@ export async function executeExtensions(parsed, context, api, resolveOrgScope) {
|
|
|
235
241
|
}
|
|
236
242
|
case "extensions.delete": {
|
|
237
243
|
const environment = readRequiredCliEnvironmentFlag(parsed);
|
|
238
|
-
const installRef = readRequiredArg(parsed, "
|
|
244
|
+
const installRef = readRequiredArg(parsed, "name");
|
|
239
245
|
announceResolvedEnvironment(parsed, context, environment);
|
|
240
|
-
await confirmDestructive(parsed, context, `Delete extension
|
|
246
|
+
await confirmDestructive(parsed, context, `Delete extension ${installRef} from ${environment}?`);
|
|
241
247
|
await api.deleteExtensionInstall(session, org.id, installRef, {
|
|
242
248
|
environment
|
|
243
249
|
});
|
|
244
250
|
return {
|
|
245
251
|
data: {},
|
|
246
|
-
human: renderSuccess(`Deleted extension
|
|
252
|
+
human: renderSuccess(`Deleted extension ${installRef} from ${environment}.`),
|
|
247
253
|
kind: "extensions_delete",
|
|
248
254
|
meta: { command: parsed.definition.path.join(" "), environment, orgId: org.id }
|
|
249
255
|
};
|
|
@@ -252,6 +258,94 @@ export async function executeExtensions(parsed, context, api, resolveOrgScope) {
|
|
|
252
258
|
throw genericProblem(`Unhandled extensions command ${parsed.definition.id}.`, parsed.definition.id);
|
|
253
259
|
}
|
|
254
260
|
}
|
|
261
|
+
function readExtensionSearchFilters(parsed, input) {
|
|
262
|
+
const description = readOptionalStringFlag(parsed, "description");
|
|
263
|
+
const kind = readOptionalStringFlag(parsed, "kind");
|
|
264
|
+
const limit = readOptionalNumberFlag(parsed, "limit");
|
|
265
|
+
const name = readOptionalStringFlag(parsed, "name");
|
|
266
|
+
const scope = readOptionalStringFlag(parsed, "scope");
|
|
267
|
+
const title = readOptionalStringFlag(parsed, "title");
|
|
268
|
+
if (input.capabilities && title) {
|
|
269
|
+
throw usageProblem("--title can only be used when searching extensions.", parsed.definition.id);
|
|
270
|
+
}
|
|
271
|
+
if (input.capabilities && scope) {
|
|
272
|
+
throw usageProblem("--scope can only be used when searching extensions.", parsed.definition.id);
|
|
273
|
+
}
|
|
274
|
+
if (!input.capabilities && kind) {
|
|
275
|
+
throw usageProblem("--kind can only be used when searching inside one extension.", parsed.definition.id);
|
|
276
|
+
}
|
|
277
|
+
return {
|
|
278
|
+
...(description ? { description } : {}),
|
|
279
|
+
...(input.capabilities && kind ? { kind } : {}),
|
|
280
|
+
...(limit !== undefined ? { limit } : {}),
|
|
281
|
+
...(name ? { name } : {}),
|
|
282
|
+
...(!input.capabilities && scope ? { scope } : {}),
|
|
283
|
+
...(!input.capabilities && title ? { title } : {})
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
function readSelectedCapability(parsed) {
|
|
287
|
+
const selected = [
|
|
288
|
+
{ kind: "function", name: readOptionalStringFlag(parsed, "function") },
|
|
289
|
+
{ kind: "tool", name: readOptionalStringFlag(parsed, "tool") },
|
|
290
|
+
{ kind: "skill", name: readOptionalStringFlag(parsed, "skill") }
|
|
291
|
+
].filter((entry) => Boolean(entry.name));
|
|
292
|
+
if (selected.length > 1) {
|
|
293
|
+
throw usageProblem("Use only one of --function, --tool, or --skill.", parsed.definition.id);
|
|
294
|
+
}
|
|
295
|
+
return selected[0] ?? null;
|
|
296
|
+
}
|
|
297
|
+
function summarizeSearchResult(input) {
|
|
298
|
+
return input.truncated
|
|
299
|
+
? `Found ${input.matches.length} of ${input.totalCount} matches. Narrow the search or raise --limit.`
|
|
300
|
+
: `Found ${input.matches.length} match${input.matches.length === 1 ? "" : "es"}.`;
|
|
301
|
+
}
|
|
302
|
+
function renderExtensionSearchHuman(matches, input) {
|
|
303
|
+
const rows = matches.map((match) => ({
|
|
304
|
+
...match,
|
|
305
|
+
nextCommand: match.nextCommands?.install ?? match.nextCommands?.get ?? "",
|
|
306
|
+
stateLabel: formatExtensionState(match)
|
|
307
|
+
}));
|
|
308
|
+
return [
|
|
309
|
+
renderTable(rows, [
|
|
310
|
+
{ key: "name", label: "Name" },
|
|
311
|
+
{ key: "status", label: "Status" },
|
|
312
|
+
{ key: "stateLabel", label: "State" },
|
|
313
|
+
{ key: "title", label: "Title" },
|
|
314
|
+
{ key: "description", label: "Description" },
|
|
315
|
+
{ key: "nextCommand", label: "Next" }
|
|
316
|
+
]),
|
|
317
|
+
renderSearchLimitHint(input, "extension")
|
|
318
|
+
].filter(Boolean).join("\n");
|
|
319
|
+
}
|
|
320
|
+
function renderCapabilitySearchHuman(matches, input) {
|
|
321
|
+
return [
|
|
322
|
+
renderTable(matches, [
|
|
323
|
+
{ key: "kind", label: "Kind" },
|
|
324
|
+
{ key: "name", label: "Name" },
|
|
325
|
+
{ key: "description", label: "Description" },
|
|
326
|
+
{ key: "nextCommand", label: "Get" }
|
|
327
|
+
]),
|
|
328
|
+
renderSearchLimitHint(input, "capability")
|
|
329
|
+
].filter(Boolean).join("\n");
|
|
330
|
+
}
|
|
331
|
+
function renderSearchLimitHint(input, context) {
|
|
332
|
+
if (!input.truncated)
|
|
333
|
+
return "";
|
|
334
|
+
const filters = context === "extension" ? "--name, --title, --description, --scope" : "--name, --description, --kind";
|
|
335
|
+
return `Too many matches (${input.totalCount}). Narrow the search with ${filters}, or raise --limit.`;
|
|
336
|
+
}
|
|
337
|
+
function formatExtensionState(match) {
|
|
338
|
+
switch (match.state) {
|
|
339
|
+
case "ready":
|
|
340
|
+
return "Ready";
|
|
341
|
+
case "setup_required":
|
|
342
|
+
return "Setup required";
|
|
343
|
+
case "disabled":
|
|
344
|
+
return "Disabled";
|
|
345
|
+
default:
|
|
346
|
+
return "";
|
|
347
|
+
}
|
|
348
|
+
}
|
|
255
349
|
function withExtensionSummary(meta, summary) {
|
|
256
350
|
const trimmed = summary?.trim();
|
|
257
351
|
return trimmed && trimmed.length > 0 ? { ...meta, summary: trimmed } : meta;
|
|
@@ -261,14 +355,6 @@ function summarizeExtensionValidation(input) {
|
|
|
261
355
|
? `Extension validation passed${formatExtensionDiagnosticSuffix(input.diagnostics)}.`
|
|
262
356
|
: `Extension validation failed${formatExtensionDiagnosticSuffix(input.diagnostics)}.`;
|
|
263
357
|
}
|
|
264
|
-
function summarizeExtensionUpdatePlan(plan) {
|
|
265
|
-
const diagnostics = Array.isArray(plan.diagnostics)
|
|
266
|
-
? plan.diagnostics.filter((entry) => typeof entry === "object" && entry !== null && !Array.isArray(entry))
|
|
267
|
-
: [];
|
|
268
|
-
return plan.updateAllowed === false
|
|
269
|
-
? `Extension update dry run blocked${formatExtensionDiagnosticSuffix(diagnostics)}.`
|
|
270
|
-
: `Extension update dry run passed${formatExtensionDiagnosticSuffix(diagnostics)}.`;
|
|
271
|
-
}
|
|
272
358
|
function formatExtensionDiagnosticSuffix(diagnostics) {
|
|
273
359
|
if (diagnostics.length === 0) {
|
|
274
360
|
return "";
|
|
@@ -285,8 +371,7 @@ function renderValidationHuman(input) {
|
|
|
285
371
|
const summary = renderKeyValue([
|
|
286
372
|
{ label: "Valid", value: input.ok },
|
|
287
373
|
{ label: "Files", value: input.fileCount },
|
|
288
|
-
{ label: "Bytes", value: input.totalBytes }
|
|
289
|
-
{ label: "Revision hash", value: input.revisionHash ?? "" }
|
|
374
|
+
{ label: "Bytes", value: input.totalBytes }
|
|
290
375
|
]);
|
|
291
376
|
if (input.diagnostics.length === 0) {
|
|
292
377
|
return summary;
|
|
@@ -301,53 +386,41 @@ function renderValidationHuman(input) {
|
|
|
301
386
|
])
|
|
302
387
|
].join("\n");
|
|
303
388
|
}
|
|
304
|
-
function renderExtensionInstallTable(installs) {
|
|
305
|
-
return renderTable(installs, [
|
|
306
|
-
{ key: "slug", label: "Slug" },
|
|
307
|
-
{ key: "enabled", label: "Enabled" },
|
|
308
|
-
{ key: "packageRevisionId", label: "Revision" },
|
|
309
|
-
{ key: "grantedPermissions", label: "Grants" }
|
|
310
|
-
]);
|
|
311
|
-
}
|
|
312
389
|
function renderBuiltInExtensionTable(builtIns) {
|
|
313
390
|
return renderTable(builtIns, [
|
|
314
|
-
{ key: "slug", label: "
|
|
391
|
+
{ key: "slug", label: "Name" },
|
|
315
392
|
{ key: "title", label: "Title" },
|
|
316
393
|
{ key: "availability", label: "Availability" },
|
|
317
394
|
{ key: "installedSlug", label: "Installed" },
|
|
318
395
|
{ key: "description", label: "Description" }
|
|
319
396
|
]);
|
|
320
397
|
}
|
|
321
|
-
function
|
|
322
|
-
const
|
|
323
|
-
const functions = Object.keys(readRecord(registrations?.functions) ?? {});
|
|
324
|
-
const tools = Object.keys(readRecord(registrations?.tools) ?? {});
|
|
325
|
-
return [
|
|
398
|
+
function renderExtensionInvocationHuman(data) {
|
|
399
|
+
const lines = [
|
|
326
400
|
renderKeyValue([
|
|
327
|
-
{ label: "
|
|
328
|
-
{ label: "
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
].join("\n");
|
|
401
|
+
{ label: "Execution", value: data.invocation.executionId },
|
|
402
|
+
{ label: "Status", value: data.invocation.status }
|
|
403
|
+
])
|
|
404
|
+
];
|
|
405
|
+
if (Object.prototype.hasOwnProperty.call(data.invocation, "output")) {
|
|
406
|
+
lines.push("", "Output:", renderPrettyJson(data.invocation.output));
|
|
407
|
+
}
|
|
408
|
+
return lines.join("\n");
|
|
336
409
|
}
|
|
337
410
|
function resolveExtensionExportSelector(parsed) {
|
|
338
|
-
const install = readOptionalStringFlag(parsed, "
|
|
339
|
-
const
|
|
411
|
+
const install = readOptionalStringFlag(parsed, "name");
|
|
412
|
+
const artifact = readOptionalStringFlag(parsed, "artifact");
|
|
340
413
|
const packageName = readOptionalStringFlag(parsed, "package");
|
|
341
|
-
const selectedCount = [Boolean(install), Boolean(
|
|
414
|
+
const selectedCount = [Boolean(install), Boolean(artifact), Boolean(packageName)].filter(Boolean).length;
|
|
342
415
|
if (selectedCount !== 1) {
|
|
343
|
-
throw usageProblem("Use exactly one of --
|
|
416
|
+
throw usageProblem("Use exactly one of --name, --artifact, or --package --latest.", parsed.definition.id);
|
|
344
417
|
}
|
|
345
418
|
if (install) {
|
|
346
419
|
const environment = readRequiredCliEnvironmentFlag(parsed);
|
|
347
420
|
return { install, ...(environment ? { environment } : {}) };
|
|
348
421
|
}
|
|
349
|
-
if (
|
|
350
|
-
return {
|
|
422
|
+
if (artifact) {
|
|
423
|
+
return { artifact };
|
|
351
424
|
}
|
|
352
425
|
if (packageName && parsed.flags.latest === true) {
|
|
353
426
|
return { latest: true, package: packageName };
|
|
@@ -356,18 +429,11 @@ function resolveExtensionExportSelector(parsed) {
|
|
|
356
429
|
}
|
|
357
430
|
async function readInstallPreconditions(parsed, context, installRef) {
|
|
358
431
|
const metadata = await readExtensionInstallExportMetadata(context.cwd, installRef);
|
|
359
|
-
const explicitBasePackageRevision = readOptionalStringFlag(parsed, "base-package-revision");
|
|
360
432
|
const explicitBaseUpdatedAt = readOptionalStringFlag(parsed, "base-updated-at");
|
|
361
433
|
return {
|
|
362
|
-
...(metadata?.packageRevisionId
|
|
363
|
-
? { basePackageRevisionId: metadata.packageRevisionId }
|
|
364
|
-
: {}),
|
|
365
434
|
...(metadata?.installUpdatedAt
|
|
366
435
|
? { baseUpdatedAt: metadata.installUpdatedAt }
|
|
367
436
|
: {}),
|
|
368
|
-
...(explicitBasePackageRevision
|
|
369
|
-
? { basePackageRevisionId: explicitBasePackageRevision }
|
|
370
|
-
: {}),
|
|
371
437
|
...(explicitBaseUpdatedAt
|
|
372
438
|
? { baseUpdatedAt: explicitBaseUpdatedAt }
|
|
373
439
|
: {})
|
|
@@ -384,9 +450,6 @@ async function readExtensionInstallExportMetadata(cwd, installRef) {
|
|
|
384
450
|
return {
|
|
385
451
|
...(typeof metadata.installUpdatedAt === "string"
|
|
386
452
|
? { installUpdatedAt: metadata.installUpdatedAt }
|
|
387
|
-
: {}),
|
|
388
|
-
...(typeof metadata.packageRevisionId === "string"
|
|
389
|
-
? { packageRevisionId: metadata.packageRevisionId }
|
|
390
453
|
: {})
|
|
391
454
|
};
|
|
392
455
|
}
|
|
@@ -401,6 +464,16 @@ async function readRequiredPermissions(parsed, context) {
|
|
|
401
464
|
const specifier = readRequiredStringFlag(parsed, "permissions");
|
|
402
465
|
return normalizePermissions(await readJsonInputSpecifier(specifier, context.stdin, parsed.definition.id, { flag: "permissions" }), parsed.definition.id);
|
|
403
466
|
}
|
|
467
|
+
async function readOptionalInvocationInput(parsed, context) {
|
|
468
|
+
const specifier = readOptionalStringFlag(parsed, "input");
|
|
469
|
+
if (!specifier) {
|
|
470
|
+
return { provided: false };
|
|
471
|
+
}
|
|
472
|
+
return {
|
|
473
|
+
provided: true,
|
|
474
|
+
value: await readJsonValueInputSpecifier(specifier, context.stdin, parsed.definition.id, { flag: "input" })
|
|
475
|
+
};
|
|
476
|
+
}
|
|
404
477
|
function normalizePermissions(input, instance) {
|
|
405
478
|
const permissions = input.grantedPermissions && isRecord(input.grantedPermissions)
|
|
406
479
|
? input.grantedPermissions
|
|
@@ -429,9 +502,6 @@ function normalizePermissions(input, instance) {
|
|
|
429
502
|
function isRecord(value) {
|
|
430
503
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
431
504
|
}
|
|
432
|
-
function readRecord(value) {
|
|
433
|
-
return isRecord(value) ? value : null;
|
|
434
|
-
}
|
|
435
505
|
function announceResolvedEnvironment(parsed, context, environment) {
|
|
436
506
|
if (!parsed.json) {
|
|
437
507
|
context.stdout.write(`Environment: ${environment}\n`);
|
|
@@ -444,3 +514,7 @@ function readRequiredArg(parsed, name) {
|
|
|
444
514
|
}
|
|
445
515
|
return value;
|
|
446
516
|
}
|
|
517
|
+
function readOptionalArg(parsed, name) {
|
|
518
|
+
const value = parsed.args[name];
|
|
519
|
+
return value && value.length > 0 ? value : undefined;
|
|
520
|
+
}
|
package/dist/files.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ interface ReadStructuredInputOptions {
|
|
|
4
4
|
flag?: string;
|
|
5
5
|
}
|
|
6
6
|
export declare function readJsonInputSpecifier(specifier: string, stdin: Readable, instance: string, options?: ReadStructuredInputOptions): Promise<Record<string, unknown>>;
|
|
7
|
+
export declare function readJsonValueInputSpecifier(specifier: string, stdin: Readable, instance: string, options?: ReadStructuredInputOptions): Promise<unknown>;
|
|
7
8
|
export declare function readTextInputSpecifier(specifier: string, stdin: Readable, instance: string): Promise<string>;
|
|
8
9
|
export declare function readImportEntries(pathValue: string): Promise<Array<{
|
|
9
10
|
content: string;
|
package/dist/files.js
CHANGED
|
@@ -8,11 +8,22 @@ const MAX_IMPORT_FILE_BYTES = 1_000_000;
|
|
|
8
8
|
const MAX_PACKAGE_FILE_BYTES = 2_000_000;
|
|
9
9
|
const MAX_IMPORT_TOTAL_BYTES = 10_000_000;
|
|
10
10
|
export async function readJsonInputSpecifier(specifier, stdin, instance, options = {}) {
|
|
11
|
+
const input = await readStructuredJsonInputSource(specifier, stdin, instance, options);
|
|
12
|
+
return readJsonObject(input.text, instance, input.options);
|
|
13
|
+
}
|
|
14
|
+
export async function readJsonValueInputSpecifier(specifier, stdin, instance, options = {}) {
|
|
15
|
+
const input = await readStructuredJsonInputSource(specifier, stdin, instance, options);
|
|
16
|
+
return readJsonValue(input.text, instance, input.options);
|
|
17
|
+
}
|
|
18
|
+
async function readStructuredJsonInputSource(specifier, stdin, instance, options = {}) {
|
|
11
19
|
if (specifier === "-") {
|
|
12
|
-
return
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
20
|
+
return {
|
|
21
|
+
options: {
|
|
22
|
+
source: "stdin",
|
|
23
|
+
...options
|
|
24
|
+
},
|
|
25
|
+
text: await readStream(stdin)
|
|
26
|
+
};
|
|
16
27
|
}
|
|
17
28
|
if (!specifier.startsWith("@")) {
|
|
18
29
|
throw usageProblem("Structured JSON input must use @file.json or - for stdin.", instance, {
|
|
@@ -35,10 +46,13 @@ export async function readJsonInputSpecifier(specifier, stdin, instance, options
|
|
|
35
46
|
}
|
|
36
47
|
throw error;
|
|
37
48
|
}
|
|
38
|
-
return
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
49
|
+
return {
|
|
50
|
+
options: {
|
|
51
|
+
filePath,
|
|
52
|
+
...options
|
|
53
|
+
},
|
|
54
|
+
text: source
|
|
55
|
+
};
|
|
42
56
|
}
|
|
43
57
|
export async function readTextInputSpecifier(specifier, stdin, instance) {
|
|
44
58
|
if (specifier === "-") {
|
|
@@ -214,25 +228,27 @@ export async function readPackageFileEntries(pathValue, instance) {
|
|
|
214
228
|
return entries;
|
|
215
229
|
}
|
|
216
230
|
function readJsonObject(source, instance, options) {
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
parsed = JSON.parse(source);
|
|
220
|
-
}
|
|
221
|
-
catch {
|
|
231
|
+
const parsed = readJsonValue(source, instance, options);
|
|
232
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
222
233
|
const sourceLabel = "filePath" in options ? `file ${options.filePath}` : "from stdin";
|
|
223
|
-
throw usageProblem(`Structured JSON input ${sourceLabel} must be
|
|
234
|
+
throw usageProblem(`Structured JSON input ${sourceLabel} must be a JSON object.`, instance, {
|
|
224
235
|
...("filePath" in options ? { filePath: options.filePath } : { source: options.source }),
|
|
225
236
|
...(options.flag ? { flag: options.flag } : {})
|
|
226
237
|
});
|
|
227
238
|
}
|
|
228
|
-
|
|
239
|
+
return parsed;
|
|
240
|
+
}
|
|
241
|
+
function readJsonValue(source, instance, options) {
|
|
242
|
+
try {
|
|
243
|
+
return JSON.parse(source);
|
|
244
|
+
}
|
|
245
|
+
catch {
|
|
229
246
|
const sourceLabel = "filePath" in options ? `file ${options.filePath}` : "from stdin";
|
|
230
|
-
throw usageProblem(`Structured JSON input ${sourceLabel} must be
|
|
247
|
+
throw usageProblem(`Structured JSON input ${sourceLabel} must be valid JSON.`, instance, {
|
|
231
248
|
...("filePath" in options ? { filePath: options.filePath } : { source: options.source }),
|
|
232
249
|
...(options.flag ? { flag: options.flag } : {})
|
|
233
250
|
});
|
|
234
251
|
}
|
|
235
|
-
return parsed;
|
|
236
252
|
}
|
|
237
253
|
async function readStream(stream) {
|
|
238
254
|
const chunks = [];
|