@ayoxx/kundex 2.0.7 → 2.0.8

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ayoxx/kundex",
3
- "version": "2.0.7",
3
+ "version": "2.0.8",
4
4
  "description": "Kundex — a terminal-based AI coding agent CLI and SDK, powered by Mistral and Heavstal AI.",
5
5
  "type": "module",
6
6
  "bin": {
package/src/index.ts CHANGED
@@ -3,7 +3,7 @@ import { runLogin } from "./login";
3
3
  import { runRepl } from "./repl";
4
4
  import { Kundex } from "./sdk";
5
5
 
6
- const VERSION = "2.0.7";
6
+ const VERSION = "2.0.8";
7
7
 
8
8
  // ─── Help text ────────────────────────────────────────────────────────────────
9
9
 
package/src/repl.ts CHANGED
@@ -179,7 +179,7 @@ ${c.bold}Tips:${c.reset}
179
179
 
180
180
  function safeGitStatus(cwd: string): string | undefined {
181
181
  try {
182
- return execSync("git status --porcelain=v1 -b", { cwd, timeout: 5000 }).toString();
182
+ return execSync("git status --porcelain=v1 -b 2>/dev/null", { cwd, timeout: 5000 }).toString();
183
183
  } catch {
184
184
  return undefined;
185
185
  }
@@ -187,6 +187,12 @@ function safeGitStatus(cwd: string): string | undefined {
187
187
 
188
188
  function safeFileTree(cwd: string): string | undefined {
189
189
  try {
190
+ // Check if this is a git repo first to avoid git errors
191
+ try {
192
+ execSync("git rev-parse --is-inside-work-tree 2>/dev/null", { cwd, timeout: 2000 });
193
+ } catch {
194
+ return undefined;
195
+ }
190
196
  return execSync(
191
197
  `find . -maxdepth 3 ! -path '*/node_modules/*' ! -path '*/.git/*' ! -path '*/dist/*' ! -path '*/build/*' -print`,
192
198
  { cwd, timeout: 5000 }
@@ -243,6 +249,15 @@ async function handleTurn(
243
249
  },
244
250
  signal,
245
251
  );
252
+ } catch (err) {
253
+ sp.clear();
254
+ const e = err as Error;
255
+ if (e.name === "AbortError") {
256
+ process.stdout.write(`\n${c.yellow} ⚡ Stopped.${c.reset}\n\n`);
257
+ return;
258
+ }
259
+ process.stdout.write(`\n${c.red} ✗ Error after tool call: ${e.message}${c.reset}\n\n`);
260
+ return;
246
261
  } finally {
247
262
  sp.clear();
248
263
  }
package/src/tools.ts CHANGED
@@ -218,7 +218,7 @@ async function gitTool(cwd: string, args: { args: string[] }): Promise<string> {
218
218
  }
219
219
 
220
220
  return new Promise((resolve) => {
221
- exec(cmd, { cwd, timeout: 30_000, maxBuffer: 1024 * 1024 }, (err, stdout, stderr) => {
221
+ exec(`${cmd} 2>/dev/null`, { cwd, timeout: 30_000, maxBuffer: 1024 * 1024 }, (err, stdout, stderr) => {
222
222
  if (err) {
223
223
  resolve(`git command failed (${err.message}):\n${stdout}\n${stderr}`);
224
224
  } else {
@@ -291,38 +291,58 @@ async function webSearchTool(_cwd: string, args: { query: string }): Promise<str
291
291
  header("web_search", args.query);
292
292
 
293
293
  try {
294
- // Use DuckDuckGo instant answer API
295
- const url = `https://api.duckduckgo.com/?q=${encodeURIComponent(args.query)}&format=json&no_html=1&skip_disambig=1`;
294
+ // Use DuckDuckGo lite HTML search and parse results
295
+ const url = `https://lite.duckduckgo.com/lite/?q=${encodeURIComponent(args.query)}`;
296
296
  const res = await fetch(url, {
297
- headers: { "User-Agent": "Kundex/2.0.6" },
298
- signal: AbortSignal.timeout(10_000),
297
+ headers: {
298
+ "User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
299
+ "Accept": "text/html",
300
+ },
301
+ signal: AbortSignal.timeout(15_000),
302
+ redirect: "follow",
299
303
  });
300
- const data = await res.json() as any;
301
304
 
305
+ if (!res.ok) {
306
+ return `Search failed: HTTP ${res.status}`;
307
+ }
308
+
309
+ const html = await res.text();
310
+
311
+ // Parse results from DuckDuckGo lite HTML
302
312
  const results: string[] = [];
303
313
 
304
- if (data.AbstractText) {
305
- results.push(`**${data.Heading || args.query}**\n${data.AbstractText}`);
306
- if (data.AbstractURL) results.push(`Source: ${data.AbstractURL}`);
307
- }
314
+ // Extract result links and snippets
315
+ const linkRegex = /<a[^>]+class="result-link"[^>]*href="([^"]*)"[^>]*>([^<]*)<\/a>/gi;
316
+ const snippetRegex = /<td[^>]+class="result-snippet"[^>]*>([\s\S]*?)<\/td>/gi;
308
317
 
309
- if (data.Answer) {
310
- results.push(`Answer: ${data.Answer}`);
318
+ const links: { url: string; title: string }[] = [];
319
+ const snippets: string[] = [];
320
+
321
+ let match;
322
+ while ((match = linkRegex.exec(html)) !== null) {
323
+ links.push({ url: match[1], title: match[2].trim() });
324
+ }
325
+ while ((match = snippetRegex.exec(html)) !== null) {
326
+ snippets.push(match[1].replace(/<[^>]+>/g, "").trim());
311
327
  }
312
328
 
313
- if (data.RelatedTopics?.length) {
314
- const topics = data.RelatedTopics
315
- .filter((t: any) => t.Text)
316
- .slice(0, 5)
317
- .map((t: any) => `- ${t.Text}${t.FirstURL ? ` (${t.FirstURL})` : ""}`);
318
- if (topics.length) {
319
- results.push("Related:\n" + topics.join("\n"));
320
- }
329
+ for (let i = 0; i < Math.min(links.length, 8); i++) {
330
+ const snippet = snippets[i] || "";
331
+ results.push(`${i + 1}. **${links[i].title}**\n ${links[i].url}\n ${snippet}`);
321
332
  }
322
333
 
323
334
  if (results.length === 0) {
324
- // Fallback: return a helpful message
325
- return `No instant answer found for "${args.query}". Try using fetch_url to read a specific documentation page, or rephrase your search.`;
335
+ // Fallback: try to extract any text content
336
+ const stripped = html
337
+ .replace(/<script[\s\S]*?<\/script>/gi, "")
338
+ .replace(/<style[\s\S]*?<\/style>/gi, "")
339
+ .replace(/<[^>]+>/g, " ")
340
+ .replace(/\s+/g, " ")
341
+ .trim();
342
+ if (stripped.length > 100) {
343
+ return `Search results:\n${stripped.slice(0, 4000)}`;
344
+ }
345
+ return `No results found for "${args.query}". Try different keywords.`;
326
346
  }
327
347
 
328
348
  return results.join("\n\n");