@jefuriiij/synthra 0.1.21 → 0.1.22
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 +35 -0
- package/dist/cli/index.js +47 -13
- package/dist/cli/index.js.map +1 -1
- package/dist/dashboard/index.js +4 -4
- package/dist/dashboard/index.js.map +1 -1
- package/dist/server/index.js +43 -9
- package/dist/server/index.js.map +1 -1
- package/package.json +3 -3
package/dist/server/index.js
CHANGED
|
@@ -2780,15 +2780,33 @@ Reason: ${retrieval.reason}
|
|
|
2780
2780
|
return textContent(`${header}
|
|
2781
2781
|
${packed.text}`);
|
|
2782
2782
|
}
|
|
2783
|
+
function resolveFileTarget(graph, filePath) {
|
|
2784
|
+
const files = graph.nodes.filter((n) => n.kind === "file");
|
|
2785
|
+
const exact = files.find((n) => n.path === filePath);
|
|
2786
|
+
if (exact) return { node: exact };
|
|
2787
|
+
const suffix = "/" + filePath;
|
|
2788
|
+
const matches = files.filter((n) => n.path.endsWith(suffix));
|
|
2789
|
+
if (matches.length === 1) return { node: matches[0] };
|
|
2790
|
+
if (matches.length > 1) return { ambiguous: matches.map((n) => n.path) };
|
|
2791
|
+
return { none: true };
|
|
2792
|
+
}
|
|
2783
2793
|
function graphRead(args, ctx) {
|
|
2784
2794
|
const target = typeof args?.target === "string" ? args.target : "";
|
|
2785
2795
|
if (!target) return errorContent("graph_read: 'target' (string) is required");
|
|
2786
2796
|
const [rawFile, symbolName] = target.includes("::") ? target.split("::", 2) : [target, void 0];
|
|
2787
2797
|
const filePath = (rawFile ?? "").trim();
|
|
2788
|
-
const
|
|
2789
|
-
|
|
2790
|
-
|
|
2791
|
-
|
|
2798
|
+
const resolved = resolveFileTarget(ctx.graph, filePath);
|
|
2799
|
+
if ("ambiguous" in resolved) {
|
|
2800
|
+
const shown = resolved.ambiguous.slice(0, 5).join(", ");
|
|
2801
|
+
const more = resolved.ambiguous.length > 5 ? ", \u2026" : "";
|
|
2802
|
+
return errorContent(
|
|
2803
|
+
`graph_read: '${filePath}' matches multiple files (${shown}${more}). Pass a longer path.`
|
|
2804
|
+
);
|
|
2805
|
+
}
|
|
2806
|
+
if ("none" in resolved) {
|
|
2807
|
+
return errorContent(`graph_read: file not found in graph: ${filePath}`);
|
|
2808
|
+
}
|
|
2809
|
+
const fileNode = resolved.node;
|
|
2792
2810
|
if (!symbolName) {
|
|
2793
2811
|
return textContent(`# ${fileNode.path}
|
|
2794
2812
|
|
|
@@ -2796,10 +2814,10 @@ ${fileNode.content}`);
|
|
|
2796
2814
|
}
|
|
2797
2815
|
const cleanSym = symbolName.trim();
|
|
2798
2816
|
const symbol = ctx.graph.nodes.find(
|
|
2799
|
-
(n) => n.kind === "symbol" && n.file ===
|
|
2817
|
+
(n) => n.kind === "symbol" && n.file === fileNode.path && n.name === cleanSym
|
|
2800
2818
|
);
|
|
2801
2819
|
if (!symbol) {
|
|
2802
|
-
return errorContent(`graph_read: symbol '${cleanSym}' not found in ${
|
|
2820
|
+
return errorContent(`graph_read: symbol '${cleanSym}' not found in ${fileNode.path}`);
|
|
2803
2821
|
}
|
|
2804
2822
|
const lines = fileNode.content.split(/\r?\n/);
|
|
2805
2823
|
const body = lines.slice(symbol.start_line - 1, symbol.end_line).join("\n");
|
|
@@ -2984,16 +3002,32 @@ function looksLikeNonSymbolQuery(pattern) {
|
|
|
2984
3002
|
}
|
|
2985
3003
|
return false;
|
|
2986
3004
|
}
|
|
2987
|
-
function recentlyTouchedMatchesQuery(recentPaths, queryTokens) {
|
|
3005
|
+
function recentlyTouchedMatchesQuery(recentPaths, queryTokens, graph) {
|
|
3006
|
+
if (recentPaths.length === 0) return [];
|
|
3007
|
+
const recent = new Set(recentPaths);
|
|
3008
|
+
const keywordsByPath = /* @__PURE__ */ new Map();
|
|
3009
|
+
for (const n of graph.nodes) {
|
|
3010
|
+
if (n.kind === "file" && recent.has(n.path)) keywordsByPath.set(n.path, n.keywords);
|
|
3011
|
+
}
|
|
2988
3012
|
const matches = [];
|
|
2989
3013
|
for (const path of recentPaths) {
|
|
2990
3014
|
const lower = path.toLowerCase();
|
|
3015
|
+
let matched = false;
|
|
2991
3016
|
for (const t of queryTokens) {
|
|
2992
3017
|
if (lower.includes(t)) {
|
|
2993
|
-
|
|
3018
|
+
matched = true;
|
|
2994
3019
|
break;
|
|
2995
3020
|
}
|
|
2996
3021
|
}
|
|
3022
|
+
if (!matched) {
|
|
3023
|
+
for (const kw of keywordsByPath.get(path) ?? []) {
|
|
3024
|
+
if (queryTokens.has(kw)) {
|
|
3025
|
+
matched = true;
|
|
3026
|
+
break;
|
|
3027
|
+
}
|
|
3028
|
+
}
|
|
3029
|
+
}
|
|
3030
|
+
if (matched) matches.push(path);
|
|
2997
3031
|
}
|
|
2998
3032
|
return matches;
|
|
2999
3033
|
}
|
|
@@ -3044,7 +3078,7 @@ async function handleGate(req, ctx) {
|
|
|
3044
3078
|
}
|
|
3045
3079
|
const qTokens = new Set(tokenizeQuery(query));
|
|
3046
3080
|
const recentPaths = ctx.activity.recentFilePaths(RECENT_ACTIVITY_WINDOW_MS);
|
|
3047
|
-
const overlap = recentlyTouchedMatchesQuery(recentPaths, qTokens);
|
|
3081
|
+
const overlap = recentlyTouchedMatchesQuery(recentPaths, qTokens, ctx.graph);
|
|
3048
3082
|
if (overlap.length > 0) {
|
|
3049
3083
|
const res2 = {
|
|
3050
3084
|
decision: "allow",
|