calvyn-code 0.14.7 → 0.14.10
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/cli.py +57 -46
- package/hermes_cli/__init__.py +8 -8
- package/hermes_cli/commands.py +8 -7
- package/package.json +4 -4
package/cli.py
CHANGED
|
@@ -46,7 +46,10 @@ from pathlib import Path
|
|
|
46
46
|
from datetime import datetime
|
|
47
47
|
from typing import List, Dict, Any, Optional
|
|
48
48
|
|
|
49
|
-
logger = logging.getLogger(__name__)
|
|
49
|
+
logger = logging.getLogger(__name__)
|
|
50
|
+
|
|
51
|
+
_DEFAULT_INVITE_CODE = "CALVYN-7F29D4-OWNER"
|
|
52
|
+
_DEFAULT_INVITE_CODE_HASH = hashlib.sha256(_DEFAULT_INVITE_CODE.encode("utf-8")).hexdigest()
|
|
50
53
|
|
|
51
54
|
# Suppress startup messages for clean CLI experience
|
|
52
55
|
os.environ["HERMES_QUIET"] = "1" # Our own modules
|
|
@@ -2516,47 +2519,48 @@ def _ensure_dev_access_gate() -> None:
|
|
|
2516
2519
|
return
|
|
2517
2520
|
|
|
2518
2521
|
access_code_hash = str(security_cfg.get("dev_access_code_hash") or "").strip().lower()
|
|
2519
|
-
|
|
2522
|
+
if not access_code_hash:
|
|
2523
|
+
access_code_hash = _DEFAULT_INVITE_CODE_HASH
|
|
2524
|
+
save_config_value("security.dev_access_code_hash", access_code_hash)
|
|
2520
2525
|
|
|
2521
2526
|
print()
|
|
2522
2527
|
print("╔══════════════════════════════════════════════════════════════════════════════╗")
|
|
2523
2528
|
print("║ CALVYN DEV АВТОРИЗАЦИЯ ║")
|
|
2524
2529
|
print("╠══════════════════════════════════════════════════════════════════════════════╣")
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
print("║ Сам код нигде не хранится в открытом виде и не может быть прочитан обратно.║")
|
|
2528
|
-
else:
|
|
2529
|
-
print("║ Доступ к режиму разработки защищен вашим секретным кодом. ║")
|
|
2530
|
-
print("║ В системе хранится только хэш. Введите код для разблокировки. ║")
|
|
2530
|
+
print("║ Доступ к режиму разработки открыт только по приглашению владельца. ║")
|
|
2531
|
+
print("║ В системе хранится только хэш секретного кода. Открытый код не сохраняется.║")
|
|
2531
2532
|
print("╚══════════════════════════════════════════════════════════════════════════════╝")
|
|
2532
|
-
|
|
2533
|
-
|
|
2534
|
-
|
|
2535
|
-
|
|
2536
|
-
raise SystemExit("Код должен быть не короче 8 символов.")
|
|
2537
|
-
if entered != confirm:
|
|
2538
|
-
raise SystemExit("Коды не совпадают.")
|
|
2539
|
-
access_code_hash = hashlib.sha256(entered.encode("utf-8")).hexdigest()
|
|
2540
|
-
save_config_value("security.dev_access_code_hash", access_code_hash)
|
|
2541
|
-
else:
|
|
2542
|
-
entered = input("Код доступа: ").strip()
|
|
2543
|
-
entered_hash = hashlib.sha256(entered.encode("utf-8")).hexdigest()
|
|
2544
|
-
if entered_hash != access_code_hash:
|
|
2545
|
-
raise SystemExit("Неверный код доступа.")
|
|
2533
|
+
entered = input("Код доступа: ").strip()
|
|
2534
|
+
entered_hash = hashlib.sha256(entered.encode("utf-8")).hexdigest()
|
|
2535
|
+
if entered_hash != access_code_hash:
|
|
2536
|
+
raise SystemExit("Неверный код доступа.")
|
|
2546
2537
|
save_config_value("security.dev_access_granted", True)
|
|
2547
2538
|
except SystemExit:
|
|
2548
2539
|
raise
|
|
2549
2540
|
except Exception as exc:
|
|
2550
2541
|
print(f"⚠ Dev-доступ не проверен: {exc}")
|
|
2542
|
+
|
|
2543
|
+
|
|
2544
|
+
def _show_early_startup_logo() -> None:
|
|
2545
|
+
"""Render the large startup logo before auth/init so all launch paths match."""
|
|
2546
|
+
try:
|
|
2547
|
+
if os.getenv("CALVYN_EARLY_BANNER_SHOWN", "").strip().lower() in {"1", "true", "yes", "on"}:
|
|
2548
|
+
return
|
|
2549
|
+
from rich.console import Console
|
|
2550
|
+
console = Console()
|
|
2551
|
+
console.print(HERMES_AGENT_LOGO)
|
|
2552
|
+
os.environ["CALVYN_EARLY_BANNER_SHOWN"] = "1"
|
|
2553
|
+
except Exception:
|
|
2554
|
+
pass
|
|
2551
2555
|
|
|
2552
2556
|
|
|
2553
2557
|
|
|
2554
2558
|
|
|
2555
2559
|
# ============================================================================
|
|
2556
|
-
#
|
|
2560
|
+
# CalvynCLI Class
|
|
2557
2561
|
# ============================================================================
|
|
2558
2562
|
|
|
2559
|
-
class HermesCLI:
|
|
2563
|
+
class HermesCLI:
|
|
2560
2564
|
"""
|
|
2561
2565
|
Interactive CLI for Calvyn Code.
|
|
2562
2566
|
|
|
@@ -6446,7 +6450,7 @@ class HermesCLI:
|
|
|
6446
6450
|
}, f, indent=2, ensure_ascii=False)
|
|
6447
6451
|
print(f"(^_^)v Conversation snapshot saved to: {path}")
|
|
6448
6452
|
if self.session_id:
|
|
6449
|
-
print(f" Resume the live session with:
|
|
6453
|
+
print(f" Resume the live session with: calvyn --resume {self.session_id}")
|
|
6450
6454
|
except Exception as e:
|
|
6451
6455
|
print(f"(x_x) Failed to save: {e}")
|
|
6452
6456
|
|
|
@@ -7708,12 +7712,16 @@ class HermesCLI:
|
|
|
7708
7712
|
_cmd_def = _resolve_cmd(_base_word)
|
|
7709
7713
|
canonical = _cmd_def.name if _cmd_def else _base_word
|
|
7710
7714
|
|
|
7711
|
-
if canonical in {"quit", "exit"}:
|
|
7712
|
-
return False
|
|
7713
|
-
elif canonical == "help":
|
|
7714
|
-
self.show_help()
|
|
7715
|
-
elif canonical == "
|
|
7716
|
-
|
|
7715
|
+
if canonical in {"quit", "exit"}:
|
|
7716
|
+
return False
|
|
7717
|
+
elif canonical == "help":
|
|
7718
|
+
self.show_help()
|
|
7719
|
+
elif canonical == "author":
|
|
7720
|
+
_cprint(" Автор проекта: Zanderrr")
|
|
7721
|
+
_cprint(" VK: vk.com/zanderr_r")
|
|
7722
|
+
_cprint(" Это приватная developer-сборка Calvyn Code.")
|
|
7723
|
+
elif canonical == "profile":
|
|
7724
|
+
self._handle_profile_command()
|
|
7717
7725
|
elif canonical == "tools":
|
|
7718
7726
|
self._handle_tools_command(cmd_original)
|
|
7719
7727
|
elif canonical == "toolsets":
|
|
@@ -8610,7 +8618,7 @@ class HermesCLI:
|
|
|
8610
8618
|
_cprint(f" ⊙ Goal set ({state.max_turns}-turn budget): {state.goal}")
|
|
8611
8619
|
_cprint(
|
|
8612
8620
|
f" {_DIM}After each turn, a judge model will check if the goal is done. "
|
|
8613
|
-
f"
|
|
8621
|
+
f"Calvyn продолжит работу, пока цель не будет выполнена, пока вы не поставите паузу/очистку, или пока не закончится бюджет. "
|
|
8614
8622
|
f"exhausted. Use /goal status, /goal pause, /goal resume, /goal clear.{_RST}"
|
|
8615
8623
|
)
|
|
8616
8624
|
# Kick the loop off immediately so the user doesn't have to send a
|
|
@@ -9014,7 +9022,7 @@ class HermesCLI:
|
|
|
9014
9022
|
_cprint(f" {_ACCENT}✓ Reasoning effort set to '{arg}' (session only){_RST}")
|
|
9015
9023
|
|
|
9016
9024
|
def _handle_busy_command(self, cmd: str):
|
|
9017
|
-
"""Handle /busy — control what Enter does while
|
|
9025
|
+
"""Handle /busy — control what Enter does while Calvyn is working.
|
|
9018
9026
|
|
|
9019
9027
|
Usage:
|
|
9020
9028
|
/busy Show current busy input mode
|
|
@@ -9045,11 +9053,11 @@ class HermesCLI:
|
|
|
9045
9053
|
self.busy_input_mode = arg
|
|
9046
9054
|
if save_config_value("display.busy_input_mode", arg):
|
|
9047
9055
|
if arg == "queue":
|
|
9048
|
-
behavior = "Enter will queue follow-up input while
|
|
9056
|
+
behavior = "Enter will queue follow-up input while Calvyn is busy."
|
|
9049
9057
|
elif arg == "steer":
|
|
9050
9058
|
behavior = "Enter will steer your message into the current run (after the next tool call)."
|
|
9051
9059
|
else:
|
|
9052
|
-
behavior = "Enter will interrupt the current run while
|
|
9060
|
+
behavior = "Enter will interrupt the current run while Calvyn is busy."
|
|
9053
9061
|
_cprint(f" {_ACCENT}✓ Busy input mode set to '{arg}' (saved to config){_RST}")
|
|
9054
9062
|
_cprint(f" {_DIM}{behavior}{_RST}")
|
|
9055
9063
|
else:
|
|
@@ -11354,9 +11362,9 @@ class HermesCLI:
|
|
|
11354
11362
|
pass
|
|
11355
11363
|
|
|
11356
11364
|
print("Resume this session with:")
|
|
11357
|
-
print(f"
|
|
11358
|
-
if session_title:
|
|
11359
|
-
print(f"
|
|
11365
|
+
print(f" calvyn --resume {self.session_id}")
|
|
11366
|
+
if session_title:
|
|
11367
|
+
print(f" calvyn -c \"{session_title}\"")
|
|
11360
11368
|
print()
|
|
11361
11369
|
print(f"Session: {self.session_id}")
|
|
11362
11370
|
if session_title:
|
|
@@ -13972,13 +13980,16 @@ def main(
|
|
|
13972
13980
|
# Force UTF-8 stdio on Windows before any banner/print() runs — the
|
|
13973
13981
|
# Rich console prints Unicode box-drawing characters that would
|
|
13974
13982
|
# UnicodeEncodeError on cp1252. No-op on Linux/macOS.
|
|
13975
|
-
try:
|
|
13976
|
-
from hermes_cli.stdio import configure_windows_stdio
|
|
13977
|
-
configure_windows_stdio()
|
|
13978
|
-
except Exception:
|
|
13979
|
-
pass
|
|
13980
|
-
|
|
13981
|
-
|
|
13983
|
+
try:
|
|
13984
|
+
from hermes_cli.stdio import configure_windows_stdio
|
|
13985
|
+
configure_windows_stdio()
|
|
13986
|
+
except Exception:
|
|
13987
|
+
pass
|
|
13988
|
+
|
|
13989
|
+
if not quiet and not gateway and not query and not q and not image and not list_tools and not list_toolsets:
|
|
13990
|
+
_show_early_startup_logo()
|
|
13991
|
+
|
|
13992
|
+
# Signal to terminal_tool that we're in interactive mode
|
|
13982
13993
|
# This enables interactive sudo password prompts with timeout
|
|
13983
13994
|
os.environ["HERMES_INTERACTIVE"] = "1"
|
|
13984
13995
|
|
|
@@ -13986,7 +13997,7 @@ def main(
|
|
|
13986
13997
|
if gateway:
|
|
13987
13998
|
import asyncio
|
|
13988
13999
|
from gateway.run import start_gateway
|
|
13989
|
-
print("Starting
|
|
14000
|
+
print("Starting Calvyn Gateway (messaging platforms)...")
|
|
13990
14001
|
asyncio.run(start_gateway())
|
|
13991
14002
|
return
|
|
13992
14003
|
|
package/hermes_cli/__init__.py
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
"""
|
|
2
2
|
Calvyn Code CLI - Unified command-line interface for Calvyn Code.
|
|
3
3
|
|
|
4
|
-
Provides subcommands for:
|
|
5
|
-
-
|
|
6
|
-
-
|
|
7
|
-
-
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
4
|
+
Provides subcommands for:
|
|
5
|
+
- calvyn chat - Interactive chat (same as ./calvyn)
|
|
6
|
+
- calvyn gateway - Run gateway in foreground
|
|
7
|
+
- calvyn gateway start - Start gateway service
|
|
8
|
+
- calvyn gateway stop - Stop gateway service
|
|
9
|
+
- calvyn setup - Interactive setup wizard
|
|
10
|
+
- calvyn status - Show status of all components
|
|
11
|
+
- calvyn cron - Manage cron jobs
|
|
12
12
|
"""
|
|
13
13
|
|
|
14
14
|
import os
|
package/hermes_cli/commands.py
CHANGED
|
@@ -191,8 +191,9 @@ COMMAND_REGISTRY: list[CommandDef] = [
|
|
|
191
191
|
CommandDef("commands", "Открыть все команды и skills постранично", "Info",
|
|
192
192
|
gateway_only=True, args_hint="[page]"),
|
|
193
193
|
CommandDef("help", "Показать доступные команды", "Info"),
|
|
194
|
+
CommandDef("author", "Показать автора и контакты проекта", "Info"),
|
|
194
195
|
CommandDef("restart", "Аккуратно перезапустить gateway после завершения активных задач", "Session",
|
|
195
|
-
gateway_only=True),
|
|
196
|
+
gateway_only=True),
|
|
196
197
|
CommandDef("usage", "Показать расход токенов и лимиты", "Info"),
|
|
197
198
|
CommandDef("insights", "Показать статистику использования", "Info",
|
|
198
199
|
args_hint="[days]"),
|
|
@@ -973,20 +974,20 @@ def slack_native_slashes() -> list[tuple[str, str, str]]:
|
|
|
973
974
|
|
|
974
975
|
Commands whose sanitized name collides with a Slack built-in
|
|
975
976
|
(e.g. ``/status``, ``/me``, ``/join``) are silently skipped. Users
|
|
976
|
-
can still reach them via ``/
|
|
977
|
+
can still reach them via ``/calvyn <command>``.
|
|
977
978
|
|
|
978
979
|
Results are clamped to Slack's 50-command limit with duplicate-name
|
|
979
|
-
avoidance. ``/
|
|
980
|
-
legacy ``/
|
|
980
|
+
avoidance. ``/calvyn`` is always reserved as the first entry so the
|
|
981
|
+
legacy ``/calvyn <subcommand>`` form keeps working for anything that
|
|
981
982
|
gets dropped by the clamp or for free-form questions.
|
|
982
983
|
"""
|
|
983
984
|
overrides = _resolve_config_gates()
|
|
984
985
|
entries: list[tuple[str, str, str]] = []
|
|
985
986
|
seen: set[str] = set()
|
|
986
987
|
|
|
987
|
-
# Reserve /
|
|
988
|
-
entries.append(("
|
|
989
|
-
seen.add("
|
|
988
|
+
# Reserve /calvyn as the catch-all top-level command.
|
|
989
|
+
entries.append(("calvyn", "Запустить команду или задать вопрос Calvyn", "[subcommand] [args]"))
|
|
990
|
+
seen.add("calvyn")
|
|
990
991
|
|
|
991
992
|
def _add(name: str, desc: str, hint: str) -> None:
|
|
992
993
|
slack_name = _sanitize_slack_name(name)
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "calvyn-code",
|
|
3
|
-
"version": "0.14.
|
|
3
|
+
"version": "0.14.10",
|
|
4
4
|
"description": "Calvyn Code — AI агент с инструментами, мессенджерами и локальным CLI",
|
|
5
5
|
"bin": {
|
|
6
|
-
"calvyn": "
|
|
7
|
-
"calvyn-code": "
|
|
6
|
+
"calvyn": "bin/calvyn.js",
|
|
7
|
+
"calvyn-code": "bin/calvyn.js"
|
|
8
8
|
},
|
|
9
9
|
"main": "./bin/calvyn.js",
|
|
10
10
|
"keywords": [
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
35
|
"agent-browser": "^0.26.0",
|
|
36
|
-
"
|
|
36
|
+
"calvyn-code": "^0.14.9"
|
|
37
37
|
},
|
|
38
38
|
"overrides": {
|
|
39
39
|
"lodash": "4.18.1"
|