@lark-apaas/miaoda-cli 0.1.22 → 0.1.24-alpha.03a64f0

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.
Files changed (48) hide show
  1. package/README.md +36 -2
  2. package/dist/api/comment/api.js +24 -0
  3. package/dist/api/comment/index.js +6 -0
  4. package/dist/api/comment/types.js +6 -0
  5. package/dist/api/deploy/index.js +3 -1
  6. package/dist/api/deploy/modern-types.js +4 -1
  7. package/dist/api/deploy/modern.js +8 -0
  8. package/dist/api/index.js +3 -1
  9. package/dist/cli/commands/app/index.js +16 -10
  10. package/dist/cli/commands/comment/index.js +55 -0
  11. package/dist/cli/commands/deploy/modern.js +34 -0
  12. package/dist/cli/commands/index.js +19 -0
  13. package/dist/cli/commands/registry/index.js +114 -0
  14. package/dist/cli/handlers/app/init.js +32 -16
  15. package/dist/cli/handlers/app/sync.js +26 -8
  16. package/dist/cli/handlers/comment/index.js +7 -0
  17. package/dist/cli/handlers/comment/list.js +132 -0
  18. package/dist/cli/handlers/comment/resolve.js +44 -0
  19. package/dist/cli/handlers/deploy/index.js +3 -1
  20. package/dist/cli/handlers/deploy/patch.js +17 -0
  21. package/dist/cli/handlers/registry/add.js +97 -0
  22. package/dist/cli/handlers/registry/index.js +7 -0
  23. package/dist/cli/handlers/registry/list.js +48 -0
  24. package/dist/cli/handlers/registry/shared.js +25 -0
  25. package/dist/cli/handlers/skills/sync.js +12 -4
  26. package/dist/config/migrate-configs/vite-react-to-nestjs-react-fullstack.js +4 -0
  27. package/dist/services/app/init/index.js +2 -1
  28. package/dist/services/app/init/template.js +14 -2
  29. package/dist/services/deploy/modern/atoms/design-build.js +49 -0
  30. package/dist/services/deploy/modern/atoms/design-upload.js +74 -0
  31. package/dist/services/deploy/modern/atoms/index.js +6 -1
  32. package/dist/services/deploy/modern/atoms/tosutil.js +246 -0
  33. package/dist/services/deploy/modern/atoms/upload.js +4 -127
  34. package/dist/services/deploy/modern/check.js +28 -16
  35. package/dist/services/deploy/modern/patch/actions.js +61 -0
  36. package/dist/services/deploy/modern/patch/content.js +18 -0
  37. package/dist/services/deploy/modern/patch/index.js +46 -0
  38. package/dist/services/deploy/modern/patch/routes.js +37 -0
  39. package/dist/services/deploy/modern/patch/source-scan.js +58 -0
  40. package/dist/services/deploy/modern/pipelines/design-local.js +52 -0
  41. package/dist/services/deploy/modern/pipelines/index.js +3 -1
  42. package/dist/services/deploy/modern/pipelines/local.js +0 -4
  43. package/dist/services/deploy/modern/protocol.js +7 -0
  44. package/dist/services/deploy/modern/run.js +10 -4
  45. package/dist/services/deploy/modern/template-key-map.js +4 -0
  46. package/dist/services/registry/index.js +293 -0
  47. package/dist/utils/http.js +1 -1
  48. package/package.json +1 -1
package/README.md CHANGED
@@ -11,12 +11,17 @@ pnpm add -g @lark-apaas/miaoda-cli
11
11
  ## 使用
12
12
 
13
13
  ```bash
14
- # 设置默认应用(需要应用上下文的命令可用 --app-id 覆盖)
14
+ # 设置默认应用(需要应用上下文的命令从 MIAODA_APP_ID 读取)
15
15
  export MIAODA_APP_ID=app_demo_xxx
16
16
 
17
17
  # 文件操作
18
18
  miaoda file ls
19
19
  miaoda file upload ./local/path
20
+
21
+ # 评论操作
22
+ miaoda comment list --json
23
+ miaoda comment list --only-unresolved --json
24
+ miaoda comment resolve 1703677660120110076 --json
20
25
  ```
21
26
 
22
27
  JSON 结构化输出(Agent 推荐):
@@ -41,9 +46,38 @@ miaoda file ls --output json
41
46
  | `miaoda file ...` | 文件操作:上传、下载、元数据、签名下载、批量删除 |
42
47
  | `miaoda db ...` | 数据操作:SQL 执行、表结构查询、数据导入导出 |
43
48
  | `miaoda observability ...` | 线上日志、链路、前端源码堆栈反查、监控指标、运营指标 |
49
+ | `miaoda comment ...` | 应用评论:查看评论列表、解决评论 |
50
+ | `miaoda registry ...` | 组件 registry:列出 / copy-in design-html SDK 文件(本地执行) |
44
51
 
45
52
  完整命令通过 `miaoda --help` 或 `miaoda <domain> --help` 查看。
46
53
 
