kubechart 0.1.0 → 0.2.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 (60) hide show
  1. package/README.md +17 -1
  2. package/dist/cli.js +68 -9
  3. package/dist/cli.js.map +1 -1
  4. package/dist/graph/builder.d.ts +19 -0
  5. package/dist/graph/builder.d.ts.map +1 -0
  6. package/dist/graph/builder.js +140 -0
  7. package/dist/graph/builder.js.map +1 -0
  8. package/dist/output/serializer.d.ts +42 -0
  9. package/dist/output/serializer.d.ts.map +1 -0
  10. package/dist/output/serializer.js +42 -0
  11. package/dist/output/serializer.js.map +1 -0
  12. package/dist/render/BlockView.d.ts +8 -0
  13. package/dist/render/BlockView.d.ts.map +1 -0
  14. package/dist/render/BlockView.js +53 -0
  15. package/dist/render/BlockView.js.map +1 -0
  16. package/dist/render/GraphNode.d.ts +8 -0
  17. package/dist/render/GraphNode.d.ts.map +1 -0
  18. package/dist/render/GraphNode.js +48 -0
  19. package/dist/render/GraphNode.js.map +1 -0
  20. package/dist/render/GraphView.d.ts +8 -0
  21. package/dist/render/GraphView.d.ts.map +1 -0
  22. package/dist/render/GraphView.js +221 -0
  23. package/dist/render/GraphView.js.map +1 -0
  24. package/dist/render/NamespaceBlock.d.ts +9 -0
  25. package/dist/render/NamespaceBlock.d.ts.map +1 -0
  26. package/dist/render/NamespaceBlock.js +84 -0
  27. package/dist/render/NamespaceBlock.js.map +1 -0
  28. package/dist/render/StatusBar.d.ts +12 -0
  29. package/dist/render/StatusBar.d.ts.map +1 -0
  30. package/dist/render/StatusBar.js +43 -0
  31. package/dist/render/StatusBar.js.map +1 -0
  32. package/dist/render/TreeView.d.ts +2 -1
  33. package/dist/render/TreeView.d.ts.map +1 -1
  34. package/dist/render/TreeView.js +13 -12
  35. package/dist/render/TreeView.js.map +1 -1
  36. package/dist/render/WatchView.d.ts +12 -0
  37. package/dist/render/WatchView.d.ts.map +1 -0
  38. package/dist/render/WatchView.js +92 -0
  39. package/dist/render/WatchView.js.map +1 -0
  40. package/dist/render/WorkloadBlock.d.ts +9 -0
  41. package/dist/render/WorkloadBlock.d.ts.map +1 -0
  42. package/dist/render/WorkloadBlock.js +47 -0
  43. package/dist/render/WorkloadBlock.js.map +1 -0
  44. package/dist/render/ascii/box.d.ts +8 -0
  45. package/dist/render/ascii/box.d.ts.map +1 -0
  46. package/dist/render/ascii/box.js +25 -0
  47. package/dist/render/ascii/box.js.map +1 -0
  48. package/dist/render/colors.d.ts +1 -0
  49. package/dist/render/colors.d.ts.map +1 -1
  50. package/dist/render/colors.js +1 -0
  51. package/dist/render/colors.js.map +1 -1
  52. package/dist/watch/differ.d.ts +8 -0
  53. package/dist/watch/differ.d.ts.map +1 -0
  54. package/dist/watch/differ.js +113 -0
  55. package/dist/watch/differ.js.map +1 -0
  56. package/dist/watch/flash.d.ts +2 -0
  57. package/dist/watch/flash.d.ts.map +1 -0
  58. package/dist/watch/flash.js +13 -0
  59. package/dist/watch/flash.js.map +1 -0
  60. package/package.json +3 -1
package/README.md CHANGED
@@ -4,6 +4,7 @@ CLI tool to visualize Kubernetes cluster as an ASCII tree directly in your termi
4
4
 
5
5
  ## Features
6
6
 
7
+ - **Watch Mode (Default)**: Auto-refresh with countdown timer, diff highlighting, and manual refresh with `r` key
7
8
  - **ASCII Tree Visualization**: Clean, readable tree structure showing namespaces, workloads, pods, services, and ingresses
