@polycode-projects/seonix 0.10.0 → 0.10.2
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 +10 -5
- package/package.json +4 -2
- package/scripts/build-roslyn.mjs +11 -0
- package/src/cs_roslyn.mjs +13 -7
- package/src/roslyn_build.mjs +59 -0
package/README.md
CHANGED
|
@@ -357,6 +357,7 @@ template — see `templates/seonix.toml` and
|
|
|
357
357
|
- `include_text`, `include_structure`, `respect_gitignore`, `markdown_sections`, `vue` — recognized and normalized, but **not yet wired to a consumer** (see "unwired keys" below).
|
|
358
358
|
- **`[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`.
|
|
359
359
|
- **`[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).
|
|
360
|
+
- **`[interfaces]`** — HTTP route↔handler edges the AST graph can't see on its own: a `Route` node per endpoint, linked to its handler by a `serves` edge, and (JS/TS + tree-sitter C#) an HTTP client call linked to the route it targets by a `callsHttp` edge. Off by default; turn it on with `enabled = true` or `SEONIX_INTERFACES=1` (env wins). Tunable: `frameworks` (default `["aspnet", "express"]`), `verbs`, `combine_controller_prefix`, `prefix_strip`, `match_threshold`.
|
|
360
361
|
- **`[telemetry]`** — `enabled = true` opts in (see [Telemetry](#telemetry) below).
|
|
361
362
|
|
|
362
363
|
**Precedence, everywhere:** explicit CLI arg > `seonix.toml` value > shipped
|
|
@@ -427,11 +428,15 @@ seonix supplies the graph; tmct owns the conversation. The old opt-in
|
|
|
427
428
|
|
|
428
429
|
Python (stdlib `ast`), JS/TS (the TypeScript compiler API, including CommonJS
|
|
429
430
|
`require`/`module.exports`), C# (Roslyn, with a tree-sitter fallback) and Java
|
|
430
|
-
(JavaParser, with a tree-sitter fallback), all merged into the one typed graph.
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
431
|
+
(JavaParser, with a tree-sitter fallback), all merged into the one typed graph.
|
|
432
|
+
The C# Roslyn helper's source ships in the package under `roslyn/`. If the .NET
|
|
433
|
+
SDK is on your PATH, seonix builds it the first time it indexes a C# repo, one
|
|
434
|
+
build, cached after that. No `dotnet` on PATH just means it uses the tree-sitter
|
|
435
|
+
fallback, silently, no error. Run `npm run build:roslyn` yourself first if you
|
|
436
|
+
want the dll ready ahead of time, e.g. in a Docker image build. The Java
|
|
437
|
+
JavaParser helper is a jar built from the repository's `java/` directory (`mvn
|
|
438
|
+
package`) and is not included in the npm package, so a package install indexes
|
|
439
|
+
Java with the tree-sitter fallback.
|
|
435
440
|
|
|
436
441
|
## Licence & safety
|
|
437
442
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@polycode-projects/seonix",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.2",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "SEONIX — a deterministic, offline, $0 code-graph tool that makes a cheap coding agent edit like an expensive one. Indexes a repo with Python ast + git (zero model calls) and renders a bounded edit-digest.",
|
|
@@ -35,6 +35,7 @@
|
|
|
35
35
|
"src/",
|
|
36
36
|
"roslyn/*.cs",
|
|
37
37
|
"roslyn/*.csproj",
|
|
38
|
+
"scripts/build-roslyn.mjs",
|
|
38
39
|
"README.md",
|
|
39
40
|
"LICENSE"
|
|
40
41
|
],
|
|
@@ -45,6 +46,7 @@
|
|
|
45
46
|
"infra"
|
|
46
47
|
],
|
|
47
48
|
"scripts": {
|
|
49
|
+
"build:roslyn": "node scripts/build-roslyn.mjs",
|
|
48
50
|
"setup": "node scripts/setup.mjs",
|
|
49
51
|
"bench": "node bench/run.mjs",
|
|
50
52
|
"bench:quick": "node bench/run.mjs --instances 1 --runs 1",
|
|
@@ -85,7 +87,7 @@
|
|
|
85
87
|
},
|
|
86
88
|
"dependencies": {
|
|
87
89
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
88
|
-
"@polycode-projects/the-mechanical-code-talker": "^0.
|
|
90
|
+
"@polycode-projects/the-mechanical-code-talker": "^0.9.0",
|
|
89
91
|
"cytoscape": "^3.30.0",
|
|
90
92
|
"smol-toml": "^1.7.0",
|
|
91
93
|
"tree-sitter": "^0.21.1",
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// build-roslyn.mjs — explicit prewarm command (`npm run build:roslyn`) for the
|
|
3
|
+
// Roslyn C# semantic extractor. NOT run automatically on `npm install` — the
|
|
4
|
+
// dll lazy-builds on first real C# extraction attempt instead (src/cs_roslyn.mjs
|
|
5
|
+
// via src/roslyn_build.mjs), so consumers who never touch C# never pay a .NET
|
|
6
|
+
// build cost at install time. Use this command ahead of time when you want the
|
|
7
|
+
// dll baked in up front (e.g. a Docker image build step, or a CI cache warm)
|
|
8
|
+
// rather than paying the lazy-build cost on first use.
|
|
9
|
+
import { ensureRoslynBuilt } from "../src/roslyn_build.mjs";
|
|
10
|
+
|
|
11
|
+
await ensureRoslynBuilt();
|
package/src/cs_roslyn.mjs
CHANGED
|
@@ -3,15 +3,21 @@
|
|
|
3
3
|
// prints the {modules:[…]} contract; this wrapper just shells out and parses it.
|
|
4
4
|
// Falls back is the caller's job (cs_treesitter) when dotnet/the tool is absent.
|
|
5
5
|
import { spawn } from "node:child_process";
|
|
6
|
-
import {
|
|
7
|
-
import { fileURLToPath } from "node:url";
|
|
8
|
-
import { access } from "node:fs/promises";
|
|
6
|
+
import { DLL as TOOL_DLL, ensureRoslynBuilt } from "./roslyn_build.mjs";
|
|
9
7
|
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
// Cached across calls within a process: chooseCs() in extract_lang.mjs calls
|
|
9
|
+
// toolAvailable() once per ingestRepo() run, but tests and multi-repo indexing
|
|
10
|
+
// can call it repeatedly — avoid re-spawning `dotnet --version` every time.
|
|
11
|
+
// A fresh process (the normal case: one index run = one process) always
|
|
12
|
+
// re-checks, so a dotnet toolchain installed after a prior failed attempt is
|
|
13
|
+
// picked up automatically on the next run, no reinstall needed.
|
|
14
|
+
let cachedAvailable;
|
|
12
15
|
|
|
16
|
+
/** True if the Roslyn dll is present, lazily building it first (once per
|
|
17
|
+
* process) when it's missing and `dotnet` is on PATH. */
|
|
13
18
|
export async function toolAvailable() {
|
|
14
|
-
|
|
19
|
+
if (cachedAvailable === undefined) cachedAvailable = await ensureRoslynBuilt();
|
|
20
|
+
return cachedAvailable;
|
|
15
21
|
}
|
|
16
22
|
|
|
17
23
|
function run(cmd, args) {
|
|
@@ -26,7 +32,7 @@ function run(cmd, args) {
|
|
|
26
32
|
}
|
|
27
33
|
|
|
28
34
|
export async function ingest(root) {
|
|
29
|
-
if (!(await toolAvailable())) throw new Error("roslyn-extract.dll not
|
|
35
|
+
if (!(await toolAvailable())) throw new Error("roslyn-extract.dll not available (no dotnet on PATH, or the lazy build failed — run `npm run build:roslyn` to retry with warnings)");
|
|
30
36
|
const { code, out, err } = await run("dotnet", [TOOL_DLL, root]);
|
|
31
37
|
if (code !== 0) throw new Error(`roslyn-extract failed (exit ${code}): ${err.slice(-300)}`);
|
|
32
38
|
let parsed;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
// roslyn_build.mjs — shared build logic for the Roslyn C# semantic extractor
|
|
2
|
+
// (roslyn/publish/roslyn-extract.dll). Used by two callers: the lazy-build path
|
|
3
|
+
// in cs_roslyn.mjs (triggered on the first real C# extraction attempt in a
|
|
4
|
+
// process, not on `npm install`) and the explicit `npm run build:roslyn`
|
|
5
|
+
// prewarm command (e.g. baking the dll into a Docker image ahead of time).
|
|
6
|
+
//
|
|
7
|
+
// Best-effort and silent-by-default: no dotnet on PATH -> skip, tree-sitter
|
|
8
|
+
// (src/cs_treesitter.mjs) covers the absent case. A `dotnet publish` failure
|
|
9
|
+
// (e.g. no network for the first NuGet restore) is a warning, never thrown.
|
|
10
|
+
import { access } from "node:fs/promises";
|
|
11
|
+
import { spawn } from "node:child_process";
|
|
12
|
+
import { dirname, join } from "node:path";
|
|
13
|
+
import { fileURLToPath } from "node:url";
|
|
14
|
+
|
|
15
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
16
|
+
export const ROOT = join(here, "..");
|
|
17
|
+
export const ROSLYN_DIR = join(ROOT, "roslyn");
|
|
18
|
+
export const DLL = join(ROSLYN_DIR, "publish", "roslyn-extract.dll");
|
|
19
|
+
|
|
20
|
+
function run(cmd, args, opts = {}) {
|
|
21
|
+
return new Promise((resolve) => {
|
|
22
|
+
const child = spawn(cmd, args, {
|
|
23
|
+
env: { ...process.env, DOTNET_CLI_TELEMETRY_OPTOUT: "1", DOTNET_NOLOGO: "1" },
|
|
24
|
+
...opts,
|
|
25
|
+
});
|
|
26
|
+
let out = "";
|
|
27
|
+
let err = "";
|
|
28
|
+
child.stdout?.on("data", (d) => (out += d));
|
|
29
|
+
child.stderr?.on("data", (d) => (err += d));
|
|
30
|
+
child.on("close", (code) => resolve({ code: code ?? -1, out, err }));
|
|
31
|
+
child.on("error", () => resolve({ code: -1, out, err: "" }));
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async function exists(p) {
|
|
36
|
+
try { await access(p); return true; } catch { return false; }
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** Build the Roslyn dll if it's missing and `dotnet` is on PATH.
|
|
40
|
+
* @returns {Promise<boolean>} true if the dll is present after this call
|
|
41
|
+
* (already built, or built now); false otherwise (no dotnet, or publish
|
|
42
|
+
* failed — caller falls back to tree-sitter). */
|
|
43
|
+
export async function ensureRoslynBuilt({ quiet = false } = {}) {
|
|
44
|
+
if (await exists(DLL)) return true;
|
|
45
|
+
|
|
46
|
+
const dotnetCheck = await run("dotnet", ["--version"]);
|
|
47
|
+
if (dotnetCheck.code !== 0) return false; // no .NET SDK — tree-sitter fallback covers C#
|
|
48
|
+
|
|
49
|
+
const publish = await run("dotnet", ["publish", "-c", "Release", "-o", "publish"], { cwd: ROSLYN_DIR });
|
|
50
|
+
if (publish.code !== 0) {
|
|
51
|
+
if (!quiet) {
|
|
52
|
+
console.warn("[seonix] Roslyn C# extractor build failed — falling back to tree-sitter for C#.");
|
|
53
|
+
console.warn(`[seonix] dotnet publish exited ${publish.code}: ${publish.err.slice(-300)}`);
|
|
54
|
+
}
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
if (!quiet) console.log("[seonix] Roslyn C# extractor built (full semantic call/type resolution enabled).");
|
|
58
|
+
return true;
|
|
59
|
+
}
|