@duckmind/dm-windows-x64 0.62.3 → 0.62.9

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 (93) hide show
  1. package/dm.exe +0 -0
  2. package/extensions/.dm-extensions.json +43 -183
  3. package/extensions/dm-context/src/context.js +1 -2
  4. package/extensions/dm-context/src/index.js +1 -2
  5. package/extensions/{greedysearch-dm/bin/cdp.mjs → dm-cua/bin/browser-cdp.mjs} +3 -3
  6. package/extensions/dm-cua/bin/browser-cua.mjs +1 -1
  7. package/extensions/{greedysearch-dm/bin/launch.mjs → dm-cua/bin/browser-launch.mjs} +12 -11
  8. package/extensions/dm-cua/index.js +1 -1
  9. package/extensions/dm-cua/src/browser-cua-lib.mjs +17 -12
  10. package/extensions/{greedysearch-dm/src/search → dm-cua/src/browser-helpers}/constants.mjs +11 -11
  11. package/extensions/{greedysearch-dm/src/utils → dm-cua/src/browser-helpers}/node-runtime.mjs +1 -1
  12. package/extensions/{greedysearch-dm/src/search → dm-cua/src/browser-helpers}/port-pid.mjs +1 -1
  13. package/extensions/dm-ponytail/extensions/ponytail.mjs +186 -0
  14. package/extensions/dm-ponytail/hooks/claude-codex-hooks.json +41 -0
  15. package/extensions/dm-ponytail/hooks/copilot-hooks.json +21 -0
  16. package/extensions/dm-ponytail/hooks/ponytail-activate.js +59 -0
  17. package/extensions/dm-ponytail/hooks/ponytail-config.js +116 -0
  18. package/extensions/dm-ponytail/hooks/ponytail-instructions.js +81 -0
  19. package/extensions/dm-ponytail/hooks/ponytail-mode-tracker.js +96 -0
  20. package/extensions/dm-ponytail/hooks/ponytail-runtime.js +79 -0
  21. package/extensions/dm-ponytail/hooks/ponytail-statusline.ps1 +24 -0
  22. package/extensions/dm-ponytail/hooks/ponytail-statusline.sh +18 -0
  23. package/extensions/dm-ponytail/hooks/ponytail-subagent.js +50 -0
  24. package/extensions/dm-ponytail/hooks/qoder-hooks.json +26 -0
  25. package/extensions/dm-ponytail/package.json +19 -0
  26. package/extensions/dm-ponytail/pi-extension/index.js +186 -0
  27. package/extensions/dm-ponytail/pi-extension/package.json +8 -0
  28. package/extensions/dm-ponytail/skills/ponytail/SKILL.md +120 -0
  29. package/extensions/dm-ponytail/skills/ponytail-audit/SKILL.md +41 -0
  30. package/extensions/dm-ponytail/skills/ponytail-debt/SKILL.md +44 -0
  31. package/extensions/dm-ponytail/skills/ponytail-gain/SKILL.md +50 -0
  32. package/extensions/dm-ponytail/skills/ponytail-help/SKILL.md +71 -0
  33. package/extensions/dm-ponytail/skills/ponytail-review/SKILL.md +57 -0
  34. package/package.json +2 -6
  35. package/extensions/dm-caveman/extensions/caveman.js +0 -300
  36. package/extensions/dm-caveman/package.json +0 -20
  37. package/extensions/dm-goal/package.json +0 -23
  38. package/extensions/dm-goal/src/goal.js +0 -914
  39. package/extensions/greedysearch-dm/bin/cdp-greedy.mjs +0 -40
  40. package/extensions/greedysearch-dm/bin/cdp-headless.mjs +0 -5
  41. package/extensions/greedysearch-dm/bin/cdp-visible.mjs +0 -5
  42. package/extensions/greedysearch-dm/bin/gschrome.mjs +0 -30
  43. package/extensions/greedysearch-dm/bin/kill-visible.mjs +0 -7
  44. package/extensions/greedysearch-dm/bin/launch-visible.mjs +0 -13
  45. package/extensions/greedysearch-dm/bin/mcp.mjs +0 -400
  46. package/extensions/greedysearch-dm/bin/search.mjs +0 -635
  47. package/extensions/greedysearch-dm/bin/visible.mjs +0 -22
  48. package/extensions/greedysearch-dm/extractors/bing-copilot.mjs +0 -344
  49. package/extensions/greedysearch-dm/extractors/chatgpt.mjs +0 -354
  50. package/extensions/greedysearch-dm/extractors/common.mjs +0 -794
  51. package/extensions/greedysearch-dm/extractors/consensus.mjs +0 -527
  52. package/extensions/greedysearch-dm/extractors/consent.mjs +0 -449
  53. package/extensions/greedysearch-dm/extractors/gemini.mjs +0 -291
  54. package/extensions/greedysearch-dm/extractors/google-ai.mjs +0 -86
  55. package/extensions/greedysearch-dm/extractors/logically.mjs +0 -589
  56. package/extensions/greedysearch-dm/extractors/perplexity.mjs +0 -370
  57. package/extensions/greedysearch-dm/extractors/selectors.mjs +0 -32
  58. package/extensions/greedysearch-dm/extractors/semantic-scholar.mjs +0 -199
  59. package/extensions/greedysearch-dm/index.js +0 -123
  60. package/extensions/greedysearch-dm/package.json +0 -27
  61. package/extensions/greedysearch-dm/skills/greedy-search/skill.md +0 -18
  62. package/extensions/greedysearch-dm/src/fetcher.mjs +0 -577
  63. package/extensions/greedysearch-dm/src/formatters/results.js +0 -95
  64. package/extensions/greedysearch-dm/src/formatters/sources.js +0 -57
  65. package/extensions/greedysearch-dm/src/formatters/synthesis.js +0 -49
  66. package/extensions/greedysearch-dm/src/github.mjs +0 -228
  67. package/extensions/greedysearch-dm/src/reddit.mjs +0 -154
  68. package/extensions/greedysearch-dm/src/search/browser-lifecycle.mjs +0 -340
  69. package/extensions/greedysearch-dm/src/search/challenge-detect.mjs +0 -156
  70. package/extensions/greedysearch-dm/src/search/chrome.mjs +0 -510
  71. package/extensions/greedysearch-dm/src/search/defaults.mjs +0 -10
  72. package/extensions/greedysearch-dm/src/search/engines.mjs +0 -79
  73. package/extensions/greedysearch-dm/src/search/fetch-source.mjs +0 -470
  74. package/extensions/greedysearch-dm/src/search/file-sources.mjs +0 -31
  75. package/extensions/greedysearch-dm/src/search/output.mjs +0 -51
  76. package/extensions/greedysearch-dm/src/search/paths.mjs +0 -48
  77. package/extensions/greedysearch-dm/src/search/pdf.mjs +0 -64
  78. package/extensions/greedysearch-dm/src/search/progress.mjs +0 -109
  79. package/extensions/greedysearch-dm/src/search/query.mjs +0 -21
  80. package/extensions/greedysearch-dm/src/search/recovery.mjs +0 -49
  81. package/extensions/greedysearch-dm/src/search/research.mjs +0 -2255
  82. package/extensions/greedysearch-dm/src/search/scale-aware.mjs +0 -61
  83. package/extensions/greedysearch-dm/src/search/simple-research.mjs +0 -418
  84. package/extensions/greedysearch-dm/src/search/sources.mjs +0 -412
  85. package/extensions/greedysearch-dm/src/search/synthesis-runner.mjs +0 -127
  86. package/extensions/greedysearch-dm/src/search/synthesis.mjs +0 -202
  87. package/extensions/greedysearch-dm/src/tools/greedy-search-handler.js +0 -209
  88. package/extensions/greedysearch-dm/src/tools/shared.js +0 -226
  89. package/extensions/greedysearch-dm/src/types.js +0 -0
  90. package/extensions/greedysearch-dm/src/utils/content.mjs +0 -38
  91. package/extensions/greedysearch-dm/src/utils/helpers.js +0 -22
  92. /package/extensions/{greedysearch-dm/src/search → dm-cua/src/browser-helpers}/minimize.mjs +0 -0
  93. /package/extensions/{greedysearch-dm/src/utils → dm-cua/src/browser-helpers}/system-cmds.mjs +0 -0
