@otonix/cli 1.0.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.
Files changed (3) hide show
  1. package/README.md +182 -0
  2. package/dist/cli.js +539 -0
  3. package/package.json +47 -0
package/README.md ADDED
@@ -0,0 +1,182 @@
1
+ # @otonix/cli
2
+
3
+ Command-line tool for the [Otonix](https://otonix.tech) sovereign compute platform.
4
+
5
+ Initialize, register, and manage autonomous AI agents from your terminal.
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ npm install -g @otonix/cli
11
+ ```
12
+
13
+ Or run directly:
14
+
15
+ ```bash
16
+ npx @otonix/cli <command>
17
+ ```
18
+
19
+ ## Quick Start
20
+
21
+ ```bash
22
+ # 1. Generate an API key (requires dashboard token)
23
+ otonix keygen my-vps-key
24
+
25
+ # 2. Configure the CLI
26
+ otonix init
27
+
28
+ # 3. Register your agent
29
+ otonix register --name my-agent --model claude-opus-4-6
30
+
31
+ # 4. Start heartbeat loop
32
+ otonix heartbeat:loop
33
+
34
+ # 5. Log actions
35
+ otonix log "Trade executed BTC/USDC" --category trading
36
+ ```
37
+
38
+ ## Commands
39
+
40
+ ### Setup
41
+
42
+ | Command | Description |
43
+ |---------|-------------|
44
+ | `otonix init` | Configure API key and endpoint interactively |
45
+ | `otonix keygen <name>` | Generate a new API key (requires dashboard token) |
46
+ | `otonix whoami` | Show current configuration |
47
+
48
+ ### Agent Management
49
+
50
+ | Command | Description |
51
+ |---------|-------------|
52
+ | `otonix register` | Register an agent on this VPS |
53
+ | `otonix status` | Show current agent status |
54
+ | `otonix heartbeat` | Send a single heartbeat ping |
55
+ | `otonix heartbeat:loop` | Start continuous heartbeat (Ctrl+C to stop) |
56
+ | `otonix log <message>` | Log an agent action |
57
+ | `otonix actions` | Show agent action log |
58
+
59
+ ### Infrastructure
60
+
61
+ | Command | Description |
62
+ |---------|-------------|
63
+ | `otonix agents` | List all connected agents |
64
+ | `otonix sandboxes` | List VPS sandboxes |
65
+ | `otonix domains` | List registered domains |
66
+
67
+ ### Platform
68
+
69
+ | Command | Description |
70
+ |---------|-------------|
71
+ | `otonix engine` | Show autonomic engine status |
72
+ | `otonix x402` | Show x402 payment configuration |
73
+
74
+ ## Command Options
75
+
76
+ ### `otonix register`
77
+
78
+ ```bash
79
+ otonix register --name my-agent --model claude-opus-4-6 --wallet 0x... --interval 60
80
+ ```
81
+
82
+ | Option | Default | Description |
83
+ |--------|---------|-------------|
84
+ | `--name` | (interactive) | Agent name |
85
+ | `--model` | `claude-opus-4-6` | AI model |
86
+ | `--wallet` | — | Wallet address for payments |
87
+ | `--interval` | `60` | Heartbeat interval in seconds |
88
+
89
+ ### `otonix log`
90
+
91
+ ```bash
92
+ otonix log "Task completed" --category compute --details "Processed 1000 records"
93
+ ```
94
+
95
+ | Option | Default | Description |
96
+ |--------|---------|-------------|
97
+ | `--category` | `system` | Action category |
98
+ | `--details` | — | Additional details |
99
+
100
+ ### `otonix actions`
101
+
102
+ ```bash
103
+ otonix actions --limit 50
104
+ ```
105
+
106
+ | Option | Default | Description |
107
+ |--------|---------|-------------|
108
+ | `--limit` | `20` | Number of actions to show |
109
+
110
+ ## Configuration
111
+
112
+ Config is stored at `~/.otonix/config.json` with file permissions `600`.
113
+
114
+ ```json
115
+ {
116
+ "apiKey": "otonix_xxxx",
117
+ "endpoint": "https://app.otonix.tech",
118
+ "agentId": "uuid-xxxx",
119
+ "agentName": "my-agent"
120
+ }
121
+ ```
122
+
123
+ ## Example Session
124
+
125
+ ```
126
+ $ otonix init
127
+ Otonix CLI Setup
128
+
129
+ Endpoint [https://app.otonix.tech]:
130
+ API Key (otonix_xxx): otonix_a1b2c3d4e5f6...
131
+
132
+ Config saved to /root/.otonix/config.json
133
+ Authenticated successfully.
134
+
135
+ $ otonix register --name sentinel-01
136
+ Agent Registered:
137
+ ID: e2998be4-b77c-495e-a535-a6e4ca9dc768
138
+ Name: sentinel-01
139
+ Model: claude-opus-4-6
140
+ VPS IP: 10.0.1.1
141
+ Tier: active
142
+ Interval: 60s
143
+
144
+ $ otonix heartbeat
145
+ Heartbeat sent — sentinel-01 [active] tier:active credits:$50.00
146
+
147
+ $ otonix log "Deployed monitoring stack" --category infra
148
+ Logged: [infra] Deployed monitoring stack (completed)
149
+
150
+ $ otonix status
151
+ Agent Status:
152
+ ID: e2998be4-b77c-495e-a535-a6e4ca9dc768
153
+ Name: sentinel-01
154
+ Status: active
155
+ Tier: full
156
+ Credits: $50.00
157
+ Model: claude-opus-4-6
158
+ VPS IP: 10.0.1.1
159
+ Heartbeat: 12s ago
160
+ Actions: 3
161
+
162
+ $ otonix engine
163
+ Autonomic Engine Status:
164
+ Running: yes
165
+ Last Cycle: 45s ago
166
+ Tier Updates: 0
167
+ Heal Attempts: 0
168
+ Renewals: 0/0
169
+ Cherry Servers: configured
170
+ Vercel Domains: configured
171
+ ```
172
+
173
+ ## Links
174
+
175
+ - [Platform](https://app.otonix.tech)
176
+ - [Website](https://otonix.tech)
177
+ - [SDK](https://www.npmjs.com/package/@otonix/sdk)
178
+ - [GitHub](https://github.com/otonix-ai)
179
+
180
+ ## License
181
+
182
+ MIT
package/dist/cli.js ADDED
@@ -0,0 +1,539 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") {
11
+ for (let key of __getOwnPropNames(from))
12
+ if (!__hasOwnProp.call(to, key) && key !== except)
13
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
14
+ }
15
+ return to;
16
+ };
17
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
18
+ // If the importer is in node compatibility mode or this is not an ESM
19
+ // file that has been converted to a CommonJS file using a Babel-
20
+ // compatible transform (i.e. "__esModule" has not been set), then set
21
+ // "default" to the CommonJS "module.exports" for node compatibility.
22
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
23
+ mod
24
+ ));
25
+
26
+ // src/cli.ts
27
+ var import_sdk = require("@otonix/sdk");
28
+ var fs = __toESM(require("fs"));
29
+ var path = __toESM(require("path"));
30
+ var readline = __toESM(require("readline"));
31
+ var VERSION = "1.0.0";
32
+ var CONFIG_DIR = path.join(process.env.HOME || "~", ".otonix");
33
+ var CONFIG_FILE = path.join(CONFIG_DIR, "config.json");
34
+ function loadConfig() {
35
+ try {
36
+ if (fs.existsSync(CONFIG_FILE)) {
37
+ return JSON.parse(fs.readFileSync(CONFIG_FILE, "utf-8"));
38
+ }
39
+ } catch {
40
+ }
41
+ return null;
42
+ }
43
+ function saveConfig(config) {
44
+ if (!fs.existsSync(CONFIG_DIR)) {
45
+ fs.mkdirSync(CONFIG_DIR, { recursive: true });
46
+ }
47
+ fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));
48
+ fs.chmodSync(CONFIG_FILE, 384);
49
+ }
50
+ function getClient() {
51
+ const config = loadConfig();
52
+ if (!config) {
53
+ console.error("Error: Not configured. Run 'otonix init' first.");
54
+ process.exit(1);
55
+ }
56
+ return new import_sdk.OtonixClient({ apiKey: config.apiKey, endpoint: config.endpoint });
57
+ }
58
+ function prompt(question) {
59
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
60
+ return new Promise((resolve) => {
61
+ rl.question(question, (answer) => {
62
+ rl.close();
63
+ resolve(answer.trim());
64
+ });
65
+ });
66
+ }
67
+ function printTable(rows) {
68
+ if (!rows.length) return;
69
+ const keys = Object.keys(rows[0]);
70
+ const widths = keys.map(
71
+ (k) => Math.max(k.length, ...rows.map((r) => String(r[k] ?? "\u2014").length))
72
+ );
73
+ const header = keys.map((k, i) => k.padEnd(widths[i])).join(" ");
74
+ const sep = widths.map((w) => "\u2500".repeat(w)).join("\u2500\u2500");
75
+ console.log(` ${header}`);
76
+ console.log(` ${sep}`);
77
+ rows.forEach((row) => {
78
+ const line = keys.map((k, i) => String(row[k] ?? "\u2014").padEnd(widths[i])).join(" ");
79
+ console.log(` ${line}`);
80
+ });
81
+ }
82
+ function formatTime(dateStr) {
83
+ if (!dateStr) return "\u2014";
84
+ const ago = Math.floor((Date.now() - new Date(dateStr).getTime()) / 1e3);
85
+ if (ago < 60) return `${ago}s ago`;
86
+ if (ago < 3600) return `${Math.floor(ago / 60)}m ago`;
87
+ if (ago < 86400) return `${Math.floor(ago / 3600)}h ago`;
88
+ return `${Math.floor(ago / 86400)}d ago`;
89
+ }
90
+ var HELP = `
91
+ otonix \u2014 CLI for the Otonix sovereign compute platform
92
+
93
+ Usage:
94
+ otonix <command> [options]
95
+
96
+ Commands:
97
+ init Configure API key and endpoint
98
+ keygen <name> Generate a new API key
99
+ register Register an agent on this VPS
100
+ heartbeat Send a heartbeat ping
101
+ heartbeat:loop Start continuous heartbeat loop
102
+ status Show agent status
103
+ agents List all connected agents
104
+ actions [--limit N] Show agent action log
105
+ log <message> Log an agent action
106
+ domains List registered domains
107
+ sandboxes List VPS sandboxes
108
+ engine Show autonomic engine status
109
+ x402 Show x402 payment config
110
+ whoami Show current configuration
111
+ version Show CLI version
112
+ help Show this help
113
+
114
+ Examples:
115
+ otonix init
116
+ otonix keygen my-vps-key
117
+ otonix register --name my-agent --model claude-opus-4-6
118
+ otonix heartbeat:loop
119
+ otonix log "Trade executed BTC/USDC" --category trading
120
+ otonix actions --limit 20
121
+ `;
122
+ async function cmdInit() {
123
+ console.log("\n Otonix CLI Setup\n");
124
+ const endpoint = await prompt(" Endpoint [https://app.otonix.tech]: ") || "https://app.otonix.tech";
125
+ const apiKey = await prompt(" API Key (otonix_xxx): ");
126
+ if (!apiKey.startsWith("otonix_")) {
127
+ console.error(" Error: API key must start with 'otonix_'");
128
+ process.exit(1);
129
+ }
130
+ const client = new import_sdk.OtonixClient({ apiKey, endpoint });
131
+ try {
132
+ const auth = await client.getAuthStatus();
133
+ if (!auth.authenticated) {
134
+ console.error(" Error: Invalid API key \u2014 authentication failed.");
135
+ process.exit(1);
136
+ }
137
+ } catch (err) {
138
+ console.error(` Error: Could not connect \u2014 ${err.message}`);
139
+ process.exit(1);
140
+ }
141
+ saveConfig({ apiKey, endpoint });
142
+ console.log(`
143
+ Config saved to ${CONFIG_FILE}`);
144
+ console.log(" Authenticated successfully.\n");
145
+ }
146
+ async function cmdKeygen(name) {
147
+ if (!name) {
148
+ console.error(" Usage: otonix keygen <name>");
149
+ process.exit(1);
150
+ }
151
+ const config = loadConfig();
152
+ const endpoint = config?.endpoint || "https://app.otonix.tech";
153
+ const dashToken = await prompt(" Dashboard Token (SESSION_SECRET): ");
154
+ const res = await fetch(`${endpoint}/api/keys/generate`, {
155
+ method: "POST",
156
+ headers: {
157
+ "Content-Type": "application/json",
158
+ "X-Dashboard-Token": dashToken
159
+ },
160
+ body: JSON.stringify({ name })
161
+ });
162
+ if (!res.ok) {
163
+ const err = await res.json().catch(() => ({ error: "Unknown error" }));
164
+ console.error(` Error: ${err.error || err.message || "Failed to generate key"}`);
165
+ process.exit(1);
166
+ }
167
+ const key = await res.json();
168
+ console.log(`
169
+ API Key Generated:`);
170
+ console.log(` Name: ${key.name}`);
171
+ console.log(` Key: ${key.key}`);
172
+ console.log(` Status: ${key.status}`);
173
+ console.log(`
174
+ Save this key \u2014 it cannot be retrieved again.
175
+ `);
176
+ }
177
+ async function cmdRegister(args) {
178
+ const client = getClient();
179
+ const config = loadConfig();
180
+ let name = "";
181
+ let model = "claude-opus-4-6";
182
+ let wallet = "";
183
+ let interval = 60;
184
+ for (let i = 0; i < args.length; i++) {
185
+ if (args[i] === "--name" && args[i + 1]) name = args[++i];
186
+ else if (args[i] === "--model" && args[i + 1]) model = args[++i];
187
+ else if (args[i] === "--wallet" && args[i + 1]) wallet = args[++i];
188
+ else if (args[i] === "--interval" && args[i + 1]) interval = parseInt(args[++i]);
189
+ }
190
+ if (!name) name = await prompt(" Agent name: ");
191
+ if (!name) {
192
+ console.error(" Error: name is required");
193
+ process.exit(1);
194
+ }
195
+ const ip = await getVpsIp();
196
+ try {
197
+ const agent = await client.register({
198
+ name,
199
+ model,
200
+ vpsIp: ip,
201
+ walletAddress: wallet || void 0,
202
+ heartbeatInterval: interval
203
+ });
204
+ saveConfig({ ...config, agentId: agent.id, agentName: agent.name });
205
+ console.log(`
206
+ Agent Registered:`);
207
+ console.log(` ID: ${agent.id}`);
208
+ console.log(` Name: ${agent.name}`);
209
+ console.log(` Model: ${agent.model}`);
210
+ console.log(` VPS IP: ${agent.vpsIp}`);
211
+ console.log(` Tier: ${agent.survivalTier}`);
212
+ console.log(` Interval: ${agent.heartbeatInterval}s
213
+ `);
214
+ } catch (err) {
215
+ console.error(` Error: ${err.message}`);
216
+ process.exit(1);
217
+ }
218
+ }
219
+ async function getVpsIp() {
220
+ try {
221
+ const res = await fetch("https://api.ipify.org?format=json", { signal: AbortSignal.timeout(5e3) });
222
+ const data = await res.json();
223
+ return data.ip;
224
+ } catch {
225
+ return "0.0.0.0";
226
+ }
227
+ }
228
+ async function cmdHeartbeat() {
229
+ const client = getClient();
230
+ const config = loadConfig();
231
+ if (!config.agentId) {
232
+ console.error(" Error: No agent registered. Run 'otonix register' first.");
233
+ process.exit(1);
234
+ }
235
+ try {
236
+ const agent = await client.heartbeat(config.agentId);
237
+ console.log(` Heartbeat sent \u2014 ${agent.name} [${agent.status}] tier:${agent.survivalTier} credits:$${agent.credits.toFixed(2)}`);
238
+ } catch (err) {
239
+ console.error(` Heartbeat failed: ${err.message}`);
240
+ process.exit(1);
241
+ }
242
+ }
243
+ async function cmdHeartbeatLoop() {
244
+ const client = getClient();
245
+ const config = loadConfig();
246
+ if (!config.agentId) {
247
+ console.error(" Error: No agent registered. Run 'otonix register' first.");
248
+ process.exit(1);
249
+ }
250
+ const agent = await client.getAgent(config.agentId);
251
+ const interval = agent.heartbeatInterval || 60;
252
+ console.log(` Starting heartbeat loop for ${agent.name} (every ${interval}s)`);
253
+ console.log(" Press Ctrl+C to stop.\n");
254
+ const hb = client.createHeartbeatLoop(config.agentId, interval);
255
+ process.on("SIGINT", () => {
256
+ hb.stop();
257
+ console.log("\n Heartbeat stopped.");
258
+ process.exit(0);
259
+ });
260
+ setInterval(() => {
261
+ }, 1e3);
262
+ }
263
+ async function cmdStatus() {
264
+ const client = getClient();
265
+ const config = loadConfig();
266
+ if (!config.agentId) {
267
+ console.error(" Error: No agent registered. Run 'otonix register' first.");
268
+ process.exit(1);
269
+ }
270
+ try {
271
+ const agent = await client.getAgent(config.agentId);
272
+ console.log(`
273
+ Agent Status:`);
274
+ console.log(` ID: ${agent.id}`);
275
+ console.log(` Name: ${agent.name}`);
276
+ console.log(` Status: ${agent.status}`);
277
+ console.log(` Tier: ${agent.survivalTier}`);
278
+ console.log(` Credits: $${agent.credits.toFixed(2)}`);
279
+ console.log(` Model: ${agent.model}`);
280
+ console.log(` VPS IP: ${agent.vpsIp || "\u2014"}`);
281
+ console.log(` Wallet: ${agent.walletAddress || "\u2014"}`);
282
+ console.log(` Heartbeat: ${formatTime(agent.lastHeartbeat)}`);
283
+ console.log(` Interval: ${agent.heartbeatInterval}s`);
284
+ console.log(` Actions: ${agent.totalActions}`);
285
+ console.log(` Replicas: ${agent.childrenCount}`);
286
+ console.log(` Registered: ${new Date(agent.createdAt).toLocaleString()}
287
+ `);
288
+ } catch (err) {
289
+ console.error(` Error: ${err.message}`);
290
+ process.exit(1);
291
+ }
292
+ }
293
+ async function cmdAgents() {
294
+ const client = getClient();
295
+ const agents = await client.listAgents();
296
+ if (!agents.length) {
297
+ console.log(" No agents connected.");
298
+ return;
299
+ }
300
+ console.log(`
301
+ Connected Agents (${agents.length}):
302
+ `);
303
+ printTable(agents.map((a) => ({
304
+ ID: a.id.slice(0, 8),
305
+ Name: a.name,
306
+ Status: a.status,
307
+ Tier: a.survivalTier,
308
+ Credits: `$${a.credits.toFixed(2)}`,
309
+ Heartbeat: formatTime(a.lastHeartbeat),
310
+ Actions: a.totalActions
311
+ })));
312
+ console.log();
313
+ }
314
+ async function cmdActions(args) {
315
+ const client = getClient();
316
+ const config = loadConfig();
317
+ if (!config.agentId) {
318
+ console.error(" Error: No agent registered. Run 'otonix register' first.");
319
+ process.exit(1);
320
+ }
321
+ let limit = 20;
322
+ for (let i = 0; i < args.length; i++) {
323
+ if (args[i] === "--limit" && args[i + 1]) limit = parseInt(args[++i]);
324
+ }
325
+ const actions = await client.getAgentActions(config.agentId);
326
+ const display = actions.slice(0, limit);
327
+ if (!display.length) {
328
+ console.log(" No actions recorded.");
329
+ return;
330
+ }
331
+ console.log(`
332
+ Agent Actions (${display.length} of ${actions.length}):
333
+ `);
334
+ printTable(display.map((a) => ({
335
+ Time: formatTime(a.createdAt),
336
+ Category: a.category,
337
+ Action: a.action.length > 50 ? a.action.slice(0, 47) + "..." : a.action,
338
+ Status: a.status,
339
+ Auto: a.autonomous ? "yes" : "no"
340
+ })));
341
+ console.log();
342
+ }
343
+ async function cmdLog(args) {
344
+ const client = getClient();
345
+ const config = loadConfig();
346
+ if (!config.agentId) {
347
+ console.error(" Error: No agent registered. Run 'otonix register' first.");
348
+ process.exit(1);
349
+ }
350
+ let message = "";
351
+ let category = "system";
352
+ let details = "";
353
+ const positional = [];
354
+ for (let i = 0; i < args.length; i++) {
355
+ if (args[i] === "--category" && args[i + 1]) category = args[++i];
356
+ else if (args[i] === "--details" && args[i + 1]) details = args[++i];
357
+ else positional.push(args[i]);
358
+ }
359
+ message = positional.join(" ");
360
+ if (!message) {
361
+ console.error(' Usage: otonix log "message" [--category system] [--details "..."]');
362
+ process.exit(1);
363
+ }
364
+ try {
365
+ const action = await client.logAction(config.agentId, {
366
+ action: message,
367
+ category,
368
+ details: details || void 0
369
+ });
370
+ console.log(` Logged: [${action.category}] ${action.action} (${action.status})`);
371
+ } catch (err) {
372
+ console.error(` Error: ${err.message}`);
373
+ process.exit(1);
374
+ }
375
+ }
376
+ async function cmdDomains() {
377
+ const client = getClient();
378
+ const domains = await client.listDomains();
379
+ if (!domains.length) {
380
+ console.log(" No domains registered.");
381
+ return;
382
+ }
383
+ console.log(`
384
+ Registered Domains (${domains.length}):
385
+ `);
386
+ printTable(domains.map((d) => ({
387
+ Name: d.name,
388
+ Status: d.status,
389
+ AutoRenew: d.autoRenew ? "yes" : "no",
390
+ Expires: d.expiresAt ? new Date(d.expiresAt).toLocaleDateString() : "\u2014",
391
+ DNS: d.dnsRecords?.length || 0,
392
+ Agent: d.agentId?.slice(0, 8) || "\u2014"
393
+ })));
394
+ console.log();
395
+ }
396
+ async function cmdSandboxes() {
397
+ const client = getClient();
398
+ const sandboxes = await client.listSandboxes();
399
+ if (!sandboxes.length) {
400
+ console.log(" No sandboxes provisioned.");
401
+ return;
402
+ }
403
+ console.log(`
404
+ VPS Sandboxes (${sandboxes.length}):
405
+ `);
406
+ printTable(sandboxes.map((s) => ({
407
+ ID: s.id.slice(0, 8),
408
+ Name: s.name,
409
+ Status: s.status,
410
+ OS: s.os,
411
+ CPU: `${s.cpu} vCPU`,
412
+ RAM: `${s.memory}MB`,
413
+ Region: s.region,
414
+ IP: s.ipAddress || "\u2014"
415
+ })));
416
+ console.log();
417
+ }
418
+ async function cmdEngine() {
419
+ const client = getClient();
420
+ const status = await client.getAutonomicStatus();
421
+ console.log(`
422
+ Autonomic Engine Status:`);
423
+ console.log(` Running: ${status.running ? "yes" : "no"}`);
424
+ console.log(` Last Cycle: ${formatTime(status.lastRunAt)}`);
425
+ console.log(` Cycle Interval: ${status.cycleIntervalSeconds}s`);
426
+ console.log(` Tier Updates: ${status.totalTierUpdates}`);
427
+ console.log(` Heal Attempts: ${status.totalHealingAttempts}`);
428
+ console.log(` Heal Success: ${status.totalHealingSuccesses}`);
429
+ console.log(` Renewals: ${status.totalRenewalSuccesses}/${status.totalRenewalAttempts}`);
430
+ console.log(` Cooldowns: ${status.activeCooldowns}`);
431
+ console.log(` Cherry Servers: ${status.cherryServersConfigured ? "configured" : "not configured"}`);
432
+ console.log(` Vercel Domains: ${status.vercelDomainsConfigured ? "configured" : "not configured"}`);
433
+ console.log(`
434
+ Tier Thresholds:`);
435
+ for (const [key, value] of Object.entries(status.tierThresholds)) {
436
+ console.log(` ${status.tierLabels[key] || key}: $${value}+`);
437
+ }
438
+ console.log();
439
+ }
440
+ async function cmdX402() {
441
+ const client = getClient();
442
+ const config = await client.getX402Config();
443
+ console.log(`
444
+ x402 Payment Config:`);
445
+ console.log(` Treasury: ${config.treasuryAddress}`);
446
+ console.log(` USDC: ${config.usdcContract}`);
447
+ console.log(` Chain ID: ${config.chainId}`);
448
+ console.log(` Network: ${config.network}`);
449
+ console.log(` Facilitator: ${config.facilitatorUrl}
450
+ `);
451
+ }
452
+ function cmdWhoami() {
453
+ const config = loadConfig();
454
+ if (!config) {
455
+ console.log(" Not configured. Run 'otonix init' first.");
456
+ return;
457
+ }
458
+ console.log(`
459
+ Current Config:`);
460
+ console.log(` Endpoint: ${config.endpoint}`);
461
+ console.log(` API Key: ${config.apiKey.slice(0, 12)}...${config.apiKey.slice(-4)}`);
462
+ console.log(` Agent ID: ${config.agentId || "not registered"}`);
463
+ console.log(` Agent: ${config.agentName || "\u2014"}`);
464
+ console.log(` Config: ${CONFIG_FILE}
465
+ `);
466
+ }
467
+ async function main() {
468
+ const args = process.argv.slice(2);
469
+ const command = args[0] || "help";
470
+ const rest = args.slice(1);
471
+ try {
472
+ switch (command) {
473
+ case "init":
474
+ await cmdInit();
475
+ break;
476
+ case "keygen":
477
+ await cmdKeygen(rest[0]);
478
+ break;
479
+ case "register":
480
+ await cmdRegister(rest);
481
+ break;
482
+ case "heartbeat":
483
+ await cmdHeartbeat();
484
+ break;
485
+ case "heartbeat:loop":
486
+ await cmdHeartbeatLoop();
487
+ break;
488
+ case "status":
489
+ await cmdStatus();
490
+ break;
491
+ case "agents":
492
+ await cmdAgents();
493
+ break;
494
+ case "actions":
495
+ await cmdActions(rest);
496
+ break;
497
+ case "log":
498
+ await cmdLog(rest);
499
+ break;
500
+ case "domains":
501
+ await cmdDomains();
502
+ break;
503
+ case "sandboxes":
504
+ await cmdSandboxes();
505
+ break;
506
+ case "engine":
507
+ await cmdEngine();
508
+ break;
509
+ case "x402":
510
+ await cmdX402();
511
+ break;
512
+ case "whoami":
513
+ cmdWhoami();
514
+ break;
515
+ case "version":
516
+ case "-v":
517
+ case "--version":
518
+ console.log(` otonix v${VERSION}`);
519
+ break;
520
+ case "help":
521
+ case "-h":
522
+ case "--help":
523
+ console.log(HELP);
524
+ break;
525
+ default:
526
+ console.error(` Unknown command: ${command}`);
527
+ console.log(HELP);
528
+ process.exit(1);
529
+ }
530
+ } catch (err) {
531
+ if (err instanceof import_sdk.OtonixError) {
532
+ console.error(` API Error (${err.status}): ${err.message}`);
533
+ } else {
534
+ console.error(` Error: ${err.message}`);
535
+ }
536
+ process.exit(1);
537
+ }
538
+ }
539
+ main();
package/package.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "@otonix/cli",
3
+ "version": "1.0.0",
4
+ "description": "CLI tool for the Otonix sovereign compute platform — initialize agents, generate API keys, register, monitor status, and manage infrastructure from the terminal.",
5
+ "main": "dist/cli.js",
6
+ "bin": {
7
+ "otonix": "dist/cli.js"
8
+ },
9
+ "files": [
10
+ "dist",
11
+ "README.md"
12
+ ],
13
+ "scripts": {
14
+ "build": "tsup src/cli.ts --format cjs --clean",
15
+ "dev": "tsup src/cli.ts --format cjs --watch",
16
+ "prepublishOnly": "echo 'already built'"
17
+ },
18
+ "keywords": [
19
+ "otonix",
20
+ "cli",
21
+ "autonomous-agents",
22
+ "web4",
23
+ "x402",
24
+ "sovereign-compute",
25
+ "ai-agents"
26
+ ],
27
+ "author": "Otonix <dev@otonix.tech>",
28
+ "license": "MIT",
29
+ "homepage": "https://github.com/otonix-ai/cli",
30
+ "repository": {
31
+ "type": "git",
32
+ "url": "https://github.com/otonix-ai/cli.git"
33
+ },
34
+ "bugs": {
35
+ "url": "https://github.com/otonix-ai/cli/issues"
36
+ },
37
+ "engines": {
38
+ "node": ">=18"
39
+ },
40
+ "dependencies": {
41
+ "@otonix/sdk": "^1.0.0"
42
+ },
43
+ "devDependencies": {
44
+ "tsup": "^8.0.0",
45
+ "typescript": "^5.0.0"
46
+ }
47
+ }