@purpleraven/hits 0.2.2 → 0.2.3

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 CHANGED
@@ -114,7 +114,7 @@ That's it. No database required — HITS uses file-based storage at `~/.hits/dat
114
114
 
115
115
  ### MCP Tools for AI Assistants
116
116
 
117
- HITS includes an MCP server so your AI can read and write handover data directly:
117
+ HITS includes an MCP server so your AI can read and write handover data directly. No need to clone the repo — it works right out of the npm package.
118
118
 
119
119
  #### Register with OpenCode (`~/.config/opencode/opencode.json`)
120
120
 
@@ -123,8 +123,7 @@ HITS includes an MCP server so your AI can read and write handover data directly
123
123
  "mcp": {
124
124
  "hits": {
125
125
  "type": "local",
126
- "command": ["python", "-m", "hits_core.mcp.server"],
127
- "cwd": "/path/to/hits"
126
+ "command": ["npx", "hits-mcp"]
128
127
  }
129
128
  }
130
129
  }
@@ -133,11 +132,24 @@ HITS includes an MCP server so your AI can read and write handover data directly
133
132
  #### Register with Claude Code
134
133
 
135
134
  ```bash
136
- claude mcp add hits \
137
- -e HITS_DATA_PATH="$HOME/.hits/data" \
138
- -- python -m hits_core.mcp.server
135
+ claude mcp add hits -- npx hits-mcp
139
136
  ```
140
137
 
138
+ #### Register with Any MCP Client
139
+
140
+ ```json
141
+ {
142
+ "mcpServers": {
143
+ "hits": {
144
+ "command": "npx",
145
+ "args": ["hits-mcp"]
146
+ }
147
+ }
148
+ }
149
+ ```
150
+
151
+ > **How it works:** `npx hits-mcp` auto-detects Python, creates a venv inside the npm package, installs dependencies, and spawns the MCP server over stdio — all automatically on first run.
152
+
141
153
  #### 5 MCP Tools
142
154
 
143
155
  | Tool | What It Does |
