xuanwu-cli 1.0.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 (45) hide show
  1. package/README.md +171 -0
  2. package/bin/xuanwu +20 -0
  3. package/dist/api/client.d.ts +30 -0
  4. package/dist/api/client.js +332 -0
  5. package/dist/commands/build.d.ts +5 -0
  6. package/dist/commands/build.js +57 -0
  7. package/dist/commands/connect.d.ts +5 -0
  8. package/dist/commands/connect.js +67 -0
  9. package/dist/commands/deploy.d.ts +5 -0
  10. package/dist/commands/deploy.js +85 -0
  11. package/dist/commands/env.d.ts +5 -0
  12. package/dist/commands/env.js +119 -0
  13. package/dist/commands/logs.d.ts +5 -0
  14. package/dist/commands/logs.js +39 -0
  15. package/dist/commands/pods.d.ts +5 -0
  16. package/dist/commands/pods.js +56 -0
  17. package/dist/commands/scale.d.ts +5 -0
  18. package/dist/commands/scale.js +32 -0
  19. package/dist/commands/svc.d.ts +5 -0
  20. package/dist/commands/svc.js +100 -0
  21. package/dist/config/store.d.ts +18 -0
  22. package/dist/config/store.js +108 -0
  23. package/dist/config/types.d.ts +86 -0
  24. package/dist/config/types.js +5 -0
  25. package/dist/index.d.ts +4 -0
  26. package/dist/index.js +142 -0
  27. package/dist/output/formatter.d.ts +15 -0
  28. package/dist/output/formatter.js +95 -0
  29. package/docs/DESIGN.md +363 -0
  30. package/docs//345/276/205/344/274/230/345/214/226.md +89 -0
  31. package/package.json +31 -0
  32. package/src/api/client.ts +380 -0
  33. package/src/commands/build.ts +67 -0
  34. package/src/commands/connect.ts +75 -0
  35. package/src/commands/deploy.ts +90 -0
  36. package/src/commands/env.ts +144 -0
  37. package/src/commands/logs.ts +47 -0
  38. package/src/commands/pods.ts +60 -0
  39. package/src/commands/scale.ts +35 -0
  40. package/src/commands/svc.ts +114 -0
  41. package/src/config/store.ts +86 -0
  42. package/src/config/types.ts +99 -0
  43. package/src/index.ts +127 -0
  44. package/src/output/formatter.ts +112 -0
  45. package/tsconfig.json +17 -0
