@rubixkube/rubix 0.0.3 → 0.0.4
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/CHANGELOG.md +8 -1
- package/README.md +2 -2
- package/dist/commands/chat.js +2 -1
- package/dist/config/env.js +2 -0
- package/dist/core/rubix-api.js +36 -7
- package/dist/core/settings.js +6 -1
- package/dist/ui/App.js +206 -160
- package/dist/ui/components/ChatTranscript.js +68 -35
- package/dist/ui/components/Composer.js +1 -1
- package/dist/ui/components/DashboardPanel.js +32 -9
- package/dist/ui/theme.js +3 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,14 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org).
|
|
7
7
|
|
|
8
|
+
## [0.0.4] - 2025-03-03
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- Environment support — `/environments` to switch
|
|
13
|
+
- System Stats Panel in dashboard with live insights and RCA
|
|
14
|
+
- Bugfixes and performance improvements
|
|
15
|
+
|
|
8
16
|
## [0.0.3]
|
|
9
17
|
|
|
10
18
|
### Added
|
|
@@ -13,7 +21,6 @@ and this project adheres to [Semantic Versioning](https://semver.org).
|
|
|
13
21
|
- Persistent user settings
|
|
14
22
|
- Bugfixes and performance improvements
|
|
15
23
|
|
|
16
|
-
|
|
17
24
|
## [0.0.2]
|
|
18
25
|
|
|
19
26
|
### Added
|
package/README.md
CHANGED
|
@@ -42,9 +42,9 @@ Start asking:
|
|
|
42
42
|
|
|
43
43
|
- **Investigate incidents** — ask natural language questions about your live infrastructure
|
|
44
44
|
- **Get RCA** — AI-generated root cause analysis, right in the terminal
|
|
45
|
-
- **Track multiple
|
|
45
|
+
- **Track multiple environments** — switch context without leaving the chat
|
|
46
46
|
- **Resume sessions** — pick up where you left off across terminal sessions
|
|
47
|
-
- **Slash commands** — `/new`, `/
|
|
47
|
+
- **Slash commands** — `/new`, `/resume`, `/environments`, `/status`, `/send`, `/clear`, `/help`, `/exit`
|
|
48
48
|
|
|
49
49
|
## Requirements
|
|
50
50
|
|
package/dist/commands/chat.js
CHANGED
|
@@ -11,7 +11,8 @@ export async function runChatCommand(options) {
|
|
|
11
11
|
seedPrompt: options.prompt,
|
|
12
12
|
}),
|
|
13
13
|
}), {
|
|
14
|
-
|
|
14
|
+
// false so App's useInput receives Ctrl+C and can implement two-press exit
|
|
15
|
+
exitOnCtrlC: false,
|
|
15
16
|
});
|
|
16
17
|
await instance.waitUntilExit();
|
|
17
18
|
}
|
package/dist/config/env.js
CHANGED
|
@@ -7,6 +7,7 @@ const DEFAULTS = {
|
|
|
7
7
|
RUBIXKUBE_AUTH0_AUDIENCE: "",
|
|
8
8
|
RUBIXKUBE_AUTH_API_BASE: "https://console.rubixkube.ai/api/orchestrator",
|
|
9
9
|
RUBIXKUBE_OPEL_API_BASE: "https://console.rubixkube.ai/api/opel",
|
|
10
|
+
RUBIXKUBE_MEMORY_API_BASE: "https://console.rubixkube.ai/api/memory",
|
|
10
11
|
RUBIXKUBE_STREAM_TIMEOUT_MS: "600000",
|
|
11
12
|
};
|
|
12
13
|
export const REQUIRED_ENV = [
|
|
@@ -27,6 +28,7 @@ export function getConfig() {
|
|
|
27
28
|
auth0Audience: (process.env.RUBIXKUBE_AUTH0_AUDIENCE ?? DEFAULTS.RUBIXKUBE_AUTH0_AUDIENCE) || undefined,
|
|
28
29
|
authApiBase: process.env.RUBIXKUBE_AUTH_API_BASE ?? DEFAULTS.RUBIXKUBE_AUTH_API_BASE,
|
|
29
30
|
opelApiBase: process.env.RUBIXKUBE_OPEL_API_BASE ?? DEFAULTS.RUBIXKUBE_OPEL_API_BASE,
|
|
31
|
+
memoryApiBase: process.env.RUBIXKUBE_MEMORY_API_BASE ?? DEFAULTS.RUBIXKUBE_MEMORY_API_BASE,
|
|
30
32
|
streamTimeoutMs: Number(process.env.RUBIXKUBE_STREAM_TIMEOUT_MS ?? DEFAULTS.RUBIXKUBE_STREAM_TIMEOUT_MS) || 600000,
|
|
31
33
|
};
|
|
32
34
|
}
|
package/dist/core/rubix-api.js
CHANGED
|
@@ -21,6 +21,35 @@ function opelBase() {
|
|
|
21
21
|
}
|
|
22
22
|
return value.replace(/\/+$/, "");
|
|
23
23
|
}
|
|
24
|
+
function memoryBase() {
|
|
25
|
+
const value = getConfig().memoryApiBase;
|
|
26
|
+
if (!value) {
|
|
27
|
+
throw new Error("RUBIXKUBE_MEMORY_API_BASE is not set.");
|
|
28
|
+
}
|
|
29
|
+
return value.replace(/\/+$/, "");
|
|
30
|
+
}
|
|
31
|
+
export async function fetchSystemStats(auth) {
|
|
32
|
+
try {
|
|
33
|
+
const url = `${memoryBase()}/api/v1/observability/stats`;
|
|
34
|
+
const response = await fetchWithAutoRefresh(auth, url, {
|
|
35
|
+
method: "GET",
|
|
36
|
+
headers: headers(auth, true),
|
|
37
|
+
});
|
|
38
|
+
if (!response.ok)
|
|
39
|
+
return null;
|
|
40
|
+
const payload = (await response.json());
|
|
41
|
+
return {
|
|
42
|
+
insights: Number(payload.insights ?? 0),
|
|
43
|
+
activeInsights: Number(payload.activeInsights ?? 0),
|
|
44
|
+
resolvedInsights: Number(payload.resolvedInsights ?? 0),
|
|
45
|
+
rcaReports: Number(payload.rcaReports ?? 0),
|
|
46
|
+
lastUpdated: String(payload.lastUpdated ?? new Date().toISOString()),
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
24
53
|
function ensureAuth(auth) {
|
|
25
54
|
const token = auth.idToken ?? auth.authToken;
|
|
26
55
|
const userId = auth.userEmail ?? auth.userId;
|
|
@@ -322,7 +351,7 @@ export async function getOrCreateSession(auth, preferredId, clusterId, appName =
|
|
|
322
351
|
return createSession(auth, appName, clusterId);
|
|
323
352
|
}
|
|
324
353
|
const HEALTHY_STATUSES = new Set(["connected", "healthy", "active"]);
|
|
325
|
-
export async function
|
|
354
|
+
export async function listEnvironments(auth) {
|
|
326
355
|
const authBase = getConfig().authApiBase;
|
|
327
356
|
if (!authBase)
|
|
328
357
|
throw new Error("RUBIXKUBE_AUTH_API_BASE is not set.");
|
|
@@ -341,22 +370,22 @@ export async function listClusters(auth) {
|
|
|
341
370
|
});
|
|
342
371
|
if (!response.ok) {
|
|
343
372
|
const text = await response.text();
|
|
344
|
-
throw new Error(`Failed to load
|
|
373
|
+
throw new Error(`Failed to load environments (${response.status}): ${text}`);
|
|
345
374
|
}
|
|
346
375
|
const payload = (await response.json());
|
|
347
376
|
return (payload.clusters ?? [])
|
|
348
377
|
.filter((c) => !!c?.cluster_id)
|
|
349
378
|
.map((c) => ({
|
|
350
379
|
id: c.id ?? c.cluster_id ?? "",
|
|
351
|
-
|
|
352
|
-
name: c.name ?? c.cluster_id ?? "Unnamed
|
|
380
|
+
environment_id: c.cluster_id ?? "",
|
|
381
|
+
name: c.name ?? c.cluster_id ?? "Unnamed environment",
|
|
353
382
|
status: (c.status ?? "unknown"),
|
|
354
383
|
region: c.region,
|
|
355
|
-
|
|
384
|
+
environment_type: c.cluster_type,
|
|
356
385
|
}));
|
|
357
386
|
}
|
|
358
|
-
export function
|
|
359
|
-
return
|
|
387
|
+
export function firstHealthyEnvironment(environments) {
|
|
388
|
+
return environments.find((c) => HEALTHY_STATUSES.has(c.status)) ?? environments[0] ?? null;
|
|
360
389
|
}
|
|
361
390
|
export async function listModels(auth) {
|
|
362
391
|
const url = `${opelBase()}/models`;
|
package/dist/core/settings.js
CHANGED
|
@@ -9,7 +9,12 @@ export function getSettingsPath() {
|
|
|
9
9
|
export async function loadSettings() {
|
|
10
10
|
try {
|
|
11
11
|
const data = await fs.readFile(getSettingsPath(), "utf8");
|
|
12
|
-
|
|
12
|
+
const raw = JSON.parse(data);
|
|
13
|
+
if (raw.clusterId && !raw.environmentId) {
|
|
14
|
+
raw.environmentId = raw.clusterId;
|
|
15
|
+
delete raw.clusterId;
|
|
16
|
+
}
|
|
17
|
+
return raw;
|
|
13
18
|
}
|
|
14
19
|
catch (error) {
|
|
15
20
|
const asNodeError = error;
|