dsh-gitnexus-plus 0.1.2 → 0.1.4
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-CN.md +189 -0
- package/README.md +219 -597
- package/lib/bin/graph-helper.d.ts +21 -0
- package/lib/bin/graph-helper.d.ts.map +1 -0
- package/lib/bin/graph-helper.js +71 -0
- package/lib/bin/graph-helper.js.map +1 -0
- package/lib/client.js +4107 -2029
- package/lib/gitnexus/analyze.d.ts +48 -8
- package/lib/gitnexus/analyze.d.ts.map +1 -1
- package/lib/gitnexus/analyze.js +376 -75
- package/lib/gitnexus/analyze.js.map +1 -1
- package/lib/gitnexus/commands.d.ts +8 -1
- package/lib/gitnexus/commands.d.ts.map +1 -1
- package/lib/gitnexus/commands.js +19 -0
- package/lib/gitnexus/commands.js.map +1 -1
- package/lib/gitnexus/coverage.d.ts +16 -0
- package/lib/gitnexus/coverage.d.ts.map +1 -1
- package/lib/gitnexus/coverage.js +58 -1
- package/lib/gitnexus/coverage.js.map +1 -1
- package/lib/gitnexus/delta.d.ts +144 -0
- package/lib/gitnexus/delta.d.ts.map +1 -0
- package/lib/gitnexus/delta.js +347 -0
- package/lib/gitnexus/delta.js.map +1 -0
- package/lib/gitnexus/git-activity.d.ts +77 -0
- package/lib/gitnexus/git-activity.d.ts.map +1 -1
- package/lib/gitnexus/git-activity.js +327 -8
- package/lib/gitnexus/git-activity.js.map +1 -1
- package/lib/gitnexus/graph.d.ts +126 -0
- package/lib/gitnexus/graph.d.ts.map +1 -0
- package/lib/gitnexus/graph.js +472 -0
- package/lib/gitnexus/graph.js.map +1 -0
- package/lib/gitnexus/root.d.ts +0 -3
- package/lib/gitnexus/root.d.ts.map +1 -1
- package/lib/gitnexus/root.js +64 -5
- package/lib/gitnexus/root.js.map +1 -1
- package/lib/gitnexus/scan.d.ts +2 -0
- package/lib/gitnexus/scan.d.ts.map +1 -1
- package/lib/gitnexus/scan.js +3 -2
- package/lib/gitnexus/scan.js.map +1 -1
- package/lib/gitnexus/search.d.ts +21 -8
- package/lib/gitnexus/search.d.ts.map +1 -1
- package/lib/gitnexus/search.js +87 -13
- package/lib/gitnexus/search.js.map +1 -1
- package/lib/index.d.ts +6 -0
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +170 -2
- package/lib/index.js.map +1 -1
- package/lib/routes/analyze.d.ts +3 -2
- package/lib/routes/analyze.d.ts.map +1 -1
- package/lib/routes/analyze.js +8 -2
- package/lib/routes/analyze.js.map +1 -1
- package/lib/routes/coverage.d.ts +2 -1
- package/lib/routes/coverage.d.ts.map +1 -1
- package/lib/routes/coverage.js +53 -1
- package/lib/routes/coverage.js.map +1 -1
- package/lib/routes/delta.d.ts +22 -0
- package/lib/routes/delta.d.ts.map +1 -0
- package/lib/routes/delta.js +50 -0
- package/lib/routes/delta.js.map +1 -0
- package/lib/routes/file-diff.d.ts +19 -0
- package/lib/routes/file-diff.d.ts.map +1 -0
- package/lib/routes/file-diff.js +69 -0
- package/lib/routes/file-diff.js.map +1 -0
- package/lib/routes/file-history.d.ts +21 -0
- package/lib/routes/file-history.d.ts.map +1 -0
- package/lib/routes/file-history.js +69 -0
- package/lib/routes/file-history.js.map +1 -0
- package/lib/routes/graph.d.ts +22 -0
- package/lib/routes/graph.d.ts.map +1 -0
- package/lib/routes/graph.js +71 -0
- package/lib/routes/graph.js.map +1 -0
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -1,632 +1,254 @@
|
|
|
1
1
|
# dsh-gitnexus-plus
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
**English** · [简体中文](README-CN.md)
|
|
4
|
+
|
|
5
|
+
**Current release: [0.1.4](https://github.com/Moowningstar/gitnexus-plus/releases/tag/v0.1.4)** ·
|
|
6
|
+
[npm](https://www.npmjs.com/package/dsh-gitnexus-plus) ·
|
|
7
|
+
[Issues](https://github.com/Moowningstar/gitnexus-plus/issues)
|
|
8
|
+
|
|
9
|
+
[What it does](#what-it-does) · [Install](#install) · [Troubleshooting](#troubleshooting) ·
|
|
10
|
+
[Upstream GitNexus docs](#upstream-gitnexus-documentation)
|
|
11
|
+
|
|
12
|
+
A DeepSeek Harness plugin: see what a GitNexus index **covers and what it leaves out**,
|
|
13
|
+
decide whether a refresh is worth running, browse the graph, refresh it from the sidebar,
|
|
14
|
+
and search its symbols by keyword.
|
|
15
|
+
|
|
16
|
+
It does not fork GitNexus, rewrite its parser, or bundle/redistribute it. `gitnexus` is a
|
|
17
|
+
**peer**; you provide it.
|
|
18
|
+
|
|
19
|
+
## What it does
|
|
20
|
+
|
|
21
|
+
- **Refresh gate (Tier 0)** — before offering a refresh, the panel compares the working
|
|
22
|
+
tree with the sha256 hashes the index recorded in `.gitnexus/gitnexus.json` and reports
|
|
23
|
+
what actually differs: modified / added / deleted, plus files the index's own policy
|
|
24
|
+
excludes. A clean tree answers in milliseconds without starting the analyzer, and the
|
|
25
|
+
button says so instead of running a minutes-long rebuild. The verdict is only called
|
|
26
|
+
"up to date" when it is anchored to the commit the index recorded; an index that
|
|
27
|
+
recorded none falls back to comparing the working tree with `HEAD` and says it cannot
|
|
28
|
+
confirm instead of claiming freshness.
|
|
29
|
+
- **Graph view** — the index's communities drawn on a canvas, with aggregated
|
|
30
|
+
cross-community edges; click a community to see its member symbols and the relations
|
|
31
|
+
among them, click a symbol to open its file at the line. Node and edge budgets are
|
|
32
|
+
applied by the host, and the view states what it left out.
|
|
33
|
+
- **Index coverage** — lists the oversized files `gitnexus analyze` skipped, with size,
|
|
34
|
+
language share, and generated/minified signals.
|
|
35
|
+
- **Index freshness** — indexed commit vs `HEAD`, classified `current` / `behind` /
|
|
36
|
+
`diverged` / `unknown`, plus the uncommitted-change count.
|
|
37
|
+
- **Graph composition** — nodes, edges, communities, processes, embeddings, edges per node.
|
|
38
|
+
- **Git activity × index** — recent commits, authors, branches and most-changed files,
|
|
39
|
+
each file marked **indexed**, **excluded by design**, or **missing from the index**.
|
|
40
|
+
Includes an activity × index cross-tab, a baseline review against the indexed commit
|
|
41
|
+
(or the activity-window start when the index recorded none), a 7/14/30-day commit
|
|
42
|
+
timeline, and a per-file timeline when a file row is clicked.
|
|
43
|
+
- **Language distribution** — bytes split into languages GitNexus can parse, formats it
|
|
44
|
+
only recognizes, and everything else. Without GitNexus, a built-in extension map keeps
|
|
45
|
+
the breakdown useful and marks it `builtin`, never "parsed".
|
|
46
|
+
- **Keyword search** — matches graph node `name` / `filePath`, returns kind, path and line;
|
|
47
|
+
clicking a hit opens the file at that line, and a separate Copy button copies
|
|
48
|
+
`path:line`.
|
|
49
|
+
- **Source fallback** — when the graph helper cannot start (no usable shell sandbox,
|
|
50
|
+
DLL/ABI, busy index), a bounded line search over the indexed files returns
|
|
51
|
+
`mode: "text"` instead of pretending to be the graph.
|
|
52
|
+
- **No-index visibility** — a git project without an index shows a scan overview,
|
|
53
|
+
language split and the initialize command instead of an empty panel.
|
|
54
|
+
- **Maintenance** — initialize, incremental refresh and full rebuild (`--force`) run
|
|
55
|
+
through DSH's shell executor, with no self-escalation. When the index reports FTS as
|
|
56
|
+
unavailable, a **修复搜索索引(FTS)** action runs `analyze --repair-fts` — the search
|
|
57
|
+
indexes only, without re-analysing the repository.
|
|
58
|
+
|
|
59
|
+
## Install
|
|
60
|
+
|
|
61
|
+
Requirements:
|
|
62
|
+
|
|
63
|
+
- DSH `>=0.2.0-rc.2 <0.3.0`
|
|
64
|
+
- Node `>=22`
|
|
65
|
+
- GitNexus `>=1.6.0 <2.0.0` (peer; not installed by this plugin)
|
|
5
66
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
`gitnexus analyze` silently drops files. Its entire surface for saying so is one
|
|
9
|
-
line on stderr, printed once:
|
|
10
|
-
|
|
11
|
-
```
|
|
12
|
-
Skipped 3 large files (>512KB, likely generated/vendored)
|
|
13
|
-
- dist/app.min.js
|
|
14
|
-
...and 2 more (set GITNEXUS_VERBOSE=1 to list them all)
|
|
67
|
+
```sh
|
|
68
|
+
dsh plugin add dsh-gitnexus-plus
|
|
15
69
|
```
|
|
16
70
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
represents your codebase and one that does not — measured on this machine,
|
|
20
|
-
`material-ui` skips 4.4 MB (12.4 % of scanned bytes), and those files contribute
|
|
21
|
-
**zero** symbols to the graph.
|
|
22
|
-
|
|
23
|
-
This plugin turns that line into data, a tool, and a route.
|
|
24
|
-
|
|
25
|
-
## What this project is, and what it is not
|
|
26
|
-
|
|
27
|
-
[GitNexus](https://github.com/abhigyanpatwari/GitNexus) is a code-intelligence engine by
|
|
28
|
-
**Abhigyan Patwari**. It parses a repository into symbols, relationships and execution
|
|
29
|
-
flows and writes them to a local graph database. It is a genuinely good piece of work,
|
|
30
|
-
and this project would have nothing to show without it.
|
|
31
|
-
|
|
32
|
-
What GitNexus does not give an everyday user is **visibility** and **automation**:
|
|
33
|
-
|
|
34
|
-
- **Visibility** — how much of the repository does the index actually cover? Which files
|
|
35
|
-
were skipped for being too large? Has the index fallen behind `HEAD`, and by how much?
|
|
36
|
-
The CLI does not answer those unasked, and the answer is invisible exactly when it
|
|
37
|
-
matters.
|
|
38
|
-
- **Automation** — once an index is stale, somebody has to remember to refresh it.
|
|
39
|
-
|
|
40
|
-
**This project is a layer that adds those two things and nothing else.** It reads the
|
|
41
|
-
index GitNexus wrote, reports what the index left out, and can start an incremental
|
|
42
|
-
refresh through GitNexus's own CLI.
|
|
43
|
-
|
|
44
|
-
It does **not**:
|
|
45
|
-
|
|
46
|
-
- fork GitNexus, patch it, or reimplement its parser or graph database;
|
|
47
|
-
- redistribute GitNexus source. Nothing from that project is inside this package's
|
|
48
|
-
tarball. `gitnexus` is declared as a **peer**, not a dependency, so installing this
|
|
49
|
-
plugin installs nothing from it — the operator supplies GitNexus, by whatever means,
|
|
50
|
-
and the two stay separate;
|
|
51
|
-
- claim authorship of, or any contribution to, GitNexus. All rights in GitNexus belong
|
|
52
|
-
to its author;
|
|
53
|
-
- replace GitNexus. With no GitNexus index there is no graph to display — only a
|
|
54
|
-
working-tree scan (file counts, bytes, languages), which is useful but is not a
|
|
55
|
-
substitute for the graph.
|
|
56
|
-
|
|
57
|
-
## Licence — read this before a commercial use
|
|
58
|
-
|
|
59
|
-
This project is **MIT** (see [LICENSE](LICENSE)).
|
|
60
|
-
|
|
61
|
-
**It depends on GitNexus, which is `PolyForm-Noncommercial-1.0.0`.** That licence grants
|
|
62
|
-
noncommercial use and restricts commercial use. GitNexus is **not** a dependency of this
|
|
63
|
-
package — it is a peer, so installing this plugin does not install it, and the plugin
|
|
64
|
-
never bundles or redistributes it. Installing this plugin's package therefore installs
|
|
65
|
-
nothing under that licence. But every GitNexus-backed feature — reading an index,
|
|
66
|
-
refreshing one, installing one on request — puts your use of *GitNexus* under
|
|
67
|
-
*GitNexus's* licence:
|
|
68
|
-
|
|
69
|
-
- **your use of this plugin's GitNexus-backed features is subject to GitNexus's
|
|
70
|
-
licence**, not to this project's MIT grant;
|
|
71
|
-
- **commercial use requires a separate grant from GitNexus's author.** If your use is
|
|
72
|
-
commercial, read
|
|
73
|
-
<https://github.com/abhigyanpatwari/GitNexus/blob/main/LICENSE> or contact the author
|
|
74
|
-
before relying on any of it.
|
|
75
|
-
|
|
76
|
-
This project cannot and does not change that: it only calls the interfaces GitNexus
|
|
77
|
-
provides. The read-only half — reading `.gitnexus/gitnexus.json` and reporting on it —
|
|
78
|
-
is this project's own code and carries no GitNexus code, but it also has nothing to
|
|
79
|
-
report on unless GitNexus produced that file.
|
|
80
|
-
|
|
81
|
-
A one-line summary: **the MIT licence here covers my code; GitNexus's licence covers
|
|
82
|
-
GitNexus, and installing this plugin installs GitNexus.**
|
|
83
|
-
|
|
84
|
-
## What it reports
|
|
85
|
-
|
|
86
|
-
- **Skipped large files** — path, size, share of its language, and two independent
|
|
87
|
-
signals for *why* it is not source: a single-line (minified) heuristic, and a
|
|
88
|
-
build-output path heuristic. Binary assets are detected separately and never
|
|
89
|
-
called minified.
|
|
90
|
-
- **Index freshness** — the indexed commit against HEAD, classified `current` /
|
|
91
|
-
`behind` / `diverged` / `unknown` the same way `gitnexus status` does, plus the
|
|
92
|
-
uncommitted-change count.
|
|
93
|
-
- **Graph composition** — nodes, edges, communities, processes, embeddings, and
|
|
94
|
-
edges-per-node, all read from the manifest.
|
|
95
|
-
- **Query surfaces** — which of graph / keyword search / semantic search are
|
|
96
|
-
actually available, with the reason when one is not. An index with no FTS cannot
|
|
97
|
-
answer keyword queries, and hiding that is how a reader concludes otherwise.
|
|
98
|
-
- **Git activity, crossed with the index** — recent commits, authors (bots marked),
|
|
99
|
-
branches, most-changed files and most-recent files, each carrying a three-way
|
|
100
|
-
verdict: *indexed*, *excluded by design*, or **missing from the index**. That last
|
|
101
|
-
one is the point: of the files people are actively editing, which does the graph
|
|
102
|
-
not see?
|
|
103
|
-
- **Language distribution by bytes**, split three ways: languages GitNexus can
|
|
104
|
-
*parse* into the graph, formats it merely *recognizes*, and everything else. When
|
|
105
|
-
GitNexus is absent, a built-in extension map keeps the breakdown useful; those
|
|
106
|
-
rows are marked `detector: "builtin"` and are never presented as *parsed*.
|
|
107
|
-
- **Resolver confidence** — untyped receiver sites, which make `impact` and
|
|
108
|
-
`context` a lower bound rather than an exact answer.
|
|
109
|
-
- **A scan-only report when there is no index** — file count, selected count, bytes
|
|
110
|
-
and language split are readable from the working tree alone. The panel shows them
|
|
111
|
-
under "尚未索引" instead of an empty state, and the initialize command sits beside
|
|
112
|
-
them.
|
|
113
|
-
- **Keyword search with click-to-open** — the panel's search box asks the graph for
|
|
114
|
-
nodes whose `name` or `filePath` contains the query, and returns the graph node
|
|
115
|
-
kind, name, path and line. **Clicking a hit opens that file in the platform's file
|
|
116
|
-
viewer at that line** through `ctx.sidebarRight.openResource` and a
|
|
117
|
-
`dsh-resource://file/session/...` address; a separate 复制 button copies
|
|
118
|
-
`path:line`. When the graph helper cannot start, the bounded source-text fallback
|
|
119
|
-
is used instead and the card is labelled 源码关键词(回退).
|
|
120
|
-
|
|
121
|
-
## Why the git three-way split matters
|
|
122
|
-
|
|
123
|
-
A two-way "indexed / not indexed" count is misleading. Measured on a real
|
|
124
|
-
repository, 1 635 files had been touched in 90 days: 491 indexed, 1 143 absent, and
|
|
125
|
-
reporting that as "70 % missing" is wrong — 1 143 of them are lockfiles, dotfiles
|
|
126
|
-
and binary assets that no scan would select either. Exactly **one** was a genuine
|
|
127
|
-
gap (`src/stores/windowModeStore.ts`). The panel reports the three numbers
|
|
128
|
-
separately, and only the third raises a warning.
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
## Design commitments
|
|
132
|
-
|
|
133
|
-
**Reuse, don't reimplement.** "Which files did GitNexus skip?" has exactly one
|
|
134
|
-
correct answer: the set `walkRepositoryPaths` produced. This plugin deep-imports
|
|
135
|
-
GitNexus's own `createIgnoreFilter`, `glob` call and `getLanguageFromFilename`
|
|
136
|
-
rather than approximating them, and `test/run.mjs` cross-checks its scan against
|
|
137
|
-
`walkRepositoryPaths` on real repositories. If upstream reshapes those modules the
|
|
138
|
-
plugin degrades to a documented fallback scan (`ScanReport.primitives === 'fallback'`)
|
|
139
|
-
instead of reporting a wrong number.
|
|
140
|
-
|
|
141
|
-
**Absent is reported as absent.** The size cap an index was built under is read from
|
|
142
|
-
that index. Legacy indexes (`meta.json`, no `indexCoverage`) are reported with the
|
|
143
|
-
cap *unknown* and a note — never defaulted to today's value, which would misattribute
|
|
144
|
-
covered files as skipped.
|
|
145
|
-
|
|
146
|
-
**Read-only.** Nothing here triggers `analyze`, writes to `.gitnexus/`, or takes the
|
|
147
|
-
index lock. A status check must never start a 30-second rebuild.
|
|
148
|
-
|
|
149
|
-
## Getting GitNexus — the prerequisite, and the two ways to satisfy it
|
|
150
|
-
|
|
151
|
-
This plugin reads an index. **Only GitNexus produces one.** So the plugin checks
|
|
152
|
-
whether GitNexus is present, and when it is not, the panel says so above everything else
|
|
153
|
-
rather than letting you wonder why the numbers are missing.
|
|
154
|
-
|
|
155
|
-
Two ways out, in the order the panel offers them:
|
|
156
|
-
|
|
157
|
-
**① Install it yourself.** The panel shows a copyable `npm install -g gitnexus`, and
|
|
158
|
-
that is the recommendation. You know your network, your registry and your toolchain; a
|
|
159
|
-
command you can run is more useful than a download this plugin performs on your behalf,
|
|
160
|
-
and it works behind whatever mirror or feed your machine actually reaches.
|
|
161
|
-
|
|
162
|
-
**② Let the plugin install it.** Second in the list and behind a confirmation, because
|
|
163
|
-
it is a much larger decision. It runs, through the host's shell executor:
|
|
71
|
+
Restart DSH after adding it. The panel is a right-sidebar tab: open the sidebar's **+**
|
|
72
|
+
→ guide page → **GitNexus 索引**.
|
|
164
73
|
|
|
165
|
-
|
|
166
|
-
|
|
74
|
+
The `desktop` profile is managed by Electron; the CLI cannot change it. Use the Web
|
|
75
|
+
sidebar's Plugins page there. From a local checkout:
|
|
76
|
+
|
|
77
|
+
```sh
|
|
78
|
+
dsh plugin --profile web add <absolute path to this package>
|
|
167
79
|
```
|
|
168
80
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
- **about 500 MB to 1 GB** downloaded, from whatever registry your `.npmrc` already
|
|
172
|
-
names — this plugin hardcodes none, because a hardcoded one breaks exactly the users
|
|
173
|
-
whose network is why they need this path;
|
|
174
|
-
- **several minutes**, longer on a slow link or when the native modules have to compile;
|
|
175
|
-
- **this machine's build toolchain is used** — `@ladybugdb/core`, `tree-sitter` and
|
|
176
|
-
`tree-sitter-*` compile on install. That is why this is `npm` and not `pnpm`: pnpm 10+
|
|
177
|
-
refuses dependency build scripts by default, and the failure it produces is one you
|
|
178
|
-
cannot act on. GitNexus's own message names the grants it needs:
|
|
179
|
-
`--allow-build=@ladybugdb/core --allow-build=gitnexus --allow-build=tree-sitter`;
|
|
180
|
-
- it installs into a **plugin-owned directory**, never your global prefix, so it needs no
|
|
181
|
-
elevation and cannot collide with a GitNexus you already have.
|
|
182
|
-
|
|
183
|
-
Everything runs through `ctx.shell`, so a sandboxed deployment confines it exactly as it
|
|
184
|
-
confines your own commands. **A refusal is reported as a refusal and never retried
|
|
185
|
-
wider** — the plugin never asks for more scope than the session already granted.
|
|
186
|
-
|
|
187
|
-
**The installed copy is the one every later step uses.** The install prefix is resolved
|
|
188
|
-
once and passed to all three consumers: the coverage engine's own scan primitives, the
|
|
189
|
-
language detector, and the `analyze` runner. This wiring was missing in 0.1.1 — the
|
|
190
|
-
installer wrote a plugin-owned tree, while the reader and runner probed only PATH and
|
|
191
|
-
the declared dependency, so the install succeeded and *nothing used it*. A machine with
|
|
192
|
-
no global GitNexus still reported "absent" after a successful install.
|
|
193
|
-
|
|
194
|
-
**Install → initialize is one authorised step.** If the current project has no index,
|
|
195
|
-
a successful install continues with a single `gitnexus analyze --index-only` for that
|
|
196
|
-
project, so the operator gets from "no GitNexus" to a visible index without a second
|
|
197
|
-
click. The install confirmation says this before anything starts. The chain is gated on
|
|
198
|
-
the install having been started from this panel and on the project still having no
|
|
199
|
-
index; it never silently refreshes an index that already exists.
|
|
200
|
-
|
|
201
|
-
If your GitNexus lives somewhere unusual, name it directly and none of this applies:
|
|
81
|
+
GitNexus can be installed by you or by the panel. For a custom location:
|
|
202
82
|
|
|
203
83
|
```sh
|
|
204
84
|
GITNEXUS_CLI=/path/to/gitnexus/dist/cli/index.js
|
|
205
85
|
```
|
|
206
86
|
|
|
207
|
-
|
|
208
|
-
put a copy anywhere, point at it, done.
|
|
87
|
+
### Getting GitNexus
|
|
209
88
|
|
|
210
|
-
|
|
89
|
+
Installing it yourself is recommended:
|
|
211
90
|
|
|
212
91
|
```sh
|
|
213
|
-
|
|
214
|
-
npm run build # tsc (host) + tsc (client) + wrap
|
|
215
|
-
node lib/bin/gitnexus-coverage.js <repo-path>
|
|
216
|
-
node lib/bin/gitnexus-coverage.js -r material-ui # by registry alias
|
|
217
|
-
node lib/bin/gitnexus-coverage.js --all --json # every indexed repository
|
|
218
|
-
node lib/bin/gitnexus-coverage.js <repo> --fail-on-large # exit 2 — CI gate
|
|
219
|
-
|
|
220
|
-
# type check
|
|
221
|
-
npm run check
|
|
222
|
-
|
|
223
|
-
# tests
|
|
224
|
-
npm test
|
|
92
|
+
npm install -g gitnexus
|
|
225
93
|
```
|
|
226
94
|
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
- **tool** `gitnexus_coverage` — `{ repo, includeLanguages? }`
|
|
230
|
-
- **route** `GET /api/gitnexus/coverage?repo=<project>` — one report, plus the
|
|
231
|
-
maintenance commands for that project
|
|
232
|
-
- **route** `GET /api/gitnexus/search?repo=<project>&q=<keyword>&limit=20` —
|
|
233
|
-
read-only keyword search over the graph's symbol names and file paths
|
|
234
|
-
- **panel** — a right-sidebar tab type `gitnexus`, opened from the sidebar's **+** →
|
|
235
|
-
guide page ("GitNexus 索引")
|
|
236
|
-
|
|
237
|
-
The coverage route is read-only. Its bound is a **project root** — a directory with a
|
|
238
|
-
`.gitnexus` index or a `.git` marker — so it cannot be turned into a filesystem probe.
|
|
239
|
-
An index is no longer required: a git project without one gets the engine's scan-only
|
|
240
|
-
report, which is what makes "no index yet" informative. It is additionally restricted
|
|
241
|
-
to loopback peers because a third-party DSH route is unauthenticated by default on a
|
|
242
|
-
bare `dsh web` profile.
|
|
243
|
-
|
|
244
|
-
There is now a **second** route, `/api/gitnexus/analyze`, and it is the only one that
|
|
245
|
-
can change anything. It answers `POST` to start an incremental refresh (`?force=1`
|
|
246
|
-
selects a full rebuild), `GET` to report where that got to, and `DELETE` to stop it. It is a separate module from the coverage
|
|
247
|
-
route so the read-only half keeps a method policy that cannot mutate — the shared guard
|
|
248
|
-
takes the accepted methods from the route rather than hard-coding one set for both. The
|
|
249
|
-
mutating verbs additionally pass the write guard, which refuses cross-origin requests;
|
|
250
|
-
loopback alone is not enough, because any page the operator visits can reach
|
|
251
|
-
`127.0.0.1`. See **Maintenance** below for what it will and will not do.
|
|
252
|
-
|
|
253
|
-
A **third** route, `/api/gitnexus/search`, is read-only like coverage but queries the
|
|
254
|
-
LadybugDB graph instead of the manifest. It opens the database read-only and searches
|
|
255
|
-
node names and file paths; it does **not** use FTS, which is why it works on an index
|
|
256
|
-
built with `--skip-fts` and on a machine where the FTS extension fails to load. The
|
|
257
|
-
response carries the node kind, name, path and line, plus an honest warning when
|
|
258
|
-
content-level FTS is unavailable.
|
|
259
|
-
|
|
260
|
-
**Two tiers, because the host shell can be unavailable.** The normal path is the
|
|
261
|
-
graph query. If the helper cannot start — a Windows sandbox backend that cannot create
|
|
262
|
-
its own temp directory, no shell executor, a busy database — the route falls back to a
|
|
263
|
-
bounded source-text search over the files listed in the index manifest. That fallback
|
|
264
|
-
needs neither a shell nor the native addon; it returns `mode: "text"`, searches code
|
|
265
|
-
files before documentation, caps files/bytes/matches, and says so in `warning` and in
|
|
266
|
-
the panel's card title. A silent swap between "graph" and "source text" would be a
|
|
267
|
-
dishonest answer, so the mode is part of the response.
|
|
268
|
-
|
|
269
|
-
**The graph query runs in a Node helper subprocess, not in the DSH host.** The host runs on
|
|
270
|
-
Electron's Node, and GitNexus's LadybugDB addon is built for the system Node ABI.
|
|
271
|
-
Loading it in-process fails with `A dynamic link library (DLL) initialization routine
|
|
272
|
-
failed ... lbugjs.node`; the same addon loads under the system Node 24 that the CLI
|
|
273
|
-
uses. The host therefore starts:
|
|
95
|
+
The panel can also install it through DSH's shell:
|
|
274
96
|
|
|
275
|
-
```
|
|
276
|
-
|
|
97
|
+
```sh
|
|
98
|
+
npm install --prefix <DSH_HOME>/gitnexus-plus/gitnexus gitnexus@^1.6.12
|
|
277
99
|
```
|
|
278
100
|
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
Consequently the graph path needs a shell executor and `node` on the shell's PATH;
|
|
282
|
-
without them it falls back to source text, not an empty result list.
|
|
283
|
-
|
|
284
|
-
**Clicking a hit opens the file, not a copy.** The row calls
|
|
285
|
-
`ctx.sidebarRight.openResourceIn(sessionId, address, { params: { line } })` (or the
|
|
286
|
-
public `openResource` when the targeted variant is unavailable) with
|
|
287
|
-
`dsh-resource://file/session/<session>/<path>`. That is the same address and line
|
|
288
|
-
parameter the built-in file strip and the chat's file links use, so the platform's
|
|
289
|
-
own file viewer/editor handles the navigation. A separate 复制 button remains for the
|
|
290
|
-
`path:line` text. A profile without a right-sidebar controller falls back to copying
|
|
291
|
-
and says so.
|
|
292
|
-
|
|
293
|
-
## TypeScript, and why the build looks the way it does
|
|
294
|
-
|
|
295
|
-
The source is TypeScript under `strict`, including `noImplicitAny`. That is not
|
|
296
|
-
decoration: an implicit `any` is a **silent** failure — it does not report an error,
|
|
297
|
-
it just makes the checker stop working exactly where it was needed. Migrating this
|
|
298
|
-
codebase from JS+JSDoc to real types surfaced six places where the documentation and
|
|
299
|
-
the code disagreed, none of which produced a runtime error until the affected branch
|
|
300
|
-
was reached:
|
|
301
|
-
|
|
302
|
-
| Where | JSDoc claimed | Actually |
|
|
303
|
-
| --- | --- | --- |
|
|
304
|
-
| `LargeFile.generatedHint` | `string \| null` | `boolean` — consumed as `if (x)` |
|
|
305
|
-
| `LargeFile.minified` | non-null | nullable, when the probe budget runs out |
|
|
306
|
-
| `analyzer.primitives` | `number` | a **string**, compared against `'gitnexus'` |
|
|
307
|
-
| `MinifiedVerdict` | a type name | **the type did not exist** |
|
|
308
|
-
| `activityView()` result | — | missing `truncated`, which callers read |
|
|
309
|
-
| `analyzeCoverage` options | 3 fields | 5 — two were undocumented |
|
|
101
|
+
That downloads roughly 500 MB–1 GB and needs a C++ toolchain; no registry is hardcoded.
|
|
102
|
+
Treat the first install as unverified and fall back to the manual command if it fails.
|
|
310
103
|
|
|
311
|
-
|
|
104
|
+
## Usage
|
|
312
105
|
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
src/routes/*.ts ────────┤
|
|
317
|
-
src/bin/*.ts ───────────┘
|
|
318
|
-
|
|
319
|
-
src/client/index.ts ────→ tsc (CommonJS) → build/client/index.js
|
|
320
|
-
↓ text wrap (scripts/build-client.mjs)
|
|
321
|
-
lib/client.js
|
|
322
|
-
```
|
|
106
|
+
The panel reports the project the current workspace points at; it has no global
|
|
107
|
+
repository list. Its bound is a project root (a `.gitnexus` index or a `.git` marker), so
|
|
108
|
+
it cannot become a filesystem probe.
|
|
323
109
|
|
|
324
|
-
|
|
325
|
-
platform baseline modules (`react`, the UI primitives) supplied by the loader's own
|
|
326
|
-
`require` at runtime, and it has no relative imports at all. `tsc --module commonjs`
|
|
327
|
-
therefore emits exactly one self-contained file, and the wrap is a text operation. A
|
|
328
|
-
bundler would add a dependency and a resolution graph to solve a problem this package
|
|
329
|
-
does not have.
|
|
330
|
-
|
|
331
|
-
`esModuleInterop` is **off** for the client target on purpose: it makes
|
|
332
|
-
`import * as React from 'react'` compile to a bare `const React = require("react")`,
|
|
333
|
-
which is precisely what the loader factory provides. With interop on, tsc injects an
|
|
334
|
-
`__importStar` helper that would ride along in every page load.
|
|
335
|
-
|
|
336
|
-
### `scripts/*.mjs` stays JavaScript (deliberate)
|
|
337
|
-
|
|
338
|
-
`scripts/link-runtime.mjs` runs from `postinstall`, and `scripts/build-client.mjs` is
|
|
339
|
-
the build driver itself. A bootstrap script **must not depend on the build it
|
|
340
|
-
bootstraps** — if those needed compiling, a fresh clone's `npm install` would fail
|
|
341
|
-
because `lib/` does not exist yet. `src/**` and `bin/**` are TypeScript; `scripts/`
|
|
342
|
-
is plain ESM, and that line is intentional rather than unfinished.
|
|
343
|
-
|
|
344
|
-
### Runtime packages ship no type declarations
|
|
345
|
-
|
|
346
|
-
`@deepseek-ai/schemastery`, `@deepseek-ai/dsh-tools`, `@deepseek-ai/cordis` and
|
|
347
|
-
`@deepseek-ai/dsh-client-ui-primitives` each declare `"types": "lib/types/index.d.ts"`
|
|
348
|
-
in their manifest and ship no such file. Every plugin author has to write these
|
|
349
|
-
declarations; `types/` holds the four, with the surface limited to what this plugin
|
|
350
|
-
actually uses. The primitive **props** were read off real call sites in shipped
|
|
351
|
-
plugins rather than guessed, because a wrong prop name fails silently at runtime —
|
|
352
|
-
the control renders with a default and nothing reports anything.
|
|
353
|
-
|
|
354
|
-
## Client half
|
|
355
|
-
|
|
356
|
-
`src/client/index.ts` is one CommonJS module using nothing but baseline modules
|
|
357
|
-
(`react`), so `scripts/build-client.mjs` wraps it into the loader's factory
|
|
358
|
-
artifact with no bundler at all — a text wrap cannot drift from its source the way
|
|
359
|
-
a bundle can.
|
|
360
|
-
|
|
361
|
-
The panel splits fetching (`CoveragePanel`) from presentation (`CoverageView`).
|
|
362
|
-
That is not stylistic: a component that fetches cannot be rendered against a
|
|
363
|
-
fixture, and the states worth asserting on — a report with skipped files, one
|
|
364
|
-
without, an error, missing language data — are exactly the ones a fixture supplies.
|
|
365
|
-
`test/client.mjs` renders each of them through a minimal single-pass hooks shim.
|
|
366
|
-
Keyword search follows the same split: `CoveragePanel` owns the request and
|
|
367
|
-
`SearchSection` is a pure function of its props, so the empty, error and result
|
|
368
|
-
states are all fixture-testable without a graph database.
|
|
369
|
-
|
|
370
|
-
Styling is theme-agnostic by construction: host elements only, `color` inherited,
|
|
371
|
-
every border derived from `currentColor`. `@deepseek-ai/dsh-client-ui-primitives` is
|
|
372
|
-
a baseline module but ships no JS in the installed runtime, so its exports cannot
|
|
373
|
-
be verified from outside — guessing at component props would fail at mount time in
|
|
374
|
-
a browser, where no test in this repository can see it.
|
|
375
|
-
|
|
376
|
-
## Verified end to end
|
|
377
|
-
|
|
378
|
-
Installed into the `web` profile and booted; the route answered with real data:
|
|
110
|
+
Inside DSH:
|
|
379
111
|
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
GET /api/gitnexus/
|
|
387
|
-
|
|
112
|
+
- tool `gitnexus_coverage`: `{ repo, includeLanguages? }`
|
|
113
|
+
- tool `gitnexus_delta`: `{ repo }` — would a refresh change anything?
|
|
114
|
+
- route `GET /api/gitnexus/coverage?repo=<project>`
|
|
115
|
+
- route `GET /api/gitnexus/search?repo=<project>&q=<keyword>&limit=20`
|
|
116
|
+
- route `GET /api/gitnexus/file-history?repo=<project>&path=<file>&days=7` — one file's
|
|
117
|
+
bounded commit timeline
|
|
118
|
+
- route `GET /api/gitnexus/delta?repo=<project>` — Tier 0 comparison against the index
|
|
119
|
+
- route `GET /api/gitnexus/graph?repo=<project>&view=communities|community&id=<community>`
|
|
120
|
+
— a bounded graph projection
|
|
121
|
+
- route `POST/GET/DELETE /api/gitnexus/analyze` (the only entry that changes an index;
|
|
122
|
+
`force=1` for a full rebuild, `mode=repair-fts` for the search indexes only)
|
|
123
|
+
- right-sidebar tab `gitnexus`
|
|
388
124
|
|
|
389
|
-
|
|
390
|
-
repository's real index (the same database the panel reads):
|
|
125
|
+
CLI:
|
|
391
126
|
|
|
392
|
-
```
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
127
|
+
```sh
|
|
128
|
+
npm run build
|
|
129
|
+
node lib/bin/gitnexus-coverage.js <repo-path>
|
|
130
|
+
node lib/bin/gitnexus-coverage.js -r material-ui # by registry alias
|
|
131
|
+
node lib/bin/gitnexus-coverage.js --all --json # every indexed repository
|
|
132
|
+
node lib/bin/gitnexus-coverage.js <repo> --fail-on-large # CI gate, exit 2
|
|
133
|
+
npm run check
|
|
134
|
+
npm test
|
|
398
135
|
```
|
|
399
136
|
|
|
400
|
-
|
|
401
|
-
parses (the host's Electron Node cannot load the native addon):
|
|
137
|
+
Search has two modes:
|
|
402
138
|
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
```
|
|
139
|
+
- **graph** — the normal path. The host does not load native `lbug`; it starts
|
|
140
|
+
`lib/bin/search-helper.js` under system Node and searches node names and file paths. It
|
|
141
|
+
does not search bodies, so it works on an index built with `--skip-fts`.
|
|
142
|
+
- **text** — the fallback when the graph query cannot start. It reads the files listed in
|
|
143
|
+
the index manifest, matches lines, searches code before docs, and caps files/bytes/
|
|
144
|
+
matches. The panel labels it 源码关键词(回退).
|
|
410
145
|
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
list indexed repositories and has no picker.
|
|
415
|
-
|
|
416
|
-
That is a deliberate reversal. The first design read `~/.gitnexus/registry.json`
|
|
417
|
-
and offered a dropdown, which made a global file a hard dependency — so a fresh
|
|
418
|
-
clone, a second working tree, or an index built with `GITNEXUS_HOME` redirected
|
|
419
|
-
could not be shown at all, which is exactly when a coverage panel is most useful.
|
|
420
|
-
The workspace comes from the slot's session-scoped props (`useWorkspaces` matched
|
|
421
|
-
by `sessionId`); the host route accepts any directory **that is already a GitNexus
|
|
422
|
-
index**, which is the bound that keeps it from being a filesystem probe.
|
|
423
|
-
|
|
424
|
-
## Maintenance: the refresh runs here, the escape hatches do not
|
|
425
|
-
|
|
426
|
-
Two situations the read-only half cannot resolve on its own:
|
|
427
|
-
|
|
428
|
-
- **初始化索引 / 增量刷新** — the index is missing or behind HEAD. This one the plugin
|
|
429
|
-
runs for you.
|
|
430
|
-
- **强制全量重构** — the incremental refresh has hung. GitNexus's update path is not
|
|
431
|
-
reliably terminating, and when it wedges a full rebuild is the only way out. This
|
|
432
|
-
one also has a button, behind its own destructive confirmation: the route implements
|
|
433
|
-
`--force`, and the dialog says what it rebuilds, how long it can take, and that the
|
|
434
|
-
index may be briefly unavailable.
|
|
435
|
-
|
|
436
|
-
**Both maintenance actions run through the host's shell executor.** An earlier revision
|
|
437
|
-
handed over every command as text, justified by "a plugin that spawns processes
|
|
438
|
-
bypasses the permission system". That reasoning was wrong, and the correction is worth
|
|
439
|
-
stating precisely:
|
|
440
|
-
|
|
441
|
-
DSH's approval service governs **sandbox escalation** — widening the scope a session was
|
|
442
|
-
granted. Its audit pair must be turn-enclosed, which is why `ApprovalService.request()`
|
|
443
|
-
throws outside an open turn; a panel route has no turn, so it cannot ask. It also has
|
|
444
|
-
nothing to ask about here: this command writes `.gitnexus/` **inside the workspace**,
|
|
445
|
-
already within the granted scope.
|
|
446
|
-
|
|
447
|
-
Confinement is not something a caller opts into. It is what `ctx.shell` *is* in a given
|
|
448
|
-
deployment — `dsh-pwsh-local` exposes the argv seam that `dsh-pwsh-sandbox` wraps
|
|
449
|
-
through `ctx.sandbox.confine`. So routing through the executor gives this plugin exactly
|
|
450
|
-
the isolation your own shell commands get.
|
|
451
|
-
|
|
452
|
-
What the plugin commits to, and what is tested:
|
|
453
|
-
|
|
454
|
-
- **It never sets `sandboxPolicy`.** Requesting one would be this plugin choosing its
|
|
455
|
-
own confinement — escalation, asked for through a door that cannot ask. A denial comes
|
|
456
|
-
back as `denied` and **is never retried wider**.
|
|
457
|
-
- **One run per repository.** Two concurrent `analyze` processes contend for the same
|
|
458
|
-
store, and the second reports a failure that says nothing about the repository.
|
|
459
|
-
- **`--index-only` always.** Without it `analyze` rewrites `AGENTS.md`, `CLAUDE.md` and
|
|
460
|
-
the agent skill files in your tree — a far larger change than "refresh the index".
|
|
461
|
-
- **A confirmation before it starts**, stating the exact command, what it touches and
|
|
462
|
-
how long it takes.
|
|
463
|
-
- **The full rebuild is a separate confirmation.** It runs only when the request carries
|
|
464
|
-
`force=1`, its confirmation says it rebuilds the graph and FTS and may take minutes,
|
|
465
|
-
and its button is labelled 全量重建 rather than borrowing the incremental one.
|
|
466
|
-
- **Cancellable**, with a ten-minute ceiling by default (`analyzeTimeoutMs`).
|
|
467
|
-
|
|
468
|
-
The full rebuild used to have no button because the host route did not implement
|
|
469
|
-
`--force`. The route does now, and the button runs exactly the command its dialog
|
|
470
|
-
shows — a button that quietly ran something other than its label would still be worse
|
|
471
|
-
than no button.
|
|
472
|
-
|
|
473
|
-
The commands shown and executed are not a bare `gitnexus analyze`, because that does not
|
|
474
|
-
work in every deployment:
|
|
146
|
+
Clicking a hit calls
|
|
147
|
+
`ctx.sidebarRight.openResourceIn(sessionId, address, { params: { line } })` to open the
|
|
148
|
+
platform file viewer at that line; without that service it falls back to copying the path.
|
|
475
149
|
|
|
476
|
-
|
|
477
|
-
$env:GITNEXUS_MEMORY='off'; $env:NODE_OPTIONS='--max-old-space-size=8192'; \
|
|
478
|
-
$env:GITNEXUS_HOME='<project>\.gitnexus\plugin-home'; \
|
|
479
|
-
gitnexus analyze --index-only '<project>'
|
|
150
|
+
## Troubleshooting
|
|
480
151
|
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
```
|
|
152
|
+
Start with the state the panel reports: `GitNexus absent`, `no index`, `index stale`,
|
|
153
|
+
`FTS unavailable`. The rows below cover this plugin's boundary; the linked upstream
|
|
154
|
+
GitNexus path owns the rest.
|
|
485
155
|
|
|
486
|
-
|
|
487
|
-
|
|
156
|
+
| Symptom | What to do here | Upstream GitNexus path |
|
|
157
|
+
| --- | --- | --- |
|
|
158
|
+
| The panel says GitNexus is absent | Install it yourself, or use the panel's install. For a non-standard location set `GITNEXUS_CLI=/path/to/gitnexus/dist/cli/index.js`. | [`gitnexus/README.md` — Requirements](https://github.com/abhigyanpatwari/GitNexus/blob/main/gitnexus/README.md#requirements), [Quick Start](https://github.com/abhigyanpatwari/GitNexus/blob/main/gitnexus/README.md#quick-start) |
|
|
159
|
+
| The project has no index | Use **初始化索引** in the panel, or run `gitnexus analyze --index-only <repo>`. | [`README.md` — CLI Reference](https://github.com/abhigyanpatwari/GitNexus/blob/main/README.md#cli-reference), [`RUNBOOK.md` — Index out of date](https://github.com/abhigyanpatwari/GitNexus/blob/main/RUNBOOK.md#index-out-of-date--stale-tools) |
|
|
160
|
+
| Refresh fails, `spawn EPERM`, or the index stays `incremental-in-progress` | The panel's command already sets `GITNEXUS_MEMORY=off`, `NODE_OPTIONS=--max-old-space-size=8192`, `GITNEXUS_HOME=<repo>/.gitnexus/plugin-home` and `--index-only`. If the sandbox still refuses, run the copied command in your own shell; the plugin will not escalate. | [`RUNBOOK.md` — LadybugDB / lock errors](https://github.com/abhigyanpatwari/GitNexus/blob/main/RUNBOOK.md#ladybugdb--lock-errors), [Memory / analyze crashes](https://github.com/abhigyanpatwari/GitNexus/blob/main/RUNBOOK.md#memory--analyze-crashes) |
|
|
161
|
+
| Refresh fails with `EPERM … mkdir` or `rmdir '<repo>\.gitnexus\parsedfile-store'` | GitNexus deletes this run-scoped store at the start of every parse, and a parse worker creates it again during the parse — both directions can be refused. Two causes, both addressed in 0.1.4: the plugin no longer pre-creates the directory (that was 0.1.3's `rmdir`), and the analyzer's shell call now carries the **repository** as its sandbox workspace root. A panel route has no session, so the sandbox used to fall back to the DSH application directory, whose write capability is a different identity — the repository's write grant never applied. If it still fails, the deployment's mode is read-only: run the copied command in a normal terminal. | [`RUNBOOK.md` — LadybugDB / lock errors](https://github.com/abhigyanpatwari/GitNexus/blob/main/RUNBOOK.md#ladybugdb--lock-errors), [`RUNBOOK.md` — Clean slate](https://github.com/abhigyanpatwari/GitNexus/blob/main/RUNBOOK.md#clean-slate-corrupt-or-huge-gitnexus) |
|
|
162
|
+
| Incremental analyze hangs, or the database reports `Maximum database size … has been reached` | Use **全量重建** (`--force`), or the clean-slate steps. | [`RUNBOOK.md` — Clean slate](https://github.com/abhigyanpatwari/GitNexus/blob/main/RUNBOOK.md#clean-slate-corrupt-or-huge-gitnexus), [`gitnexus/README.md` — Troubleshooting](https://github.com/abhigyanpatwari/GitNexus/blob/main/gitnexus/README.md#troubleshooting) |
|
|
163
|
+
| Refresh fails with `EPERM … open '<repo>\.gitnexus\lbug.init.lock'` or `unable to acquire init lock` | A transient file lock, not a permissions problem: the ACL for `.gitnexus` was checked on the machine that reported it and came back healthy. GitNexus's first write is that lock, and a scanner, the indexer, or a crashed run can hold it. The plugin clears a stale lock and retries once automatically (the run shows `attempts: 2`). If it still fails, wait a moment and retry, or run the copied command in a normal terminal. | This plugin's retry plus the analyzer's own lock file; no upstream GitNexus path. |
|
|
164
|
+
| Search fails with `A dynamic link library (DLL) initialization routine failed` / `lbugjs.node` | Graph search runs in `lib/bin/search-helper.js`, never in the Electron host. Restart DSH after upgrading and keep `node` on the shell PATH. If the helper cannot start at all, search falls back to source text. | [`gitnexus/README.md` — Troubleshooting](https://github.com/abhigyanpatwari/GitNexus/blob/main/gitnexus/README.md#troubleshooting) |
|
|
165
|
+
| Windows search returns very few hits, or the panel warns FTS is unavailable | The index was built with `--skip-fts`, or the FTS extension cannot load. Keyword search still matches names and paths; the source fallback matches lines. The panel then offers **修复搜索索引(FTS)**, which runs `analyze --repair-fts` and leaves the graph alone. Two ways it still fails, and the panel names which: the repair must install/load the extension **out of process**, which a confined shell refuses (`spawn EPERM` — run the copied command in a terminal), or the extension file exists but cannot load, which is a missing Windows runtime (VC++ 2015-2022 x64 and OpenSSL 3), not an index problem. | [`gitnexus/README.md` — Windows: full-text search unavailable](https://github.com/abhigyanpatwari/GitNexus/blob/main/gitnexus/README.md#windows-full-text-search-unavailable), [Analyze warns about unavailable FTS](https://github.com/abhigyanpatwari/GitNexus/blob/main/gitnexus/README.md#analyze-warns-about-unavailable-fts-or-vector-extensions) |
|
|
166
|
+
| The refresh button says 无需刷新 and is disabled | That is the Tier 0 verdict, not a failure: every file the index recorded still hashes the same, so re-running the analyzer would change nothing. **仍然刷新** forces it anyway (useful after a schema or GitNexus upgrade). If the index recorded no commit baseline, the panel does **not** claim 无需刷新 — it says it cannot confirm and leaves the button enabled. | This plugin's delta engine; no upstream GitNexus path. |
|
|
167
|
+
| The gate says 无法确认 instead of 无需刷新 | The index recorded no commit, so the comparison can only see the working tree. A confined analyze cannot start `git`, which is how the manifest ends up with an empty `lastCommit` — measured here: the same command writes it in a normal terminal and leaves it empty under the sandbox. Run the copied command outside the sandbox once if you want the stronger verdict; the refresh button stays usable either way. | This plugin's delta engine plus the analyzer's git access; no upstream GitNexus path. |
|
|
168
|
+
| The graph card is empty, or fails with 404 | A 404 means the host predates `/api/gitnexus/graph` — restart DSH, not just the page. An empty canvas with a message means the index has no communities yet (an old index), or the store is busy: refresh the index. Nodes are capped by design; the card states how much it left out. | This plugin's host route; graph data itself comes from the GitNexus index. |
|
|
169
|
+
| Clicking a search hit does not open a file | The click uses `ctx.sidebarRight.openResourceIn`; a profile without that service falls back to copying `path:line`. Restart DSH; if it persists, use the Copy button. | This panel/DSH boundary; no upstream GitNexus path. |
|
|
170
|
+
| The file timeline fails with 404/401 | The client hot-reloaded before the host did, so `/api/gitnexus/file-history` is not mounted yet. Restart DSH (not just refresh the page). | This plugin's host route; no upstream GitNexus path. |
|
|
171
|
+
| Analyze runs out of memory | Keep the panel's `NODE_OPTIONS` / `GITNEXUS_MEMORY` settings, or raise the heap manually; the index may need a full rebuild. | [`gitnexus/README.md` — Analysis runs out of memory](https://github.com/abhigyanpatwari/GitNexus/blob/main/gitnexus/README.md#analysis-runs-out-of-memory), [`RUNBOOK.md` — Memory / analyze crashes](https://github.com/abhigyanpatwari/GitNexus/blob/main/RUNBOOK.md#memory--analyze-crashes) |
|
|
172
|
+
| A large file is missing from the graph | This is what the panel reports: size/share, generated/minified heuristics, binary detection. Raising the cap is an upstream analyze option; this plugin only reports the skip. | [`gitnexus/README.md` — Large files are being skipped](https://github.com/abhigyanpatwari/GitNexus/blob/main/gitnexus/README.md#large-files-are-being-skipped) |
|
|
173
|
+
| Native install fails (`@ladybugdb/core`, `tree-sitter-*`) | The plugin runs `npm install --prefix …`; it needs a C++ toolchain and a reachable registry. Run the manual command from **Getting GitNexus** to see the compiler error. | [`gitnexus/README.md` — Installation fails with native module errors](https://github.com/abhigyanpatwari/GitNexus/blob/main/gitnexus/README.md#installation-fails-with-native-module-errors) |
|
|
174
|
+
| The panel does not appear at all | Check that `dsh plugin add` succeeded and DSH was restarted; open it from the sidebar's **+** guide page. For the `desktop` profile, use the Web Plugins page. | This plugin's install path; no upstream GitNexus path. |
|
|
175
|
+
|
|
176
|
+
## Upstream GitNexus documentation
|
|
177
|
+
|
|
178
|
+
This README describes the plugin, not GitNexus. GitNexus behavior follows its source docs.
|
|
179
|
+
Repository: [`abhigyanpatwari/GitNexus`](https://github.com/abhigyanpatwari/GitNexus)
|
|
180
|
+
(branch `main`).
|
|
181
|
+
|
|
182
|
+
| Topic | Path |
|
|
183
|
+
| --- | --- |
|
|
184
|
+
| Install, CLI, environment variables, MCP | [`README.md`](https://github.com/abhigyanpatwari/GitNexus/blob/main/README.md) |
|
|
185
|
+
| CLI package, requirements, full Troubleshooting | [`gitnexus/README.md`](https://github.com/abhigyanpatwari/GitNexus/blob/main/gitnexus/README.md) |
|
|
186
|
+
| Index stale, clean slate, locks, memory | [`RUNBOOK.md`](https://github.com/abhigyanpatwari/GitNexus/blob/main/RUNBOOK.md) |
|
|
187
|
+
| Architecture and data flow | [`ARCHITECTURE.md`](https://github.com/abhigyanpatwari/GitNexus/blob/main/ARCHITECTURE.md) |
|
|
188
|
+
| Tests and guardrails | [`TESTING.md`](https://github.com/abhigyanpatwari/GitNexus/blob/main/TESTING.md), [`GUARDRAILS.md`](https://github.com/abhigyanpatwari/GitNexus/blob/main/GUARDRAILS.md) |
|
|
189
|
+
| CLI command reference | [`gitnexus/skills/gitnexus-cli.md`](https://github.com/abhigyanpatwari/GitNexus/blob/main/gitnexus/skills/gitnexus-cli.md) |
|
|
190
|
+
| Language-specific notes | [`docs/languages/`](https://github.com/abhigyanpatwari/GitNexus/tree/main/docs/languages) |
|
|
191
|
+
|
|
192
|
+
Local `.docs/` notes are gitignored; the links above are the published source of truth.
|
|
193
|
+
|
|
194
|
+
## Maintenance commands
|
|
195
|
+
|
|
196
|
+
The panel shows and runs more than a bare `gitnexus analyze`:
|
|
197
|
+
|
|
198
|
+
```powershell
|
|
199
|
+
$env:GITNEXUS_MEMORY='off'; $env:NODE_OPTIONS='--max-old-space-size=8192'; `
|
|
200
|
+
$env:GITNEXUS_HOME='<repo>/.gitnexus/plugin-home'; `
|
|
201
|
+
gitnexus analyze --index-only '<repo>'
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
Add `--force` for a full rebuild, or `--repair-fts` alone to rebuild the search indexes
|
|
205
|
+
without touching the graph (the panel offers that as **修复搜索索引(FTS)** when the index
|
|
206
|
+
reports FTS as unavailable).
|
|
207
|
+
|
|
208
|
+
- `GITNEXUS_MEMORY=off` — stops the CLI from re-spawning itself over piped stdio, which a
|
|
209
|
+
confined sandbox denies (`spawn EPERM`).
|
|
488
210
|
- `NODE_OPTIONS=--max-old-space-size=8192` — supplies the heap that respawn wanted.
|
|
489
|
-
- `GITNEXUS_HOME
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
`--skip-fts`
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
spawning anything**: with no CLI it reports `unavailable` and tells the operator to
|
|
534
|
-
install one, rather than starting a process that cannot work. Spawning the CLI to ask
|
|
535
|
-
its version would be the direct test, but a confined process denies piped stdio, so
|
|
536
|
-
the probe only stats the filesystem. The engine degrades on its own too — `scan.ts`
|
|
537
|
-
falls back to its own walker and reports `primitives: 'fallback'`, and the built-in
|
|
538
|
-
size caps apply.
|
|
539
|
-
- **A report that reused GitNexus's scan rules and one that fell back to an
|
|
540
|
-
approximation are still not distinguished per file.** The toolchain verdict travels
|
|
541
|
-
with the report, the language breakdown carries `detector: "gitnexus" | "builtin"`,
|
|
542
|
-
and the fallback rows are never labelled *parsed* — but the remaining per-file numbers
|
|
543
|
-
do not carry a provenance marker, so a fallback walk is not labelled as one where
|
|
544
|
-
those numbers are shown. The built-in walker deliberately does **not** implement
|
|
545
|
-
upstream's ignore rules faithfully, and its uncovered-file count can therefore carry
|
|
546
|
-
false positives.
|
|
547
|
-
- **Installing GitNexus from the panel has never been run against a real network.** The
|
|
548
|
-
command shape is verified (`npm install --prefix … --no-audit --no-fund`, no hardcoded
|
|
549
|
-
registry), the runner's state machine is covered by fourteen assertions, and the
|
|
550
|
-
failure paths name the two likely causes — unreachable registry, missing C++ toolchain.
|
|
551
|
-
What is **not** verified is the download and compile itself: it is several hundred
|
|
552
|
-
megabytes and was never executed from inside a confined DSH process. Treat the first
|
|
553
|
-
authorised install on any machine as untested, and fall back to the manual command if
|
|
554
|
-
it fails — which is why that command is offered first. What *is* verified by tests is
|
|
555
|
-
that the installed prefix is the one the reader, the language detector and the analyze
|
|
556
|
-
runner all resolve; the download and compile remain unverified.
|
|
557
|
-
- **`--omit=optional` saves about 486 MB of that install, and is not used by default.**
|
|
558
|
-
Measured: a full GitNexus tree is 998.9 MB, and omitting the optional dependencies
|
|
559
|
-
gives 513.2 MB by dropping `onnxruntime-node` (287 MB), `onnxruntime-web` (139 MB) and
|
|
560
|
-
`@huggingface/transformers`. Those serve vector search and embeddings, which this
|
|
561
|
-
plugin never enables and reports as `unavailable`. The default does not pass the flag
|
|
562
|
-
because the plugin cannot verify that analysis still succeeds without them on every
|
|
563
|
-
platform, and a refresh that fails in an unexplained way is worse than one that is
|
|
564
|
-
large. A deployment that wants the smaller tree can set `gitnexusInstallDir` aside and
|
|
565
|
-
install by hand with `--omit=optional`.
|
|
566
|
-
- **The refresh runs outside the conversation, and that has a real consequence.** A
|
|
567
|
-
command started from the panel goes through `ctx.shell` and is confined exactly as
|
|
568
|
-
your own shell commands are, but it is **not** a tool call: it writes no
|
|
569
|
-
`approval/asked` + `approval/decided` pair into the session log, and it does not
|
|
570
|
-
appear in the transcript. That pair could not be written even if it were wanted —
|
|
571
|
-
`ApprovalService.request()` requires an open turn and throws without one, which is
|
|
572
|
-
also why there is nothing to approve: the command does not escalate. The audit record
|
|
573
|
-
is the run state the panel holds, which is per-process and is not persisted. If you
|
|
574
|
-
want a refresh on the conversation's record, run the handed-over command in the
|
|
575
|
-
session instead; that path is unchanged.
|
|
576
|
-
- **Walk cost scales with file count.** ~29 000 files takes ~1.4 s warm, ~13 s on a
|
|
577
|
-
cold filesystem cache. The host half caches reports for 15 s; a panel that polls
|
|
578
|
-
faster than that gains nothing.
|
|
579
|
-
- **The minified heuristic reads a 64 KB head and extrapolates.** It flags
|
|
580
|
-
single-line bundles reliably and correctly *declines* generated-but-multi-line
|
|
581
|
-
output (verified: a 2.3 MB, 75 263-line file averages 31 chars/line). The
|
|
582
|
-
generated-path heuristic covers that gap, as a hint rather than a verdict.
|
|
583
|
-
- **Binary assets are detected and reported separately, and that is not cosmetic.**
|
|
584
|
-
A first revision tested only "no newlines ⇒ one enormous line", so a real 380 MB
|
|
585
|
-
`.glb` was reported as *"single-line ≈ 399 230 584 chars — probably minified
|
|
586
|
-
rather than source"*. The number was absurd; the conclusion was worse, because it
|
|
587
|
-
implied that 97 % of one repository's skipped bytes were compressed **source**
|
|
588
|
-
when 414 of 417 MB were 3D models that could never hold a symbol. Detection is
|
|
589
|
-
git's own rule (a NUL byte in the head means binary), plus a control-byte ratio;
|
|
590
|
-
binary short-circuits both the minified and generated claims, and the headline
|
|
591
|
-
warning now separates binary from text so the figure worth acting on is visible.
|
|
592
|
-
Verified end to end on the repository that exposed it: the actionable remainder
|
|
593
|
-
went from an implied 416.9 MB to **2.6 MB**.
|
|
594
|
-
- **`git ls-tree` is not used.** An earlier design compared the index against
|
|
595
|
-
git-tracked files; real data killed it — 8 of the "missing" tracked files in a
|
|
596
|
-
37-file repo were dotfiles excluded by the walker's `dot: false`, and 2 indexed
|
|
597
|
-
files were untracked. The walker's own rules are the only honest denominator.
|
|
598
|
-
- **Keyword search is graph name/path first, with a source-text fallback.** The graph
|
|
599
|
-
mode finds symbols and files whose *names* or *paths* contain the query; it does not
|
|
600
|
-
search function bodies, comments or descriptions. The fallback (`mode: "text"`) does
|
|
601
|
-
search line text, but only in the files the index manifest lists, and only when the
|
|
602
|
-
graph helper cannot start. Content-level search as a first-class mode is GitNexus's
|
|
603
|
-
FTS surface, and on this machine the FTS extension fails to load
|
|
604
|
-
(`libfts.lbug_extension` missing) and the current index was built with `--skip-fts`.
|
|
605
|
-
The panel labels the two modes separately (符号名 / 文件路径 vs 源码关键词(回退)) and
|
|
606
|
-
never presents a text hit as a graph hit.
|
|
607
|
-
- **Search needs a child Node process for the graph path.** The host's Electron Node
|
|
608
|
-
cannot load the LadybugDB addon (ABI mismatch), so the query is delegated to
|
|
609
|
-
`lib/bin/search-helper.js` under the system Node 24. This is deliberate, not a
|
|
610
|
-
workaround to remove: an in-process search fails on the host with the DLL
|
|
611
|
-
initialization error above. If the shell executor is unavailable (measured on this
|
|
612
|
-
machine: the Windows `windows-acl-run` sandbox cannot create its temp directory),
|
|
613
|
-
search does **not** fail — it falls back to the bounded source-text scan and labels
|
|
614
|
-
the result `text`. The graph query remains the preferred path when the helper can
|
|
615
|
-
start.
|
|
616
|
-
- **The source fallback is not the graph.** It searches line text in the files the
|
|
617
|
-
index manifest lists, not symbol relationships; code paths are searched before
|
|
618
|
-
documentation, and the file/byte/match caps can truncate a large repository. The
|
|
619
|
-
panel's card title changes to 源码关键词(回退) and the warning names the fallback,
|
|
620
|
-
so a text hit is never presented as a graph hit.
|
|
621
|
-
- **Panel effects and re-render are still not automated.** `react-dom` is not installed
|
|
622
|
-
on this machine, so rendering uses a single-pass shim: `useState` yields its initial
|
|
623
|
-
value and `useEffect` never runs. The pure view is covered; the fetch lifecycle is
|
|
624
|
-
not. The panel has now been checked once against the real right sidebar, and that
|
|
625
|
-
check is what exposed the two-column layout clipping the language card at a narrow
|
|
626
|
-
pane edge, the grey single-bucket chart, the invented `--dsw-color-*` tokens, the
|
|
627
|
-
raw English `index` cap source, and the `--skip-fts` config default. Those are
|
|
628
|
-
fixed, but a future prop or layout change can still pass every test here without
|
|
629
|
-
being seen in a browser.
|
|
630
|
-
- **Install → initialize has not been exercised end to end against a real npm install.**
|
|
631
|
-
The managed-prefix wiring, the auto-chain gate, and the analyze command are covered by
|
|
632
|
-
tests; the several-hundred-megabyte download and native compile are not.
|
|
211
|
+
- `GITNEXUS_HOME` — redirects the global registry write into the project, so a failed
|
|
212
|
+
write to `~/.gitnexus` cannot leave the index stuck at `incremental-in-progress`.
|
|
213
|
+
- `--index-only` — otherwise `analyze` rewrites `AGENTS.md`, `CLAUDE.md` and skill files
|
|
214
|
+
inside the repository.
|
|
215
|
+
|
|
216
|
+
`--skip-fts` is **adaptive per index**: no flag when the manifest says FTS is available,
|
|
217
|
+
and the flag when it is not. `skipFts: true` can force the flag; there is no config that
|
|
218
|
+
forces FTS on, because enabling it is a repair (`gitnexus analyze --repair-fts`), not an
|
|
219
|
+
incremental refresh — so the panel exposes it as its own action, and a repair run never
|
|
220
|
+
carries `--skip-fts` (the CLI accepts that pair and exits 0 having done nothing).
|
|
221
|
+
|
|
222
|
+
## License (read before commercial use)
|
|
223
|
+
|
|
224
|
+
This plugin is **MIT** (see [LICENSE](LICENSE)).
|
|
225
|
+
|
|
226
|
+
**GitNexus is `PolyForm-Noncommercial-1.0.0`**: noncommercial use is granted, commercial
|
|
227
|
+
use is restricted. `gitnexus` is a **peer**; this package does not install, bundle or
|
|
228
|
+
redistribute it. But using this plugin's GitNexus-backed features (reading an index,
|
|
229
|
+
refreshing it, installing it) puts **your use of GitNexus** under GitNexus's license;
|
|
230
|
+
commercial use needs a separate grant from GitNexus's author:
|
|
231
|
+
|
|
232
|
+
<https://github.com/abhigyanpatwari/GitNexus/blob/main/LICENSE>
|
|
233
|
+
|
|
234
|
+
In one line: **MIT covers this plugin's code; GitNexus's license covers GitNexus, and using
|
|
235
|
+
the related features puts that use under it.**
|
|
236
|
+
|
|
237
|
+
## Boundaries
|
|
238
|
+
|
|
239
|
+
- Coverage and search are read-only; maintenance is a separately confirmed write and
|
|
240
|
+
never starts by itself.
|
|
241
|
+
- The refresh gate compares content hashes of the files the index recorded. It cannot
|
|
242
|
+
see a change the analyzer would make for its own reasons (a schema upgrade, a new
|
|
243
|
+
feature mode); **仍然刷新** exists for exactly that case.
|
|
244
|
+
- The graph view draws communities, not every symbol: the overview is the community
|
|
245
|
+
graph, and a drill-down shows at most the configured node budget of one community's
|
|
246
|
+
members. Both say when they are truncated.
|
|
247
|
+
- The plugin reports facts about a GitNexus index; it does not rewrite the parser or
|
|
248
|
+
reimplement the graph database.
|
|
249
|
+
- Graph search matches names/paths, not bodies; the text fallback matches lines and is
|
|
250
|
+
capped.
|
|
251
|
+
- The source fallback only covers files in the index manifest; refresh the index for new
|
|
252
|
+
files.
|
|
253
|
+
- Deeper design/build notes are kept out of the public README; this file stays at the
|
|
254
|
+
"what it does" and "how to fix it" level.
|