@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.
@@ -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) @class.name) @mixin
779
- (extension_declaration (identifier) @class.name) @ext
780
- (function_signature (identifier) @function.name) @function
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
- return runGenericParser(
784
- {
785
- grammar: "dart",
786
- query: QUERY4,
787
- decls: [
788
- { declCapture: "class", nameCapture: "class.name", kind: "class" },
789
- { declCapture: "mixin", nameCapture: "class.name", kind: "class" },
790
- { declCapture: "ext", nameCapture: "class.name", kind: "class" },
791
- { declCapture: "function", nameCapture: "function.name", kind: "function" }
792
- ]
793
- },
794
- f,
795
- source
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 firstLine2(text, max = 200) {
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: firstLine2(funcDecl.text)
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: firstLine2(classDecl.text)
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 firstLine3(text, max = 200) {
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: firstLine3(shape.decl.text)
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 Parser.Language.load(wasmPath);
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 = 2;
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
- "proactively update `.synthra/CONTEXT.md` with:",
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
- "- **Current Task**: one sentence on what was being worked on",
1548
- "- **Key Decisions**: bullet list, max 3 items",
1549
- "- **Next Steps**: bullet list, max 3 items",
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
- "Keep `CONTEXT.md` under 20 lines total. Don't summarise the conversation",
1552
- "\u2014 write only what's needed to resume next session.",
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._",