103 lines
4.4 KiB
Python
103 lines
4.4 KiB
Python
"""Команды sdlc-hub: init (настройки из config.example.json), serve (HTTP), mcp [модуль] (stdio), tokens,
|
||
agent publish (версия агента для самообновления) и подкоманды модулей (jira: import)."""
|
||
import argparse
|
||
import json
|
||
import sys
|
||
|
||
from . import db, paths, registry, settings
|
||
from .paths import secure_dir
|
||
|
||
|
||
def main(argv=None) -> int:
|
||
ap = argparse.ArgumentParser(prog="sdlc-hub", description="SDLC-хаб: ядро и модули")
|
||
sub = ap.add_subparsers(dest="cmd", required=True)
|
||
p = sub.add_parser("init", help="перенести настройки проекта из config.example.json, создать токены")
|
||
p.add_argument("--config", required=True)
|
||
p.add_argument("--force", action="store_true")
|
||
p = sub.add_parser("serve", help="запустить HTTP API")
|
||
p.add_argument("--host", default="0.0.0.0")
|
||
p.add_argument("--port", type=int)
|
||
p = sub.add_parser("mcp", help="MCP-сервер модуля по stdio ")
|
||
p.add_argument("module", nargs="?", default=None, help="имя модуля (jira, wiki); без модуля или неизвестный — код 2")
|
||
p.add_argument("--project", help="метка проекта, к которому привязана сессия")
|
||
for m in registry.modules():
|
||
if m.cli_register:
|
||
m.cli_register(sub)
|
||
sub.add_parser("tokens", help="показать токены клиента и агентов")
|
||
p = sub.add_parser("agent", help="версия агента для самообновления")
|
||
agent_sub = p.add_subparsers(dest="agent_cmd", required=True)
|
||
p = agent_sub.add_parser("publish", help="опубликовать agent.py (версия только вверх)")
|
||
p.add_argument("--module", default=registry.DEFAULT_AGENT, help=f"модуль агента (по умолчанию {registry.DEFAULT_AGENT})")
|
||
p.add_argument("path")
|
||
args = ap.parse_args(argv)
|
||
|
||
if args.cmd == "agent":
|
||
from . import release
|
||
names = [m.name for m in registry.agent_modules()]
|
||
if args.module not in names:
|
||
print(f"неизвестный модуль {args.module}; модули с агентами: {', '.join(names)}", file=sys.stderr)
|
||
return 2
|
||
try:
|
||
secure_dir(paths.release_root())
|
||
release.migrate_layout(paths.release_root()) # прежняя раскладка release/ до проверки «только вверх»
|
||
m = release.publish(release.module_dir(paths.release_root(), args.module), args.path)
|
||
except release.PublishError as e:
|
||
print(e, file=sys.stderr)
|
||
return 1
|
||
print(f"опубликована v{m['version']}, sha256 {m['sha256'][:12]}…, {m['size']} байт")
|
||
return 0
|
||
|
||
if args.cmd == "serve":
|
||
from . import api
|
||
hub = api.Hub(paths.db_path())
|
||
conn = hub.conn()
|
||
port = args.port or int(settings.get(conn, "port") or 8790)
|
||
conn.close()
|
||
api.serve(hub, args.host, port)
|
||
return 0
|
||
if args.cmd == "mcp":
|
||
from . import mcp
|
||
return mcp.run(args.module, args.project)
|
||
for m in registry.modules():
|
||
if m.cli_run:
|
||
rc = m.cli_run(args)
|
||
if rc is not None:
|
||
return rc
|
||
|
||
conn = db.connect(paths.db_path())
|
||
settings.ensure_defaults(conn)
|
||
try:
|
||
if args.cmd == "init":
|
||
with open(args.config, encoding="utf-8") as f:
|
||
cfg = json.load(f)
|
||
lines: list[str] = []
|
||
try:
|
||
for m in registry.modules():
|
||
if m.on_init:
|
||
lines += m.on_init(conn, cfg, args.force)
|
||
except RuntimeError as e:
|
||
print(e, file=sys.stderr)
|
||
return 1
|
||
for line in lines:
|
||
print(line)
|
||
_print_tokens(conn)
|
||
return 0
|
||
if args.cmd == "tokens":
|
||
_print_tokens(conn)
|
||
return 0
|
||
finally:
|
||
conn.close()
|
||
return 2
|
||
|
||
|
||
def _print_tokens(conn) -> None:
|
||
tok = settings.tokens(conn)
|
||
print(f"клиентский токен: {tok['client']}")
|
||
for m in registry.agent_modules():
|
||
print(f"агент {m.name}: {tok['agents'][m.name]}")
|
||
print(f"база: {paths.db_path()}")
|
||
|
||
|
||
if __name__ == "__main__":
|
||
sys.exit(main())
|