@ultime/cli 0.1.2 → 0.1.4

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/CHANGELOG.md CHANGED
@@ -1,5 +1,16 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.1.4 - 2026-11-10
4
+
5
+ - 构建改用 `vp pack`,产物同时生成 `dist/index.js` 与 `dist/index.d.ts`。
6
+ - `exports.types` 指向 `dist/index.d.ts`,包体不再包含 `src/`;安装后类型解析不依赖源码。
7
+ - 无运行时 API 变化。
8
+
9
+ ## 0.1.3 - 2026-11-10
10
+
11
+ - 修复 `--key=value` 的值含等号时被截断:`--define=KEY=VALUE` 现在完整保留。
12
+ - 包内新增 `llms.txt` / `SKILLS.md` 作为消费侧 AI 入口;`rules/` 留仓,操作约束并入 `AGENTS.md`。
13
+
3
14
  ## 0.1.2 - 2026-11-09
4
15
 
5
16
  - 移除仓库内遗留的 `bin/ultime.js`:它不是本包的公开入口,引用的路径也已不存在。
package/CONTRIBUTING.md CHANGED
@@ -2,25 +2,43 @@
2
2
 
3
3
  > 给贡献者与 AI 的最短协作规则。命令见 [README](./README.md)。
4
4
 
5
- ## 工作流
5
+ ## Git 流程
6
6
 
7
- 1. 从 `main` 切 `feat/<主题>` / `fix/<主题>`。
8
- 2. 完成后 `git rebase main` 再合并;主分支不保留中间提交。
9
- 3. 一次提交一件事,提交信息用 `type(scope): subject`。
7
+ 1. 从 `main` 切 `feat/<主题>` / `fix/<主题>` / `docs-<主题>`。
8
+ 2. 开发完成后 `git rebase main`;一次提交一件事,提交信息用 `type(scope): subject`。
9
+ 3. push 分支并开 PR;CI 必须通过,评论必须解决。
10
+ 4. 用 rebase / squash 合并,删除分支;`main` 不保留中间提交。
11
+ 5. 不直接 push `main`,不 force push、不删除 `main`;`main` 受保护,管理员也一样。
12
+ 6. 发布按包版本打 tag,由 CI 执行;tag 规则见仓库保护设置。
10
13
 
11
14
  ## 改动规则
12
15
 
13
16
  - CLI 只做参数 / 路径 / IO / 退出码;配置合法性与产物内容归调用方包。
14
17
  - 不 import 任何调用方包的源码,只通过公开包名与 exports 依赖。
15
18
  - 不自维护具体项目的字段清单;`schema` 之类由调用方投影。
16
- - 新增命令或退出码:同步 README、`skills.md`、测试与版本戳。
19
+ - 新增命令或退出码:同步 README、`SKILLS.md`、测试与版本戳。
20
+
21
+ ## Review
22
+
23
+ 提交 PR 前自查五件事:
24
+
25
+ - **文档**:README / 用法 / 示例是否仍准确;链接、版本、CHANGELOG 是否同步。
26
+ - **注释**:只写为什么、约束、反直觉处;不复述代码。
27
+ - **冗余**:同一事实只有一份正文;新增说明先改真源,其他位置只留指针。
28
+ - **缺漏**:新增能力是否有入口、示例与验证命令。
29
+ - **漂移**:`package.json` / README / `CHANGELOG` / VERSION(及适用的 AI 文档)版本是否一致。
30
+ - **包体**:`npm pack --dry-run` 不含 `tests` / `scripts` / `rules` / 包根 `AGENTS.md` / 构建配置 / lockfile;`exports` 与类型入口一致。
31
+ - **基线**:`engines.node >= 22.18`、产物 `target: node22` 未偏离;开发端脚本与依赖不进入发布包。
32
+
33
+ 机械检查交给 CI;人审看架构、边界、语义与取舍。
17
34
 
18
35
  ## 验证
19
36
 
20
37
  ```bash
21
38
  pnpm check
22
39
  pnpm test
23
- pnpm typecheck
40
+ pnpm build # 含 publint / attw / unused
41
+ pnpm size # 体积只报告,不设门禁
24
42
  npm pack --dry-run
25
43
  ```
26
44
 
package/README.md CHANGED
@@ -9,7 +9,7 @@
9
9
  pnpm add @ultime/cli
