zero-ai 1.0.75 → 1.0.79
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 +1 -1
- package/r2mo-init/.obsidian/app.json +1 -0
- package/r2mo-init/.obsidian/appearance.json +10 -0
- package/r2mo-init/.obsidian/community-plugins.json +7 -0
- package/r2mo-init/.obsidian/core-plugins.json +33 -0
- package/r2mo-init/.obsidian/plugins/dataview/main.js +20876 -0
- package/r2mo-init/.obsidian/plugins/dataview/manifest.json +11 -0
- package/r2mo-init/.obsidian/plugins/dataview/styles.css +141 -0
- package/r2mo-init/.obsidian/plugins/obsidian-excalidraw-plugin/data.json +815 -0
- package/r2mo-init/.obsidian/plugins/obsidian-excalidraw-plugin/main.js +10 -0
- package/r2mo-init/.obsidian/plugins/obsidian-excalidraw-plugin/manifest.json +12 -0
- package/r2mo-init/.obsidian/plugins/obsidian-excalidraw-plugin/styles.css +1 -0
- package/r2mo-init/.obsidian/plugins/obsidian-kanban/main.js +153 -0
- package/r2mo-init/.obsidian/plugins/obsidian-kanban/manifest.json +11 -0
- package/r2mo-init/.obsidian/plugins/obsidian-kanban/styles.css +1 -0
- package/r2mo-init/.obsidian/plugins/obsidian-plantuml/main.js +7732 -0
- package/r2mo-init/.obsidian/plugins/obsidian-plantuml/manifest.json +10 -0
- package/r2mo-init/.obsidian/plugins/obsidian-plantuml/styles.css +38 -0
- package/r2mo-init/.obsidian/plugins/obsidian-tasks-plugin/main.js +504 -0
- package/r2mo-init/.obsidian/plugins/obsidian-tasks-plugin/manifest.json +12 -0
- package/r2mo-init/.obsidian/plugins/obsidian-tasks-plugin/styles.css +1 -0
- package/r2mo-init/.obsidian/snippets/body-font.css +9 -0
- package/r2mo-init/.obsidian/themes/Comfort/manifest.json +11 -0
- package/r2mo-init/.obsidian/themes/Comfort/theme.css +218 -0
- package/r2mo-init/.obsidian/themes/Primary/manifest.json +9 -0
- package/r2mo-init/.obsidian/themes/Primary/theme.css +3878 -0
- package/r2mo-init/.obsidian/themes/Retro Windows/manifest.json +7 -0
- package/r2mo-init/.obsidian/themes/Retro Windows/theme.css +582 -0
- package/r2mo-init/.obsidian/themes/RetroOS 98/manifest.json +9 -0
- package/r2mo-init/.obsidian/themes/RetroOS 98/theme.css +2566 -0
- package/r2mo-init/.obsidian/themes/Serenity/manifest.json +7 -0
- package/r2mo-init/.obsidian/themes/Serenity/theme.css +7258 -0
- package/r2mo-init/.obsidian/themes/W95/manifest.json +8 -0
- package/r2mo-init/.obsidian/themes/W95/theme.css +768 -0
- package/r2mo-init/.obsidian/types.json +28 -0
- package/r2mo-init/task/command/ex-api.yaml.example +13 -0
- package/r2mo-init/task/task-001.md +144 -0
- package/r2mo-init/task/task-002.md +4 -0
- package/r2mo-init/task/task-003.md +4 -0
- package/r2mo-init/task/thread +1 -0
- package/src/commander/ex-api.json +1 -2
- package/src/commander/ex-crud.json +1 -1
- package/src/commander-ai/fn.ex.api.js +192 -103
- package/src/commander-ai/fn.ex.crud.js +102 -58
- package/.cursor/rules/test.mdc +0 -4
|
@@ -8,7 +8,7 @@ const yaml = require("js-yaml");
|
|
|
8
8
|
const inquirer = require("inquirer");
|
|
9
9
|
const { v4: uuidv4 } = require("uuid");
|
|
10
10
|
|
|
11
|
-
const
|
|
11
|
+
const CONFIG_DIR = ".r2mo/task/command/ex-crud";
|
|
12
12
|
const REQUIRED_ENV_DB = ["Z_DB_TYPE", "Z_DB_HOST", "Z_DB_PORT", "Z_DBS_INSTANCE", "Z_DB_APP_USER", "Z_DB_APP_PASS"];
|
|
13
13
|
const REQUIRED_ENV_APP = ["Z_APP_ID", "Z_TENANT", "Z_SIGMA"];
|
|
14
14
|
|
|
@@ -261,23 +261,35 @@ async function copyTemplateWithReplace(templateDir, destDir, meta, skipNames) {
|
|
|
261
261
|
}
|
|
262
262
|
}
|
|
263
263
|
|
|
264
|
-
/**
|
|
265
|
-
function
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
const
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
if (
|
|
264
|
+
/** 校验 ex-crud metadata:至少 keyword、identifier 非空 */
|
|
265
|
+
function validateExCrudMetadata(config) {
|
|
266
|
+
if (!config || !config.metadata || typeof config.metadata !== "object") return { valid: false, error: "缺少 metadata" };
|
|
267
|
+
const m = config.metadata;
|
|
268
|
+
const keyword = m.keyword != null ? String(m.keyword).trim() : "";
|
|
269
|
+
const identifier = m.identifier != null ? String(m.identifier).trim() : "";
|
|
270
|
+
if (!keyword) return { valid: false, error: "metadata.keyword 为空" };
|
|
271
|
+
if (!identifier) return { valid: false, error: "metadata.identifier 为空" };
|
|
272
|
+
if (!/^[a-zA-Z0-9._-]+$/.test(identifier)) return { valid: false, error: "metadata.identifier 仅允许字母数字、点、下划线、横线" };
|
|
273
|
+
return { valid: true };
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/** 解析 ex-crud 配置目录:cwd / 上级 / 上上级 */
|
|
277
|
+
function resolveExCrudConfigDir(cwd) {
|
|
278
|
+
const primary = path.resolve(cwd, CONFIG_DIR);
|
|
279
|
+
if (fs.existsSync(primary) && fs.statSync(primary).isDirectory()) return primary;
|
|
280
|
+
const parent = path.resolve(cwd, "..", CONFIG_DIR);
|
|
281
|
+
if (fs.existsSync(parent) && fs.statSync(parent).isDirectory()) return parent;
|
|
282
|
+
const grand = path.resolve(cwd, "..", "..", CONFIG_DIR);
|
|
283
|
+
if (fs.existsSync(grand) && fs.statSync(grand).isDirectory()) return grand;
|
|
272
284
|
return primary;
|
|
273
285
|
}
|
|
274
286
|
|
|
275
287
|
module.exports = async (options) => {
|
|
276
288
|
const cwd = process.cwd();
|
|
277
|
-
const
|
|
278
|
-
if (!fs.existsSync(
|
|
279
|
-
|
|
280
|
-
|
|
289
|
+
const configDir = resolveExCrudConfigDir(cwd);
|
|
290
|
+
if (!fs.existsSync(configDir)) {
|
|
291
|
+
fs.mkdirSync(configDir, { recursive: true });
|
|
292
|
+
const templatePath = path.join(configDir, "ex-crud.yaml");
|
|
281
293
|
const template = `# ai ex-crud 使用此配置,请按项目修改
|
|
282
294
|
metadata:
|
|
283
295
|
keyword: "log"
|
|
@@ -290,56 +302,45 @@ metadata:
|
|
|
290
302
|
# root: "ZERO_MODULE"
|
|
291
303
|
# module: "ambient"
|
|
292
304
|
`;
|
|
293
|
-
fs.writeFileSync(
|
|
294
|
-
Ec.info("
|
|
305
|
+
fs.writeFileSync(templatePath, template, "utf-8");
|
|
306
|
+
Ec.info("配置目录缺失,已创建并写入模板:" + templatePath);
|
|
295
307
|
Ec.info("请编辑后重新执行: ai ex-crud");
|
|
296
308
|
process.exit(1);
|
|
297
309
|
}
|
|
298
310
|
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
311
|
+
const backupDir = path.join(configDir, "backup");
|
|
312
|
+
const allEntries = fs.readdirSync(configDir, { withFileTypes: true });
|
|
313
|
+
const yamlFiles = allEntries.filter((e) => !e.isDirectory() && e.isFile() && (e.name.endsWith(".yaml") || e.name.endsWith(".yml")));
|
|
314
|
+
const entries = [];
|
|
315
|
+
for (const e of yamlFiles) {
|
|
316
|
+
const f = e.name;
|
|
317
|
+
const full = path.join(configDir, f);
|
|
318
|
+
try {
|
|
319
|
+
const config = yaml.load(fs.readFileSync(full, "utf-8"));
|
|
320
|
+
const valid = validateExCrudMetadata(config);
|
|
321
|
+
if (!valid.valid) {
|
|
322
|
+
Ec.info("[ex-crud] 警告(metadata 不合法,已跳过):" + f + "," + (valid.error || ""));
|
|
323
|
+
continue;
|
|
324
|
+
}
|
|
325
|
+
const label = (config.metadata.identifier || f) + " | " + (config.metadata.keyword || "") + (config.metadata.name ? " " + config.metadata.name : "");
|
|
326
|
+
entries.push({ path: full, config, label });
|
|
327
|
+
} catch (err) {
|
|
328
|
+
Ec.info("[ex-crud] 跳过(解析失败):" + f + "," + (err && err.message));
|
|
329
|
+
}
|
|
309
330
|
}
|
|
310
331
|
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
if (target && typeof target === "object") {
|
|
315
|
-
const root = target.root != null ? String(target.root).trim() : "";
|
|
316
|
-
const moduleName = target.module != null ? String(target.module).trim() : "";
|
|
317
|
-
if (root && moduleName) target = { root, module: moduleName };
|
|
318
|
-
else target = null;
|
|
319
|
-
} else {
|
|
320
|
-
target = null;
|
|
332
|
+
if (entries.length === 0) {
|
|
333
|
+
Ec.error("[ex-crud] 无有效配置:请在 " + configDir + " 下添加含合法 metadata(keyword、identifier)的 yaml");
|
|
334
|
+
process.exit(1);
|
|
321
335
|
}
|
|
322
|
-
Ec.info("[ex-crud] 配置:" + configFullPath + (target ? ",target=" + target.module : ",无 target"));
|
|
323
|
-
const meta = {
|
|
324
|
-
keyword: metadata.keyword != null ? String(metadata.keyword).trim() : "",
|
|
325
|
-
identifier: metadata.identifier != null ? String(metadata.identifier).trim() : "",
|
|
326
|
-
actor: metadata.actor != null ? String(metadata.actor).trim() : "",
|
|
327
|
-
name: metadata.name != null ? String(metadata.name).trim() : "",
|
|
328
|
-
type: metadata.type != null ? String(metadata.type).trim() : ""
|
|
329
|
-
};
|
|
330
336
|
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
if (!fs.existsSync(dpaRoot) || !isDpaRoot(dpaRoot)) {
|
|
339
|
-
Ec.error(`ZERO_MODULE 下 DPA 目录不是标准架构:${dpaRoot}`);
|
|
340
|
-
Ec.info("需存在 pom.xml 且包含 xxx-api、xxx-domain 子目录");
|
|
341
|
-
process.exit(1);
|
|
342
|
-
}
|
|
337
|
+
const answer = await inquirer.prompt([
|
|
338
|
+
{ type: "checkbox", name: "selected", message: "选择要执行的 CRUD 配置(多选)", choices: entries.map((e) => ({ name: e.label, value: e.path })) }
|
|
339
|
+
]);
|
|
340
|
+
const selectedPaths = answer && answer.selected && Array.isArray(answer.selected) ? answer.selected : [];
|
|
341
|
+
if (selectedPaths.length === 0) {
|
|
342
|
+
Ec.info("未选择任何项,退出");
|
|
343
|
+
process.exit(0);
|
|
343
344
|
}
|
|
344
345
|
|
|
345
346
|
const parsed = Ut.parseArgument(options);
|
|
@@ -358,8 +359,27 @@ metadata:
|
|
|
358
359
|
|
|
359
360
|
Ec.execute("ai ex-crud:配置已加载。");
|
|
360
361
|
|
|
361
|
-
// 1. 模板目录(R2MO-INIT 包内)与输出目录(与 ex-api 一致:有 target 时分流到 zero-exmodule-{module},无 target 时为 zero-launcher-configuration)
|
|
362
362
|
const templateDir = path.resolve(__dirname, "..", "_template", "EXCEL", "ex-crud");
|
|
363
|
+
const loadedConfigs = selectedPaths.map((p) => ({ path: p, config: yaml.load(fs.readFileSync(p, "utf-8")) }));
|
|
364
|
+
const first = loadedConfigs[0];
|
|
365
|
+
let target = first.config && first.config.target && typeof first.config.target === "object"
|
|
366
|
+
? (first.config.target.root && first.config.target.module ? { root: String(first.config.target.root).trim(), module: String(first.config.target.module).trim() } : null)
|
|
367
|
+
: null;
|
|
368
|
+
|
|
369
|
+
if (target) {
|
|
370
|
+
const zeroModule = process.env.ZERO_MODULE;
|
|
371
|
+
if (!zeroModule || !String(zeroModule).trim()) {
|
|
372
|
+
Ec.error("存在 target 配置时,环境变量 ZERO_MODULE 必须已设置");
|
|
373
|
+
process.exit(1);
|
|
374
|
+
}
|
|
375
|
+
const dpaRoot = path.resolve(zeroModule || "", `zero-exmodule-${target.module}`);
|
|
376
|
+
if (!fs.existsSync(dpaRoot) || !isDpaRoot(dpaRoot)) {
|
|
377
|
+
Ec.error(`ZERO_MODULE 下 DPA 目录不是标准架构:${dpaRoot}`);
|
|
378
|
+
Ec.info("需存在 pom.xml 且包含 xxx-api、xxx-domain 子目录");
|
|
379
|
+
process.exit(1);
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
|
|
363
383
|
const excelRoot = resolveExcelRoot(cwd, target);
|
|
364
384
|
const domainName = target && target.module ? `zero-exmodule-${target.module}-domain` : null;
|
|
365
385
|
const pluginsBase = domainName
|
|
@@ -376,7 +396,31 @@ metadata:
|
|
|
376
396
|
Ec.info("[ex-crud] RBAC_CRUD:" + rbacCrudDir);
|
|
377
397
|
Ec.info("[ex-crud] RBAC_ROLE :" + rbacRoleDir);
|
|
378
398
|
|
|
379
|
-
|
|
399
|
+
for (const { path: configPath, config } of loadedConfigs) {
|
|
400
|
+
const valid = validateExCrudMetadata(config);
|
|
401
|
+
if (!valid.valid) {
|
|
402
|
+
Ec.info("[ex-crud] 警告(metadata 不合法,跳过执行):" + path.basename(configPath) + "," + (valid.error || ""));
|
|
403
|
+
continue;
|
|
404
|
+
}
|
|
405
|
+
const metadata = config.metadata;
|
|
406
|
+
const meta = {
|
|
407
|
+
keyword: metadata.keyword != null ? String(metadata.keyword).trim() : "",
|
|
408
|
+
identifier: metadata.identifier != null ? String(metadata.identifier).trim() : "",
|
|
409
|
+
actor: metadata.actor != null ? String(metadata.actor).trim() : "",
|
|
410
|
+
name: metadata.name != null ? String(metadata.name).trim() : "",
|
|
411
|
+
type: metadata.type != null ? String(metadata.type).trim() : ""
|
|
412
|
+
};
|
|
413
|
+
Ec.info("[ex-crud] 处理:" + (metadata.identifier || path.basename(configPath)));
|
|
414
|
+
try {
|
|
415
|
+
await copyTemplateWithReplace(templateDir, rbacCrudDir, meta, ["ex-crud.yaml", "README.md", "template-RBAC_ROLE.xlsx", ".DS_Store"]);
|
|
416
|
+
if (!fs.existsSync(backupDir)) fs.mkdirSync(backupDir, { recursive: true });
|
|
417
|
+
const bakPath = path.join(backupDir, path.basename(configPath) + ".bak");
|
|
418
|
+
fs.renameSync(configPath, bakPath);
|
|
419
|
+
Ec.info("[ex-crud] 已备份:" + path.basename(configPath) + " -> backup/" + path.basename(configPath) + ".bak");
|
|
420
|
+
} catch (err) {
|
|
421
|
+
Ec.info("[ex-crud] 生成或备份失败(未备份):" + path.basename(configPath) + "," + (err && err.message));
|
|
422
|
+
}
|
|
423
|
+
}
|
|
380
424
|
|
|
381
425
|
Ec.info("[ex-crud] 已生成 CRUD 文件到 RBAC_CRUD");
|
|
382
426
|
|
|
@@ -436,7 +480,7 @@ metadata:
|
|
|
436
480
|
const rolePermsToWrite = roleIds.flatMap((rid) => permissionIds.map((pid) => ({ ROLE_ID: rid, PERM_ID: pid })));
|
|
437
481
|
if (!fs.existsSync(rbacRoleDir)) fs.mkdirSync(rbacRoleDir, { recursive: true });
|
|
438
482
|
const ExcelJS = require("exceljs");
|
|
439
|
-
const roleFileName = "falcon-crud-" + (
|
|
483
|
+
const roleFileName = "falcon-crud-" + (first.config.metadata && first.config.metadata.identifier ? String(first.config.metadata.identifier) : "batch").replace(/[^a-zA-Z0-9._-]/g, "_") + ".xlsx";
|
|
440
484
|
const outRolePath = path.join(rbacRoleDir, roleFileName);
|
|
441
485
|
const templatePath = path.resolve(__dirname, "..", "_template", "EXCEL", "ex-crud", "template-RBAC_ROLE.xlsx");
|
|
442
486
|
let roleWorkbook;
|
package/.cursor/rules/test.mdc
DELETED