kubeagent 0.1.23 → 0.1.24
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 +19 -13
- package/dist/auth.d.ts +10 -5
- package/dist/cli.js +47 -7
- package/dist/proxy-client.js +11 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -24,10 +24,15 @@ kubeagent watch
|
|
|
24
24
|
|
|
25
25
|
| Command | Description |
|
|
26
26
|
|---------|-------------|
|
|
27
|
-
| `status` | Quick cluster health check |
|
|
27
|
+
| `status` | Quick cluster health check (no LLM) |
|
|
28
28
|
| `onboard` | Scan cluster + codebases, generate knowledge base |
|
|
29
29
|
| `watch` | Continuous monitoring with auto-remediation |
|
|
30
30
|
| `diagnose <resource>` | One-shot diagnosis of a pod/deployment/service |
|
|
31
|
+
| `scan <directory>` | Match local project directories to cluster deployments |
|
|
32
|
+
| `notify` | Manage notification channels (`list`, `add`, `remove`, `test`) |
|
|
33
|
+
| `login` | Log in to KubeAgent (browser or `--device` for headless) |
|
|
34
|
+
| `account` | Show account info and token balance |
|
|
35
|
+
| `logout` | Clear saved credentials |
|
|
31
36
|
| `<prompt>` | Ask a freeform question about your cluster |
|
|
32
37
|
|
|
33
38
|
### Common Options
|
|
@@ -35,6 +40,7 @@ kubeagent watch
|
|
|
35
40
|
- `-c, --context <name>` — Kubernetes context (defaults to current)
|
|
36
41
|
- `-n, --namespace <name>` — Namespace (for `diagnose`)
|
|
37
42
|
- `-i, --interval <seconds>` — Check interval for `watch` (default: 300)
|
|
43
|
+
- `--no-interactive` — Auto-deny all approvals, skip questions (for `watch` in background/CI)
|
|
38
44
|
|
|
39
45
|
## Knowledge Base
|
|
40
46
|
|
|
@@ -64,25 +70,25 @@ Actions are classified into tiers:
|
|
|
64
70
|
|
|
65
71
|
## Notifications
|
|
66
72
|
|
|
67
|
-
|
|
73
|
+
Add and manage channels from the CLI:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
kubeagent notify add # interactive setup
|
|
77
|
+
kubeagent notify list # show configured channels
|
|
78
|
+
kubeagent notify test # send a test alert to all channels
|
|
79
|
+
kubeagent notify remove 1 # remove channel by index
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Supported channels:
|
|
68
83
|
|
|
69
84
|
| Channel | Setup |
|
|
70
85
|
|---------|-------|
|
|
71
|
-
| **Slack** | Connect via OAuth from the dashboard |
|
|
86
|
+
| **Slack** | Connect via OAuth from the dashboard at [app.kubeagent.net](https://app.kubeagent.net), or paste a webhook URL |
|
|
72
87
|
| **PagerDuty** | Add your integration key — verified automatically |
|
|
73
88
|
| **Discord** | Paste a Discord webhook URL |
|
|
74
89
|
| **Microsoft Teams** | Paste a Teams incoming webhook URL |
|
|
75
90
|
| **Custom Webhook** | Any HTTP endpoint that accepts JSON payloads |
|
|
76
91
|
|
|
77
|
-
You can also configure webhooks manually in `~/.kubeagent/config.yaml`:
|
|
78
|
-
|
|
79
|
-
```yaml
|
|
80
|
-
webhooks:
|
|
81
|
-
- url: https://hooks.slack.com/services/T.../B.../xxx
|
|
82
|
-
type: slack
|
|
83
|
-
severityFilter: critical
|
|
84
|
-
```
|
|
85
|
-
|
|
86
92
|
## Requirements
|
|
87
93
|
|
|
88
94
|
- Node.js >= 20
|
|
@@ -105,7 +111,7 @@ Each instance operates independently and reports incidents to the same account.
|
|
|
105
111
|
Safe actions (pod restarts, rollout restarts, scaling up) are applied automatically. Anything potentially destructive pauses and waits for your approval.
|
|
106
112
|
|
|
107
113
|
**Where is my API key stored?**
|
|
108
|
-
Credentials are stored locally at `~/.kubeagent/
|
|
114
|
+
Credentials are stored locally at `~/.kubeagent/auth.json` and are never sent anywhere except the KubeAgent API.
|
|
109
115
|
|
|
110
116
|
## License
|
|
111
117
|
|
package/dist/auth.d.ts
CHANGED
|
@@ -15,10 +15,15 @@ export declare function createApiKey(auth: AuthState, name: string): Promise<{
|
|
|
15
15
|
key: string;
|
|
16
16
|
prefix: string;
|
|
17
17
|
}>;
|
|
18
|
+
export interface BalanceInfo {
|
|
19
|
+
monthlyRemaining: number;
|
|
20
|
+
extraRemaining: number;
|
|
21
|
+
totalRemaining: number;
|
|
22
|
+
resetsAt: string;
|
|
23
|
+
plan: string | null;
|
|
24
|
+
planName: string | null;
|
|
25
|
+
monthlyTotal: number;
|
|
26
|
+
}
|
|
18
27
|
export declare function showAccount(auth: AuthState): Promise<{
|
|
19
|
-
balance:
|
|
20
|
-
monthlyRemaining: number;
|
|
21
|
-
extraRemaining: number;
|
|
22
|
-
totalRemaining: number;
|
|
23
|
-
};
|
|
28
|
+
balance: BalanceInfo;
|
|
24
29
|
}>;
|
package/dist/cli.js
CHANGED
|
@@ -92,6 +92,23 @@ program
|
|
|
92
92
|
preflight.fail(`Cannot reach cluster: ${err.message}`);
|
|
93
93
|
process.exit(1);
|
|
94
94
|
}
|
|
95
|
+
// Load auth early so it's available for balance check and Slack merge below
|
|
96
|
+
const auth = loadAuth();
|
|
97
|
+
// Pre-flight: warn if token balance is low (< 20% of monthly allocation)
|
|
98
|
+
if (auth?.apiKey) {
|
|
99
|
+
try {
|
|
100
|
+
const { balance } = await showAccount(auth);
|
|
101
|
+
if (balance.monthlyTotal > 0 && balance.monthlyRemaining < balance.monthlyTotal * 0.2) {
|
|
102
|
+
const pct = Math.round((balance.monthlyRemaining / balance.monthlyTotal) * 100);
|
|
103
|
+
const upgradeUrl = `${auth.appUrl ?? auth.serverUrl}/billing`;
|
|
104
|
+
console.log(chalk.yellow(` ⚠ Low token balance: ${pct}% remaining (${balance.monthlyRemaining.toLocaleString()} tokens).`));
|
|
105
|
+
console.log(chalk.dim(` Upgrade at: `) + chalk.cyan(upgradeUrl) + "\n");
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
catch {
|
|
109
|
+
// Non-fatal — balance check failure should not prevent monitoring
|
|
110
|
+
}
|
|
111
|
+
}
|
|
95
112
|
const intervalLabel = intervalSec >= 60
|
|
96
113
|
? `${Math.floor(intervalSec / 60)}m`
|
|
97
114
|
: `${intervalSec}s`;
|
|
@@ -107,7 +124,6 @@ program
|
|
|
107
124
|
console.log(chalk.dim(" Non-interactive mode — approvals auto-denied, questions skipped\n"));
|
|
108
125
|
}
|
|
109
126
|
// Merge server-stored Slack webhook (from dashboard "Add to Slack") into local config channels
|
|
110
|
-
const auth = loadAuth();
|
|
111
127
|
if (auth?.apiKey) {
|
|
112
128
|
const serverSlack = await fetchSlackWebhook(auth);
|
|
113
129
|
if (serverSlack.connected && serverSlack.webhookUrl) {
|
|
@@ -421,10 +437,33 @@ program
|
|
|
421
437
|
}
|
|
422
438
|
try {
|
|
423
439
|
const { balance } = await showAccount(auth);
|
|
424
|
-
|
|
425
|
-
console.log(
|
|
426
|
-
|
|
427
|
-
|
|
440
|
+
const upgradeUrl = `${auth.appUrl ?? auth.serverUrl}/billing`;
|
|
441
|
+
console.log(chalk.bold("\nToken Balance"));
|
|
442
|
+
if (balance.planName) {
|
|
443
|
+
console.log(` Plan: ${chalk.cyan(balance.planName)}`);
|
|
444
|
+
}
|
|
445
|
+
if (balance.monthlyTotal > 0) {
|
|
446
|
+
const usedPct = Math.round(((balance.monthlyTotal - balance.monthlyRemaining) / balance.monthlyTotal) * 100);
|
|
447
|
+
console.log(` Monthly tokens: ${balance.monthlyRemaining.toLocaleString()} / ${balance.monthlyTotal.toLocaleString()} (${usedPct}% used)`);
|
|
448
|
+
}
|
|
449
|
+
else {
|
|
450
|
+
console.log(` Monthly remaining: ${balance.monthlyRemaining.toLocaleString()}`);
|
|
451
|
+
}
|
|
452
|
+
if (balance.extraRemaining > 0) {
|
|
453
|
+
console.log(` Extra credits: ${balance.extraRemaining.toLocaleString()}`);
|
|
454
|
+
}
|
|
455
|
+
console.log(` Total remaining: ${balance.totalRemaining.toLocaleString()}`);
|
|
456
|
+
if (balance.resetsAt) {
|
|
457
|
+
const resetDate = new Date(balance.resetsAt).toLocaleDateString(undefined, { month: "short", day: "numeric", year: "numeric" });
|
|
458
|
+
console.log(` Resets: ${resetDate}`);
|
|
459
|
+
}
|
|
460
|
+
// Low-balance warning: < 20% of monthly allocation remaining
|
|
461
|
+
if (balance.monthlyTotal > 0 && balance.monthlyRemaining < balance.monthlyTotal * 0.2) {
|
|
462
|
+
const pct = Math.round((balance.monthlyRemaining / balance.monthlyTotal) * 100);
|
|
463
|
+
console.log("\n" + chalk.yellow(` ⚠ Low balance: ${pct}% of monthly tokens remaining.`));
|
|
464
|
+
console.log(chalk.dim(` Upgrade or buy extra credits: `) + chalk.cyan(upgradeUrl));
|
|
465
|
+
}
|
|
466
|
+
console.log();
|
|
428
467
|
}
|
|
429
468
|
catch (err) {
|
|
430
469
|
console.error(chalk.red(err.message));
|
|
@@ -461,8 +500,9 @@ program
|
|
|
461
500
|
}
|
|
462
501
|
catch (err) {
|
|
463
502
|
const e = err;
|
|
464
|
-
if (e.status ===
|
|
465
|
-
|
|
503
|
+
if (e.status === 402 || e.code === "token_exhausted") {
|
|
504
|
+
const upgradeUrl = `${auth.appUrl ?? auth.serverUrl}/billing`;
|
|
505
|
+
console.error(chalk.red("Token balance exhausted (402).") + " " + chalk.dim("Run: ") + chalk.cyan("kubeagent account") + chalk.dim(" to check, or upgrade at ") + chalk.cyan(upgradeUrl));
|
|
466
506
|
}
|
|
467
507
|
else if (e.status === 401) {
|
|
468
508
|
console.error(chalk.red("Not authenticated.") + " " + chalk.dim("Run: kubeagent login"));
|
package/dist/proxy-client.js
CHANGED
|
@@ -28,6 +28,16 @@ export async function proxyRequest(auth, body) {
|
|
|
28
28
|
dbg("proxy", `response ${res.status} from ${url}`);
|
|
29
29
|
if (res.status !== 429 && res.status !== 503)
|
|
30
30
|
break;
|
|
31
|
+
// 402 is handled above (not 429/503), but peek 429 bodies to avoid
|
|
32
|
+
// retrying when tokens are permanently exhausted.
|
|
33
|
+
if (res.status === 429) {
|
|
34
|
+
const clone = res.clone();
|
|
35
|
+
const body429 = await clone.json().catch(() => ({}));
|
|
36
|
+
if (body429.code === "token_exhausted") {
|
|
37
|
+
dbg("proxy", "token exhausted — not retrying");
|
|
38
|
+
break;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
31
41
|
dbg("proxy", `transient error ${res.status}, will retry`);
|
|
32
42
|
lastErr = res;
|
|
33
43
|
}
|
|
@@ -41,6 +51,7 @@ export async function proxyRequest(auth, body) {
|
|
|
41
51
|
: "";
|
|
42
52
|
throw Object.assign(new Error(`KubeAgent proxy: ${message}${hint}`), {
|
|
43
53
|
status: res.status,
|
|
54
|
+
code: errBody.code,
|
|
44
55
|
});
|
|
45
56
|
}
|
|
46
57
|
return (await res.json());
|