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/README.md
CHANGED
|
@@ -11,7 +11,7 @@ npx noiton
|
|
|
11
11
|
```
|
|
12
12
|
|
|
13
13
|
The octopus will:
|
|
14
|
-
1. π Detect which AI agents are installed (OpenCode, Hermes
|
|
14
|
+
1. π Detect which AI agents are installed (OpenCode, Hermes)
|
|
15
15
|
2. π¦ If none found, offer to install OpenCode or Hermes based on your use case
|
|
16
16
|
3. π If OpenCode is outdated, offer to update it
|
|
17
17
|
4. π Ask for your NOITON API key (one key serves all agents)
|
|
@@ -25,11 +25,6 @@ The octopus will:
|
|
|
25
25
|
|-------|------|---------------|-----------------|
|
|
26
26
|
| **OpenCode** | CLI | JSON (`opencode.json`) | β
|
|
|
27
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 |
|
|
33
28
|
|
|
34
29
|
## Commands
|
|
35
30
|
|
|
@@ -45,15 +40,10 @@ npx noiton --version # Show version
|
|
|
45
40
|
|
|
46
41
|
## How It Works
|
|
47
42
|
|
|
48
|
-
NOITON detects your installed agents
|
|
43
|
+
NOITON detects your installed agents by checking if the CLI binary is on PATH, then writes to each one's native config format:
|
|
49
44
|
|
|
50
45
|
- **OpenCode** β `~/.config/opencode/opencode.json` (provider block)
|
|
51
46
|
- **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
47
|
|
|
58
48
|
Existing configurations are preserved β NOITON only adds/removes its own entries.
|
|
59
49
|
|
package/package.json
CHANGED
|
@@ -1,16 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "noiton",
|
|
3
|
-
"version": "2.0.
|
|
4
|
-
"description": "π Universal AI Agent Connector - one key, many agents (OpenCode, Hermes
|
|
3
|
+
"version": "2.0.3",
|
|
4
|
+
"description": "π Universal AI Agent Connector - one key, many agents (OpenCode, Hermes)",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"noiton",
|
|
7
7
|
"opencode",
|
|
8
8
|
"hermes",
|
|
9
|
-
"openclaw",
|
|
10
|
-
"cline",
|
|
11
|
-
"aider",
|
|
12
|
-
"kilo",
|
|
13
|
-
"kimi",
|
|
14
9
|
"ai",
|
|
15
10
|
"cli",
|
|
16
11
|
"agent",
|
package/src/commands/change.js
CHANGED
|
@@ -4,13 +4,13 @@
|
|
|
4
4
|
|
|
5
5
|
import { input, confirm } from "@inquirer/prompts";
|
|
6
6
|
import { c } from "../constants.js";
|
|
7
|
-
import {
|
|
7
|
+
import { printBanner, spinner, ok, fail, info, box, dim } from "../ui.js";
|
|
8
8
|
import { getConfiguredAgents } from "../lib/agents/index.js";
|
|
9
9
|
import { validateKey, maskKey } from "../lib/api.js";
|
|
10
10
|
import { farewellMessage } from "../messages.js";
|
|
11
11
|
|
|
12
12
|
export async function changeCommand() {
|
|
13
|
-
|
|
13
|
+
printBanner();
|
|
14
14
|
|
|
15
15
|
const configured = getConfiguredAgents();
|
|
16
16
|
|
package/src/commands/init.js
CHANGED
|
@@ -21,6 +21,7 @@ import { input, confirm, select, checkbox } from "@inquirer/prompts";
|
|
|
21
21
|
import { c } from "../constants.js";
|
|
22
22
|
import {
|
|
23
23
|
printBanner,
|
|
24
|
+
successBanner,
|
|
24
25
|
box,
|
|
25
26
|
spinner,
|
|
26
27
|
ok,
|
|
@@ -52,7 +53,7 @@ import { installAgent, updateAgent, offerInstall } from "../lib/install.js";
|
|
|
52
53
|
|
|
53
54
|
export async function initCommand() {
|
|
54
55
|
// ============= STEP 1: BANNER =============
|
|
55
|
-
printBanner(
|
|
56
|
+
printBanner();
|
|
56
57
|
await sleep(400);
|
|
57
58
|
|
|
58
59
|
// ============= STEP 2: DETECT AGENTS =============
|
|
@@ -317,7 +318,7 @@ export async function initCommand() {
|
|
|
317
318
|
divider();
|
|
318
319
|
await sleep(300);
|
|
319
320
|
console.log();
|
|
320
|
-
|
|
321
|
+
successBanner();
|
|
321
322
|
await sleep(400);
|
|
322
323
|
|
|
323
324
|
const successCount = results.filter((r) => r.ok).length;
|
package/src/commands/refresh.js
CHANGED
|
@@ -3,14 +3,14 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import { c } from "../constants.js";
|
|
6
|
-
import {
|
|
6
|
+
import { printBanner, spinner, ok, fail, info, box, dim } from "../ui.js";
|
|
7
7
|
import { getConfiguredAgents, getAgent } from "../lib/agents/index.js";
|
|
8
8
|
import { validateKey, maskKey } from "../lib/api.js";
|
|
9
9
|
import { input } from "@inquirer/prompts";
|
|
10
10
|
import { farewellMessage } from "../messages.js";
|
|
11
11
|
|
|
12
12
|
export async function refreshCommand() {
|
|
13
|
-
|
|
13
|
+
printBanner();
|
|
14
14
|
|
|
15
15
|
const configured = getConfiguredAgents();
|
|
16
16
|
|
package/src/commands/remove.js
CHANGED
|
@@ -4,12 +4,12 @@
|
|
|
4
4
|
|
|
5
5
|
import { confirm } from "@inquirer/prompts";
|
|
6
6
|
import { c } from "../constants.js";
|
|
7
|
-
import {
|
|
7
|
+
import { printBanner, spinner, ok, fail, info, box, dim } from "../ui.js";
|
|
8
8
|
import { getConfiguredAgents } from "../lib/agents/index.js";
|
|
9
9
|
import { farewellMessage, cancelMessage } from "../messages.js";
|
|
10
10
|
|
|
11
11
|
export async function removeCommand() {
|
|
12
|
-
|
|
12
|
+
printBanner();
|
|
13
13
|
|
|
14
14
|
const configured = getConfiguredAgents();
|
|
15
15
|
|
package/src/commands/status.js
CHANGED
|
@@ -3,13 +3,13 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import { c } from "../constants.js";
|
|
6
|
-
import {
|
|
6
|
+
import { printBanner, ok, warn, fail, info, dim, divider, checklist, box } from "../ui.js";
|
|
7
7
|
import { getAllStatuses } from "../lib/agents/index.js";
|
|
8
8
|
import { maskKey } from "../lib/api.js";
|
|
9
9
|
import { farewellMessage } from "../messages.js";
|
|
10
10
|
|
|
11
11
|
export async function statusCommand() {
|
|
12
|
-
|
|
12
|
+
printBanner();
|
|
13
13
|
|
|
14
14
|
const statuses = getAllStatuses();
|
|
15
15
|
const detected = statuses.filter((s) => s.detected);
|
package/src/index.js
CHANGED
|
@@ -23,11 +23,6 @@ ${c.bold("USAGE")}
|
|
|
23
23
|
${c.bold("AGENTES SUPORTADOS")}
|
|
24
24
|
${c.cyan("β’")} OpenCode Programador IA (CLI)
|
|
25
25
|
${c.cyan("β’")} Hermes Assistente de tarefas (CLI)
|
|
26
|
-
${c.cyan("β’")} OpenClaw Agente open-source (CLI)
|
|
27
|
-
${c.cyan("β’")} Cline ExtensΓ£o VS Code
|
|
28
|
-
${c.cyan("β’")} Aider Pair programmer de terminal
|
|
29
|
-
${c.cyan("β’")} Kilo Code CLI + extensΓ£o VS Code
|
|
30
|
-
${c.cyan("β’")} Kimi Code CLI + extensΓ£o VS Code
|
|
31
26
|
|
|
32
27
|
${c.bold("EXEMPLOS")}
|
|
33
28
|
npx noiton # configura pela primeira vez
|
package/src/lib/agents/hermes.js
CHANGED
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
import { readFileSync, writeFileSync, existsSync, mkdirSync, appendFileSync } from "node:fs";
|
|
15
15
|
import { join, dirname } from "node:path";
|
|
16
16
|
import { homedir } from "node:os";
|
|
17
|
+
import { execSync } from "node:child_process";
|
|
17
18
|
import YAML from "yaml";
|
|
18
19
|
import { BASE_URL } from "../../constants.js";
|
|
19
20
|
|
|
@@ -22,6 +23,19 @@ const CONFIG_PATH = join(HOME, ".hermes", "config.yaml");
|
|
|
22
23
|
const ENV_PATH = join(HOME, ".hermes", ".env");
|
|
23
24
|
const ENV_KEY = "NOITON_API_KEY";
|
|
24
25
|
|
|
26
|
+
/**
|
|
27
|
+
* Check if hermes binary exists on PATH.
|
|
28
|
+
* @returns {boolean}
|
|
29
|
+
*/
|
|
30
|
+
function hasHermesBin() {
|
|
31
|
+
try {
|
|
32
|
+
execSync(`command -v hermes 2>/dev/null`, { stdio: "ignore" });
|
|
33
|
+
return true;
|
|
34
|
+
} catch {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
25
39
|
function readYaml() {
|
|
26
40
|
if (!existsSync(CONFIG_PATH)) return { config: {}, path: CONFIG_PATH };
|
|
27
41
|
try {
|
|
@@ -75,8 +89,13 @@ export const hermesAgent = {
|
|
|
75
89
|
name: "Hermes",
|
|
76
90
|
supportsMultipleModels: false,
|
|
77
91
|
|
|
92
|
+
/**
|
|
93
|
+
* Detect if Hermes is really installed.
|
|
94
|
+
* Requires the binary on PATH - config files alone aren't enough
|
|
95
|
+
* (could be leftover from uninstalled tools).
|
|
96
|
+
*/
|
|
78
97
|
detect() {
|
|
79
|
-
return
|
|
98
|
+
return hasHermesBin();
|
|
80
99
|
},
|
|
81
100
|
|
|
82
101
|
isConfigured() {
|
package/src/lib/agents/index.js
CHANGED
|
@@ -6,24 +6,38 @@
|
|
|
6
6
|
* configure, changeKey, refresh, remove }
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
+
import { execSync } from "node:child_process";
|
|
10
|
+
import { existsSync } from "node:fs";
|
|
9
11
|
import { opencodeAgent } from "./opencode.js";
|
|
10
12
|
import { hermesAgent } from "./hermes.js";
|
|
11
|
-
import { openclawAgent } from "./openclaw.js";
|
|
12
|
-
import { clineAgent } from "./cline.js";
|
|
13
|
-
import { aiderAgent } from "./aider.js";
|
|
14
|
-
import { kiloAgent } from "./kilo.js";
|
|
15
|
-
import { kimiAgent } from "./kimi.js";
|
|
16
13
|
|
|
17
14
|
export const REGISTRY = [
|
|
18
15
|
opencodeAgent,
|
|
19
16
|
hermesAgent,
|
|
20
|
-
openclawAgent,
|
|
21
|
-
clineAgent,
|
|
22
|
-
aiderAgent,
|
|
23
|
-
kiloAgent,
|
|
24
|
-
kimiAgent,
|
|
25
17
|
];
|
|
26
18
|
|
|
19
|
+
/**
|
|
20
|
+
* Get version of a CLI binary (best-effort).
|
|
21
|
+
* @param {string} bin
|
|
22
|
+
* @returns {string|null}
|
|
23
|
+
*/
|
|
24
|
+
function getBinVersion(bin) {
|
|
25
|
+
for (const flag of ["--version", "-v"]) {
|
|
26
|
+
try {
|
|
27
|
+
const out = execSync(`${bin} ${flag} 2>/dev/null`, {
|
|
28
|
+
encoding: "utf8",
|
|
29
|
+
timeout: 5000,
|
|
30
|
+
}).trim();
|
|
31
|
+
const match = out.match(/(\d+\.\d+(?:\.\d+)?(?:-\w+)?)/);
|
|
32
|
+
if (match) return match[1];
|
|
33
|
+
return out.split("\n")[0];
|
|
34
|
+
} catch {
|
|
35
|
+
// try next flag
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
|
|
27
41
|
/**
|
|
28
42
|
* Get an agent adapter by ID.
|
|
29
43
|
* @param {string} id
|
|
@@ -35,10 +49,26 @@ export function getAgent(id) {
|
|
|
35
49
|
|
|
36
50
|
/**
|
|
37
51
|
* Get all agents that are detected as installed.
|
|
52
|
+
* Enriches each adapter with version and configFound info.
|
|
38
53
|
* @returns {Array}
|
|
39
54
|
*/
|
|
40
55
|
export function getDetectedAgents() {
|
|
41
|
-
return REGISTRY.filter((a) => a.detect())
|
|
56
|
+
return REGISTRY.filter((a) => a.detect()).map((a) => {
|
|
57
|
+
// Try to get version from binary
|
|
58
|
+
let version = null;
|
|
59
|
+
const bins = { opencode: "opencode", hermes: "hermes" };
|
|
60
|
+
const bin = bins[a.id];
|
|
61
|
+
if (bin) {
|
|
62
|
+
version = getBinVersion(bin);
|
|
63
|
+
}
|
|
64
|
+
// Check if config file exists
|
|
65
|
+
let configFound = false;
|
|
66
|
+
try {
|
|
67
|
+
const status = a.getStatus();
|
|
68
|
+
configFound = Boolean(status?.path && existsSync(status.path));
|
|
69
|
+
} catch {}
|
|
70
|
+
return { ...a, version, configFound };
|
|
71
|
+
});
|
|
42
72
|
}
|
|
43
73
|
|
|
44
74
|
/**
|
|
@@ -56,7 +86,7 @@ export function getConfiguredAgents() {
|
|
|
56
86
|
}
|
|
57
87
|
|
|
58
88
|
/**
|
|
59
|
-
* Get status of all
|
|
89
|
+
* Get status of all agents.
|
|
60
90
|
* @returns {Array}
|
|
61
91
|
*/
|
|
62
92
|
export function getAllStatuses() {
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
import { readFileSync, writeFileSync, existsSync, mkdirSync } from "node:fs";
|
|
9
9
|
import { join, dirname } from "node:path";
|
|
10
10
|
import { homedir } from "node:os";
|
|
11
|
+
import { execSync } from "node:child_process";
|
|
11
12
|
import {
|
|
12
13
|
PROVIDER_ID,
|
|
13
14
|
PROVIDER_NAME,
|
|
@@ -18,6 +19,19 @@ import {
|
|
|
18
19
|
const HOME = homedir();
|
|
19
20
|
const XDG = process.env.XDG_CONFIG_HOME || join(HOME, ".config");
|
|
20
21
|
|
|
22
|
+
/**
|
|
23
|
+
* Check if opencode binary exists on PATH.
|
|
24
|
+
* @returns {boolean}
|
|
25
|
+
*/
|
|
26
|
+
function hasOpencodeBin() {
|
|
27
|
+
try {
|
|
28
|
+
execSync(`command -v opencode 2>/dev/null`, { stdio: "ignore" });
|
|
29
|
+
return true;
|
|
30
|
+
} catch {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
21
35
|
/** @returns {string} config path */
|
|
22
36
|
export function getConfigPath() {
|
|
23
37
|
if (process.env.OPENCODE_CONFIG) return process.env.OPENCODE_CONFIG;
|
|
@@ -116,8 +130,12 @@ export const opencodeAgent = {
|
|
|
116
130
|
name: "OpenCode",
|
|
117
131
|
supportsMultipleModels: true,
|
|
118
132
|
|
|
133
|
+
/**
|
|
134
|
+
* Detect if OpenCode is really installed.
|
|
135
|
+
* Requires the binary on PATH - config files alone aren't enough.
|
|
136
|
+
*/
|
|
119
137
|
detect() {
|
|
120
|
-
return
|
|
138
|
+
return hasOpencodeBin();
|
|
121
139
|
},
|
|
122
140
|
|
|
123
141
|
isConfigured() {
|
package/src/lib/detect.js
CHANGED
|
@@ -1,18 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* NOITON Agent Detection
|
|
3
3
|
*
|
|
4
|
-
* Detects which AI coding agents are installed on the system
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* Returns a list of detected agents with metadata.
|
|
4
|
+
* Detects which AI coding agents are installed on the system.
|
|
5
|
+
* Detection requires the CLI binary to be on PATH (not just config files,
|
|
6
|
+
* which can be leftover from uninstalled tools).
|
|
9
7
|
*/
|
|
10
8
|
|
|
11
9
|
import { existsSync } from "node:fs";
|
|
12
10
|
import { join } from "node:path";
|
|
13
11
|
import { homedir } from "node:os";
|
|
14
12
|
import { execSync } from "node:child_process";
|
|
15
|
-
import { c } from "../constants.js";
|
|
16
13
|
|
|
17
14
|
const HOME = homedir();
|
|
18
15
|
const XDG = process.env.XDG_CONFIG_HOME || join(HOME, ".config");
|
|
@@ -24,7 +21,7 @@ const XDG = process.env.XDG_CONFIG_HOME || join(HOME, ".config");
|
|
|
24
21
|
*/
|
|
25
22
|
function hasBin(bin) {
|
|
26
23
|
try {
|
|
27
|
-
execSync(`
|
|
24
|
+
execSync(`command -v ${bin} 2>/dev/null`, { stdio: "ignore" });
|
|
28
25
|
return true;
|
|
29
26
|
} catch {
|
|
30
27
|
return false;
|
|
@@ -44,7 +41,6 @@ function getBinVersion(bin) {
|
|
|
44
41
|
encoding: "utf8",
|
|
45
42
|
timeout: 5000,
|
|
46
43
|
}).trim();
|
|
47
|
-
// Extract first version-like token
|
|
48
44
|
const match = out.match(/(\d+\.\d+(?:\.\d+)?(?:-\w+)?)/);
|
|
49
45
|
if (match) return match[1];
|
|
50
46
|
return out.split("\n")[0];
|
|
@@ -76,8 +72,6 @@ function getNpmLatest(pkg) {
|
|
|
76
72
|
/**
|
|
77
73
|
* Compare two semver-like version strings.
|
|
78
74
|
* Returns: 1 if a > b, -1 if a < b, 0 if equal.
|
|
79
|
-
* @param {string} a
|
|
80
|
-
* @param {string} b
|
|
81
75
|
*/
|
|
82
76
|
function compareVersions(a, b) {
|
|
83
77
|
const pa = a.split(".").map(Number);
|
|
@@ -93,10 +87,6 @@ function compareVersions(a, b) {
|
|
|
93
87
|
|
|
94
88
|
// ============= AGENT DEFINITIONS =============
|
|
95
89
|
|
|
96
|
-
/**
|
|
97
|
-
* Registry of all supported agents.
|
|
98
|
-
* Each entry describes how to detect the agent and where its config lives.
|
|
99
|
-
*/
|
|
100
90
|
export const AGENT_REGISTRY = [
|
|
101
91
|
{
|
|
102
92
|
id: "opencode",
|
|
@@ -125,109 +115,42 @@ export const AGENT_REGISTRY = [
|
|
|
125
115
|
description: "Assistente que faz tarefas e se integra com apps",
|
|
126
116
|
useCase: "assistant",
|
|
127
117
|
},
|
|
128
|
-
{
|
|
129
|
-
id: "openclaw",
|
|
130
|
-
name: "OpenClaw",
|
|
131
|
-
type: "CLI",
|
|
132
|
-
bin: "openclaw",
|
|
133
|
-
npmPkg: null,
|
|
134
|
-
installMethod: null,
|
|
135
|
-
installCmd: null,
|
|
136
|
-
configPath: join(HOME, ".openclaw", "openclaw.json"),
|
|
137
|
-
supportsMultipleModels: true,
|
|
138
|
-
description: "Agente de IA open-source com providers customizΓ‘veis",
|
|
139
|
-
useCase: "programming",
|
|
140
|
-
},
|
|
141
|
-
{
|
|
142
|
-
id: "cline",
|
|
143
|
-
name: "Cline",
|
|
144
|
-
type: "VSCode Extension",
|
|
145
|
-
bin: null,
|
|
146
|
-
npmPkg: null,
|
|
147
|
-
installMethod: null,
|
|
148
|
-
installCmd: null,
|
|
149
|
-
configPath: join(XDG, "Code", "User", "settings.json"),
|
|
150
|
-
supportsMultipleModels: true,
|
|
151
|
-
description: "ExtensΓ£o VS Code para programaΓ§Γ£o com IA",
|
|
152
|
-
useCase: "programming",
|
|
153
|
-
},
|
|
154
|
-
{
|
|
155
|
-
id: "aider",
|
|
156
|
-
name: "Aider",
|
|
157
|
-
type: "CLI",
|
|
158
|
-
bin: "aider",
|
|
159
|
-
npmPkg: null,
|
|
160
|
-
installMethod: "pip",
|
|
161
|
-
installCmd: "pip install aider-chat",
|
|
162
|
-
configPath: join(HOME, ".aider.conf.yml"),
|
|
163
|
-
supportsMultipleModels: false,
|
|
164
|
-
description: "Pair programmer de terminal que edita cΓ³digo com vocΓͺ",
|
|
165
|
-
useCase: "programming",
|
|
166
|
-
},
|
|
167
|
-
{
|
|
168
|
-
id: "kilo",
|
|
169
|
-
name: "Kilo Code",
|
|
170
|
-
type: "CLI + VSCode",
|
|
171
|
-
bin: "kilo",
|
|
172
|
-
npmPkg: "@kilocode/cli",
|
|
173
|
-
installMethod: "npm",
|
|
174
|
-
installCmd: "npm install -g @kilocode/cli",
|
|
175
|
-
configPath: join(XDG, "kilo", "kilo.jsonc"),
|
|
176
|
-
supportsMultipleModels: true,
|
|
177
|
-
description: "Agente de IA com CLI e extensΓ£o VS Code",
|
|
178
|
-
useCase: "programming",
|
|
179
|
-
},
|
|
180
|
-
{
|
|
181
|
-
id: "kimi",
|
|
182
|
-
name: "Kimi Code",
|
|
183
|
-
type: "CLI + VSCode",
|
|
184
|
-
bin: "kimi",
|
|
185
|
-
npmPkg: null,
|
|
186
|
-
installMethod: null,
|
|
187
|
-
installCmd: null,
|
|
188
|
-
configPath: join(HOME, ".kimi-code", "config.toml"),
|
|
189
|
-
supportsMultipleModels: false,
|
|
190
|
-
description: "Agente de IA da Moonshot com CLI e VS Code",
|
|
191
|
-
useCase: "programming",
|
|
192
|
-
},
|
|
193
118
|
];
|
|
194
119
|
|
|
195
120
|
/**
|
|
196
121
|
* Detect all installed agents.
|
|
122
|
+
* An agent is "installed" only if its binary is on PATH.
|
|
123
|
+
* Config files alone are NOT enough (could be leftover from uninstalled tools).
|
|
197
124
|
* @returns {Array} detected agents with status info
|
|
198
125
|
*/
|
|
199
126
|
export function detectAgents() {
|
|
200
127
|
const detected = [];
|
|
201
128
|
for (const agent of AGENT_REGISTRY) {
|
|
202
|
-
|
|
203
|
-
const
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
});
|
|
215
|
-
}
|
|
129
|
+
if (!agent.bin) continue;
|
|
130
|
+
const binFound = hasBin(agent.bin);
|
|
131
|
+
if (!binFound) continue;
|
|
132
|
+
|
|
133
|
+
const version = getBinVersion(agent.bin);
|
|
134
|
+
detected.push({
|
|
135
|
+
...agent,
|
|
136
|
+
installed: true,
|
|
137
|
+
version,
|
|
138
|
+
binFound: true,
|
|
139
|
+
configFound: existsSync(agent.configPath),
|
|
140
|
+
});
|
|
216
141
|
}
|
|
217
142
|
return detected;
|
|
218
143
|
}
|
|
219
144
|
|
|
220
145
|
/**
|
|
221
|
-
* Check if a specific agent is installed.
|
|
146
|
+
* Check if a specific agent is installed (binary on PATH).
|
|
222
147
|
* @param {string} id
|
|
223
148
|
* @returns {boolean}
|
|
224
149
|
*/
|
|
225
150
|
export function isAgentInstalled(id) {
|
|
226
151
|
const agent = AGENT_REGISTRY.find((a) => a.id === id);
|
|
227
|
-
if (!agent) return false;
|
|
228
|
-
|
|
229
|
-
const configFound = existsSync(agent.configPath);
|
|
230
|
-
return binFound || configFound;
|
|
152
|
+
if (!agent || !agent.bin) return false;
|
|
153
|
+
return hasBin(agent.bin);
|
|
231
154
|
}
|
|
232
155
|
|
|
233
156
|
/**
|
|
@@ -240,13 +163,10 @@ export function getOpenCodeStatus() {
|
|
|
240
163
|
if (!agent) return null;
|
|
241
164
|
|
|
242
165
|
const binFound = hasBin("opencode");
|
|
243
|
-
|
|
244
|
-
const installed = binFound || configFound;
|
|
166
|
+
if (!binFound) return null;
|
|
245
167
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
const version = binFound ? getBinVersion("opencode") : null;
|
|
249
|
-
const latest = binFound ? getNpmLatest("opencode-ai") : null;
|
|
168
|
+
const version = getBinVersion("opencode");
|
|
169
|
+
const latest = getNpmLatest("opencode-ai");
|
|
250
170
|
const updateAvailable =
|
|
251
171
|
version && latest ? compareVersions(latest, version) > 0 : false;
|
|
252
172
|
|
|
@@ -256,8 +176,29 @@ export function getOpenCodeStatus() {
|
|
|
256
176
|
version,
|
|
257
177
|
latest,
|
|
258
178
|
updateAvailable,
|
|
259
|
-
binFound,
|
|
260
|
-
configFound,
|
|
179
|
+
binFound: true,
|
|
180
|
+
configFound: existsSync(agent.configPath),
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Get the Hermes agent status.
|
|
186
|
+
* @returns {object|null}
|
|
187
|
+
*/
|
|
188
|
+
export function getHermesStatus() {
|
|
189
|
+
const agent = AGENT_REGISTRY.find((a) => a.id === "hermes");
|
|
190
|
+
if (!agent) return null;
|
|
191
|
+
|
|
192
|
+
const binFound = hasBin("hermes");
|
|
193
|
+
if (!binFound) return null;
|
|
194
|
+
|
|
195
|
+
const version = getBinVersion("hermes");
|
|
196
|
+
return {
|
|
197
|
+
...agent,
|
|
198
|
+
installed: true,
|
|
199
|
+
version,
|
|
200
|
+
binFound: true,
|
|
201
|
+
configFound: existsSync(agent.configPath),
|
|
261
202
|
};
|
|
262
203
|
}
|
|
263
204
|
|
|
@@ -275,7 +216,6 @@ export function getInstallableAgents() {
|
|
|
275
216
|
* @returns {object|null}
|
|
276
217
|
*/
|
|
277
218
|
export function getRecommendedAgent(useCase) {
|
|
278
|
-
// Prefer OpenCode for programming, Hermes for assistant
|
|
279
219
|
if (useCase === "programming") {
|
|
280
220
|
return AGENT_REGISTRY.find((a) => a.id === "opencode");
|
|
281
221
|
}
|
package/src/lib/install.js
CHANGED
|
@@ -80,8 +80,6 @@ export async function updateAgent(agentId) {
|
|
|
80
80
|
|
|
81
81
|
const updateCmds = {
|
|
82
82
|
opencode: "curl -fsSL https://opencode.ai/install | bash",
|
|
83
|
-
kilo: "npm update -g @kilocode/cli",
|
|
84
|
-
aider: "pip install --upgrade aider-chat",
|
|
85
83
|
hermes: "pip install --upgrade nous-hermes",
|
|
86
84
|
};
|
|
87
85
|
|