@lotics/cli 0.1.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 ADDED
@@ -0,0 +1,65 @@
1
+ # @lotics/cli
2
+
3
+ CLI and SDK for AI agents to interact with Lotics.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install -g @lotics/cli
9
+ ```
10
+
11
+ ## Update
12
+
13
+ ```bash
14
+ npm install -g @lotics/cli@latest
15
+ ```
16
+
17
+ The CLI checks for updates once per day and prompts when a new version is available.
18
+
19
+ ## CLI
20
+
21
+ ```bash
22
+ # 1. Authenticate
23
+ lotics auth
24
+
25
+ # 2. Discover tools
26
+ lotics tools # list all tool names
27
+ lotics tools query_records # show description + input schema
28
+
29
+ # 3. Execute
30
+ lotics run query_tables '{}'
31
+ lotics run query_records '{"table_id":"tbl_...","field_keys":["name"]}'
32
+ lotics run query_records --json '{"table_id":"tbl_..."}'
33
+
34
+ # Pipe args via stdin
35
+ echo '{"table_id":"tbl_..."}' | lotics run query_records
36
+
37
+ # Upload a file
38
+ lotics upload ./report.pdf
39
+ lotics upload ./photo.jpg --as cover.jpg
40
+
41
+ # Generate a file, then download it
42
+ lotics run generate_excel_from_template '{"..."}' --json
43
+ # → {"file_id":"fil_...","url":"...","filename":"report.xlsx",...}
44
+ lotics download fil_... -o ./reports/
45
+
46
+ # CI / non-interactive
47
+ LOTICS_API_KEY=ltk_... lotics run query_tables '{}'
48
+ ```
49
+
50
+ ## SDK
51
+
52
+ ```typescript
53
+ import { LoticsClient } from "@lotics/cli";
54
+
55
+ const client = new LoticsClient({
56
+ apiKey: "ltk_...",
57
+ baseUrl: "https://api.lotics.com",
58
+ });
59
+
60
+ const { result } = await client.execute("query_tables", {});
61
+ const upload = await client.uploadFile("./report.pdf");
62
+ await client.downloadFile(url, "./output.xlsx");
63
+ const { tools } = await client.listTools();
64
+ const info = await client.getTool("query_records");
65
+ ```
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
@@ -0,0 +1,277 @@
1
+ #!/usr/bin/env node
2
+ import readline from "node:readline";
3
+ import { LoticsClient } from "./client.js";
4
+ import { resolveAuth, loadConfig, saveConfig, deleteConfig, getConfigPath, checkForUpdate } from "./config.js";
5
+ import { VERSION } from "./version.js";
6
+ function printHelp() {
7
+ console.log(`Lotics CLI v${VERSION} — AI agent interface for Lotics
8
+
9
+ Lotics is an AI-powered operations platform for structured data,
10
+ document generation, automations, and knowledge management.
11
+
12
+ COMMANDS
13
+ lotics auth Save API key (interactive)
14
+ lotics logout Remove saved credentials
15
+ lotics tools List all available tools
16
+ lotics tools <name> Show tool description and input schema
17
+ lotics run <tool> '<json>' Execute a tool
18
+ lotics run <tool> --json Full JSON output instead of compact text
19
+ lotics upload <file> Upload a local file
20
+ lotics download <file_id> Download a file by ID
21
+
22
+ FLAGS
23
+ --json Full JSON output
24
+ --timeout <ms> Timeout for tool execution (default: 60000)
25
+ -o <path> Output dir for downloads
26
+ --as <name> Override upload filename
27
+ --api-key <key> API key (for CI/agents)
28
+ --api-url <url> API URL override
29
+ --version Show version
30
+
31
+ WORKFLOW
32
+ 1. lotics auth Authenticate once
33
+ 2. lotics tools See what's available
34
+ 3. lotics tools <name> Read the schema before calling
35
+ 4. lotics run <tool> '<json>' Execute with correct args
36
+
37
+ ENVIRONMENT
38
+ LOTICS_API_KEY API key (overrides saved config)
39
+ LOTICS_API_URL API URL (overrides saved config)`);
40
+ }
41
+ function parseArgs(argv) {
42
+ const flags = {
43
+ json: false,
44
+ timeout: undefined,
45
+ output: undefined,
46
+ as: undefined,
47
+ apiKey: undefined,
48
+ apiUrl: undefined,
49
+ version: false,
50
+ help: false,
51
+ };
52
+ let command;
53
+ let subcommand;
54
+ let toolArgs;
55
+ let i = 0;
56
+ while (i < argv.length) {
57
+ const arg = argv[i];
58
+ switch (arg) {
59
+ case "--json":
60
+ flags.json = true;
61
+ break;
62
+ case "--timeout":
63
+ flags.timeout = parseInt(argv[++i], 10);
64
+ break;
65
+ case "--output":
66
+ case "-o":
67
+ flags.output = argv[++i];
68
+ break;
69
+ case "--as":
70
+ flags.as = argv[++i];
71
+ break;
72
+ case "--api-key":
73
+ flags.apiKey = argv[++i];
74
+ break;
75
+ case "--api-url":
76
+ flags.apiUrl = argv[++i];
77
+ break;
78
+ case "--version":
79
+ case "-v":
80
+ flags.version = true;
81
+ break;
82
+ case "--help":
83
+ case "-h":
84
+ flags.help = true;
85
+ break;
86
+ default:
87
+ if (!command) {
88
+ command = arg;
89
+ }
90
+ else if (!subcommand) {
91
+ subcommand = arg;
92
+ }
93
+ else if (!toolArgs) {
94
+ toolArgs = arg;
95
+ }
96
+ break;
97
+ }
98
+ i++;
99
+ }
100
+ return { command, subcommand, toolArgs, flags };
101
+ }
102
+ function readStdin() {
103
+ return new Promise((resolve, reject) => {
104
+ const chunks = [];
105
+ process.stdin.on("data", (chunk) => chunks.push(chunk));
106
+ process.stdin.on("end", () => resolve(Buffer.concat(chunks).toString("utf-8").trim()));
107
+ process.stdin.on("error", reject);
108
+ });
109
+ }
110
+ function prompt(question) {
111
+ const rl = readline.createInterface({
112
+ input: process.stdin,
113
+ output: process.stderr,
114
+ });
115
+ return new Promise((resolve) => {
116
+ rl.question(question, (answer) => {
117
+ rl.close();
118
+ resolve(answer.trim());
119
+ });
120
+ });
121
+ }
122
+ async function handleAuth(flags) {
123
+ const apiKey = await prompt("Enter your API key: ");
124
+ if (!apiKey) {
125
+ console.error("No API key provided.");
126
+ process.exit(1);
127
+ }
128
+ const apiUrlInput = flags.apiUrl ?? (await prompt("API URL (default: https://api.lotics.com): "));
129
+ const apiUrl = apiUrlInput || "https://api.lotics.com";
130
+ const client = new LoticsClient({ apiKey, baseUrl: apiUrl });
131
+ try {
132
+ await client.listTools();
133
+ }
134
+ catch (error) {
135
+ const message = error instanceof Error ? error.message : String(error);
136
+ console.error(`Authentication failed: ${message}`);
137
+ process.exit(1);
138
+ }
139
+ const existing = loadConfig() ?? {};
140
+ saveConfig({ ...existing, api_key: apiKey, api_url: apiUrl });
141
+ console.error(`Authenticated. Config saved to ${getConfigPath()}`);
142
+ }
143
+ function requireClient(flags) {
144
+ const auth = resolveAuth(flags);
145
+ if (!auth) {
146
+ console.error('Not authenticated. Run "lotics auth" or set LOTICS_API_KEY.');
147
+ process.exit(1);
148
+ }
149
+ return new LoticsClient({ apiKey: auth.apiKey, baseUrl: auth.apiUrl });
150
+ }
151
+ async function main() {
152
+ const { command, subcommand, toolArgs, flags } = parseArgs(process.argv.slice(2));
153
+ if (flags.help || (!command && !flags.version)) {
154
+ printHelp();
155
+ return;
156
+ }
157
+ if (flags.version) {
158
+ console.log(VERSION);
159
+ return;
160
+ }
161
+ // --- Commands that don't require auth ---
162
+ if (command === "auth") {
163
+ await handleAuth(flags);
164
+ return;
165
+ }
166
+ if (command === "logout") {
167
+ deleteConfig();
168
+ console.error("Logged out. Credentials removed.");
169
+ return;
170
+ }
171
+ // --- Validate command before auth ---
172
+ if (command !== "tools" && command !== "upload" && command !== "run" && command !== "download") {
173
+ console.error(`Unknown command: ${command}`);
174
+ console.error('Run "lotics --help" for usage.');
175
+ process.exit(1);
176
+ }
177
+ if (command === "run" && !subcommand) {
178
+ console.error('Usage: lotics run <tool> \'<json_args>\'');
179
+ console.error('Run "lotics tools" to see available tools.');
180
+ process.exit(1);
181
+ }
182
+ if (command === "upload" && !subcommand) {
183
+ console.error('Usage: lotics upload <file> [--as <name>]');
184
+ console.error('Uploads a local file and returns its file_id.');
185
+ process.exit(1);
186
+ }
187
+ if (command === "download" && !subcommand) {
188
+ console.error('Usage: lotics download <file_id> [-o <dir>]');
189
+ console.error('File IDs come from upload results or generate_* tool output (--json).');
190
+ process.exit(1);
191
+ }
192
+ const client = requireClient(flags);
193
+ // lotics tools / lotics tools <name>
194
+ if (command === "tools") {
195
+ if (subcommand) {
196
+ const info = await client.getTool(subcommand);
197
+ console.log(JSON.stringify(info, null, 2));
198
+ }
199
+ else {
200
+ const { categories } = await client.listTools();
201
+ for (const [category, names] of Object.entries(categories)) {
202
+ console.log(`\n${category}`);
203
+ console.log(` ${names.join(" ")}`);
204
+ }
205
+ console.log("");
206
+ }
207
+ return;
208
+ }
209
+ // lotics upload <file> [--as <name>]
210
+ if (command === "upload") {
211
+ const upload = await client.uploadFile(subcommand, {
212
+ filename: flags.as,
213
+ });
214
+ if (upload.errors.length > 0) {
215
+ console.error(`Upload failed: ${upload.errors[0].error}`);
216
+ process.exit(1);
217
+ }
218
+ console.log(JSON.stringify(upload.files[0], null, 2));
219
+ return;
220
+ }
221
+ // lotics download <file_id> [-o <path>]
222
+ if (command === "download") {
223
+ const { path: filePath, filename } = await client.downloadFileById(subcommand, flags.output);
224
+ console.error(`Downloaded: ${filePath} (${filename})`);
225
+ return;
226
+ }
227
+ // lotics run <tool> [json_args]
228
+ if (command === "run") {
229
+ const toolName = subcommand;
230
+ let rawArgs = toolArgs;
231
+ if (!rawArgs && !process.stdin.isTTY) {
232
+ rawArgs = await readStdin();
233
+ }
234
+ let args = {};
235
+ if (rawArgs) {
236
+ try {
237
+ args = JSON.parse(rawArgs);
238
+ }
239
+ catch {
240
+ console.error(`Invalid JSON: ${rawArgs}`);
241
+ process.exit(1);
242
+ }
243
+ }
244
+ const format = flags.json ? "json" : "text";
245
+ const timeoutMs = flags.timeout ?? 60000;
246
+ const result = await client.execute(toolName, args, { format, timeoutMs });
247
+ if (result.error) {
248
+ console.error(result.error);
249
+ console.error(`\nHint: run "lotics tools ${toolName}" to see the expected input schema.`);
250
+ process.exit(1);
251
+ }
252
+ if (format === "text" && result.model_output) {
253
+ console.log(result.model_output);
254
+ }
255
+ else {
256
+ console.log(JSON.stringify(result.result, null, 2));
257
+ }
258
+ return;
259
+ }
260
+ }
261
+ main()
262
+ .then(() => checkForUpdate(VERSION))
263
+ .catch((error) => {
264
+ const message = error instanceof Error ? error.message : String(error);
265
+ if (message.includes("fetch failed") || message.includes("ECONNREFUSED")) {
266
+ console.error("Could not connect to the Lotics API.");
267
+ console.error('Check your API URL or run "lotics auth" to reconfigure.');
268
+ }
269
+ else if (message.includes("ENOENT")) {
270
+ const pathMatch = message.match(/open '([^']+)'/);
271
+ console.error(`File not found: ${pathMatch?.[1] ?? message}`);
272
+ }
273
+ else {
274
+ console.error(message);
275
+ }
276
+ process.exit(1);
277
+ });
@@ -0,0 +1,51 @@
1
+ export interface LoticsClientOptions {
2
+ apiKey: string;
3
+ baseUrl?: string;
4
+ }
5
+ export interface ToolExecuteResult {
6
+ result: unknown;
7
+ model_output?: string;
8
+ error?: string;
9
+ }
10
+ export interface ToolInfo {
11
+ name: string;
12
+ description: string;
13
+ input_schema: unknown;
14
+ }
15
+ export interface FileUploadResult {
16
+ files: Array<{
17
+ id: string;
18
+ filename: string;
19
+ mime_type: string;
20
+ }>;
21
+ errors: Array<{
22
+ filename: string;
23
+ error: string;
24
+ }>;
25
+ }
26
+ export declare class LoticsClient {
27
+ private apiKey;
28
+ private baseUrl;
29
+ constructor(options: LoticsClientOptions);
30
+ private throwResponseError;
31
+ private request;
32
+ listTools(): Promise<{
33
+ tools: Array<{
34
+ name: string;
35
+ }>;
36
+ categories: Record<string, string[]>;
37
+ }>;
38
+ getTool(name: string): Promise<ToolInfo>;
39
+ execute(tool: string, args: Record<string, unknown>, options?: {
40
+ format?: "json" | "text";
41
+ timeoutMs?: number;
42
+ }): Promise<ToolExecuteResult>;
43
+ downloadFile(url: string, outputPath: string): Promise<string>;
44
+ downloadFileById(fileId: string, outputDir?: string): Promise<{
45
+ path: string;
46
+ filename: string;
47
+ }>;
48
+ uploadFile(filePath: string, options?: {
49
+ filename?: string;
50
+ }): Promise<FileUploadResult>;
51
+ }
@@ -0,0 +1,137 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ const MIME_MAP = {
4
+ ".jpg": "image/jpeg",
5
+ ".jpeg": "image/jpeg",
6
+ ".png": "image/png",
7
+ ".gif": "image/gif",
8
+ ".webp": "image/webp",
9
+ ".svg": "image/svg+xml",
10
+ ".pdf": "application/pdf",
11
+ ".csv": "text/csv",
12
+ ".xlsx": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
13
+ ".docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
14
+ ".txt": "text/plain",
15
+ ".json": "application/json",
16
+ ".html": "text/html",
17
+ ".xml": "application/xml",
18
+ ".zip": "application/zip",
19
+ };
20
+ function getMimeType(filename) {
21
+ const ext = path.extname(filename).toLowerCase();
22
+ return MIME_MAP[ext] ?? "application/octet-stream";
23
+ }
24
+ export class LoticsClient {
25
+ apiKey;
26
+ baseUrl;
27
+ constructor(options) {
28
+ this.apiKey = options.apiKey;
29
+ this.baseUrl = (options.baseUrl ?? "https://api.lotics.com").replace(/\/$/, "");
30
+ }
31
+ async throwResponseError(response) {
32
+ const text = await response.text();
33
+ let message;
34
+ try {
35
+ const json = JSON.parse(text);
36
+ message = json.message ?? text;
37
+ }
38
+ catch {
39
+ message = text;
40
+ }
41
+ throw new Error(`${response.status}: ${message}`);
42
+ }
43
+ async request(method, path, body) {
44
+ const url = `${this.baseUrl}${path}`;
45
+ const headers = {
46
+ "x-api-key": this.apiKey,
47
+ };
48
+ const init = { method, headers };
49
+ if (body !== undefined) {
50
+ headers["Content-Type"] = "application/json";
51
+ init.body = JSON.stringify(body);
52
+ }
53
+ const response = await fetch(url, init);
54
+ if (!response.ok)
55
+ await this.throwResponseError(response);
56
+ return response.json();
57
+ }
58
+ async listTools() {
59
+ return this.request("GET", "/v1/tools");
60
+ }
61
+ async getTool(name) {
62
+ return this.request("GET", `/v1/tools/${encodeURIComponent(name)}`);
63
+ }
64
+ async execute(tool, args, options) {
65
+ const body = { tool, args, format: options?.format ?? "text" };
66
+ if (options?.timeoutMs) {
67
+ const controller = new AbortController();
68
+ const timeout = setTimeout(() => controller.abort(), options.timeoutMs);
69
+ try {
70
+ const url = `${this.baseUrl}/v1/tools/execute`;
71
+ const response = await fetch(url, {
72
+ method: "POST",
73
+ headers: { "x-api-key": this.apiKey, "Content-Type": "application/json" },
74
+ body: JSON.stringify(body),
75
+ signal: controller.signal,
76
+ });
77
+ if (!response.ok)
78
+ await this.throwResponseError(response);
79
+ return response.json();
80
+ }
81
+ catch (error) {
82
+ if (error instanceof Error && error.name === "AbortError") {
83
+ throw new Error(`Tool execution timed out after ${options.timeoutMs}ms`);
84
+ }
85
+ throw error;
86
+ }
87
+ finally {
88
+ clearTimeout(timeout);
89
+ }
90
+ }
91
+ return this.request("POST", "/v1/tools/execute", body);
92
+ }
93
+ async downloadFile(url, outputPath) {
94
+ const response = await fetch(url);
95
+ if (!response.ok) {
96
+ throw new Error(`${response.status}: Failed to download file`);
97
+ }
98
+ const buffer = Buffer.from(await response.arrayBuffer());
99
+ const absolutePath = path.resolve(outputPath);
100
+ await fs.promises.writeFile(absolutePath, buffer);
101
+ return absolutePath;
102
+ }
103
+ async downloadFileById(fileId, outputDir) {
104
+ const url = `${this.baseUrl}/v1/files/${encodeURIComponent(fileId)}/download`;
105
+ const response = await fetch(url, {
106
+ headers: { "x-api-key": this.apiKey },
107
+ });
108
+ if (!response.ok)
109
+ await this.throwResponseError(response);
110
+ const disposition = response.headers.get("content-disposition") ?? "";
111
+ const match = disposition.match(/filename="?([^";\n]+)"?/);
112
+ const filename = match?.[1] ?? fileId;
113
+ const buffer = Buffer.from(await response.arrayBuffer());
114
+ const dir = outputDir ? path.resolve(outputDir) : process.cwd();
115
+ const absolutePath = path.join(dir, filename);
116
+ await fs.promises.writeFile(absolutePath, buffer);
117
+ return { path: absolutePath, filename };
118
+ }
119
+ async uploadFile(filePath, options) {
120
+ const absolutePath = path.resolve(filePath);
121
+ const buffer = await fs.promises.readFile(absolutePath);
122
+ const filename = options?.filename ?? path.basename(absolutePath);
123
+ const mimeType = getMimeType(filename);
124
+ const blob = new Blob([buffer], { type: mimeType });
125
+ const formData = new FormData();
126
+ formData.append("file", blob, filename);
127
+ const url = `${this.baseUrl}/v1/files`;
128
+ const response = await fetch(url, {
129
+ method: "POST",
130
+ headers: { "x-api-key": this.apiKey },
131
+ body: formData,
132
+ });
133
+ if (!response.ok)
134
+ await this.throwResponseError(response);
135
+ return response.json();
136
+ }
137
+ }
@@ -0,0 +1,27 @@
1
+ export interface LoticsConfig {
2
+ api_key?: string;
3
+ api_url?: string;
4
+ last_update_check?: number;
5
+ latest_version?: string;
6
+ }
7
+ export declare function loadConfig(): LoticsConfig | null;
8
+ export declare function saveConfig(config: LoticsConfig): void;
9
+ export declare function deleteConfig(): void;
10
+ export declare function getConfigPath(): string;
11
+ /**
12
+ * Check for a newer CLI version. Synchronous — prints a warning to stderr
13
+ * if the cached latest version is newer than current. Kicks off a background
14
+ * fetch if the cache is stale (result is written to config for next run).
15
+ */
16
+ export declare function checkForUpdate(currentVersion: string): void;
17
+ /**
18
+ * Resolve API key and URL from flags, env vars, or config file.
19
+ * Priority: flag > env > config file > default.
20
+ */
21
+ export declare function resolveAuth(flags: {
22
+ apiKey?: string;
23
+ apiUrl?: string;
24
+ }): {
25
+ apiKey: string;
26
+ apiUrl: string;
27
+ } | null;
@@ -0,0 +1,91 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import os from "node:os";
4
+ const CONFIG_DIR = path.join(os.homedir(), ".lotics");
5
+ const CONFIG_FILE = path.join(CONFIG_DIR, "config.json");
6
+ export function loadConfig() {
7
+ try {
8
+ const raw = fs.readFileSync(CONFIG_FILE, "utf-8");
9
+ return JSON.parse(raw);
10
+ }
11
+ catch {
12
+ return null;
13
+ }
14
+ }
15
+ export function saveConfig(config) {
16
+ fs.mkdirSync(CONFIG_DIR, { recursive: true });
17
+ fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2) + "\n", "utf-8");
18
+ }
19
+ export function deleteConfig() {
20
+ try {
21
+ fs.unlinkSync(CONFIG_FILE);
22
+ }
23
+ catch {
24
+ // Already deleted or never existed
25
+ }
26
+ }
27
+ export function getConfigPath() {
28
+ return CONFIG_FILE;
29
+ }
30
+ const UPDATE_CHECK_INTERVAL_MS = 24 * 60 * 60 * 1000; // 24 hours
31
+ /**
32
+ * Check for a newer CLI version. Synchronous — prints a warning to stderr
33
+ * if the cached latest version is newer than current. Kicks off a background
34
+ * fetch if the cache is stale (result is written to config for next run).
35
+ */
36
+ export function checkForUpdate(currentVersion) {
37
+ const config = loadConfig();
38
+ const lastCheck = config?.last_update_check ?? 0;
39
+ if (Date.now() - lastCheck < UPDATE_CHECK_INTERVAL_MS) {
40
+ if (config?.latest_version && config.latest_version !== currentVersion) {
41
+ printUpdateWarning(currentVersion, config.latest_version);
42
+ }
43
+ return;
44
+ }
45
+ // Cache is stale — fetch in background, don't block exit
46
+ fetchLatestVersion().then((latest) => {
47
+ if (!latest)
48
+ return;
49
+ const existing = loadConfig() ?? {};
50
+ saveConfig({ ...existing, last_update_check: Date.now(), latest_version: latest });
51
+ }).catch(() => { });
52
+ }
53
+ async function fetchLatestVersion() {
54
+ const controller = new AbortController();
55
+ const timeout = setTimeout(() => controller.abort(), 3000);
56
+ timeout.unref();
57
+ try {
58
+ const response = await fetch("https://registry.npmjs.org/@lotics/cli/latest", {
59
+ signal: controller.signal,
60
+ });
61
+ if (!response.ok)
62
+ return null;
63
+ const data = (await response.json());
64
+ return data.version ?? null;
65
+ }
66
+ catch {
67
+ return null;
68
+ }
69
+ finally {
70
+ clearTimeout(timeout);
71
+ }
72
+ }
73
+ function printUpdateWarning(current, latest) {
74
+ console.error(`\nUpdate available: ${current} → ${latest}`);
75
+ console.error(`Run: npm i -g @lotics/cli\n`);
76
+ }
77
+ /**
78
+ * Resolve API key and URL from flags, env vars, or config file.
79
+ * Priority: flag > env > config file > default.
80
+ */
81
+ export function resolveAuth(flags) {
82
+ const config = loadConfig();
83
+ const apiKey = flags.apiKey ?? process.env.LOTICS_API_KEY ?? config?.api_key;
84
+ if (!apiKey)
85
+ return null;
86
+ const apiUrl = flags.apiUrl ??
87
+ process.env.LOTICS_API_URL ??
88
+ config?.api_url ??
89
+ "https://api.lotics.com";
90
+ return { apiKey, apiUrl };
91
+ }
@@ -0,0 +1 @@
1
+ export declare const VERSION = "0.1.0";
@@ -0,0 +1 @@
1
+ export const VERSION = "0.1.0";
package/package.json ADDED
@@ -0,0 +1,36 @@
1
+ {
2
+ "name": "@lotics/cli",
3
+ "version": "0.1.0",
4
+ "description": "Lotics SDK and CLI for AI agents",
5
+ "type": "module",
6
+ "bin": {
7
+ "lotics": "./dist/src/cli.js"
8
+ },
9
+ "exports": {
10
+ ".": "./dist/src/client.js"
11
+ },
12
+ "files": [
13
+ "dist",
14
+ "README.md"
15
+ ],
16
+ "scripts": {
17
+ "build": "tsgo",
18
+ "typecheck": "tsgo --noEmit",
19
+ "prepublishOnly": "npm run build"
20
+ },
21
+ "keywords": [
22
+ "lotics",
23
+ "sdk",
24
+ "cli",
25
+ "ai-agent"
26
+ ],
27
+ "engines": {
28
+ "node": ">=18"
29
+ },
30
+ "license": "MIT",
31
+ "repository": {
32
+ "type": "git",
33
+ "url": "https://github.com/lotics/lotics.git",
34
+ "directory": "packages/sdk"
35
+ }
36
+ }