@kora-platform/cli 0.7.0-rc1 → 0.8.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.
Files changed (38) hide show
  1. package/README.md +21 -0
  2. package/dist/api-client.d.ts +250 -93
  3. package/dist/api-client.js +187 -163
  4. package/dist/api-types.d.ts +280 -162
  5. package/dist/artifact-api-client.d.ts +28 -1
  6. package/dist/artifact-api-client.js +33 -0
  7. package/dist/artifact-commands.d.ts +5 -0
  8. package/dist/artifact-commands.js +172 -1
  9. package/dist/audit-commands.d.ts +12 -0
  10. package/dist/audit-commands.js +74 -0
  11. package/dist/auth-commands.d.ts +1 -0
  12. package/dist/auth-commands.js +116 -29
  13. package/dist/command-builders.d.ts +1 -0
  14. package/dist/command-builders.js +1 -0
  15. package/dist/command-groups.js +10 -12
  16. package/dist/command-registry.js +548 -243
  17. package/dist/commands.js +652 -602
  18. package/dist/environment-context.d.ts +9 -0
  19. package/dist/environment-context.js +32 -0
  20. package/dist/{integration-commands.d.ts → extension-commands.d.ts} +3 -2
  21. package/dist/extension-commands.js +446 -0
  22. package/dist/files.d.ts +33 -0
  23. package/dist/files.js +247 -12
  24. package/dist/format.d.ts +5 -0
  25. package/dist/format.js +78 -1
  26. package/dist/runner.js +14 -5
  27. package/dist/schema-registry-data.d.ts +272 -569
  28. package/dist/schema-registry-data.js +307 -700
  29. package/dist/session.d.ts +1 -0
  30. package/dist/transport.d.ts +10 -0
  31. package/dist/transport.js +22 -0
  32. package/dist/types.d.ts +2 -1
  33. package/dist/workspace-source.d.ts +1 -0
  34. package/dist/workspace-source.js +13 -0
  35. package/package.json +2 -1
  36. package/dist/integration-api-client.d.ts +0 -29
  37. package/dist/integration-api-client.js +0 -50
  38. package/dist/integration-commands.js +0 -208
package/dist/session.d.ts CHANGED
@@ -16,6 +16,7 @@ export interface CliSessionState {
16
16
  status: string;
17
17
  } | null;
18
18
  baseUrl: string;
19
+ defaultEnvironment?: string;
19
20
  refreshToken: string;
20
21
  refreshTokenExpiresAt: string;
