kubechart 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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 kubechart contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,157 @@
1
+ # kubechart
2
+
3
+ CLI tool to visualize Kubernetes cluster as an ASCII tree directly in your terminal. Perfect for quick debugging when SSH'd into servers.
4
+
5
+ ## Features
6
+
7
+ - **ASCII Tree Visualization**: Clean, readable tree structure showing namespaces, workloads, pods, services, and ingresses
8
+ - **Color-Coded Status**: Visual indicators for pod health (Running, Pending, Failed, etc.)
9
+ - **Resource Type Symbols**: Distinct symbols for Deployments, StatefulSets, DaemonSets, Jobs, CronJobs, Services, and Ingresses
10
+ - **Flexible Filtering**: Filter by namespace, label selector, or show only resources with errors
11
+ - **Multi-Context Support**: Switch between different kubeconfig contexts
12
+ - **Error Handling**: Clear error messages for common K8s connection issues
13
+
14
+ ## Installation
15
+
16
+ ```bash
17
+ npm install -g kubechart
18
+ ```
19
+
20
+ Or use with npx:
21
+
22
+ ```bash
23
+ npx kubechart
24
+ ```
25
+
26
+ ## Usage
27
+
28
+ ### Basic Usage
29
+
30
+ ```bash
31
+ # Show current namespace (kubectl-compatible behavior)
32
+ kubechart
33
+
34
+ # Show all namespaces
35
+ kubechart -A
36
+
37
+ # Filter by specific namespace
38
+ kubechart -n production
39
+ ```
40
+
41
+ ### Filtering Options
42
+
43
+ ```bash
44
+ # Use specific kubeconfig context
45
+ kubechart --context my-eks-cluster
46
+
47
+ # Label selector (same syntax as kubectl)
48
+ kubechart -l app=api
49
+ kubechart --selector app=api,env=prod
50
+
51
+ # Show only workloads with errors
52
+ kubechart --show-errors
53
+ ```
54
+
55
+ ### Output Options
56
+
57
+ ```bash
58
+ # Disable colored output
59
+ kubechart --no-color
60
+ ```
61
+
62
+ ### Examples
63
+
64
+ ```
65
+ ◆ CLUSTER prod-cluster | k8s v1.29.2 | 3 nodes
66
+
67
+ ├── NAMESPACE production [Active]
68
+ │ ├── ▲ Deployment api-server [3/3]
69
+ │ │ ├── POD ● api-server-7d9f-xk2p node-01 192.168.1.10 0 restarts
70
+ │ │ ├── POD ● api-server-7d9f-mn4q node-02 192.168.1.11 0 restarts
71
+ │ │ └── POD ✖ api-server-7d9f-rs7w node-03 CrashLoopBackOff 5 restarts
72
+ │ ├── ◆ StatefulSet postgres [1/1]
73
+ │ │ └── POD ● postgres-0 node-03 PVC: pg-data-0
74
+ │ ├── ● SVC api-svc ClusterIP 10.96.0.50 80/TCP
75
+ │ └── ◆ ING api.example.com 🔒 → /, /api
76
+
77
+ └── NAMESPACE staging [Active]
78
+ └── ▲ Deployment worker [0/2] ⚠ degraded
79
+ ├── POD ◌ worker-abc-hk4p Pending
80
+ └── POD ✖ worker-abc-xx9q OOMKilled 3 restarts
81
+
82
+ ────────────────────────────────────────
83
+ namespaces: 2 | workloads: 3 | pods: 5 | services: 1 | ingresses: 1
84
+ Pod Status: ● Running+Ready ◑ Running+NotReady ◌ Pending ✖ Failed ○ Succeeded
85
+ ```
86
+
87
+ ## Pod Status Legend
88
+
89
+ | Symbol | Color | Meaning |
90
+ | ------ | ------ | ------------------------------------- |
91
+ | `●` | green | Running + Ready |
92
+ | `◑` | yellow | Running but not Ready |
93
+ | `◌` | yellow | Pending |
94
+ | `✖` | red | Failed / CrashLoopBackOff / OOMKilled |
95
+ | `○` | gray | Succeeded (Job completed) |
96
+
97
+ ## Resource Type Legend
98
+
99
+ | Symbol | Type |
100
+ | ------ | ------------ |
101
+ | ▲ | Deployment |
102
+ | ◆ | StatefulSet |
103
+ | ■ | DaemonSet |
104
+ | ● | Job |
105
+ | ○ | CronJob |
106
+ | ● | ClusterIP |
107
+ | ◆ | NodePort |
108
+ | ▲ | LoadBalancer |
109
+ | ○ | ExternalName |
110
+ | ◆ | Ingress |
111
+
112
+ ## Error Handling
113
+
114
+ kubechart provides clear error messages for common issues:
115
+
116
+ - **Cannot load kubeconfig**: Check that `~/.kube/config` exists
117
+ - **Context not found**: Verify the context name in your kubeconfig
118
+ - **Cannot connect to cluster**: Ensure your cluster is running and accessible
119
+ - **Forbidden/Unauthorized**: Check your RBAC permissions and credentials
120
+
121
+ ## Development
122
+
123
+ ```bash
124
+ # Install dependencies
125
+ npm install
126
+
127
+ # Build
128
+ npm run build
129
+
130
+ # Run with local cluster
131
+ npm start
132
+
133
+ # Watch mode with hot reload
134
+ npm run dev -- -n <namespace>
135
+
136
+ # Run tests
137
+ npm test
138
+
139
+ # Run tests with coverage
140
+ npm run test:coverage
141
+
142
+ # Lint
143
+ npm run lint
144
+
145
+ # Format
146
+ npm run format
147
+ ```
148
+
149
+ ## Requirements
150
+
151
+ - Node.js >= 18.0.0
152
+ - Access to a Kubernetes cluster
153
+ - Valid kubeconfig file
154
+
155
+ ## License
156
+
157
+ MIT
package/dist/cli.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
package/dist/cli.js ADDED
@@ -0,0 +1,59 @@
1
+ #!/usr/bin/env node
2
+ import { Command } from 'commander';
3
+ import { render } from 'ink';
4
+ import React from 'react';
5
+ import { createClient } from './k8s/client.js';
6
+ import { fetchClusterData } from './k8s/fetcher.js';
7
+ import { buildTree } from './tree/builder.js';
8
+ import { TreeView } from './render/TreeView.js';
9
+ import { setUseColors } from './render/colors.js';
10
+ const program = new Command();
11
+ program
12
+ .name('kubechart')
13
+ .description('Visualize Kubernetes cluster as ASCII tree')
14
+ .version('0.1.0')
15
+ .option('-n, --namespace <ns>', 'Filter by namespace')
16
+ .option('-A, --all-namespaces', 'Show all namespaces')
17
+ .option('--context <ctx>', 'Kubeconfig context to use')
18
+ .option('-l, --selector <sel>', 'Label selector (e.g. app=api,env=prod)')
19
+ .option('--show-errors', 'Only show workloads with errors')
20
+ .option('--no-color', 'Disable colored output')
21
+ .parse(process.argv);
22
+ const options = program.opts();
23
+ async function main() {
24
+ try {
25
+ // Set color mode based on --no-color flag
26
+ setUseColors(options.color !== false);
27
+ // Create K8s client
28
+ const client = createClient(options.context);
29
+ // Build fetch options
30
+ // Default to current namespace (kubectl behavior)
31
+ // Use -A for all namespaces, -n for specific namespace
32
+ const fetchOpts = {
33
+ namespace: options.allNamespaces ? undefined : options.namespace || client.currentNamespace,
34
+ allNamespaces: options.allNamespaces,
35
+ selector: options.selector,
36
+ showErrors: options.showErrors,
37
+ };
38
+ // Fetch cluster data
39
+ const rawData = await fetchClusterData(client, fetchOpts);
40
+ // Build tree
41
+ const tree = buildTree(rawData, client.contextName, {
42
+ showErrors: options.showErrors,
43
+ selector: options.selector,
44
+ });
45
+ // Render using ink
46
+ const { waitUntilExit } = render(React.createElement(TreeView, { tree }));
47
+ await waitUntilExit();
48
+ }
49
+ catch (error) {
50
+ if (error instanceof Error) {
51
+ console.error(`Error: ${error.message}`);
52
+ process.exit(1);
53
+ }
54
+ console.error('Unknown error occurred');
55
+ process.exit(1);
56
+ }
57
+ }
58
+ main();
59
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,MAAM,EAAE,MAAM,KAAK,CAAC;AAC7B,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAC9C,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAGlD,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,WAAW,CAAC;KACjB,WAAW,CAAC,4CAA4C,CAAC;KACzD,OAAO,CAAC,OAAO,CAAC;KAChB,MAAM,CAAC,sBAAsB,EAAE,qBAAqB,CAAC;KACrD,MAAM,CAAC,sBAAsB,EAAE,qBAAqB,CAAC;KACrD,MAAM,CAAC,iBAAiB,EAAE,2BAA2B,CAAC;KACtD,MAAM,CAAC,sBAAsB,EAAE,wCAAwC,CAAC;KACxE,MAAM,CAAC,eAAe,EAAE,iCAAiC,CAAC;KAC1D,MAAM,CAAC,YAAY,EAAE,wBAAwB,CAAC;KAC9C,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;AAEvB,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;AAE/B,KAAK,UAAU,IAAI;IACjB,IAAI,CAAC;QACH,0CAA0C;QAC1C,YAAY,CAAC,OAAO,CAAC,KAAK,KAAK,KAAK,CAAC,CAAC;QAEtC,oBAAoB;QACpB,MAAM,MAAM,GAAG,YAAY,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QAE7C,sBAAsB;QACtB,kDAAkD;QAClD,uDAAuD;QACvD,MAAM,SAAS,GAAiB;YAC9B,SAAS,EAAE,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,IAAI,MAAM,CAAC,gBAAgB;YAC3F,aAAa,EAAE,OAAO,CAAC,aAAa;YACpC,QAAQ,EAAE,OAAO,CAAC,QAAQ;YAC1B,UAAU,EAAE,OAAO,CAAC,UAAU;SAC/B,CAAC;QAEF,qBAAqB;QACrB,MAAM,OAAO,GAAG,MAAM,gBAAgB,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;QAE1D,aAAa;QACb,MAAM,IAAI,GAAG,SAAS,CAAC,OAAO,EAAE,MAAM,CAAC,WAAW,EAAE;YAClD,UAAU,EAAE,OAAO,CAAC,UAAU;YAC9B,QAAQ,EAAE,OAAO,CAAC,QAAQ;SAC3B,CAAC,CAAC;QAEH,mBAAmB;QACnB,MAAM,EAAE,aAAa,EAAE,GAAG,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC,QAAQ,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;QAC1E,MAAM,aAAa,EAAE,CAAC;IACxB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;YAC3B,OAAO,CAAC,KAAK,CAAC,UAAU,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;YACzC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QACD,OAAO,CAAC,KAAK,CAAC,wBAAwB,CAAC,CAAC;QACxC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC;AAED,IAAI,EAAE,CAAC"}
@@ -0,0 +1,9 @@
1
+ export { createClient } from './k8s/client.js';
2
+ export { fetchClusterData } from './k8s/fetcher.js';
3
+ export type { K8sClient } from './k8s/client.js';
4
+ export type { FetchOptions, RawClusterData } from './k8s/types.js';
5
+ export { buildTree } from './tree/builder.js';
6
+ export type { ClusterTree, NamespaceNode, WorkloadNode, PodNode, PodPhase, ResourceKind, } from './tree/types.js';
7
+ export { TreeView } from './render/TreeView.js';
8
+ export { colors, getPodStatusColor } from './render/colors.js';
9
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,YAAY,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,YAAY,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AACnE,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAC9C,YAAY,EACV,WAAW,EACX,aAAa,EACb,YAAY,EACZ,OAAO,EACP,QAAQ,EACR,YAAY,GACb,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAChD,OAAO,EAAE,MAAM,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,7 @@
1
+ // Main export for kubechart
2
+ export { createClient } from './k8s/client.js';
3
+ export { fetchClusterData } from './k8s/fetcher.js';
4
+ export { buildTree } from './tree/builder.js';
5
+ export { TreeView } from './render/TreeView.js';
6
+ export { colors, getPodStatusColor } from './render/colors.js';
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,4BAA4B;AAC5B,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAGpD,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAS9C,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAChD,OAAO,EAAE,MAAM,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC"}
@@ -0,0 +1,12 @@
1
+ import * as k8s from '@kubernetes/client-node';
2
+ export interface K8sClient {
3
+ core: k8s.CoreV1Api;
4
+ apps: k8s.AppsV1Api;
5
+ batch: k8s.BatchV1Api;
6
+ networking: k8s.NetworkingV1Api;
7
+ version: k8s.VersionApi;
8
+ contextName: string;
9
+ currentNamespace: string;
10
+ }
11
+ export declare function createClient(context?: string): K8sClient;
12
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/k8s/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,GAAG,MAAM,yBAAyB,CAAC;AAE/C,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,GAAG,CAAC,SAAS,CAAC;IACpB,IAAI,EAAE,GAAG,CAAC,SAAS,CAAC;IACpB,KAAK,EAAE,GAAG,CAAC,UAAU,CAAC;IACtB,UAAU,EAAE,GAAG,CAAC,eAAe,CAAC;IAChC,OAAO,EAAE,GAAG,CAAC,UAAU,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED,wBAAgB,YAAY,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAoCxD"}
@@ -0,0 +1,36 @@
1
+ import * as k8s from '@kubernetes/client-node';
2
+ export function createClient(context) {
3
+ const kc = new k8s.KubeConfig();
4
+ try {
5
+ kc.loadFromDefault();
6
+ }
7
+ catch (error) {
8
+ if (error instanceof Error) {
9
+ throw new Error(`Cannot load kubeconfig: ${error.message}`);
10
+ }
11
+ throw new Error('Cannot load kubeconfig: unknown error');
12
+ }
13
+ if (context) {
14
+ const contexts = kc.getContexts();
15
+ const contextExists = contexts.some((ctx) => ctx.name === context);
16
+ if (!contextExists) {
17
+ throw new Error(`Context '${context}' not found in kubeconfig`);
18
+ }
19
+ kc.setCurrentContext(context);
20
+ }
21
+ // Get current namespace from context
22
+ const currentContext = kc
23
+ .getContexts()
24
+ .find((ctx) => ctx.name === kc.getCurrentContext());
25
+ const currentNamespace = currentContext?.namespace || 'default';
26
+ return {
27
+ core: kc.makeApiClient(k8s.CoreV1Api),
28
+ apps: kc.makeApiClient(k8s.AppsV1Api),
29
+ batch: kc.makeApiClient(k8s.BatchV1Api),
30
+ networking: kc.makeApiClient(k8s.NetworkingV1Api),
31
+ version: kc.makeApiClient(k8s.VersionApi),
32
+ contextName: kc.getCurrentContext(),
33
+ currentNamespace,
34
+ };
35
+ }
36
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/k8s/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,GAAG,MAAM,yBAAyB,CAAC;AAY/C,MAAM,UAAU,YAAY,CAAC,OAAgB;IAC3C,MAAM,EAAE,GAAG,IAAI,GAAG,CAAC,UAAU,EAAE,CAAC;IAEhC,IAAI,CAAC;QACH,EAAE,CAAC,eAAe,EAAE,CAAC;IACvB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;YAC3B,MAAM,IAAI,KAAK,CAAC,2BAA2B,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;QAC9D,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC;IAC3D,CAAC;IAED,IAAI,OAAO,EAAE,CAAC;QACZ,MAAM,QAAQ,GAAG,EAAE,CAAC,WAAW,EAAE,CAAC;QAClC,MAAM,aAAa,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,GAAqB,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC;QACrF,IAAI,CAAC,aAAa,EAAE,CAAC;YACnB,MAAM,IAAI,KAAK,CAAC,YAAY,OAAO,2BAA2B,CAAC,CAAC;QAClE,CAAC;QACD,EAAE,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC;IAChC,CAAC;IAED,qCAAqC;IACrC,MAAM,cAAc,GAAG,EAAE;SACtB,WAAW,EAAE;SACb,IAAI,CAAC,CAAC,GAAqB,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,KAAK,EAAE,CAAC,iBAAiB,EAAE,CAAC,CAAC;IACxE,MAAM,gBAAgB,GAAG,cAAc,EAAE,SAAS,IAAI,SAAS,CAAC;IAEhE,OAAO;QACL,IAAI,EAAE,EAAE,CAAC,aAAa,CAAC,GAAG,CAAC,SAAS,CAAC;QACrC,IAAI,EAAE,EAAE,CAAC,aAAa,CAAC,GAAG,CAAC,SAAS,CAAC;QACrC,KAAK,EAAE,EAAE,CAAC,aAAa,CAAC,GAAG,CAAC,UAAU,CAAC;QACvC,UAAU,EAAE,EAAE,CAAC,aAAa,CAAC,GAAG,CAAC,eAAe,CAAC;QACjD,OAAO,EAAE,EAAE,CAAC,aAAa,CAAC,GAAG,CAAC,UAAU,CAAC;QACzC,WAAW,EAAE,EAAE,CAAC,iBAAiB,EAAE;QACnC,gBAAgB;KACjB,CAAC;AACJ,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { K8sClient } from './client.js';
2
+ import type { FetchOptions, RawClusterData } from './types.js';
3
+ export declare function fetchClusterData(client: K8sClient, opts: FetchOptions): Promise<RawClusterData>;
4
+ //# sourceMappingURL=fetcher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fetcher.d.ts","sourceRoot":"","sources":["../../src/k8s/fetcher.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAE/D,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,SAAS,EACjB,IAAI,EAAE,YAAY,GACjB,OAAO,CAAC,cAAc,CAAC,CAkGzB"}
@@ -0,0 +1,161 @@
1
+ export async function fetchClusterData(client, opts) {
2
+ try {
3
+ // Fetch server version and node count
4
+ const versionInfo = await client.version.getCode();
5
+ const serverVersion = versionInfo.body.gitVersion || 'unknown';
6
+ const nodeList = await client.core.listNode();
7
+ const nodeCount = nodeList.body.items.length;
8
+ // Fetch namespaces
9
+ const namespaces = await fetchNamespaces(client.core, opts.namespace);
10
+ // Fetch all resources for each namespace
11
+ const deployments = [];
12
+ const statefulSets = [];
13
+ const daemonSets = [];
14
+ const jobs = [];
15
+ const cronJobs = [];
16
+ const pods = [];
17
+ const services = [];
18
+ const ingresses = [];
19
+ for (const ns of namespaces) {
20
+ const nsName = ns.metadata?.name;
21
+ if (!nsName)
22
+ continue;
23
+ const [nsDeployments, nsStatefulSets, nsDaemonSets, nsJobs, nsCronJobs, nsPods, nsServices, nsIngresses,] = await Promise.all([
24
+ fetchDeployments(client.apps, nsName),
25
+ fetchStatefulSets(client.apps, nsName),
26
+ fetchDaemonSets(client.apps, nsName),
27
+ fetchJobs(client.batch, nsName),
28
+ fetchCronJobs(client.batch, nsName),
29
+ fetchPods(client.core, nsName, opts.selector),
30
+ fetchServices(client.core, nsName),
31
+ fetchIngresses(client.networking, nsName),
32
+ ]);
33
+ deployments.push(...nsDeployments);
34
+ statefulSets.push(...nsStatefulSets);
35
+ daemonSets.push(...nsDaemonSets);
36
+ jobs.push(...nsJobs);
37
+ cronJobs.push(...nsCronJobs);
38
+ pods.push(...nsPods);
39
+ services.push(...nsServices);
40
+ ingresses.push(...nsIngresses);
41
+ }
42
+ return {
43
+ namespaces,
44
+ deployments,
45
+ statefulSets,
46
+ daemonSets,
47
+ jobs,
48
+ cronJobs,
49
+ pods,
50
+ services,
51
+ ingresses,
52
+ serverVersion,
53
+ nodeCount,
54
+ };
55
+ }
56
+ catch (error) {
57
+ if (error instanceof Error) {
58
+ // Handle specific K8s API errors
59
+ const errorMessage = error.message.toLowerCase();
60
+ if (errorMessage.includes('econnrefused') ||
61
+ errorMessage.includes('connect') ||
62
+ errorMessage.includes('timeout')) {
63
+ throw new Error('Cannot connect to cluster. Is the cluster running?');
64
+ }
65
+ if (errorMessage.includes('forbidden') || errorMessage.includes('403')) {
66
+ throw new Error('Forbidden — missing RBAC permissions to access cluster resources');
67
+ }
68
+ if (errorMessage.includes('unauthorized') || errorMessage.includes('401')) {
69
+ throw new Error('Unauthorized — invalid credentials or token expired');
70
+ }
71
+ if (errorMessage.includes('not found') || errorMessage.includes('404')) {
72
+ throw new Error('Resource not found in cluster');
73
+ }
74
+ throw new Error(`Failed to fetch cluster data: ${error.message}`);
75
+ }
76
+ throw new Error('Failed to fetch cluster data: unknown error');
77
+ }
78
+ }
79
+ async function fetchNamespaces(core, namespace) {
80
+ if (namespace) {
81
+ const res = await core.readNamespace(namespace);
82
+ return [res.body];
83
+ }
84
+ const res = await core.listNamespace();
85
+ return res.body.items;
86
+ }
87
+ async function fetchDeployments(apps, ns) {
88
+ try {
89
+ const res = await apps.listNamespacedDeployment(ns);
90
+ return res.body.items;
91
+ }
92
+ catch (error) {
93
+ // Namespace might not have deployments
94
+ return [];
95
+ }
96
+ }
97
+ async function fetchPods(core, ns, selector) {
98
+ try {
99
+ const res = await core.listNamespacedPod(ns, undefined, undefined, undefined, undefined, selector);
100
+ return res.body.items;
101
+ }
102
+ catch (error) {
103
+ // Namespace might not have pods
104
+ return [];
105
+ }
106
+ }
107
+ async function fetchStatefulSets(apps, ns) {
108
+ try {
109
+ const res = await apps.listNamespacedStatefulSet(ns);
110
+ return res.body.items;
111
+ }
112
+ catch (error) {
113
+ return [];
114
+ }
115
+ }
116
+ async function fetchDaemonSets(apps, ns) {
117
+ try {
118
+ const res = await apps.listNamespacedDaemonSet(ns);
119
+ return res.body.items;
120
+ }
121
+ catch (error) {
122
+ return [];
123
+ }
124
+ }
125
+ async function fetchJobs(batch, ns) {
126
+ try {
127
+ const res = await batch.listNamespacedJob(ns);
128
+ return res.body.items;
129
+ }
130
+ catch (error) {
131
+ return [];
132
+ }
133
+ }
134
+ async function fetchCronJobs(batch, ns) {
135
+ try {
136
+ const res = await batch.listNamespacedCronJob(ns);
137
+ return res.body.items;
138
+ }
139
+ catch (error) {
140
+ return [];
141
+ }
142
+ }
143
+ async function fetchServices(core, ns) {
144
+ try {
145
+ const res = await core.listNamespacedService(ns);
146
+ return res.body.items;
147
+ }
148
+ catch (error) {
149
+ return [];
150
+ }
151
+ }
152
+ async function fetchIngresses(net, ns) {
153
+ try {
154
+ const res = await net.listNamespacedIngress(ns);
155
+ return res.body.items;
156
+ }
157
+ catch (error) {
158
+ return [];
159
+ }
160
+ }
161
+ //# sourceMappingURL=fetcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fetcher.js","sourceRoot":"","sources":["../../src/k8s/fetcher.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ export * from '@kubernetes/client-node';
2
+ export interface FetchOptions {
3
+ namespace?: string;
4
+ allNamespaces?: boolean;
5
+ selector?: string;
6
+ showErrors?: boolean;
7
+ }
8
+ export interface RawClusterData {
9
+ namespaces: import('@kubernetes/client-node').V1Namespace[];
10
+ deployments: import('@kubernetes/client-node').V1Deployment[];
11
+ statefulSets: import('@kubernetes/client-node').V1StatefulSet[];
12
+ daemonSets: import('@kubernetes/client-node').V1DaemonSet[];
13
+ jobs: import('@kubernetes/client-node').V1Job[];
14
+ cronJobs: import('@kubernetes/client-node').V1CronJob[];
15
+ pods: import('@kubernetes/client-node').V1Pod[];
16
+ services: import('@kubernetes/client-node').V1Service[];
17
+ ingresses: import('@kubernetes/client-node').V1Ingress[];
18
+ serverVersion?: string;
19
+ nodeCount?: number;
20
+ }
21
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/k8s/types.ts"],"names":[],"mappings":"AACA,cAAc,yBAAyB,CAAC;AAExC,MAAM,WAAW,YAAY;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,cAAc;IAC7B,UAAU,EAAE,OAAO,yBAAyB,EAAE,WAAW,EAAE,CAAC;IAC5D,WAAW,EAAE,OAAO,yBAAyB,EAAE,YAAY,EAAE,CAAC;IAC9D,YAAY,EAAE,OAAO,yBAAyB,EAAE,aAAa,EAAE,CAAC;IAChE,UAAU,EAAE,OAAO,yBAAyB,EAAE,WAAW,EAAE,CAAC;IAC5D,IAAI,EAAE,OAAO,yBAAyB,EAAE,KAAK,EAAE,CAAC;IAChD,QAAQ,EAAE,OAAO,yBAAyB,EAAE,SAAS,EAAE,CAAC;IACxD,IAAI,EAAE,OAAO,yBAAyB,EAAE,KAAK,EAAE,CAAC;IAChD,QAAQ,EAAE,OAAO,yBAAyB,EAAE,SAAS,EAAE,CAAC;IACxD,SAAS,EAAE,OAAO,yBAAyB,EAAE,SAAS,EAAE,CAAC;IACzD,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB"}
@@ -0,0 +1,3 @@
1
+ // Raw K8s resource types - re-exported from @kubernetes/client-node for convenience
2
+ export * from '@kubernetes/client-node';
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/k8s/types.ts"],"names":[],"mappings":"AAAA,oFAAoF;AACpF,cAAc,yBAAyB,CAAC"}
@@ -0,0 +1,8 @@
1
+ import React from 'react';
2
+ import type { ClusterTree } from '../tree/types.js';
3
+ interface TreeViewProps {
4
+ tree: ClusterTree;
5
+ }
6
+ export declare function TreeView({ tree }: TreeViewProps): React.ReactElement;
7
+ export {};
8
+ //# sourceMappingURL=TreeView.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TreeView.d.ts","sourceRoot":"","sources":["../../src/render/TreeView.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,KAAK,EAAE,WAAW,EAAiB,MAAM,kBAAkB,CAAC;AAGnE,UAAU,aAAa;IACrB,IAAI,EAAE,WAAW,CAAC;CACnB;AAED,wBAAgB,QAAQ,CAAC,EAAE,IAAI,EAAE,EAAE,aAAa,GAAG,KAAK,CAAC,YAAY,CAyDpE"}