@kora-platform/cli 0.7.0-rc1 → 0.8.0-rc10

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 (49) hide show
  1. package/README.md +21 -0
  2. package/dist/api-client.d.ts +274 -106
  3. package/dist/api-client.js +192 -167
  4. package/dist/api-types.d.ts +301 -163
  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 +177 -4
  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 +195 -32
  13. package/dist/cli-errors.d.ts +7 -1
  14. package/dist/cli-errors.js +12 -1
  15. package/dist/command-builders.d.ts +1 -0
  16. package/dist/command-builders.js +1 -0
  17. package/dist/command-flags.d.ts +1 -0
  18. package/dist/command-flags.js +7 -0
  19. package/dist/command-groups.js +10 -12
  20. package/dist/command-registry.js +595 -277
  21. package/dist/commands.js +728 -636
  22. package/dist/environment-context.d.ts +9 -0
  23. package/dist/environment-context.js +32 -0
  24. package/dist/error-code.d.ts +2 -0
  25. package/dist/error-code.js +9 -0
  26. package/dist/{integration-commands.d.ts → extension-commands.d.ts} +3 -2
  27. package/dist/extension-commands.js +446 -0
  28. package/dist/files.d.ts +44 -4
  29. package/dist/files.js +349 -26
  30. package/dist/format.d.ts +6 -0
  31. package/dist/format.js +83 -1
  32. package/dist/runner.js +28 -10
  33. package/dist/schema-registry-data.d.ts +318 -571
  34. package/dist/schema-registry-data.js +356 -698
  35. package/dist/session-store.js +80 -0
  36. package/dist/session.d.ts +1 -0
  37. package/dist/transport-refresh.d.ts +10 -0
  38. package/dist/transport-refresh.js +51 -0
  39. package/dist/transport.d.ts +31 -0
  40. package/dist/transport.js +102 -36
  41. package/dist/types.d.ts +2 -1
  42. package/dist/workspace-source.d.ts +1 -0
  43. package/dist/workspace-source.js +13 -0
  44. package/package.json +2 -1
  45. package/dist/dotenv.d.ts +0 -1
  46. package/dist/dotenv.js +0 -26
  47. package/dist/integration-api-client.d.ts +0 -29
  48. package/dist/integration-api-client.js +0 -50
  49. package/dist/integration-commands.js +0 -208
@@ -1,5 +1,10 @@
1
+ import { mkdir, open, rm, stat } from "node:fs/promises";
2
+ import { dirname } from "node:path";
1
3
  import { readSessionFile, removeSessionFile, writeSessionFile } from "./session.js";
