sxng-cli 1.0.5 → 1.0.7

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.
Files changed (65) hide show
  1. package/README.md +120 -4
  2. package/dist/commands/build-graph.d.ts +8 -0
  3. package/dist/commands/build-graph.d.ts.map +1 -0
  4. package/dist/commands/build-graph.js +70 -0
  5. package/dist/commands/build-graph.js.map +1 -0
  6. package/dist/commands/extract.d.ts +11 -0
  7. package/dist/commands/extract.d.ts.map +1 -0
  8. package/dist/commands/extract.js +88 -0
  9. package/dist/commands/extract.js.map +1 -0
  10. package/dist/commands/graph-add.d.ts +13 -0
  11. package/dist/commands/graph-add.d.ts.map +1 -0
  12. package/dist/commands/graph-add.js +155 -0
  13. package/dist/commands/graph-add.js.map +1 -0
  14. package/dist/commands/query-graph.d.ts +11 -0
  15. package/dist/commands/query-graph.d.ts.map +1 -0
  16. package/dist/commands/query-graph.js +153 -0
  17. package/dist/commands/query-graph.js.map +1 -0
  18. package/dist/commands/raw.d.ts +14 -0
  19. package/dist/commands/raw.d.ts.map +1 -0
  20. package/dist/commands/raw.js +125 -0
  21. package/dist/commands/raw.js.map +1 -0
  22. package/dist/commands/session.d.ts +28 -0
  23. package/dist/commands/session.d.ts.map +1 -0
  24. package/dist/commands/session.js +144 -0
  25. package/dist/commands/session.js.map +1 -0
  26. package/dist/config.d.ts +1 -1
  27. package/dist/config.d.ts.map +1 -1
  28. package/dist/config.js +1 -1
  29. package/dist/config.js.map +1 -1
  30. package/dist/deep/dedupe.d.ts +14 -0
  31. package/dist/deep/dedupe.d.ts.map +1 -0
  32. package/dist/deep/dedupe.js +53 -0
  33. package/dist/deep/dedupe.js.map +1 -0
  34. package/dist/deep/extractor.d.ts +29 -0
  35. package/dist/deep/extractor.d.ts.map +1 -0
  36. package/dist/deep/extractor.js +125 -0
  37. package/dist/deep/extractor.js.map +1 -0
  38. package/dist/deep/graph.d.ts +55 -0
  39. package/dist/deep/graph.d.ts.map +1 -0
  40. package/dist/deep/graph.js +153 -0
  41. package/dist/deep/graph.js.map +1 -0
  42. package/dist/deep/index.d.ts +10 -0
  43. package/dist/deep/index.d.ts.map +1 -0
  44. package/dist/deep/index.js +10 -0
  45. package/dist/deep/index.js.map +1 -0
  46. package/dist/deep/keywords.d.ts +27 -0
  47. package/dist/deep/keywords.d.ts.map +1 -0
  48. package/dist/deep/keywords.js +293 -0
  49. package/dist/deep/keywords.js.map +1 -0
  50. package/dist/deep/rrf.d.ts +13 -0
  51. package/dist/deep/rrf.d.ts.map +1 -0
  52. package/dist/deep/rrf.js +23 -0
  53. package/dist/deep/rrf.js.map +1 -0
  54. package/dist/deep/session.d.ts +69 -0
  55. package/dist/deep/session.d.ts.map +1 -0
  56. package/dist/deep/session.js +206 -0
  57. package/dist/deep/session.js.map +1 -0
  58. package/dist/deep/simhash.d.ts +12 -0
  59. package/dist/deep/simhash.d.ts.map +1 -0
  60. package/dist/deep/simhash.js +56 -0
  61. package/dist/deep/simhash.js.map +1 -0
  62. package/dist/runCli.d.ts.map +1 -1
  63. package/dist/runCli.js +394 -100
  64. package/dist/runCli.js.map +1 -1
  65. package/package.json +6 -2
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Content extraction using linkedom + @mozilla/readability
3
+ */
4
+ export interface ExtractorOptions {
5
+ timeoutMs?: number;
6
+ concurrency?: number;
7
+ maxResponseBytes?: number;
8
+ }
9
+ export interface ExtractedContent {
10
+ title: string;
11
+ content: string;
12
+ excerpt: string;
13
+ url: string;
14
+ byline?: string;
15
+ siteName?: string;
16
+ length: number;
17
+ extractedAt: number;
18
+ error?: string;
19
+ }
20
+ export declare class ContentExtractor {
21
+ private timeoutMs;
22
+ private concurrency;
23
+ private maxResponseBytes;
24
+ constructor(options?: ExtractorOptions);
25
+ extract(url: string): Promise<ExtractedContent>;
26
+ extractFromHtml(html: string, url: string): ExtractedContent;
27
+ extractBatch(urls: string[]): Promise<ExtractedContent[]>;
28
+ }
29
+ //# sourceMappingURL=extractor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extractor.d.ts","sourceRoot":"","sources":["../../src/deep/extractor.ts"],"names":[],"mappings":"AAAA;;GAEG;AASH,MAAM,WAAW,gBAAgB;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,gBAAgB;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,qBAAa,gBAAgB;IACzB,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,gBAAgB,CAAS;gBAErB,OAAO,CAAC,EAAE,gBAAgB;IAMhC,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;IA8DrD,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,gBAAgB;IAyCtD,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC;CASlE"}
@@ -0,0 +1,125 @@
1
+ /**
2
+ * Content extraction using linkedom + @mozilla/readability
3
+ */
4
+ import { parseHTML } from 'linkedom';
5
+ import { Readability } from '@mozilla/readability';
6
+ const DEFAULT_TIMEOUT_MS = 10_000;
7
+ const DEFAULT_CONCURRENCY = 3;
8
+ const MAX_RESPONSE_BYTES = 5 * 1024 * 1024; // 5MB
9
+ export class ContentExtractor {
10
+ timeoutMs;
11
+ concurrency;
12
+ maxResponseBytes;
13
+ constructor(options) {
14
+ this.timeoutMs = options?.timeoutMs ?? DEFAULT_TIMEOUT_MS;
15
+ this.concurrency = options?.concurrency ?? DEFAULT_CONCURRENCY;
16
+ this.maxResponseBytes = options?.maxResponseBytes ?? MAX_RESPONSE_BYTES;
17
+ }
18
+ async extract(url) {
19
+ try {
20
+ const response = await fetch(url, {
21
+ headers: {
22
+ 'User-Agent': 'Mozilla/5.0 (compatible; SxngDeepSearch/1.0)',
23
+ 'Accept': 'text/html,application/xhtml+xml',
24
+ },
25
+ signal: AbortSignal.timeout(this.timeoutMs),
26
+ });
27
+ if (!response.ok) {
28
+ return {
29
+ title: '',
30
+ content: '',
31
+ excerpt: '',
32
+ url,
33
+ length: 0,
34
+ extractedAt: Date.now(),
35
+ error: `HTTP ${response.status}: ${response.statusText}`,
36
+ };
37
+ }
38
+ const contentLength = response.headers.get('content-length');
39
+ if (contentLength && parseInt(contentLength, 10) > this.maxResponseBytes) {
40
+ return {
41
+ title: '',
42
+ content: '',
43
+ excerpt: '',
44
+ url,
45
+ length: 0,
46
+ extractedAt: Date.now(),
47
+ error: `Response too large: ${contentLength} bytes (max ${this.maxResponseBytes})`,
48
+ };
49
+ }
50
+ const html = await response.text();
51
+ if (html.length > this.maxResponseBytes) {
52
+ return {
53
+ title: '',
54
+ content: '',
55
+ excerpt: '',
56
+ url,
57
+ length: 0,
58
+ extractedAt: Date.now(),
59
+ error: `Response too large: ${html.length} bytes (max ${this.maxResponseBytes})`,
60
+ };
61
+ }
62
+ return this.extractFromHtml(html, url);
63
+ }
64
+ catch (error) {
65
+ return {
66
+ title: '',
67
+ content: '',
68
+ excerpt: '',
69
+ url,
70
+ length: 0,
71
+ extractedAt: Date.now(),
72
+ error: error instanceof Error ? error.message : String(error),
73
+ };
74
+ }
75
+ }
76
+ extractFromHtml(html, url) {
77
+ try {
78
+ const { document } = parseHTML(html);
79
+ const reader = new Readability(document, { charThreshold: 100 });
80
+ const article = reader.parse();
81
+ if (!article || !article.textContent) {
82
+ return {
83
+ title: '',
84
+ content: '',
85
+ excerpt: '',
86
+ url,
87
+ length: 0,
88
+ extractedAt: Date.now(),
89
+ error: 'Readability could not extract content',
90
+ };
91
+ }
92
+ return {
93
+ title: article.title || '',
94
+ content: article.textContent.replace(/\n{3,}/g, '\n\n').trim(),
95
+ excerpt: article.excerpt || '',
96
+ url,
97
+ byline: article.byline || undefined,
98
+ siteName: article.siteName || undefined,
99
+ length: article.length || article.textContent.length,
100
+ extractedAt: Date.now(),
101
+ };
102
+ }
103
+ catch (error) {
104
+ return {
105
+ title: '',
106
+ content: '',
107
+ excerpt: '',
108
+ url,
109
+ length: 0,
110
+ extractedAt: Date.now(),
111
+ error: error instanceof Error ? error.message : 'HTML parsing failed',
112
+ };
113
+ }
114
+ }
115
+ async extractBatch(urls) {
116
+ const results = [];
117
+ for (let i = 0; i < urls.length; i += this.concurrency) {
118
+ const batch = urls.slice(i, i + this.concurrency);
119
+ const batchResults = await Promise.all(batch.map(u => this.extract(u)));
120
+ results.push(...batchResults);
121
+ }
122
+ return results;
123
+ }
124
+ }
125
+ //# sourceMappingURL=extractor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extractor.js","sourceRoot":"","sources":["../../src/deep/extractor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Entity-centric knowledge graph using graphology
3
+ *
4
+ * The graph stores entities and their relationships.
5
+ * Search results are stored as lightweight metadata nodes (title, url, rank)
6
+ * connected to entities via "mentions" edges.
7
+ *
8
+ * Entity extraction is done by the Agent (LLM), not by the CLI.
9
+ * The CLI only stores what the Agent sends via graph-add.
10
+ */
11
+ import { DirectedGraph } from 'graphology';
12
+ export interface GraphNodeAttrs {
13
+ type: 'entity' | 'result' | 'query' | 'domain';
14
+ label: string;
15
+ entityType?: string;
16
+ score?: number;
17
+ url?: string;
18
+ rank?: number;
19
+ title?: string;
20
+ query?: string;
21
+ round?: number;
22
+ domain?: string;
23
+ }
24
+ export interface GraphEdgeAttrs {
25
+ relation: string;
26
+ weight: number;
27
+ }
28
+ /** Create an empty entity-centric knowledge graph */
29
+ export declare function createGraph(): DirectedGraph<GraphNodeAttrs, GraphEdgeAttrs>;
30
+ /** Generate a node ID for an entity */
31
+ export declare function entityId(label: string): string;
32
+ /** Generate a node ID for a result */
33
+ export declare function resultId(url: string): string;
34
+ /** Generate a node ID for a query */
35
+ export declare function queryId(query: string): string;
36
+ /** Generate a node ID for a domain */
37
+ export declare function domainId(domain: string): string;
38
+ /** Auto-build structural edges: query→result→domain */
39
+ export declare function buildStructuralEdges(graph: DirectedGraph<GraphNodeAttrs, GraphEdgeAttrs>, query: string, results: Array<{
40
+ url: string;
41
+ title: string;
42
+ rank?: number;
43
+ }>, round?: number): void;
44
+ export declare function bfsSubgraph(graph: DirectedGraph<GraphNodeAttrs, GraphEdgeAttrs>, seeds: string[], depth?: number): DirectedGraph<GraphNodeAttrs, GraphEdgeAttrs>;
45
+ export declare function serializeGraph(graph: DirectedGraph<GraphNodeAttrs, GraphEdgeAttrs>): object;
46
+ export declare function deserializeGraph(data: any): DirectedGraph<GraphNodeAttrs, GraphEdgeAttrs>;
47
+ export declare function graphStats(graph: DirectedGraph<GraphNodeAttrs, GraphEdgeAttrs>): {
48
+ nodes: number;
49
+ edges: number;
50
+ entities: number;
51
+ results: number;
52
+ queries: number;
53
+ domains: number;
54
+ };
55
+ //# sourceMappingURL=graph.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"graph.d.ts","sourceRoot":"","sources":["../../src/deep/graph.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE3C,MAAM,WAAW,cAAc;IAC3B,IAAI,EAAE,QAAQ,GAAG,QAAQ,GAAG,OAAO,GAAG,QAAQ,CAAC;IAC/C,KAAK,EAAE,MAAM,CAAC;IAEd,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf,MAAM,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,cAAc;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;CAClB;AAMD,qDAAqD;AACrD,wBAAgB,WAAW,IAAI,aAAa,CAAC,cAAc,EAAE,cAAc,CAAC,CAE3E;AAED,uCAAuC;AACvC,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE9C;AAED,sCAAsC;AACtC,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAE5C;AAED,qCAAqC;AACrC,wBAAgB,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE7C;AAED,sCAAsC;AACtC,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAE/C;AAWD,uDAAuD;AACvD,wBAAgB,oBAAoB,CAChC,KAAK,EAAE,aAAa,CAAC,cAAc,EAAE,cAAc,CAAC,EACpD,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,KAAK,CAAC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,EAC7D,KAAK,CAAC,EAAE,MAAM,GACf,IAAI,CAuDN;AAED,wBAAgB,WAAW,CACvB,KAAK,EAAE,aAAa,CAAC,cAAc,EAAE,cAAc,CAAC,EACpD,KAAK,EAAE,MAAM,EAAE,EACf,KAAK,GAAE,MAAU,GAClB,aAAa,CAAC,cAAc,EAAE,cAAc,CAAC,CA+B/C;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,aAAa,CAAC,cAAc,EAAE,cAAc,CAAC,GAAG,MAAM,CAE3F;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,GAAG,GAAG,aAAa,CAAC,cAAc,EAAE,cAAc,CAAC,CAIzF;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,aAAa,CAAC,cAAc,EAAE,cAAc,CAAC,GAAG;IAC9E,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACnB,CAiBA"}
@@ -0,0 +1,153 @@
1
+ /**
2
+ * Entity-centric knowledge graph using graphology
3
+ *
4
+ * The graph stores entities and their relationships.
5
+ * Search results are stored as lightweight metadata nodes (title, url, rank)
6
+ * connected to entities via "mentions" edges.
7
+ *
8
+ * Entity extraction is done by the Agent (LLM), not by the CLI.
9
+ * The CLI only stores what the Agent sends via graph-add.
10
+ */
11
+ import { DirectedGraph } from 'graphology';
12
+ function generateId(prefix, value) {
13
+ return `${prefix}:${value.toLowerCase().replace(/[^\w]+/g, '_').slice(0, 60)}`;
14
+ }
15
+ /** Create an empty entity-centric knowledge graph */
16
+ export function createGraph() {
17
+ return new DirectedGraph();
18
+ }
19
+ /** Generate a node ID for an entity */
20
+ export function entityId(label) {
21
+ return generateId('e', label);
22
+ }
23
+ /** Generate a node ID for a result */
24
+ export function resultId(url) {
25
+ return generateId('r', url);
26
+ }
27
+ /** Generate a node ID for a query */
28
+ export function queryId(query) {
29
+ return generateId('q', query);
30
+ }
31
+ /** Generate a node ID for a domain */
32
+ export function domainId(domain) {
33
+ return generateId('d', domain);
34
+ }
35
+ /** Extract domain from URL */
36
+ function extractDomain(url) {
37
+ try {
38
+ return new URL(url).hostname;
39
+ }
40
+ catch {
41
+ return url;
42
+ }
43
+ }
44
+ /** Auto-build structural edges: query→result→domain */
45
+ export function buildStructuralEdges(graph, query, results, round) {
46
+ const qId = queryId(query);
47
+ // Ensure query node exists
48
+ if (!graph.hasNode(qId)) {
49
+ graph.mergeNode(qId, {
50
+ type: 'query',
51
+ label: query,
52
+ query,
53
+ round,
54
+ });
55
+ }
56
+ for (let i = 0; i < results.length; i++) {
57
+ const r = results[i];
58
+ const rId = resultId(r.url);
59
+ // Ensure result node exists
60
+ if (!graph.hasNode(rId)) {
61
+ graph.mergeNode(rId, {
62
+ type: 'result',
63
+ label: r.title,
64
+ url: r.url,
65
+ title: r.title,
66
+ rank: r.rank ?? i + 1,
67
+ });
68
+ }
69
+ // query→result edge
70
+ if (!graph.hasEdge(qId, rId)) {
71
+ graph.addEdge(qId, rId, {
72
+ relation: 'yields',
73
+ weight: 1 / (i + 1),
74
+ });
75
+ }
76
+ // domain node and result→domain edge
77
+ const domain = extractDomain(r.url);
78
+ if (domain) {
79
+ const dId = domainId(domain);
80
+ if (!graph.hasNode(dId)) {
81
+ graph.mergeNode(dId, {
82
+ type: 'domain',
83
+ label: domain,
84
+ domain,
85
+ });
86
+ }
87
+ if (!graph.hasEdge(rId, dId)) {
88
+ graph.addEdge(rId, dId, {
89
+ relation: 'belongs_to',
90
+ weight: 1,
91
+ });
92
+ }
93
+ }
94
+ }
95
+ }
96
+ export function bfsSubgraph(graph, seeds, depth = 2) {
97
+ const visited = new Set();
98
+ const queue = seeds
99
+ .filter(id => graph.hasNode(id))
100
+ .map(id => ({ id, depth: 0 }));
101
+ while (queue.length > 0) {
102
+ const { id, depth: d } = queue.shift();
103
+ if (d > depth || visited.has(id))
104
+ continue;
105
+ visited.add(id);
106
+ graph.forEachNeighbor(id, (neighbor) => {
107
+ if (!visited.has(neighbor)) {
108
+ queue.push({ id: neighbor, depth: d + 1 });
109
+ }
110
+ });
111
+ }
112
+ const subgraph = new DirectedGraph();
113
+ for (const nodeId of visited) {
114
+ const attrs = graph.getNodeAttributes(nodeId);
115
+ subgraph.mergeNode(nodeId, attrs);
116
+ }
117
+ graph.forEachEdge((edge, attrs, source, target) => {
118
+ if (visited.has(source) && visited.has(target)) {
119
+ subgraph.mergeEdge(source, target, attrs);
120
+ }
121
+ });
122
+ return subgraph;
123
+ }
124
+ export function serializeGraph(graph) {
125
+ return graph.export();
126
+ }
127
+ export function deserializeGraph(data) {
128
+ const graph = new DirectedGraph();
129
+ graph.import(data);
130
+ return graph;
131
+ }
132
+ export function graphStats(graph) {
133
+ let entities = 0, results = 0, queries = 0, domains = 0;
134
+ graph.forEachNode((node, attrs) => {
135
+ if (attrs.type === 'entity')
136
+ entities++;
137
+ else if (attrs.type === 'result')
138
+ results++;
139
+ else if (attrs.type === 'query')
140
+ queries++;
141
+ else if (attrs.type === 'domain')
142
+ domains++;
143
+ });
144
+ return {
145
+ nodes: graph.order,
146
+ edges: graph.size,
147
+ entities,
148
+ results,
149
+ queries,
150
+ domains,
151
+ };
152
+ }
153
+ //# sourceMappingURL=graph.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"graph.js","sourceRoot":"","sources":["../../src/deep/graph.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Deep search module exports
3
+ */
4
+ export { rrf, RrfInputItem, RrfOutputItem } from './rrf.js';
5
+ export { SimHash } from './simhash.js';
6
+ export { dedupe, dedupeByUrl, dedupeBySimHash, normalizeUrl, DedupItem } from './dedupe.js';
7
+ export { ContentExtractor, ExtractedContent } from './extractor.js';
8
+ export { createGraph, entityId, resultId, queryId, domainId, buildStructuralEdges, bfsSubgraph, serializeGraph, deserializeGraph, graphStats, GraphNodeAttrs, GraphEdgeAttrs } from './graph.js';
9
+ export { initSessionDir, resolveSessionPath, appendSessionResults, updateSessionGraph, loadSessionResults, mergeExtractedContent, SessionResult } from './session.js';
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/deep/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,GAAG,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAC5D,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,eAAe,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAC5F,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AACpE,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,oBAAoB,EAAE,WAAW,EAAE,cAAc,EAAE,gBAAgB,EAAE,UAAU,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AACjM,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Deep search module exports
3
+ */
4
+ export { rrf } from './rrf.js';
5
+ export { SimHash } from './simhash.js';
6
+ export { dedupe, dedupeByUrl, dedupeBySimHash, normalizeUrl } from './dedupe.js';
7
+ export { ContentExtractor } from './extractor.js';
8
+ export { createGraph, entityId, resultId, queryId, domainId, buildStructuralEdges, bfsSubgraph, serializeGraph, deserializeGraph, graphStats } from './graph.js';
9
+ export { initSessionDir, resolveSessionPath, appendSessionResults, updateSessionGraph, loadSessionResults, mergeExtractedContent } from './session.js';
10
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/deep/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,GAAG,EAA+B,MAAM,UAAU,CAAC;AAC5D,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,eAAe,EAAE,YAAY,EAAa,MAAM,aAAa,CAAC;AAC5F,OAAO,EAAE,gBAAgB,EAAoB,MAAM,gBAAgB,CAAC;AACpE,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,oBAAoB,EAAE,WAAW,EAAE,cAAc,EAAE,gBAAgB,EAAE,UAAU,EAAkC,MAAM,YAAY,CAAC;AACjM,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,qBAAqB,EAAiB,MAAM,cAAc,CAAC"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Entity extraction using compromise NLP (English) + BM25 bigrams (CJK)
3
+ *
4
+ * English: compromise extracts named entities + noun phrases (POS-aware)
5
+ * CJK: character bigrams with BM25 scoring (compromise doesn't support CJK)
6
+ * Both phases use BM25 cross-document scoring for relevance ranking.
7
+ */
8
+ export interface KeywordResult {
9
+ term: string;
10
+ score: number;
11
+ type: 'named' | 'proper' | 'phrase';
12
+ }
13
+ /**
14
+ * Extract keywords from a collection of documents.
15
+ *
16
+ * English: compromise for POS-aware candidate extraction (named entities,
17
+ * proper nouns, noun phrases), filtered for validity.
18
+ * CJK: character bigrams with stop word filtering.
19
+ * Both: BM25 cross-document scoring for relevance ranking.
20
+ */
21
+ export declare function extractKeywords(documents: string[], topN?: number): KeywordResult[][];
22
+ /**
23
+ * Extract global keywords across all documents.
24
+ * Aggregates scores and boosts terms appearing in multiple documents.
25
+ */
26
+ export declare function extractGlobalKeywords(documents: string[], topN?: number): KeywordResult[];
27
+ //# sourceMappingURL=keywords.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keywords.d.ts","sourceRoot":"","sources":["../../src/deep/keywords.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,MAAM,WAAW,aAAa;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,OAAO,GAAG,QAAQ,GAAG,QAAQ,CAAC;CACvC;AAkQD;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAC3B,SAAS,EAAE,MAAM,EAAE,EACnB,IAAI,GAAE,MAAU,GACjB,aAAa,EAAE,EAAE,CAwBnB;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CACjC,SAAS,EAAE,MAAM,EAAE,EACnB,IAAI,GAAE,MAAW,GAClB,aAAa,EAAE,CAwBjB"}