@done-coding/cli-skills 0.1.0

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 ADDED
@@ -0,0 +1,11 @@
1
+ # @done-coding/cli-skills
2
+
3
+ ```
4
+ done-coding CLI 各命令的 Agent Skills 聚合包与安装器
5
+ ```
6
+
7
+ ## 使用
8
+
9
+ ```bash
10
+ npm install @done-coding/cli-skills
11
+ ```
package/es/cli.mjs ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ import { a } from "./main-BjgtGCEn.js";
3
+ a();
package/es/index.mjs ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env node
2
+ import { S as e, c as m, h as o } from "./main-BjgtGCEn.js";
3
+ export {
4
+ e as SubcommandEnum,
5
+ m as createAsSubcommand,
6
+ o as handler
7
+ };
@@ -0,0 +1,149 @@
1
+ #!/usr/bin/env node
2
+ import { homedir as $ } from "node:os";
3
+ import { join as l } from "node:path";
4
+ import { outputConsole as a, safeCwd as y, xPrompts as w, getRootScriptName as b, createSubcommand as f, createMainCommand as C } from "@done-coding/cli-utils";
5
+ import { existsSync as m, readdirSync as L, readFileSync as I, mkdirSync as N, cpSync as v } from "node:fs";
6
+ import { fileURLToPath as A } from "node:url";
7
+ var d = /* @__PURE__ */ ((t) => (t.INSTALL = "install", t))(d || {});
8
+ const u = {
9
+ name: "@done-coding/cli-skills",
10
+ version: "0.1.0",
11
+ description: "done-coding CLI 各命令的 Agent Skills 聚合包与安装器",
12
+ bin: {
13
+ "dc-cli-skills": "es/cli.mjs"
14
+ },
15
+ cliConfig: {
16
+ namespaceDir: ".${organization}",
17
+ moduleName: "${name}"
18
+ }
19
+ }, D = () => A(new URL("../skills", import.meta.url)), x = (t) => {
20
+ const e = t.match(/^---\s*\n([\s\S]*?)\n---/);
21
+ if (!e) return {};
22
+ const s = e[1], i = (r) => {
23
+ var o;
24
+ const n = s.match(new RegExp(`^${r}\\s*:\\s*(.+)$`, "m"));
25
+ return (o = n == null ? void 0 : n[1]) == null ? void 0 : o.trim().replace(/^["']|["']$/g, "");
26
+ };
27
+ return { name: i("name"), description: i("description") };
28
+ }, T = (t) => m(t) ? L(t, { withFileTypes: !0 }).filter((e) => e.isDirectory()).map((e) => {
29
+ const s = l(t, e.name), i = l(s, "SKILL.md");
30
+ if (!m(i)) return;
31
+ const r = x(I(i, "utf-8"));
32
+ return {
33
+ name: e.name,
34
+ description: r.description ?? "",
35
+ sourceDir: s
36
+ };
37
+ }).filter((e) => e !== void 0) : [], j = (t, e, { force: s = !1 } = {}) => (N(e, { recursive: !0 }), t.map((i) => {
38
+ const r = l(e, i.name), n = m(r);
39
+ return n && !s ? { name: i.name, targetDir: r, status: "skipped" } : (v(i.sourceDir, r, { recursive: !0, force: !0 }), {
40
+ name: i.name,
41
+ targetDir: r,
42
+ status: n ? "overwritten" : "installed"
43
+ });
44
+ })), F = () => ({
45
+ global: {
46
+ type: "boolean",
47
+ alias: "g",
48
+ describe: "安装到全局 ~/.claude/skills(默认安装到项目 ./.claude/skills)",
49
+ default: !1
50
+ },
51
+ all: {
52
+ type: "boolean",
53
+ alias: "a",
54
+ describe: "安装全部内置 skill,跳过交互选择",
55
+ default: !1
56
+ },
57
+ skill: {
58
+ type: "array",
59
+ alias: "s",
60
+ describe: "指定要安装的 skill 名称(可多个),跳过交互选择"
61
+ },
62
+ force: {
63
+ type: "boolean",
64
+ alias: "f",
65
+ describe: "覆盖已存在的同名 skill",
66
+ default: !1
67
+ }
68
+ }), R = async (t, e) => {
69
+ if (t.all)
70
+ return e;
71
+ const s = (t.skill ?? []).map(String);
72
+ if (s.length > 0) {
73
+ const n = s.filter(
74
+ (o) => !e.some((c) => c.name === o)
75
+ );
76
+ return n.length > 0 && a.warn(`未找到 skill: ${n.join(", ")}`), e.filter((o) => s.includes(o.name));
77
+ }
78
+ const { picked: i } = await w({
79
+ type: "multiselect",
80
+ name: "picked",
81
+ message: "选择要安装的 skill(空格勾选,回车确认)",
82
+ choices: e.map((n) => ({
83
+ title: n.name,
84
+ value: n.name,
85
+ description: n.description
86
+ })),
87
+ min: 1
88
+ }), r = i ?? [];
89
+ return e.filter((n) => r.includes(n.name));
90
+ }, k = async (t) => {
91
+ const e = D(), s = T(e);
92
+ if (s.length === 0) {
93
+ a.warn(`未发现任何内置 skill(目录: ${e})`);
94
+ return;
95
+ }
96
+ const i = await R(t, s);
97
+ if (i.length === 0) {
98
+ a.warn("未选择任何 skill,已退出");
99
+ return;
100
+ }
101
+ const r = t.global ? l($(), ".claude", "skills") : l(y(), ".claude", "skills"), n = j(i, r, {
102
+ force: t.force
103
+ });
104
+ for (const c of n) {
105
+ const h = c.status === "skipped" ? "跳过(已存在,--force 覆盖)" : c.status === "overwritten" ? "覆盖" : "安装";
106
+ a.info(`[${h}] ${c.name} → ${c.targetDir}`);
107
+ }
108
+ const o = n.filter(
109
+ (c) => c.status !== "skipped"
110
+ ).length;
111
+ a.success(
112
+ `完成:${o}/${n.length} 个 skill 已写入 ${r}`
113
+ );
114
+ }, U = {
115
+ command: d.INSTALL,
116
+ describe: "把内置的 done-coding CLI skill(s) 安装到 .claude/skills",
117
+ options: F(),
118
+ handler: k
119
+ }, O = async (t, e) => {
120
+ switch (t) {
121
+ case d.INSTALL:
122
+ return k(e);
123
+ default:
124
+ throw new Error(`不支持的命令 ${t}`);
125
+ }
126
+ }, { version: E, description: P } = u, g = {
127
+ describe: P,
128
+ version: E,
129
+ subcommands: [U].map(f),
130
+ demandCommandCount: 1,
131
+ rootScriptName: b({ packageJson: u })
132
+ }, {
133
+ cliConfig: { moduleName: p }
134
+ } = u, S = (t = !1) => {
135
+ const e = t ? p : void 0, s = `$0${t ? ` ${p}` : ""} <command> [options]`;
136
+ return { command: e, usage: s };
137
+ }, q = async () => C({
138
+ ...g,
139
+ ...S()
140
+ }), G = () => f({
141
+ ...g,
142
+ ...S(!0)
143
+ });
144
+ export {
145
+ d as S,
146
+ q as a,
147
+ G as c,
148
+ O as h
149
+ };
package/package.json ADDED
@@ -0,0 +1,62 @@
1
+ {
2
+ "name": "@done-coding/cli-skills",
3
+ "version": "0.1.0",
4
+ "description": "done-coding CLI 各命令的 Agent Skills 聚合包与安装器",
5
+ "private": false,
6
+ "module": "es/index.mjs",
7
+ "types": "types/index.d.ts",
8
+ "type": "module",
9
+ "bin": {
10
+ "dc-cli-skills": "es/cli.mjs"
11
+ },
12
+ "exports": {
13
+ ".": {
14
+ "import": "./es/index.mjs",
15
+ "types": "./types/index.d.ts"
16
+ }
17
+ },
18
+ "files": [
19
+ "es",
20
+ "lib",
21
+ "types",
22
+ "skills"
23
+ ],
24
+ "scripts": {
25
+ "predev": "dc-inject",
26
+ "dev": "vite build -w -m hotBuild",
27
+ "prebuild": "dc-inject",
28
+ "build": "vite build",
29
+ "prepack": "pnpm build",
30
+ "test": "vitest",
31
+ "coverage": "vitest run --coverage"
32
+ },
33
+ "repository": {
34
+ "type": "git",
35
+ "url": "git@gitee.com:done-coding/done-coding-cli.git"
36
+ },
37
+ "publishConfig": {
38
+ "access": "public",
39
+ "registry": "https://registry.npmjs.org/"
40
+ },
41
+ "author": "JustSoSu",
42
+ "license": "MIT",
43
+ "sideEffects": false,
44
+ "devDependencies": {
45
+ "@done-coding/cli-inject": "^0.5.17",
46
+ "@types/node": "^18.0.0",
47
+ "@types/prompts": "^2.4.6",
48
+ "@types/yargs": "^17.0.28",
49
+ "@vitest/coverage-v8": "^1.6.1",
50
+ "typescript": "^5.8.3",
51
+ "vite": "^5.0.10",
52
+ "vite-plugin-dts": "^3.7.0",
53
+ "vitest": "^1.6.1"
54
+ },
55
+ "dependencies": {
56
+ "@done-coding/cli-utils": "0.11.0"
57
+ },
58
+ "engines": {
59
+ "node": ">=18.0.0"
60
+ },
61
+ "gitHead": "d5d89297f6cf953893f2d9ceb591c96ce0114656"
62
+ }
@@ -0,0 +1,119 @@
1
+ ---
2
+ name: create-done-coding
3
+ description: Use when scaffolding / creating / initializing a new done-coding project from a template(创建、初始化、新建 done-coding 项目;用 done-coding 模板生成工程). Drives the create-done-coding CLI non-interactively via npx — no resident MCP needed.
4
+ ---
5
+
6
+ # 创建 done-coding 项目(create-done-coding)
7
+
8
+ 用 `create-done-coding` CLI 从模板**非交互**地生成 done-coding 项目。全程经 `npx ...@latest` 现取现用,无需预装 CLI、无需常驻 MCP。
9
+
10
+ ## 何时用
11
+
12
+ 用户要:创建 / 初始化 / 新建一个 done-coding 项目;用某模板 scaffold 工程;从模板列表里挑一个生成。
13
+
14
+ ## 心智模型(两步)
15
+
16
+ 1. **查问题** `--list-questions`:拿到该模板要哪些答案(JSON,机读)。
17
+ 2. **带答案建** `--env`:把答案一次性传入,非交互生成项目。
18
+
19
+ 模板要么是一个 git 仓库(远端地址 / 本地绝对路径),要么是仓库内的某个子目录(用 `--templateDirectory`)。
20
+
21
+ ## 前置:确定模板来源(templateUrl)
22
+
23
+ 模板来源是 git 地址或本地 git 仓库**根路径**(`/` 开头)。两种拿法:
24
+
25
+ ⓐ **用户已指明模板**(给了 git 地址 / 本地路径)→ 直接作为 `-p` 的值。
26
+ ⓑ **从本地模板列表挑**:用户维护的模板列表是一个 JSON:
27
+
28
+ ```json
29
+ { "templateList": [
30
+ { "name": "...", "url": "<git 或本地仓库根路径>", "directory": "<仓库内子目录,可选>", "branch": "<分支,可选>" }
31
+ ] }
32
+ ```
33
+
34
+ 读这个文件,与用户确认选哪一个,取其 `url`(及 `directory` / `branch`)。
35
+
36
+ > [MUST] 显式传 `-p <url>`(或 `--templateConfig <本地列表路径>`)。不要依赖「不传任何来源时静默回落远端默认列表」——来源要可见、可复述。
37
+ > 子目录模板用 `--templateDirectory <子目录>`(如 monorepo 子包 `packages/xxx`),**不要**把子目录拼进 `url`;本地来源的 `url` 必须是 git 仓库根。
38
+
39
+ ## 步骤 1 — 查询模板需要哪些答案
40
+
41
+ ```bash
42
+ npx create-done-coding@latest \
43
+ -p <templateUrl> \
44
+ [--templateDirectory <仓库内子目录>] \
45
+ [-b <分支>] \
46
+ --list-questions
47
+ ```
48
+
49
+ 仅向 **stdout** 打印 JSON(不创建项目,退出码 0)。形如:
50
+
51
+ ```json
52
+ [
53
+ { "key": "organization", "required": false, "default": "done-coding" },
54
+ { "key": "name", "required": true },
55
+ { "key": "description", "required": true }
56
+ ]
57
+ ```
58
+
59
+ 判定规则:
60
+ - `required: true`(且无 `default` 字段)→ **必填**,[MUST] 供答。
61
+ - `required: false`(带 `default`)→ 选填,不供答则回落 `default`。
62
+
63
+ ## 步骤 2 — 收集答案后非交互创建
64
+
65
+ 答案拼成 JSON(key 对齐步骤 1 的 `key`,**是 key 不是中文 label**),经 `--env` 一次性供答:
66
+
67
+ ```bash
68
+ npx create-done-coding@latest \
69
+ -n <projectName> \
70
+ -p <templateUrl> \
71
+ [--templateDirectory <仓库内子目录>] \
72
+ [-b <分支>] \
73
+ --env '{"name":"<projectName>","description":"...","organization":"done-coding"}'
74
+ ```
75
+
76
+ 答案多时可改用文件:`--env-file ./answers.json`(内容为 `{ key: value }`)。两者同给时 `--env` 浅覆盖 `--env-file`。
77
+
78
+ ## 完整示例
79
+
80
+ 从某 monorepo hub 的子包模板 `packages/npm-node-cli`(本地仓库根 `/abs/hub`,分支 master)创建名为 `my-tool` 的项目:
81
+
82
+ ```bash
83
+ # 1. 先查问题
84
+ npx create-done-coding@latest -p /abs/hub -b master \
85
+ --templateDirectory packages/npm-node-cli --list-questions
86
+ # → [{"key":"organization","required":false,"default":"done-coding"},
87
+ # {"key":"organizationAbr","required":false,"default":"dc"},
88
+ # {"key":"name","required":true},{"key":"description","required":true},
89
+ # {"key":"repositoryUrl","required":false,"default":""}]
90
+
91
+ # 2. 补必填(name/description)后创建
92
+ npx create-done-coding@latest -n my-tool -p /abs/hub -b master \
93
+ --templateDirectory packages/npm-node-cli \
94
+ --env '{"name":"my-tool","description":"我的命令行工具","organization":"done-coding"}'
95
+ # → 生成 ./my-tool/
96
+ ```
97
+
98
+ ## 行为约定(据实测)
99
+
100
+ - **退出码可信**:缺必填 / 失败 → **退出码 1**,且在 **stderr** 列出缺哪些(如 `name(包名)、description(描述)`),不创建任何目录;成功 → 退出码 0。agent 可直接靠退出码判断成败。
101
+ - **stdout 只出数据**:`--list-questions` 的 JSON 走 stdout,诊断/报错走 stderr——解析时只读 stdout。
102
+ - **无 TTY 自动非交互**:CI / agent / 管道环境下不等终端输入,缺答案即快速失败,不会卡住。
103
+ - **生成位置**:当前工作目录下的 `<projectName>/`(或 `--rootDir` 指定的根下)。
104
+ - **git 行为**:默认会对新项目做 git 初始化;但若创建在**已有 git 仓库内**(如往 monorepo 的 `packages/` 下生成),会自动**跳过**嵌套 `git init`。
105
+ - 创建后提示用户:`cd <projectName> && pnpm install`。
106
+
107
+ ## 选项速查(公开项)
108
+
109
+ | 选项 | 别名 | 说明 |
110
+ |---|---|---|
111
+ | `--projectName` | `-n` | 项目名称(生成的目录名) |
112
+ | `--templateUrl` | `-p` | 模板地址:git 地址或本地仓库根路径 |
113
+ | `--templateGitBranch` | `-b` | 模板仓库分支 |
114
+ | `--templateDirectory` | | 仓库内模板子目录 |
115
+ | `--templateConfig` | | 本地模板列表配置文件路径 |
116
+ | `--env` | | 预设答案 JSON 字符串 |
117
+ | `--env-file` | | 预设答案 JSON 文件路径 |
118
+ | `--list-questions` | | 仅打印模板预设问题清单(JSON),不创建 |
119
+ | `--gitCommitMessage` | `-m` | git 初始化的提交信息 |
package/types/cli.d.ts ADDED
@@ -0,0 +1 @@
1
+ export { }
@@ -0,0 +1,37 @@
1
+ import { CliHandlerArgv } from '@done-coding/cli-utils';
2
+ import { CommandModule } from 'yargs';
3
+
4
+ /** 作为子命令创建 */
5
+ export declare const createAsSubcommand: () => CommandModule<{}, {}>;
6
+
7
+ /** 导出供外部 export使用, cli内部不会通过改方法调用各子命令方法 */
8
+ export declare const handler: (command: SubcommandEnum, argv: CliHandlerArgv<any>) => Promise<void>;
9
+
10
+ /** install 子命令选项 */
11
+ export declare interface InstallOptions {
12
+ /** 安装到全局 ~/.claude/skills(默认安装到项目 ./.claude/skills) */
13
+ global?: boolean;
14
+ /** 安装全部内置 skill,跳过交互选择 */
15
+ all?: boolean;
16
+ /** 指定要安装的 skill 名称(可多个),跳过交互选择 */
17
+ skill?: string[];
18
+ /** 覆盖已存在的同名 skill */
19
+ force?: boolean;
20
+ }
21
+
22
+ /** 内置 skill 元信息(取自各 SKILL.md frontmatter) */
23
+ export declare interface SkillMeta {
24
+ /** skill 名(= 目录名,作为安装目标目录名与唯一标识) */
25
+ name: string;
26
+ /** 一句话描述(取自 SKILL.md frontmatter description) */
27
+ description: string;
28
+ /** 该 skill 源目录绝对路径 */
29
+ sourceDir: string;
30
+ }
31
+
32
+ /** 子命令枚举 */
33
+ export declare enum SubcommandEnum {
34
+ INSTALL = "install"
35
+ }
36
+
37
+ export { }