olakai-cli 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -2,10 +2,286 @@
2
2
 
3
3
  // src/index.ts
4
4
  import { Command } from "commander";
5
+
6
+ // src/commands/login.ts
7
+ import open from "open";
8
+
9
+ // src/lib/config.ts
10
+ var HOSTS = {
11
+ production: "https://app.olakai.ai",
12
+ staging: "https://staging.app.olakai.ai",
13
+ local: "http://localhost:3000"
14
+ };
15
+ var CLIENT_ID = "olakai-cli";
16
+ var currentEnvironment = "production";
17
+ function setEnvironment(env) {
18
+ currentEnvironment = env;
19
+ }
20
+ function getEnvironment() {
21
+ const envVar = process.env.OLAKAI_ENV;
22
+ if (envVar && isValidEnvironment(envVar)) {
23
+ return envVar;
24
+ }
25
+ return currentEnvironment;
26
+ }
27
+ function getBaseUrl() {
28
+ return HOSTS[getEnvironment()];
29
+ }
30
+ function isValidEnvironment(env) {
31
+ return env === "production" || env === "staging" || env === "local";
32
+ }
33
+ function getValidEnvironments() {
34
+ return ["production", "staging", "local"];
35
+ }
36
+
37
+ // src/lib/auth.ts
38
+ import * as fs from "fs";
39
+ import * as path from "path";
40
+ import * as os from "os";
41
+ function getCredentialsPath() {
42
+ const configDir = path.join(os.homedir(), ".config", "olakai");
43
+ return path.join(configDir, "credentials.json");
44
+ }
45
+ function ensureConfigDir() {
46
+ const configDir = path.dirname(getCredentialsPath());
47
+ if (!fs.existsSync(configDir)) {
48
+ fs.mkdirSync(configDir, { recursive: true, mode: 448 });
49
+ }
50
+ }
51
+ function saveToken(token, expiresIn) {
52
+ ensureConfigDir();
53
+ const credentials = {
54
+ token,
55
+ expiresAt: Math.floor(Date.now() / 1e3) + expiresIn,
56
+ environment: getEnvironment()
57
+ };
58
+ const credentialsPath = getCredentialsPath();
59
+ fs.writeFileSync(credentialsPath, JSON.stringify(credentials, null, 2), {
60
+ mode: 384
61
+ // Read/write for owner only
62
+ });
63
+ }
64
+ function loadToken() {
65
+ const credentialsPath = getCredentialsPath();
66
+ if (!fs.existsSync(credentialsPath)) {
67
+ return null;
68
+ }
69
+ try {
70
+ const content = fs.readFileSync(credentialsPath, "utf-8");
71
+ const credentials = JSON.parse(content);
72
+ return credentials;
73
+ } catch {
74
+ return null;
75
+ }
76
+ }
77
+ function clearToken() {
78
+ const credentialsPath = getCredentialsPath();
79
+ if (fs.existsSync(credentialsPath)) {
80
+ fs.unlinkSync(credentialsPath);
81
+ }
82
+ }
83
+ function isTokenValid() {
84
+ const credentials = loadToken();
85
+ if (!credentials) {
86
+ return false;
87
+ }
88
+ const now = Math.floor(Date.now() / 1e3);
89
+ if (credentials.expiresAt <= now + 60) {
90
+ return false;
91
+ }
92
+ if (credentials.environment !== getEnvironment()) {
93
+ return false;
94
+ }
95
+ return true;
96
+ }
97
+ function getValidToken() {
98
+ if (!isTokenValid()) {
99
+ return null;
100
+ }
101
+ const credentials = loadToken();
102
+ return credentials?.token ?? null;
103
+ }
104
+
105
+ // src/lib/api.ts
106
+ async function requestDeviceCode() {
107
+ const response = await fetch(`${getBaseUrl()}/api/auth/device/code`, {
108
+ method: "POST",
109
+ headers: {
110
+ "Content-Type": "application/json"
111
+ },
112
+ body: JSON.stringify({ client_id: CLIENT_ID })
113
+ });
114
+ if (!response.ok) {
115
+ const error = await response.json();
116
+ throw new Error(error.error_description || error.error || "Failed to request device code");
117
+ }
118
+ return await response.json();
119
+ }
120
+ async function pollForToken(deviceCode) {
121
+ const response = await fetch(`${getBaseUrl()}/api/auth/device/token`, {
122
+ method: "POST",
123
+ headers: {
124
+ "Content-Type": "application/json"
125
+ },
126
+ body: JSON.stringify({
127
+ grant_type: "urn:ietf:params:oauth:grant-type:device_code",
128
+ device_code: deviceCode,
129
+ client_id: CLIENT_ID
130
+ })
131
+ });
132
+ const data = await response.json();
133
+ if (!response.ok) {
134
+ if ("error" in data && data.error === "authorization_pending") {
135
+ return null;
136
+ }
137
+ const errorMsg = "error_description" in data ? data.error_description : "error" in data ? data.error : "Token exchange failed";
138
+ throw new Error(errorMsg || "Token exchange failed");
139
+ }
140
+ return data;
141
+ }
142
+ async function getCurrentUser() {
143
+ const token = getValidToken();
144
+ if (!token) {
145
+ throw new Error("Not logged in. Run 'olakai login' first.");
146
+ }
147
+ const response = await fetch(`${getBaseUrl()}/api/user/me`, {
148
+ headers: {
149
+ Authorization: `Bearer ${token}`
150
+ }
151
+ });
152
+ if (!response.ok) {
153
+ if (response.status === 401) {
154
+ throw new Error("Session expired. Run 'olakai login' to authenticate again.");
155
+ }
156
+ throw new Error("Failed to get user info");
157
+ }
158
+ return await response.json();
159
+ }
160
+
161
+ // src/commands/login.ts
162
+ var POLL_INTERVAL_MS = 5e3;
163
+ async function loginCommand() {
164
+ if (isTokenValid()) {
165
+ try {
166
+ const user = await getCurrentUser();
167
+ console.log(`Already logged in as ${user.email}`);
168
+ console.log("Run 'olakai logout' to log out first.");
169
+ return;
170
+ } catch {
171
+ }
172
+ }
173
+ console.log(`Logging in to Olakai (${getEnvironment()})...
174
+ `);
175
+ try {
176
+ const deviceCode = await requestDeviceCode();
177
+ console.log("To complete login, visit:");
178
+ console.log(`
179
+ ${deviceCode.verification_uri_complete}
180
+ `);
181
+ console.log(`Or go to ${deviceCode.verification_uri} and enter code:`);
182
+ console.log(`
183
+ ${deviceCode.user_code}
184
+ `);
185
+ console.log("Opening browser...");
186
+ try {
187
+ await open(deviceCode.verification_uri_complete);
188
+ } catch {
189
+ console.log("(Could not open browser automatically)");
190
+ }
191
+ console.log("\nWaiting for authorization...");
192
+ const expiresAt = Date.now() + deviceCode.expires_in * 1e3;
193
+ while (Date.now() < expiresAt) {
194
+ await sleep(POLL_INTERVAL_MS);
195
+ try {
196
+ const tokenResponse = await pollForToken(deviceCode.device_code);
197
+ if (tokenResponse) {
198
+ saveToken(tokenResponse.access_token, tokenResponse.expires_in);
199
+ const user = await getCurrentUser();
200
+ console.log(`
201
+ Logged in as ${user.email}`);
202
+ console.log(`Account: ${user.accountId}`);
203
+ console.log(`Role: ${user.role}`);
204
+ return;
205
+ }
206
+ process.stdout.write(".");
207
+ } catch (error) {
208
+ if (error instanceof Error) {
209
+ console.error(`
210
+ Login failed: ${error.message}`);
211
+ } else {
212
+ console.error("\nLogin failed: Unknown error");
213
+ }
214
+ process.exit(1);
215
+ }
216
+ }
217
+ console.error("\nLogin timed out. Please try again.");
218
+ process.exit(1);
219
+ } catch (error) {
220
+ if (error instanceof Error) {
221
+ console.error(`Login failed: ${error.message}`);
222
+ } else {
223
+ console.error("Login failed: Unknown error");
224
+ }
225
+ process.exit(1);
226
+ }
227
+ }
228
+ function sleep(ms) {
229
+ return new Promise((resolve) => setTimeout(resolve, ms));
230
+ }
231
+
232
+ // src/commands/logout.ts
233
+ function logoutCommand() {
234
+ if (!isTokenValid()) {
235
+ console.log("Not currently logged in.");
236
+ return;
237
+ }
238
+ clearToken();
239
+ console.log("Logged out successfully.");
240
+ }
241
+
242
+ // src/commands/whoami.ts
243
+ async function whoamiCommand() {
244
+ if (!isTokenValid()) {
245
+ console.log("Not logged in. Run 'olakai login' to authenticate.");
246
+ process.exit(1);
247
+ }
248
+ try {
249
+ const user = await getCurrentUser();
250
+ console.log(`Email: ${user.email}`);
251
+ console.log(`Name: ${user.firstName} ${user.lastName}`);
252
+ console.log(`Role: ${user.role}`);
253
+ console.log(`Account ID: ${user.accountId}`);
254
+ console.log(`Environment: ${getEnvironment()}`);
255
+ } catch (error) {
256
+ if (error instanceof Error) {
257
+ console.error(`Error: ${error.message}`);
258
+ } else {
259
+ console.error("Failed to get user info");
260
+ }
261
+ process.exit(1);
262
+ }
263
+ }
264
+
265
+ // src/index.ts
5
266
  var program = new Command();
