@polycode-projects/seonix 0.6.1 → 0.7.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 +280 -4
- package/bin/cli.mjs +313 -17
- package/package.json +2 -1
- package/src/ask.mjs +17 -1
- package/src/browser.mjs +16 -7
- package/src/chat.mjs +79 -14
- package/src/codegraph.mjs +11 -1
- package/src/config.mjs +7 -1
- package/src/extract.mjs +405 -48
- package/src/graph-format.mjs +156 -0
- package/src/graph-ops.mjs +92 -0
- package/src/manifest.mjs +148 -0
- package/src/server.mjs +11 -0
- package/src/sessions.mjs +7 -2
- package/src/source.mjs +34 -4
- package/src/store.mjs +282 -0
- package/src/summary.mjs +241 -0
- package/src/telemetry.mjs +90 -0
- package/src/timeline.mjs +12 -4
- package/src/toml-config.mjs +183 -0
- package/src/uuid.mjs +16 -0
- package/src/viz.mjs +72 -12
- package/src/walk.mjs +0 -0
package/README.md
CHANGED
|
@@ -110,10 +110,286 @@ within one repo. Query a merged graph by passing the merge root as `repo_path`
|
|
|
110
110
|
## The shape that ships
|
|
111
111
|
|
|
112
112
|
The product is the **no-MCP digest path**: render the digest, inject it once, run
|
|
113
|
-
with **no server**. The
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
113
|
+
with **no server**. The stdio MCP server still ships and is fully supported (bare
|
|
114
|
+
`seonix` starts it) — it's just not the recommended default, because even
|
|
115
|
+
mitigated the interactive tool loop never cleared the 50% bar: the cost lies in
|
|
116
|
+
the round-trip count rather than the resident schema. Use `seonix_search`
|
|
117
|
+
(`locate`, self-derives the target) in production; pass a known target (`oracle`)
|
|
118
|
+
only to measure the headroom.
|
|
119
|
+
|
|
120
|
+
## CLI reference
|
|
121
|
+
|
|
122
|
+
Every invocation shape `bin/cli.mjs` dispatches on, verified against the current source.
|
|
123
|
+
|
|
124
|
+
### Bare invocation — MCP stdio server
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
seonix
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
No flags, no config file. Starts the stdio MCP server against
|
|
131
|
+
`<cwd>/.seonix/graph.json` (override with `SEONIX_GRAPH_FILE`). MCP launchers
|
|
132
|
+
should start it with cwd = the indexed worktree.
|
|
133
|
+
|
|
134
|
+
### `cli index_repository` — build the graph
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
seonix cli index_repository '{"repo_path":"/abs/repo"}'
|
|
138
|
+
seonix cli index_repository '{"repo_paths":["/abs/repo1","/abs/repo2"],"out_root":"/abs/dir"}'
|
|
139
|
+
seonix cli index_repository '{"multi_root":"/abs/estate"}'
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
`repo_path` / `repo_paths`+`out_root` / `multi_root` are mutually exclusive — pass
|
|
143
|
+
exactly one (or let `seonix.toml`'s `repositories` supply the set when none is
|
|
144
|
+
given explicitly). Shared JSON options:
|
|
145
|
+
|
|
146
|
+
- `ignores` (bool, default `true`) — honour the repo's `.seonixignore`. Pass
|
|
147
|
+
`"ignores":false` to index everything regardless (the bench harness always
|
|
148
|
+
passes this, so a subject repo's own `.seonixignore` never shapes an arm's index).
|
|
149
|
+
- `config` (bool, default `true`) — read `seonix.toml` from the target dir. Pass
|
|
150
|
+
`"config":false` to skip it entirely (byte-identical to no-file behaviour; the
|
|
151
|
+
bench harness's index/locate/digest calls always pass this).
|
|
152
|
+
- `sync` (bool) — on a `multi_root` call, `"sync":true` routes through the same
|
|
153
|
+
incremental path as `cli sync` instead of a full re-index.
|
|
154
|
+
- `history_depth` (non-negative integer) — cap on the git-history pass (both the
|
|
155
|
+
commit walk and the history-symbol pass). `0` skips git history entirely;
|
|
156
|
+
absent uses the default depth. Precedence: this arg > `seonix.toml`
|
|
157
|
+
`[index].history_depth` > default.
|
|
158
|
+
|
|
159
|
+
Writes `<out_root-or-repo_path>/.seonix/graph.json` (+ manifest for
|
|
160
|
+
`multi_root`/`sync`), prints indexed counts to stderr and a human summary MD to
|
|
161
|
+
stdout.
|
|
162
|
+
|
|
163
|
+
### `cli sync` — incremental estate re-index
|
|
164
|
+
|
|
165
|
+
```bash
|
|
166
|
+
seonix cli sync '{"multi_root":"/abs/estate"}'
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
Fingerprints every child repo of `multi_root` and re-extracts only the ones that
|
|
170
|
+
changed since the last run (per-repo cache under `.seonix/cache/`); one union
|
|
171
|
+
rebuild is exact-equal to a full re-index, and an unchanged estate is a byte-stable
|
|
172
|
+
no-op. Accepts `ignores` and `history_depth` as above. Writes
|
|
173
|
+
`.seonix/manifest.json`.
|
|
174
|
+
|
|
175
|
+
### `cli digest` — the no-MCP injection payload
|
|
176
|
+
|
|
177
|
+
```bash
|
|
178
|
+
seonix cli digest '{"repo_path":"/abs/repo","modules":["path/to/mod.mjs","other/mod.py"]}'
|
|
179
|
+
seonix cli digest '{"repo_path":"/abs/repo","query":"add a truncate filter to the article view"}'
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
Two ways to pick the modules: an explicit `modules` array, or a `query` string —
|
|
183
|
+
`query` auto-locates and score-gap-selects the modules in one call (`modules`
|
|
184
|
+
wins if both are given). Prints an architecture map + a size-adaptive context
|
|
185
|
+
bundle per module to stdout, headed by a machine-readable line the rig parses:
|
|
186
|
+
`# seonix-digest tier=<NONE|TINY|MID|LARGE|FULL> topup=<bool> modules=<N>
|
|
187
|
+
[selected=<comma-list>]` (`selected=` only appears in query mode).
|
|
188
|
+
|
|
189
|
+
Tuning flags (all optional, precedence explicit arg > `seonix.toml [tune]` >
|
|
190
|
+
shipped default):
|
|
191
|
+
|
|
192
|
+
- `top_k` (int, query mode only, default 2) — how many modules `query` mode selects.
|
|
193
|
+
- `score_gap` (number, or `false` to disable) — the score-gap cutoff for query-mode selection.
|
|
194
|
+
- `literal_mention` (bool, default `true`) — credit verbatim dotted-name/path mentions in the raw query text.
|
|
195
|
+
- `min` (bool) — force the leanest bundle (no auto top-up).
|
|
196
|
+
- `untuned` (bool) — the pre-tuning escalation behaviour.
|
|
197
|
+
- `max` (bool) — the injection ceiling: every requested module gets a FULL (untrimmed) bundle instead of primary-full + capped trimmed secondaries.
|
|
198
|
+
|
|
199
|
+
### `cli seonix_locate` — ranked module list (recall probe)
|
|
200
|
+
|
|
201
|
+
```bash
|
|
202
|
+
seonix cli seonix_locate '{"query":"…","repo_path":"/abs/repo"}'
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
Prints `<relpath>\t<score>` per line, highest first — the raw ranking a caller
|
|
206
|
+
(or the rig) can threshold itself. Recall/precision levers, all optional
|
|
207
|
+
(precedence arg > `seonix.toml [tune]` > default, all default `false` unless noted):
|
|
208
|
+
|
|
209
|
+
- `demote_nonprod` — demote `examples/`/`fixtures/`/`test-*` paths.
|
|
210
|
+
- `call_adjacency` — resolved-call adjacency bonus.
|
|
211
|
+
- `impl_of_interface` — C# impl-of-interface boost.
|
|
212
|
+
- `beam_search` (+ `beam_width`) — multi-ply discriminative beam expansion.
|
|
213
|
+
- `literal_mention` (default `true`) — verbatim dotted-name/path mention matching against the raw query.
|
|
214
|
+
- `raw_query` — forward a separately-normalized raw problem text for literal matching (else derived from `query`).
|
|
215
|
+
- `spiral` (+ `spiral_depth`, `limit`) — a bounded-radius, degree-ordered ego-neighbourhood walk from the lexical seeds that can surface lexically-invisible modules. `spiral_depth` is the hop radius (only honoured if `>0`); `limit` overrides how many newly-reached nodes the spiral may surface (default 100 — deliberately above the internal 12-node default, since this CLI surface is a recall probe, not a token budget).
|
|
216
|
+
|
|
217
|
+
### `cli browser_link` — NL request → Chronograph URL
|
|
218
|
+
|
|
219
|
+
```bash
|
|
220
|
+
seonix cli browser_link '{"query":"classes that change with render","base":"https://example.com"}'
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
Maps a natural-language-ish request to the code-browser query grammar
|
|
224
|
+
deterministically (no model call), self-tests the resulting link against the
|
|
225
|
+
local temporal graph (must match ≥1 node and every cursor must resolve), then
|
|
226
|
+
prints the URL — or exits 1 with the failure reason(s) rather than printing a
|
|
227
|
+
dead link. Accepts `repo_path` (which repo's graph to test against), `base` (the
|
|
228
|
+
URL prefix the link is built on), `at` / `b` (the two temporal cursors — single
|
|
229
|
+
cursor / diff-cursor), `scope` (restrict the graph to a package-prefix set,
|
|
230
|
+
same values as `viz --scope`), and `grammar:true` (take `query` as grammar
|
|
231
|
+
verbatim, skipping NL mapping).
|
|
232
|
+
|
|
233
|
+
### `cli store_rebuild` — force-rebuild the sqlite store
|
|
234
|
+
|
|
235
|
+
```bash
|
|
236
|
+
seonix cli store_rebuild '{"repo_path":"/abs/repo"}'
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
Force-(re)builds the opt-in `node:sqlite` resident store (see
|
|
240
|
+
[SEONIX_STORE](#seonix_store--seonix_graph_format) below) from the current
|
|
241
|
+
`graph.json`. The store is a derived, rebuildable companion — read paths never
|
|
242
|
+
auto-build it, so this is the explicit way to (re)materialize it after an index
|
|
243
|
+
or a manual `graph.json` edit.
|
|
244
|
+
|
|
245
|
+
### `cli <toolName>` — generic MCP tool fallback
|
|
246
|
+
|
|
247
|
+
```bash
|
|
248
|
+
seonix cli seonix_ask '{"query":"which modules import codegraph"}'
|
|
249
|
+
seonix cli seonix_context '{"symbol":"buildContextBundle","repo_path":"/abs/repo"}'
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
Any sub-command name that isn't one of the above routes straight to the MCP tool
|
|
253
|
+
dispatcher, so any tool in the server's surface — cold or hot — is invokable from
|
|
254
|
+
Bash with no MCP connection. `repo_path` in the JSON arg selects the target
|
|
255
|
+
graph; every other key is passed through as the tool's own arguments.
|
|
256
|
+
|
|
257
|
+
### `hook-augment` — PreToolUse Grep/Glob augmenter
|
|
258
|
+
|
|
259
|
+
```bash
|
|
260
|
+
seonix hook-augment # reads a PreToolUse hook event JSON from stdin
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
Reads the hook event from stdin, extracts the Grep/Glob pattern, and — if the
|
|
264
|
+
local graph has a hit — writes `{hookSpecificOutput:{hookEventName,
|
|
265
|
+
additionalContext}}` to stdout so the agent sees seon typed-graph hits alongside
|
|
266
|
+
its own search. Silent (exit 0, no output) on any failure — empty/malformed
|
|
267
|
+
input, no graph, no hit — the **never-block contract**.
|
|
268
|
+
|
|
269
|
+
### `init [--dotnet]` — seed a seonix.toml
|
|
270
|
+
|
|
271
|
+
```bash
|
|
272
|
+
seonix init # single-repo template
|
|
273
|
+
seonix init --dotnet # estate/.NET template (repositories + broader include_text/exclude)
|
|
274
|
+
seonix init --force # overwrite an existing seonix.toml
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
Copies the shipped template to `./seonix.toml` (byte-for-byte). Refuses to
|
|
278
|
+
overwrite an existing file unless `--force` (exit 2).
|
|
279
|
+
|
|
280
|
+
### `config --effective [--repo <abs>]`
|
|
281
|
+
|
|
282
|
+
```bash
|
|
283
|
+
seonix config --effective
|
|
284
|
+
seonix config --effective --repo /abs/repo
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
Prints the merged `{effective, sources}` config (sorted keys) as JSON — every
|
|
288
|
+
knob's resolved value plus which source won it (`"arg"` | `"seonix.toml"` |
|
|
289
|
+
`"default"`). `--repo` defaults to cwd. Requires `--effective`; without it,
|
|
290
|
+
prints usage and exits 2.
|
|
291
|
+
|
|
292
|
+
### `viz` — render the code-map / code-browser / timeline
|
|
293
|
+
|
|
294
|
+
```bash
|
|
295
|
+
seonix viz --focus <Symbol> --out graph.html
|
|
296
|
+
seonix viz --serve --port 8080 --focus <Symbol>
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
Flags: `--focus <sym>` (default: highest-degree module), `--depth N` (default 2),
|
|
300
|
+
`--hub N` (hub-degree cap, default 40), `--max N` (node cap, default 200), `--out
|
|
301
|
+
f.html` (default `seon-graph.html`), `--data-out f.json` (split viewer + sidecar
|
|
302
|
+
data file instead of embedding), `--graph <path>` (override the graph.json
|
|
303
|
+
location), `--repo-url <url> --ref <branch>` (source links), `--site-nav`
|
|
304
|
+
(add the site's absolute home entry), `--nlp` (include the optional wink-nlp
|
|
305
|
+
lemma tier in the chat panel), `--force-inline` (embed the full graph inline even
|
|
306
|
+
past the size gate that would otherwise split it out with a message).
|
|
307
|
+
|
|
308
|
+
By default `viz` also writes a `code-browser.html` (Chronograph) and a
|
|
309
|
+
`timeline.html` next to `--out` with a working header nav; override their paths
|
|
310
|
+
with `--browser-out f.html` / `--browser-data-out f.json` / `--timeline-out
|
|
311
|
+
f.html`, or suppress both siblings with `--graph-only`. `--scope
|
|
312
|
+
product|<prefixes>` filters the Chronograph browser/timeline to a package
|
|
313
|
+
prefix set. `--limit N` caps the commit timeline to the newest N commits (0 =
|
|
314
|
+
unlimited; default 100 — an estate-scale timeline stays openable, with a "newest
|
|
315
|
+
N of M" header note when truncated).
|
|
316
|
+
|
|
317
|
+
`--serve [--port N]` serves the same viewer live against this repo's own index
|
|
318
|
+
(code browser at `/code-browser.html`, alias `/browser`; timeline at
|
|
319
|
+
`/timeline.html`; live re-annotates on HEAD change via `/code-browser-version`) —
|
|
320
|
+
port 0 (default) picks a free port.
|
|
321
|
+
|
|
322
|
+
### `chat` — interactive client over the mechanical ask engine
|
|
323
|
+
|
|
324
|
+
```bash
|
|
325
|
+
seonix chat [--repo /abs/path] [--with-claude|--with-copilot]
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
See [Chat](#chat) below for the full behaviour (slash-commands, focus tracking,
|
|
329
|
+
conversational manners, session logging, the opt-in `--with-claude`/
|
|
330
|
+
`--with-copilot` LLM fallback).
|
|
331
|
+
|
|
332
|
+
### `SEONIX_STORE` / `SEONIX_GRAPH_FORMAT`
|
|
333
|
+
|
|
334
|
+
Two opt-in/opt-out environment knobs, orthogonal to everything above:
|
|
335
|
+
`SEONIX_STORE=sqlite` turns on the resident `node:sqlite` store as a derived,
|
|
336
|
+
rebuildable companion to `graph.json` (rebuild it explicitly with `cli
|
|
337
|
+
store_rebuild`; unset, nothing sqlite loads). `SEONIX_GRAPH_FORMAT` controls the
|
|
338
|
+
graph's on-disk wire format — the interned v2 form is the shipped default;
|
|
339
|
+
set `SEONIX_GRAPH_FORMAT=1` to opt back out to the legacy v1 form.
|
|
340
|
+
|
|
341
|
+
## Configuration (seonix.toml)
|
|
342
|
+
|
|
343
|
+
An optional `seonix.toml` at a repo (or estate) root steers indexing and
|
|
344
|
+
scoring. Absent file = shipped defaults, byte-for-byte today's behaviour.
|
|
345
|
+
`seonix init` (or `seonix init --dotnet` for an estate) seeds a commented
|
|
346
|
+
template — see `packages/seonix/templates/seonix.toml` and
|
|
347
|
+
`templates/seonix-dotnet.toml` for the full annotated reference.
|
|
348
|
+
|
|
349
|
+
- **`repositories`** — the repo set for an estate config: an inline array of
|
|
350
|
+
paths, or a string naming a newline-delimited file (both resolved relative
|
|
351
|
+
to the config file). Only consulted when no explicit `repo_path` /
|
|
352
|
+
`repo_paths` / `multi_root` arg is given.
|
|
353
|
+
- **`out_root`** — where the merged graph artifact is written (default `.`).
|
|
354
|
+
- **`[index]`**
|
|
355
|
+
- `languages` — the AST languages to parse (`javascript`, `typescript`, `python`, `csharp`, `java`, …).
|
|
356
|
+
- `exclude` — additive glob excludes on top of `.seonixignore` (ordered; a leading `!` re-includes).
|
|
357
|
+
- `secret_exclude` — a hard, fail-safe-ON glob list (env files, keys, certs) that is never indexed and never grabbed as text, even as a text/structure source.
|
|
358
|
+
- `history_depth` — cap on the git-history pass (0 = skip entirely). Precedence: CLI arg > this key > default.
|
|
359
|
+
- `include_text`, `include_structure`, `respect_gitignore`, `markdown_sections`, `vue` — recognized and normalized, but **not yet wired to a consumer** (see "unwired keys" below).
|
|
360
|
+
- **`[tune]`** — the locate/digest scoring knobs: `score_gap_k`, `literal_mention` (shipped default `true`), `demote_non_prod`, `call_adjacency`, `impl_of_interface`, `beam_search` (+ `beam_width`), `embed_rank`, `prose_layers`.
|
|
361
|
+
- **`[tune.expansion]`** — graph-traversal expansion mode used by locate/the viewer's navigation: `strategy` (`none` | `beam` | `spiral` | `ppr`; `none` is the byte-identical shipped default), `nodes` (breadth/token-budget cap), `q` (proportion of most-distinctive neighbours followed per step), `depth` (hop radius).
|
|
362
|
+
- **`[telemetry]`** — `enabled = true` opts in (see [Telemetry](#telemetry) below).
|
|
363
|
+
|
|
364
|
+
**Precedence, everywhere:** explicit CLI arg > `seonix.toml` value > shipped
|
|
365
|
+
default. `seonix cli … '{"config":false}'` (always set on the bench path) skips
|
|
366
|
+
reading `seonix.toml` entirely, so a subject repo's config file can never shape
|
|
367
|
+
a benchmark arm. A `seonix.toml` key that parses and normalizes but has no
|
|
368
|
+
wired consumer yet (`index.include_text`, `index.include_structure`,
|
|
369
|
+
`index.respect_gitignore`, `index.markdown_sections`, `index.vue`) triggers a
|
|
370
|
+
one-time stderr warning per process rather than silently doing nothing.
|
|
371
|
+
`seonix config --effective [--repo <abs>]` prints the fully merged config plus,
|
|
372
|
+
per key, which source won it.
|
|
373
|
+
|
|
374
|
+
## Telemetry
|
|
375
|
+
|
|
376
|
+
Opt-in, off by default, and the OFF path is **byte-identical** to no telemetry
|
|
377
|
+
existing at all — no file, no stdout/stderr change. Turn it on with
|
|
378
|
+
`SEONIX_TELEMETRY=1` (env always wins both directions — `SEONIX_TELEMETRY=0`
|
|
379
|
+
force-disables even if the toml turns it on) or `[telemetry] enabled = true` in
|
|
380
|
+
`seonix.toml`.
|
|
381
|
+
|
|
382
|
+
When enabled, each `cli` invocation (digest / locate / the generic tool
|
|
383
|
+
fallback) appends fire-and-forget JSONL lines to
|
|
384
|
+
`<repo>/.seonix/seonix-<uuidv7>.log` — one line per query, schema-versioned
|
|
385
|
+
(`v: 1`) with an `id` (the invocation id, reusable across a host's own trace
|
|
386
|
+
via `SEONIX_INVOCATION_ID`), a monotonic `seq`, and per-surface fields
|
|
387
|
+
(`query`, `response`, `perf`, `cost`). A structural redactor drops any
|
|
388
|
+
`text`/`content`/`snippet` field at any depth and truncates long strings —
|
|
389
|
+
**telemetry never records file contents**, only ids/paths/scores/sizes/counts.
|
|
390
|
+
Writes are swallowed on error: telemetry can never throw, block a query, or
|
|
391
|
+
touch stdout (stdout is the MCP transport / the digest injected into the
|
|
392
|
+
no-MCP arm).
|
|
117
393
|
|
|
118
394
|
## Visualise
|
|
119
395
|
|