@lark-apaas/miaoda-cli 0.1.28 → 0.1.29
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.
|
@@ -411,6 +411,19 @@ const ISO_TIMESTAMP_RE = /^\d{4}-\d{2}-\d{2}(?:[T ]\d{2}:\d{2}:\d{2}(?:\.\d+)?(?
|
|
|
411
411
|
const SYNTAX_RE = /syntax error at or near "([^"]+)"/i;
|
|
412
412
|
const RELATION_RE = /relation "([^"]+)" does not exist/i;
|
|
413
413
|
const COLUMN_RE = /column "([^"]+)"(?: of relation "([^"]+)")? does not exist/i;
|
|
414
|
+
const KEYWORD_TYPO_IGNORE_WORDS = new Set([
|
|
415
|
+
// Legal PostgreSQL terms that are not useful keyword typo candidates.
|
|
416
|
+
'ROW',
|
|
417
|
+
'LEVEL',
|
|
418
|
+
'SECURITY',
|
|
419
|
+
// Common index access methods used after `USING`.
|
|
420
|
+
'BTREE',
|
|
421
|
+
'HASH',
|
|
422
|
+
'GIST',
|
|
423
|
+
'SPGIST',
|
|
424
|
+
'GIN',
|
|
425
|
+
'BRIN',
|
|
426
|
+
]);
|
|
414
427
|
/**
|
|
415
428
|
* 在错误抛出前富化 next_actions(最多 1 条 hint),按 PG 报错形态分发:
|
|
416
429
|
*
|
|
@@ -540,6 +553,8 @@ function findKeywordTypo(sql) {
|
|
|
540
553
|
const upper = tok.toUpperCase();
|
|
541
554
|
if (sql_keywords_1.SQL_KEYWORDS.includes(upper))
|
|
542
555
|
continue; // 写对的关键字
|
|
556
|
+
if (KEYWORD_TYPO_IGNORE_WORDS.has(upper))
|
|
557
|
+
continue;
|
|
543
558
|
const guess = (0, fuzzy_match_1.suggest)(upper, sql_keywords_1.SQL_KEYWORDS);
|
|
544
559
|
if (guess && guess !== upper) {
|
|
545
560
|
return { input: tok, suggest: guess };
|
|
@@ -0,0 +1,63 @@
|
|
|
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.createProgram = createProgram;
|
|
7
|
+
const commander_1 = require("commander");
|
|
8
|
+
const index_1 = require("../cli/commands/index");
|
|
9
|
+
const shared_1 = require("../cli/commands/shared");
|
|
10
|
+
const help_1 = require("../cli/help");
|
|
11
|
+
const version_option_1 = require("../cli/version-option");
|
|
12
|
+
const config_1 = require("../utils/config");
|
|
13
|
+
const log_id_1 = require("../utils/log_id");
|
|
14
|
+
const package_json_1 = __importDefault(require("../../package.json"));
|
|
15
|
+
// 副作用:MiaodaHelp 对齐 CLI 规范(描述置顶 / Flags / Global Flags / 段顺序)。
|
|
16
|
+
// 在 Command.prototype 上 patch createHelp,让所有命令实例(含动态注册的子命令)统一走
|
|
17
|
+
// MiaodaHelp 渲染,避免在每个子命令上重复 configureHelp。
|
|
18
|
+
commander_1.Command.prototype.createHelp = function () {
|
|
19
|
+
return Object.assign(new help_1.MiaodaHelp(), this.configureHelp());
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* 装配 root program(命令树 + 全局参数 + preAction hook)。
|
|
23
|
+
*
|
|
24
|
+
* 抽成工厂而非写在 main.ts 里,是为了让接线可测 —— main.ts 在 import 期就会 parseAsync,
|
|
25
|
+
* 测试无法 import 它,只能复刻装配,那测到的就不是生产代码。
|
|
26
|
+
* 见 test/cli/program-version-wiring.test.ts。
|
|
27
|
+
*
|
|
28
|
+
* @param argv 供 `--version` 归属判定使用的 argv(process.argv 形态)。显式传入而非直接读
|
|
29
|
+
* process.argv,同样是为了可测。
|
|
30
|
+
*/
|
|
31
|
+
function createProgram(argv = process.argv) {
|
|
32
|
+
const program = new commander_1.Command();
|
|
33
|
+
const { version } = package_json_1.default;
|
|
34
|
+
program.name('miaoda');
|
|
35
|
+
// 命令树必须先建:shouldExposeRootVersion 要从树上反推「哪些命令自己声明了 --version」。
|
|
36
|
+
(0, index_1.registerCommands)(program);
|
|
37
|
+
program
|
|
38
|
+
.description('妙搭平台 CLI,提供数据服务、文件存储等命令行操作。')
|
|
39
|
+
.usage('<command> [flags]');
|
|
40
|
+
// 条件注册:仅当本次 argv 未命中「声明了 --version 的命令路径」时,root 才接管 --version。
|
|
41
|
+
// 注册位置保持在 option 链首位,否则 -v, --version 会从 Global Flags 第一行掉到末尾。
|
|
42
|
+
// 详见 src/cli/version-option.ts。
|
|
43
|
+
if ((0, version_option_1.shouldExposeRootVersion)(program, argv)) {
|
|
44
|
+
program.version(version, '-v, --version', '显示版本号');
|
|
45
|
+
}
|
|
46
|
+
program
|
|
47
|
+
.option('--json [fields]', 'JSON 输出,可选字段级选择')
|
|
48
|
+
.addOption(new commander_1.Option('--output <format>', '输出格式(pretty | json,大小写不敏感)')
|
|
49
|
+
.choices(['pretty', 'json'])
|
|
50
|
+
.argParser((0, shared_1.caseInsensitiveChoice)(['pretty', 'json']))
|
|
51
|
+
.default('pretty'))
|
|
52
|
+
.option('--verbose', 'debug 日志到 stderr')
|
|
53
|
+
// 全局接受 -y/--yes:作为 root 全局 option 下发到所有子命令解析(同 --json/--verbose),
|
|
54
|
+
// 让任意命令带 --yes 都不报 unknown option。对有确认门的破坏性命令生效,其余命令忽略。
|
|
55
|
+
.option('-y, --yes', '跳过确认提示(对有确认门的命令生效,其余命令忽略)')
|
|
56
|
+
.helpOption('-h, --help', '显示帮助信息')
|
|
57
|
+
.hook('preAction', (_thisCmd, actionCmd) => {
|
|
58
|
+
(0, log_id_1.generateLogId)();
|
|
59
|
+
const opts = actionCmd.optsWithGlobals();
|
|
60
|
+
(0, config_1.initConfigFromOpts)(opts);
|
|
61
|
+
});
|
|
62
|
+
return program;
|
|
63
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.shouldExposeRootVersion = shouldExposeRootVersion;
|
|
4
|
+
/**
|
|
5
|
+
* root 是否应该注册 `-v, --version`。
|
|
6
|
+
*
|
|
7
|
+
* 背景:Commander 13 默认关闭 positional options,root 的 parseOptions 会扫描整个 argv
|
|
8
|
+
* (这也正是 `--json` / `--verbose` 写在子命令之后仍生效的机制)。因此 root 一旦声明
|
|
9
|
+
* `--version`,任何位置的 `--version` 都会先被 root 的 version listener 命中、打印版本并
|
|
10
|
+
* exit 0,导致 `skills sync --version <ver>` 这类子命令 flag 永远拿不到值。
|
|
11
|
+
*
|
|
12
|
+
* 解法:仅当本次 argv 连续命中「某条自己声明了 --version 的命令路径」时才不注册,把
|
|
13
|
+
* `--version` 让给叶子;其余一切情况照常注册,行为与历史完全一致(例如
|
|
14
|
+
* `miaoda app get --version` 仍打印 CLI 版本)。
|
|
15
|
+
*
|
|
16
|
+
* 路径集从命令树反推,不硬编码 —— 以后任何叶子加 `--version` 都自动纳入。
|
|
17
|
+
*
|
|
18
|
+
* 设计与行为矩阵见
|
|
19
|
+
* docs/superpowers/specs/2026-07-29-root-version-option-collision-design.md。
|
|
20
|
+
*/
|
|
21
|
+
function shouldExposeRootVersion(root, argv) {
|
|
22
|
+
const tokens = argv.slice(2);
|
|
23
|
+
if (tokens.length === 0)
|
|
24
|
+
return true;
|
|
25
|
+
return !collectVersionOwningPaths(root).some((path) => containsPath(tokens, path));
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* 收集自己声明了 `--version` 的命令路径。
|
|
29
|
+
*
|
|
30
|
+
* 每条路径是一个「段」数组,每段是该层可接受的 token 名(正名 + 全部 alias)。
|
|
31
|
+
* 例如 `skills sync` → `[['skills'], ['sync']]`。
|
|
32
|
+
*/
|
|
33
|
+
function collectVersionOwningPaths(root) {
|
|
34
|
+
const paths = [];
|
|
35
|
+
const walk = (cmd, trail) => {
|
|
36
|
+
for (const sub of cmd.commands) {
|
|
37
|
+
const here = [...trail, [sub.name(), ...sub.aliases()]];
|
|
38
|
+
if (sub.options.some((o) => o.long === '--version'))
|
|
39
|
+
paths.push(here);
|
|
40
|
+
walk(sub, here);
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
walk(root, []);
|
|
44
|
+
return paths;
|
|
45
|
+
}
|
|
46
|
+
/** tokens 里是否存在一段连续子序列,逐位命中 path 各段的正名或 alias。 */
|
|
47
|
+
function containsPath(tokens, path) {
|
|
48
|
+
outer: for (let i = 0; i + path.length <= tokens.length; i++) {
|
|
49
|
+
for (let j = 0; j < path.length; j++) {
|
|
50
|
+
if (!path[j].includes(tokens[i + j]))
|
|
51
|
+
continue outer;
|
|
52
|
+
}
|
|
53
|
+
return true;
|
|
54
|
+
}
|
|
55
|
+
return false;
|
|
56
|
+
}
|
package/dist/main.js
CHANGED
|
@@ -1,45 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
const
|
|
7
|
-
const index_1 = require("./cli/commands/index");
|
|
8
|
-
const shared_1 = require("./cli/commands/shared");
|
|
9
|
-
const help_1 = require("./cli/help");
|
|
10
|
-
const config_1 = require("./utils/config");
|
|
11
|
-
const log_id_1 = require("./utils/log_id");
|
|
3
|
+
const program_1 = require("./cli/program");
|
|
12
4
|
const output_1 = require("./utils/output");
|
|
13
|
-
const
|
|
14
|
-
// MiaodaHelp 对齐 CLI 规范(描述置顶 / Flags / Global Flags / 段顺序):
|
|
15
|
-
// 在 Command.prototype 上 patch createHelp,让所有命令实例(含动态注册的
|
|
16
|
-
// 子命令)统一走 MiaodaHelp 渲染,避免在每个子命令上重复 configureHelp。
|
|
17
|
-
commander_1.Command.prototype.createHelp = function () {
|
|
18
|
-
return Object.assign(new help_1.MiaodaHelp(), this.configureHelp());
|
|
19
|
-
};
|
|
20
|
-
const program = new commander_1.Command();
|
|
21
|
-
const { version } = package_json_1.default;
|
|
22
|
-
program
|
|
23
|
-
.name('miaoda')
|
|
24
|
-
.description('妙搭平台 CLI,提供数据服务、文件存储等命令行操作。')
|
|
25
|
-
.usage('<command> [flags]')
|
|
26
|
-
.version(version, '-v, --version', '显示版本号')
|
|
27
|
-
.option('--json [fields]', 'JSON 输出,可选字段级选择')
|
|
28
|
-
.addOption(new commander_1.Option('--output <format>', '输出格式(pretty | json,大小写不敏感)')
|
|
29
|
-
.choices(['pretty', 'json'])
|
|
30
|
-
.argParser((0, shared_1.caseInsensitiveChoice)(['pretty', 'json']))
|
|
31
|
-
.default('pretty'))
|
|
32
|
-
.option('--verbose', 'debug 日志到 stderr')
|
|
33
|
-
// 全局接受 -y/--yes:作为 root 全局 option 下发到所有子命令解析(同 --json/--verbose),
|
|
34
|
-
// 让任意命令带 --yes 都不报 unknown option。对有确认门的破坏性命令生效,其余命令忽略。
|
|
35
|
-
.option('-y, --yes', '跳过确认提示(对有确认门的命令生效,其余命令忽略)')
|
|
36
|
-
.helpOption('-h, --help', '显示帮助信息')
|
|
37
|
-
.hook('preAction', (_thisCmd, actionCmd) => {
|
|
38
|
-
(0, log_id_1.generateLogId)();
|
|
39
|
-
const opts = actionCmd.optsWithGlobals();
|
|
40
|
-
(0, config_1.initConfigFromOpts)(opts);
|
|
41
|
-
});
|
|
42
|
-
(0, index_1.registerCommands)(program);
|
|
5
|
+
const program = (0, program_1.createProgram)();
|
|
43
6
|
program.parseAsync(process.argv).catch((err) => {
|
|
44
7
|
(0, output_1.emitError)(err);
|
|
45
8
|
process.exitCode = 1;
|
|
@@ -19,14 +19,32 @@ exports.EXCLUDES = new Set([
|
|
|
19
19
|
'yarn.lock',
|
|
20
20
|
'.gitignore',
|
|
21
21
|
'.npmrc',
|
|
22
|
+
// agent / 编辑器配置目录与指令文件:只服务本地开发,不属于应用资产。
|
|
23
|
+
// 注意 .claude/skills 在 flat layout 下是指向 ../.agents/skills 的软链,而 listSourceFiles
|
|
24
|
+
// 会 follow 软链,所以必须按 basename 把 .claude 整个排掉,否则 skills 会从软链侧被带进产物。
|
|
22
25
|
'.agent',
|
|
23
26
|
'.agents',
|
|
27
|
+
'.claude',
|
|
28
|
+
'.codex',
|
|
29
|
+
'.cursor',
|
|
30
|
+
'.gemini',
|
|
31
|
+
'.trae',
|
|
32
|
+
'.windsurf',
|
|
33
|
+
'.vscode',
|
|
34
|
+
'.idea',
|
|
35
|
+
'AGENTS.md',
|
|
36
|
+
'CLAUDE.md',
|
|
37
|
+
'GEMINI.md',
|
|
24
38
|
'skills',
|
|
25
39
|
'.env',
|
|
26
40
|
'.env.local',
|
|
27
41
|
'README.md',
|
|
28
42
|
'.DS_Store',
|
|
29
43
|
'.spark',
|
|
44
|
+
// 本地开发的临时/运行时目录:tmp 里的 .html 是草稿或中间产物,logs 是本地日志,
|
|
45
|
+
// 两者既不进产物也不该出现在 routes.json。
|
|
46
|
+
'tmp',
|
|
47
|
+
'logs',
|
|
30
48
|
]);
|
|
31
49
|
/**
|
|
32
50
|
* 递归列出 root 下所有文件的相对 posix 路径,跳过 EXCLUDES(任意层级 basename),
|