@ghenya/clinn 0.7.12 → 0.7.14
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/Logos/StartLogo.txt +1 -1
- package/config.json +1 -1
- package/install.js +77 -82
- package/package.json +2 -1
package/Logos/StartLogo.txt
CHANGED
package/config.json
CHANGED
package/install.js
CHANGED
|
@@ -6,99 +6,71 @@ const fs = require("fs");
|
|
|
6
6
|
const path = require("path");
|
|
7
7
|
const { execSync } = require("child_process");
|
|
8
8
|
|
|
9
|
-
const VER = "0.7.
|
|
10
|
-
const
|
|
11
|
-
const CYAN = "\x1b[0;36m";
|
|
12
|
-
const YELLOW = "\x1b[0;33m";
|
|
13
|
-
const RED = "\x1b[0;31m";
|
|
14
|
-
const NC = "\x1b[0m";
|
|
15
|
-
const DIM = "\x1b[2m";
|
|
9
|
+
const VER = "0.7.14";
|
|
10
|
+
const G = "\x1b[0;32m", C = "\x1b[0;36m", Y = "\x1b[0;33m", R = "\x1b[0;31m", N = "\x1b[0m", D = "\x1b[2m";
|
|
16
11
|
|
|
17
12
|
const IS_WIN = process.platform === "win32";
|
|
18
|
-
const
|
|
13
|
+
const HOME = os.homedir();
|
|
14
|
+
const CLINN_HOME = path.join(HOME, ".clinn");
|
|
15
|
+
const CLINN_CONFIG = path.join(CLINN_HOME, "config.json");
|
|
19
16
|
|
|
20
17
|
function run(cmd, silent) {
|
|
21
|
-
try {
|
|
22
|
-
|
|
23
|
-
} catch (_) {
|
|
24
|
-
return "";
|
|
25
|
-
}
|
|
18
|
+
try { return execSync(cmd, { encoding: "utf-8", stdio: silent ? "pipe" : "inherit" }); }
|
|
19
|
+
catch (_) { return ""; }
|
|
26
20
|
}
|
|
27
21
|
|
|
28
22
|
function panic(msg) {
|
|
29
|
-
console.error(`${
|
|
23
|
+
console.error(`${R}${msg}${N}`);
|
|
30
24
|
process.exit(1);
|
|
31
25
|
}
|
|
32
26
|
|
|
33
27
|
console.log("");
|
|
34
|
-
console.log(` ${
|
|
35
|
-
console.log(` ${
|
|
36
|
-
console.log(` ${
|
|
28
|
+
console.log(` ${C}============================================${N}`);
|
|
29
|
+
console.log(` ${C} Clinn v${VER} — 安装中...${N}`);
|
|
30
|
+
console.log(` ${C}============================================${N}`);
|
|
37
31
|
console.log("");
|
|
38
32
|
|
|
39
|
-
try { run("node --version", true); } catch (_) { panic("Node.js
|
|
33
|
+
try { run("node --version", true); } catch (_) { panic("Node.js >= 18 required"); }
|
|
40
34
|
|
|
41
|
-
|
|
42
|
-
if (
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
35
|
+
function ensureClinnDir() {
|
|
36
|
+
if (!fs.existsSync(CLINN_HOME)) fs.mkdirSync(CLINN_HOME, { recursive: true });
|
|
37
|
+
const memDir = path.join(CLINN_HOME, "mem");
|
|
38
|
+
if (!fs.existsSync(memDir)) fs.mkdirSync(memDir, { recursive: true });
|
|
39
|
+
const toolsDir = path.join(CLINN_HOME, "Tools", "custom");
|
|
40
|
+
if (!fs.existsSync(toolsDir)) fs.mkdirSync(toolsDir, { recursive: true });
|
|
47
41
|
}
|
|
48
42
|
|
|
49
|
-
console.log(` ${DIM}目标目录: ${DEST}${NC}`);
|
|
50
|
-
|
|
51
43
|
let oldKey = "";
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
try {
|
|
55
|
-
oldKey = require(oldConfig).llm?.apiKey || "";
|
|
56
|
-
} catch (_) {}
|
|
44
|
+
if (fs.existsSync(CLINN_CONFIG)) {
|
|
45
|
+
try { oldKey = require(CLINN_CONFIG).llm?.apiKey || ""; } catch (_) {}
|
|
57
46
|
}
|
|
58
47
|
|
|
59
|
-
|
|
60
|
-
if (fs.existsSync(DEST)) fs.rmSync(DEST, { recursive: true, force: true });
|
|
61
|
-
if (!IS_WIN) {
|
|
62
|
-
for (const bin of ["/usr/local/bin/clinn", "/usr/bin/clinn", "/usr/local/sbin/clinn"]) {
|
|
63
|
-
try { fs.unlinkSync(bin); } catch (_) {}
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
function cleanShellRC() {
|
|
48
|
+
function cleanOldShellRC() {
|
|
68
49
|
if (IS_WIN) return;
|
|
69
|
-
const
|
|
70
|
-
|
|
71
|
-
for (const f of files) {
|
|
72
|
-
const p = path.join(home, f);
|
|
50
|
+
for (const f of [".bashrc", ".zshrc", ".bash_profile", ".profile"]) {
|
|
51
|
+
const p = path.join(HOME, f);
|
|
73
52
|
if (!fs.existsSync(p)) continue;
|
|
74
53
|
let content = fs.readFileSync(p, "utf-8");
|
|
75
|
-
const
|
|
76
|
-
|
|
54
|
+
const oldLen = content.split("\n").length;
|
|
55
|
+
content = content.split("\n").filter(l => !/clinn/i.test(l)).join("\n");
|
|
56
|
+
if (content.split("\n").length !== oldLen) fs.writeFileSync(p, content, "utf-8");
|
|
77
57
|
}
|
|
78
58
|
}
|
|
79
|
-
cleanShellRC();
|
|
80
|
-
|
|
81
|
-
console.log(` ${CYAN}正在复制文件...${NC}`);
|
|
82
|
-
const dirs = ["Src", "Tools", "Mem", "Logos", "bin"];
|
|
83
|
-
fs.mkdirSync(DEST, { recursive: true });
|
|
84
|
-
for (const d of dirs) {
|
|
85
|
-
const src = path.join(SRC, d);
|
|
86
|
-
if (fs.existsSync(src)) fs.cpSync(src, path.join(DEST, d), { recursive: true });
|
|
87
|
-
}
|
|
88
|
-
const cfgSrc = path.join(SRC, "config.json");
|
|
89
|
-
if (fs.existsSync(cfgSrc)) fs.copyFileSync(cfgSrc, path.join(DEST, "config.json"));
|
|
90
|
-
fs.mkdirSync(path.join(DEST, "Tools", "custom"), { recursive: true });
|
|
91
59
|
|
|
92
|
-
|
|
93
|
-
|
|
60
|
+
function getNpmBinDir() {
|
|
61
|
+
if (IS_WIN) {
|
|
62
|
+
return path.join(process.env.APPDATA || "", "npm");
|
|
63
|
+
}
|
|
94
64
|
try {
|
|
95
|
-
const
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
65
|
+
const prefix = execSync("npm config get prefix", { encoding: "utf-8" }).trim();
|
|
66
|
+
return path.join(prefix, "bin");
|
|
67
|
+
} catch (_) {
|
|
68
|
+
return "/usr/local/bin";
|
|
69
|
+
}
|
|
99
70
|
}
|
|
100
71
|
|
|
101
|
-
function
|
|
72
|
+
function ensureNpmBinInPATH() {
|
|
73
|
+
const npmBin = getNpmBinDir();
|
|
102
74
|
if (IS_WIN) {
|
|
103
75
|
const levels = ["User", "Machine"];
|
|
104
76
|
for (const level of levels) {
|
|
@@ -106,33 +78,56 @@ function updatePATH() {
|
|
|
106
78
|
try {
|
|
107
79
|
raw = execSync(`powershell -NoProfile -Command "[Environment]::GetEnvironmentVariable('Path', '${level}')"`, { encoding: "utf-8", windowsHide: true }).trim();
|
|
108
80
|
} catch (_) { continue; }
|
|
109
|
-
const
|
|
110
|
-
const
|
|
81
|
+
const norm = npmBin.toLowerCase().replace(/\//g, "\\");
|
|
82
|
+
const parts = raw.split(";").filter(p => {
|
|
83
|
+
const lo = p.toLowerCase().replace(/\//g, "\\");
|
|
84
|
+
return lo && !lo.includes("clinn") && !lo.includes("\\Clinn\\");
|
|
85
|
+
});
|
|
86
|
+
const has = parts.some(p => p.toLowerCase().replace(/\//g, "\\") === norm);
|
|
87
|
+
if (!has) parts.push(npmBin);
|
|
88
|
+
const clean = parts.join(";");
|
|
111
89
|
try {
|
|
112
90
|
execSync(`powershell -NoProfile -Command "[Environment]::SetEnvironmentVariable('Path', '${clean.replace(/\\/g, "\\\\")}', '${level}')"`, { windowsHide: true });
|
|
113
91
|
} catch (_) {}
|
|
114
92
|
}
|
|
93
|
+
console.log(` ${G}PATH 已注入:${N} ${D}${npmBin}${N}`);
|
|
115
94
|
} else {
|
|
116
|
-
const
|
|
117
|
-
const
|
|
118
|
-
|
|
119
|
-
|
|
95
|
+
const shellRC = process.env.SHELL?.includes("zsh") ? ".zshrc" : ".bashrc";
|
|
96
|
+
const rcPath = path.join(HOME, shellRC);
|
|
97
|
+
let content = "";
|
|
98
|
+
if (fs.existsSync(rcPath)) content = fs.readFileSync(rcPath, "utf-8");
|
|
99
|
+
const marker = "# npm global bin";
|
|
100
|
+
if (!content.includes(`export PATH="${npmBin}:$PATH"`) && !content.includes(npmBin)) {
|
|
101
|
+
content += `\n${marker}\nexport PATH="${npmBin}:$PATH"\n`;
|
|
102
|
+
fs.writeFileSync(rcPath, content, "utf-8");
|
|
103
|
+
console.log(` ${G}PATH 已注入:${N} ${D}${npmBin} → ${rcPath}${N}`);
|
|
104
|
+
}
|
|
120
105
|
}
|
|
121
106
|
}
|
|
122
|
-
updatePATH();
|
|
123
107
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
108
|
+
cleanOldShellRC();
|
|
109
|
+
ensureNpmBinInPATH();
|
|
110
|
+
|
|
111
|
+
ensureClinnDir();
|
|
112
|
+
|
|
113
|
+
if (!fs.existsSync(CLINN_CONFIG)) {
|
|
114
|
+
const pkgCfg = path.join(__dirname, "config.json");
|
|
115
|
+
if (fs.existsSync(pkgCfg)) {
|
|
116
|
+
const cfg = JSON.parse(fs.readFileSync(pkgCfg, "utf-8"));
|
|
117
|
+
if (oldKey && oldKey !== "YOUR_API_KEY" && oldKey !== "YOUR_DEEPSEEK_API_KEY_HERE") {
|
|
118
|
+
cfg.llm.apiKey = oldKey;
|
|
119
|
+
}
|
|
120
|
+
fs.writeFileSync(CLINN_CONFIG, JSON.stringify(cfg, null, 2), "utf-8");
|
|
121
|
+
console.log(` ${G}配置文件已创建:${N} ${D}${CLINN_CONFIG}${N}`);
|
|
122
|
+
}
|
|
127
123
|
}
|
|
128
124
|
|
|
129
125
|
console.log("");
|
|
130
|
-
console.log(` ${
|
|
131
|
-
console.log(` ${
|
|
132
|
-
console.log(` ${
|
|
126
|
+
console.log(` ${G}============================================${N}`);
|
|
127
|
+
console.log(` ${G} 安装完成! 打开新终端输入 clinn 即可启动${N}`);
|
|
128
|
+
console.log(` ${G}============================================${N}`);
|
|
133
129
|
console.log("");
|
|
134
|
-
console.log(`
|
|
135
|
-
console.log(`
|
|
136
|
-
console.log(`
|
|
137
|
-
console.log(` 卸载: ${CYAN}${IS_WIN ? `rmdir /s /q "${DEST}"` : `sudo rm -rf ${DEST} /usr/local/bin/clinn`}${NC}`);
|
|
130
|
+
console.log(` 版本: ${C}clinn --version${N}`);
|
|
131
|
+
console.log(` 配置: ${C}${CLINN_CONFIG}${N}`);
|
|
132
|
+
console.log(` 设置Key: ${C}clinn → /api key <你的Key>${N}`);
|
|
138
133
|
console.log("");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ghenya/clinn",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.14",
|
|
4
4
|
"description": "终端原生 AI 编程助手 — DeepSeek 驱动,50+ 工具,对话记忆,虚拟浏览器",
|
|
5
5
|
"main": "Src/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
"install.bat"
|
|
20
20
|
],
|
|
21
21
|
"scripts": {
|
|
22
|
+
"postinstall": "node install.js",
|
|
22
23
|
"start": "node Src/index.js",
|
|
23
24
|
"lint": "node --check Src/index.js && node --check Src/agent.js && node --check Src/llm.js && node --check Tools/index.js && node --check Tools/extended_tools.js && node --check Tools/search_tools.js && node --check Tools/browser.js && node --check Mem/index.js && node --check Mem/history.js"
|
|
24
25
|
},
|