@cloudverse/aix-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.
- package/README.md +91 -0
- package/dist/formatters.d.ts +5 -0
- package/dist/formatters.js +164 -0
- package/dist/http.d.ts +12 -0
- package/dist/http.js +37 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +144 -0
- package/package.json +40 -0
package/README.md
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# AIX CLI
|
|
2
|
+
|
|
3
|
+
Command-line interface for the AIX Brain Decision Engine. Decision-only surface — no gateway behavior, no prompt proxying.
|
|
4
|
+
|
|
5
|
+
## Setup
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
# From repo root
|
|
9
|
+
cd packages/aix-cli
|
|
10
|
+
|
|
11
|
+
# Set environment
|
|
12
|
+
export AIX_API_URL=http://localhost:5000 # or https://aix.cloudverse.ai
|
|
13
|
+
export AIX_TOKEN=your_api_key_here # AIX API key or legacy key
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Commands
|
|
17
|
+
|
|
18
|
+
### `aix decide`
|
|
19
|
+
|
|
20
|
+
Request a routing decision from the AIX Brain.
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
# Basic decision
|
|
24
|
+
npx tsx src/index.ts decide --execution-class conversation
|
|
25
|
+
|
|
26
|
+
# With priority and constraints
|
|
27
|
+
npx tsx src/index.ts decide \
|
|
28
|
+
--execution-class code_generation \
|
|
29
|
+
--priority quality \
|
|
30
|
+
--max-cost-usd 0.05 \
|
|
31
|
+
--max-latency-ms 3000
|
|
32
|
+
|
|
33
|
+
# With token estimates for cost simulation
|
|
34
|
+
npx tsx src/index.ts decide \
|
|
35
|
+
--execution-class conversation \
|
|
36
|
+
--input-tokens 1000 \
|
|
37
|
+
--output-tokens 500
|
|
38
|
+
|
|
39
|
+
# JSON output
|
|
40
|
+
npx tsx src/index.ts decide --execution-class conversation --format json
|
|
41
|
+
|
|
42
|
+
# From intent JSON file
|
|
43
|
+
npx tsx src/index.ts decide --intent-json ./my-request.json
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### `aix explain <decision_id>`
|
|
47
|
+
|
|
48
|
+
Get explanation and trace for a past decision.
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
npx tsx src/index.ts explain dec_abc123
|
|
52
|
+
npx tsx src/index.ts explain dec_abc123 --format json
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### `aix health`
|
|
56
|
+
|
|
57
|
+
Check AIX Brain health and coverage.
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
npx tsx src/index.ts health
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### `aix policy show`
|
|
64
|
+
|
|
65
|
+
Show current org routing policy.
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
npx tsx src/index.ts policy show
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### `aix catalog status`
|
|
72
|
+
|
|
73
|
+
Show catalog status and coverage.
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
npx tsx src/index.ts catalog status
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Environment Variables
|
|
80
|
+
|
|
81
|
+
| Variable | Required | Default | Description |
|
|
82
|
+
|----------|----------|---------|-------------|
|
|
83
|
+
| `AIX_API_URL` | No | `http://localhost:5000` | AIX server base URL |
|
|
84
|
+
| `AIX_TOKEN` | Yes* | — | API key for authentication |
|
|
85
|
+
|
|
86
|
+
*Not required if server allows unauthenticated access in local dev mode.
|
|
87
|
+
|
|
88
|
+
## Output Formats
|
|
89
|
+
|
|
90
|
+
- `--format pretty` (default): Human-readable with color coding
|
|
91
|
+
- `--format json`: Raw JSON for piping to other tools
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export declare function formatDecision(d: any): void;
|
|
2
|
+
export declare function formatExplanation(d: any): void;
|
|
3
|
+
export declare function formatHealth(h: any): void;
|
|
4
|
+
export declare function formatPolicy(p: any): void;
|
|
5
|
+
export declare function formatCatalogStatus(c: any): void;
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
const GREEN = '\x1b[32m';
|
|
2
|
+
const YELLOW = '\x1b[33m';
|
|
3
|
+
const RED = '\x1b[31m';
|
|
4
|
+
const CYAN = '\x1b[36m';
|
|
5
|
+
const DIM = '\x1b[2m';
|
|
6
|
+
const BOLD = '\x1b[1m';
|
|
7
|
+
const RESET = '\x1b[0m';
|
|
8
|
+
function check(ok) {
|
|
9
|
+
return ok ? `${GREEN}OK${RESET}` : `${YELLOW}WARN${RESET}`;
|
|
10
|
+
}
|
|
11
|
+
function statusIcon(status) {
|
|
12
|
+
if (status === 'ok' || status === 'healthy')
|
|
13
|
+
return `${GREEN}OK${RESET}`;
|
|
14
|
+
if (status === 'degraded')
|
|
15
|
+
return `${YELLOW}DEGRADED${RESET}`;
|
|
16
|
+
return `${RED}FAILED${RESET}`;
|
|
17
|
+
}
|
|
18
|
+
export function formatDecision(d) {
|
|
19
|
+
console.log(`\n${BOLD}AIX Brain Decision${RESET}`);
|
|
20
|
+
console.log(`${'─'.repeat(50)}`);
|
|
21
|
+
console.log(` Status: ${statusIcon(d.decision_status)} ${d.degraded_reason || d.degradation_reason || ''}`);
|
|
22
|
+
console.log(` Provider: ${CYAN}${d.provider}${RESET}`);
|
|
23
|
+
console.log(` Model: ${CYAN}${d.model_name || d.model_class}${RESET}`);
|
|
24
|
+
console.log(` Class: ${d.model_class}`);
|
|
25
|
+
console.log(` Confidence: ${d.confidence?.toFixed(2) || 'N/A'}`);
|
|
26
|
+
console.log(` Data Used: ${d.data_used}`);
|
|
27
|
+
console.log(` Decision: ${DIM}${d.decision_id}${RESET}`);
|
|
28
|
+
if (d.reason) {
|
|
29
|
+
console.log(`\n ${DIM}Reason: ${d.reason}${RESET}`);
|
|
30
|
+
}
|
|
31
|
+
if (d.explanation) {
|
|
32
|
+
console.log(` ${DIM}Explanation: ${d.explanation}${RESET}`);
|
|
33
|
+
}
|
|
34
|
+
if (d.score_breakdown) {
|
|
35
|
+
console.log(`\n ${BOLD}Score Breakdown${RESET}`);
|
|
36
|
+
const sb = d.score_breakdown;
|
|
37
|
+
console.log(` Cost: ${sb.cost?.toFixed(3) || '-'}`);
|
|
38
|
+
console.log(` Latency: ${sb.latency?.toFixed(3) || '-'}`);
|
|
39
|
+
console.log(` QSR: ${sb.qsr?.toFixed(3) || '-'}`);
|
|
40
|
+
console.log(` Reliability: ${sb.reliability?.toFixed(3) || '-'}`);
|
|
41
|
+
console.log(` Total: ${BOLD}${sb.total?.toFixed(3) || '-'}${RESET}`);
|
|
42
|
+
if (sb.cost_source) {
|
|
43
|
+
console.log(` Cost Source: ${sb.cost_source}`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
if (d.alternatives && d.alternatives.length > 0) {
|
|
47
|
+
console.log(`\n ${BOLD}Top Alternatives${RESET}`);
|
|
48
|
+
d.alternatives.slice(0, 3).forEach((alt, i) => {
|
|
49
|
+
console.log(` ${i + 1}. ${alt.provider}/${alt.model_name || alt.model_class} (score: ${alt.score?.toFixed(3)}, data: ${alt.data_used})`);
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
console.log('');
|
|
53
|
+
}
|
|
54
|
+
export function formatExplanation(d) {
|
|
55
|
+
console.log(`\n${BOLD}Decision Explanation${RESET}`);
|
|
56
|
+
console.log(`${'─'.repeat(50)}`);
|
|
57
|
+
console.log(` Decision ID: ${d.id || d.decision_id}`);
|
|
58
|
+
console.log(` Execution Class: ${d.execution_class}`);
|
|
59
|
+
console.log(` Provider: ${CYAN}${d.provider}${RESET}`);
|
|
60
|
+
console.log(` Model: ${CYAN}${d.model_name || d.model_class}${RESET}`);
|
|
61
|
+
console.log(` Confidence: ${d.confidence?.toFixed?.(2) || d.confidence || 'N/A'}`);
|
|
62
|
+
console.log(` Data Used: ${d.data_used}`);
|
|
63
|
+
console.log(` Created: ${d.created_at || 'N/A'}`);
|
|
64
|
+
if (d.reason) {
|
|
65
|
+
console.log(`\n ${BOLD}Reason${RESET}`);
|
|
66
|
+
console.log(` ${d.reason}`);
|
|
67
|
+
}
|
|
68
|
+
if (d.score_breakdown) {
|
|
69
|
+
console.log(`\n ${BOLD}Score Breakdown${RESET}`);
|
|
70
|
+
console.log(` ${JSON.stringify(d.score_breakdown, null, 4).split('\n').join('\n ')}`);
|
|
71
|
+
}
|
|
72
|
+
console.log('');
|
|
73
|
+
}
|
|
74
|
+
export function formatHealth(h) {
|
|
75
|
+
console.log(`\n${BOLD}AIX Brain Health${RESET}`);
|
|
76
|
+
console.log(`${'─'.repeat(50)}`);
|
|
77
|
+
console.log(` Overall: ${statusIcon(h.status)}`);
|
|
78
|
+
if (h.execution_class_coverage) {
|
|
79
|
+
const ec = h.execution_class_coverage;
|
|
80
|
+
console.log(`\n ${BOLD}Execution Class Coverage${RESET}`);
|
|
81
|
+
console.log(` Total classes: ${ec.total}`);
|
|
82
|
+
console.log(` With capabilities: ${ec.with_capability_rows} ${check(ec.with_capability_rows > 0)}`);
|
|
83
|
+
if (ec.details && ec.details.length > 0) {
|
|
84
|
+
ec.details.forEach((d) => {
|
|
85
|
+
const icon = d.supported_rows > 0 ? `${GREEN}OK${RESET}` : `${RED}--${RESET}`;
|
|
86
|
+
console.log(` ${icon} ${d.name} (${d.supported_rows} providers)`);
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
if (h.routable_models) {
|
|
91
|
+
console.log(`\n ${BOLD}Routable Models${RESET}`);
|
|
92
|
+
console.log(` Active: ${h.routable_models.total} ${check(h.routable_models.total > 0)}`);
|
|
93
|
+
}
|
|
94
|
+
if (h.provider_defaults) {
|
|
95
|
+
console.log(`\n ${BOLD}Provider Defaults${RESET}`);
|
|
96
|
+
console.log(` Count: ${h.provider_defaults.count}`);
|
|
97
|
+
console.log(` Coverage: ${check(h.provider_defaults.coverage === 'ok')}`);
|
|
98
|
+
console.log(` Safe Fallback: ${check(h.provider_defaults.safe_fallback === 'ok')}`);
|
|
99
|
+
}
|
|
100
|
+
if (h.pricing) {
|
|
101
|
+
console.log(`\n ${BOLD}Pricing${RESET}`);
|
|
102
|
+
console.log(` Coverage: ${h.pricing.coverage}`);
|
|
103
|
+
console.log(` Last Sync: ${h.pricing.last_sync || 'never'}`);
|
|
104
|
+
}
|
|
105
|
+
console.log(`\n Discovered Models: ${h.discovered_models || 0}`);
|
|
106
|
+
console.log('');
|
|
107
|
+
}
|
|
108
|
+
export function formatPolicy(p) {
|
|
109
|
+
console.log(`\n${BOLD}AIX Brain Routing Policy${RESET}`);
|
|
110
|
+
console.log(`${'─'.repeat(50)}`);
|
|
111
|
+
console.log(` Org: ${p.org_id}`);
|
|
112
|
+
console.log(` Source: ${p.source}`);
|
|
113
|
+
if (p.policy) {
|
|
114
|
+
const pol = p.policy;
|
|
115
|
+
if (pol.allowed_providers && pol.allowed_providers.length > 0) {
|
|
116
|
+
console.log(`\n ${BOLD}Allowed Providers${RESET}`);
|
|
117
|
+
pol.allowed_providers.forEach((prov) => {
|
|
118
|
+
console.log(` - ${prov}`);
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
122
|
+
console.log(`\n Allowed Providers: ${DIM}all (no restrictions)${RESET}`);
|
|
123
|
+
}
|
|
124
|
+
if (pol.default_priority) {
|
|
125
|
+
console.log(` Default Priority: ${pol.default_priority}`);
|
|
126
|
+
}
|
|
127
|
+
if (pol.mode) {
|
|
128
|
+
console.log(` Routing Mode: ${pol.mode}`);
|
|
129
|
+
}
|
|
130
|
+
if (pol.budget_guard) {
|
|
131
|
+
console.log(`\n ${BOLD}Budget Guard${RESET}`);
|
|
132
|
+
console.log(` ${JSON.stringify(pol.budget_guard, null, 4).split('\n').join('\n ')}`);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
console.log(`\n Connected Providers: ${p.connected_providers_count}`);
|
|
136
|
+
if (p.connected_providers && p.connected_providers.length > 0) {
|
|
137
|
+
p.connected_providers.forEach((prov) => {
|
|
138
|
+
console.log(` - ${prov}`);
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
console.log('');
|
|
142
|
+
}
|
|
143
|
+
export function formatCatalogStatus(c) {
|
|
144
|
+
console.log(`\n${BOLD}AIX Brain Catalog Status${RESET}`);
|
|
145
|
+
console.log(`${'─'.repeat(50)}`);
|
|
146
|
+
console.log(` Discovered Models: ${c.discovered_model_count}`);
|
|
147
|
+
console.log(` Routable Models: ${c.routable_model_count}`);
|
|
148
|
+
console.log(` Provider Defaults: ${c.defaults_count}`);
|
|
149
|
+
if (c.activation_gates) {
|
|
150
|
+
const ag = c.activation_gates;
|
|
151
|
+
console.log(`\n ${BOLD}Activation Gates${RESET}`);
|
|
152
|
+
console.log(` Pricing Coverage: ${check(ag.has_pricing_coverage)}`);
|
|
153
|
+
console.log(` Capability Rows: ${check(ag.has_capability_rows)}`);
|
|
154
|
+
console.log(` Execution Classes: ${ag.execution_classes_with_coverage}/${ag.execution_classes_total} with coverage`);
|
|
155
|
+
}
|
|
156
|
+
if (c.pricing) {
|
|
157
|
+
console.log(`\n ${BOLD}Pricing Catalog${RESET}`);
|
|
158
|
+
console.log(` LLM Models: ${c.pricing.llm_models}`);
|
|
159
|
+
console.log(` GPU SKUs: ${c.pricing.gpu_skus}`);
|
|
160
|
+
console.log(` Providers: ${c.pricing.providers}`);
|
|
161
|
+
console.log(` Last Sync: ${c.pricing.last_sync_at || 'never'}`);
|
|
162
|
+
}
|
|
163
|
+
console.log('');
|
|
164
|
+
}
|
package/dist/http.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export interface HttpConfig {
|
|
2
|
+
baseUrl: string;
|
|
3
|
+
token: string | null;
|
|
4
|
+
}
|
|
5
|
+
export declare function getConfig(): HttpConfig;
|
|
6
|
+
export interface HttpResponse<T = any> {
|
|
7
|
+
ok: boolean;
|
|
8
|
+
status: number;
|
|
9
|
+
data: T;
|
|
10
|
+
}
|
|
11
|
+
export declare function request<T = any>(method: 'GET' | 'POST', path: string, body?: any): Promise<HttpResponse<T>>;
|
|
12
|
+
export declare function exitWithError(message: string, details?: string): never;
|
package/dist/http.js
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
const DEFAULT_BASE_URL = 'http://localhost:5000';
|
|
2
|
+
export function getConfig() {
|
|
3
|
+
return {
|
|
4
|
+
baseUrl: (process.env.AIX_API_URL || DEFAULT_BASE_URL).replace(/\/$/, ''),
|
|
5
|
+
token: process.env.AIX_TOKEN || null,
|
|
6
|
+
};
|
|
7
|
+
}
|
|
8
|
+
export async function request(method, path, body) {
|
|
9
|
+
const config = getConfig();
|
|
10
|
+
const url = `${config.baseUrl}${path}`;
|
|
11
|
+
const headers = {
|
|
12
|
+
'Content-Type': 'application/json',
|
|
13
|
+
'Accept': 'application/json',
|
|
14
|
+
};
|
|
15
|
+
if (config.token) {
|
|
16
|
+
headers['Authorization'] = `Bearer ${config.token}`;
|
|
17
|
+
}
|
|
18
|
+
const res = await fetch(url, {
|
|
19
|
+
method,
|
|
20
|
+
headers,
|
|
21
|
+
body: body ? JSON.stringify(body) : undefined,
|
|
22
|
+
});
|
|
23
|
+
let data;
|
|
24
|
+
try {
|
|
25
|
+
data = await res.json();
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
data = { error: `HTTP ${res.status}: ${res.statusText}` };
|
|
29
|
+
}
|
|
30
|
+
return { ok: res.ok, status: res.status, data };
|
|
31
|
+
}
|
|
32
|
+
export function exitWithError(message, details) {
|
|
33
|
+
console.error(`\x1b[31mError:\x1b[0m ${message}`);
|
|
34
|
+
if (details)
|
|
35
|
+
console.error(` ${details}`);
|
|
36
|
+
process.exit(1);
|
|
37
|
+
}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command } from 'commander';
|
|
3
|
+
import { request, exitWithError } from './http.js';
|
|
4
|
+
import { formatDecision, formatExplanation, formatHealth, formatPolicy, formatCatalogStatus } from './formatters.js';
|
|
5
|
+
const program = new Command();
|
|
6
|
+
program
|
|
7
|
+
.name('aix')
|
|
8
|
+
.description('AIX Brain Decision Engine CLI — decision-only surface')
|
|
9
|
+
.version('1.0.0');
|
|
10
|
+
program
|
|
11
|
+
.command('decide')
|
|
12
|
+
.description('Request a routing decision from the AIX Brain')
|
|
13
|
+
.requiredOption('--execution-class <string>', 'Execution class (e.g., conversation, code_generation)')
|
|
14
|
+
.option('--priority <string>', 'Scoring priority: cost | balanced | quality | latency', 'balanced')
|
|
15
|
+
.option('--allow-substitution <boolean>', 'Allow model substitution', 'true')
|
|
16
|
+
.option('--max-cost-usd <number>', 'Max cost constraint in USD')
|
|
17
|
+
.option('--max-latency-ms <number>', 'Max latency constraint in ms')
|
|
18
|
+
.option('--min-qsr <number>', 'Minimum quality score ratio')
|
|
19
|
+
.option('--compliance-tier <string>', 'Compliance tier (passed through)')
|
|
20
|
+
.option('--input-tokens <number>', 'Estimated input tokens for cost simulation')
|
|
21
|
+
.option('--output-tokens <number>', 'Estimated output tokens for cost simulation')
|
|
22
|
+
.option('--intent-json <path>', 'Path to JSON file with full request payload')
|
|
23
|
+
.option('--format <string>', 'Output format: pretty | json', 'pretty')
|
|
24
|
+
.action(async (opts) => {
|
|
25
|
+
let payload;
|
|
26
|
+
if (opts.intentJson) {
|
|
27
|
+
const fs = await import('fs');
|
|
28
|
+
try {
|
|
29
|
+
const raw = fs.readFileSync(opts.intentJson, 'utf-8');
|
|
30
|
+
payload = JSON.parse(raw);
|
|
31
|
+
}
|
|
32
|
+
catch (err) {
|
|
33
|
+
exitWithError(`Failed to read intent JSON file: ${opts.intentJson}`, err.message);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
payload = {
|
|
38
|
+
execution_class: opts.executionClass,
|
|
39
|
+
intent: {
|
|
40
|
+
priority: opts.priority,
|
|
41
|
+
constraints: {},
|
|
42
|
+
},
|
|
43
|
+
process_model: {
|
|
44
|
+
allow_model_substitution: opts.allowSubstitution === 'true',
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
if (opts.maxCostUsd)
|
|
48
|
+
payload.intent.constraints.max_cost_usd = parseFloat(opts.maxCostUsd);
|
|
49
|
+
if (opts.maxLatencyMs)
|
|
50
|
+
payload.intent.constraints.max_latency_ms = parseInt(opts.maxLatencyMs);
|
|
51
|
+
if (opts.minQsr)
|
|
52
|
+
payload.intent.constraints.min_qsr = parseFloat(opts.minQsr);
|
|
53
|
+
if (opts.complianceTier)
|
|
54
|
+
payload.compliance_tier = opts.complianceTier;
|
|
55
|
+
if (opts.inputTokens || opts.outputTokens) {
|
|
56
|
+
payload.token_estimates = {};
|
|
57
|
+
if (opts.inputTokens)
|
|
58
|
+
payload.token_estimates.input_tokens = parseInt(opts.inputTokens);
|
|
59
|
+
if (opts.outputTokens)
|
|
60
|
+
payload.token_estimates.output_tokens = parseInt(opts.outputTokens);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
const res = await request('POST', '/api/brain/decide', payload);
|
|
64
|
+
if (!res.ok) {
|
|
65
|
+
exitWithError(`Decision failed (HTTP ${res.status})`, JSON.stringify(res.data, null, 2));
|
|
66
|
+
}
|
|
67
|
+
if (opts.format === 'json') {
|
|
68
|
+
console.log(JSON.stringify(res.data, null, 2));
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
formatDecision(res.data);
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
program
|
|
75
|
+
.command('explain <decision_id>')
|
|
76
|
+
.description('Get explanation and trace for a past decision')
|
|
77
|
+
.option('--format <string>', 'Output format: pretty | json', 'pretty')
|
|
78
|
+
.action(async (decisionId, opts) => {
|
|
79
|
+
const res = await request('GET', `/api/brain/decisions/${decisionId}`);
|
|
80
|
+
if (!res.ok) {
|
|
81
|
+
exitWithError(`Failed to fetch decision (HTTP ${res.status})`, JSON.stringify(res.data, null, 2));
|
|
82
|
+
}
|
|
83
|
+
if (opts.format === 'json') {
|
|
84
|
+
console.log(JSON.stringify(res.data, null, 2));
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
formatExplanation(res.data);
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
program
|
|
91
|
+
.command('health')
|
|
92
|
+
.description('Check AIX Brain health and coverage')
|
|
93
|
+
.option('--format <string>', 'Output format: pretty | json', 'pretty')
|
|
94
|
+
.action(async (opts) => {
|
|
95
|
+
const res = await request('GET', '/api/brain/health');
|
|
96
|
+
if (!res.ok) {
|
|
97
|
+
exitWithError(`Health check failed (HTTP ${res.status})`, JSON.stringify(res.data, null, 2));
|
|
98
|
+
}
|
|
99
|
+
if (opts.format === 'json') {
|
|
100
|
+
console.log(JSON.stringify(res.data, null, 2));
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
formatHealth(res.data);
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
const policyCmd = program
|
|
107
|
+
.command('policy')
|
|
108
|
+
.description('Brain routing policy commands');
|
|
109
|
+
policyCmd
|
|
110
|
+
.command('show')
|
|
111
|
+
.description('Show current org routing policy')
|
|
112
|
+
.option('--format <string>', 'Output format: pretty | json', 'pretty')
|
|
113
|
+
.action(async (opts) => {
|
|
114
|
+
const res = await request('GET', '/api/brain/policy');
|
|
115
|
+
if (!res.ok) {
|
|
116
|
+
exitWithError(`Policy fetch failed (HTTP ${res.status})`, JSON.stringify(res.data, null, 2));
|
|
117
|
+
}
|
|
118
|
+
if (opts.format === 'json') {
|
|
119
|
+
console.log(JSON.stringify(res.data, null, 2));
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
122
|
+
formatPolicy(res.data);
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
const catalogCmd = program
|
|
126
|
+
.command('catalog')
|
|
127
|
+
.description('Brain catalog commands');
|
|
128
|
+
catalogCmd
|
|
129
|
+
.command('status')
|
|
130
|
+
.description('Show catalog status and coverage')
|
|
131
|
+
.option('--format <string>', 'Output format: pretty | json', 'pretty')
|
|
132
|
+
.action(async (opts) => {
|
|
133
|
+
const res = await request('GET', '/api/brain/catalog/status');
|
|
134
|
+
if (!res.ok) {
|
|
135
|
+
exitWithError(`Catalog status failed (HTTP ${res.status})`, JSON.stringify(res.data, null, 2));
|
|
136
|
+
}
|
|
137
|
+
if (opts.format === 'json') {
|
|
138
|
+
console.log(JSON.stringify(res.data, null, 2));
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
formatCatalogStatus(res.data);
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
program.parse();
|
package/package.json
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@cloudverse/aix-cli",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "AIX Brain Decision Engine CLI - decision-only surface for AI workload routing",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"aix": "./dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"main": "dist/index.js",
|
|
10
|
+
"files": [
|
|
11
|
+
"dist",
|
|
12
|
+
"README.md"
|
|
13
|
+
],
|
|
14
|
+
"scripts": {
|
|
15
|
+
"build": "tsc",
|
|
16
|
+
"dev": "tsx src/index.ts",
|
|
17
|
+
"clean": "rm -rf dist",
|
|
18
|
+
"prepublishOnly": "npm run build"
|
|
19
|
+
},
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"commander": "^12.0.0"
|
|
22
|
+
},
|
|
23
|
+
"devDependencies": {
|
|
24
|
+
"typescript": "^5.4.0",
|
|
25
|
+
"tsx": "^4.7.0",
|
|
26
|
+
"@types/node": "^20.0.0"
|
|
27
|
+
},
|
|
28
|
+
"keywords": ["aix", "cloudverse", "cli", "brain", "decision", "llm", "routing", "ai", "gpu"],
|
|
29
|
+
"license": "MIT",
|
|
30
|
+
"repository": {
|
|
31
|
+
"type": "git",
|
|
32
|
+
"url": "https://github.com/cloudverse-ai/aix-cli"
|
|
33
|
+
},
|
|
34
|
+
"engines": {
|
|
35
|
+
"node": ">=18"
|
|
36
|
+
},
|
|
37
|
+
"publishConfig": {
|
|
38
|
+
"access": "public"
|
|
39
|
+
}
|
|
40
|
+
}
|