54
+ ## 组件 registry(design-html)
55
+
56
+ `miaoda registry` 为 design-html 技术栈提供 shadcn 式的「组件 registry」:把 SDK 文件**拷进**当前项目(copy-in),而非作为依赖安装。registry 是独立 npm 包,按运行时分发(design-html → buildless runtime → `@lark-apaas/coding-registry-buildless`)。
57
+
58
+ 前置:当前目录(或 `--dir`)已走过 `miaoda app init`,`.spark/meta.json` 含 `stack=design-html`。
59
+
60
+ ```bash
61
+ # 列出可用 SDK 条目(输出各文件 USAGE 注释块原文,便于 Agent 直接读用法)
62
+ miaoda registry list
63
+ miaoda registry list --json
64
+
65
+ # 把条目 copy-in 到当前项目(自动按 USAGE 块的 Depends 解析依赖闭包一并拷入)
66
+ miaoda registry add deck-slide
67
+ miaoda registry add foo.css theme --dry-run # 只报告将写 / 将跳,不落盘
68
+ miaoda registry add deck-slide --overwrite # 目标已存在时覆盖(默认跳过以保护改动)
69
+ ```
70
+
71
+ 要点:
72
+
73
+ - **条目**:registry 包根 `components/` · `scripts/` · `stylesheets/` 三个顶层目录(任意深度)下的代码文件即条目。USAGE 注释块**可选**(有则提供描述 + Depends,无则空描述、无依赖);包根直放文件、其它目录、非代码文件都不算条目。
74
+ - **寻址**:`add` / `Depends` 的 token 可写三种形式 —— `name`(去扩展名,如 `foo`)/ 完整文件名(如 `foo.css`)/ relPath(如 `stylesheets/foo.css`)。`name` **不要求唯一**,`list --json` 的 `file`(relPath)是永远无歧义的 canonical 地址。
75
+ - **多匹配全拉**:token 命中多个同名条目时全部 copy-in(如 `add foo` 把 `foo.jsx` + `foo.css` 一起拉),想只要其一就用完整文件名或 relPath。
76
+ - **拍平落地**:所有文件**拍平**到项目根(`scripts/deck-slide.js` → 项目 `deck-slide.js`,不保留子目录);闭包内同名 basename 撞车时后者覆盖前者。
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 与人同样可读。
79
+ - `--version <ver>` 指定 registry 包版本或 dist-tag(缺省 `latest`),`--dir <path>` 指定项目目录(缺省当前目录)。
80
+
47
81
  ## 全局参数
48
82
 
49
83
  - `--json [fields]`:输出结构化 JSON,可选字段级选择(如 `--json id,name`)。
@@ -55,7 +89,7 @@ miaoda file ls --output json
55
89
  ## 环境变量
56
90
 
57
91
  - `MIAODA_APP_ID`:默认应用 ID,等价于 `--app-id`。
58
- - `MIAODA_CANARY_HEADER`:HTTP 请求的 `x-tt-env` 小流量头取值。未设置时默认 `boe_miaoda_doubao`;设为空字符串则不带该头(例:`export MIAODA_CANARY_HEADER=boe_xxx`)。值形如 `ppe_xxx` 时额外带上 `x-use-ppe: 1`。
92
+ - `MIAODA_CANARY_HEADER`:HTTP 请求的 `x-tt-env` 小流量头取值。未设置时默认 `boe_miaoda_ccm`;设为空字符串则不带该头(例:`export MIAODA_CANARY_HEADER=boe_xxx`)。值形如 `ppe_xxx` 时额外带上 `x-use-ppe: 1`。
59
93
 
60
94
  ## 输出契约
