noiton 2.0.1 → 2.0.3
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 +2 -12
- package/package.json +2 -7
- package/src/commands/change.js +2 -2
- package/src/commands/init.js +3 -2
- package/src/commands/refresh.js +2 -2
- package/src/commands/remove.js +2 -2
- package/src/commands/status.js +2 -2
- package/src/index.js +0 -5
- package/src/lib/agents/hermes.js +20 -1
- package/src/lib/agents/index.js +42 -12
- package/src/lib/agents/opencode.js +19 -1
- package/src/lib/detect.js +47 -107
- package/src/lib/install.js +0 -2
- package/src/octopus.js +62 -212
- package/src/ui.js +2 -23
- package/src/lib/agents/aider.js +0 -141
- package/src/lib/agents/cline.js +0 -128
- package/src/lib/agents/kilo.js +0 -140
- package/src/lib/agents/kimi.js +0 -149
- package/src/lib/agents/openclaw.js +0 -155
package/src/octopus.js
CHANGED
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* NOITON
|
|
2
|
+
* NOITON Banner - Clean OpenCode-style design
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
* -
|
|
6
|
-
* -
|
|
7
|
-
* -
|
|
8
|
-
* -
|
|
4
|
+
* Features:
|
|
5
|
+
* - Big 🐙 emoji prominently displayed
|
|
6
|
+
* - Large "NOITON" wordmark in figlet (ANSI Shadow)
|
|
7
|
+
* - Clean subtitle line
|
|
8
|
+
* - No more ASCII art octopus
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
+
import figlet from "figlet";
|
|
11
12
|
import gradient from "gradient-string";
|
|
13
|
+
import { VERSION, c } from "./constants.js";
|
|
12
14
|
|
|
13
|
-
// NOITON brand gradient
|
|
15
|
+
// NOITON brand gradient (purple → magenta → cyan)
|
|
14
16
|
const brandGradient = gradient([
|
|
15
17
|
"#A78BFA", // light purple
|
|
16
18
|
"#C084FC", // purple
|
|
@@ -22,229 +24,77 @@ const brandGradient = gradient([
|
|
|
22
24
|
const successGradient = gradient(["#34D399", "#22D3EE", "#A78BFA"]);
|
|
23
25
|
const errorGradient = gradient(["#F87171", "#EF4444"]);
|
|
24
26
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
╭┘ ╰┐
|
|
42
|
-
╭┘ ♥ ✦ ♥ ╰┐
|
|
43
|
-
│ │
|
|
44
|
-
╰╮ ╭╯
|
|
45
|
-
╰╮ ✦ ♥ ╭╯
|
|
46
|
-
╰╮ ╭╯
|
|
47
|
-
╰─✦───♥─✦─╯
|
|
48
|
-
`);
|
|
27
|
+
// Cache the figlet rendering for performance
|
|
28
|
+
let cachedFiglet = null;
|
|
29
|
+
function getFiglet() {
|
|
30
|
+
if (!cachedFiglet) {
|
|
31
|
+
try {
|
|
32
|
+
cachedFiglet = figlet.textSync("NOITON", {
|
|
33
|
+
font: "ANSI Shadow",
|
|
34
|
+
width: 80,
|
|
35
|
+
whitespaceBreak: true,
|
|
36
|
+
});
|
|
37
|
+
} catch {
|
|
38
|
+
// Fallback if figlet fails
|
|
39
|
+
cachedFiglet = `N O I T O N`;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return cachedFiglet;
|
|
49
43
|
}
|
|
50
44
|
|
|
51
45
|
/**
|
|
52
|
-
*
|
|
46
|
+
* Print the big NOITON banner with octopus emoji.
|
|
47
|
+
* OpenCode-style: big emoji + big text + subtitle
|
|
53
48
|
*/
|
|
54
|
-
export function
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
╲_______╱
|
|
60
|
-
╭╯ ╰╮
|
|
61
|
-
╭┘ ◠ ◠ ╰┐
|
|
62
|
-
╰╮ ♥ ╭╯
|
|
63
|
-
╰───╯
|
|
64
|
-
`);
|
|
65
|
-
}
|
|
49
|
+
export function printBanner() {
|
|
50
|
+
console.log();
|
|
51
|
+
// Big octopus emoji on its own line, centered
|
|
52
|
+
console.log(c.cyan(" 🐙"));
|
|
53
|
+
console.log();
|
|
66
54
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
*/
|
|
70
|
-
export function octopusCurious() {
|
|
71
|
-
return brandGradient.multiline(`
|
|
72
|
-
╭━━━━━━━━━╮
|
|
73
|
-
╱ ╲
|
|
74
|
-
│ ? ? │
|
|
75
|
-
│ ◡ │
|
|
76
|
-
╲___________╱
|
|
77
|
-
│ ╲___╱ │
|
|
78
|
-
╭┤ ├╮
|
|
79
|
-
╭┘╰┐ ╭━┘╰┐
|
|
80
|
-
╭┘ ╰╮ ╭┘ ╰┐
|
|
81
|
-
╭┘ ╰━╯ ╰┐
|
|
82
|
-
╭┘ ╰┐
|
|
83
|
-
╭┘ ? ? ? ╰┐
|
|
84
|
-
│ │
|
|
85
|
-
╰╮ ╭╯
|
|
86
|
-
╰╮ ╭╯
|
|
87
|
-
╰╮ ? ? ╭╯
|
|
88
|
-
╰───────────╯
|
|
89
|
-
`);
|
|
90
|
-
}
|
|
55
|
+
// Big NOITON wordmark with gradient
|
|
56
|
+
console.log(brandGradient.multiline(getFiglet()));
|
|
91
57
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
│ @ @ │
|
|
100
|
-
│ ▬ │
|
|
101
|
-
╲___________╱
|
|
102
|
-
│ ╲___╱ │
|
|
103
|
-
╭┤ ├╮
|
|
104
|
-
╭┘╰┐ ╭━┘╰┐
|
|
105
|
-
╭┘ ╰╮ ╭┘ ╰┐
|
|
106
|
-
╭┘ ◠ ╰━╯ ◠ ╰┐
|
|
107
|
-
╭┘ ⚙ ╰┐
|
|
108
|
-
╭┘ ⚙ ⚙ ⚙ ╰┐
|
|
109
|
-
│ ⚙ ⚙ │
|
|
110
|
-
╰╮ ⚙ ⚙ ╭╯
|
|
111
|
-
╰╮ ╭╯
|
|
112
|
-
╰╮──⚙───⚙──⚙─╭╯
|
|
113
|
-
╰───────────╯
|
|
114
|
-
`);
|
|
58
|
+
// Subtitle line
|
|
59
|
+
console.log(
|
|
60
|
+
" " +
|
|
61
|
+
c.bold(c.white("🐙 Universal AI Agent Connector")) +
|
|
62
|
+
c.dim(` · v${VERSION}`)
|
|
63
|
+
);
|
|
64
|
+
console.log();
|
|
115
65
|
}
|
|
116
66
|
|
|
117
67
|
/**
|
|
118
|
-
*
|
|
68
|
+
* Smaller success banner (used at end of init flow)
|
|
119
69
|
*/
|
|
120
|
-
export function
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
╭━━━╭┘ ╰╮ ╭┘ ╰┐━━━╮
|
|
131
|
-
╭━━━╭┘ ◠ ╰━╯ ◠ ╰┐━━━╮
|
|
132
|
-
╭━━━╭┘ ╰┐━━━╮
|
|
133
|
-
╭━━━╭┘ ♥ ★ ♥ ╰┐━━━╮
|
|
134
|
-
│ │
|
|
135
|
-
╰╮ ★ ♥ ★ ♥ ╭╯
|
|
136
|
-
╰╮ ╭╯
|
|
137
|
-
★ ╰╮ ♥ ★ ♥ ╭╯ ★
|
|
138
|
-
╰─★──♥───★──♥──★╯
|
|
139
|
-
♪ ♥ ♪
|
|
140
|
-
`);
|
|
70
|
+
export function successBanner() {
|
|
71
|
+
console.log();
|
|
72
|
+
console.log(c.green(" 🐙"));
|
|
73
|
+
console.log();
|
|
74
|
+
console.log(successGradient.multiline(getFiglet()));
|
|
75
|
+
console.log(
|
|
76
|
+
" " +
|
|
77
|
+
c.bold(c.green("✨ Tudo conectado! ✨"))
|
|
78
|
+
);
|
|
79
|
+
console.log();
|
|
141
80
|
}
|
|
142
81
|
|
|
143
82
|
/**
|
|
144
|
-
* Sad
|
|
83
|
+
* Sad/small banner
|
|
145
84
|
*/
|
|
146
|
-
export function
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
╲___________╱
|
|
153
|
-
│ ╲___╱ │
|
|
154
|
-
╭┤ ├╮
|
|
155
|
-
╭┘╰┐ ╭━┘╰┐
|
|
156
|
-
╭━┘ ╰╮ ╭┘ ╰━╗
|
|
157
|
-
╭┘ ╰━╯ ╰┐
|
|
158
|
-
╭┘ ╰┐
|
|
159
|
-
│ │
|
|
160
|
-
╰╮ ╭╯
|
|
161
|
-
╰╮ ╭╯
|
|
162
|
-
╰╮ ╭╯
|
|
163
|
-
╰╮ ╭╯
|
|
164
|
-
╰──────╯
|
|
165
|
-
`);
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
/**
|
|
169
|
-
* Sleeping octopus - zzz floating
|
|
170
|
-
*/
|
|
171
|
-
export function octopusSleeping() {
|
|
172
|
-
return brandGradient.multiline(`
|
|
173
|
-
╭━━━━━━━━━╮
|
|
174
|
-
╱ ╲
|
|
175
|
-
│ - - │
|
|
176
|
-
│ ▬ │
|
|
177
|
-
╲___________╱ z
|
|
178
|
-
│ ╲___╱ │ zZ
|
|
179
|
-
╭┤ ├╮ zZZ
|
|
180
|
-
╭┘╰┐ ╭━┘╰┐
|
|
181
|
-
╭┘ ╰╮ ╭┘ ╰┐
|
|
182
|
-
╭┘ ╰━╯ ╰┐
|
|
183
|
-
╭┘ z ╰┐
|
|
184
|
-
╭┘ zZ ╰┐
|
|
185
|
-
│ zZZ │
|
|
186
|
-
╰╮ ╭╯
|
|
187
|
-
╰╮ ╭╯
|
|
188
|
-
╰──────────────╯
|
|
189
|
-
`);
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
/**
|
|
193
|
-
* Coding octopus - typing on keyboard
|
|
194
|
-
*/
|
|
195
|
-
export function octopusCoding() {
|
|
196
|
-
return brandGradient.multiline(`
|
|
197
|
-
╭━━━━━━━━━╮
|
|
198
|
-
╱ ╲
|
|
199
|
-
│ ◉ ◉ │
|
|
200
|
-
│ ◡ │
|
|
201
|
-
╲___________╱
|
|
202
|
-
│ ╲___╱ │
|
|
203
|
-
╭┤ ├╮
|
|
204
|
-
╭───╭┘╰┐ ╭━┘╰┐───╮
|
|
205
|
-
╭┘ ╭┘ ╰╮ ╭┘ ╰┐ ╰┐
|
|
206
|
-
╭┘ ╭┘ ◠ ╰━╯ ◠ ╰┐ ╰┐
|
|
207
|
-
╭┘ ╭┘ ╰┐ ╰┐
|
|
208
|
-
╭┘ ╭┘ ╰┐ ╰┐
|
|
209
|
-
│ │ [ / / / / ] │ │
|
|
210
|
-
╰╮ ╰╮ ╭╯ ╭╯
|
|
211
|
-
╰╮ ╰╮ ▓▓▓▓▓▓▓ ╭╯ ╭╯
|
|
212
|
-
╰╮ ╰╮ ╭╯ ╭╯
|
|
213
|
-
╰╮╰──────────╯ ╭╯
|
|
214
|
-
╰╮ ▓▓ ╭╯
|
|
215
|
-
╰──────────╯
|
|
216
|
-
`);
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
/**
|
|
220
|
-
* NOITON wordmark logo with small octopus on top
|
|
221
|
-
*/
|
|
222
|
-
export function octopusLogo() {
|
|
223
|
-
return brandGradient.multiline(`
|
|
224
|
-
╭━━━━━╮
|
|
225
|
-
╱ ◉ ◉ ╲
|
|
226
|
-
│ ◡ │
|
|
227
|
-
╲_______╱
|
|
228
|
-
╭╯ ╰╮
|
|
229
|
-
╭┘ ◠ ◠ ╰┐
|
|
230
|
-
╰╮ ♥ ╭╯
|
|
231
|
-
╰───╯
|
|
232
|
-
|
|
233
|
-
███╗ ██╗ ██████╗ ██╗████████╗ ██████╗ ███╗ ██╗
|
|
234
|
-
████╗ ██║██╔═══██╗██║╚══██╔══╝██╔═══██╗████╗ ██║
|
|
235
|
-
██╔██╗ ██║██║ ██║██║ ██║ ██║ ██║██╔██╗ ██║
|
|
236
|
-
██║╚██╗██║██║ ██║██║ ██║ ██║ ██║██║╚██╗██║
|
|
237
|
-
██║ ╚████║╚██████╔╝██║ ██║ ╚██████╔╝██║ ╚████║
|
|
238
|
-
╚═╝ ╚═══╝ ╚═════╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═══╝
|
|
239
|
-
`);
|
|
85
|
+
export function errorBanner() {
|
|
86
|
+
console.log();
|
|
87
|
+
console.log(c.red(" 🐙"));
|
|
88
|
+
console.log();
|
|
89
|
+
console.log(errorGradient.multiline(getFiglet()));
|
|
90
|
+
console.log();
|
|
240
91
|
}
|
|
241
92
|
|
|
242
93
|
/**
|
|
243
|
-
* Get
|
|
94
|
+
* Get just the big octopus emoji (for inline use)
|
|
244
95
|
*/
|
|
245
|
-
export function
|
|
246
|
-
|
|
247
|
-
return poses[Math.floor(Math.random() * poses.length)]();
|
|
96
|
+
export function bigOctopus() {
|
|
97
|
+
return c.cyan("🐙");
|
|
248
98
|
}
|
|
249
99
|
|
|
250
100
|
export {
|
package/src/ui.js
CHANGED
|
@@ -9,30 +9,9 @@ import picocolors from "picocolors";
|
|
|
9
9
|
import ora from "ora";
|
|
10
10
|
import boxen from "boxen";
|
|
11
11
|
import { VERSION, c } from "./constants.js";
|
|
12
|
-
import {
|
|
12
|
+
import { printBanner, successBanner, errorBanner, bigOctopus, brandGradient } from "./octopus.js";
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Print the main NOITON banner with octopus mascot.
|
|
18
|
-
* @param {"happy"|"curious"|"dancing"|"sad"|"sleeping"|"working"} mood
|
|
19
|
-
*/
|
|
20
|
-
export function printBanner(mood = "happy") {
|
|
21
|
-
const octopus = {
|
|
22
|
-
happy: octopusHappy,
|
|
23
|
-
curious: octopusCurious,
|
|
24
|
-
dancing: octopusDancing,
|
|
25
|
-
sad: octopusSad,
|
|
26
|
-
sleeping: octopusSleeping,
|
|
27
|
-
working: octopusWorking,
|
|
28
|
-
}[mood] || octopusHappy;
|
|
29
|
-
|
|
30
|
-
console.log();
|
|
31
|
-
console.log(octopus());
|
|
32
|
-
console.log(brandGradient(` N O I T O N v${VERSION}`));
|
|
33
|
-
console.log(c.dim(` 🐙 Universal AI Agent Connector 🐙`));
|
|
34
|
-
console.log();
|
|
35
|
-
}
|
|
14
|
+
export { printBanner, successBanner, errorBanner, bigOctopus, brandGradient };
|
|
36
15
|
|
|
37
16
|
// ============= BOXES =============
|
|
38
17
|
|
package/src/lib/agents/aider.js
DELETED
|
@@ -1,141 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Aider Agent Adapter
|
|
3
|
-
*
|
|
4
|
-
* Config: ~/.aider.conf.yml (YAML) + env vars
|
|
5
|
-
* Format:
|
|
6
|
-
* openai-api-base: <BASE_URL>
|
|
7
|
-
* model: <model-id>
|
|
8
|
-
* .env: OPENAI_API_KEY=<key>
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
import { readFileSync, writeFileSync, existsSync, mkdirSync } from "node:fs";
|
|
12
|
-
import { join, dirname } from "node:path";
|
|
13
|
-
import { homedir } from "node:os";
|
|
14
|
-
import YAML from "yaml";
|
|
15
|
-
import { BASE_URL } from "../../constants.js";
|
|
16
|
-
|
|
17
|
-
const HOME = homedir();
|
|
18
|
-
const CONFIG_PATH = join(HOME, ".aider.conf.yml");
|
|
19
|
-
const ENV_PATH = join(HOME, ".env");
|
|
20
|
-
|
|
21
|
-
function readYaml() {
|
|
22
|
-
if (!existsSync(CONFIG_PATH)) return { config: {}, path: CONFIG_PATH };
|
|
23
|
-
try {
|
|
24
|
-
const raw = readFileSync(CONFIG_PATH, "utf8");
|
|
25
|
-
return { config: YAML.parse(raw) || {}, path: CONFIG_PATH };
|
|
26
|
-
} catch {
|
|
27
|
-
return { config: {}, path: CONFIG_PATH };
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
function writeYaml(config) {
|
|
32
|
-
if (!existsSync(dirname(CONFIG_PATH))) {
|
|
33
|
-
mkdirSync(dirname(CONFIG_PATH), { recursive: true });
|
|
34
|
-
}
|
|
35
|
-
writeFileSync(CONFIG_PATH, YAML.stringify(config, { indent: 2 }), "utf8");
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
function readEnvFile() {
|
|
39
|
-
if (!existsSync(ENV_PATH)) return {};
|
|
40
|
-
const raw = readFileSync(ENV_PATH, "utf8");
|
|
41
|
-
const env = {};
|
|
42
|
-
for (const line of raw.split("\n")) {
|
|
43
|
-
const m = line.match(/^([A-Z_][A-Z0-9_]*)=(.*)$/);
|
|
44
|
-
if (m) env[m[1]] = m[2];
|
|
45
|
-
}
|
|
46
|
-
return env;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
function writeEnvFile(env) {
|
|
50
|
-
const lines = Object.entries(env).map(([k, v]) => `${k}=${v}`);
|
|
51
|
-
writeFileSync(ENV_PATH, lines.join("\n") + "\n", "utf8");
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
// ============= ADAPTER INTERFACE =============
|
|
55
|
-
|
|
56
|
-
export const aiderAgent = {
|
|
57
|
-
id: "aider",
|
|
58
|
-
name: "Aider",
|
|
59
|
-
supportsMultipleModels: false,
|
|
60
|
-
|
|
61
|
-
detect() {
|
|
62
|
-
return existsSync(CONFIG_PATH);
|
|
63
|
-
},
|
|
64
|
-
|
|
65
|
-
isConfigured() {
|
|
66
|
-
const { config } = readYaml();
|
|
67
|
-
return Boolean(config?.["openai-api-base"] === BASE_URL);
|
|
68
|
-
},
|
|
69
|
-
|
|
70
|
-
getStatus() {
|
|
71
|
-
const { config, path } = readYaml();
|
|
72
|
-
const env = readEnvFile();
|
|
73
|
-
const apiKey = env.OPENAI_API_KEY;
|
|
74
|
-
const configured = config?.["openai-api-base"] === BASE_URL;
|
|
75
|
-
const models = config?.model ? [config.model] : [];
|
|
76
|
-
return {
|
|
77
|
-
configured,
|
|
78
|
-
path,
|
|
79
|
-
models,
|
|
80
|
-
apiKey: apiKey ? `${apiKey.slice(0, 6)}...${apiKey.slice(-4)}` : null,
|
|
81
|
-
envPath: ENV_PATH,
|
|
82
|
-
};
|
|
83
|
-
},
|
|
84
|
-
|
|
85
|
-
configure({ apiKey, models, primaryModel }) {
|
|
86
|
-
const { config } = readYaml();
|
|
87
|
-
config["openai-api-base"] = `${BASE_URL}/v1`;
|
|
88
|
-
config.model = primaryModel || models[0]?.id || "gpt-4";
|
|
89
|
-
config["weak-model"] = primaryModel || models[0]?.id || "gpt-4";
|
|
90
|
-
writeYaml(config);
|
|
91
|
-
|
|
92
|
-
// Set API key in .env
|
|
93
|
-
const env = readEnvFile();
|
|
94
|
-
env.OPENAI_API_KEY = apiKey;
|
|
95
|
-
writeEnvFile(env);
|
|
96
|
-
|
|
97
|
-
return { path: CONFIG_PATH, envPath: ENV_PATH, modelsCount: 1 };
|
|
98
|
-
},
|
|
99
|
-
|
|
100
|
-
changeKey(apiKey) {
|
|
101
|
-
if (!this.isConfigured()) {
|
|
102
|
-
throw new Error("NOITON não está configurado no Aider");
|
|
103
|
-
}
|
|
104
|
-
const env = readEnvFile();
|
|
105
|
-
env.OPENAI_API_KEY = apiKey;
|
|
106
|
-
writeEnvFile(env);
|
|
107
|
-
return { path: ENV_PATH };
|
|
108
|
-
},
|
|
109
|
-
|
|
110
|
-
refresh(models) {
|
|
111
|
-
const { config } = readYaml();
|
|
112
|
-
if (!config?.["openai-api-base"]) {
|
|
113
|
-
throw new Error("NOITON não está configurado no Aider");
|
|
114
|
-
}
|
|
115
|
-
if (models.length > 0) {
|
|
116
|
-
config.model = models[0].id;
|
|
117
|
-
config["weak-model"] = models[0].id;
|
|
118
|
-
}
|
|
119
|
-
writeYaml(config);
|
|
120
|
-
return { path: CONFIG_PATH, modelsCount: 1 };
|
|
121
|
-
},
|
|
122
|
-
|
|
123
|
-
remove() {
|
|
124
|
-
const { config } = readYaml();
|
|
125
|
-
let removed = false;
|
|
126
|
-
if (config?.["openai-api-base"] === BASE_URL) {
|
|
127
|
-
delete config["openai-api-base"];
|
|
128
|
-
delete config.model;
|
|
129
|
-
delete config["weak-model"];
|
|
130
|
-
removed = true;
|
|
131
|
-
writeYaml(config);
|
|
132
|
-
}
|
|
133
|
-
const env = readEnvFile();
|
|
134
|
-
if (env.OPENAI_API_KEY) {
|
|
135
|
-
delete env.OPENAI_API_KEY;
|
|
136
|
-
writeEnvFile(env);
|
|
137
|
-
removed = true;
|
|
138
|
-
}
|
|
139
|
-
return { path: CONFIG_PATH, envPath: ENV_PATH, removed };
|
|
140
|
-
},
|
|
141
|
-
};
|
package/src/lib/agents/cline.js
DELETED
|
@@ -1,128 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Cline Agent Adapter
|
|
3
|
-
*
|
|
4
|
-
* Config: VS Code settings.json with cline config block.
|
|
5
|
-
* Format (under `cline` key):
|
|
6
|
-
* "cline.provider": "openai",
|
|
7
|
-
* "cline.openAiBaseUrl": "<BASE_URL>",
|
|
8
|
-
* "cline.openAiApiKey": "<key>",
|
|
9
|
-
* "cline.openAiModelId": "<model>"
|
|
10
|
-
*
|
|
11
|
-
* VS Code stores multiple providers via cline.provider entries.
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
import { readFileSync, writeFileSync, existsSync, mkdirSync } from "node:fs";
|
|
15
|
-
import { join, dirname } from "node:path";
|
|
16
|
-
import { homedir } from "node:os";
|
|
17
|
-
import JSON5 from "json5";
|
|
18
|
-
import { BASE_URL, PROVIDER_ID } from "../../constants.js";
|
|
19
|
-
|
|
20
|
-
const HOME = homedir();
|
|
21
|
-
const XDG = process.env.XDG_CONFIG_HOME || join(HOME, ".config");
|
|
22
|
-
const CONFIG_PATH = join(XDG, "Code", "User", "settings.json");
|
|
23
|
-
|
|
24
|
-
function readConfig() {
|
|
25
|
-
if (!existsSync(CONFIG_PATH)) return { config: {}, path: CONFIG_PATH };
|
|
26
|
-
try {
|
|
27
|
-
// VS Code settings support JSON with comments (JSONC)
|
|
28
|
-
const raw = readFileSync(CONFIG_PATH, "utf8");
|
|
29
|
-
const cleaned = raw.replace(/\/\/.*$/gm, "").replace(/\/\*[\s\S]*?\*\//g, "");
|
|
30
|
-
return { config: JSON5.parse(cleaned), path: CONFIG_PATH };
|
|
31
|
-
} catch {
|
|
32
|
-
return { config: {}, path: CONFIG_PATH };
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
function writeConfig(config) {
|
|
37
|
-
if (!existsSync(dirname(CONFIG_PATH))) {
|
|
38
|
-
mkdirSync(dirname(dirname(CONFIG_PATH)), { recursive: true });
|
|
39
|
-
}
|
|
40
|
-
writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2) + "\n", "utf8");
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
// ============= ADAPTER INTERFACE =============
|
|
44
|
-
|
|
45
|
-
export const clineAgent = {
|
|
46
|
-
id: "cline",
|
|
47
|
-
name: "Cline",
|
|
48
|
-
supportsMultipleModels: true,
|
|
49
|
-
|
|
50
|
-
detect() {
|
|
51
|
-
return existsSync(CONFIG_PATH);
|
|
52
|
-
},
|
|
53
|
-
|
|
54
|
-
isConfigured() {
|
|
55
|
-
const { config } = readConfig();
|
|
56
|
-
const result = Boolean(
|
|
57
|
-
config?.["cline.openAiBaseUrl"] === BASE_URL ||
|
|
58
|
-
config?.["cline.apiProvider"] === "openai" && config?.["cline.openAiApiKey"]
|
|
59
|
-
);
|
|
60
|
-
return result;
|
|
61
|
-
},
|
|
62
|
-
|
|
63
|
-
getStatus() {
|
|
64
|
-
const { config, path } = readConfig();
|
|
65
|
-
const baseUrl = config?.["cline.openAiBaseUrl"];
|
|
66
|
-
const apiKey = config?.["cline.openAiApiKey"];
|
|
67
|
-
const modelId = config?.["cline.openAiModelId"];
|
|
68
|
-
const configured = Boolean(baseUrl === BASE_URL || (apiKey && baseUrl));
|
|
69
|
-
|
|
70
|
-
const models = modelId ? [modelId] : [];
|
|
71
|
-
|
|
72
|
-
return {
|
|
73
|
-
configured,
|
|
74
|
-
path,
|
|
75
|
-
models,
|
|
76
|
-
apiKey: apiKey ? `${apiKey.slice(0, 6)}...${apiKey.slice(-4)}` : null,
|
|
77
|
-
};
|
|
78
|
-
},
|
|
79
|
-
|
|
80
|
-
configure({ apiKey, models, primaryModel }) {
|
|
81
|
-
const { config } = readConfig();
|
|
82
|
-
config["cline.apiProvider"] = "openai";
|
|
83
|
-
config["cline.openAiBaseUrl"] = `${BASE_URL}/v1`;
|
|
84
|
-
config["cline.openAiApiKey"] = apiKey;
|
|
85
|
-
config["cline.openAiModelId"] = primaryModel || models[0]?.id;
|
|
86
|
-
// Save list of available models as a JSON array string
|
|
87
|
-
config["cline.noitonModels"] = JSON.stringify(models.map((m) => m.id));
|
|
88
|
-
writeConfig(config);
|
|
89
|
-
return { path: CONFIG_PATH, modelsCount: 1 };
|
|
90
|
-
},
|
|
91
|
-
|
|
92
|
-
changeKey(apiKey) {
|
|
93
|
-
const { config } = readConfig();
|
|
94
|
-
if (!config?.["cline.openAiApiKey"]) {
|
|
95
|
-
throw new Error("NOITON não está configurado no Cline");
|
|
96
|
-
}
|
|
97
|
-
config["cline.openAiApiKey"] = apiKey;
|
|
98
|
-
writeConfig(config);
|
|
99
|
-
return { path: CONFIG_PATH };
|
|
100
|
-
},
|
|
101
|
-
|
|
102
|
-
refresh(models) {
|
|
103
|
-
const { config } = readConfig();
|
|
104
|
-
if (!config?.["cline.openAiBaseUrl"]) {
|
|
105
|
-
throw new Error("NOITON não está configurado no Cline");
|
|
106
|
-
}
|
|
107
|
-
config["cline.openAiModelId"] = models[0]?.id || config["cline.openAiModelId"];
|
|
108
|
-
config["cline.noitonModels"] = JSON.stringify(models.map((m) => m.id));
|
|
109
|
-
writeConfig(config);
|
|
110
|
-
return { path: CONFIG_PATH, modelsCount: 1 };
|
|
111
|
-
},
|
|
112
|
-
|
|
113
|
-
remove() {
|
|
114
|
-
const { config } = readConfig();
|
|
115
|
-
let removed = false;
|
|
116
|
-
if (config?.["cline.openAiBaseUrl"] === BASE_URL ||
|
|
117
|
-
config?.["cline.openAiApiKey"]) {
|
|
118
|
-
delete config["cline.apiProvider"];
|
|
119
|
-
delete config["cline.openAiBaseUrl"];
|
|
120
|
-
delete config["cline.openAiApiKey"];
|
|
121
|
-
delete config["cline.openAiModelId"];
|
|
122
|
-
delete config["cline.noitonModels"];
|
|
123
|
-
removed = true;
|
|
124
|
-
}
|
|
125
|
-
if (removed) writeConfig(config);
|
|
126
|
-
return { path: CONFIG_PATH, removed };
|
|
127
|
-
},
|
|
128
|
-
};
|