@lark-apaas/miaoda-cli 0.1.21 → 0.1.22-beta.ad5773e
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 +36 -2
- package/dist/api/comment/api.js +24 -0
- package/dist/api/comment/index.js +6 -0
- package/dist/api/comment/types.js +6 -0
- package/dist/api/deploy/index.js +3 -1
- package/dist/api/deploy/modern-types.js +4 -1
- package/dist/api/deploy/modern.js +8 -0
- package/dist/api/index.js +3 -1
- package/dist/cli/commands/app/index.js +23 -3
- package/dist/cli/commands/comment/index.js +55 -0
- package/dist/cli/commands/deploy/modern.js +34 -0
- package/dist/cli/commands/index.js +19 -0
- package/dist/cli/commands/registry/index.js +114 -0
- package/dist/cli/handlers/app/init.js +36 -13
- package/dist/cli/handlers/comment/index.js +7 -0
- package/dist/cli/handlers/comment/list.js +132 -0
- package/dist/cli/handlers/comment/resolve.js +44 -0
- package/dist/cli/handlers/deploy/index.js +3 -1
- package/dist/cli/handlers/deploy/patch.js +17 -0
- package/dist/cli/handlers/registry/add.js +97 -0
- package/dist/cli/handlers/registry/index.js +7 -0
- package/dist/cli/handlers/registry/list.js +48 -0
- package/dist/cli/handlers/registry/shared.js +25 -0
- package/dist/cli/handlers/skills/sync.js +12 -4
- package/dist/services/app/init/import-source.js +67 -0
- package/dist/services/app/init/index.js +8 -1
- package/dist/services/app/init/template.js +48 -1
- package/dist/services/deploy/modern/atoms/design-build.js +49 -0
- package/dist/services/deploy/modern/atoms/design-upload.js +74 -0
- package/dist/services/deploy/modern/atoms/index.js +6 -1
- package/dist/services/deploy/modern/atoms/tosutil.js +246 -0
- package/dist/services/deploy/modern/atoms/upload.js +4 -127
- package/dist/services/deploy/modern/check.js +28 -16
- package/dist/services/deploy/modern/patch/actions.js +61 -0
- package/dist/services/deploy/modern/patch/content.js +18 -0
- package/dist/services/deploy/modern/patch/index.js +46 -0
- package/dist/services/deploy/modern/patch/routes.js +37 -0
- package/dist/services/deploy/modern/patch/source-scan.js +58 -0
- package/dist/services/deploy/modern/pipelines/design-local.js +56 -0
- package/dist/services/deploy/modern/pipelines/index.js +3 -1
- package/dist/services/deploy/modern/protocol.js +7 -0
- package/dist/services/deploy/modern/run.js +10 -4
- package/dist/services/deploy/modern/template-key-map.js +4 -0
- package/dist/services/registry/index.js +293 -0
- package/dist/utils/http.js +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.handleCommentList = handleCommentList;
|
|
37
|
+
const api = __importStar(require("../../../api/index"));
|
|
38
|
+
const shared_1 = require("../../../cli/commands/shared");
|
|
39
|
+
const output_1 = require("../../../utils/output");
|
|
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
|
+
}
|
|
117
|
+
async function handleCommentList(opts) {
|
|
118
|
+
const appId = (0, shared_1.resolveAppId)({ appId: opts.appId });
|
|
119
|
+
const comments = await api.comment.getComments(appId, opts.onlyUnresolved ?? false);
|
|
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');
|
|
132
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.handleCommentResolve = handleCommentResolve;
|
|
37
|
+
const api = __importStar(require("../../../api/index"));
|
|
38
|
+
const shared_1 = require("../../../cli/commands/shared");
|
|
39
|
+
const output_1 = require("../../../utils/output");
|
|
40
|
+
async function handleCommentResolve(commentId, opts) {
|
|
41
|
+
const appId = (0, shared_1.resolveAppId)({ appId: opts.appId });
|
|
42
|
+
await api.comment.resolveComment(appId, commentId);
|
|
43
|
+
(0, output_1.emitOk)({ comment_id: commentId, resolved: true });
|
|
44
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.DEFAULT_POLL_INTERVAL_MS = exports.waitForPipeline = exports.handleDeployErrorLog = exports.handleDeployHistory = exports.handleDeployGet = exports.handleDeploy = void 0;
|
|
3
|
+
exports.handleDeployPatch = exports.DEFAULT_POLL_INTERVAL_MS = exports.waitForPipeline = exports.handleDeployErrorLog = exports.handleDeployHistory = exports.handleDeployGet = exports.handleDeploy = void 0;
|
|
4
4
|
var deploy_1 = require("./deploy");
|
|
5
5
|
Object.defineProperty(exports, "handleDeploy", { enumerable: true, get: function () { return deploy_1.handleDeploy; } });
|
|
6
6
|
var get_1 = require("./get");
|
|
@@ -12,3 +12,5 @@ Object.defineProperty(exports, "handleDeployErrorLog", { enumerable: true, get:
|
|
|
12
12
|
var polling_1 = require("./polling");
|
|
13
13
|
Object.defineProperty(exports, "waitForPipeline", { enumerable: true, get: function () { return polling_1.waitForPipeline; } });
|
|
14
14
|
Object.defineProperty(exports, "DEFAULT_POLL_INTERVAL_MS", { enumerable: true, get: function () { return polling_1.DEFAULT_POLL_INTERVAL_MS; } });
|
|
15
|
+
var patch_1 = require("./patch");
|
|
16
|
+
Object.defineProperty(exports, "handleDeployPatch", { enumerable: true, get: function () { return patch_1.handleDeployPatch; } });
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.handleDeployPatch = handleDeployPatch;
|
|
4
|
+
const index_1 = require("../../../services/deploy/modern/patch/index");
|
|
5
|
+
const output_1 = require("../../../utils/output");
|
|
6
|
+
/** miaoda deploy patch —— design-html 文件级增量发布 */
|
|
7
|
+
async function handleDeployPatch(opts) {
|
|
8
|
+
const result = await (0, index_1.patchDesignDeploy)({
|
|
9
|
+
appId: opts.appId,
|
|
10
|
+
projectDir: opts.dir ?? process.cwd(),
|
|
11
|
+
creates: opts.creates,
|
|
12
|
+
updates: opts.updates,
|
|
13
|
+
deletes: opts.deletes,
|
|
14
|
+
sessionId: opts.sessionId,
|
|
15
|
+
});
|
|
16
|
+
(0, output_1.emit)({ data: result });
|
|
17
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
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.handleRegistryAdd = handleRegistryAdd;
|
|
7
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
8
|
+
const index_1 = require("../../../services/registry/index");
|
|
9
|
+
const shared_1 = require("./shared");
|
|
10
|
+
const error_1 = require("../../../utils/error");
|
|
11
|
+
const output_1 = require("../../../utils/output");
|
|
12
|
+
/**
|
|
13
|
+
* miaoda registry add <name...> [--overwrite] [--dry-run] [--dir <path>] [--version <ver>]
|
|
14
|
+
*
|
|
15
|
+
* 解析 USAGE 块 Depends 传递闭包,把每个条目对应的 SDK 文件从 registry 包根的 <relPath>
|
|
16
|
+
* **保留相对路径**拷到项目根(--dir 指定目录的根)。
|
|
17
|
+
* skip-by-disk:目标已存在默认跳过,--overwrite 才覆盖。不写任何安装记账文件。
|
|
18
|
+
*/
|
|
19
|
+
async function handleRegistryAdd(opts) {
|
|
20
|
+
await Promise.resolve();
|
|
21
|
+
if (opts.names.length === 0) {
|
|
22
|
+
throw new error_1.AppError('ARGS_INVALID', 'registry add 至少需要一个条目名');
|
|
23
|
+
}
|
|
24
|
+
const targetDir = node_path_1.default.resolve(opts.dir ?? process.cwd());
|
|
25
|
+
const stack = (0, shared_1.resolveRegistryStack)(targetDir);
|
|
26
|
+
const reg = (0, index_1.loadRegistry)({ stack, version: opts.version });
|
|
27
|
+
try {
|
|
28
|
+
const plan = (0, index_1.planAdd)({
|
|
29
|
+
entries: reg.entries,
|
|
30
|
+
targetDir,
|
|
31
|
+
names: opts.names,
|
|
32
|
+
});
|
|
33
|
+
const result = (0, index_1.applyAdd)(plan.files, {
|
|
34
|
+
overwrite: opts.overwrite === true,
|
|
35
|
+
dryRun: opts.dryRun === true,
|
|
36
|
+
});
|
|
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
|
+
};
|
|
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'));
|
|
93
|
+
}
|
|
94
|
+
finally {
|
|
95
|
+
reg.cleanup();
|
|
96
|
+
}
|
|
97
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.handleRegistryAdd = exports.handleRegistryList = void 0;
|
|
4
|
+
var list_1 = require("./list");
|
|
5
|
+
Object.defineProperty(exports, "handleRegistryList", { enumerable: true, get: function () { return list_1.handleRegistryList; } });
|
|
6
|
+
var add_1 = require("./add");
|
|
7
|
+
Object.defineProperty(exports, "handleRegistryAdd", { enumerable: true, get: function () { return add_1.handleRegistryAdd; } });
|
|
@@ -0,0 +1,48 @@
|
|
|
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.handleRegistryList = handleRegistryList;
|
|
7
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
8
|
+
const index_1 = require("../../../services/registry/index");
|
|
9
|
+
const shared_1 = require("./shared");
|
|
10
|
+
const output_1 = require("../../../utils/output");
|
|
11
|
+
/**
|
|
12
|
+
* miaoda registry list [--dir <path>] [--version <ver>]
|
|
13
|
+
*
|
|
14
|
+
* 从 .spark/meta.json 读 stack → runtime → 包名,拉对应 registry 包,从包根递归扫含 USAGE 块的 SDK 文件。
|
|
15
|
+
*
|
|
16
|
+
* - 默认(pretty):输出各条目 USAGE 块原文,带文件名分隔,给 Agent 直接读注释。
|
|
17
|
+
* - --json:输出 [{name, file, usage(原文字符串), dependsOn[]}],usage 保持原文不解析成字段。
|
|
18
|
+
* file 是相对包根的路径(如 scripts/deck-stage.js),即 add 后的落地相对路径。
|
|
19
|
+
*/
|
|
20
|
+
async function handleRegistryList(opts) {
|
|
21
|
+
await Promise.resolve();
|
|
22
|
+
const targetDir = node_path_1.default.resolve(opts.dir ?? process.cwd());
|
|
23
|
+
const stack = (0, shared_1.resolveRegistryStack)(targetDir);
|
|
24
|
+
const reg = (0, index_1.loadRegistry)({ stack, version: opts.version });
|
|
25
|
+
try {
|
|
26
|
+
if ((0, output_1.isJsonMode)()) {
|
|
27
|
+
(0, output_1.emit)({
|
|
28
|
+
data: reg.entries.map((e) => ({
|
|
29
|
+
name: e.name,
|
|
30
|
+
file: e.relPath,
|
|
31
|
+
usage: e.usage,
|
|
32
|
+
dependsOn: e.dependsOn,
|
|
33
|
+
})),
|
|
34
|
+
});
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
// pretty:各条目 USAGE 块原文拼接,带文件路径分隔(让 Agent 直接读注释)
|
|
38
|
+
if (reg.entries.length === 0) {
|
|
39
|
+
(0, output_1.emit)('(no registry entries)');
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
const blocks = reg.entries.map((e) => `# ${e.relPath}\n${e.usage}`);
|
|
43
|
+
(0, output_1.emit)(blocks.join('\n\n'));
|
|
44
|
+
}
|
|
45
|
+
finally {
|
|
46
|
+
reg.cleanup();
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.resolveRegistryStack = resolveRegistryStack;
|
|
4
|
+
const spark_meta_1 = require("../../../utils/spark-meta");
|
|
5
|
+
const index_1 = require("../../../services/registry/index");
|
|
6
|
+
const error_1 = require("../../../utils/error");
|
|
7
|
+
/**
|
|
8
|
+
* 从 <targetDir>/.spark/meta.json 读 stack,校验该 stack 有组件 registry。
|
|
9
|
+
* 缺 stack → 提示先 init;stack 无 registry(无对应 runtime / runtime 无 registry 包)→ 提示支持哪些 stack。
|
|
10
|
+
*
|
|
11
|
+
* 这里只做「stack 是否在支持列表」的早校验给用户友好提示;包名的两跳解析
|
|
12
|
+
* (stack → runtime → 包)由 loadRegistry/resolveRegistryPackage 负责。
|
|
13
|
+
*/
|
|
14
|
+
function resolveRegistryStack(targetDir) {
|
|
15
|
+
const meta = (0, spark_meta_1.readSparkMeta)(targetDir);
|
|
16
|
+
if (meta.stack === undefined || meta.stack === '') {
|
|
17
|
+
throw new error_1.AppError('REGISTRY_META_INCOMPLETE', '.spark/meta.json missing stack — run `miaoda app init` first');
|
|
18
|
+
}
|
|
19
|
+
if (!index_1.REGISTRY_SUPPORTED_STACKS.includes(meta.stack)) {
|
|
20
|
+
throw new error_1.AppError('REGISTRY_STACK_UNSUPPORTED', `stack "${meta.stack}" 没有组件 registry`, {
|
|
21
|
+
next_actions: [`支持 registry 的 stack:${index_1.REGISTRY_SUPPORTED_STACKS.join(', ') || '(none)'}`],
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
return meta.stack;
|
|
25
|
+
}
|
|
@@ -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
|
|
@@ -0,0 +1,67 @@
|
|
|
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.IMPORT_SKIP_FILES = exports.IMPORT_SKIP_DIRS = void 0;
|
|
7
|
+
exports.importSourceSrc = importSourceSrc;
|
|
8
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
9
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
10
|
+
const error_1 = require("../../../utils/error");
|
|
11
|
+
const logger_1 = require("../../../utils/logger");
|
|
12
|
+
/** 导入时跳过的目录名(任意层级命中即整目录跳过)。 */
|
|
13
|
+
exports.IMPORT_SKIP_DIRS = new Set(['node_modules', '.git', 'dist', 'build']);
|
|
14
|
+
/** 导入时跳过的精确文件名。`.env.*`(如 .env.local)另由前缀规则处理。 */
|
|
15
|
+
exports.IMPORT_SKIP_FILES = new Set([
|
|
16
|
+
'.env',
|
|
17
|
+
'.DS_Store',
|
|
18
|
+
'.npmrc',
|
|
19
|
+
'package.json',
|
|
20
|
+
'package-lock.json',
|
|
21
|
+
'yarn.lock',
|
|
22
|
+
'pnpm-lock.yaml',
|
|
23
|
+
]);
|
|
24
|
+
function isSkippedFile(name) {
|
|
25
|
+
if (exports.IMPORT_SKIP_FILES.has(name))
|
|
26
|
+
return true;
|
|
27
|
+
// .env.local / .env.production 等一律跳过
|
|
28
|
+
if (name.startsWith('.env.'))
|
|
29
|
+
return true;
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* 把整个 sourcePath 递归拷进 targetDir/src/(叠加,同名覆盖,不删目标已有文件),
|
|
34
|
+
* 按 IMPORT_SKIP_DIRS / IMPORT_SKIP_FILES 过滤。
|
|
35
|
+
* sourcePath 不存在或非目录 → 抛 ARGS_INVALID。
|
|
36
|
+
*/
|
|
37
|
+
function importSourceSrc(opts) {
|
|
38
|
+
const sourcePath = node_path_1.default.resolve(opts.sourcePath);
|
|
39
|
+
if (!node_fs_1.default.existsSync(sourcePath) || !node_fs_1.default.statSync(sourcePath).isDirectory()) {
|
|
40
|
+
throw new error_1.AppError('ARGS_INVALID', `--source-path 不存在或不是目录: ${opts.sourcePath}`);
|
|
41
|
+
}
|
|
42
|
+
const destSrc = node_path_1.default.join(opts.targetDir, 'src');
|
|
43
|
+
node_fs_1.default.mkdirSync(destSrc, { recursive: true });
|
|
44
|
+
let count = 0;
|
|
45
|
+
const walk = (relDir) => {
|
|
46
|
+
const absDir = node_path_1.default.join(sourcePath, relDir);
|
|
47
|
+
for (const entry of node_fs_1.default.readdirSync(absDir, { withFileTypes: true })) {
|
|
48
|
+
if (entry.isDirectory()) {
|
|
49
|
+
if (exports.IMPORT_SKIP_DIRS.has(entry.name))
|
|
50
|
+
continue;
|
|
51
|
+
walk(node_path_1.default.join(relDir, entry.name));
|
|
52
|
+
}
|
|
53
|
+
else if (entry.isFile()) {
|
|
54
|
+
if (isSkippedFile(entry.name))
|
|
55
|
+
continue;
|
|
56
|
+
const rel = node_path_1.default.join(relDir, entry.name);
|
|
57
|
+
const dest = node_path_1.default.join(destSrc, rel);
|
|
58
|
+
node_fs_1.default.mkdirSync(node_path_1.default.dirname(dest), { recursive: true });
|
|
59
|
+
node_fs_1.default.copyFileSync(node_path_1.default.join(sourcePath, rel), dest);
|
|
60
|
+
count += 1;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
walk('.');
|
|
65
|
+
(0, logger_1.log)('init', `Imported ${String(count)} file(s) from ${sourcePath} → src/`);
|
|
66
|
+
return { importedFileCount: count };
|
|
67
|
+
}
|
|
@@ -1,10 +1,17 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ASYNC_INSTALL_LOG = exports.runAsyncInstallWorker = exports.dispatchAsyncInstall = exports.resolveNpmInstallRegistry = exports.installDependencies = exports.writeSparkMeta = exports.readSparkMeta = exports.TEMPLATE_PACKAGE_BY_STACK = exports.SUPPORTED_STACKS = exports.renderTemplate = void 0;
|
|
3
|
+
exports.ASYNC_INSTALL_LOG = exports.runAsyncInstallWorker = exports.dispatchAsyncInstall = exports.resolveNpmInstallRegistry = exports.installDependencies = exports.writeSparkMeta = exports.readSparkMeta = exports.IMPORT_SKIP_FILES = exports.IMPORT_SKIP_DIRS = exports.importSourceSrc = exports.TEMPLATE_PACKAGE_BY_STACK = exports.STACK_BY_APP_TYPE = exports.APP_TYPES = exports.SUPPORTED_STACKS = exports.resolveStack = exports.renderTemplate = void 0;
|
|
4
4
|
var template_1 = require("./template");
|
|
5
5
|
Object.defineProperty(exports, "renderTemplate", { enumerable: true, get: function () { return template_1.renderTemplate; } });
|
|
6
|
+
Object.defineProperty(exports, "resolveStack", { enumerable: true, get: function () { return template_1.resolveStack; } });
|
|
6
7
|
Object.defineProperty(exports, "SUPPORTED_STACKS", { enumerable: true, get: function () { return template_1.SUPPORTED_STACKS; } });
|
|
8
|
+
Object.defineProperty(exports, "APP_TYPES", { enumerable: true, get: function () { return template_1.APP_TYPES; } });
|
|
9
|
+
Object.defineProperty(exports, "STACK_BY_APP_TYPE", { enumerable: true, get: function () { return template_1.STACK_BY_APP_TYPE; } });
|
|
7
10
|
Object.defineProperty(exports, "TEMPLATE_PACKAGE_BY_STACK", { enumerable: true, get: function () { return template_1.TEMPLATE_PACKAGE_BY_STACK; } });
|
|
11
|
+
var import_source_1 = require("./import-source");
|
|
12
|
+
Object.defineProperty(exports, "importSourceSrc", { enumerable: true, get: function () { return import_source_1.importSourceSrc; } });
|
|
13
|
+
Object.defineProperty(exports, "IMPORT_SKIP_DIRS", { enumerable: true, get: function () { return import_source_1.IMPORT_SKIP_DIRS; } });
|
|
14
|
+
Object.defineProperty(exports, "IMPORT_SKIP_FILES", { enumerable: true, get: function () { return import_source_1.IMPORT_SKIP_FILES; } });
|
|
8
15
|
var spark_meta_1 = require("../../../utils/spark-meta");
|
|
9
16
|
Object.defineProperty(exports, "readSparkMeta", { enumerable: true, get: function () { return spark_meta_1.readSparkMeta; } });
|
|
10
17
|
Object.defineProperty(exports, "writeSparkMeta", { enumerable: true, get: function () { return spark_meta_1.writeSparkMeta; } });
|
|
@@ -3,7 +3,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.SUPPORTED_STACKS = exports.TEMPLATE_PINNED_VERSION_BY_STACK = exports.TEMPLATE_PACKAGE_BY_STACK = void 0;
|
|
6
|
+
exports.APP_TYPES = exports.STACK_BY_APP_TYPE = exports.SUPPORTED_STACKS = exports.TEMPLATE_PINNED_VERSION_BY_STACK = exports.TEMPLATE_PACKAGE_BY_STACK = void 0;
|
|
7
|
+
exports.resolveStack = resolveStack;
|
|
7
8
|
exports.renderTemplate = renderTemplate;
|
|
8
9
|
const node_fs_1 = __importDefault(require("node:fs"));
|
|
9
10
|
const node_path_1 = __importDefault(require("node:path"));
|
|
@@ -15,6 +16,7 @@ exports.TEMPLATE_PACKAGE_BY_STACK = {
|
|
|
15
16
|
'vite-react': '@lark-apaas/coding-template-vite-react',
|
|
16
17
|
html: '@lark-apaas/coding-template-html',
|
|
17
18
|
'nestjs-react-fullstack': '@lark-apaas/coding-template-nestjs-react-fullstack',
|
|
19
|
+
'design-html': '@lark-apaas/coding-template-design-html',
|
|
18
20
|
};
|
|
19
21
|
/**
|
|
20
22
|
* 短名 → template 包钉版表。renderTemplate 默认按这张表取版本号,表外 stack 跟 npm latest。
|
|
@@ -25,6 +27,51 @@ exports.TEMPLATE_PACKAGE_BY_STACK = {
|
|
|
25
27
|
*/
|
|
26
28
|
exports.TEMPLATE_PINNED_VERSION_BY_STACK = {};
|
|
27
29
|
exports.SUPPORTED_STACKS = Object.keys(exports.TEMPLATE_PACKAGE_BY_STACK);
|
|
30
|
+
/**
|
|
31
|
+
* app_type(业务类型)→ stack 短名映射。仅在调用方未显式传 --template 时用于解析 stack。
|
|
32
|
+
* 与 src/api/app/types.ts 的 AppType 枚举无关,是独立的业务类型概念。
|
|
33
|
+
*/
|
|
34
|
+
exports.STACK_BY_APP_TYPE = {
|
|
35
|
+
html: 'html',
|
|
36
|
+
modern_html: 'html',
|
|
37
|
+
jspage: 'vite-react',
|
|
38
|
+
full_stack: 'nestjs-react-fullstack',
|
|
39
|
+
};
|
|
40
|
+
exports.APP_TYPES = Object.keys(exports.STACK_BY_APP_TYPE);
|
|
41
|
+
/**
|
|
42
|
+
* 解析要用的 stack(template-first):
|
|
43
|
+
* 1. template 传了 → 直接用(SUPPORTED_STACKS 校验)
|
|
44
|
+
* 2. 否则 appType 传了 → 按 STACK_BY_APP_TYPE 查表
|
|
45
|
+
* 3. 都没传 → ARGS_INVALID
|
|
46
|
+
* 非法 template / 非法 appType 均抛 ARGS_INVALID。
|
|
47
|
+
*/
|
|
48
|
+
function resolveStack(opts) {
|
|
49
|
+
const { template, appType } = opts;
|
|
50
|
+
// 用真值判断(非 undefined/null/空串):空串视为未传,回落到 appType。
|
|
51
|
+
if (template) {
|
|
52
|
+
if (!exports.SUPPORTED_STACKS.includes(template)) {
|
|
53
|
+
throw new error_1.AppError('ARGS_INVALID', `不支持的 template: ${template}`, {
|
|
54
|
+
next_actions: [`可用 stack:${exports.SUPPORTED_STACKS.join(', ')}`],
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
return template;
|
|
58
|
+
}
|
|
59
|
+
if (appType) {
|
|
60
|
+
const stack = exports.STACK_BY_APP_TYPE[appType];
|
|
61
|
+
if (!stack) {
|
|
62
|
+
throw new error_1.AppError('ARGS_INVALID', `不支持的 app_type: ${appType}`, {
|
|
63
|
+
next_actions: [`可用 app_type:${exports.APP_TYPES.join(', ')}`],
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
return stack;
|
|
67
|
+
}
|
|
68
|
+
throw new error_1.AppError('ARGS_INVALID', '缺少 --template 或 --app-type', {
|
|
69
|
+
next_actions: [
|
|
70
|
+
`可用 stack:${exports.SUPPORTED_STACKS.join(', ')}`,
|
|
71
|
+
`可用 app_type:${exports.APP_TYPES.join(', ')}`,
|
|
72
|
+
],
|
|
73
|
+
});
|
|
74
|
+
}
|
|
28
75
|
// template/ 内以下划线开头的占位文件名在渲染时改名。
|
|
29
76
|
// 原因:
|
|
30
77
|
// 1. npm pack 强制剥的:.npmrc(防 auth token 泄露)
|
|
@@ -0,0 +1,49 @@
|
|
|
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.buildDesignOutput = buildDesignOutput;
|
|
7
|
+
exports.cleanDesignDist = cleanDesignDist;
|
|
8
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
9
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
10
|
+
const error_1 = require("../../../../utils/error");
|
|
11
|
+
const logger_1 = require("../../../../utils/logger");
|
|
12
|
+
const constants_1 = require("../constants");
|
|
13
|
+
const source_scan_1 = require("../patch/source-scan");
|
|
14
|
+
const routes_1 = require("../patch/routes");
|
|
15
|
+
/**
|
|
16
|
+
* design-html buildless 闭环 build(替代模板 scripts/build.sh):
|
|
17
|
+
* 1. rm -rf <projectDir>/dist
|
|
18
|
+
* 2. 拷源码 → dist/output(套 EXCLUDES,与 routes 同一份 listSourceFiles)
|
|
19
|
+
* 3. 写 dist/output/routes.json = generateRoutes(projectDir)
|
|
20
|
+
* 不跑 npm run build、不依赖技术栈内 build.sh。
|
|
21
|
+
* fs / scan / routes 任何失败统一包成 AppError('DEPLOY_BUILD_FAILED'),与旧 runDesignBuild 对齐。
|
|
22
|
+
*/
|
|
23
|
+
function buildDesignOutput(opts) {
|
|
24
|
+
(0, logger_1.log)('deploy', 'Building (design, CLI)...');
|
|
25
|
+
try {
|
|
26
|
+
const distDir = node_path_1.default.join(opts.projectDir, constants_1.DIST_DIR);
|
|
27
|
+
const outputDir = node_path_1.default.join(distDir, constants_1.OUTPUT_DIR);
|
|
28
|
+
node_fs_1.default.rmSync(distDir, { recursive: true, force: true });
|
|
29
|
+
node_fs_1.default.mkdirSync(outputDir, { recursive: true });
|
|
30
|
+
for (const rel of (0, source_scan_1.listSourceFiles)(opts.projectDir)) {
|
|
31
|
+
const dest = node_path_1.default.join(outputDir, rel);
|
|
32
|
+
node_fs_1.default.mkdirSync(node_path_1.default.dirname(dest), { recursive: true });
|
|
33
|
+
node_fs_1.default.copyFileSync(node_path_1.default.join(opts.projectDir, rel), dest);
|
|
34
|
+
}
|
|
35
|
+
node_fs_1.default.writeFileSync(node_path_1.default.join(outputDir, 'routes.json'), (0, routes_1.generateRoutes)(opts.projectDir), 'utf-8');
|
|
36
|
+
}
|
|
37
|
+
catch (err) {
|
|
38
|
+
if (err instanceof error_1.AppError)
|
|
39
|
+
throw err;
|
|
40
|
+
throw new error_1.AppError('DEPLOY_BUILD_FAILED', `design build failed: ${err.message}`);
|
|
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
|
+
}
|