61
95
 
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getComments = getComments;
4
+ exports.resolveComment = resolveComment;
5
+ const http_1 = require("../../utils/http");
6
+ /**
7
+ * 评论接口走管理端 inner-api(getHttpClient + 小写 status_code 信封),与 app / deploy /
8
+ * observability 等域一致:统一的 verbose 请求/响应日志、错误映射、信封解析,不再域内自实现。
9
+ */
10
+ /** GET /api/v1/studio/innerapi/apps/:appID/comments — 获取应用评论列表 */
11
+ async function getComments(appID, onlyUnresolved = false) {
12
+ let url = `/api/v1/studio/innerapi/apps/${encodeURIComponent(appID)}/comments`;
13
+ if (onlyUnresolved)
14
+ url += '?onlyUnresolved=true';
15
+ const body = await (0, http_1.getInnerApi)(url, {
16
+ errPrefix: 'Failed to list comments',
17
+ });
18
+ return body.items ?? [];
19
+ }
20
+ /** POST /api/v1/studio/innerapi/apps/:appID/comments/:commentID/resolve — 解决评论 */
21
+ async function resolveComment(appID, commentID) {
22
+ const url = `/api/v1/studio/innerapi/apps/${encodeURIComponent(appID)}/comments/${encodeURIComponent(commentID)}/resolve`;
23
+ await (0, http_1.postInnerApi)(url, undefined, { errPrefix: 'Failed to resolve comment' });
24
+ }
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resolveComment = exports.getComments = void 0;
4
+ var api_1 = require("./api");
5
+ Object.defineProperty(exports, "getComments", { enumerable: true, get: function () { return api_1.getComments; } });
6
+ Object.defineProperty(exports, "resolveComment", { enumerable: true, get: function () { return api_1.resolveComment; } });
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ /**
3
+ * 评论相关类型,镜像 inner-api 返回的 data 结构(snake_case 原样,与 lark docs 评论体一致)。
4
+ * ID 为 int64 itoa 后的字符串;时间为秒级 epoch。
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -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.LocalReleaseStatus = 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.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; } });
@@ -14,8 +14,10 @@ Object.defineProperty(exports, "callbackStatic", { enumerable: true, get: functi
14
14
  Object.defineProperty(exports, "createModernRelease", { enumerable: true, get: function () { return modern_1.createRelease; } });
15
15
  Object.defineProperty(exports, "getModernReleaseStatus", { enumerable: true, get: function () { return modern_1.getReleaseStatus; } });
16
16
  Object.defineProperty(exports, "getModernLastPublishedVersion", { enumerable: true, get: function () { return modern_1.getLastPublishedVersion; } });
17
+ Object.defineProperty(exports, "applyTosDiff", { enumerable: true, get: function () { return modern_1.applyTosDiff; } });
17
18
  var modern_types_1 = require("./modern-types");
18
19
  Object.defineProperty(exports, "LocalReleaseStatus", { enumerable: true, get: function () { return modern_types_1.LocalReleaseStatus; } });
20
+ Object.defineProperty(exports, "TosActionType", { enumerable: true, get: function () { return modern_types_1.TosActionType; } });
19
21
  var plugin_instances_1 = require("./plugin-instances");
20
22
  Object.defineProperty(exports, "batchSavePluginInstances", { enumerable: true, get: function () { return plugin_instances_1.batchSavePluginInstances; } });
21
23
  var schemas_1 = require("./schemas");
@@ -8,7 +8,7 @@
8
8
  //
9
9
  // 远端部署链路(B/C)所需的 release 接口先预留类型骨架,待 B/C 落地时启用。
10
10
  Object.defineProperty(exports, "__esModule", { value: true });
11
- exports.LocalReleaseStatus = void 0;
11
+ exports.TosActionType = exports.LocalReleaseStatus = void 0;
12
12
  /**
13
13
  * localPublish 状态枚举(数值,与服务端 IDL 对齐)。
14
14
  * CLI updateLocalRelease 只翻 Finished / Failed 两个终态;其它由后端流转。
@@ -21,3 +21,6 @@ exports.LocalReleaseStatus = {
21
21
  Canceled: 4,
22
22
  Rollback: 5,
23
23
  };
24
+ // ── applyTosDiff(design-html 增量发布;后端应用 TOS diff) ──
25
+ /** 对齐 IDL publish.TosActionType(UNSPECIFIED=0 不用) */
26
+ exports.TosActionType = { CREATE: 1, UPDATE: 2, DELETE: 3 };
@@ -17,6 +17,7 @@ exports.callbackStatic = callbackStatic;
17
17
  exports.createRelease = createRelease;
18
18
  exports.getReleaseStatus = getReleaseStatus;
19
19
  exports.getLastPublishedVersion = getLastPublishedVersion;
20
+ exports.applyTosDiff = applyTosDiff;
20
21
  const http_1 = require("../../utils/http");
21
22
  const devops_error_1 = require("../../utils/devops-error");
22
23
  const DEFAULT_ERR_CODE = 'INTERNAL_DEVOPS_ERROR';
@@ -76,3 +77,10 @@ async function getLastPublishedVersion(req) {
76
77
  const url = `/v1/devops/app/${encodeURIComponent(appID)}/last_published_version`;
77
78
  return (0, http_1.postInnerApi)(url, {}, envelopeOpts('Failed to get last published version'));
78
79
  }
80
+ // ── applyTosDiff ──
81
+ /** POST /v1/devops/app/:appID/apply_tos_diff —— 增量应用 TOS 文件 diff */
82
+ async function applyTosDiff(req) {
83
+ const { appID, ...body } = req;
84
+ const url = `/v1/devops/app/${encodeURIComponent(appID)}/apply_tos_diff`;
85
+ return (0, http_1.postInnerApi)(url, body, envelopeOpts('Failed to apply tos diff'));
86
+ }
package/dist/api/index.js CHANGED
@@ -33,16 +33,18 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.deploy = exports.app = exports.observability = exports.db = exports.file = exports.plugin = void 0;
36
+ exports.comment = exports.deploy = exports.app = exports.observability = exports.db = exports.file = exports.plugin = void 0;
37
37
  const _plugin = __importStar(require("../api/plugin/index"));
38
38
  const _file = __importStar(require("../api/file/index"));
39
39
  const _db = __importStar(require("../api/db/index"));
40
40
  const _observability = __importStar(require("../api/observability/index"));
41
41
  const _app = __importStar(require("../api/app/index"));
42
42
  const _deploy = __importStar(require("../api/deploy/index"));
43
+ const _comment = __importStar(require("../api/comment/index"));
43
44
  exports.plugin = { ..._plugin };
44
45
  exports.file = { ..._file };
45
46
  exports.db = { ..._db };
46
47
  exports.observability = { ..._observability };
47
48
  exports.app = { ..._app };
48
49
  exports.deploy = { ..._deploy };
