kubeagent 0.1.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 (57) hide show
  1. package/LICENSE +72 -0
  2. package/README.md +154 -0
  3. package/dist/auth.d.ts +23 -0
  4. package/dist/auth.js +162 -0
  5. package/dist/cli.d.ts +2 -0
  6. package/dist/cli.js +447 -0
  7. package/dist/config.d.ts +50 -0
  8. package/dist/config.js +79 -0
  9. package/dist/debug.d.ts +10 -0
  10. package/dist/debug.js +18 -0
  11. package/dist/diagnoser/index.d.ts +17 -0
  12. package/dist/diagnoser/index.js +251 -0
  13. package/dist/diagnoser/tools.d.ts +119 -0
  14. package/dist/diagnoser/tools.js +108 -0
  15. package/dist/kb/loader.d.ts +1 -0
  16. package/dist/kb/loader.js +41 -0
  17. package/dist/kb/writer.d.ts +11 -0
  18. package/dist/kb/writer.js +36 -0
  19. package/dist/kubectl-config.d.ts +7 -0
  20. package/dist/kubectl-config.js +47 -0
  21. package/dist/kubectl.d.ts +13 -0
  22. package/dist/kubectl.js +57 -0
  23. package/dist/monitor/checks.d.ts +71 -0
  24. package/dist/monitor/checks.js +167 -0
  25. package/dist/monitor/index.d.ts +7 -0
  26. package/dist/monitor/index.js +126 -0
  27. package/dist/monitor/types.d.ts +11 -0
  28. package/dist/monitor/types.js +1 -0
  29. package/dist/notify/index.d.ts +5 -0
  30. package/dist/notify/index.js +40 -0
  31. package/dist/notify/setup.d.ts +4 -0
  32. package/dist/notify/setup.js +88 -0
  33. package/dist/notify/slack.d.ts +4 -0
  34. package/dist/notify/slack.js +76 -0
  35. package/dist/notify/telegram.d.ts +8 -0
  36. package/dist/notify/telegram.js +63 -0
  37. package/dist/notify/webhook.d.ts +3 -0
  38. package/dist/notify/webhook.js +49 -0
  39. package/dist/onboard/cluster-scan.d.ts +42 -0
  40. package/dist/onboard/cluster-scan.js +103 -0
  41. package/dist/onboard/code-scan.d.ts +9 -0
  42. package/dist/onboard/code-scan.js +114 -0
  43. package/dist/onboard/index.d.ts +1 -0
  44. package/dist/onboard/index.js +328 -0
  45. package/dist/onboard/interview.d.ts +12 -0
  46. package/dist/onboard/interview.js +71 -0
  47. package/dist/onboard/project-matcher.d.ts +25 -0
  48. package/dist/onboard/project-matcher.js +149 -0
  49. package/dist/orchestrator.d.ts +3 -0
  50. package/dist/orchestrator.js +222 -0
  51. package/dist/proxy-client.d.ts +15 -0
  52. package/dist/proxy-client.js +72 -0
  53. package/dist/render.d.ts +5 -0
  54. package/dist/render.js +143 -0
  55. package/dist/verifier.d.ts +9 -0
  56. package/dist/verifier.js +17 -0
  57. package/package.json +39 -0
