@jefuriiij/synthra 0.1.9 → 0.1.11
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/CHANGELOG.md +109 -0
- package/README.md +5 -3
- package/dist/cli/index.js +218 -71
- package/dist/cli/index.js.map +1 -1
- package/dist/server/index.js +129 -34
- package/dist/server/index.js.map +1 -1
- package/package.json +3 -2
package/dist/server/index.js
CHANGED
|
@@ -485,7 +485,7 @@ function extractKeywords(content, _ext) {
|
|
|
485
485
|
}
|
|
486
486
|
|
|
487
487
|
// src/scanner/extract.ts
|
|
488
|
-
var RESOLVE_EXTS = [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".py", ".svelte", ".vue"];
|
|
488
|
+
var RESOLVE_EXTS = [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".py", ".svelte", ".vue", ".dart"];
|
|
489
489
|
var INDEX_FILES = ["index.ts", "index.tsx", "index.js", "index.jsx", "__init__.py"];
|
|
490
490
|
function fileId(relPath) {
|
|
491
491
|
return `file:${relPath}`;
|
|
@@ -625,7 +625,7 @@ function buildSymbolIndex(graph) {
|
|
|
625
625
|
// src/scanner/parser.ts
|
|
626
626
|
import { readFile as readFile3 } from "fs/promises";
|
|
627
627
|
import { createRequire } from "module";
|
|
628
|
-
import Parser from "web-tree-sitter";
|
|
628
|
+
import { Language, Parser } from "web-tree-sitter";
|
|
629
629
|
|
|
630
630
|
// src/scanner/parsers/_generic.ts
|
|
631
631
|
function firstLine(text, max = 200) {
|
|
@@ -774,26 +774,93 @@ async function parseCSharp(f, source) {
|
|
|
774
774
|
|
|
775
775
|
// src/scanner/parsers/dart.ts
|
|
776
776
|
var QUERY4 = `
|
|
777
|
-
(class_definition (identifier) @class.name) @class
|
|
778
|
-
(mixin_declaration (identifier) @
|
|
779
|
-
(extension_declaration (identifier) @
|
|
780
|
-
(
|
|
777
|
+
(class_definition name: (identifier) @class.name) @class
|
|
778
|
+
(mixin_declaration (identifier) @mixin.name) @mixin
|
|
779
|
+
(extension_declaration name: (identifier) @ext.name) @ext
|
|
780
|
+
(enum_declaration name: (identifier) @enum.name) @enum
|
|
781
|
+
(type_alias (type_identifier) @typedef.name) @typedef
|
|
782
|
+
|
|
783
|
+
(program (function_signature name: (identifier) @function.name) @function)
|
|
784
|
+
|
|
785
|
+
(method_signature (function_signature name: (identifier) @method.name)) @method
|
|
786
|
+
(method_signature (getter_signature name: (identifier) @getter.name)) @getter
|
|
787
|
+
(method_signature (setter_signature name: (identifier) @setter.name)) @setter
|
|
788
|
+
(constructor_signature name: (identifier) @ctor.name) @ctor
|
|
789
|
+
|
|
790
|
+
(import_or_export (library_import (import_specification (configurable_uri (uri (string_literal) @import)))))
|
|
781
791
|
`;
|
|
792
|
+
var DECLS = [
|
|
793
|
+
{ declCap: "class", nameCap: "class.name", kind: "class" },
|
|
794
|
+
{ declCap: "mixin", nameCap: "mixin.name", kind: "class" },
|
|
795
|
+
{ declCap: "ext", nameCap: "ext.name", kind: "class" },
|
|
796
|
+
{ declCap: "enum", nameCap: "enum.name", kind: "enum" },
|
|
797
|
+
{ declCap: "typedef", nameCap: "typedef.name", kind: "type" },
|
|
798
|
+
{ declCap: "function", nameCap: "function.name", kind: "function" },
|
|
799
|
+
{ declCap: "method", nameCap: "method.name", kind: "method" },
|
|
800
|
+
{ declCap: "getter", nameCap: "getter.name", kind: "method" },
|
|
801
|
+
{ declCap: "setter", nameCap: "setter.name", kind: "method" },
|
|
802
|
+
{ declCap: "ctor", nameCap: "ctor.name", kind: "method" }
|
|
803
|
+
];
|
|
804
|
+
function firstLine2(text, max = 200) {
|
|
805
|
+
const line = text.split(/\r?\n/, 1)[0] ?? "";
|
|
806
|
+
return line.length > max ? line.slice(0, max) + "\u2026" : line;
|
|
807
|
+
}
|
|
808
|
+
function normalizeDartImport(raw) {
|
|
809
|
+
const stripped = raw.replace(/^['"]|['"]$/g, "");
|
|
810
|
+
if (!stripped) return null;
|
|
811
|
+
if (stripped.startsWith("package:")) return null;
|
|
812
|
+
if (stripped.startsWith("dart:")) return null;
|
|
813
|
+
if (stripped.startsWith(".") || stripped.startsWith("/")) return stripped;
|
|
814
|
+
return `./${stripped}`;
|
|
815
|
+
}
|
|
782
816
|
async function parseDart(f, source) {
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
817
|
+
let symbols = [];
|
|
818
|
+
let imports = [];
|
|
819
|
+
try {
|
|
820
|
+
const { parser, language } = await createParser("dart");
|
|
821
|
+
const tree = parser.parse(source);
|
|
822
|
+
if (!tree) return { file: f, source, symbols, imports, calls: [] };
|
|
823
|
+
const query = language.query(QUERY4);
|
|
824
|
+
const matches = query.matches(tree.rootNode);
|
|
825
|
+
for (const match of matches) {
|
|
826
|
+
const byName = /* @__PURE__ */ new Map();
|
|
827
|
+
for (const cap of match.captures) byName.set(cap.name, cap.node);
|
|
828
|
+
let matched = null;
|
|
829
|
+
for (const d of DECLS) {
|
|
830
|
+
if (byName.has(d.declCap) && byName.has(d.nameCap)) {
|
|
831
|
+
matched = d;
|
|
832
|
+
break;
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
if (matched) {
|
|
836
|
+
const declNode = byName.get(matched.declCap);
|
|
837
|
+
const nameNode = byName.get(matched.nameCap);
|
|
838
|
+
symbols.push({
|
|
839
|
+
name: nameNode.text,
|
|
840
|
+
kind: matched.kind,
|
|
841
|
+
startLine: declNode.startPosition.row + 1,
|
|
842
|
+
endLine: declNode.endPosition.row + 1,
|
|
843
|
+
signature: firstLine2(declNode.text)
|
|
844
|
+
});
|
|
845
|
+
continue;
|
|
846
|
+
}
|
|
847
|
+
const importNode = byName.get("import");
|
|
848
|
+
if (importNode) {
|
|
849
|
+
const norm = normalizeDartImport(importNode.text);
|
|
850
|
+
if (norm) imports.push(norm);
|
|
851
|
+
}
|
|
852
|
+
}
|
|
853
|
+
const seen = /* @__PURE__ */ new Set();
|
|
854
|
+
symbols = symbols.filter((s) => {
|
|
855
|
+
const k = `${s.name}:${s.startLine}`;
|
|
856
|
+
if (seen.has(k)) return false;
|
|
857
|
+
seen.add(k);
|
|
858
|
+
return true;
|
|
859
|
+
});
|
|
860
|
+
imports = Array.from(new Set(imports));
|
|
861
|
+
} catch {
|
|
862
|
+
}
|
|
863
|
+
return { file: f, source, symbols, imports, calls: [] };
|
|
797
864
|
}
|
|
798
865
|
|
|
799
866
|
// src/scanner/parsers/go.ts
|
|
@@ -904,7 +971,7 @@ var QUERY9 = `
|
|
|
904
971
|
(import_from_statement module_name: (dotted_name) @import.from)
|
|
905
972
|
(import_from_statement module_name: (relative_import) @import.from)
|
|
906
973
|
`;
|
|
907
|
-
function
|
|
974
|
+
function firstLine3(text, max = 200) {
|
|
908
975
|
const line = text.split(/\r?\n/, 1)[0] ?? "";
|
|
909
976
|
return line.length > max ? line.slice(0, max) + "\u2026" : line;
|
|
910
977
|
}
|
|
@@ -930,7 +997,7 @@ async function parsePython(f, source) {
|
|
|
930
997
|
kind: isMethod ? "method" : "function",
|
|
931
998
|
startLine: funcDecl.startPosition.row + 1,
|
|
932
999
|
endLine: funcDecl.endPosition.row + 1,
|
|
933
|
-
signature:
|
|
1000
|
+
signature: firstLine3(funcDecl.text)
|
|
934
1001
|
});
|
|
935
1002
|
continue;
|
|
936
1003
|
}
|
|
@@ -942,7 +1009,7 @@ async function parsePython(f, source) {
|
|
|
942
1009
|
kind: "class",
|
|
943
1010
|
startLine: classDecl.startPosition.row + 1,
|
|
944
1011
|
endLine: classDecl.endPosition.row + 1,
|
|
945
|
-
signature:
|
|
1012
|
+
signature: firstLine3(classDecl.text)
|
|
946
1013
|
});
|
|
947
1014
|
continue;
|
|
948
1015
|
}
|
|
@@ -1042,7 +1109,7 @@ function queryFor(grammar) {
|
|
|
1042
1109
|
function unquote(s) {
|
|
1043
1110
|
return s.replace(/^["'`]|["'`]$/g, "");
|
|
1044
1111
|
}
|
|
1045
|
-
function
|
|
1112
|
+
function firstLine4(text, max = 200) {
|
|
1046
1113
|
const line = text.split(/\r?\n/, 1)[0] ?? "";
|
|
1047
1114
|
return line.length > max ? line.slice(0, max) + "\u2026" : line;
|
|
1048
1115
|
}
|
|
@@ -1074,7 +1141,7 @@ async function parseTypeScript(f, source) {
|
|
|
1074
1141
|
kind: shape.kind,
|
|
1075
1142
|
startLine: shape.decl.startPosition.row + 1,
|
|
1076
1143
|
endLine: shape.decl.endPosition.row + 1,
|
|
1077
|
-
signature:
|
|
1144
|
+
signature: firstLine4(shape.decl.text)
|
|
1078
1145
|
});
|
|
1079
1146
|
continue;
|
|
1080
1147
|
}
|
|
@@ -1219,7 +1286,7 @@ async function loadGrammar(name) {
|
|
|
1219
1286
|
const cached = languageCache.get(name);
|
|
1220
1287
|
if (cached) return cached;
|
|
1221
1288
|
const wasmPath = require2.resolve(GRAMMAR_FILES[name]);
|
|
1222
|
-
const lang = await
|
|
1289
|
+
const lang = await Language.load(wasmPath);
|
|
1223
1290
|
languageCache.set(name, lang);
|
|
1224
1291
|
return lang;
|
|
1225
1292
|
}
|
|
@@ -1308,7 +1375,29 @@ var DEFAULT_IGNORE = [
|
|
|
1308
1375
|
".turbo/",
|
|
1309
1376
|
".cache/",
|
|
1310
1377
|
".vscode/",
|
|
1311
|
-
".idea/"
|
|
1378
|
+
".idea/",
|
|
1379
|
+
".vs/",
|
|
1380
|
+
// Flutter / Dart build caches — IDE-rehydrated, contain third-party
|
|
1381
|
+
// type stubs (typescript.d.ts, babylon.js etc.) that contaminate the graph.
|
|
1382
|
+
".dart_tool/",
|
|
1383
|
+
".flutter-plugins",
|
|
1384
|
+
".flutter-plugins-dependencies",
|
|
1385
|
+
// Android / Java / Kotlin / Rust
|
|
1386
|
+
".gradle/",
|
|
1387
|
+
"target/",
|
|
1388
|
+
// iOS / Xcode
|
|
1389
|
+
"Pods/",
|
|
1390
|
+
"DerivedData/",
|
|
1391
|
+
// Python
|
|
1392
|
+
"__pycache__/",
|
|
1393
|
+
".venv/",
|
|
1394
|
+
"venv/",
|
|
1395
|
+
".tox/",
|
|
1396
|
+
".pytest_cache/",
|
|
1397
|
+
".mypy_cache/",
|
|
1398
|
+
".ruff_cache/",
|
|
1399
|
+
// .NET
|
|
1400
|
+
"obj/"
|
|
1312
1401
|
];
|
|
1313
1402
|
var BINARY_EXTS = /* @__PURE__ */ new Set([
|
|
1314
1403
|
".png",
|
|
@@ -1463,7 +1552,7 @@ import { mkdir as mkdir3, readFile as readFile7, stat as stat2, writeFile as wri
|
|
|
1463
1552
|
|
|
1464
1553
|
// src/hooks/claude-md.ts
|
|
1465
1554
|
import { readFile as readFile6, writeFile as writeFile2 } from "fs/promises";
|
|
1466
|
-
var POLICY_VERSION =
|
|
1555
|
+
var POLICY_VERSION = 3;
|
|
1467
1556
|
var POLICY_BEGIN = `<!-- synthra-policy v${POLICY_VERSION} BEGIN -->`;
|
|
1468
1557
|
var POLICY_END = `<!-- synthra-policy v${POLICY_VERSION} END -->`;
|
|
1469
1558
|
var ANY_BLOCK_RE = /<!--\s*synthra-policy\s+v\d+\s+BEGIN\s*-->[\s\S]*?<!--\s*synthra-policy\s+v\d+\s+END\s*-->\s*/g;
|
|
@@ -1542,14 +1631,20 @@ function policyBlock() {
|
|
|
1542
1631
|
"### Session-end resume note",
|
|
1543
1632
|
"",
|
|
1544
1633
|
`When the user signals they're done (e.g. "bye", "wrap up", "done"),`,
|
|
1545
|
-
"
|
|
1634
|
+
"persist the resume state by calling `context_remember` once per bullet.",
|
|
1635
|
+
"Synthra re-renders `.synthra/CONTEXT.md` from those entries at session",
|
|
1636
|
+
"end \u2014 do **NOT** write to `CONTEXT.md` directly, it is a derived view",
|
|
1637
|
+
"and direct edits are overwritten by the Stop hook.",
|
|
1638
|
+
"",
|
|
1639
|
+
"Use these `kind` values:",
|
|
1546
1640
|
"",
|
|
1547
|
-
|
|
1548
|
-
"-
|
|
1549
|
-
|
|
1641
|
+
'- **`kind: "task"`** \u2014 what is being worked on right now (1 entry)',
|
|
1642
|
+
'- **`kind: "decision"`** \u2014 non-obvious choices made this session (max 3)',
|
|
1643
|
+
'- **`kind: "next"`** \u2014 concrete next steps (max 3)',
|
|
1550
1644
|
"",
|
|
1551
|
-
|
|
1552
|
-
|
|
1645
|
+
'Tag entries with the relevant area (`tags: ["auth"]`) and the files',
|
|
1646
|
+
'they touch (`files: ["src/auth.ts"]`) so later `context_recall` queries',
|
|
1647
|
+
"can filter. Keep each `text` to 1\u20132 sentences.",
|
|
1553
1648
|
"",
|
|
1554
1649
|
"_This block is managed by Synthra. Edits inside the BEGIN/END markers",
|
|
1555
1650
|
"are overwritten on every `syn .` run._",
|