50
+ exports.comment = { ..._comment };
@@ -96,6 +96,9 @@ function registerAppSync(parent) {
96
96
  action-plugin postinstall 在 npm install 时缺平台 env 的卡点(需要时再
97
97
  FORCE_AUTHN_INNERAPI_DOMAIN=... npm install 手动跑一次)。
98
98
 
99
+ stack 未纳入 sync 范围(无 SyncConfig 且无 upgrade/templates/<stack>/,如 design-html
100
+ buildless 静态 HTML)→ 跳过同步(no-op, skipped=true),退出码 0,不阻断 dev/启动链路。
101
+
99
102
  JSON 输出
100
103
  {"data": {"stack": "...",
101
104
  "appliedRules": [{"type": "...", "action": "...", "path": "...", "detail": "..."}],
@@ -103,6 +106,7 @@ JSON 输出
103
106
  "mergedJsonFiles": [{"path": "...", "keys": [...]}],
104
107
  "patchedScripts": [...],
105
108
  "upgradedPackages": [{"name": "...", "from": "...", "to": "...", "section": "..."}]}}
109
+ 跳过时:{"data": {"stack": "...", "skipped": true, "reason": "stack_not_in_sync_scope", ...空数组}}
106
110
 
107
111
  示例
108
112
  $ miaoda app sync
@@ -164,9 +168,9 @@ function registerAppInit(parent) {
164
168
  .command('init')
165
169
  .description('初始化应用代码:抓 template 渲染、同步 upgrade/templates、装 .agent/steering/ skills、写 .spark/meta.json。.spark/meta.json 已存在则直接退出')
166
170
  .option('--template <stack>', `技术栈短名(${index_1.SUPPORTED_STACKS.join(' / ')})`)
167
- .option('--app-type <type>', 'aPaaS 业务类型(html / modern_html / jspage / full_stack);未传 --template 时用于解析技术栈')
171
+ .option('--app-type <type>', 'aPaaS 业务类型(html / modern_html / frontend / jspage / full_stack);未传 --template 时用于解析技术栈')
168
172
  .option('--source-path <path>', '导入源目录:把该目录内容聚合进脚手架 src/(当前仅 --app-type modern_html 生效)')
169
- .option('--conf <json>', 'init 配置 JSON。支持 {"version": "<template 版本>"},默认 latest')
173
+ .option('--conf [json]', 'init 配置 JSON。支持 {"version": "<template 版本>"},默认 latest')
170
174
  .option('--skip-install', '跳过依赖安装', false)
171
175
  .option('--async-install', '派发后台进程装依赖并立即返回(与 --skip-install 互斥)', false)
172
176
  .addOption((0, shared_1.appIdOption)())
@@ -183,8 +187,8 @@ function registerAppInit(parent) {
183
187
  env 未设置时回退到 meta.json.app_id。
184
188
 
185
189
  技术栈解析(--template / --app-type)
186
- --template 传了 → 直接用(vite-react / html / nestjs-react-fullstack)
187
- 否则 --app-type 传了 → 查表:html→html, modern_html→html, jspage→vite-react, full_stack→nestjs-react-fullstack
190
+ --template 传了 → 直接用(vite-react / html / design-html / nestjs-react-fullstack)
191
+ 否则 --app-type 传了 → 查表:html→design-html, modern_html→html, frontend/jspage→vite-react, full_stack→nestjs-react-fullstack
188
192
  两者都没传 → 报错 ARGS_INVALID
189
193
 
190
194
  源码导入(--source-path)
@@ -193,11 +197,11 @@ function registerAppInit(parent) {
193
197
  source-path 不存在 → 报错;非 modern_html 传了 source-path → 警告并忽略,继续正常 init。
194
198
  app_type 不写入 .spark/meta.json。
195
199
 
196
- 平台同步(upgrade/templates)
197
- init 内嵌一次 upgrade/templates 同步(跟 app upgrade 共用同一份 util):
198
- miaoda-cli 自带的 upgrade/templates/<stack>/ 同步 files/(覆盖)+ patches/
199
- (JSON deep merge,含 scripts.dev:local 等)。目标 stack 未纳入 upgrade/templates/
200
- 时跳过(不报错)。后续要把 @lark-apaas/* 平台包统一指 latest,跑 'miaoda app upgrade'。
200
+ 平台同步(不在 init 内做)
201
+ init 不跑 'miaoda app sync' 的任何子动作(SyncRule 应用 / 平台脚本覆盖 / patches /
202
+ @lark-apaas/* latest)。渲染出的 scripts/ 等是 template 包发版时的版本,
203
+ package.json template 完全一致。首次同步交给 'miaoda app sync':本地 dev.sh 入口
204
+ 起服务前会先跑一次,沙箱 pod 启动阶段平台侧也会做,init 不重复。
201
205
 
202
206
  依赖安装
203
207
  默认:npm install --no-audit --no-fund
@@ -252,7 +256,9 @@ JSON 输出
252
256
  }));
253
257
  }
254
258
  function parseInitConf(raw) {
255
- if (raw === undefined)
259
+ // --conf 为可选值:未传(undefined)、裸 --conf(Commander 给 true)、空/纯空白字符串
260
+ // 一律视为不配置,回退默认(latest)。
261
+ if (raw === undefined || typeof raw === 'boolean' || raw.trim() === '')
256
262
  return undefined;
257
263
  let parsed;
258
264
  try {
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.registerCommentCommands = registerCommentCommands;
4
+ const shared_1 = require("../../../cli/commands/shared");
5
+ const index_1 = require("../../../cli/handlers/comment/index");
6
+ function registerCommentCommands(program) {
7
+ const commentCmd = program
8
+ .command('comment')
9
+ .description('应用评论:查看评论列表、解决评论')
10
+ .usage('<command> [flags]');
11
+ commentCmd.action(() => {
12
+ commentCmd.outputHelp();
13
+ });
14
+ commentCmd.addHelpText('after', `
15
+ 作用范围
16
+ 操作当前应用的评论。应用上下文:--app-id <id> 或环境变量 MIAODA_APP_ID。
17
+ `);
18
+ const listCmd = commentCmd
19
+ .command('list')
20
+ .description('查看应用评论列表')
21
+ .addOption((0, shared_1.appIdOption)().hideHelp())
22
+ .option('--only-unresolved', '仅返回未解决的评论', false)
23
+ .addHelpText('after', `
24
+ JSON 输出
25
+ {"data": [{"comment_id": "...", "content": "...", "user_id": "...",
26
+ "finish": 0, "resolved": false, "create_time": 1700000000}]}
27
+
28
+ 示例
29
+ $ miaoda comment list --json
30
+ $ miaoda comment list --only-unresolved --json
31
+ `);
32
+ listCmd.action((0, shared_1.withHelp)(listCmd, async (rawOpts) => {
33
+ (0, shared_1.rejectCliOverride)(listCmd, 'appId');
34
+ await (0, index_1.handleCommentList)({
35
+ appId: rawOpts.appId,
36
+ onlyUnresolved: rawOpts.onlyUnresolved,
37
+ });
38
+ }));
39
+ const resolveCmd = commentCmd
40
+ .command('resolve')
41
+ .description('把一条评论标记为已解决')
42
+ .argument('<commentID>', '待解决的评论 ID')
43
+ .addOption((0, shared_1.appIdOption)().hideHelp())
44
+ .addHelpText('after', `
45
+ JSON 输出
46
+ {"data": {"comment_id": "...", "resolved": true}}
47
+
48
+ 示例
49
+ $ miaoda comment resolve 1703677660120110076 --json
50
+ `);
51
+ resolveCmd.action((0, shared_1.withHelp)(resolveCmd, async (commentId, rawOpts) => {
52
+ (0, shared_1.rejectCliOverride)(resolveCmd, 'appId');
53
+ await (0, index_1.handleCommentResolve)(commentId, { appId: rawOpts.appId });
54
+ }));
55
+ }
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.registerDeployCommandsModern = registerDeployCommandsModern;
4
4
  const shared_1 = require("../../../cli/commands/shared");
5
5
  const modern_1 = require("../../../cli/handlers/deploy/modern");
6
+ const index_1 = require("../../../cli/handlers/deploy/index");
6
7
  /**
7
8
  * modern scene (MIAODA_APP_TYPE=7) 专用 deploy 注册。
8
9
  * 仅披露顶层 `miaoda deploy`,CLI 表面对齐 openclaw-cli:`--dir / --skip-build`。
@@ -56,4 +57,37 @@ JSON 输出(stdout)
56
57
  conf: rawOpts.conf,
57
58
  });
58
59
  }));
60
+ const patchCmd = deployCmd
61
+ .command('patch')
62
+ .description('design-html 增量发布:按文件 create/update/delete,.html 增删时同步 routes.json')
63
+ .option('--create <relpath>', '新增文件(可重复)', shared_1.collectRepeatedOption, [])
64
+ .option('--update <relpath>', '覆盖已有文件(可重复)', shared_1.collectRepeatedOption, [])
65
+ .option('--delete <relpath>', '删除文件(可重复)', shared_1.collectRepeatedOption, [])
66
+ .option('--session-id <id>', '会话 ID,发布时透传给下游(可选)')
67
+ .addHelpText('after', `
68
+ --dir 为项目目录(与 deploy 同名参数,默认当前目录)。
69
+ 仅支持 design-html(design_local_deploy)。路径为工程根相对路径(= 服务端 latest 下 key),
70
+ 禁绝对路径与 ".."。--create/--update 的本地文件必须存在。.html 被新增/删除(路由集合变化)
71
+ 时自动重算并随包更新 routes.json;纯 --update 现有 .html 只改内容,不动 routes.json。
72
+ routes.json 每项为 {path, file}:path 为相对路径(不含 base 前缀,由消费侧拼接),file 为
73
+ 对应源文件(如 / → index.html)。
74
+
75
+ JSON 输出
76
+ {"data": {"upsertCount": <n>, "deleteCount": <n>, "actionsSent": <n>, "routesRegenerated": <bool>}}
77
+
78
+ 示例
79
+ $ miaoda deploy patch --update index.html
80
+ $ miaoda deploy patch --create blog/post.html --delete blog/old.html
81
+ $ miaoda deploy patch --update assets/app.js --update assets/app.css
82
+ `);
83
+ patchCmd.action((0, shared_1.withHelp)(patchCmd, async (rawOpts) => {
84
+ await (0, index_1.handleDeployPatch)({
85
+ appId: (0, shared_1.resolveAppId)({}),
86
+ dir: deployCmd.opts().dir ?? '.',
87
+ creates: rawOpts.create,
88
+ updates: rawOpts.update,
89
+ deletes: rawOpts.delete,
90
+ sessionID: rawOpts.sessionId,
91
+ });
92
+ }));
59
93
  }
@@ -9,11 +9,14 @@ const index_4 = require("../../cli/commands/app/index");
9
9
  const index_5 = require("../../cli/commands/deploy/index");
10
10
  const modern_1 = require("../../cli/commands/deploy/modern");
11
11
  const index_6 = require("../../cli/commands/skills/index");
12
+ const index_7 = require("../../cli/commands/comment/index");
13
+ const index_8 = require("../../cli/commands/registry/index");
12
14
  // scene 跟 dispatcher(MIAODA_APP_TYPE)同语义层级 —— app 业务类型维度,
13
15
  // 对齐后端 devops app_common.AppType 枚举:
14
16
  // 3 = AppType_APPLICATION(全栈应用,当前仅 nestjs-react-fullstack 一个 stack)
15
17
  // 4 = AppType_DESIGN(design-stack,SSR 渲染、无业务逻辑、无数据库)
16
18
  // 7 = miaoda-cli 自定义 modern 占位(后端枚举无 7,沙箱目前不传)
19
+ // 8 = AppType_DESIGN_HTML(design-html,buildless 静态 HTML,命令集同 modern)
17
20
  // 其它(0/1/2/5/6 / 未设)→ default(命令全开,本地 dev / CI / 兼容回退)
18
21
  // stack 维度(nestjs-react-fullstack / vite-react / ...)是正交的,
19
22
  // skills sync 内部按 .spark/meta.json.stack 拉对应 coding-steering/steering/<stack>/ 子目录。
@@ -24,6 +27,8 @@ function resolveScene(appType, _archType) {
24
27
  return 'application';
25
28
  if (appType === '4')
26
29
  return 'design';
30
+ if (appType === '8')
31
+ return 'design-html';
27
32
  return 'default';
28
33
  }
29
34
  const SCENE_REGISTRARS = {
@@ -37,11 +42,13 @@ const SCENE_REGISTRARS = {
37
42
  (0, index_1.registerFileCommands)(p);
38
43
  (0, index_3.registerObservabilityCommands)(p);
39
44
  (0, index_6.registerSkillsCommands)(p);
45
+ (0, index_7.registerCommentCommands)(p);
40
46
  },
41
47
  modern: (p) => {
42
48
  (0, index_4.registerAppCommands)(p, { includeInit: true });
43
49
  (0, modern_1.registerDeployCommandsModern)(p);
44
50
  (0, index_6.registerSkillsCommands)(p);
51
+ (0, index_7.registerCommentCommands)(p);
45
52
  },
46
53
  // application scene(AppType_APPLICATION=3):
47
54
  // 在 default 命令集基础上加 skills(按 meta.json.stack 拉对应 stack 技能)
@@ -53,6 +60,7 @@ const SCENE_REGISTRARS = {
53
60
  (0, index_1.registerFileCommands)(p);
54
61
  (0, index_3.registerObservabilityCommands)(p);
55
62
  (0, index_6.registerSkillsCommands)(p);
63
+ (0, index_7.registerCommentCommands)(p);
56
64
  },
57
65
  // design scene(AppType_DESIGN=4):design-stack 仅 SSR 渲染、无后端业务逻辑、
58
66
  // 无数据库、无 UGC 文件。命令集裁掉 db / file,保留 deploy / observability / app(init) / skills。
@@ -61,6 +69,17 @@ const SCENE_REGISTRARS = {
61
69
  (0, index_5.registerDeployCommands)(p);
62
70
  (0, index_3.registerObservabilityCommands)(p);
63
71
  (0, index_6.registerSkillsCommands)(p);
72
+ (0, index_7.registerCommentCommands)(p);
73
+ },
74
+ // design-html scene(AppType_DESIGN_HTML=8):buildless 静态 HTML,
75
+ // 命令集与 modern 一致(app init/sync + modern 拆分版 deploy + skills),不挂 db/file/observability。
76
+ // 额外挂 registry(shadcn 式 copy-in SDK,design-html scene 专属)。
77
+ 'design-html': (p) => {
78
+ (0, index_4.registerAppCommands)(p, { includeInit: true });
79
+ (0, modern_1.registerDeployCommandsModern)(p);
80
+ (0, index_6.registerSkillsCommands)(p);
81
+ (0, index_8.registerRegistryCommands)(p);
82
+ (0, index_7.registerCommentCommands)(p);
64
83
  },
65
84
  };
66
85
  function readEnv(name) {
@@ -0,0 +1,114 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.registerRegistryCommands = registerRegistryCommands;
4
+ const shared_1 = require("../../../cli/commands/shared");
5
+ const index_1 = require("../../../cli/handlers/registry/index");
6
+ /**
7
+ * miaoda registry:design-html 技术栈的「组件 registry」(shadcn 式 copy-in)。
8
+ *
9
+ * registry 是独立 npm 包,按 runtime 命名分发(buildless runtime → @lark-apaas/coding-registry-buildless)。
10
+ * SDK 文件放在包根的 components/ · scripts/ · stylesheets/ 三个目录下(这三个顶层目录里的代码文件
11
+ * 才算条目);文件可带 USAGE 注释块(可选,声明描述 / 用法 / Depends)。CLI 抓 tarball、按
12
+ * .spark/meta.json.stack → runtime → 包名 选包,把 SDK 文件**拍平**copy-in 到用户项目根。
13
+ * 不写安装记账文件——项目文件树即状态(skip-by-disk)。
14
+ */
15
+ function registerRegistryCommands(program) {
16
+ const registryCmd = program
17
+ .command('registry')
18
+ .description('组件 registry:列出 / copy-in design-html SDK 文件')
19
+ .usage('<command> [flags]');
20
+ registryCmd.action(() => {
21
+ registryCmd.outputHelp();
22
+ });
23
+ registryCmd.addHelpText('after', `
24
+ 概念
25
+ - registry 包:独立 npm 包(按 runtime 命名)
26
+ - 条目 (entry):包根 components/ · scripts/ · stylesheets/ 顶层目录(任意深度)下的代码文件;
27
+ name = 文件名去扩展名(不要求唯一)。包根直放文件、其它目录、非代码文件都不算条目
28
+ - 寻址:add / Depends 的 token 可写三种形式——name(foo)/ 完整文件名(foo.css)/ relPath(stylesheets/foo.css)
29
+ - 多匹配全拉:token 命中多个同名条目时全部 copy-in(不报歧义);想只要其一就写完整文件名 / relPath
30
+ - USAGE 块:可选元数据,声明描述 / Exports / Usage / Depends;无 USAGE 也是条目(空描述、无依赖)
31
+ - Depends:从 USAGE 块解析的跨条目依赖,add 时传递解析、一并 copy-in
32
+ - add 落地:拍平到项目根(包根 scripts/x.js → 项目 x.js);同名 basename 撞车时后者覆盖前者
33
+
34
+ 前置
35
+ 当前目录(或 --dir)已走过 'miaoda app init'(.spark/meta.json 含 stack=design-html)
36
+ `);
37
+ registerRegistryList(registryCmd);
38
+ registerRegistryAdd(registryCmd);
39
+ }
40
+ function registerRegistryList(parent) {
41
+ const cmd = parent
42
+ .command('list')
43
+ .description('列出 registry 可用 SDK 条目,输出各文件的 USAGE 块原文')
44
+ .option('--dir <path>', '项目目录,默认当前目录', '.')
45
+ .option('--version <ver>', 'registry 包版本或 dist-tag,缺省 latest')
46
+ .addHelpText('after', `
47
+ 输出
48
+ 默认(pretty):各条目 USAGE 块原文拼接,带文件名分隔,给 Agent 直接读注释
49
+
50
+ JSON 输出
51
+ {"data": [{"name": "...", "file": "...", "usage": "<原文>", "dependsOn": [...]}, ...]}
52
+ (usage 保持 USAGE 块原文,不解析成结构化字段)
53
+
54
+ 示例
55
+ $ miaoda registry list
56
+ $ miaoda registry list --json
57
+ `);
58
+ cmd.action((0, shared_1.withHelp)(cmd, async (rawOpts) => {
59
+ await (0, index_1.handleRegistryList)({
60
+ dir: rawOpts.dir,
61
+ version: rawOpts.version,
62
+ });
63
+ }));
64
+ }
65
+ function registerRegistryAdd(parent) {
66
+ const cmd = parent
67
+ .command('add')
68
+ .description('把一个或多个 SDK 文件 copy-in 到当前项目(拍平到项目根,含 Depends 闭包)')
69
+ .argument('<token...>', 'name / 完整文件名 / relPath,可传多个;同名多匹配全拉,Depends 自动传递解析')
70
+ .option('--dir <path>', '项目目录,默认当前目录', '.')
71
+ .option('--version <ver>', 'registry 包版本或 dist-tag,缺省 latest')
72
+ .option('--overwrite', '目标文件已存在时覆盖(默认跳过以保护用户改动)', false)
73
+ .option('--dry-run', '只报告将写 / 将跳哪些文件,不落盘', false)
74
+ .addHelpText('after', `
75
+ 行为
76
+ - token 寻址:name(foo)/ 完整文件名(foo.css)/ relPath(stylesheets/foo.css)任一形式
77
+ - 多匹配全拉:token 命中多个同名条目时全部 copy-in;想只要其一就写完整文件名 / relPath
78
+ - 解析 USAGE 块 Depends 传递闭包,把 SDK 文件**拍平**拷到项目根
79
+ (包根 scripts/deck-stage.js → 项目 deck-stage.js;同名 basename 撞车时后者覆盖前者)
80
+ - skip-by-disk:目标文件已存在默认跳过;--overwrite 才覆盖
81
+ - 不写任何安装记账文件(项目文件树即状态)
82
+
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)
99
+
100
+ 示例
101
+ $ miaoda registry add deck-slide
102
+ $ miaoda registry add deck-slide theme --dry-run
103
+ $ miaoda registry add deck-slide --overwrite --json
104
+ `);
105
+ cmd.action((0, shared_1.withHelp)(cmd, async (names, rawOpts) => {
106
+ await (0, index_1.handleRegistryAdd)({
107
+ names,
108
+ dir: rawOpts.dir,
109
+ version: rawOpts.version,
110
+ overwrite: rawOpts.overwrite,
111
+ dryRun: rawOpts.dryRun,
112
+ });
113
+ }));
114
+ }
@@ -60,9 +60,18 @@ async function handleAppInit(opts) {
60
60
  const tplResult = (0, index_1.renderTemplate)({ stack, version, targetDir, projectName });
61
61
  // source_path 导入:当前仅 app_type=modern_html 生效。渲染完模板后、装依赖前叠加进 src/。
62
62
  const sourceImport = applySourcePathImport(opts, targetDir);
63
+ // 本地脚手架门禁:沙箱内所有栈照旧同步(nested,产出 .agent/);本地只有 LOCAL_STEERING_STACKS
64
+ // 白名单栈(nestjs-react-fullstack / vite-react)才落地 steering(.claude/.agents)与 logs/。
65
+ // html / design-html 是纯静态 / 设计产物,本地不需要这套 agent skills 脚手架,整段跳过。
66
+ const sandbox = (0, env_1.isSandboxEnv)();
67
+ const scaffoldSteering = sandbox || index_1.LOCAL_STEERING_STACKS.has(stack);
63
68
  // 先建 logs/,防止 user 跑 dev 之前 AI/工具 redirect 到 logs/*.log 因为父目录不存在直接挂
64
- // (dev.js / dev-local.js 自己也建 logs/,但只在它启动后;启动前的 shell redirect 会先于此)
65
- (0, logs_dir_1.ensureLogsDir)(targetDir);
69
+ // (dev.js / dev-local.js 自己也建 logs/,但只在它启动后;启动前的 shell redirect 会先于此)
70
+ // 仅本地白名单栈需要:沙箱环境由平台 supervisor 拉起 dev,无 init 前的 shell redirect 场景;
71
+ // 非白名单栈本地不落 steering 脚手架,也无需预建 logs/。
72
+ if (!sandbox && scaffoldSteering) {
73
+ (0, logs_dir_1.ensureLogsDir)(targetDir);
74
+ }
66
75
  // skills 同步软失败:拉不到 coding-steering 包不该阻断 writeSparkMeta /
67
76
  // activateGitHooks(之前会让 .spark/meta.json 没写,下次 init 半渲染状态又得重跑全套)。
68
77
  // 按运行环境(isSandboxEnv:MIAODA_DEP_CACHE_DIR 非空)分流 outputLayout,不绑 stack:
@@ -70,21 +79,28 @@ async function handleAppInit(opts) {
70
79
  // 跟沙箱端 update-skills.sh 链路对齐
71
80
  // - 本地 → flat (.agents/skills + .claude/skills 软链),
72
81
  // Agent / Claude Code 用同一份;nrf 在本地是主战场,vite-react 等也一样适用
73
- const outputLayout = (0, env_1.isSandboxEnv)() ? 'nested' : 'flat';
74
- let steeringResult;
82
+ const outputLayout = sandbox ? 'nested' : 'flat';
83
+ // 默认空结果:非白名单栈跳过 steering 同步时(scaffoldSteering=false)直接沿用,
84
+ // 与"拉不到 coding-steering 包"软失败路径共用同一份占位,emit / meta 落盘不受影响。
85
+ let steeringResult = {
86
+ version: 'unknown',
87
+ syncedSkills: [],
88
+ techSynced: false,
89
+ };
75
90
  let steeringError;
76
- try {
77
- steeringResult = (0, coding_steering_1.syncCodingSteering)({
78
- stack,
79
- targetDir,
80
- logPrefix: 'init',
81
- outputLayout,
82
- });
83
- }
84
- catch (err) {
85
- steeringError = err instanceof Error ? err.message : String(err);
86
- (0, logger_1.log)('init', `⚠ skills sync failed (continuing init): ${steeringError}`);
87
- steeringResult = { version: 'unknown', syncedSkills: [], techSynced: false };
91
+ if (scaffoldSteering) {
92
+ try {
93
+ steeringResult = (0, coding_steering_1.syncCodingSteering)({
94
+ stack,
95
+ targetDir,
96
+ logPrefix: 'init',
97
+ outputLayout,
98
+ });
99
+ }
100
+ catch (err) {
101
+ steeringError = err instanceof Error ? err.message : String(err);
102
+ (0, logger_1.log)('init', `⚠ skills sync failed (continuing init): ${steeringError}`);
103
+ }
88
104
  }
89
105
  // 依赖安装:async 模式留到 meta 落盘后派发后台进程(不等装完),同步模式当场装。
90
106
  // 同步:装模板钉死的依赖。不带 <pkg>@latest 位置参数,因此 npm 不会改写 package.json/lockfile