@@ -0,0 +1,133 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * HITS MCP Server - Node.js Wrapper
5
+ *
6
+ * Launches the HITS Python MCP server over stdio transport.
7
+ * Auto-detects Python, creates venv, installs deps — same as `npx hits`.
8
+ *
9
+ * Usage:
10
+ * npx hits-mcp
11
+ *
12
+ * Or in MCP config:
13
+ * { "command": ["npx", "hits-mcp"] }
14
+ *
15
+ * Environment:
16
+ * HITS_PYTHON Path to python executable (default: auto-detect)
17
+ * HITS_DATA_PATH Data storage path (default: ~/.hits/data)
18
+ */
19
+
20
+ import { spawn, execSync } from 'node:child_process';
21
+ import { existsSync } from 'node:fs';
22
+ import { join, dirname } from 'node:path';
23
+ import { fileURLToPath } from 'node:url';
24
+ import { platform } from 'node:os';
25
+
26
+ const __dirname = dirname(fileURLToPath(import.meta.url));
27
+ const ROOT = __dirname;
28
+ const isWin = platform() === 'win32';
29
+
30
+ // ─── Python Detection (same logic as server.js) ────────────────
31
+
32
+ function findPython() {
33
+ const envPython = process.env.HITS_PYTHON;
34
+ if (envPython && existsSync(envPython)) return envPython;
35
+
36
+ const candidates = isWin
37
+ ? ['python', 'python3', 'py']
38
+ : ['python3', 'python'];
39
+
40
+ for (const cmd of candidates) {
41
+ try {
42
+ const ver = execSync(`${cmd} --version`, { encoding: 'utf8', stdio: ['pipe', 'pipe', 'ignore'] });
43
+ const match = ver.match(/Python (\d+)\.(\d+)/);
44
+ if (match && (parseInt(match[1]) > 3 || (parseInt(match[1]) === 3 && parseInt(match[2]) >= 10))) {
45
+ return cmd;
46
+ }
47
+ } catch {}
48
+ }
49
+ return null;
50
+ }
51
+
52
+ // ─── Venv Management ────────────────────────────────────────────
53
+
54
+ const VENV_DIR = join(ROOT, 'venv');
55
+ const PYTHON_BIN = isWin
56
+ ? join(VENV_DIR, 'Scripts', 'python.exe')
57
+ : join(VENV_DIR, 'bin', 'python');
58
+
59
+ function runCommand(cmd, args, opts = {}) {
60
+ return new Promise((resolve, reject) => {
61
+ const proc = spawn(cmd, args, { stdio: 'inherit', ...opts });
62
+ proc.on('close', (code) => {
63
+ if (code === 0) resolve();
64
+ else reject(new Error(`Command failed: ${cmd} ${args.join(' ')} (exit ${code})`));
65
+ });
66
+ proc.on('error', reject);
67
+ });
68
+ }
69
+
70
+ async function ensurePython() {
71
+ const pythonCmd = findPython();
72
+ if (!pythonCmd) {
73
+ console.error('[hits-mcp] Error: Python 3.10+ not found.');
74
+ console.error('[hits-mcp] Install: https://www.python.org/downloads/');
75
+ process.exit(1);
76
+ }
77
+
78
+ // Create venv if needed
79
+ if (!existsSync(PYTHON_BIN)) {
80
+ console.error(`[hits-mcp] Creating virtual environment... (${pythonCmd})`);
81
+ await runCommand(pythonCmd, ['-m', 'venv', VENV_DIR], { cwd: ROOT });
82
+ }
83
+
84
+ // Check if deps are installed
85
+ try {
86
+ execSync(
87
+ `${PYTHON_BIN} -c "import fastapi, pydantic, argon2, jose"`,
88
+ { stdio: 'ignore' }
89
+ );
90
+ } catch {
91
+ console.error('[hits-mcp] Installing Python dependencies...');
92
+ await runCommand(PYTHON_BIN, ['-m', 'pip', 'install', '-q', '--upgrade', 'pip'], { cwd: ROOT });
93
+ await runCommand(PYTHON_BIN, ['-m', 'pip', 'install', '-q', '-r', join(ROOT, 'requirements.txt')], { cwd: ROOT });
94
+ console.error('[hits-mcp] Dependencies installed.');
95
+ }
96
+ }
97
+
98
+ // ─── Launch MCP Server ──────────────────────────────────────────
99
+
100
+ async function main() {
101
+ await ensurePython();
102
+
103
+ // Spawn Python MCP server with stdio transport
104
+ const proc = spawn(PYTHON_BIN, ['-m', 'hits_core.mcp.server'], {
105
+ cwd: ROOT,
106
+ stdio: 'inherit', // stdin/stdout/stderr all connected to parent (MCP stdio)
107
+ env: {
108
+ ...process.env,
109
+ PYTHONPATH: ROOT,
110
+ },
111
+ });
112
+
113
+ proc.on('error', (err) => {
114
+ console.error(`[hits-mcp] Failed to start: ${err.message}`);
115
+ process.exit(1);
116
+ });
117
+
118
+ proc.on('exit', (code, signal) => {
119
+ if (signal) {
120
+ console.error(`[hits-mcp] Terminated by signal: ${signal}`);
121
+ }
122
+ process.exit(code || 0);
123
+ });
124
+
125
+ // Forward signals
126
+ process.on('SIGINT', () => proc.kill('SIGINT'));
127
+ process.on('SIGTERM', () => proc.kill('SIGTERM'));
128
+ }
129
+
130
+ main().catch((err) => {
131
+ console.error(`[hits-mcp] Fatal: ${err.message}`);
132
+ process.exit(1);
133
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@purpleraven/hits",
3
- "version": "0.2.2",
3
+ "version": "0.2.3",
4
4
  "description": "HITS - Hybrid Intel Trace System. AI session handover with secure web UI.",
5
5
  "keywords": [
6
6
  "knowledge-management",
@@ -12,7 +12,8 @@
12
12
  "author": "HITS Team",
13
13
  "type": "module",
14
14
  "bin": {
15
- "hits": "bin/hits.js"
15
+ "hits": "bin/hits.js",
16
+ "hits-mcp": "bin/hits-mcp.js"
16
17
  },
17
18
  "scripts": {
18
19
  "start": "node bin/hits.js",
@@ -51,7 +52,7 @@
51
52
  "devDependencies": {},
52
53
  "repository": {
53
54
  "type": "git",
54
- "url": "git+https://lhjnano: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@github.com/lhjnano/hits.git"
55
+ "url": "git+https://github.com/lhjnano/hits.git"
55
56
  },
56
57
  "bugs": {
57
58
  "url": "https://github.com/lhjnano/hits/issues"