10
10
  ```
11
11
 
12
- 需要 Node >= 22.18;包发的是编译后的 ESM(`dist/`),类型来自 `src/*.ts`。
12
+ 需要 Node >= 22.18;包发的是编译后的 ESM(`dist/`),类型来自 `dist/*.d.ts`。
13
13
 
14
14
  ## 用它做什么
15
15
 
@@ -44,6 +44,8 @@ process.exitCode = runCli(spec, process.argv.slice(2), processContext())
44
44
 
45
45
  `parseArgs` 只认 `command`、`--flag`、`--key value` / `--key=value`;`-h/--help` 与 `-v/--version` 是保留 flag。
46
46
 
47
+ AI 入口:[`llms.txt`](./llms.txt)(路由)与 [`SKILLS.md`](./SKILLS.md)(能力表)随包发布。
48
+
47
49
  ## 边界
48
50
 
49
51
  - **零领域依赖**:不 import 任何领域包,也不认识具体业务对象。
package/SKILLS.md ADDED
@@ -0,0 +1,42 @@
1
+ # @ultime/cli · 可调用能力
2
+
3
+ > 定位:AI 可调用的通用命令设施。领域命令不在这里。
4
+ > 适用版本:0.1.x
5
+ > 同步基线:0.1.x(手写;API 变化时同批更新)
6
+
7
+ ---
8
+
9
+ ## 入口
10
+
11
+ ```ts
12
+ import { parseArgs, runCli, processContext } from '@ultime/cli'
13
+ import type { ParsedArgs, CliContext, CliSpec, CommandSpec } from '@ultime/cli'
14
+ ```
15
+
16
+ | 能力 | 输入 | 输出 |
17
+ |---|---|---|
18
+ | `parseArgs(argv)` | 字符串数组 | `{ command, flags, positional }` |
19
+ | `runCli(spec, argv, ctx?)` | `CliSpec` + 参数 | 退出码;版本 / 帮助 / 未知命令 / 异常由它处理 |
20
+ | `processContext()` | — | `{ cwd, out, err }` |
21
+
22
+ ## `CliSpec`
23
+
24
+ ```ts
25
+ {
26
+ name: string
27
+ version: string
28
+ usage: string
29
+ commands: Record<string, { help?: string; run(args, ctx): number }>
30
+ }
31
+ ```
32
+
33
+ ## 错误语义
34
+
35
+ - 未知命令:`err` 写错误,`out` 写 usage,返回 1;
36
+ - 命令抛异常:`err` 写 message,返回 1;
37
+ - 版本 / 帮助:返回 0,不执行命令。
38
+
39
+ ## 反例
40
+
41
+ - 把 `--check` 当成 cli 内置 flag:它属于调用方的命令。
42
+ - 在 cli 里读具体项目配置:IO 与配置语义属于调用方命令。
@@ -0,0 +1,34 @@
1
+ /**
2
+ * args.ts — 命令行参数解析(纯函数)
3
+ * ---------------------------------------------------------------------------
4
+ * 只认三种形态:`command`、`--flag`、`--key value` / `--key=value`;
5
+ * 不引第三方解析库 —— CLI 必须零依赖可跑。
6
+ */
7
+ interface ParsedArgs {
8
+ command: string;
9
+ flags: Record<string, string | true>;
10
+ positional: string[];
11
+ }
12
+ export declare function parseArgs(argv: string[]): ParsedArgs;
13
+ /** 命令上下文:把「往哪写、怎么写」抽出来,测试里换成内存收集器即可,不用起子进程。 */
14
+ interface CliContext {
15
+ /** 工作目录:配置与产物路径都相对它解析 */
16
+ cwd: string;
17
+ out: (line: string) => void;
18
+ err: (line: string) => void;
19
+ }
20
+ export declare function processContext(): CliContext;
21
+ interface CommandSpec {
22
+ /** 单条命令的 help;缺省时回落到全局 usage */
23
+ help?: string;
24
+ run: (args: ParsedArgs, ctx: CliContext) => number;
25
+ }
26
+ interface CliSpec {
27
+ /** 用于错误与帮助文案,例如 `ultime` */
28
+ name: string;
29
+ version: string;
30
+ usage: string;
31
+ commands: Record<string, CommandSpec>;
32
+ }
33
+ export declare function runCli(spec: CliSpec, argv: string[], ctx?: CliContext): number;
34
+ export type { CliContext, CliSpec, CommandSpec, ParsedArgs };
package/dist/index.js CHANGED
@@ -14,16 +14,17 @@ function parseArgs(argv) {
14
14
  continue;
15
15
  }
