@polycode-projects/seonix 0.10.7 → 0.10.9
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/bin/cli.mjs +68 -3
- package/package.json +2 -2
package/bin/cli.mjs
CHANGED
|
@@ -22,6 +22,10 @@
|
|
|
22
22
|
// seonix cli index_repository '{"multi_root":"<abs-dir>"}' → estate discovery: every immediate
|
|
23
23
|
// child directory carrying a .git (dir or file) is indexed as a repo, merged into
|
|
24
24
|
// <multi_root>/.seonix/ (discovered/skipped counts logged to stderr)
|
|
25
|
+
// seonix cli index_repository --multi-root [path] → same, flag form — no JSON
|
|
26
|
+
// quoting needed; a bare `--multi-root` (no path) defaults to cwd, e.g. `cd <estate> &&
|
|
27
|
+
// npx seonix cli index_repository --multi-root`. `--repo-path [path]` and `--out-root
|
|
28
|
+
// <path>` (always needs a value) are the flag forms of the other two path args.
|
|
25
29
|
// seonix cli sync '{"multi_root":"<abs-dir>"}' → incrementally re-index the estate: fingerprint
|
|
26
30
|
// every child repo (git/gitparent/plain), re-extract ONLY the changed ones (per-repo cache in
|
|
27
31
|
// .seonix/cache/), one union rebuild = exact full-re-index. Unchanged-everything = byte-stable
|
|
@@ -54,7 +58,7 @@
|
|
|
54
58
|
|
|
55
59
|
import { dirname, join } from "node:path";
|
|
56
60
|
import { existsSync } from "node:fs";
|
|
57
|
-
import { readFile, writeFile } from "node:fs/promises";
|
|
61
|
+
import { readFile, writeFile, readdir } from "node:fs/promises";
|
|
58
62
|
import { fileURLToPath } from "node:url";
|
|
59
63
|
import { startServer } from "../src/server.mjs";
|
|
60
64
|
import { dispatchTool, buildContextBundle, TOOLS } from "../src/server.mjs";
|
|
@@ -80,6 +84,32 @@ function parsePayload(payload) {
|
|
|
80
84
|
catch { return null; }
|
|
81
85
|
}
|
|
82
86
|
|
|
87
|
+
const INDEX_FLAG_KEYS = { "--multi-root": "multi_root", "--repo-path": "repo_path", "--out-root": "out_root" };
|
|
88
|
+
|
|
89
|
+
/** Flag-style alternative to index_repository's JSON payload — `--multi-root [path]` /
|
|
90
|
+
* `--repo-path [path]` (also `--flag=path`), so `npx seonix cli index_repository
|
|
91
|
+
* --multi-root` works without JSON-quoting a path. A bare `--multi-root`/`--repo-path`
|
|
92
|
+
* (no path following, or the payload ends there) defaults to cwd, matching the JSON form's
|
|
93
|
+
* own cwd-default convention. `--out-root` always needs an explicit value — there's no
|
|
94
|
+
* sensible cwd default for it. Returns an args object shaped like the JSON payload, or
|
|
95
|
+
* null if the first token isn't a recognised flag (falls back to JSON parsing). */
|
|
96
|
+
function parseIndexFlags(argv) {
|
|
97
|
+
const args = {};
|
|
98
|
+
for (let i = 0; i < argv.length; i++) {
|
|
99
|
+
const tok = argv[i];
|
|
100
|
+
const eq = tok.indexOf("=");
|
|
101
|
+
const flag = eq === -1 ? tok : tok.slice(0, eq);
|
|
102
|
+
const key = INDEX_FLAG_KEYS[flag];
|
|
103
|
+
if (!key) return null;
|
|
104
|
+
if (eq !== -1) { args[key] = tok.slice(eq + 1); continue; }
|
|
105
|
+
const next = argv[i + 1];
|
|
106
|
+
if (next !== undefined && !next.startsWith("--")) { args[key] = next; i++; }
|
|
107
|
+
else if (key === "multi_root" || key === "repo_path") { args[key] = process.cwd(); }
|
|
108
|
+
else return null;
|
|
109
|
+
}
|
|
110
|
+
return Object.keys(args).length ? args : null;
|
|
111
|
+
}
|
|
112
|
+
|
|
83
113
|
/** Nearest ancestor of `startDir` (itself first) containing a .seonix/ directory, or null. */
|
|
84
114
|
function findIndexRoot(startDir = process.cwd()) {
|
|
85
115
|
let dir = startDir;
|
|
@@ -113,6 +143,36 @@ function defaultRepoPath(args, { mustExist = true } = {}) {
|
|
|
113
143
|
return args;
|
|
114
144
|
}
|
|
115
145
|
|
|
146
|
+
/** Single-mode index_repository against a directory that (a) isn't itself a git repo and
|
|
147
|
+
* (b) has ≥2 immediate child directories that ARE — the exact signature of an estate root
|
|
148
|
+
* mistaken for one flat repo (the `multi_root` docs' own warning: "repo_path would index it
|
|
149
|
+
* as one flat repo"). Silent consequence: git history extraction fails against the non-repo
|
|
150
|
+
* root (0 commits, no error the caller necessarily notices among the rest of the index
|
|
151
|
+
* output), module ids aren't per-repo-prefixed, and every sub-repo gets flattened together.
|
|
152
|
+
* Best-effort (readdir failure just means no warning, never a crash) — this only ADDS a
|
|
153
|
+
* warning in a case that previously silently mis-indexed, so it can't change any existing
|
|
154
|
+
* single-repo index's output. */
|
|
155
|
+
async function warnIfLooksLikeEstateRoot(repoPath) {
|
|
156
|
+
if (existsSync(join(repoPath, ".git"))) return;
|
|
157
|
+
let entries;
|
|
158
|
+
try { entries = await readdir(repoPath, { withFileTypes: true }); }
|
|
159
|
+
catch { return; }
|
|
160
|
+
let childRepoCount = 0;
|
|
161
|
+
for (const e of entries) {
|
|
162
|
+
if (e.isDirectory() && existsSync(join(repoPath, e.name, ".git"))) childRepoCount++;
|
|
163
|
+
if (childRepoCount >= 2) break;
|
|
164
|
+
}
|
|
165
|
+
if (childRepoCount >= 2) {
|
|
166
|
+
process.stderr.write(
|
|
167
|
+
`seonix: WARNING — ${repoPath} has no .git of its own, but multiple child directories do. ` +
|
|
168
|
+
"This looks like a multi-repo estate root, not a single repo — indexing it this way flattens " +
|
|
169
|
+
"every sub-repo together with NO git history (git log fails against a non-repo root) and no " +
|
|
170
|
+
"per-repo module-id prefixing. If that's not what you want, re-run with " +
|
|
171
|
+
`'{"multi_root":"${repoPath}"}' instead, which discovers each child repo and indexes it properly.\n`,
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
116
176
|
// Hot tools (server.mjs's TOOLS) carry an inputSchema but no example value, so their
|
|
117
177
|
// example-args + primary-arg-key aren't derivable the way COLD_TOOLS' are — hand-maintained
|
|
118
178
|
// here, right next to COLD_TOOLS' import, so a new hot tool is a one-line addition in both places.
|
|
@@ -482,9 +542,13 @@ async function main() {
|
|
|
482
542
|
// '{"repo_paths":[…],"out_root":"<abs>"}' (explicit n-repo merge) or
|
|
483
543
|
// '{"multi_root":"<abs>"}' (discover child repos, merge into <multi_root>/.seonix/).
|
|
484
544
|
if (sub === "index_repository") {
|
|
485
|
-
const
|
|
545
|
+
const isFlagForm = payload !== undefined && payload.startsWith("--");
|
|
546
|
+
const args = isFlagForm ? parseIndexFlags(process.argv.slice(4)) : parsePayload(payload);
|
|
486
547
|
if (args === null) {
|
|
487
|
-
process.stderr.write(
|
|
548
|
+
process.stderr.write(
|
|
549
|
+
"seonix: index_repository expects a JSON arg, e.g. '{\"repo_path\":\"/abs\"}', " +
|
|
550
|
+
"or a flag: --multi-root [path], --repo-path [path], --out-root <path>\n",
|
|
551
|
+
);
|
|
488
552
|
process.exit(2);
|
|
489
553
|
}
|
|
490
554
|
const given = ["repo_path", "repo_paths", "multi_root"].filter((k) => args[k] !== undefined);
|
|
@@ -557,6 +621,7 @@ async function main() {
|
|
|
557
621
|
};
|
|
558
622
|
|
|
559
623
|
if (args.repo_path) {
|
|
624
|
+
await warnIfLooksLikeEstateRoot(args.repo_path);
|
|
560
625
|
const { graphFile, counts, summary } = await indexRepository(args.repo_path, { ignores: args.ignores !== false, historyDepth, extraIgnores, languages: tomlLanguages, interfaces: tomlInterfaces });
|
|
561
626
|
emitSummary(graphFile, counts, "");
|
|
562
627
|
// A1: the human summary MD goes to STDOUT (bench ignores index stdout — safe;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@polycode-projects/seonix",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.9",
|
|
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.",
|
|
@@ -87,7 +87,7 @@
|
|
|
87
87
|
},
|
|
88
88
|
"dependencies": {
|
|
89
89
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
90
|
-
"@polycode-projects/the-mechanical-code-talker": "^0.9.
|
|
90
|
+
"@polycode-projects/the-mechanical-code-talker": "^0.9.8",
|
|
91
91
|
"cytoscape": "^3.30.0",
|
|
92
92
|
"smol-toml": "^1.7.0",
|
|
93
93
|
"tree-sitter": "^0.21.1",
|