calvyn-code 0.14.0 → 0.14.2
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 +83 -83
- package/bin/calvyn.js +23 -1
- package/calvyn_constants.py +62 -43
- package/cli-config.yaml +21 -0
- package/cli.py +12 -6
- package/hermes_bootstrap.py +1 -0
- package/hermes_cli/__init__.py +1 -1
- package/hermes_cli/auth.py +3 -2
- package/hermes_cli/main.py +14 -13
- package/hermes_cli/models.py +7 -3
- package/hermes_cli/providers.py +19 -9
- package/hermes_constants.py +1 -0
- package/hermes_logging.py +1 -0
- package/hermes_state.py +1 -0
- package/hermes_time.py +1 -0
- package/package.json +86 -77
- package/plugins/model-providers/freemodel/__init__.py +16 -0
- package/plugins/model-providers/freemodel/plugin.yaml +5 -0
- package/pyproject.toml +24 -26
- package/scripts/postinstall.js +20 -0
package/README.md
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
<p align="center">
|
|
2
|
-
<img src="assets/banner.png" alt="
|
|
2
|
+
<img src="assets/banner.png" alt="Calvyn Code" width="100%">
|
|
3
3
|
</p>
|
|
4
4
|
|
|
5
|
-
#
|
|
5
|
+
# Calvyn Code ☤
|
|
6
6
|
|
|
7
7
|
<p align="center">
|
|
8
|
-
<a href="https://
|
|
8
|
+
<a href="https://calvyn-code.nousresearch.com/docs/"><img src="https://img.shields.io/badge/Docs-calvyn--code.nousresearch.com-FFD700?style=for-the-badge" alt="Documentation"></a>
|
|
9
9
|
<a href="https://discord.gg/NousResearch"><img src="https://img.shields.io/badge/Discord-5865F2?style=for-the-badge&logo=discord&logoColor=white" alt="Discord"></a>
|
|
10
|
-
<a href="https://github.com/
|
|
10
|
+
<a href="https://github.com/calvyns/calvyn-code/blob/main/LICENSE"><img src="https://img.shields.io/badge/License-MIT-green?style=for-the-badge" alt="License: MIT"></a>
|
|
11
11
|
<a href="https://nousresearch.com"><img src="https://img.shields.io/badge/Built%20by-Nous%20Research-blueviolet?style=for-the-badge" alt="Built by Nous Research"></a>
|
|
12
12
|
<a href="README.zh-CN.md"><img src="https://img.shields.io/badge/Lang-中文-red?style=for-the-badge" alt="中文"></a>
|
|
13
13
|
</p>
|
|
14
14
|
|
|
15
15
|
**The self-improving AI agent built by [Nous Research](https://nousresearch.com).** It's the only agent with a built-in learning loop — it creates skills from experience, improves them during use, nudges itself to persist knowledge, searches its own past conversations, and builds a deepening model of who you are across sessions. Run it on a $5 VPS, a GPU cluster, or serverless infrastructure that costs nearly nothing when idle. It's not tied to your laptop — talk to it from Telegram while it works on a cloud VM.
|
|
16
16
|
|
|
17
|
-
Use any model you want — [Nous Portal](https://portal.nousresearch.com), [OpenRouter](https://openrouter.ai) (200+ models), [NovitaAI](https://novita.ai) (AI-native cloud for Model API, Agent Sandbox, and GPU Cloud), [NVIDIA NIM](https://build.nvidia.com) (Nemotron), [Xiaomi MiMo](https://platform.xiaomimimo.com), [z.ai/GLM](https://z.ai), [Kimi/Moonshot](https://platform.moonshot.ai), [MiniMax](https://www.minimax.io), [Hugging Face](https://huggingface.co), OpenAI, or your own endpoint. Switch with `
|
|
17
|
+
Use any model you want — [Nous Portal](https://portal.nousresearch.com), [OpenRouter](https://openrouter.ai) (200+ models), [NovitaAI](https://novita.ai) (AI-native cloud for Model API, Agent Sandbox, and GPU Cloud), [NVIDIA NIM](https://build.nvidia.com) (Nemotron), [Xiaomi MiMo](https://platform.xiaomimimo.com), [z.ai/GLM](https://z.ai), [Kimi/Moonshot](https://platform.moonshot.ai), [MiniMax](https://www.minimax.io), [Hugging Face](https://huggingface.co), OpenAI, or your own endpoint. Switch with `calvyn model` — no code changes, no lock-in.
|
|
18
18
|
|
|
19
19
|
<table>
|
|
20
20
|
<tr><td><b>A real terminal interface</b></td><td>Full TUI with multiline editing, slash-command autocomplete, conversation history, interrupt-and-redirect, and streaming tool output.</td></tr>
|
|
@@ -28,61 +28,61 @@ Use any model you want — [Nous Portal](https://portal.nousresearch.com), [Open
|
|
|
28
28
|
|
|
29
29
|
---
|
|
30
30
|
|
|
31
|
-
## Quick Install
|
|
32
|
-
|
|
33
|
-
### npm install -g
|
|
34
|
-
|
|
35
|
-
Если хочешь ставить через `npm`, теперь можно так
|
|
36
|
-
|
|
37
|
-
```bash
|
|
38
|
-
npm install -g calvyn-code
|
|
39
|
-
calvyn
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
Что важно
|
|
43
|
-
|
|
44
|
-
- внутри это все равно Python-проект, не Node.js-перепись
|
|
45
|
-
- нужен `Python 3.11+`
|
|
46
|
-
- на Linux, macOS, Windows и Termux эта npm-обертка сама создаст `.venv` и поставит Calvyn
|
|
47
|
-
- на телефоне лучше запускать через Termux где есть и `node`, и `python`
|
|
48
|
-
- публикация в npm требует, чтобы пакет `calvyn-code` был реально выложен в registry
|
|
49
|
-
|
|
50
|
-
Если после установки что-то сломалось
|
|
51
|
-
|
|
52
|
-
```bash
|
|
53
|
-
npm rebuild -g calvyn-code
|
|
54
|
-
calvyn
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
### Linux, macOS, WSL2, Termux
|
|
31
|
+
## Quick Install
|
|
32
|
+
|
|
33
|
+
### npm install -g
|
|
34
|
+
|
|
35
|
+
Если хочешь ставить через `npm`, теперь можно так
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
npm install -g calvyn-code
|
|
39
|
+
calvyn
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Что важно
|
|
43
|
+
|
|
44
|
+
- внутри это все равно Python-проект, не Node.js-перепись
|
|
45
|
+
- нужен `Python 3.11+`
|
|
46
|
+
- на Linux, macOS, Windows и Termux эта npm-обертка сама создаст `.venv` и поставит Calvyn
|
|
47
|
+
- на телефоне лучше запускать через Termux где есть и `node`, и `python`
|
|
48
|
+
- публикация в npm требует, чтобы пакет `calvyn-code` был реально выложен в registry
|
|
49
|
+
|
|
50
|
+
Если после установки что-то сломалось
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
npm rebuild -g calvyn-code
|
|
54
|
+
calvyn
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### Linux, macOS, WSL2, Termux
|
|
58
58
|
|
|
59
59
|
```bash
|
|
60
|
-
curl -fsSL https://raw.githubusercontent.com/
|
|
60
|
+
curl -fsSL https://raw.githubusercontent.com/calvyns/calvyn-code/main/scripts/install.sh | bash
|
|
61
61
|
```
|
|
62
62
|
|
|
63
63
|
### Windows (native, PowerShell) — Early Beta
|
|
64
64
|
|
|
65
|
-
> **Heads up:** Native Windows support is **early beta**. It installs and runs, but hasn't been road-tested as broadly as our Linux/macOS/WSL2 paths. Please [file issues](https://github.com/
|
|
65
|
+
> **Heads up:** Native Windows support is **early beta**. It installs and runs, but hasn't been road-tested as broadly as our Linux/macOS/WSL2 paths. Please [file issues](https://github.com/calvyns/calvyn-code/issues) when you hit rough edges. For the most battle-tested Windows setup today, run the Linux/macOS one-liner above inside **WSL2**.
|
|
66
66
|
|
|
67
67
|
Run this in PowerShell:
|
|
68
68
|
|
|
69
69
|
```powershell
|
|
70
|
-
irm https://raw.githubusercontent.com/
|
|
70
|
+
irm https://raw.githubusercontent.com/calvyns/calvyn-code/main/scripts/install.ps1 | iex
|
|
71
71
|
```
|
|
72
72
|
|
|
73
|
-
The installer handles everything: uv, Python 3.11, Node.js, ripgrep, ffmpeg, **and a portable Git Bash** (MinGit, unpacked to `%LOCALAPPDATA%\
|
|
73
|
+
The installer handles everything: uv, Python 3.11, Node.js, ripgrep, ffmpeg, **and a portable Git Bash** (MinGit, unpacked to `%LOCALAPPDATA%\calvyn\git` — no admin required, completely isolated from any system Git install). Calvyn uses this bundled Git Bash to run shell commands.
|
|
74
74
|
|
|
75
75
|
If you already have Git installed, the installer detects it and uses that instead. Otherwise a ~45MB MinGit download is all you need — it won't touch or interfere with any system Git.
|
|
76
76
|
|
|
77
|
-
> **Android / Termux:** The tested manual path is documented in the [Termux guide](https://
|
|
77
|
+
> **Android / Termux:** The tested manual path is documented in the [Termux guide](https://calvyn-code.nousresearch.com/docs/getting-started/termux). On Termux, Calvyn installs a curated `.[termux]` extra because the full `.[all]` extra currently pulls Android-incompatible voice dependencies.
|
|
78
78
|
>
|
|
79
|
-
> **Windows:** Native Windows is supported as an **early beta** — the PowerShell one-liner above installs everything, but expect rough edges and please file issues when you hit them. If you'd rather use WSL2 (our most battle-tested Windows path), the Linux command works there too. Native Windows install lives under `%LOCALAPPDATA%\
|
|
79
|
+
> **Windows:** Native Windows is supported as an **early beta** — the PowerShell one-liner above installs everything, but expect rough edges and please file issues when you hit them. If you'd rather use WSL2 (our most battle-tested Windows path), the Linux command works there too. Native Windows install lives under `%LOCALAPPDATA%\calvyn`; WSL2 installs under `~/.calvyn` as on Linux. The only Calvyn feature that currently needs WSL2 specifically is the browser-based dashboard chat pane (it uses a POSIX PTY — classic CLI and gateway both run natively).
|
|
80
80
|
|
|
81
81
|
After installation:
|
|
82
82
|
|
|
83
83
|
```bash
|
|
84
84
|
source ~/.bashrc # reload shell (or: source ~/.zshrc)
|
|
85
|
-
|
|
85
|
+
calvyn # start chatting!
|
|
86
86
|
```
|
|
87
87
|
|
|
88
88
|
---
|
|
@@ -90,26 +90,26 @@ hermes # start chatting!
|
|
|
90
90
|
## Getting Started
|
|
91
91
|
|
|
92
92
|
```bash
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
93
|
+
calvyn # Interactive CLI — start a conversation
|
|
94
|
+
calvyn model # Choose your LLM provider and model
|
|
95
|
+
calvyn tools # Configure which tools are enabled
|
|
96
|
+
calvyn config set # Set individual config values
|
|
97
|
+
calvyn gateway # Start the messaging gateway (Telegram, Discord, etc.)
|
|
98
|
+
calvyn setup # Run the full setup wizard (configures everything at once)
|
|
99
|
+
calvyn claw migrate # Migrate from OpenClaw (if coming from OpenClaw)
|
|
100
|
+
calvyn update # Update to the latest version
|
|
101
|
+
calvyn doctor # Diagnose any issues
|
|
102
102
|
```
|
|
103
103
|
|
|
104
|
-
📖 **[Full documentation →](https://
|
|
104
|
+
📖 **[Full documentation →](https://calvyn-code.nousresearch.com/docs/)**
|
|
105
105
|
|
|
106
106
|
## CLI vs Messaging Quick Reference
|
|
107
107
|
|
|
108
|
-
|
|
108
|
+
Calvyn has two entry points: start the terminal UI with `calvyn`, or run the gateway and talk to it from Telegram, Discord, Slack, WhatsApp, Signal, or Email. Once you're in a conversation, many slash commands are shared across both interfaces.
|
|
109
109
|
|
|
110
110
|
| Action | CLI | Messaging platforms |
|
|
111
111
|
|---------|-----|---------------------|
|
|
112
|
-
| Start chatting | `
|
|
112
|
+
| Start chatting | `calvyn` | Run `calvyn gateway setup` + `calvyn gateway start`, then send the bot a message |
|
|
113
113
|
| Start fresh conversation | `/new` or `/reset` | `/new` or `/reset` |
|
|
114
114
|
| Change model | `/model [provider:model]` | `/model [provider:model]` |
|
|
115
115
|
| Set a personality | `/personality [name]` | `/personality [name]` |
|
|
@@ -119,47 +119,47 @@ Hermes has two entry points: start the terminal UI with `hermes`, or run the gat
|
|
|
119
119
|
| Interrupt current work | `Ctrl+C` or send a new message | `/stop` or send a new message |
|
|
120
120
|
| Platform-specific status | `/platforms` | `/status`, `/sethome` |
|
|
121
121
|
|
|
122
|
-
For the full command lists, see the [CLI guide](https://
|
|
122
|
+
For the full command lists, see the [CLI guide](https://calvyn-code.nousresearch.com/docs/user-guide/cli) and the [Messaging Gateway guide](https://calvyn-code.nousresearch.com/docs/user-guide/messaging).
|
|
123
123
|
|
|
124
124
|
---
|
|
125
125
|
|
|
126
126
|
## Documentation
|
|
127
127
|
|
|
128
|
-
All documentation lives at **[
|
|
128
|
+
All documentation lives at **[calvyn-code.nousresearch.com/docs](https://calvyn-code.nousresearch.com/docs/)**:
|
|
129
129
|
|
|
130
130
|
| Section | What's Covered |
|
|
131
131
|
|---------|---------------|
|
|
132
|
-
| [Quickstart](https://
|
|
133
|
-
| [CLI Usage](https://
|
|
134
|
-
| [Configuration](https://
|
|
135
|
-
| [Messaging Gateway](https://
|
|
136
|
-
| [Security](https://
|
|
137
|
-
| [Tools & Toolsets](https://
|
|
138
|
-
| [Skills System](https://
|
|
139
|
-
| [Memory](https://
|
|
140
|
-
| [MCP Integration](https://
|
|
141
|
-
| [Cron Scheduling](https://
|
|
142
|
-
| [Context Files](https://
|
|
143
|
-
| [Architecture](https://
|
|
144
|
-
| [Contributing](https://
|
|
145
|
-
| [CLI Reference](https://
|
|
146
|
-
| [Environment Variables](https://
|
|
132
|
+
| [Quickstart](https://calvyn-code.nousresearch.com/docs/getting-started/quickstart) | Install → setup → first conversation in 2 minutes |
|
|
133
|
+
| [CLI Usage](https://calvyn-code.nousresearch.com/docs/user-guide/cli) | Commands, keybindings, personalities, sessions |
|
|
134
|
+
| [Configuration](https://calvyn-code.nousresearch.com/docs/user-guide/configuration) | Config file, providers, models, all options |
|
|
135
|
+
| [Messaging Gateway](https://calvyn-code.nousresearch.com/docs/user-guide/messaging) | Telegram, Discord, Slack, WhatsApp, Signal, Home Assistant |
|
|
136
|
+
| [Security](https://calvyn-code.nousresearch.com/docs/user-guide/security) | Command approval, DM pairing, container isolation |
|
|
137
|
+
| [Tools & Toolsets](https://calvyn-code.nousresearch.com/docs/user-guide/features/tools) | 40+ tools, toolset system, terminal backends |
|
|
138
|
+
| [Skills System](https://calvyn-code.nousresearch.com/docs/user-guide/features/skills) | Procedural memory, Skills Hub, creating skills |
|
|
139
|
+
| [Memory](https://calvyn-code.nousresearch.com/docs/user-guide/features/memory) | Persistent memory, user profiles, best practices |
|
|
140
|
+
| [MCP Integration](https://calvyn-code.nousresearch.com/docs/user-guide/features/mcp) | Connect any MCP server for extended capabilities |
|
|
141
|
+
| [Cron Scheduling](https://calvyn-code.nousresearch.com/docs/user-guide/features/cron) | Scheduled tasks with platform delivery |
|
|
142
|
+
| [Context Files](https://calvyn-code.nousresearch.com/docs/user-guide/features/context-files) | Project context that shapes every conversation |
|
|
143
|
+
| [Architecture](https://calvyn-code.nousresearch.com/docs/developer-guide/architecture) | Project structure, agent loop, key classes |
|
|
144
|
+
| [Contributing](https://calvyn-code.nousresearch.com/docs/developer-guide/contributing) | Development setup, PR process, code style |
|
|
145
|
+
| [CLI Reference](https://calvyn-code.nousresearch.com/docs/reference/cli-commands) | All commands and flags |
|
|
146
|
+
| [Environment Variables](https://calvyn-code.nousresearch.com/docs/reference/environment-variables) | Complete env var reference |
|
|
147
147
|
|
|
148
148
|
---
|
|
149
149
|
|
|
150
150
|
## Migrating from OpenClaw
|
|
151
151
|
|
|
152
|
-
If you're coming from OpenClaw,
|
|
152
|
+
If you're coming from OpenClaw, Calvyn can automatically import your settings, memories, skills, and API keys.
|
|
153
153
|
|
|
154
|
-
**During first-time setup:** The setup wizard (`
|
|
154
|
+
**During first-time setup:** The setup wizard (`calvyn setup`) automatically detects `~/.openclaw` and offers to migrate before configuration begins.
|
|
155
155
|
|
|
156
156
|
**Anytime after install:**
|
|
157
157
|
|
|
158
158
|
```bash
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
159
|
+
calvyn claw migrate # Interactive migration (full preset)
|
|
160
|
+
calvyn claw migrate --dry-run # Preview what would be migrated
|
|
161
|
+
calvyn claw migrate --preset user-data # Migrate without secrets
|
|
162
|
+
calvyn claw migrate --overwrite # Overwrite existing conflicts
|
|
163
163
|
```
|
|
164
164
|
|
|
165
165
|
What gets imported:
|
|
@@ -172,21 +172,21 @@ What gets imported:
|
|
|
172
172
|
- **TTS assets** — workspace audio files
|
|
173
173
|
- **Workspace instructions** — AGENTS.md (with `--workspace-target`)
|
|
174
174
|
|
|
175
|
-
See `
|
|
175
|
+
See `calvyn claw migrate --help` for all options, or use the `openclaw-migration` skill for an interactive agent-guided migration with dry-run previews.
|
|
176
176
|
|
|
177
177
|
---
|
|
178
178
|
|
|
179
179
|
## Contributing
|
|
180
180
|
|
|
181
|
-
We welcome contributions! See the [Contributing Guide](https://
|
|
181
|
+
We welcome contributions! See the [Contributing Guide](https://calvyn-code.nousresearch.com/docs/developer-guide/contributing) for development setup, code style, and PR process.
|
|
182
182
|
|
|
183
|
-
Quick start for contributors — clone and go with `setup-
|
|
183
|
+
Quick start for contributors — clone and go with `setup-calvyn.sh`:
|
|
184
184
|
|
|
185
185
|
```bash
|
|
186
|
-
git clone https://github.com/
|
|
187
|
-
cd
|
|
188
|
-
./setup-
|
|
189
|
-
./
|
|
186
|
+
git clone https://github.com/calvyns/calvyn-code.git
|
|
187
|
+
cd calvyn-code
|
|
188
|
+
./setup-calvyn.sh # installs uv, creates venv, installs .[all], symlinks ~/.local/bin/calvyn
|
|
189
|
+
./calvyn # auto-detects the venv, no need to `source` first
|
|
190
190
|
```
|
|
191
191
|
|
|
192
192
|
Manual path (equivalent to the above):
|
|
@@ -205,8 +205,8 @@ scripts/run_tests.sh
|
|
|
205
205
|
|
|
206
206
|
- 💬 [Discord](https://discord.gg/NousResearch)
|
|
207
207
|
- 📚 [Skills Hub](https://agentskills.io)
|
|
208
|
-
- 🐛 [Issues](https://github.com/
|
|
209
|
-
- 🔌 [HermesClaw](https://github.com/AaronWong1999/hermesclaw) — Community WeChat bridge: Run
|
|
208
|
+
- 🐛 [Issues](https://github.com/calvyns/calvyn-code/issues)
|
|
209
|
+
- 🔌 [HermesClaw](https://github.com/AaronWong1999/hermesclaw) — Community WeChat bridge: Run Calvyn Code and OpenClaw on the same WeChat account.
|
|
210
210
|
|
|
211
211
|
---
|
|
212
212
|
|
package/bin/calvyn.js
CHANGED
|
@@ -49,14 +49,36 @@ function runPostinstallIfNeeded() {
|
|
|
49
49
|
return calvynBinary
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
+
function shouldShowBanner(args) {
|
|
53
|
+
if (!args.length) return true
|
|
54
|
+
const first = String(args[0] || "").trim().toLowerCase()
|
|
55
|
+
return !["-h", "--help", "-v", "--version", "version"].includes(first)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function printNpmLaunchHeader() {
|
|
59
|
+
console.log("")
|
|
60
|
+
console.log("")
|
|
61
|
+
console.log("")
|
|
62
|
+
console.log(" ╔════════════════════════════════════════════════════════════════════════════╗")
|
|
63
|
+
console.log(" ║ ✦ CALVYN CODE ║")
|
|
64
|
+
console.log(" ║ Запуск через npm ║")
|
|
65
|
+
console.log(" ╚════════════════════════════════════════════════════════════════════════════╝")
|
|
66
|
+
console.log("")
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const args = process.argv.slice(2)
|
|
52
70
|
const calvynBinary = runPostinstallIfNeeded()
|
|
53
|
-
|
|
71
|
+
if (shouldShowBanner(args)) {
|
|
72
|
+
printNpmLaunchHeader()
|
|
73
|
+
}
|
|
74
|
+
const result = spawnSync(calvynBinary, args, {
|
|
54
75
|
stdio: "inherit",
|
|
55
76
|
shell: false,
|
|
56
77
|
env: {
|
|
57
78
|
...process.env,
|
|
58
79
|
CALVYN_LAUNCHED_FROM_NPM: "1",
|
|
59
80
|
CALVYN_REPO_ROOT: packageRoot,
|
|
81
|
+
CALVYN_HOME: process.env.CALVYN_HOME || path.join(require("os").homedir(), ".calvyn"),
|
|
60
82
|
},
|
|
61
83
|
})
|
|
62
84
|
|
package/calvyn_constants.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"""Shared constants for
|
|
1
|
+
"""Shared constants for Calvyn Code.
|
|
2
2
|
|
|
3
3
|
Import-safe module with no dependencies — can be imported from anywhere
|
|
4
4
|
without risk of circular imports.
|
|
@@ -8,14 +8,24 @@ import os
|
|
|
8
8
|
from pathlib import Path
|
|
9
9
|
|
|
10
10
|
|
|
11
|
-
_profile_fallback_warned: bool = False
|
|
11
|
+
_profile_fallback_warned: bool = False
|
|
12
|
+
_CALVYN_HOME_ENV = "CALVYN_HOME"
|
|
13
|
+
_LEGACY_HOME_ENV = "HERMES_HOME"
|
|
14
|
+
_DEFAULT_HOME_DIRNAME = ".calvyn"
|
|
15
|
+
_LEGACY_HOME_DIRNAME = ".hermes"
|
|
12
16
|
|
|
13
17
|
|
|
14
|
-
def get_hermes_home() -> Path:
|
|
15
|
-
"""Return the
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
18
|
+
def get_hermes_home() -> Path:
|
|
19
|
+
"""Return the Calvyn home directory.
|
|
20
|
+
|
|
21
|
+
Preference order:
|
|
22
|
+
1. ``CALVYN_HOME``
|
|
23
|
+
2. ``HERMES_HOME`` for legacy compatibility
|
|
24
|
+
3. ``~/.calvyn``
|
|
25
|
+
4. ``~/.hermes`` only when it already exists and ``~/.calvyn`` does not
|
|
26
|
+
|
|
27
|
+
This keeps Calvyn isolated from Hermes by default while still allowing
|
|
28
|
+
explicit legacy overrides.
|
|
19
29
|
|
|
20
30
|
When ``HERMES_HOME`` is unset but an ``active_profile`` file indicates
|
|
21
31
|
a non-default profile is active, logs a loud one-shot warning to
|
|
@@ -27,22 +37,26 @@ def get_hermes_home() -> Path:
|
|
|
27
37
|
template in ``hermes_cli/gateway.py`` and the kanban dispatcher in
|
|
28
38
|
``hermes_cli/kanban_db.py``). See https://github.com/NousResearch/hermes-agent/issues/18594.
|
|
29
39
|
"""
|
|
30
|
-
val = os.environ.get(
|
|
31
|
-
if val:
|
|
32
|
-
return Path(val)
|
|
40
|
+
val = os.environ.get(_CALVYN_HOME_ENV, "").strip()
|
|
41
|
+
if val:
|
|
42
|
+
return Path(val)
|
|
43
|
+
|
|
44
|
+
val = os.environ.get(_LEGACY_HOME_ENV, "").strip()
|
|
45
|
+
if val:
|
|
46
|
+
return Path(val)
|
|
33
47
|
|
|
34
48
|
# Guard: if a non-default profile is sticky-active, warn once that
|
|
35
49
|
# the fallback to the default profile is almost certainly wrong.
|
|
36
50
|
global _profile_fallback_warned
|
|
37
51
|
if not _profile_fallback_warned:
|
|
38
52
|
try:
|
|
39
|
-
# Inline the default-root resolution from get_default_hermes_root()
|
|
40
|
-
# to stay import-safe (this function is called from module scope
|
|
41
|
-
# in 30+ files; we cannot afford to trigger logging setup here).
|
|
42
|
-
active_path = (Path.home() /
|
|
43
|
-
active = active_path.read_text().strip() if active_path.exists() else ""
|
|
44
|
-
except (UnicodeDecodeError, OSError):
|
|
45
|
-
active = ""
|
|
53
|
+
# Inline the default-root resolution from get_default_hermes_root()
|
|
54
|
+
# to stay import-safe (this function is called from module scope
|
|
55
|
+
# in 30+ files; we cannot afford to trigger logging setup here).
|
|
56
|
+
active_path = (Path.home() / _DEFAULT_HOME_DIRNAME / "active_profile")
|
|
57
|
+
active = active_path.read_text().strip() if active_path.exists() else ""
|
|
58
|
+
except (UnicodeDecodeError, OSError):
|
|
59
|
+
active = ""
|
|
46
60
|
if active and active != "default":
|
|
47
61
|
_profile_fallback_warned = True
|
|
48
62
|
# Write directly to stderr. We intentionally do NOT route this
|
|
@@ -52,24 +66,28 @@ def get_hermes_home() -> Path:
|
|
|
52
66
|
# on consoles where a StreamHandler is already attached.
|
|
53
67
|
import sys
|
|
54
68
|
msg = (
|
|
55
|
-
f"[
|
|
56
|
-
f"profile is {active!r}. Falling back to
|
|
57
|
-
f"is the DEFAULT profile — not {active!r}. Any data this "
|
|
58
|
-
f"process writes will land in the wrong profile. The "
|
|
59
|
-
f"subprocess spawner should pass
|
|
60
|
-
f"(see issue #18594)."
|
|
61
|
-
)
|
|
69
|
+
f"[CALVYN_HOME fallback] CALVYN_HOME is unset but active "
|
|
70
|
+
f"profile is {active!r}. Falling back to ~/{_DEFAULT_HOME_DIRNAME}, which "
|
|
71
|
+
f"is the DEFAULT profile — not {active!r}. Any data this "
|
|
72
|
+
f"process writes will land in the wrong profile. The "
|
|
73
|
+
f"subprocess spawner should pass CALVYN_HOME explicitly "
|
|
74
|
+
f"(see issue #18594)."
|
|
75
|
+
)
|
|
62
76
|
try:
|
|
63
77
|
sys.stderr.write(msg + "\n")
|
|
64
78
|
sys.stderr.flush()
|
|
65
79
|
except Exception:
|
|
66
80
|
pass
|
|
67
81
|
|
|
68
|
-
|
|
82
|
+
calvyn_home = Path.home() / _DEFAULT_HOME_DIRNAME
|
|
83
|
+
legacy_home = Path.home() / _LEGACY_HOME_DIRNAME
|
|
84
|
+
if calvyn_home.exists() or not legacy_home.exists():
|
|
85
|
+
return calvyn_home
|
|
86
|
+
return legacy_home
|
|
69
87
|
|
|
70
88
|
|
|
71
|
-
def get_default_hermes_root() -> Path:
|
|
72
|
-
"""Return the root
|
|
89
|
+
def get_default_hermes_root() -> Path:
|
|
90
|
+
"""Return the root Calvyn directory for profile-level operations.
|
|
73
91
|
|
|
74
92
|
In standard deployments this is ``~/.hermes``.
|
|
75
93
|
|
|
@@ -84,8 +102,8 @@ def get_default_hermes_root() -> Path:
|
|
|
84
102
|
|
|
85
103
|
Import-safe — no dependencies beyond stdlib.
|
|
86
104
|
"""
|
|
87
|
-
native_home = Path.home() /
|
|
88
|
-
env_home = os.environ.get("
|
|
105
|
+
native_home = Path.home() / _DEFAULT_HOME_DIRNAME
|
|
106
|
+
env_home = os.environ.get(_CALVYN_HOME_ENV, "") or os.environ.get(_LEGACY_HOME_ENV, "")
|
|
89
107
|
if not env_home:
|
|
90
108
|
return native_home
|
|
91
109
|
env_path = Path(env_home)
|
|
@@ -110,10 +128,11 @@ def get_default_hermes_root() -> Path:
|
|
|
110
128
|
def get_optional_skills_dir(default: Path | None = None) -> Path:
|
|
111
129
|
"""Return the optional-skills directory, honoring package-manager wrappers.
|
|
112
130
|
|
|
113
|
-
Packaged installs may ship ``optional-skills`` outside the Python package
|
|
114
|
-
tree and expose it via ``
|
|
115
|
-
|
|
116
|
-
|
|
131
|
+
Packaged installs may ship ``optional-skills`` outside the Python package
|
|
132
|
+
tree and expose it via ``CALVYN_OPTIONAL_SKILLS`` or the legacy
|
|
133
|
+
``HERMES_OPTIONAL_SKILLS``.
|
|
134
|
+
"""
|
|
135
|
+
override = os.getenv("CALVYN_OPTIONAL_SKILLS", "").strip() or os.getenv("HERMES_OPTIONAL_SKILLS", "").strip()
|
|
117
136
|
if override:
|
|
118
137
|
return Path(override)
|
|
119
138
|
if default is not None:
|
|
@@ -122,7 +141,7 @@ def get_optional_skills_dir(default: Path | None = None) -> Path:
|
|
|
122
141
|
|
|
123
142
|
|
|
124
143
|
def get_hermes_dir(new_subpath: str, old_name: str) -> Path:
|
|
125
|
-
"""Resolve a
|
|
144
|
+
"""Resolve a Calvyn subdirectory with backward compatibility.
|
|
126
145
|
|
|
127
146
|
New installs get the consolidated layout (e.g. ``cache/images``).
|
|
128
147
|
Existing installs that already have the old path (e.g. ``image_cache``)
|
|
@@ -143,17 +162,17 @@ def get_hermes_dir(new_subpath: str, old_name: str) -> Path:
|
|
|
143
162
|
|
|
144
163
|
|
|
145
164
|
def display_hermes_home() -> str:
|
|
146
|
-
"""Return a user-friendly display string for the current
|
|
165
|
+
"""Return a user-friendly display string for the current Calvyn home.
|
|
147
166
|
|
|
148
167
|
Uses ``~/`` shorthand for readability::
|
|
149
168
|
|
|
150
|
-
default: ``~/.
|
|
151
|
-
profile: ``~/.
|
|
152
|
-
custom: ``/opt/hermes-custom``
|
|
169
|
+
default: ``~/.calvyn``
|
|
170
|
+
profile: ``~/.calvyn/profiles/coder``
|
|
171
|
+
custom: ``/opt/hermes-custom``
|
|
153
172
|
|
|
154
|
-
Use this in **user-facing** print/log messages instead of hardcoding
|
|
155
|
-
``~/.
|
|
156
|
-
:func:`get_hermes_home` instead.
|
|
173
|
+
Use this in **user-facing** print/log messages instead of hardcoding
|
|
174
|
+
``~/.calvyn``. For code that needs a real ``Path``, use
|
|
175
|
+
:func:`get_hermes_home` instead.
|
|
157
176
|
"""
|
|
158
177
|
home = get_hermes_home()
|
|
159
178
|
try:
|
|
@@ -165,7 +184,7 @@ def display_hermes_home() -> str:
|
|
|
165
184
|
def get_subprocess_home() -> str | None:
|
|
166
185
|
"""Return a per-profile HOME directory for subprocesses, or None.
|
|
167
186
|
|
|
168
|
-
When ``{
|
|
187
|
+
When ``{CALVYN_HOME}/home/`` exists on disk, subprocesses should use it
|
|
169
188
|
as ``HOME`` so system tools (git, ssh, gh, npm …) write their configs
|
|
170
189
|
inside the Hermes data directory instead of the OS-level ``/root`` or
|
|
171
190
|
``~/``. This provides:
|
|
@@ -179,7 +198,7 @@ def get_subprocess_home() -> str | None:
|
|
|
179
198
|
Activation is directory-based: if the ``home/`` subdirectory doesn't
|
|
180
199
|
exist, returns ``None`` and behavior is unchanged.
|
|
181
200
|
"""
|
|
182
|
-
hermes_home = os.getenv(
|
|
201
|
+
hermes_home = os.getenv(_CALVYN_HOME_ENV) or os.getenv(_LEGACY_HOME_ENV)
|
|
183
202
|
if not hermes_home:
|
|
184
203
|
return None
|
|
185
204
|
profile_home = os.path.join(hermes_home, "home")
|
package/cli-config.yaml
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
model:
|
|
2
|
+
provider: "freemodel"
|
|
3
|
+
default: "gpt-5.5"
|
|
4
|
+
base_url: "https://api.freemodel.dev"
|
|
5
|
+
api_mode: "codex_responses"
|
|
6
|
+
|
|
7
|
+
agent:
|
|
8
|
+
reasoning_effort: "xhigh"
|
|
9
|
+
|
|
10
|
+
providers:
|
|
11
|
+
freemodel:
|
|
12
|
+
name: "freemodel"
|
|
13
|
+
base_url: "https://api.freemodel.dev"
|
|
14
|
+
key_env: "FREEMODEL_API_KEY"
|
|
15
|
+
api_mode: "codex_responses"
|
|
16
|
+
model: "gpt-5.5"
|
|
17
|
+
|
|
18
|
+
model_provider: "freemodel"
|
|
19
|
+
model_reasoning_effort: "xhigh"
|
|
20
|
+
disable_response_storage: true
|
|
21
|
+
preferred_auth_method: "apikey"
|
package/cli.py
CHANGED
|
@@ -11542,12 +11542,18 @@ class HermesCLI:
|
|
|
11542
11542
|
# responses, and prompt all appear pinned to the bottom — empty
|
|
11543
11543
|
# space stays above, not below. This prints enough blank lines to
|
|
11544
11544
|
# scroll the cursor to the last row before any content is rendered.
|
|
11545
|
-
try:
|
|
11546
|
-
|
|
11547
|
-
|
|
11548
|
-
|
|
11549
|
-
|
|
11550
|
-
|
|
11545
|
+
try:
|
|
11546
|
+
if os.getenv("CALVYN_LAUNCHED_FROM_NPM", "").strip().lower() not in {
|
|
11547
|
+
"1",
|
|
11548
|
+
"true",
|
|
11549
|
+
"yes",
|
|
11550
|
+
"on",
|
|
11551
|
+
}:
|
|
11552
|
+
_term_lines = shutil.get_terminal_size().lines
|
|
11553
|
+
if _term_lines > 2:
|
|
11554
|
+
print("\n" * (_term_lines - 1), end="", flush=True)
|
|
11555
|
+
except Exception:
|
|
11556
|
+
pass
|
|
11551
11557
|
|
|
11552
11558
|
self.show_banner()
|
|
11553
11559
|
# Surface any active supply-chain security advisories right after the
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from calvyn_bootstrap import * # noqa: F401,F403
|
package/hermes_cli/__init__.py
CHANGED
package/hermes_cli/auth.py
CHANGED
|
@@ -1387,8 +1387,9 @@ def resolve_provider(
|
|
|
1387
1387
|
"kimi": "kimi-coding", "kimi-for-coding": "kimi-coding", "moonshot": "kimi-coding",
|
|
1388
1388
|
"kimi-cn": "kimi-coding-cn", "moonshot-cn": "kimi-coding-cn",
|
|
1389
1389
|
"step": "stepfun", "stepfun-coding-plan": "stepfun",
|
|
1390
|
-
"arcee-ai": "arcee", "arceeai": "arcee",
|
|
1391
|
-
"gmi-cloud": "gmi", "gmicloud": "gmi",
|
|
1390
|
+
"arcee-ai": "arcee", "arceeai": "arcee",
|
|
1391
|
+
"gmi-cloud": "gmi", "gmicloud": "gmi",
|
|
1392
|
+
"freemodel": "freemodel", "free-model": "freemodel", "free_model": "freemodel",
|
|
1392
1393
|
"minimax-china": "minimax-cn", "minimax_cn": "minimax-cn",
|
|
1393
1394
|
"minimax-portal": "minimax-oauth", "minimax-global": "minimax-oauth", "minimax_oauth": "minimax-oauth",
|
|
1394
1395
|
"alibaba_coding": "alibaba-coding-plan", "alibaba-coding": "alibaba-coding-plan",
|
package/hermes_cli/main.py
CHANGED
|
@@ -2011,11 +2011,11 @@ def select_provider_and_model(args=None):
|
|
|
2011
2011
|
_model_flow_bedrock(config, current_model)
|
|
2012
2012
|
elif selected_provider == "azure-foundry":
|
|
2013
2013
|
_model_flow_azure_foundry(config, current_model)
|
|
2014
|
-
elif selected_provider in {
|
|
2015
|
-
"gemini",
|
|
2016
|
-
"deepseek",
|
|
2017
|
-
"xai",
|
|
2018
|
-
"zai",
|
|
2014
|
+
elif selected_provider in {
|
|
2015
|
+
"gemini",
|
|
2016
|
+
"deepseek",
|
|
2017
|
+
"xai",
|
|
2018
|
+
"zai",
|
|
2019
2019
|
"kimi-coding-cn",
|
|
2020
2020
|
"minimax",
|
|
2021
2021
|
"minimax-cn",
|
|
@@ -2024,14 +2024,15 @@ def select_provider_and_model(args=None):
|
|
|
2024
2024
|
"opencode-go",
|
|
2025
2025
|
"alibaba",
|
|
2026
2026
|
"huggingface",
|
|
2027
|
-
"xiaomi",
|
|
2028
|
-
"arcee",
|
|
2029
|
-
"gmi",
|
|
2030
|
-
"
|
|
2031
|
-
"
|
|
2032
|
-
"
|
|
2033
|
-
"
|
|
2034
|
-
|
|
2027
|
+
"xiaomi",
|
|
2028
|
+
"arcee",
|
|
2029
|
+
"gmi",
|
|
2030
|
+
"freemodel",
|
|
2031
|
+
"nvidia",
|
|
2032
|
+
"ollama-cloud",
|
|
2033
|
+
"tencent-tokenhub",
|
|
2034
|
+
"lmstudio",
|
|
2035
|
+
} or _is_profile_api_key_provider(selected_provider):
|
|
2035
2036
|
_model_flow_api_key_provider(config, selected_provider, current_model)
|
|
2036
2037
|
|
|
2037
2038
|
# ── Post-switch cleanup: clear stale OPENAI_BASE_URL ──────────────
|
package/hermes_cli/models.py
CHANGED
|
@@ -949,7 +949,8 @@ CANONICAL_PROVIDERS: list[ProviderEntry] = [
|
|
|
949
949
|
ProviderEntry("minimax-cn", "MiniMax (China)", "MiniMax China (domestic direct API)"),
|
|
950
950
|
ProviderEntry("ollama-cloud", "Ollama Cloud", "Ollama Cloud (cloud-hosted open models — ollama.com)"),
|
|
951
951
|
ProviderEntry("arcee", "Arcee AI", "Arcee AI (Trinity models — direct API)"),
|
|
952
|
-
ProviderEntry("gmi", "GMI Cloud", "GMI Cloud (multi-model direct API)"),
|
|
952
|
+
ProviderEntry("gmi", "GMI Cloud", "GMI Cloud (multi-model direct API)"),
|
|
953
|
+
ProviderEntry("freemodel", "FreeModel", "FreeModel (OpenAI-compatible direct API)"),
|
|
953
954
|
ProviderEntry("kilocode", "Kilo Code", "Kilo Code (Kilo Gateway API)"),
|
|
954
955
|
ProviderEntry("opencode-zen", "OpenCode Zen", "OpenCode Zen (35+ curated models, pay-as-you-go)"),
|
|
955
956
|
ProviderEntry("opencode-go", "OpenCode Go", "OpenCode Go (open models, $10/month subscription)"),
|
|
@@ -1005,8 +1006,11 @@ _PROVIDER_ALIASES = {
|
|
|
1005
1006
|
"stepfun-coding-plan": "stepfun",
|
|
1006
1007
|
"arcee-ai": "arcee",
|
|
1007
1008
|
"arceeai": "arcee",
|
|
1008
|
-
"gmi-cloud": "gmi",
|
|
1009
|
-
"gmicloud": "gmi",
|
|
1009
|
+
"gmi-cloud": "gmi",
|
|
1010
|
+
"gmicloud": "gmi",
|
|
1011
|
+
"freemodel": "freemodel",
|
|
1012
|
+
"free-model": "freemodel",
|
|
1013
|
+
"free_model": "freemodel",
|
|
1010
1014
|
"minimax-china": "minimax-cn",
|
|
1011
1015
|
"minimax_cn": "minimax-cn",
|
|
1012
1016
|
"minimax-portal": "minimax-oauth",
|
package/hermes_cli/providers.py
CHANGED
|
@@ -190,12 +190,18 @@ HERMES_OVERLAYS: Dict[str, HermesOverlay] = {
|
|
|
190
190
|
base_url_override="https://api.arcee.ai/api/v1",
|
|
191
191
|
base_url_env_var="ARCEE_BASE_URL",
|
|
192
192
|
),
|
|
193
|
-
"gmi": HermesOverlay(
|
|
194
|
-
transport="openai_chat",
|
|
195
|
-
extra_env_vars=("GMI_API_KEY",),
|
|
196
|
-
base_url_override="https://api.gmi-serving.com/v1",
|
|
197
|
-
base_url_env_var="GMI_BASE_URL",
|
|
198
|
-
),
|
|
193
|
+
"gmi": HermesOverlay(
|
|
194
|
+
transport="openai_chat",
|
|
195
|
+
extra_env_vars=("GMI_API_KEY",),
|
|
196
|
+
base_url_override="https://api.gmi-serving.com/v1",
|
|
197
|
+
base_url_env_var="GMI_BASE_URL",
|
|
198
|
+
),
|
|
199
|
+
"freemodel": HermesOverlay(
|
|
200
|
+
transport="openai_chat",
|
|
201
|
+
extra_env_vars=("FREEMODEL_API_KEY",),
|
|
202
|
+
base_url_override="https://api.freemodel.xyz/v1",
|
|
203
|
+
base_url_env_var="FREEMODEL_BASE_URL",
|
|
204
|
+
),
|
|
199
205
|
"ollama-cloud": HermesOverlay(
|
|
200
206
|
transport="openai_chat",
|
|
201
207
|
base_url_env_var="OLLAMA_BASE_URL",
|
|
@@ -349,8 +355,11 @@ ALIASES: Dict[str, str] = {
|
|
|
349
355
|
"arceeai": "arcee",
|
|
350
356
|
|
|
351
357
|
# gmi
|
|
352
|
-
"gmi-cloud": "gmi",
|
|
353
|
-
"gmicloud": "gmi",
|
|
358
|
+
"gmi-cloud": "gmi",
|
|
359
|
+
"gmicloud": "gmi",
|
|
360
|
+
"freemodel": "freemodel",
|
|
361
|
+
"free-model": "freemodel",
|
|
362
|
+
"free_model": "freemodel",
|
|
354
363
|
|
|
355
364
|
# Local server aliases → virtual "local" concept (resolved via user config)
|
|
356
365
|
"lmstudio": "lmstudio",
|
|
@@ -374,7 +383,8 @@ _LABEL_OVERRIDES: Dict[str, str] = {
|
|
|
374
383
|
"copilot-acp": "GitHub Copilot ACP",
|
|
375
384
|
"stepfun": "StepFun Step Plan",
|
|
376
385
|
"xiaomi": "Xiaomi MiMo",
|
|
377
|
-
"gmi": "GMI Cloud",
|
|
386
|
+
"gmi": "GMI Cloud",
|
|
387
|
+
"freemodel": "FreeModel",
|
|
378
388
|
"tencent-tokenhub": "Tencent TokenHub",
|
|
379
389
|
"lmstudio": "LM Studio",
|
|
380
390
|
"local": "Local endpoint",
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from calvyn_constants import * # noqa: F401,F403
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from calvyn_logging import * # noqa: F401,F403
|
package/hermes_state.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from calvyn_state import * # noqa: F401,F403
|
package/hermes_time.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from calvyn_time import * # noqa: F401,F403
|
package/package.json
CHANGED
|
@@ -1,78 +1,87 @@
|
|
|
1
1
|
{
|
|
2
|
-
"name": "calvyn-code",
|
|
3
|
-
"version": "0.14.
|
|
4
|
-
"description": "Calvyn Code — AI агент с инструментами, мессенджерами и локальным CLI",
|
|
5
|
-
"bin": {
|
|
6
|
-
"calvyn": "./bin/calvyn.js"
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
"
|
|
10
|
-
|
|
11
|
-
"
|
|
12
|
-
"
|
|
13
|
-
"
|
|
14
|
-
"
|
|
15
|
-
"
|
|
16
|
-
"
|
|
17
|
-
"
|
|
18
|
-
"
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
"
|
|
22
|
-
"
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
"
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
"
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
"
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
"
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
"
|
|
49
|
-
"
|
|
50
|
-
"
|
|
51
|
-
"
|
|
52
|
-
"
|
|
53
|
-
"
|
|
54
|
-
"
|
|
55
|
-
"
|
|
56
|
-
"
|
|
57
|
-
"
|
|
58
|
-
"
|
|
59
|
-
"
|
|
60
|
-
"
|
|
61
|
-
"
|
|
62
|
-
"
|
|
63
|
-
"
|
|
64
|
-
"
|
|
65
|
-
"
|
|
66
|
-
"
|
|
67
|
-
"
|
|
68
|
-
"
|
|
69
|
-
"
|
|
70
|
-
"
|
|
71
|
-
"
|
|
72
|
-
"
|
|
73
|
-
"
|
|
74
|
-
"
|
|
75
|
-
"
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
2
|
+
"name": "calvyn-code",
|
|
3
|
+
"version": "0.14.2",
|
|
4
|
+
"description": "Calvyn Code — AI агент с инструментами, мессенджерами и локальным CLI",
|
|
5
|
+
"bin": {
|
|
6
|
+
"calvyn": "./bin/calvyn.js",
|
|
7
|
+
"calvyn-code": "./bin/calvyn.js"
|
|
8
|
+
},
|
|
9
|
+
"main": "./bin/calvyn.js",
|
|
10
|
+
"keywords": [
|
|
11
|
+
"ai",
|
|
12
|
+
"agent",
|
|
13
|
+
"cli",
|
|
14
|
+
"calvyn",
|
|
15
|
+
"python",
|
|
16
|
+
"telegram",
|
|
17
|
+
"discord",
|
|
18
|
+
"slack",
|
|
19
|
+
"whatsapp"
|
|
20
|
+
],
|
|
21
|
+
"author": "Calvyn Code Contributors",
|
|
22
|
+
"homepage": "https://github.com/calvyns/calvyn-code#readme",
|
|
23
|
+
"scripts": {
|
|
24
|
+
"postinstall": "node ./scripts/postinstall.js"
|
|
25
|
+
},
|
|
26
|
+
"repository": {
|
|
27
|
+
"type": "git",
|
|
28
|
+
"url": "git+https://github.com/calvyns/calvyn-code.git"
|
|
29
|
+
},
|
|
30
|
+
"license": "MIT",
|
|
31
|
+
"bugs": {
|
|
32
|
+
"url": "https://github.com/calvyns/calvyn-code/issues"
|
|
33
|
+
},
|
|
34
|
+
"dependencies": {
|
|
35
|
+
"@askjo/camofox-browser": "^1.5.2",
|
|
36
|
+
"agent-browser": "^0.26.0"
|
|
37
|
+
},
|
|
38
|
+
"overrides": {
|
|
39
|
+
"lodash": "4.18.1"
|
|
40
|
+
},
|
|
41
|
+
"engines": {
|
|
42
|
+
"node": ">=20.0.0"
|
|
43
|
+
},
|
|
44
|
+
"publishConfig": {
|
|
45
|
+
"access": "public"
|
|
46
|
+
},
|
|
47
|
+
"files": [
|
|
48
|
+
"bin",
|
|
49
|
+
"scripts",
|
|
50
|
+
"hermes_cli",
|
|
51
|
+
"agent",
|
|
52
|
+
"gateway",
|
|
53
|
+
"tui_gateway",
|
|
54
|
+
"cron",
|
|
55
|
+
"acp_adapter",
|
|
56
|
+
"plugins",
|
|
57
|
+
"providers",
|
|
58
|
+
"tools",
|
|
59
|
+
"assets",
|
|
60
|
+
"locales",
|
|
61
|
+
"optional-skills",
|
|
62
|
+
"skills",
|
|
63
|
+
"run_agent.py",
|
|
64
|
+
"model_tools.py",
|
|
65
|
+
"toolsets.py",
|
|
66
|
+
"batch_runner.py",
|
|
67
|
+
"trajectory_compressor.py",
|
|
68
|
+
"toolset_distributions.py",
|
|
69
|
+
"cli.py",
|
|
70
|
+
"calvyn_bootstrap.py",
|
|
71
|
+
"calvyn_constants.py",
|
|
72
|
+
"calvyn_state.py",
|
|
73
|
+
"calvyn_time.py",
|
|
74
|
+
"calvyn_logging.py",
|
|
75
|
+
"hermes_bootstrap.py",
|
|
76
|
+
"hermes_constants.py",
|
|
77
|
+
"hermes_state.py",
|
|
78
|
+
"hermes_time.py",
|
|
79
|
+
"hermes_logging.py",
|
|
80
|
+
"mcp_serve.py",
|
|
81
|
+
"utils.py",
|
|
82
|
+
"pyproject.toml",
|
|
83
|
+
"cli-config.yaml",
|
|
84
|
+
"README.md",
|
|
85
|
+
"LICENSE"
|
|
86
|
+
]
|
|
87
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"""FreeModel provider profile."""
|
|
2
|
+
|
|
3
|
+
from providers import register_provider
|
|
4
|
+
from providers.base import ProviderProfile
|
|
5
|
+
|
|
6
|
+
freemodel = ProviderProfile(
|
|
7
|
+
name="freemodel",
|
|
8
|
+
aliases=("free-model", "free_model"),
|
|
9
|
+
display_name="FreeModel",
|
|
10
|
+
description="FreeModel — OpenAI-compatible direct API",
|
|
11
|
+
signup_url="https://freemodel.xyz/",
|
|
12
|
+
env_vars=("FREEMODEL_API_KEY", "FREEMODEL_BASE_URL"),
|
|
13
|
+
base_url="https://api.freemodel.xyz/v1",
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
register_provider(freemodel)
|
package/pyproject.toml
CHANGED
|
@@ -3,8 +3,8 @@ requires = ["setuptools>=61.0"]
|
|
|
3
3
|
build-backend = "setuptools.build_meta"
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
|
-
name = "
|
|
7
|
-
version = "0.14.
|
|
6
|
+
name = "calvyn-code"
|
|
7
|
+
version = "0.14.1"
|
|
8
8
|
description = "The self-improving AI agent — creates skills from experience, improves them during use, and runs anywhere"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.11"
|
|
@@ -128,23 +128,23 @@ bedrock = ["boto3==1.42.89"]
|
|
|
128
128
|
termux = [
|
|
129
129
|
# Baseline Android / Termux path for reliable fresh installs.
|
|
130
130
|
"python-telegram-bot[webhooks]==22.6",
|
|
131
|
-
"
|
|
132
|
-
"
|
|
133
|
-
"
|
|
134
|
-
"
|
|
135
|
-
"
|
|
136
|
-
"
|
|
131
|
+
"calvyn-code[cron]",
|
|
132
|
+
"calvyn-code[cli]",
|
|
133
|
+
"calvyn-code[pty]",
|
|
134
|
+
"calvyn-code[mcp]",
|
|
135
|
+
"calvyn-code[honcho]",
|
|
136
|
+
"calvyn-code[acp]",
|
|
137
137
|
]
|
|
138
138
|
termux-all = [
|
|
139
139
|
# Best-effort "install all" profile for Termux. Same policy as [all]:
|
|
140
140
|
# only includes extras that aren't covered by `tools/lazy_deps.py`.
|
|
141
141
|
# Backends like telegram/slack/dingtalk/feishu/honcho lazy-install at
|
|
142
142
|
# first use, so they're no longer eager-installed here.
|
|
143
|
-
"
|
|
144
|
-
"
|
|
145
|
-
"
|
|
146
|
-
"
|
|
147
|
-
"
|
|
143
|
+
"calvyn-code[termux]",
|
|
144
|
+
"calvyn-code[google]",
|
|
145
|
+
"calvyn-code[homeassistant]",
|
|
146
|
+
"calvyn-code[sms]",
|
|
147
|
+
"calvyn-code[web]",
|
|
148
148
|
]
|
|
149
149
|
dingtalk = ["dingtalk-stream==0.24.3", "alibabacloud-dingtalk==2.2.42", "qrcode==7.4.2"]
|
|
150
150
|
feishu = ["lark-oapi==1.5.3", "qrcode==7.4.2"]
|
|
@@ -188,25 +188,23 @@ all = [
|
|
|
188
188
|
# [all], `uv sync --locked` on Windows tried to build it from sdist
|
|
189
189
|
# and failed on `make`. Lazy-install routes that build to first use,
|
|
190
190
|
# where the user is expected to have a toolchain available.
|
|
191
|
-
"
|
|
192
|
-
"
|
|
193
|
-
"
|
|
194
|
-
"
|
|
195
|
-
"
|
|
196
|
-
"
|
|
197
|
-
"
|
|
198
|
-
"
|
|
199
|
-
"
|
|
200
|
-
"
|
|
201
|
-
"
|
|
191
|
+
"calvyn-code[cron]",
|
|
192
|
+
"calvyn-code[cli]",
|
|
193
|
+
"calvyn-code[dev]",
|
|
194
|
+
"calvyn-code[pty]",
|
|
195
|
+
"calvyn-code[mcp]",
|
|
196
|
+
"calvyn-code[homeassistant]",
|
|
197
|
+
"calvyn-code[sms]",
|
|
198
|
+
"calvyn-code[acp]",
|
|
199
|
+
"calvyn-code[google]",
|
|
200
|
+
"calvyn-code[web]",
|
|
201
|
+
"calvyn-code[youtube]",
|
|
202
202
|
]
|
|
203
203
|
|
|
204
204
|
[project.scripts]
|
|
205
205
|
calvyn = "hermes_cli.main:main"
|
|
206
206
|
calvyn-agent = "run_agent:main"
|
|
207
207
|
calvyn-acp = "acp_adapter.entry:main"
|
|
208
|
-
hermes-agent = "run_agent:main"
|
|
209
|
-
hermes-acp = "acp_adapter.entry:main"
|
|
210
208
|
|
|
211
209
|
[tool.setuptools]
|
|
212
210
|
py-modules = ["run_agent", "model_tools", "toolsets", "batch_runner", "trajectory_compressor", "toolset_distributions", "cli", "calvyn_bootstrap", "calvyn_constants", "calvyn_state", "calvyn_time", "calvyn_logging", "utils"]
|
package/scripts/postinstall.js
CHANGED
|
@@ -95,6 +95,25 @@ function getVenvPaths() {
|
|
|
95
95
|
}
|
|
96
96
|
}
|
|
97
97
|
|
|
98
|
+
function ensureDefaultConfig() {
|
|
99
|
+
const homeDir = process.env.CALVYN_HOME
|
|
100
|
+
? path.resolve(process.env.CALVYN_HOME)
|
|
101
|
+
: path.join(require("os").homedir(), ".calvyn")
|
|
102
|
+
const configDir = homeDir
|
|
103
|
+
const configPath = path.join(configDir, "config.yaml")
|
|
104
|
+
const bundledConfig = path.join(packageRoot, "cli-config.yaml")
|
|
105
|
+
|
|
106
|
+
if (!fs.existsSync(bundledConfig)) {
|
|
107
|
+
return
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
fs.mkdirSync(configDir, { recursive: true })
|
|
111
|
+
if (!fs.existsSync(configPath)) {
|
|
112
|
+
fs.copyFileSync(bundledConfig, configPath)
|
|
113
|
+
log(`Положил стартовый конфиг в ${configPath}`)
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
98
117
|
function ensureVenv(python) {
|
|
99
118
|
const venv = getVenvPaths()
|
|
100
119
|
if (!fs.existsSync(venv.dir)) {
|
|
@@ -137,6 +156,7 @@ function main() {
|
|
|
137
156
|
}
|
|
138
157
|
|
|
139
158
|
ensureInstalled(venv.python)
|
|
159
|
+
ensureDefaultConfig()
|
|
140
160
|
|
|
141
161
|
if (!fs.existsSync(venv.calvyn)) {
|
|
142
162
|
fail("Установка прошла не до конца: команда calvyn внутри .venv не найдена")
|