21
22
  user: {
@@ -10,6 +10,7 @@ export interface CliAuthSettings {
10
10
  oidcEnabled: boolean;
11
11
  selfServiceOrgCreationEnabled: boolean;
12
12
  }
13
+ export type ApiErrorDetails = Record<string, unknown>;
13
14
  type RequestBody = unknown | ((session: CliSessionState) => unknown);
14
15
  type BytesRequest = {
15
16
  createMaxBytesError?: (input: {
@@ -20,11 +21,13 @@ type BytesRequest = {
20
21
  maxBytes?: number;
21
22
  method?: string;
22
23
  path: string;
24
+ rawBody?: Uint8Array;
23
25
  session: CliSessionState | null;
24
26
  validateHeaders?: (headers: Headers) => void;
25
27
  };
26
28
  export declare class ApiError extends Error {
27
29
  readonly detail: string;
30
+ readonly details?: ApiErrorDetails;
28
31
  readonly instance: string;
29
32
  readonly rawDetail?: string;
30
33
  readonly status: number;
@@ -32,6 +35,7 @@ export declare class ApiError extends Error {
32
35
  readonly type: string;
33
36
  constructor(input: {
34
37
  detail: string;
38
+ details?: ApiErrorDetails;
35
39
  instance: string;
36
40
  rawDetail?: string;
37
41
  status: number;
@@ -49,6 +53,12 @@ export declare function createPlatformTransport(input: {
49
53
  email: string;
50
54
  password: string;
51
55
  }): Promise<CliSessionState>;
56
+ signup(credentials: {
57
+ baseUrl: string;
58
+ email: string;
59
+ name: string;
60
+ password: string;
61
+ }): Promise<CliSessionState>;
52
62
  refreshSession(session: CliSessionState): Promise<CliSessionState>;
53
63
  requestJson<T>(request: {
54
64
  body?: RequestBody;
package/dist/transport.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { extractRefreshTokenFromHeaders } from "./session.js";
2
2
  export class ApiError extends Error {
3
3
  detail;
4
+ details;
4
5
  instance;
5
6
  rawDetail;
6
7
  status;
@@ -10,6 +11,9 @@ export class ApiError extends Error {
10
11
  super(input.detail);
11
12
  this.name = "ApiError";
12
13
  this.detail = input.detail;
14
+ if (input.details) {
15
+ this.details = input.details;
16
+ }
13
17
  this.instance = input.instance;
14
18
  if (input.rawDetail !== undefined) {
15
19
  this.rawDetail = input.rawDetail;
@@ -45,6 +49,23 @@ export function createPlatformTransport(input) {
45
49
  await input.sessionStore.write(session);
46
50
  return session;
47
51
  },
52
+ async signup(credentials) {
53
+ const normalizedBaseUrl = normalizeBaseUrl(credentials.baseUrl);
54
+ const response = await fetch(joinBaseUrl(normalizedBaseUrl, "/api/v1/auth/signup"), {
55
+ body: JSON.stringify({
56
+ email: credentials.email,
57
+ name: credentials.name,
58
+ password: credentials.password
59
+ }),
60
+ headers: {
61
+ "content-type": "application/json"
62
+ },
63
+ method: "POST"
64
+ });
65
+ const session = await parseSessionResponse(response, normalizedBaseUrl, "/api/v1/auth/signup");
66
+ await input.sessionStore.write(session);
67
+ return session;
68
+ },
48
69
  async refreshSession(session) {
49
70
  const response = await fetch(joinBaseUrl(session.baseUrl, "/api/v1/auth/refresh"), {
50
71
  body: JSON.stringify({
@@ -255,6 +276,7 @@ async function toApiError(response, path) {
255
276
  const detail = relabelBackendText(rawDetail || response.statusText);
256
277
  return new ApiError({
257
278
  detail,
279
+ ...(parsed?.error?.details ? { details: parsed.error.details } : {}),
258
280
  instance: path,
259
281
  ...(rawDetail ? { rawDetail } : {}),
260
282
  status: response.status,
package/dist/types.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  export type CommandPagination = "none" | "limit" | "limit-offset" | "cursor";
2
- export type CommandLabel = "access" | "action" | "activity" | "admin" | "artifact" | "auth" | "chat" | "completion" | "credential" | "destructive" | "env" | "execution" | "help" | "integration" | "local" | "mcp" | "org" | "org-model" | "output" | "probe" | "publish" | "read" | "release" | "run" | "schema" | "secret" | "skill" | "status" | "task" | "workflow" | "write";
2
+ export type CommandLabel = "access" | "action" | "activity" | "admin" | "artifact" | "audit" | "auth" | "chat" | "chat-execution" | "chat-read" | "chat-write" | "completion" | "credential" | "destructive" | "env" | "environment" | "execution" | "extension" | "help" | "local" | "org" | "org-model" | "output" | "probe" | "publish" | "read" | "release" | "deployment" | "run" | "schema" | "secret" | "status" | "task" | "workspace" | "workflow" | "write";
3
3
  export interface CommandArgDefinition {
4
4
  description: string;
5
5
  name: string;
@@ -9,6 +9,7 @@ export interface CommandFlagDefinition {
9
9
  acceptsValue: boolean;
10
10
  defaultValue?: boolean | number | string;
11
11
  description: string;
12
+ hiddenWhenCommandFiltered?: boolean;
12
13
  knownValues?: string[];
13
14
  name: string;
14
15
  repeatable?: boolean;
@@ -0,0 +1 @@
1
+ export declare function shouldIgnoreWorkspacePath(pathValue: string): boolean;
@@ -0,0 +1,13 @@
1
+ const IGNORED_WORKSPACE_DIRECTORY_NAMES = new Set([
2
+ ".git",
3
+ ".kora",
4
+ "coverage",
5
+ "dist",
6
+ "node_modules"
7
+ ]);
8
+ const IGNORED_WORKSPACE_FILE_NAMES = new Set([".DS_Store", "Thumbs.db"]);
9
+ export function shouldIgnoreWorkspacePath(pathValue) {
10
+ const segments = pathValue.replace(/\\/gu, "/").split("/").filter((segment) => segment.length > 0);
11
+ return segments.some((segment) => IGNORED_WORKSPACE_DIRECTORY_NAMES.has(segment)) ||
12
+ IGNORED_WORKSPACE_FILE_NAMES.has(segments.at(-1) ?? "");
13
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kora-platform/cli",
3
- "version": "0.7.0-rc1",
3
+ "version": "0.8.0-rc2",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "main": "dist/library.js",
@@ -34,6 +34,7 @@
34
34
  "engines": {
35
35
  "node": ">=24.0.0"
36
36
  },
37
+ "dependencies": {},
37
38
  "scripts": {
38
39
  "build": "pnpm run clean && pnpm run generate:schema-registry && tsc -b tsconfig.build.json",
39
40
  "check:package": "pnpm run build && node ../../../scripts/check-cli-pack-output.mjs",
@@ -1,29 +0,0 @@
1
- import type { ManagedIntegrationActionDescriptor, ManagedIntegrationActionInput, ManagedIntegrationActionResult, ManagedIntegrationConnectionSummary, ManagedIntegrationDiagnostic, ManagedIntegrationPromptGuidance, ManagedIntegrationSummary } from "./api-types.js";
2
- import type { CliSessionState } from "./transport.js";
3
- import { createPlatformTransport } from "./transport.js";
4
- export interface PlatformIntegrationApiClientInput {
5
- sessionStore: Parameters<typeof createPlatformTransport>[0]["sessionStore"];
6
- }
7
- export declare function createPlatformIntegrationApiClient(input: PlatformIntegrationApiClientInput): {
8
- listManagedIntegrations(session: CliSessionState, orgId: string): Promise<{
9
- integrations: ManagedIntegrationSummary[];
10
- }>;
11
- listManagedIntegrationDiagnostics(session: CliSessionState, orgId: string): Promise<{
12
- integrations: ManagedIntegrationDiagnostic[];
13
- }>;
14
- getManagedIntegration(session: CliSessionState, orgId: string, integrationId: string): Promise<{
15
- integration: ManagedIntegrationSummary;
16
- }>;
17
- listManagedIntegrationConnections(session: CliSessionState, orgId: string, integrationId: string): Promise<{
18
- connections: ManagedIntegrationConnectionSummary[];
19
- }>;
20
- listManagedIntegrationActions(session: CliSessionState, orgId: string, integrationId: string): Promise<{
21
- actions: ManagedIntegrationActionDescriptor[];
22
- }>;
23
- executeManagedIntegrationAction(session: CliSessionState, orgId: string, integrationId: string, actionId: string, inputData: ManagedIntegrationActionInput): Promise<{
24
- result: ManagedIntegrationActionResult;
25
- }>;
26
- listManagedIntegrationPromptGuidance(session: CliSessionState, orgId: string): Promise<{
27
- guidance: ManagedIntegrationPromptGuidance[];
28
- }>;
29
- };
@@ -1,50 +0,0 @@
1
- import { createPlatformTransport } from "./transport.js";
2
- export function createPlatformIntegrationApiClient(input) {
3
- const transport = createPlatformTransport(input);
4
- return {
5
- async listManagedIntegrations(session, orgId) {
6
- return transport.requestJson({
7
- path: `/api/v1/orgs/${encodeURIComponent(orgId)}/integration-host/integrations`,
8
- session
9
- });
10
- },
11
- async listManagedIntegrationDiagnostics(session, orgId) {
12
- return transport.requestJson({
13
- path: `/api/v1/orgs/${encodeURIComponent(orgId)}/integration-host/integrations/diagnostics`,
14
- session
15
- });
16
- },
17
- async getManagedIntegration(session, orgId, integrationId) {
18
- return transport.requestJson({
19
- path: `/api/v1/orgs/${encodeURIComponent(orgId)}/integration-host/integrations/${encodeURIComponent(integrationId)}`,
20
- session
21
- });
22
- },
23
- async listManagedIntegrationConnections(session, orgId, integrationId) {
24
- return transport.requestJson({
25
- path: `/api/v1/orgs/${encodeURIComponent(orgId)}/integration-host/integrations/${encodeURIComponent(integrationId)}/connections`,
26
- session
27
- });
28
- },
29
- async listManagedIntegrationActions(session, orgId, integrationId) {
30
- return transport.requestJson({
31
- path: `/api/v1/orgs/${encodeURIComponent(orgId)}/integration-host/integrations/${encodeURIComponent(integrationId)}/actions`,
32
- session
33
- });
34
- },
35
- async executeManagedIntegrationAction(session, orgId, integrationId, actionId, inputData) {
36
- return transport.requestJson({
37
- body: inputData,
38
- method: "POST",
39
- path: `/api/v1/orgs/${encodeURIComponent(orgId)}/integration-host/integrations/${encodeURIComponent(integrationId)}/actions/${encodeURIComponent(actionId)}`,
40
- session
41
- });
42
- },
43
- async listManagedIntegrationPromptGuidance(session, orgId) {
44
- return transport.requestJson({
45
- path: `/api/v1/orgs/${encodeURIComponent(orgId)}/integration-host/prompt-guidance`,
46
- session
47
- });
48
- }
49
- };
50
- }
@@ -1,208 +0,0 @@
1
- import { shouldAutoOpenBrowser, openBrowser } from "./browser.js";
2
- import { genericProblem, notFoundProblem, usageProblem } from "./cli-errors.js";
3
- import { readOptionalStringFlag } from "./command-flags.js";
4
- import { readJsonInputSpecifier } from "./files.js";
5
- import { renderPrettyJson, renderTable } from "./format.js";
6
- import { createPlatformIntegrationApiClient } from "./integration-api-client.js";
7
- import { isInteractive } from "./prompts.js";
8
- export async function executeIntegrations(parsed, context, api, resolveOrgScope) {
9
- const { org, session } = await resolveOrgScope(parsed, context, api);
10
- const integrationApi = createPlatformIntegrationApiClient({
11
- sessionStore: context.sessionStore
12
- });
13
- switch (parsed.definition.id) {
14
- case "integrations.list": {
15
- const data = redactIntegrationCliOutput(await integrationApi.listManagedIntegrations(session, org.id));
16
- return {
17
- data,
18
- human: renderTable(data.integrations, [
19
- { key: "id", label: "Integration" },
20
- { key: "displayName", label: "Name" },
21
- { key: "description", label: "Description" }
22
- ]),
23
- kind: "integrations_list",
24
- meta: { command: parsed.definition.path.join(" "), orgId: org.id }
25
- };
26
- }
27
- case "integrations.diagnostics": {
28
- const data = redactIntegrationCliOutput(await integrationApi.listManagedIntegrationDiagnostics(session, org.id));
29
- return {
30
- data,
31
- human: renderTable(data.integrations, [
32
- { key: "id", label: "Integration" },
33
- { key: "displayName", label: "Name" },
34
- { key: "status", label: "Status" },
35
- { key: "message", label: "Message" },
36
- { key: "missingConfigFields", label: "Missing config" },
37
- { key: "invalidConfigFields", label: "Invalid config" }
38
- ]),
39
- kind: "integrations_diagnostics",
40
- meta: { command: parsed.definition.path.join(" "), orgId: org.id }
41
- };
42
- }
43
- case "integrations.get": {
44
- const data = redactIntegrationCliOutput(await integrationApi.getManagedIntegration(session, org.id, readRequiredArg(parsed, "integration-id")));
45
- return {
46
- data,
47
- human: renderPrettyJson(data.integration),
48
- kind: "integrations_get",
49
- meta: { command: parsed.definition.path.join(" "), orgId: org.id }
50
- };
51
- }
52
- case "integrations.actions": {
53
- const data = redactIntegrationCliOutput(await integrationApi.listManagedIntegrationActions(session, org.id, readRequiredArg(parsed, "integration-id")));
54
- return {
55
- data,
56
- human: renderTable(data.actions, [
57
- { key: "id", label: "Action" },
58
- { key: "label", label: "Label" },
59
- { key: "cliSafe", label: "CLI" },
60
- { key: "description", label: "Description" }
61
- ]),
62
- kind: "integrations_actions",
63
- meta: { command: parsed.definition.path.join(" "), orgId: org.id }
64
- };
65
- }
66
- case "integrations.connections": {
67
- const data = redactIntegrationCliOutput(await integrationApi.listManagedIntegrationConnections(session, org.id, readRequiredArg(parsed, "integration-id")));
68
- return {
69
- data,
70
- human: renderTable(data.connections, [
71
- { key: "connectionRef", label: "Connection" },
72
- { key: "displayName", label: "Name" },
73
- { key: "status", label: "Status" },
74
- { key: "labels", label: "Labels" }
75
- ]),
76
- kind: "integrations_connections",
77
- meta: { command: parsed.definition.path.join(" "), orgId: org.id }
78
- };
79
- }
80
- case "integrations.action": {
81
- const integrationId = readRequiredArg(parsed, "integration-id");
82
- const actionId = readRequiredArg(parsed, "action-id");
83
- const actions = (await integrationApi.listManagedIntegrationActions(session, org.id, integrationId)).actions;
84
- const action = requireFound(actions.find((entry) => entry.id === actionId) ?? null, `Integration action '${actionId}' was not found.`, parsed.definition.id);
85
- if (!action.cliSafe) {
86
- throw usageProblem(`Integration action '${actionId}' requires the Settings UI.`, parsed.definition.id);
87
- }
88
- const input = await buildIntegrationActionInput(parsed, context);
89
- const data = redactIntegrationCliOutput(await integrationApi.executeManagedIntegrationAction(session, org.id, integrationId, actionId, input));
90
- await handleIntegrationExternalUrls(data.result.effects, parsed, context);
91
- return {
92
- data,
93
- human: renderIntegrationActionHuman(data.result),
94
- kind: "integrations_action_execute",
95
- meta: { command: parsed.definition.path.join(" "), orgId: org.id }
96
- };
97
- }
98
- default:
99
- throw genericProblem(`Unhandled integrations command ${parsed.definition.id}.`, parsed.definition.id);
100
- }
101
- }
102
- async function buildIntegrationActionInput(parsed, context) {
103
- const input = {};
104
- const connectionRef = readOptionalStringFlag(parsed, "connection");
105
- if (connectionRef) {
106
- input.connectionRef = connectionRef;
107
- }
108
- const inputSpecifier = readOptionalStringFlag(parsed, "input");
109
- if (inputSpecifier) {
110
- const value = await readJsonInputSpecifier(inputSpecifier, context.stdin, parsed.definition.id);
111
- if (!isManagedIntegrationJsonObject(value)) {
112
- throw usageProblem("Integration action input must be a JSON object.", parsed.definition.id);
113
- }
114
- input.input = value;
115
- }
116
- return input;
117
- }
118
- async function handleIntegrationExternalUrls(effects, parsed, context) {
119
- const externalUrls = effects.filter((effect) => effect.kind === "open_external_url");
120
- if (externalUrls.length === 0) {
121
- return;
122
- }
123
- const explicitOpen = parsed.flags.open === true;
124
- const shouldOpen = shouldAutoOpenBrowser({
125
- env: context.env,
126
- explicitNoOpen: parsed.flags["no-open"] === true,
127
- explicitOpen,
128
- interactive: isInteractive(context),
129
- openBrowserConfig: context.config.openBrowser
130
- });
131
- if (!shouldOpen) {
132
- return;
133
- }
134
- for (const effect of externalUrls) {
135
- const opened = await openBrowser(effect.url);
136
- if (explicitOpen && !opened) {
137
- throw genericProblem(`Could not open a browser automatically. Visit ${effect.url}`, parsed.definition.id);
138
- }
139
- }
140
- }
141
- function renderIntegrationActionHuman(result) {
142
- const lines = [`Integration action ${result.actionId} completed.`];
143
- for (const effect of result.effects) {
144
- switch (effect.kind) {
145
- case "user_message":
146
- lines.push(effect.message);
147
- break;
148
- case "open_external_url":
149
- lines.push(`${effect.label ?? "Open"}: ${effect.url}`);
150
- break;
151
- case "connection_ready":
152
- lines.push(`Connection ready: ${effect.displayName} (${effect.connectionRef})`);
153
- break;
154
- case "terminal_failure":
155
- lines.push(`Failure: ${effect.message}`);
156
- break;
157
- case "schedule_poll":
158
- lines.push(`Polling scheduled in ${String(effect.intervalMs)}ms${effect.reason ? `: ${effect.reason}` : ""}.`);
159
- break;
160
- case "refresh_state":
161
- lines.push(`State refresh requested${effect.reason ? `: ${effect.reason}` : ""}.`);
162
- break;
163
- default:
164
- assertNever(effect);
165
- }
166
- }
167
- return lines.join("\n");
168
- }
169
- function redactIntegrationCliOutput(value) {
170
- return redactIntegrationCliValue(value, null);
171
- }
172
- function redactIntegrationCliValue(value, key) {
173
- if (key !== null && isSecretLikeKey(key) && value !== null && value !== undefined) {
174
- return "[redacted]";
175
- }
176
- if (Array.isArray(value)) {
177
- return value.map((entry) => redactIntegrationCliValue(entry, null));
178
- }
179
- if (typeof value === "object" && value !== null) {
180
- return Object.fromEntries(Object.entries(value).map(([entryKey, entryValue]) => [
181
- entryKey,
182
- redactIntegrationCliValue(entryValue, entryKey)
183
- ]));
184
- }
185
- return value;
186
- }
187
- function isSecretLikeKey(key) {
188
- return /(?:access|refresh)?token|secret|private[_-]?key|password|credential|authorization/i.test(key);
189
- }
190
- function isManagedIntegrationJsonObject(value) {
191
- return typeof value === "object" && value !== null && !Array.isArray(value);
192
- }
193
- function readRequiredArg(parsed, name) {
194
- const value = parsed.args[name];
195
- if (!value) {
196
- throw usageProblem(`Missing required argument <${name}>.`, parsed.definition.id);
197
- }
198
- return value;
199
- }
200
- function requireFound(value, detail, instance) {
201
- if (value === null || value === undefined) {
202
- throw notFoundProblem(detail, instance);
203
- }
204
- return value;
205
- }
206
- function assertNever(value) {
207
- throw new Error(`Unhandled integration host effect: ${JSON.stringify(value)}`);
208
- }