@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.
- 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
package/dist/session.d.ts
CHANGED
package/dist/transport.d.ts
CHANGED
|
@@ -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" | "
|
|
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.
|
|
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
|
-
}
|