@choiceopen/automation-plugin-cli 0.0.1 → 0.1.2

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 CHANGED
@@ -20,7 +20,7 @@ $ npm install -g @choiceopen/automation-plugin-cli
20
20
  $ automation COMMAND
21
21
  running command...
22
22
  $ automation (--version)
23
- @choiceopen/automation-plugin-cli/0.0.1 darwin-arm64 node-v24.12.0
23
+ @choiceopen/automation-plugin-cli/0.1.2 darwin-arm64 node-v24.12.0
24
24
  $ automation --help [COMMAND]
25
25
  USAGE
26
26
  $ automation COMMAND
@@ -32,11 +32,7 @@ USAGE
32
32
  * [`automation auth login`](#automation-auth-login)
33
33
  * [`automation autocomplete [SHELL]`](#automation-autocomplete-shell)
34
34
  * [`automation help [COMMAND]`](#automation-help-command)
35
- * [`automation plugin checksum [FILE]`](#automation-plugin-checksum-file)
36
- * [`automation plugin init`](#automation-plugin-init)
37
- * [`automation plugin pack [FILE]`](#automation-plugin-pack-file)
38
- * [`automation plugin permission [FILE]`](#automation-plugin-permission-file)
39
- * [`automation plugin run [FILE]`](#automation-plugin-run-file)
35
+ * [`automation plugin refresh-key`](#automation-plugin-refresh-key)
40
36
  * [`automation version`](#automation-version)
41
37
 
42
38
  ## `automation auth login`
@@ -61,7 +57,7 @@ EXAMPLES
61
57
  $ automation auth login
62
58
  ```
63
59
 
64
- _See code: [src/commands/auth/login.ts](https://github.com/choice-open/automation-plugin-cli/blob/v0.0.1/src/commands/auth/login.ts)_
60
+ _See code: [src/commands/auth/login.ts](https://github.com/choice-open/automation-plugin-cli/blob/v0.1.2/src/commands/auth/login.ts)_
65
61
 
66
62
  ## `automation autocomplete [SHELL]`
67
63
 
@@ -114,143 +110,22 @@ DESCRIPTION
114
110
 
115
111
  _See code: [@oclif/plugin-help](https://github.com/oclif/plugin-help/blob/v6.2.36/src/commands/help.ts)_
116
112
 
117
- ## `automation plugin checksum [FILE]`
113
+ ## `automation plugin refresh-key`
118
114
 
119
- describe the command here
115
+ Refresh or create API Key for plugin debugging in development stage.
120
116
 
121
117
  ```
122
118
  USAGE
123
- $ automation plugin checksum [FILE] [-f] [-n <value>]
124
-
125
- ARGUMENTS
126
- [FILE] file to read
127
-
128
- FLAGS
129
- -f, --force
130
- -n, --name=<value> name to print
131
-
132
- DESCRIPTION
133
- describe the command here
134
-
135
- EXAMPLES
136
- $ automation plugin checksum
137
- ```
138
-
139
- _See code: [src/commands/plugin/checksum.ts](https://github.com/choice-open/automation-plugin-cli/blob/v0.0.1/src/commands/plugin/checksum.ts)_
140
-
141
- ## `automation plugin init`
142
-
143
- Initialize a new plugin with step-by-step interactive instructions.
144
-
145
- ```
146
- USAGE
147
- $ automation plugin init [-i] [-n my-awesome-plugin] [-d Descriptive
148
- text...] [-a John Doe] [-e john.doe@example.com] [-u <value>] [--locales en_US|zh_Hans|ja_JP...] [-l
149
- elixir|python|typescript] [-t extension|llm|tool|trigger] [-p endpoints:register|model:call_llm|model:call_embedding
150
- |model:call_moderation|model:call_rerank|model:call_stt|model:call_tts|storage:kv|tools:invoke...]
151
-
152
- FLAGS
153
- -a, --author=John Doe Author name
154
- -d, --description=Descriptive text... Short description
155
- -e, --email=john.doe@example.com Author email address
156
- -i, --[no-]interactive Use interactive mode (by default)
157
- -l, --language=<option> Programming language to use for plugin development
158
- <options: elixir|python|typescript>
159
- -n, --name=my-awesome-plugin Plugin name
160
- -p, --permissions=<option>... Permissions required by the plugin
161
- <options:
162
- endpoints:register|model:call_llm|model:call_embedding|model:call_moderation|mo
163
- del:call_rerank|model:call_stt|model:call_tts|storage:kv|tools:invoke>
164
- -t, --type=<option> Plugin type
165
- <options: extension|llm|tool|trigger>
166
- -u, --url=<value> Repository URL
167
- --locales=<option>... Provide READMEs in which languages
168
- <options: en_US|zh_Hans|ja_JP>
169
-
170
- DESCRIPTION
171
- Initialize a new plugin with step-by-step interactive instructions.
172
-
173
- Providing required flags skips interactive flow and completes initialization in one go.
174
-
175
- EXAMPLES
176
- Start with interactive initialization:
177
-
178
- $ automation plugin init
179
- ```
180
-
181
- _See code: [src/commands/plugin/init.ts](https://github.com/choice-open/automation-plugin-cli/blob/v0.0.1/src/commands/plugin/init.ts)_
182
-
183
- ## `automation plugin pack [FILE]`
184
-
185
- describe the command here
186
-
187
- ```
188
- USAGE
189
- $ automation plugin pack [FILE] [-f] [-n <value>]
190
-
191
- ARGUMENTS
192
- [FILE] file to read
193
-
194
- FLAGS
195
- -f, --force
196
- -n, --name=<value> name to print
197
-
198
- DESCRIPTION
199
- describe the command here
200
-
201
- EXAMPLES
202
- $ automation plugin pack
203
- ```
204
-
205
- _See code: [src/commands/plugin/pack.ts](https://github.com/choice-open/automation-plugin-cli/blob/v0.0.1/src/commands/plugin/pack.ts)_
206
-
207
- ## `automation plugin permission [FILE]`
208
-
209
- describe the command here
210
-
211
- ```
212
- USAGE
213
- $ automation plugin permission [FILE] [-f] [-n <value>]
214
-
215
- ARGUMENTS
216
- [FILE] file to read
217
-
218
- FLAGS
219
- -f, --force
220
- -n, --name=<value> name to print
221
-
222
- DESCRIPTION
223
- describe the command here
224
-
225
- EXAMPLES
226
- $ automation plugin permission
227
- ```
228
-
229
- _See code: [src/commands/plugin/permission.ts](https://github.com/choice-open/automation-plugin-cli/blob/v0.0.1/src/commands/plugin/permission.ts)_
230
-
231
- ## `automation plugin run [FILE]`
232
-
233
- describe the command here
234
-
235
- ```
236
- USAGE
237
- $ automation plugin run [FILE] [-f] [-n <value>]
238
-
239
- ARGUMENTS
240
- [FILE] file to read
241
-
242
- FLAGS
243
- -f, --force
244
- -n, --name=<value> name to print
119
+ $ automation plugin refresh-key
245
120
 
246
121
  DESCRIPTION
247
- describe the command here
122
+ Refresh or create API Key for plugin debugging in development stage.
248
123
 
249
124
  EXAMPLES
250
- $ automation plugin run
125
+ $ automation plugin refresh-key
251
126
  ```
252
127
 
253
- _See code: [src/commands/plugin/run.ts](https://github.com/choice-open/automation-plugin-cli/blob/v0.0.1/src/commands/plugin/run.ts)_
128
+ _See code: [src/commands/plugin/refresh-key.ts](https://github.com/choice-open/automation-plugin-cli/blob/v0.1.2/src/commands/plugin/refresh-key.ts)_
254
129
 
255
130
  ## `automation version`
256
131
 
@@ -29,15 +29,16 @@ export default class AuthLogin extends Command {
29
29
  await this.parse(AuthLogin);
30
30
  const config = await configStore.load();
31
31
  assert(config.auth?.endpoint, "Auth endpoint is required");
32
- const payload = await this.requestDeviceCode(config.auth.endpoint);
32
+ this.endpoint = config.auth.endpoint;
33
+ const payload = await this.requestDeviceCode(this.endpoint);
33
34
  this.log(colorize("yellowBright", "Starting device authorization flow...\n"));
34
35
  this.log(colorize("bold", colorize("gray", "Verification URL : ")), payload.verification_uri);
35
36
  this.log(colorize("bold", colorize("gray", "Verification Code: ")), `${payload.user_code}\n`);
36
37
  const autoOpen = await confirm({
37
38
  message: dedent `
38
- Do you want to open the verification URL in your browser automatically?
39
- If not, you can manually open the URL and paste the code.
40
- `,
39
+ Do you want to open the verification URL in your browser automatically?
40
+ If not, you can manually open the URL and paste the code.
41
+ `,
41
42
  });
42
43
  if (autoOpen) {
43
44
  await open(payload.verification_uri_complete);
@@ -45,7 +46,7 @@ export default class AuthLogin extends Command {
45
46
  const spinner = yoctoSpinner({ text: "Polling for token..." }).start();
46
47
  const result = (await this.pollForToken(payload.device_code, spinner));
47
48
  await configStore.update({ auth: { access_token: result.access_token } });
48
- const session = await fetch(`${config.auth.endpoint}/v1/auth/get-session`, {
49
+ const session = await fetch(`${this.endpoint}/v1/auth/get-session`, {
49
50
  headers: {
50
51
  "Content-Type": "application/json",
51
52
  "User-Agent": "Choiceform (Automation Plugin CLI)",
@@ -53,10 +54,10 @@ export default class AuthLogin extends Command {
53
54
  },
54
55
  }).then((response) => response.json());
55
56
  this.log(colorize("greenBright", dedent `
56
- Welcome back, ${session.user.name} <${session.user.email}>!
57
- To create a new plugin, you can use the following command:
58
- \`${colorize("bold", colorize("yellowBright", "automation plugin init"))}\`
59
- `));
57
+ Welcome back, ${session.user.name} <${session.user.email}>!
58
+ To create a new plugin, you can use the following command:
59
+ \`${colorize("bold", colorize("yellowBright", "automation plugin init"))}\`
60
+ `));
60
61
  }
61
62
  async requestDeviceCode(endpoint) {
62
63
  const response = await fetch(`${endpoint}/v1/auth/device/code`, {
@@ -72,7 +73,7 @@ export default class AuthLogin extends Command {
72
73
  async pollForToken(device_code, spinner) {
73
74
  return new Promise((resolve) => {
74
75
  const poll = async () => {
75
- const response = await fetch("http://localhost:5001/v1/auth/device/token", {
76
+ const response = await fetch(`${this.endpoint}/v1/auth/device/token`, {
76
77
  method: "POST",
77
78
  headers: {
78
79
  "Content-Type": "application/json",
@@ -92,6 +93,7 @@ export default class AuthLogin extends Command {
92
93
  break;
93
94
  case "slow_down":
94
95
  this.pollingInterval += 5;
96
+ setTimeout(poll, this.pollingInterval * 1000);
95
97
  break;
96
98
  case "access_denied":
97
99
  spinner.error("Access was denied by the user");
@@ -10,6 +10,7 @@ export default class Plugin extends Command {
10
10
  ];
11
11
  static hidden = true;
12
12
  async run() {
13
+ await this.parse(Plugin);
13
14
  await this.config.runCommand("help", ["plugin"]);
14
15
  }
15
16
  }
@@ -0,0 +1,103 @@
1
+ import { promises as fs } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { Command } from "@oclif/core";
4
+ import { colorize } from "@oclif/core/ux";
5
+ import { assert } from "es-toolkit";
6
+ import { dedent } from "ts-dedent";
7
+ import * as configStore from "../../utils/config.js";
8
+ export default class PluginRefreshKey extends Command {
9
+ static description = dedent `Refresh or create API Key for plugin debugging in development stage.`;
10
+ static examples = ["<%= config.bin %> <%= command.id %>"];
11
+ async run() {
12
+ await this.parse(PluginRefreshKey);
13
+ // Step 1: Check access token
14
+ const config = await configStore.load();
15
+ if (!config.auth?.access_token) {
16
+ this.log(colorize("red", "✗ You're not authenticated yet, please run 'automation auth login' first."));
17
+ return process.exit(1);
18
+ }
19
+ try {
20
+ // Step 2: Fetch debug API Key
21
+ const apiKey = await this.fetchDebugApiKey(config.auth.access_token);
22
+ // Step 3: Manage .env file
23
+ await this.updateEnvFile(apiKey);
24
+ // Display success message
25
+ this.log(colorize("green", "✓ Debug API Key refreshed successfully"));
26
+ this.log(colorize("green", "✓ DEBUG_API_KEY updated in .env file"));
27
+ this.log("");
28
+ this.log("Your debug API Key has been saved to .env file.");
29
+ this.log(`Key preview: ${this.maskApiKey(apiKey)}`);
30
+ }
31
+ catch (error) {
32
+ const message = error instanceof Error ? error.message : "Unknown error";
33
+ this.log(colorize("red", `✗ Failed to refresh debug API Key: ${message}`));
34
+ return process.exit(1);
35
+ }
36
+ }
37
+ async fetchDebugApiKey(accessToken) {
38
+ // Get endpoint from config, use default if not available
39
+ const config = await configStore.load();
40
+ assert(config.hub?.endpoint, "Hub endpoint is required");
41
+ const response = await fetch(`${config.hub.endpoint}/api/v1/debug_api_key`, {
42
+ method: "GET",
43
+ headers: {
44
+ "Content-Type": "application/json",
45
+ "User-Agent": "Choiceform (Automation Plugin CLI)",
46
+ Authorization: `Bearer ${accessToken}`,
47
+ },
48
+ });
49
+ if (!response.ok) {
50
+ if (response.status === 401) {
51
+ throw new Error("Access token is invalid or expired, please login again");
52
+ }
53
+ throw new Error(`API request failed: ${response.status} ${response.statusText}`);
54
+ }
55
+ const data = (await response.json());
56
+ if (!data.api_key) {
57
+ throw new Error("API response format error: missing api_key field");
58
+ }
59
+ return data.api_key;
60
+ }
61
+ async updateEnvFile(apiKey) {
62
+ const envPath = join(process.cwd(), ".env");
63
+ try {
64
+ // Check if .env file exists
65
+ let envContent = "";
66
+ let existingKey = false;
67
+ try {
68
+ envContent = await fs.readFile(envPath, "utf-8");
69
+ existingKey = envContent.includes("DEBUG_API_KEY=");
70
+ }
71
+ catch (_error) {
72
+ // File doesn't exist, will create new file
73
+ }
74
+ let newContent;
75
+ if (existingKey) {
76
+ // Replace existing DEBUG_API_KEY
77
+ newContent = envContent.replace(/^DEBUG_API_KEY=.*$/m, `DEBUG_API_KEY=${apiKey}`);
78
+ }
79
+ else {
80
+ // Append new DEBUG_API_KEY
81
+ const separator = envContent && !envContent.endsWith("\n") ? "\n" : "";
82
+ newContent = `${envContent + separator}DEBUG_API_KEY=${apiKey}\n`;
83
+ }
84
+ await fs.writeFile(envPath, newContent, "utf-8");
85
+ }
86
+ catch (error) {
87
+ if (error instanceof Error &&
88
+ "code" in error &&
89
+ error.code === "EACCES") {
90
+ throw new Error("Permission denied: cannot write .env file");
91
+ }
92
+ throw new Error(`Failed to update .env file: ${error instanceof Error ? error.message : "Unknown error"}`);
93
+ }
94
+ }
95
+ maskApiKey(apiKey) {
96
+ if (apiKey.length <= 8) {
97
+ return "***";
98
+ }
99
+ const start = apiKey.substring(0, 4);
100
+ const end = apiKey.substring(apiKey.length - 4);
101
+ return `${start}...${end}`;
102
+ }
103
+ }
@@ -4,6 +4,9 @@ declare const ConfigSchema: z.ZodObject<{
4
4
  endpoint: z.ZodOptional<z.ZodURL>;
5
5
  access_token: z.ZodOptional<z.ZodString>;
6
6
  }, z.core.$strip>>;
7
+ hub: z.ZodOptional<z.ZodObject<{
8
+ endpoint: z.ZodOptional<z.ZodURL>;
9
+ }, z.core.$strip>>;
7
10
  }, z.core.$strip>;
8
11
  export type Config = z.infer<typeof ConfigSchema>;
9
12
  export declare function save(config: Config): Promise<void>;
@@ -7,7 +7,7 @@ function getConfigDir() {
7
7
  return process.env.CHOICEFORM_CONFIG_DIR ?? join(homedir(), ".choiceform");
8
8
  }
9
9
  function getConfigFile() {
10
- return join(getConfigDir(), "automation.json");
10
+ return join(getConfigDir(), "atomemo.json");
11
11
  }
12
12
  const ConfigSchema = z.object({
13
13
  auth: z
@@ -16,6 +16,11 @@ const ConfigSchema = z.object({
16
16
  access_token: z.string().optional(),
17
17
  })
18
18
  .optional(),
19
+ hub: z
20
+ .object({
21
+ endpoint: z.url().optional(),
22
+ })
23
+ .optional(),
19
24
  });
20
25
  export async function save(config) {
21
26
  const validated = ConfigSchema.parse(config);
@@ -36,7 +41,12 @@ export async function load() {
36
41
  auth: {
37
42
  endpoint: process.env.NODE_ENV === "production"
38
43
  ? "https://oneauth.choiceform.io"
39
- : "http://localhost:5001",
44
+ : "https://oneauth.choiceform.io",
45
+ },
46
+ hub: {
47
+ endpoint: process.env.NODE_ENV === "production"
48
+ ? "https://automation-plugin-api.choiceform.io"
49
+ : "https://automation-plugin-api.choiceform.io",
40
50
  },
41
51
  };
42
52
  await save(defaultConfig);