@kubernetesjs/cli 0.0.3 → 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 (59) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +54 -55
  3. package/commands/apply.d.ts +4 -0
  4. package/commands/apply.js +171 -0
  5. package/commands/cluster-info.d.ts +4 -0
  6. package/commands/cluster-info.js +26 -0
  7. package/commands/config-handler.d.ts +11 -0
  8. package/commands/config-handler.js +81 -0
  9. package/commands/config.d.ts +4 -0
  10. package/commands/config.js +72 -0
  11. package/commands/delete.d.ts +4 -0
  12. package/commands/delete.js +256 -0
  13. package/commands/deploy.d.ts +6 -0
  14. package/commands/deploy.js +209 -0
  15. package/commands/describe.d.ts +4 -0
  16. package/commands/describe.js +216 -0
  17. package/commands/exec.d.ts +4 -0
  18. package/commands/exec.js +145 -0
  19. package/commands/get.d.ts +4 -0
  20. package/commands/get.js +164 -0
  21. package/commands/logs.d.ts +4 -0
  22. package/commands/logs.js +110 -0
  23. package/commands/port-forward.d.ts +4 -0
  24. package/commands/port-forward.js +143 -0
  25. package/commands.d.ts +3 -0
  26. package/commands.js +93 -0
  27. package/config.d.ts +22 -0
  28. package/config.js +113 -0
  29. package/esm/commands/apply.js +133 -0
  30. package/esm/commands/cluster-info.js +21 -0
  31. package/esm/commands/config-handler.js +43 -0
  32. package/esm/commands/config.js +67 -0
  33. package/esm/commands/delete.js +218 -0
  34. package/esm/commands/deploy.js +207 -0
  35. package/esm/commands/describe.js +211 -0
  36. package/esm/commands/exec.js +140 -0
  37. package/esm/commands/get.js +159 -0
  38. package/esm/commands/logs.js +105 -0
  39. package/esm/commands/port-forward.js +138 -0
  40. package/esm/commands.js +86 -0
  41. package/esm/config.js +74 -0
  42. package/esm/index.js +19 -0
  43. package/esm/package.js +26 -0
  44. package/esm/utils.js +49 -0
  45. package/index.d.ts +3 -0
  46. package/index.js +22 -0
  47. package/package.d.ts +1 -0
  48. package/package.js +29 -0
  49. package/package.json +37 -61
  50. package/utils.d.ts +11 -0
  51. package/utils.js +58 -0
  52. package/main/client.js +0 -156
  53. package/main/index.js +0 -2598
  54. package/module/client.js +0 -129
  55. package/module/index.js +0 -2594
  56. package/src/client.ts +0 -156
  57. package/src/index.ts +0 -14187
  58. package/types/client.d.ts +0 -31
  59. package/types/index.d.ts +0 -11331