package/LICENSE ADDED
@@ -0,0 +1,72 @@
1
+ KubeAgent Commercial License
2
+ Copyright (c) 2025 KubeAgent (kubeagent.net). All rights reserved.
3
+
4
+ TERMS AND CONDITIONS
5
+
6
+ 1. DEFINITIONS
7
+
8
+ "Software" means the KubeAgent software and associated documentation files.
9
+ "Licensor" means KubeAgent (kubeagent.net).
10
+ "You" means the individual or legal entity exercising rights under this License.
11
+ "Commercial Use" means any use of the Software for commercial advantage or
12
+ monetary compensation, including use within a business or organization.
13
+
14
+ 2. GRANT OF LICENSE
15
+
16
+ Subject to the terms of this License, Licensor grants You a non-exclusive,
17
+ non-transferable, limited license to:
18
+
19
+ a. Use the Software for personal, non-commercial evaluation purposes.
20
+ b. Access and modify the source code for the purpose of contributing to the
21
+ official KubeAgent repository via pull request.
22
+
23
+ 3. RESTRICTIONS
24
+
25
+ You may NOT, without explicit written permission from the Licensor:
26
+
27
+ a. Use the Software for Commercial Use.
28
+ b. Distribute, sublicense, sell, resell, transfer, assign, or otherwise
29
+ commercially exploit or make available the Software or any derivative works.
30
+ c. Copy or use the Software for any purpose other than as permitted in Section 2.
31
+ d. Remove or alter any proprietary notices, labels, or marks on the Software.
32
+ e. Use the KubeAgent name, logo, or trademarks to endorse or promote products
33
+ derived from this Software without prior written consent.
34
+
35
+ 4. COMMERCIAL LICENSING
36
+
37
+ Commercial use of the Software requires a separate commercial license agreement
38
+ with the Licensor. To obtain a commercial license, please contact:
39
+
40
+ Email: hello@kubeagent.net
41
+ Website: https://kubeagent.net
42
+
43
+ Paid plans that include a commercial license are available at:
44
+ https://kubeagent.net/#pricing
45
+
46
+ 5. CONTRIBUTIONS
47
+
48
+ By submitting a pull request or patch to the official KubeAgent repository,
49
+ You grant the Licensor a perpetual, worldwide, non-exclusive, royalty-free,
50
+ irrevocable license to use, reproduce, modify, distribute, and sublicense
51
+ your contribution as part of the Software under any license the Licensor chooses.
52
+
53
+ 6. DISCLAIMER OF WARRANTIES
54
+
55
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
56
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
57
+ FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. IN NO EVENT SHALL
58
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER
59
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT, OR OTHERWISE, ARISING FROM,
60
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
61
+ THE SOFTWARE.
62
+
63
+ 7. TERMINATION
64
+
65
+ This License is effective until terminated. Your rights under this License
66
+ terminate automatically if You fail to comply with any of its terms. Upon
67
+ termination, You must destroy all copies of the Software in your possession.
68
+
69
+ 8. GOVERNING LAW
70
+
71
+ This License shall be governed by and construed in accordance with applicable
72
+ law, without regard to conflict of law principles.
package/README.md ADDED
@@ -0,0 +1,154 @@
1
+ # KubeAgent
2
+
3
+ AI-powered Kubernetes monitoring, diagnosis, and remediation CLI. Uses Claude to investigate cluster issues, determine root causes, and apply fixes — with human approval for risky actions.
4
+
5
+ Built for solo DevOps engineers and small teams who want an intelligent on-call assistant.
6
+
7
+ ## How It Works
8
+
9
+ ```
10
+ Monitor (kubectl polling) --> Diagnoser (Claude API) --> Verifier (re-check)
11
+ ```
12
+
13
+ 1. **Monitor** polls your cluster for issues (CrashLoopBackOff, OOM, ImagePullBackOff, node pressure, etc.) — no LLM involved.
14
+ 2. **Diagnoser** sends issues to Claude with your cluster's knowledge base as context. Claude investigates using kubectl tools (logs, describe, events) in an agentic loop.
15
+ 3. **Verifier** re-checks the cluster after a fix to confirm the issue is resolved.
16
+
17
+ Safe actions (pod restart, rollout restart, scale up) are auto-applied. Risky actions (rollback, delete, scale to zero) require your approval.
18
+
19
+ ## Quick Start
20
+
21
+ ```bash
22
+ # Install dependencies
23
+ npm install
24
+
25
+ # Set your API key
26
+ export ANTHROPIC_API_KEY=sk-...
27
+
28
+ # Check cluster health (no LLM)
29
+ npx tsx src/cli.ts status
30
+
31
+ # Onboard — scan cluster, detect tech stacks, build knowledge base
32
+ npx tsx src/cli.ts onboard
33
+
34
+ # Watch mode — continuous monitoring with auto-remediation
35
+ npx tsx src/cli.ts watch
36
+
37
+ # One-shot diagnosis of a specific resource
38
+ npx tsx src/cli.ts diagnose my-pod -n production
39
+
40
+ # Ask a freeform question about your cluster
41
+ npx tsx src/cli.ts "why is the retime API returning 503s?"
42
+ ```
43
+
44
+ ## Install Globally
45
+
46
+ ```bash
47
+ npm run build
48
+ npm link
49
+ kubeagent status
50
+ ```
51
+
52
+ ## Commands
53
+
54
+ | Command | Description | Uses LLM |
55
+ |---------|-------------|----------|
56
+ | `status` | Quick cluster health check | No |
57
+ | `onboard` | Scan cluster + codebases, interview, generate knowledge base | Yes |
58
+ | `watch` | Continuous monitoring with auto-remediation | Yes |
59
+ | `diagnose <resource>` | One-shot diagnosis of a pod/deployment/service | Yes |
60
+ | `<prompt>` | Freeform question about your cluster | Yes |
61
+
62
+ ### Common Options
63
+
64
+ - `-c, --context <name>` — Kubernetes context (defaults to current)
65
+ - `-n, --namespace <name>` — Namespace (for `diagnose`)
66
+ - `-i, --interval <seconds>` — Check interval for `watch` (default: 60)
67
+
68
+ ## Knowledge Base
69
+
70
+ KubeAgent builds a per-cluster knowledge base at `~/.kubeagent/clusters/<context>/` during onboarding:
71
+
72
+ ```
73
+ ~/.kubeagent/
74
+ config.yaml # Global config (clusters, webhooks, intervals)
75
+ clusters/
76
+ hetzner-prod/
77
+ cluster.md # Nodes, namespaces, deployments, services
78
+ projects/
79
+ retime.md # Tech stack, dependencies, notes
80
+ dove.md
81
+ runbooks/ # Custom runbooks (manually added)
82
+ incidents/ # Auto-logged incident reports
83
+ ```
84
+
85
+ This context is injected into Claude's system prompt during diagnosis, giving it awareness of your specific infrastructure.
86
+
87
+ ## Action Safety
88
+
89
+ Actions are classified into tiers:
90
+
91
+ | Tier | Actions | Behavior |
92
+ |------|---------|----------|
93
+ | **Safe** | `get_logs`, `describe_resource`, `get_events`, `restart_pod`, `rollout_restart`, `scale_deployment` | Auto-executed |
94
+ | **Risky** | `rollback_deployment`, `scale_to_zero`, `delete_resource`, `edit_configmap`, `apply_manifest` | Requires approval |
95
+ | **Never** | `delete namespace`, `delete node`, etc. | Refused |
96
+
97
+ ## Notifications
98
+
99
+ Configure webhooks in `~/.kubeagent/config.yaml` to get alerts in Slack, Mattermost, or Discord:
100
+
101
+ ```yaml
102
+ webhooks:
103
+ - url: https://hooks.slack.com/services/T.../B.../xxx
104
+ type: slack
105
+ severityFilter: critical
106
+ ```
107
+
108
+ ## Architecture
109
+
110
+ ```
111
+ src/
112
+ cli.ts # Commander.js CLI entry point
113
+ config.ts # YAML config (~/.kubeagent/config.yaml)
114
+ kubectl.ts # kubectl exec wrapper
115
+ orchestrator.ts # Monitor -> Diagnose -> Verify pipeline
116
+ verifier.ts # Post-fix verification
117
+ monitor/
118
+ types.ts # Issue types (Severity, IssueKind, Issue)
119
+ checks.ts # Pod and node issue detection
120
+ index.ts # Polling loop
121
+ diagnoser/
122
+ tools.ts # Zod-defined kubectl tools for Claude
123
+ index.ts # Claude API agentic loop
124
+ kb/
125
+ loader.ts # Read KB into system prompt
126
+ writer.ts # Write cluster/project/runbook/incident markdown
127
+ notify/
128
+ index.ts # Notification dispatcher
129
+ webhook.ts # Slack/Mattermost/Discord webhooks
130
+ onboard/
131
+ cluster-scan.ts # Auto-discover K8s resources
132
+ code-scan.ts # Detect tech stack from project files
133
+ interview.ts # Claude-generated clarifying questions
134
+ index.ts # Full onboarding flow
135
+ ```
136
+
137
+ ## Requirements
138
+
139
+ - Node.js >= 20
140
+ - `kubectl` configured with cluster access
141
+ - `ANTHROPIC_API_KEY` environment variable (for LLM features)
142
+
143
+ ## Development
144
+
145
+ ```bash
146
+ npm test # Run all tests
147
+ npm run test:watch # Watch mode
148
+ npm run build # Compile TypeScript
149
+ npx tsx src/cli.ts # Run without building
150
+ ```
151
+
152
+ ## License
153
+
154
+ MIT
package/dist/auth.d.ts ADDED
@@ -0,0 +1,23 @@
1
+ export interface AuthState {
2
+ serverUrl: string;
3
+ appUrl: string;
4
+ token: string;
5
+ email?: string;
6
+ name?: string;
7
+ apiKey?: string;
8
+ }
9
+ export declare function loadAuth(): AuthState | null;
10
+ export declare function saveAuth(auth: AuthState): void;
11
+ export declare function clearAuth(): void;
12
+ export declare function loginBrowser(serverUrl: string, appUrl: string): Promise<AuthState>;
13
+ export declare function createApiKey(auth: AuthState, name: string): Promise<{
14
+ key: string;
15
+ prefix: string;
16
+ }>;
17
+ export declare function showAccount(auth: AuthState): Promise<{
18
+ balance: {
19
+ monthlyRemaining: number;
20
+ extraRemaining: number;
21
+ totalRemaining: number;
22
+ };
23
+ }>;
package/dist/auth.js ADDED
@@ -0,0 +1,162 @@
1
+ import { readFileSync, writeFileSync, existsSync, mkdirSync, unlinkSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { createServer } from "node:http";
4
+ import { randomBytes } from "node:crypto";
5
+ import { configDir } from "./config.js";
6
+ import { dbg } from "./debug.js";
7
+ function authPath() {
8
+ return join(configDir(), "auth.json");
9
+ }
10
+ export function loadAuth() {
11
+ const path = authPath();
12
+ if (!existsSync(path)) {
13
+ dbg("auth", "no auth file found", { path });
14
+ return null;
15
+ }
16
+ try {
17
+ const auth = JSON.parse(readFileSync(path, "utf-8"));
18
+ dbg("auth", "loaded", {
19
+ serverUrl: auth.serverUrl,
20
+ email: auth.email,
21
+ keyPrefix: auth.apiKey ? auth.apiKey.slice(0, 12) + "..." : "(none)",
22
+ hasToken: !!auth.token,
23
+ });
24
+ return auth;
25
+ }
26
+ catch {
27
+ dbg("auth", "failed to parse auth file");
28
+ return null;
29
+ }
30
+ }
31
+ export function saveAuth(auth) {
32
+ const dir = configDir();
33
+ if (!existsSync(dir))
34
+ mkdirSync(dir, { recursive: true });
35
+ writeFileSync(authPath(), JSON.stringify(auth, null, 2));
36
+ }
37
+ export function clearAuth() {
38
+ const path = authPath();
39
+ if (existsSync(path))
40
+ unlinkSync(path);
41
+ }
42
+ // Browser-based login flow (like Tailscale / GitHub CLI):
43
+ // 1. Generate random state + start local HTTP listener on a free port
44
+ // 2. Open browser to <appUrl>/auth/cli?state=<s>&port=<p>
45
+ // 3. User logs in (if needed) and clicks "Authorize"
46
+ // 4. Server redirects to http://localhost:<p>/callback?token=...&email=...
47
+ // 5. CLI saves token and resolves
48
+ export async function loginBrowser(serverUrl, appUrl) {
49
+ const state = randomBytes(16).toString("hex");
50
+ const { token, email, name } = await new Promise((resolve, reject) => {
51
+ const server = createServer((req, res) => {
52
+ if (!req.url?.startsWith("/callback")) {
53
+ res.end();
54
+ return;
55
+ }
56
+ const url = new URL(req.url, "http://localhost");
57
+ const receivedState = url.searchParams.get("state");
58
+ const token = url.searchParams.get("token");
59
+ const email = url.searchParams.get("email") ?? "";
60
+ const name = url.searchParams.get("name") ?? "";
61
+ res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
62
+ res.end(`<!DOCTYPE html>
63
+ <html lang="en">
64
+ <head>
65
+ <meta charset="UTF-8" />
66
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
67
+ <title>KubeAgent — Authorized</title>
68
+ <style>
69
+ * { box-sizing: border-box; margin: 0; padding: 0; }
70
+ body { background: #0a0a0a; color: #e5e5e5; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; display: flex; align-items: center; justify-content: center; min-height: 100vh; }
71
+ .card { background: #141414; border: 1px solid #262626; border-radius: 12px; padding: 2.5rem 3rem; text-align: center; max-width: 420px; width: 90%; }
72
+ .icon { font-size: 3rem; margin-bottom: 1.25rem; }
73
+ h1 { font-size: 1.4rem; font-weight: 700; margin-bottom: 0.6rem; color: #f5f5f5; }
74
+ p { color: #737373; font-size: 0.95rem; line-height: 1.6; }
75
+ .check { display: inline-flex; align-items: center; justify-content: center; width: 64px; height: 64px; border-radius: 50%; background: #052e16; margin-bottom: 1.25rem; }
76
+ .check svg { width: 32px; height: 32px; stroke: #34d399; }
77
+ </style>
78
+ <script>setTimeout(() => window.close(), 2000);</script>
79
+ </head>
80
+ <body>
81
+ <div class="card">
82
+ <div class="check">
83
+ <svg fill="none" viewBox="0 0 24 24" stroke-width="2.5" stroke="currentColor">
84
+ <path stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5" />
85
+ </svg>
86
+ </div>
87
+ <h1>CLI Authorized</h1>
88
+ <p>You're logged in. Return to your terminal — this tab will close automatically.</p>
89
+ </div>
90
+ </body>
91
+ </html>`);
92
+ server.close();
93
+ if (receivedState !== state || !token) {
94
+ reject(new Error("Invalid callback — state mismatch or missing token"));
95
+ }
96
+ else {
97
+ resolve({ token, email, name });
98
+ }
99
+ });
100
+ server.listen(0, "127.0.0.1", async () => {
101
+ const port = server.address().port;
102
+ const authUrl = `${appUrl}/auth/cli?state=${state}&port=${port}`;
103
+ // Open browser cross-platform
104
+ const { execSync } = await import("node:child_process");
105
+ const cmd = process.platform === "darwin" ? `open "${authUrl}"`
106
+ : process.platform === "win32" ? `start "" "${authUrl}"`
107
+ : `xdg-open "${authUrl}"`;
108
+ try {
109
+ execSync(cmd);
110
+ }
111
+ catch {
112
+ // fallback: just print the URL
113
+ }
114
+ console.log(`\nOpening browser for authentication...`);
115
+ console.log(`If the browser didn't open, visit:\n ${authUrl}\n`);
116
+ });
117
+ // Timeout after 5 minutes
118
+ const timeoutId = setTimeout(() => {
119
+ server.close();
120
+ reject(new Error("Login timed out (5 minutes)"));
121
+ }, 5 * 60 * 1000);
122
+ // Unref so the timeout doesn't keep Node alive if something else exits first
123
+ timeoutId.unref();
124
+ });
125
+ const auth = { serverUrl, appUrl, token, email, name };
126
+ saveAuth(auth);
127
+ return auth;
128
+ }
129
+ export async function createApiKey(auth, name) {
130
+ const url = `${auth.serverUrl}/keys`;
131
+ let res;
132
+ try {
133
+ res = await fetch(url, {
134
+ method: "POST",
135
+ headers: {
136
+ "Content-Type": "application/json",
137
+ Authorization: `Bearer ${auth.token}`,
138
+ },
139
+ body: JSON.stringify({ name }),
140
+ });
141
+ }
142
+ catch (err) {
143
+ throw new Error(`Could not reach server at ${url} — is it running?\n (${err.message})`);
144
+ }
145
+ if (!res.ok) {
146
+ const body = await res.json().catch(() => ({}));
147
+ throw new Error(body.error ?? `Failed to create API key (${res.status})`);
148
+ }
149
+ const data = (await res.json());
150
+ auth.apiKey = data.key;
151
+ saveAuth(auth);
152
+ return data;
153
+ }
154
+ export async function showAccount(auth) {
155
+ const res = await fetch(`${auth.serverUrl}/v1/balance`, {
156
+ headers: { Authorization: `ApiKey ${auth.apiKey ?? auth.token}` },
157
+ });
158
+ if (!res.ok) {
159
+ throw new Error(`Failed to fetch account info (${res.status})`);
160
+ }
161
+ return { balance: (await res.json()) };
162
+ }
package/dist/cli.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};