@ols-cli/lightspeed 0.1.2 → 0.2.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 (2) hide show
  1. package/bin/ols.js +84 -51
  2. package/package.json +3 -3
package/bin/ols.js CHANGED
@@ -1,16 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
3
  * ols — OpenShift Lightspeed CLI
4
- *
5
- * Usage:
6
- * ols Interactive mode
7
- * ols "how do I scale?" One-shot query
8
- * ols health Check OLS health
9
- * ols conversations List conversations
10
- * ols config set <key> <val> Set config
11
- * ols config show Show config
4
+ * AI-powered assistant with OLS + NVIDIA NIM backends
12
5
  */
13
- const { OLSClient, loadOLSConfig, saveOLSConfig } = require("@ols-cli/client");
6
+ const { OLSClient, smartQuery, loadOLSConfig, saveOLSConfig } = require("@ols-cli/client");
14
7
 
15
8
  const cyan = "\x1b[36m";
16
9
  const green = "\x1b[32m";
@@ -24,7 +17,11 @@ function configCmd(args) {
24
17
  const cmd = args[0];
25
18
  if (!cmd || cmd === "show") {
26
19
  const cfg = loadOLSConfig();
27
- console.log(JSON.stringify(cfg, null, 2));
20
+ // Mask API keys
21
+ const safe = { ...cfg };
22
+ if (safe.nimApiKey) safe.nimApiKey = safe.nimApiKey.slice(0, 8) + "...";
23
+ if (safe._conversationId) delete safe._conversationId;
24
+ console.log(JSON.stringify(safe, null, 2));
28
25
  return;
29
26
  }
30
27
  if (cmd === "set" && args[1] && args[2] !== undefined) {
@@ -37,34 +34,60 @@ function configCmd(args) {
37
34
  }
38
35
  if (cmd === "init") {
39
36
  console.log(`${cyan}OpenShift Lightspeed CLI Configuration${reset}\n`);
37
+ console.log(" # Option 1: OpenShift Lightspeed Service");
40
38
  console.log(" ols config set serviceUrl https://lightspeed-service.example.com:8443");
41
- console.log(" ols config set namespace openshift-operators\n");
42
- console.log("Auth comes from kubeconfig just run: oc login");
39
+ console.log("");
40
+ console.log(" # Option 2: NVIDIA NIM (works without OLS)");
41
+ console.log(" ols config set nimApiKey nvapi-xxxxx");
42
+ console.log(" ols config set nimModel nvidia/llama-3.1-nemotron-70b-instruct");
43
+ console.log("");
44
+ console.log(" # Auth from kubeconfig (for OLS): oc login");
43
45
  return;
44
46
  }
45
47
  console.log("Usage: ols config [show|set|init]");
46
48
  }
47
49
 
48
50
  async function healthCmd() {
49
- try {
50
- const client = new OLSClient(loadOLSConfig());
51
- const h = await client.health();
52
- console.log(`${green}✓${reset} OLS Status: ${h.status}`);
53
- if (h.services) {
54
- for (const [name, status] of Object.entries(h.services)) {
55
- const icon = status === "ok" || status === "ready" ? green : yellow;
56
- console.log(` ${icon}●${reset} ${name}: ${status}`);
57
- }
51
+ const cfg = loadOLSConfig();
52
+ console.log(`\n${bold}Health Check${reset}\n`);
53
+
54
+ // Check OLS
55
+ if (cfg.serviceUrl) {
56
+ try {
57
+ const client = new OLSClient(cfg);
58
+ const h = await client.health();
59
+ console.log(` ${green}✓${reset} OLS: ${h.status}`);
60
+ } catch (e) {
61
+ console.log(` ${red}✗${reset} OLS: ${e.message}`);
58
62
  }
59
- } catch (e) {
60
- console.error(`${red}✗${reset} ${e.message}`);
61
- process.exit(1);
63
+ } else {
64
+ console.log(` ${yellow}○${reset} OLS: not configured`);
65
+ }
66
+
67
+ // Check NIM
68
+ if (cfg.nimApiKey) {
69
+ try {
70
+ const { NIMClient } = require("@ols-cli/client");
71
+ const nim = new NIMClient(cfg);
72
+ const resp = await nim.chat([{ role: "user", content: "ping" }]);
73
+ console.log(` ${green}✓${reset} NIM: connected (${cfg.nimModel || "default model"})`);
74
+ } catch (e) {
75
+ console.log(` ${red}✗${reset} NIM: ${e.message}`);
76
+ }
77
+ } else {
78
+ console.log(` ${yellow}○${reset} NIM: not configured (set nimApiKey)`);
62
79
  }
80
+ console.log();
63
81
  }
64
82
 
65
83
  async function conversationsCmd() {
84
+ const cfg = loadOLSConfig();
85
+ if (!cfg.serviceUrl) {
86
+ console.log(`${yellow}OLS not configured. Set serviceUrl first.${reset}`);
87
+ return;
88
+ }
66
89
  try {
67
- const client = new OLSClient(loadOLSConfig());
90
+ const client = new OLSClient(cfg);
68
91
  const convos = await client.listConversations();
69
92
  if (convos.length === 0) {
70
93
  console.log(`${dim}No conversations found.${reset}`);
@@ -77,38 +100,37 @@ async function conversationsCmd() {
77
100
  }
78
101
  } catch (e) {
79
102
  console.error(`${red}✗${reset} ${e.message}`);
80
- process.exit(1);
81
103
  }
82
104
  }
83
105
 
84
106
  async function queryCmd(question) {
85
107
  try {
86
- const client = new OLSClient(loadOLSConfig());
87
- const resp = await client.query({ query: question });
88
- console.log(`\n${resp.response}\n`);
89
- if (resp.referenced_documents && resp.referenced_documents.length) {
108
+ const cfg = loadOLSConfig();
109
+ const result = await smartQuery(question, cfg, []);
110
+ console.log(`\n${result.response}\n`);
111
+ if (result.references && result.references.length) {
90
112
  console.log(`${dim}References:${reset}`);
91
- for (const doc of resp.referenced_documents) {
113
+ for (const doc of result.references) {
92
114
  console.log(` ${cyan}→${reset} ${doc.title} ${dim}(${doc.url})${reset}`);
93
115
  }
94
116
  console.log();
95
117
  }
96
- if (resp.conversation_id) {
97
- console.log(`${dim}Conversation: ${resp.conversation_id}${reset}`);
98
- }
118
+ console.log(`${dim}via ${result.source}${reset}`);
99
119
  } catch (e) {
100
120
  console.error(`${red}✗${reset} ${e.message}`);
101
- process.exit(1);
102
121
  }
103
122
  }
104
123
 
105
124
  async function interactiveMode() {
106
125
  const readline = require("readline");
126
+ const cfg = loadOLSConfig();
127
+
128
+ const backend = cfg.nimApiKey ? (cfg.serviceUrl ? "OLS + NIM" : "NIM") : "OLS";
107
129
 
108
- console.log(`\n${bold}${cyan}OpenShift Lightspeed CLI${reset} v0.1.0`);
130
+ console.log(`\n${bold}${cyan}OpenShift Lightspeed CLI${reset} v0.2.0 ${dim}[${backend}]${reset}`);
109
131
  console.log(`${dim}Type your question, or 'quit' to exit.${reset}\n`);
110
132
 
111
- let conversationId;
133
+ const history = [];
112
134
 
113
135
  const rl = readline.createInterface({
114
136
  input: process.stdin,
@@ -127,19 +149,22 @@ async function interactiveMode() {
127
149
  }
128
150
  if (input === "health") { await healthCmd(); rl.prompt(); return; }
129
151
  if (input === "conversations") { await conversationsCmd(); rl.prompt(); return; }
152
+ if (input === "config") { configCmd(["show"]); rl.prompt(); return; }
130
153
 
131
154
  try {
132
- const client = new OLSClient(loadOLSConfig());
133
- const resp = await client.query({ query: input, conversation_id: conversationId });
134
- conversationId = resp.conversation_id;
135
- console.log(`\n${resp.response}\n`);
136
- if (resp.referenced_documents && resp.referenced_documents.length) {
155
+ const currentCfg = loadOLSConfig();
156
+ const result = await smartQuery(input, currentCfg, history);
157
+ history.push({ role: "user", content: input });
158
+ history.push({ role: "assistant", content: result.response });
159
+ console.log(`\n${result.response}\n`);
160
+ if (result.references && result.references.length) {
137
161
  console.log(`${dim}References:${reset}`);
138
- for (const doc of resp.referenced_documents) {
162
+ for (const doc of result.references) {
139
163
  console.log(` ${cyan}→${reset} ${doc.title}`);
140
164
  }
141
165
  console.log();
142
166
  }
167
+ console.log(`${dim}via ${result.source}${reset}`);
143
168
  } catch (e) {
144
169
  console.error(`${red}✗${reset} ${e.message}`);
145
170
  }
@@ -149,26 +174,34 @@ async function interactiveMode() {
149
174
 
150
175
  async function main() {
151
176
  const args = process.argv.slice(2);
152
-
153
- if (args.length === 0) {
154
- return interactiveMode();
155
- }
177
+ if (args.length === 0) return interactiveMode();
156
178
 
157
179
  const cmd = args[0];
158
-
159
180
  if (cmd === "config") return configCmd(args.slice(1));
160
181
  if (cmd === "health") return await healthCmd();
161
182
  if (cmd === "conversations" || cmd === "convos") return await conversationsCmd();
162
183
  if (cmd === "--help" || cmd === "-h" || cmd === "help") {
163
- console.log(`${bold}Usage:${reset}
184
+ console.log(`${bold}OpenShift Lightspeed CLI${reset}
185
+
186
+ ${bold}Usage:${reset}
164
187
  ols Interactive mode
165
188
  ols "your question" One-shot query
166
- ols health Check OLS service health
167
- ols conversations List past conversations
189
+ ols health Check backends health
190
+ ols conversations List OLS conversations
168
191
  ols config show Show configuration
169
192
  ols config set <key> <val> Set config value
170
193
  ols config init Setup help
171
194
  ols help This help
195
+
196
+ ${bold}Config keys:${reset}
197
+ serviceUrl OLS service URL
198
+ nimApiKey NVIDIA NIM API key (fallback LLM)
199
+ nimModel NIM model name
200
+ nimBaseUrl NIM API base URL
201
+
202
+ ${bold}Backends:${reset}
203
+ 1. OLS (OpenShift Lightspeed Service) — primary
204
+ 2. NVIDIA NIM (OpenAI-compatible) — fallback
172
205
  `);
173
206
  return;
174
207
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ols-cli/lightspeed",
3
- "version": "0.1.2",
3
+ "version": "0.2.0",
4
4
  "description": "OpenShift Lightspeed CLI — AI-powered assistant for OpenShift from your terminal",
5
5
  "bin": {
6
6
  "ols": "./bin/ols.js"
@@ -16,7 +16,7 @@
16
16
  },
17
17
  "keywords": [
18
18
  "openshift", "lightspeed", "ols", "kubernetes", "cli",
19
- "ai-agent", "assistant", "terminal", "devops"
19
+ "ai-agent", "assistant", "terminal", "devops", "nvidia", "nim"
20
20
  ],
21
21
  "author": "Chin (kcns008)",
22
22
  "license": "Apache-2.0",
@@ -35,6 +35,6 @@
35
35
  "access": "public"
36
36
  },
37
37
  "dependencies": {
38
- "@ols-cli/client": "^0.1.1"
38
+ "@ols-cli/client": "^0.2.0"
39
39
  }
40
40
  }