@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.
@@ -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
- Optional autostart:
73
+ Autostart (enabled by default):
74
74
  ```powershell
75
- powershell -ExecutionPolicy Bypass -File .\scripts\install-zocket.ps1 -EnableAutostart
75
+ powershell -ExecutionPolicy Bypass -File .\scripts\install-zocket.ps1
76
76
  ```
77
77
 
78
78
  This creates scheduled tasks:
79
79
  - `ZocketWeb`
80
- - `ZocketMcpHttp`
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
- ```bash
113
- sudo env ZOCKET_HOME=/var/lib/zocket zocket harden install-linux-system \
114
- --service-user zocketd \
115
- --zocket-home /var/lib/zocket \
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
- zocket autostart install --target web --web-port 18001
169
- zocket autostart install --target mcp --mcp-port 18002 --mcp-mode metadata --mcp-host 127.0.0.1
170
- zocket autostart status --target both
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 (manual)
174
- Create `~/Library/LaunchAgents/dev.zocket.web.plist`, `dev.zocket.mcp-sse.plist`,
175
- and `dev.zocket.mcp-streamable.plist`:
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"?>
@@ -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.0.0",
4
- "description": "Cross-platform npm launcher for Zocket (local MCP + web vault)",
5
- "license": "MIT",
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": "bin/zocket.cjs",
10
- "zocket-setup": "bin/zocket-setup.cjs"
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
- "bin/",
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
- "scripts/ai-autodeploy.py",
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
  }
@@ -12,7 +12,7 @@ Param(
12
12
  [int]$McpStreamPort = 18003,
13
13
  [ValidateSet("metadata", "admin")]
14
14
  [string]$McpMode = "metadata",
15
- [switch]$EnableAutostart
15
+ [bool]$EnableAutostart = $true
16
16
  )
17
17
 
18
18
  $ErrorActionPreference = "Stop"
@@ -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
- "${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
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
- 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
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
@@ -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"]