@@ -1,61 +0,0 @@
1
- import { trimText } from "./sources.mjs";
2
- import { runGeminiPrompt } from "./synthesis-runner.mjs";
3
- import { parseStructuredJson } from "./synthesis.mjs";
4
- const COMPLEXITY_PROMPT_TIMEOUT_MS = 30000;
5
- function clampInt(value, min, max, fallback) {
6
- const n = Number.parseInt(String(value ?? ""), 10);
7
- if (!Number.isFinite(n))
8
- return fallback;
9
- return Math.min(max, Math.max(min, n));
10
- }
11
- export async function classifyResearchComplexity(query) {
12
- const prompt = [
13
- "You are a research complexity classifier.",
14
- "Classify the following query by research complexity.",
15
- "",
16
- "- simple: A narrow factual question (what is X, define X, how does X work).",
17
- " Answerable with 1-3 search queries and a short synthesis. No sub-questions.",
18
- "- moderate: A focused comparison, recent change, or best-practice lookup.",
19
- " Needs 2-4 angles but stays within one domain.",
20
- "- complex: Multi-faceted survey, landscape analysis, or cross-domain investigation.",
21
- " Benefits from parallel research directions and iterative deepening.",
22
- "",
23
- "Respond ONLY with JSON wrapped in BEGIN_JSON / END_JSON markers:",
24
- "BEGIN_JSON",
25
- JSON.stringify({
26
- complexity: "simple",
27
- reasoning: "narrow factual question",
28
- suggestedBreadth: 1,
29
- suggestedIterations: 1,
30
- needsAcademicSources: false
31
- }, null, 2),
32
- "END_JSON",
33
- "",
34
- "Query: " + query
35
- ].join(`
36
- `);
37
- try {
38
- const raw = await runGeminiPrompt(prompt, {
39
- timeoutMs: COMPLEXITY_PROMPT_TIMEOUT_MS
40
- });
41
- const parsed = parseStructuredJson(raw?.answer || "") || {};
42
- const complexity = ["simple", "moderate", "complex"].includes(parsed.complexity) ? parsed.complexity : "moderate";
43
- return {
44
- complexity,
45
- reasoning: trimText(parsed.reasoning || "", 200),
46
- suggestedBreadth: clampInt(parsed.suggestedBreadth, 1, 5, complexity === "simple" ? 1 : 3),
47
- suggestedIterations: clampInt(parsed.suggestedIterations, 1, 3, complexity === "simple" ? 1 : 2),
48
- needsAcademicSources: parsed.needsAcademicSources === true
49
- };
50
- } catch (error) {
51
- process.stderr.write(`[greedysearch] Complexity classification failed, defaulting to moderate: ${error.message}
52
- `);
53
- return {
54
- complexity: "moderate",
55
- reasoning: "classification failed",
56
- suggestedBreadth: 3,
57
- suggestedIterations: 2,
58
- needsAcademicSources: false
59
- };
60
- }
61
- }
@@ -1,418 +0,0 @@
1
- import { ALL_ENGINES, RESEARCH_ENGINES } from "./constants.mjs";
2
- import {
3
- buildSourceRegistry,
4
- mergeFetchDataIntoSources,
5
- normalizeUrl,
6
- trimText
7
- } from "./sources.mjs";
8
- import {
9
- auditCitations,
10
- buildFinalReportPrompt,
11
- buildSynthesisFromEvidencePrompt,
12
- computeResearchFloor,
13
- createQuestionLedger,
14
- extractEvidenceFromSources,
15
- reconcileQuestionsFromSynthesis,
16
- runCitationUrlCheck,
17
- writeResearchBundle
18
- } from "./research.mjs";
19
- import { parseStructuredJson } from "./synthesis.mjs";
20
- import { writeSourcesToFiles } from "./file-sources.mjs";
21
- import { fetchMultipleSources } from "./fetch-source.mjs";
22
- import { runGeminiPrompt } from "./synthesis-runner.mjs";
23
- import { createProgressTracker } from "./progress.mjs";
24
- import { spawn } from "node:child_process";
25
- import { nodeRuntimeCommand } from "../utils/node-runtime.mjs";
26
- import { join } from "node:path";
27
- import { fileURLToPath } from "node:url";
28
- const __dir = fileURLToPath(new URL(".", import.meta.url)).replace(/^\/([A-Z]:)/, "$1");
29
- const SEARCH_BIN = join(__dir, "..", "..", "bin", "search.mjs");
30
- function uniqueStrings(items, limit = 1 / 0) {
31
- const seen = new Set;
32
- const out = [];
33
- for (const item of items || []) {
34
- const clean = trimText(String(item || ""), 1000);
35
- if (!clean || seen.has(clean))
36
- continue;
37
- seen.add(clean);
38
- out.push(clean);
39
- if (out.length >= limit)
40
- break;
41
- }
42
- return out;
43
- }
44
- export function buildSearchAngles(query) {
45
- const trimmed = String(query || "").trim();
46
- if (!trimmed)
47
- return [];
48
- return [
49
- `${trimmed} — definition and overview`,
50
- `${trimmed} — how it works, mechanism, or key details`,
51
- `${trimmed} — current usage, comparison, or best practices`
52
- ];
53
- }
54
- export function mergeSourcesByUrl(existing, incoming) {
55
- const urlMap = new Map;
56
- for (const s of existing || []) {
57
- const key = s?.canonicalUrl || s?.finalUrl || s?.url;
58
- if (key)
59
- urlMap.set(key, s);
60
- }
61
- for (const s of incoming || []) {
62
- const key = s?.canonicalUrl || s?.finalUrl || s?.url;
63
- if (!key)
64
- continue;
65
- if (urlMap.has(key)) {
66
- const merged = {
67
- ...urlMap.get(key),
68
- angles: [
69
- ...urlMap.get(key).angles || [urlMap.get(key).query || ""],
70
- s.query || ""
71
- ]
72
- };
73
- urlMap.set(key, merged);
74
- } else {
75
- urlMap.set(key, s);
76
- }
77
- }
78
- return Array.from(urlMap.values());
79
- }
80
- const _enginePattern = ALL_ENGINES.join("|");
81
- const _engineRegex = new RegExp(`^\\[(${_enginePattern})\\]`);
82
- function shouldForwardChildStderr(line) {
83
- return /^PROGRESS:/.test(line) || /^\[greedysearch\]/.test(line) || _engineRegex.test(line) || /^GreedySearch Chrome/.test(line) || /^Launching GreedySearch Chrome/.test(line) || /^Headless mode/.test(line) || /^Ready\.?$/.test(line);
84
- }
85
- async function runFastAllSearch(query, { locale = null, short = true } = {}) {
86
- const args = [SEARCH_BIN, "all", "--inline", "--stdin", "--fast"];
87
- if (!short)
88
- args.push("--full");
89
- if (locale)
90
- args.push("--locale", locale);
91
- return new Promise((resolve, reject) => {
92
- const proc = spawn(nodeRuntimeCommand(), args, {
93
- stdio: ["pipe", "pipe", "pipe"],
94
- env: { ...process.env, GREEDY_SEARCH_RESEARCH_CHILD: "1" }
95
- });
96
- proc.stdin.write(query);
97
- proc.stdin.end();
98
- let out = "";
99
- let err = "";
100
- let stderrBuffer = "";
101
- proc.stdout.on("data", (d) => out += d);
102
- proc.stderr.on("data", (d) => {
103
- err += d;
104
- stderrBuffer += d.toString();
105
- const lines = stderrBuffer.split(`
106
- `);
107
- stderrBuffer = lines.pop() || "";
108
- for (const line of lines) {
109
- if (shouldForwardChildStderr(line)) {
110
- process.stderr.write(`${line}
111
- `);
112
- }
113
- }
114
- });
115
- const t = setTimeout(() => {
116
- proc.kill();
117
- reject(new Error(`research child search timed out for: ${query}`));
118
- }, 140000);
119
- proc.on("close", (code) => {
120
- clearTimeout(t);
121
- if (code !== 0) {
122
- reject(new Error(err.trim() || `search child exited with code ${code}`));
123
- return;
124
- }
125
- try {
126
- resolve(JSON.parse(out.trim()));
127
- } catch {
128
- reject(new Error(`Invalid JSON from research child: ${out.slice(0, 200)}`));
129
- }
130
- });
131
- });
132
- }
133
- function annotateFetchedSourcesWithIds(fetchedSources, sources) {
134
- const byUrl = new Map;
135
- for (const source of sources || []) {
136
- const key = normalizeUrl(source?.canonicalUrl || source?.finalUrl || source?.url);
137
- if (key && source?.id)
138
- byUrl.set(key, source.id);
139
- }
140
- return (fetchedSources || []).map((source, index) => {
141
- const key = normalizeUrl(source?.finalUrl || source?.canonicalUrl || source?.url);
142
- return {
143
- ...source,
144
- id: source?.id || byUrl.get(key) || `F${index + 1}`
145
- };
146
- });
147
- }
148
- function questionProgress(questions) {
149
- const total = questions.length;
150
- const closed = questions.filter((q) => q.status === "closed").length;
151
- return { total, closed, open: Math.max(0, total - closed) };
152
- }
153
- export async function runSimpleResearchMode({
154
- query,
155
- locale = null,
156
- maxSources = 5,
157
- qualityThreshold = 8.5,
158
- writeBundle = process.env.GREEDY_RESEARCH_BUNDLE !== "0",
159
- researchOutDir = null
160
- } = {}) {
161
- const startedAt = new Date().toISOString();
162
- const startMs = Date.now();
163
- const questions = createQuestionLedger(query);
164
- const extractedSourceKeys = new Set;
165
- process.stderr.write(`[greedysearch] Simple research mode: single-pass for "${trimText(query, 80)}"
166
- `);
167
- const searchAnglesCount = 3;
168
- const totalSteps = searchAnglesCount + 1 + 2;
169
- const progressTracker = createProgressTracker({
170
- totalActions: totalSteps,
171
- totalRounds: 1,
172
- totalFetches: 1,
173
- silent: process.env.GREEDY_RESEARCH_QUIET === "1"
174
- });
175
- progressTracker.startRound(1);
176
- let combinedSources = [];
177
- let fetchedSources = [];
178
- const searchAngles = buildSearchAngles(query);
179
- const searchResults = [];
180
- progressTracker.startAction("search", `${searchAngles.length} angles in parallel`);
181
- const angleOutcomes = await Promise.allSettled(searchAngles.map((angle) => runFastAllSearch(angle, { locale, short: true })));
182
- for (let i = 0;i < searchAngles.length; i++) {
183
- const angle = searchAngles[i];
184
- const outcome = angleOutcomes[i];
185
- progressTracker.endAction();
186
- if (outcome.status === "fulfilled") {
187
- const result = outcome.value;
188
- searchResults.push({ angle, result });
189
- const sources = buildSourceRegistry(result, angle);
190
- combinedSources = mergeSourcesByUrl(combinedSources, sources);
191
- } else {
192
- process.stderr.write(`[greedysearch] Simple search angle "${angle}" failed: ${outcome.reason.message}
193
- `);
194
- }
195
- }
196
- process.stderr.write(`PROGRESS:research:simple:fetching
197
- `);
198
- if (combinedSources.length > 0) {
199
- try {
200
- progressTracker.startFetch(`top ${Math.min(maxSources, combinedSources.length)} sources`);
201
- fetchedSources = await fetchMultipleSources(combinedSources, Math.min(maxSources, combinedSources.length), 8000, Math.min(3, maxSources));
202
- progressTracker.endFetch(true);
203
- combinedSources = mergeFetchDataIntoSources(combinedSources, fetchedSources);
204
- } catch (error) {
205
- progressTracker.endFetch(false);
206
- process.stderr.write(`[greedysearch] Source fetching failed: ${error.message}
207
- `);
208
- }
209
- }
210
- fetchedSources = annotateFetchedSourcesWithIds(fetchedSources, combinedSources);
211
- process.stderr.write(`PROGRESS:research:simple:evidence
212
- `);
213
- let evidenceItems = [];
214
- try {
215
- const evidenceRun = await extractEvidenceFromSources({
216
- query,
217
- questions,
218
- fetchedSources,
219
- extractedSourceKeys
220
- });
221
- evidenceItems = evidenceRun.evidence || [];
222
- for (const evidence of evidenceRun.evidence) {
223
- const answered = Array.isArray(evidence.answers) ? evidence.answers : [];
224
- for (const ans of answered) {
225
- const id = ans?.id || ans?.question;
226
- if (id) {
227
- const target = questions.find((q) => q.id === id);
228
- if (target) {
229
- target.status = "closed";
230
- target.closedRound = 1;
231
- if (ans.evidence)
232
- target.evidence = uniqueStrings([...target.evidence || [], ans.evidence], 4);
233
- }
234
- }
235
- }
236
- const newQs = Array.isArray(evidence.newQuestions) ? evidence.newQuestions : [];
237
- for (const q of newQs) {
238
- const clean = trimText(String(q), 320);
239
- if (clean && !questions.some((x) => x.question === clean)) {
240
- questions.push({
241
- id: `Q${questions.length + 1}`,
242
- question: clean,
243
- status: "open",
244
- reason: "Discovered gap/follow-up",
245
- createdRound: 1,
246
- evidence: [],
247
- sourceIds: []
248
- });
249
- }
250
- }
251
- }
252
- } catch (error) {
253
- process.stderr.write(`[greedysearch] Evidence extraction failed: ${error.message}
254
- `);
255
- }
256
- process.stderr.write(`PROGRESS:research:simple:synthesizing
257
- `);
258
- let synthesis = {
259
- answer: "",
260
- agreement: { level: "mixed", summary: "Single-pass synthesis." },
261
- differences: [],
262
- caveats: [],
263
- claims: [],
264
- recommendedSources: combinedSources.slice(0, 4).map((s) => s.id),
265
- synthesized: false
266
- };
267
- if (evidenceItems.length > 0) {
268
- try {
269
- progressTracker.startAction("synth-evidence", "from evidence");
270
- const rawReport = await runGeminiPrompt(buildSynthesisFromEvidencePrompt(query, combinedSources, questions, evidenceItems), { timeoutMs: 120000 });
271
- progressTracker.endAction();
272
- synthesis = {
273
- ...synthesis,
274
- ...parseStructuredJson(rawReport?.answer || "") || {}
275
- };
276
- synthesis.synthesized = Array.isArray(synthesis.claims) && synthesis.claims.length > 0;
277
- } catch (error) {
278
- process.stderr.write(`[greedysearch] Evidence synthesis failed: ${error.message}
279
- `);
280
- }
281
- }
282
- if (!synthesis.synthesized && combinedSources.length > 0) {
283
- try {
284
- progressTracker.startAction("synth-final", "fallback report");
285
- const rawReport = await runGeminiPrompt(buildFinalReportPrompt(query, [{ round: 1, learnings: [], gaps: [], actions: [] }], combinedSources, questions, evidenceItems), { timeoutMs: 120000 });
286
- progressTracker.endAction();
287
- synthesis = {
288
- ...synthesis,
289
- ...parseStructuredJson(rawReport?.answer || "") || {}
290
- };
291
- synthesis.synthesized = Array.isArray(synthesis.claims) && synthesis.claims.length > 0;
292
- } catch (error) {
293
- process.stderr.write(`[greedysearch] Final synthesis failed: ${error.message}
294
- `);
295
- }
296
- }
297
- process.stderr.write(`PROGRESS:research:simple:audit
298
- `);
299
- const citationAudit = auditCitations(synthesis.answer || "", combinedSources);
300
- const citationUrls = await runCitationUrlCheck(combinedSources, citationAudit);
301
- reconcileQuestionsFromSynthesis(questions, synthesis, citationAudit);
302
- const allGaps = uniqueStrings(synthesis.caveats || []);
303
- const floor = computeResearchFloor({
304
- sources: combinedSources,
305
- fetchedSources,
306
- synthesis,
307
- citationAudit,
308
- gaps: allGaps,
309
- questions,
310
- rounds: [{ round: 1, actions: [], learnings: [], gaps: allGaps }],
311
- qualityScore: synthesis.synthesized ? 8 : 5,
312
- qualityThreshold,
313
- maxSources
314
- });
315
- const finishedAt = new Date().toISOString();
316
- const durationMs = Date.now() - startMs;
317
- const baseManifest = {
318
- startedAt,
319
- finishedAt,
320
- durationMs,
321
- rounds: 1,
322
- terminationReason: "simple_single_pass"
323
- };
324
- let bundle = null;
325
- let fetchedFiles;
326
- if (writeBundle) {
327
- process.stderr.write(`PROGRESS:research:simple:bundle
328
- `);
329
- try {
330
- bundle = await writeResearchBundle({
331
- query,
332
- rounds: [
333
- {
334
- round: 1,
335
- actions: [],
336
- learnings: [],
337
- gaps: allGaps,
338
- evidence: evidenceItems
339
- }
340
- ],
341
- sources: combinedSources,
342
- fetchedSources,
343
- evidenceItems,
344
- synthesis,
345
- citationAudit,
346
- citationUrls,
347
- floor,
348
- manifest: {
349
- ...baseManifest,
350
- engines: RESEARCH_ENGINES,
351
- synthesizer: "gemini",
352
- actionsRun: 1,
353
- searches: 1,
354
- fetches: fetchedSources.length,
355
- sourcesFetched: fetchedSources.filter((s) => s?.contentChars > 100).length,
356
- engineFailures: [],
357
- floorMet: floor.floorMet
358
- },
359
- allGaps,
360
- questions,
361
- outDir: researchOutDir
362
- });
363
- fetchedFiles = bundle.sourceFiles;
364
- delete bundle.sourceFiles;
365
- } catch (error) {
366
- process.stderr.write(`[greedysearch] Research bundle write failed: ${error.message}
367
- `);
368
- bundle = { error: error.message || String(error) };
369
- fetchedFiles = await writeSourcesToFiles(fetchedSources);
370
- }
371
- } else {
372
- fetchedFiles = await writeSourcesToFiles(fetchedSources);
373
- }
374
- process.stderr.write(`PROGRESS:research:done
375
- `);
376
- progressTracker.endRound();
377
- progressTracker.finish();
378
- return {
379
- query,
380
- _research: {
381
- mode: "simple",
382
- breadth: 1,
383
- iterations: 1,
384
- maxSources,
385
- rounds: [
386
- {
387
- round: 1,
388
- actions: [],
389
- learnings: [],
390
- gaps: allGaps,
391
- evidence: evidenceItems
392
- }
393
- ],
394
- learnings: [],
395
- gaps: allGaps,
396
- evidence: evidenceItems,
397
- questions,
398
- questionProgress: questionProgress(questions),
399
- qualityHistory: [synthesis.synthesized ? 8 : 5],
400
- terminationReason: "simple_single_pass",
401
- qualityThreshold,
402
- floor,
403
- bundle,
404
- manifest: baseManifest
405
- },
406
- _citationAudit: citationAudit,
407
- _citationUrls: citationUrls,
408
- _sources: combinedSources,
409
- _fetchedSources: fetchedFiles,
410
- _synthesis: synthesis,
411
- _confidence: {
412
- sourcesCount: combinedSources.length,
413
- fetchedSourceSuccessRate: fetchedSources.length > 0 ? fetchedSources.filter((source) => source.contentChars > 100).length / fetchedSources.length : 0,
414
- agreementLevel: synthesis.agreement?.level || "mixed",
415
- floorMet: floor.floorMet
416
- }
417
- };
418
- }