4
+ const REFRESH_LOCK_STALE_MS = 30_000;
5
+ const REFRESH_LOCK_RETRY_MS = 25;
2
6
  export function createFileSessionStore(path) {
7
+ const refreshLockPath = `${path}.refresh.lock`;
3
8
  return {
4
9
  async clear() {
5
10
  await removeSessionFile(path);
@@ -9,11 +14,15 @@ export function createFileSessionStore(path) {
9
14
  },
10
15
  async write(session) {
11
16
  await writeSessionFile(path, session);
17
+ },
18
+ async withRefreshLock(operation) {
19
+ return withFileRefreshLock(refreshLockPath, operation);
12
20
  }
13
21
  };
14
22
  }
15
23
  export function createMemorySessionStore(initial = null) {
16
24
  let current = initial;
25
+ let refreshLock = Promise.resolve();
17
26
  return {
18
27
  async clear() {
19
28
  current = null;
@@ -23,6 +32,77 @@ export function createMemorySessionStore(initial = null) {
23
32
  },
24
33
  async write(session) {
25
34
  current = session;
35
+ },
36
+ async withRefreshLock(operation) {
37
+ const previous = refreshLock;
38
+ let release;
39
+ refreshLock = new Promise((resolve) => {
40
+ release = resolve;
41
+ });
42
+ await previous;
43
+ try {
44
+ return await operation();
45
+ }
46
+ finally {
47
+ release();
48
+ }
26
49
  }
27
50
  };
28
51
  }
52
+ async function withFileRefreshLock(lockPath, operation) {
53
+ const release = await acquireFileRefreshLock(lockPath);
54
+ try {
55
+ return await operation();
56
+ }
57
+ finally {
58
+ await release();
59
+ }
60
+ }
61
+ async function acquireFileRefreshLock(lockPath) {
62
+ await mkdir(dirname(lockPath), { recursive: true });
63
+ while (true) {
64
+ try {
65
+ const handle = await open(lockPath, "wx", 0o600);
66
+ try {
67
+ await handle.writeFile(`${String(process.pid)} ${new Date().toISOString()}\n`);
68
+ }
69
+ finally {
70
+ await handle.close();
71
+ }
72
+ return async () => {
73
+ await rm(lockPath, { force: true });
74
+ };
75
+ }
76
+ catch (error) {
77
+ if (!isFileExistsError(error)) {
78
+ throw error;
79
+ }
80
+ await removeStaleFileRefreshLock(lockPath);
81
+ await sleep(REFRESH_LOCK_RETRY_MS);
82
+ }
83
+ }
84
+ }
85
+ async function removeStaleFileRefreshLock(lockPath) {
86
+ try {
87
+ const fileStat = await stat(lockPath);
88
+ if (Date.now() - fileStat.mtimeMs > REFRESH_LOCK_STALE_MS) {
89
+ await rm(lockPath, { force: true });
90
+ }
91
+ }
92
+ catch (error) {
93
+ if (!isMissingFileError(error)) {
94
+ throw error;
95
+ }
96
+ }
97
+ }
98
+ async function sleep(ms) {
99
+ await new Promise((resolve) => {
100
+ setTimeout(resolve, ms);
101
+ });
102
+ }
103
+ function isFileExistsError(error) {
104
+ return Boolean(error && typeof error === "object" && "code" in error && error.code === "EEXIST");
105
+ }
106
+ function isMissingFileError(error) {
107
+ return Boolean(error && typeof error === "object" && "code" in error && error.code === "ENOENT");
108
+ }
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: {
@@ -0,0 +1,10 @@
1
+ import type { CliSessionState } from "./session.js";
2
+ import type { SessionStore } from "./transport.js";
3
+ export declare function refreshSessionWithCoordination(input: {
4
+ isRefreshTokenInvalidError: (error: unknown) => boolean;
5
+ refreshSessionDirect: (session: CliSessionState) => Promise<CliSessionState>;
6
+ session: CliSessionState;
7
+ sessionStore: SessionStore;
8
+ shouldRefresh: (session: CliSessionState) => boolean;
9
+ }): Promise<CliSessionState>;
10
+ export declare function resolveEffectiveSession(requestSession: CliSessionState | null, sessionStore: SessionStore): Promise<CliSessionState | null>;
@@ -0,0 +1,51 @@
1
+ export async function refreshSessionWithCoordination(input) {
2
+ return withRefreshLock(input.sessionStore, async () => {
3
+ const effectiveSession = (await resolveEffectiveSession(input.session, input.sessionStore)) ?? input.session;
4
+ if (isSessionNewer(effectiveSession, input.session) && !input.shouldRefresh(effectiveSession)) {
5
+ return effectiveSession;
6
+ }
7
+ try {
8
+ return await input.refreshSessionDirect(effectiveSession);
9
+ }
10
+ catch (error) {
11
+ if (input.isRefreshTokenInvalidError(error)) {
12
+ const recoveredSession = await resolveEffectiveSession(input.session, input.sessionStore);
13
+ if (recoveredSession &&
14
+ isSessionNewer(recoveredSession, input.session) &&
15
+ !input.shouldRefresh(recoveredSession)) {
16
+ return recoveredSession;
17
+ }
18
+ }
19
+ throw error;
20
+ }
21
+ });
22
+ }
23
+ async function withRefreshLock(sessionStore, operation) {
24
+ return sessionStore.withRefreshLock
25
+ ? sessionStore.withRefreshLock(operation)
26
+ : operation();
27
+ }
28
+ export async function resolveEffectiveSession(requestSession, sessionStore) {
29
+ if (!requestSession) {
30
+ return null;
31
+ }
32
+ const storedSession = await sessionStore.read();
33
+ if (!storedSession || !isSameSessionIdentity(storedSession, requestSession)) {
34
+ return requestSession;
35
+ }
36
+ return isSessionNewer(storedSession, requestSession) ? storedSession : requestSession;
37
+ }
38
+ function isSameSessionIdentity(candidate, current) {
39
+ return candidate.baseUrl === current.baseUrl
40
+ && candidate.user.id === current.user.id
41
+ && candidate.accessTokenPayload.sub === current.accessTokenPayload.sub;
42
+ }
43
+ function isSessionNewer(candidate, current) {
44
+ if (candidate.accessToken === current.accessToken && candidate.refreshToken === current.refreshToken) {
45
+ return false;
46
+ }
47
+ if (candidate.accessTokenPayload.exp !== current.accessTokenPayload.exp) {
48
+ return candidate.accessTokenPayload.exp > current.accessTokenPayload.exp;
49
+ }
50
+ return candidate.accessTokenPayload.iat >= current.accessTokenPayload.iat;
51
+ }
@@ -2,6 +2,7 @@ import { type CliSessionState } from "./session.js";
2
2
  export interface SessionStore {
3
3
  clear(): Promise<void>;
4
4
  read(): Promise<CliSessionState | null>;
5
+ withRefreshLock?<T>(operation: () => Promise<T>): Promise<T>;
5
6
  write(session: CliSessionState): Promise<void>;
6
7
  }
7
8
  export interface CliAuthSettings {
@@ -10,6 +11,20 @@ export interface CliAuthSettings {
10
11
  oidcEnabled: boolean;
11
12
  selfServiceOrgCreationEnabled: boolean;
12
13
  }
14
+ export interface CliDeviceLoginStart {
15
+ deviceCode: string;
16
+ expiresAt: string;
17
+ pollIntervalSeconds: number;
18
+ userCode: string;
19
+ verificationPath: string;
20
+ }
21
+ export type CliDeviceLoginClaim = {
22
+ session: CliSessionState;
23
+ status: "approved";
24
+ } | {
25
+ status: "denied" | "expired" | "pending";
26
+ };
27
+ export type ApiErrorDetails = Record<string, unknown>;
13
28
  type RequestBody = unknown | ((session: CliSessionState) => unknown);
14
29
  type BytesRequest = {
15
30
  createMaxBytesError?: (input: {
@@ -20,18 +35,23 @@ type BytesRequest = {
20
35
  maxBytes?: number;
21
36
  method?: string;
22
37
  path: string;
38
+ rawBody?: Uint8Array;
23
39
  session: CliSessionState | null;
24
40
  validateHeaders?: (headers: Headers) => void;
25
41
  };
26
42
  export declare class ApiError extends Error {
43
+ readonly code: string;
27
44
  readonly detail: string;
45
+ readonly details?: ApiErrorDetails;
28
46
  readonly instance: string;
29
47
  readonly rawDetail?: string;
30
48
  readonly status: number;
31
49
  readonly title: string;
32
50
  readonly type: string;
33
51
  constructor(input: {
52
+ code?: string;
34
53
  detail: string;
54
+ details?: ApiErrorDetails;
35
55
  instance: string;
36
56
  rawDetail?: string;
37
57
  status: number;
@@ -49,6 +69,17 @@ export declare function createPlatformTransport(input: {
49
69
  email: string;
50
70
  password: string;
51
71
  }): Promise<CliSessionState>;
72
+ signup(credentials: {
73
+ baseUrl: string;
74
+ email: string;
75
+ name: string;
76
+ password: string;
77
+ }): Promise<CliSessionState>;
78
+ startDeviceLogin(baseUrl: string): Promise<CliDeviceLoginStart>;
79
+ claimDeviceLogin(claim: {
80
+ baseUrl: string;
81
+ deviceCode: string;
82
+ }): Promise<CliDeviceLoginClaim>;
52
83
  refreshSession(session: CliSessionState): Promise<CliSessionState>;
53
84
  requestJson<T>(request: {
54
85
  body?: RequestBody;
package/dist/transport.js CHANGED
@@ -1,6 +1,10 @@
1
+ import { normalizePublicErrorCode, readPublicErrorCodeFromType } from "./error-code.js";
1
2
  import { extractRefreshTokenFromHeaders } from "./session.js";
3
+ import { refreshSessionWithCoordination, resolveEffectiveSession } from "./transport-refresh.js";
2
4
  export class ApiError extends Error {
5
+ code;
3
6
  detail;
7
+ details;
4
8
  instance;
5
9
  rawDetail;
6
10
  status;
@@ -9,7 +13,11 @@ export class ApiError extends Error {
9
13
  constructor(input) {
10
14
  super(input.detail);
11
15
  this.name = "ApiError";
16
+ this.code = normalizePublicErrorCode(input.code ?? readPublicErrorCodeFromType(input.type));
12
17
  this.detail = input.detail;
18
+ if (input.details) {
19
+ this.details = input.details;
20
+ }
13
21
  this.instance = input.instance;
14
22
  if (input.rawDetail !== undefined) {
15
23
  this.rawDetail = input.rawDetail;
@@ -21,6 +29,13 @@ export class ApiError extends Error {
21
29
  }
22
30
  export function createPlatformTransport(input) {
23
31
  const now = input.now ?? Date.now;
32
+ const refreshSession = async (session) => refreshSessionWithCoordination({
33
+ isRefreshTokenInvalidError,
34
+ refreshSessionDirect: async (effectiveSession) => refreshSessionDirect(input.sessionStore, effectiveSession),
35
+ session,
36
+ sessionStore: input.sessionStore,
37
+ shouldRefresh: (effectiveSession) => shouldRefresh(effectiveSession, now)
38
+ });
24
39
  return {
25
40
  async getAuthSettings(baseUrl) {
26
41
  const normalizedBaseUrl = normalizeBaseUrl(baseUrl);
@@ -45,19 +60,71 @@ export function createPlatformTransport(input) {
45
60
  await input.sessionStore.write(session);
46
61
  return session;
47
62
  },
48
- async refreshSession(session) {
49
- const response = await fetch(joinBaseUrl(session.baseUrl, "/api/v1/auth/refresh"), {
63
+ async signup(credentials) {
64
+ const normalizedBaseUrl = normalizeBaseUrl(credentials.baseUrl);
65
+ const response = await fetch(joinBaseUrl(normalizedBaseUrl, "/api/v1/auth/signup"), {
66
+ body: JSON.stringify({
67
+ email: credentials.email,
68
+ name: credentials.name,
69
+ password: credentials.password
70
+ }),
71
+ headers: {
72
+ "content-type": "application/json"
73
+ },
74
+ method: "POST"
75
+ });
76
+ const session = await parseSessionResponse(response, normalizedBaseUrl, "/api/v1/auth/signup");
77
+ await input.sessionStore.write(session);
78
+ return session;
79
+ },
80
+ async startDeviceLogin(baseUrl) {
81
+ const normalizedBaseUrl = normalizeBaseUrl(baseUrl);
82
+ const path = "/api/v1/auth/device/start";
83
+ const response = await fetch(joinBaseUrl(normalizedBaseUrl, path), {
84
+ method: "POST"
85
+ });
86
+ return handleJsonResponse(response, path);
87
+ },
88
+ async claimDeviceLogin(claim) {
89
+ const normalizedBaseUrl = normalizeBaseUrl(claim.baseUrl);
90
+ const path = "/api/v1/auth/device/claim";
91
+ const response = await fetch(joinBaseUrl(normalizedBaseUrl, path), {
50
92
  body: JSON.stringify({
51
- refreshToken: session.refreshToken
93
+ deviceCode: claim.deviceCode
52
94
  }),
53
95
  headers: {
54
96
  "content-type": "application/json"
55
97
  },
56
98
  method: "POST"
57
99
  });
58
- const nextSession = await parseSessionResponse(response, session.baseUrl, "/api/v1/auth/refresh", session.activeOrg);
59
- await input.sessionStore.write(nextSession);
60
- return nextSession;
100
+ if (!response.ok) {
101
+ throw await toApiError(response, path);
102
+ }
103
+ const payload = await response.json();
104
+ if (payload.status !== "approved") {
105
+ return { status: payload.status };
106
+ }
107
+ if (!payload.tokens || !payload.user) {
108
+ throw new Error("Device login approval response did not include a session.");
109
+ }
110
+ const refreshToken = extractRefreshTokenFromHeaders(response.headers);
111
+ if (!refreshToken) {
112
+ throw new Error("Refresh token cookie was not returned by the Platform API.");
113
+ }
114
+ const session = {
115
+ accessToken: payload.tokens.accessToken,
116
+ accessTokenPayload: payload.tokens.accessTokenPayload,
117
+ activeOrg: null,
118
+ baseUrl: normalizedBaseUrl,
119
+ refreshToken,
120
+ refreshTokenExpiresAt: payload.tokens.refreshTokenExpiresAt,
121
+ user: payload.user
122
+ };
123
+ await input.sessionStore.write(session);
124
+ return { session, status: "approved" };
125
+ },
126
+ async refreshSession(session) {
127
+ return refreshSession(session);
61
128
  },
62
129
  async requestJson(request) {
63
130
  let session = await resolveEffectiveSession(request.session, input.sessionStore);
@@ -71,11 +138,11 @@ export function createPlatformTransport(input) {
71
138
  });
72
139
  }
73
140
  if (shouldRefresh(session, now) && canRefresh(session)) {
74
- session = await this.refreshSession(session);
141
+ session = await refreshSession(session);
75
142
  }
76
143
  const firstResponse = await authenticatedFetch(session, request);
77
144
  if (firstResponse.status === 401 && canRefresh(session)) {
78
- session = await this.refreshSession(session);
145
+ session = await refreshSession(session);
79
146
  return handleJsonResponse(await authenticatedFetch(session, request), request.path);
80
147
  }
81
148
  return handleJsonResponse(firstResponse, request.path);
@@ -92,17 +159,36 @@ export function createPlatformTransport(input) {
92
159
  });
93
160
  }
94
161
  if (shouldRefresh(session, now) && canRefresh(session)) {
95
- session = await this.refreshSession(session);
162
+ session = await refreshSession(session);
96
163
  }
97
164
  const firstResponse = await authenticatedFetch(session, request);
98
165
  if (firstResponse.status === 401 && canRefresh(session)) {
99
- session = await this.refreshSession(session);
166
+ session = await refreshSession(session);
100
167
  return handleBytesResponse(await authenticatedFetch(session, request), request);
101
168
  }
102
169
  return handleBytesResponse(firstResponse, request);
103
170
  }
104
171
  };
105
172
  }
173
+ async function refreshSessionDirect(sessionStore, session) {
174
+ const response = await fetch(joinBaseUrl(session.baseUrl, "/api/v1/auth/refresh"), {
175
+ body: JSON.stringify({
176
+ refreshToken: session.refreshToken
177
+ }),
178
+ headers: {
179
+ "content-type": "application/json"
180
+ },
181
+ method: "POST"
182
+ });
183
+ const nextSession = await parseSessionResponse(response, session.baseUrl, "/api/v1/auth/refresh", session.activeOrg);
184
+ await sessionStore.write(nextSession);
185
+ return nextSession;
186
+ }
187
+ function isRefreshTokenInvalidError(error) {
188
+ return error instanceof ApiError &&
189
+ error.code === "auth/token_invalid" &&
190
+ error.instance === "/api/v1/auth/refresh";
191
+ }
106
192
  async function authenticatedFetch(session, request) {
107
193
  const body = resolveRequestBody(request.body, session);
108
194
  const hasJsonBody = body !== undefined;
@@ -222,11 +308,12 @@ async function readResponseBytes(response, request) {
222
308
  }
223
309
  function createMaxBytesError(request, actualBytes, maxBytes) {
224
310
  return request.createMaxBytesError?.({ actualBytes, maxBytes }) ?? new ApiError({
311
+ code: "request/too_large",
225
312
  detail: `Response body is ${String(actualBytes)} bytes, which exceeds the limit of ${String(maxBytes)} bytes.`,
226
313
  instance: request.path,
227
314
  status: 413,
228
315
  title: "Payload Too Large",
229
- type: "https://errors.kora.dev/request/too-large"
316
+ type: "https://errors.kora.dev/request/too_large"
230
317
  });
231
318
  }
232
319
  function concatBytes(chunks, totalBytes) {
@@ -250,11 +337,13 @@ async function toApiError(response, path) {
250
337
  if (contentType.includes("application/json")) {
251
338
  const rawBody = await response.text();
252
339
  const parsed = tryParseJsonErrorBody(rawBody);
253
- const code = parsed?.error?.code ?? "internal/error";
340
+ const code = normalizePublicErrorCode(parsed?.error?.code ?? "internal/error");
254
341
  const rawDetail = (parsed?.error?.message ?? rawBody) || response.statusText;
255
342
  const detail = relabelBackendText(rawDetail || response.statusText);
256
343
  return new ApiError({
344
+ code,
257
345
  detail,
346
+ ...(parsed?.error?.details ? { details: parsed.error.details } : {}),
258
347
  instance: path,
259
348
  ...(rawDetail ? { rawDetail } : {}),
260
349
  status: response.status,
@@ -264,6 +353,7 @@ async function toApiError(response, path) {
264
353
  }
265
354
  const rawDetail = await response.text();
266
355
  return new ApiError({
356
+ code: "internal/error",
267
357
  detail: relabelBackendText(rawDetail),
268
358
  instance: path,
269
359
  ...(rawDetail ? { rawDetail } : {}),
@@ -315,27 +405,3 @@ function shouldRefresh(session, now) {
315
405
  function canRefresh(session) {
316
406
  return session.refreshToken.trim().length > 0;
317
407
  }
318
- async function resolveEffectiveSession(requestSession, sessionStore) {
319
- if (!requestSession) {
320
- return null;
321
- }
322
- const storedSession = await sessionStore.read();
323
- if (!storedSession || !isSameSessionIdentity(storedSession, requestSession)) {
324
- return requestSession;
325
- }
326
- return isSessionNewer(storedSession, requestSession) ? storedSession : requestSession;
327
- }
328
- function isSameSessionIdentity(candidate, current) {
329
- return candidate.baseUrl === current.baseUrl
330
- && candidate.user.id === current.user.id
331
- && candidate.accessTokenPayload.sub === current.accessTokenPayload.sub;
332
- }
333
- function isSessionNewer(candidate, current) {
334
- if (candidate.accessToken === current.accessToken && candidate.refreshToken === current.refreshToken) {
335
- return false;
336
- }
337
- if (candidate.accessTokenPayload.exp !== current.accessTokenPayload.exp) {
338
- return candidate.accessTokenPayload.exp > current.accessTokenPayload.exp;
339
- }
340
- return candidate.accessTokenPayload.iat >= current.accessTokenPayload.iat;
341
- }
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-rc10",
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",
package/dist/dotenv.d.ts DELETED
@@ -1 +0,0 @@
1
- export declare function parseDotEnv(source: string): Record<string, string>;
package/dist/dotenv.js DELETED
@@ -1,26 +0,0 @@
1
- const ENV_NAME_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/u;
2
- export function parseDotEnv(source) {
3
- const parsed = {};
4
- const lines = source.split(/\r?\n/u);
5
- for (const rawLine of lines) {
6
- const line = rawLine.trim();
7
- if (line.length === 0 || line.startsWith("#")) {
8
- continue;
9
- }
10
- const separatorIndex = line.indexOf("=");
11
- if (separatorIndex <= 0) {
12
- continue;
13
- }
14
- const rawName = line.slice(0, separatorIndex).trim();
15
- if (!ENV_NAME_PATTERN.test(rawName)) {
16
- continue;
17
- }
18
- let value = line.slice(separatorIndex + 1).trim();
19
- if ((value.startsWith("\"") && value.endsWith("\"")) ||
20
- (value.startsWith("'") && value.endsWith("'"))) {
21
- value = value.slice(1, -1);
22
- }
23
- parsed[rawName] = value;
24
- }
25
- return parsed;
26
- }
@@ -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
- }