@aipt/idp-cli 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/README.md +23 -0
- package/bin/idp.mjs +117 -0
- package/package.json +25 -0
package/README.md
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# IDP Developer CLI
|
|
2
|
+
|
|
3
|
+
`idp` 是开发者统一入口,不是第三套 Kernel。它用中文发现当前上下文,并将工程能力委托给 Dyyto、将交付和环境能力委托给 idp-deploy。
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
node bin/idp.mjs doctor
|
|
7
|
+
node bin/idp.mjs app inspect --cwd /absolute/project
|
|
8
|
+
node bin/idp.mjs capability catalog search
|
|
9
|
+
node bin/idp.mjs delivery lifecycle check
|
|
10
|
+
node bin/idp.mjs environment foundation doctor
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
开发、计划和渲染不要求 Kubernetes;具体部署动作是否需要环境资源,由 idp-deploy 合同判断。可用 `IDP_DYYTO_BIN` 和 `IDP_DEPLOY_BIN` 指向源码构建产物,默认也会发现 PATH 或同级源码仓库。
|
|
14
|
+
|
|
15
|
+
## 验证
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm run check
|
|
19
|
+
npm run example
|
|
20
|
+
npm run example:clean
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
人工检查 `.examples/delegation` 的输出:doctor 应显示本地开发可进行,委托动作应保留完整 argv,且无需 Kubernetes。真实脚手架仍走 Dyyto 的 Catalog、Plan、Apply、Verifier,不由本仓库复制模板。
|
package/bin/idp.mjs
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { accessSync, constants, existsSync } from 'node:fs';
|
|
3
|
+
import { dirname, resolve } from 'node:path';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
import { spawnSync } from 'node:child_process';
|
|
6
|
+
|
|
7
|
+
const repoRoot = resolve(dirname(fileURLToPath(import.meta.url)), '..');
|
|
8
|
+
const spacesRoot = resolve(repoRoot, '..');
|
|
9
|
+
|
|
10
|
+
function executable(path) {
|
|
11
|
+
try { accessSync(path, constants.X_OK); return true; } catch { return false; }
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function commandOnPath(name) {
|
|
15
|
+
const result = spawnSync('which', [name], { encoding: 'utf8', shell: false });
|
|
16
|
+
return result.status === 0 ? result.stdout.trim() : null;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function discoverKernel(kind) {
|
|
20
|
+
const isDyyto = kind === 'dyyto';
|
|
21
|
+
const configured = process.env[isDyyto ? 'IDP_DYYTO_BIN' : 'IDP_DEPLOY_BIN'];
|
|
22
|
+
if (configured) return { command: process.execPath, prefix: [resolve(configured)], source: 'environment' };
|
|
23
|
+
const pathName = isDyyto ? 'dyyto' : 'idpctl';
|
|
24
|
+
const fromPath = commandOnPath(pathName);
|
|
25
|
+
if (fromPath) return { command: fromPath, prefix: [], source: 'path' };
|
|
26
|
+
const local = isDyyto
|
|
27
|
+
? resolve(spacesRoot, 'dyyto/apps/cli/dist/cli.js')
|
|
28
|
+
: resolve(spacesRoot, 'idp-deploy/bin/idpctl.mjs');
|
|
29
|
+
if (existsSync(local)) return { command: process.execPath, prefix: [local], source: 'sibling' };
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function parseGlobal(argv) {
|
|
34
|
+
let cwd = process.cwd();
|
|
35
|
+
let json = false;
|
|
36
|
+
const rest = [];
|
|
37
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
38
|
+
if (argv[index] === '--cwd') {
|
|
39
|
+
if (!argv[index + 1]) throw new Error('--cwd 缺少目录参数');
|
|
40
|
+
cwd = resolve(argv[++index]);
|
|
41
|
+
} else if (argv[index] === '--json') { json = true; rest.push(argv[index]); }
|
|
42
|
+
else rest.push(argv[index]);
|
|
43
|
+
}
|
|
44
|
+
if (!existsSync(cwd)) throw new Error(`工作目录不存在:${cwd}`);
|
|
45
|
+
return { cwd, json, rest };
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function run(kernelName, args, cwd) {
|
|
49
|
+
const kernel = discoverKernel(kernelName);
|
|
50
|
+
if (!kernel) {
|
|
51
|
+
const variable = kernelName === 'dyyto' ? 'IDP_DYYTO_BIN' : 'IDP_DEPLOY_BIN';
|
|
52
|
+
throw new Error(`未找到 ${kernelName} Kernel;请安装对应 CLI,或设置 ${variable}`);
|
|
53
|
+
}
|
|
54
|
+
const child = spawnSync(kernel.command, [...kernel.prefix, ...args], {
|
|
55
|
+
cwd, stdio: 'inherit', shell: false, env: process.env
|
|
56
|
+
});
|
|
57
|
+
if (child.error) throw child.error;
|
|
58
|
+
return child.status ?? 1;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function doctor(cwd, json) {
|
|
62
|
+
const dyyto = discoverKernel('dyyto');
|
|
63
|
+
const deploy = discoverKernel('deploy');
|
|
64
|
+
const report = {
|
|
65
|
+
schemaVersion: 1,
|
|
66
|
+
cwd,
|
|
67
|
+
project: { git: existsSync(resolve(cwd, '.git')), dyytoManifest: existsSync(resolve(cwd, '.dyyto/manifest.json')) },
|
|
68
|
+
kernels: { dyyto: Boolean(dyyto), idpDeploy: Boolean(deploy) },
|
|
69
|
+
optionalTargets: { kubectl: Boolean(commandOnPath('kubectl')) },
|
|
70
|
+
readiness: {
|
|
71
|
+
development: Boolean(dyyto),
|
|
72
|
+
deliveryPlanning: Boolean(deploy),
|
|
73
|
+
kubernetesDeployment: false
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
if (json) console.log(JSON.stringify(report));
|
|
77
|
+
else {
|
|
78
|
+
console.log('IDP 开发环境检查');
|
|
79
|
+
console.log(`工程目录:${cwd}`);
|
|
80
|
+
console.log(`工程采用 Kernel:${report.kernels.dyyto ? '已就绪' : '缺失'}`);
|
|
81
|
+
console.log(`交付部署 Kernel:${report.kernels.idpDeploy ? '已就绪' : '缺失'}`);
|
|
82
|
+
console.log(`Kubernetes 客户端:${report.optionalTargets.kubectl ? '已安装(未探测目标环境)' : '未安装(不影响本地开发)'}`);
|
|
83
|
+
console.log(`本地开发:${report.readiness.development ? '可进行' : '需先安装 Dyyto CLI'}`);
|
|
84
|
+
}
|
|
85
|
+
return report.readiness.development ? 0 : 2;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function help() {
|
|
89
|
+
console.log(`idp:开发者统一入口(薄门面)
|
|
90
|
+
|
|
91
|
+
用法:
|
|
92
|
+
idp doctor [--cwd <目录>] [--json]
|
|
93
|
+
idp app create|inspect [--cwd <目录>] [Kernel 参数...]
|
|
94
|
+
idp capability <Dyyto 参数...> [--cwd <目录>]
|
|
95
|
+
idp delivery <idpctl 参数...> [--cwd <目录>]
|
|
96
|
+
idp environment <idpctl 参数...> [--cwd <目录>]
|
|
97
|
+
|
|
98
|
+
说明:工程能力由 Dyyto Kernel 执行;交付与环境能力由 idp-deploy Kernel 执行。`);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
try {
|
|
102
|
+
const { cwd, json, rest } = parseGlobal(process.argv.slice(2));
|
|
103
|
+
if (rest.length === 0 || rest[0] === '--help' || rest[0] === 'help') { help(); process.exit(0); }
|
|
104
|
+
const [group, action, ...args] = rest;
|
|
105
|
+
let status;
|
|
106
|
+
if (group === 'doctor') status = doctor(cwd, json);
|
|
107
|
+
else if (group === 'app' && action === 'create') status = run('dyyto', ['create', ...args], cwd);
|
|
108
|
+
else if (group === 'app' && action === 'inspect') status = run('dyyto', ['inspect', ...args], cwd);
|
|
109
|
+
else if (group === 'capability' && action) status = run('dyyto', [action, ...args], cwd);
|
|
110
|
+
else if (group === 'delivery' && action) status = run('deploy', [action, ...args], cwd);
|
|
111
|
+
else if (group === 'environment' && action) status = run('deploy', [action, ...args], cwd);
|
|
112
|
+
else throw new Error(`未知命令:${rest.join(' ')};运行 idp --help 查看用法`);
|
|
113
|
+
process.exit(status);
|
|
114
|
+
} catch (error) {
|
|
115
|
+
console.error(`错误:${error.message}`);
|
|
116
|
+
process.exit(2);
|
|
117
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@aipt/idp-cli",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "IDP 开发者统一入口,委托 Dyyto 与 idp-deploy 执行工程和交付能力。",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"idp": "./bin/idp.mjs"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"bin",
|
|
11
|
+
"README.md"
|
|
12
|
+
],
|
|
13
|
+
"publishConfig": {
|
|
14
|
+
"access": "public"
|
|
15
|
+
},
|
|
16
|
+
"engines": {
|
|
17
|
+
"node": ">=20"
|
|
18
|
+
},
|
|
19
|
+
"scripts": {
|
|
20
|
+
"test": "node --test tests/*.test.mjs",
|
|
21
|
+
"check": "node --check bin/idp.mjs && npm test",
|
|
22
|
+
"example": "node scripts/run-example.mjs",
|
|
23
|
+
"example:clean": "node scripts/clean-example.mjs"
|
|
24
|
+
}
|
|
25
|
+
}
|