@apmantza/greedysearch-pi 1.7.0 → 1.7.2

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.
@@ -1,68 +1,68 @@
1
- /**
2
- * Coding task result formatters
3
- * Extracted from index.ts to reduce complexity
4
- */
5
-
6
- import { formatEngineName } from "../utils/helpers.js";
7
-
8
- interface CodeBlock {
9
- language: string;
10
- code: string;
11
- }
12
-
13
- interface CodingResult {
14
- explanation?: string;
15
- code?: CodeBlock[];
16
- url?: string;
17
- error?: string;
18
- }
19
-
20
- /**
21
- * Format a single coding result (explanation + code blocks + source)
22
- * Extracted to avoid duplication in multi-engine and single-engine paths
23
- */
24
- function formatCodingResult(result: CodingResult, lines: string[]): void {
25
- if (result.error) {
26
- lines.push(`⚠️ Error: ${result.error}\n`);
27
- return;
28
- }
29
-
30
- if (result.explanation) {
31
- lines.push(String(result.explanation));
32
- }
33
-
34
- if (Array.isArray(result.code) && result.code.length > 0) {
35
- for (const block of result.code) {
36
- lines.push(`\n\`\`\`${block.language}\n${block.code}\n\`\`\`\n`);
37
- }
38
- }
39
-
40
- if (result.url) {
41
- lines.push(`*Source: ${result.url}*\n`);
42
- }
43
- }
44
-
45
- /**
46
- * Format coding task results - supports both single and multi-engine results
47
- */
48
- export function formatCodingTask(
49
- data: Record<string, unknown> | Record<string, Record<string, unknown>>,
50
- ): string {
51
- const lines: string[] = [];
52
-
53
- // Check if it's multi-engine result
54
- const hasMultipleEngines = "gemini" in data || "copilot" in data;
55
-
56
- if (hasMultipleEngines) {
57
- // Multi-engine result
58
- for (const [engineName, result] of Object.entries(data)) {
59
- lines.push(`## ${formatEngineName(engineName)}\n`);
60
- formatCodingResult(result as CodingResult, lines);
61
- }
62
- } else {
63
- // Single engine result
64
- formatCodingResult(data as CodingResult, lines);
65
- }
66
-
67
- return lines.join("\n").trim();
68
- }
1
+ /**
2
+ * Coding task result formatters
3
+ * Extracted from index.ts to reduce complexity
4
+ */
5
+
6
+ import { formatEngineName } from "../utils/helpers.js";
7
+
8
+ interface CodeBlock {
9
+ language: string;
10
+ code: string;
11
+ }
12
+
13
+ interface CodingResult {
14
+ explanation?: string;
15
+ code?: CodeBlock[];
16
+ url?: string;
17
+ error?: string;
18
+ }
19
+
20
+ /**
21
+ * Format a single coding result (explanation + code blocks + source)
22
+ * Extracted to avoid duplication in multi-engine and single-engine paths
23
+ */
24
+ function formatCodingResult(result: CodingResult, lines: string[]): void {
25
+ if (result.error) {
26
+ lines.push(`⚠️ Error: ${result.error}\n`);
27
+ return;
28
+ }
29
+
30
+ if (result.explanation) {
31
+ lines.push(String(result.explanation));
32
+ }
33
+
34
+ if (Array.isArray(result.code) && result.code.length > 0) {
35
+ for (const block of result.code) {
36
+ lines.push(`\n\`\`\`${block.language}\n${block.code}\n\`\`\`\n`);
37
+ }
38
+ }
39
+
40
+ if (result.url) {
41
+ lines.push(`*Source: ${result.url}*\n`);
42
+ }
43
+ }
44
+
45
+ /**
46
+ * Format coding task results - supports both single and multi-engine results
47
+ */
48
+ export function formatCodingTask(
49
+ data: Record<string, unknown> | Record<string, Record<string, unknown>>,
50
+ ): string {
51
+ const lines: string[] = [];
52
+
53
+ // Check if it's multi-engine result
54
+ const hasMultipleEngines = "gemini" in data || "copilot" in data;
55
+
56
+ if (hasMultipleEngines) {
57
+ // Multi-engine result
58
+ for (const [engineName, result] of Object.entries(data)) {
59
+ lines.push(`## ${formatEngineName(engineName)}\n`);
60
+ formatCodingResult(result as CodingResult, lines);
61
+ }
62
+ } else {
63
+ // Single engine result
64
+ formatCodingResult(data as CodingResult, lines);
65
+ }
66
+
67
+ return lines.join("\n").trim();
68
+ }
@@ -1,116 +1,116 @@
1
- /**
2
- * Source formatting utilities
3
- * Extracted from index.ts
4
- */
5
-
6
- import { formatEngineName, humanizeSourceType } from "../utils/helpers.js";
7
-
8
- /**
9
- * Get source URL from various possible fields
10
- */
11
- export function sourceUrl(source: Record<string, unknown>): string {
12
- return String(source.displayUrl || source.canonicalUrl || source.url || "");
13
- }
14
-
15
- /**
16
- * Get source label/title from various possible fields
17
- */
18
- export function sourceLabel(source: Record<string, unknown>): string {
19
- return String(
20
- source.title || source.domain || sourceUrl(source) || "Untitled source",
21
- );
22
- }
23
-
24
- /**
25
- * Calculate consensus score (engine count)
26
- */
27
- export function sourceConsensus(source: Record<string, unknown>): number {
28
- if (typeof source.engineCount === "number") return source.engineCount;
29
- const engines = Array.isArray(source.engines)
30
- ? (source.engines as string[])
31
- : [];
32
- return engines.length;
33
- }
34
-
35
- /**
36
- * Build a map of sources by ID for quick lookup
37
- */
38
- export function getSourceMap(
39
- sources: Array<Record<string, unknown>>,
40
- ): Map<string, Record<string, unknown>> {
41
- return new Map(
42
- sources
43
- .map((source) => [String(source.id || ""), source] as const)
44
- .filter(([id]) => id),
45
- );
46
- }
47
-
48
- /**
49
- * Format a single source line for display
50
- */
51
- export function formatSourceLine(source: Record<string, unknown>): string {
52
- const id = String(source.id || "?");
53
- const url = sourceUrl(source);
54
- const title = sourceLabel(source);
55
- const domain = String(source.domain || "");
56
- const engines = Array.isArray(source.engines)
57
- ? (source.engines as string[])
58
- : [];
59
- const consensus = sourceConsensus(source);
60
- const typeLabel = humanizeSourceType(String(source.sourceType || ""));
61
- const fetch = source.fetch as Record<string, unknown> | undefined;
62
- const fetchStatus = fetch?.ok
63
- ? `fetched ${fetch.status || 200}`
64
- : fetch?.attempted
65
- ? "fetch failed"
66
- : "";
67
-
68
- const pieces = [
69
- `${id} - [${title}](${url})`,
70
- domain,
71
- typeLabel,
72
- engines.length
73
- ? `cited by ${engines.map(formatEngineName).join(", ")} (${consensus}/3)`
74
- : `${consensus}/3`,
75
- fetchStatus,
76
- ].filter(Boolean);
77
-
78
- return `- ${pieces.join(" - ")}`;
79
- }
80
-
81
- /**
82
- * Render source evidence (snippet, last modified, errors)
83
- */
84
- export function renderSourceEvidence(
85
- lines: string[],
86
- source: Record<string, unknown>,
87
- ): void {
88
- const fetch = source.fetch as Record<string, unknown> | undefined;
89
- if (!fetch?.attempted) return;
90
-
91
- const snippet = String(fetch.snippet || "").trim();
92
- const lastModified = String(fetch.lastModified || "").trim();
93
-
94
- if (snippet) lines.push(` Evidence: ${snippet}`);
95
- if (lastModified) lines.push(` Last-Modified: ${lastModified}`);
96
- if (fetch.error) lines.push(` Fetch error: ${String(fetch.error)}`);
97
- }
98
-
99
- /**
100
- * Pick top sources, preferring recommended ones
101
- */
102
- export function pickSources(
103
- sources: Array<Record<string, unknown>>,
104
- recommendedIds: string[] = [],
105
- max = 6,
106
- ): Array<Record<string, unknown>> {
107
- if (!sources.length) return [];
108
-
109
- const sourceMap = getSourceMap(sources);
110
- const recommended = recommendedIds
111
- .map((id) => sourceMap.get(id))
112
- .filter((source): source is Record<string, unknown> => Boolean(source));
113
-
114
- if (recommended.length > 0) return recommended.slice(0, max);
115
- return sources.slice(0, max);
116
- }
1
+ /**
2
+ * Source formatting utilities
3
+ * Extracted from index.ts
4
+ */
5
+
6
+ import { formatEngineName, humanizeSourceType } from "../utils/helpers.js";
7
+
8
+ /**
9
+ * Get source URL from various possible fields
10
+ */
11
+ export function sourceUrl(source: Record<string, unknown>): string {
12
+ return String(source.displayUrl || source.canonicalUrl || source.url || "");
13
+ }
14
+
15
+ /**
16
+ * Get source label/title from various possible fields
17
+ */
18
+ export function sourceLabel(source: Record<string, unknown>): string {
19
+ return String(
20
+ source.title || source.domain || sourceUrl(source) || "Untitled source",
21
+ );
22
+ }
23
+
24
+ /**
25
+ * Calculate consensus score (engine count)
26
+ */
27
+ export function sourceConsensus(source: Record<string, unknown>): number {
28
+ if (typeof source.engineCount === "number") return source.engineCount;
29
+ const engines = Array.isArray(source.engines)
30
+ ? (source.engines as string[])
31
+ : [];
32
+ return engines.length;
33
+ }
34
+
35
+ /**
36
+ * Build a map of sources by ID for quick lookup
37
+ */
38
+ export function getSourceMap(
39
+ sources: Array<Record<string, unknown>>,
40
+ ): Map<string, Record<string, unknown>> {
41
+ return new Map(
42
+ sources
43
+ .map((source) => [String(source.id || ""), source] as const)
44
+ .filter(([id]) => id),
45
+ );
46
+ }
47
+
48
+ /**
49
+ * Format a single source line for display
50
+ */
51
+ export function formatSourceLine(source: Record<string, unknown>): string {
52
+ const id = String(source.id || "?");
53
+ const url = sourceUrl(source);
54
+ const title = sourceLabel(source);
55
+ const domain = String(source.domain || "");
56
+ const engines = Array.isArray(source.engines)
57
+ ? (source.engines as string[])
58
+ : [];
59
+ const consensus = sourceConsensus(source);
60
+ const typeLabel = humanizeSourceType(String(source.sourceType || ""));
61
+ const fetch = source.fetch as Record<string, unknown> | undefined;
62
+ const fetchStatus = fetch?.ok
63
+ ? `fetched ${fetch.status || 200}`
64
+ : fetch?.attempted
65
+ ? "fetch failed"
66
+ : "";
67
+
68
+ const pieces = [
69
+ `${id} - [${title}](${url})`,
70
+ domain,
71
+ typeLabel,
72
+ engines.length
73
+ ? `cited by ${engines.map(formatEngineName).join(", ")} (${consensus}/3)`
74
+ : `${consensus}/3`,
75
+ fetchStatus,
76
+ ].filter(Boolean);
77
+
78
+ return `- ${pieces.join(" - ")}`;
79
+ }
80
+
81
+ /**
82
+ * Render source evidence (snippet, last modified, errors)
83
+ */
84
+ export function renderSourceEvidence(
85
+ lines: string[],
86
+ source: Record<string, unknown>,
87
+ ): void {
88
+ const fetch = source.fetch as Record<string, unknown> | undefined;
89
+ if (!fetch?.attempted) return;
90
+
91
+ const snippet = String(fetch.snippet || "").trim();
92
+ const lastModified = String(fetch.lastModified || "").trim();
93
+
94
+ if (snippet) lines.push(` Evidence: ${snippet}`);
95
+ if (lastModified) lines.push(` Last-Modified: ${lastModified}`);
96
+ if (fetch.error) lines.push(` Fetch error: ${String(fetch.error)}`);
97
+ }
98
+
99
+ /**
100
+ * Pick top sources, preferring recommended ones
101
+ */
102
+ export function pickSources(
103
+ sources: Array<Record<string, unknown>>,
104
+ recommendedIds: string[] = [],
105
+ max = 6,
106
+ ): Array<Record<string, unknown>> {
107
+ if (!sources.length) return [];
108
+
109
+ const sourceMap = getSourceMap(sources);
110
+ const recommended = recommendedIds
111
+ .map((id) => sourceMap.get(id))
112
+ .filter((source): source is Record<string, unknown> => Boolean(source));
113
+
114
+ if (recommended.length > 0) return recommended.slice(0, max);
115
+ return sources.slice(0, max);
116
+ }
@@ -1,91 +1,91 @@
1
- /**
2
- * Synthesis and research result formatters
3
- * Extracted from index.ts
4
- */
5
-
6
- import { formatAgreementLevel } from "../utils/helpers.js";
7
- import {
8
- formatSourceLine,
9
- pickSources,
10
- renderSourceEvidence,
11
- } from "./sources.js";
12
-
13
- /**
14
- * Render synthesis data (answer, consensus, differences, caveats, claims, sources)
15
- */
16
- export function renderSynthesis(
17
- lines: string[],
18
- synthesis: Record<string, unknown>,
19
- sources: Array<Record<string, unknown>>,
20
- maxSources = 6,
21
- ): void {
22
- // Answer section
23
- if (synthesis.answer) {
24
- lines.push("## Answer");
25
- lines.push(String(synthesis.answer));
26
- lines.push("");
27
- }
28
-
29
- // Consensus section
30
- const agreement = synthesis.agreement as Record<string, unknown> | undefined;
31
- const agreementSummary = String(agreement?.summary || "").trim();
32
- const agreementLevel = String(agreement?.level || "").trim();
33
-
34
- if (agreementSummary || agreementLevel) {
35
- lines.push("## Consensus");
36
- lines.push(
37
- `- ${formatAgreementLevel(agreementLevel)}${agreementSummary ? ` - ${agreementSummary}` : ""}`,
38
- );
39
- lines.push("");
40
- }
41
-
42
- // Differences section
43
- const differences = Array.isArray(synthesis.differences)
44
- ? (synthesis.differences as string[])
45
- : [];
46
- if (differences.length > 0) {
47
- lines.push("## Where Engines Differ");
48
- for (const difference of differences) lines.push(`- ${difference}`);
49
- lines.push("");
50
- }
51
-
52
- // Caveats section
53
- const caveats = Array.isArray(synthesis.caveats)
54
- ? (synthesis.caveats as string[])
55
- : [];
56
- if (caveats.length > 0) {
57
- lines.push("## Caveats");
58
- for (const caveat of caveats) lines.push(`- ${caveat}`);
59
- lines.push("");
60
- }
61
-
62
- // Claims section
63
- const claims = Array.isArray(synthesis.claims)
64
- ? (synthesis.claims as Array<Record<string, unknown>>)
65
- : [];
66
- if (claims.length > 0) {
67
- lines.push("## Key Claims");
68
- for (const claim of claims) {
69
- const sourceIds = Array.isArray(claim.sourceIds)
70
- ? (claim.sourceIds as string[])
71
- : [];
72
- const support = String(claim.support || "moderate");
73
- lines.push(
74
- `- ${String(claim.claim || "")} [${support}${sourceIds.length ? `; ${sourceIds.join(", ")}` : ""}]`,
75
- );
76
- }
77
- lines.push("");
78
- }
79
-
80
- // Top sources section
81
- const recommendedIds = Array.isArray(synthesis.recommendedSources)
82
- ? (synthesis.recommendedSources as string[])
83
- : [];
84
- const topSources = pickSources(sources, recommendedIds, maxSources);
85
-
86
- if (topSources.length > 0) {
87
- lines.push("## Top Sources");
88
- for (const source of topSources) lines.push(formatSourceLine(source));
89
- lines.push("");
90
- }
91
- }
1
+ /**
2
+ * Synthesis and research result formatters
3
+ * Extracted from index.ts
4
+ */
5
+
6
+ import { formatAgreementLevel } from "../utils/helpers.js";
7
+ import {
8
+ formatSourceLine,
9
+ pickSources,
10
+ renderSourceEvidence,
11
+ } from "./sources.js";
12
+
13
+ /**
14
+ * Render synthesis data (answer, consensus, differences, caveats, claims, sources)
15
+ */
16
+ export function renderSynthesis(
17
+ lines: string[],
18
+ synthesis: Record<string, unknown>,
19
+ sources: Array<Record<string, unknown>>,
20
+ maxSources = 6,
21
+ ): void {
22
+ // Answer section
23
+ if (synthesis.answer) {
24
+ lines.push("## Answer");
25
+ lines.push(String(synthesis.answer));
26
+ lines.push("");
27
+ }
28
+
29
+ // Consensus section
30
+ const agreement = synthesis.agreement as Record<string, unknown> | undefined;
31
+ const agreementSummary = String(agreement?.summary || "").trim();
32
+ const agreementLevel = String(agreement?.level || "").trim();
33
+
34
+ if (agreementSummary || agreementLevel) {
35
+ lines.push("## Consensus");
36
+ lines.push(
37
+ `- ${formatAgreementLevel(agreementLevel)}${agreementSummary ? ` - ${agreementSummary}` : ""}`,
38
+ );
39
+ lines.push("");
40
+ }
41
+
42
+ // Differences section
43
+ const differences = Array.isArray(synthesis.differences)
44
+ ? (synthesis.differences as string[])
45
+ : [];
46
+ if (differences.length > 0) {
47
+ lines.push("## Where Engines Differ");
48
+ for (const difference of differences) lines.push(`- ${difference}`);
49
+ lines.push("");
50
+ }
51
+
52
+ // Caveats section
53
+ const caveats = Array.isArray(synthesis.caveats)
54
+ ? (synthesis.caveats as string[])
55
+ : [];
56
+ if (caveats.length > 0) {
57
+ lines.push("## Caveats");
58
+ for (const caveat of caveats) lines.push(`- ${caveat}`);
59
+ lines.push("");
60
+ }
61
+
62
+ // Claims section
63
+ const claims = Array.isArray(synthesis.claims)
64
+ ? (synthesis.claims as Array<Record<string, unknown>>)
65
+ : [];
66
+ if (claims.length > 0) {
67
+ lines.push("## Key Claims");
68
+ for (const claim of claims) {
69
+ const sourceIds = Array.isArray(claim.sourceIds)
70
+ ? (claim.sourceIds as string[])
71
+ : [];
72
+ const support = String(claim.support || "moderate");
73
+ lines.push(
74
+ `- ${String(claim.claim || "")} [${support}${sourceIds.length ? `; ${sourceIds.join(", ")}` : ""}]`,
75
+ );
76
+ }
77
+ lines.push("");
78
+ }
79
+
80
+ // Top sources section
81
+ const recommendedIds = Array.isArray(synthesis.recommendedSources)
82
+ ? (synthesis.recommendedSources as string[])
83
+ : [];
84
+ const topSources = pickSources(sources, recommendedIds, maxSources);
85
+
86
+ if (topSources.length > 0) {
87
+ lines.push("## Top Sources");
88
+ for (const source of topSources) lines.push(formatSourceLine(source));
89
+ lines.push("");
90
+ }
91
+ }