threadlens 1.0.1 → 1.1.1
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 +55 -11
- package/bin/resolve.js +85 -0
- package/bin/threadlens.js +14 -60
- package/package.json +8 -9
- package/vendor/threadlens/__init__.py +0 -4
- package/vendor/threadlens/__main__.py +0 -6
- package/vendor/threadlens/cli.py +0 -1395
- package/vendor/threadlens/extract.py +0 -369
- package/vendor/threadlens/models.py +0 -25
- package/vendor/threadlens/paths.py +0 -85
- package/vendor/threadlens/profiles.py +0 -102
- package/vendor/threadlens/skills/threadlens/SKILL.md +0 -102
- package/vendor/threadlens/skills/threadlens/agents/openai.yaml +0 -4
- package/vendor/threadlens/sources.py +0 -665
- package/vendor/threadlens/store.py +0 -652
package/README.md
CHANGED
|
@@ -4,32 +4,76 @@ Local cross-harness search for coding-agent sessions.
|
|
|
4
4
|
|
|
5
5
|
```bash
|
|
6
6
|
npm install -g threadlens
|
|
7
|
-
threadlens start
|
|
8
7
|
threadlens search "plunk otp"
|
|
8
|
+
threadlens skill
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
Or run
|
|
11
|
+
Or run once without installing:
|
|
12
12
|
|
|
13
13
|
```bash
|
|
14
14
|
npx threadlens search "plunk otp"
|
|
15
15
|
```
|
|
16
16
|
|
|
17
|
+
## How it works
|
|
18
|
+
|
|
19
|
+
This package ships a tiny JS shim (`bin/threadlens.js`) with no vendored Python.
|
|
20
|
+
Installing it pulls in the matching pre-built native binary via npm's
|
|
21
|
+
`optionalDependencies` mechanism — exactly the way esbuild distributes its binary.
|
|
22
|
+
|
|
23
|
+
| Platform | Package pulled |
|
|
24
|
+
|---|---|
|
|
25
|
+
| macOS arm64 | `@moinulmoin/threadlens-darwin-arm64` |
|
|
26
|
+
| macOS x64 | `@moinulmoin/threadlens-darwin-x64` |
|
|
27
|
+
| Linux x64 (glibc) | `@moinulmoin/threadlens-linux-x64-gnu` |
|
|
28
|
+
|
|
29
|
+
The binary is a self-contained [PyInstaller](https://pyinstaller.org/) onedir
|
|
30
|
+
bundle — no Python required on the host machine.
|
|
31
|
+
|
|
17
32
|
## Requirements
|
|
18
33
|
|
|
19
|
-
|
|
20
|
-
|
|
34
|
+
- **Node.js 16+** (for the shim)
|
|
35
|
+
- One of the supported platforms above
|
|
36
|
+
- No Python required
|
|
21
37
|
|
|
22
|
-
|
|
38
|
+
## Override / escape hatches
|
|
23
39
|
|
|
24
|
-
|
|
25
|
-
|
|
40
|
+
**Point at a custom binary:**
|
|
41
|
+
```bash
|
|
42
|
+
THREADLENS_BINARY=/path/to/threadlens threadlens search "..."
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
**Installed with `--omit=optional`?** The shim will print a clear error. Fix it:
|
|
46
|
+
```bash
|
|
47
|
+
npm install -g threadlens # re-install without --omit=optional
|
|
48
|
+
```
|
|
26
49
|
|
|
50
|
+
**Unsupported platform or prefer Python?**
|
|
27
51
|
```bash
|
|
28
|
-
uv tool install threadlens
|
|
29
|
-
uvx threadlens search "..."
|
|
52
|
+
uv tool install threadlens # installs from PyPI, brings its own Python
|
|
53
|
+
uvx threadlens search "..." # run without installing
|
|
30
54
|
```
|
|
31
55
|
|
|
32
|
-
|
|
56
|
+
Or download a release archive directly from
|
|
57
|
+
<https://github.com/moinulmoin/threadlens/releases>.
|
|
58
|
+
|
|
59
|
+
## Binary resolution order
|
|
60
|
+
|
|
61
|
+
1. `THREADLENS_BINARY` environment variable (if set, used verbatim)
|
|
62
|
+
2. Platform lookup: `${process.platform}-${process.arch}` → scoped package name
|
|
63
|
+
3. `require.resolve('<pkg>/package.json')` to locate the package directory
|
|
64
|
+
4. Execute `<pkgDir>/bin/threadlens/threadlens` with all args forwarded
|
|
65
|
+
|
|
66
|
+
If step 2 or 3 fails, the shim exits 127 with a diagnostic message.
|
|
67
|
+
|
|
68
|
+
## Development
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
# Regenerate platform package scaffolds and sync version from threadlens/__init__.py
|
|
72
|
+
node scripts/sync.mjs
|
|
73
|
+
|
|
74
|
+
# Run the shim unit tests (no binaries needed)
|
|
75
|
+
node --test npm/test/shim.test.mjs
|
|
76
|
+
```
|
|
33
77
|
|
|
34
78
|
See the [project README](https://github.com/moinulmoin/threadlens#readme) for
|
|
35
|
-
full usage.
|
|
79
|
+
full usage and source.
|
package/bin/resolve.js
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
// Pure platform-to-binary resolution logic.
|
|
4
|
+
// No side-effects; injectable for tests.
|
|
5
|
+
|
|
6
|
+
const path = require("node:path");
|
|
7
|
+
|
|
8
|
+
/** Maps ${platform}-${arch} -> optional-dependency package name. */
|
|
9
|
+
const PLATFORM_MAP = {
|
|
10
|
+
"darwin-arm64": "@moinulmoin/threadlens-darwin-arm64",
|
|
11
|
+
"linux-x64": "@moinulmoin/threadlens-linux-x64-gnu",
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Resolve the absolute path to the threadlens native binary.
|
|
16
|
+
*
|
|
17
|
+
* All inputs are injectable so the function is unit-testable without real
|
|
18
|
+
* platform packages on disk.
|
|
19
|
+
*
|
|
20
|
+
* @param {object} [opts]
|
|
21
|
+
* @param {string} [opts.platform] — defaults to process.platform
|
|
22
|
+
* @param {string} [opts.arch] — defaults to process.arch
|
|
23
|
+
* @param {object} [opts.env] — defaults to process.env
|
|
24
|
+
* @param {Function} [opts.resolver] — defaults to require.resolve
|
|
25
|
+
* @returns {string} Absolute path to the executable.
|
|
26
|
+
* @throws {Error} err.code === "UNSUPPORTED_PLATFORM" | "MISSING_PACKAGE"
|
|
27
|
+
*/
|
|
28
|
+
function resolveBinary({ platform, arch, env, resolver } = {}) {
|
|
29
|
+
platform = platform !== undefined ? platform : process.platform;
|
|
30
|
+
arch = arch !== undefined ? arch : process.arch;
|
|
31
|
+
env = env !== undefined ? env : process.env;
|
|
32
|
+
resolver = resolver !== undefined ? resolver : require.resolve;
|
|
33
|
+
|
|
34
|
+
// Explicit override wins unconditionally.
|
|
35
|
+
if (env.THREADLENS_BINARY) {
|
|
36
|
+
return env.THREADLENS_BINARY;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const key = `${platform}-${arch}`;
|
|
40
|
+
const pkg = PLATFORM_MAP[key];
|
|
41
|
+
|
|
42
|
+
if (!pkg) {
|
|
43
|
+
throw Object.assign(
|
|
44
|
+
new Error(
|
|
45
|
+
[
|
|
46
|
+
`threadlens: unsupported platform "${key}".`,
|
|
47
|
+
"",
|
|
48
|
+
"Pre-built binaries are available for: darwin-arm64, darwin-x64, linux-x64.",
|
|
49
|
+
"Alternatives:",
|
|
50
|
+
" uv tool install threadlens # installs from PyPI (brings its own Python)",
|
|
51
|
+
' uvx threadlens search "..." # one-shot, no install',
|
|
52
|
+
" https://github.com/moinulmoin/threadlens/releases (release archives)",
|
|
53
|
+
].join("\n")
|
|
54
|
+
),
|
|
55
|
+
{ code: "UNSUPPORTED_PLATFORM" }
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
let pkgJsonPath;
|
|
60
|
+
try {
|
|
61
|
+
pkgJsonPath = resolver(`${pkg}/package.json`);
|
|
62
|
+
} catch (_) {
|
|
63
|
+
throw Object.assign(
|
|
64
|
+
new Error(
|
|
65
|
+
[
|
|
66
|
+
`threadlens: platform package "${pkg}" is not installed.`,
|
|
67
|
+
"",
|
|
68
|
+
"This usually means npm was invoked with --omit=optional (or --no-optional).",
|
|
69
|
+
"Fix it with one of:",
|
|
70
|
+
" npm install -g threadlens (re-install without --omit=optional)",
|
|
71
|
+
" uv tool install threadlens (install from PyPI instead)",
|
|
72
|
+
' uvx threadlens search "..." (run once without installing)',
|
|
73
|
+
" https://github.com/moinulmoin/threadlens/releases (download a release archive)",
|
|
74
|
+
].join("\n")
|
|
75
|
+
),
|
|
76
|
+
{ code: "MISSING_PACKAGE" }
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const pkgDir = path.dirname(pkgJsonPath);
|
|
81
|
+
// The onedir bundle is laid out as: <pkgDir>/bin/threadlens/threadlens
|
|
82
|
+
return path.join(pkgDir, "bin", "threadlens", "threadlens");
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
module.exports = { PLATFORM_MAP, resolveBinary };
|
package/bin/threadlens.js
CHANGED
|
@@ -1,75 +1,29 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
"use strict";
|
|
3
3
|
|
|
4
|
-
// Thin launcher
|
|
4
|
+
// Thin launcher — resolves the pre-built native binary for this platform
|
|
5
|
+
// and exec's it, passing all arguments through verbatim.
|
|
5
6
|
//
|
|
6
|
-
//
|
|
7
|
-
// source under ./vendor and runs it with the user's own Python interpreter, so
|
|
8
|
-
// `threadlens skill` keeps returning a real, copyable on-disk path (a zipapp
|
|
9
|
-
// would hide those files inside an archive).
|
|
7
|
+
// Set THREADLENS_BINARY=/path/to/binary to override the auto-resolved path.
|
|
10
8
|
|
|
11
9
|
const { spawnSync } = require("node:child_process");
|
|
12
|
-
const
|
|
10
|
+
const { resolveBinary } = require("./resolve.js");
|
|
13
11
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
const res = spawnSync(cmd, ["-c", probe], { stdio: "ignore" });
|
|
21
|
-
return res.status === 0;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
function pickPython() {
|
|
25
|
-
const override = process.env.THREADLENS_PYTHON;
|
|
26
|
-
const candidates = override ? [override] : ["python3", "python"];
|
|
27
|
-
for (const cmd of candidates) {
|
|
28
|
-
try {
|
|
29
|
-
if (isPython310(cmd)) return cmd;
|
|
30
|
-
} catch (_) {
|
|
31
|
-
// not found / not executable; try the next candidate
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
return null;
|
|
12
|
+
let bin;
|
|
13
|
+
try {
|
|
14
|
+
bin = resolveBinary();
|
|
15
|
+
} catch (err) {
|
|
16
|
+
process.stderr.write(err.message + "\n");
|
|
17
|
+
process.exit(127);
|
|
35
18
|
}
|
|
36
19
|
|
|
37
|
-
const
|
|
20
|
+
const result = spawnSync(bin, process.argv.slice(2), { stdio: "inherit" });
|
|
38
21
|
|
|
39
|
-
if (
|
|
22
|
+
if (result.error) {
|
|
40
23
|
process.stderr.write(
|
|
41
|
-
|
|
42
|
-
"threadlens: could not find Python 3.10+ on your PATH.",
|
|
43
|
-
"",
|
|
44
|
-
"threadlens is a Python CLI; this npm package is a thin launcher.",
|
|
45
|
-
"Fix it with either:",
|
|
46
|
-
"",
|
|
47
|
-
" • Install Python 3.10+ (https://www.python.org/downloads or `brew install python`)",
|
|
48
|
-
" • Or install the native build with uv (it can fetch Python for you):",
|
|
49
|
-
" uv tool install threadlens # then run `threadlens`",
|
|
50
|
-
' uvx threadlens search "..." # run without installing',
|
|
51
|
-
"",
|
|
52
|
-
"Already have a specific interpreter? Point at it:",
|
|
53
|
-
" THREADLENS_PYTHON=/path/to/python threadlens ...",
|
|
54
|
-
"",
|
|
55
|
-
].join("\n")
|
|
24
|
+
`threadlens: failed to launch binary (${bin}): ${result.error.message}\n`
|
|
56
25
|
);
|
|
57
|
-
process.exit(127);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
const env = { ...process.env, PYTHONDONTWRITEBYTECODE: "1" };
|
|
61
|
-
env.PYTHONPATH = env.PYTHONPATH
|
|
62
|
-
? vendorDir + path.delimiter + env.PYTHONPATH
|
|
63
|
-
: vendorDir;
|
|
64
|
-
|
|
65
|
-
const res = spawnSync(python, ["-m", "threadlens", ...process.argv.slice(2)], {
|
|
66
|
-
stdio: "inherit",
|
|
67
|
-
env,
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
if (res.error) {
|
|
71
|
-
process.stderr.write(`threadlens: failed to launch Python: ${res.error.message}\n`);
|
|
72
26
|
process.exit(1);
|
|
73
27
|
}
|
|
74
28
|
|
|
75
|
-
process.exit(
|
|
29
|
+
process.exit(result.status === null ? 1 : result.status);
|
package/package.json
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "threadlens",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.1",
|
|
4
4
|
"description": "Local cross-harness search for agent threads",
|
|
5
5
|
"bin": {
|
|
6
6
|
"threadlens": "bin/threadlens.js"
|
|
7
7
|
},
|
|
8
8
|
"files": [
|
|
9
|
-
"bin
|
|
10
|
-
"vendor/"
|
|
9
|
+
"bin"
|
|
11
10
|
],
|
|
12
11
|
"engines": {
|
|
13
12
|
"node": ">=16"
|
|
14
13
|
},
|
|
15
14
|
"scripts": {
|
|
16
|
-
"
|
|
15
|
+
"sync": "node scripts/sync.mjs",
|
|
16
|
+
"prepare": "node scripts/sync.mjs"
|
|
17
17
|
},
|
|
18
18
|
"keywords": [
|
|
19
19
|
"agents",
|
|
@@ -26,11 +26,6 @@
|
|
|
26
26
|
"cursor"
|
|
27
27
|
],
|
|
28
28
|
"license": "MIT",
|
|
29
|
-
"os": [
|
|
30
|
-
"darwin",
|
|
31
|
-
"linux",
|
|
32
|
-
"win32"
|
|
33
|
-
],
|
|
34
29
|
"repository": {
|
|
35
30
|
"type": "git",
|
|
36
31
|
"url": "git+https://github.com/moinulmoin/threadlens.git"
|
|
@@ -38,5 +33,9 @@
|
|
|
38
33
|
"homepage": "https://github.com/moinulmoin/threadlens#readme",
|
|
39
34
|
"bugs": {
|
|
40
35
|
"url": "https://github.com/moinulmoin/threadlens/issues"
|
|
36
|
+
},
|
|
37
|
+
"optionalDependencies": {
|
|
38
|
+
"@moinulmoin/threadlens-darwin-arm64": "1.1.1",
|
|
39
|
+
"@moinulmoin/threadlens-linux-x64-gnu": "1.1.1"
|
|
41
40
|
}
|
|
42
41
|
}
|