@openyida/yidacli 0.1.3 → 0.1.5
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/bin/yidacli.js +13 -0
- package/dist/copy.js +6 -0
- package/dist/env.js +1 -1
- package/package.json +1 -2
- package/scripts/postinstall.js +0 -126
package/bin/yidacli.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
*
|
|
5
5
|
* 命令列表:
|
|
6
6
|
* yidacli env 检测当前 AI 工具环境和登录态
|
|
7
|
+
* yidacli copy [--force] 复制 openyida 工作目录到当前 AI 工具环境
|
|
7
8
|
* yidacli login 登录态管理
|
|
8
9
|
* yidacli logout 退出登录
|
|
9
10
|
* yidacli create-app "<名称>" [desc] [icon] [color] 创建应用
|
|
@@ -38,6 +39,7 @@ yidacli - 宜搭命令行工具
|
|
|
38
39
|
|
|
39
40
|
命令:
|
|
40
41
|
env 检测当前 AI 工具环境和登录态
|
|
42
|
+
copy [--force] 复制 openyida 工作目录到当前 AI 工具环境
|
|
41
43
|
login 登录态管理(优先缓存,否则扫码)
|
|
42
44
|
logout 退出登录 / 切换账号
|
|
43
45
|
create-app "<名称>" [描述] [图标] [颜色] 创建应用,输出 appType
|
|
@@ -73,6 +75,11 @@ async function main() {
|
|
|
73
75
|
process.exit(0);
|
|
74
76
|
}
|
|
75
77
|
|
|
78
|
+
if (command === '--version' || command === '-v') {
|
|
79
|
+
console.log(currentVersion);
|
|
80
|
+
process.exit(0);
|
|
81
|
+
}
|
|
82
|
+
|
|
76
83
|
switch (command) {
|
|
77
84
|
case 'env': {
|
|
78
85
|
const { run } = require('../dist/env');
|
|
@@ -80,6 +87,12 @@ async function main() {
|
|
|
80
87
|
break;
|
|
81
88
|
}
|
|
82
89
|
|
|
90
|
+
case 'copy': {
|
|
91
|
+
const { run } = require('../dist/copy');
|
|
92
|
+
run();
|
|
93
|
+
break;
|
|
94
|
+
}
|
|
95
|
+
|
|
83
96
|
case 'login': {
|
|
84
97
|
const { ensureLogin, checkLoginOnly } = require('../dist/login');
|
|
85
98
|
if (args[0] === '--check-only') {
|
package/dist/copy.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
let fs=require("fs"),path=require("path"),os=require("os"),detectEnvironment=require("./env").detectEnvironment;function findPackageOpenyidaDir(){try{var o=require.resolve("@openyida/yidacli/package.json"),e=path.dirname(o),r=path.join(e,"openyida");return fs.existsSync(r)?r:null}catch{return null}}function mergeCopyDir(o,e){if(!fs.existsSync(o))return 0;var r;fs.mkdirSync(e,{recursive:!0});let n=0;for(r of fs.readdirSync(o,{withFileTypes:!0})){var i=path.join(o,r.name),l=path.join(e,r.name);r.isDirectory()?n+=mergeCopyDir(i,l):(fs.copyFileSync(i,l),console.log(" 覆盖: "+l),n++)}return n}function run(){var l="=".repeat(55);console.log(l),console.log(" yidacli copy - 初始化 openyida 工作目录"),console.log(l);var c=process.argv.slice(3).includes("--force"),s=findPackageOpenyidaDir();if(s||(console.error("\n❌ 未找到 npm 包内的 openyida/ 目录"),console.error(" 请确认 @openyida/yidacli 已正确全局安装:"),console.error(" npm install -g @openyida/yidacli"),process.exit(1)),console.log(`
|
|
2
|
+
📦 源目录: `+s),c){let o=path.join(process.cwd(),"openyida"),e=(console.log("⚠️ --force 模式:强制复制到当前目录"),console.log(`📁 目标目录: ${o}
|
|
3
|
+
`),mergeCopyDir(s,o));console.log(`
|
|
4
|
+
`+l),console.log(`✅ 完成!共复制/更新 ${e} 个文件`),console.log(" 目标目录: "+o),void console.log(l)}else{let{activeToolName:e,activeProjectRoot:o,results:r}=detectEnvironment();c=r.find(o=>o.displayName===e);let n,i=(c&&".real"===c.dirName?n=o||path.join(os.homedir(),".real","workspace","openyida"):e?n=path.join(process.cwd(),"openyida"):(console.error("\n❌ 未检测到活跃的 AI 工具环境"),console.error(" 支持的工具:悟空、OpenCode、Claude Code、Aone Copilot、Cursor、Qoder、iFlow"),console.error("\n 当前检测结果:"),r.forEach(o=>{console.error(` ${o.isActive?"✅":"⬜"} `+o.displayName)}),console.error("\n 如需强制复制到当前目录,请运行:"),console.error(" yidacli copy --force"),process.exit(1)),console.log("🤖 当前 AI 工具: "+e),console.log(`📁 目标目录: ${n}
|
|
5
|
+
`),mergeCopyDir(s,n));console.log(`
|
|
6
|
+
`+l),console.log(`✅ 完成!共复制/更新 ${i} 个文件`),console.log(" 目标目录: "+n),console.log(l)}}module.exports={run:run};
|
package/dist/env.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
let fs=require("fs"),path=require("path"),os=require("os"),{loadCookieData,resolveBaseUrl,extractInfoFromCookies}=require("./utils"),home=os.homedir()
|
|
1
|
+
let fs=require("fs"),path=require("path"),os=require("os"),execSync=require("child_process").execSync,{loadCookieData,resolveBaseUrl,extractInfoFromCookies}=require("./utils"),home=os.homedir();function getParentProcessChain(){try{let o=process.pid;var s=[];for(let e=0;e<15;e++){var n=execSync(`ps -p ${o} -o pid=,ppid=,comm=`,{encoding:"utf8",stdio:["pipe","pipe","ignore"]}).trim();if(!n)break;var t=n.trim().split(/\s+/),c=t[1],r=t.slice(2).join(" ");if(s.push(r.toLowerCase()),"1"===c||c===o)break;o=c}return s.join("|")}catch{return""}}let _parentChainCache=null;function getParentChain(){return _parentChainCache=null===_parentChainCache?getParentProcessChain():_parentChainCache}let TOOL_DETECTORS=[{dirName:".real",displayName:"悟空(Wukong)",detectByProcess:e=>e.includes("dingtalkwukong")||e.includes("dingtalkreal"),detectByFiles:()=>!1},{dirName:".opencode",displayName:"OpenCode",detectByProcess:e=>e.includes("opencode"),detectByFiles:e=>fs.existsSync(path.join(e,".opencode","bun.lock"))},{dirName:".claudecode",displayName:"Claude Code",detectByProcess:e=>e.includes("claude"),detectByFiles:e=>fs.existsSync(path.join(e,".claudecode","settings.json"))||!!process.env.CLAUDE_CODE||!!process.env.ANTHROPIC_API_KEY},{dirName:".aone_copilot",displayName:"Aone Copilot",detectByProcess:(e,o)=>e.includes("visual studio code")&&fs.existsSync(path.join(o,".aone_copilot","hardware_id.txt")),detectByFiles:()=>!1},{dirName:".cursor",displayName:"Cursor",detectByProcess:e=>e.includes("cursor"),detectByFiles:()=>(process.env.VSCODE_GIT_ASKPASS_NODE||"").toLowerCase().includes("cursor")},{dirName:".qoder",displayName:"Qoder",detectByProcess:e=>e.includes("qoder"),detectByFiles:e=>fs.existsSync(path.join(e,".qoder",".config.json"))&&fs.existsSync(path.join(e,".qoder","agents"))},{dirName:".iflow",displayName:"iFlow",detectByProcess:e=>e.includes("iflow"),detectByFiles:e=>fs.existsSync(path.join(e,".iflow","aone_token.json"))||fs.existsSync(path.join(e,".iflow","installation_id"))}];function detectEnvironment(){var t=[];let c=getParentChain();var r=path.join(process.cwd(),"openyida");for(let{dirName:e,displayName:o,detectByProcess:s,detectByFiles:n}of TOOL_DETECTORS){var i,l,a,d=path.join(home,e);fs.existsSync(d)&&(a=".real"===e,i=(()=>{try{return s(c,home)}catch{return!1}})(),l=(()=>{try{return n(home)}catch{return!1}})(),l=i||l,a=a?path.join(d,"workspace","openyida"):r,d=fs.existsSync(a),t.push({displayName:o,dirName:e,isActive:l,byProcess:i,hasProject:d,workspaceRoot:a}))}let e=t.find(e=>e.byProcess&&".real"!==e.dirName);return{activeToolName:(e=(e=(e=e||t.find(e=>e.byProcess&&".real"===e.dirName))||t.find(e=>e.isActive&&".real"!==e.dirName))||t.find(e=>e.isActive&&".real"===e.dirName&&e.hasProject))?e.displayName:null,activeProjectRoot:e?e.workspaceRoot:null,results:t}}function detectLoginStatus(e){var o,s,n,e=loadCookieData(e);return e&&e.cookies?({csrfToken:o,corpId:s,userId:n}=extractInfoFromCookies(e.cookies),{loggedIn:!!o,csrfToken:o,corpId:s,userId:n,baseUrl:resolveBaseUrl(e)}):{loggedIn:!1,csrfToken:null,corpId:null,userId:null,baseUrl:null}}function run(){var e="=".repeat(55),{activeToolName:o,activeProjectRoot:s,results:n}=(console.log(e),console.log(" yidacli env - 环境检测"),console.log(e),console.log("\n📋 系统信息"),console.log(` 操作系统: ${process.platform} (${os.arch()})`),console.log(" Node.js: "+process.version),console.log(" 主目录: "+os.homedir()),console.log(" 工作目录: "+process.cwd()),console.log("\n🤖 AI 工具检测"),detectEnvironment());if(0===n.length)console.log(" ⚠️ 未检测到任何已知 AI 工具");else for(var{displayName:t,isActive:c,hasProject:r,workspaceRoot:i}of n){let e,o;o=c&&r?(e="✅","← 当前活跃,项目已就绪"):c&&!r?(e="🟡","← 当前活跃,但无 openyida 项目"):!c&&r?(e="⬜","(已安装,项目存在,但未活跃)"):(e="⬜","(已安装,未活跃)"),console.log(` ${e} ${t.padEnd(18)} `+o)}console.log("\n🎯 当前生效环境"),o&&s?(console.log(" AI 工具: "+o),console.log(" 项目根目录: "+s)):(0<(o=n.filter(e=>e.isActive)).length?console.log(` AI 工具: ${o.map(e=>e.displayName).join(", ")} (活跃,但无 openyida 项目)`):console.log(" AI 工具: 未检测到活跃工具"),console.log(` 项目根目录: ${process.cwd()} (fallback)`)),console.log("\n🔐 登录态检测");n=detectLoginStatus(s||process.cwd());n.loggedIn?(console.log(" 状态: ✅ 已登录"),console.log(" 域名: "+n.baseUrl),console.log(" 组织 ID: "+(n.corpId||"(未知)")),console.log(" 用户 ID: "+(n.userId||"(未知)")),console.log(` csrf_token: ${n.csrfToken.slice(0,16)}...`)):console.log(" 状态: ❌ 未登录(运行 yidacli login 进行登录)"),console.log("\n"+e)}module.exports={run:run,detectEnvironment:detectEnvironment,detectLoginStatus:detectLoginStatus};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openyida/yidacli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
4
4
|
"description": "宜搭 CLI 工具 - 宜搭平台应用、页面、表单的命令行管理工具",
|
|
5
5
|
"main": "bin/yidacli.js",
|
|
6
6
|
"bin": {
|
|
@@ -16,7 +16,6 @@
|
|
|
16
16
|
"build": "node scripts/build.js",
|
|
17
17
|
"prepublishOnly": "node scripts/build.js && node scripts/prepublish.js",
|
|
18
18
|
"postpublish": "node scripts/prepublish.js --cleanup",
|
|
19
|
-
"postinstall": "playwright install chromium && node scripts/postinstall.js",
|
|
20
19
|
"release": "npm version patch && npm publish",
|
|
21
20
|
"test": "jest --config tests/jest.config.js",
|
|
22
21
|
"test:unit": "jest --config tests/jest.config.js tests/unit",
|
package/scripts/postinstall.js
DELETED
|
@@ -1,126 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* postinstall.js - npm 安装后钩子
|
|
4
|
-
*
|
|
5
|
-
* 检测当前运行的 AI 工具环境,将 npm 包内的 openyida/ 目录
|
|
6
|
-
* 合并复制到对应目标目录下。
|
|
7
|
-
*
|
|
8
|
-
* 复制目标策略:
|
|
9
|
-
* - 悟空(Wukong):复制到 ~/.real/workspace/openyida(专属 workspace)
|
|
10
|
-
* - 其他 AI 工具:复制到当前工程目录(process.cwd())下的 openyida/
|
|
11
|
-
*
|
|
12
|
-
* 文件覆盖策略:
|
|
13
|
-
* - 已存在的文件:强制覆盖(更新到最新版本)
|
|
14
|
-
* - 目标目录中已有但源目录没有的文件:保留(不删除用户数据)
|
|
15
|
-
*
|
|
16
|
-
* AI 工具检测逻辑复用 dist/env.js 的 detectEnvironment,
|
|
17
|
-
* 避免与 src/env.js 中的 TOOL_DETECTORS 产生重复维护的风险。
|
|
18
|
-
*/
|
|
19
|
-
|
|
20
|
-
"use strict";
|
|
21
|
-
|
|
22
|
-
const fs = require("fs");
|
|
23
|
-
const path = require("path");
|
|
24
|
-
const os = require("os");
|
|
25
|
-
|
|
26
|
-
// npm 包内的 openyida 目录(由 prepublish 脚本拷贝进来)
|
|
27
|
-
const PACKAGE_OPENYIDA_DIR = path.resolve(__dirname, "..", "openyida");
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* 检测所有活跃的 AI 工具,返回其目标 openyida 目录列表。
|
|
31
|
-
*
|
|
32
|
-
* 复制策略:
|
|
33
|
-
* - 悟空(Wukong):复制到 ~/.real/workspace/openyida(专属 workspace)
|
|
34
|
-
* - 其他 AI 工具:复制到当前工程目录(process.cwd())下的 openyida/
|
|
35
|
-
*
|
|
36
|
-
* 复用 dist/env.js 的 detectEnvironment,避免重复维护 TOOL_DETECTORS。
|
|
37
|
-
*/
|
|
38
|
-
function detectActiveWorkspaces() {
|
|
39
|
-
// dist/env.js 由 prepublishOnly 构建产生,随 npm 包一起发布
|
|
40
|
-
const { detectEnvironment } = require("../dist/env");
|
|
41
|
-
const { results } = detectEnvironment();
|
|
42
|
-
|
|
43
|
-
const cwd = process.cwd();
|
|
44
|
-
|
|
45
|
-
return results
|
|
46
|
-
.filter((entry) => entry.isActive)
|
|
47
|
-
.map(({ displayName, dirName, workspaceRoot }) => {
|
|
48
|
-
const isWukong = dirName === ".real";
|
|
49
|
-
if (isWukong) {
|
|
50
|
-
// 悟空:使用专属 workspace 路径(workspaceRoot 已是 ~/.real/workspace/openyida)
|
|
51
|
-
return { displayName, destOpenyidaDir: workspaceRoot };
|
|
52
|
-
} else {
|
|
53
|
-
// 其他 AI 工具:复制到当前工程目录下的 openyida/
|
|
54
|
-
return { displayName, destOpenyidaDir: path.join(cwd, "openyida") };
|
|
55
|
-
}
|
|
56
|
-
});
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* 合并复制目录:
|
|
61
|
-
* - 源目录中的文件 → 强制覆盖到目标目录
|
|
62
|
-
* - 目标目录中已有但源目录没有的文件 → 保留不动
|
|
63
|
-
*/
|
|
64
|
-
function mergeCopyDir(sourceDir, destDir) {
|
|
65
|
-
if (!fs.existsSync(sourceDir)) return 0;
|
|
66
|
-
|
|
67
|
-
fs.mkdirSync(destDir, { recursive: true });
|
|
68
|
-
|
|
69
|
-
const entries = fs.readdirSync(sourceDir, { withFileTypes: true });
|
|
70
|
-
let copiedCount = 0;
|
|
71
|
-
|
|
72
|
-
for (const entry of entries) {
|
|
73
|
-
const sourcePath = path.join(sourceDir, entry.name);
|
|
74
|
-
const destPath = path.join(destDir, entry.name);
|
|
75
|
-
|
|
76
|
-
if (entry.isDirectory()) {
|
|
77
|
-
copiedCount += mergeCopyDir(sourcePath, destPath);
|
|
78
|
-
} else {
|
|
79
|
-
fs.copyFileSync(sourcePath, destPath);
|
|
80
|
-
console.log(` 覆盖: ${path.relative(os.homedir(), destPath)}`);
|
|
81
|
-
copiedCount++;
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
return copiedCount;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
function main() {
|
|
89
|
-
console.log("=".repeat(55));
|
|
90
|
-
console.log(" yidacli postinstall - 初始化 openyida 工作目录");
|
|
91
|
-
console.log("=".repeat(55));
|
|
92
|
-
|
|
93
|
-
// 检查 npm 包内是否有 openyida 目录
|
|
94
|
-
if (!fs.existsSync(PACKAGE_OPENYIDA_DIR)) {
|
|
95
|
-
console.log("\n⚠️ npm 包内未找到 openyida/ 目录,跳过初始化");
|
|
96
|
-
console.log(" (这是正常情况,如需初始化请手动运行 yidacli env)");
|
|
97
|
-
return;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
// 检测活跃的 AI 工具
|
|
101
|
-
const activeWorkspaces = detectActiveWorkspaces();
|
|
102
|
-
|
|
103
|
-
if (activeWorkspaces.length === 0) {
|
|
104
|
-
console.log("\n⚠️ 未检测到活跃的 AI 工具环境,跳过初始化");
|
|
105
|
-
console.log(" 支持的工具:悟空、OpenCode、Claude Code、Aone Copilot、Cursor、Qoder、iFlow");
|
|
106
|
-
return;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
console.log(`\n🤖 检测到 ${activeWorkspaces.length} 个活跃 AI 工具环境\n`);
|
|
110
|
-
|
|
111
|
-
let totalCopied = 0;
|
|
112
|
-
|
|
113
|
-
for (const { displayName, destOpenyidaDir } of activeWorkspaces) {
|
|
114
|
-
console.log(` 📁 ${displayName}`);
|
|
115
|
-
console.log(` 目标: ${destOpenyidaDir}`);
|
|
116
|
-
|
|
117
|
-
const copiedCount = mergeCopyDir(PACKAGE_OPENYIDA_DIR, destOpenyidaDir);
|
|
118
|
-
console.log(` ✅ 完成,共复制/更新 ${copiedCount} 个文件\n`);
|
|
119
|
-
totalCopied += copiedCount;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
console.log(`✅ 初始化完成,共处理 ${totalCopied} 个文件`);
|
|
123
|
-
console.log("=".repeat(55));
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
main();
|