@ao_zorin/zocket 1.0.0
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/LICENSE +21 -0
- package/README.md +92 -0
- package/bin/zocket-setup.cjs +12 -0
- package/bin/zocket.cjs +174 -0
- package/docs/AI_AUTODEPLOY.md +52 -0
- package/docs/CLIENTS_MCP.md +59 -0
- package/docs/INSTALL.md +288 -0
- package/docs/LOCAL_MODELS.md +95 -0
- package/package.json +52 -0
- package/pyproject.toml +29 -0
- package/scripts/ai-autodeploy.py +127 -0
- package/scripts/install-zocket.ps1 +116 -0
- package/scripts/install-zocket.sh +228 -0
- package/zocket/__init__.py +2 -0
- package/zocket/__main__.py +5 -0
- package/zocket/audit.py +76 -0
- package/zocket/auth.py +34 -0
- package/zocket/autostart.py +281 -0
- package/zocket/backup.py +33 -0
- package/zocket/cli.py +655 -0
- package/zocket/config_store.py +68 -0
- package/zocket/crypto.py +158 -0
- package/zocket/harden.py +136 -0
- package/zocket/i18n.py +216 -0
- package/zocket/mcp_server.py +249 -0
- package/zocket/paths.py +50 -0
- package/zocket/runner.py +108 -0
- package/zocket/templates/index.html +1062 -0
- package/zocket/templates/login.html +244 -0
- package/zocket/vault.py +331 -0
- package/zocket/web.py +490 -0
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# Local Models (Ollama / Hugging Face) with zocket Workflows
|
|
2
|
+
|
|
3
|
+
zocket itself is model-agnostic.
|
|
4
|
+
You can use local models in agent clients while zocket provides secrets/MCP.
|
|
5
|
+
|
|
6
|
+
## 1) Ollama (local)
|
|
7
|
+
|
|
8
|
+
Start Ollama and pull a model:
|
|
9
|
+
```bash
|
|
10
|
+
ollama serve
|
|
11
|
+
ollama pull qwen2.5-coder:7b
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Ollama OpenAI-compatible endpoint is typically:
|
|
15
|
+
```text
|
|
16
|
+
http://127.0.0.1:11434/v1
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
### OpenCode + Ollama
|
|
20
|
+
|
|
21
|
+
`~/.config/opencode/opencode.json`:
|
|
22
|
+
```json
|
|
23
|
+
{
|
|
24
|
+
"$schema": "https://opencode.ai/config.json",
|
|
25
|
+
"provider": {
|
|
26
|
+
"ollama": {
|
|
27
|
+
"npm": "opencode-ollama",
|
|
28
|
+
"name": "Ollama",
|
|
29
|
+
"models": {
|
|
30
|
+
"qwen2.5-coder:7b": {}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
"agent": {
|
|
35
|
+
"coder": {
|
|
36
|
+
"model": "ollama/qwen2.5-coder:7b"
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### Qwen CLI + Ollama (OpenAI-compatible)
|
|
43
|
+
|
|
44
|
+
`~/.qwen/settings.json`:
|
|
45
|
+
```json
|
|
46
|
+
{
|
|
47
|
+
"modelProviders": {
|
|
48
|
+
"local_ollama": {
|
|
49
|
+
"name": "Local Ollama",
|
|
50
|
+
"baseURL": "http://127.0.0.1:11434/v1",
|
|
51
|
+
"apiKey": "ollama",
|
|
52
|
+
"models": ["qwen2.5-coder:7b"]
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
"model": "local_ollama/qwen2.5-coder:7b"
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## 2) Hugging Face local models
|
|
60
|
+
|
|
61
|
+
Recommended path:
|
|
62
|
+
- run local Text Generation Inference (TGI) server
|
|
63
|
+
- expose OpenAI-compatible endpoint
|
|
64
|
+
- connect client via custom provider settings
|
|
65
|
+
|
|
66
|
+
Typical local endpoint:
|
|
67
|
+
```text
|
|
68
|
+
http://127.0.0.1:8080/v1
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Example (Qwen CLI custom provider):
|
|
72
|
+
```json
|
|
73
|
+
{
|
|
74
|
+
"modelProviders": {
|
|
75
|
+
"local_hf_tgi": {
|
|
76
|
+
"name": "HF TGI Local",
|
|
77
|
+
"baseURL": "http://127.0.0.1:8080/v1",
|
|
78
|
+
"apiKey": "hf-local",
|
|
79
|
+
"models": ["Qwen/Qwen2.5-Coder-7B-Instruct"]
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
"model": "local_hf_tgi/Qwen/Qwen2.5-Coder-7B-Instruct"
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## 3) Clients that are primarily cloud-first
|
|
87
|
+
|
|
88
|
+
- Codex CLI / Claude / Antigravity are primarily documented for hosted model backends.
|
|
89
|
+
- Keep zocket MCP integration enabled independently from model backend choice.
|
|
90
|
+
|
|
91
|
+
## 4) Security notes
|
|
92
|
+
|
|
93
|
+
- Keep local model APIs on loopback only (`127.0.0.1`).
|
|
94
|
+
- Do not expose local model endpoints publicly without auth and TLS.
|
|
95
|
+
- Keep zocket in `metadata` mode by default for MCP clients.
|
package/package.json
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ao_zorin/zocket",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Cross-platform npm launcher for Zocket (local MCP + web vault)",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"private": false,
|
|
7
|
+
"type": "commonjs",
|
|
8
|
+
"bin": {
|
|
9
|
+
"zocket": "bin/zocket.cjs",
|
|
10
|
+
"zocket-setup": "bin/zocket-setup.cjs"
|
|
11
|
+
},
|
|
12
|
+
"files": [
|
|
13
|
+
"bin/",
|
|
14
|
+
"docs/AI_AUTODEPLOY.md",
|
|
15
|
+
"docs/CLIENTS_MCP.md",
|
|
16
|
+
"docs/INSTALL.md",
|
|
17
|
+
"docs/LOCAL_MODELS.md",
|
|
18
|
+
"scripts/ai-autodeploy.py",
|
|
19
|
+
"scripts/install-zocket.sh",
|
|
20
|
+
"scripts/install-zocket.ps1",
|
|
21
|
+
"zocket/*.py",
|
|
22
|
+
"zocket/templates/*.html",
|
|
23
|
+
"pyproject.toml",
|
|
24
|
+
"README.md",
|
|
25
|
+
"LICENSE"
|
|
26
|
+
],
|
|
27
|
+
"engines": {
|
|
28
|
+
"node": ">=18"
|
|
29
|
+
},
|
|
30
|
+
"scripts": {
|
|
31
|
+
"test:python": "PYTHONPATH=. pytest -q",
|
|
32
|
+
"smoke:npm": "node ./bin/zocket.cjs --help"
|
|
33
|
+
},
|
|
34
|
+
"keywords": [
|
|
35
|
+
"mcp",
|
|
36
|
+
"model-context-protocol",
|
|
37
|
+
"secrets",
|
|
38
|
+
"vault",
|
|
39
|
+
"cli",
|
|
40
|
+
"agents",
|
|
41
|
+
"codex",
|
|
42
|
+
"claude"
|
|
43
|
+
],
|
|
44
|
+
"repository": {
|
|
45
|
+
"type": "git",
|
|
46
|
+
"url": "https://github.com/aozorin/zocket.git"
|
|
47
|
+
},
|
|
48
|
+
"homepage": "https://github.com/aozorin/zocket#readme",
|
|
49
|
+
"bugs": {
|
|
50
|
+
"url": "https://github.com/aozorin/zocket/issues"
|
|
51
|
+
}
|
|
52
|
+
}
|
package/pyproject.toml
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "zocket"
|
|
7
|
+
version = "1.0.0"
|
|
8
|
+
description = "Local MCP + web vault for project auth secrets"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
dependencies = [
|
|
12
|
+
"cryptography>=43.0.0",
|
|
13
|
+
"flask>=3.0.0",
|
|
14
|
+
"keyring>=25.0.0",
|
|
15
|
+
"mcp>=1.0.0",
|
|
16
|
+
"waitress>=3.0.0",
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
[project.scripts]
|
|
20
|
+
zocket = "zocket.cli:main"
|
|
21
|
+
|
|
22
|
+
[project.optional-dependencies]
|
|
23
|
+
dev = ["pytest>=8.0.0"]
|
|
24
|
+
|
|
25
|
+
[tool.setuptools.packages.find]
|
|
26
|
+
include = ["zocket*"]
|
|
27
|
+
|
|
28
|
+
[tool.setuptools.package-data]
|
|
29
|
+
zocket = ["templates/*.html"]
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import argparse
|
|
5
|
+
import os
|
|
6
|
+
import platform
|
|
7
|
+
import shutil
|
|
8
|
+
import subprocess
|
|
9
|
+
import sys
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def run(cmd: list[str]) -> None:
|
|
14
|
+
print(f"[ai-autodeploy] $ {' '.join(cmd)}")
|
|
15
|
+
cp = subprocess.run(cmd, check=False)
|
|
16
|
+
if cp.returncode != 0:
|
|
17
|
+
raise RuntimeError(f"Command failed with code {cp.returncode}: {' '.join(cmd)}")
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def ensure_tool(name: str) -> str:
|
|
21
|
+
path = shutil.which(name)
|
|
22
|
+
if not path:
|
|
23
|
+
raise RuntimeError(f"Required tool not found: {name}")
|
|
24
|
+
return path
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def clone_or_update(repo_url: str, repo_ref: str, checkout_dir: Path) -> None:
|
|
28
|
+
git = ensure_tool("git")
|
|
29
|
+
if (checkout_dir / ".git").exists():
|
|
30
|
+
run([git, "-C", str(checkout_dir), "fetch", "--all", "--tags"])
|
|
31
|
+
run([git, "-C", str(checkout_dir), "checkout", repo_ref])
|
|
32
|
+
run([git, "-C", str(checkout_dir), "pull", "--ff-only"])
|
|
33
|
+
return
|
|
34
|
+
checkout_dir.parent.mkdir(parents=True, exist_ok=True)
|
|
35
|
+
run([git, "clone", "--depth", "1", "--branch", repo_ref, repo_url, str(checkout_dir)])
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def default_checkout_dir() -> Path:
|
|
39
|
+
if sys.platform.startswith("win"):
|
|
40
|
+
root = Path(os.environ.get("LOCALAPPDATA", str(Path.home() / "AppData" / "Local")))
|
|
41
|
+
return root / "zocket" / "bootstrap-src"
|
|
42
|
+
return Path.home() / ".local" / "share" / "zocket" / "bootstrap-src"
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def main() -> int:
|
|
46
|
+
ap = argparse.ArgumentParser(description="One-file zocket bootstrap for AI agents.")
|
|
47
|
+
ap.add_argument("--repo-url", default="https://github.com/your-org/zocket.git")
|
|
48
|
+
ap.add_argument("--repo-ref", default="main")
|
|
49
|
+
ap.add_argument("--checkout-dir", default=str(default_checkout_dir()))
|
|
50
|
+
ap.add_argument("--lang", default="en", choices=["en", "ru"])
|
|
51
|
+
ap.add_argument("--web-port", default="18001")
|
|
52
|
+
ap.add_argument("--mcp-port", default="18002")
|
|
53
|
+
ap.add_argument("--mcp-mode", default="metadata", choices=["metadata", "admin"])
|
|
54
|
+
ap.add_argument("--autostart", default="user", choices=["user", "system", "none"])
|
|
55
|
+
ap.add_argument("--service-user", default="zocketd")
|
|
56
|
+
ap.add_argument("--zocket-home", default=str(Path.home() / ".zocket"))
|
|
57
|
+
args = ap.parse_args()
|
|
58
|
+
|
|
59
|
+
checkout_dir = Path(args.checkout_dir).expanduser().resolve()
|
|
60
|
+
clone_or_update(args.repo_url, args.repo_ref, checkout_dir)
|
|
61
|
+
|
|
62
|
+
system = platform.system().lower()
|
|
63
|
+
if system == "windows":
|
|
64
|
+
ps = shutil.which("pwsh") or shutil.which("powershell")
|
|
65
|
+
if not ps:
|
|
66
|
+
raise RuntimeError("PowerShell not found")
|
|
67
|
+
installer = checkout_dir / "scripts" / "install-zocket.ps1"
|
|
68
|
+
cmd = [
|
|
69
|
+
ps,
|
|
70
|
+
"-ExecutionPolicy",
|
|
71
|
+
"Bypass",
|
|
72
|
+
"-File",
|
|
73
|
+
str(installer),
|
|
74
|
+
"-Source",
|
|
75
|
+
"Local",
|
|
76
|
+
"-InstallRoot",
|
|
77
|
+
str(Path(os.environ.get("LOCALAPPDATA", str(Path.home() / "AppData" / "Local"))) / "zocket"),
|
|
78
|
+
"-ZocketHome",
|
|
79
|
+
args.zocket_home,
|
|
80
|
+
"-Lang",
|
|
81
|
+
args.lang,
|
|
82
|
+
"-WebPort",
|
|
83
|
+
args.web_port,
|
|
84
|
+
"-McpPort",
|
|
85
|
+
args.mcp_port,
|
|
86
|
+
"-McpMode",
|
|
87
|
+
args.mcp_mode,
|
|
88
|
+
]
|
|
89
|
+
if args.autostart != "none":
|
|
90
|
+
cmd.append("-EnableAutostart")
|
|
91
|
+
run(cmd)
|
|
92
|
+
else:
|
|
93
|
+
bash = ensure_tool("bash")
|
|
94
|
+
installer = checkout_dir / "scripts" / "install-zocket.sh"
|
|
95
|
+
run(
|
|
96
|
+
[
|
|
97
|
+
bash,
|
|
98
|
+
str(installer),
|
|
99
|
+
"--source",
|
|
100
|
+
"local",
|
|
101
|
+
"--install-root",
|
|
102
|
+
str(checkout_dir.parent),
|
|
103
|
+
"--zocket-home",
|
|
104
|
+
args.zocket_home,
|
|
105
|
+
"--lang",
|
|
106
|
+
args.lang,
|
|
107
|
+
"--web-port",
|
|
108
|
+
args.web_port,
|
|
109
|
+
"--mcp-port",
|
|
110
|
+
args.mcp_port,
|
|
111
|
+
"--mcp-mode",
|
|
112
|
+
args.mcp_mode,
|
|
113
|
+
"--autostart",
|
|
114
|
+
args.autostart,
|
|
115
|
+
"--service-user",
|
|
116
|
+
args.service_user,
|
|
117
|
+
]
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
print("[ai-autodeploy] Completed successfully.")
|
|
121
|
+
print("[ai-autodeploy] Web: http://127.0.0.1:18001")
|
|
122
|
+
print("[ai-autodeploy] MCP: http://127.0.0.1:18002/mcp")
|
|
123
|
+
return 0
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
if __name__ == "__main__":
|
|
127
|
+
raise SystemExit(main())
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
Param(
|
|
2
|
+
[ValidateSet("Auto", "Local", "Git", "PyPI")]
|
|
3
|
+
[string]$Source = "Auto",
|
|
4
|
+
[string]$RepoUrl = "https://github.com/your-org/zocket.git",
|
|
5
|
+
[string]$RepoRef = "main",
|
|
6
|
+
[string]$InstallRoot = "$env:LOCALAPPDATA\zocket",
|
|
7
|
+
[string]$ZocketHome = "$env:USERPROFILE\.zocket",
|
|
8
|
+
[ValidateSet("en", "ru")]
|
|
9
|
+
[string]$Lang = "en",
|
|
10
|
+
[int]$WebPort = 18001,
|
|
11
|
+
[int]$McpPort = 18002,
|
|
12
|
+
[int]$McpStreamPort = 18003,
|
|
13
|
+
[ValidateSet("metadata", "admin")]
|
|
14
|
+
[string]$McpMode = "metadata",
|
|
15
|
+
[switch]$EnableAutostart
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
$ErrorActionPreference = "Stop"
|
|
19
|
+
|
|
20
|
+
function Resolve-Python {
|
|
21
|
+
if (Get-Command py -ErrorAction SilentlyContinue) {
|
|
22
|
+
return @{Cmd = "py"; Prefix = @("-3")}
|
|
23
|
+
}
|
|
24
|
+
if (Get-Command python -ErrorAction SilentlyContinue) {
|
|
25
|
+
return @{Cmd = "python"; Prefix = @()}
|
|
26
|
+
}
|
|
27
|
+
throw "Python 3.10+ not found. Install Python and rerun."
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function Run-Step([string]$Cmd, [string[]]$Args) {
|
|
31
|
+
& $Cmd @Args
|
|
32
|
+
if ($LASTEXITCODE -ne 0) {
|
|
33
|
+
throw "Command failed: $Cmd $($Args -join ' ')"
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function Ensure-Dir([string]$Path) {
|
|
38
|
+
if (-not (Test-Path -LiteralPath $Path)) {
|
|
39
|
+
New-Item -ItemType Directory -Path $Path | Out-Null
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
$repoRoot = Split-Path -Parent $PSScriptRoot
|
|
44
|
+
if ($Source -eq "Auto") {
|
|
45
|
+
if (Test-Path -LiteralPath (Join-Path $repoRoot "pyproject.toml")) {
|
|
46
|
+
$Source = "Local"
|
|
47
|
+
} else {
|
|
48
|
+
$Source = "Git"
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
Ensure-Dir $InstallRoot
|
|
53
|
+
$srcDir = Join-Path $InstallRoot "src"
|
|
54
|
+
|
|
55
|
+
$pkgSource = $null
|
|
56
|
+
if ($Source -eq "Local") {
|
|
57
|
+
$pkgSource = $repoRoot
|
|
58
|
+
} elseif ($Source -eq "Git") {
|
|
59
|
+
if (Test-Path -LiteralPath (Join-Path $srcDir ".git")) {
|
|
60
|
+
Run-Step "git" @("-C", $srcDir, "fetch", "--all", "--tags")
|
|
61
|
+
Run-Step "git" @("-C", $srcDir, "checkout", $RepoRef)
|
|
62
|
+
Run-Step "git" @("-C", $srcDir, "pull", "--ff-only")
|
|
63
|
+
} else {
|
|
64
|
+
if (Test-Path -LiteralPath $srcDir) {
|
|
65
|
+
Remove-Item -LiteralPath $srcDir -Recurse -Force
|
|
66
|
+
}
|
|
67
|
+
Run-Step "git" @("clone", "--depth", "1", "--branch", $RepoRef, $RepoUrl, $srcDir)
|
|
68
|
+
}
|
|
69
|
+
$pkgSource = $srcDir
|
|
70
|
+
} else {
|
|
71
|
+
$pkgSource = "zocket"
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
$py = Resolve-Python
|
|
75
|
+
$venvDir = Join-Path $InstallRoot "venv"
|
|
76
|
+
$venvPy = Join-Path $venvDir "Scripts\python.exe"
|
|
77
|
+
$zocketExe = Join-Path $venvDir "Scripts\zocket.exe"
|
|
78
|
+
|
|
79
|
+
Run-Step $py.Cmd ($py.Prefix + @("-m", "venv", $venvDir))
|
|
80
|
+
Run-Step $venvPy @("-m", "pip", "install", "--upgrade", "pip", "setuptools", "wheel")
|
|
81
|
+
|
|
82
|
+
if ($Source -eq "PyPI") {
|
|
83
|
+
Run-Step $venvPy @("-m", "pip", "install", "--upgrade", $pkgSource)
|
|
84
|
+
} else {
|
|
85
|
+
Run-Step $venvPy @("-m", "pip", "install", "--upgrade", $pkgSource)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
Ensure-Dir $ZocketHome
|
|
89
|
+
$env:ZOCKET_HOME = $ZocketHome
|
|
90
|
+
|
|
91
|
+
if (-not (Test-Path -LiteralPath (Join-Path $ZocketHome "vault.enc"))) {
|
|
92
|
+
Run-Step $zocketExe @("init")
|
|
93
|
+
}
|
|
94
|
+
Run-Step $zocketExe @("config", "set-language", $Lang)
|
|
95
|
+
|
|
96
|
+
if ($EnableAutostart) {
|
|
97
|
+
$webTask = "ZocketWeb"
|
|
98
|
+
$mcpSseTask = "ZocketMcpSse"
|
|
99
|
+
$mcpStreamTask = "ZocketMcpStreamable"
|
|
100
|
+
|
|
101
|
+
$webCmd = "`"$venvPy`" -m zocket web --host 127.0.0.1 --port $WebPort"
|
|
102
|
+
$mcpSseCmd = "`"$venvPy`" -m zocket mcp --transport sse --mode $McpMode --host 127.0.0.1 --port $McpPort"
|
|
103
|
+
$mcpStreamCmd = "`"$venvPy`" -m zocket mcp --transport streamable-http --mode $McpMode --host 127.0.0.1 --port $McpStreamPort"
|
|
104
|
+
|
|
105
|
+
schtasks /Create /F /SC ONLOGON /RL LIMITED /TN $webTask /TR $webCmd | Out-Null
|
|
106
|
+
schtasks /Create /F /SC ONLOGON /RL LIMITED /TN $mcpSseTask /TR $mcpSseCmd | Out-Null
|
|
107
|
+
schtasks /Create /F /SC ONLOGON /RL LIMITED /TN $mcpStreamTask /TR $mcpStreamCmd | Out-Null
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
Write-Output "zocket installed successfully."
|
|
111
|
+
Write-Output "venv: $venvDir"
|
|
112
|
+
Write-Output "zocket: $zocketExe"
|
|
113
|
+
Write-Output "ZOCKET_HOME=$ZocketHome"
|
|
114
|
+
Write-Output "web panel: http://127.0.0.1:$WebPort"
|
|
115
|
+
Write-Output "mcp sse: http://127.0.0.1:$McpPort/sse"
|
|
116
|
+
Write-Output "mcp http: http://127.0.0.1:$McpStreamPort/mcp"
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
5
|
+
REPO_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
|
|
6
|
+
|
|
7
|
+
SOURCE_MODE="${SOURCE_MODE:-auto}" # auto|local|git|pypi
|
|
8
|
+
REPO_URL="${REPO_URL:-https://github.com/your-org/zocket.git}"
|
|
9
|
+
REPO_REF="${REPO_REF:-main}"
|
|
10
|
+
INSTALL_ROOT="${INSTALL_ROOT:-$HOME/.local/share/zocket}"
|
|
11
|
+
ZOCKET_HOME_DIR="${ZOCKET_HOME_DIR:-$HOME/.zocket}"
|
|
12
|
+
LANGUAGE="${LANGUAGE:-en}" # en|ru
|
|
13
|
+
WEB_PORT="${WEB_PORT:-18001}"
|
|
14
|
+
MCP_PORT="${MCP_PORT:-18002}"
|
|
15
|
+
MCP_STREAM_PORT="${MCP_STREAM_PORT:-18003}"
|
|
16
|
+
MCP_MODE="${MCP_MODE:-metadata}" # metadata|admin
|
|
17
|
+
AUTOSTART="${AUTOSTART:-user}" # user|system|none
|
|
18
|
+
SERVICE_USER="${SERVICE_USER:-zocketd}"
|
|
19
|
+
|
|
20
|
+
usage() {
|
|
21
|
+
cat <<EOF
|
|
22
|
+
Usage: $(basename "$0") [options]
|
|
23
|
+
|
|
24
|
+
Options:
|
|
25
|
+
--source <auto|local|git|pypi>
|
|
26
|
+
--repo-url <git-url>
|
|
27
|
+
--repo-ref <branch-or-tag>
|
|
28
|
+
--install-root <path>
|
|
29
|
+
--zocket-home <path>
|
|
30
|
+
--lang <en|ru>
|
|
31
|
+
--web-port <port>
|
|
32
|
+
--mcp-port <port>
|
|
33
|
+
--mcp-stream-port <port>
|
|
34
|
+
--mcp-mode <metadata|admin>
|
|
35
|
+
--autostart <user|system|none>
|
|
36
|
+
--service-user <name>
|
|
37
|
+
-h, --help
|
|
38
|
+
|
|
39
|
+
Environment variables with same names are also supported.
|
|
40
|
+
EOF
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
while [[ $# -gt 0 ]]; do
|
|
44
|
+
case "$1" in
|
|
45
|
+
--source) SOURCE_MODE="$2"; shift 2 ;;
|
|
46
|
+
--repo-url) REPO_URL="$2"; shift 2 ;;
|
|
47
|
+
--repo-ref) REPO_REF="$2"; shift 2 ;;
|
|
48
|
+
--install-root) INSTALL_ROOT="$2"; shift 2 ;;
|
|
49
|
+
--zocket-home) ZOCKET_HOME_DIR="$2"; shift 2 ;;
|
|
50
|
+
--lang) LANGUAGE="$2"; shift 2 ;;
|
|
51
|
+
--web-port) WEB_PORT="$2"; shift 2 ;;
|
|
52
|
+
--mcp-port) MCP_PORT="$2"; shift 2 ;;
|
|
53
|
+
--mcp-stream-port) MCP_STREAM_PORT="$2"; shift 2 ;;
|
|
54
|
+
--mcp-mode) MCP_MODE="$2"; shift 2 ;;
|
|
55
|
+
--autostart) AUTOSTART="$2"; shift 2 ;;
|
|
56
|
+
--service-user) SERVICE_USER="$2"; shift 2 ;;
|
|
57
|
+
-h|--help) usage; exit 0 ;;
|
|
58
|
+
*) echo "Unknown argument: $1" >&2; usage; exit 2 ;;
|
|
59
|
+
esac
|
|
60
|
+
done
|
|
61
|
+
|
|
62
|
+
have_cmd() {
|
|
63
|
+
command -v "$1" >/dev/null 2>&1
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
run_sudo() {
|
|
67
|
+
if have_cmd sudo; then
|
|
68
|
+
sudo "$@"
|
|
69
|
+
else
|
|
70
|
+
"$@"
|
|
71
|
+
fi
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
install_python_linux() {
|
|
75
|
+
if have_cmd apt-get; then
|
|
76
|
+
run_sudo apt-get update
|
|
77
|
+
run_sudo apt-get install -y python3 python3-venv python3-pip git curl
|
|
78
|
+
return
|
|
79
|
+
fi
|
|
80
|
+
if have_cmd dnf; then
|
|
81
|
+
run_sudo dnf install -y python3 python3-pip python3-virtualenv git curl
|
|
82
|
+
return
|
|
83
|
+
fi
|
|
84
|
+
if have_cmd yum; then
|
|
85
|
+
run_sudo yum install -y python3 python3-pip git curl
|
|
86
|
+
return
|
|
87
|
+
fi
|
|
88
|
+
if have_cmd pacman; then
|
|
89
|
+
run_sudo pacman -Sy --noconfirm python python-pip git curl
|
|
90
|
+
return
|
|
91
|
+
fi
|
|
92
|
+
if have_cmd zypper; then
|
|
93
|
+
run_sudo zypper install -y python3 python3-pip python3-virtualenv git curl
|
|
94
|
+
return
|
|
95
|
+
fi
|
|
96
|
+
if have_cmd apk; then
|
|
97
|
+
run_sudo apk add --no-cache python3 py3-pip py3-virtualenv git curl
|
|
98
|
+
return
|
|
99
|
+
fi
|
|
100
|
+
echo "Unsupported Linux package manager. Install Python 3.10+, pip, and venv manually." >&2
|
|
101
|
+
exit 1
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
install_python_macos() {
|
|
105
|
+
if ! have_cmd brew; then
|
|
106
|
+
echo "Homebrew not found. Install Homebrew first: https://brew.sh" >&2
|
|
107
|
+
exit 1
|
|
108
|
+
fi
|
|
109
|
+
brew install python git curl
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
OS="$(uname -s | tr '[:upper:]' '[:lower:]')"
|
|
113
|
+
if ! have_cmd python3; then
|
|
114
|
+
echo "python3 not found, installing dependencies..."
|
|
115
|
+
case "$OS" in
|
|
116
|
+
linux*) install_python_linux ;;
|
|
117
|
+
darwin*) install_python_macos ;;
|
|
118
|
+
*)
|
|
119
|
+
echo "Unsupported OS for this installer: $OS" >&2
|
|
120
|
+
exit 1
|
|
121
|
+
;;
|
|
122
|
+
esac
|
|
123
|
+
fi
|
|
124
|
+
|
|
125
|
+
if ! have_cmd git; then
|
|
126
|
+
echo "git not found, installing..."
|
|
127
|
+
case "$OS" in
|
|
128
|
+
linux*) install_python_linux ;;
|
|
129
|
+
darwin*) install_python_macos ;;
|
|
130
|
+
*) echo "Install git manually and rerun." >&2; exit 1 ;;
|
|
131
|
+
esac
|
|
132
|
+
fi
|
|
133
|
+
|
|
134
|
+
if [[ "$SOURCE_MODE" == "auto" ]]; then
|
|
135
|
+
if [[ -f "${REPO_ROOT}/pyproject.toml" ]]; then
|
|
136
|
+
SOURCE_MODE="local"
|
|
137
|
+
else
|
|
138
|
+
SOURCE_MODE="git"
|
|
139
|
+
fi
|
|
140
|
+
fi
|
|
141
|
+
|
|
142
|
+
PKG_SOURCE=""
|
|
143
|
+
SRC_DIR="${INSTALL_ROOT}/src"
|
|
144
|
+
|
|
145
|
+
mkdir -p "${INSTALL_ROOT}"
|
|
146
|
+
|
|
147
|
+
if [[ "$SOURCE_MODE" == "local" ]]; then
|
|
148
|
+
PKG_SOURCE="${REPO_ROOT}"
|
|
149
|
+
elif [[ "$SOURCE_MODE" == "git" ]]; then
|
|
150
|
+
if [[ -d "${SRC_DIR}/.git" ]]; then
|
|
151
|
+
git -C "${SRC_DIR}" fetch --all --tags
|
|
152
|
+
git -C "${SRC_DIR}" checkout "${REPO_REF}"
|
|
153
|
+
git -C "${SRC_DIR}" pull --ff-only
|
|
154
|
+
else
|
|
155
|
+
rm -rf "${SRC_DIR}"
|
|
156
|
+
git clone --depth 1 --branch "${REPO_REF}" "${REPO_URL}" "${SRC_DIR}"
|
|
157
|
+
fi
|
|
158
|
+
PKG_SOURCE="${SRC_DIR}"
|
|
159
|
+
elif [[ "$SOURCE_MODE" == "pypi" ]]; then
|
|
160
|
+
PKG_SOURCE="zocket"
|
|
161
|
+
else
|
|
162
|
+
echo "Invalid source mode: $SOURCE_MODE" >&2
|
|
163
|
+
exit 2
|
|
164
|
+
fi
|
|
165
|
+
|
|
166
|
+
VENV_DIR="${INSTALL_ROOT}/venv"
|
|
167
|
+
PY_BIN="${VENV_DIR}/bin/python3"
|
|
168
|
+
ZOCKET_BIN="${VENV_DIR}/bin/zocket"
|
|
169
|
+
|
|
170
|
+
python3 -m venv "${VENV_DIR}"
|
|
171
|
+
"${PY_BIN}" -m pip install --upgrade pip setuptools wheel
|
|
172
|
+
|
|
173
|
+
if [[ "$SOURCE_MODE" == "pypi" ]]; then
|
|
174
|
+
"${PY_BIN}" -m pip install --upgrade "${PKG_SOURCE}"
|
|
175
|
+
else
|
|
176
|
+
"${PY_BIN}" -m pip install --upgrade "${PKG_SOURCE}"
|
|
177
|
+
fi
|
|
178
|
+
|
|
179
|
+
mkdir -p "$HOME/.local/bin"
|
|
180
|
+
ln -sf "${ZOCKET_BIN}" "$HOME/.local/bin/zocket"
|
|
181
|
+
|
|
182
|
+
export ZOCKET_HOME="${ZOCKET_HOME_DIR}"
|
|
183
|
+
mkdir -p "${ZOCKET_HOME_DIR}"
|
|
184
|
+
|
|
185
|
+
if [[ ! -f "${ZOCKET_HOME_DIR}/vault.enc" ]]; then
|
|
186
|
+
"${ZOCKET_BIN}" init
|
|
187
|
+
fi
|
|
188
|
+
|
|
189
|
+
"${ZOCKET_BIN}" config set-language "${LANGUAGE}" >/dev/null
|
|
190
|
+
|
|
191
|
+
if [[ "$AUTOSTART" == "user" && "$OS" == linux* ]]; then
|
|
192
|
+
"${ZOCKET_BIN}" autostart install \
|
|
193
|
+
--target both \
|
|
194
|
+
--web-port "${WEB_PORT}" \
|
|
195
|
+
--mcp-port "${MCP_PORT}" \
|
|
196
|
+
--mcp-mode "${MCP_MODE}" \
|
|
197
|
+
--zocket-home "${ZOCKET_HOME_DIR}" >/dev/null
|
|
198
|
+
fi
|
|
199
|
+
|
|
200
|
+
if [[ "$AUTOSTART" == "system" && "$OS" == linux* ]]; then
|
|
201
|
+
run_sudo env ZOCKET_HOME="${ZOCKET_HOME_DIR}" "${PY_BIN}" -m zocket harden install-linux-system \
|
|
202
|
+
--service-user "${SERVICE_USER}" \
|
|
203
|
+
--zocket-home "${ZOCKET_HOME_DIR}" \
|
|
204
|
+
--web-port "${WEB_PORT}" \
|
|
205
|
+
--mcp-host 127.0.0.1 \
|
|
206
|
+
--mcp-port "${MCP_PORT}" \
|
|
207
|
+
--mcp-mode "${MCP_MODE}" >/dev/null
|
|
208
|
+
fi
|
|
209
|
+
|
|
210
|
+
cat <<EOF
|
|
211
|
+
zocket installed successfully.
|
|
212
|
+
|
|
213
|
+
Runtime:
|
|
214
|
+
venv: ${VENV_DIR}
|
|
215
|
+
zocket: ${ZOCKET_BIN}
|
|
216
|
+
ZOCKET_HOME=${ZOCKET_HOME_DIR}
|
|
217
|
+
|
|
218
|
+
Default ports:
|
|
219
|
+
web panel: http://127.0.0.1:${WEB_PORT}
|
|
220
|
+
MCP SSE: http://127.0.0.1:${MCP_PORT}/sse
|
|
221
|
+
MCP HTTP: http://127.0.0.1:${MCP_STREAM_PORT}/mcp
|
|
222
|
+
|
|
223
|
+
Next steps:
|
|
224
|
+
1) Open web: ${ZOCKET_BIN} web --host 127.0.0.1 --port ${WEB_PORT}
|
|
225
|
+
2) MCP SSE (Claude Code): ${ZOCKET_BIN} mcp --transport sse --mode ${MCP_MODE} --host 127.0.0.1 --port ${MCP_PORT}
|
|
226
|
+
3) MCP Streamable (Codex): ${ZOCKET_BIN} mcp --transport streamable-http --mode ${MCP_MODE} --host 127.0.0.1 --port ${MCP_STREAM_PORT}
|
|
227
|
+
4) MCP stdio: ${ZOCKET_BIN} mcp --transport stdio --mode ${MCP_MODE}
|
|
228
|
+
EOF
|