@lark-apaas/miaoda-cli 0.1.4 → 0.1.5-beta.27ede41
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 +6 -5
- package/dist/api/deploy/index.js +13 -1
- package/dist/api/deploy/modern-types.js +23 -0
- package/dist/api/deploy/modern.js +78 -0
- package/dist/api/deploy/plugin-instances-types.js +6 -0
- package/dist/api/deploy/plugin-instances.js +22 -0
- package/dist/api/observability/api.js +10 -0
- package/dist/api/observability/index.js +2 -1
- package/dist/cli/commands/app/index.js +84 -2
- package/dist/cli/commands/deploy/modern.js +50 -0
- package/dist/cli/commands/index.js +33 -5
- package/dist/cli/commands/observability/index.js +62 -6
- package/dist/cli/commands/shared.js +5 -0
- package/dist/cli/commands/skills/index.js +63 -0
- package/dist/cli/handlers/app/index.js +6 -1
- package/dist/cli/handlers/app/init.js +88 -0
- package/dist/cli/handlers/deploy/modern.js +33 -0
- package/dist/cli/handlers/observability/helpers.js +4 -0
- package/dist/cli/handlers/observability/index.js +3 -1
- package/dist/cli/handlers/observability/log.js +8 -2
- package/dist/cli/handlers/observability/source-stack.js +389 -0
- package/dist/cli/handlers/observability/trace.js +7 -1
- package/dist/cli/handlers/skills/index.js +7 -0
- package/dist/cli/handlers/skills/status.js +31 -0
- package/dist/cli/handlers/skills/sync.js +38 -0
- package/dist/services/app/init/index.js +12 -0
- package/dist/services/app/init/install.js +101 -0
- package/dist/services/app/init/template.js +87 -0
- package/dist/services/deploy/modern/atoms/build.js +59 -0
- package/dist/services/deploy/modern/atoms/context.js +27 -0
- package/dist/services/deploy/modern/atoms/index.js +17 -0
- package/dist/services/deploy/modern/atoms/local-release.js +27 -0
- package/dist/services/deploy/modern/atoms/pre-release.js +13 -0
- package/dist/services/deploy/modern/atoms/save-plugin-instances.js +72 -0
- package/dist/services/deploy/modern/atoms/upload.js +246 -0
- package/dist/services/deploy/modern/check.js +53 -0
- package/dist/services/deploy/modern/constants.js +13 -0
- package/dist/services/deploy/modern/index.js +16 -0
- package/dist/services/deploy/modern/pipelines/index.js +5 -0
- package/dist/services/deploy/modern/pipelines/local.js +75 -0
- package/dist/services/deploy/modern/protocol.js +122 -0
- package/dist/services/deploy/modern/run-types.js +4 -0
- package/dist/services/deploy/modern/run.js +13 -0
- package/dist/services/deploy/modern/template-key-map.js +22 -0
- package/dist/services/skills/index.js +5 -0
- package/dist/services/skills/status.js +37 -0
- package/dist/utils/coding-steering.js +85 -0
- package/dist/utils/git.js +22 -0
- package/dist/utils/http.js +21 -11
- package/dist/utils/npm-pack.js +55 -0
- package/dist/utils/spark-meta.js +42 -0
- package/package.json +1 -1
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.syncCodingSteering = syncCodingSteering;
|
|
7
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
8
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
9
|
+
const npm_pack_1 = require("../utils/npm-pack");
|
|
10
|
+
const logger_1 = require("../utils/logger");
|
|
11
|
+
const STEERING_PACKAGE = '@lark-apaas/coding-steering';
|
|
12
|
+
/**
|
|
13
|
+
* 把 coding-steering 包内 _common/skills + <stack>/skills 同步到 <targetDir>/.agent/steering/skills/,
|
|
14
|
+
* 同名 stack 子目录覆盖 _common。tech.md 存在时也同步到 .agent/steering/tech.md。
|
|
15
|
+
*
|
|
16
|
+
* 纯本地 atom(pull npm package + 拷贝文件),不属于任何 cli 域;放在 utils 让
|
|
17
|
+
* app init handler 与独立 skills sync handler 都能复用。
|
|
18
|
+
*/
|
|
19
|
+
function syncCodingSteering(opts) {
|
|
20
|
+
const logPrefix = opts.logPrefix ?? 'skills';
|
|
21
|
+
(0, logger_1.log)(logPrefix, `Fetching ${STEERING_PACKAGE}@${opts.version ?? 'latest'}...`);
|
|
22
|
+
const fetched = (0, npm_pack_1.fetchNpmPackage)({
|
|
23
|
+
packageName: STEERING_PACKAGE,
|
|
24
|
+
version: opts.version,
|
|
25
|
+
});
|
|
26
|
+
try {
|
|
27
|
+
const steeringRoot = node_path_1.default.join(fetched.extractDir, 'steering');
|
|
28
|
+
const stackDir = node_path_1.default.join(steeringRoot, opts.stack);
|
|
29
|
+
const commonSkillsDir = node_path_1.default.join(steeringRoot, '_common', 'skills');
|
|
30
|
+
// steering 落到 .agent/skills/steering/<stack>/。.agent/skills/ 是 agent skills 的
|
|
31
|
+
// 公共容器,steering 是其中一个 producer,<stack> 再做命名空间隔离。内部仍保留
|
|
32
|
+
// 包内 steering/<stack>/skills/ 的结构,便于按"包内子目录 → 本地子目录"一一对应排查。
|
|
33
|
+
const dstRoot = node_path_1.default.join(opts.targetDir, '.agent', 'skills', 'steering', opts.stack);
|
|
34
|
+
const dstSkillsDir = node_path_1.default.join(dstRoot, 'skills');
|
|
35
|
+
node_fs_1.default.mkdirSync(dstSkillsDir, { recursive: true });
|
|
36
|
+
let techSynced = false;
|
|
37
|
+
const techSrc = node_path_1.default.join(stackDir, 'tech.md');
|
|
38
|
+
if (node_fs_1.default.existsSync(techSrc)) {
|
|
39
|
+
node_fs_1.default.copyFileSync(techSrc, node_path_1.default.join(dstRoot, 'tech.md'));
|
|
40
|
+
techSynced = true;
|
|
41
|
+
}
|
|
42
|
+
const synced = [];
|
|
43
|
+
// 先拷 _common/skills/,再拷 <stack>/skills/。stack 同名覆盖 common
|
|
44
|
+
if (node_fs_1.default.existsSync(commonSkillsDir)) {
|
|
45
|
+
for (const name of node_fs_1.default.readdirSync(commonSkillsDir)) {
|
|
46
|
+
const src = node_path_1.default.join(commonSkillsDir, name);
|
|
47
|
+
if (!node_fs_1.default.statSync(src).isDirectory())
|
|
48
|
+
continue;
|
|
49
|
+
copyDir(src, node_path_1.default.join(dstSkillsDir, name));
|
|
50
|
+
synced.push(`_common/skills/${name}`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
const stackSkillsDir = node_path_1.default.join(stackDir, 'skills');
|
|
54
|
+
if (node_fs_1.default.existsSync(stackSkillsDir)) {
|
|
55
|
+
for (const name of node_fs_1.default.readdirSync(stackSkillsDir)) {
|
|
56
|
+
const src = node_path_1.default.join(stackSkillsDir, name);
|
|
57
|
+
if (!node_fs_1.default.statSync(src).isDirectory())
|
|
58
|
+
continue;
|
|
59
|
+
const dst = node_path_1.default.join(dstSkillsDir, name);
|
|
60
|
+
if (node_fs_1.default.existsSync(dst))
|
|
61
|
+
node_fs_1.default.rmSync(dst, { recursive: true, force: true });
|
|
62
|
+
copyDir(src, dst);
|
|
63
|
+
synced.push(`${opts.stack}/skills/${name}`);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
(0, logger_1.log)(logPrefix, `Synced ${String(synced.length)} skill(s), tech.md ${techSynced ? 'yes' : 'no'}`);
|
|
67
|
+
return { version: fetched.version, syncedSkills: synced, techSynced };
|
|
68
|
+
}
|
|
69
|
+
finally {
|
|
70
|
+
fetched.cleanup();
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
function copyDir(src, dest) {
|
|
74
|
+
node_fs_1.default.mkdirSync(dest, { recursive: true });
|
|
75
|
+
for (const entry of node_fs_1.default.readdirSync(src, { withFileTypes: true })) {
|
|
76
|
+
const srcPath = node_path_1.default.join(src, entry.name);
|
|
77
|
+
const destPath = node_path_1.default.join(dest, entry.name);
|
|
78
|
+
if (entry.isDirectory()) {
|
|
79
|
+
copyDir(srcPath, destPath);
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
node_fs_1.default.copyFileSync(srcPath, destPath);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
package/dist/utils/git.js
CHANGED
|
@@ -2,6 +2,27 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.getCurrentGitBranch = getCurrentGitBranch;
|
|
4
4
|
const node_child_process_1 = require("node:child_process");
|
|
5
|
+
const GIT_LOCAL_ENV_KEYS = new Set([
|
|
6
|
+
'GIT_ALTERNATE_OBJECT_DIRECTORIES',
|
|
7
|
+
'GIT_CONFIG',
|
|
8
|
+
'GIT_CONFIG_PARAMETERS',
|
|
9
|
+
'GIT_CONFIG_COUNT',
|
|
10
|
+
'GIT_OBJECT_DIRECTORY',
|
|
11
|
+
'GIT_DIR',
|
|
12
|
+
'GIT_WORK_TREE',
|
|
13
|
+
'GIT_IMPLICIT_WORK_TREE',
|
|
14
|
+
'GIT_GRAFT_FILE',
|
|
15
|
+
'GIT_INDEX_FILE',
|
|
16
|
+
'GIT_NO_REPLACE_OBJECTS',
|
|
17
|
+
'GIT_REPLACE_REF_BASE',
|
|
18
|
+
'GIT_PREFIX',
|
|
19
|
+
'GIT_INTERNAL_SUPER_PREFIX',
|
|
20
|
+
'GIT_SHALLOW_FILE',
|
|
21
|
+
'GIT_COMMON_DIR',
|
|
22
|
+
]);
|
|
23
|
+
function withoutGitLocalEnv() {
|
|
24
|
+
return Object.fromEntries(Object.entries(process.env).filter(([key]) => !GIT_LOCAL_ENV_KEYS.has(key)));
|
|
25
|
+
}
|
|
5
26
|
/**
|
|
6
27
|
* 读取 cwd 所在仓库的当前分支名。
|
|
7
28
|
*
|
|
@@ -13,6 +34,7 @@ function getCurrentGitBranch(cwd = process.cwd()) {
|
|
|
13
34
|
try {
|
|
14
35
|
result = (0, node_child_process_1.spawnSync)('git', ['rev-parse', '--abbrev-ref', 'HEAD'], {
|
|
15
36
|
cwd,
|
|
37
|
+
env: withoutGitLocalEnv(),
|
|
16
38
|
encoding: 'utf8',
|
|
17
39
|
stdio: ['ignore', 'pipe', 'ignore'],
|
|
18
40
|
});
|
package/dist/utils/http.js
CHANGED
|
@@ -60,13 +60,27 @@ function createClient(opts) {
|
|
|
60
60
|
instance.interceptors.request.use(applyCanaryHeader);
|
|
61
61
|
return instance;
|
|
62
62
|
}
|
|
63
|
-
/**
|
|
63
|
+
/**
|
|
64
|
+
* 默认灰度泳道。当前 miaoda CLI 接入的新接口(modern deploy 等)只在该泳道生效,
|
|
65
|
+
* 缺省走这个。MIAODA_CANARY_HEADER 可显式覆盖;设为空字符串则去掉头。
|
|
66
|
+
*/
|
|
67
|
+
const DEFAULT_CANARY_HEADER = 'boe_miaoda_doubao';
|
|
68
|
+
/**
|
|
69
|
+
* 注入 x-tt-env 小流量头:env 显式设值 > DEFAULT_CANARY_HEADER。
|
|
70
|
+
*
|
|
71
|
+
* 当泳道形如 `ppe_xxx`(PPE 预发环境)时,额外加 `x-use-ppe: 1`;
|
|
72
|
+
* BOE 泳道(`boe_xxx`)只带 x-tt-env,不加该头。
|
|
73
|
+
*/
|
|
64
74
|
function applyCanaryHeader(reqConfig) {
|
|
65
|
-
|
|
75
|
+
// env 显式设为空字符串视为"去掉灰度头";未设置时用 DEFAULT_CANARY_HEADER
|
|
76
|
+
const canary = process.env.MIAODA_CANARY_HEADER ?? DEFAULT_CANARY_HEADER;
|
|
66
77
|
if (!canary)
|
|
67
78
|
return reqConfig;
|
|
68
79
|
const headers = new Headers(reqConfig.headers);
|
|
69
80
|
headers.set('x-tt-env', canary);
|
|
81
|
+
if (canary.startsWith('ppe_')) {
|
|
82
|
+
headers.set('x-use-ppe', '1');
|
|
83
|
+
}
|
|
70
84
|
reqConfig.headers = headers;
|
|
71
85
|
return reqConfig;
|
|
72
86
|
}
|
|
@@ -103,14 +117,14 @@ async function handleInnerEnvelope(response, url, opts) {
|
|
|
103
117
|
throw new error_1.HttpError(response.status, url, `${opts.errPrefix}: ${String(response.status)} ${response.statusText}`);
|
|
104
118
|
}
|
|
105
119
|
const result = await response.json();
|
|
120
|
+
// verbose: 把完整响应体打到 stderr,便于排查(业务错误 / 字段缺失等)
|
|
121
|
+
if ((0, config_1.getConfig)().verbose) {
|
|
122
|
+
(0, logger_1.debug)(` resp: ${truncateForLog(safeStringify(result), 2000)}`);
|
|
123
|
+
}
|
|
106
124
|
if (typeof result === 'object' && result !== null && 'status_code' in result) {
|
|
107
125
|
const env = result;
|
|
108
126
|
if (env.status_code !== undefined && env.status_code !== '0') {
|
|
109
127
|
const msg = env.message ?? env.error_msg ?? 'unknown error';
|
|
110
|
-
// verbose: 把完整业务错误信封打到 stderr,便于追溯
|
|
111
|
-
if ((0, config_1.getConfig)().verbose) {
|
|
112
|
-
(0, logger_1.debug)(` envelope: ${truncateForLog(safeStringify(env), 1000)}`);
|
|
113
|
-
}
|
|
114
128
|
const mapped = opts.mapErr?.(env.status_code, msg);
|
|
115
129
|
if (mapped)
|
|
116
130
|
throw mapped;
|
|
@@ -163,12 +177,8 @@ function logResponseFailure(method, url, err, startMs) {
|
|
|
163
177
|
const msgPart = e.message ? ` (${e.message})` : '';
|
|
164
178
|
(0, logger_1.debug)(`✗ ${method} ${url} ${statusPart} ${String(elapsedMs)}ms${logidPart}${msgPart}`);
|
|
165
179
|
}
|
|
166
|
-
/** BAM gateway 在不同 PSM/版本上 logid 落在不同 header;按命中顺序取第一个非空。 */
|
|
167
180
|
function pickLogid(headers) {
|
|
168
|
-
return
|
|
169
|
-
headers.get('x-logid') ??
|
|
170
|
-
headers.get('logid') ??
|
|
171
|
-
headers.get('x-tt-trace-tag'));
|
|
181
|
+
return headers.get('x-tt-logid');
|
|
172
182
|
}
|
|
173
183
|
function safeStringify(v) {
|
|
174
184
|
try {
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.fetchNpmPackage = fetchNpmPackage;
|
|
7
|
+
const node_child_process_1 = require("node:child_process");
|
|
8
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
9
|
+
const node_os_1 = __importDefault(require("node:os"));
|
|
10
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
11
|
+
const error_1 = require("./error");
|
|
12
|
+
const logger_1 = require("./logger");
|
|
13
|
+
const DEFAULT_REGISTRY = 'https://registry.npmmirror.com/';
|
|
14
|
+
/**
|
|
15
|
+
* `npm pack <pkg>@<ver> --registry <r>` + `tar -xzf`,解到临时目录。
|
|
16
|
+
* extractDir 是包内容根(含 package.json)。使用完必须 cleanup()。
|
|
17
|
+
*/
|
|
18
|
+
function fetchNpmPackage(opts) {
|
|
19
|
+
const registry = opts.registry ?? process.env.MIAODA_NPM_REGISTRY ?? DEFAULT_REGISTRY;
|
|
20
|
+
const version = opts.version ?? 'latest';
|
|
21
|
+
const pkgSpec = `${opts.packageName}@${version}`;
|
|
22
|
+
const tmpDir = node_fs_1.default.mkdtempSync(node_path_1.default.join(node_os_1.default.tmpdir(), 'miaoda-pack-'));
|
|
23
|
+
try {
|
|
24
|
+
(0, logger_1.debug)(`npm pack ${pkgSpec} --registry ${registry} → ${tmpDir}`);
|
|
25
|
+
const stdout = (0, node_child_process_1.execFileSync)('npm', ['pack', pkgSpec, '--pack-destination', tmpDir, '--json', '--registry', registry], { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] });
|
|
26
|
+
const packInfo = JSON.parse(stdout);
|
|
27
|
+
const tgzFilename = packInfo[0]?.filename;
|
|
28
|
+
const pkgVersion = packInfo[0]?.version ?? version;
|
|
29
|
+
if (!tgzFilename) {
|
|
30
|
+
throw new error_1.AppError('NPM_PACK_FAILED', `npm pack 未返回 filename:${pkgSpec}`);
|
|
31
|
+
}
|
|
32
|
+
const tgzPath = node_path_1.default.join(tmpDir, tgzFilename);
|
|
33
|
+
const extractDir = node_path_1.default.join(tmpDir, 'extracted');
|
|
34
|
+
node_fs_1.default.mkdirSync(extractDir, { recursive: true });
|
|
35
|
+
(0, node_child_process_1.execFileSync)('tar', ['-xzf', tgzPath, '-C', extractDir], {
|
|
36
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
37
|
+
});
|
|
38
|
+
return {
|
|
39
|
+
extractDir: node_path_1.default.join(extractDir, 'package'),
|
|
40
|
+
version: pkgVersion,
|
|
41
|
+
cleanup: () => {
|
|
42
|
+
node_fs_1.default.rmSync(tmpDir, { recursive: true, force: true });
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
catch (err) {
|
|
47
|
+
node_fs_1.default.rmSync(tmpDir, { recursive: true, force: true });
|
|
48
|
+
if (err instanceof error_1.AppError)
|
|
49
|
+
throw err;
|
|
50
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
51
|
+
throw new error_1.AppError('NPM_PACK_FAILED', `抓取 npm 包失败 (${pkgSpec}): ${msg}`, {
|
|
52
|
+
next_actions: [`确认包已发布到 registry:${registry}`, `检查版本号 / dist-tag 拼写`],
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.readSparkMeta = readSparkMeta;
|
|
7
|
+
exports.writeSparkMeta = writeSparkMeta;
|
|
8
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
9
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
10
|
+
const SPARK_DIR = '.spark';
|
|
11
|
+
const SPARK_META_FILE = 'meta.json';
|
|
12
|
+
function readSparkMeta(appDir) {
|
|
13
|
+
const metaPath = node_path_1.default.join(appDir, SPARK_DIR, SPARK_META_FILE);
|
|
14
|
+
if (!node_fs_1.default.existsSync(metaPath))
|
|
15
|
+
return {};
|
|
16
|
+
try {
|
|
17
|
+
return JSON.parse(node_fs_1.default.readFileSync(metaPath, 'utf-8'));
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
return {};
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* merge 写入:已有字段保留,undefined 不覆盖;不再维护时间戳。
|
|
25
|
+
*/
|
|
26
|
+
function writeSparkMeta(appDir, meta) {
|
|
27
|
+
const sparkDir = node_path_1.default.join(appDir, SPARK_DIR);
|
|
28
|
+
node_fs_1.default.mkdirSync(sparkDir, { recursive: true });
|
|
29
|
+
const metaPath = node_path_1.default.join(sparkDir, SPARK_META_FILE);
|
|
30
|
+
let existing = {};
|
|
31
|
+
if (node_fs_1.default.existsSync(metaPath)) {
|
|
32
|
+
try {
|
|
33
|
+
existing = JSON.parse(node_fs_1.default.readFileSync(metaPath, 'utf-8'));
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
/* 读不出就当空 */
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
const defined = Object.fromEntries(Object.entries(meta).filter(([, v]) => v !== undefined));
|
|
40
|
+
const merged = { ...existing, ...defined };
|
|
41
|
+
node_fs_1.default.writeFileSync(metaPath, JSON.stringify(merged, null, 2) + '\n', 'utf-8');
|
|
42
|
+
}
|