@lark-apaas/miaoda-cli 0.1.38 → 0.1.39-alpha.0b274c0
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 +25 -0
- package/dist/api/deploy/api.js +3 -1
- package/dist/api/deploy/approval.js +77 -0
- package/dist/api/deploy/index.js +7 -1
- package/dist/api/deploy/schemas.js +3 -0
- package/dist/api/deploy/types.js +19 -1
- package/dist/cli/commands/app/index.js +59 -14
- package/dist/cli/commands/deploy/index.js +30 -6
- package/dist/cli/commands/deploy/modern.js +34 -11
- package/dist/cli/commands/skills/index.js +1 -1
- package/dist/cli/handlers/app/export.js +3 -3
- package/dist/cli/handlers/app/init.js +67 -2
- package/dist/cli/handlers/app/migrate.js +105 -213
- package/dist/cli/handlers/app/sync.js +39 -5
- package/dist/cli/handlers/db/sql.js +8 -6
- package/dist/cli/handlers/deploy/deploy.js +57 -4
- package/dist/cli/handlers/deploy/format.js +13 -0
- package/dist/cli/handlers/deploy/get.js +41 -1
- package/dist/cli/handlers/deploy/helpers.js +29 -2
- package/dist/cli/handlers/deploy/modern.js +39 -3
- package/dist/cli/handlers/deploy/polling.js +13 -9
- package/dist/cli/handlers/plugin/plugin-local.js +5 -4
- package/dist/config/fullstack-managed-files.js +67 -0
- package/dist/config/migrate-configs/index.js +9 -0
- package/dist/config/migrate-configs/vite-react-to-nestjs-react-fullstack.js +183 -193
- package/dist/config/sync-configs/design-stack.js +3 -4
- package/dist/config/sync-configs/nestjs-react-fullstack.js +17 -23
- package/dist/services/app/init/async-install.js +34 -2
- package/dist/services/app/init/index.js +3 -1
- package/dist/services/app/init/install.js +4 -3
- package/dist/services/app/init/workspace-check.js +105 -0
- package/dist/services/app/migrate/detect.js +34 -0
- package/dist/services/app/migrate/index.js +8 -0
- package/dist/services/app/migrate/run.js +502 -0
- package/dist/services/app/migrate/symlinks.js +146 -0
- package/dist/services/deploy/modern/atoms/build.js +3 -3
- package/dist/services/deploy/modern/atoms/local-release.js +3 -0
- package/dist/services/deploy/modern/atoms/tosutil.js +6 -8
- package/dist/services/deploy/modern/patch/actions.js +7 -1
- package/dist/services/deploy/modern/patch/index.js +2 -1
- package/dist/services/deploy/modern/pipelines/design-local.js +7 -1
- package/dist/services/deploy/modern/pipelines/local.js +7 -1
- package/dist/utils/archive.js +103 -0
- package/dist/utils/coding-steering.js +30 -2
- package/dist/utils/engineering-state.js +52 -0
- package/dist/utils/file-ops.js +28 -8
- package/dist/utils/http.js +6 -6
- package/dist/utils/migrate-adapters.js +513 -0
- package/dist/utils/migrate-rule.js +508 -26
- package/dist/utils/npm-pack.js +6 -7
- package/dist/utils/project-snapshot.js +99 -0
- package/dist/utils/run-npm.js +102 -0
- package/dist/utils/spark-meta.js +31 -10
- package/dist/utils/sync-rule.js +86 -11
- package/dist/utils/typescript-exclude.js +36 -0
- package/dist/utils/which.js +27 -0
- package/package.json +6 -2
- package/upgrade/templates/nestjs-react-fullstack/templates/nest-cli.json +1 -10
- package/upgrade/templates/nestjs-react-fullstack/templates/scripts/prune-smart.js +41 -1
package/README.md
CHANGED
|
@@ -52,6 +52,30 @@ miaoda file ls --output json
|
|
|
52
52
|
|
|
53
53
|
完整命令通过 `miaoda --help` 或 `miaoda <domain> --help` 查看。
|
|
54
54
|
|
|
55
|
+
## 工程初始化、同步与转换
|
|
56
|
+
|
|
57
|
+
`miaoda app init / sync / migrate` 管理本地应用工程(平台调用方与本地开发共用):
|
|
58
|
+
|
|
59
|
+
- `init`:按 `--template` 或 `--app-type` 渲染模板(`full_stack → nestjs-react-fullstack`,`frontend / jspage → vite-react`)。工程已存在时不重新渲染、不覆盖业务代码,只输出就绪核验结果 `ready / problems`;`--strict` 下未就绪(meta 损坏、stack 不符、必要文件缺失、依赖未安装、上次操作失败)退出码 1。同步安装失败输出 `status=failed` 并退出码 1。
|
|
60
|
+
- `sync`:按 stack 的同步规则更新平台托管内容。全栈工程的托管文件是明确清单(`scripts/dev.sh`、`dev.js`、`dev-local.js`、`build.sh`、`run.sh`、`lint.js`、`prune-smart.js`、`hooks/run-precommit.js` 与 `.githooks/pre-commit`),`scripts/` 下其他用户文件保留;连续执行无漂移。依赖安装失败输出 `status=failed` 并退出码 1。
|
|
61
|
+
- `migrate`(不在 help 列表中展示):工程转换原语,在原工程目录内执行。目标模板先渲染到临时模板目录(不复制用户工程),再只读预检冲突:同路径不同内容、重复插件 ID、无法确定的 package.json / tsconfig / vite.config / index.html 形态等返回 `status=conflict` 与具体路径,工程不写入。预检通过后在原目录定向转换(`src/ public/ → client/`、插件迁 `server/capabilities`、配置定向适配),执行中出现的冲突即停、不覆盖用户不同内容;随后在原目录安装依赖并完整构建(`npm run build`)。任一阶段失败退出码 1,`failure.stage` 给出 `install` / `verify` 等阶段,现场保留、不自动回滚;`originalIntact=true` 仅表示失败发生在任何工程写入之前,写入后一律为 false(已写入文件见 `changes`)。磁盘已是目标布局时走 repair(补齐适配 / 安装 / 构建,保留已有 `node_modules` 接续安装),不返回 NOOP;meta 已是目标 stack 不代表上次成功,以 `.spark/local/engineering-state.json` 的终态为准。放弃转换由调用方按代码版本恢复。输出包含源 / 目标 stack、模板与 CLI 版本、真实阶段结果与冲突路径;运行 readiness 由调用方核验(`readiness.status=pending_caller_verification`),`restartSignalSent` 只表示发出了重启信号。执行期间的并发编辑由调用方现有互斥与调度保证。
|
|
62
|
+
|
|
63
|
+
`migrate` 不自动解引用工程外文件。迁移涉及的文件或父目录存在符号链接时,在规则执行前返回 `MIGRATE_UNSAFE_SYMLINK` 和具体 `conflicts[].path`;请改为工程拥有的普通文件或目录后重试。`html → design-html` 的 `src → .` 涉及整个工程根目录。原目录 install/build 前拒绝绝对链接、工程外链接、无法解析的链接及指向排除目录的链接;未触及且在工程内解析的相对业务链接保留,安装生成的普通 `node_modules/.bin` 相对链接允许。规则执行后、安装后及构建前再次检查链接边界。扫描失败返回 `MIGRATE_SYMLINK_CHECK_FAILED`;失败或链接冲突在安全的 `.spark/local` 写入终态,状态写路径不安全时不写入并给出 warning。该检查不是 npm 脚本的安全沙箱,不限制脚本主动访问其他绝对路径。
|
|
64
|
+
|
|
65
|
+
临时模板目录清理失败只加入 `warnings`(`path`、系统错误 `code`、`message`),不影响 `status`。
|
|
66
|
+
|
|
67
|
+
全栈 / design-stack 的 `postinstall` 只升级完整历史平台值(`fullstack-cli action-plugin init` 或 `npx -y @lark-apaas/fullstack-cli action-plugin init`),目标为 `npx -y @lark-apaas/fullstack-cli@latest action-plugin init`;`latest` 是渠道,不是固定版本。带追加命令、参数或用户指定版本的值保留。`migrate` 在原目录执行正常 npm 安装生命周期,包括用户脚本及依赖补丁;生命周期失败即 `install` 阶段失败,保留现场。
|
|
68
|
+
|
|
69
|
+
## 全栈应用的 MCP UI 检查
|
|
70
|
+
|
|
71
|
+
创建 MCP UI 时,Agent 在 `server/mcp/ui` 中同时生成 `tsconfig.json` 和 `eslint.config.cjs`,修改 UI 或其 shared 依赖后主动运行独立检查。模板和 CLI 不生成 UI 配置,也不将 UI 检查接入主工程 lint/type:check。
|
|
72
|
+
|
|
73
|
+
主工程保留原 client/server 检查。Agent 从工程根执行 `npx --no-install tsc --noEmit --project server/mcp/ui/tsconfig.json`,再执行 `npx --no-install eslint --config server/mcp/ui/eslint.config.cjs "server/mcp/ui/**/*.{ts,tsx,js,jsx}" --max-warnings 0`;必须检查退出码并修复错误。无需辅助脚本或新增 npm 命令。
|
|
74
|
+
|
|
75
|
+
CLI 不注入 MCP UI 检查命令;主工程保留原有 client/server 检查,UI 由 Agent 按独立配置执行标准 tsc/eslint。
|
|
76
|
+
|
|
77
|
+
存量 sync 不改写 ESLint 源码;UI 全局排除项由平台 ESLint 预设提供。TS 仅向已有显式 `exclude` 数组追加目录,保留注释和原项;依赖继承且未显式声明 `exclude` 的自定义配置保持不变并提示人工调整。自定义检查命令保留。lint.js 和 build.sh 仍由平台脚本模板维护,不依赖预设包中的脚本执行入口。
|
|
78
|
+
|
|
55
79
|
## 打包可本地访问的静态产物
|
|
56
80
|
|
|
57
81
|
`miaoda app pack`(默认 `--mode standalone`)把当前应用构建成一份自包含静态产物,可脱离妙搭平台本地打开。
|
|
@@ -112,6 +136,7 @@ miaoda registry add deck-slide --overwrite # 目标已存在时覆盖(
|
|
|
112
136
|
## 环境变量
|
|
113
137
|
|
|
114
138
|
- `MIAODA_APP_ID`:默认应用 ID,等价于 `--app-id`。
|
|
139
|
+
- `MIAODA_MIGRATE_STEP_TIMEOUT_MS`:`app migrate` 单个依赖安装 / 构建步骤的超时(毫秒),默认 20 分钟。
|
|
115
140
|
- `MIAODA_CANARY_HEADER`:HTTP 请求的 `x-tt-env` 小流量头取值。未设置时默认 `boe_miaoda_ccm`;设为空字符串则不带该头(例:`export MIAODA_CANARY_HEADER=boe_xxx`)。值形如 `ppe_xxx` 时额外带上 `x-use-ppe: 1`。
|
|
116
141
|
|
|
117
142
|
## 输出契约
|
package/dist/api/deploy/api.js
CHANGED
|
@@ -50,9 +50,11 @@ async function getErrorLog(req) {
|
|
|
50
50
|
* GET /v1/pipeline/app/:appID/instance/:instanceID/detail — 轮询发布状态
|
|
51
51
|
*
|
|
52
52
|
* 走 lark.apaas.devops_platform PSM;URL 前缀不同但共用同一管理端 gateway。
|
|
53
|
+
* 显式带 withTransformApprovalData=true 取审批展示视图(job 上挂 approval);IDL 默认 false,
|
|
54
|
+
* 不带时拿不到审批链接与拒绝原因。该参数只改返回投影,无副作用。
|
|
53
55
|
*/
|
|
54
56
|
async function queryPipelineInstance(req) {
|
|
55
|
-
const url = `/v1/pipeline/app/${encodeURIComponent(req.appID)}/instance/${encodeURIComponent(req.instanceID)}/detail`;
|
|
57
|
+
const url = `/v1/pipeline/app/${encodeURIComponent(req.appID)}/instance/${encodeURIComponent(req.instanceID)}/detail?withTransformApprovalData=true`;
|
|
56
58
|
return (0, http_1.getInnerApi)(url, {
|
|
57
59
|
errPrefix: 'Failed to query pipeline',
|
|
58
60
|
defaultErrCode: DEFAULT_ERR_CODE,
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TERMINAL_NODE_STATUSES = void 0;
|
|
4
|
+
exports.approvalStatusText = approvalStatusText;
|
|
5
|
+
exports.findApproval = findApproval;
|
|
6
|
+
exports.approvalURL = approvalURL;
|
|
7
|
+
const types_1 = require("./types");
|
|
8
|
+
/** 流水线终态;REJECTED 为卡点审批被拒 */
|
|
9
|
+
exports.TERMINAL_NODE_STATUSES = [
|
|
10
|
+
types_1.NodeStatus.SUCCESS,
|
|
11
|
+
types_1.NodeStatus.FAILED,
|
|
12
|
+
types_1.NodeStatus.CANCELED,
|
|
13
|
+
types_1.NodeStatus.REJECTED,
|
|
14
|
+
];
|
|
15
|
+
const APPROVAL_STATUS_TEXT = {
|
|
16
|
+
[types_1.ApprovalStatus.UNSPECIFIED]: 'unknown',
|
|
17
|
+
[types_1.ApprovalStatus.PENDING]: 'pending',
|
|
18
|
+
[types_1.ApprovalStatus.APPROVED]: 'approved',
|
|
19
|
+
[types_1.ApprovalStatus.REJECTED]: 'rejected',
|
|
20
|
+
[types_1.ApprovalStatus.CANCELED]: 'canceled',
|
|
21
|
+
[types_1.ApprovalStatus.FAILED]: 'failed',
|
|
22
|
+
};
|
|
23
|
+
/** 仍需用户知道点什么的卡点:在等谁、为什么被拒、平台没把审批发出去;已通过 / 已撤回不再展示 */
|
|
24
|
+
const SURFACED_APPROVAL_STATUSES = [
|
|
25
|
+
types_1.ApprovalStatus.PENDING,
|
|
26
|
+
types_1.ApprovalStatus.REJECTED,
|
|
27
|
+
types_1.ApprovalStatus.FAILED,
|
|
28
|
+
];
|
|
29
|
+
/** 卡点审批状态数字 → 可读字符串;未知值为 unknown(n) */
|
|
30
|
+
function approvalStatusText(v) {
|
|
31
|
+
return APPROVAL_STATUS_TEXT[Number(v)] ?? `unknown(${String(v)})`;
|
|
32
|
+
}
|
|
33
|
+
function isRecord(v) {
|
|
34
|
+
return typeof v === 'object' && v !== null && !Array.isArray(v);
|
|
35
|
+
}
|
|
36
|
+
function* jobsOf(stages) {
|
|
37
|
+
if (!Array.isArray(stages))
|
|
38
|
+
return;
|
|
39
|
+
for (const stage of stages) {
|
|
40
|
+
if (!isRecord(stage) || !Array.isArray(stage.jobs))
|
|
41
|
+
continue;
|
|
42
|
+
for (const group of stage.jobs) {
|
|
43
|
+
if (!Array.isArray(group))
|
|
44
|
+
continue;
|
|
45
|
+
for (const job of group)
|
|
46
|
+
if (isRecord(job))
|
|
47
|
+
yield job;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* 从 CliQueryPipelineInstance 的 PipelineInstance(请求带 withTransformApprovalData=true,返回审批展示视图)中摘出需要输出的卡点:
|
|
53
|
+
* 第一个 status 为 PENDING / REJECTED / FAILED 的 Job.approval。一次发布可以被拦多次
|
|
54
|
+
* (build / db_check / deploy),已通过的卡点可能排在前面,不能取它;流水线串行,需要输出的至多一个。
|
|
55
|
+
* 与妙搭发布面板 findApprovalJob 同一口径。
|
|
56
|
+
*
|
|
57
|
+
* 原样透传,status 转为可读字符串,原始数字保留在 status_code(与 detail 各层 status 的约定一致)。
|
|
58
|
+
* 是否在审批中由顶层 status(PENDING)表达,这里只负责摘出审批链接、拒绝原因等上下文。
|
|
59
|
+
*/
|
|
60
|
+
function findApproval(instance) {
|
|
61
|
+
for (const job of jobsOf(instance.stages)) {
|
|
62
|
+
const approval = job.approval;
|
|
63
|
+
if (!isRecord(approval) || !SURFACED_APPROVAL_STATUSES.includes(approval.status))
|
|
64
|
+
continue;
|
|
65
|
+
return {
|
|
66
|
+
...approval,
|
|
67
|
+
status: approvalStatusText(approval.status),
|
|
68
|
+
status_code: approval.status,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
return undefined;
|
|
72
|
+
}
|
|
73
|
+
/** 取审批链接;缺失或不是非空字符串时返回 undefined。是否可信由调用方(Skill)判断。 */
|
|
74
|
+
function approvalURL(approval) {
|
|
75
|
+
const url = approval?.approvalURL;
|
|
76
|
+
return typeof url === 'string' && url !== '' ? url : undefined;
|
|
77
|
+
}
|
package/dist/api/deploy/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.NodeStatus = exports.nodeStatusFromText = exports.nodeStatusText = exports.errorJobSchema = exports.deployGetSchema = exports.deployHistorySchema = exports.batchSavePluginInstances = exports.TosActionType = exports.LocalReleaseStatus = exports.applyTosDiff = exports.getModernLastPublishedVersion = exports.getModernReleaseStatus = exports.createModernRelease = exports.callbackStatic = exports.updateLocalRelease = exports.createLocalRelease = exports.preRelease = exports.queryPipelineInstance = exports.getErrorLog = exports.listPipelineInstances = exports.createRelease = void 0;
|
|
3
|
+
exports.TERMINAL_NODE_STATUSES = exports.approvalStatusText = exports.approvalURL = exports.findApproval = exports.ApprovalStatus = exports.NodeStatus = exports.nodeStatusFromText = exports.nodeStatusText = exports.errorJobSchema = exports.deployGetSchema = exports.deployHistorySchema = exports.batchSavePluginInstances = exports.TosActionType = exports.LocalReleaseStatus = exports.applyTosDiff = exports.getModernLastPublishedVersion = exports.getModernReleaseStatus = exports.createModernRelease = exports.callbackStatic = exports.updateLocalRelease = exports.createLocalRelease = exports.preRelease = exports.queryPipelineInstance = exports.getErrorLog = exports.listPipelineInstances = exports.createRelease = void 0;
|
|
4
4
|
var api_1 = require("./api");
|
|
5
5
|
Object.defineProperty(exports, "createRelease", { enumerable: true, get: function () { return api_1.createRelease; } });
|
|
6
6
|
Object.defineProperty(exports, "listPipelineInstances", { enumerable: true, get: function () { return api_1.listPipelineInstances; } });
|
|
@@ -28,3 +28,9 @@ Object.defineProperty(exports, "nodeStatusText", { enumerable: true, get: functi
|
|
|
28
28
|
Object.defineProperty(exports, "nodeStatusFromText", { enumerable: true, get: function () { return schemas_1.nodeStatusFromText; } });
|
|
29
29
|
var types_1 = require("./types");
|
|
30
30
|
Object.defineProperty(exports, "NodeStatus", { enumerable: true, get: function () { return types_1.NodeStatus; } });
|
|
31
|
+
Object.defineProperty(exports, "ApprovalStatus", { enumerable: true, get: function () { return types_1.ApprovalStatus; } });
|
|
32
|
+
var approval_1 = require("./approval");
|
|
33
|
+
Object.defineProperty(exports, "findApproval", { enumerable: true, get: function () { return approval_1.findApproval; } });
|
|
34
|
+
Object.defineProperty(exports, "approvalURL", { enumerable: true, get: function () { return approval_1.approvalURL; } });
|
|
35
|
+
Object.defineProperty(exports, "approvalStatusText", { enumerable: true, get: function () { return approval_1.approvalStatusText; } });
|
|
36
|
+
Object.defineProperty(exports, "TERMINAL_NODE_STATUSES", { enumerable: true, get: function () { return approval_1.TERMINAL_NODE_STATUSES; } });
|
|
@@ -13,6 +13,9 @@ const NODE_STATUS_TEXT = {
|
|
|
13
13
|
[types_1.NodeStatus.FAILED]: 'failed',
|
|
14
14
|
[types_1.NodeStatus.CANCELED]: 'canceled',
|
|
15
15
|
[types_1.NodeStatus.HOLD_ON]: 'hold_on',
|
|
16
|
+
[types_1.NodeStatus.SKIPPED]: 'skipped',
|
|
17
|
+
[types_1.NodeStatus.PENDING]: 'pending',
|
|
18
|
+
[types_1.NodeStatus.REJECTED]: 'rejected',
|
|
16
19
|
};
|
|
17
20
|
function nodeStatusText(v) {
|
|
18
21
|
if (typeof v === 'string')
|
package/dist/api/deploy/types.js
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
// 发布单的唯一标识是 pipelineTaskID,对外即 deploy-id;error-log 等接口直接用它做
|
|
9
9
|
// URL 路径段(instanceID)。曾经的 Release/releaseID 概念已全面废弃。
|
|
10
10
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
-
exports.NodeStatus = void 0;
|
|
11
|
+
exports.ApprovalStatus = exports.NodeStatus = void 0;
|
|
12
12
|
/** Pipeline 节点状态(devops_platform) */
|
|
13
13
|
var NodeStatus;
|
|
14
14
|
(function (NodeStatus) {
|
|
@@ -18,5 +18,23 @@ var NodeStatus;
|
|
|
18
18
|
NodeStatus[NodeStatus["SUCCESS"] = 3] = "SUCCESS";
|
|
19
19
|
NodeStatus[NodeStatus["FAILED"] = 4] = "FAILED";
|
|
20
20
|
NodeStatus[NodeStatus["CANCELED"] = 5] = "CANCELED";
|
|
21
|
+
/** 已废弃:服务端不再产出,保留仅为兼容历史数据 */
|
|
21
22
|
NodeStatus[NodeStatus["HOLD_ON"] = 6] = "HOLD_ON";
|
|
23
|
+
/** 流水线内部中间态 */
|
|
24
|
+
NodeStatus[NodeStatus["SKIPPED"] = 7] = "SKIPPED";
|
|
25
|
+
NodeStatus[NodeStatus["PENDING"] = 8] = "PENDING";
|
|
26
|
+
/** 卡点审批被拒(人工拒绝 / 超时自动拒绝) */
|
|
27
|
+
NodeStatus[NodeStatus["REJECTED"] = 9] = "REJECTED";
|
|
22
28
|
})(NodeStatus || (exports.NodeStatus = NodeStatus = {}));
|
|
29
|
+
// ── 发布审批(卡点)信息 ────────────
|
|
30
|
+
/** 卡点审批状态(devops_platform ApprovalStatus) */
|
|
31
|
+
var ApprovalStatus;
|
|
32
|
+
(function (ApprovalStatus) {
|
|
33
|
+
ApprovalStatus[ApprovalStatus["UNSPECIFIED"] = 0] = "UNSPECIFIED";
|
|
34
|
+
ApprovalStatus[ApprovalStatus["PENDING"] = 1] = "PENDING";
|
|
35
|
+
ApprovalStatus[ApprovalStatus["APPROVED"] = 2] = "APPROVED";
|
|
36
|
+
ApprovalStatus[ApprovalStatus["REJECTED"] = 3] = "REJECTED";
|
|
37
|
+
ApprovalStatus[ApprovalStatus["CANCELED"] = 4] = "CANCELED";
|
|
38
|
+
/** 卡点异常:发起审批失败等平台侧错误 */
|
|
39
|
+
ApprovalStatus[ApprovalStatus["FAILED"] = 5] = "FAILED";
|
|
40
|
+
})(ApprovalStatus || (exports.ApprovalStatus = ApprovalStatus = {}));
|
|
@@ -40,24 +40,51 @@ function registerAppMigrate(parent) {
|
|
|
40
40
|
// 用 addCommand(cmd, { hidden: true }) 而非 parent.command(...),因为 commander 13
|
|
41
41
|
// 的 fluent `.command()` 不支持设置 hidden。
|
|
42
42
|
const cmd = new commander_1.Command('migrate')
|
|
43
|
-
.description('
|
|
43
|
+
.description('工程转换原语:原目录内按 MigrateConfig 预检冲突 → 定向转换 → 安装 → 严格验证;冲突不覆盖用户内容,失败保留现场')
|
|
44
44
|
.requiredOption('--to <stack>', '目标 stack 短名')
|
|
45
|
-
.option('--from <stack>', '源 stack
|
|
46
|
-
.option('--dir <path>', '项目目录,默认 cwd
|
|
45
|
+
.option('--from <stack>', '源 stack;默认按磁盘实际布局识别(识别不了再读 .spark/meta.json)')
|
|
46
|
+
.option('--dir <path>', '项目目录,默认 cwd')
|
|
47
|
+
.option('--purpose <purpose>', '调用目的:manual / upgrade / history_restore(只用于记录与关联)', 'manual')
|
|
48
|
+
.option('--operation-ref <id>', '调用方已有的操作 / 任务关联标识,原样回显')
|
|
49
|
+
.addOption((0, shared_1.appIdOption)())
|
|
47
50
|
.addHelpText('after', `
|
|
48
51
|
已支持的迁移路径
|
|
49
52
|
${supportedDesc || '(none)'}
|
|
53
|
+
磁盘已是目标布局(同目标)时走 repair:补齐适配 / 安装 / 构建,不返回 NOOP。
|
|
54
|
+
|
|
55
|
+
文件规则
|
|
56
|
+
明确托管的平台脚本(scripts 清单 + .githooks/pre-commit)按模板更新,scripts/ 下用户文件保留;
|
|
57
|
+
src/ public/ 搬入 client/、插件迁 server/capabilities,同路径不同内容或重复插件 ID → 冲突;
|
|
58
|
+
server / shared 只补平台缺失文件,app.module.ts 定向注册平台模块;package.json scripts、
|
|
59
|
+
tsconfig、vite.config、index.html 定向适配,无法确定的形态 → 冲突,不整文件覆盖。
|
|
60
|
+
|
|
61
|
+
结果语义
|
|
62
|
+
status=converted 原目录内文件适配、依赖安装、严格验证(全栈为完整构建)全部完成;
|
|
63
|
+
运行 readiness 由调用方核验(readiness.status=pending_caller_verification),
|
|
64
|
+
restartSignalSent / devRestarted 只表示发出了重启信号
|
|
65
|
+
status=conflict conflicts 给出具体路径 / ID,冲突文件不覆盖
|
|
66
|
+
status=failed failure.stage / failure.code 给出失败阶段与原因,现场保留、不自动回滚
|
|
67
|
+
originalIntact=true 仅表示失败发生在任何工程写入之前;写入后为 false(部分改动见 changes)。
|
|
68
|
+
失败后对同一工程重跑同目标 migrate 即按真实布局 repair(可接续安装 / 构建)。
|
|
69
|
+
非 converted 退出码为 1。
|
|
50
70
|
|
|
51
71
|
JSON 输出
|
|
52
|
-
{"data": {"
|
|
53
|
-
"
|
|
54
|
-
"
|
|
55
|
-
"
|
|
56
|
-
"
|
|
72
|
+
{"data": {"status": "converted|conflict|failed", "mode": "migrate|repair", "runId": "...",
|
|
73
|
+
"purpose": "...", "operationRef": "...",
|
|
74
|
+
"source": {"metaStack": "...", "detectedStack": "...", "stack": "..."},
|
|
75
|
+
"target": {"stack": "...", "templatePackage": "...", "templateVersion": "...", "cliVersion": "..."},
|
|
76
|
+
"stages": [{"name": "preflight|render|precheck|apply|install|verify|restart", "status": "...", "durationMs": 0}],
|
|
77
|
+
"failure": {"stage": "...", "code": "...", "message": "...", "retryable": true},
|
|
78
|
+
"conflicts": [{"path": "...", "reason": "...", "with": "...", "id": "..."}],
|
|
79
|
+
"changes": {"added": [...], "modified": [...], "deleted": [...]},
|
|
80
|
+
"install": {"status": "ok|failed|not_run"}, "verify": {"status": "...", "steps": [...]},
|
|
81
|
+
"originalIntact": true,
|
|
82
|
+
"restartSignalSent": false, "readiness": {"status": "...", "detail": "..."},
|
|
83
|
+
"appliedRules": [...], "nextActions": [...]}}
|
|
57
84
|
|
|
58
85
|
示例
|
|
59
86
|
$ miaoda app migrate --to nestjs-react-fullstack
|
|
60
|
-
$ miaoda app migrate --
|
|
87
|
+
$ miaoda app migrate --to nestjs-react-fullstack --purpose upgrade --operation-ref op_demo_xxx
|
|
61
88
|
$ miaoda app migrate --to nestjs-react-fullstack --dir /path/to/app
|
|
62
89
|
`);
|
|
63
90
|
cmd.action((0, shared_1.withHelp)(cmd, async (rawOpts) => {
|
|
@@ -65,6 +92,9 @@ JSON 输出
|
|
|
65
92
|
dir: rawOpts.dir,
|
|
66
93
|
from: rawOpts.from,
|
|
67
94
|
to: rawOpts.to,
|
|
95
|
+
appId: rawOpts.appId,
|
|
96
|
+
purpose: rawOpts.purpose,
|
|
97
|
+
operationRef: rawOpts.operationRef,
|
|
68
98
|
});
|
|
69
99
|
}));
|
|
70
100
|
parent.addCommand(cmd, { hidden: true });
|
|
@@ -97,12 +127,18 @@ function registerAppSync(parent) {
|
|
|
97
127
|
4. npm install --no-audit --no-fund --ignore-scripts。--ignore-scripts 是为绕开
|
|
98
128
|
action-plugin postinstall 在 npm install 时缺平台 env 的卡点(需要时再
|
|
99
129
|
FORCE_AUTHN_INNERAPI_DOMAIN=... npm install 手动跑一次)。
|
|
130
|
+
安装是必要步骤:失败时输出 status=failed、failedStage=install 与 installError,退出码 1
|
|
131
|
+
(已应用的文件规则保留,重跑 sync 幂等补齐)。
|
|
132
|
+
|
|
133
|
+
nestjs-react-fullstack 的平台托管文件是明确清单(scripts/dev.sh、dev.js、dev-local.js、
|
|
134
|
+
build.sh、run.sh、lint.js、prune-smart.js、hooks/run-precommit.js 与 .githooks/pre-commit),
|
|
135
|
+
同名更新;scripts/ 下其他用户文件保留。内容未变化的规则报 noop,连续 sync 不产生漂移。
|
|
100
136
|
|
|
101
137
|
stack 未纳入 sync 范围(无 SyncConfig 且无 upgrade/templates/<stack>/,如 design-html
|
|
102
138
|
buildless 静态 HTML)→ 跳过同步(no-op, skipped=true),退出码 0,不阻断 dev/启动链路。
|
|
103
139
|
|
|
104
140
|
JSON 输出
|
|
105
|
-
{"data": {"stack": "...",
|
|
141
|
+
{"data": {"stack": "...", "status": "succeeded|failed", "failedStage": "install",
|
|
106
142
|
"appliedRules": [{"type": "...", "action": "...", "path": "...", "detail": "..."}],
|
|
107
143
|
"syncedFiles": [...],
|
|
108
144
|
"mergedJsonFiles": [{"path": "...", "keys": [...]}],
|
|
@@ -308,14 +344,21 @@ function registerAppInit(parent) {
|
|
|
308
344
|
.option('--conf [json]', 'init 配置 JSON。支持 {"version": "<template 版本>"},默认 latest')
|
|
309
345
|
.option('--skip-install', '跳过依赖安装', false)
|
|
310
346
|
.option('--async-install', '派发后台进程装依赖并立即返回(与 --skip-install 互斥)', false)
|
|
347
|
+
.option('--strict', '平台严格调用:工程已存在时核验是否真正就绪(meta 可解析、stack 匹配、必要文件、依赖安装、上次操作结果),未就绪退出码 1', false)
|
|
311
348
|
.addOption((0, shared_1.appIdOption)())
|
|
312
349
|
.addHelpText('after', `
|
|
313
350
|
幂等
|
|
314
|
-
.spark/meta.json
|
|
315
|
-
|
|
316
|
-
meta
|
|
351
|
+
.spark/meta.json 已存在时不再渲染 / 安装(initialized=false, reason=already_initialized),
|
|
352
|
+
不覆盖已有业务代码;同时输出 ready 与 problems(工程就绪核验结果)。
|
|
353
|
+
meta 存在不等于就绪:--strict 时 problems 非空(meta 损坏、stack 与请求不符、必要文件缺失、
|
|
354
|
+
依赖未安装、上次 init/sync/migrate 失败)退出码 1,供平台严格调用判断。
|
|
317
355
|
上一次失败留下半渲染状态时(package.json 在但 meta.json 没在)允许重跑。
|
|
318
356
|
|
|
357
|
+
依赖安装失败
|
|
358
|
+
同步安装失败时 init 输出 status=failed、failedStage=install 并以退出码 1 结束;
|
|
359
|
+
已渲染的脚手架与 meta 保留(避免重跑时覆盖已开始编辑的文件),本地执行记录标为 install_failed,
|
|
360
|
+
后续 'miaoda app sync' 会补装依赖,--strict 在补装前报告未就绪。
|
|
361
|
+
|
|
319
362
|
应用身份(app_id)
|
|
320
363
|
--app-id <id>(或 MIAODA_APP_ID env)提供时写入 .spark/meta.json 的 app_id 字段;
|
|
321
364
|
未提供则不写。运行端命令(deploy / file / plugin 等)仍优先读 MIAODA_APP_ID env,
|
|
@@ -358,7 +401,8 @@ function registerAppInit(parent) {
|
|
|
358
401
|
与 --skip-install 互斥。
|
|
359
402
|
|
|
360
403
|
JSON 输出
|
|
361
|
-
已初始化:{"data": {"initialized": false, "reason": "already_initialized", "targetDir": "..."
|
|
404
|
+
已初始化:{"data": {"initialized": false, "reason": "already_initialized", "targetDir": "...",
|
|
405
|
+
"ready": true|false, "problems": [{"code": "...", "message": "..."}]}}
|
|
362
406
|
新初始化:{"data": {"initialized": true, "template": "...", "templateVersion": "...", "steeringVersion": "...",
|
|
363
407
|
"appId": "...", "appType": "modern_html", "sourceImported": true, "importedFileCount": 7,
|
|
364
408
|
"platformStackFound": true, "platformSyncedFiles": [...],
|
|
@@ -387,6 +431,7 @@ JSON 输出
|
|
|
387
431
|
skipInstall: rawOpts.skipInstall,
|
|
388
432
|
appId: rawOpts.appId,
|
|
389
433
|
asyncInstall: rawOpts.asyncInstall,
|
|
434
|
+
strict: rawOpts.strict,
|
|
390
435
|
});
|
|
391
436
|
}));
|
|
392
437
|
}
|
|
@@ -4,6 +4,18 @@ exports.registerDeployCommands = registerDeployCommands;
|
|
|
4
4
|
const commander_1 = require("commander");
|
|
5
5
|
const shared_1 = require("../../../cli/commands/shared");
|
|
6
6
|
const index_1 = require("../../../cli/handlers/deploy/index");
|
|
7
|
+
/** deploy history --status 可选值(pipeline 节点状态);hold_on 已被服务端废弃,仅为兼容保留 */
|
|
8
|
+
const HISTORY_STATUS_CHOICES = [
|
|
9
|
+
'todo',
|
|
10
|
+
'running',
|
|
11
|
+
'success',
|
|
12
|
+
'failed',
|
|
13
|
+
'canceled',
|
|
14
|
+
'rejected',
|
|
15
|
+
'pending',
|
|
16
|
+
'skipped',
|
|
17
|
+
'hold_on',
|
|
18
|
+
];
|
|
7
19
|
const COMMON_TIME_HELP = `
|
|
8
20
|
时间格式:
|
|
9
21
|
- 相对时间:30m(30 分钟前)、1h、2d、1w
|
|
@@ -21,8 +33,9 @@ function registerDeployCommands(program) {
|
|
|
21
33
|
.description('触发发布;支持 --wait 阻塞到终态。子命令:get / history / error-log')
|
|
22
34
|
.addOption((0, shared_1.appIdOption)().hideHelp())
|
|
23
35
|
.addOption((0, shared_1.branchOption)().hideHelp())
|
|
24
|
-
.option('--wait', '
|
|
36
|
+
.option('--wait', '阻塞直到流水线终态或进入人工审批', false)
|
|
25
37
|
.option('--timeout <sec>', '--wait 最长等待秒数(默认 300)', parseTimeout, 300)
|
|
38
|
+
.option('--apply-reason <text>', '发布申请理由,写入审批单(单行,最多 1000 字符;是否必填由服务端按应用类型判定)')
|
|
26
39
|
.addHelpText('after', `
|
|
27
40
|
不要用异步模式或后台模式调用 deploy(例如 &、nohup、后台 task、detached run,或任何会让命令提前返回的包装方式),否则调用可能提前结束,Agent 会误判发布已完成。
|
|
28
41
|
部署前置检查(Agent 必须执行)
|
|
@@ -31,20 +44,29 @@ function registerDeployCommands(program) {
|
|
|
31
44
|
- 是本次任务的产物 → 先 commit + push 再 deploy
|
|
32
45
|
- 不能确定意图 → 用 AskUser 跟用户确认(不要默默继续)
|
|
33
46
|
|
|
47
|
+
发布理由与审批
|
|
48
|
+
需要审批的应用发布时须带 --apply-reason(是否必填由服务端判定,缺失时服务端会报错)。
|
|
49
|
+
理由为单行文本,最多 1000 字符,不能包含控制字符、零宽字符与双向控制字符。
|
|
50
|
+
发布进入人工审批(status=pending)后 --wait 会立即返回,退出码为 0,不会轮询到超时。
|
|
51
|
+
|
|
34
52
|
JSON 输出
|
|
35
53
|
不带 --wait:{"data": {"pipelineTaskID": "..."}}(pipelineTaskID 即 deploy-id)
|
|
36
|
-
带 --wait:data 额外包含 detail(pipeline
|
|
54
|
+
带 --wait:data 额外包含 detail(pipeline 当前状态);
|
|
55
|
+
有卡点信息时还包含 approval(如 status、approvalURL、被拒时的 message)。
|
|
37
56
|
detail/status 字段为可读字符串;对应 *_code 字段保留 BAM 原始数字枚举。
|
|
38
57
|
|
|
39
58
|
状态确认(Agent 必须执行)
|
|
40
|
-
优先使用 --wait
|
|
59
|
+
优先使用 --wait。status 为 pending 时停止轮询,告诉用户正在等待审批负责人处理;
|
|
60
|
+
用户确认审批处理完后,查询同一个 deploy-id,不要重新发起发布。
|
|
61
|
+
其余情况下,只要 deploy 调用后没有明确的 success / failed / rejected / canceled 终态或 pending,
|
|
41
62
|
都必须每 2s 轮询一次当前发布状态:拿到 pipelineTaskID 就执行 \`miaoda deploy get <pipelineTaskID> --json\`;
|
|
42
63
|
如果没有拿到 deploy-id 或输出为空,先执行 \`miaoda deploy history --limit 1 --json\` 找到对应发布记录并取得 ID,
|
|
43
|
-
再用这个 ID 每 2s 执行一次 \`miaoda deploy get <ID> --json\`,直到 status
|
|
64
|
+
再用这个 ID 每 2s 执行一次 \`miaoda deploy get <ID> --json\`,直到 status 进入终态或 pending。
|
|
44
65
|
|
|
45
66
|
示例
|
|
46
67
|
$ miaoda deploy
|
|
47
68
|
$ miaoda deploy --wait --timeout 600
|
|
69
|
+
$ miaoda deploy --wait --apply-reason "修复登录页报错"
|
|
48
70
|
$ miaoda deploy get 12345
|
|
49
71
|
$ miaoda deploy history --status failed
|
|
50
72
|
`);
|
|
@@ -55,6 +77,7 @@ JSON 输出
|
|
|
55
77
|
branch: rawOpts.branch,
|
|
56
78
|
wait: rawOpts.wait,
|
|
57
79
|
timeout: rawOpts.timeout,
|
|
80
|
+
applyReason: rawOpts.applyReason,
|
|
58
81
|
});
|
|
59
82
|
}));
|
|
60
83
|
registerDeployGet(deployCmd);
|
|
@@ -72,6 +95,7 @@ JSON 输出
|
|
|
72
95
|
{"data": {"ID": ..., "status": ..., "creator": "...", "createdAt": ..., "updatedAt": ..., ...}, "next_cursor": null, "has_more": false}
|
|
73
96
|
ID 即 deploy-id(== pipelineTaskID)
|
|
74
97
|
data.status 为可读字符串;data.status_code 为 BAM 原始数字枚举。
|
|
98
|
+
status 为 pending / rejected / failed 且存在审批单时,额外包含 approval(如 status、approvalURL、被拒时的 message)。
|
|
75
99
|
|
|
76
100
|
示例
|
|
77
101
|
$ miaoda deploy get 12345
|
|
@@ -90,8 +114,8 @@ function registerDeployHistory(parent) {
|
|
|
90
114
|
.description('查询发布历史(按时间倒序,分页)')
|
|
91
115
|
.addOption((0, shared_1.appIdOption)().hideHelp())
|
|
92
116
|
.addOption(new commander_1.Option('--status <status>', '状态过滤(pipeline 节点状态,大小写不敏感)')
|
|
93
|
-
.choices(
|
|
94
|
-
.argParser((0, shared_1.caseInsensitiveChoice)(
|
|
117
|
+
.choices(HISTORY_STATUS_CHOICES)
|
|
118
|
+
.argParser((0, shared_1.caseInsensitiveChoice)(HISTORY_STATUS_CHOICES)))
|
|
95
119
|
.option('--since <time>', '起始时间')
|
|
96
120
|
.option('--until <time>', '截止时间')
|
|
97
121
|
.option('--limit <n>', '返回条数上限(1~100)', parseLimit, 50)
|
|
@@ -18,7 +18,14 @@ function registerDeployCommandsModern(program) {
|
|
|
18
18
|
.option('--dir <path>', '项目目录', '.')
|
|
19
19
|
.option('--skip-build', '跳过 build 步骤(已构建好时使用)', false)
|
|
20
20
|
.option('--skip-release', '不创建/更新本地发布单,发布单状态由外部托管', false)
|
|
21
|
-
.option('--conf <json>', '关联元信息 JSON,仅识别 checkPointVersion / commitID
|
|
21
|
+
.option('--conf <json>', '关联元信息 JSON,仅识别 checkPointVersion / commitID / sessionID / marker / versionLevel 五字段')
|
|
22
|
+
// 这三个 flag 只在父命令声明一份,deploy 与 deploy patch 共用。
|
|
23
|
+
// 不能在 patch 上再声明一遍:commander 遇到父子同名 option 会把值判给父命令,
|
|
24
|
+
// 子命令拿到空数组,`deploy patch --create x` 会静默失效(deploy-patch-wiring 测试可复现)。
|
|
25
|
+
// patch 从 deployCmd.opts() 读,与它今天读 --dir 的方式一致。
|
|
26
|
+
.option('--create <relpath>', '新增文件(可重复)', shared_1.collectRepeatedOption, [])
|
|
27
|
+
.option('--update <relpath>', '修改文件(可重复)', shared_1.collectRepeatedOption, [])
|
|
28
|
+
.option('--delete <relpath>', '删除文件(可重复)', shared_1.collectRepeatedOption, [])
|
|
22
29
|
.addHelpText('after', `
|
|
23
30
|
不要用异步模式或后台模式调用 deploy,否则调用可能提前结束,Agent 会误判发布已完成。
|
|
24
31
|
|
|
@@ -41,14 +48,27 @@ function registerDeployCommandsModern(program) {
|
|
|
41
48
|
外部据 stdout 返回的 version / preReleaseID 自行建单,并据本命令的
|
|
42
49
|
退出码决定把发布单翻成 Finished 还是 Failed —— 失败态由外部负责,CLI 不再兜底。
|
|
43
50
|
该模式下 releaseID / url 输出为 null(CLI 未建单,无从得知)。
|
|
44
|
-
注意:--conf
|
|
51
|
+
注意:--conf 的四个字段唯一消费者是 createLocalRelease,
|
|
45
52
|
本模式下不生效(静默忽略,不报错),需要关联请在外部建单时自行传递。
|
|
46
53
|
|
|
54
|
+
--create / --update / --delete(变更文件清单)
|
|
55
|
+
可重复,值为工程根相对路径(禁绝对路径与 "..")。deploy patch 消费它做增量发布;
|
|
56
|
+
在 deploy 下当前是预留口子——只校验路径并记一行日志,不改变上传行为:
|
|
57
|
+
deploy 仍然全量上传产物,latest 每次被重建为工作区的精确镜像(prune 清理远端多余对象),
|
|
58
|
+
以此保证 git 仓库与 TOS 资源不会不一致。
|
|
59
|
+
后续若实现增量上传,从这里取「要 PUT 哪些文件」即可,调用方无需改动;
|
|
60
|
+
删除仍交给 prune,因为 prune 比对的是完整本地清单,与上传了哪些文件无关。
|
|
61
|
+
|
|
47
62
|
--conf(关联元信息透传)
|
|
48
|
-
值为 JSON string
|
|
63
|
+
值为 JSON string,只识别四个字段,其余 key 忽略:
|
|
49
64
|
checkPointVersion 关联的 checkpoint 版本
|
|
50
65
|
commitID 关联的代码 commit ID
|
|
51
|
-
|
|
66
|
+
sessionID 发起本次发布的页面会话 ID,原样透传不做净化
|
|
67
|
+
marker 本次发布的变更说明,落发布单 description
|
|
68
|
+
四字段均可选;非法 JSON / 非对象 / 字段值非字符串会报错。
|
|
69
|
+
versionLevel:本次发布的版本档位。"major" 声明这是一个大版本,历史记录里强制开新组;
|
|
70
|
+
"minor" 声明是小版本,即使距上次发布超过聚合阈值也不提升。不传则由服务端按
|
|
71
|
+
时间间隔自动判定,与改造前行为一致——只有会主动声明档位的链路需要传。
|
|
52
72
|
|
|
53
73
|
JSON 输出(stdout)
|
|
54
74
|
{"data": {"appId": "...", "version": <n>, "url": "...", "releaseID": "...", "preReleaseID": "..."}}
|
|
@@ -60,6 +80,8 @@ JSON 输出(stdout)
|
|
|
60
80
|
$ miaoda deploy --skip-build
|
|
61
81
|
$ miaoda deploy --skip-release
|
|
62
82
|
$ miaoda deploy --conf '{"checkPointVersion":"v3","commitID":"a1b2c3d"}'
|
|
83
|
+
$ miaoda deploy --conf '{"commitID":"a1b2c3d","sessionID":"<uuid>","marker":"编辑保存:修改 index.html"}'
|
|
84
|
+
$ miaoda deploy --update index.html --create assets/new.js --delete old.html
|
|
63
85
|
`);
|
|
64
86
|
deployCmd.action((0, shared_1.withHelp)(deployCmd, async (rawOpts) => {
|
|
65
87
|
await (0, modern_1.handleDeployModern)({
|
|
@@ -68,17 +90,18 @@ JSON 输出(stdout)
|
|
|
68
90
|
skipBuild: rawOpts.skipBuild,
|
|
69
91
|
skipRelease: rawOpts.skipRelease,
|
|
70
92
|
conf: rawOpts.conf,
|
|
93
|
+
creates: rawOpts.create,
|
|
94
|
+
updates: rawOpts.update,
|
|
95
|
+
deletes: rawOpts.delete,
|
|
71
96
|
});
|
|
72
97
|
}));
|
|
73
98
|
const patchCmd = deployCmd
|
|
74
99
|
.command('patch')
|
|
75
100
|
.description('design-html 增量发布:按文件 create/update/delete,.html 变动时同步 routes.json')
|
|
76
|
-
.option('--create <relpath>', '新增文件(可重复)', shared_1.collectRepeatedOption, [])
|
|
77
|
-
.option('--update <relpath>', '覆盖已有文件(可重复)', shared_1.collectRepeatedOption, [])
|
|
78
|
-
.option('--delete <relpath>', '删除文件(可重复)', shared_1.collectRepeatedOption, [])
|
|
79
101
|
.option('--session-id <id>', '会话 ID,发布时透传给下游(可选)')
|
|
80
102
|
.addHelpText('after', `
|
|
81
|
-
--dir
|
|
103
|
+
--dir / --create / --update / --delete 声明在父命令 deploy 上,本命令共用,用法不变。
|
|
104
|
+
--dir 为项目目录,默认当前目录。
|
|
82
105
|
仅支持 design-html(design_local_deploy)。路径为工程根相对路径(= 服务端 latest 下 key),
|
|
83
106
|
禁绝对路径与 ".."。--create/--update 的本地文件必须存在。改动里含任意 .html(增 / 改 / 删)
|
|
84
107
|
时自动重算并随包更新 routes.json;纯非 .html 改动不动 routes.json。
|
|
@@ -98,9 +121,9 @@ JSON 输出
|
|
|
98
121
|
await (0, index_1.handleDeployPatch)({
|
|
99
122
|
appId: (0, shared_1.resolveAppId)({}),
|
|
100
123
|
dir: deployCmd.opts().dir ?? '.',
|
|
101
|
-
creates:
|
|
102
|
-
updates:
|
|
103
|
-
deletes:
|
|
124
|
+
creates: deployCmd.opts().create,
|
|
125
|
+
updates: deployCmd.opts().update,
|
|
126
|
+
deletes: deployCmd.opts().delete,
|
|
104
127
|
sessionID: rawOpts.sessionId,
|
|
105
128
|
});
|
|
106
129
|
}));
|
|
@@ -53,7 +53,7 @@ function registerSkillsSync(parent) {
|
|
|
53
53
|
|
|
54
54
|
JSON 输出
|
|
55
55
|
{"data": {"stack": "...", "version": "...", "syncedSkills": [...], "techSynced": true|false,
|
|
56
|
-
"claudeSkillsLink": "created|updated|noop|conflict" // 仅 --local 时}}
|
|
56
|
+
"claudeSkillsLink": "created|updated|noop|conflict|unsupported" // 仅 --local 时}}
|
|
57
57
|
|
|
58
58
|
传 --type 时:
|
|
59
59
|
{"data": {"mode": "sandbox", "type": "...", "packageName": "...", "version": "...",
|
|
@@ -38,11 +38,11 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
38
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
39
|
exports.UPGRADE_MANIFEST_FILENAME = exports.DEFAULT_EXPORT_OUT = void 0;
|
|
40
40
|
exports.handleAppExport = handleAppExport;
|
|
41
|
-
const node_child_process_1 = require("node:child_process");
|
|
42
41
|
const node_fs_1 = __importDefault(require("node:fs"));
|
|
43
42
|
const node_os_1 = __importDefault(require("node:os"));
|
|
44
43
|
const node_path_1 = __importDefault(require("node:path"));
|
|
45
44
|
const api = __importStar(require("../../../api/index"));
|
|
45
|
+
const archive_1 = require("../../../utils/archive");
|
|
46
46
|
const error_1 = require("../../../utils/error");
|
|
47
47
|
const output_1 = require("../../../utils/output");
|
|
48
48
|
const logger_1 = require("../../../utils/logger");
|
|
@@ -95,11 +95,11 @@ function extractArchive(archivePath, destDir, head) {
|
|
|
95
95
|
const isZip = head.length >= 4 && head[0] === 0x50 && head[1] === 0x4b;
|
|
96
96
|
const isGzip = head.length >= 2 && head[0] === 0x1f && head[1] === 0x8b;
|
|
97
97
|
if (isZip) {
|
|
98
|
-
(0,
|
|
98
|
+
(0, archive_1.extractZip)(archivePath, destDir);
|
|
99
99
|
return;
|
|
100
100
|
}
|
|
101
101
|
if (isGzip) {
|
|
102
|
-
(0,
|
|
102
|
+
(0, archive_1.extractTarGz)(archivePath, destDir);
|
|
103
103
|
return;
|
|
104
104
|
}
|
|
105
105
|
throw new error_1.AppError('EXPORT_ARCHIVE_INVALID', '无法识别归档格式(非 zip / tar.gz)', {
|