qmem-cli 0.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 ADDED
@@ -0,0 +1,71 @@
1
+ # smart-query npm wrapper
2
+
3
+ This package provides an npm-installed `smart-query` launcher for the Rust CLI.
4
+
5
+ ## Current state
6
+
7
+ This wrapper can now try to download a matching prebuilt binary during `npm install`.
8
+
9
+ The launcher looks for a usable `smart-query` binary in this order:
10
+
11
+ 1. `SMART_QUERY_BIN`
12
+ 2. `npm/vendor/<platform>-<arch>/smart-query`
13
+ 3. `target/release/smart-query`
14
+ 4. `target/debug/smart-query`
15
+
16
+ On Windows it looks for `smart-query.exe`.
17
+
18
+ ## Install behavior
19
+
20
+ During `postinstall`, the package tries to fetch a release asset from:
21
+
22
+ ```text
23
+ https://github.com/IAmMarcellus/smart-query/releases/download/v<version>/smart-query-v<version>-<target>.tar.gz
24
+ ```
25
+
26
+ Current target mapping:
27
+ - Linux x64 → `x86_64-unknown-linux-gnu`
28
+ - Linux arm64 → `aarch64-unknown-linux-gnu`
29
+ - macOS x64 → `x86_64-apple-darwin`
30
+ - macOS arm64 → `aarch64-apple-darwin`
31
+ - Windows x64 → `x86_64-pc-windows-msvc`
32
+ - Windows arm64 → `aarch64-pc-windows-msvc`
33
+
34
+ The downloaded archive is expected to extract a `smart-query` binary directly into the package vendor directory.
35
+
36
+ ## Useful environment variables
37
+
38
+ - `SMART_QUERY_BIN` — bypass downloader and use an explicit binary path
39
+ - `SMART_QUERY_SKIP_DOWNLOAD=1` — skip postinstall download attempt
40
+ - `SMART_QUERY_RELEASE_BASE_URL` — override the GitHub Releases base URL
41
+
42
+ ## Local development
43
+
44
+ From the repo root:
45
+
46
+ ```bash
47
+ cargo build --release -p smart-query-cli
48
+ npm --prefix npm link
49
+ smart-query --help
50
+ ```
51
+
52
+ Or point directly at an existing binary:
53
+
54
+ ```bash
55
+ SMART_QUERY_BIN=/path/to/smart-query npm --prefix npm link
56
+ smart-query --help
57
+ ```
58
+
59
+ ## Release packaging expectation
60
+
61
+ To publish this wrapper for real `npm install -g smart-query` use, release assets should be uploaded with names like:
62
+
63
+ ```text
64
+ smart-query-v0.1.1-x86_64-unknown-linux-gnu.tar.gz
65
+ smart-query-v0.1.1-aarch64-apple-darwin.tar.gz
66
+ smart-query-v0.1.1-x86_64-pc-windows-msvc.tar.gz
67
+ ```
68
+
69
+ Each archive should unpack to a binary named:
70
+ - `smart-query`
71
+ - `smart-query.exe` on Windows
@@ -0,0 +1,53 @@
1
+ #!/usr/bin/env node
2
+
3
+ const { spawnSync } = require('node:child_process');
4
+ const fs = require('node:fs');
5
+ const path = require('node:path');
6
+
7
+ const exeName = process.platform === 'win32' ? 'smart-query.exe' : 'smart-query';
8
+ const wrapperDir = path.resolve(__dirname, '..');
9
+ const candidatePaths = [
10
+ process.env.SMART_QUERY_BIN,
11
+ path.join(wrapperDir, 'vendor', process.platform + '-' + process.arch, exeName),
12
+ path.resolve(wrapperDir, '..', 'target', 'release', exeName),
13
+ path.resolve(wrapperDir, '..', 'target', 'debug', exeName),
14
+ ].filter(Boolean);
15
+
16
+ const binaryPath = candidatePaths.find((candidate) => {
17
+ try {
18
+ return fs.statSync(candidate).isFile();
19
+ } catch {
20
+ return false;
21
+ }
22
+ });
23
+
24
+ if (!binaryPath) {
25
+ console.error([
26
+ 'smart-query: no packaged binary was found.',
27
+ '',
28
+ 'This npm wrapper currently expects one of:',
29
+ ' - SMART_QUERY_BIN to point at a built smart-query binary, or',
30
+ ' - an auto-downloaded or vendored binary at npm/vendor/<platform>-<arch>/smart-query, or',
31
+ ' - a local repo build at target/release/smart-query or target/debug/smart-query.',
32
+ '',
33
+ 'If postinstall download failed, build locally or set SMART_QUERY_BIN.',
34
+ '',
35
+ 'Example local build flow:',
36
+ ' cargo build --release -p smart-query-cli',
37
+ ' npm --prefix npm link',
38
+ ].join('\n'));
39
+ process.exit(1);
40
+ }
41
+
42
+ const result = spawnSync(binaryPath, process.argv.slice(2), {
43
+ stdio: 'inherit',
44
+ env: process.env,
45
+ });
46
+
47
+ if (result.error) {
48
+ console.error(`smart-query: failed to launch ${binaryPath}`);
49
+ console.error(result.error.message);
50
+ process.exit(1);
51
+ }
52
+
53
+ process.exit(result.status ?? 1);
package/package.json ADDED
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "qmem-cli",
3
+ "version": "0.1.1",
4
+ "description": "qmem — fast local semantic + lexical search/retrieval CLI (Rust)",
5
+ "license": "MIT OR Apache-2.0",
6
+ "type": "commonjs",
7
+ "bin": {
8
+ "qmem": "bin/smart-query.js"
9
+ },
10
+ "files": [
11
+ "bin",
12
+ "scripts",
13
+ "README.md"
14
+ ],
15
+ "keywords": [
16
+ "search",
17
+ "retrieval",
18
+ "cli",
19
+ "rust",
20
+ "memory"
21
+ ],
22
+ "repository": {
23
+ "type": "git",
24
+ "url": "https://github.com/IAmMarcellus/smart-query.git",
25
+ "directory": "npm"
26
+ },
27
+ "homepage": "https://github.com/IAmMarcellus/smart-query",
28
+ "bugs": {
29
+ "url": "https://github.com/IAmMarcellus/smart-query/issues"
30
+ },
31
+ "engines": {
32
+ "node": ">=18"
33
+ },
34
+ "scripts": {
35
+ "postinstall": "node ./scripts/install.js",
36
+ "test": "node ./bin/smart-query.js --help"
37
+ }
38
+ }
@@ -0,0 +1,154 @@
1
+ #!/usr/bin/env node
2
+
3
+ const fs = require('node:fs');
4
+ const os = require('node:os');
5
+ const path = require('node:path');
6
+ const http = require('node:http');
7
+ const https = require('node:https');
8
+ const { pipeline } = require('node:stream');
9
+ const { promisify } = require('node:util');
10
+ const { spawnSync } = require('node:child_process');
11
+
12
+ const streamPipeline = promisify(pipeline);
13
+ const pkg = require('../package.json');
14
+
15
+ const platformMap = {
16
+ linux: 'unknown-linux-gnu',
17
+ darwin: 'apple-darwin',
18
+ win32: 'pc-windows-msvc',
19
+ };
20
+
21
+ const archMap = {
22
+ x64: 'x86_64',
23
+ arm64: 'aarch64',
24
+ };
25
+
26
+ const platform = process.platform;
27
+ const arch = process.arch;
28
+ const targetPlatform = platformMap[platform];
29
+ const targetArch = archMap[arch];
30
+ const exeName = platform === 'win32' ? 'smart-query.exe' : 'smart-query';
31
+ const wrapperRoot = path.resolve(__dirname, '..');
32
+ const vendorDir = path.join(wrapperRoot, 'vendor', `${platform}-${arch}`);
33
+ const vendorBinaryPath = path.join(vendorDir, exeName);
34
+
35
+ function log(message) {
36
+ console.log(`smart-query postinstall: ${message}`);
37
+ }
38
+
39
+ function warn(message) {
40
+ console.warn(`smart-query postinstall: ${message}`);
41
+ }
42
+
43
+ function hasFile(filePath) {
44
+ try {
45
+ return fs.statSync(filePath).isFile();
46
+ } catch {
47
+ return false;
48
+ }
49
+ }
50
+
51
+ function getReleaseBaseUrl() {
52
+ if (process.env.SMART_QUERY_RELEASE_BASE_URL) {
53
+ return process.env.SMART_QUERY_RELEASE_BASE_URL.replace(/\/$/, '');
54
+ }
55
+ const version = pkg.version;
56
+ return `https://github.com/IAmMarcellus/smart-query/releases/download/v${version}`;
57
+ }
58
+
59
+ function getAssetName() {
60
+ if (!targetPlatform || !targetArch) {
61
+ return null;
62
+ }
63
+ return `smart-query-v${pkg.version}-${targetArch}-${targetPlatform}.tar.gz`;
64
+ }
65
+
66
+ function request(url) {
67
+ const client = url.startsWith('https:') ? https : http;
68
+ return new Promise((resolve, reject) => {
69
+ const req = client.get(url, (res) => {
70
+ if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
71
+ res.resume();
72
+ resolve(request(res.headers.location));
73
+ return;
74
+ }
75
+ if (res.statusCode !== 200) {
76
+ res.resume();
77
+ reject(new Error(`HTTP ${res.statusCode} for ${url}`));
78
+ return;
79
+ }
80
+ resolve(res);
81
+ });
82
+ req.on('error', reject);
83
+ });
84
+ }
85
+
86
+ async function download(url, destination) {
87
+ const res = await request(url);
88
+ await fs.promises.mkdir(path.dirname(destination), { recursive: true });
89
+ const file = fs.createWriteStream(destination);
90
+ await streamPipeline(res, file);
91
+ }
92
+
93
+ async function main() {
94
+ if (process.env.SMART_QUERY_SKIP_DOWNLOAD === '1') {
95
+ log('skipping download because SMART_QUERY_SKIP_DOWNLOAD=1');
96
+ return;
97
+ }
98
+
99
+ if (process.env.SMART_QUERY_BIN) {
100
+ log('skipping download because SMART_QUERY_BIN is set');
101
+ return;
102
+ }
103
+
104
+ if (hasFile(vendorBinaryPath)) {
105
+ log(`using existing vendored binary at ${vendorBinaryPath}`);
106
+ return;
107
+ }
108
+
109
+ const assetName = getAssetName();
110
+ if (!assetName) {
111
+ warn(`unsupported platform/arch for automatic download: ${platform}/${arch}`);
112
+ return;
113
+ }
114
+
115
+ const releaseBaseUrl = getReleaseBaseUrl();
116
+ const assetUrl = `${releaseBaseUrl}/${assetName}`;
117
+ const tmpDir = await fs.promises.mkdtemp(path.join(os.tmpdir(), 'smart-query-install-'));
118
+ const archivePath = path.join(tmpDir, assetName);
119
+
120
+ try {
121
+ log(`downloading ${assetUrl}`);
122
+ await download(assetUrl, archivePath);
123
+ await fs.promises.mkdir(vendorDir, { recursive: true });
124
+
125
+ const tarArgs = platform === 'win32'
126
+ ? ['-xzf', archivePath, '-C', vendorDir]
127
+ : ['-xzf', archivePath, '-C', vendorDir];
128
+ const tar = spawnSync('tar', tarArgs, { stdio: 'inherit' });
129
+ if (tar.error) {
130
+ throw tar.error;
131
+ }
132
+ if (tar.status !== 0) {
133
+ throw new Error(`tar exited with status ${tar.status}`);
134
+ }
135
+
136
+ if (!hasFile(vendorBinaryPath)) {
137
+ throw new Error(`archive extracted, but ${vendorBinaryPath} was not found`);
138
+ }
139
+
140
+ if (platform !== 'win32') {
141
+ await fs.promises.chmod(vendorBinaryPath, 0o755);
142
+ }
143
+
144
+ log(`installed ${vendorBinaryPath}`);
145
+ } catch (error) {
146
+ warn(`automatic binary download failed: ${error.message}`);
147
+ warn('you can still use this package by setting SMART_QUERY_BIN or by building the Rust binary locally.');
148
+ }
149
+ }
150
+
151
+ main().catch((error) => {
152
+ warn(`unexpected install failure: ${error.message}`);
153
+ process.exit(0);
154
+ });