16
16
  if (token.startsWith("--")) {
17
- const [key, inline] = token.slice(2).split("=", 2);
18
- if (inline != null) {
19
- flags[key] = inline;
17
+ const body = token.slice(2);
18
+ const equal = body.indexOf("=");
19
+ if (equal !== -1) {
20
+ flags[body.slice(0, equal)] = body.slice(equal + 1);
20
21
  continue;
21
22
  }
22
23
  const next = argv[i + 1];
23
24
  if (next && !next.startsWith("-")) {
24
- flags[key] = next;
25
+ flags[body] = next;
25
26
  i += 1;
26
- } else flags[key] = true;
27
+ } else flags[body] = true;
27
28
  continue;
28
29
  }
29
30
  if (!command) command = token;
@@ -35,6 +36,7 @@ function parseArgs(argv) {
35
36
  positional
36
37
  };
37
38
  }
39
+
38
40
  // src/context.ts
39
41
  function processContext() {
40
42
  return {
@@ -43,6 +45,7 @@ function processContext() {
43
45
  err: (line) => console.error(line)
44
46
  };
45
47
  }
48
+
46
49
  // src/run.ts
47
50
  /**
48
51
  * run.ts — 命令注册与退出码
@@ -77,4 +80,5 @@ function runCli(spec, argv, ctx = processContext()) {
77
80
  return 1;
78
81
  }
79
82
  }
80
- export { parseArgs, processContext, runCli };
83
+
84
+ export { parseArgs, processContext, runCli };
package/llms.txt ADDED
@@ -0,0 +1,16 @@
1
+ # @ultime/cli · AI 索引
2
+
3
+ 适用版本:0.1.x
4
+
5
+ ## 去哪找
6
+
7
+ - 怎么用:[README.md](./README.md)
8
+ - 可调用能力:[SKILLS.md](./SKILLS.md)
9
+
10
+ ## 机器入口
11
+
12
+ - 公共出口:`@ultime/cli` 的 `parseArgs` / `runCli` / `processContext` 与类型。
13
+
14
+ ## 边界
15
+
16
+ - 通用设施,不含任何领域命令;读盘写盘归调用方。
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ultime/cli",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "description": "Ultime · cli:通用命令行设施(参数 / 命令注册 / 上下文 / 退出码),零领域依赖",
5
5
  "keywords": [
6
6
  "argument-parser",
@@ -22,8 +22,9 @@
22
22
  },
23
23
  "files": [
24
24
  "dist",
25
- "src",
26
25
  "README.md",
26
+ "llms.txt",
27
+ "SKILLS.md",
27
28
  "CHANGELOG.md",
28
29
  "CONTRIBUTING.md",
29
30
  "SECURITY.md"
@@ -31,7 +32,7 @@
31
32
  "type": "module",
32
33
  "exports": {
33
34
  ".": {
34
- "types": "./src/index.ts",
35
+ "types": "./dist/index.d.ts",
35
36
  "import": "./dist/index.js"
36
37
  }
37
38
  },
@@ -39,18 +40,32 @@
39
40
  "access": "public"
40
41
  },
41
42
  "scripts": {
42
- "build": "vp build",
43
- "check": "vp check",
43
+ "build": "vp pack",
44
+ "check": "vp check && checks run && pnpm cycles",
45
+ "checks": "checks run",
46
+ "cycles": "vp lint --import-plugin --deny=import/no-cycle src",
44
47
  "test": "vp test",
45
- "typecheck": "tsc -p tsconfig.json --noEmit",
46
- "prepublishOnly": "pnpm check && pnpm test && pnpm build"
48
+ "size": "size-limit --json",
49
+ "prepublishOnly": "pnpm check && pnpm test && pnpm build",
50
+ "prepare": "vp config --no-agent"
47
51
  },
48
52
  "devDependencies": {
53
+ "@arethetypeswrong/core": "^0.18.5",
54
+ "@size-limit/preset-small-lib": "^14.3.0",
49
55
  "@types/node": "^22.20.5",
50
- "tsx": "^4.23.15",
56
+ "@ultime/checks": "^0.2.0",
57
+ "publint": "^0.3.25",
58
+ "size-limit": "^14.3.0",
51
59
  "typescript": "^5.9.3",
52
- "vite-plus": "1.4.0"
60
+ "unplugin-unused": "^0.6.0",
61
+ "vite-plus": "1.5.1"
53
62
  },
63
+ "size-limit": [
64
+ {
65
+ "name": "@ultime/cli",
66
+ "path": "dist/index.js"
67
+ }
68
+ ],
54
69
  "engines": {
55
70
  "node": ">=22.18"
56
71
  },
package/src/args.ts DELETED
@@ -1,49 +0,0 @@
1
- /**
2
- * args.ts — 命令行参数解析(纯函数)
3
- * ---------------------------------------------------------------------------
4
- * 只认三种形态:`command`、`--flag`、`--key value` / `--key=value`;
5
- * 不引第三方解析库 —— CLI 必须零依赖可跑。
6
- */
7
-
8
- export interface ParsedArgs {
9
- command: string
10
- flags: Record<string, string | true>
11
- positional: string[]
12
- }
13
-
14
- export function parseArgs(argv: string[]): ParsedArgs {
15
- const flags: Record<string, string | true> = {}
16
- const positional: string[] = []
17
- let command = ''
18
-
19
- for (let i = 0; i < argv.length; i += 1) {
20
- const token = argv[i]
21
- if (token === '-h' || token === '--help') {
22
- flags.help = true
23
- continue
24
- }
25
- if (token === '-v' || token === '--version') {
26
- flags.version = true
27
- continue
28
- }
29
- if (token.startsWith('--')) {
30
- const [key, inline] = token.slice(2).split('=', 2)
31
- if (inline != null) {
32
- flags[key] = inline
33
- continue
34
- }
35
- const next = argv[i + 1]
36
- if (next && !next.startsWith('-')) {
37
- flags[key] = next
38
- i += 1
39
- } else {
40
- flags[key] = true
41
- }
42
- continue
43
- }
44
- if (!command) command = token
45
- else positional.push(token)
46
- }
47
-
48
- return { command, flags, positional }
49
- }
package/src/context.ts DELETED
@@ -1,15 +0,0 @@
1
- /** 命令上下文:把「往哪写、怎么写」抽出来,测试里换成内存收集器即可,不用起子进程。 */
2
- export interface CliContext {
3
- /** 工作目录:配置与产物路径都相对它解析 */
4
- cwd: string
5
- out: (line: string) => void
6
- err: (line: string) => void
7
- }
8
-
9
- export function processContext(): CliContext {
10
- return {
11
- cwd: process.cwd(),
12
- out: (line) => console.log(line),
13
- err: (line) => console.error(line),
14
- }
15
- }
package/src/index.ts DELETED
@@ -1,3 +0,0 @@
1
- export { parseArgs, type ParsedArgs } from './args.ts'
2
- export { processContext, type CliContext } from './context.ts'
3
- export { runCli, type CommandSpec, type CliSpec } from './run.ts'
package/src/run.ts DELETED
@@ -1,54 +0,0 @@
1
- /**
2
- * run.ts — 命令注册与退出码
3
- * ---------------------------------------------------------------------------
4
- * 通用设施:只负责版本 / 帮助 / 未知命令 / 异常转退出码;
5
- * 具体命令由调用方注册,cli 包不出现任何领域命令。
6
- */
7
-
8
- import { parseArgs, type ParsedArgs } from './args.ts'
9
- import { processContext, type CliContext } from './context.ts'
10
-
11
- export interface CommandSpec {
12
- /** 单条命令的 help;缺省时回落到全局 usage */
13
- help?: string
14
- run: (args: ParsedArgs, ctx: CliContext) => number
15
- }
16
-
17
- export interface CliSpec {
18
- /** 用于错误与帮助文案,例如 `ultime` */
19
- name: string
20
- version: string
21
- usage: string
22
- commands: Record<string, CommandSpec>
23
- }
24
-
25
- export function runCli(spec: CliSpec, argv: string[], ctx: CliContext = processContext()): number {
26
- const args = parseArgs(argv)
27
-
28
- if (args.flags.version) {
29
- ctx.out(spec.version)
30
- return 0
31
- }
32
- if (args.flags.help) {
33
- ctx.out(args.command && spec.commands[args.command]?.help ? spec.commands[args.command]!.help! : spec.usage)
34
- return 0
35
- }
36
- if (!args.command) {
37
- ctx.out(spec.usage)
38
- return 1
39
- }
40
-
41
- const command = spec.commands[args.command]
42
- if (!command) {
43
- ctx.err(`✗ 未知命令:${args.command}\n`)
44
- ctx.out(spec.usage)
45
- return 1
46
- }
47
-
48
- try {
49
- return command.run(args, ctx)
50
- } catch (error) {
51
- ctx.err(`✗ ${error instanceof Error ? error.message : String(error)}`)
52
- return 1
53
- }
54
- }