@lark-apaas/miaoda-cli 0.1.5 → 0.1.6-alpha.388541c
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 +1 -1
- package/dist/api/deploy/index.js +13 -1
- package/dist/api/deploy/modern-types.js +23 -0
- package/dist/api/deploy/modern.js +78 -0
- package/dist/api/deploy/plugin-instances-types.js +6 -0
- package/dist/api/deploy/plugin-instances.js +22 -0
- package/dist/cli/commands/app/index.js +144 -2
- package/dist/cli/commands/deploy/modern.js +50 -0
- package/dist/cli/commands/index.js +68 -5
- package/dist/cli/commands/skills/index.js +79 -0
- package/dist/cli/handlers/app/index.js +9 -1
- package/dist/cli/handlers/app/init.js +132 -0
- package/dist/cli/handlers/app/sync.js +219 -0
- package/dist/cli/handlers/deploy/modern.js +33 -0
- package/dist/cli/handlers/skills/index.js +7 -0
- package/dist/cli/handlers/skills/status.js +31 -0
- package/dist/cli/handlers/skills/sync.js +49 -0
- package/dist/config/fullstack-cli-pin.js +17 -0
- package/dist/config/sync-configs/design-stack.js +98 -0
- package/dist/config/sync-configs/index.js +62 -0
- package/dist/config/sync-configs/nestjs-react-fullstack.js +177 -0
- package/dist/config/sync.js +14 -0
- package/dist/services/app/init/index.js +12 -0
- package/dist/services/app/init/install.js +123 -0
- package/dist/services/app/init/template.js +109 -0
- package/dist/services/deploy/modern/atoms/build.js +59 -0
- package/dist/services/deploy/modern/atoms/context.js +27 -0
- package/dist/services/deploy/modern/atoms/index.js +17 -0
- package/dist/services/deploy/modern/atoms/local-release.js +27 -0
- package/dist/services/deploy/modern/atoms/pre-release.js +13 -0
- package/dist/services/deploy/modern/atoms/save-plugin-instances.js +72 -0
- package/dist/services/deploy/modern/atoms/upload.js +246 -0
- package/dist/services/deploy/modern/check.js +53 -0
- package/dist/services/deploy/modern/constants.js +13 -0
- package/dist/services/deploy/modern/index.js +16 -0
- package/dist/services/deploy/modern/pipelines/index.js +5 -0
- package/dist/services/deploy/modern/pipelines/local.js +75 -0
- package/dist/services/deploy/modern/protocol.js +122 -0
- package/dist/services/deploy/modern/run-types.js +4 -0
- package/dist/services/deploy/modern/run.js +13 -0
- package/dist/services/deploy/modern/template-key-map.js +22 -0
- package/dist/services/skills/index.js +5 -0
- package/dist/services/skills/status.js +37 -0
- package/dist/utils/coding-steering.js +169 -0
- package/dist/utils/file-ops.js +45 -0
- package/dist/utils/githooks.js +55 -0
- package/dist/utils/http.js +21 -11
- package/dist/utils/merge-json.js +63 -0
- package/dist/utils/npm-pack.js +55 -0
- package/dist/utils/platform-sync.js +160 -0
- package/dist/utils/spark-meta.js +42 -0
- package/dist/utils/sync-rule.js +295 -0
- package/package.json +5 -3
- package/upgrade/templates/README.md +34 -0
- package/upgrade/templates/design-stack/templates/.githooks/pre-commit +4 -0
- package/upgrade/templates/design-stack/templates/scripts/dev-local.sh +53 -0
- package/upgrade/templates/design-stack/templates/scripts/dev.sh +25 -0
- package/upgrade/templates/design-stack/templates/scripts/hooks/run-precommit.js +37 -0
- package/upgrade/templates/nestjs-react-fullstack/templates/.githooks/pre-commit +4 -0
- package/upgrade/templates/nestjs-react-fullstack/templates/.gitignore.append +8 -0
- package/upgrade/templates/nestjs-react-fullstack/templates/.spark_project +16 -0
- package/upgrade/templates/nestjs-react-fullstack/templates/drizzle.config.ts +55 -0
- package/upgrade/templates/nestjs-react-fullstack/templates/helper/gen-openapi.ts +34 -0
- package/upgrade/templates/nestjs-react-fullstack/templates/nest-cli.json +25 -0
- package/upgrade/templates/nestjs-react-fullstack/templates/scripts/build.sh +207 -0
- package/upgrade/templates/nestjs-react-fullstack/templates/scripts/dev-local.sh +61 -0
- package/upgrade/templates/nestjs-react-fullstack/templates/scripts/dev.js +295 -0
- package/upgrade/templates/nestjs-react-fullstack/templates/scripts/dev.sh +25 -0
- package/upgrade/templates/nestjs-react-fullstack/templates/scripts/hooks/run-precommit.js +37 -0
- package/upgrade/templates/nestjs-react-fullstack/templates/scripts/lint.js +150 -0
- package/upgrade/templates/nestjs-react-fullstack/templates/scripts/prune-smart.js +330 -0
- package/upgrade/templates/nestjs-react-fullstack/templates/scripts/run.sh +8 -0
- package/upgrade/templates/nestjs-react-fullstack/templates/server/global.d.ts +19 -0
- package/upgrade/templates/nestjs-react-fullstack/templates/tsconfig.node.json +5 -0
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.handleAppInit = handleAppInit;
|
|
7
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
8
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
9
|
+
const index_1 = require("../../../services/app/init/index");
|
|
10
|
+
const coding_steering_1 = require("../../../utils/coding-steering");
|
|
11
|
+
const logger_1 = require("../../../utils/logger");
|
|
12
|
+
const githooks_1 = require("../../../utils/githooks");
|
|
13
|
+
const sync_1 = require("../../../cli/handlers/app/sync");
|
|
14
|
+
const error_1 = require("../../../utils/error");
|
|
15
|
+
const output_1 = require("../../../utils/output");
|
|
16
|
+
/**
|
|
17
|
+
* miaoda app init
|
|
18
|
+
*
|
|
19
|
+
* 一站式本地脚手架:render template → upgrade/templates sync → skills sync → install deps,把
|
|
20
|
+
* {stack, version, archType, app_id?} 写入 .spark/meta.json。--app-id(或 MIAODA_APP_ID)提供时
|
|
21
|
+
* 持久化 app_id;运行端命令仍优先读 env,未设置时回退到 meta.json。
|
|
22
|
+
*
|
|
23
|
+
* 幂等:.spark/meta.json 存在即表示已完整成功一次,直接退出,不重跑任何子步骤。
|
|
24
|
+
* 半渲染状态(package.json 在但 meta.json 不在)会重新跑完整流程。
|
|
25
|
+
*/
|
|
26
|
+
async function handleAppInit(opts) {
|
|
27
|
+
await Promise.resolve();
|
|
28
|
+
const targetDir = opts.targetDir ?? process.cwd();
|
|
29
|
+
const metaPath = node_path_1.default.join(targetDir, '.spark', 'meta.json');
|
|
30
|
+
if (node_fs_1.default.existsSync(metaPath)) {
|
|
31
|
+
if (!(0, output_1.isJsonMode)()) {
|
|
32
|
+
process.stdout.write(`Already initialized: ${metaPath}\n`);
|
|
33
|
+
}
|
|
34
|
+
(0, output_1.emit)({
|
|
35
|
+
data: {
|
|
36
|
+
initialized: false,
|
|
37
|
+
reason: 'already_initialized',
|
|
38
|
+
targetDir,
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
const stack = opts.template;
|
|
44
|
+
if (!stack) {
|
|
45
|
+
throw new error_1.AppError('ARGS_INVALID', '缺少 --template <stack>', {
|
|
46
|
+
next_actions: [`可用 stack:${index_1.SUPPORTED_STACKS.join(', ')}`],
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
if (!index_1.SUPPORTED_STACKS.includes(stack)) {
|
|
50
|
+
throw new error_1.AppError('ARGS_INVALID', `不支持的 template: ${stack}`, {
|
|
51
|
+
next_actions: [`可用 stack:${index_1.SUPPORTED_STACKS.join(', ')}`],
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
const version = opts.conf?.version;
|
|
55
|
+
const projectName = node_path_1.default.basename(targetDir);
|
|
56
|
+
const tplResult = (0, index_1.renderTemplate)({ stack, version, targetDir, projectName });
|
|
57
|
+
// sync 紧跟 template 渲染之后,赶在 install 之前:
|
|
58
|
+
// 这样 directory / merge-json / add-script 等 rule 都已落地,install 出来的 lockfile
|
|
59
|
+
// 与最终态对齐;patches 还能覆盖 template 提供的同名文件。
|
|
60
|
+
const syncRunResult = (0, sync_1.runStackSync)(stack, targetDir, 'init');
|
|
61
|
+
const syncSummary = (0, sync_1.summarizeSyncResults)(syncRunResult);
|
|
62
|
+
// template 渲染下来的 @lark-apaas/* 版本可能落后 PINNED 表,赶在 install 之前钉到表版本,
|
|
63
|
+
// 这样一次 npm install 就直接装最终版本,不需要 install 完再补一遍。
|
|
64
|
+
const upgradedPackages = (0, sync_1.upgradePlatformDeps)(targetDir, 'init');
|
|
65
|
+
// skills 同步软失败:拉不到 coding-steering 包不该阻断 writeSparkMeta /
|
|
66
|
+
// activateGitHooks(之前会让 .spark/meta.json 没写,下次 init 半渲染状态又得重跑全套)。
|
|
67
|
+
let steeringResult;
|
|
68
|
+
let steeringError;
|
|
69
|
+
try {
|
|
70
|
+
steeringResult = (0, coding_steering_1.syncCodingSteering)({
|
|
71
|
+
stack,
|
|
72
|
+
targetDir,
|
|
73
|
+
version: opts.conf?.steeringVersion,
|
|
74
|
+
logPrefix: 'init',
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
catch (err) {
|
|
78
|
+
steeringError = err instanceof Error ? err.message : String(err);
|
|
79
|
+
(0, logger_1.log)('init', `⚠ skills sync failed (continuing init): ${steeringError}`);
|
|
80
|
+
steeringResult = { version: 'unknown', syncedSkills: [], techSynced: false };
|
|
81
|
+
}
|
|
82
|
+
const installResult = (0, index_1.installDependencies)({
|
|
83
|
+
targetDir,
|
|
84
|
+
skip: opts.skipInstall,
|
|
85
|
+
quietStdout: (0, output_1.isJsonMode)(),
|
|
86
|
+
});
|
|
87
|
+
// template 自带 .githooks/pre-commit;如果用户项目已 git init,顺便设上 core.hooksPath。
|
|
88
|
+
const hookActivation = (0, githooks_1.activateGitHooks)(targetDir);
|
|
89
|
+
(0, index_1.writeSparkMeta)(targetDir, {
|
|
90
|
+
stack,
|
|
91
|
+
version: tplResult.version,
|
|
92
|
+
archType: tplResult.archType,
|
|
93
|
+
app_id: opts.appId,
|
|
94
|
+
steeringVersion: steeringResult.version,
|
|
95
|
+
});
|
|
96
|
+
const syncedSummary = syncRunResult.stackFound
|
|
97
|
+
? syncRunResult.rulesApplied.length > 0
|
|
98
|
+
? `${syncRunResult.rulesApplied.length.toString()} rule(s)`
|
|
99
|
+
: 'legacy'
|
|
100
|
+
: 'skipped';
|
|
101
|
+
if (!(0, output_1.isJsonMode)()) {
|
|
102
|
+
process.stdout.write(`✓ Initialized ${stack} (template ${tplResult.version}, steering ${steeringResult.version}, sync ${syncedSummary}, install ${installResult.source}) in ${targetDir}\n`);
|
|
103
|
+
}
|
|
104
|
+
(0, output_1.emit)({
|
|
105
|
+
data: {
|
|
106
|
+
initialized: true,
|
|
107
|
+
template: stack,
|
|
108
|
+
templatePackage: tplResult.packageName,
|
|
109
|
+
templateVersion: tplResult.version,
|
|
110
|
+
steeringVersion: steeringResult.version,
|
|
111
|
+
archType: tplResult.archType,
|
|
112
|
+
appId: opts.appId,
|
|
113
|
+
syncedSkills: steeringResult.syncedSkills,
|
|
114
|
+
techSynced: steeringResult.techSynced,
|
|
115
|
+
steeringError,
|
|
116
|
+
// sync 流程的产出:rule-driven 时 appliedRules + 一系列汇总字段;fallback 到旧 platform-sync
|
|
117
|
+
// 时只填 platformSyncedFiles / platformMergedJsonFiles;stack 不识别时全空且 platformStackFound=false。
|
|
118
|
+
platformStackFound: syncRunResult.stackFound,
|
|
119
|
+
appliedRules: syncSummary.appliedRules,
|
|
120
|
+
platformSyncedFiles: syncSummary.syncedFiles,
|
|
121
|
+
platformMergedJsonFiles: syncSummary.mergedJsonFiles,
|
|
122
|
+
patchedScripts: syncSummary.patchedScripts,
|
|
123
|
+
upgradedPackages,
|
|
124
|
+
gitHooks: hookActivation.action,
|
|
125
|
+
installed: installResult.installed,
|
|
126
|
+
installSource: installResult.source,
|
|
127
|
+
installHash: installResult.hash,
|
|
128
|
+
cacheZip: installResult.cacheZip,
|
|
129
|
+
installError: installResult.error,
|
|
130
|
+
},
|
|
131
|
+
});
|
|
132
|
+
}
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.handleAppUpgrade = void 0;
|
|
7
|
+
exports.handleAppSync = handleAppSync;
|
|
8
|
+
exports.runStackSync = runStackSync;
|
|
9
|
+
exports.summarizeSyncResults = summarizeSyncResults;
|
|
10
|
+
exports.upgradePlatformDeps = upgradePlatformDeps;
|
|
11
|
+
const node_child_process_1 = require("node:child_process");
|
|
12
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
13
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
14
|
+
const sync_configs_1 = require("../../../config/sync-configs");
|
|
15
|
+
const sync_rule_1 = require("../../../utils/sync-rule");
|
|
16
|
+
const platform_sync_1 = require("../../../utils/platform-sync");
|
|
17
|
+
const githooks_1 = require("../../../utils/githooks");
|
|
18
|
+
const spark_meta_1 = require("../../../utils/spark-meta");
|
|
19
|
+
const error_1 = require("../../../utils/error");
|
|
20
|
+
const output_1 = require("../../../utils/output");
|
|
21
|
+
const logger_1 = require("../../../utils/logger");
|
|
22
|
+
/**
|
|
23
|
+
* 平台包钉死版本表 —— `miaoda app sync` 不查 npm dist-tags,直接按这张表把
|
|
24
|
+
* user app 已有的 @lark-apaas/* 依赖钉到对应版本。
|
|
25
|
+
*
|
|
26
|
+
* 为什么不跟 alpha dist-tag:alpha 通道被多个团队共享,外部 prerelease 时常打过去,
|
|
27
|
+
* 自动跟 alpha 会把回归版本(如 fullstack-vite-preset@1.0.24-alpha.5 退化没读 .env.local)
|
|
28
|
+
* 拉进 user app。维护这张白名单可控性更高,每次升基线时人工 review 一次再改这里。
|
|
29
|
+
*
|
|
30
|
+
* 表里没有的 @lark-apaas/* 包:sync 不动(既不升也不报错);user app 没装的包也不引入。
|
|
31
|
+
* 改这张表请同步把 user app 端到端 smoke 跑一次(init → sync → npm run dev)。
|
|
32
|
+
*/
|
|
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',
|
|
45
|
+
};
|
|
46
|
+
/**
|
|
47
|
+
* miaoda app sync [--dir <path>]
|
|
48
|
+
*
|
|
49
|
+
* 一站式同步:把当前 stack 的 sync 规则全套 apply 到 user app,对齐沙箱里
|
|
50
|
+
* `npm run upgrade → npx fullstack-cli sync` 的行为,并补 miaoda-cli 本地开发独有规则。
|
|
51
|
+
*
|
|
52
|
+
* 执行流:
|
|
53
|
+
* 1. SyncRule[] 全量 apply —— 来自 src/config/sync-configs/<stack>.ts。每个 stack
|
|
54
|
+
* 自带模板资源在 upgrade/templates/<stack>/templates/。表里没有该 stack 时回退到
|
|
55
|
+
* 旧 platform-sync 兜底(兼容尚未迁移的 stack)。
|
|
56
|
+
* 2. PINNED 平台 deps 钉版本 —— user app 已装的 @lark-apaas/* 升到 PINNED 表。
|
|
57
|
+
* 3. activateGitHooks —— 设置 core.hooksPath(template 自带 .githooks/pre-commit)。
|
|
58
|
+
* 4. npm install --no-audit --no-fund --ignore-scripts —— 物化新版本,绕开
|
|
59
|
+
* action-plugin postinstall 在缺平台 env 时的 ENOENT。
|
|
60
|
+
*
|
|
61
|
+
* 需要 .spark/meta.json 已含 stack(走过 `miaoda app init`)。
|
|
62
|
+
* 不动 .agent/skills/(那是 `miaoda skills sync` 的事)。
|
|
63
|
+
*/
|
|
64
|
+
async function handleAppSync(opts) {
|
|
65
|
+
await Promise.resolve();
|
|
66
|
+
const targetDir = node_path_1.default.resolve(opts.dir ?? process.cwd());
|
|
67
|
+
const meta = (0, spark_meta_1.readSparkMeta)(targetDir);
|
|
68
|
+
if (meta.stack === undefined || meta.stack === '') {
|
|
69
|
+
throw new error_1.AppError('SYNC_META_INCOMPLETE', '.spark/meta.json missing stack — run `miaoda app init` first');
|
|
70
|
+
}
|
|
71
|
+
// 1. apply SyncRule[],stack 没注册时回退到旧 platform-sync 兜底;都不识别就报错
|
|
72
|
+
const syncResults = runStackSync(meta.stack, targetDir, 'sync');
|
|
73
|
+
if (!syncResults.stackFound) {
|
|
74
|
+
throw new error_1.AppError('SYNC_STACK_NOT_SUPPORTED', `stack '${meta.stack}' has no SyncConfig and no upgrade/templates/${meta.stack}/ — 该 stack 暂未纳入 sync 范围`, {
|
|
75
|
+
next_actions: [
|
|
76
|
+
`src/config/sync-configs/${meta.stack}.ts 加 SyncConfig 并在 STACK_REGISTRY 注册`,
|
|
77
|
+
],
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
// 2. @lark-apaas/* dep pin(按 PINNED_PLATFORM_VERSIONS 表,user app 已装才钉)
|
|
81
|
+
const upgradedPackages = upgradePlatformDeps(targetDir, 'sync');
|
|
82
|
+
// 3. activate git hooks(template 自带 .githooks/pre-commit,core.hooksPath 一次性设置)
|
|
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...');
|
|
86
|
+
let installError;
|
|
87
|
+
try {
|
|
88
|
+
(0, node_child_process_1.execFileSync)('npm', ['install', '--no-audit', '--no-fund', '--ignore-scripts'], {
|
|
89
|
+
cwd: targetDir,
|
|
90
|
+
stdio: (0, output_1.isJsonMode)() ? ['ignore', 'ignore', 'inherit'] : 'inherit',
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
catch (err) {
|
|
94
|
+
installError = err instanceof Error ? err.message : String(err);
|
|
95
|
+
(0, logger_1.log)('sync', `⚠ npm install failed (continuing): ${installError}`);
|
|
96
|
+
}
|
|
97
|
+
(0, output_1.emit)({
|
|
98
|
+
data: {
|
|
99
|
+
stack: meta.stack,
|
|
100
|
+
...summarizeSyncResults(syncResults),
|
|
101
|
+
upgradedPackages,
|
|
102
|
+
gitHooks: hookActivation.action,
|
|
103
|
+
installError,
|
|
104
|
+
},
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
/** 老命令 `miaoda app upgrade` 的 handler 名,保留为 sync handler 的 alias。 */
|
|
108
|
+
exports.handleAppUpgrade = handleAppSync;
|
|
109
|
+
/**
|
|
110
|
+
* 给 stack 应用 sync rules(sync handler + init handler 共用)。
|
|
111
|
+
* stack 在 STACK_REGISTRY 注册时走新 SyncRule 机制,否则回落到旧 platform-sync。
|
|
112
|
+
*
|
|
113
|
+
* stack 完全不识别(既不在 STACK_REGISTRY 也无 upgrade/templates/<stack>/ 目录)时返回
|
|
114
|
+
* `stackFound: false` 而非抛错 —— 让调用方按场景决定:sync handler 抛 AppError,init handler
|
|
115
|
+
* 允许(fresh init 时 stack 还在加注册的过渡期)。
|
|
116
|
+
*/
|
|
117
|
+
function runStackSync(stack, targetDir, logPrefix) {
|
|
118
|
+
const config = (0, sync_configs_1.getSyncConfig)(stack);
|
|
119
|
+
if (config !== null) {
|
|
120
|
+
const sourceRoot = (0, sync_configs_1.getStackTemplatesRoot)(stack);
|
|
121
|
+
if (!node_fs_1.default.existsSync(sourceRoot)) {
|
|
122
|
+
throw new error_1.AppError('SYNC_TEMPLATES_MISSING', `upgrade/templates/${stack}/templates/ not found at ${sourceRoot} — cli 安装异常?`);
|
|
123
|
+
}
|
|
124
|
+
(0, logger_1.log)(logPrefix, `Applying ${config.sync.length.toString()} sync rule(s) for stack '${stack}'`);
|
|
125
|
+
const rulesApplied = (0, sync_rule_1.applySyncRules)(config.sync, { sourceRoot, targetDir, logPrefix });
|
|
126
|
+
return { stackFound: true, rulesApplied };
|
|
127
|
+
}
|
|
128
|
+
// fallback:表外 stack 仍用旧 platform-sync 机制(files/ overlay + patches/ deep merge)
|
|
129
|
+
(0, logger_1.log)(logPrefix, `Stack '${stack}' not in new sync registry, falling back to legacy platform-sync`);
|
|
130
|
+
const legacy = (0, platform_sync_1.syncPlatformControlled)({ stack, targetDir, logPrefix });
|
|
131
|
+
return {
|
|
132
|
+
stackFound: legacy.stackFound,
|
|
133
|
+
rulesApplied: [],
|
|
134
|
+
legacy: { syncedFiles: legacy.syncedFiles, mergedJsonFiles: legacy.mergedJsonFiles },
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
/** 把 SyncRuleResult[] / legacy 输出汇总成 emit data 里的几组字段,便于诊断。 */
|
|
138
|
+
function summarizeSyncResults(result) {
|
|
139
|
+
if (result.legacy !== undefined) {
|
|
140
|
+
return {
|
|
141
|
+
appliedRules: [],
|
|
142
|
+
syncedFiles: result.legacy.syncedFiles,
|
|
143
|
+
mergedJsonFiles: result.legacy.mergedJsonFiles,
|
|
144
|
+
patchedScripts: [],
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
const appliedRules = result.rulesApplied.map((r) => ({
|
|
148
|
+
type: r.rule.type,
|
|
149
|
+
action: r.action,
|
|
150
|
+
path: r.path,
|
|
151
|
+
detail: r.detail,
|
|
152
|
+
}));
|
|
153
|
+
const syncedFiles = [];
|
|
154
|
+
for (const r of result.rulesApplied) {
|
|
155
|
+
if ((r.action === 'synced' || r.action === 'created') && r.path !== undefined) {
|
|
156
|
+
syncedFiles.push(r.path);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
const mergedJsonFiles = [];
|
|
160
|
+
for (const r of result.rulesApplied) {
|
|
161
|
+
if (r.rule.type !== 'merge-json')
|
|
162
|
+
continue;
|
|
163
|
+
if (r.action !== 'merged' && r.action !== 'created')
|
|
164
|
+
continue;
|
|
165
|
+
if (r.path === undefined)
|
|
166
|
+
continue;
|
|
167
|
+
mergedJsonFiles.push({
|
|
168
|
+
path: r.path,
|
|
169
|
+
keys: r.detail !== undefined ? r.detail.split(',').filter(Boolean) : [],
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
const patchedScripts = result.rulesApplied
|
|
173
|
+
.filter((r) => (r.rule.type === 'patch-script' || r.rule.type === 'add-script') &&
|
|
174
|
+
(r.action === 'patched' || r.action === 'created'))
|
|
175
|
+
.map((r) => r.rule.name);
|
|
176
|
+
return { appliedRules, syncedFiles, mergedJsonFiles, patchedScripts };
|
|
177
|
+
}
|
|
178
|
+
function readPackageJson(pkgJsonPath) {
|
|
179
|
+
if (!node_fs_1.default.existsSync(pkgJsonPath))
|
|
180
|
+
return null;
|
|
181
|
+
return JSON.parse(node_fs_1.default.readFileSync(pkgJsonPath, 'utf-8'));
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* 把 user app package.json 里已装的 @lark-apaas/* 包钉到 PINNED_PLATFORM_VERSIONS 表版本。
|
|
185
|
+
* 由 `miaoda app sync` 和 `miaoda app init`(template 渲染后、install 之前)共用。
|
|
186
|
+
*
|
|
187
|
+
* - user app 已装的 PINNED 包 → 钉到表版本
|
|
188
|
+
* - user app 未装的 PINNED 包 → 不引入(sync 的职责是对齐,不是塞依赖)
|
|
189
|
+
* - 装着但不在 PINNED 表的 @lark-apaas/* 包 → 完全不动
|
|
190
|
+
*
|
|
191
|
+
* @param logPrefix 用于 `[<prefix>] deps.xxx: a → b` 日志前缀;sync 流程传 'sync',init 流程传 'init'。
|
|
192
|
+
*/
|
|
193
|
+
function upgradePlatformDeps(targetDir, logPrefix = 'sync') {
|
|
194
|
+
const pkgJsonPath = node_path_1.default.join(targetDir, 'package.json');
|
|
195
|
+
const pkg = readPackageJson(pkgJsonPath);
|
|
196
|
+
if (!pkg)
|
|
197
|
+
return [];
|
|
198
|
+
const updated = [];
|
|
199
|
+
for (const section of ['dependencies', 'devDependencies']) {
|
|
200
|
+
const deps = pkg[section];
|
|
201
|
+
if (!deps || typeof deps !== 'object')
|
|
202
|
+
continue;
|
|
203
|
+
for (const name of Object.keys(deps)) {
|
|
204
|
+
if (!Object.prototype.hasOwnProperty.call(PINNED_PLATFORM_VERSIONS, name))
|
|
205
|
+
continue;
|
|
206
|
+
const target = PINNED_PLATFORM_VERSIONS[name];
|
|
207
|
+
const from = deps[name];
|
|
208
|
+
if (from === target)
|
|
209
|
+
continue;
|
|
210
|
+
deps[name] = target;
|
|
211
|
+
updated.push({ name, from, to: target, section });
|
|
212
|
+
(0, logger_1.log)(logPrefix, ` ${section}.${name}: ${from} → ${target}`);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
if (updated.length > 0) {
|
|
216
|
+
node_fs_1.default.writeFileSync(pkgJsonPath, JSON.stringify(pkg, null, 2) + '\n', 'utf-8');
|
|
217
|
+
}
|
|
218
|
+
return updated;
|
|
219
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.handleDeployModern = handleDeployModern;
|
|
7
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
8
|
+
const output_1 = require("../../../utils/output");
|
|
9
|
+
const index_1 = require("../../../services/deploy/modern/index");
|
|
10
|
+
/**
|
|
11
|
+
* miaoda deploy(modern scene 专用,CLI 表面对齐 openclaw-cli)
|
|
12
|
+
*
|
|
13
|
+
* 进程信息走 stderr(log_id / step),最终结果通过 emit 输出 envelope 到 stdout。
|
|
14
|
+
*/
|
|
15
|
+
async function handleDeployModern(opts) {
|
|
16
|
+
const projectDir = node_path_1.default.resolve(opts.dir);
|
|
17
|
+
const result = await (0, index_1.runModernDeploy)({
|
|
18
|
+
projectDir,
|
|
19
|
+
appId: opts.appId,
|
|
20
|
+
skipBuild: opts.skipBuild ?? false,
|
|
21
|
+
});
|
|
22
|
+
(0, output_1.emit)({
|
|
23
|
+
data: {
|
|
24
|
+
appId: result.appId,
|
|
25
|
+
version: result.version,
|
|
26
|
+
url: result.url,
|
|
27
|
+
releaseID: result.releaseID,
|
|
28
|
+
preReleaseID: result.preReleaseID,
|
|
29
|
+
},
|
|
30
|
+
next_cursor: null,
|
|
31
|
+
has_more: false,
|
|
32
|
+
});
|
|
33
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.handleSkillsStatus = exports.handleSkillsSync = void 0;
|
|
4
|
+
var sync_1 = require("./sync");
|
|
5
|
+
Object.defineProperty(exports, "handleSkillsSync", { enumerable: true, get: function () { return sync_1.handleSkillsSync; } });
|
|
6
|
+
var status_1 = require("./status");
|
|
7
|
+
Object.defineProperty(exports, "handleSkillsStatus", { enumerable: true, get: function () { return status_1.handleSkillsStatus; } });
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.handleSkillsStatus = handleSkillsStatus;
|
|
7
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
8
|
+
const index_1 = require("../../../services/skills/index");
|
|
9
|
+
const spark_meta_1 = require("../../../utils/spark-meta");
|
|
10
|
+
const output_1 = require("../../../utils/output");
|
|
11
|
+
/**
|
|
12
|
+
* miaoda skills status [--dir <path>]
|
|
13
|
+
*
|
|
14
|
+
* 从 .spark/meta.json 读 stack,扫描 <dir>/.agent/steering/<stack>/,
|
|
15
|
+
* 给出当前装了哪些 skills、tech.md 是否在。纯本地操作,不联网。
|
|
16
|
+
* meta 缺 stack 时返回 present=false(不抛错,方便和 init 的引导分开)。
|
|
17
|
+
*/
|
|
18
|
+
async function handleSkillsStatus(opts) {
|
|
19
|
+
await Promise.resolve();
|
|
20
|
+
const targetDir = node_path_1.default.resolve(opts.dir ?? process.cwd());
|
|
21
|
+
const meta = (0, spark_meta_1.readSparkMeta)(targetDir);
|
|
22
|
+
const status = (0, index_1.readSkillsStatus)({ targetDir, stack: meta.stack });
|
|
23
|
+
(0, output_1.emit)({
|
|
24
|
+
data: {
|
|
25
|
+
stack: meta.stack ?? null,
|
|
26
|
+
present: status.present,
|
|
27
|
+
skills: status.skills,
|
|
28
|
+
techSynced: status.techSynced,
|
|
29
|
+
},
|
|
30
|
+
});
|
|
31
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.handleSkillsSync = handleSkillsSync;
|
|
7
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
8
|
+
const coding_steering_1 = require("../../../utils/coding-steering");
|
|
9
|
+
const spark_meta_1 = require("../../../utils/spark-meta");
|
|
10
|
+
const error_1 = require("../../../utils/error");
|
|
11
|
+
const output_1 = require("../../../utils/output");
|
|
12
|
+
/**
|
|
13
|
+
* miaoda skills sync [version] [--dir <path>]
|
|
14
|
+
*
|
|
15
|
+
* 从 .spark/meta.json 读 stack(+ 默认 steeringVersion),把 coding-steering 包内对应 stack
|
|
16
|
+
* 的 skills + tech.md 同步到 <dir>/.agent/steering/。需要先跑过 `miaoda app init`。
|
|
17
|
+
*/
|
|
18
|
+
async function handleSkillsSync(opts) {
|
|
19
|
+
await Promise.resolve();
|
|
20
|
+
const targetDir = node_path_1.default.resolve(opts.dir ?? process.cwd());
|
|
21
|
+
const meta = (0, spark_meta_1.readSparkMeta)(targetDir);
|
|
22
|
+
if (meta.stack === undefined || meta.stack === '') {
|
|
23
|
+
throw new error_1.AppError('SKILLS_META_INCOMPLETE', '.spark/meta.json missing stack — run `miaoda app init` first');
|
|
24
|
+
}
|
|
25
|
+
const version = opts.version ?? meta.steeringVersion;
|
|
26
|
+
const versionSource = opts.version
|
|
27
|
+
? 'cli-arg'
|
|
28
|
+
: meta.steeringVersion
|
|
29
|
+
? 'meta.json'
|
|
30
|
+
: 'default-latest';
|
|
31
|
+
const result = (0, coding_steering_1.syncCodingSteering)({
|
|
32
|
+
stack: meta.stack,
|
|
33
|
+
targetDir,
|
|
34
|
+
version,
|
|
35
|
+
outputLayout: opts.local === true ? 'flat' : 'nested',
|
|
36
|
+
});
|
|
37
|
+
(0, output_1.emit)({
|
|
38
|
+
data: {
|
|
39
|
+
stack: meta.stack,
|
|
40
|
+
version: result.version,
|
|
41
|
+
versionSource,
|
|
42
|
+
syncedSkills: result.syncedSkills,
|
|
43
|
+
techSynced: result.techSynced,
|
|
44
|
+
...(result.claudeSkillsLink !== undefined
|
|
45
|
+
? { claudeSkillsLink: result.claudeSkillsLink }
|
|
46
|
+
: {}),
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FULLSTACK_CLI_PIN_SPEC = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* 临时钉死 `@lark-apaas/fullstack-cli` 的 npx 调用版本。
|
|
6
|
+
*
|
|
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
|
|
16
|
+
*/
|
|
17
|
+
exports.FULLSTACK_CLI_PIN_SPEC = '@lark-apaas/fullstack-cli@1.1.49-alpha.0';
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* design-stack 的 sync 规则。
|
|
4
|
+
*
|
|
5
|
+
* design-stack 是 SSR-only 全栈 stack(design scene,MIAODA_APP_TYPE=4),无 nest 后端、
|
|
6
|
+
* 无数据库、无 nestjs-cli。所以规则集是 nestjs-react-fullstack 的子集:只保留
|
|
7
|
+
* scripts/.githooks/ 派生 + 基础 npm scripts,不动 nest-cli.json / drizzle / tsconfig.node.json。
|
|
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。
|
|
11
|
+
*/
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.SYNC_CONFIG = void 0;
|
|
14
|
+
const fullstack_cli_pin_1 = require("../../config/fullstack-cli-pin");
|
|
15
|
+
exports.SYNC_CONFIG = {
|
|
16
|
+
sync: [
|
|
17
|
+
// 1. 派生 scripts/(含 design 专属 dev-local.sh + 通用 dev.sh / hooks/run-precommit.js)
|
|
18
|
+
{
|
|
19
|
+
type: 'directory',
|
|
20
|
+
from: 'scripts',
|
|
21
|
+
to: 'scripts',
|
|
22
|
+
overwrite: true,
|
|
23
|
+
},
|
|
24
|
+
// 1a. 同步 .githooks/(hook 入口,可执行 sh)
|
|
25
|
+
{
|
|
26
|
+
type: 'directory',
|
|
27
|
+
from: '.githooks',
|
|
28
|
+
to: '.githooks',
|
|
29
|
+
overwrite: true,
|
|
30
|
+
},
|
|
31
|
+
// 1b. scripts.prepare:npm install 后激活 git hooks
|
|
32
|
+
{
|
|
33
|
+
type: 'add-script',
|
|
34
|
+
name: 'prepare',
|
|
35
|
+
command: 'chmod +x .githooks/pre-commit 2>/dev/null; git config core.hooksPath .githooks 2>/dev/null || true',
|
|
36
|
+
overwrite: false,
|
|
37
|
+
},
|
|
38
|
+
// 1c. scripts.precommit
|
|
39
|
+
{
|
|
40
|
+
type: 'add-script',
|
|
41
|
+
name: 'precommit',
|
|
42
|
+
command: 'node scripts/hooks/run-precommit.js',
|
|
43
|
+
overwrite: false,
|
|
44
|
+
},
|
|
45
|
+
// 2. .gitignore 卫生:移除 package-lock.json + 加 .agent/
|
|
46
|
+
{
|
|
47
|
+
type: 'remove-line',
|
|
48
|
+
to: '.gitignore',
|
|
49
|
+
pattern: 'package-lock.json',
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
type: 'add-line',
|
|
53
|
+
to: '.gitignore',
|
|
54
|
+
line: '.agent/',
|
|
55
|
+
},
|
|
56
|
+
// 3. 老 npm scripts 迁移(裸 fullstack-cli → 钉版 npx)。两条 ifStartsWith 分别覆盖
|
|
57
|
+
// "裸 fullstack-cli"(最老形态)和 "npx 未钉版" 形态,统一升到 FULLSTACK_CLI_PIN_SPEC。
|
|
58
|
+
{
|
|
59
|
+
type: 'patch-script',
|
|
60
|
+
name: 'postinstall',
|
|
61
|
+
to: `npx -y ${fullstack_cli_pin_1.FULLSTACK_CLI_PIN_SPEC} action-plugin init`,
|
|
62
|
+
ifStartsWith: 'fullstack-cli action-plugin init',
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
type: 'patch-script',
|
|
66
|
+
name: 'postinstall',
|
|
67
|
+
to: `npx -y ${fullstack_cli_pin_1.FULLSTACK_CLI_PIN_SPEC} action-plugin init`,
|
|
68
|
+
ifStartsWith: 'npx -y @lark-apaas/fullstack-cli action-plugin init',
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
type: 'patch-script',
|
|
72
|
+
name: 'upgrade',
|
|
73
|
+
to: `npx -y ${fullstack_cli_pin_1.FULLSTACK_CLI_PIN_SPEC} sync --disable-gen-openapi`,
|
|
74
|
+
ifStartsWith: 'fullstack-cli sync',
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
type: 'patch-script',
|
|
78
|
+
name: 'upgrade',
|
|
79
|
+
to: `npx -y ${fullstack_cli_pin_1.FULLSTACK_CLI_PIN_SPEC} sync --disable-gen-openapi`,
|
|
80
|
+
ifStartsWith: 'npx -y @lark-apaas/fullstack-cli sync',
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
type: 'patch-script',
|
|
84
|
+
name: 'dev',
|
|
85
|
+
to: './scripts/dev.sh',
|
|
86
|
+
ifStartsWith: 'npm run upgrade && ',
|
|
87
|
+
},
|
|
88
|
+
// ===== miaoda-cli 本地开发新增规则 =====
|
|
89
|
+
// M1. scripts.dev:local —— 本地用户绕过 SANDBOX_ID 分发直接跑本地链路(npm run dev:local)。
|
|
90
|
+
{
|
|
91
|
+
type: 'add-script',
|
|
92
|
+
name: 'dev:local',
|
|
93
|
+
command: './scripts/dev-local.sh',
|
|
94
|
+
overwrite: false,
|
|
95
|
+
},
|
|
96
|
+
],
|
|
97
|
+
};
|
|
98
|
+
exports.default = exports.SYNC_CONFIG;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* 按 stack 短名拿到对应的 SyncConfig + 模板源根目录。
|
|
4
|
+
*
|
|
5
|
+
* - 类型化的 SyncConfig 放在 src/config/sync-configs/<stack>.ts(被 tsc 编进 dist 一起发)。
|
|
6
|
+
* - 模板资源文件放在 upgrade/templates/<stack>/templates/(cli 发布时整个目录原样 ship)。
|
|
7
|
+
*
|
|
8
|
+
* handler 拿到 stack 后,先 getSyncConfig 拿 rule 列表,再 getStackTemplatesRoot 拿模板根,
|
|
9
|
+
* 一起喂给 applySyncRules。
|
|
10
|
+
*
|
|
11
|
+
* 新加 stack:
|
|
12
|
+
* 1. src/config/sync-configs/<stack>.ts 里 export default SYNC_CONFIG
|
|
13
|
+
* 2. upgrade/templates/<stack>/templates/ 下放对应资源文件
|
|
14
|
+
* 3. 在 STACK_REGISTRY 里加一条
|
|
15
|
+
*/
|
|
16
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
17
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
18
|
+
};
|
|
19
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
20
|
+
exports.getSyncConfig = getSyncConfig;
|
|
21
|
+
exports.getStackTemplatesRoot = getStackTemplatesRoot;
|
|
22
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
23
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
24
|
+
const nestjs_react_fullstack_1 = __importDefault(require("./nestjs-react-fullstack"));
|
|
25
|
+
const design_stack_1 = __importDefault(require("./design-stack"));
|
|
26
|
+
/**
|
|
27
|
+
* 已纳入新 sync 机制的 stack 注册表。未在表里的 stack(如老 vite-react / html)走旧的
|
|
28
|
+
* `upgrade/templates/<stack>/{files,patches}` 机制,由 sync handler 兜底。
|
|
29
|
+
*/
|
|
30
|
+
const STACK_REGISTRY = {
|
|
31
|
+
'nestjs-react-fullstack': nestjs_react_fullstack_1.default,
|
|
32
|
+
'design-stack': design_stack_1.default,
|
|
33
|
+
};
|
|
34
|
+
/** 返回该 stack 的 SyncConfig;表里没有时返回 null。 */
|
|
35
|
+
function getSyncConfig(stack) {
|
|
36
|
+
return STACK_REGISTRY[stack] ?? null;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* 计算 stack 模板资源根目录(绝对路径)。
|
|
40
|
+
*
|
|
41
|
+
* cli 发布时 upgrade/ 目录整个 ship,编译产物在 dist/ 下若干层。从当前模块向上回溯找含
|
|
42
|
+
* upgrade/ + package.json 的目录就是 cli 根。
|
|
43
|
+
*
|
|
44
|
+
* 跟 utils/platform-sync.ts 同款 pattern;保持对齐避免两边漂移。
|
|
45
|
+
*/
|
|
46
|
+
function getStackTemplatesRoot(stack) {
|
|
47
|
+
return node_path_1.default.join(findCliRoot(), 'upgrade', 'templates', stack, 'templates');
|
|
48
|
+
}
|
|
49
|
+
let cliRootCache = null;
|
|
50
|
+
function findCliRoot() {
|
|
51
|
+
if (cliRootCache !== null)
|
|
52
|
+
return cliRootCache;
|
|
53
|
+
let dir = __dirname;
|
|
54
|
+
while (dir !== node_path_1.default.dirname(dir)) {
|
|
55
|
+
if (node_fs_1.default.existsSync(node_path_1.default.join(dir, 'upgrade')) && node_fs_1.default.existsSync(node_path_1.default.join(dir, 'package.json'))) {
|
|
56
|
+
cliRootCache = dir;
|
|
57
|
+
return dir;
|
|
58
|
+
}
|
|
59
|
+
dir = node_path_1.default.dirname(dir);
|
|
60
|
+
}
|
|
61
|
+
throw new Error(`miaoda-cli root (containing upgrade/) not found from ${__dirname}`);
|
|
62
|
+
}
|