noiton 1.0.0 → 2.0.1
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 +46 -31
- package/package.json +25 -8
- package/src/commands/change.js +44 -54
- package/src/commands/init.js +317 -42
- package/src/commands/refresh.js +59 -47
- package/src/commands/remove.js +46 -22
- package/src/commands/status.js +58 -31
- package/src/constants.js +31 -17
- package/src/index.js +21 -10
- package/src/lib/agents/aider.js +141 -0
- package/src/lib/agents/cline.js +128 -0
- package/src/lib/agents/hermes.js +156 -0
- package/src/lib/agents/index.js +82 -0
- package/src/lib/agents/kilo.js +140 -0
- package/src/lib/agents/kimi.js +149 -0
- package/src/lib/agents/openclaw.js +155 -0
- package/src/lib/agents/opencode.js +177 -0
- package/src/lib/detect.js +286 -0
- package/src/lib/install.js +210 -0
- package/src/messages.js +169 -0
- package/src/octopus.js +254 -0
- package/src/ui.js +230 -0
package/README.md
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
# NOITON
|
|
1
|
+
# 🐙 NOITON
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
**Universal AI Agent Connector** — one key, many agents.
|
|
4
|
+
|
|
5
|
+
NOITON is a CLI wizard that connects your API key to multiple AI coding agents at once. Run it once, pick your agents, paste your key — done.
|
|
4
6
|
|
|
5
7
|
## Quick Start
|
|
6
8
|
|
|
@@ -8,51 +10,64 @@ OpenCode authenticator - configure providers with a single key.
|
|
|
8
10
|
npx noiton
|
|
9
11
|
```
|
|
10
12
|
|
|
11
|
-
The
|
|
12
|
-
1.
|
|
13
|
-
2.
|
|
14
|
-
3.
|
|
15
|
-
4.
|
|
13
|
+
The octopus will:
|
|
14
|
+
1. 🔍 Detect which AI agents are installed (OpenCode, Hermes, OpenClaw, Cline, Aider, Kilo Code, Kimi Code)
|
|
15
|
+
2. 📦 If none found, offer to install OpenCode or Hermes based on your use case
|
|
16
|
+
3. 🔄 If OpenCode is outdated, offer to update it
|
|
17
|
+
4. 🔑 Ask for your NOITON API key (one key serves all agents)
|
|
18
|
+
5. 📋 Fetch available models from the API
|
|
19
|
+
6. ⚙️ Configure each selected agent in its native format
|
|
20
|
+
7. 🎉 Show a funny success message (with easter eggs on holidays!)
|
|
21
|
+
|
|
22
|
+
## Supported Agents
|
|
23
|
+
|
|
24
|
+
| Agent | Type | Config Format | Multiple Models |
|
|
25
|
+
|-------|------|---------------|-----------------|
|
|
26
|
+
| **OpenCode** | CLI | JSON (`opencode.json`) | ✅ |
|
|
27
|
+
| **Hermes** | CLI | YAML (`config.yaml` + `.env`) | Single default |
|
|
28
|
+
| **OpenClaw** | CLI | JSON5 (`openclaw.json`) | ✅ |
|
|
29
|
+
| **Cline** | VS Code ext | JSON (VS Code settings) | Single |
|
|
30
|
+
| **Aider** | CLI | YAML (`.aider.conf.yml` + `.env`) | Single |
|
|
31
|
+
| **Kilo Code** | CLI + VS Code | JSONC (`kilo.jsonc`) | ✅ |
|
|
32
|
+
| **Kimi Code** | CLI + VS Code | TOML (`config.toml`) | Single |
|
|
16
33
|
|
|
17
34
|
## Commands
|
|
18
35
|
|
|
19
36
|
```bash
|
|
20
37
|
npx noiton # Setup wizard (default)
|
|
21
|
-
npx noiton status # Show
|
|
38
|
+
npx noiton status # Show configuration across all agents
|
|
22
39
|
npx noiton refresh # Re-fetch models from API
|
|
23
|
-
npx noiton change # Change API key
|
|
24
|
-
npx noiton remove # Remove NOITON from
|
|
40
|
+
npx noiton change # Change API key in all agents
|
|
41
|
+
npx noiton remove # Remove NOITON from all agents
|
|
25
42
|
npx noiton help # Show help
|
|
43
|
+
npx noiton --version # Show version
|
|
26
44
|
```
|
|
27
45
|
|
|
28
46
|
## How It Works
|
|
29
47
|
|
|
30
|
-
NOITON
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
```
|
|
48
|
+
NOITON detects your installed agents and writes to each one's native config format:
|
|
49
|
+
|
|
50
|
+
- **OpenCode** → `~/.config/opencode/opencode.json` (provider block)
|
|
51
|
+
- **Hermes** → `~/.hermes/config.yaml` (model block) + `~/.hermes/.env` (API key)
|
|
52
|
+
- **OpenClaw** → `~/.openclaw/openclaw.json` (models.providers block)
|
|
53
|
+
- **Cline** → VS Code `settings.json` (cline.* keys)
|
|
54
|
+
- **Aider** → `~/.aider.conf.yml` (openai-api-base) + `~/.env` (OPENAI_API_KEY)
|
|
55
|
+
- **Kilo Code** → `~/.config/kilo/kilo.jsonc` (provider.openai-compatible block)
|
|
56
|
+
- **Kimi Code** → `~/.kimi-code/config.toml` (providers + models blocks)
|
|
57
|
+
|
|
58
|
+
Existing configurations are preserved — NOITON only adds/removes its own entries.
|
|
59
|
+
|
|
60
|
+
## Auto-Install
|
|
61
|
+
|
|
62
|
+
If no agents are detected, NOITON asks what you want to do:
|
|
49
63
|
|
|
50
|
-
|
|
64
|
+
- 💻 **Programar** → installs OpenCode (`curl -fsSL https://opencode.ai/install | bash`)
|
|
65
|
+
- 🤖 **Assistente** → installs Hermes (`pip install nous-hermes`)
|
|
51
66
|
|
|
52
67
|
## Requirements
|
|
53
68
|
|
|
54
69
|
- Node.js >= 18
|
|
55
|
-
-
|
|
70
|
+
- At least one supported agent (or let NOITON install one for you)
|
|
56
71
|
|
|
57
72
|
## License
|
|
58
73
|
|
package/package.json
CHANGED
|
@@ -1,17 +1,26 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "noiton",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "2.0.1",
|
|
4
|
+
"description": "🐙 Universal AI Agent Connector - one key, many agents (OpenCode, Hermes, OpenClaw, Cline, Aider, Kilo, Kimi)",
|
|
5
5
|
"keywords": [
|
|
6
|
+
"noiton",
|
|
6
7
|
"opencode",
|
|
7
|
-
"
|
|
8
|
+
"hermes",
|
|
9
|
+
"openclaw",
|
|
10
|
+
"cline",
|
|
11
|
+
"aider",
|
|
12
|
+
"kilo",
|
|
13
|
+
"kimi",
|
|
14
|
+
"ai",
|
|
8
15
|
"cli",
|
|
9
|
-
"
|
|
10
|
-
"
|
|
11
|
-
"
|
|
16
|
+
"agent",
|
|
17
|
+
"wizard",
|
|
18
|
+
"setup",
|
|
19
|
+
"auth"
|
|
12
20
|
],
|
|
13
21
|
"license": "MIT",
|
|
14
22
|
"author": "NOITON",
|
|
23
|
+
"homepage": "https://github.com/tokensilimitados/noiton",
|
|
15
24
|
"type": "module",
|
|
16
25
|
"bin": {
|
|
17
26
|
"noiton": "./bin/noiton.js"
|
|
@@ -27,11 +36,19 @@
|
|
|
27
36
|
"node": ">=18"
|
|
28
37
|
},
|
|
29
38
|
"dependencies": {
|
|
30
|
-
"@inquirer/prompts": "^7.0.0"
|
|
39
|
+
"@inquirer/prompts": "^7.0.0",
|
|
40
|
+
"@iarna/toml": "^2.2.5",
|
|
41
|
+
"boxen": "^8.0.0",
|
|
42
|
+
"gradient-string": "^3.0.0",
|
|
43
|
+
"json5": "^2.2.3",
|
|
44
|
+
"ora": "^8.0.0",
|
|
45
|
+
"picocolors": "^1.1.0",
|
|
46
|
+
"yaml": "^2.8.4"
|
|
31
47
|
},
|
|
32
48
|
"scripts": {
|
|
33
49
|
"test": "node --test tests/",
|
|
34
|
-
"prepublishOnly": "echo 'no build step - pure JS'"
|
|
50
|
+
"prepublishOnly": "echo 'no build step - pure JS'",
|
|
51
|
+
"view-octopus": "node -e \"import('./src/octopus.js').then(m => console.log(m.octopusHappy()))\""
|
|
35
52
|
},
|
|
36
53
|
"publishConfig": {
|
|
37
54
|
"access": "public",
|
package/src/commands/change.js
CHANGED
|
@@ -1,77 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NOITON change command - swap the API key across all configured agents
|
|
3
|
+
*/
|
|
4
|
+
|
|
1
5
|
import { input, confirm } from "@inquirer/prompts";
|
|
2
|
-
import {
|
|
6
|
+
import { c } from "../constants.js";
|
|
7
|
+
import { printHeader, spinner, ok, fail, info, box, dim } from "../ui.js";
|
|
8
|
+
import { getConfiguredAgents } from "../lib/agents/index.js";
|
|
3
9
|
import { validateKey, maskKey } from "../lib/api.js";
|
|
4
|
-
import {
|
|
5
|
-
readConfig,
|
|
6
|
-
writeConfig,
|
|
7
|
-
hasProvider,
|
|
8
|
-
getProvider,
|
|
9
|
-
upsertProvider,
|
|
10
|
-
buildModels,
|
|
11
|
-
} from "../lib/config.js";
|
|
10
|
+
import { farewellMessage } from "../messages.js";
|
|
12
11
|
|
|
13
|
-
/**
|
|
14
|
-
* Change API key (re-runs wizard with new key).
|
|
15
|
-
*/
|
|
16
12
|
export async function changeCommand() {
|
|
17
|
-
|
|
13
|
+
printHeader("Trocar Chave API");
|
|
18
14
|
|
|
19
|
-
const
|
|
15
|
+
const configured = getConfiguredAgents();
|
|
20
16
|
|
|
21
|
-
if (
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
process.exit(1);
|
|
17
|
+
if (configured.length === 0) {
|
|
18
|
+
box("NOITON não está configurado em nenhum agente.\n\nRode 'npx noiton' para configurar.", "warning");
|
|
19
|
+
return;
|
|
25
20
|
}
|
|
26
21
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
console.log(color(" Chave atual: ", "dim") + maskKey(oldKey) + "\n");
|
|
22
|
+
info(`Agentes configurados: ${configured.map(a => a.name).join(", ")}`);
|
|
23
|
+
console.log();
|
|
31
24
|
|
|
32
25
|
const newKey = await input({
|
|
33
|
-
message: " Nova chave:",
|
|
26
|
+
message: " Nova chave NOITON:",
|
|
34
27
|
validate: (v) => (v.trim().length >= 10 ? true : "Chave muito curta"),
|
|
35
28
|
transformer: (v) => maskKey(v),
|
|
36
29
|
});
|
|
37
30
|
|
|
38
|
-
const
|
|
31
|
+
const trimmed = newKey.trim();
|
|
39
32
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
const { valid,
|
|
33
|
+
// Validate the new key
|
|
34
|
+
const s = spinner("Validando nova chave...");
|
|
35
|
+
const { valid, error } = await validateKey(trimmed);
|
|
43
36
|
|
|
44
37
|
if (!valid) {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
console.log(color(" ✓ Chave válida!\n", "green"));
|
|
50
|
-
|
|
51
|
-
if (!models || models.length === 0) {
|
|
52
|
-
console.log(color(" ⚠ Nenhum modelo disponível para esta chave.\n", "yellow"));
|
|
53
|
-
process.exit(1);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
console.log(color(` 📦 ${models.length} modelo(s) encontrado(s):\n`, "cyan"));
|
|
57
|
-
for (const m of models) {
|
|
58
|
-
console.log(` • ${m.id}`);
|
|
38
|
+
s.fail(`Chave inválida: ${error}`);
|
|
39
|
+
return;
|
|
59
40
|
}
|
|
60
41
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
42
|
+
s.succeed("Nova chave válida!");
|
|
43
|
+
console.log();
|
|
44
|
+
|
|
45
|
+
let success = 0;
|
|
46
|
+
for (const agent of configured) {
|
|
47
|
+
const sub = spinner(`Atualizando ${agent.name}...`);
|
|
48
|
+
try {
|
|
49
|
+
agent.changeKey(trimmed);
|
|
50
|
+
sub.succeed(`${agent.name} atualizado!`);
|
|
51
|
+
success++;
|
|
52
|
+
} catch (err) {
|
|
53
|
+
sub.fail(`${agent.name}: ${err.message}`);
|
|
54
|
+
}
|
|
69
55
|
}
|
|
70
56
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
57
|
+
console.log();
|
|
58
|
+
box(
|
|
59
|
+
success > 0
|
|
60
|
+
? `✨ Chave trocada em ${success} agente(s)!`
|
|
61
|
+
: "⚠️ Nenhum agente pôde ser atualizado.",
|
|
62
|
+
success > 0 ? "success" : "warning"
|
|
63
|
+
);
|
|
74
64
|
|
|
75
|
-
console.log(
|
|
76
|
-
console.log(
|
|
65
|
+
console.log();
|
|
66
|
+
console.log(c.dim(` ${farewellMessage()}`));
|
|
77
67
|
}
|
package/src/commands/init.js
CHANGED
|
@@ -1,35 +1,222 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
/**
|
|
2
|
+
* NOITON init command - the universal multi-agent wizard
|
|
3
|
+
*
|
|
4
|
+
* Flow (with proper pacing and step-by-step reveals):
|
|
5
|
+
* 1. Print banner with octopus mascot
|
|
6
|
+
* 2. Detect all installed agents (with spinner + gradual reveal)
|
|
7
|
+
* 3. If no agents, offer to install OpenCode or Hermes
|
|
8
|
+
* 4. If OpenCode installed, check version & offer update
|
|
9
|
+
* 5. Show checklist of detected agents (one by one)
|
|
10
|
+
* 6. Ask which agents to configure
|
|
11
|
+
* 7. Check if already configured, ask to overwrite
|
|
12
|
+
* 8. Ask for NOITON API key (once)
|
|
13
|
+
* 9. Validate key + fetch models (with spinner)
|
|
14
|
+
* 10. Show models list
|
|
15
|
+
* 11. Ask which model to use as primary
|
|
16
|
+
* 12. Configure each selected agent (with per-agent spinner)
|
|
17
|
+
* 13. Show summary + funny success message + easter egg
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import { input, confirm, select, checkbox } from "@inquirer/prompts";
|
|
21
|
+
import { c } from "../constants.js";
|
|
22
|
+
import {
|
|
23
|
+
printBanner,
|
|
24
|
+
box,
|
|
25
|
+
spinner,
|
|
26
|
+
ok,
|
|
27
|
+
warn,
|
|
28
|
+
fail,
|
|
29
|
+
info,
|
|
30
|
+
dim,
|
|
31
|
+
step,
|
|
32
|
+
checklist,
|
|
33
|
+
divider,
|
|
34
|
+
sleep,
|
|
35
|
+
line,
|
|
36
|
+
} from "../ui.js";
|
|
37
|
+
import {
|
|
38
|
+
successMessage,
|
|
39
|
+
noAgentMessage,
|
|
40
|
+
thinkingMessage,
|
|
41
|
+
cancelMessage,
|
|
42
|
+
farewellMessage,
|
|
43
|
+
getEasterEgg,
|
|
44
|
+
} from "../messages.js";
|
|
3
45
|
import { validateKey, maskKey } from "../lib/api.js";
|
|
46
|
+
import { getDetectedAgents, getAgent } from "../lib/agents/index.js";
|
|
4
47
|
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
buildModels,
|
|
10
|
-
} from "../lib/config.js";
|
|
48
|
+
detectAgents,
|
|
49
|
+
getOpenCodeStatus,
|
|
50
|
+
} from "../lib/detect.js";
|
|
51
|
+
import { installAgent, updateAgent, offerInstall } from "../lib/install.js";
|
|
11
52
|
|
|
12
|
-
/**
|
|
13
|
-
* Main wizard command - interactive setup.
|
|
14
|
-
*/
|
|
15
53
|
export async function initCommand() {
|
|
16
|
-
|
|
54
|
+
// ============= STEP 1: BANNER =============
|
|
55
|
+
printBanner("happy");
|
|
56
|
+
await sleep(400);
|
|
57
|
+
|
|
58
|
+
// ============= STEP 2: DETECT AGENTS =============
|
|
59
|
+
step(1, "Procurando agentes de IA instalados...");
|
|
60
|
+
await sleep(300);
|
|
61
|
+
|
|
62
|
+
const detectSpinner = spinner("Escaneando seu sistema...");
|
|
63
|
+
await sleep(800);
|
|
64
|
+
const detected = getDetectedAgents();
|
|
65
|
+
const opencodeStatus = getOpenCodeStatus();
|
|
66
|
+
detectSpinner.succeed("Escaneamento concluído!");
|
|
67
|
+
await sleep(300);
|
|
68
|
+
|
|
69
|
+
// ============= STEP 2a: NO AGENTS FOUND =============
|
|
70
|
+
if (detected.length === 0) {
|
|
71
|
+
console.log();
|
|
72
|
+
await sleep(200);
|
|
73
|
+
box(noAgentMessage(), "warning");
|
|
74
|
+
await sleep(500);
|
|
75
|
+
console.log();
|
|
76
|
+
|
|
77
|
+
const installChoice = await offerInstall();
|
|
78
|
+
if (!installChoice) {
|
|
79
|
+
console.log();
|
|
80
|
+
info(cancelMessage());
|
|
81
|
+
await sleep(200);
|
|
82
|
+
console.log();
|
|
83
|
+
console.log(c.dim(" 💡 Dica: instale OpenCode ou Hermes e rode noiton novamente!"));
|
|
84
|
+
console.log(c.dim(" OpenCode: curl -fsSL https://opencode.ai/install | bash"));
|
|
85
|
+
console.log(c.dim(" Hermes: pip install nous-hermes"));
|
|
86
|
+
console.log();
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Install the chosen agent
|
|
91
|
+
const result = await installAgent(installChoice);
|
|
92
|
+
if (!result.ok) {
|
|
93
|
+
console.log();
|
|
94
|
+
fail(`Não foi possível instalar: ${result.error}`);
|
|
95
|
+
console.log(c.dim(" Tente instalar manualmente e rode noiton novamente."));
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
await sleep(500);
|
|
100
|
+
// Re-detect after install
|
|
101
|
+
const reDetected = getDetectedAgents();
|
|
102
|
+
if (reDetected.length === 0) {
|
|
103
|
+
console.log();
|
|
104
|
+
warn("Instalação concluída, mas não foi possível detectar o agente.");
|
|
105
|
+
info("Reinicie o terminal e rode 'npx noiton' novamente.");
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
detected.push(...reDetected);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// ============= STEP 3: CHECK OPENCODE VERSION =============
|
|
112
|
+
if (opencodeStatus?.updateAvailable) {
|
|
113
|
+
await sleep(400);
|
|
114
|
+
console.log();
|
|
115
|
+
box(
|
|
116
|
+
`🔄 OpenCode v${opencodeStatus.latest} disponível!\n` +
|
|
117
|
+
` Você tem v${opencodeStatus.version}.\n\n` +
|
|
118
|
+
` Atualizar agora?`,
|
|
119
|
+
"warning"
|
|
120
|
+
);
|
|
121
|
+
await sleep(300);
|
|
122
|
+
const wantUpdate = await confirm({
|
|
123
|
+
message: "Atualizar OpenCode?",
|
|
124
|
+
default: true,
|
|
125
|
+
});
|
|
126
|
+
if (wantUpdate) {
|
|
127
|
+
const updateResult = await updateAgent("opencode");
|
|
128
|
+
if (updateResult.ok) {
|
|
129
|
+
ok("OpenCode atualizado!");
|
|
130
|
+
} else {
|
|
131
|
+
warn(`Não foi possível atualizar: ${updateResult.error}`);
|
|
132
|
+
}
|
|
133
|
+
await sleep(300);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// ============= STEP 4: SHOW DETECTED AGENTS ONE BY ONE =============
|
|
138
|
+
step(2, "Agentes detectados");
|
|
139
|
+
await sleep(300);
|
|
140
|
+
|
|
141
|
+
// Reveal each agent with a small delay
|
|
142
|
+
const items = detected.map((a) => ({
|
|
143
|
+
label: a.name,
|
|
144
|
+
ok: true,
|
|
145
|
+
detail: a.version ? `v${a.version}` : "(config encontrado)",
|
|
146
|
+
}));
|
|
147
|
+
|
|
148
|
+
// Print one by one for a "checking" feel
|
|
149
|
+
for (const item of items) {
|
|
150
|
+
const mark = c.green("✓");
|
|
151
|
+
const label = c.white(item.label);
|
|
152
|
+
const detail = c.dim(` ${item.detail}`);
|
|
153
|
+
process.stdout.write(` ${mark} ${label}${detail}`);
|
|
154
|
+
await sleep(250);
|
|
155
|
+
process.stdout.write("\n");
|
|
156
|
+
}
|
|
157
|
+
console.log();
|
|
158
|
+
await sleep(300);
|
|
159
|
+
|
|
160
|
+
// ============= STEP 5: CHOOSE AGENTS TO CONFIGURE =============
|
|
161
|
+
step(3, "Escolha quais agentes configurar");
|
|
162
|
+
await sleep(200);
|
|
163
|
+
|
|
164
|
+
const agentChoices = detected.map((a) => ({
|
|
165
|
+
name: `${a.name}${a.version ? ` (v${a.version})` : ""}`,
|
|
166
|
+
value: a.id,
|
|
167
|
+
checked: true,
|
|
168
|
+
}));
|
|
169
|
+
|
|
170
|
+
let selectedIds;
|
|
171
|
+
if (detected.length === 1) {
|
|
172
|
+
selectedIds = [detected[0].id];
|
|
173
|
+
info(`Configurando: ${detected[0].name}`);
|
|
174
|
+
await sleep(200);
|
|
175
|
+
} else {
|
|
176
|
+
selectedIds = await checkbox({
|
|
177
|
+
message: "Quais agentes você quer conectar ao NOITON?",
|
|
178
|
+
choices: agentChoices,
|
|
179
|
+
required: true,
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
const selectedAgents = selectedIds
|
|
184
|
+
.map((id) => getAgent(id))
|
|
185
|
+
.filter(Boolean);
|
|
17
186
|
|
|
18
|
-
|
|
187
|
+
// ============= STEP 6: CHECK EXISTING CONFIG =============
|
|
188
|
+
const alreadyConfigured = selectedAgents.filter((a) => {
|
|
189
|
+
try {
|
|
190
|
+
return a.isConfigured();
|
|
191
|
+
} catch {
|
|
192
|
+
return false;
|
|
193
|
+
}
|
|
194
|
+
});
|
|
19
195
|
|
|
20
|
-
if (
|
|
21
|
-
|
|
196
|
+
if (alreadyConfigured.length > 0) {
|
|
197
|
+
await sleep(300);
|
|
198
|
+
console.log();
|
|
199
|
+
warn(
|
|
200
|
+
`NOITON já está configurado em: ${alreadyConfigured.map((a) => a.name).join(", ")}`
|
|
201
|
+
);
|
|
202
|
+
await sleep(200);
|
|
22
203
|
const overwrite = await confirm({
|
|
23
|
-
message: "
|
|
204
|
+
message: "Sobrescrever configuração existente?",
|
|
24
205
|
default: false,
|
|
25
206
|
});
|
|
26
207
|
if (!overwrite) {
|
|
27
|
-
console.log(
|
|
208
|
+
console.log();
|
|
209
|
+
info(cancelMessage());
|
|
28
210
|
return;
|
|
29
211
|
}
|
|
30
212
|
}
|
|
31
213
|
|
|
32
|
-
|
|
214
|
+
// ============= STEP 7: ASK FOR API KEY =============
|
|
215
|
+
step(4, "Cole sua chave NOITON");
|
|
216
|
+
await sleep(200);
|
|
217
|
+
console.log(c.dim(" Uma chave só serve para todos os agentes! 🐙"));
|
|
218
|
+
await sleep(200);
|
|
219
|
+
console.log();
|
|
33
220
|
|
|
34
221
|
const apiKey = await input({
|
|
35
222
|
message: " Chave:",
|
|
@@ -39,47 +226,135 @@ export async function initCommand() {
|
|
|
39
226
|
|
|
40
227
|
const trimmedKey = apiKey.trim();
|
|
41
228
|
|
|
42
|
-
|
|
43
|
-
|
|
229
|
+
// ============= STEP 8: VALIDATE KEY + FETCH MODELS =============
|
|
230
|
+
console.log();
|
|
231
|
+
await sleep(200);
|
|
232
|
+
const s = spinner(`${thinkingMessage()} Validando chave...`);
|
|
233
|
+
await sleep(500);
|
|
44
234
|
const { valid, models, error } = await validateKey(trimmedKey);
|
|
45
235
|
|
|
46
236
|
if (!valid) {
|
|
47
|
-
|
|
48
|
-
|
|
237
|
+
s.fail(`Erro: ${error}`);
|
|
238
|
+
console.log();
|
|
239
|
+
fail("Não foi possível validar a chave. Verifique e tente novamente.");
|
|
240
|
+
return;
|
|
49
241
|
}
|
|
50
242
|
|
|
51
|
-
|
|
243
|
+
s.succeed("Chave válida!");
|
|
244
|
+
await sleep(300);
|
|
52
245
|
|
|
53
246
|
if (!models || models.length === 0) {
|
|
54
|
-
console.log(
|
|
55
|
-
|
|
247
|
+
console.log();
|
|
248
|
+
warn("Nenhum modelo disponível para esta chave.");
|
|
249
|
+
return;
|
|
56
250
|
}
|
|
57
251
|
|
|
58
|
-
|
|
252
|
+
// ============= STEP 9: SHOW MODELS =============
|
|
253
|
+
step(5, `Modelos disponíveis (${models.length})`);
|
|
254
|
+
await sleep(200);
|
|
255
|
+
|
|
59
256
|
for (const m of models) {
|
|
60
257
|
const ctx = m.context_window
|
|
61
|
-
?
|
|
258
|
+
? c.dim(` (${Math.round(m.context_window / 1000)}K ctx)`)
|
|
62
259
|
: "";
|
|
63
|
-
|
|
260
|
+
process.stdout.write(` ${c.cyan("•")} ${m.id}${ctx}`);
|
|
261
|
+
await sleep(120);
|
|
262
|
+
process.stdout.write("\n");
|
|
64
263
|
}
|
|
264
|
+
console.log();
|
|
265
|
+
await sleep(300);
|
|
65
266
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
default: true,
|
|
69
|
-
});
|
|
267
|
+
// ============= STEP 10: CHOOSE PRIMARY MODEL =============
|
|
268
|
+
const needsPrimaryModel = selectedAgents.some((a) => !a.supportsMultipleModels);
|
|
70
269
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
270
|
+
let primaryModel = null;
|
|
271
|
+
if (needsPrimaryModel) {
|
|
272
|
+
step(6, "Escolha o modelo principal");
|
|
273
|
+
await sleep(200);
|
|
274
|
+
console.log(c.dim(" Alguns agentes usam apenas 1 modelo por vez."));
|
|
275
|
+
await sleep(200);
|
|
276
|
+
console.log();
|
|
277
|
+
|
|
278
|
+
const modelChoices = models.map((m) => ({
|
|
279
|
+
name: `${m.id}${m.context_window ? ` (${Math.round(m.context_window / 1000)}K ctx)` : ""}`,
|
|
280
|
+
value: m.id,
|
|
281
|
+
}));
|
|
282
|
+
|
|
283
|
+
primaryModel = await select({
|
|
284
|
+
message: "Qual modelo usar como principal?",
|
|
285
|
+
choices: modelChoices,
|
|
286
|
+
default: models[0]?.id,
|
|
287
|
+
});
|
|
288
|
+
console.log();
|
|
289
|
+
await sleep(200);
|
|
74
290
|
}
|
|
75
291
|
|
|
76
|
-
|
|
292
|
+
// ============= STEP 11: CONFIGURE EACH AGENT =============
|
|
293
|
+
step(needsPrimaryModel ? 7 : 6, "Configurando agentes...");
|
|
294
|
+
await sleep(300);
|
|
295
|
+
|
|
296
|
+
const results = [];
|
|
297
|
+
for (const agent of selectedAgents) {
|
|
298
|
+
const s = spinner(`Configurando ${agent.name}...`);
|
|
299
|
+
await sleep(400);
|
|
300
|
+
try {
|
|
301
|
+
const result = agent.configure({
|
|
302
|
+
apiKey: trimmedKey,
|
|
303
|
+
models,
|
|
304
|
+
primaryModel,
|
|
305
|
+
});
|
|
306
|
+
s.succeed(`${agent.name} configurado!`);
|
|
307
|
+
results.push({ agent: agent.name, ok: true, ...result });
|
|
308
|
+
} catch (err) {
|
|
309
|
+
s.fail(`Erro em ${agent.name}: ${err.message}`);
|
|
310
|
+
results.push({ agent: agent.name, ok: false, error: err.message });
|
|
311
|
+
}
|
|
312
|
+
await sleep(200);
|
|
313
|
+
}
|
|
77
314
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
315
|
+
// ============= STEP 12: SUMMARY =============
|
|
316
|
+
console.log();
|
|
317
|
+
divider();
|
|
318
|
+
await sleep(300);
|
|
319
|
+
console.log();
|
|
320
|
+
printBanner("dancing");
|
|
321
|
+
await sleep(400);
|
|
322
|
+
|
|
323
|
+
const successCount = results.filter((r) => r.ok).length;
|
|
324
|
+
if (successCount > 0) {
|
|
325
|
+
box(
|
|
326
|
+
`${successMessage()}\n\n` +
|
|
327
|
+
`${successCount} de ${selectedAgents.length} agente(s) configurado(s):`,
|
|
328
|
+
"success"
|
|
329
|
+
);
|
|
330
|
+
console.log();
|
|
331
|
+
await sleep(200);
|
|
332
|
+
for (const r of results) {
|
|
333
|
+
if (r.ok) {
|
|
334
|
+
ok(`${r.agent} ${c.dim(`→ ${r.path}`)}`);
|
|
335
|
+
} else {
|
|
336
|
+
fail(`${r.agent} ${c.dim(`→ ${r.error}`)}`);
|
|
337
|
+
}
|
|
338
|
+
await sleep(150);
|
|
339
|
+
}
|
|
340
|
+
} else {
|
|
341
|
+
box("Nenhum agente foi configurado. Tente novamente!", "error");
|
|
342
|
+
return;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
// ============= STEP 13: EASTER EGG + FAREWELL =============
|
|
346
|
+
const egg = getEasterEgg();
|
|
347
|
+
if (egg) {
|
|
348
|
+
console.log();
|
|
349
|
+
await sleep(200);
|
|
350
|
+
console.log(c.yellow(` 🎁 ${egg}`));
|
|
351
|
+
}
|
|
81
352
|
|
|
82
|
-
console.log(
|
|
83
|
-
|
|
84
|
-
console.log(
|
|
353
|
+
console.log();
|
|
354
|
+
await sleep(200);
|
|
355
|
+
console.log(c.dim(" 💡 Reinicie os agentes para aplicar as mudanças."));
|
|
356
|
+
console.log();
|
|
357
|
+
await sleep(200);
|
|
358
|
+
console.log(c.purple(` ${farewellMessage()}`));
|
|
359
|
+
console.log();
|
|
85
360
|
}
|