skill-router 0.0.1-snapshot → 0.0.2-snapshot
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 +13 -1
- package/package.json +4 -3
- package/router.py +31 -6
- package/scripts/postinstall.js +46 -0
package/README.md
CHANGED
|
@@ -11,9 +11,16 @@ npm install -g .
|
|
|
11
11
|
The package runs this postinstall hook:
|
|
12
12
|
|
|
13
13
|
```bash
|
|
14
|
-
|
|
14
|
+
node scripts/postinstall.js
|
|
15
15
|
```
|
|
16
16
|
|
|
17
|
+
It creates an isolated venv in `~/.cache/skill-router/venv` and installs:
|
|
18
|
+
|
|
19
|
+
- `fastembed`
|
|
20
|
+
- `numpy`
|
|
21
|
+
|
|
22
|
+
This avoids PEP 668 / externally-managed-environment failures on Ubuntu.
|
|
23
|
+
|
|
17
24
|
## Usage
|
|
18
25
|
|
|
19
26
|
```bash
|
|
@@ -38,6 +45,11 @@ If the provided `--skills-dir` does not exist or has no `.md` files, it returns:
|
|
|
38
45
|
{"skill_id":null,"score":0.0}
|
|
39
46
|
```
|
|
40
47
|
|
|
48
|
+
Lookup order:
|
|
49
|
+
|
|
50
|
+
1. `--skills-dir` (default: `~/.cache/skills-router`)
|
|
51
|
+
2. Fallback: `~/.cache/gemini-skills`
|
|
52
|
+
|
|
41
53
|
## Cache
|
|
42
54
|
|
|
43
55
|
Cache is stored in:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "skill-router",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.2-snapshot",
|
|
4
4
|
"description": "Local semantic skill router for gemini-cli-pro",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "commonjs",
|
|
@@ -8,10 +8,11 @@
|
|
|
8
8
|
"skill-router": "./router.py"
|
|
9
9
|
},
|
|
10
10
|
"scripts": {
|
|
11
|
-
"postinstall": "
|
|
11
|
+
"postinstall": "node scripts/postinstall.js"
|
|
12
12
|
},
|
|
13
13
|
"files": [
|
|
14
14
|
"router.py",
|
|
15
|
-
"README.md"
|
|
15
|
+
"README.md",
|
|
16
|
+
"scripts"
|
|
16
17
|
]
|
|
17
18
|
}
|
package/router.py
CHANGED
|
@@ -7,10 +7,26 @@ import argparse
|
|
|
7
7
|
import hashlib
|
|
8
8
|
import json
|
|
9
9
|
import os
|
|
10
|
+
import site
|
|
10
11
|
import sys
|
|
11
12
|
from pathlib import Path
|
|
12
13
|
from typing import Iterable
|
|
13
14
|
|
|
15
|
+
|
|
16
|
+
def _cache_root_dir() -> Path:
|
|
17
|
+
# Keep ~/.cache across Linux and macOS for compatibility with gemini-cli-pro integration.
|
|
18
|
+
return Path.home() / ".cache" / "skill-router"
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _inject_cached_venv_site_packages() -> None:
|
|
22
|
+
py_tag = f"python{sys.version_info.major}.{sys.version_info.minor}"
|
|
23
|
+
candidate = _cache_root_dir() / "venv" / "lib" / py_tag / "site-packages"
|
|
24
|
+
if candidate.exists() and candidate.is_dir():
|
|
25
|
+
site.addsitedir(str(candidate))
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
_inject_cached_venv_site_packages()
|
|
29
|
+
|
|
14
30
|
import numpy as np
|
|
15
31
|
|
|
16
32
|
try:
|
|
@@ -20,9 +36,11 @@ except Exception: # pragma: no cover - runtime dependency may be unavailable
|
|
|
20
36
|
|
|
21
37
|
|
|
22
38
|
MODEL_NAME = "BAAI/bge-small-en-v1.5"
|
|
23
|
-
CACHE_ROOT =
|
|
39
|
+
CACHE_ROOT = _cache_root_dir()
|
|
24
40
|
DATA_FILE = CACHE_ROOT / "data.npy"
|
|
25
41
|
SKILLS_CACHE_FILE = CACHE_ROOT / ".skills_cache.npy"
|
|
42
|
+
DEFAULT_SKILLS_DIR = Path.home() / ".cache" / "skills-router"
|
|
43
|
+
GLOBAL_GEMINI_SKILLS_DIR = Path.home() / ".cache" / "gemini-skills"
|
|
26
44
|
|
|
27
45
|
_EMBEDDER = None
|
|
28
46
|
|
|
@@ -77,9 +95,14 @@ def _has_skill_markdown(skills_dir: Path) -> bool:
|
|
|
77
95
|
|
|
78
96
|
|
|
79
97
|
def _resolve_available_skills_dir(preferred_skills_dir: Path) -> Path | None:
|
|
80
|
-
|
|
81
|
-
if _has_skill_markdown(
|
|
82
|
-
return
|
|
98
|
+
primary = preferred_skills_dir.resolve()
|
|
99
|
+
if _has_skill_markdown(primary):
|
|
100
|
+
return primary
|
|
101
|
+
|
|
102
|
+
fallback = GLOBAL_GEMINI_SKILLS_DIR.resolve()
|
|
103
|
+
if _has_skill_markdown(fallback):
|
|
104
|
+
return fallback
|
|
105
|
+
|
|
83
106
|
return None
|
|
84
107
|
|
|
85
108
|
|
|
@@ -155,7 +178,9 @@ def _get_embedder() -> TextEmbedding:
|
|
|
155
178
|
global _EMBEDDER
|
|
156
179
|
if _EMBEDDER is None:
|
|
157
180
|
if TextEmbedding is None:
|
|
158
|
-
raise RuntimeError(
|
|
181
|
+
raise RuntimeError(
|
|
182
|
+
f"missing_dependency: fastembed (expected venv at {CACHE_ROOT / 'venv'})"
|
|
183
|
+
)
|
|
159
184
|
_EMBEDDER = TextEmbedding(model_name=MODEL_NAME)
|
|
160
185
|
return _EMBEDDER
|
|
161
186
|
|
|
@@ -306,7 +331,7 @@ def main() -> int:
|
|
|
306
331
|
parser.add_argument("--prompt", default="", help="User text prompt")
|
|
307
332
|
parser.add_argument(
|
|
308
333
|
"--skills-dir",
|
|
309
|
-
default=
|
|
334
|
+
default=str(DEFAULT_SKILLS_DIR),
|
|
310
335
|
help="Path to skills directory",
|
|
311
336
|
)
|
|
312
337
|
parser.add_argument(
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const { spawnSync } = require("child_process");
|
|
4
|
+
const fs = require("fs");
|
|
5
|
+
const os = require("os");
|
|
6
|
+
const path = require("path");
|
|
7
|
+
|
|
8
|
+
function run(cmd, args, options = {}) {
|
|
9
|
+
const result = spawnSync(cmd, args, {
|
|
10
|
+
stdio: "inherit",
|
|
11
|
+
env: process.env,
|
|
12
|
+
...options,
|
|
13
|
+
});
|
|
14
|
+
return result.status === 0;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function main() {
|
|
18
|
+
const cacheRoot = path.join(os.homedir(), ".cache", "skill-router");
|
|
19
|
+
const venvDir = path.join(cacheRoot, "venv");
|
|
20
|
+
const venvPython = path.join(venvDir, "bin", "python");
|
|
21
|
+
|
|
22
|
+
try {
|
|
23
|
+
fs.mkdirSync(cacheRoot, { recursive: true });
|
|
24
|
+
} catch (err) {
|
|
25
|
+
console.warn("[skill-router] warning: failed to create cache dir:", err.message);
|
|
26
|
+
process.exit(0);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (!fs.existsSync(venvPython)) {
|
|
30
|
+
const created = run("python3", ["-m", "venv", venvDir]);
|
|
31
|
+
if (!created) {
|
|
32
|
+
console.warn("[skill-router] warning: failed to create Python venv. Install will continue without blocking.");
|
|
33
|
+
process.exit(0);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Best-effort dependency setup. We avoid failing npm install if pip/network is unavailable.
|
|
38
|
+
run(venvPython, ["-m", "pip", "install", "--upgrade", "pip", "setuptools", "wheel"]);
|
|
39
|
+
const depsOk = run(venvPython, ["-m", "pip", "install", "--upgrade", "fastembed", "numpy"]);
|
|
40
|
+
|
|
41
|
+
if (!depsOk) {
|
|
42
|
+
console.warn("[skill-router] warning: could not install Python deps in venv. The CLI will report missing_dependency at runtime.");
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
main();
|