6
- program.name("olakai").description("Olakai CLI tool").version("0.1.0");
7
- program.command("hello").description("Say hello").argument("[name]", "Name to greet", "World").action((name) => {
8
- console.log(`Hello, ${name}!`);
267
+ program.name("olakai").description("Olakai CLI tool").version("0.1.0").option(
268
+ "-e, --env <environment>",
269
+ `Environment to use (${getValidEnvironments().join(", ")})`,
270
+ "production"
271
+ ).hook("preAction", (thisCommand) => {
272
+ const options = thisCommand.opts();
273
+ if (options.env) {
274
+ if (!isValidEnvironment(options.env)) {
275
+ console.error(
276
+ `Invalid environment: ${options.env}. Valid options: ${getValidEnvironments().join(", ")}`
277
+ );
278
+ process.exit(1);
279
+ }
280
+ setEnvironment(options.env);
281
+ }
9
282
  });
283
+ program.command("login").description("Log in to Olakai using browser authentication").action(loginCommand);
284
+ program.command("logout").description("Log out from Olakai").action(logoutCommand);
285
+ program.command("whoami").description("Show current logged-in user").action(whoamiCommand);
10
286
  program.parse();
11
287
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { Command } from \"commander\";\n\nconst program = new Command();\n\nprogram\n .name(\"olakai\")\n .description(\"Olakai CLI tool\")\n .version(\"0.1.0\");\n\nprogram\n .command(\"hello\")\n .description(\"Say hello\")\n .argument(\"[name]\", \"Name to greet\", \"World\")\n .action((name: string) => {\n console.log(`Hello, ${name}!`);\n });\n\nprogram.parse();\n"],"mappings":";;;AAEA,SAAS,eAAe;AAExB,IAAM,UAAU,IAAI,QAAQ;AAE5B,QACG,KAAK,QAAQ,EACb,YAAY,iBAAiB,EAC7B,QAAQ,OAAO;AAElB,QACG,QAAQ,OAAO,EACf,YAAY,WAAW,EACvB,SAAS,UAAU,iBAAiB,OAAO,EAC3C,OAAO,CAAC,SAAiB;AACxB,UAAQ,IAAI,UAAU,IAAI,GAAG;AAC/B,CAAC;AAEH,QAAQ,MAAM;","names":[]}
1
+ {"version":3,"sources":["../src/index.ts","../src/commands/login.ts","../src/lib/config.ts","../src/lib/auth.ts","../src/lib/api.ts","../src/commands/logout.ts","../src/commands/whoami.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { Command } from \"commander\";\nimport { loginCommand } from \"./commands/login.js\";\nimport { logoutCommand } from \"./commands/logout.js\";\nimport { whoamiCommand } from \"./commands/whoami.js\";\nimport {\n setEnvironment,\n isValidEnvironment,\n getValidEnvironments,\n type Environment,\n} from \"./lib/config.js\";\n\nconst program = new Command();\n\nprogram\n .name(\"olakai\")\n .description(\"Olakai CLI tool\")\n .version(\"0.1.0\")\n .option(\n \"-e, --env <environment>\",\n `Environment to use (${getValidEnvironments().join(\", \")})`,\n \"production\",\n )\n .hook(\"preAction\", (thisCommand) => {\n const options = thisCommand.opts();\n if (options.env) {\n if (!isValidEnvironment(options.env)) {\n console.error(\n `Invalid environment: ${options.env}. Valid options: ${getValidEnvironments().join(\", \")}`,\n );\n process.exit(1);\n }\n setEnvironment(options.env as Environment);\n }\n });\n\nprogram\n .command(\"login\")\n .description(\"Log in to Olakai using browser authentication\")\n .action(loginCommand);\n\nprogram\n .command(\"logout\")\n .description(\"Log out from Olakai\")\n .action(logoutCommand);\n\nprogram\n .command(\"whoami\")\n .description(\"Show current logged-in user\")\n .action(whoamiCommand);\n\nprogram.parse();\n","import open from \"open\";\nimport { requestDeviceCode, pollForToken, getCurrentUser } from \"../lib/api.js\";\nimport { saveToken, isTokenValid } from \"../lib/auth.js\";\nimport { getEnvironment } from \"../lib/config.js\";\n\nconst POLL_INTERVAL_MS = 5000; // 5 seconds\n\n/**\n * Login command handler\n */\nexport async function loginCommand(): Promise<void> {\n // Check if already logged in\n if (isTokenValid()) {\n try {\n const user = await getCurrentUser();\n console.log(`Already logged in as ${user.email}`);\n console.log(\"Run 'olakai logout' to log out first.\");\n return;\n } catch {\n // Token is invalid, continue with login\n }\n }\n\n console.log(`Logging in to Olakai (${getEnvironment()})...\\n`);\n\n try {\n // Request device code\n const deviceCode = await requestDeviceCode();\n\n // Display instructions\n console.log(\"To complete login, visit:\");\n console.log(`\\n ${deviceCode.verification_uri_complete}\\n`);\n console.log(`Or go to ${deviceCode.verification_uri} and enter code:`);\n console.log(`\\n ${deviceCode.user_code}\\n`);\n\n // Try to open browser\n console.log(\"Opening browser...\");\n try {\n await open(deviceCode.verification_uri_complete);\n } catch {\n console.log(\"(Could not open browser automatically)\");\n }\n\n console.log(\"\\nWaiting for authorization...\");\n\n // Poll for token\n const expiresAt = Date.now() + deviceCode.expires_in * 1000;\n\n while (Date.now() < expiresAt) {\n await sleep(POLL_INTERVAL_MS);\n\n try {\n const tokenResponse = await pollForToken(deviceCode.device_code);\n\n if (tokenResponse) {\n // Save token\n saveToken(tokenResponse.access_token, tokenResponse.expires_in);\n\n // Get user info\n const user = await getCurrentUser();\n\n console.log(`\\nLogged in as ${user.email}`);\n console.log(`Account: ${user.accountId}`);\n console.log(`Role: ${user.role}`);\n return;\n }\n\n // Still pending, show spinner\n process.stdout.write(\".\");\n } catch (error) {\n if (error instanceof Error) {\n console.error(`\\nLogin failed: ${error.message}`);\n } else {\n console.error(\"\\nLogin failed: Unknown error\");\n }\n process.exit(1);\n }\n }\n\n console.error(\"\\nLogin timed out. Please try again.\");\n process.exit(1);\n } catch (error) {\n if (error instanceof Error) {\n console.error(`Login failed: ${error.message}`);\n } else {\n console.error(\"Login failed: Unknown error\");\n }\n process.exit(1);\n }\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n","export type Environment = \"production\" | \"staging\" | \"local\";\n\nconst HOSTS: Record<Environment, string> = {\n production: \"https://app.olakai.ai\",\n staging: \"https://staging.app.olakai.ai\",\n local: \"http://localhost:3000\",\n};\n\n// CLI client identifier\nexport const CLIENT_ID = \"olakai-cli\";\n\nlet currentEnvironment: Environment = \"production\";\n\n/**\n * Set the current environment\n */\nexport function setEnvironment(env: Environment): void {\n currentEnvironment = env;\n}\n\n/**\n * Get the current environment from:\n * 1. Environment variable OLAKAI_ENV\n * 2. Programmatically set value\n * 3. Default to \"production\"\n */\nexport function getEnvironment(): Environment {\n const envVar = process.env.OLAKAI_ENV as Environment | undefined;\n if (envVar && isValidEnvironment(envVar)) {\n return envVar;\n }\n return currentEnvironment;\n}\n\n/**\n * Get the API base URL for the current environment\n */\nexport function getBaseUrl(): string {\n return HOSTS[getEnvironment()];\n}\n\n/**\n * Check if a string is a valid environment\n */\nexport function isValidEnvironment(env: string): env is Environment {\n return env === \"production\" || env === \"staging\" || env === \"local\";\n}\n\n/**\n * Get list of valid environments for CLI help\n */\nexport function getValidEnvironments(): Environment[] {\n return [\"production\", \"staging\", \"local\"];\n}\n","import * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport * as os from \"node:os\";\nimport { type Environment, getEnvironment } from \"./config.js\";\n\ninterface StoredCredentials {\n token: string;\n expiresAt: number; // Unix timestamp in seconds\n environment: Environment;\n}\n\n/**\n * Get the credentials file path\n */\nfunction getCredentialsPath(): string {\n const configDir = path.join(os.homedir(), \".config\", \"olakai\");\n return path.join(configDir, \"credentials.json\");\n}\n\n/**\n * Ensure the config directory exists\n */\nfunction ensureConfigDir(): void {\n const configDir = path.dirname(getCredentialsPath());\n if (!fs.existsSync(configDir)) {\n fs.mkdirSync(configDir, { recursive: true, mode: 0o700 });\n }\n}\n\n/**\n * Save an access token to disk\n */\nexport function saveToken(token: string, expiresIn: number): void {\n ensureConfigDir();\n\n const credentials: StoredCredentials = {\n token,\n expiresAt: Math.floor(Date.now() / 1000) + expiresIn,\n environment: getEnvironment(),\n };\n\n const credentialsPath = getCredentialsPath();\n fs.writeFileSync(credentialsPath, JSON.stringify(credentials, null, 2), {\n mode: 0o600, // Read/write for owner only\n });\n}\n\n/**\n * Load the stored token\n */\nexport function loadToken(): StoredCredentials | null {\n const credentialsPath = getCredentialsPath();\n\n if (!fs.existsSync(credentialsPath)) {\n return null;\n }\n\n try {\n const content = fs.readFileSync(credentialsPath, \"utf-8\");\n const credentials = JSON.parse(content) as StoredCredentials;\n return credentials;\n } catch {\n return null;\n }\n}\n\n/**\n * Clear stored credentials\n */\nexport function clearToken(): void {\n const credentialsPath = getCredentialsPath();\n\n if (fs.existsSync(credentialsPath)) {\n fs.unlinkSync(credentialsPath);\n }\n}\n\n/**\n * Check if the stored token is valid (exists and not expired)\n */\nexport function isTokenValid(): boolean {\n const credentials = loadToken();\n\n if (!credentials) {\n return false;\n }\n\n // Check if expired (with 60 second buffer)\n const now = Math.floor(Date.now() / 1000);\n if (credentials.expiresAt <= now + 60) {\n return false;\n }\n\n // Check if environment matches\n if (credentials.environment !== getEnvironment()) {\n return false;\n }\n\n return true;\n}\n\n/**\n * Get the current valid token or null\n */\nexport function getValidToken(): string | null {\n if (!isTokenValid()) {\n return null;\n }\n\n const credentials = loadToken();\n return credentials?.token ?? null;\n}\n","import { getBaseUrl, CLIENT_ID } from \"./config.js\";\nimport { getValidToken } from \"./auth.js\";\n\nexport interface DeviceCodeResponse {\n device_code: string;\n user_code: string;\n verification_uri: string;\n verification_uri_complete: string;\n expires_in: number;\n interval: number;\n}\n\nexport interface TokenResponse {\n access_token: string;\n token_type: string;\n expires_in: number;\n}\n\nexport interface TokenErrorResponse {\n error: \"authorization_pending\" | \"expired_token\" | \"access_denied\";\n error_description?: string;\n}\n\nexport interface UserMeResponse {\n id: string;\n email: string;\n firstName: string;\n lastName: string;\n role: string;\n accountId: string;\n}\n\n/**\n * Request a device code to start the login flow\n */\nexport async function requestDeviceCode(): Promise<DeviceCodeResponse> {\n const response = await fetch(`${getBaseUrl()}/api/auth/device/code`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({ client_id: CLIENT_ID }),\n });\n\n if (!response.ok) {\n const error = (await response.json()) as { error_description?: string; error?: string };\n throw new Error(error.error_description || error.error || \"Failed to request device code\");\n }\n\n return (await response.json()) as DeviceCodeResponse;\n}\n\n/**\n * Poll for token exchange\n * Returns the token response if approved, or throws an error\n */\nexport async function pollForToken(\n deviceCode: string,\n): Promise<TokenResponse | null> {\n const response = await fetch(`${getBaseUrl()}/api/auth/device/token`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n grant_type: \"urn:ietf:params:oauth:grant-type:device_code\",\n device_code: deviceCode,\n client_id: CLIENT_ID,\n }),\n });\n\n const data = (await response.json()) as TokenResponse | TokenErrorResponse;\n\n if (!response.ok) {\n if (\"error\" in data && data.error === \"authorization_pending\") {\n return null; // Still waiting for user\n }\n const errorMsg = \"error_description\" in data ? data.error_description : (\"error\" in data ? data.error : \"Token exchange failed\");\n throw new Error(errorMsg || \"Token exchange failed\");\n }\n\n return data as TokenResponse;\n}\n\n/**\n * Get current user info\n */\nexport async function getCurrentUser(): Promise<UserMeResponse> {\n const token = getValidToken();\n\n if (!token) {\n throw new Error(\"Not logged in. Run 'olakai login' first.\");\n }\n\n const response = await fetch(`${getBaseUrl()}/api/user/me`, {\n headers: {\n Authorization: `Bearer ${token}`,\n },\n });\n\n if (!response.ok) {\n if (response.status === 401) {\n throw new Error(\"Session expired. Run 'olakai login' to authenticate again.\");\n }\n throw new Error(\"Failed to get user info\");\n }\n\n return (await response.json()) as UserMeResponse;\n}\n","import { clearToken, isTokenValid } from \"../lib/auth.js\";\n\n/**\n * Logout command handler\n */\nexport function logoutCommand(): void {\n if (!isTokenValid()) {\n console.log(\"Not currently logged in.\");\n return;\n }\n\n clearToken();\n console.log(\"Logged out successfully.\");\n}\n","import { getCurrentUser } from \"../lib/api.js\";\nimport { isTokenValid } from \"../lib/auth.js\";\nimport { getEnvironment } from \"../lib/config.js\";\n\n/**\n * Whoami command handler\n */\nexport async function whoamiCommand(): Promise<void> {\n if (!isTokenValid()) {\n console.log(\"Not logged in. Run 'olakai login' to authenticate.\");\n process.exit(1);\n }\n\n try {\n const user = await getCurrentUser();\n\n console.log(`Email: ${user.email}`);\n console.log(`Name: ${user.firstName} ${user.lastName}`);\n console.log(`Role: ${user.role}`);\n console.log(`Account ID: ${user.accountId}`);\n console.log(`Environment: ${getEnvironment()}`);\n } catch (error) {\n if (error instanceof Error) {\n console.error(`Error: ${error.message}`);\n } else {\n console.error(\"Failed to get user info\");\n }\n process.exit(1);\n }\n}\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "olakai-cli",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Olakai CLI tool",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -37,7 +37,8 @@
37
37
  "typescript-eslint": "^8.0.0"
38
38
  },
39
39
  "dependencies": {
40
- "commander": "^12.0.0"
40
+ "commander": "^12.0.0",
41
+ "open": "^10.0.0"
41
42
  },
42
43
  "packageManager": "pnpm@10.10.0"
43
44
  }