@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 +18 -6
- package/bin/hits-mcp.js +133 -0
- package/package.json +4 -3
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": ["
|
|
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 |
|
package/bin/hits-mcp.js
ADDED
|
@@ -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.
|
|
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://
|
|
55
|
+
"url": "git+https://github.com/lhjnano/hits.git"
|
|
55
56
|
},
|
|
56
57
|
"bugs": {
|
|
57
58
|
"url": "https://github.com/lhjnano/hits/issues"
|