8
9
  - **Color-Coded Status**: Visual indicators for pod health (Running, Pending, Failed, etc.)
9
10
  - **Resource Type Symbols**: Distinct symbols for Deployments, StatefulSets, DaemonSets, Jobs, CronJobs, Services, and Ingresses
@@ -28,9 +29,12 @@ npx kubechart
28
29
  ### Basic Usage
29
30
 
30
31
  ```bash
31
- # Show current namespace (kubectl-compatible behavior)
32
+ # Watch mode (default) - auto-refresh every 5s
32
33
  kubechart
33
34
 
35
+ # Print once and exit
36
+ kubechart --once
37
+
34
38
  # Show all namespaces
35
39
  kubechart -A
36
40
 
@@ -38,6 +42,18 @@ kubechart -A
38
42
  kubechart -n production
39
43
  ```
40
44
 
45
+ ### Watch Mode
46
+
47
+ ```bash
48
+ # Watch with default interval (5s)
49
+ kubechart
50
+
51
+ # Custom refresh interval
52
+ kubechart --interval 10
53
+
54
+ # Manual refresh with 'r' key, quit with 'q' or Ctrl+C
55
+ ```
56
+
41
57
  ### Filtering Options
42
58
 
43
59
  ```bash
package/dist/cli.js CHANGED
@@ -6,7 +6,13 @@ import { createClient } from './k8s/client.js';
6
6
  import { fetchClusterData } from './k8s/fetcher.js';
7
7
  import { buildTree } from './tree/builder.js';
8
8
  import { TreeView } from './render/TreeView.js';
9
+ import { BlockView } from './render/BlockView.js';
10
+ import { GraphView } from './render/GraphView.js';
11
+ import { WatchView } from './render/WatchView.js';
9
12
  import { setUseColors } from './render/colors.js';
13
+ import { serializeCluster } from './output/serializer.js';
14
+ import * as fs from 'fs';
15
+ import * as yaml from 'js-yaml';
10
16
  const program = new Command();
11
17
  program
12
18
  .name('kubechart')
@@ -18,6 +24,11 @@ program
18
24
  .option('-l, --selector <sel>', 'Label selector (e.g. app=api,env=prod)')
19
25
  .option('--show-errors', 'Only show workloads with errors')
20
26
  .option('--no-color', 'Disable colored output')
27
+ .option('--once', 'Print chart once and exit (default: watch mode)')
28
+ .option('--interval <seconds>', 'Watch refresh interval (default: 5)', '5')
29
+ .option('--view <mode>', 'View mode: tree | block | graph (default: tree)', 'tree')
30
+ .option('--output <format>', 'Output format: json | yaml (requires --out-file)')
31
+ .option('--out-file <path>', 'File path to write output (requires --output)')
21
32
  .parse(process.argv);
22
33
  const options = program.opts();
23
34
  async function main() {
@@ -35,15 +46,63 @@ async function main() {
35
46
  selector: options.selector,
36
47
  showErrors: options.showErrors,
37
48
  };
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 }));
49
+ // Static mode (--once flag)
50
+ if (options.once) {
51
+ const rawData = await fetchClusterData(client, fetchOpts);
52
+ const tree = buildTree(rawData, client.contextName, {
53
+ showErrors: options.showErrors,
54
+ selector: options.selector,
55
+ });
56
+ // Output to file
57
+ if (options.output && options.outFile) {
58
+ const snapshot = serializeCluster(tree);
59
+ let content;
60
+ if (options.output === 'json') {
61
+ content = JSON.stringify(snapshot, null, 2);
62
+ }
63
+ else if (options.output === 'yaml') {
64
+ content = yaml.dump(snapshot);
65
+ }
66
+ else {
67
+ console.error(`Error: --output must be 'json' or 'yaml'`);
68
+ process.exit(1);
69
+ }
70
+ fs.writeFileSync(options.outFile, content, 'utf-8');
71
+ console.log(`Output written to ${options.outFile}`);
72
+ return;
73
+ }
74
+ if (options.output || options.outFile) {
75
+ console.error('Error: --output and --out-file must be used together');
76
+ process.exit(1);
77
+ }
78
+ // Select view component based on --view flag
79
+ let ViewComponent;
80
+ if (options.view === 'block') {
81
+ ViewComponent = BlockView;
82
+ }
83
+ else if (options.view === 'graph') {
84
+ ViewComponent = GraphView;
85
+ }
86
+ else {
87
+ ViewComponent = TreeView;
88
+ }
89
+ const { waitUntilExit } = render(React.createElement(ViewComponent, { tree }));
90
+ await waitUntilExit();
91
+ return;
92
+ }
93
+ // Watch mode (default)
94
+ const interval = parseInt(options.interval, 10);
95
+ if (isNaN(interval) || interval < 1) {
96
+ console.error('Error: --interval must be a positive number');
97
+ process.exit(1);
98
+ }
99
+ const { waitUntilExit } = render(React.createElement(WatchView, {
100
+ opts: {
101
+ interval,
102
+ fetchOpts,
103
+ client,
104
+ },
105
+ }));
47
106
  await waitUntilExit();
48
107
  }
49
108
  catch (error) {
package/dist/cli.js.map CHANGED
@@ -1 +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"}
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ import type { NamespaceNode, PodPhase } from '../tree/types.js';
2
+ export interface GraphNode {
3
+ id: string;
4
+ kind: 'Internet' | 'Ingress' | 'Service' | 'Workload' | 'Pod';
5
+ label: string;
6
+ meta: string[];
7
+ status?: PodPhase;
8
+ }
9
+ export interface GraphEdge {
10
+ from: string;
11
+ to: string;
12
+ label?: string;
13
+ }
14
+ export interface Graph {
15
+ nodes: GraphNode[];
16
+ edges: GraphEdge[];
17
+ }
18
+ export declare function buildGraph(ns: NamespaceNode): Graph;
19
+ //# sourceMappingURL=builder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"builder.d.ts","sourceRoot":"","sources":["../../src/graph/builder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEhE,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,UAAU,GAAG,SAAS,GAAG,SAAS,GAAG,UAAU,GAAG,KAAK,CAAC;IAC9D,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,MAAM,CAAC,EAAE,QAAQ,CAAC;CACnB;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,KAAK;IACpB,KAAK,EAAE,SAAS,EAAE,CAAC;IACnB,KAAK,EAAE,SAAS,EAAE,CAAC;CACpB;AAED,wBAAgB,UAAU,CAAC,EAAE,EAAE,aAAa,GAAG,KAAK,CAqInD"}
@@ -0,0 +1,140 @@
1
+ export function buildGraph(ns) {
2
+ const nodes = [];
3
+ const edges = [];
4
+ const nodeIds = new Set();
5
+ // Helper to add node if not exists
6
+ const addNode = (node) => {
7
+ if (!nodeIds.has(node.id)) {
8
+ nodes.push(node);
9
+ nodeIds.add(node.id);
10
+ }
11
+ };
12
+ // Helper to add edge
13
+ const addEdge = (edge) => {
14
+ edges.push(edge);
15
+ };
16
+ // Start with Internet node
17
+ addNode({
18
+ id: 'internet',
19
+ kind: 'Internet',
20
+ label: 'Internet',
21
+ meta: [],
22
+ });
23
+ // Process Ingresses
24
+ for (const ingress of ns.ingresses) {
25
+ const ingressId = `ingress-${ingress.name}`;
26
+ addNode({
27
+ id: ingressId,
28
+ kind: 'Ingress',
29
+ label: `Ingress`,
30
+ meta: [ingress.host, ingress.tls ? 'TLS: ✓' : 'TLS: ✗'],
31
+ });
32
+ // Edge from Internet to Ingress
33
+ addEdge({
34
+ from: 'internet',
35
+ to: ingressId,
36
+ label: ingress.host,
37
+ });
38
+ // Find target service from ingress paths
39
+ for (const path of ingress.paths) {
40
+ // Extract service name from path (simplified - assumes format like /path -> service:port)
41
+ const serviceName = path.split(':')[0] || path;
42
+ const targetService = ns.services.find((s) => s.name === serviceName);
43
+ if (targetService) {
44
+ const serviceId = `service-${targetService.name}`;
45
+ addNode({
46
+ id: serviceId,
47
+ kind: 'Service',
48
+ label: `Service: ${targetService.name}`,
49
+ meta: [
50
+ `${targetService.type} ${targetService.clusterIP}`,
51
+ `port: ${targetService.ports.join(', ')}`,
52
+ ],
53
+ });
54
+ addEdge({
55
+ from: ingressId,
56
+ to: serviceId,
57
+ label: `→ ${targetService.name}:${targetService.ports[0] || '80'}`,
58
+ });
59
+ }
60
+ }
61
+ }
62
+ // Process Services (including those not linked to Ingress)
63
+ for (const service of ns.services) {
64
+ const serviceId = `service-${service.name}`;
65
+ if (!nodeIds.has(serviceId)) {
66
+ addNode({
67
+ id: serviceId,
68
+ kind: 'Service',
69
+ label: `Service: ${service.name}`,
70
+ meta: [
71
+ `${service.type} ${service.clusterIP}`,
72
+ `port: ${service.ports.join(', ')}`,
73
+ ],
74
+ });
75
+ }
76
+ // Find pods that match this service's selector
77
+ // For simplicity, we'll link all pods in the namespace to all services
78
+ // In a real implementation, this would use label selectors
79
+ for (const workload of ns.workloads) {
80
+ for (const pod of workload.pods) {
81
+ const podId = `pod-${pod.name}`;
82
+ addNode({
83
+ id: podId,
84
+ kind: 'Pod',
85
+ label: pod.name,
86
+ meta: [
87
+ `${getPodStatusSymbol(pod.phase, pod.ready)} ${pod.phase}`,
88
+ `node: ${pod.nodeName}`,
89
+ pod.restarts > 0 ? `restarts: ${pod.restarts}` : '',
90
+ ].filter(Boolean),
91
+ status: pod.phase,
92
+ });
93
+ addEdge({
94
+ from: serviceId,
95
+ to: podId,
96
+ label: `load balances to`,
97
+ });
98
+ }
99
+ }
100
+ }
101
+ // Process workloads (as grouping for pods)
102
+ for (const workload of ns.workloads) {
103
+ const workloadId = `workload-${workload.name}`;
104
+ addNode({
105
+ id: workloadId,
106
+ kind: 'Workload',
107
+ label: `${workload.kind}: ${workload.name}`,
108
+ meta: [`ready: ${workload.ready}`, `image: ${workload.image}`],
109
+ });
110
+ // Link pods to workload
111
+ for (const pod of workload.pods) {
112
+ const podId = `pod-${pod.name}`;
113
+ addEdge({
114
+ from: podId,
115
+ to: workloadId,
116
+ });
117
+ }
118
+ }
119
+ return { nodes, edges };
120
+ }
121
+ function getPodStatusSymbol(phase, ready) {
122
+ if (phase === 'Running') {
123
+ const [readyContainers, totalContainers] = ready.split('/').map(Number);
124
+ if (readyContainers < totalContainers) {
125
+ return '◑';
126
+ }
127
+ return '●';
128
+ }
129
+ switch (phase) {
130
+ case 'Pending':
131
+ return '◌';
132
+ case 'Failed':
133
+ return '✖';
134
+ case 'Succeeded':
135
+ return '○';
136
+ default:
137
+ return '?';
138
+ }
139
+ }
140
+ //# sourceMappingURL=builder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"builder.js","sourceRoot":"","sources":["../../src/graph/builder.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,42 @@
1
+ import type { ClusterTree } from '../tree/types.js';
2
+ export interface ClusterSnapshot {
3
+ cluster: {
4
+ contextName: string;
5
+ serverVersion: string;
6
+ nodeCount: number;
7
+ fetchedAt: string;
8
+ };
9
+ namespaces: Array<{
10
+ name: string;
11
+ status: string;
12
+ workloads: Array<{
13
+ name: string;
14
+ kind: string;
15
+ ready: string;
16
+ image: string;
17
+ pods: Array<{
18
+ name: string;
19
+ phase: string;
20
+ nodeName: string;
21
+ ip: string;
22
+ restarts: number;
23
+ reason?: string;
24
+ ready: string;
25
+ }>;
26
+ }>;
27
+ services: Array<{
28
+ name: string;
29
+ type: string;
30
+ clusterIP: string;
31
+ ports: string[];
32
+ }>;
33
+ ingresses: Array<{
34
+ name: string;
35
+ host: string;
36
+ paths: string[];
37
+ tls: boolean;
38
+ }>;
39
+ }>;
40
+ }
41
+ export declare function serializeCluster(tree: ClusterTree): ClusterSnapshot;
42
+ //# sourceMappingURL=serializer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"serializer.d.ts","sourceRoot":"","sources":["../../src/output/serializer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAEpD,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE;QACP,WAAW,EAAE,MAAM,CAAC;QACpB,aAAa,EAAE,MAAM,CAAC;QACtB,SAAS,EAAE,MAAM,CAAC;QAClB,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC;IACF,UAAU,EAAE,KAAK,CAAC;QAChB,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,EAAE,MAAM,CAAC;QACf,SAAS,EAAE,KAAK,CAAC;YACf,IAAI,EAAE,MAAM,CAAC;YACb,IAAI,EAAE,MAAM,CAAC;YACb,KAAK,EAAE,MAAM,CAAC;YACd,KAAK,EAAE,MAAM,CAAC;YACd,IAAI,EAAE,KAAK,CAAC;gBACV,IAAI,EAAE,MAAM,CAAC;gBACb,KAAK,EAAE,MAAM,CAAC;gBACd,QAAQ,EAAE,MAAM,CAAC;gBACjB,EAAE,EAAE,MAAM,CAAC;gBACX,QAAQ,EAAE,MAAM,CAAC;gBACjB,MAAM,CAAC,EAAE,MAAM,CAAC;gBAChB,KAAK,EAAE,MAAM,CAAC;aACf,CAAC,CAAC;SACJ,CAAC,CAAC;QACH,QAAQ,EAAE,KAAK,CAAC;YACd,IAAI,EAAE,MAAM,CAAC;YACb,IAAI,EAAE,MAAM,CAAC;YACb,SAAS,EAAE,MAAM,CAAC;YAClB,KAAK,EAAE,MAAM,EAAE,CAAC;SACjB,CAAC,CAAC;QACH,SAAS,EAAE,KAAK,CAAC;YACf,IAAI,EAAE,MAAM,CAAC;YACb,IAAI,EAAE,MAAM,CAAC;YACb,KAAK,EAAE,MAAM,EAAE,CAAC;YAChB,GAAG,EAAE,OAAO,CAAC;SACd,CAAC,CAAC;KACJ,CAAC,CAAC;CACJ;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,WAAW,GAAG,eAAe,CAwCnE"}
@@ -0,0 +1,42 @@
1
+ export function serializeCluster(tree) {
2
+ return {
3
+ cluster: {
4
+ contextName: tree.contextName,
5
+ serverVersion: tree.serverVersion,
6
+ nodeCount: tree.nodeCount,
7
+ fetchedAt: tree.fetchedAt.toISOString(),
8
+ },
9
+ namespaces: tree.namespaces.map((ns) => ({
10
+ name: ns.name,
11
+ status: ns.status,
12
+ workloads: ns.workloads.map((wl) => ({
13
+ name: wl.name,
14
+ kind: wl.kind,
15
+ ready: wl.ready,
16
+ image: wl.image,
17
+ pods: wl.pods.map((pod) => ({
18
+ name: pod.name,
19
+ phase: pod.phase,
20
+ nodeName: pod.nodeName,
21
+ ip: pod.ip,
22
+ restarts: pod.restarts,
23
+ reason: pod.reason,
24
+ ready: pod.ready,
25
+ })),
26
+ })),
27
+ services: ns.services.map((svc) => ({
28
+ name: svc.name,
29
+ type: svc.type,
30
+ clusterIP: svc.clusterIP,
31
+ ports: svc.ports,
32
+ })),
33
+ ingresses: ns.ingresses.map((ing) => ({
34
+ name: ing.name,
35
+ host: ing.host,
36
+ paths: ing.paths,
37
+ tls: ing.tls,
38
+ })),
39
+ })),
40
+ };
41
+ }
42
+ //# sourceMappingURL=serializer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"serializer.js","sourceRoot":"","sources":["../../src/output/serializer.ts"],"names":[],"mappings":"AA0CA,MAAM,UAAU,gBAAgB,CAAC,IAAiB;IAChD,OAAO;QACL,OAAO,EAAE;YACP,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,aAAa,EAAE,IAAI,CAAC,aAAa;YACjC,SAAS,EAAE,IAAI,CAAC,SAAS;YACzB,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE;SACxC;QACD,UAAU,EAAE,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;YACvC,IAAI,EAAE,EAAE,CAAC,IAAI;YACb,MAAM,EAAE,EAAE,CAAC,MAAM;YACjB,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;gBACnC,IAAI,EAAE,EAAE,CAAC,IAAI;gBACb,IAAI,EAAE,EAAE,CAAC,IAAI;gBACb,KAAK,EAAE,EAAE,CAAC,KAAK;gBACf,KAAK,EAAE,EAAE,CAAC,KAAK;gBACf,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;oBAC1B,IAAI,EAAE,GAAG,CAAC,IAAI;oBACd,KAAK,EAAE,GAAG,CAAC,KAAK;oBAChB,QAAQ,EAAE,GAAG,CAAC,QAAQ;oBACtB,EAAE,EAAE,GAAG,CAAC,EAAE;oBACV,QAAQ,EAAE,GAAG,CAAC,QAAQ;oBACtB,MAAM,EAAE,GAAG,CAAC,MAAM;oBAClB,KAAK,EAAE,GAAG,CAAC,KAAK;iBACjB,CAAC,CAAC;aACJ,CAAC,CAAC;YACH,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;gBAClC,IAAI,EAAE,GAAG,CAAC,IAAI;gBACd,IAAI,EAAE,GAAG,CAAC,IAAI;gBACd,SAAS,EAAE,GAAG,CAAC,SAAS;gBACxB,KAAK,EAAE,GAAG,CAAC,KAAK;aACjB,CAAC,CAAC;YACH,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;gBACpC,IAAI,EAAE,GAAG,CAAC,IAAI;gBACd,IAAI,EAAE,GAAG,CAAC,IAAI;gBACd,KAAK,EAAE,GAAG,CAAC,KAAK;gBAChB,GAAG,EAAE,GAAG,CAAC,GAAG;aACb,CAAC,CAAC;SACJ,CAAC,CAAC;KACJ,CAAC;AACJ,CAAC"}
@@ -0,0 +1,8 @@
1
+ import React from 'react';
2
+ import type { ClusterTree } from '../tree/types.js';
3
+ interface BlockViewProps {
4
+ tree: ClusterTree;
5
+ }
6
+ export declare function BlockView({ tree }: BlockViewProps): React.ReactElement;
7
+ export {};
8
+ //# sourceMappingURL=BlockView.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BlockView.d.ts","sourceRoot":"","sources":["../../src/render/BlockView.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA8B,MAAM,OAAO,CAAC;AAGnD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAEpD,UAAU,cAAc;IACtB,IAAI,EAAE,WAAW,CAAC;CACnB;AAED,wBAAgB,SAAS,CAAC,EAAE,IAAI,EAAE,EAAE,cAAc,GAAG,KAAK,CAAC,YAAY,CA2DtE"}
@@ -0,0 +1,53 @@
1
+ import React, { useState, useEffect } from 'react';
2
+ import { Box, Text } from 'ink';
3
+ import { NamespaceBlock } from './NamespaceBlock.js';
4
+ export function BlockView({ tree }) {
5
+ const [terminalWidth, setTerminalWidth] = useState(process.stdout.columns || 80);
6
+ useEffect(() => {
7
+ const handleResize = () => {
8
+ setTerminalWidth(process.stdout.columns || 80);
9
+ };
10
+ process.stdout.on('resize', handleResize);
11
+ return () => {
12
+ process.stdout.off('resize', handleResize);
13
+ };
14
+ }, []);
15
+ // Calculate stats
16
+ const totalNamespaces = tree.namespaces.length;
17
+ const totalWorkloads = tree.namespaces.reduce((sum, ns) => sum + ns.workloads.length, 0);
18
+ const totalPods = tree.namespaces.reduce((sum, ns) => sum + ns.workloads.reduce((pSum, wl) => pSum + wl.pods.length, 0), 0);
19
+ const totalServices = tree.namespaces.reduce((sum, ns) => sum + ns.services.length, 0);
20
+ const totalIngresses = tree.namespaces.reduce((sum, ns) => sum + ns.ingresses.length, 0);
21
+ // Count errors (pods with Failed phase or non-zero restarts)
22
+ const totalErrors = tree.namespaces.reduce((sum, ns) => sum +
23
+ ns.workloads.reduce((wlSum, wl) => wlSum +
24
+ wl.pods.filter((pod) => pod.phase === 'Failed' || pod.restarts > 0).length, 0), 0);
25
+ return (React.createElement(Box, { flexDirection: "column" },
26
+ React.createElement(Box, { marginBottom: 1 },
27
+ React.createElement(Text, null,
28
+ "CLUSTER: ",
29
+ tree.contextName,
30
+ " | k8s ",
31
+ tree.serverVersion,
32
+ " | ",
33
+ tree.nodeCount,
34
+ " nodes")),
35
+ tree.namespaces.map((ns) => (React.createElement(NamespaceBlock, { key: ns.name, namespace: ns, terminalWidth: terminalWidth }))),
36
+ React.createElement(Box, { marginTop: 1 },
37
+ React.createElement(Text, null, "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")),
38
+ React.createElement(Box, null,
39
+ React.createElement(Text, null,
40
+ "namespaces: ",
41
+ totalNamespaces,
42
+ " | workloads: ",
43
+ totalWorkloads,
44
+ " | pods: ",
45
+ totalPods,
46
+ " | services: ",
47
+ totalServices,
48
+ " | ingresses: ",
49
+ totalIngresses,
50
+ " | errors: ",
51
+ totalErrors))));
52
+ }
53
+ //# sourceMappingURL=BlockView.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BlockView.js","sourceRoot":"","sources":["../../src/render/BlockView.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ import React from 'react';
2
+ import type { GraphNode } from '../graph/builder.js';
3
+ interface GraphNodeProps {
4
+ node: GraphNode;
5
+ }
6
+ export declare function GraphNodeComponent({ node }: GraphNodeProps): React.ReactElement;
7
+ export {};
8
+ //# sourceMappingURL=GraphNode.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GraphNode.d.ts","sourceRoot":"","sources":["../../src/render/GraphNode.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAErD,UAAU,cAAc;IACtB,IAAI,EAAE,SAAS,CAAC;CACjB;AAED,wBAAgB,kBAAkB,CAAC,EAAE,IAAI,EAAE,EAAE,cAAc,GAAG,KAAK,CAAC,YAAY,CAgD/E"}
@@ -0,0 +1,48 @@
1
+ import React from 'react';
2
+ import { Box, Text } from 'ink';
3
+ export function GraphNodeComponent({ node }) {
4
+ const getStatusColor = () => {
5
+ if (node.kind === 'Pod' && node.status) {
6
+ switch (node.status) {
7
+ case 'Running':
8
+ return 'green';
9
+ case 'Pending':
10
+ return 'yellow';
11
+ case 'Failed':
12
+ return 'red';
13
+ case 'Succeeded':
14
+ return 'gray';
15
+ default:
16
+ return 'white';
17
+ }
18
+ }
19
+ return 'white';
20
+ };
21
+ const getKindSymbol = () => {
22
+ switch (node.kind) {
23
+ case 'Internet':
24
+ return '☁';
25
+ case 'Ingress':
26
+ return '◆';
27
+ case 'Service':
28
+ return '●';
29
+ case 'Workload':
30
+ return '▲';
31
+ case 'Pod':
32
+ return '○';
33
+ default:
34
+ return '▪';
35
+ }
36
+ };
37
+ return (React.createElement(Box, { flexDirection: "column" },
38
+ React.createElement(Box, null,
39
+ React.createElement(Text, { color: getStatusColor() },
40
+ getKindSymbol(),
41
+ " ",
42
+ node.label)),
43
+ node.meta.map((line, index) => (React.createElement(Box, { key: index },
44
+ React.createElement(Text, { dimColor: true },
45
+ " ",
46
+ line))))));
47
+ }
48
+ //# sourceMappingURL=GraphNode.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GraphNode.js","sourceRoot":"","sources":["../../src/render/GraphNode.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAOhC,MAAM,UAAU,kBAAkB,CAAC,EAAE,IAAI,EAAkB;IACzD,MAAM,cAAc,GAAG,GAAG,EAAE;QAC1B,IAAI,IAAI,CAAC,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YACvC,QAAQ,IAAI,CAAC,MAAM,EAAE,CAAC;gBACpB,KAAK,SAAS;oBACZ,OAAO,OAAO,CAAC;gBACjB,KAAK,SAAS;oBACZ,OAAO,QAAQ,CAAC;gBAClB,KAAK,QAAQ;oBACX,OAAO,KAAK,CAAC;gBACf,KAAK,WAAW;oBACd,OAAO,MAAM,CAAC;gBAChB;oBACE,OAAO,OAAO,CAAC;YACnB,CAAC;QACH,CAAC;QACD,OAAO,OAAO,CAAC;IACjB,CAAC,CAAC;IAEF,MAAM,aAAa,GAAG,GAAG,EAAE;QACzB,QAAQ,IAAI,CAAC,IAAI,EAAE,CAAC;YAClB,KAAK,UAAU;gBACb,OAAO,GAAG,CAAC;YACb,KAAK,SAAS;gBACZ,OAAO,GAAG,CAAC;YACb,KAAK,SAAS;gBACZ,OAAO,GAAG,CAAC;YACb,KAAK,UAAU;gBACb,OAAO,GAAG,CAAC;YACb,KAAK,KAAK;gBACR,OAAO,GAAG,CAAC;YACb;gBACE,OAAO,GAAG,CAAC;QACf,CAAC;IACH,CAAC,CAAC;IAEF,OAAO,CACL,oBAAC,GAAG,IAAC,aAAa,EAAC,QAAQ;QACzB,oBAAC,GAAG;YACF,oBAAC,IAAI,IAAC,KAAK,EAAE,cAAc,EAAE;gBAAG,aAAa,EAAE;;gBAAG,IAAI,CAAC,KAAK,CAAQ,CAChE;QACL,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,CAC9B,oBAAC,GAAG,IAAC,GAAG,EAAE,KAAK;YACb,oBAAC,IAAI,IAAC,QAAQ;;gBAAI,IAAI,CAAQ,CAC1B,CACP,CAAC,CACE,CACP,CAAC;AACJ,CAAC"}
@@ -0,0 +1,8 @@
1
+ import React from 'react';
2
+ import type { ClusterTree } from '../tree/types.js';
3
+ interface GraphViewProps {
4
+ tree: ClusterTree;
5
+ }
6
+ export declare function GraphView({ tree }: GraphViewProps): React.ReactElement;
7
+ export {};
8
+ //# sourceMappingURL=GraphView.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GraphView.d.ts","sourceRoot":"","sources":["../../src/render/GraphView.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,KAAK,EAAE,WAAW,EAAiB,MAAM,kBAAkB,CAAC;AAGnE,UAAU,cAAc;IACtB,IAAI,EAAE,WAAW,CAAC;CACnB;AAED,wBAAgB,SAAS,CAAC,EAAE,IAAI,EAAE,EAAE,cAAc,GAAG,KAAK,CAAC,YAAY,CAgBtE"}