@@ -0,0 +1,159 @@
1
+ import chalk from 'chalk';
2
+ import { KubernetesClient } from 'kubernetesjs';
3
+ import { getCurrentNamespace } from '../config';
4
+ async function promptResourceType(prompter, argv) {
5
+ const resourceTypes = [
6
+ 'pods',
7
+ 'services',
8
+ 'deployments',
9
+ 'replicasets',
10
+ 'statefulsets',
11
+ 'daemonsets',
12
+ 'configmaps',
13
+ 'secrets',
14
+ 'namespaces',
15
+ 'all'
16
+ ];
17
+ const question = {
18
+ type: 'autocomplete',
19
+ name: 'resourceType',
20
+ message: 'Select resource type',
21
+ options: resourceTypes,
22
+ maxDisplayLines: 10,
23
+ required: true
24
+ };
25
+ const { resourceType } = await prompter.prompt(argv, [question]);
26
+ return resourceType;
27
+ }
28
+ function formatPodData(pod) {
29
+ const name = pod.metadata.name;
30
+ const ready = `${pod.status.containerStatuses?.filter((c) => c.ready).length || 0}/${pod.status.containerStatuses?.length || 0}`;
31
+ const status = pod.status.phase;
32
+ const restarts = pod.status.containerStatuses?.reduce((sum, c) => sum + c.restartCount, 0) || 0;
33
+ const age = new Date(pod.metadata.creationTimestamp).toLocaleString();
34
+ console.log(chalk.green(name.padEnd(50)) +
35
+ ready.padEnd(10) +
36
+ status.padEnd(15) +
37
+ restarts.toString().padEnd(10) +
38
+ age);
39
+ }
40
+ function formatServiceData(service) {
41
+ const name = service.metadata.name;
42
+ const type = service.spec.type;
43
+ const clusterIP = service.spec.clusterIP;
44
+ const externalIP = service.spec.externalIPs?.join(',') || '<none>';
45
+ const ports = service.spec.ports?.map((p) => `${p.port}:${p.targetPort}`).join(',') || '<none>';
46
+ const age = new Date(service.metadata.creationTimestamp).toLocaleString();
47
+ console.log(chalk.green(name.padEnd(30)) +
48
+ type.padEnd(15) +
49
+ clusterIP.padEnd(20) +
50
+ externalIP.padEnd(20) +
51
+ ports.padEnd(20) +
52
+ age);
53
+ }
54
+ function formatDeploymentData(deployment) {
55
+ const name = deployment.metadata.name;
56
+ const ready = `${deployment.status.readyReplicas || 0}/${deployment.status.replicas || 0}`;
57
+ const upToDate = deployment.status.updatedReplicas || 0;
58
+ const available = deployment.status.availableReplicas || 0;
59
+ const age = new Date(deployment.metadata.creationTimestamp).toLocaleString();
60
+ console.log(chalk.green(name.padEnd(30)) +
61
+ ready.padEnd(10) +
62
+ upToDate.toString().padEnd(10) +
63
+ available.toString().padEnd(10) +
64
+ age);
65
+ }
66
+ async function getAllResources(client, namespace) {
67
+ try {
68
+ const pods = await client.listCoreV1NamespacedPod({
69
+ path: { namespace },
70
+ query: { limit: 100 }
71
+ });
72
+ if (pods.items && pods.items.length > 0) {
73
+ console.log(chalk.bold('\nPODS:'));
74
+ console.log(chalk.bold('NAME'.padEnd(50) + 'READY'.padEnd(10) + 'STATUS'.padEnd(15) + 'RESTARTS'.padEnd(10) + 'AGE'));
75
+ pods.items.forEach(formatPodData);
76
+ }
77
+ const services = await client.listCoreV1NamespacedService({
78
+ path: { namespace },
79
+ query: { limit: 100 }
80
+ });
81
+ if (services.items && services.items.length > 0) {
82
+ console.log(chalk.bold('\nSERVICES:'));
83
+ console.log(chalk.bold('NAME'.padEnd(30) + 'TYPE'.padEnd(15) + 'CLUSTER-IP'.padEnd(20) + 'EXTERNAL-IP'.padEnd(20) + 'PORT(S)'.padEnd(20) + 'AGE'));
84
+ services.items.forEach(formatServiceData);
85
+ }
86
+ const deployments = await client.listAppsV1NamespacedDeployment({
87
+ path: { namespace },
88
+ query: { limit: 100 }
89
+ });
90
+ if (deployments.items && deployments.items.length > 0) {
91
+ console.log(chalk.bold('\nDEPLOYMENTS:'));
92
+ console.log(chalk.bold('NAME'.padEnd(30) + 'READY'.padEnd(10) + 'UP-TO-DATE'.padEnd(10) + 'AVAILABLE'.padEnd(10) + 'AGE'));
93
+ deployments.items.forEach(formatDeploymentData);
94
+ }
95
+ }
96
+ catch (error) {
97
+ console.error(chalk.red(`Error getting resources: ${error}`));
98
+ }
99
+ }
100
+ export default async (argv, prompter, _options) => {
101
+ try {
102
+ const client = new KubernetesClient({
103
+ restEndpoint: argv.clientUrl
104
+ });
105
+ const namespace = argv.n || argv.namespace || getCurrentNamespace();
106
+ const resourceType = argv._?.[0] || await promptResourceType(prompter, argv);
107
+ console.log(chalk.blue(`Getting ${resourceType} in namespace ${namespace}...`));
108
+ if (resourceType === 'all') {
109
+ await getAllResources(client, namespace);
110
+ return;
111
+ }
112
+ switch (resourceType) {
113
+ case 'pods':
114
+ const pods = await client.listCoreV1NamespacedPod({
115
+ path: { namespace },
116
+ query: { limit: 100 }
117
+ });
118
+ console.log(chalk.bold('NAME'.padEnd(50) + 'READY'.padEnd(10) + 'STATUS'.padEnd(15) + 'RESTARTS'.padEnd(10) + 'AGE'));
119
+ if (pods.items && pods.items.length > 0) {
120
+ pods.items.forEach(formatPodData);
121
+ }
122
+ else {
123
+ console.log(chalk.yellow('No pods found'));
124
+ }
125
+ break;
126
+ case 'services':
127
+ const services = await client.listCoreV1NamespacedService({
128
+ path: { namespace },
129
+ query: { limit: 100 }
130
+ });
131
+ console.log(chalk.bold('NAME'.padEnd(30) + 'TYPE'.padEnd(15) + 'CLUSTER-IP'.padEnd(20) + 'EXTERNAL-IP'.padEnd(20) + 'PORT(S)'.padEnd(20) + 'AGE'));
132
+ if (services.items && services.items.length > 0) {
133
+ services.items.forEach(formatServiceData);
134
+ }
135
+ else {
136
+ console.log(chalk.yellow('No services found'));
137
+ }
138
+ break;
139
+ case 'deployments':
140
+ const deployments = await client.listAppsV1NamespacedDeployment({
141
+ path: { namespace },
142
+ query: { limit: 100 }
143
+ });
144
+ console.log(chalk.bold('NAME'.padEnd(30) + 'READY'.padEnd(10) + 'UP-TO-DATE'.padEnd(10) + 'AVAILABLE'.padEnd(10) + 'AGE'));
145
+ if (deployments.items && deployments.items.length > 0) {
146
+ deployments.items.forEach(formatDeploymentData);
147
+ }
148
+ else {
149
+ console.log(chalk.yellow('No deployments found'));
150
+ }
151
+ break;
152
+ default:
153
+ console.log(chalk.yellow(`Resource type '${resourceType}' not implemented yet`));
154
+ }
155
+ }
156
+ catch (error) {
157
+ console.error(chalk.red(`Error: ${error}`));
158
+ }
159
+ };
@@ -0,0 +1,105 @@
1
+ import chalk from 'chalk';
2
+ import { KubernetesClient } from 'kubernetesjs';
3
+ import { getCurrentNamespace } from '../config';
4
+ async function promptPodName(prompter, argv, namespace, client) {
5
+ try {
6
+ const pods = await client.listCoreV1NamespacedPod({
7
+ path: { namespace },
8
+ query: { limit: 100 }
9
+ });
10
+ if (!pods.items || pods.items.length === 0) {
11
+ console.log(chalk.yellow(`No pods found in namespace ${namespace}`));
12
+ return '';
13
+ }
14
+ const options = pods.items.map(pod => ({
15
+ name: pod.metadata.name,
16
+ value: pod.metadata.name
17
+ }));
18
+ const question = {
19
+ type: 'autocomplete',
20
+ name: 'podName',
21
+ message: 'Select pod',
22
+ options,
23
+ maxDisplayLines: 10,
24
+ required: true
25
+ };
26
+ const { podName } = await prompter.prompt(argv, [question]);
27
+ return podName;
28
+ }
29
+ catch (error) {
30
+ console.error(chalk.red(`Error getting pods: ${error}`));
31
+ return '';
32
+ }
33
+ }
34
+ async function promptContainerName(prompter, argv, namespace, podName, client) {
35
+ try {
36
+ const pod = await client.readCoreV1NamespacedPod({
37
+ path: {
38
+ namespace,
39
+ name: podName
40
+ },
41
+ query: {}
42
+ });
43
+ if (!pod.spec || !pod.spec.containers || pod.spec.containers.length === 0) {
44
+ console.log(chalk.yellow(`No containers found in pod ${podName}`));
45
+ return '';
46
+ }
47
+ if (pod.spec.containers.length === 1) {
48
+ return pod.spec.containers[0].name;
49
+ }
50
+ const options = pod.spec.containers.map(container => ({
51
+ name: container.name,
52
+ value: container.name
53
+ }));
54
+ const question = {
55
+ type: 'autocomplete',
56
+ name: 'containerName',
57
+ message: 'Select container',
58
+ options,
59
+ maxDisplayLines: 10,
60
+ required: true
61
+ };
62
+ const { containerName } = await prompter.prompt(argv, [question]);
63
+ return containerName;
64
+ }
65
+ catch (error) {
66
+ console.error(chalk.red(`Error getting containers: ${error}`));
67
+ return '';
68
+ }
69
+ }
70
+ export default async (argv, prompter, _options) => {
71
+ try {
72
+ const client = new KubernetesClient({
73
+ restEndpoint: argv.clientUrl
74
+ });
75
+ const namespace = argv.n || argv.namespace || getCurrentNamespace();
76
+ const podName = argv._?.[0] || await promptPodName(prompter, argv, namespace, client);
77
+ if (!podName) {
78
+ return;
79
+ }
80
+ let containerName = argv.c || argv.container;
81
+ if (!containerName) {
82
+ containerName = await promptContainerName(prompter, argv, namespace, podName, client);
83
+ if (!containerName) {
84
+ return;
85
+ }
86
+ }
87
+ console.log(chalk.blue(`Getting logs for ${containerName ? 'container ' + containerName + ' in ' : ''}pod ${podName} in namespace ${namespace}...`));
88
+ const logs = await client.readCoreV1NamespacedPodLog({
89
+ path: {
90
+ namespace,
91
+ name: podName
92
+ },
93
+ query: {
94
+ container: containerName,
95
+ tailLines: argv.tail ? parseInt(argv.tail, 10) : undefined,
96
+ follow: false,
97
+ previous: argv.previous === true
98
+ }
99
+ });
100
+ console.log(logs);
101
+ }
102
+ catch (error) {
103
+ console.error(chalk.red(`Error: ${error}`));
104
+ }
105
+ };
@@ -0,0 +1,138 @@
1
+ import chalk from 'chalk';
2
+ import { KubernetesClient } from 'kubernetesjs';
3
+ import { getCurrentNamespace } from '../config';
4
+ import { spawn } from 'child_process';
5
+ async function promptServiceName(prompter, argv, namespace, client) {
6
+ try {
7
+ const services = await client.listCoreV1NamespacedService({
8
+ path: { namespace },
9
+ query: { limit: 100 }
10
+ });
11
+ if (!services.items || services.items.length === 0) {
12
+ console.log(chalk.yellow(`No services found in namespace ${namespace}`));
13
+ return '';
14
+ }
15
+ const options = services.items.map(service => ({
16
+ name: service.metadata.name,
17
+ value: service.metadata.name
18
+ }));
19
+ const question = {
20
+ type: 'autocomplete',
21
+ name: 'serviceName',
22
+ message: 'Select service',
23
+ options,
24
+ maxDisplayLines: 10,
25
+ required: true
26
+ };
27
+ const { serviceName } = await prompter.prompt(argv, [question]);
28
+ return serviceName;
29
+ }
30
+ catch (error) {
31
+ console.error(chalk.red(`Error getting services: ${error}`));
32
+ return '';
33
+ }
34
+ }
35
+ async function promptPortMapping(prompter, argv, namespace, serviceName, client) {
36
+ try {
37
+ const service = await client.readCoreV1NamespacedService({
38
+ path: {
39
+ namespace,
40
+ name: serviceName
41
+ },
42
+ query: {}
43
+ });
44
+ if (!service.spec || !service.spec.ports || service.spec.ports.length === 0) {
45
+ console.log(chalk.yellow(`No ports found in service ${serviceName}`));
46
+ return '';
47
+ }
48
+ if (service.spec.ports.length === 1) {
49
+ const port = service.spec.ports[0];
50
+ const localPort = port.port;
51
+ const remotePort = port.targetPort || port.port;
52
+ const confirmQuestion = {
53
+ type: 'confirm',
54
+ name: 'confirmPortMapping',
55
+ message: `Use port mapping ${localPort}:${remotePort}?`,
56
+ required: true
57
+ };
58
+ const { confirmPortMapping } = await prompter.prompt(argv, [confirmQuestion]);
59
+ if (confirmPortMapping) {
60
+ return `${localPort}:${remotePort}`;
61
+ }
62
+ }
63
+ const portMappingQuestion = {
64
+ type: 'text',
65
+ name: 'portMapping',
66
+ message: 'Enter port mapping (local:remote)',
67
+ required: true
68
+ };
69
+ const { portMapping } = await prompter.prompt(argv, [portMappingQuestion]);
70
+ return portMapping;
71
+ }
72
+ catch (error) {
73
+ console.error(chalk.red(`Error getting service ports: ${error}`));
74
+ return '';
75
+ }
76
+ }
77
+ async function portForward(namespace, resourceType, resourceName, portMapping) {
78
+ console.log(chalk.blue(`Forwarding ports ${portMapping} to ${resourceType}/${resourceName} in namespace ${namespace}...`));
79
+ console.log(chalk.yellow('Press Ctrl+C to stop port forwarding'));
80
+ const kubectlArgs = [
81
+ 'port-forward',
82
+ '-n', namespace,
83
+ `${resourceType}/${resourceName}`,
84
+ portMapping
85
+ ];
86
+ const kubectl = spawn('kubectl', kubectlArgs, {
87
+ stdio: 'inherit',
88
+ shell: true
89
+ });
90
+ return new Promise((resolve, reject) => {
91
+ kubectl.on('close', (code) => {
92
+ if (code === 0 || code === 130) { // 130 is the exit code when terminated by Ctrl+C
93
+ resolve();
94
+ }
95
+ else {
96
+ reject(new Error(`kubectl port-forward exited with code ${code}`));
97
+ }
98
+ });
99
+ kubectl.on('error', (error) => {
100
+ reject(error);
101
+ });
102
+ });
103
+ }
104
+ export default async (argv, prompter, _options) => {
105
+ try {
106
+ const client = new KubernetesClient({
107
+ restEndpoint: argv.clientUrl
108
+ });
109
+ const namespace = argv.n || argv.namespace || getCurrentNamespace();
110
+ let resourceType = 'svc';
111
+ let resourceName = '';
112
+ if (argv._?.[0]) {
113
+ const resourceArg = argv._[0];
114
+ if (resourceArg.includes('/')) {
115
+ const [type, name] = resourceArg.split('/');
116
+ resourceType = type;
117
+ resourceName = name;
118
+ }
119
+ else {
120
+ resourceName = resourceArg;
121
+ }
122
+ }
123
+ if (!resourceName) {
124
+ resourceName = await promptServiceName(prompter, argv, namespace, client);
125
+ if (!resourceName) {
126
+ return;
127
+ }
128
+ }
129
+ const portMapping = argv._?.[1] || await promptPortMapping(prompter, argv, namespace, resourceName, client);
130
+ if (!portMapping) {
131
+ return;
132
+ }
133
+ await portForward(namespace, resourceType, resourceName, portMapping);
134
+ }
135
+ catch (error) {
136
+ console.error(chalk.red(`Error: ${error}`));
137
+ }
138
+ };
@@ -0,0 +1,86 @@
1
+ import { readAndParsePackageJson } from './package';
2
+ import { extractFirst, usageText } from './utils';
3
+ // Commands
4
+ import deploy from './commands/deploy';
5
+ import get from './commands/get';
6
+ import describe from './commands/describe';
7
+ import logs from './commands/logs';
8
+ import apply from './commands/apply';
9
+ import deleteCmd from './commands/delete';
10
+ import exec from './commands/exec';
11
+ import portForward from './commands/port-forward';
12
+ import clusterInfo from './commands/cluster-info';
13
+ import config from './commands/config';
14
+ const commandMap = {
15
+ deploy,
16
+ get,
17
+ describe,
18
+ logs,
19
+ apply,
20
+ delete: deleteCmd,
21
+ exec,
22
+ 'port-forward': portForward,
23
+ 'cluster-info': clusterInfo,
24
+ config
25
+ };
26
+ import configHandler from './commands/config-handler';
27
+ export const commands = async (argv, prompter, options) => {
28
+ if (argv.version || argv.v) {
29
+ const pkg = readAndParsePackageJson();
30
+ console.log(pkg.version);
31
+ process.exit(0);
32
+ }
33
+ if (argv.config) {
34
+ const handled = await configHandler(argv, prompter, options, commandMap);
35
+ if (handled) {
36
+ prompter.close();
37
+ return argv;
38
+ }
39
+ }
40
+ let { first: command, newArgv } = extractFirst(argv);
41
+ // Show usage if explicitly requested
42
+ if (argv.help || argv.h || command === 'help') {
43
+ console.log(usageText);
44
+ process.exit(0);
45
+ }
46
+ // Prompt if no command provided
47
+ if (!command) {
48
+ const answer = await prompter.prompt(argv, [
49
+ {
50
+ type: 'autocomplete',
51
+ name: 'command',
52
+ message: 'What do you want to do?',
53
+ options: Object.keys(commandMap)
54
+ }
55
+ ]);
56
+ command = answer.command;
57
+ }
58
+ // Prompt for working directory and client URL
59
+ newArgv = await prompter.prompt(newArgv, [
60
+ {
61
+ type: 'text',
62
+ name: 'cwd',
63
+ message: 'Working directory',
64
+ required: false,
65
+ default: process.cwd(),
66
+ useDefault: true
67
+ },
68
+ {
69
+ type: 'text',
70
+ name: 'clientUrl',
71
+ message: 'Kubernetes API URL',
72
+ required: false,
73
+ default: 'http://127.0.0.1:8001',
74
+ useDefault: true
75
+ }
76
+ ]);
77
+ const commandFn = commandMap[command];
78
+ if (!commandFn) {
79
+ console.error(`Unknown command: ${command}`);
80
+ console.log(usageText);
81
+ process.exit(1);
82
+ }
83
+ await commandFn(newArgv, prompter, options);
84
+ prompter.close();
85
+ return argv;
86
+ };
package/esm/config.js ADDED
@@ -0,0 +1,74 @@
1
+ import { existsSync, readFileSync, writeFileSync } from 'fs';
2
+ import { homedir } from 'os';
3
+ import { join } from 'path';
4
+ import * as yaml from 'js-yaml';
5
+ const KUBECONFIG_PATH = join(homedir(), '.kubeconfig');
6
+ const DEFAULT_NAMESPACE = 'default';
7
+ /**
8
+ * Read and parse a YAML file
9
+ * @param filePath Path to the YAML file
10
+ * @returns Parsed YAML content
11
+ */
12
+ export function readYamlFile(filePath) {
13
+ try {
14
+ const fileContent = readFileSync(filePath, 'utf8');
15
+ return yaml.load(fileContent);
16
+ }
17
+ catch (error) {
18
+ console.error(`Error reading YAML file: ${error}`);
19
+ throw error;
20
+ }
21
+ }
22
+ /**
23
+ * Infer the resource type from a Kubernetes YAML
24
+ * @param resource The parsed Kubernetes resource
25
+ * @returns The resource type (lowercase)
26
+ */
27
+ export function inferResourceType(resource) {
28
+ if (!resource || !resource.kind) {
29
+ throw new Error('Invalid Kubernetes resource: missing kind');
30
+ }
31
+ return resource.kind.toLowerCase();
32
+ }
33
+ /**
34
+ * Get the current namespace from the local kubeconfig
35
+ * @returns The current namespace
36
+ */
37
+ export function getCurrentNamespace() {
38
+ try {
39
+ if (!existsSync(KUBECONFIG_PATH)) {
40
+ return DEFAULT_NAMESPACE;
41
+ }
42
+ const configContent = readFileSync(KUBECONFIG_PATH, 'utf8');
43
+ const config = JSON.parse(configContent);
44
+ return config.currentNamespace || DEFAULT_NAMESPACE;
45
+ }
46
+ catch (error) {
47
+ console.error(`Error reading kubeconfig: ${error}`);
48
+ return DEFAULT_NAMESPACE;
49
+ }
50
+ }
51
+ /**
52
+ * Set the current namespace in the local kubeconfig
53
+ * @param namespace The namespace to set
54
+ */
55
+ export function setCurrentNamespace(namespace) {
56
+ try {
57
+ let config = { currentNamespace: namespace };
58
+ if (existsSync(KUBECONFIG_PATH)) {
59
+ try {
60
+ const configContent = readFileSync(KUBECONFIG_PATH, 'utf8');
61
+ config = { ...JSON.parse(configContent), currentNamespace: namespace };
62
+ }
63
+ catch (error) {
64
+ console.error(`Error parsing existing kubeconfig: ${error}`);
65
+ }
66
+ }
67
+ writeFileSync(KUBECONFIG_PATH, JSON.stringify(config, null, 2), 'utf8');
68
+ console.log(`Namespace set to "${namespace}"`);
69
+ }
70
+ catch (error) {
71
+ console.error(`Error setting namespace: ${error}`);
72
+ throw error;
73
+ }
74
+ }
package/esm/index.js ADDED
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env node
2
+ import { CLI } from 'inquirerer';
3
+ import { commands } from './commands';
4
+ export const options = {
5
+ minimistOpts: {
6
+ alias: {
7
+ v: 'version',
8
+ h: 'help',
9
+ c: 'clientUrl'
10
+ }
11
+ }
12
+ };
13
+ const app = new CLI(commands, options);
14
+ app.run().then(() => {
15
+ // all done!
16
+ }).catch(error => {
17
+ console.error(error);
18
+ process.exit(1);
19
+ });
package/esm/package.js ADDED
@@ -0,0 +1,26 @@
1
+ import { existsSync, readFileSync } from 'fs';
2
+ import { dirname, join } from 'path';
3
+ // need to search due to the dist/ folder and src/, etc.
4
+ function findPackageJson(currentDir) {
5
+ const filePath = join(currentDir, 'package.json');
6
+ // Check if package.json exists in the current directory
7
+ if (existsSync(filePath)) {
8
+ return filePath;
9
+ }
10
+ // Get the parent directory
11
+ const parentDir = dirname(currentDir);
12
+ // If reached the root directory, package.json is not found
13
+ if (parentDir === currentDir) {
14
+ throw new Error('package.json not found in any parent directory');
15
+ }
16
+ // Recursively look in the parent directory
17
+ return findPackageJson(parentDir);
18
+ }
19
+ export function readAndParsePackageJson() {
20
+ // Start searching from the current directory
21
+ const pkgPath = findPackageJson(__dirname);
22
+ // Read and parse the package.json
23
+ const str = readFileSync(pkgPath, 'utf8');
24
+ const pkg = JSON.parse(str);
25
+ return pkg;
26
+ }
package/esm/utils.js ADDED
@@ -0,0 +1,49 @@
1
+ import chalk from 'chalk';
2
+ import { readAndParsePackageJson } from './package';
3
+ export const extractFirst = (argv) => {
4
+ const first = argv._?.[0];
5
+ const newArgv = {
6
+ ...argv,
7
+ _: argv._?.slice(1) ?? []
8
+ };
9
+ return { first, newArgv };
10
+ };
11
+ // Function to display the version information
12
+ export function displayVersion() {
13
+ const pkg = readAndParsePackageJson();
14
+ console.log(chalk.green(`Name: ${pkg.name}`));
15
+ console.log(chalk.blue(`Version: ${pkg.version}`));
16
+ }
17
+ export const usageText = `
18
+ Usage: k8s <command> [options]
19
+
20
+ Commands:
21
+ get [resource] List resources (pods, services, deployments, etc.)
22
+ describe [resource] Show detailed information about a specific resource
23
+ logs [pod] Display logs from a container in a pod
24
+ exec [pod] -- [cmd] Execute a command in a container
25
+ apply -f [file] Apply a configuration to a resource by file name
26
+ delete [resource] Delete resources
27
+ port-forward [svc] Forward one or more local ports to a pod
28
+ cluster-info Display cluster information
29
+ config Modify kubeconfig files
30
+ deploy Deploy a container to Kubernetes
31
+ version, -v Display the version of the CLI
32
+
33
+ Configuration File:
34
+ --config <path> Specify the path to a YAML configuration file.
35
+ Command-line options will override settings from this file if both are provided.
36
+
37
+ Namespace:
38
+ -n, --namespace Specify the namespace to use. Default is from local config or "default".
39
+
40
+ Additional Options:
41
+ -c, --clientUrl <url> Specify the Kubernetes API endpoint URL.
42
+ Default is http://127.0.0.1:8001 (kubectl proxy)
43
+
44
+ Additional Help:
45
+ $ k8s help Display this help information.
46
+ `;
47
+ export function displayUsage() {
48
+ console.log(usageText);
49
+ }
package/index.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ import { CLIOptions } from 'inquirerer';
3
+ export declare const options: Partial<CLIOptions>;
package/index.js ADDED
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.options = void 0;
5
+ const inquirerer_1 = require("inquirerer");
6
+ const commands_1 = require("./commands");
7
+ exports.options = {
8
+ minimistOpts: {
9
+ alias: {
10
+ v: 'version',
11
+ h: 'help',
12
+ c: 'clientUrl'
13
+ }
14
+ }
15
+ };
16
+ const app = new inquirerer_1.CLI(commands_1.commands, exports.options);
17
+ app.run().then(() => {
18
+ // all done!
19
+ }).catch(error => {
20
+ console.error(error);
21
+ process.exit(1);
22
+ });
package/package.d.ts ADDED
@@ -0,0 +1 @@
1
+ export declare function readAndParsePackageJson(): any;