zero-ai 1.0.69 → 1.0.71

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zero-ai",
3
- "version": "1.0.69",
3
+ "version": "1.0.71",
4
4
  "description": "Zero Ecotope AI",
5
5
  "main": "src/ai.js",
6
6
  "bin": {
@@ -3,17 +3,8 @@
3
3
  "description": "同步 Zero Ui 的最新框架",
4
4
  "command": "sync",
5
5
  "options": [
6
- {
7
- "name": "path",
8
- "alias": "p",
9
- "description": "本地配置文件路径,默认 .zero",
10
- "default": ".zero"
11
- },
12
- {
13
- "name": "mode",
14
- "alias": "m",
15
- "description": "指定同步模块的模式,是否本地同步",
16
- "default": false
17
- }
6
+ {"name": "path", "alias": "p", "description": "本地配置文件路径,默认 .zero", "default": ".zero"},
7
+ {"name": "mode", "alias": "m", "description": "指定同步模块的模式,是否本地同步", "default": false},
8
+ {"name": "reverse", "alias": "r", "type": "boolean", "description": "逆向拷贝:从当前项目拷贝到 Z_ZERO_UI 指定目录", "default": false}
18
9
  ]
19
- }
10
+ }
@@ -181,6 +181,51 @@ module.exports = async (options) => {
181
181
  Ec.info(`安装位置:${targetLabels.join("、")}`);
182
182
  Ec.info(`已安装 ${selectedFiles.length} 个规则文件`);
183
183
 
184
+ // work-claude/:提取标题形成菜单,用户选择后拷贝 CLAUDE-*.md 为项目根目录 CLAUDE.md
185
+ const workClaudeDir = path.join(repoCache, "work-claude");
186
+ if (fs.existsSync(workClaudeDir)) {
187
+ const workClaudeFiles = fs.readdirSync(workClaudeDir).filter((file) => {
188
+ const p = path.join(workClaudeDir, file);
189
+ return fs.statSync(p).isFile() && file.startsWith("CLAUDE-") && file.endsWith(".md");
190
+ });
191
+ if (workClaudeFiles.length > 0) {
192
+ const choicesWithTitle = workClaudeFiles.map((file) => {
193
+ const fullPath = path.join(workClaudeDir, file);
194
+ const content = fs.readFileSync(fullPath, "utf-8");
195
+ const match = content.match(/^#\s+(.+)$/m);
196
+ const title = match ? match[1].trim() : path.basename(file, ".md");
197
+ return { name: title, value: file };
198
+ });
199
+ const { selectedClaude } = await inquirer.prompt([
200
+ {
201
+ type: "list",
202
+ name: "selectedClaude",
203
+ message: "请选择要安装的 Claude 工作说明(将拷贝为项目根目录 CLAUDE.md):",
204
+ choices: choicesWithTitle
205
+ }
206
+ ]);
207
+ const sourceClaude = path.join(workClaudeDir, selectedClaude);
208
+ const targetClaude = path.resolve(outputPath, "CLAUDE.md");
209
+ fs.copyFileSync(sourceClaude, targetClaude);
210
+ Ec.info(`已安装:${selectedClaude} → CLAUDE.md`);
211
+ // 将 CLAUDE.md 追加到 .gitignore
212
+ const gitignorePathClaude = path.resolve(outputPath, ".gitignore");
213
+ const claudeIgnoreEntry = "CLAUDE.md";
214
+ if (fs.existsSync(gitignorePathClaude)) {
215
+ const content = fs.readFileSync(gitignorePathClaude, "utf-8");
216
+ const hasClaude = content.split("\n").some((line) => line.trim() === claudeIgnoreEntry);
217
+ if (!hasClaude) {
218
+ const newContent = content.endsWith("\n") ? `${content}${claudeIgnoreEntry}\n` : `${content}\n${claudeIgnoreEntry}\n`;
219
+ fs.writeFileSync(gitignorePathClaude, newContent, "utf-8");
220
+ Ec.info(`已将 ${claudeIgnoreEntry} 添加到 .gitignore`);
221
+ }
222
+ } else {
223
+ fs.writeFileSync(gitignorePathClaude, `${claudeIgnoreEntry}\n`, "utf-8");
224
+ Ec.info(`已创建 .gitignore 并添加 ${claudeIgnoreEntry}`);
225
+ }
226
+ }
227
+ }
228
+
184
229
  // 添加 AI 工具目录到 .git/info/exclude
185
230
  const excludeEntries = [".cursor/", ".claude/", ".gemini/", ".trae/", ".lingma/"];
186
231
  const gitPath = path.resolve(outputPath, ".git");
@@ -1,7 +1,12 @@
1
1
  const Ec = require("../epic");
2
+ const fs = require("fs");
3
+ const path = require("path");
2
4
  const child = require('child_process');
3
5
  const Ut = require("../commander-shared");
4
6
 
7
+ const REPO_URL = "https://gitee.com/silentbalanceyh/scaffold-ui.git";
8
+ const REPO_NAME = "scaffold-ui";
9
+
5
10
  const COMMANDS = [
6
11
  "run-default.sh",
7
12
  "run-doc.sh",
@@ -60,24 +65,21 @@ const COMMANDS = [
60
65
  ]
61
66
 
62
67
  const executeRemote = (actual = {}, options = {}) => {
63
- const path = actual.path;
64
- // 2. 创建 .zero 目录
65
- const cmdDir = `mkdir -p ${path}`;
66
- child.execSync(cmdDir, options);
67
- const pathSource = `${path}/scaffold-ui`
68
- // 3. 删除 .zero/scaffold-ui 目录
69
- if (Ec.isExist(pathSource)) {
70
- Ec.info(`发现存在旧代码,正在删除:${pathSource}`);
71
- const cmdDel = `rm -rf ${pathSource}`;
72
- child.execSync(cmdDel, options);
68
+ const outputBase = "."; // 仓库与 .gitignore 使用项目根目录
69
+ const repoCache = path.resolve(outputBase, ".r2mo", "repo", REPO_NAME);
70
+ const repoCacheDir = path.dirname(repoCache);
71
+ // 确保 .r2mo/repo 目录存在
72
+ if (!fs.existsSync(repoCacheDir)) {
73
+ fs.mkdirSync(repoCacheDir, { recursive: true });
74
+ }
75
+ // 若已有克隆则先删除,再拉取
76
+ if (Ec.isExist(repoCache)) {
77
+ Ec.info(`发现存在旧仓库,正在删除:${repoCache}`);
78
+ child.execSync(`rm -rf ${repoCache}`, options);
73
79
  }
74
- // 4. 重新拉取代码
75
- Ec.info(`拉取最新代码:${pathSource}`);
76
- const cmdGit = `git clone https://gitee.com/silentbalanceyh/scaffold-ui.git ${pathSource}`;
77
- child.execSync(cmdGit, options);
78
- const cmdRm = `rm -rf ${pathSource}/.git`;
79
- child.execSync(cmdRm, options);
80
- return pathSource;
80
+ Ec.info(`拉取最新代码到:${repoCache}`);
81
+ child.execSync(`git clone ${REPO_URL} ${repoCache}`, options);
82
+ return repoCache;
81
83
  }
82
84
 
83
85
  const executeLocal = (actual = {}, options = {}) => {
@@ -89,6 +91,35 @@ const executeLocal = (actual = {}, options = {}) => {
89
91
  return pathEnv;
90
92
  }
91
93
 
94
+ /**
95
+ * 逆向拷贝:从当前项目将 COMMANDS 所列内容拷贝到 Z_ZERO_UI 指定目录
96
+ */
97
+ const executeReverse = (targetBase, options = {}) => {
98
+ Ec.info(`逆向拷贝目标:${targetBase}`);
99
+ Ec.info(`开始逆向拷贝主框架(与正向 sync 相同内容):......`.yellow);
100
+ COMMANDS.forEach((command) => {
101
+ Ec.info(`处理:${command.green}`);
102
+ const src = `./${command}`;
103
+ const dest = path.resolve(targetBase, command);
104
+ if (command.endsWith("/")) {
105
+ if (!Ec.isExist(src)) return;
106
+ const destDir = path.resolve(targetBase, command);
107
+ if (!fs.existsSync(destDir)) {
108
+ fs.mkdirSync(destDir, { recursive: true });
109
+ }
110
+ child.execSync(`cp -rf ${src}* "${destDir}"`, options);
111
+ } else {
112
+ if (!Ec.isExist(src)) return;
113
+ const destDir = path.dirname(dest);
114
+ if (!fs.existsSync(destDir)) {
115
+ fs.mkdirSync(destDir, { recursive: true });
116
+ }
117
+ child.execSync(`cp -rf ${src} "${dest}"`, options);
118
+ }
119
+ });
120
+ Ec.info(`逆向拷贝完成:${targetBase}!`.help);
121
+ };
122
+
92
123
  module.exports = (options) => {
93
124
 
94
125
  // 获取当前操作系统
@@ -105,6 +136,14 @@ module.exports = (options) => {
105
136
  optionsWait = {stdio: 'inherit'};
106
137
  }
107
138
 
139
+ // -r / --reverse 无值时补 "true",否则 parseArgument 会报缺值
140
+ const argvRest = process.argv.slice(3);
141
+ const rIdx = argvRest.indexOf("-r");
142
+ const revIdx = argvRest.indexOf("--reverse");
143
+ const flagIdx = rIdx >= 0 ? rIdx : revIdx;
144
+ if (flagIdx >= 0 && (flagIdx + 1 >= argvRest.length || (argvRest[flagIdx + 1] && argvRest[flagIdx + 1].startsWith("-")))) {
145
+ process.argv.splice(3 + flagIdx + 1, 0, "true");
146
+ }
108
147
  const parsed = Ut.parseArgument(options);
109
148
  // 1. 环境检查
110
149
  if (!Ec.isExist(".git")) {
@@ -112,6 +151,18 @@ module.exports = (options) => {
112
151
  return;
113
152
  }
114
153
 
154
+ // 逆向拷贝:-r 时从当前项目拷贝到 Z_ZERO_UI
155
+ if (parsed.reverse) {
156
+ const targetBase = process.env.Z_ZERO_UI;
157
+ if (!targetBase || !targetBase.trim()) {
158
+ Ec.error("逆向拷贝需要设置环境变量 Z_ZERO_UI(拷贝目标地址),未设置则退出。");
159
+ process.exit(1);
160
+ }
161
+ const resolved = path.resolve(targetBase.trim());
162
+ executeReverse(resolved, optionsWait);
163
+ return;
164
+ }
165
+
115
166
  let pathSource;
116
167
  if (parsed.mode) {
117
168
  // 本地模式
@@ -121,26 +172,45 @@ module.exports = (options) => {
121
172
  pathSource = executeRemote(parsed, optionsWait);
122
173
  }
123
174
  if (pathSource) {
124
- // 5. 拷贝 Ignore 文件全部指令
175
+ const outputBase = ".";
176
+ // 确保 .r2mo/repo 在 .gitignore 中
177
+ const gitignorePath = path.resolve(outputBase, ".gitignore");
178
+ const ignoreEntry = ".r2mo/repo/";
179
+ if (fs.existsSync(gitignorePath)) {
180
+ const gitignoreContent = fs.readFileSync(gitignorePath, "utf-8");
181
+ const hasIgnoreEntry = gitignoreContent.split("\n").some((line) => {
182
+ const t = line.trim();
183
+ return t === ".r2mo/repo" || t === ".r2mo/repo/";
184
+ });
185
+ if (!hasIgnoreEntry) {
186
+ const newContent = gitignoreContent.endsWith("\n")
187
+ ? `${gitignoreContent}${ignoreEntry}\n`
188
+ : `${gitignoreContent}\n${ignoreEntry}\n`;
189
+ fs.writeFileSync(gitignorePath, newContent, "utf-8");
190
+ Ec.info(`已将 ${ignoreEntry} 添加到 .gitignore`);
191
+ }
192
+ } else {
193
+ fs.writeFileSync(gitignorePath, `${ignoreEntry}\n`, "utf-8");
194
+ Ec.info(`已创建 .gitignore 并添加 ${ignoreEntry}`);
195
+ }
196
+ // 拷贝框架文件
125
197
  Ec.info(`开始更新主框架:......`.yellow);
126
198
  COMMANDS.forEach(command => {
127
199
  Ec.info(`处理目录:${command.green}`);
128
- let cmd;
129
200
  if (command.endsWith("/")) {
130
- // 目录拷贝
131
201
  if (!Ec.isExist(command)) {
132
- const cmdDir = `mkdir -p ${command}`;
133
- child.execSync(cmdDir, optionsWait);
202
+ child.execSync(`mkdir -p ${command}`, optionsWait);
134
203
  }
135
- cmd = `cp -rf ${pathSource}/${command}* ./${command}`;
136
- child.execSync(cmd, optionsWait);
204
+ child.execSync(`cp -rf ${pathSource}/${command}* ./${command}`, optionsWait);
137
205
  } else {
138
- // 文件拷贝
139
- cmd = `cp -rf ${pathSource}/${command} ./${command}`;
140
- child.execSync(cmd, optionsWait);
206
+ child.execSync(`cp -rf ${pathSource}/${command} ./${command}`, optionsWait);
141
207
  }
142
- })
208
+ });
143
209
  Ec.info(`主框架更新完成:${pathSource}!`.help);
210
+ // 拷贝完成后移除临时仓库
211
+ Ec.info(`正在移除临时仓库:${pathSource}`);
212
+ child.execSync(`rm -rf ${pathSource}`, optionsWait);
213
+ Ec.info(`临时仓库已移除。`);
144
214
  }
145
215
  }
146
216
  /**