sciogen 0.1.2__tar.gz → 0.1.3__tar.gz
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.
- {sciogen-0.1.2 → sciogen-0.1.3}/PKG-INFO +8 -2
- {sciogen-0.1.2 → sciogen-0.1.3}/README.md +7 -1
- {sciogen-0.1.2 → sciogen-0.1.3}/pyproject.toml +1 -1
- {sciogen-0.1.2 → sciogen-0.1.3}/sciogen/__init__.py +1 -1
- {sciogen-0.1.2 → sciogen-0.1.3}/sciogen/cli/explore/template.html +132 -42
- {sciogen-0.1.2 → sciogen-0.1.3}/site/docs.html +36 -1
- {sciogen-0.1.2 → sciogen-0.1.3}/.gitignore +0 -0
- {sciogen-0.1.2 → sciogen-0.1.3}/LICENSE +0 -0
- {sciogen-0.1.2 → sciogen-0.1.3}/docs/architecture.md +0 -0
- {sciogen-0.1.2 → sciogen-0.1.3}/docs/cli.md +0 -0
- {sciogen-0.1.2 → sciogen-0.1.3}/docs/mcp.md +0 -0
- {sciogen-0.1.2 → sciogen-0.1.3}/docs/quickstart.md +0 -0
- {sciogen-0.1.2 → sciogen-0.1.3}/docs/schema.md +0 -0
- {sciogen-0.1.2 → sciogen-0.1.3}/sciogen/__main__.py +0 -0
- {sciogen-0.1.2 → sciogen-0.1.3}/sciogen/api.py +0 -0
- {sciogen-0.1.2 → sciogen-0.1.3}/sciogen/cli/__init__.py +0 -0
- {sciogen-0.1.2 → sciogen-0.1.3}/sciogen/cli/banner.py +0 -0
- {sciogen-0.1.2 → sciogen-0.1.3}/sciogen/cli/console.py +0 -0
- {sciogen-0.1.2 → sciogen-0.1.3}/sciogen/cli/explore/__init__.py +0 -0
- {sciogen-0.1.2 → sciogen-0.1.3}/sciogen/cli/main.py +0 -0
- {sciogen-0.1.2 → sciogen-0.1.3}/sciogen/config.py +0 -0
- {sciogen-0.1.2 → sciogen-0.1.3}/sciogen/discovery.py +0 -0
- {sciogen-0.1.2 → sciogen-0.1.3}/sciogen/embed/__init__.py +0 -0
- {sciogen-0.1.2 → sciogen-0.1.3}/sciogen/embed/hashing.py +0 -0
- {sciogen-0.1.2 → sciogen-0.1.3}/sciogen/embed/nomic.py +0 -0
- {sciogen-0.1.2 → sciogen-0.1.3}/sciogen/index/__init__.py +0 -0
- {sciogen-0.1.2 → sciogen-0.1.3}/sciogen/index/pipeline.py +0 -0
- {sciogen-0.1.2 → sciogen-0.1.3}/sciogen/ir.py +0 -0
- {sciogen-0.1.2 → sciogen-0.1.3}/sciogen/mcp/__init__.py +0 -0
- {sciogen-0.1.2 → sciogen-0.1.3}/sciogen/mcp/server.py +0 -0
- {sciogen-0.1.2 → sciogen-0.1.3}/sciogen/normalize/__init__.py +0 -0
- {sciogen-0.1.2 → sciogen-0.1.3}/sciogen/normalize/base.py +0 -0
- {sciogen-0.1.2 → sciogen-0.1.3}/sciogen/normalize/generic.py +0 -0
- {sciogen-0.1.2 → sciogen-0.1.3}/sciogen/normalize/javascript.py +0 -0
- {sciogen-0.1.2 → sciogen-0.1.3}/sciogen/normalize/python.py +0 -0
- {sciogen-0.1.2 → sciogen-0.1.3}/sciogen/parsing/__init__.py +0 -0
- {sciogen-0.1.2 → sciogen-0.1.3}/sciogen/parsing/languages.py +0 -0
- {sciogen-0.1.2 → sciogen-0.1.3}/sciogen/parsing/parser.py +0 -0
- {sciogen-0.1.2 → sciogen-0.1.3}/sciogen/query/__init__.py +0 -0
- {sciogen-0.1.2 → sciogen-0.1.3}/sciogen/query/engine.py +0 -0
- {sciogen-0.1.2 → sciogen-0.1.3}/sciogen/query/results.py +0 -0
- {sciogen-0.1.2 → sciogen-0.1.3}/sciogen/resolve/__init__.py +0 -0
- {sciogen-0.1.2 → sciogen-0.1.3}/sciogen/resolve/resolver.py +0 -0
- {sciogen-0.1.2 → sciogen-0.1.3}/sciogen/stores/__init__.py +0 -0
- {sciogen-0.1.2 → sciogen-0.1.3}/sciogen/stores/graph.py +0 -0
- {sciogen-0.1.2 → sciogen-0.1.3}/sciogen/stores/meta.py +0 -0
- {sciogen-0.1.2 → sciogen-0.1.3}/sciogen/stores/vectors.py +0 -0
- {sciogen-0.1.2 → sciogen-0.1.3}/site/index.html +0 -0
- {sciogen-0.1.2 → sciogen-0.1.3}/site/public/icon.png +0 -0
- {sciogen-0.1.2 → sciogen-0.1.3}/site/public/logo.png +0 -0
- {sciogen-0.1.2 → sciogen-0.1.3}/tests/conftest.py +0 -0
- {sciogen-0.1.2 → sciogen-0.1.3}/tests/test_cli.py +0 -0
- {sciogen-0.1.2 → sciogen-0.1.3}/tests/test_discovery.py +0 -0
- {sciogen-0.1.2 → sciogen-0.1.3}/tests/test_graph_store.py +0 -0
- {sciogen-0.1.2 → sciogen-0.1.3}/tests/test_normalize_python.py +0 -0
- {sciogen-0.1.2 → sciogen-0.1.3}/tests/test_pipeline_and_query.py +0 -0
- {sciogen-0.1.2 → sciogen-0.1.3}/tests/test_resolver.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sciogen
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.3
|
|
4
4
|
Summary: Codebase intelligence layer — a queryable knowledge graph over your code.
|
|
5
5
|
Project-URL: Homepage, https://ayanbag.github.io/sciogen/
|
|
6
6
|
Project-URL: Repository, https://github.com/ayanbag/sciogen
|
|
@@ -34,7 +34,13 @@ Requires-Dist: einops; extra == 'embeddings'
|
|
|
34
34
|
Requires-Dist: sentence-transformers>=3.0; extra == 'embeddings'
|
|
35
35
|
Description-Content-Type: text/markdown
|
|
36
36
|
|
|
37
|
-
<img src="
|
|
37
|
+
<img src="https://github.com/user-attachments/assets/1f736f23-c647-4838-8901-5db0edb91616" alt="Image" width="100%" />
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
|
|
38
44
|
|
|
39
45
|
<div align="center">
|
|
40
46
|
<p>
|
|
@@ -284,7 +284,8 @@ GRAPH.edges.forEach(e => {
|
|
|
284
284
|
if (adjacency.has(e.dst)) adjacency.get(e.dst).push(e);
|
|
285
285
|
});
|
|
286
286
|
const degree = id => GRAPH.in_degrees[id] || 0;
|
|
287
|
-
|
|
287
|
+
let maxDegree = 1;
|
|
288
|
+
for (const v of Object.values(GRAPH.in_degrees)) if (v > maxDegree) maxDegree = v;
|
|
288
289
|
const nodeSize = id => 22 + 36 * Math.sqrt(degree(id) / maxDegree);
|
|
289
290
|
const shortLabel = n => n.kind === "FileNode" ? n.name.split("/").pop() : (n.name.split(".").pop() || n.name);
|
|
290
291
|
|
|
@@ -293,6 +294,8 @@ const visible = new Set(GRAPH.nodes.filter(n => n.kind === "FileNode").map(n =>
|
|
|
293
294
|
const revealedBy = new Map();
|
|
294
295
|
const expanded = new Set();
|
|
295
296
|
const hiddenKinds = new Set();
|
|
297
|
+
const savedPos = new Map(); // id → {x,y}; lets nodes reappear where they were
|
|
298
|
+
const LAYOUT_ANIM_MAX = 700; // above this many visible nodes, layout runs without animation
|
|
296
299
|
let minConf = 0;
|
|
297
300
|
let currentLayout = "force";
|
|
298
301
|
let shownEdges = 0;
|
|
@@ -374,45 +377,129 @@ const cy = cytoscape({
|
|
|
374
377
|
wheelSensitivity: 0.25,
|
|
375
378
|
});
|
|
376
379
|
|
|
377
|
-
/*
|
|
380
|
+
/* persist node positions after any layout or manual drag, so incremental
|
|
381
|
+
updates never re-simulate — reappearing nodes land where they were */
|
|
382
|
+
cy.on("layoutstop", () => {
|
|
383
|
+
cy.nodes().forEach(n => savedPos.set(n.id(), { x: n.position("x"), y: n.position("y") }));
|
|
384
|
+
});
|
|
385
|
+
cy.on("dragfree", "node", e =>
|
|
386
|
+
savedPos.set(e.target.id(), { x: e.target.position("x"), y: e.target.position("y") }));
|
|
387
|
+
|
|
388
|
+
/* fade the initial file nodes in as one group (not one timer per node) */
|
|
378
389
|
if (!reduce) {
|
|
379
|
-
cy.nodes()
|
|
380
|
-
|
|
381
|
-
|
|
390
|
+
const first = cy.nodes();
|
|
391
|
+
first.style("opacity", 0);
|
|
392
|
+
first.animate({ style: { opacity: 1 } }, { duration: 300, easing: "ease-out" });
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
/* Desired on-screen sets. Edges are collected by walking only the adjacency
|
|
396
|
+
of visible nodes — never the full GRAPH.edges array — so cost scales with
|
|
397
|
+
what's shown, not with the size of the whole codebase. */
|
|
398
|
+
function computeWanted() {
|
|
399
|
+
const wantNodes = new Set();
|
|
400
|
+
for (const id of visible) {
|
|
401
|
+
const n = nodesById.get(id);
|
|
402
|
+
if (n && !hiddenKinds.has(n.kind)) wantNodes.add(id);
|
|
403
|
+
}
|
|
404
|
+
const wantEdges = new Map();
|
|
405
|
+
for (const id of wantNodes) {
|
|
406
|
+
const adj = adjacency.get(id);
|
|
407
|
+
if (!adj) continue;
|
|
408
|
+
for (const e of adj) {
|
|
409
|
+
if (e.kind === "DEFINES" || e.kind === "PART_OF") continue;
|
|
410
|
+
if (e.confidence < minConf) continue;
|
|
411
|
+
if (!wantNodes.has(e.src) || !wantNodes.has(e.dst)) continue;
|
|
412
|
+
const key = e.src + "→" + e.dst + "→" + e.kind;
|
|
413
|
+
if (!wantEdges.has(key)) wantEdges.set(key, e);
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
shownEdges = wantEdges.size;
|
|
417
|
+
return { wantNodes, wantEdges };
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
/* Place freshly-revealed nodes in a ring around whatever expanded them —
|
|
421
|
+
no physics, no global relayout, existing nodes never move. */
|
|
422
|
+
function positionNew(added, curNodes) {
|
|
423
|
+
const groups = new Map();
|
|
424
|
+
added.forEach(n => {
|
|
425
|
+
const id = n.id();
|
|
426
|
+
if (savedPos.has(id)) { n.position(savedPos.get(id)); return; }
|
|
427
|
+
const by = revealedBy.get(id) || "__root";
|
|
428
|
+
(groups.get(by) || groups.set(by, []).get(by)).push(n);
|
|
382
429
|
});
|
|
430
|
+
// position groups whose anchor already existed first, so anchors added in
|
|
431
|
+
// this same batch are themselves placed before their children reference them
|
|
432
|
+
const order = [...groups.keys()].sort((a, b) =>
|
|
433
|
+
(curNodes.has(a) ? 0 : 1) - (curNodes.has(b) ? 0 : 1));
|
|
434
|
+
for (const by of order) {
|
|
435
|
+
const members = groups.get(by);
|
|
436
|
+
const anchor = by !== "__root" ? cy.getElementById(by) : null;
|
|
437
|
+
const has = anchor && anchor.nonempty();
|
|
438
|
+
const cx = has ? anchor.position("x") : cy.width() / 2;
|
|
439
|
+
const cyy = has ? anchor.position("y") : cy.height() / 2;
|
|
440
|
+
const r = 55 + members.length * 7;
|
|
441
|
+
members.forEach((m, i) => {
|
|
442
|
+
const a = (2 * Math.PI * i) / members.length - Math.PI / 2;
|
|
443
|
+
m.position({ x: cx + r * Math.cos(a), y: cyy + r * Math.sin(a) });
|
|
444
|
+
savedPos.set(m.id(), { x: m.position("x"), y: m.position("y") });
|
|
445
|
+
});
|
|
446
|
+
}
|
|
383
447
|
}
|
|
384
448
|
|
|
449
|
+
/* Incremental reconciliation: diff current vs wanted, add/remove only the
|
|
450
|
+
delta inside one batched frame. No cy.json() teardown, no relayout. */
|
|
385
451
|
function refresh(opts) {
|
|
386
452
|
opts = opts || {};
|
|
387
|
-
const
|
|
388
|
-
const
|
|
389
|
-
const
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
if (!before.has(n.id())) {
|
|
397
|
-
n.style("opacity", 0);
|
|
398
|
-
n.animate({ style: { opacity: 1 } }, { duration: 240, easing: "ease-out" });
|
|
399
|
-
}
|
|
400
|
-
});
|
|
453
|
+
const { wantNodes, wantEdges } = computeWanted();
|
|
454
|
+
const curNodes = new Set(cy.nodes().map(n => n.id()));
|
|
455
|
+
const curEdges = new Set(cy.edges().map(e => e.id()));
|
|
456
|
+
|
|
457
|
+
let remove = cy.collection();
|
|
458
|
+
cy.nodes().forEach(n => {
|
|
459
|
+
if (!wantNodes.has(n.id())) {
|
|
460
|
+
savedPos.set(n.id(), { x: n.position("x"), y: n.position("y") });
|
|
461
|
+
remove = remove.union(n);
|
|
401
462
|
}
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
463
|
+
});
|
|
464
|
+
cy.edges().forEach(e => { if (!wantEdges.has(e.id())) remove = remove.union(e); });
|
|
465
|
+
|
|
466
|
+
const addNodes = [], addEdges = [];
|
|
467
|
+
for (const id of wantNodes) {
|
|
468
|
+
if (curNodes.has(id)) continue;
|
|
469
|
+
const n = nodesById.get(id);
|
|
470
|
+
addNodes.push({ group: "nodes", data: { id, label: shortLabel(n), kind: n.kind, size: nodeSize(id) } });
|
|
471
|
+
}
|
|
472
|
+
for (const [key, e] of wantEdges) {
|
|
473
|
+
if (curEdges.has(key)) continue;
|
|
474
|
+
addEdges.push({ group: "edges", data: { id: key, source: e.src, target: e.dst, kind: e.kind, confidence: e.confidence }, classes: edgeClass(e.confidence) });
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
let added = cy.collection();
|
|
478
|
+
cy.batch(() => {
|
|
479
|
+
if (remove.nonempty()) cy.remove(remove);
|
|
480
|
+
if (addNodes.length) { added = cy.add(addNodes); positionNew(added, curNodes); }
|
|
481
|
+
if (addEdges.length) cy.add(addEdges);
|
|
482
|
+
});
|
|
407
483
|
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
leaving.animate({ style: { opacity: 0 } }, { duration: 150, easing: "ease-in" });
|
|
412
|
-
setTimeout(doUpdate, 160);
|
|
413
|
-
} else {
|
|
414
|
-
doUpdate();
|
|
484
|
+
if (!reduce && added.nonempty()) {
|
|
485
|
+
added.style("opacity", 0);
|
|
486
|
+
added.animate({ style: { opacity: 1 } }, { duration: 240, easing: "ease-out" });
|
|
415
487
|
}
|
|
488
|
+
if (opts.fit) cy.animate({ fit: { padding: 40 }, duration: reduce ? 0 : 350, easing: "ease-out" });
|
|
489
|
+
updateStats();
|
|
490
|
+
if (opts.then) opts.then();
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
/* Explicit, user-triggered global relayout (layout buttons, expand-all).
|
|
494
|
+
Skips animation past LAYOUT_ANIM_MAX so big graphs snap instead of grind. */
|
|
495
|
+
function runLayout(opts) {
|
|
496
|
+
opts = opts || {};
|
|
497
|
+
const big = cy.nodes().length > LAYOUT_ANIM_MAX;
|
|
498
|
+
const cfg = Object.assign({}, LAYOUTS[currentLayout], {
|
|
499
|
+
animate: (reduce || big) ? false : (currentLayout === "force" ? "end" : true),
|
|
500
|
+
fit: !!opts.fit,
|
|
501
|
+
});
|
|
502
|
+
cy.layout(cfg).run();
|
|
416
503
|
}
|
|
417
504
|
|
|
418
505
|
function updateStats() {
|
|
@@ -497,8 +584,7 @@ function esc(s) { const d = document.createElement("div"); d.textContent = s; re
|
|
|
497
584
|
cy.on("mouseover", "node", evt => {
|
|
498
585
|
const n = evt.target;
|
|
499
586
|
const hood = n.closedNeighborhood();
|
|
500
|
-
cy.elements().not(hood).addClass("dim");
|
|
501
|
-
hood.addClass("hot");
|
|
587
|
+
cy.batch(() => { cy.elements().not(hood).addClass("dim"); hood.addClass("hot"); });
|
|
502
588
|
tip.innerHTML = nodeTip(n);
|
|
503
589
|
tip.classList.add("show");
|
|
504
590
|
moveTip(evt);
|
|
@@ -506,15 +592,17 @@ cy.on("mouseover", "node", evt => {
|
|
|
506
592
|
});
|
|
507
593
|
cy.on("mouseover", "edge", evt => {
|
|
508
594
|
const e = evt.target;
|
|
509
|
-
cy.
|
|
510
|
-
|
|
595
|
+
cy.batch(() => {
|
|
596
|
+
cy.elements().not(e.connectedNodes().union(e)).addClass("dim");
|
|
597
|
+
e.addClass("hot"); e.connectedNodes().addClass("hot");
|
|
598
|
+
});
|
|
511
599
|
tip.innerHTML = edgeTip(e);
|
|
512
600
|
tip.classList.add("show");
|
|
513
601
|
moveTip(evt);
|
|
514
602
|
});
|
|
515
603
|
cy.on("mousemove", "node, edge", moveTip);
|
|
516
604
|
cy.on("mouseout", "node, edge", () => {
|
|
517
|
-
cy.elements().removeClass("dim hot");
|
|
605
|
+
cy.batch(() => cy.elements().removeClass("dim hot"));
|
|
518
606
|
tip.classList.remove("show");
|
|
519
607
|
document.getElementById("cy").style.cursor = "";
|
|
520
608
|
});
|
|
@@ -651,15 +739,15 @@ searchInput.addEventListener("blur", () => setTimeout(closeSug, 150));
|
|
|
651
739
|
|
|
652
740
|
/* ---------------------------------------------------- toolbar controls */
|
|
653
741
|
document.getElementById("btn-expand").onclick = () => {
|
|
654
|
-
GRAPH.nodes.forEach(n => visible.add(n.id));
|
|
655
|
-
|
|
656
|
-
|
|
742
|
+
GRAPH.nodes.forEach(n => { visible.add(n.id); expanded.add(n.id); });
|
|
743
|
+
refresh(); // add the full delta incrementally (no layout inside)
|
|
744
|
+
runLayout({ fit: true }); // one explicit relayout to arrange the whole graph
|
|
657
745
|
};
|
|
658
746
|
document.getElementById("btn-collapse").onclick = () => {
|
|
659
747
|
visible.clear(); revealedBy.clear(); expanded.clear();
|
|
660
748
|
GRAPH.nodes.filter(n => n.kind === "FileNode").forEach(n => visible.add(n.id));
|
|
661
749
|
hidePanel();
|
|
662
|
-
refresh({ fit: true });
|
|
750
|
+
refresh({ fit: true }); // file nodes stay put on their saved positions
|
|
663
751
|
};
|
|
664
752
|
document.getElementById("btn-fit").onclick = () =>
|
|
665
753
|
cy.animate({ fit: { padding: 40 }, duration: reduce ? 0 : 350, easing: "ease-out" });
|
|
@@ -669,16 +757,18 @@ function setLayout(name) {
|
|
|
669
757
|
currentLayout = name;
|
|
670
758
|
btnForce.classList.toggle("active", name === "force");
|
|
671
759
|
btnHier.classList.toggle("active", name === "hier");
|
|
672
|
-
|
|
760
|
+
runLayout({ fit: true }); // relayout existing nodes in place — no rebuild
|
|
673
761
|
}
|
|
674
762
|
btnForce.onclick = () => setLayout("force");
|
|
675
763
|
btnHier.onclick = () => setLayout("hier");
|
|
676
764
|
|
|
677
765
|
const confSlider = document.getElementById("conf"), confVal = document.getElementById("conf-val");
|
|
766
|
+
let confTimer = null;
|
|
678
767
|
confSlider.addEventListener("input", () => {
|
|
679
768
|
minConf = parseFloat(confSlider.value);
|
|
680
769
|
confVal.textContent = minConf.toFixed(2);
|
|
681
|
-
|
|
770
|
+
clearTimeout(confTimer);
|
|
771
|
+
confTimer = setTimeout(refresh, 90); // debounce; only edges change, nodes never move
|
|
682
772
|
});
|
|
683
773
|
|
|
684
774
|
/* ------------------------------------------------------ legend filters */
|
|
@@ -367,6 +367,10 @@
|
|
|
367
367
|
<a href="#cli">CLI reference</a>
|
|
368
368
|
<a href="#configuration">Configuration</a>
|
|
369
369
|
</div>
|
|
370
|
+
<div class="group">
|
|
371
|
+
<div class="group-label">Community</div>
|
|
372
|
+
<a href="#contributing">Contributing</a>
|
|
373
|
+
</div>
|
|
370
374
|
</aside>
|
|
371
375
|
|
|
372
376
|
<main class="doc">
|
|
@@ -817,10 +821,41 @@
|
|
|
817
821
|
<tr><td><code>SCIOGEN_DATA_DIR</code></td><td>Override the index location (default <code><project>/.sciogen</code>)</td></tr>
|
|
818
822
|
</tbody>
|
|
819
823
|
</table></div>
|
|
824
|
+
</section>
|
|
825
|
+
|
|
826
|
+
<!-- ============================ CONTRIBUTING ============================ -->
|
|
827
|
+
<section class="block" id="contributing">
|
|
828
|
+
<h2 class="reveal">Contributing <a class="hash" href="#contributing">#</a></h2>
|
|
829
|
+
<p class="reveal">sciogen is open source and contributions are welcome — bug reports, language-normalizer improvements, docs, and features all move it forward. The complete guide lives in <a href="https://github.com/ayanbag/sciogen/blob/master/CONTRIBUTING.md" target="_blank" rel="noopener">CONTRIBUTING.md</a>; the essentials are below.</p>
|
|
830
|
+
|
|
831
|
+
<h3 class="reveal">Set up a dev environment</h3>
|
|
832
|
+
<p class="reveal">sciogen targets <b>Python 3.10+</b> and builds with hatchling. Install it <b>editable</b> (<code>-e</code>) so source edits — including the version and CLI banner — take effect immediately, with no reinstall:</p>
|
|
833
|
+
<div class="code reveal"><span class="lang">shell</span><button class="copy" type="button" data-copy='git clone https://github.com/ayanbag/sciogen && cd sciogen && pip install -e ".[dev,embeddings]"' aria-label="Copy"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="9" y="9" width="12" height="12" rx="2"/><path d="M5 15V5a2 2 0 0 1 2-2h10"/></svg></button>
|
|
834
|
+
<pre><span class="g">$</span> git clone https://github.com/ayanbag/sciogen
|
|
835
|
+
<span class="g">$</span> cd sciogen
|
|
836
|
+
<span class="g">$</span> pip install -e ".[dev,embeddings]"</pre></div>
|
|
837
|
+
<p class="reveal">Then confirm your environment is live — both must print the <b>same</b> version; if they disagree you're running a stale install:</p>
|
|
838
|
+
<div class="code reveal"><span class="lang">shell</span><button class="copy" type="button" data-copy='python -c "import sciogen; print(sciogen.__version__)" && python -m sciogen --version' aria-label="Copy"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="9" y="9" width="12" height="12" rx="2"/><path d="M5 15V5a2 2 0 0 1 2-2h10"/></svg></button>
|
|
839
|
+
<pre><span class="g">$</span> python -c "import sciogen; print(sciogen.__version__)"
|
|
840
|
+
<span class="g">$</span> python -m sciogen --version</pre></div>
|
|
841
|
+
|
|
842
|
+
<h3 class="reveal">Run the tests</h3>
|
|
843
|
+
<p class="reveal">Every change should keep the suite green. New behavior needs a test; a bug fix should add a regression test that fails before and passes after.</p>
|
|
844
|
+
<div class="code reveal"><span class="lang">shell</span><button class="copy" type="button" data-copy="pytest" aria-label="Copy"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="9" y="9" width="12" height="12" rx="2"/><path d="M5 15V5a2 2 0 0 1 2-2h10"/></svg></button>
|
|
845
|
+
<pre><span class="g">$</span> pytest <span class="mut"># full suite</span>
|
|
846
|
+
<span class="g">$</span> pytest -p no:randomly <span class="mut"># deterministic order</span></pre></div>
|
|
847
|
+
|
|
848
|
+
<div class="callout reveal">
|
|
849
|
+
<span class="t">What belongs in sciogen</span>
|
|
850
|
+
<p>sciogen is a static index, not a generative tool. A few constraints are non-negotiable, and a PR that breaks one will be asked to change: <b>no LLM calls</b> anywhere; <b>no token counting or context-window logic</b>; query methods return <b>typed nodes, never raw source</b>; the pipeline <b>writes every edge</b> and confidence is filtered at query time, not at write time. Language-specific logic lives in exactly one place — the <b>AST normalizer</b> — so everything downstream stays language-agnostic.</p>
|
|
851
|
+
</div>
|
|
852
|
+
|
|
853
|
+
<h3 class="reveal">Versioning</h3>
|
|
854
|
+
<p class="reveal">The version lives in a <b>single place</b> — <code>__version__</code> in <code>sciogen/__init__.py</code>. <code>pyproject.toml</code> reads it via hatchling and the CLI banner imports the same constant, so bump that one line and everything stays in lockstep. Never add a second version string.</p>
|
|
820
855
|
|
|
821
856
|
<div class="doc-nav reveal">
|
|
822
857
|
<a href="index.html"><span class="lbl">← Back</span><div class="ttl">sciogen home</div></a>
|
|
823
|
-
<a class="next" href="https://github.com/ayanbag/sciogen" target="_blank" rel="noopener"><span class="lbl">
|
|
858
|
+
<a class="next" href="https://github.com/ayanbag/sciogen/blob/master/CONTRIBUTING.md" target="_blank" rel="noopener"><span class="lbl">Full guide →</span><div class="ttl">CONTRIBUTING.md</div></a>
|
|
824
859
|
</div>
|
|
825
860
|
</section>
|
|
826
861
|
</main>
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|