@kora-platform/cli 0.7.0-rc1 → 0.8.0-rc1
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/README.md +21 -0
- package/dist/api-client.d.ts +250 -93
- package/dist/api-client.js +187 -163
- package/dist/api-types.d.ts +280 -162
- package/dist/artifact-api-client.d.ts +28 -1
- package/dist/artifact-api-client.js +33 -0
- package/dist/artifact-commands.d.ts +5 -0
- package/dist/artifact-commands.js +172 -1
- package/dist/audit-commands.d.ts +12 -0
- package/dist/audit-commands.js +74 -0
- package/dist/auth-commands.d.ts +1 -0
- package/dist/auth-commands.js +116 -29
- package/dist/command-builders.d.ts +1 -0
- package/dist/command-builders.js +1 -0
- package/dist/command-groups.js +10 -12
- package/dist/command-registry.js +548 -243
- package/dist/commands.js +652 -602
- package/dist/environment-context.d.ts +9 -0
- package/dist/environment-context.js +32 -0
- package/dist/{integration-commands.d.ts → extension-commands.d.ts} +3 -2
- package/dist/extension-commands.js +446 -0
- package/dist/files.d.ts +33 -0
- package/dist/files.js +247 -12
- package/dist/format.d.ts +5 -0
- package/dist/format.js +78 -1
- package/dist/runner.js +14 -5
- package/dist/schema-registry-data.d.ts +272 -569
- package/dist/schema-registry-data.js +307 -700
- package/dist/session.d.ts +1 -0
- package/dist/transport.d.ts +10 -0
- package/dist/transport.js +22 -0
- package/dist/types.d.ts +2 -1
- package/dist/workspace-source.d.ts +1 -0
- package/dist/workspace-source.js +13 -0
- package/package.json +2 -1
- package/dist/integration-api-client.d.ts +0 -29
- package/dist/integration-api-client.js +0 -50
- package/dist/integration-commands.js +0 -208
|
@@ -3,7 +3,8 @@ import { basename, resolve } from "node:path";
|
|
|
3
3
|
import { TextDecoder } from "node:util";
|
|
4
4
|
import { genericProblem, usageProblem } from "./cli-errors.js";
|
|
5
5
|
import { readOptionalNumberFlag, readOptionalStringFlag, readRequiredStringFlag } from "./command-flags.js";
|
|
6
|
-
import { renderSuccess, renderTable } from "./format.js";
|
|
6
|
+
import { renderKeyValue, renderSuccess, renderTable } from "./format.js";
|
|
7
|
+
import { confirmDestructive } from "./interaction.js";
|
|
7
8
|
export async function executeArtifactUpload(parsed, context, api, resolveOrgScope) {
|
|
8
9
|
const { org, session } = await resolveOrgScope(parsed, context, api);
|
|
9
10
|
const pathValue = readRequiredArg(parsed, "path");
|
|
@@ -40,6 +41,27 @@ export async function executeArtifactList(parsed, context, api, resolveOrgScope)
|
|
|
40
41
|
meta: { command: "artifact list", orgId: org.id }
|
|
41
42
|
};
|
|
42
43
|
}
|
|
44
|
+
export async function executeArtifactInventory(parsed, context, api, resolveOrgScope) {
|
|
45
|
+
const { org, session } = await resolveOrgScope(parsed, context, api);
|
|
46
|
+
const data = await api.listArtifacts(session, org.id, readArtifactInventoryFilters(parsed));
|
|
47
|
+
return {
|
|
48
|
+
data,
|
|
49
|
+
human: renderArtifactInventory(data.artifacts),
|
|
50
|
+
kind: "runtime_artifact_inventory",
|
|
51
|
+
meta: { command: "artifact inventory", orgId: org.id }
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
export async function executeArtifactInspect(parsed, context, api, resolveOrgScope) {
|
|
55
|
+
const { org, session } = await resolveOrgScope(parsed, context, api);
|
|
56
|
+
const artifactId = readRequiredArg(parsed, "artifact-id");
|
|
57
|
+
const data = await api.getArtifactDetail(session, org.id, artifactId);
|
|
58
|
+
return {
|
|
59
|
+
data,
|
|
60
|
+
human: renderArtifactDetail(data),
|
|
61
|
+
kind: "runtime_artifact_inspect",
|
|
62
|
+
meta: { command: "artifact inspect", orgId: org.id }
|
|
63
|
+
};
|
|
64
|
+
}
|
|
43
65
|
export async function executeArtifactDownload(parsed, context, api, resolveOrgScope) {
|
|
44
66
|
const { org, session } = await resolveOrgScope(parsed, context, api);
|
|
45
67
|
const artifactId = readRequiredArg(parsed, "artifact-id");
|
|
@@ -94,6 +116,40 @@ export async function executeArtifactRead(parsed, context, api, resolveOrgScope)
|
|
|
94
116
|
meta: { command: "artifact read", orgId: org.id }
|
|
95
117
|
};
|
|
96
118
|
}
|
|
119
|
+
export async function executeArtifactArchive(parsed, context, api, resolveOrgScope) {
|
|
120
|
+
const { org, session } = await resolveOrgScope(parsed, context, api);
|
|
121
|
+
const artifactId = readRequiredArg(parsed, "artifact-id");
|
|
122
|
+
const data = await api.archiveArtifact(session, org.id, artifactId);
|
|
123
|
+
return {
|
|
124
|
+
data,
|
|
125
|
+
human: renderSuccess(`Archived artifact ${data.artifact.name} (${data.artifact.artifactId}).`),
|
|
126
|
+
kind: "runtime_artifact_archive",
|
|
127
|
+
meta: { command: "artifact archive", orgId: org.id }
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
export async function executeArtifactRestore(parsed, context, api, resolveOrgScope) {
|
|
131
|
+
const { org, session } = await resolveOrgScope(parsed, context, api);
|
|
132
|
+
const artifactId = readRequiredArg(parsed, "artifact-id");
|
|
133
|
+
const data = await api.restoreArtifact(session, org.id, artifactId);
|
|
134
|
+
return {
|
|
135
|
+
data,
|
|
136
|
+
human: renderSuccess(`Restored artifact ${data.artifact.name} (${data.artifact.artifactId}).`),
|
|
137
|
+
kind: "runtime_artifact_restore",
|
|
138
|
+
meta: { command: "artifact restore", orgId: org.id }
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
export async function executeArtifactPurge(parsed, context, api, resolveOrgScope) {
|
|
142
|
+
const { org, session } = await resolveOrgScope(parsed, context, api);
|
|
143
|
+
const artifactId = readRequiredArg(parsed, "artifact-id");
|
|
144
|
+
await confirmDestructive(parsed, context, `Purge bytes for artifact ${artifactId}?`);
|
|
145
|
+
const data = await api.purgeArtifact(session, org.id, artifactId);
|
|
146
|
+
return {
|
|
147
|
+
data,
|
|
148
|
+
human: renderSuccess(`Purged artifact ${data.artifact.name} (${data.artifact.artifactId}); byte deletion is ${data.artifact.byteDeletionStatus}.`),
|
|
149
|
+
kind: "runtime_artifact_purge",
|
|
150
|
+
meta: { command: "artifact purge", orgId: org.id }
|
|
151
|
+
};
|
|
152
|
+
}
|
|
97
153
|
function readRequiredArg(parsed, name) {
|
|
98
154
|
const value = parsed.args[name];
|
|
99
155
|
if (!value) {
|
|
@@ -108,6 +164,108 @@ function readArtifactReadMaxBytes(parsed) {
|
|
|
108
164
|
}
|
|
109
165
|
return maxBytes;
|
|
110
166
|
}
|
|
167
|
+
function readArtifactInventoryLimit(parsed) {
|
|
168
|
+
const limit = readOptionalNumberFlag(parsed, "limit");
|
|
169
|
+
if (limit === undefined) {
|
|
170
|
+
return undefined;
|
|
171
|
+
}
|
|
172
|
+
if (!Number.isInteger(limit) || limit <= 0 || limit > 500) {
|
|
173
|
+
throw usageProblem("--limit must be an integer between 1 and 500.", parsed.definition.id);
|
|
174
|
+
}
|
|
175
|
+
return limit;
|
|
176
|
+
}
|
|
177
|
+
function readArtifactInventoryFilters(parsed) {
|
|
178
|
+
const producerType = readOptionalStringFlag(parsed, "producer-type");
|
|
179
|
+
const associationRole = readOptionalStringFlag(parsed, "association-role");
|
|
180
|
+
const associationKind = readOptionalStringFlag(parsed, "association-kind");
|
|
181
|
+
const runId = readOptionalStringFlag(parsed, "run-id");
|
|
182
|
+
const workflowId = readOptionalStringFlag(parsed, "workflow-id");
|
|
183
|
+
const workflowNodeTestId = readOptionalStringFlag(parsed, "workflow-node-test-id");
|
|
184
|
+
const nodeId = readOptionalStringFlag(parsed, "node-id");
|
|
185
|
+
const mediaType = readOptionalStringFlag(parsed, "media-type");
|
|
186
|
+
const lifecycleStatus = readOptionalArtifactLifecycleFilter(parsed);
|
|
187
|
+
const createdAfter = readOptionalStringFlag(parsed, "created-after");
|
|
188
|
+
const createdBefore = readOptionalStringFlag(parsed, "created-before");
|
|
189
|
+
const limit = readArtifactInventoryLimit(parsed);
|
|
190
|
+
return {
|
|
191
|
+
...(producerType ? { producerType } : {}),
|
|
192
|
+
...(associationRole ? { associationRole } : {}),
|
|
193
|
+
...(associationKind ? { associationKind } : {}),
|
|
194
|
+
...(runId ? { runId } : {}),
|
|
195
|
+
...(workflowId ? { workflowId } : {}),
|
|
196
|
+
...(workflowNodeTestId ? { workflowNodeTestId } : {}),
|
|
197
|
+
...(nodeId ? { nodeId } : {}),
|
|
198
|
+
...(mediaType ? { mediaType } : {}),
|
|
199
|
+
...(lifecycleStatus ? { lifecycleStatus } : {}),
|
|
200
|
+
...(createdAfter ? { createdAfter } : {}),
|
|
201
|
+
...(createdBefore ? { createdBefore } : {}),
|
|
202
|
+
...(limit !== undefined ? { limit } : {})
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
function renderArtifactInventory(records) {
|
|
206
|
+
return renderTable(records.map((record) => ({
|
|
207
|
+
artifactId: record.artifact.artifactId,
|
|
208
|
+
byteDeletionStatus: record.artifact.byteDeletionStatus,
|
|
209
|
+
inputUsageCount: record.associationSummary.inputUsageCount,
|
|
210
|
+
lifecycleStatus: record.artifact.lifecycleStatus,
|
|
211
|
+
name: record.artifact.name,
|
|
212
|
+
origin: formatArtifactAssociationOrigin(record.originAssociation),
|
|
213
|
+
outputOriginCount: record.associationSummary.outputOriginCount,
|
|
214
|
+
producerType: record.artifact.producerType,
|
|
215
|
+
reviewUsageCount: record.associationSummary.reviewUsageCount
|
|
216
|
+
})), [
|
|
217
|
+
{ key: "artifactId", label: "Artifact" },
|
|
218
|
+
{ key: "name", label: "Name" },
|
|
219
|
+
{ key: "lifecycleStatus", label: "Lifecycle" },
|
|
220
|
+
{ key: "byteDeletionStatus", label: "Bytes" },
|
|
221
|
+
{ key: "producerType", label: "Producer" },
|
|
222
|
+
{ key: "origin", label: "Origin" },
|
|
223
|
+
{ key: "inputUsageCount", label: "Inputs" },
|
|
224
|
+
{ key: "outputOriginCount", label: "Outputs" },
|
|
225
|
+
{ key: "reviewUsageCount", label: "Reviews" }
|
|
226
|
+
]);
|
|
227
|
+
}
|
|
228
|
+
function renderArtifactDetail(input) {
|
|
229
|
+
const summary = renderKeyValue([
|
|
230
|
+
{ label: "Artifact", value: input.artifact.artifactId },
|
|
231
|
+
{ label: "Name", value: input.artifact.name },
|
|
232
|
+
{ label: "Lifecycle", value: input.artifact.lifecycleStatus },
|
|
233
|
+
{ label: "Bytes", value: input.artifact.byteDeletionStatus },
|
|
234
|
+
{ label: "Producer", value: input.artifact.producerType },
|
|
235
|
+
{ label: "Media type", value: input.artifact.mediaType ?? "" },
|
|
236
|
+
{ label: "Size bytes", value: input.artifact.sizeBytes },
|
|
237
|
+
{ label: "Scan", value: input.artifact.scanStatus },
|
|
238
|
+
{ label: "Created", value: input.artifact.createdAt },
|
|
239
|
+
{ label: "Archived", value: input.artifact.archivedAt ?? "" },
|
|
240
|
+
{ label: "Purged", value: input.artifact.purgedAt ?? "" },
|
|
241
|
+
{ label: "Bytes deleted", value: input.artifact.bytesDeletedAt ?? "" }
|
|
242
|
+
]);
|
|
243
|
+
const associations = renderTable(input.associations.map((association) => ({
|
|
244
|
+
associatedAt: association.associatedAt,
|
|
245
|
+
associationKind: association.associationKind,
|
|
246
|
+
nodeId: association.nodeId ?? "",
|
|
247
|
+
origin: formatArtifactAssociationOrigin(association),
|
|
248
|
+
role: association.role,
|
|
249
|
+
})), [
|
|
250
|
+
{ key: "associationKind", label: "Kind" },
|
|
251
|
+
{ key: "role", label: "Role" },
|
|
252
|
+
{ key: "origin", label: "Origin" },
|
|
253
|
+
{ key: "nodeId", label: "Node" },
|
|
254
|
+
{ key: "associatedAt", label: "Associated" }
|
|
255
|
+
]);
|
|
256
|
+
return `${summary}\n\nAssociations:\n${associations}`;
|
|
257
|
+
}
|
|
258
|
+
function formatArtifactAssociationOrigin(association) {
|
|
259
|
+
if (!association) {
|
|
260
|
+
return "";
|
|
261
|
+
}
|
|
262
|
+
if (association.workflowNodeTestId) {
|
|
263
|
+
return association.workflowName
|
|
264
|
+
? `${association.workflowName}/${association.workflowNodeTestId}`
|
|
265
|
+
: association.workflowNodeTestId;
|
|
266
|
+
}
|
|
267
|
+
return association.workflowRunId ?? association.workflowId ?? "";
|
|
268
|
+
}
|
|
111
269
|
function isInlineArtifactMediaType(contentType) {
|
|
112
270
|
const normalized = contentType.split(";", 1)[0]?.trim().toLowerCase() ?? "";
|
|
113
271
|
if (normalized === "text/html" ||
|
|
@@ -124,3 +282,16 @@ function isInlineArtifactMediaType(contentType) {
|
|
|
124
282
|
function readArtifactContentType(headers) {
|
|
125
283
|
return headers.get("content-type") ?? "application/octet-stream";
|
|
126
284
|
}
|
|
285
|
+
function readOptionalArtifactLifecycleFilter(parsed) {
|
|
286
|
+
const lifecycleStatus = readOptionalStringFlag(parsed, "lifecycle-status");
|
|
287
|
+
if (!lifecycleStatus) {
|
|
288
|
+
return undefined;
|
|
289
|
+
}
|
|
290
|
+
if (lifecycleStatus !== "active" &&
|
|
291
|
+
lifecycleStatus !== "archived" &&
|
|
292
|
+
lifecycleStatus !== "purged" &&
|
|
293
|
+
lifecycleStatus !== "all") {
|
|
294
|
+
throw usageProblem("--lifecycle-status must be one of active, archived, purged, or all.", parsed.definition.id);
|
|
295
|
+
}
|
|
296
|
+
return lifecycleStatus;
|
|
297
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { createPlatformApiClient } from "./api-client.js";
|
|
2
|
+
import type { CommandExecutionContext, ExecutedCommand } from "./command-types.js";
|
|
3
|
+
import type { ParsedCommand } from "./runner.js";
|
|
4
|
+
import type { CliSessionState } from "./session.js";
|
|
5
|
+
type ResolveOrgScope = (parsed: ParsedCommand, context: CommandExecutionContext, api: ReturnType<typeof createPlatformApiClient>) => Promise<{
|
|
6
|
+
org: {
|
|
7
|
+
id: string;
|
|
8
|
+
};
|
|
9
|
+
session: CliSessionState;
|
|
10
|
+
}>;
|
|
11
|
+
export declare function executeAudit(parsed: ParsedCommand, context: CommandExecutionContext, api: ReturnType<typeof createPlatformApiClient>, resolveOrgScope: ResolveOrgScope): Promise<ExecutedCommand>;
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { usageProblem, genericProblem } from "./cli-errors.js";
|
|
2
|
+
import { readOptionalNumberFlag, readOptionalStringFlag } from "./command-flags.js";
|
|
3
|
+
import { renderPrettyJson, renderTable } from "./format.js";
|
|
4
|
+
export async function executeAudit(parsed, context, api, resolveOrgScope) {
|
|
5
|
+
const { org, session } = await resolveOrgScope(parsed, context, api);
|
|
6
|
+
switch (parsed.definition.id) {
|
|
7
|
+
case "audit.list": {
|
|
8
|
+
const action = readOptionalStringFlag(parsed, "action");
|
|
9
|
+
const actorId = readOptionalStringFlag(parsed, "actor");
|
|
10
|
+
const category = readOptionalStringFlag(parsed, "category");
|
|
11
|
+
const from = readOptionalStringFlag(parsed, "from");
|
|
12
|
+
const limit = readOptionalNumberFlag(parsed, "limit");
|
|
13
|
+
const outcome = readOptionalStringFlag(parsed, "outcome");
|
|
14
|
+
const resourceId = readOptionalStringFlag(parsed, "resource-id");
|
|
15
|
+
const resourceType = readOptionalStringFlag(parsed, "resource-type");
|
|
16
|
+
const to = readOptionalStringFlag(parsed, "to");
|
|
17
|
+
const data = await api.listAuditEvents(session, org.id, {
|
|
18
|
+
...(action ? { action } : {}),
|
|
19
|
+
...(actorId ? { actorId } : {}),
|
|
20
|
+
...(category ? { category } : {}),
|
|
21
|
+
...(from ? { from } : {}),
|
|
22
|
+
...(limit !== undefined ? { limit } : {}),
|
|
23
|
+
...(outcome ? { outcome } : {}),
|
|
24
|
+
...(resourceId ? { resourceId } : {}),
|
|
25
|
+
...(resourceType ? { resourceType } : {}),
|
|
26
|
+
...(to ? { to } : {})
|
|
27
|
+
});
|
|
28
|
+
return {
|
|
29
|
+
data,
|
|
30
|
+
human: renderTable(data.events.map(formatAuditEventRow), [
|
|
31
|
+
{ key: "occurredAt", label: "Occurred" },
|
|
32
|
+
{ key: "outcome", label: "Outcome" },
|
|
33
|
+
{ key: "category", label: "Category" },
|
|
34
|
+
{ key: "action", label: "Action" },
|
|
35
|
+
{ key: "actorId", label: "Actor" },
|
|
36
|
+
{ key: "resource", label: "Resource" },
|
|
37
|
+
{ key: "id", label: "Event" }
|
|
38
|
+
]),
|
|
39
|
+
kind: "audit_event_list",
|
|
40
|
+
meta: { command: parsed.definition.path.join(" "), orgId: org.id }
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
case "audit.get": {
|
|
44
|
+
const data = await api.getAuditEvent(session, org.id, readRequiredArg(parsed, "event-id"));
|
|
45
|
+
return {
|
|
46
|
+
data,
|
|
47
|
+
human: renderPrettyJson(data.event),
|
|
48
|
+
kind: "audit_event_get",
|
|
49
|
+
meta: { command: parsed.definition.path.join(" "), orgId: org.id }
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
default:
|
|
53
|
+
throw genericProblem(`Unhandled audit command ${parsed.definition.id}.`, parsed.definition.id);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
function formatAuditEventRow(event) {
|
|
57
|
+
return {
|
|
58
|
+
...event,
|
|
59
|
+
resource: formatAuditResource(event)
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
function formatAuditResource(event) {
|
|
63
|
+
if (event.resourceType && event.resourceId) {
|
|
64
|
+
return `${event.resourceType}:${event.resourceId}`;
|
|
65
|
+
}
|
|
66
|
+
return event.resourceType ?? event.resourceId ?? "";
|
|
67
|
+
}
|
|
68
|
+
function readRequiredArg(parsed, name) {
|
|
69
|
+
const value = parsed.args[name];
|
|
70
|
+
if (!value) {
|
|
71
|
+
throw usageProblem(`Missing required argument <${name}>.`, parsed.definition.id);
|
|
72
|
+
}
|
|
73
|
+
return value;
|
|
74
|
+
}
|
package/dist/auth-commands.d.ts
CHANGED
|
@@ -2,5 +2,6 @@ import type { createPlatformApiClient } from "./api-client.js";
|
|
|
2
2
|
import type { CommandExecutionContext, ExecutedCommand } from "./command-types.js";
|
|
3
3
|
import type { ParsedCommand } from "./runner.js";
|
|
4
4
|
export declare function executeAuthLogin(parsed: ParsedCommand, context: CommandExecutionContext, api: ReturnType<typeof createPlatformApiClient>): Promise<ExecutedCommand>;
|
|
5
|
+
export declare function executeAuthSignup(parsed: ParsedCommand, context: CommandExecutionContext, api: ReturnType<typeof createPlatformApiClient>): Promise<ExecutedCommand>;
|
|
5
6
|
export declare function executeAuthLogout(context: CommandExecutionContext, api: ReturnType<typeof createPlatformApiClient>): Promise<ExecutedCommand>;
|
|
6
7
|
export declare function executeAuthWhoami(context: CommandExecutionContext, api: ReturnType<typeof createPlatformApiClient>): Promise<ExecutedCommand>;
|
package/dist/auth-commands.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { authProblem, toProblem } from "./cli-errors.js";
|
|
2
|
+
import { readOptionalStringFlag } from "./command-flags.js";
|
|
2
3
|
import { writeCliConfig, readCliConfig, findRepoConfigPath } from "./config.js";
|
|
3
4
|
import { renderKeyValue, renderSuccess } from "./format.js";
|
|
4
5
|
import { chooseOrganization, ensureInteractive } from "./interaction.js";
|
|
@@ -11,12 +12,8 @@ export async function executeAuthLogin(parsed, context, api) {
|
|
|
11
12
|
}
|
|
12
13
|
: context;
|
|
13
14
|
ensureInteractive(prompts, "auth login");
|
|
14
|
-
const
|
|
15
|
-
const
|
|
16
|
-
const repoConfig = repoConfigPath ? await readCliConfig(repoConfigPath) : {};
|
|
17
|
-
const envBaseUrl = context.env.KORA_BASE_URL;
|
|
18
|
-
const configuredBaseUrl = envBaseUrl ?? repoConfig.baseUrl ?? persistedGlobalConfig.baseUrl;
|
|
19
|
-
const baseUrl = configuredBaseUrl ?? await promptText("Platform base URL: ", prompts);
|
|
15
|
+
const resolvedBaseUrl = await resolveAuthBaseUrl(parsed, context, prompts);
|
|
16
|
+
const { baseUrl } = resolvedBaseUrl;
|
|
20
17
|
const authSettings = await readAuthSettingsOrDefault(api, baseUrl);
|
|
21
18
|
const oidcLoginUrl = buildOidcStartUrl(baseUrl);
|
|
22
19
|
if (authSettings.oidcEnabled && !authSettings.localEnabled) {
|
|
@@ -45,30 +42,16 @@ export async function executeAuthLogin(parsed, context, api) {
|
|
|
45
42
|
const email = await promptText("Email: ", prompts);
|
|
46
43
|
const password = await promptPassword("Password: ", prompts);
|
|
47
44
|
const session = await api.login({ baseUrl, email, password });
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
const nextSession = {
|
|
57
|
-
...sessionForWrite,
|
|
58
|
-
activeOrg: activeOrg
|
|
59
|
-
? {
|
|
60
|
-
id: activeOrg.id,
|
|
61
|
-
name: activeOrg.name,
|
|
62
|
-
role: activeOrg.role,
|
|
63
|
-
slug: activeOrg.slug,
|
|
64
|
-
status: activeOrg.status
|
|
65
|
-
}
|
|
66
|
-
: null
|
|
67
|
-
};
|
|
68
|
-
await context.sessionStore.write(nextSession);
|
|
69
|
-
if (!envBaseUrl && !repoConfig.baseUrl) {
|
|
45
|
+
const nextSession = await writeSessionWithSelectedOrg({
|
|
46
|
+
api,
|
|
47
|
+
context,
|
|
48
|
+
parsed,
|
|
49
|
+
prompts,
|
|
50
|
+
session
|
|
51
|
+
});
|
|
52
|
+
if (resolvedBaseUrl.shouldPersistGlobalBaseUrl) {
|
|
70
53
|
await writeCliConfig(context.configPath, {
|
|
71
|
-
...persistedGlobalConfig,
|
|
54
|
+
...resolvedBaseUrl.persistedGlobalConfig,
|
|
72
55
|
baseUrl
|
|
73
56
|
});
|
|
74
57
|
}
|
|
@@ -87,6 +70,110 @@ export async function executeAuthLogin(parsed, context, api) {
|
|
|
87
70
|
}
|
|
88
71
|
};
|
|
89
72
|
}
|
|
73
|
+
export async function executeAuthSignup(parsed, context, api) {
|
|
74
|
+
const prompts = parsed.json
|
|
75
|
+
? {
|
|
76
|
+
...context,
|
|
77
|
+
stdout: context.stderr
|
|
78
|
+
}
|
|
79
|
+
: context;
|
|
80
|
+
ensureInteractive(prompts, "auth signup");
|
|
81
|
+
const resolvedBaseUrl = await resolveAuthBaseUrl(parsed, context, prompts);
|
|
82
|
+
const { baseUrl } = resolvedBaseUrl;
|
|
83
|
+
const authSettings = await readAuthSettingsOrDefault(api, baseUrl);
|
|
84
|
+
const oidcLoginUrl = buildOidcStartUrl(baseUrl);
|
|
85
|
+
if (!authSettings.localEnabled) {
|
|
86
|
+
return {
|
|
87
|
+
data: {
|
|
88
|
+
loginUrl: oidcLoginUrl,
|
|
89
|
+
mode: authSettings.mode
|
|
90
|
+
},
|
|
91
|
+
human: [
|
|
92
|
+
"Local account signup is disabled for this deployment.",
|
|
93
|
+
`Open this URL in a browser: ${oidcLoginUrl}`,
|
|
94
|
+
"Account creation is managed by SSO for this deployment."
|
|
95
|
+
].join("\n"),
|
|
96
|
+
kind: "access_auth_signup_sso_required",
|
|
97
|
+
meta: {
|
|
98
|
+
command: "auth signup",
|
|
99
|
+
orgId: null
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
if (authSettings.oidcEnabled) {
|
|
104
|
+
prompts.stdout.write(`SSO is also available at: ${oidcLoginUrl}\n`);
|
|
105
|
+
prompts.stdout.write("Continuing with local account signup.\n");
|
|
106
|
+
}
|
|
107
|
+
const name = await promptText("Name: ", prompts);
|
|
108
|
+
const email = await promptText("Email: ", prompts);
|
|
109
|
+
const password = await promptPassword("Password: ", prompts);
|
|
110
|
+
const session = await api.signup({ baseUrl, email, name, password });
|
|
111
|
+
const nextSession = await writeSessionWithSelectedOrg({
|
|
112
|
+
api,
|
|
113
|
+
context,
|
|
114
|
+
parsed,
|
|
115
|
+
prompts,
|
|
116
|
+
session
|
|
117
|
+
});
|
|
118
|
+
if (resolvedBaseUrl.shouldPersistGlobalBaseUrl) {
|
|
119
|
+
await writeCliConfig(context.configPath, {
|
|
120
|
+
...resolvedBaseUrl.persistedGlobalConfig,
|
|
121
|
+
baseUrl
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
return {
|
|
125
|
+
data: {
|
|
126
|
+
activeOrg: nextSession.activeOrg,
|
|
127
|
+
user: nextSession.user
|
|
128
|
+
},
|
|
129
|
+
human: renderSuccess(nextSession.activeOrg
|
|
130
|
+
? `Signed up as ${nextSession.user.email}. Active org: ${nextSession.activeOrg.slug}.`
|
|
131
|
+
: `Signed up as ${nextSession.user.email}.`),
|
|
132
|
+
kind: "access_auth_signup",
|
|
133
|
+
meta: {
|
|
134
|
+
command: "auth signup",
|
|
135
|
+
orgId: nextSession.activeOrg?.id ?? null
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
async function resolveAuthBaseUrl(parsed, context, prompts) {
|
|
140
|
+
const persistedGlobalConfig = await readCliConfig(context.configPath);
|
|
141
|
+
const repoConfigPath = await findRepoConfigPath(context.cwd);
|
|
142
|
+
const repoConfig = repoConfigPath ? await readCliConfig(repoConfigPath) : {};
|
|
143
|
+
const flagBaseUrl = readOptionalStringFlag(parsed, "base-url");
|
|
144
|
+
const envBaseUrl = context.env.KORA_BASE_URL;
|
|
145
|
+
const configuredBaseUrl = flagBaseUrl ?? envBaseUrl ?? repoConfig.baseUrl ?? persistedGlobalConfig.baseUrl;
|
|
146
|
+
const baseUrl = configuredBaseUrl ?? await promptText("Platform base URL: ", prompts);
|
|
147
|
+
return {
|
|
148
|
+
baseUrl,
|
|
149
|
+
persistedGlobalConfig,
|
|
150
|
+
shouldPersistGlobalBaseUrl: !flagBaseUrl && !envBaseUrl && !repoConfig.baseUrl
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
async function writeSessionWithSelectedOrg(input) {
|
|
154
|
+
const organizations = (await input.api.listOrganizations(input.session)).organizations;
|
|
155
|
+
const activeOrg = organizations.length === 1
|
|
156
|
+
? organizations[0] ?? null
|
|
157
|
+
: organizations.length > 1
|
|
158
|
+
? await chooseOrganization(organizations, input.prompts, input.parsed)
|
|
159
|
+
: null;
|
|
160
|
+
const latestSession = await readLatestSessionForWrite(input.context.sessionStore, input.session);
|
|
161
|
+
const sessionForWrite = isSameSessionIdentity(latestSession, input.session) ? latestSession : input.session;
|
|
162
|
+
const nextSession = {
|
|
163
|
+
...sessionForWrite,
|
|
164
|
+
activeOrg: activeOrg
|
|
165
|
+
? {
|
|
166
|
+
id: activeOrg.id,
|
|
167
|
+
name: activeOrg.name,
|
|
168
|
+
role: activeOrg.role,
|
|
169
|
+
slug: activeOrg.slug,
|
|
170
|
+
status: activeOrg.status
|
|
171
|
+
}
|
|
172
|
+
: null
|
|
173
|
+
};
|
|
174
|
+
await input.context.sessionStore.write(nextSession);
|
|
175
|
+
return nextSession;
|
|
176
|
+
}
|
|
90
177
|
async function readAuthSettingsOrDefault(api, baseUrl) {
|
|
91
178
|
try {
|
|
92
179
|
return await api.getAuthSettings(baseUrl);
|
|
@@ -3,6 +3,7 @@ export declare function arg(name: string, description: string, required?: boolea
|
|
|
3
3
|
export declare function flag(name: string, description: string, input?: {
|
|
4
4
|
acceptsValue?: boolean;
|
|
5
5
|
defaultValue?: boolean | number | string;
|
|
6
|
+
hiddenWhenCommandFiltered?: boolean;
|
|
6
7
|
knownValues?: string[];
|
|
7
8
|
repeatable?: boolean;
|
|
8
9
|
required?: boolean;
|
package/dist/command-builders.js
CHANGED
|
@@ -10,6 +10,7 @@ export function flag(name, description, input = {}) {
|
|
|
10
10
|
acceptsValue: input.acceptsValue ?? false,
|
|
11
11
|
...(input.defaultValue !== undefined ? { defaultValue: input.defaultValue } : {}),
|
|
12
12
|
description,
|
|
13
|
+
...(input.hiddenWhenCommandFiltered ? { hiddenWhenCommandFiltered: true } : {}),
|
|
13
14
|
...(input.knownValues ? { knownValues: input.knownValues } : {}),
|
|
14
15
|
name,
|
|
15
16
|
...(input.repeatable ? { repeatable: true } : {}),
|
package/dist/command-groups.js
CHANGED
|
@@ -5,29 +5,27 @@ const COMMAND_GROUP_DESCRIPTIONS = new Map([
|
|
|
5
5
|
["access members", "Organization member inspection and membership lifecycle."],
|
|
6
6
|
["activity", "Recent workflow, agent, person, and capability activity."],
|
|
7
7
|
["admin", "Platform-admin lifecycle controls."],
|
|
8
|
-
["artifact", "Managed
|
|
8
|
+
["artifact", "Managed runtime artifact upload and inspection."],
|
|
9
|
+
["audit", "Organization admin audit event inspection."],
|
|
9
10
|
["auth", "Current identity and login session management."],
|
|
10
|
-
["chat", "Chat session
|
|
11
|
+
["chat", "Chat session health and history inspection."],
|
|
11
12
|
["completion", "Shell completion and completion helpers."],
|
|
12
|
-
["
|
|
13
|
-
["
|
|
14
|
-
["
|
|
15
|
-
["
|
|
13
|
+
["deployment", "Environment deployment inspection."],
|
|
14
|
+
["env", "Runtime variables for an environment."],
|
|
15
|
+
["environment", "Deployment environments and environment actions."],
|
|
16
|
+
["extensions", "Extension package, install, and built-in lifecycle."],
|
|
17
|
+
["extensions built-ins", "Kora-provided built-in extension catalog and installation."],
|
|
16
18
|
["secrets", "Organization secret definitions."],
|
|
17
|
-
["org", "Organization selection
|
|
18
|
-
["org bundle", "Current organization bundle inspection."],
|
|
19
|
+
["org", "Organization selection and settings."],
|
|
19
20
|
["org settings", "Applied organization settings."],
|
|
20
21
|
["org-model", "Modeled people, roles, agents, assignments, capabilities, operations, and related inventory."],
|
|
21
22
|
["org-model agents", "Modeled agents in the executable organization model."],
|
|
22
23
|
["org-model assignments", "Role and capability assignments in the executable organization model."],
|
|
23
24
|
["org-model capabilities", "Modeled capabilities in the executable organization model."],
|
|
24
|
-
["org-model connectors", "Modeled connectors in the executable organization model."],
|
|
25
|
-
["org-model mcp-servers", "Modeled MCP servers in the executable organization model."],
|
|
26
25
|
["org-model operations", "Modeled operations in the executable organization model."],
|
|
27
26
|
["org-model people", "Modeled people in the executable organization model."],
|
|
28
27
|
["org-model roles", "Modeled roles in the executable organization model."],
|
|
29
|
-
["release", "
|
|
30
|
-
["release deployment", "Deployment inspection for a release."],
|
|
28
|
+
["release", "Release artifacts and deployment readiness."],
|
|
31
29
|
["run", "Workflow run inspection and run control."],
|
|
32
30
|
["schema", "Product and resource schemas."],
|
|
33
31
|
["task", "Task and inbox inspection plus task completion."],
|