@lark-apaas/miaoda-cli 0.1.6-alpha.388541c → 0.1.7-alpha.3b4268d

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.
@@ -46,8 +46,8 @@ function registerAppSync(parent) {
46
46
  delete-file/delete-directory → 删除
47
47
  沙箱里跑的 fullstack-cli sync 走同一套 rule 类型,行为对齐;miaoda app sync 在此之上
48
48
  补 dev:local 等本地开发独有规则。
49
- 2. 平台 deps 钉版本:按 handlers/app/sync.ts 里 PINNED_PLATFORM_VERSIONS 升 user app 已装的
50
- @lark-apaas/* 包;表外 / 未装的不动。
49
+ 2. 平台 deps latest:按 handlers/app/sync.ts 里 MANAGED_PLATFORM_PACKAGES 白名单把
50
+ user app 已装的 @lark-apaas/* 包改写为 "latest";表外 / 未装的不动。
51
51
  3. activateGitHooks:core.hooksPath 一次性指向 .githooks/。
52
52
  4. npm install --no-audit --no-fund --ignore-scripts。--ignore-scripts 是为绕开
53
53
  action-plugin postinstall 在 npm install 时缺平台 env 的卡点(需要时再
@@ -140,7 +140,7 @@ function registerAppInit(parent) {
140
140
  init 内嵌一次 upgrade/templates 同步(跟 app upgrade 共用同一份 util):
141
141
  从 miaoda-cli 自带的 upgrade/templates/<stack>/ 同步 files/(覆盖)+ patches/
142
142
  (JSON deep merge,含 scripts.dev:local 等)。目标 stack 未纳入 upgrade/templates/
143
- 时跳过(不报错)。后续要升 @lark-apaas/* 平台包到最新 alpha,跑 'miaoda app upgrade'。
143
+ 时跳过(不报错)。后续要把 @lark-apaas/* 平台包统一指 latest,跑 'miaoda app upgrade'。
144
144
 
145
145
  依赖安装
146
146
  默认:npm install --no-audit --no-fund
@@ -160,7 +160,7 @@ JSON 输出
160
160
  示例
161
161
  $ miaoda app init --template vite-react
162
162
  $ miaoda app init --template nestjs-react-fullstack --app-id app_xxx
163
- $ miaoda app init --template vite-react --conf '{"version": "0.1.0-alpha.1"}'
163
+ $ miaoda app init --template vite-react --conf '{"version": "0.1.0"}'
164
164
  $ miaoda app init --template vite-react --conf '{"steeringVersion": "0.1.0"}'
165
165
  $ miaoda app init --template vite-react --skip-install
166
166
  $ MIAODA_DEP_CACHE_DIR=/tmp/dep-cache miaoda app init --template vite-react
@@ -59,8 +59,8 @@ async function handleAppInit(opts) {
59
59
  // 与最终态对齐;patches 还能覆盖 template 提供的同名文件。
60
60
  const syncRunResult = (0, sync_1.runStackSync)(stack, targetDir, 'init');
61
61
  const syncSummary = (0, sync_1.summarizeSyncResults)(syncRunResult);
62
- // template 渲染下来的 @lark-apaas/* 版本可能落后 PINNED 表,赶在 install 之前钉到表版本,
63
- // 这样一次 npm install 就直接装最终版本,不需要 install 完再补一遍。
62
+ // template 渲染下来的 @lark-apaas/* 版本可能落后 MANAGED_PLATFORM_PACKAGES 白名单,赶在
63
+ // install 之前统一指 latest,这样一次 npm install 就直接装最新版本,不需要 install 完再补。
64
64
  const upgradedPackages = (0, sync_1.upgradePlatformDeps)(targetDir, 'init');
65
65
  // skills 同步软失败:拉不到 coding-steering 包不该阻断 writeSparkMeta /
66
66
  // activateGitHooks(之前会让 .spark/meta.json 没写,下次 init 半渲染状态又得重跑全套)。
@@ -20,28 +20,27 @@ const error_1 = require("../../../utils/error");
20
20
  const output_1 = require("../../../utils/output");
21
21
  const logger_1 = require("../../../utils/logger");
22
22
  /**
23
- * 平台包钉死版本表 —— `miaoda app sync` 不查 npm dist-tags,直接按这张表把
24
- * user app 已有的 @lark-apaas/* 依赖钉到对应版本。
23
+ * `miaoda app sync` / `miaoda app init` 管控的平台包白名单 —— user app 已装这些包时,
24
+ * sync package.json 里的版本规范统一改写成 `"latest"`,npm install 时解析到当前 latest。
25
25
  *
26
- * 为什么不跟 alpha dist-tag:alpha 通道被多个团队共享,外部 prerelease 时常打过去,
27
- * 自动跟 alpha 会把回归版本(如 fullstack-vite-preset@1.0.24-alpha.5 退化没读 .env.local)
28
- * 拉进 user app。维护这张白名单可控性更高,每次升基线时人工 review 一次再改这里。
26
+ * 白名单外的 @lark-apaas/* 包:sync 不动;user app 未装的包:sync 不引入。
29
27
  *
30
- * 表里没有的 @lark-apaas/* 包:sync 不动(既不升也不报错);user app 没装的包也不引入。
31
- * 改这张表请同步把 user app 端到端 smoke 跑一次(init → sync → npm run dev)。
28
+ * 之前曾按表钉死具体 alpha 版本(避免外部 prerelease 回归),上线切 latest 通道后简化为
29
+ * 仅维护包名白名单。若某个包出现回归需要临时止血,把对应行从 `"latest"` 改为具体版本号
30
+ * 即可(用 Record<string, string> 结构而不是 Set,保留这个 escape hatch 的可能性)。
32
31
  */
33
- const PINNED_PLATFORM_VERSIONS = {
34
- '@lark-apaas/auth-sdk': '0.1.5-alpha.4',
35
- '@lark-apaas/client-toolkit': '1.2.47-alpha.0',
36
- '@lark-apaas/client-toolkit-lite': '1.1.8-alpha.0',
37
- '@lark-apaas/dataloom': '0.1.2-alpha.6',
38
- '@lark-apaas/db-schema-sync': '0.1.6-alpha.2',
39
- '@lark-apaas/express-core': '1.0.4-alpha.7',
40
- '@lark-apaas/fullstack-cli': '1.1.49-alpha.0',
41
- '@lark-apaas/fullstack-nestjs-core': '1.1.52-alpha.1',
42
- '@lark-apaas/fullstack-rspack-preset': '1.0.56-alpha.8',
43
- '@lark-apaas/fullstack-vite-preset': '1.0.24-alpha.9',
44
- '@lark-apaas/http-client': '0.1.7-alpha.8',
32
+ const MANAGED_PLATFORM_PACKAGES = {
33
+ '@lark-apaas/auth-sdk': 'latest',
34
+ '@lark-apaas/client-toolkit': 'latest',
35
+ '@lark-apaas/client-toolkit-lite': 'latest',
36
+ '@lark-apaas/dataloom': 'latest',
37
+ '@lark-apaas/db-schema-sync': 'latest',
38
+ '@lark-apaas/express-core': 'latest',
39
+ '@lark-apaas/fullstack-cli': 'latest',
40
+ '@lark-apaas/fullstack-nestjs-core': 'latest',
41
+ '@lark-apaas/fullstack-rspack-preset': 'latest',
42
+ '@lark-apaas/fullstack-vite-preset': 'latest',
43
+ '@lark-apaas/http-client': 'latest',
45
44
  };
46
45
  /**
47
46
  * miaoda app sync [--dir <path>]
@@ -53,7 +52,8 @@ const PINNED_PLATFORM_VERSIONS = {
53
52
  * 1. SyncRule[] 全量 apply —— 来自 src/config/sync-configs/<stack>.ts。每个 stack
54
53
  * 自带模板资源在 upgrade/templates/<stack>/templates/。表里没有该 stack 时回退到
55
54
  * 旧 platform-sync 兜底(兼容尚未迁移的 stack)。
56
- * 2. PINNED 平台 deps 钉版本 —— user app 已装的 @lark-apaas/* 升到 PINNED 表。
55
+ * 2. 平台 deps latest —— user app 已装的 @lark-apaas/* MANAGED_PLATFORM_PACKAGES
56
+ * 白名单改写为 "latest"(紧急止血时表里可填具体版本)。
57
57
  * 3. activateGitHooks —— 设置 core.hooksPath(template 自带 .githooks/pre-commit)。
58
58
  * 4. npm install --no-audit --no-fund --ignore-scripts —— 物化新版本,绕开
59
59
  * action-plugin postinstall 在缺平台 env 时的 ENOENT。
@@ -77,15 +77,25 @@ async function handleAppSync(opts) {
77
77
  ],
78
78
  });
79
79
  }
80
- // 2. @lark-apaas/* dep pin(按 PINNED_PLATFORM_VERSIONS 表,user app 已装才钉)
80
+ // 2. @lark-apaas/* dep 统一指 latest(按 MANAGED_PLATFORM_PACKAGES 白名单,user app 已装才升)
81
81
  const upgradedPackages = upgradePlatformDeps(targetDir, 'sync');
82
82
  // 3. activate git hooks(template 自带 .githooks/pre-commit,core.hooksPath 一次性设置)
83
83
  const hookActivation = (0, githooks_1.activateGitHooks)(targetDir);
84
- // 4. npm install —— 跟 init 一样软失败,install 挂了不该阻断 emit / sync 总结输出
85
- (0, logger_1.log)('sync', 'Running npm install --ignore-scripts...');
84
+ // 4. npm install —— 跟 init 一样软失败,install 挂了不该阻断 emit / sync 总结输出。
85
+ // 把本次实际有 from→to 变化的管控包**显式**作为位置参数传给 npm install,强制 npm 重新
86
+ // resolve lockfile entry。原因:user app 老 lockfile 可能锁着 alpha 版本,纯 `npm install`
87
+ // 看 lockfile 锁定值跟 package.json spec ("latest" range) 兼容会保留 alpha,导致 sync 后
88
+ // package.json 写了 latest 但实际还是装 alpha。显式 `npm install foo@latest bar@latest`
89
+ // 会重新解析这些包,lockfile 跟着更新。没变化的包不动,避免 noisy lockfile diff。
90
+ // --ignore-scripts 绕开 action-plugin postinstall 在缺平台 env 时的 ENOENT。
91
+ const installArgs = ['install', '--no-audit', '--no-fund', '--ignore-scripts'];
92
+ for (const bump of upgradedPackages) {
93
+ installArgs.push(`${bump.name}@${bump.to}`);
94
+ }
95
+ (0, logger_1.log)('sync', `Running npm ${installArgs.join(' ')}...`);
86
96
  let installError;
87
97
  try {
88
- (0, node_child_process_1.execFileSync)('npm', ['install', '--no-audit', '--no-fund', '--ignore-scripts'], {
98
+ (0, node_child_process_1.execFileSync)('npm', installArgs, {
89
99
  cwd: targetDir,
90
100
  stdio: (0, output_1.isJsonMode)() ? ['ignore', 'ignore', 'inherit'] : 'inherit',
91
101
  });
@@ -181,12 +191,13 @@ function readPackageJson(pkgJsonPath) {
181
191
  return JSON.parse(node_fs_1.default.readFileSync(pkgJsonPath, 'utf-8'));
182
192
  }
183
193
  /**
184
- * 把 user app package.json 里已装的 @lark-apaas/* 包钉到 PINNED_PLATFORM_VERSIONS 表版本。
185
- * `miaoda app sync` 和 `miaoda app init`(template 渲染后、install 之前)共用。
194
+ * 把 user app package.json 里已装的 @lark-apaas/* 平台包改写成 MANAGED_PLATFORM_PACKAGES
195
+ * 表里的目标 spec(缺省 `"latest"`)。由 `miaoda app sync` 和 `miaoda app init`(template
196
+ * 渲染后、install 之前)共用。
186
197
  *
187
- * - user app 已装的 PINNED 钉到表版本
188
- * - user app 未装的 PINNED 包 → 不引入(sync 的职责是对齐,不是塞依赖)
189
- * - 装着但不在 PINNED 表的 @lark-apaas/* 包 → 完全不动
198
+ * - user app 已装的管控包 写表里的目标 spec(默认 latest,紧急止血时可改具体版本)
199
+ * - user app 未装的管控包 → 不引入(sync 的职责是对齐,不是塞依赖)
200
+ * - 装着但不在白名单的 @lark-apaas/* 包 → 完全不动
190
201
  *
191
202
  * @param logPrefix 用于 `[<prefix>] deps.xxx: a → b` 日志前缀;sync 流程传 'sync',init 流程传 'init'。
192
203
  */
@@ -201,9 +212,9 @@ function upgradePlatformDeps(targetDir, logPrefix = 'sync') {
201
212
  if (!deps || typeof deps !== 'object')
202
213
  continue;
203
214
  for (const name of Object.keys(deps)) {
204
- if (!Object.prototype.hasOwnProperty.call(PINNED_PLATFORM_VERSIONS, name))
215
+ if (!Object.prototype.hasOwnProperty.call(MANAGED_PLATFORM_PACKAGES, name))
205
216
  continue;
206
- const target = PINNED_PLATFORM_VERSIONS[name];
217
+ const target = MANAGED_PLATFORM_PACKAGES[name];
207
218
  const from = deps[name];
208
219
  if (from === target)
209
220
  continue;
@@ -2,16 +2,12 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.FULLSTACK_CLI_PIN_SPEC = void 0;
4
4
  /**
5
- * 临时钉死 `@lark-apaas/fullstack-cli` 的 npx 调用版本。
5
+ * `@lark-apaas/fullstack-cli` 的 npx 调用 spec。
6
6
  *
7
7
  * 用于 user app `package.json` 里所有 `npx -y @lark-apaas/fullstack-cli ...` 调用 ——
8
- * sync 规则会按本常量生成 `npx -y <FULLSTACK_CLI_PIN_SPEC> ...`,确保 user app 每次
9
- * postinstall / gen-db-schema / sync 都拉到验证过能装插件的版本(避免 npx 拉 latest
10
- * 时碰到外部 prerelease 回归版本)。
11
- *
12
- * 维护:
13
- * - 跟 src/cli/handlers/app/sync.ts 里 PINNED_PLATFORM_VERSIONS['@lark-apaas/fullstack-cli']
14
- * **保持一致**(前者用于 user app dependencies dep bump,后者用于 npm script 里 npx 调用)
15
- * - 一旦 latest fullstack-cli 稳定且 token 鉴权回归 OK,可以去掉版本钉,让 npx 走 latest
8
+ * sync 规则会按本常量生成 `npx -y <FULLSTACK_CLI_PIN_SPEC> ...`。常量化是为了:
9
+ * - src/cli/handlers/app/sync.ts MANAGED_PLATFORM_PACKAGES['@lark-apaas/fullstack-cli']
10
+ * spec 保持一致(user app deps 跟 npm script 里 npx 调用同步切渠道)
11
+ * - 紧急止血时改一行就能把所有 user app 的 npm script 改回钉版(例如 `@1.1.49-alpha.0`)
16
12
  */
17
- exports.FULLSTACK_CLI_PIN_SPEC = '@lark-apaas/fullstack-cli@1.1.49-alpha.0';
13
+ exports.FULLSTACK_CLI_PIN_SPEC = '@lark-apaas/fullstack-cli@latest';
@@ -6,15 +6,15 @@
6
6
  * 无数据库、无 nestjs-cli。所以规则集是 nestjs-react-fullstack 的子集:只保留
7
7
  * scripts/.githooks/ 派生 + 基础 npm scripts,不动 nest-cli.json / drizzle / tsconfig.node.json。
8
8
  *
9
- * dev-local.sh 跟 nestjs-react-fullstack 不同(单进程 npm run dev,MIAODA_APP_TYPE=4),
10
- * 单独维护在 upgrade/templates/design-stack/templates/scripts/dev-local.sh
9
+ * dev-local.js 跟 nestjs-react-fullstack 不同(单进程 npm run dev,MIAODA_APP_TYPE=4),
10
+ * 单独维护在 upgrade/templates/design-stack/templates/scripts/dev-local.js
11
11
  */
12
12
  Object.defineProperty(exports, "__esModule", { value: true });
13
13
  exports.SYNC_CONFIG = void 0;
14
14
  const fullstack_cli_pin_1 = require("../../config/fullstack-cli-pin");
15
15
  exports.SYNC_CONFIG = {
16
16
  sync: [
17
- // 1. 派生 scripts/(含 design 专属 dev-local.sh + 通用 dev.sh / hooks/run-precommit.js)
17
+ // 1. 派生 scripts/(含 design 专属 dev-local.js + 通用 dev.sh / hooks/run-precommit.js)
18
18
  {
19
19
  type: 'directory',
20
20
  from: 'scripts',
@@ -90,7 +90,7 @@ exports.SYNC_CONFIG = {
90
90
  {
91
91
  type: 'add-script',
92
92
  name: 'dev:local',
93
- command: './scripts/dev-local.sh',
93
+ command: 'node ./scripts/dev-local.js',
94
94
  overwrite: false,
95
95
  },
96
96
  ],
@@ -13,7 +13,7 @@ const fullstack_cli_pin_1 = require("../../config/fullstack-cli-pin");
13
13
  exports.SYNC_CONFIG = {
14
14
  sync: [
15
15
  // ===== fullstack-cli sync 同款规则(对齐沙箱行为) =====
16
- // 1. 派生 scripts 目录(包含 dev.sh / dev-local.sh / dev.js / build.sh / run.sh /
16
+ // 1. 派生 scripts 目录(包含 dev.sh / dev-local.js / dev.js / build.sh / run.sh /
17
17
  // lint.js / prune-smart.js / hooks/run-precommit.js;directory rule 自动给 .sh +x)
18
18
  {
19
19
  type: 'directory',
@@ -131,7 +131,7 @@ exports.SYNC_CONFIG = {
131
131
  // 10. 把老 `npm run upgrade && ./scripts/dev.sh` 形式迁移到 `./scripts/dev.sh`,
132
132
  // 让本地 `npm run dev` 不再前置跑 fullstack-cli sync。新版 dev.sh 按 SANDBOX_ID 是否非空
133
133
  // 判分支:沙箱直接 exec dev.js(脚本同步由平台 pod 启动时做过,dev 入口不再 upgrade);
134
- // 本地走 miaoda app sync 兜底 + dev-local.sh
134
+ // 本地走 miaoda app sync 兜底 + dev-local.js
135
135
  {
136
136
  type: 'patch-script',
137
137
  name: 'dev',
@@ -155,12 +155,12 @@ exports.SYNC_CONFIG = {
155
155
  },
156
156
  // ===== miaoda-cli 本地开发新增规则(fullstack-cli sync 不会执行) =====
157
157
  // M1. scripts.dev:local —— 本地用户绕过 SANDBOX_ID 分发直接跑本地链路(npm run dev:local)。
158
- // dev.sh 在 SANDBOX_ID 非空时跑 dev.js(沙箱保活)、否则 exec dev-local.sh;显式 dev:local
158
+ // dev.sh 在 SANDBOX_ID 非空时跑 dev.js(沙箱保活)、否则 exec dev-local.js;显式 dev:local
159
159
  // 用于 agent 在本地稳定调试,不受任何 env 影响。
160
160
  {
161
161
  type: 'add-script',
162
162
  name: 'dev:local',
163
- command: './scripts/dev-local.sh',
163
+ command: 'node ./scripts/dev-local.js',
164
164
  overwrite: false,
165
165
  },
166
166
  // M2. tsconfig.node.json 合并 watchOptions.preserveWatchOutput —— tsc --watch 默认每次
@@ -17,17 +17,13 @@ exports.TEMPLATE_PACKAGE_BY_STACK = {
17
17
  'nestjs-react-fullstack': '@lark-apaas/coding-template-nestjs-react-fullstack',
18
18
  };
19
19
  /**
20
- * 短名 → template 包钉死版本。renderTemplate 默认按这张表取版本号,表外 stack npm latest。
20
+ * 短名 → template 包钉版表。renderTemplate 默认按这张表取版本号,表外 stack npm latest。
21
21
  *
22
- * 钉死稳定版本而非跟 alpha dist-tag —— alpha 通道被多团队共享,外部 prerelease 时常打过去,
23
- * 自动跟 alpha 会把回归版本拉进 user app。每次升基线人工 review 一次再改这里。
22
+ * 上线起所有 stack 跟随 latest dist-tag(保留 export + 表结构是为了紧急止血时可以一行钉版
23
+ * 不动 caller,例如 `'nestjs-react-fullstack': '0.1.0-alpha.6'`)。
24
24
  * 用户显式传 `--conf '{"version": "..."}'` 仍 override 此默认值。
25
25
  */
26
- exports.TEMPLATE_PINNED_VERSION_BY_STACK = {
27
- 'nestjs-react-fullstack': '0.1.0-alpha.6',
28
- html: '0.1.5-alpha.6',
29
- // vite-react 暂不钉版,跟 latest dist-tag(新版正常迭代后再纳入钉版)
30
- };
26
+ exports.TEMPLATE_PINNED_VERSION_BY_STACK = {};
31
27
  exports.SUPPORTED_STACKS = Object.keys(exports.TEMPLATE_PACKAGE_BY_STACK);
32
28
  // template/ 内以下划线开头的占位文件名在渲染时改名。
33
29
  // 原因:
@@ -46,8 +42,7 @@ function renderTemplate(opts) {
46
42
  next_actions: [`可用 stack:${exports.SUPPORTED_STACKS.join(', ')}`],
47
43
  });
48
44
  }
49
- // 默认按 TEMPLATE_PINNED_VERSION_BY_STACK 取钉版(避免 npm latest 碰外部 prerelease 回归);
50
- // 表外 stack fallback 到 'latest';用户显式传 --conf.version 仍 override 钉版。
45
+ // 缺省走 latest dist-tag;表里有钉版(紧急止血时填)则用钉版;--conf.version override。
51
46
  const pinned = Object.prototype.hasOwnProperty.call(exports.TEMPLATE_PINNED_VERSION_BY_STACK, opts.stack)
52
47
  ? exports.TEMPLATE_PINNED_VERSION_BY_STACK[opts.stack]
53
48
  : undefined;
@@ -9,11 +9,6 @@ const node_path_1 = __importDefault(require("node:path"));
9
9
  const npm_pack_1 = require("../utils/npm-pack");
10
10
  const logger_1 = require("../utils/logger");
11
11
  const STEERING_PACKAGE = '@lark-apaas/coding-steering';
12
- // 钉死稳定 alpha 版本而非跟 `alpha` dist-tag —— alpha 通道被多个团队共享,外部 prerelease
13
- // 时常打过去,自动跟 alpha 会把回归版本拉进 user app。维护这个常量比维护 alpha 通道可控。
14
- // 用户显式传具体版本(如 `miaoda skills sync 0.2.0`)仍 override 这个默认值。
15
- // 升基线时:跑端到端 smoke(init → skills sync → 看 skills 内容)→ 改这个常量。
16
- const DEFAULT_PINNED_VERSION = '0.1.6-alpha.11';
17
12
  function inferMode() {
18
13
  // process.env.SANDBOX_ID 非空 → 沙箱;其他(undefined / 空串)→ 本地
19
14
  return process.env.SANDBOX_ID ? 'sandbox' : 'local';
@@ -44,7 +39,7 @@ function inferMode() {
44
39
  */
45
40
  function syncCodingSteering(opts) {
46
41
  const logPrefix = opts.logPrefix ?? 'skills';
47
- const effectiveVersion = opts.version ?? DEFAULT_PINNED_VERSION;
42
+ const effectiveVersion = opts.version ?? 'latest';
48
43
  const mode = opts.mode ?? inferMode();
49
44
  const layout = opts.outputLayout ?? 'nested';
50
45
  (0, logger_1.log)(logPrefix, `Fetching ${STEERING_PACKAGE}@${effectiveVersion} (mode=${mode}, layout=${layout})...`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lark-apaas/miaoda-cli",
3
- "version": "0.1.6-alpha.388541c",
3
+ "version": "0.1.7-alpha.3b4268d",
4
4
  "description": "Miaoda 平台命令行工具,面向 Agent 调用",
5
5
  "type": "commonjs",
6
6
  "bin": {
@@ -9,7 +9,7 @@ upgrade/
9
9
  └── templates/
10
10
  └── <stack>/
11
11
  ├── files/ ← 文件模式:按相对路径整文件覆盖
12
- │ └── <rel-path> ← 例如 scripts/dev-local.sh → <app>/scripts/dev-local.sh
12
+ │ └── <rel-path> ← 例如 scripts/dev-local.js → <app>/scripts/dev-local.js
13
13
  └── patches/ ← JSON merge 模式:按相对路径 deep merge(任意 JSON 文件)
14
14
  └── <rel-path>.json ← 例如 package.json / tsconfig.json / nest-cli.json
15
15
  ```
@@ -0,0 +1,84 @@
1
+ #!/usr/bin/env node
2
+ // ============================================================================
3
+ // 本地开发启动脚本(由 miaoda app sync 维护,请勿手改)
4
+ // Stack: design-stack
5
+ //
6
+ // 流程:
7
+ // 1. env pull —— 拉沙箱身份/凭证到 .env.local
8
+ // 2. skills sync —— 同步当前 stack 的 agent skills
9
+ // 3. dotenv 加载 .env / .env.local 到 process.env(含 SUDA_WEBUSER 适配)
10
+ // 4. 起单进程 dev server(design-stack 单进程,无 server/client 拆分)
11
+ //
12
+ // 设计同 nestjs-react-fullstack/dev-local.js,SDK 包不需要自己 require('dotenv'),
13
+ // env 加载收敛在启动脚本单点。SUDA_WEBUSER 适配同 nrf 那份。
14
+ // ============================================================================
15
+ const fs = require('node:fs');
16
+ const path = require('node:path');
17
+ const { execSync, spawn, spawnSync } = require('node:child_process');
18
+
19
+ process.chdir(path.resolve(__dirname, '..'));
20
+
21
+ function warn(msg) {
22
+ if (process.stderr.isTTY) process.stderr.write(`\x1b[33mWARNING: ${msg}\x1b[0m\n`);
23
+ else process.stderr.write(`WARNING: ${msg}\n`);
24
+ }
25
+
26
+ if (!process.env.MIAODA_APP_TYPE) process.env.MIAODA_APP_TYPE = '4';
27
+ process.env.MIAODA_LOCAL_DEV = '1';
28
+
29
+ console.log('[dev-local] (1/4) env pull...');
30
+ const hasLarkCli = spawnSync('command', ['-v', 'lark-cli'], { shell: true, stdio: 'ignore' }).status === 0;
31
+ if (hasLarkCli) {
32
+ let appId = '';
33
+ try {
34
+ appId = JSON.parse(fs.readFileSync('.spark/meta.json', 'utf8')).app_id || '';
35
+ } catch {
36
+ /* meta.json 不存在或非法 JSON */
37
+ }
38
+ if (appId) {
39
+ const r = spawnSync('lark-cli', ['apps', '+env-pull', '--app-id', appId, '--as', 'user'], {
40
+ stdio: 'inherit',
41
+ });
42
+ if (r.status !== 0) warn('env pull 失败,继续按 .env.local 现状启动');
43
+ } else {
44
+ warn('.spark/meta.json 缺 app_id,请先跑 `miaoda app init --app-id <id>`');
45
+ }
46
+ } else {
47
+ warn('lark-cli 未安装,跳过 env pull;请确保 .env.local 已就绪');
48
+ }
49
+
50
+ // skills sync —— --local 切 flat layout;临时钉 @alpha,等 0.1.7 发到 latest 后切回。
51
+ console.log('[dev-local] (2/4) miaoda skills sync...');
52
+ try {
53
+ execSync('npx -y @lark-apaas/miaoda-cli@alpha skills sync --local', { stdio: 'inherit' });
54
+ } catch {
55
+ console.log(' (skills sync 失败,继续启动)');
56
+ }
57
+
58
+ console.log('[dev-local] (3/4) loading .env / .env.local...');
59
+ const dotenv = require('dotenv');
60
+ dotenv.config({ path: '.env.local' });
61
+ dotenv.config({ path: '.env' });
62
+
63
+ if (process.env.SUDA_WEBUSER) {
64
+ const raw = process.env.SUDA_WEBUSER;
65
+ try {
66
+ JSON.parse(raw);
67
+ } catch {
68
+ try {
69
+ const unescaped = raw.replace(/\\"/g, '"');
70
+ JSON.parse(unescaped);
71
+ process.env.SUDA_WEBUSER = unescaped;
72
+ } catch {
73
+ warn(`SUDA_WEBUSER 解析失败,值头部: ${raw.slice(0, 80)}...`);
74
+ }
75
+ }
76
+ }
77
+
78
+ console.log('[dev-local] (4/4) npm run dev');
79
+ const child = spawn('npm', ['run', 'dev'], { stdio: 'inherit', env: process.env });
80
+ child.on('exit', (code) => process.exit(code ?? 0));
81
+ child.on('error', (err) => {
82
+ console.error(err);
83
+ process.exit(1);
84
+ });
@@ -3,7 +3,7 @@
3
3
  # - SANDBOX_ID 非空(沙箱平台注入应用所属沙箱 ID)→ 直接跑 dev.js
4
4
  # (保活 / restart loop / 文件日志 —— 沙箱生产形态)。脚本同步由平台 pod 启动阶段做过,
5
5
  # dev 入口不再额外 `npm run upgrade`。
6
- # - 否则(本地)→ 走 miaoda app sync 兜底 + 跑 dev-local.sh:纯 stdout、崩了就崩、Agent 友好。
6
+ # - 否则(本地)→ 走 miaoda app sync 兜底 + 跑 dev-local.js:纯 stdout、崩了就崩、Agent 友好。
7
7
  # 显式想跑本地路径可用 `npm run dev:local`(绕过 SANDBOX_ID 判断)。
8
8
  set -euo pipefail
9
9
  SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
@@ -12,14 +12,15 @@ if [ -n "${SANDBOX_ID:-}" ]; then
12
12
  exec node "$SCRIPT_DIR/dev.js" "$@"
13
13
  fi
14
14
 
15
- if [ ! -x "$SCRIPT_DIR/dev-local.sh" ]; then
16
- echo "[dev] scripts/dev-local.sh 缺失或不可执行;先跑 \`npx -y @lark-apaas/miaoda-cli@alpha app sync\` 同步平台脚本" >&2
15
+ if [ ! -f "$SCRIPT_DIR/dev-local.js" ]; then
16
+ echo "[dev] scripts/dev-local.js 缺失;先跑 \`npx -y @lark-apaas/miaoda-cli@alpha app sync\` 同步平台脚本" >&2
17
17
  exit 1
18
18
  fi
19
19
 
20
20
  # 本地启动前先跑一次 miaoda app sync:同步 platform-controlled 内容 + 升 @lark-apaas/* 到
21
- # 钉版 + 迁移老 npm scripts。沙箱不走这里(SANDBOX_ID 分支已经 exec return)。
22
- # npx 不依赖用户全局装 miaoda;钉到 @alpha dist-tag 跟随最新发布。
21
+ # latest + 迁移老 npm scripts。沙箱不走这里(SANDBOX_ID 分支已经 exec return)。
22
+ # 临时钉 @alpha:latest dist-tag 还停在老版(0.1.6,无 app sync 子命令);等 0.1.7 发到
23
+ # latest 后切回 @latest。
23
24
  npx -y @lark-apaas/miaoda-cli@alpha app sync || echo "[dev] miaoda app sync 失败,按现状继续" >&2
24
25
 
25
- exec "$SCRIPT_DIR/dev-local.sh" "$@"
26
+ exec node "$SCRIPT_DIR/dev-local.js" "$@"
@@ -0,0 +1,113 @@
1
+ #!/usr/bin/env node
2
+ // ============================================================================
3
+ // 本地开发启动脚本(由 miaoda app sync 维护,请勿手改)
4
+ // Stack: nestjs-react-fullstack
5
+ //
6
+ // 流程:
7
+ // 1. env pull —— 拉沙箱身份/凭证到 .env.local
8
+ // 2. skills sync —— 同步当前 stack 的 agent skills
9
+ // 3. dotenv 加载 .env / .env.local 到 process.env(含 SUDA_WEBUSER 适配)
10
+ // 4. 并发起 dev:server + dev:client(子进程继承 process.env)
11
+ //
12
+ // 关键设计:本脚本在 spawn 子进程之前先把 .env / .env.local 加载到 process.env,
13
+ // 然后 spawn 的 server / client 进程通过 env 继承直接拿到——SDK(fullstack-nestjs-core
14
+ // / fullstack-vite-preset / fullstack-rspack-preset)无需自己 require('dotenv')。
15
+ //
16
+ // SUDA_WEBUSER 适配:沙箱 env pull 下发到 .env.local 的形态是
17
+ // `SUDA_WEBUSER="{\"user_id\":\"...\"}"`(shell-quoted JSON),dotenv@17 剥外层引号后
18
+ // 保留内部 `\"` 转义不还原,导致 process.env.SUDA_WEBUSER 是 `{\"user_id\":\"...\"}`
19
+ // 这种带反斜杠串,下游 JSON.parse 直接挂。这里做一次「直接 parse 失败则 unescape
20
+ // 后重 parse」兜底,把容错收敛在启动期单点,下游拿到干净 JSON 字符串。
21
+ // ============================================================================
22
+ const fs = require('node:fs');
23
+ const path = require('node:path');
24
+ const { execSync, spawn, spawnSync } = require('node:child_process');
25
+
26
+ process.chdir(path.resolve(__dirname, '..'));
27
+
28
+ function warn(msg) {
29
+ if (process.stderr.isTTY) process.stderr.write(`\x1b[33mWARNING: ${msg}\x1b[0m\n`);
30
+ else process.stderr.write(`WARNING: ${msg}\n`);
31
+ }
32
+
33
+ if (!process.env.MIAODA_APP_TYPE) process.env.MIAODA_APP_TYPE = '3';
34
+ process.env.MIAODA_LOCAL_DEV = '1';
35
+
36
+ // 1. env pull
37
+ console.log('[dev-local] (1/4) env pull...');
38
+ const hasLarkCli = spawnSync('command', ['-v', 'lark-cli'], { shell: true, stdio: 'ignore' }).status === 0;
39
+ if (hasLarkCli) {
40
+ let appId = '';
41
+ try {
42
+ appId = JSON.parse(fs.readFileSync('.spark/meta.json', 'utf8')).app_id || '';
43
+ } catch {
44
+ /* meta.json 不存在或非法 JSON */
45
+ }
46
+ if (appId) {
47
+ const r = spawnSync('lark-cli', ['apps', '+env-pull', '--app-id', appId, '--as', 'user'], {
48
+ stdio: 'inherit',
49
+ });
50
+ if (r.status !== 0) warn('env pull 失败,继续按 .env.local 现状启动');
51
+ } else {
52
+ warn('.spark/meta.json 缺 app_id,请先跑 `miaoda app init --app-id <id>`');
53
+ }
54
+ } else {
55
+ warn('lark-cli 未安装,跳过 env pull;请确保 .env.local 已就绪');
56
+ }
57
+
58
+ // 2. skills sync —— --local 切到 flat layout (.agents/skills + .claude/skills 软链),
59
+ // 跟沙箱 nested layout 区分。临时钉 @alpha:latest dist-tag 还停在老版 (0.1.6,无 skills /
60
+ // app sync 子命令);等 0.1.7 发到 latest 后切回 @latest。
61
+ console.log('[dev-local] (2/4) miaoda skills sync...');
62
+ try {
63
+ execSync('npx -y @lark-apaas/miaoda-cli@alpha skills sync --local', { stdio: 'inherit' });
64
+ } catch {
65
+ console.log(' (skills sync 失败,继续启动)');
66
+ }
67
+
68
+ // 3. 加载 .env / .env.local 到 process.env
69
+ // dotenv 默认 override:false,先到先得 → 先 .env.local 让它优先于 .env;
70
+ // shell env 已在 process.env,两次 config 都不会覆盖。
71
+ console.log('[dev-local] (3/4) loading .env / .env.local...');
72
+ const dotenv = require('dotenv');
73
+ dotenv.config({ path: '.env.local' });
74
+ dotenv.config({ path: '.env' });
75
+
76
+ // SUDA_WEBUSER 适配(详见文件头注释)
77
+ if (process.env.SUDA_WEBUSER) {
78
+ const raw = process.env.SUDA_WEBUSER;
79
+ try {
80
+ JSON.parse(raw);
81
+ } catch {
82
+ try {
83
+ const unescaped = raw.replace(/\\"/g, '"');
84
+ JSON.parse(unescaped);
85
+ process.env.SUDA_WEBUSER = unescaped;
86
+ } catch {
87
+ warn(`SUDA_WEBUSER 解析失败,值头部: ${raw.slice(0, 80)}...`);
88
+ }
89
+ }
90
+ }
91
+
92
+ // 4. 并发起前后端 dev server
93
+ console.log('[dev-local] (4/4) 并发起 dev:server + dev:client');
94
+ const child = spawn(
95
+ 'npx',
96
+ [
97
+ '--no-install',
98
+ 'concurrently',
99
+ '--names',
100
+ 'server,client',
101
+ '--prefix-colors',
102
+ 'blue,green',
103
+ '--kill-others-on-fail',
104
+ 'npm run dev:server',
105
+ 'npm run dev:client',
106
+ ],
107
+ { stdio: 'inherit', env: process.env },
108
+ );
109
+ child.on('exit', (code) => process.exit(code ?? 0));
110
+ child.on('error', (err) => {
111
+ console.error(err);
112
+ process.exit(1);
113
+ });
@@ -3,7 +3,7 @@
3
3
  # - SANDBOX_ID 非空(沙箱平台注入应用所属沙箱 ID)→ 直接跑 dev.js
4
4
  # (保活 / restart loop / 文件日志 —— 沙箱生产形态)。脚本同步由平台 pod 启动阶段做过,
5
5
  # dev 入口不再额外 `npm run upgrade`。
6
- # - 否则(本地)→ 走 miaoda app sync 兜底 + 跑 dev-local.sh:纯 stdout、崩了就崩、Agent 友好。
6
+ # - 否则(本地)→ 走 miaoda app sync 兜底 + 跑 dev-local.js:纯 stdout、崩了就崩、Agent 友好。
7
7
  # 显式想跑本地路径可用 `npm run dev:local`(绕过 SANDBOX_ID 判断)。
8
8
  set -euo pipefail
9
9
  SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
@@ -12,14 +12,15 @@ if [ -n "${SANDBOX_ID:-}" ]; then
12
12
  exec node "$SCRIPT_DIR/dev.js" "$@"
13
13
  fi
14
14
 
15
- if [ ! -x "$SCRIPT_DIR/dev-local.sh" ]; then
16
- echo "[dev] scripts/dev-local.sh 缺失或不可执行;先跑 \`npx -y @lark-apaas/miaoda-cli@alpha app sync\` 同步平台脚本" >&2
15
+ if [ ! -f "$SCRIPT_DIR/dev-local.js" ]; then
16
+ echo "[dev] scripts/dev-local.js 缺失;先跑 \`npx -y @lark-apaas/miaoda-cli@alpha app sync\` 同步平台脚本" >&2
17
17
  exit 1
18
18
  fi
19
19
 
20
20
  # 本地启动前先跑一次 miaoda app sync:同步 platform-controlled 内容 + 升 @lark-apaas/* 到
21
- # 钉版 + 迁移老 npm scripts。沙箱不走这里(SANDBOX_ID 分支已经 exec return)。
22
- # npx 不依赖用户全局装 miaoda;钉到 @alpha dist-tag 跟随最新发布。
21
+ # latest + 迁移老 npm scripts。沙箱不走这里(SANDBOX_ID 分支已经 exec return)。
22
+ # 临时钉 @alpha:latest dist-tag 还停在老版(0.1.6,无 app sync 子命令);等 0.1.7 发到
23
+ # latest 后切回 @latest。
23
24
  npx -y @lark-apaas/miaoda-cli@alpha app sync || echo "[dev] miaoda app sync 失败,按现状继续" >&2
24
25
 
25
- exec "$SCRIPT_DIR/dev-local.sh" "$@"
26
+ exec node "$SCRIPT_DIR/dev-local.js" "$@"
@@ -1,53 +0,0 @@
1
- #!/usr/bin/env bash
2
- # ============================================================================
3
- # 本地 dev 启动脚本(平台控制,通过 `miaoda app upgrade` 同步,请勿手改)
4
- # Stack: design-stack(SSR-only,无 server 业务逻辑,无数据库)
5
- # 流程:env pull → skills sync → 起 dev server
6
- # ============================================================================
7
- set -euo pipefail
8
- ROOT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
9
- cd "$ROOT_DIR"
10
-
11
- # Stack 是 design-stack,对应 miaoda CLI 的 design scene
12
- # 沙箱里这个 env 由平台注入,本地 dev 由本脚本兜底,确保 miaoda 子命令(skills/sync)能看见
13
- export MIAODA_APP_TYPE="${MIAODA_APP_TYPE:-4}"
14
-
15
- # 本地开发总开关:SDK 据此启用本地兜底逻辑(view-context 占位填充 / __runtime__ 反代 / csrf+webuser)
16
- # 沙箱 dev / 生产不设此 env,SDK 行为完全不变
17
- export MIAODA_LOCAL_DEV=1
18
-
19
- # 临时:绕 npmmirror/bnpm 内网到 npmjs 的同步延迟,等 coding-steering 正式版去掉
20
- export MIAODA_NPM_REGISTRY="${MIAODA_NPM_REGISTRY:-https://registry.npmjs.org/}"
21
-
22
- # === .env.local / .env 加载由 SDK 侧负责,本脚本不再手工 source ===
23
- # fullstack-nestjs-core 在 module init 通过 dotenv 读 .env.local + .env;
24
- # fullstack-{vite,rspack}-preset 的 defineConfig 同理。优先级:shell > .env.local > .env。
25
-
26
- # 1. 拉本地 dev 所需 ENV(jwt / cookie 等,写入 .env.local)
27
- # app_id 从 .spark/meta.json 读 —— `miaoda app init --app-id <id>` 时持久化的权威源,
28
- # 后续 dev / sync 全部沿用这一个值;不在脚本里 hack 别的推断渠道。
29
- # lark-cli 子命令真名是 `+env-pull`(带 + 前缀单 token,不是 `env pull` 空格分隔);
30
- # `--as user` 必须显式:env-pull 只接受 user identity,默认 bot 会校验失败。
31
- echo "[dev-local] (1/3) env pull..."
32
- if command -v lark-cli >/dev/null 2>&1; then
33
- # 用 node 读 .spark/meta.json,不引 python3 依赖(user app 必装 node)。
34
- APP_ID=$(node -e 'try{process.stdout.write(JSON.parse(require("fs").readFileSync(".spark/meta.json","utf8")).app_id||"")}catch(e){}' 2>/dev/null || echo "")
35
- if [ -n "$APP_ID" ]; then
36
- lark-cli apps +env-pull --app-id "$APP_ID" --as user || echo " (env pull 失败,后续按 .env.local 现状继续)"
37
- else
38
- echo " (.spark/meta.json 缺 app_id,先跑 \`miaoda app init --app-id <id>\` 写入)"
39
- fi
40
- else
41
- echo " (lark-cli 未装,跳过 env pull;请确保 .env.local 已就绪)"
42
- fi
43
-
44
- # 2. 同步 stack 对应 skills(coding-steering)。走 npx 不依赖用户全局装 miaoda;
45
- # 钉到 @alpha dist-tag 跟随最新发布,miaoda-cli 通道我们自己控制风险小。
46
- echo "[dev-local] (2/3) miaoda skills sync..."
47
- npx -y @lark-apaas/miaoda-cli@alpha skills sync || echo " (skills sync 失败,继续启动)"
48
-
49
- # 3. 起 dev server(design-stack 只有 SSR 渲染,单进程即可;不走 scripts/dev.js 的保活)
50
- # 如果模板的 npm run dev 本身就是裸进程(无保活)则直接调即可;
51
- # 如果 design-stack 模板的 dev 也是 dev.js 包装,后续需要新增 dev:raw 之类的直通命令
52
- echo "[dev-local] (3/3) npm run dev"
53
- exec npm run dev
@@ -1,61 +0,0 @@
1
- #!/usr/bin/env bash
2
- # ============================================================================
3
- # 本地 dev 启动脚本(平台控制,通过 `miaoda app upgrade` 同步,请勿手改)
4
- # Stack: nestjs-react-fullstack
5
- # 流程:env pull → skills sync → 并发起 server + client
6
- # ============================================================================
7
- set -euo pipefail
8
- ROOT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
9
- cd "$ROOT_DIR"
10
-
11
- # === Sentinels(必须由本脚本注入,不属于 .env.local 业务范畴)===
12
-
13
- # Stack 对应 miaoda CLI 的 application scene;沙箱里平台注入,本地脚本兜底,
14
- # 让后续 miaoda 子命令(skills sync 等)走对的 scene。
15
- export MIAODA_APP_TYPE="${MIAODA_APP_TYPE:-3}"
16
-
17
- # 本地开发总开关:SDK(fullstack-vite-preset / fullstack-rspack-preset /
18
- # fullstack-nestjs-core)据此启用本地兜底逻辑:
19
- # - vite/rspack-preset:反代 /__runtime__ 到沙箱(带 cookie / webuser header)
20
- # - nestjs-core:从 cookie 补 csrf header + 注入 webuser header
21
- # 沙箱 dev / 生产不设此 env,SDK 行为完全不变。
22
- export MIAODA_LOCAL_DEV=1
23
-
24
- # 临时:绕 npmmirror/bnpm 内网到 npmjs 的同步延迟,等 coding-steering 正式版去掉。
25
- export MIAODA_NPM_REGISTRY="${MIAODA_NPM_REGISTRY:-https://registry.npmjs.org/}"
26
-
27
- # === .env.local / .env 加载由 SDK 侧负责,本脚本不再手工 source ===
28
- # fullstack-nestjs-core 在 module init 通过 dotenv 读 .env.local + .env;
29
- # fullstack-{vite,rspack}-preset 的 defineConfig 同理。优先级:shell > .env.local > .env。
30
- # 历史版本曾在这里用 bash 自写 parser,引号 / 多行 / 行尾注释处理不全且重复造轮子,已下放到 SDK。
31
-
32
- # 1. 拉本地 dev 所需 ENV(jwt / cookie / sandbox URL 等,写入 .env.local)
33
- # app_id 从 .spark/meta.json 读 —— `miaoda app init --app-id <id>` 时持久化的权威源,
34
- # 后续 dev / sync 全部沿用这一个值;不在脚本里 hack 别的推断渠道。
35
- # lark-cli 子命令真名是 `+env-pull`(带 + 前缀单 token,不是 `env pull` 空格分隔);
36
- # `--as user` 必须显式:env-pull 只接受 user identity,默认 bot 会校验失败。
37
- echo "[dev-local] (1/3) env pull..."
38
- if command -v lark-cli >/dev/null 2>&1; then
39
- # 用 node 读 .spark/meta.json,不引 python3 依赖(user app 必装 node)。
40
- APP_ID=$(node -e 'try{process.stdout.write(JSON.parse(require("fs").readFileSync(".spark/meta.json","utf8")).app_id||"")}catch(e){}' 2>/dev/null || echo "")
41
- if [ -n "$APP_ID" ]; then
42
- lark-cli apps +env-pull --app-id "$APP_ID" --as user || echo " (env pull 失败,后续按 .env.local 现状继续)"
43
- else
44
- echo " (.spark/meta.json 缺 app_id,先跑 \`miaoda app init --app-id <id>\` 写入)"
45
- fi
46
- else
47
- echo " (lark-cli 未装,跳过 env pull;请确保 .env.local 已就绪)"
48
- fi
49
-
50
- # 2. 同步 stack 对应 skills(coding-steering)。走 npx 不依赖用户全局装 miaoda;
51
- # 钉到 @alpha dist-tag 跟随最新发布,miaoda-cli 通道我们自己控制风险小。
52
- echo "[dev-local] (2/3) miaoda skills sync..."
53
- npx -y @lark-apaas/miaoda-cli@alpha skills sync || echo " (skills sync 失败,继续启动)"
54
-
55
- # 3. 并发起 dev:server(NestJS)+ dev:client(vite/rspack)
56
- # 端口、SANDBOX_* 等业务 env 由 SDK 内 dotenv 加载,不在 banner 里假装显示。
57
- # 不走 scripts/dev.js(保活 / restart / 日志写文件那套)—— 本地崩就崩,错日志直接 stdout。
58
- echo "[dev-local] (3/3) 并发起 dev:server + dev:client"
59
- exec npx --no-install concurrently \
60
- --names "server,client" --prefix-colors "blue,green" --kill-others-on-fail \
61
- "npm run dev:server" "npm run dev:client"