@@ -0,0 +1,85 @@
1
+ "use strict";
2
+ /**
3
+ * 部署命令
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.makeDeployCommand = makeDeployCommand;
7
+ const commander_1 = require("commander");
8
+ const store_1 = require("../config/store");
9
+ const client_1 = require("../api/client");
10
+ const formatter_1 = require("../output/formatter");
11
+ function makeDeployCommand() {
12
+ const cmd = new commander_1.Command('deploy')
13
+ .description('Deploy services to environment')
14
+ .argument('<namespace>', 'Target namespace')
15
+ .argument('<service-name>', 'Service name')
16
+ .option('-t, --type <type>', 'Service type (application|database|image)', 'image')
17
+ .option('--git <url>', 'Git repository URL')
18
+ .option('--git-branch <branch>', 'Git branch', 'main')
19
+ .option('--build-type <type>', 'Build type (template|dockerfile)', 'template')
20
+ .option('--language <lang>', 'Language (java-springboot|nodejs|python|golang)')
21
+ .option('--dockerfile-path <path>', 'Dockerfile path')
22
+ .option('--db-type <type>', 'Database type (mysql|redis|postgres|elasticsearch)')
23
+ .option('--db-version <version>', 'Database version')
24
+ .option('--root-password <password>', 'Root password')
25
+ .option('--password <password>', 'Password')
26
+ .option('--user <user>', 'Username')
27
+ .option('--database <name>', 'Database name')
28
+ .option('--image <image>', 'Container image')
29
+ .option('-p, --port <port>', 'Container port')
30
+ .option('-r, --replicas <num>', 'Number of replicas', '1')
31
+ .option('--cpu <value>', 'CPU limit')
32
+ .option('--memory <value>', 'Memory limit')
33
+ .option('--domain <prefix>', 'Domain prefix')
34
+ .option('-e, --env <key=value>', 'Environment variables', (val, memo = {}) => {
35
+ const [key, value] = val.split('=');
36
+ memo[key] = value;
37
+ return memo;
38
+ }, {})
39
+ .action(async (namespace, serviceName, options) => {
40
+ const conn = store_1.configStore.getDefaultConnection();
41
+ if (!conn) {
42
+ formatter_1.OutputFormatter.error('No connection configured');
43
+ return;
44
+ }
45
+ const type = options.type;
46
+ const deployOptions = {
47
+ namespace,
48
+ serviceName,
49
+ type,
50
+ port: options.port ? parseInt(options.port) : undefined,
51
+ replicas: options.replicas ? parseInt(options.replicas) : undefined,
52
+ cpu: options.cpu,
53
+ memory: options.memory,
54
+ domain: options.domain,
55
+ envVars: options.env
56
+ };
57
+ // 根据类型添加配置
58
+ if (type === 'application') {
59
+ deployOptions.git = options.git;
60
+ deployOptions.gitBranch = options.gitBranch;
61
+ deployOptions.buildType = options.buildType;
62
+ deployOptions.language = options.language;
63
+ deployOptions.dockerfilePath = options.dockerfilePath;
64
+ }
65
+ else if (type === 'database') {
66
+ deployOptions.dbType = options.dbType;
67
+ deployOptions.dbVersion = options.dbVersion;
68
+ deployOptions.rootPassword = options.rootPassword;
69
+ deployOptions.password = options.password;
70
+ deployOptions.user = options.user;
71
+ deployOptions.database = options.database;
72
+ }
73
+ else if (type === 'image') {
74
+ deployOptions.image = options.image;
75
+ }
76
+ const client = (0, client_1.createClient)(conn);
77
+ const result = await client.deploy(deployOptions);
78
+ if (!result.success) {
79
+ formatter_1.OutputFormatter.error(result.error.message);
80
+ return;
81
+ }
82
+ formatter_1.OutputFormatter.success(`Service "${serviceName}" deployed to ${namespace}`);
83
+ });
84
+ return cmd;
85
+ }
@@ -0,0 +1,5 @@
1
+ /**
2
+ * 环境管理命令
3
+ */
4
+ import { Command } from 'commander';
5
+ export declare function makeEnvCommand(): Command;
@@ -0,0 +1,119 @@
1
+ "use strict";
2
+ /**
3
+ * 环境管理命令
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.makeEnvCommand = makeEnvCommand;
7
+ const commander_1 = require("commander");
8
+ const store_1 = require("../config/store");
9
+ const client_1 = require("../api/client");
10
+ const formatter_1 = require("../output/formatter");
11
+ function makeEnvCommand() {
12
+ const cmd = new commander_1.Command('env')
13
+ .description('Manage environments (K8s namespaces)');
14
+ cmd
15
+ .command('ls')
16
+ .description('List accessible environments')
17
+ .action(async () => {
18
+ const conn = store_1.configStore.getDefaultConnection();
19
+ if (!conn) {
20
+ formatter_1.OutputFormatter.error('No connection configured. Run: xuanwu connect add <name> -e <endpoint> -t <token>');
21
+ return;
22
+ }
23
+ const client = (0, client_1.createClient)(conn);
24
+ const result = await client.listNamespaces();
25
+ if (!result.success) {
26
+ formatter_1.OutputFormatter.error(result.error.message);
27
+ return;
28
+ }
29
+ const spaces = result.data || [];
30
+ if (spaces.length === 0) {
31
+ formatter_1.OutputFormatter.info('No environments found');
32
+ return;
33
+ }
34
+ formatter_1.OutputFormatter.table(['Name', 'Identifier', 'Environment', 'Status'], spaces.map((s) => [
35
+ s.name || s.identifier,
36
+ s.identifier,
37
+ s.environment,
38
+ s.status || 'active'
39
+ ]));
40
+ });
41
+ cmd
42
+ .command('create <namespace>')
43
+ .description('Create a new environment (K8s namespace)')
44
+ .option('-p, --project-id <id>', 'Project ID')
45
+ .option('-e, --environment <env>', 'Environment type (development|staging|production)', 'development')
46
+ .action(async (namespace, options) => {
47
+ const conn = store_1.configStore.getDefaultConnection();
48
+ if (!conn) {
49
+ formatter_1.OutputFormatter.error('No connection configured');
50
+ return;
51
+ }
52
+ const client = (0, client_1.createClient)(conn);
53
+ let projectId = options.projectId;
54
+ // 如果没有指定 project-id,尝试获取第一个项目
55
+ if (!projectId) {
56
+ const projectsResult = await client.getProjects();
57
+ if (!projectsResult.success || !projectsResult.data || projectsResult.data.length === 0) {
58
+ formatter_1.OutputFormatter.error('No projects found. Please specify --project-id');
59
+ return;
60
+ }
61
+ projectId = projectsResult.data[0].id;
62
+ formatter_1.OutputFormatter.info(`Using project: ${projectsResult.data[0].name}`);
63
+ }
64
+ const result = await client.createNamespaceWithProject(namespace, projectId, options.environment);
65
+ if (!result.success) {
66
+ formatter_1.OutputFormatter.error(result.error.message);
67
+ return;
68
+ }
69
+ formatter_1.OutputFormatter.success(`Environment "${namespace}" created`);
70
+ });
71
+ cmd
72
+ .command('rm <namespace>')
73
+ .description('Delete an environment')
74
+ .action(async (namespace) => {
75
+ const conn = store_1.configStore.getDefaultConnection();
76
+ if (!conn) {
77
+ formatter_1.OutputFormatter.error('No connection configured');
78
+ return;
79
+ }
80
+ const client = (0, client_1.createClient)(conn);
81
+ // 先获取 namespace ID
82
+ const infoResult = await client.getNamespaceInfo(namespace);
83
+ if (!infoResult.success || !infoResult.data) {
84
+ formatter_1.OutputFormatter.error(`Environment "${namespace}" not found`);
85
+ return;
86
+ }
87
+ const envData = Array.isArray(infoResult.data) ? infoResult.data[0] : infoResult.data;
88
+ const id = envData.id;
89
+ const result = await client.deleteNamespace(id);
90
+ if (!result.success) {
91
+ formatter_1.OutputFormatter.error(result.error.message);
92
+ return;
93
+ }
94
+ formatter_1.OutputFormatter.success(`Environment "${namespace}" deleted`);
95
+ });
96
+ cmd
97
+ .command('info <namespace>')
98
+ .description('Show environment details')
99
+ .action(async (namespace) => {
100
+ const conn = store_1.configStore.getDefaultConnection();
101
+ if (!conn) {
102
+ formatter_1.OutputFormatter.error('No connection configured');
103
+ return;
104
+ }
105
+ const client = (0, client_1.createClient)(conn);
106
+ const result = await client.getNamespaceInfo(namespace);
107
+ if (!result.success) {
108
+ formatter_1.OutputFormatter.error(result.error.message);
109
+ return;
110
+ }
111
+ const info = result.data;
112
+ formatter_1.OutputFormatter.info(`Name: ${info.name}`);
113
+ formatter_1.OutputFormatter.info(`Identifier: ${info.identifier}`);
114
+ formatter_1.OutputFormatter.info(`Namespace: ${info.namespace}`);
115
+ formatter_1.OutputFormatter.info(`Environment: ${info.environment}`);
116
+ formatter_1.OutputFormatter.info(`Status: ${info.status}`);
117
+ });
118
+ return cmd;
119
+ }
@@ -0,0 +1,5 @@
1
+ /**
2
+ * 日志命令
3
+ */
4
+ import { Command } from 'commander';
5
+ export declare function makeLogsCommand(): Command;
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ /**
3
+ * 日志命令
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.makeLogsCommand = makeLogsCommand;
7
+ const commander_1 = require("commander");
8
+ const store_1 = require("../config/store");
9
+ const client_1 = require("../api/client");
10
+ const formatter_1 = require("../output/formatter");
11
+ function makeLogsCommand() {
12
+ const cmd = new commander_1.Command('logs')
13
+ .description('View service logs')
14
+ .argument('<namespace>', 'Target namespace')
15
+ .argument('<service-name>', 'Service name')
16
+ .option('-n, --lines <num>', 'Number of lines', '100')
17
+ .option('-f, --follow', 'Follow logs in real-time (SSE)')
18
+ .action(async (namespace, serviceName, options) => {
19
+ const conn = store_1.configStore.getDefaultConnection();
20
+ if (!conn) {
21
+ formatter_1.OutputFormatter.error('No connection configured');
22
+ return;
23
+ }
24
+ const client = (0, client_1.createClient)(conn);
25
+ if (options.follow) {
26
+ // 使用 SSE 实时日志
27
+ await client.streamLogs(namespace, serviceName);
28
+ }
29
+ else {
30
+ const result = await client.getLogs(namespace, serviceName, parseInt(options.lines), false);
31
+ if (!result.success) {
32
+ formatter_1.OutputFormatter.error(result.error.message);
33
+ return;
34
+ }
35
+ console.log(result.data?.logs || result.data || '');
36
+ }
37
+ });
38
+ return cmd;
39
+ }
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Pods 命令
3
+ */
4
+ import { Command } from 'commander';
5
+ export declare function makePodsCommand(): Command;
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+ /**
3
+ * Pods 命令
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.makePodsCommand = makePodsCommand;
7
+ const commander_1 = require("commander");
8
+ const store_1 = require("../config/store");
9
+ const client_1 = require("../api/client");
10
+ const formatter_1 = require("../output/formatter");
11
+ function getAge(timestamp) {
12
+ if (!timestamp)
13
+ return '-';
14
+ const created = new Date(timestamp);
15
+ const now = new Date();
16
+ const diff = Math.floor((now.getTime() - created.getTime()) / 1000);
17
+ if (diff < 60)
18
+ return `${diff}s`;
19
+ if (diff < 3600)
20
+ return `${Math.floor(diff / 60)}m`;
21
+ if (diff < 86400)
22
+ return `${Math.floor(diff / 3600)}h`;
23
+ return `${Math.floor(diff / 86400)}d`;
24
+ }
25
+ function makePodsCommand() {
26
+ const cmd = new commander_1.Command('pods')
27
+ .description('List pods')
28
+ .argument('<namespace>', 'Target namespace')
29
+ .argument('<service-name>', 'Service name')
30
+ .action(async (namespace, serviceName) => {
31
+ const conn = store_1.configStore.getDefaultConnection();
32
+ if (!conn) {
33
+ formatter_1.OutputFormatter.error('No connection configured');
34
+ return;
35
+ }
36
+ const client = (0, client_1.createClient)(conn);
37
+ const result = await client.listPods(namespace, serviceName);
38
+ if (!result.success) {
39
+ formatter_1.OutputFormatter.error(result.error.message);
40
+ return;
41
+ }
42
+ const pods = Array.isArray(result.data) ? result.data : (result.data?.items || []);
43
+ if (pods.length === 0) {
44
+ formatter_1.OutputFormatter.info('No pods found');
45
+ return;
46
+ }
47
+ formatter_1.OutputFormatter.table(['Name', 'Status', 'Ready', 'Restarts', 'Age'], pods.map((p) => [
48
+ p.metadata?.name || 'unknown',
49
+ p.status?.phase || 'Unknown',
50
+ `${p.status?.containerStatuses?.filter((c) => c.ready).length || 0}/${p.spec?.containers?.length || 0}`,
51
+ p.status?.containerStatuses?.[0]?.restartCount?.toString() || '0',
52
+ getAge(p.metadata?.creationTimestamp)
53
+ ]));
54
+ });
55
+ return cmd;
56
+ }
@@ -0,0 +1,5 @@
1
+ /**
2
+ * 扩缩容命令
3
+ */
4
+ import { Command } from 'commander';
5
+ export declare function makeScaleCommand(): Command;
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ /**
3
+ * 扩缩容命令
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.makeScaleCommand = makeScaleCommand;
7
+ const commander_1 = require("commander");
8
+ const store_1 = require("../config/store");
9
+ const client_1 = require("../api/client");
10
+ const formatter_1 = require("../output/formatter");
11
+ function makeScaleCommand() {
12
+ const cmd = new commander_1.Command('scale')
13
+ .description('Scale services')
14
+ .argument('<namespace>', 'Target namespace')
15
+ .argument('<service-name>', 'Service name')
16
+ .requiredOption('-r, --replicas <num>', 'Number of replicas')
17
+ .action(async (namespace, serviceName, options) => {
18
+ const conn = store_1.configStore.getDefaultConnection();
19
+ if (!conn) {
20
+ formatter_1.OutputFormatter.error('No connection configured');
21
+ return;
22
+ }
23
+ const client = (0, client_1.createClient)(conn);
24
+ const result = await client.scale(namespace, serviceName, parseInt(options.replicas));
25
+ if (!result.success) {
26
+ formatter_1.OutputFormatter.error(result.error.message);
27
+ return;
28
+ }
29
+ formatter_1.OutputFormatter.success(`Scaled to ${options.replicas} replicas`);
30
+ });
31
+ return cmd;
32
+ }
@@ -0,0 +1,5 @@
1
+ /**
2
+ * 服务管理命令
3
+ */
4
+ import { Command } from 'commander';
5
+ export declare function makeSvcCommand(): Command;
@@ -0,0 +1,100 @@
1
+ "use strict";
2
+ /**
3
+ * 服务管理命令
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.makeSvcCommand = makeSvcCommand;
7
+ const commander_1 = require("commander");
8
+ const store_1 = require("../config/store");
9
+ const client_1 = require("../api/client");
10
+ const formatter_1 = require("../output/formatter");
11
+ function getAge(timestamp) {
12
+ if (!timestamp)
13
+ return '-';
14
+ const created = new Date(timestamp);
15
+ const now = new Date();
16
+ const diff = Math.floor((now.getTime() - created.getTime()) / 1000);
17
+ if (diff < 60)
18
+ return `${diff}s`;
19
+ if (diff < 3600)
20
+ return `${Math.floor(diff / 60)}m`;
21
+ if (diff < 86400)
22
+ return `${Math.floor(diff / 3600)}h`;
23
+ return `${Math.floor(diff / 86400)}d`;
24
+ }
25
+ function makeSvcCommand() {
26
+ const cmd = new commander_1.Command('svc')
27
+ .description('Manage services');
28
+ cmd
29
+ .command('ls <namespace>')
30
+ .description('List services in namespace')
31
+ .action(async (namespace) => {
32
+ const conn = store_1.configStore.getDefaultConnection();
33
+ if (!conn) {
34
+ formatter_1.OutputFormatter.error('No connection configured');
35
+ return;
36
+ }
37
+ const client = (0, client_1.createClient)(conn);
38
+ const result = await client.listServices(namespace);
39
+ if (!result.success) {
40
+ formatter_1.OutputFormatter.error(result.error.message);
41
+ return;
42
+ }
43
+ const services = result.data || [];
44
+ if (services.length === 0) {
45
+ formatter_1.OutputFormatter.info(`No services in ${namespace}`);
46
+ return;
47
+ }
48
+ formatter_1.OutputFormatter.table(['Name', 'Ready', 'Up-to-date', 'Available', 'Age'], services.map((s) => [
49
+ s.metadata?.name || 'unknown',
50
+ `${s.status?.readyReplicas || 0}/${s.status?.replicas || 0}`,
51
+ s.status?.updatedReplicas || 0,
52
+ s.status?.availableReplicas || 0,
53
+ getAge(s.metadata?.creationTimestamp)
54
+ ]));
55
+ });
56
+ cmd
57
+ .command('status <namespace> <service-name>')
58
+ .description('Get service status')
59
+ .action(async (namespace, serviceName) => {
60
+ const conn = store_1.configStore.getDefaultConnection();
61
+ if (!conn) {
62
+ formatter_1.OutputFormatter.error('No connection configured');
63
+ return;
64
+ }
65
+ const client = (0, client_1.createClient)(conn);
66
+ const result = await client.getServiceStatus(namespace, serviceName);
67
+ if (!result.success) {
68
+ formatter_1.OutputFormatter.error(result.error.message);
69
+ return;
70
+ }
71
+ const info = result.data;
72
+ formatter_1.OutputFormatter.info(`Service: ${info.name}`);
73
+ formatter_1.OutputFormatter.info(`Namespace: ${info.namespace}`);
74
+ formatter_1.OutputFormatter.info(`Replicas: ${info.replicas}`);
75
+ formatter_1.OutputFormatter.info(`Ready Replicas: ${info.readyReplicas}`);
76
+ formatter_1.OutputFormatter.info(`Available Replicas: ${info.availableReplicas}`);
77
+ formatter_1.OutputFormatter.info(`Image: ${info.image}`);
78
+ if (info.labels) {
79
+ formatter_1.OutputFormatter.info(`Labels: ${JSON.stringify(info.labels)}`);
80
+ }
81
+ });
82
+ cmd
83
+ .command('rm <namespace> <service-name>')
84
+ .description('Delete a service')
85
+ .action(async (namespace, serviceName) => {
86
+ const conn = store_1.configStore.getDefaultConnection();
87
+ if (!conn) {
88
+ formatter_1.OutputFormatter.error('No connection configured');
89
+ return;
90
+ }
91
+ const client = (0, client_1.createClient)(conn);
92
+ const result = await client.deleteService(namespace, serviceName);
93
+ if (!result.success) {
94
+ formatter_1.OutputFormatter.error(result.error.message);
95
+ return;
96
+ }
97
+ formatter_1.OutputFormatter.success(`Service "${serviceName}" deleted`);
98
+ });
99
+ return cmd;
100
+ }
@@ -0,0 +1,18 @@
1
+ /**
2
+ * 配置存储
3
+ */
4
+ import { Config, Connection } from './types';
5
+ export declare class ConfigStore {
6
+ private config;
7
+ constructor();
8
+ private load;
9
+ private save;
10
+ getConnections(): Connection[];
11
+ getConnection(name: string): Connection | undefined;
12
+ getDefaultConnection(): Connection | undefined;
13
+ addConnection(connection: Connection): void;
14
+ removeConnection(name: string): void;
15
+ setDefaultConnection(name: string): void;
16
+ getConfig(): Config;
17
+ }
18
+ export declare const configStore: ConfigStore;
@@ -0,0 +1,108 @@
1
+ "use strict";
2
+ /**
3
+ * 配置存储
4
+ */
5
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
6
+ if (k2 === undefined) k2 = k;
7
+ var desc = Object.getOwnPropertyDescriptor(m, k);
8
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
9
+ desc = { enumerable: true, get: function() { return m[k]; } };
10
+ }
11
+ Object.defineProperty(o, k2, desc);
12
+ }) : (function(o, m, k, k2) {
13
+ if (k2 === undefined) k2 = k;
14
+ o[k2] = m[k];
15
+ }));
16
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
17
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
18
+ }) : function(o, v) {
19
+ o["default"] = v;
20
+ });
21
+ var __importStar = (this && this.__importStar) || (function () {
22
+ var ownKeys = function(o) {
23
+ ownKeys = Object.getOwnPropertyNames || function (o) {
24
+ var ar = [];
25
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
26
+ return ar;
27
+ };
28
+ return ownKeys(o);
29
+ };
30
+ return function (mod) {
31
+ if (mod && mod.__esModule) return mod;
32
+ var result = {};
33
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
34
+ __setModuleDefault(result, mod);
35
+ return result;
36
+ };
37
+ })();
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.configStore = exports.ConfigStore = void 0;
40
+ const fs = __importStar(require("fs"));
41
+ const path = __importStar(require("path"));
42
+ const os = __importStar(require("os"));
43
+ const CONFIG_DIR = path.join(os.homedir(), '.xuanwu');
44
+ const CONFIG_FILE = path.join(CONFIG_DIR, 'config.json');
45
+ const DEFAULT_CONFIG = {
46
+ version: '1.0',
47
+ connections: []
48
+ };
49
+ class ConfigStore {
50
+ constructor() {
51
+ this.config = this.load();
52
+ }
53
+ load() {
54
+ try {
55
+ if (fs.existsSync(CONFIG_FILE)) {
56
+ const data = fs.readFileSync(CONFIG_FILE, 'utf-8');
57
+ return JSON.parse(data);
58
+ }
59
+ }
60
+ catch (error) {
61
+ console.error('Failed to load config:', error);
62
+ }
63
+ return { ...DEFAULT_CONFIG };
64
+ }
65
+ save() {
66
+ try {
67
+ if (!fs.existsSync(CONFIG_DIR)) {
68
+ fs.mkdirSync(CONFIG_DIR, { recursive: true });
69
+ }
70
+ fs.writeFileSync(CONFIG_FILE, JSON.stringify(this.config, null, 2));
71
+ }
72
+ catch (error) {
73
+ console.error('Failed to save config:', error);
74
+ throw error;
75
+ }
76
+ }
77
+ getConnections() {
78
+ return this.config.connections;
79
+ }
80
+ getConnection(name) {
81
+ return this.config.connections.find(c => c.name === name);
82
+ }
83
+ getDefaultConnection() {
84
+ return this.config.connections.find(c => c.isDefault);
85
+ }
86
+ addConnection(connection) {
87
+ // Remove existing with same name
88
+ this.config.connections = this.config.connections.filter(c => c.name !== connection.name);
89
+ this.config.connections.push(connection);
90
+ this.save();
91
+ }
92
+ removeConnection(name) {
93
+ this.config.connections = this.config.connections.filter(c => c.name !== name);
94
+ this.save();
95
+ }
96
+ setDefaultConnection(name) {
97
+ this.config.connections = this.config.connections.map(c => ({
98
+ ...c,
99
+ isDefault: c.name === name
100
+ }));
101
+ this.save();
102
+ }
103
+ getConfig() {
104
+ return this.config;
105
+ }
106
+ }
107
+ exports.ConfigStore = ConfigStore;
108
+ exports.configStore = new ConfigStore();
@@ -0,0 +1,86 @@
1
+ /**
2
+ * xuanwu-cli 类型定义
3
+ */
4
+ export interface Connection {
5
+ name: string;
6
+ endpoint: string;
7
+ token: string;
8
+ isDefault: boolean;
9
+ }
10
+ export interface Config {
11
+ version: string;
12
+ connections: Connection[];
13
+ }
14
+ export interface ServiceType {
15
+ type: 'application' | 'database' | 'image';
16
+ }
17
+ export interface ApplicationOptions extends ServiceType {
18
+ git?: string;
19
+ gitBranch?: string;
20
+ buildType?: 'template' | 'dockerfile';
21
+ language?: string;
22
+ dockerfilePath?: string;
23
+ }
24
+ export interface DatabaseOptions extends ServiceType {
25
+ dbType: 'mysql' | 'redis' | 'postgres' | 'elasticsearch';
26
+ dbVersion: string;
27
+ rootPassword?: string;
28
+ password?: string;
29
+ user?: string;
30
+ database?: string;
31
+ }
32
+ export interface ImageOptions extends ServiceType {
33
+ image: string;
34
+ }
35
+ export interface DeployOptions {
36
+ namespace: string;
37
+ serviceName: string;
38
+ type: 'application' | 'database' | 'image';
39
+ port?: number;
40
+ replicas?: number;
41
+ cpu?: string;
42
+ memory?: string;
43
+ domain?: string;
44
+ envVars?: Record<string, string>;
45
+ volume?: string;
46
+ git?: string;
47
+ gitBranch?: string;
48
+ buildType?: 'template' | 'dockerfile';
49
+ language?: string;
50
+ dockerfilePath?: string;
51
+ dbType?: 'mysql' | 'redis' | 'postgres' | 'elasticsearch';
52
+ dbVersion?: string;
53
+ rootPassword?: string;
54
+ password?: string;
55
+ user?: string;
56
+ database?: string;
57
+ image?: string;
58
+ }
59
+ export interface ServiceInfo {
60
+ name: string;
61
+ type: string;
62
+ status: string;
63
+ ready: string;
64
+ image: string;
65
+ age: string;
66
+ ports: number[];
67
+ endpoint?: string;
68
+ }
69
+ export interface NamespaceInfo {
70
+ name: string;
71
+ status: string;
72
+ age: string;
73
+ }
74
+ export interface CLIResult<T = any> {
75
+ success: boolean;
76
+ data?: T;
77
+ error?: {
78
+ code: string;
79
+ message: string;
80
+ details?: any;
81
+ };
82
+ meta?: {
83
+ timestamp: string;
84
+ duration?: number;
85
+ };
86
+ }