@lark-apaas/miaoda-cli 0.1.19-alpha.574dcb5 → 0.1.19-alpha.62c220f
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 +2 -1
- package/dist/api/comment/api.js +7 -25
- package/dist/api/comment/types.js +4 -0
- package/dist/cli/commands/deploy/modern.js +2 -0
- package/dist/cli/commands/index.js +1 -0
- package/dist/cli/commands/registry/index.js +16 -4
- package/dist/cli/handlers/comment/list.js +89 -19
- package/dist/cli/handlers/deploy/patch.js +1 -0
- package/dist/cli/handlers/registry/add.js +55 -12
- package/dist/cli/handlers/skills/sync.js +12 -4
- package/dist/services/deploy/modern/atoms/design-build.js +8 -0
- package/dist/services/deploy/modern/atoms/index.js +2 -1
- package/dist/services/deploy/modern/patch/index.js +6 -1
- package/dist/services/deploy/modern/patch/source-scan.js +2 -0
- package/dist/services/deploy/modern/pipelines/design-local.js +30 -21
- package/dist/utils/http.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -75,6 +75,7 @@ miaoda registry add deck-slide --overwrite # 目标已存在时覆盖(
|
|
|
75
75
|
- **多匹配全拉**:token 命中多个同名条目时全部 copy-in(如 `add foo` 把 `foo.jsx` + `foo.css` 一起拉),想只要其一就用完整文件名或 relPath。
|
|
76
76
|
- **拍平落地**:所有文件**拍平**到项目根(`scripts/deck-slide.js` → 项目 `deck-slide.js`,不保留子目录);闭包内同名 basename 撞车时后者覆盖前者。
|
|
77
77
|
- **skip-by-disk**:项目已有同名(拍平后的 basename)文件默认跳过,`--overwrite` 才覆盖;不写任何安装记账文件,项目文件树即状态。
|
|
78
|
+
- **add 回执带 usage**:`add` 结果的 `entries` 只列**你请求的条目**(不含被 `Depends` 传递拉进来的依赖——依赖照常落地在 `added`/`skipped`,但那是"管道"),逐条给出 `usage`(USAGE 块原文)与 `dependsOn`,Agent `add` 完即可直接读用法,无需再 `registry list`。请求的条目即使已存在被跳过也回带 usage(`status` 标 `added`/`skipped`,据此判断磁盘上是 registry 版还是你改过的旧版)。`--json` 结构为 `{registryVersion, added, skipped, dryRun, entries}`;pretty(默认)输出 `registry@<ver>` + `added:`/`skipped:` 逗号列表 + 各请求条目的 USAGE 块,稳定 label、无 JSON 数组、无截断,对 Agent 与人同样可读。
|
|
78
79
|
- `--version <ver>` 指定 registry 包版本或 dist-tag(缺省 `latest`),`--dir <path>` 指定项目目录(缺省当前目录)。
|
|
79
80
|
|
|
80
81
|
## 全局参数
|
|
@@ -88,7 +89,7 @@ miaoda registry add deck-slide --overwrite # 目标已存在时覆盖(
|
|
|
88
89
|
## 环境变量
|
|
89
90
|
|
|
90
91
|
- `MIAODA_APP_ID`:默认应用 ID,等价于 `--app-id`。
|
|
91
|
-
- `MIAODA_CANARY_HEADER`:HTTP 请求的 `x-tt-env` 小流量头取值。未设置时默认 `
|
|
92
|
+
- `MIAODA_CANARY_HEADER`:HTTP 请求的 `x-tt-env` 小流量头取值。未设置时默认 `boe_miaoda_ccm`;设为空字符串则不带该头(例:`export MIAODA_CANARY_HEADER=boe_xxx`)。值形如 `ppe_xxx` 时额外带上 `x-use-ppe: 1`。
|
|
92
93
|
|
|
93
94
|
## 输出契约
|
|
94
95
|
|
package/dist/api/comment/api.js
CHANGED
|
@@ -3,40 +3,22 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.getComments = getComments;
|
|
4
4
|
exports.resolveComment = resolveComment;
|
|
5
5
|
const http_1 = require("../../utils/http");
|
|
6
|
-
const error_1 = require("../../utils/error");
|
|
7
6
|
/**
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* - StatusCode !== 0 → AppError(业务/下游失败,HTTP 通常仍 200)
|
|
11
|
-
* - 否则返回平铺响应体
|
|
12
|
-
*
|
|
13
|
-
* 注意:评论接口用大写 StatusCode/StatusMessage,与 utils/http.ts 的
|
|
14
|
-
* getInnerApi(小写 status_code)信封不同,故域内自带解析。
|
|
7
|
+
* 评论接口走管理端 inner-api(getHttpClient + 小写 status_code 信封),与 app / deploy /
|
|
8
|
+
* observability 等域一致:统一的 verbose 请求/响应日志、错误映射、信封解析,不再域内自实现。
|
|
15
9
|
*/
|
|
16
|
-
async function parseBaseResp(response, url, errPrefix) {
|
|
17
|
-
if (!response.ok) {
|
|
18
|
-
throw new error_1.HttpError(response.status, url, `${errPrefix}: ${String(response.status)} ${response.statusText}`.trim());
|
|
19
|
-
}
|
|
20
|
-
const body = (await response.json());
|
|
21
|
-
if (body.StatusCode !== 0) {
|
|
22
|
-
throw new error_1.AppError('INTERNAL_API_ERROR', `${errPrefix}: ${body.StatusMessage ?? 'unknown error'}`);
|
|
23
|
-
}
|
|
24
|
-
return body;
|
|
25
|
-
}
|
|
26
10
|
/** GET /api/v1/studio/innerapi/apps/:appID/comments — 获取应用评论列表 */
|
|
27
11
|
async function getComments(appID, onlyUnresolved = false) {
|
|
28
|
-
const client = (0, http_1.getRuntimeHttpClient)();
|
|
29
12
|
let url = `/api/v1/studio/innerapi/apps/${encodeURIComponent(appID)}/comments`;
|
|
30
13
|
if (onlyUnresolved)
|
|
31
14
|
url += '?onlyUnresolved=true';
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
|
|
15
|
+
const body = await (0, http_1.getInnerApi)(url, {
|
|
16
|
+
errPrefix: 'Failed to list comments',
|
|
17
|
+
});
|
|
18
|
+
return body.items ?? [];
|
|
35
19
|
}
|
|
36
20
|
/** POST /api/v1/studio/innerapi/apps/:appID/comments/:commentID/resolve — 解决评论 */
|
|
37
21
|
async function resolveComment(appID, commentID) {
|
|
38
|
-
const client = (0, http_1.getRuntimeHttpClient)();
|
|
39
22
|
const url = `/api/v1/studio/innerapi/apps/${encodeURIComponent(appID)}/comments/${encodeURIComponent(commentID)}/resolve`;
|
|
40
|
-
|
|
41
|
-
await parseBaseResp(response, url, 'Failed to resolve comment');
|
|
23
|
+
await (0, http_1.postInnerApi)(url, undefined, { errPrefix: 'Failed to resolve comment' });
|
|
42
24
|
}
|
|
@@ -63,6 +63,7 @@ JSON 输出(stdout)
|
|
|
63
63
|
.option('--create <relpath>', '新增文件(可重复)', shared_1.collectRepeatedOption, [])
|
|
64
64
|
.option('--update <relpath>', '覆盖已有文件(可重复)', shared_1.collectRepeatedOption, [])
|
|
65
65
|
.option('--delete <relpath>', '删除文件(可重复)', shared_1.collectRepeatedOption, [])
|
|
66
|
+
.option('--session-id <id>', '会话 ID,发布时透传给下游(可选)')
|
|
66
67
|
.addHelpText('after', `
|
|
67
68
|
--dir 为项目目录(与 deploy 同名参数,默认当前目录)。
|
|
68
69
|
仅支持 design-html(design_local_deploy)。路径为工程根相对路径(= 服务端 latest 下 key),
|
|
@@ -86,6 +87,7 @@ JSON 输出
|
|
|
86
87
|
creates: rawOpts.create,
|
|
87
88
|
updates: rawOpts.update,
|
|
88
89
|
deletes: rawOpts.delete,
|
|
90
|
+
sessionId: rawOpts.sessionId,
|
|
89
91
|
});
|
|
90
92
|
}));
|
|
91
93
|
}
|
|
@@ -80,10 +80,22 @@ function registerRegistryAdd(parent) {
|
|
|
80
80
|
- skip-by-disk:目标文件已存在默认跳过;--overwrite 才覆盖
|
|
81
81
|
- 不写任何安装记账文件(项目文件树即状态)
|
|
82
82
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
83
|
+
输出(pretty,默认)
|
|
84
|
+
registry@<ver>
|
|
85
|
+
added: <落地 basename 逗号列表> # 含 Depends 闭包全部落地文件
|
|
86
|
+
skipped: <逗号列表> # 仅有跳过时出现
|
|
87
|
+
dry-run: true (no files written) # 仅 --dry-run 时出现
|
|
88
|
+
|
|
89
|
+
# <请求条目落地 basename>
|
|
90
|
+
<该条目 USAGE 块原文> # 只列你请求的条目,依赖不占 usage 位
|
|
91
|
+
|
|
92
|
+
JSON 输出(--json)
|
|
93
|
+
{"data": {"registryVersion": "...", "added": [...], "skipped": [...], "dryRun": false,
|
|
94
|
+
"entries": [{"name": "...", "file": "<来源 relPath>", "dest": "<落地 basename>",
|
|
95
|
+
"status": "added|skipped", "usage": "<USAGE 块原文>", "dependsOn": [...]}, ...]}}
|
|
96
|
+
(added / skipped 覆盖依赖闭包全部落地文件;entries 只列**你请求的条目**
|
|
97
|
+
(不含被 Depends 传递拉入的依赖),逐条给 usage / dependsOn,add 完直接读用法。
|
|
98
|
+
请求的条目即使已存在被 skip 也回带 usage,status 标 added / skipped)
|
|
87
99
|
|
|
88
100
|
示例
|
|
89
101
|
$ miaoda registry add deck-slide
|
|
@@ -37,26 +37,96 @@ exports.handleCommentList = handleCommentList;
|
|
|
37
37
|
const api = __importStar(require("../../../api/index"));
|
|
38
38
|
const shared_1 = require("../../../cli/commands/shared");
|
|
39
39
|
const output_1 = require("../../../utils/output");
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
40
|
+
const fmtTime = output_1.fmt.sec();
|
|
41
|
+
/** 去掉飞书内联 `<at ...>@某人</at>` 标签,保留内部 @文本。 */
|
|
42
|
+
function stripAtTags(s) {
|
|
43
|
+
return s.replace(/<at\b[^>]*>/g, '').replace(/<\/at>/g, '');
|
|
44
|
+
}
|
|
45
|
+
/** 单个内联元素渲染成文本:text_run 出文本、docs_link 出链接、person 出 @user。 */
|
|
46
|
+
function renderElement(el) {
|
|
47
|
+
if (el.text_run?.text)
|
|
48
|
+
return stripAtTags(el.text_run.text);
|
|
49
|
+
if (el.docs_link?.url)
|
|
50
|
+
return el.docs_link.url;
|
|
51
|
+
if (el.person?.user_id)
|
|
52
|
+
return `@${el.person.user_id}`;
|
|
53
|
+
return '';
|
|
54
|
+
}
|
|
55
|
+
/** 一条 reply 的正文文本(各 element 拼接、去 at 标签)。 */
|
|
56
|
+
function replyText(r) {
|
|
57
|
+
return (r.content?.elements ?? []).map(renderElement).join('').trim();
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* 评论级 extra 里的 content_anchor_id(评论锚定的页面元素定位)。
|
|
61
|
+
* extra 后端返回 JSON 字符串(也兼容已是对象的情况),解析失败返回 undefined。
|
|
62
|
+
*/
|
|
63
|
+
function commentAnchor(c) {
|
|
64
|
+
const { extra } = c;
|
|
65
|
+
let obj = extra;
|
|
66
|
+
if (typeof extra === 'string') {
|
|
67
|
+
try {
|
|
68
|
+
obj = JSON.parse(extra);
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
return undefined;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
if (typeof obj === 'object' && obj !== null) {
|
|
75
|
+
const anchor = obj.content_anchor_id;
|
|
76
|
+
if (typeof anchor === 'string' && anchor.length > 0)
|
|
77
|
+
return anchor;
|
|
78
|
+
}
|
|
79
|
+
return undefined;
|
|
80
|
+
}
|
|
81
|
+
/** 一条 reply 的附加标注:图片数量、reaction。 */
|
|
82
|
+
function replyAnnotations(r) {
|
|
83
|
+
const ann = [];
|
|
84
|
+
const images = r.extra?.image_list;
|
|
85
|
+
if (Array.isArray(images) && images.length > 0)
|
|
86
|
+
ann.push(`[图片×${String(images.length)}]`);
|
|
87
|
+
for (const rc of r.reactions ?? []) {
|
|
88
|
+
if (rc.reaction_key)
|
|
89
|
+
ann.push(`[${rc.reaction_key}×${String(rc.count ?? 0)}]`);
|
|
90
|
+
}
|
|
91
|
+
return ann;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* 渲染一条评论为多行块(信息全保留,靠结构化标签 + 列对齐提升可读性):
|
|
95
|
+
* ● [未解决] <comment_id> · N 条回复
|
|
96
|
+
* 引用 <quote>
|
|
97
|
+
* 锚点 <content_anchor_id 全量>
|
|
98
|
+
* <user 对齐> <time> <正文 + 标注>
|
|
99
|
+
* userWidth 为所有回复 user_id 的最大宽度,用于跨评论列对齐。
|
|
100
|
+
*/
|
|
101
|
+
function renderComment(c, userWidth) {
|
|
102
|
+
const replies = c.reply_list?.replies ?? [];
|
|
103
|
+
const lines = [
|
|
104
|
+
`● ${c.is_solved ? '[已解决]' : '[未解决]'} ${c.comment_id} · ${String(replies.length)} 条回复`,
|
|
105
|
+
];
|
|
106
|
+
if (typeof c.quote === 'string' && c.quote.length > 0)
|
|
107
|
+
lines.push(` 引用 ${c.quote}`);
|
|
108
|
+
const anchor = commentAnchor(c);
|
|
109
|
+
if (anchor !== undefined)
|
|
110
|
+
lines.push(` 锚点 ${anchor}`);
|
|
111
|
+
for (const r of replies) {
|
|
112
|
+
const body = [replyText(r), ...replyAnnotations(r)].filter((p) => p.length > 0).join(' ');
|
|
113
|
+
lines.push(` ${(r.user_id ?? '-').padEnd(userWidth)} ${fmtTime(r.create_time)} ${body}`);
|
|
114
|
+
}
|
|
115
|
+
return lines.join('\n');
|
|
116
|
+
}
|
|
50
117
|
async function handleCommentList(opts) {
|
|
51
118
|
const appId = (0, shared_1.resolveAppId)({ appId: opts.appId });
|
|
52
119
|
const comments = await api.comment.getComments(appId, opts.onlyUnresolved ?? false);
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
120
|
+
// JSON 模式:原样透传完整评论结构(含 reply_list / replies / reactions …),与 openapi 一致。
|
|
121
|
+
if ((0, output_1.isJsonMode)()) {
|
|
122
|
+
(0, output_1.emit)({ data: comments });
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
// pretty 模式:信息密集的分块形态,一条评论一块、每条回复一行(含人 / 时间 / 正文 / 标注)。
|
|
126
|
+
// 跨评论对齐 user 列:取所有回复 user_id 的最大宽度。
|
|
127
|
+
const userWidth = Math.max(0, ...comments.flatMap((c) => c.reply_list?.replies ?? []).map((r) => (r.user_id ?? '-').length));
|
|
128
|
+
const body = comments.length === 0
|
|
129
|
+
? '(无评论)'
|
|
130
|
+
: comments.map((c) => renderComment(c, userWidth)).join('\n\n');
|
|
131
|
+
process.stdout.write(body + '\n');
|
|
62
132
|
}
|
|
@@ -9,7 +9,6 @@ const index_1 = require("../../../services/registry/index");
|
|
|
9
9
|
const shared_1 = require("./shared");
|
|
10
10
|
const error_1 = require("../../../utils/error");
|
|
11
11
|
const output_1 = require("../../../utils/output");
|
|
12
|
-
const logger_1 = require("../../../utils/logger");
|
|
13
12
|
/**
|
|
14
13
|
* miaoda registry add <name...> [--overwrite] [--dry-run] [--dir <path>] [--version <ver>]
|
|
15
14
|
*
|
|
@@ -35,18 +34,62 @@ async function handleRegistryAdd(opts) {
|
|
|
35
34
|
overwrite: opts.overwrite === true,
|
|
36
35
|
dryRun: opts.dryRun === true,
|
|
37
36
|
});
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
37
|
+
// entries:**只列用户请求的条目**(opts.names 命中的),给它们的 usage / dependsOn,
|
|
38
|
+
// 让 Agent add 完直接拿到用法、无需再 `registry list`。被 Depends 传递拉进来的依赖是
|
|
39
|
+
// "管道"(照常在 added/skipped 里落地),不占 usage 位。请求的条目即使已存在被 skip
|
|
40
|
+
// 也回带 usage(status=skipped,Agent 借此判断磁盘上是 registry 版还是自己改过的旧版)。
|
|
41
|
+
const requestedRelPaths = new Set();
|
|
42
|
+
for (const token of opts.names) {
|
|
43
|
+
for (const e of plan.entries) {
|
|
44
|
+
if ((0, index_1.tokenMatches)(e, token))
|
|
45
|
+
requestedRelPaths.add(e.relPath);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
// relPath → 落地的 PlannedFile(拿 dest / 落地状态)
|
|
49
|
+
const fileByRelPath = new Map(plan.files.map((f) => [f.srcRelPath, f]));
|
|
50
|
+
const addedSet = new Set(result.added);
|
|
51
|
+
const skippedSet = new Set(result.skipped);
|
|
52
|
+
const entries = plan.entries
|
|
53
|
+
.filter((e) => requestedRelPaths.has(e.relPath))
|
|
54
|
+
.map((e) => {
|
|
55
|
+
const f = fileByRelPath.get(e.relPath);
|
|
56
|
+
const dest = f?.dest ?? e.relPath.split('/').pop() ?? e.relPath;
|
|
57
|
+
const status = skippedSet.has(dest) && !addedSet.has(dest) ? 'skipped' : 'added';
|
|
58
|
+
return {
|
|
59
|
+
name: e.name,
|
|
60
|
+
file: e.relPath,
|
|
61
|
+
dest,
|
|
62
|
+
status,
|
|
63
|
+
usage: e.usage,
|
|
64
|
+
dependsOn: e.dependsOn,
|
|
65
|
+
};
|
|
49
66
|
});
|
|
67
|
+
// 只透出对 add 完的 Agent 可操作的字段:项目里实际多了什么(added)、什么没动(skipped)、
|
|
68
|
+
// 请求条目怎么用(entries)。requested(纯回显)、resolved(包内诊断路径)不透出。
|
|
69
|
+
const data = {
|
|
70
|
+
registryVersion: reg.version,
|
|
71
|
+
added: result.added,
|
|
72
|
+
skipped: result.skipped,
|
|
73
|
+
dryRun: opts.dryRun === true,
|
|
74
|
+
entries,
|
|
75
|
+
};
|
|
76
|
+
if ((0, output_1.isJsonMode)()) {
|
|
77
|
+
(0, output_1.emit)({ data });
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
// pretty 是 Agent 不加 --json 时的默认载荷,也要对 AI 友好:信息量与 JSON 对齐,
|
|
81
|
+
// 但换成稳定 label + 逗号列表(无 JSON 数组、无 TTY 截断、空/默认值不打印),
|
|
82
|
+
// summary 在前、各请求条目的 USAGE 块原文在后。整体走一次纯字符串 emit(不进 key-value 渲染)。
|
|
83
|
+
const summaryLines = [`registry@${reg.version}`];
|
|
84
|
+
if (opts.dryRun === true)
|
|
85
|
+
summaryLines.push('dry-run: true (no files written)');
|
|
86
|
+
if (result.added.length > 0)
|
|
87
|
+
summaryLines.push(`added: ${result.added.join(', ')}`);
|
|
88
|
+
if (result.skipped.length > 0)
|
|
89
|
+
summaryLines.push(`skipped: ${result.skipped.join(', ')}`);
|
|
90
|
+
const blocks = entries.filter((e) => e.usage !== '').map((e) => `# ${e.dest}\n${e.usage}`);
|
|
91
|
+
const parts = [summaryLines.join('\n'), ...blocks];
|
|
92
|
+
(0, output_1.emit)(parts.join('\n\n'));
|
|
50
93
|
}
|
|
51
94
|
finally {
|
|
52
95
|
reg.cleanup();
|
|
@@ -15,8 +15,13 @@ const output_1 = require("../../../utils/output");
|
|
|
15
15
|
* 从 .spark/meta.json 读 stack,把 coding-steering 包内对应 stack 的 skills + tech.md
|
|
16
16
|
* 同步到 <dir>/.agent/steering/。需要先跑过 `miaoda app init`。
|
|
17
17
|
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
18
|
+
* 版本来源优先级(从高到低):
|
|
19
|
+
* 1. CLI `--version` flag(显式指定)
|
|
20
|
+
* 2. `FORCE_FRAMEWORK_ENVIRONMENT=boe` → dist-tag `dev`(BOE 测试灰度,跟随
|
|
21
|
+
* publish-alpha.sh 在 develop 分支打的 dev tag,便于在 BOE 沙箱里验证预发 steering)
|
|
22
|
+
* 3. 默认 `latest`
|
|
23
|
+
*
|
|
24
|
+
* **不读 meta.json**——steering 版本不在 meta 里钉。
|
|
20
25
|
*/
|
|
21
26
|
async function handleSkillsSync(opts) {
|
|
22
27
|
await Promise.resolve();
|
|
@@ -25,17 +30,20 @@ async function handleSkillsSync(opts) {
|
|
|
25
30
|
if (meta.stack === undefined || meta.stack === '') {
|
|
26
31
|
throw new error_1.AppError('SKILLS_META_INCOMPLETE', '.spark/meta.json missing stack — run `miaoda app init` first');
|
|
27
32
|
}
|
|
33
|
+
const isBoe = process.env.FORCE_FRAMEWORK_ENVIRONMENT === 'boe';
|
|
34
|
+
const effectiveVersion = opts.version ?? (isBoe ? 'dev' : undefined);
|
|
35
|
+
const versionSource = opts.version !== undefined ? 'cli-arg' : isBoe ? 'boe-default-dev' : 'default-latest';
|
|
28
36
|
const result = (0, coding_steering_1.syncCodingSteering)({
|
|
29
37
|
stack: meta.stack,
|
|
30
38
|
targetDir,
|
|
31
|
-
version:
|
|
39
|
+
version: effectiveVersion,
|
|
32
40
|
outputLayout: opts.local === true ? 'flat' : 'nested',
|
|
33
41
|
});
|
|
34
42
|
(0, output_1.emit)({
|
|
35
43
|
data: {
|
|
36
44
|
stack: meta.stack,
|
|
37
45
|
version: result.version,
|
|
38
|
-
versionSource
|
|
46
|
+
versionSource,
|
|
39
47
|
syncedSkills: result.syncedSkills,
|
|
40
48
|
techSynced: result.techSynced,
|
|
41
49
|
...(result.claudeSkillsLink !== undefined
|
|
@@ -4,6 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.buildDesignOutput = buildDesignOutput;
|
|
7
|
+
exports.cleanDesignDist = cleanDesignDist;
|
|
7
8
|
const node_fs_1 = __importDefault(require("node:fs"));
|
|
8
9
|
const node_path_1 = __importDefault(require("node:path"));
|
|
9
10
|
const error_1 = require("../../../../utils/error");
|
|
@@ -39,3 +40,10 @@ function buildDesignOutput(opts) {
|
|
|
39
40
|
throw new error_1.AppError('DEPLOY_BUILD_FAILED', `design build failed: ${err.message}`);
|
|
40
41
|
}
|
|
41
42
|
}
|
|
43
|
+
/**
|
|
44
|
+
* 删除 <projectDir>/dist(本地构建产物)。幂等:不存在也不报错(force)。
|
|
45
|
+
* design 部署收尾调用,部署动作结束后不在用户项目里留产物。
|
|
46
|
+
*/
|
|
47
|
+
function cleanDesignDist(projectDir) {
|
|
48
|
+
node_fs_1.default.rmSync(node_path_1.default.join(projectDir, constants_1.DIST_DIR), { recursive: true, force: true });
|
|
49
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.savePluginInstances = exports.LocalReleaseStatus = exports.finalizeLocalRelease = exports.createLocalRelease = exports.uploadArtifacts = exports.uploadDesignArtifacts = exports.buildDesignOutput = exports.runBuild = exports.preRelease = exports.prepareDeployContext = void 0;
|
|
3
|
+
exports.savePluginInstances = exports.LocalReleaseStatus = exports.finalizeLocalRelease = exports.createLocalRelease = exports.uploadArtifacts = exports.uploadDesignArtifacts = exports.cleanDesignDist = exports.buildDesignOutput = exports.runBuild = exports.preRelease = exports.prepareDeployContext = void 0;
|
|
4
4
|
var context_1 = require("./context");
|
|
5
5
|
Object.defineProperty(exports, "prepareDeployContext", { enumerable: true, get: function () { return context_1.prepareDeployContext; } });
|
|
6
6
|
var pre_release_1 = require("./pre-release");
|
|
@@ -9,6 +9,7 @@ var build_1 = require("./build");
|
|
|
9
9
|
Object.defineProperty(exports, "runBuild", { enumerable: true, get: function () { return build_1.runBuild; } });
|
|
10
10
|
var design_build_1 = require("./design-build");
|
|
11
11
|
Object.defineProperty(exports, "buildDesignOutput", { enumerable: true, get: function () { return design_build_1.buildDesignOutput; } });
|
|
12
|
+
Object.defineProperty(exports, "cleanDesignDist", { enumerable: true, get: function () { return design_build_1.cleanDesignDist; } });
|
|
12
13
|
var design_upload_1 = require("./design-upload");
|
|
13
14
|
Object.defineProperty(exports, "uploadDesignArtifacts", { enumerable: true, get: function () { return design_upload_1.uploadDesignArtifacts; } });
|
|
14
15
|
var upload_1 = require("./upload");
|
|
@@ -30,7 +30,12 @@ async function patchDesignDeploy(opts) {
|
|
|
30
30
|
});
|
|
31
31
|
const routesRegenerated = actions.some((a) => a.filePath === 'routes.json');
|
|
32
32
|
(0, logger_1.log)('deploy', `Applying ${String(actions.length)} file action(s)...`);
|
|
33
|
-
const res = await (0, index_1.applyTosDiff)({
|
|
33
|
+
const res = await (0, index_1.applyTosDiff)({
|
|
34
|
+
appID: opts.appId,
|
|
35
|
+
templateKey,
|
|
36
|
+
actions,
|
|
37
|
+
sessionId: opts.sessionId,
|
|
38
|
+
});
|
|
34
39
|
(0, logger_1.log)('deploy', `Patched: upsert=${String(res.upsertCount)} delete=${String(res.deleteCount)}`);
|
|
35
40
|
return {
|
|
36
41
|
upsertCount: res.upsertCount,
|
|
@@ -20,28 +20,37 @@ async function designLocalPublishPipeline(opts) {
|
|
|
20
20
|
throw new error_1.AppError('DEPLOY_PRE_RELEASE_DATA_MISSING', 'preRelease did not return a `data` map — backend tcc may not be configured for current template_key');
|
|
21
21
|
}
|
|
22
22
|
const data = pre.data;
|
|
23
|
-
|
|
24
|
-
(0, index_1.buildDesignOutput)({ projectDir: ctx.projectDir });
|
|
25
|
-
}
|
|
26
|
-
(0, logger_1.log)('deploy', 'Creating local release...');
|
|
27
|
-
const release = await (0, index_1.createLocalRelease)(ctx.appId, pre.version);
|
|
23
|
+
// dist 是本地构建产物,部署动作结束(无论成败)都清掉,不在用户项目里留产物。
|
|
28
24
|
try {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
await (0, index_1.
|
|
34
|
-
|
|
25
|
+
if (!opts.skipBuild) {
|
|
26
|
+
(0, index_1.buildDesignOutput)({ projectDir: ctx.projectDir });
|
|
27
|
+
}
|
|
28
|
+
(0, logger_1.log)('deploy', 'Creating local release...');
|
|
29
|
+
const release = await (0, index_1.createLocalRelease)(ctx.appId, pre.version, {
|
|
30
|
+
checkPointVersion: opts.checkPointVersion,
|
|
31
|
+
commitID: opts.commitID,
|
|
32
|
+
});
|
|
33
|
+
try {
|
|
34
|
+
await (0, index_1.uploadDesignArtifacts)({ projectDir: ctx.projectDir, data });
|
|
35
|
+
await (0, index_1.finalizeLocalRelease)(ctx.appId, release.releaseID, index_1.LocalReleaseStatus.Finished);
|
|
36
|
+
}
|
|
37
|
+
catch (err) {
|
|
38
|
+
await (0, index_1.finalizeLocalRelease)(ctx.appId, release.releaseID, index_1.LocalReleaseStatus.Failed);
|
|
39
|
+
throw err;
|
|
40
|
+
}
|
|
41
|
+
if (release.onlineUrl !== undefined && release.onlineUrl !== '') {
|
|
42
|
+
(0, spark_meta_1.writeSparkMeta)(ctx.projectDir, { appUrl: release.onlineUrl });
|
|
43
|
+
}
|
|
44
|
+
(0, logger_1.log)('deploy', 'Deployed successfully');
|
|
45
|
+
return {
|
|
46
|
+
appId: ctx.appId,
|
|
47
|
+
version: pre.version,
|
|
48
|
+
url: release.onlineUrl ?? '',
|
|
49
|
+
releaseID: release.releaseID,
|
|
50
|
+
preReleaseID: pre.preReleaseID,
|
|
51
|
+
};
|
|
35
52
|
}
|
|
36
|
-
|
|
37
|
-
(0,
|
|
53
|
+
finally {
|
|
54
|
+
(0, index_1.cleanDesignDist)(ctx.projectDir);
|
|
38
55
|
}
|
|
39
|
-
(0, logger_1.log)('deploy', 'Deployed successfully');
|
|
40
|
-
return {
|
|
41
|
-
appId: ctx.appId,
|
|
42
|
-
version: pre.version,
|
|
43
|
-
url: release.onlineUrl ?? '',
|
|
44
|
-
releaseID: release.releaseID,
|
|
45
|
-
preReleaseID: pre.preReleaseID,
|
|
46
|
-
};
|
|
47
56
|
}
|
package/dist/utils/http.js
CHANGED
|
@@ -64,7 +64,7 @@ function createClient(opts) {
|
|
|
64
64
|
* 默认灰度泳道。当前 miaoda CLI 接入的新接口(modern deploy 等)只在该泳道生效,
|
|
65
65
|
* 缺省走这个。MIAODA_CANARY_HEADER 可显式覆盖;设为空字符串则去掉头。
|
|
66
66
|
*/
|
|
67
|
-
const DEFAULT_CANARY_HEADER = '
|
|
67
|
+
const DEFAULT_CANARY_HEADER = 'boe_miaoda_ccm';
|
|
68
68
|
/**
|
|
69
69
|
* 注入 x-tt-env 小流量头:env 显式设值 > DEFAULT_CANARY_HEADER。
|
|
70
70
|
*
|