@kaitranntt/ccs 7.65.3-dev.8 → 7.65.3-dev.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.
@@ -67,6 +67,8 @@ const PROVIDER_CONFIG = {
67
67
 
68
68
  const ddgLinkRe = /<a[^>]*class="[^"]*result__a[^"]*"[^>]*href="([^"]+)"[^>]*>([\s\S]*?)<\/a>/g;
69
69
  const ddgSnippetRe = /<a class="result__snippet[^"]*".*?>([\s\S]*?)<\/a>/g;
70
+ const ddgNoResultsRe = /class=['"][^'"]*no-results(?:__message)?[^'"]*['"]/i;
71
+ const ddgNoResultsHeadingRe = /No results found for/i;
70
72
  const htmlTagRe = /<[^>]+>/g;
71
73
 
72
74
  function debug(message) {
@@ -427,6 +429,30 @@ function extractDuckDuckGoResults(html, count) {
427
429
  });
428
430
  }
429
431
 
432
+ function classifyDuckDuckGoHtml(html, count) {
433
+ const responseHtml = String(html || '');
434
+ const results = extractDuckDuckGoResults(responseHtml, count);
435
+ if (results.length > 0) {
436
+ return {
437
+ kind: 'results',
438
+ results,
439
+ };
440
+ }
441
+
442
+ if (ddgNoResultsRe.test(responseHtml) || ddgNoResultsHeadingRe.test(responseHtml)) {
443
+ return {
444
+ kind: 'no_results',
445
+ results: [],
446
+ };
447
+ }
448
+
449
+ return {
450
+ kind: 'non_result_html',
451
+ results: [],
452
+ error: 'DuckDuckGo returned non-result HTML response (possible anti-bot/challenge page)',
453
+ };
454
+ }
455
+
430
456
  function formatStructuredSearchResults(query, providerName, results) {
431
457
  const lines = [
432
458
  'CCS local WebSearch evidence',
@@ -680,10 +706,18 @@ async function tryDuckDuckGoSearch(query, timeoutSec = DEFAULT_TIMEOUT_SEC) {
680
706
  }
681
707
 
682
708
  const html = await response.text();
683
- const results = extractDuckDuckGoResults(html, getResultCount('duckduckgo'));
709
+ const parsed = classifyDuckDuckGoHtml(html, getResultCount('duckduckgo'));
710
+ if (parsed.kind === 'non_result_html') {
711
+ return {
712
+ success: false,
713
+ error: `${parsed.error} (status ${response.status})`,
714
+ statusCode: response.status,
715
+ };
716
+ }
717
+
684
718
  return {
685
719
  success: true,
686
- content: formatStructuredSearchResults(query, 'DuckDuckGo', results),
720
+ content: formatStructuredSearchResults(query, 'DuckDuckGo', parsed.results),
687
721
  };
688
722
  } catch (error) {
689
723
  return {
@@ -1229,6 +1263,7 @@ if (require.main === module) {
1229
1263
  module.exports = {
1230
1264
  buildFailureHookOutput,
1231
1265
  buildSuccessHookOutput,
1266
+ classifyDuckDuckGoHtml,
1232
1267
  extractDuckDuckGoResults,
1233
1268
  formatStructuredSearchResults,
1234
1269
  getActiveProviders,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kaitranntt/ccs",
3
- "version": "7.65.3-dev.8",
3
+ "version": "7.65.3-dev.9",
4
4
  "description": "Claude Code Switch - Instant profile switching between Claude, GLM, Kimi, and more",
5
5
  "keywords": [
6
6
  "cli",