kubeagent 0.1.13 → 0.1.14

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 CHANGED
@@ -10,7 +10,7 @@ Built for solo DevOps engineers and small teams who want an intelligent on-call
10
10
  # Install
11
11
  npm install -g kubeagent
12
12
 
13
- # Log in (creates your account / links your cluster)
13
+ # Log in (opens browser; uses device-code flow on headless machines)
14
14
  kubeagent login
15
15
 
16
16
  # Onboard — scan cluster, detect your services, build knowledge base
@@ -64,7 +64,17 @@ Actions are classified into tiers:
64
64
 
65
65
  ## Notifications
66
66
 
67
- Configure Slack notifications from the dashboard at [app.kubeagent.net](https://app.kubeagent.net), or set up webhooks manually in `~/.kubeagent/config.yaml`:
67
+ Configure notification channels from the dashboard at [app.kubeagent.net](https://app.kubeagent.net):
68
+
69
+ | Channel | Setup |
70
+ |---------|-------|
71
+ | **Slack** | Connect via OAuth from the dashboard |
72
+ | **PagerDuty** | Add your integration key — verified automatically |
73
+ | **Discord** | Paste a Discord webhook URL |
74
+ | **Microsoft Teams** | Paste a Teams incoming webhook URL |
75
+ | **Custom Webhook** | Any HTTP endpoint that accepts JSON payloads |
76
+
77
+ You can also configure webhooks manually in `~/.kubeagent/config.yaml`:
68
78
 
69
79
  ```yaml
70
80
  webhooks:
package/dist/cli.js CHANGED
@@ -326,7 +326,7 @@ notifyCmd
326
326
  });
327
327
  notifyCmd
328
328
  .command("add")
329
- .description("Add a Slack or Telegram notification channel")
329
+ .description("Add a notification channel")
330
330
  .action(async () => {
331
331
  const { interactiveAddChannel } = await import("./notify/setup.js");
332
332
  const channel = await interactiveAddChannel();
@@ -113,7 +113,7 @@ export async function onboard() {
113
113
  if (existingChannels.length > 0) {
114
114
  console.log(chalk.dim(` ${existingChannels.length} channel(s) already configured.`));
115
115
  }
116
- const addNotify = await ask("Set up a notification channel (Slack / Telegram)? [y/N]");
116
+ const addNotify = await ask("Set up a notification channel? [y/N]");
117
117
  if (addNotify.toLowerCase() === "y") {
118
118
  let adding = true;
119
119
  while (adding) {
@@ -290,7 +290,7 @@ export async function onboard() {
290
290
  if (existingChannels.length > 0) {
291
291
  console.log(chalk.dim(` ${existingChannels.length} channel(s) already configured.`));
292
292
  }
293
- const addNotify = await ask("Set up a notification channel (Slack / Telegram)? [y/N]");
293
+ const addNotify = await ask("Set up a notification channel? [y/N]");
294
294
  if (addNotify.toLowerCase() === "y") {
295
295
  let adding = true;
296
296
  while (adding) {
@@ -1,7 +1,7 @@
1
1
  import chalk from "chalk";
2
2
  import { diagnose } from "./diagnoser/index.js";
3
3
  import { verify } from "./verifier.js";
4
- import { sendNotification } from "./notify/index.js";
4
+ import { notifyViaServer } from "./proxy-client.js";
5
5
  import { writeIncident, writeUnresolved } from "./kb/writer.js";
6
6
  import { join } from "node:path";
7
7
  import { configDir } from "./config.js";
@@ -115,7 +115,10 @@ export async function handleIssues(issues, config, clusterContext, noInteractive
115
115
  }
116
116
  if (actionableIssues.length === 0)
117
117
  return;
118
- await sendNotification(actionableIssues, config, clusterContext);
118
+ const auth = loadAuth();
119
+ if (auth?.apiKey) {
120
+ await notifyViaServer(auth, actionableIssues, clusterContext);
121
+ }
119
122
  // ── Diagnosing ────────────────────────────────────────────
120
123
  sectionHeader("Diagnosing", chalk.blue.bold);
121
124
  const result = await diagnose(actionableIssues, kbDir, clusterContext, {
@@ -200,7 +203,6 @@ export async function handleIssues(issues, config, clusterContext, noInteractive
200
203
  ].join("\n");
201
204
  writeIncident(kbDir, dateStr, incidentName, incidentContent);
202
205
  // Report to SaaS if authenticated
203
- const auth = loadAuth();
204
206
  if (auth?.apiKey) {
205
207
  try {
206
208
  await reportIncident(auth, {
@@ -16,3 +16,10 @@ export declare function reportIncident(auth: AuthState, incident: {
16
16
  export declare function registerWebhook(auth: AuthState, url: string, label: string | undefined, severity: string): Promise<{
17
17
  secret?: string;
18
18
  }>;
19
+ export declare function notifyViaServer(auth: AuthState, issues: Array<{
20
+ kind: string;
21
+ severity: string;
22
+ message: string;
23
+ namespace?: string;
24
+ resource?: string;
25
+ }>, clusterContext?: string): Promise<void>;
@@ -89,3 +89,29 @@ export async function registerWebhook(auth, url, label, severity) {
89
89
  return {};
90
90
  }
91
91
  }
92
+ export async function notifyViaServer(auth, issues, clusterContext) {
93
+ const apiKey = auth.apiKey ?? auth.token;
94
+ try {
95
+ await fetch(`${auth.serverUrl}/notify`, {
96
+ method: "POST",
97
+ headers: {
98
+ "Content-Type": "application/json",
99
+ Authorization: `ApiKey ${apiKey}`,
100
+ },
101
+ body: JSON.stringify({
102
+ issues: issues.map((i) => ({
103
+ kind: i.kind,
104
+ severity: i.severity,
105
+ message: i.message,
106
+ namespace: i.namespace,
107
+ resource: i.resource,
108
+ })),
109
+ clusterContext,
110
+ }),
111
+ signal: AbortSignal.timeout(15_000),
112
+ });
113
+ }
114
+ catch {
115
+ // Silent — don't break the watch loop if server is unreachable
116
+ }
117
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kubeagent",
3
- "version": "0.1.13",
3
+ "version": "0.1.14",
4
4
  "description": "AI-powered Kubernetes management CLI",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "type": "module",