@lotics/cli 0.3.1 → 0.4.0

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
@@ -23,18 +23,34 @@ npm install -g @lotics/cli@latest
23
23
 
24
24
  The CLI checks for updates once per day and prompts when a new version is available.
25
25
 
26
- ## CLI
26
+ ## Authentication
27
+
28
+ **`lotics signup`** — Creates a new Lotics account, organization, workspace, and API key in one step. Prints email and auto-generated password for web app login.
29
+
30
+ ```bash
31
+ lotics signup # interactive prompts
32
+ lotics signup --email a@b.com --name "Agent" # non-interactive
33
+ ```
34
+
35
+ **`lotics auth`** — Saves an existing API key directly (e.g. one created in the Lotics web app).
27
36
 
28
37
  ```bash
29
- # 1. Authenticate
30
38
  lotics auth # interactive prompt
31
- lotics auth ltk_... # non-interactive (for agents/CI)
39
+ lotics auth ltk_... # non-interactive
40
+ ```
41
+
42
+ API key is saved to `~/.lotics/config.json`. Run `lotics logout` to remove saved credentials.
43
+
44
+ Auth priority: `--api-key` flag > `LOTICS_API_KEY` env > `~/.lotics/config.json`.
32
45
 
33
- # 2. Discover tools
46
+ ## CLI
47
+
48
+ ```bash
49
+ # Discover tools
34
50
  lotics tools # list tools by category with descriptions
35
51
  lotics tools query_records # show full description + input schema
36
52
 
37
- # 3. Execute
53
+ # Execute
38
54
  lotics run query_tables '{}'
39
55
  lotics run query_records '{"table_id":"tbl_...","field_keys":["name"]}'
40
56
 
package/dist/src/cli.js CHANGED
@@ -2,8 +2,8 @@
2
2
  import fs from "node:fs";
3
3
  import path from "node:path";
4
4
  import readline from "node:readline";
5
- import { LoticsClient } from "./client.js";
6
- import { resolveAuth, loadConfig, saveConfig, deleteConfig, getConfigPath, checkForUpdate } from "./config.js";
5
+ import { LoticsClient, API_BASE_URL } from "./client.js";
6
+ import { resolveAuth, loadConfig, saveConfig, deleteConfig, checkForUpdate } from "./config.js";
7
7
  import { VERSION } from "./version.js";
8
8
  function printHelp() {
9
9
  console.log(`Lotics CLI v${VERSION} — AI agent interface for Lotics
@@ -14,8 +14,22 @@ Lotics is an AI-powered operations platform. Through this CLI you can:
14
14
  - Build and run automations (event-driven workflows)
15
15
  - Create and manage apps, knowledge docs, and files
16
16
 
17
+ AUTHENTICATION
18
+ lotics signup Create account, org, workspace, and API key
19
+ lotics auth [api_key] Save an existing API key (e.g. from the web app)
20
+ lotics whoami Show the email of the current account
21
+ lotics logout Remove saved credentials
22
+
23
+ Signup flags:
24
+ --email <email> Email (required; prompted if omitted)
25
+ --name <name> Display name (defaults to email prefix)
26
+
27
+ Signup prints email and auto-generated password for web app login.
28
+ Use lotics whoami to check the current account email.
29
+ Auth priority: --api-key flag > LOTICS_API_KEY env > saved config.
30
+
17
31
  USAGE
18
- 1. lotics auth [api_key] Authenticate (saves key to ~/.lotics/config.json)
32
+ 1. lotics signup Create account and get API key
19
33
  2. lotics tools List available tools by category
20
34
  3. lotics tools <name> Show tool description and full input schema
21
35
  4. lotics run <tool> '<json>' Execute a tool with JSON arguments
@@ -25,8 +39,6 @@ USAGE
25
39
  Query tools return IDs used as arguments to other tools.
26
40
 
27
41
  COMMANDS
28
- lotics auth [api_key] Save API key (interactive prompt if omitted)
29
- lotics logout Remove saved credentials
30
42
  lotics tools List all available tools
31
43
  lotics tools <name> Show tool description and input schema
32
44
  lotics run <tool> '<json>' Execute a tool
@@ -41,9 +53,6 @@ FLAGS
41
53
  --api-key <key> API key (overrides saved config and LOTICS_API_KEY)
42
54
  --version Show version
43
55
 
44
- For non-interactive use, set LOTICS_API_KEY in the environment
45
- instead of running lotics auth.
46
-
47
56
  OUTPUT
48
57
  Default output is a human-readable text summary. Use --json to get
49
58
  structured JSON for programmatic use. Errors print to stderr and
@@ -73,6 +82,8 @@ function parseArgs(argv) {
73
82
  output: undefined,
74
83
  as: undefined,
75
84
  apiKey: undefined,
85
+ email: undefined,
86
+ name: undefined,
76
87
  version: false,
77
88
  help: false,
78
89
  };
