@ao_zorin/zocket 1.0.0 → 1.1.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/README.md +17 -22
- package/dist/zocket.js +1999 -0
- package/docs/GIT_NPM_RELEASE.md +53 -0
- package/docs/INSTALL.md +27 -56
- package/docs/SOURCES.md +29 -0
- package/package.json +49 -37
- package/scripts/install-zocket.ps1 +1 -1
- package/scripts/install-zocket.sh +131 -13
- package/bin/zocket-setup.cjs +0 -12
- package/bin/zocket.cjs +0 -174
- package/pyproject.toml +0 -29
- package/scripts/ai-autodeploy.py +0 -127
- package/zocket/__init__.py +0 -2
- package/zocket/__main__.py +0 -5
- package/zocket/audit.py +0 -76
- package/zocket/auth.py +0 -34
- package/zocket/autostart.py +0 -281
- package/zocket/backup.py +0 -33
- package/zocket/cli.py +0 -655
- package/zocket/config_store.py +0 -68
- package/zocket/crypto.py +0 -158
- package/zocket/harden.py +0 -136
- package/zocket/i18n.py +0 -216
- package/zocket/mcp_server.py +0 -249
- package/zocket/paths.py +0 -50
- package/zocket/runner.py +0 -108
- package/zocket/templates/index.html +0 -1062
- package/zocket/templates/login.html +0 -244
- package/zocket/vault.py +0 -331
- package/zocket/web.py +0 -490
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# Git + npm + Python Release Guide
|
|
2
|
+
|
|
3
|
+
## 1) Initialize git project
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
git init
|
|
7
|
+
git add .
|
|
8
|
+
git commit -m "feat: zocket initial release"
|
|
9
|
+
git branch -M main
|
|
10
|
+
git remote add origin git@github.com:your-org/zocket.git
|
|
11
|
+
git push -u origin main
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## 2) Pre-release checks
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
bash scripts/release-check.sh
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## 3) Publish Python package (PyPI)
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
python3 -m pip install --upgrade build twine
|
|
24
|
+
python3 -m build
|
|
25
|
+
twine upload dist/*
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## 4) Publish npm package
|
|
29
|
+
|
|
30
|
+
Update metadata in `package.json`:
|
|
31
|
+
- `name`
|
|
32
|
+
- `repository.url`
|
|
33
|
+
- `homepage`
|
|
34
|
+
- `bugs.url`
|
|
35
|
+
|
|
36
|
+
Then:
|
|
37
|
+
```bash
|
|
38
|
+
npm login
|
|
39
|
+
npm publish --access public
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## 5) Tag release
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
git tag -a v1.0.0 -m "zocket v1.0.0"
|
|
46
|
+
git push origin v1.0.0
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## 6) Optional GitHub Release artifacts
|
|
50
|
+
|
|
51
|
+
Upload:
|
|
52
|
+
- Python wheels/sdist from `dist/`
|
|
53
|
+
- npm package tarball from `npm pack`
|
package/docs/INSTALL.md
CHANGED
|
@@ -70,14 +70,20 @@ Requirements:
|
|
|
70
70
|
- Python 3.10+ (recommended from `python.org` or `winget`)
|
|
71
71
|
- Git for Windows
|
|
72
72
|
|
|
73
|
-
|
|
73
|
+
Autostart (enabled by default):
|
|
74
74
|
```powershell
|
|
75
|
-
powershell -ExecutionPolicy Bypass -File .\scripts\install-zocket.ps1
|
|
75
|
+
powershell -ExecutionPolicy Bypass -File .\scripts\install-zocket.ps1
|
|
76
76
|
```
|
|
77
77
|
|
|
78
78
|
This creates scheduled tasks:
|
|
79
79
|
- `ZocketWeb`
|
|
80
|
-
- `
|
|
80
|
+
- `ZocketMcpSse`
|
|
81
|
+
- `ZocketMcpStreamable`
|
|
82
|
+
|
|
83
|
+
Disable autostart:
|
|
84
|
+
```powershell
|
|
85
|
+
powershell -ExecutionPolicy Bypass -File .\scripts\install-zocket.ps1 -EnableAutostart:$false
|
|
86
|
+
```
|
|
81
87
|
|
|
82
88
|
## 5) NPM package usage
|
|
83
89
|
|
|
@@ -109,70 +115,35 @@ zocket mcp --transport streamable-http --mode metadata --host 127.0.0.1 --port 1
|
|
|
109
115
|
|
|
110
116
|
## 6) Systemd hardening on Linux (production)
|
|
111
117
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
--web-port 18001 \
|
|
117
|
-
--mcp-host 127.0.0.1 \
|
|
118
|
-
--mcp-port 18002 \
|
|
119
|
-
--mcp-mode metadata
|
|
120
|
-
```
|
|
118
|
+
If you install with `--autostart system`, the installer creates and enables:
|
|
119
|
+
- `zocket-web.service` (web panel on 18001)
|
|
120
|
+
- `zocket-mcp-sse.service` (Claude Code, 18002)
|
|
121
|
+
- `zocket-mcp-http.service` (Codex, 18003)
|
|
121
122
|
|
|
122
123
|
Check:
|
|
123
124
|
```bash
|
|
124
125
|
systemctl status zocket-web.service --no-pager
|
|
126
|
+
systemctl status zocket-mcp-sse.service --no-pager
|
|
125
127
|
systemctl status zocket-mcp-http.service --no-pager
|
|
126
|
-
systemctl status zocket-mcp-http-streamable.service --no-pager
|
|
127
|
-
```
|
|
128
|
-
|
|
129
|
-
### Optional: systemd unit for Codex (streamable HTTP on 18003)
|
|
130
|
-
|
|
131
|
-
Create `/etc/systemd/system/zocket-mcp-http-streamable.service`:
|
|
132
|
-
```ini
|
|
133
|
-
[Unit]
|
|
134
|
-
Description=Zocket MCP HTTP Streamable (system)
|
|
135
|
-
After=network-online.target
|
|
136
|
-
Wants=network-online.target
|
|
137
|
-
|
|
138
|
-
[Service]
|
|
139
|
-
Type=simple
|
|
140
|
-
User=zocketd
|
|
141
|
-
Group=zocketd
|
|
142
|
-
Environment=ZOCKET_HOME=/var/lib/zocket
|
|
143
|
-
ExecStart=/usr/bin/python3 -m zocket mcp --transport streamable-http --mode metadata --host 127.0.0.1 --port 18003
|
|
144
|
-
Restart=on-failure
|
|
145
|
-
RestartSec=2
|
|
146
|
-
NoNewPrivileges=true
|
|
147
|
-
PrivateTmp=true
|
|
148
|
-
ProtectSystem=strict
|
|
149
|
-
ProtectHome=read-only
|
|
150
|
-
ProtectKernelTunables=true
|
|
151
|
-
ProtectControlGroups=true
|
|
152
|
-
LockPersonality=true
|
|
153
|
-
MemoryDenyWriteExecute=true
|
|
154
|
-
ReadWritePaths=/var/lib/zocket
|
|
155
|
-
|
|
156
|
-
[Install]
|
|
157
|
-
WantedBy=multi-user.target
|
|
158
|
-
```
|
|
159
|
-
|
|
160
|
-
Enable and start:
|
|
161
|
-
```bash
|
|
162
|
-
sudo systemctl daemon-reload
|
|
163
|
-
sudo systemctl enable --now zocket-mcp-http-streamable.service
|
|
164
128
|
```
|
|
165
129
|
|
|
166
130
|
### Linux user-level autostart (no root)
|
|
167
131
|
```bash
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
132
|
+
systemctl --user enable --now zocket-web.service
|
|
133
|
+
systemctl --user enable --now zocket-mcp-sse.service
|
|
134
|
+
systemctl --user enable --now zocket-mcp-http.service
|
|
135
|
+
systemctl --user status zocket-web.service --no-pager
|
|
136
|
+
systemctl --user status zocket-mcp-sse.service --no-pager
|
|
137
|
+
systemctl --user status zocket-mcp-http.service --no-pager
|
|
171
138
|
```
|
|
172
139
|
|
|
173
|
-
### macOS launchd autostart (
|
|
174
|
-
|
|
175
|
-
|
|
140
|
+
### macOS launchd autostart (installed by script)
|
|
141
|
+
Installer creates and loads:
|
|
142
|
+
- `~/Library/LaunchAgents/dev.zocket.web.plist`
|
|
143
|
+
- `~/Library/LaunchAgents/dev.zocket.mcp-sse.plist`
|
|
144
|
+
- `~/Library/LaunchAgents/dev.zocket.mcp-streamable.plist`
|
|
145
|
+
|
|
146
|
+
If you need to install manually, use:
|
|
176
147
|
|
|
177
148
|
```xml
|
|
178
149
|
<?xml version="1.0" encoding="UTF-8"?>
|
package/docs/SOURCES.md
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# External References Used
|
|
2
|
+
|
|
3
|
+
Official docs used while preparing client/install instructions:
|
|
4
|
+
|
|
5
|
+
- OpenAI Codex CLI MCP docs:
|
|
6
|
+
- https://platform.openai.com/docs/codex/mcp
|
|
7
|
+
- https://developers.openai.com/codex/cli
|
|
8
|
+
- Claude Code MCP docs:
|
|
9
|
+
- https://docs.anthropic.com/en/docs/claude-code/mcp
|
|
10
|
+
- Claude Desktop MCP setup/help:
|
|
11
|
+
- https://support.claude.com/en/articles/12304248-setting-up-remote-mcp-servers-in-claude-desktop
|
|
12
|
+
- OpenCode docs:
|
|
13
|
+
- https://opencode.ai/docs/
|
|
14
|
+
- https://opencode.ai/docs/config
|
|
15
|
+
- https://opencode.ai/docs/providers
|
|
16
|
+
- https://opencode.ai/docs/mcp-servers
|
|
17
|
+
- Qwen Code docs:
|
|
18
|
+
- https://qwenlm.github.io/qwen-code-docs/getting-started/
|
|
19
|
+
- https://qwenlm.github.io/qwen-code-docs/advanced/model-providers/
|
|
20
|
+
- https://qwenlm.github.io/qwen-code-docs/advanced/mcp/
|
|
21
|
+
- Windsurf MCP docs:
|
|
22
|
+
- https://docs.windsurf.com/windsurf/cascade/mcp
|
|
23
|
+
- Antigravity MCP setup docs:
|
|
24
|
+
- https://docs.cloud.google.com/vertex-ai/generative-ai/docs/agent-engine/mcp/use-with-antigravity
|
|
25
|
+
- https://firebase.google.com/docs/studio/set-up-mcp-server
|
|
26
|
+
- Ollama docs:
|
|
27
|
+
- https://docs.ollama.com/
|
|
28
|
+
- Hugging Face local/openai-compatible docs:
|
|
29
|
+
- https://huggingface.co/docs/text-generation-inference/main/en/messages_api
|
package/package.json
CHANGED
|
@@ -1,52 +1,64 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ao_zorin/zocket",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "
|
|
5
|
-
"
|
|
6
|
-
"private": false,
|
|
7
|
-
"type": "commonjs",
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"description": "Local encrypted vault + web panel + MCP server for AI agent workflows",
|
|
5
|
+
"type": "module",
|
|
8
6
|
"bin": {
|
|
9
|
-
"zocket": "
|
|
10
|
-
|
|
7
|
+
"zocket": "dist/zocket.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"build": "tsup",
|
|
11
|
+
"dev": "tsup --watch",
|
|
12
|
+
"test": "vitest run",
|
|
13
|
+
"test:watch": "vitest",
|
|
14
|
+
"typecheck": "tsc --noEmit",
|
|
15
|
+
"prepublishOnly": "npm run build"
|
|
16
|
+
},
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"@anthropic-ai/sdk": "^0.78.0",
|
|
19
|
+
"@hono/node-server": "^1.13.0",
|
|
20
|
+
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
21
|
+
"commander": "^12.0.0",
|
|
22
|
+
"hono": "^4.0.0",
|
|
23
|
+
"proper-lockfile": "^4.1.2",
|
|
24
|
+
"zod": "^3.22.0"
|
|
25
|
+
},
|
|
26
|
+
"peerDependencies": {
|
|
27
|
+
"keytar": "^7.0.0"
|
|
28
|
+
},
|
|
29
|
+
"peerDependenciesMeta": {
|
|
30
|
+
"keytar": {
|
|
31
|
+
"optional": true
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"@anthropic-ai/tokenizer": "^0.0.4",
|
|
36
|
+
"@types/node": "^20.0.0",
|
|
37
|
+
"@types/proper-lockfile": "^4.1.4",
|
|
38
|
+
"js-tiktoken": "^1.0.21",
|
|
39
|
+
"tsup": "^8.0.0",
|
|
40
|
+
"typescript": "^5.0.0",
|
|
41
|
+
"vitest": "^2.0.0"
|
|
42
|
+
},
|
|
43
|
+
"engines": {
|
|
44
|
+
"node": ">=18.0.0"
|
|
11
45
|
},
|
|
12
46
|
"files": [
|
|
13
|
-
"
|
|
47
|
+
"dist",
|
|
48
|
+
"README.md",
|
|
49
|
+
"LICENSE",
|
|
14
50
|
"docs/AI_AUTODEPLOY.md",
|
|
15
51
|
"docs/CLIENTS_MCP.md",
|
|
52
|
+
"docs/GIT_NPM_RELEASE.md",
|
|
16
53
|
"docs/INSTALL.md",
|
|
17
54
|
"docs/LOCAL_MODELS.md",
|
|
18
|
-
"
|
|
55
|
+
"docs/SOURCES.md",
|
|
19
56
|
"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"
|
|
57
|
+
"scripts/install-zocket.ps1"
|
|
43
58
|
],
|
|
59
|
+
"license": "MIT",
|
|
44
60
|
"repository": {
|
|
45
61
|
"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"
|
|
62
|
+
"url": "git+https://github.com/aozorin/zocket.git"
|
|
51
63
|
}
|
|
52
64
|
}
|
|
@@ -109,6 +109,95 @@ install_python_macos() {
|
|
|
109
109
|
brew install python git curl
|
|
110
110
|
}
|
|
111
111
|
|
|
112
|
+
write_systemd_unit() {
|
|
113
|
+
local unit_path="$1"
|
|
114
|
+
local exec_start="$2"
|
|
115
|
+
local svc_user="$3"
|
|
116
|
+
local svc_group="$4"
|
|
117
|
+
local zocket_home="$5"
|
|
118
|
+
local extra_rw="${6:-}"
|
|
119
|
+
run_sudo tee "${unit_path}" >/dev/null <<EOF
|
|
120
|
+
[Unit]
|
|
121
|
+
Description=Zocket $(basename "${unit_path%.service}")
|
|
122
|
+
After=network-online.target
|
|
123
|
+
Wants=network-online.target
|
|
124
|
+
|
|
125
|
+
[Service]
|
|
126
|
+
Type=simple
|
|
127
|
+
User=${svc_user}
|
|
128
|
+
Group=${svc_group}
|
|
129
|
+
Environment=ZOCKET_HOME=${zocket_home}
|
|
130
|
+
ExecStart=${exec_start}
|
|
131
|
+
Restart=on-failure
|
|
132
|
+
RestartSec=2
|
|
133
|
+
NoNewPrivileges=true
|
|
134
|
+
PrivateTmp=true
|
|
135
|
+
ProtectSystem=strict
|
|
136
|
+
ProtectHome=read-only
|
|
137
|
+
ProtectKernelTunables=true
|
|
138
|
+
ProtectControlGroups=true
|
|
139
|
+
LockPersonality=true
|
|
140
|
+
MemoryDenyWriteExecute=true
|
|
141
|
+
ReadWritePaths=${zocket_home} ${extra_rw}
|
|
142
|
+
|
|
143
|
+
[Install]
|
|
144
|
+
WantedBy=multi-user.target
|
|
145
|
+
EOF
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
write_systemd_user_unit() {
|
|
149
|
+
local unit_path="$1"
|
|
150
|
+
local exec_start="$2"
|
|
151
|
+
local zocket_home="$3"
|
|
152
|
+
mkdir -p "$(dirname "${unit_path}")"
|
|
153
|
+
cat > "${unit_path}" <<EOF
|
|
154
|
+
[Unit]
|
|
155
|
+
Description=Zocket $(basename "${unit_path%.service}")
|
|
156
|
+
After=default.target
|
|
157
|
+
|
|
158
|
+
[Service]
|
|
159
|
+
Type=simple
|
|
160
|
+
Environment=ZOCKET_HOME=${zocket_home}
|
|
161
|
+
ExecStart=${exec_start}
|
|
162
|
+
Restart=on-failure
|
|
163
|
+
RestartSec=2
|
|
164
|
+
|
|
165
|
+
[Install]
|
|
166
|
+
WantedBy=default.target
|
|
167
|
+
EOF
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
install_launchd() {
|
|
171
|
+
local label="$1"
|
|
172
|
+
local exec_start="$2"
|
|
173
|
+
local zocket_home="$3"
|
|
174
|
+
local plist_dir="$4"
|
|
175
|
+
mkdir -p "${plist_dir}"
|
|
176
|
+
cat > "${plist_dir}/${label}.plist" <<EOF
|
|
177
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
178
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
179
|
+
<plist version="1.0">
|
|
180
|
+
<dict>
|
|
181
|
+
<key>Label</key><string>${label}</string>
|
|
182
|
+
<key>ProgramArguments</key>
|
|
183
|
+
<array>
|
|
184
|
+
EOF
|
|
185
|
+
for part in ${exec_start}; do
|
|
186
|
+
echo " <string>${part}</string>" >> "${plist_dir}/${label}.plist"
|
|
187
|
+
done
|
|
188
|
+
cat >> "${plist_dir}/${label}.plist" <<EOF
|
|
189
|
+
</array>
|
|
190
|
+
<key>EnvironmentVariables</key>
|
|
191
|
+
<dict>
|
|
192
|
+
<key>ZOCKET_HOME</key><string>${zocket_home}</string>
|
|
193
|
+
</dict>
|
|
194
|
+
<key>RunAtLoad</key><true/>
|
|
195
|
+
<key>KeepAlive</key><true/>
|
|
196
|
+
</dict>
|
|
197
|
+
</plist>
|
|
198
|
+
EOF
|
|
199
|
+
}
|
|
200
|
+
|
|
112
201
|
OS="$(uname -s | tr '[:upper:]' '[:lower:]')"
|
|
113
202
|
if ! have_cmd python3; then
|
|
114
203
|
echo "python3 not found, installing dependencies..."
|
|
@@ -189,22 +278,51 @@ fi
|
|
|
189
278
|
"${ZOCKET_BIN}" config set-language "${LANGUAGE}" >/dev/null
|
|
190
279
|
|
|
191
280
|
if [[ "$AUTOSTART" == "user" && "$OS" == linux* ]]; then
|
|
192
|
-
"$
|
|
193
|
-
|
|
194
|
-
--
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
281
|
+
USER_UNIT_DIR="$HOME/.config/systemd/user"
|
|
282
|
+
write_systemd_user_unit "${USER_UNIT_DIR}/zocket-web.service" \
|
|
283
|
+
"${PY_BIN} -m zocket web --host 127.0.0.1 --port ${WEB_PORT}" \
|
|
284
|
+
"${ZOCKET_HOME_DIR}"
|
|
285
|
+
write_systemd_user_unit "${USER_UNIT_DIR}/zocket-mcp-sse.service" \
|
|
286
|
+
"${PY_BIN} -m zocket mcp --transport sse --mode ${MCP_MODE} --host 127.0.0.1 --port ${MCP_PORT}" \
|
|
287
|
+
"${ZOCKET_HOME_DIR}"
|
|
288
|
+
write_systemd_user_unit "${USER_UNIT_DIR}/zocket-mcp-http.service" \
|
|
289
|
+
"${PY_BIN} -m zocket mcp --transport streamable-http --mode ${MCP_MODE} --host 127.0.0.1 --port ${MCP_STREAM_PORT}" \
|
|
290
|
+
"${ZOCKET_HOME_DIR}"
|
|
291
|
+
systemctl --user daemon-reload
|
|
292
|
+
systemctl --user enable --now zocket-web.service zocket-mcp-sse.service zocket-mcp-http.service >/dev/null
|
|
198
293
|
fi
|
|
199
294
|
|
|
200
295
|
if [[ "$AUTOSTART" == "system" && "$OS" == linux* ]]; then
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
--
|
|
206
|
-
|
|
207
|
-
|
|
296
|
+
write_systemd_unit "/etc/systemd/system/zocket-web.service" \
|
|
297
|
+
"${PY_BIN} -m zocket web --host 127.0.0.1 --port ${WEB_PORT}" \
|
|
298
|
+
"${SERVICE_USER}" "${SERVICE_USER}" "${ZOCKET_HOME_DIR}" "/tmp"
|
|
299
|
+
write_systemd_unit "/etc/systemd/system/zocket-mcp-sse.service" \
|
|
300
|
+
"${PY_BIN} -m zocket mcp --transport sse --mode ${MCP_MODE} --host 127.0.0.1 --port ${MCP_PORT}" \
|
|
301
|
+
"${SERVICE_USER}" "${SERVICE_USER}" "${ZOCKET_HOME_DIR}"
|
|
302
|
+
write_systemd_unit "/etc/systemd/system/zocket-mcp-http.service" \
|
|
303
|
+
"${PY_BIN} -m zocket mcp --transport streamable-http --mode ${MCP_MODE} --host 127.0.0.1 --port ${MCP_STREAM_PORT}" \
|
|
304
|
+
"${SERVICE_USER}" "${SERVICE_USER}" "${ZOCKET_HOME_DIR}"
|
|
305
|
+
run_sudo systemctl daemon-reload
|
|
306
|
+
run_sudo systemctl enable --now zocket-web.service zocket-mcp-sse.service zocket-mcp-http.service >/dev/null
|
|
307
|
+
fi
|
|
308
|
+
|
|
309
|
+
if [[ "$AUTOSTART" != "none" && "$OS" == darwin* ]]; then
|
|
310
|
+
PLIST_DIR="$HOME/Library/LaunchAgents"
|
|
311
|
+
install_launchd "dev.zocket.web" \
|
|
312
|
+
"${PY_BIN} -m zocket web --host 127.0.0.1 --port ${WEB_PORT}" \
|
|
313
|
+
"${ZOCKET_HOME_DIR}" "${PLIST_DIR}"
|
|
314
|
+
install_launchd "dev.zocket.mcp-sse" \
|
|
315
|
+
"${PY_BIN} -m zocket mcp --transport sse --mode ${MCP_MODE} --host 127.0.0.1 --port ${MCP_PORT}" \
|
|
316
|
+
"${ZOCKET_HOME_DIR}" "${PLIST_DIR}"
|
|
317
|
+
install_launchd "dev.zocket.mcp-streamable" \
|
|
318
|
+
"${PY_BIN} -m zocket mcp --transport streamable-http --mode ${MCP_MODE} --host 127.0.0.1 --port ${MCP_STREAM_PORT}" \
|
|
319
|
+
"${ZOCKET_HOME_DIR}" "${PLIST_DIR}"
|
|
320
|
+
launchctl unload "${PLIST_DIR}/dev.zocket.web.plist" >/dev/null 2>&1 || true
|
|
321
|
+
launchctl unload "${PLIST_DIR}/dev.zocket.mcp-sse.plist" >/dev/null 2>&1 || true
|
|
322
|
+
launchctl unload "${PLIST_DIR}/dev.zocket.mcp-streamable.plist" >/dev/null 2>&1 || true
|
|
323
|
+
launchctl load "${PLIST_DIR}/dev.zocket.web.plist"
|
|
324
|
+
launchctl load "${PLIST_DIR}/dev.zocket.mcp-sse.plist"
|
|
325
|
+
launchctl load "${PLIST_DIR}/dev.zocket.mcp-streamable.plist"
|
|
208
326
|
fi
|
|
209
327
|
|
|
210
328
|
cat <<EOF
|
package/bin/zocket-setup.cjs
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
const cp = require("child_process");
|
|
4
|
-
const path = require("path");
|
|
5
|
-
|
|
6
|
-
const launcher = path.resolve(__dirname, "zocket.cjs");
|
|
7
|
-
const res = cp.spawnSync(process.execPath, [launcher, "setup"], {
|
|
8
|
-
stdio: "inherit",
|
|
9
|
-
env: process.env,
|
|
10
|
-
});
|
|
11
|
-
|
|
12
|
-
process.exit(res.status === null ? 1 : res.status);
|
package/bin/zocket.cjs
DELETED
|
@@ -1,174 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
const cp = require("child_process");
|
|
4
|
-
const fs = require("fs");
|
|
5
|
-
const os = require("os");
|
|
6
|
-
const path = require("path");
|
|
7
|
-
|
|
8
|
-
const isWin = process.platform === "win32";
|
|
9
|
-
const args = process.argv.slice(2);
|
|
10
|
-
const pkgRoot = path.resolve(__dirname, "..");
|
|
11
|
-
const launcherVersion = "1.0.0";
|
|
12
|
-
|
|
13
|
-
function fail(msg, code = 1) {
|
|
14
|
-
process.stderr.write(`${msg}\n`);
|
|
15
|
-
process.exit(code);
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
function run(cmd, cmdArgs, opts = {}) {
|
|
19
|
-
const res = cp.spawnSync(cmd, cmdArgs, {
|
|
20
|
-
stdio: "inherit",
|
|
21
|
-
env: process.env,
|
|
22
|
-
...opts,
|
|
23
|
-
});
|
|
24
|
-
return res.status === null ? 1 : res.status;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
function probe(cmd, cmdArgs) {
|
|
28
|
-
const res = cp.spawnSync(cmd, cmdArgs, {
|
|
29
|
-
stdio: "ignore",
|
|
30
|
-
env: process.env,
|
|
31
|
-
});
|
|
32
|
-
return res.status === 0;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
function findPython() {
|
|
36
|
-
const candidates = isWin
|
|
37
|
-
? [
|
|
38
|
-
{ cmd: "py", prefix: ["-3"] },
|
|
39
|
-
{ cmd: "python", prefix: [] },
|
|
40
|
-
{ cmd: "python3", prefix: [] },
|
|
41
|
-
]
|
|
42
|
-
: [
|
|
43
|
-
{ cmd: "python3", prefix: [] },
|
|
44
|
-
{ cmd: "python", prefix: [] },
|
|
45
|
-
];
|
|
46
|
-
|
|
47
|
-
for (const item of candidates) {
|
|
48
|
-
const ok = probe(item.cmd, [...item.prefix, "-c", "import sys;sys.exit(0)"]);
|
|
49
|
-
if (ok) {
|
|
50
|
-
return item;
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
return null;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
function installRoot() {
|
|
57
|
-
if (isWin) {
|
|
58
|
-
const base = process.env.LOCALAPPDATA || path.join(os.homedir(), "AppData", "Local");
|
|
59
|
-
return path.join(base, "zocket");
|
|
60
|
-
}
|
|
61
|
-
return path.join(os.homedir(), ".local", "share", "zocket");
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
function venvPython(venvDir) {
|
|
65
|
-
return isWin
|
|
66
|
-
? path.join(venvDir, "Scripts", "python.exe")
|
|
67
|
-
: path.join(venvDir, "bin", "python3");
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
function removeIfExists(target) {
|
|
71
|
-
if (fs.existsSync(target)) {
|
|
72
|
-
fs.rmSync(target, { recursive: true, force: true });
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
function prepareInstallSource(rootDir) {
|
|
77
|
-
const sourceDir = path.join(rootDir, "npm-install-source");
|
|
78
|
-
removeIfExists(sourceDir);
|
|
79
|
-
fs.mkdirSync(sourceDir, { recursive: true });
|
|
80
|
-
|
|
81
|
-
const filesToCopy = ["pyproject.toml", "README.md", "zocket"];
|
|
82
|
-
for (const item of filesToCopy) {
|
|
83
|
-
const src = path.join(pkgRoot, item);
|
|
84
|
-
if (!fs.existsSync(src)) {
|
|
85
|
-
continue;
|
|
86
|
-
}
|
|
87
|
-
const dst = path.join(sourceDir, item);
|
|
88
|
-
const stat = fs.statSync(src);
|
|
89
|
-
if (stat.isDirectory()) {
|
|
90
|
-
fs.cpSync(src, dst, { recursive: true });
|
|
91
|
-
} else {
|
|
92
|
-
fs.copyFileSync(src, dst);
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
return sourceDir;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
function ensureVenv() {
|
|
99
|
-
const root = installRoot();
|
|
100
|
-
const venvDir = path.join(root, "venv");
|
|
101
|
-
const marker = path.join(root, "npm-launcher-version.txt");
|
|
102
|
-
const pyBin = venvPython(venvDir);
|
|
103
|
-
let needInstall = !fs.existsSync(pyBin);
|
|
104
|
-
|
|
105
|
-
if (!needInstall && fs.existsSync(marker)) {
|
|
106
|
-
const current = fs.readFileSync(marker, "utf-8").trim();
|
|
107
|
-
if (current !== launcherVersion) {
|
|
108
|
-
needInstall = true;
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
if (!needInstall) {
|
|
113
|
-
const healthy = probe(pyBin, ["-c", "import zocket, cryptography"]);
|
|
114
|
-
if (!healthy) {
|
|
115
|
-
needInstall = true;
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
if (!needInstall) {
|
|
120
|
-
return pyBin;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
const py = findPython();
|
|
124
|
-
if (!py) {
|
|
125
|
-
fail(
|
|
126
|
-
[
|
|
127
|
-
"Python 3.10+ was not found.",
|
|
128
|
-
"Install Python first, then rerun:",
|
|
129
|
-
" zocket setup",
|
|
130
|
-
].join("\n")
|
|
131
|
-
);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
fs.mkdirSync(root, { recursive: true });
|
|
135
|
-
let code = run(py.cmd, [...py.prefix, "-m", "venv", venvDir]);
|
|
136
|
-
if (code !== 0) {
|
|
137
|
-
fail("Failed to create virtual environment for zocket.");
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
code = run(pyBin, ["-m", "pip", "install", "--upgrade", "pip", "setuptools", "wheel"]);
|
|
141
|
-
if (code !== 0) {
|
|
142
|
-
fail("Failed to bootstrap pip in zocket virtual environment.");
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
// Install from a writable user-owned source copy to avoid permission issues.
|
|
146
|
-
const sourceDir = prepareInstallSource(root);
|
|
147
|
-
code = run(pyBin, ["-m", "pip", "install", sourceDir]);
|
|
148
|
-
if (code !== 0) {
|
|
149
|
-
fail("Failed to install zocket Python package from npm bundle.");
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
fs.writeFileSync(marker, `${launcherVersion}\n`, "utf-8");
|
|
153
|
-
return pyBin;
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
if (args[0] === "setup") {
|
|
157
|
-
ensureVenv();
|
|
158
|
-
process.stdout.write("zocket runtime is installed.\n");
|
|
159
|
-
process.exit(0);
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
if (args[0] === "doctor") {
|
|
163
|
-
const py = findPython();
|
|
164
|
-
const root = installRoot();
|
|
165
|
-
const pyBin = venvPython(path.join(root, "venv"));
|
|
166
|
-
process.stdout.write(`python_found=${py ? "yes" : "no"}\n`);
|
|
167
|
-
process.stdout.write(`venv_python=${pyBin}\n`);
|
|
168
|
-
process.stdout.write(`venv_exists=${fs.existsSync(pyBin) ? "yes" : "no"}\n`);
|
|
169
|
-
process.exit(0);
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
const runtimePython = ensureVenv();
|
|
173
|
-
const code = run(runtimePython, ["-m", "zocket", ...args]);
|
|
174
|
-
process.exit(code);
|
package/pyproject.toml
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
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"]
|