@fux-engine/reader 0.0.0-stage → 4.0.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 +109 -2
- package/fux.mjs +0 -0
- package/mcp-tools.json +66 -0
- package/package.json +40 -4
package/README.md
CHANGED
|
@@ -1,3 +1,110 @@
|
|
|
1
|
-
#
|
|
1
|
+
# fux-engine — the Node read plane
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Read a [fux](https://github.com/arpitarya/fux) index from Node. **The command
|
|
4
|
+
is `fux`; the package is `fux-engine`** — `fux` was taken on npm in 2016.
|
|
5
|
+
|
|
6
|
+
> **This file ships twice**, on purpose: it is the npm package's page, and
|
|
7
|
+
> `fux setup` vendors it into your repository at `.fux/node/README.md`. So it is
|
|
8
|
+
> written for whoever finds it, in either place.
|
|
9
|
+
|
|
10
|
+
## Run it
|
|
11
|
+
|
|
12
|
+
**In a repository that has a fux index, always through the shim:**
|
|
13
|
+
|
|
14
|
+
```console
|
|
15
|
+
$ .fux/fux find rollback
|
|
16
|
+
$ .fux/fux ask "how do we roll back a release" --band
|
|
17
|
+
$ .fux/fux answer "retry policy" --json
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
🔴 **`.fux/fux` is the one entry point that is correct in every shape**, which
|
|
21
|
+
is why it is the only one documented. It resolves the reader in three rungs —
|
|
22
|
+
the vendored bundle, then `.fux/node/node_modules/.bin/fux`, then every
|
|
23
|
+
ancestor's `node_modules/.bin/fux` — because npm and Yarn hoist that binary to
|
|
24
|
+
the workspace root and **pnpm and bun do not**. Naming a path instead would be
|
|
25
|
+
right for half the ecosystem and silently wrong for the other half.
|
|
26
|
+
|
|
27
|
+
**Without a repository, or to try it:**
|
|
28
|
+
|
|
29
|
+
```console
|
|
30
|
+
$ npx fux-engine --version
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
**As a library:**
|
|
34
|
+
|
|
35
|
+
```js
|
|
36
|
+
import { open } from 'fux-engine'
|
|
37
|
+
const ix = await open('.')
|
|
38
|
+
await ix.find('rollback', { top: 5 })
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## What is in `.fux/node/`
|
|
42
|
+
|
|
43
|
+
`fux setup` writes one of two shapes, and it detects which:
|
|
44
|
+
|
|
45
|
+
| | what is there | offline | how it runs |
|
|
46
|
+
|---|---|---|---|
|
|
47
|
+
| **the default** | `fux.mjs` (one generated file) · `package.json` · `mcp-tools.json` · this file | **yes** — nothing to install | `.fux/fux …` |
|
|
48
|
+
| **a monorepo** | `package.json` only, declaring `fux-engine@<version>` | after an install | `.fux/fux …`, once your package manager has run |
|
|
49
|
+
|
|
50
|
+
In the monorepo shape `.fux/node` is declared as a **workspace member** in your
|
|
51
|
+
root manifest — `fux setup` adds that one line, says so, and never adds it
|
|
52
|
+
twice. Run your package manager's `install` afterwards; `fux doctor` tells you
|
|
53
|
+
if you have not.
|
|
54
|
+
|
|
55
|
+
🔴 **`fux.mjs` is GENERATED. Do not edit it.** It is rebuilt from fux's sources
|
|
56
|
+
at publish time and overwritten whenever the engine version changes. To see what
|
|
57
|
+
it does, read `node/fux.mjs` and `node/src/**` in the fux repository at the
|
|
58
|
+
matching tag — or regenerate it and compare bytes:
|
|
59
|
+
|
|
60
|
+
```console
|
|
61
|
+
$ python -m fux.store.nodebundle node node/dist
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## What it is
|
|
65
|
+
|
|
66
|
+
A fux index is a small, plain-text index committed to git — statistics about
|
|
67
|
+
your documents, never the documents. Python writes it; **Python or Node reads
|
|
68
|
+
it, and the two are held byte-equal by a differential law.**
|
|
69
|
+
|
|
70
|
+
- **Zero dependencies, and no build step *for you*.** There is no
|
|
71
|
+
`dependencies` key in the published `package.json` at all. Fux's own release
|
|
72
|
+
pipeline has a bundler; nobody running `fux setup` does, and nothing is
|
|
73
|
+
compiled on your machine.
|
|
74
|
+
- **One artefact, not a module tree.** What lands in your repository is one
|
|
75
|
+
generated file, so a fux upgrade is a one-file diff and a tampered reader is
|
|
76
|
+
detectable by rebuilding it. Before 2026-09-12 it was 47 of fux's own `.mjs`
|
|
77
|
+
files in your tree; `fux setup` deletes them when it upgrades you.
|
|
78
|
+
- **It never fetches, and it writes one thing: the derived plane.** `fux
|
|
79
|
+
build` rebuilds the gitignored `.fux/runtime/` from the committed index,
|
|
80
|
+
byte-identical to Python's build, under the same write lock, and `--fast`
|
|
81
|
+
then answers from it. `ingest`, `add`, `enrich` and every other write verb
|
|
82
|
+
belongs to Python fux, and typing one here tells you so rather than saying
|
|
83
|
+
*unknown command*.
|
|
84
|
+
- **Same answers as Python.** Same ids, same order, same locators, same band;
|
|
85
|
+
scores equal after `round(9)`, which is the sort key's own resolution.
|
|
86
|
+
- **Two things it deliberately does not do.** It cannot read a document that
|
|
87
|
+
needs a decoder (a `.pdf`, a `.xlsx`, your own `.fux/decoders/*.py`), so
|
|
88
|
+
`answer` **declines** to cite one rather than quoting line numbers into text
|
|
89
|
+
the index never held; and it never touches the network.
|
|
90
|
+
|
|
91
|
+
## Two `fux` commands on one PATH
|
|
92
|
+
|
|
93
|
+
Python's `fux-engine` installs a `fux` too, with a **different verb set**.
|
|
94
|
+
`--version` names the runtime, so no bug report is ever ambiguous:
|
|
95
|
+
|
|
96
|
+
```console
|
|
97
|
+
$ fux --version
|
|
98
|
+
fux 2.0.0 (node 24.13.0)
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
`fux doctor` (Python's) reports when a Node `fux` sits earlier on your PATH.
|
|
102
|
+
|
|
103
|
+
## Verbs
|
|
104
|
+
|
|
105
|
+
`find` · `ask` · `answer` · `explain` · `graph` · `path` · `mcp`
|
|
106
|
+
|
|
107
|
+
`fux mcp` serves the index over the Model Context Protocol on stdio —
|
|
108
|
+
`fux_search`, `fux_passage`, `fux_related` — so an agent can query it with no
|
|
109
|
+
glue. `verify`, `--why`, `--receipt` and `--journal` have no Node twin; they are
|
|
110
|
+
Python's.
|
package/fux.mjs
ADDED
|
Binary file
|
package/mcp-tools.json
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
{
|
|
2
|
+
"_comment": "The MCP tool descriptions, the authored text for node/src/verbs/mcp.mjs, held equal to src/fux/mcp.py's literal by tests/test_mcp.py. A description is what an agent reads to decide whether to call a tool, so two hand-maintained copies would drift into two products wearing one name. {{TOP}} is substituted with the connection's resolved [mcp] top.",
|
|
3
|
+
"tools": [
|
|
4
|
+
{
|
|
5
|
+
"name": "fux_search",
|
|
6
|
+
"description": "Search the committed index for documents relevant to a natural-language question. Returns ranked documents with content hashes and the headings that match your query -- section-level, not line-level; call fux_passage for the lines. This is the call to make first for any 'where is X' or 'why did we decide Y' question about this repository. READ THE `confidence` BLOCK BEFORE USING THE RESULTS. If `confidence.answerable` is false, do not answer from these results at all -- say what was searched and stop. If `confidence.band` is 'partial', answer but name every term in `confidence.missing`: those are words from the question that appear in no document here. If it is 'weak', the ranking could not separate the top hits -- that is a SIGNAL and not a refusal (`answerable` stays true): read the near-tied candidates and judge, and if neither answers, say the documents do not say and report what was searched rather than a conclusion. The payload also carries `related`: documents that NO query word matched, returned because the ranked results above LINK to them, each with the `route` it was reached by. They are not matches and must never be cited as one -- read a related document with fux_passage before you use it, and say that you followed a link to it rather than found it.",
|
|
7
|
+
"inputSchema": {
|
|
8
|
+
"type": "object",
|
|
9
|
+
"properties": {
|
|
10
|
+
"query": {
|
|
11
|
+
"type": "string",
|
|
12
|
+
"description": "A natural-language question."
|
|
13
|
+
},
|
|
14
|
+
"k": {
|
|
15
|
+
"type": "integer",
|
|
16
|
+
"description": "Maximum results (default {{TOP}}; this repository's .fux/output.toml may set a different default under [mcp]).",
|
|
17
|
+
"default": "{{TOP}}"
|
|
18
|
+
},
|
|
19
|
+
"expand": {
|
|
20
|
+
"type": "string",
|
|
21
|
+
"description": "OPTIONAL. Words you expect the document to use, when they differ from the question's. Scored at a lower weight than the question's own terms, and a document matching ONLY these is never returned. Use it after a search comes back `partial` with a non-empty `missing`: re-search with the vocabulary the corpus would use for the missing term."
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"required": [
|
|
25
|
+
"query"
|
|
26
|
+
]
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"name": "fux_passage",
|
|
31
|
+
"description": "Read the verbatim text of a cited span, addressed as returned by fux_search. Use this instead of reading a whole file when you already have a citation: it returns only the cited lines and the hash they were read at, as `path`, `line_start`, `line_end`, `sha` and `text`.",
|
|
32
|
+
"inputSchema": {
|
|
33
|
+
"type": "object",
|
|
34
|
+
"properties": {
|
|
35
|
+
"path": {
|
|
36
|
+
"type": "string"
|
|
37
|
+
},
|
|
38
|
+
"line_start": {
|
|
39
|
+
"type": "integer"
|
|
40
|
+
},
|
|
41
|
+
"line_end": {
|
|
42
|
+
"type": "integer"
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
"required": [
|
|
46
|
+
"path"
|
|
47
|
+
]
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
"name": "fux_related",
|
|
52
|
+
"description": "The neighbourhood around a document: what it links to, what links to it, what it supersedes or is superseded by, and whether it is archived. Use when a result raises 'what else was decided with this?' It returns `path`, `title`, `archived`, `superseded`, `outbound` and `inbound`.",
|
|
53
|
+
"inputSchema": {
|
|
54
|
+
"type": "object",
|
|
55
|
+
"properties": {
|
|
56
|
+
"path": {
|
|
57
|
+
"type": "string"
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
"required": [
|
|
61
|
+
"path"
|
|
62
|
+
]
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
]
|
|
66
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,42 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fux-engine/reader",
|
|
3
|
-
"version": "
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "4.0.1",
|
|
4
|
+
"description": "Read a fux index from Node. Ranked, cited answers from a small index committed to git — no server, no model, no Python.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"engines": {
|
|
7
|
+
"node": ">=22"
|
|
8
|
+
},
|
|
9
|
+
"bin": {
|
|
10
|
+
"fux": "./fux.mjs"
|
|
11
|
+
},
|
|
12
|
+
"exports": {
|
|
13
|
+
".": "./fux.mjs"
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"fux.mjs",
|
|
17
|
+
"mcp-tools.json",
|
|
18
|
+
"README.md"
|
|
19
|
+
],
|
|
20
|
+
"license": "MIT",
|
|
21
|
+
"repository": {
|
|
22
|
+
"type": "git",
|
|
23
|
+
"url": "git+https://github.com/arpitarya/fux.git"
|
|
24
|
+
},
|
|
25
|
+
"homepage": "https://github.com/arpitarya/fux#readme",
|
|
26
|
+
"bugs": {
|
|
27
|
+
"url": "https://github.com/arpitarya/fux/issues"
|
|
28
|
+
},
|
|
29
|
+
"keywords": [
|
|
30
|
+
"knowledge",
|
|
31
|
+
"documentation",
|
|
32
|
+
"search",
|
|
33
|
+
"index",
|
|
34
|
+
"bm25",
|
|
35
|
+
"adr",
|
|
36
|
+
"runbook"
|
|
37
|
+
],
|
|
38
|
+
"publishConfig": {
|
|
39
|
+
"access": "public",
|
|
40
|
+
"tag": "alpha"
|
|
41
|
+
}
|
|
42
|
+
}
|