@@ -100,6 +111,12 @@ function parseArgs(argv) {
100
111
  case "--api-key":
101
112
  flags.apiKey = argv[++i];
102
113
  break;
114
+ case "--email":
115
+ flags.email = argv[++i];
116
+ break;
117
+ case "--name":
118
+ flags.name = argv[++i];
119
+ break;
103
120
  case "--version":
104
121
  case "-v":
105
122
  flags.version = true;
@@ -147,6 +164,46 @@ function prompt(question) {
147
164
  });
148
165
  });
149
166
  }
167
+ async function publicPost(path, body) {
168
+ const response = await fetch(`${API_BASE_URL}${path}`, {
169
+ method: "POST",
170
+ headers: { "Content-Type": "application/json" },
171
+ body: JSON.stringify(body),
172
+ });
173
+ const data = await response.json();
174
+ return { ok: response.ok, status: response.status, data };
175
+ }
176
+ async function handleSignup(flags) {
177
+ const email = flags.email ?? (process.stdin.isTTY ? await prompt("Email: ") : "");
178
+ if (!email) {
179
+ console.error("Email is required. Use --email or run interactively.");
180
+ process.exit(1);
181
+ }
182
+ const name = flags.name ?? (process.stdin.isTTY ? await prompt("Name (enter to use email): ") : undefined);
183
+ const body = { email };
184
+ if (name)
185
+ body.name = name;
186
+ const { ok, status, data } = await publicPost("/v1/cli/signup", body);
187
+ if (!ok) {
188
+ if (status === 409) {
189
+ console.error("An account with this email already exists. Use: lotics auth");
190
+ }
191
+ else if (status === 429) {
192
+ console.error("Too many signup attempts. Try again later.");
193
+ }
194
+ else {
195
+ console.error(`Signup failed: ${data.message ?? JSON.stringify(data)}`);
196
+ }
197
+ process.exit(1);
198
+ }
199
+ const existing = loadConfig() ?? {};
200
+ saveConfig({ ...existing, api_key: data.api_key, email: data.email });
201
+ console.error(`Account created. You can now use the CLI.`);
202
+ console.error(` Email: ${data.email}`);
203
+ console.error(` Password: ${data.password}`);
204
+ console.error(`\nUse these credentials to log into the Lotics web app.`);
205
+ console.error(`Run "lotics whoami" to check the current account email.`);
206
+ }
150
207
  async function handleAuth(providedKey) {
151
208
  const apiKey = providedKey ?? await prompt("Enter your API key: ");
152
209
  if (!apiKey) {
@@ -164,7 +221,7 @@ async function handleAuth(providedKey) {
164
221
  }
165
222
  const existing = loadConfig() ?? {};
166
223
  saveConfig({ ...existing, api_key: apiKey });
167
- console.error(`Authenticated. Config saved to ${getConfigPath()}`);
224
+ console.error("Authenticated.");
168
225
  }
169
226
  function requireClient(flags) {
170
227
  const auth = resolveAuth(flags);
@@ -207,10 +264,25 @@ async function main() {
207
264
  return;
208
265
  }
209
266
  // --- Commands that don't require auth ---
267
+ if (command === "signup") {
268
+ await handleSignup(flags);
269
+ return;
270
+ }
210
271
  if (command === "auth") {
211
272
  await handleAuth(subcommand ?? flags.apiKey);
212
273
  return;
213
274
  }
275
+ if (command === "whoami") {
276
+ const config = loadConfig();
277
+ if (config?.email) {
278
+ console.log(config.email);
279
+ }
280
+ else {
281
+ console.error("Not signed up. Run: lotics signup");
282
+ process.exit(1);
283
+ }
284
+ return;
285
+ }
214
286
  if (command === "logout") {
215
287
  deleteConfig();
216
288
  console.error("Logged out. Credentials removed.");
@@ -22,6 +22,7 @@ export interface FileUploadResult {
22
22
  error: string;
23
23
  }>;
24
24
  }
25
+ export declare const API_BASE_URL: string;
25
26
  export declare class LoticsClient {
26
27
  private apiKey;
27
28
  private baseUrl;
@@ -21,12 +21,13 @@ function getMimeType(filename) {
21
21
  const ext = path.extname(filename).toLowerCase();
22
22
  return MIME_MAP[ext] ?? "application/octet-stream";
23
23
  }
24
+ export const API_BASE_URL = process.env.LOTICS_API_URL ?? "https://api.lotics.ai";
24
25
  export class LoticsClient {
25
26
  apiKey;
26
27
  baseUrl;
27
28
  constructor(options) {
28
29
  this.apiKey = options.apiKey;
29
- this.baseUrl = "https://api.lotics.ai";
30
+ this.baseUrl = API_BASE_URL;
30
31
  }
31
32
  async throwResponseError(response) {
32
33
  const text = await response.text();
@@ -1,5 +1,6 @@
1
1
  export interface LoticsConfig {
2
2
  api_key?: string;
3
+ email?: string;
3
4
  last_update_check?: number;
4
5
  latest_version?: string;
5
6
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lotics/cli",
3
- "version": "0.3.1",
3
+ "version": "0.4.0",
4
4
  "description": "Lotics SDK and CLI for AI agents",
5
5
  "type": "module",
6
6
  "bin": {