inillucent 0.1.3 → 0.1.5
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 +102 -102
- package/bin/inillucent-mcp.mjs +33 -33
- package/bin/inillucent-migrate.mjs +33 -33
- package/bin/inillucent-shell.mjs +33 -33
- package/bin/inillucent.mjs +33 -33
- package/package.json +6 -6
- package/resolve.mjs +122 -114
package/README.md
CHANGED
|
@@ -1,102 +1,102 @@
|
|
|
1
|
-
# inillucent
|
|
2
|
-
|
|
3
|
-
An embedded SQL database that speaks SQLite's dialect on its own storage, with
|
|
4
|
-
full-text and vector search built in — the job of PostgreSQL + pgvector + an
|
|
5
|
-
embedding server, in one process and one file.
|
|
6
|
-
|
|
7
|
-
```sh
|
|
8
|
-
npm install -g inillucent
|
|
9
|
-
# or, without installing anything permanently:
|
|
10
|
-
npx inillucent help
|
|
11
|
-
```
|
|
12
|
-
|
|
13
|
-
No native build step and no postinstall download: the binaries ship as
|
|
14
|
-
per-platform packages that npm installs only where they run, so `npm ci` works
|
|
15
|
-
offline and behind a proxy.
|
|
16
|
-
|
|
17
|
-
## Four programs
|
|
18
|
-
|
|
19
|
-
| | |
|
|
20
|
-
|---|---|
|
|
21
|
-
| `inillucent` | the command line: `query`, `exec`, `describe`, `import`, `export`, `search`, and twenty more |
|
|
22
|
-
| `inillucent-shell` | an interactive shell shaped like `sqlite3`, with all 63 of its dot commands |
|
|
23
|
-
| `inillucent-mcp` | the same commands served to an AI agent over MCP |
|
|
24
|
-
| `inillucent-migrate` | builds an inillucent database from a SQLite file |
|
|
25
|
-
|
|
26
|
-
## From a shell
|
|
27
|
-
|
|
28
|
-
```sh
|
|
29
|
-
inillucent create app.rdb
|
|
30
|
-
inillucent --db app.rdb exec "CREATE TABLE notes (id INTEGER PRIMARY KEY, body TEXT)"
|
|
31
|
-
inillucent --db app.rdb exec "INSERT INTO notes (body) VALUES (?1)" --params '["hello"]'
|
|
32
|
-
inillucent --db app.rdb query "SELECT * FROM notes"
|
|
33
|
-
inillucent --db app.rdb describe notes
|
|
34
|
-
inillucent help
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
Exit codes carry meaning: `0` success, `1` failed, `2` a command line nobody
|
|
38
|
-
could act on, and **`3` a construct the engine has not built yet** — so a script
|
|
39
|
-
can branch on "not yet" without matching on a message.
|
|
40
|
-
|
|
41
|
-
## From Node
|
|
42
|
-
|
|
43
|
-
```js
|
|
44
|
-
import { query, inillucent } from 'inillucent';
|
|
45
|
-
|
|
46
|
-
const rows = await query('SELECT id, body FROM notes WHERE id > ?1', {
|
|
47
|
-
db: 'app.rdb',
|
|
48
|
-
params: [3],
|
|
49
|
-
});
|
|
50
|
-
// [{ id: 4, body: 'hello' }]
|
|
51
|
-
|
|
52
|
-
const described = await inillucent('describe', { db: 'app.rdb', table: 'notes' });
|
|
53
|
-
console.log(described.ddl, described.indexes, described.row_count_in_table);
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
Each call is a process, so this is the right tool for the dozen calls a build
|
|
57
|
-
script or a tool wrapper makes and the wrong one for a loop over a million rows.
|
|
58
|
-
For that, write a binding over the C ABI — the header ships in this package's
|
|
59
|
-
platform dependency under `include/`, and
|
|
60
|
-
[`drivers/README.md`](https://github.com/Black-Rainbow-Labs/Inillucent/blob/main/drivers/README.md)
|
|
61
|
-
is written to be followed.
|
|
62
|
-
|
|
63
|
-
## For an agent
|
|
64
|
-
|
|
65
|
-
```json
|
|
66
|
-
{
|
|
67
|
-
"mcpServers": {
|
|
68
|
-
"inillucent": {
|
|
69
|
-
"command": "npx",
|
|
70
|
-
"args": ["-y", "inillucent-mcp", "--db", "app.rdb"]
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
```
|
|
75
|
-
|
|
76
|
-
27 tools, generated from the same command table the CLI reads, so the two can
|
|
77
|
-
never drift. `--readonly` refuses every statement that changes something, and
|
|
78
|
-
`--root DIR` refuses every path outside a directory.
|
|
79
|
-
|
|
80
|
-
## Licence
|
|
81
|
-
|
|
82
|
-
MIT. Source: <https://github.com/Black-Rainbow-Labs/Inillucent>
|
|
83
|
-
|
|
84
|
-
## The API
|
|
85
|
-
|
|
86
|
-
Every method this binding has. The worked example each one appears in is the link; nothing here is
|
|
87
|
-
a summary of a method that does not exist, because
|
|
88
|
-
`cargo test -p inillucent-compat --test documentation` reads this table and fails on a name the
|
|
89
|
-
binding source does not declare.
|
|
90
|
-
|
|
91
|
-
| what | one line |
|
|
92
|
-
|---|---|
|
|
93
|
-
| `inillucent(command, options)` | run one command of the command line and return its parsed JSON. `options.db` names the file, `options.args` the rest. |
|
|
94
|
-
| `query(sql, options)` | run one `SELECT` and return its rows. `options.params` binds `?1`, `?2`; `options.limit` caps the rows kept. |
|
|
95
|
-
| `resolveBinary(program)` | the path to one of the four programs on this platform, from the platform package npm installed. |
|
|
96
|
-
| `platformPackage()` | the name of the platform package this machine needs, which is what an install failure should name. |
|
|
97
|
-
| `PROGRAMS` | the four programs and what each is for, as an object. |
|
|
98
|
-
|
|
99
|
-
Every call goes through the command line rather than through the C ABI: the four programs are what
|
|
100
|
-
the platform package ships, and `--output json` is the same object every other binding sees. That
|
|
101
|
-
is why there is no `Connection` here and no transaction - a command is one process, and a
|
|
102
|
-
transaction that spanned two of them would be a transaction nothing held open.
|
|
1
|
+
# inillucent
|
|
2
|
+
|
|
3
|
+
An embedded SQL database that speaks SQLite's dialect on its own storage, with
|
|
4
|
+
full-text and vector search built in — the job of PostgreSQL + pgvector + an
|
|
5
|
+
embedding server, in one process and one file.
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
npm install -g inillucent
|
|
9
|
+
# or, without installing anything permanently:
|
|
10
|
+
npx inillucent help
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
No native build step and no postinstall download: the binaries ship as
|
|
14
|
+
per-platform packages that npm installs only where they run, so `npm ci` works
|
|
15
|
+
offline and behind a proxy.
|
|
16
|
+
|
|
17
|
+
## Four programs
|
|
18
|
+
|
|
19
|
+
| | |
|
|
20
|
+
|---|---|
|
|
21
|
+
| `inillucent` | the command line: `query`, `exec`, `describe`, `import`, `export`, `search`, and twenty more |
|
|
22
|
+
| `inillucent-shell` | an interactive shell shaped like `sqlite3`, with all 63 of its dot commands |
|
|
23
|
+
| `inillucent-mcp` | the same commands served to an AI agent over MCP |
|
|
24
|
+
| `inillucent-migrate` | builds an inillucent database from a SQLite file |
|
|
25
|
+
|
|
26
|
+
## From a shell
|
|
27
|
+
|
|
28
|
+
```sh
|
|
29
|
+
inillucent create app.rdb
|
|
30
|
+
inillucent --db app.rdb exec "CREATE TABLE notes (id INTEGER PRIMARY KEY, body TEXT)"
|
|
31
|
+
inillucent --db app.rdb exec "INSERT INTO notes (body) VALUES (?1)" --params '["hello"]'
|
|
32
|
+
inillucent --db app.rdb query "SELECT * FROM notes"
|
|
33
|
+
inillucent --db app.rdb describe notes
|
|
34
|
+
inillucent help
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Exit codes carry meaning: `0` success, `1` failed, `2` a command line nobody
|
|
38
|
+
could act on, and **`3` a construct the engine has not built yet** — so a script
|
|
39
|
+
can branch on "not yet" without matching on a message.
|
|
40
|
+
|
|
41
|
+
## From Node
|
|
42
|
+
|
|
43
|
+
```js
|
|
44
|
+
import { query, inillucent } from 'inillucent';
|
|
45
|
+
|
|
46
|
+
const rows = await query('SELECT id, body FROM notes WHERE id > ?1', {
|
|
47
|
+
db: 'app.rdb',
|
|
48
|
+
params: [3],
|
|
49
|
+
});
|
|
50
|
+
// [{ id: 4, body: 'hello' }]
|
|
51
|
+
|
|
52
|
+
const described = await inillucent('describe', { db: 'app.rdb', table: 'notes' });
|
|
53
|
+
console.log(described.ddl, described.indexes, described.row_count_in_table);
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Each call is a process, so this is the right tool for the dozen calls a build
|
|
57
|
+
script or a tool wrapper makes and the wrong one for a loop over a million rows.
|
|
58
|
+
For that, write a binding over the C ABI — the header ships in this package's
|
|
59
|
+
platform dependency under `include/`, and
|
|
60
|
+
[`drivers/README.md`](https://github.com/Black-Rainbow-Labs/Inillucent/blob/main/drivers/README.md)
|
|
61
|
+
is written to be followed.
|
|
62
|
+
|
|
63
|
+
## For an agent
|
|
64
|
+
|
|
65
|
+
```json
|
|
66
|
+
{
|
|
67
|
+
"mcpServers": {
|
|
68
|
+
"inillucent": {
|
|
69
|
+
"command": "npx",
|
|
70
|
+
"args": ["-y", "inillucent-mcp", "--db", "app.rdb"]
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
27 tools, generated from the same command table the CLI reads, so the two can
|
|
77
|
+
never drift. `--readonly` refuses every statement that changes something, and
|
|
78
|
+
`--root DIR` refuses every path outside a directory.
|
|
79
|
+
|
|
80
|
+
## Licence
|
|
81
|
+
|
|
82
|
+
MIT. Source: <https://github.com/Black-Rainbow-Labs/Inillucent>
|
|
83
|
+
|
|
84
|
+
## The API
|
|
85
|
+
|
|
86
|
+
Every method this binding has. The worked example each one appears in is the link; nothing here is
|
|
87
|
+
a summary of a method that does not exist, because
|
|
88
|
+
`cargo test -p inillucent-compat --test documentation` reads this table and fails on a name the
|
|
89
|
+
binding source does not declare.
|
|
90
|
+
|
|
91
|
+
| what | one line |
|
|
92
|
+
|---|---|
|
|
93
|
+
| `inillucent(command, options)` | run one command of the command line and return its parsed JSON. `options.db` names the file, `options.args` the rest. |
|
|
94
|
+
| `query(sql, options)` | run one `SELECT` and return its rows. `options.params` binds `?1`, `?2`; `options.limit` caps the rows kept. |
|
|
95
|
+
| `resolveBinary(program)` | the path to one of the four programs on this platform, from the platform package npm installed. |
|
|
96
|
+
| `platformPackage()` | the name of the platform package this machine needs, which is what an install failure should name. |
|
|
97
|
+
| `PROGRAMS` | the four programs and what each is for, as an object. |
|
|
98
|
+
|
|
99
|
+
Every call goes through the command line rather than through the C ABI: the four programs are what
|
|
100
|
+
the platform package ships, and `--output json` is the same object every other binding sees. That
|
|
101
|
+
is why there is no `Connection` here and no transaction - a command is one process, and a
|
|
102
|
+
transaction that spanned two of them would be a transaction nothing held open.
|
package/bin/inillucent-mcp.mjs
CHANGED
|
@@ -1,33 +1,33 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
// The `inillucent-mcp` shim: resolve the platform binary and become it.
|
|
3
|
-
//
|
|
4
|
-
// `spawn` with `stdio: 'inherit'` rather than an exec, because Node has no
|
|
5
|
-
// execve and this has to work on Windows. The child's exit code and its signal
|
|
6
|
-
// are both passed back up: a wrapper that always exited 0 would break every
|
|
7
|
-
// script that branches on the exit code, and inillucent's exit codes carry
|
|
8
|
-
// meaning - 3 is "the engine has not built that".
|
|
9
|
-
import { spawn } from 'node:child_process';
|
|
10
|
-
import { resolveBinary } from '../resolve.mjs';
|
|
11
|
-
|
|
12
|
-
let binary;
|
|
13
|
-
try {
|
|
14
|
-
binary = resolveBinary('inillucent-mcp');
|
|
15
|
-
} catch (why) {
|
|
16
|
-
process.stderr.write(String(why.message ?? why) + '\n');
|
|
17
|
-
process.exit(1);
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
const child = spawn(binary, process.argv.slice(2), { stdio: 'inherit' });
|
|
21
|
-
child.on('error', (why) => {
|
|
22
|
-
process.stderr.write(`inillucent: could not run ${binary}: ${why.message}\n`);
|
|
23
|
-
process.exit(1);
|
|
24
|
-
});
|
|
25
|
-
child.on('exit', (code, signal) => {
|
|
26
|
-
if (signal) {
|
|
27
|
-
// Re-raise it on ourselves so a shell sees the same thing it would have
|
|
28
|
-
// seen from the real program, rather than a plain exit.
|
|
29
|
-
process.kill(process.pid, signal);
|
|
30
|
-
return;
|
|
31
|
-
}
|
|
32
|
-
process.exit(code ?? 0);
|
|
33
|
-
});
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// The `inillucent-mcp` shim: resolve the platform binary and become it.
|
|
3
|
+
//
|
|
4
|
+
// `spawn` with `stdio: 'inherit'` rather than an exec, because Node has no
|
|
5
|
+
// execve and this has to work on Windows. The child's exit code and its signal
|
|
6
|
+
// are both passed back up: a wrapper that always exited 0 would break every
|
|
7
|
+
// script that branches on the exit code, and inillucent's exit codes carry
|
|
8
|
+
// meaning - 3 is "the engine has not built that".
|
|
9
|
+
import { spawn } from 'node:child_process';
|
|
10
|
+
import { resolveBinary } from '../resolve.mjs';
|
|
11
|
+
|
|
12
|
+
let binary;
|
|
13
|
+
try {
|
|
14
|
+
binary = resolveBinary('inillucent-mcp');
|
|
15
|
+
} catch (why) {
|
|
16
|
+
process.stderr.write(String(why.message ?? why) + '\n');
|
|
17
|
+
process.exit(1);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const child = spawn(binary, process.argv.slice(2), { stdio: 'inherit' });
|
|
21
|
+
child.on('error', (why) => {
|
|
22
|
+
process.stderr.write(`inillucent: could not run ${binary}: ${why.message}\n`);
|
|
23
|
+
process.exit(1);
|
|
24
|
+
});
|
|
25
|
+
child.on('exit', (code, signal) => {
|
|
26
|
+
if (signal) {
|
|
27
|
+
// Re-raise it on ourselves so a shell sees the same thing it would have
|
|
28
|
+
// seen from the real program, rather than a plain exit.
|
|
29
|
+
process.kill(process.pid, signal);
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
process.exit(code ?? 0);
|
|
33
|
+
});
|
|
@@ -1,33 +1,33 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
// The `inillucent-migrate` shim: resolve the platform binary and become it.
|
|
3
|
-
//
|
|
4
|
-
// `spawn` with `stdio: 'inherit'` rather than an exec, because Node has no
|
|
5
|
-
// execve and this has to work on Windows. The child's exit code and its signal
|
|
6
|
-
// are both passed back up: a wrapper that always exited 0 would break every
|
|
7
|
-
// script that branches on the exit code, and inillucent's exit codes carry
|
|
8
|
-
// meaning - 3 is "the engine has not built that".
|
|
9
|
-
import { spawn } from 'node:child_process';
|
|
10
|
-
import { resolveBinary } from '../resolve.mjs';
|
|
11
|
-
|
|
12
|
-
let binary;
|
|
13
|
-
try {
|
|
14
|
-
binary = resolveBinary('inillucent-migrate');
|
|
15
|
-
} catch (why) {
|
|
16
|
-
process.stderr.write(String(why.message ?? why) + '\n');
|
|
17
|
-
process.exit(1);
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
const child = spawn(binary, process.argv.slice(2), { stdio: 'inherit' });
|
|
21
|
-
child.on('error', (why) => {
|
|
22
|
-
process.stderr.write(`inillucent: could not run ${binary}: ${why.message}\n`);
|
|
23
|
-
process.exit(1);
|
|
24
|
-
});
|
|
25
|
-
child.on('exit', (code, signal) => {
|
|
26
|
-
if (signal) {
|
|
27
|
-
// Re-raise it on ourselves so a shell sees the same thing it would have
|
|
28
|
-
// seen from the real program, rather than a plain exit.
|
|
29
|
-
process.kill(process.pid, signal);
|
|
30
|
-
return;
|
|
31
|
-
}
|
|
32
|
-
process.exit(code ?? 0);
|
|
33
|
-
});
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// The `inillucent-migrate` shim: resolve the platform binary and become it.
|
|
3
|
+
//
|
|
4
|
+
// `spawn` with `stdio: 'inherit'` rather than an exec, because Node has no
|
|
5
|
+
// execve and this has to work on Windows. The child's exit code and its signal
|
|
6
|
+
// are both passed back up: a wrapper that always exited 0 would break every
|
|
7
|
+
// script that branches on the exit code, and inillucent's exit codes carry
|
|
8
|
+
// meaning - 3 is "the engine has not built that".
|
|
9
|
+
import { spawn } from 'node:child_process';
|
|
10
|
+
import { resolveBinary } from '../resolve.mjs';
|
|
11
|
+
|
|
12
|
+
let binary;
|
|
13
|
+
try {
|
|
14
|
+
binary = resolveBinary('inillucent-migrate');
|
|
15
|
+
} catch (why) {
|
|
16
|
+
process.stderr.write(String(why.message ?? why) + '\n');
|
|
17
|
+
process.exit(1);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const child = spawn(binary, process.argv.slice(2), { stdio: 'inherit' });
|
|
21
|
+
child.on('error', (why) => {
|
|
22
|
+
process.stderr.write(`inillucent: could not run ${binary}: ${why.message}\n`);
|
|
23
|
+
process.exit(1);
|
|
24
|
+
});
|
|
25
|
+
child.on('exit', (code, signal) => {
|
|
26
|
+
if (signal) {
|
|
27
|
+
// Re-raise it on ourselves so a shell sees the same thing it would have
|
|
28
|
+
// seen from the real program, rather than a plain exit.
|
|
29
|
+
process.kill(process.pid, signal);
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
process.exit(code ?? 0);
|
|
33
|
+
});
|
package/bin/inillucent-shell.mjs
CHANGED
|
@@ -1,33 +1,33 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
// The `inillucent-shell` shim: resolve the platform binary and become it.
|
|
3
|
-
//
|
|
4
|
-
// `spawn` with `stdio: 'inherit'` rather than an exec, because Node has no
|
|
5
|
-
// execve and this has to work on Windows. The child's exit code and its signal
|
|
6
|
-
// are both passed back up: a wrapper that always exited 0 would break every
|
|
7
|
-
// script that branches on the exit code, and inillucent's exit codes carry
|
|
8
|
-
// meaning - 3 is "the engine has not built that".
|
|
9
|
-
import { spawn } from 'node:child_process';
|
|
10
|
-
import { resolveBinary } from '../resolve.mjs';
|
|
11
|
-
|
|
12
|
-
let binary;
|
|
13
|
-
try {
|
|
14
|
-
binary = resolveBinary('inillucent-shell');
|
|
15
|
-
} catch (why) {
|
|
16
|
-
process.stderr.write(String(why.message ?? why) + '\n');
|
|
17
|
-
process.exit(1);
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
const child = spawn(binary, process.argv.slice(2), { stdio: 'inherit' });
|
|
21
|
-
child.on('error', (why) => {
|
|
22
|
-
process.stderr.write(`inillucent: could not run ${binary}: ${why.message}\n`);
|
|
23
|
-
process.exit(1);
|
|
24
|
-
});
|
|
25
|
-
child.on('exit', (code, signal) => {
|
|
26
|
-
if (signal) {
|
|
27
|
-
// Re-raise it on ourselves so a shell sees the same thing it would have
|
|
28
|
-
// seen from the real program, rather than a plain exit.
|
|
29
|
-
process.kill(process.pid, signal);
|
|
30
|
-
return;
|
|
31
|
-
}
|
|
32
|
-
process.exit(code ?? 0);
|
|
33
|
-
});
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// The `inillucent-shell` shim: resolve the platform binary and become it.
|
|
3
|
+
//
|
|
4
|
+
// `spawn` with `stdio: 'inherit'` rather than an exec, because Node has no
|
|
5
|
+
// execve and this has to work on Windows. The child's exit code and its signal
|
|
6
|
+
// are both passed back up: a wrapper that always exited 0 would break every
|
|
7
|
+
// script that branches on the exit code, and inillucent's exit codes carry
|
|
8
|
+
// meaning - 3 is "the engine has not built that".
|
|
9
|
+
import { spawn } from 'node:child_process';
|
|
10
|
+
import { resolveBinary } from '../resolve.mjs';
|
|
11
|
+
|
|
12
|
+
let binary;
|
|
13
|
+
try {
|
|
14
|
+
binary = resolveBinary('inillucent-shell');
|
|
15
|
+
} catch (why) {
|
|
16
|
+
process.stderr.write(String(why.message ?? why) + '\n');
|
|
17
|
+
process.exit(1);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const child = spawn(binary, process.argv.slice(2), { stdio: 'inherit' });
|
|
21
|
+
child.on('error', (why) => {
|
|
22
|
+
process.stderr.write(`inillucent: could not run ${binary}: ${why.message}\n`);
|
|
23
|
+
process.exit(1);
|
|
24
|
+
});
|
|
25
|
+
child.on('exit', (code, signal) => {
|
|
26
|
+
if (signal) {
|
|
27
|
+
// Re-raise it on ourselves so a shell sees the same thing it would have
|
|
28
|
+
// seen from the real program, rather than a plain exit.
|
|
29
|
+
process.kill(process.pid, signal);
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
process.exit(code ?? 0);
|
|
33
|
+
});
|
package/bin/inillucent.mjs
CHANGED
|
@@ -1,33 +1,33 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
// The `inillucent` shim: resolve the platform binary and become it.
|
|
3
|
-
//
|
|
4
|
-
// `spawn` with `stdio: 'inherit'` rather than an exec, because Node has no
|
|
5
|
-
// execve and this has to work on Windows. The child's exit code and its signal
|
|
6
|
-
// are both passed back up: a wrapper that always exited 0 would break every
|
|
7
|
-
// script that branches on the exit code, and inillucent's exit codes carry
|
|
8
|
-
// meaning - 3 is "the engine has not built that".
|
|
9
|
-
import { spawn } from 'node:child_process';
|
|
10
|
-
import { resolveBinary } from '../resolve.mjs';
|
|
11
|
-
|
|
12
|
-
let binary;
|
|
13
|
-
try {
|
|
14
|
-
binary = resolveBinary('inillucent');
|
|
15
|
-
} catch (why) {
|
|
16
|
-
process.stderr.write(String(why.message ?? why) + '\n');
|
|
17
|
-
process.exit(1);
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
const child = spawn(binary, process.argv.slice(2), { stdio: 'inherit' });
|
|
21
|
-
child.on('error', (why) => {
|
|
22
|
-
process.stderr.write(`inillucent: could not run ${binary}: ${why.message}\n`);
|
|
23
|
-
process.exit(1);
|
|
24
|
-
});
|
|
25
|
-
child.on('exit', (code, signal) => {
|
|
26
|
-
if (signal) {
|
|
27
|
-
// Re-raise it on ourselves so a shell sees the same thing it would have
|
|
28
|
-
// seen from the real program, rather than a plain exit.
|
|
29
|
-
process.kill(process.pid, signal);
|
|
30
|
-
return;
|
|
31
|
-
}
|
|
32
|
-
process.exit(code ?? 0);
|
|
33
|
-
});
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// The `inillucent` shim: resolve the platform binary and become it.
|
|
3
|
+
//
|
|
4
|
+
// `spawn` with `stdio: 'inherit'` rather than an exec, because Node has no
|
|
5
|
+
// execve and this has to work on Windows. The child's exit code and its signal
|
|
6
|
+
// are both passed back up: a wrapper that always exited 0 would break every
|
|
7
|
+
// script that branches on the exit code, and inillucent's exit codes carry
|
|
8
|
+
// meaning - 3 is "the engine has not built that".
|
|
9
|
+
import { spawn } from 'node:child_process';
|
|
10
|
+
import { resolveBinary } from '../resolve.mjs';
|
|
11
|
+
|
|
12
|
+
let binary;
|
|
13
|
+
try {
|
|
14
|
+
binary = resolveBinary('inillucent');
|
|
15
|
+
} catch (why) {
|
|
16
|
+
process.stderr.write(String(why.message ?? why) + '\n');
|
|
17
|
+
process.exit(1);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const child = spawn(binary, process.argv.slice(2), { stdio: 'inherit' });
|
|
21
|
+
child.on('error', (why) => {
|
|
22
|
+
process.stderr.write(`inillucent: could not run ${binary}: ${why.message}\n`);
|
|
23
|
+
process.exit(1);
|
|
24
|
+
});
|
|
25
|
+
child.on('exit', (code, signal) => {
|
|
26
|
+
if (signal) {
|
|
27
|
+
// Re-raise it on ourselves so a shell sees the same thing it would have
|
|
28
|
+
// seen from the real program, rather than a plain exit.
|
|
29
|
+
process.kill(process.pid, signal);
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
process.exit(code ?? 0);
|
|
33
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "inillucent",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
4
4
|
"description": "Embedded SQL database with full-text and vector search, an MCP server, and a sqlite3-shaped shell. No native build step: the binaries ship as platform packages.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"database",
|
|
@@ -43,10 +43,10 @@
|
|
|
43
43
|
"README.md"
|
|
44
44
|
],
|
|
45
45
|
"optionalDependencies": {
|
|
46
|
-
"@blackrainbowlabs/cli-win32-x64": "0.1.
|
|
47
|
-
"@blackrainbowlabs/cli-darwin-arm64": "0.1.
|
|
48
|
-
"@blackrainbowlabs/cli-darwin-x64": "0.1.
|
|
49
|
-
"@blackrainbowlabs/cli-linux-x64": "0.1.
|
|
50
|
-
"@blackrainbowlabs/cli-linux-arm64": "0.1.
|
|
46
|
+
"@blackrainbowlabs/cli-win32-x64": "0.1.5",
|
|
47
|
+
"@blackrainbowlabs/cli-darwin-arm64": "0.1.5",
|
|
48
|
+
"@blackrainbowlabs/cli-darwin-x64": "0.1.5",
|
|
49
|
+
"@blackrainbowlabs/cli-linux-x64": "0.1.5",
|
|
50
|
+
"@blackrainbowlabs/cli-linux-arm64": "0.1.5"
|
|
51
51
|
}
|
|
52
52
|
}
|
package/resolve.mjs
CHANGED
|
@@ -1,114 +1,122 @@
|
|
|
1
|
-
// Finds the binary for the machine this is running on.
|
|
2
|
-
//
|
|
3
|
-
// The arrangement is esbuild's, and it is the right one: the binaries live in
|
|
4
|
-
// per-platform packages listed as `optionalDependencies`, npm installs only the
|
|
5
|
-
// one that matches, and this package's `bin` entries are tiny shims that
|
|
6
|
-
// resolve it and hand over. There is no postinstall script and nothing is
|
|
7
|
-
// downloaded at install time, which means `npm ci` works offline, in a locked
|
|
8
|
-
// CI, and behind a registry proxy - none of which is true of a package that
|
|
9
|
-
// fetches a binary from GitHub when it is installed.
|
|
10
|
-
//
|
|
11
|
-
// The cost is that a platform without a published package cannot install, and
|
|
12
|
-
// the failure has to say so in a sentence somebody can act on rather than as an
|
|
13
|
-
// unresolved import. That is what `resolveBinary` is for.
|
|
14
|
-
|
|
15
|
-
import { createRequire } from 'node:module';
|
|
16
|
-
import { accessSync, constants, existsSync } from 'node:fs';
|
|
17
|
-
import { dirname, join } from 'node:path';
|
|
18
|
-
|
|
19
|
-
const require = createRequire(import.meta.url);
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
'
|
|
34
|
-
'
|
|
35
|
-
'
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
*
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
//
|
|
63
|
-
//
|
|
64
|
-
//
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
}
|
|
88
|
-
const
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
1
|
+
// Finds the binary for the machine this is running on.
|
|
2
|
+
//
|
|
3
|
+
// The arrangement is esbuild's, and it is the right one: the binaries live in
|
|
4
|
+
// per-platform packages listed as `optionalDependencies`, npm installs only the
|
|
5
|
+
// one that matches, and this package's `bin` entries are tiny shims that
|
|
6
|
+
// resolve it and hand over. There is no postinstall script and nothing is
|
|
7
|
+
// downloaded at install time, which means `npm ci` works offline, in a locked
|
|
8
|
+
// CI, and behind a registry proxy - none of which is true of a package that
|
|
9
|
+
// fetches a binary from GitHub when it is installed.
|
|
10
|
+
//
|
|
11
|
+
// The cost is that a platform without a published package cannot install, and
|
|
12
|
+
// the failure has to say so in a sentence somebody can act on rather than as an
|
|
13
|
+
// unresolved import. That is what `resolveBinary` is for.
|
|
14
|
+
|
|
15
|
+
import { createRequire } from 'node:module';
|
|
16
|
+
import { accessSync, constants, existsSync } from 'node:fs';
|
|
17
|
+
import { dirname, join } from 'node:path';
|
|
18
|
+
|
|
19
|
+
const require = createRequire(import.meta.url);
|
|
20
|
+
|
|
21
|
+
// **The scope here is the scope they are published under, and the two came apart (task-1995).**
|
|
22
|
+
// The packages were renamed from `@inillucent/*` to `@blackrainbowlabs/*` in build.mjs and in this
|
|
23
|
+
// package's optionalDependencies, and this table was missed. npm then installed
|
|
24
|
+
// `@blackrainbowlabs/cli-win32-x64` correctly and the shim looked for `@inillucent/cli-win32-x64`,
|
|
25
|
+
// so every install on every platform ended at "inillucent's binary for win32-x64 is not installed"
|
|
26
|
+
// - naming a package that does not exist. It reached the registry, where a version cannot be
|
|
27
|
+
// replaced. resolve.test.mjs compares this table against package.json and against build.mjs, and it
|
|
28
|
+
// no longer hard-codes a scope, so a rename that touches one of the three fails here instead.
|
|
29
|
+
/** The platform packages, by the `process.platform`-`process.arch` pair each serves. */
|
|
30
|
+
const PACKAGES = {
|
|
31
|
+
'win32-x64': '@blackrainbowlabs/cli-win32-x64',
|
|
32
|
+
'darwin-arm64': '@blackrainbowlabs/cli-darwin-arm64',
|
|
33
|
+
'darwin-x64': '@blackrainbowlabs/cli-darwin-x64',
|
|
34
|
+
'linux-x64': '@blackrainbowlabs/cli-linux-x64',
|
|
35
|
+
'linux-arm64': '@blackrainbowlabs/cli-linux-arm64',
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
/** The four programs the release ships, and what each one is for. */
|
|
39
|
+
export const PROGRAMS = {
|
|
40
|
+
inillucent: 'the command line: query, exec, describe, import, export, search',
|
|
41
|
+
'inillucent-shell': 'the interactive sqlite3-shaped shell',
|
|
42
|
+
'inillucent-mcp': 'the MCP server, for an agent',
|
|
43
|
+
'inillucent-migrate': 'builds an inillucent database from a SQLite file',
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Returns the platform package name for this machine, or null if there is none.
|
|
48
|
+
*/
|
|
49
|
+
export function platformPackage() {
|
|
50
|
+
return PACKAGES[`${process.platform}-${process.arch}`] ?? null;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Returns the absolute path of one of the four programs on this machine.
|
|
55
|
+
*
|
|
56
|
+
* @param program - which program, as it is named in PROGRAMS
|
|
57
|
+
*/
|
|
58
|
+
export function resolveBinary(program) {
|
|
59
|
+
if (!(program in PROGRAMS)) {
|
|
60
|
+
throw new Error(`inillucent has no program called ${program}`);
|
|
61
|
+
}
|
|
62
|
+
// **`INILLUCENT_BIN` wins, the way it already does for the Go and PHP
|
|
63
|
+
// wrappers (task-1969, 4.5).** It names the `inillucent` binary; the others
|
|
64
|
+
// are looked for beside it, which is where a build and an install both put
|
|
65
|
+
// them. Without this the wrappers stage of `tools/validate` could point the
|
|
66
|
+
// other two languages at a freshly built binary and had no way to point this
|
|
67
|
+
// one, so the only npm test that could run was the one that reads the
|
|
68
|
+
// platform table as text.
|
|
69
|
+
//
|
|
70
|
+
// It throws rather than falling through when the named binary is not there:
|
|
71
|
+
// a caller who says where the binary is and is wrong wants to know, not to
|
|
72
|
+
// have the resolver quietly go looking somewhere else.
|
|
73
|
+
const named = process.env.INILLUCENT_BIN;
|
|
74
|
+
if (named) {
|
|
75
|
+
const suffix = process.platform === 'win32' ? '.exe' : '';
|
|
76
|
+
const beside = program === 'inillucent'
|
|
77
|
+
? named
|
|
78
|
+
: join(dirname(named), `${program}${suffix}`);
|
|
79
|
+
if (!existsSync(beside)) {
|
|
80
|
+
throw new Error(
|
|
81
|
+
`INILLUCENT_BIN is set and ${beside} is not there.
|
|
82
|
+
` +
|
|
83
|
+
` Unset INILLUCENT_BIN to look for an installed copy instead.`,
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
return beside;
|
|
87
|
+
}
|
|
88
|
+
const name = platformPackage();
|
|
89
|
+
if (!name) {
|
|
90
|
+
throw new Error(
|
|
91
|
+
`inillucent has no prebuilt binary for ${process.platform}-${process.arch}.\n` +
|
|
92
|
+
` Build it from source instead: cargo install inillucent-cli\n` +
|
|
93
|
+
` Or open an issue: https://github.com/Black-Rainbow-Labs/Inillucent/issues`,
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
const suffix = process.platform === 'win32' ? '.exe' : '';
|
|
97
|
+
let path;
|
|
98
|
+
try {
|
|
99
|
+
// The platform package's own entry point tells us where its bin directory
|
|
100
|
+
// is, rather than this package guessing at a node_modules layout - which
|
|
101
|
+
// pnpm, yarn's pnp and a hoisted npm tree all arrange differently.
|
|
102
|
+
path = require.resolve(`${name}/bin/${program}${suffix}`);
|
|
103
|
+
} catch {
|
|
104
|
+
throw new Error(
|
|
105
|
+
`inillucent's binary for ${process.platform}-${process.arch} is not installed.\n` +
|
|
106
|
+
` The package ${name} should have been installed as an optional dependency.\n` +
|
|
107
|
+
` If your installer was run with --no-optional, install it directly:\n` +
|
|
108
|
+
` npm install ${name}\n`,
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
try {
|
|
112
|
+
accessSync(path, constants.X_OK);
|
|
113
|
+
} catch {
|
|
114
|
+
// An npm tarball does not always preserve the executable bit, and the
|
|
115
|
+
// failure it produces otherwise is EACCES from execve with no explanation.
|
|
116
|
+
throw new Error(
|
|
117
|
+
`${path} is not executable.\n Fix it with: chmod +x ${path}\n` +
|
|
118
|
+
` Then please report it: https://github.com/Black-Rainbow-Labs/Inillucent/issues`,
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
return path;
|
|
122
|
+
}
|