@humain/terminal 0.1.1 → 0.2.1

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 (193) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/bundle/chunks/{anthropic-messages-XULXUBIG.js → anthropic-messages-QFCEKGI3.js} +1 -1
  3. package/dist/bundle/chunks/{azure-openai-responses-JEG2XOYC.js → azure-openai-responses-G4ZMHV37.js} +1 -1
  4. package/dist/bundle/chunks/chunk-7T6XCLJF.js +22 -0
  5. package/dist/bundle/chunks/chunk-D6HHRSB5.js +103 -0
  6. package/dist/bundle/chunks/chunk-EY4DWHQU.js +2 -0
  7. package/dist/bundle/chunks/{chunk-LYAMSPR2.js → chunk-I47ZWR55.js} +483 -506
  8. package/dist/bundle/chunks/{chunk-JUPSJTFQ.js → chunk-K4JAZYQH.js} +1 -1
  9. package/dist/bundle/chunks/{chunk-HPPQHK3J.js → chunk-KKIB2TVR.js} +1 -1
  10. package/dist/bundle/chunks/chunk-LI2YVPWP.js +2 -0
  11. package/dist/bundle/chunks/{chunk-BZQ53VGE.js → chunk-XSR434CO.js} +1 -1
  12. package/dist/bundle/chunks/compat-QCV26HNS.js +2 -0
  13. package/dist/bundle/chunks/dist-PRPIUY3U.js +2 -0
  14. package/dist/bundle/chunks/esm-E7UVEYTO.js +4 -0
  15. package/dist/bundle/chunks/{extract-TRW5FBY6.js → extract-CTIFQZDJ.js} +15 -14
  16. package/dist/bundle/chunks/{google-generative-ai-OX6VSCA6.js → google-generative-ai-RSUU4MWO.js} +1 -1
  17. package/dist/bundle/chunks/{google-vertex-GW76GSS2.js → google-vertex-CKQPOITO.js} +1 -1
  18. package/dist/bundle/chunks/host-WP3MVKS2.js +2 -0
  19. package/dist/bundle/chunks/{node-KOIP55YZ.js → node-NF43OPII.js} +1 -1
  20. package/dist/bundle/chunks/{node-XY3CBY3C.js → node-UMFM7CDZ.js} +1 -1
  21. package/dist/bundle/chunks/{openai-codex-responses-NPLWP6ZC.js → openai-codex-responses-S34V5ZSD.js} +1 -1
  22. package/dist/bundle/chunks/{openai-completions-OT2GTJKC.js → openai-completions-T2IGVUEI.js} +1 -1
  23. package/dist/bundle/chunks/{openai-responses-5A6CR7GI.js → openai-responses-GYZODCT3.js} +1 -1
  24. package/dist/bundle/chunks/readability-LAGF34IB.js +3 -0
  25. package/dist/bundle/chunks/turndown.cjs-HRMZVRUL.js +2 -0
  26. package/dist/bundle/cli.js +1 -1
  27. package/dist/bundle/index.js +1 -1
  28. package/dist/bundle/rpc-entry.js +1 -1
  29. package/dist/core/tools/file-mutation-queue.d.ts.map +1 -1
  30. package/dist/core/tools/file-mutation-queue.js +21 -8
  31. package/dist/core/tools/file-mutation-queue.js.map +1 -1
  32. package/dist/core/tools/subagent-env.d.ts +18 -0
  33. package/dist/core/tools/subagent-env.d.ts.map +1 -0
  34. package/dist/core/tools/subagent-env.js +43 -0
  35. package/dist/core/tools/subagent-env.js.map +1 -0
  36. package/dist/core/tools/subagent-scheduler.d.ts +31 -0
  37. package/dist/core/tools/subagent-scheduler.d.ts.map +1 -0
  38. package/dist/core/tools/subagent-scheduler.js +203 -0
  39. package/dist/core/tools/subagent-scheduler.js.map +1 -0
  40. package/dist/core/tools/subagent.d.ts +83 -3
  41. package/dist/core/tools/subagent.d.ts.map +1 -1
  42. package/dist/core/tools/subagent.js +214 -76
  43. package/dist/core/tools/subagent.js.map +1 -1
  44. package/dist/humain/mcp-adapter/vendor/CHANGELOG.md +78 -0
  45. package/dist/humain/mcp-adapter/vendor/README.md +125 -19
  46. package/dist/humain/mcp-adapter/vendor/agent-plugin-loader.ts +69 -30
  47. package/dist/humain/mcp-adapter/vendor/agent-plugin-provenance.ts +36 -0
  48. package/dist/humain/mcp-adapter/vendor/claude-plugin-loader.ts +365 -0
  49. package/dist/humain/mcp-adapter/vendor/commands.ts +13 -15
  50. package/dist/humain/mcp-adapter/vendor/config.ts +198 -30
  51. package/dist/humain/mcp-adapter/vendor/consent-manager.ts +40 -9
  52. package/dist/humain/mcp-adapter/vendor/direct-tool-surface.ts +250 -0
  53. package/dist/humain/mcp-adapter/vendor/direct-tools.ts +9 -228
  54. package/dist/humain/mcp-adapter/vendor/dist/agent-plugin-loader.js +74 -32
  55. package/dist/humain/mcp-adapter/vendor/dist/agent-plugin-loader.js.map +1 -1
  56. package/dist/humain/mcp-adapter/vendor/dist/agent-plugin-provenance.d.ts +1 -0
  57. package/dist/humain/mcp-adapter/vendor/dist/agent-plugin-provenance.js +31 -0
  58. package/dist/humain/mcp-adapter/vendor/dist/agent-plugin-provenance.js.map +1 -0
  59. package/dist/humain/mcp-adapter/vendor/dist/claude-plugin-loader.d.ts +9 -0
  60. package/dist/humain/mcp-adapter/vendor/dist/claude-plugin-loader.js +362 -0
  61. package/dist/humain/mcp-adapter/vendor/dist/claude-plugin-loader.js.map +1 -0
  62. package/dist/humain/mcp-adapter/vendor/dist/config.d.ts +3 -1
  63. package/dist/humain/mcp-adapter/vendor/dist/config.js +189 -27
  64. package/dist/humain/mcp-adapter/vendor/dist/config.js.map +1 -1
  65. package/dist/humain/mcp-adapter/vendor/dist/metadata-cache.js +7 -16
  66. package/dist/humain/mcp-adapter/vendor/dist/metadata-cache.js.map +1 -1
  67. package/dist/humain/mcp-adapter/vendor/dist/package-mcp-loader.js +5 -17
  68. package/dist/humain/mcp-adapter/vendor/dist/package-mcp-loader.js.map +1 -1
  69. package/dist/humain/mcp-adapter/vendor/dist/types.d.ts +30 -4
  70. package/dist/humain/mcp-adapter/vendor/dist/types.js +26 -0
  71. package/dist/humain/mcp-adapter/vendor/dist/types.js.map +1 -1
  72. package/dist/humain/mcp-adapter/vendor/dist/utils.d.ts +6 -0
  73. package/dist/humain/mcp-adapter/vendor/dist/utils.js +65 -6
  74. package/dist/humain/mcp-adapter/vendor/dist/utils.js.map +1 -1
  75. package/dist/humain/mcp-adapter/vendor/host-html-template.ts +20 -19
  76. package/dist/humain/mcp-adapter/vendor/http-ca.ts +84 -0
  77. package/dist/humain/mcp-adapter/vendor/index.bundle.mjs +37102 -15103
  78. package/dist/humain/mcp-adapter/vendor/index.ts +828 -164
  79. package/dist/humain/mcp-adapter/vendor/init.ts +48 -10
  80. package/dist/humain/mcp-adapter/vendor/lazy-loader.ts +7 -0
  81. package/dist/humain/mcp-adapter/vendor/mcp-auth-fetch.ts +113 -0
  82. package/dist/humain/mcp-adapter/vendor/mcp-auth-flow.ts +256 -77
  83. package/dist/humain/mcp-adapter/vendor/mcp-auth.ts +316 -54
  84. package/dist/humain/mcp-adapter/vendor/mcp-code.ts +45 -18
  85. package/dist/humain/mcp-adapter/vendor/mcp-install.ts +60 -0
  86. package/dist/humain/mcp-adapter/vendor/mcp-oauth-provider.ts +70 -6
  87. package/dist/humain/mcp-adapter/vendor/mcp-output-guard.ts +53 -42
  88. package/dist/humain/mcp-adapter/vendor/mcp-panel-theme.ts +105 -0
  89. package/dist/humain/mcp-adapter/vendor/mcp-panel.ts +366 -331
  90. package/dist/humain/mcp-adapter/vendor/mcp-references.ts +9 -14
  91. package/dist/humain/mcp-adapter/vendor/mcp-script-worker.mjs +3 -1
  92. package/dist/humain/mcp-adapter/vendor/mcp-setup-panel.ts +383 -341
  93. package/dist/humain/mcp-adapter/vendor/mcp-status.ts +5 -0
  94. package/dist/humain/mcp-adapter/vendor/metadata-cache.ts +7 -16
  95. package/dist/humain/mcp-adapter/vendor/namespace-tools.ts +61 -3
  96. package/dist/humain/mcp-adapter/vendor/oauth.ts +6 -2
  97. package/dist/humain/mcp-adapter/vendor/package-mcp-loader.ts +5 -17
  98. package/dist/humain/mcp-adapter/vendor/package.json +13 -3
  99. package/dist/humain/mcp-adapter/vendor/prompts.ts +35 -3
  100. package/dist/humain/mcp-adapter/vendor/proxy-modes.ts +108 -7
  101. package/dist/humain/mcp-adapter/vendor/runtime-owner.ts +16 -1
  102. package/dist/humain/mcp-adapter/vendor/sampling-handler.ts +9 -32
  103. package/dist/humain/mcp-adapter/vendor/sandbox-proxy-template.ts +20 -93
  104. package/dist/humain/mcp-adapter/vendor/server-manager.ts +227 -40
  105. package/dist/humain/mcp-adapter/vendor/session-approvals.ts +187 -0
  106. package/dist/humain/mcp-adapter/vendor/skills/mcp-scripting/SKILL.md +9 -1
  107. package/dist/humain/mcp-adapter/vendor/state.ts +10 -1
  108. package/dist/humain/mcp-adapter/vendor/tool-approval.ts +10 -22
  109. package/dist/humain/mcp-adapter/vendor/tool-metadata.ts +14 -0
  110. package/dist/humain/mcp-adapter/vendor/types.ts +57 -4
  111. package/dist/humain/mcp-adapter/vendor/ui-server.ts +36 -28
  112. package/dist/humain/mcp-adapter/vendor/utils.ts +64 -6
  113. package/dist/humain/web-access/vendor/abortable.d.ts +3 -0
  114. package/dist/humain/web-access/vendor/abortable.d.ts.map +1 -0
  115. package/dist/humain/web-access/vendor/abortable.js +22 -0
  116. package/dist/humain/web-access/vendor/abortable.js.map +1 -0
  117. package/dist/humain/web-access/vendor/crawl4ai.d.ts +9 -0
  118. package/dist/humain/web-access/vendor/crawl4ai.d.ts.map +1 -0
  119. package/dist/humain/web-access/vendor/crawl4ai.js +187 -0
  120. package/dist/humain/web-access/vendor/crawl4ai.js.map +1 -0
  121. package/dist/humain/web-access/vendor/credential-source.d.ts.map +1 -1
  122. package/dist/humain/web-access/vendor/credential-source.js +1 -0
  123. package/dist/humain/web-access/vendor/credential-source.js.map +1 -1
  124. package/dist/humain/web-access/vendor/curator-page.d.ts.map +1 -1
  125. package/dist/humain/web-access/vendor/curator-page.js +20 -2
  126. package/dist/humain/web-access/vendor/curator-page.js.map +1 -1
  127. package/dist/humain/web-access/vendor/curator-run.d.ts +11 -0
  128. package/dist/humain/web-access/vendor/curator-run.d.ts.map +1 -0
  129. package/dist/humain/web-access/vendor/curator-run.js +38 -0
  130. package/dist/humain/web-access/vendor/curator-run.js.map +1 -0
  131. package/dist/humain/web-access/vendor/curator-server.d.ts +1 -0
  132. package/dist/humain/web-access/vendor/curator-server.d.ts.map +1 -1
  133. package/dist/humain/web-access/vendor/curator-server.js +2 -0
  134. package/dist/humain/web-access/vendor/curator-server.js.map +1 -1
  135. package/dist/humain/web-access/vendor/duckduckgo.d.ts.map +1 -1
  136. package/dist/humain/web-access/vendor/duckduckgo.js +1 -1
  137. package/dist/humain/web-access/vendor/duckduckgo.js.map +1 -1
  138. package/dist/humain/web-access/vendor/extract.d.ts +1 -1
  139. package/dist/humain/web-access/vendor/extract.d.ts.map +1 -1
  140. package/dist/humain/web-access/vendor/extract.js +58 -11
  141. package/dist/humain/web-access/vendor/extract.js.map +1 -1
  142. package/dist/humain/web-access/vendor/fetch-params.js +1 -1
  143. package/dist/humain/web-access/vendor/fetch-params.js.map +1 -1
  144. package/dist/humain/web-access/vendor/gemini-search.d.ts +2 -2
  145. package/dist/humain/web-access/vendor/gemini-search.d.ts.map +1 -1
  146. package/dist/humain/web-access/vendor/gemini-search.js +12 -5
  147. package/dist/humain/web-access/vendor/gemini-search.js.map +1 -1
  148. package/dist/humain/web-access/vendor/index.d.ts.map +1 -1
  149. package/dist/humain/web-access/vendor/index.js +23 -19
  150. package/dist/humain/web-access/vendor/index.js.map +1 -1
  151. package/dist/humain/web-access/vendor/openai-search.d.ts.map +1 -1
  152. package/dist/humain/web-access/vendor/openai-search.js +40 -14
  153. package/dist/humain/web-access/vendor/openai-search.js.map +1 -1
  154. package/dist/humain/web-access/vendor/page-query.d.ts.map +1 -1
  155. package/dist/humain/web-access/vendor/page-query.js +6 -2
  156. package/dist/humain/web-access/vendor/page-query.js.map +1 -1
  157. package/dist/humain/web-access/vendor/query-rewrite.d.ts.map +1 -1
  158. package/dist/humain/web-access/vendor/query-rewrite.js +6 -2
  159. package/dist/humain/web-access/vendor/query-rewrite.js.map +1 -1
  160. package/dist/humain/web-access/vendor/serpapi.d.ts +4 -0
  161. package/dist/humain/web-access/vendor/serpapi.d.ts.map +1 -0
  162. package/dist/humain/web-access/vendor/serpapi.js +215 -0
  163. package/dist/humain/web-access/vendor/serpapi.js.map +1 -0
  164. package/dist/humain/web-access/vendor/ssrf-protection.d.ts.map +1 -1
  165. package/dist/humain/web-access/vendor/ssrf-protection.js +5 -1
  166. package/dist/humain/web-access/vendor/ssrf-protection.js.map +1 -1
  167. package/dist/humain/web-access/vendor/storage.d.ts.map +1 -1
  168. package/dist/humain/web-access/vendor/storage.js +9 -0
  169. package/dist/humain/web-access/vendor/storage.js.map +1 -1
  170. package/dist/humain/web-access/vendor/summary-review.d.ts +1 -1
  171. package/dist/humain/web-access/vendor/summary-review.d.ts.map +1 -1
  172. package/dist/humain/web-access/vendor/summary-review.js +35 -24
  173. package/dist/humain/web-access/vendor/summary-review.js.map +1 -1
  174. package/dist/humain/web-access/vendor/utils.d.ts.map +1 -1
  175. package/dist/humain/web-access/vendor/utils.js +5 -3
  176. package/dist/humain/web-access/vendor/utils.js.map +1 -1
  177. package/dist/modes/json-event.d.ts +8 -0
  178. package/dist/modes/json-event.d.ts.map +1 -1
  179. package/dist/modes/json-event.js +17 -0
  180. package/dist/modes/json-event.js.map +1 -1
  181. package/dist/modes/print-mode.d.ts.map +1 -1
  182. package/dist/modes/print-mode.js +3 -2
  183. package/dist/modes/print-mode.js.map +1 -1
  184. package/docs/environment-variables.md +8 -0
  185. package/docs/json.md +16 -0
  186. package/npm-shrinkwrap.json +6 -6
  187. package/package.json +2 -2
  188. package/src/humain/mcp-adapter/UPSTREAM.md +56 -7
  189. package/src/humain/mcp-adapter/upstream.json +6 -4
  190. package/src/humain/mcp-adapter/vendor/CHANGELOG.md +78 -0
  191. package/src/humain/web-access/UPSTREAM.md +18 -8
  192. package/src/humain/web-access/upstream.json +6 -5
  193. package/dist/bundle/chunks/chunk-2LC3S3VV.js +0 -105
@@ -1,8 +1,4 @@
1
1
  import { existsSync, readFileSync } from "node:fs";
2
- import { Readability } from "@mozilla/readability";
3
- import { resizeImage } from "../host.js";
4
- import { parseHTML } from "linkedom";
5
- import TurndownService from "turndown";
6
2
  import pLimit from "p-limit";
7
3
  import { activityMonitor } from "./activity.js";
8
4
  import { extractRSCContent } from "./rsc-extract.js";
@@ -20,6 +16,7 @@ import { extractWithQuerit, isQueritAvailable } from "./querit.js";
20
16
  import { extractWithKagi, isKagiExtractAvailable } from "./kagi.js";
21
17
  import { extractWithOllama, isOllamaFetchAvailable } from "./ollama.js";
22
18
  import { extractWithFirecrawl, isFirecrawlAvailable } from "./firecrawl.js";
19
+ import { extractWithCrawl4ai, isCrawl4aiAvailable } from "./crawl4ai.js";
23
20
  import { extractWithBrightDataUnlocker, isBrightDataUnlockerAvailable } from "./brightdata-unlocker.js";
24
21
  import { isVideoFile, extractVideo, extractVideoFrame, getLocalVideoDuration } from "./video-extract.js";
25
22
  import { appendDeclaredWebLinks, discoverDeclaredWebLinks } from "./declared-web-links.js";
@@ -68,8 +65,8 @@ function loadFetchTimeoutMs() {
68
65
  const NON_RECOVERABLE_ERRORS = ["Unsupported content type", "Response too large", "PDF extraction is disabled", "Image fetching is disabled"];
69
66
  const MIN_USEFUL_CONTENT = 500;
70
67
  const SUPPORTED_IMAGE_TYPES = new Set(["image/png", "image/jpeg", "image/webp", "image/gif"]);
71
- const FETCH_PROVIDERS = ["http", "firecrawl", "jina", "tinyfish", "search1api", "querit", "kagi", "ollama", "parallel", "parallel-mcp", "brightdata", "gemini"];
72
- const DEFAULT_FETCH_PROVIDER_ORDER = ["http", "firecrawl", "jina", "tinyfish", "search1api", "querit", "kagi", "ollama", "parallel", "brightdata", "gemini"];
68
+ const FETCH_PROVIDERS = ["http", "firecrawl", "crawl4ai", "jina", "tinyfish", "search1api", "querit", "kagi", "ollama", "parallel", "parallel-mcp", "brightdata", "gemini"];
69
+ const DEFAULT_FETCH_PROVIDER_ORDER = ["http", "firecrawl", "crawl4ai", "jina", "tinyfish", "search1api", "querit", "kagi", "ollama", "parallel", "brightdata", "gemini"];
73
70
  const REMOTE_HOSTED_FETCH_PROVIDERS = new Set(["jina", "tinyfish", "search1api", "querit", "kagi", "ollama", "parallel", "parallel-mcp", "brightdata", "gemini"]);
74
71
  function isDefuddleConsoleError(args) {
75
72
  const prefix = args[0];
@@ -77,6 +74,7 @@ function isDefuddleConsoleError(args) {
77
74
  }
78
75
  async function extractWithDefuddle(text, url) {
79
76
  const { Defuddle } = await import("defuddle/node");
77
+ const { parseHTML } = await import("linkedom");
80
78
  const { document } = parseHTML(text);
81
79
  Object.defineProperty(document, "location", {
82
80
  value: new URL(url),
@@ -122,6 +120,9 @@ function isConfigParseError(err) {
122
120
  function isAbortError(err) {
123
121
  return errorMessage(err).toLowerCase().includes("abort");
124
122
  }
123
+ function isAbortException(err) {
124
+ return err instanceof DOMException && (err.name === "AbortError" || err.name === "TimeoutError");
125
+ }
125
126
  function isRedirectPolicyError(message) {
126
127
  return message.startsWith("Authenticated fetch refused cross-origin redirect") ||
127
128
  message.startsWith("Blocked internal ") ||
@@ -257,10 +258,19 @@ function notFoundGuidance(result, toolNames) {
257
258
  function abortedResult(url) {
258
259
  return { url, title: "", content: "", error: "Aborted" };
259
260
  }
260
- const turndown = new TurndownService({
261
- headingStyle: "atx",
262
- codeBlockStyle: "fenced",
263
- });
261
+ // Share first-use initialization without loading Turndown at extension startup.
262
+ let turndownInstance;
263
+ async function loadTurndown() {
264
+ const { default: TurndownService } = await import("turndown");
265
+ return new TurndownService({
266
+ headingStyle: "atx",
267
+ codeBlockStyle: "fenced",
268
+ });
269
+ }
270
+ function getTurndown() {
271
+ turndownInstance ??= loadTurndown();
272
+ return turndownInstance;
273
+ }
264
274
  const fetchLimit = pLimit(CONCURRENT_LIMIT);
265
275
  /** Resolve the direct HTTP/Jina fetch budget, with a per-call override taking precedence. */
266
276
  export function resolveFetchTimeoutMs(options) {
@@ -689,6 +699,7 @@ export async function extractContent(url, signal, options) {
689
699
  return null;
690
700
  };
691
701
  let firecrawlError = null;
702
+ let crawl4aiError = null;
692
703
  let tinyfishError = null;
693
704
  let search1apiError = null;
694
705
  let queritError = null;
@@ -733,6 +744,28 @@ export async function extractContent(url, signal, options) {
733
744
  }
734
745
  continue;
735
746
  }
747
+ if (provider === "crawl4ai") {
748
+ try {
749
+ if (isCrawl4aiAvailable()) {
750
+ const ssrf = loadSsrfConfig();
751
+ const crawl4aiResult = await extractWithCrawl4ai(url, signal, {
752
+ timeoutMs: options?.timeoutMs,
753
+ ...(options?.lookup ? { lookup: options.lookup } : {}),
754
+ ssrf,
755
+ });
756
+ if (crawl4aiResult)
757
+ return withDeclaredLinks(crawl4aiResult);
758
+ }
759
+ }
760
+ catch (err) {
761
+ if (signal?.aborted || isAbortException(err))
762
+ return abortedResult(url);
763
+ crawl4aiError = errorMessage(err);
764
+ if (isConfigParseError(err))
765
+ return parseErrorResult(crawl4aiError);
766
+ }
767
+ continue;
768
+ }
736
769
  if (provider === "jina") {
737
770
  const jinaResult = await extractWithJinaReader(url, fetchTimeoutMs, signal, options?.lookup);
738
771
  if (jinaResult)
@@ -920,6 +953,7 @@ export async function extractContent(url, signal, options) {
920
953
  const guidance = [
921
954
  finalHttpResult?.error ?? "No fetch_content provider returned content",
922
955
  ...(firecrawlError ? [`Firecrawl fallback failed: ${firecrawlError}`] : []),
956
+ ...(crawl4aiError ? [`Crawl4AI fallback failed: ${crawl4aiError}`] : []),
923
957
  ...(tinyfishError ? [`TinyFish fallback failed: ${tinyfishError}`] : []),
924
958
  ...(search1apiError ? [`Search1API fallback failed: ${search1apiError}`] : []),
925
959
  ...(queritError ? [`Querit fallback failed: ${queritError}`] : []),
@@ -931,6 +965,7 @@ export async function extractContent(url, signal, options) {
931
965
  "",
932
966
  "Fallback options:",
933
967
  ` • Set firecrawlBaseUrl in ${WEB_SEARCH_CONFIG_PATH} to a self-hosted Firecrawl instance`,
968
+ ` • Set crawl4aiBaseUrl in ${WEB_SEARCH_CONFIG_PATH} to a self-hosted Crawl4AI instance`,
934
969
  ` • Set tinyfishApiKey in ${WEB_SEARCH_CONFIG_PATH} or TINYFISH_API_KEY`,
935
970
  ` • Set search1apiApiKey in ${WEB_SEARCH_CONFIG_PATH} or SEARCH1API_KEY`,
936
971
  ` • Set queritApiKey in ${WEB_SEARCH_CONFIG_PATH} or QUERIT_API_KEY`,
@@ -1029,6 +1064,7 @@ function responseSizeLimitError(maxBytes) {
1029
1064
  async function extractViaHttp(url, timeoutMs, signal, options) {
1030
1065
  const activityId = activityMonitor.logStart({ type: "fetch", url });
1031
1066
  const controller = new AbortController();
1067
+ const startedAt = Date.now();
1032
1068
  const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
1033
1069
  const onAbort = () => controller.abort();
1034
1070
  signal?.addEventListener("abort", onAbort);
@@ -1111,6 +1147,7 @@ async function extractViaHttp(url, timeoutMs, signal, options) {
1111
1147
  }
1112
1148
  try {
1113
1149
  const buffer = await readResponseBufferWithLimit(response, maxResponseSize, () => responseSizeLimitError(maxResponseSize));
1150
+ const { resizeImage } = await import("../host.js");
1114
1151
  const resized = await resizeImage(new Uint8Array(buffer), mimeType, { maxWidth: 2000, maxHeight: 2000 });
1115
1152
  activityMonitor.logComplete(activityId, response.status);
1116
1153
  if (!resized)
@@ -1178,9 +1215,11 @@ async function extractViaHttp(url, timeoutMs, signal, options) {
1178
1215
  const title = extractTextTitle(text, url);
1179
1216
  return { url, title, content: text, error: null };
1180
1217
  }
1218
+ const { parseHTML } = await import("linkedom");
1181
1219
  const { document } = parseHTML(text);
1182
1220
  const documentTitle = document.title?.trim() ?? "";
1183
1221
  const declaredLinks = discoverDeclaredWebLinks(document, response.headers.get("link"), response.url || url);
1222
+ const { Readability } = await import("@mozilla/readability");
1184
1223
  const reader = new Readability(document);
1185
1224
  const article = reader.parse();
1186
1225
  if (!article) {
@@ -1224,7 +1263,7 @@ async function extractViaHttp(url, timeoutMs, signal, options) {
1224
1263
  if (typeof article.content !== "string") {
1225
1264
  throw new Error("Readability returned invalid article content");
1226
1265
  }
1227
- const markdown = turndown.turndown(article.content);
1266
+ const markdown = (await getTurndown()).turndown(article.content);
1228
1267
  activityMonitor.logComplete(activityId, response.status);
1229
1268
  if (markdown.length < MIN_USEFUL_CONTENT) {
1230
1269
  const rscResult = extractRSCContent(text);
@@ -1280,6 +1319,14 @@ async function extractViaHttp(url, timeoutMs, signal, options) {
1280
1319
  finally {
1281
1320
  clearTimeout(timeoutId);
1282
1321
  signal?.removeEventListener("abort", onAbort);
1322
+ // Imports and CPU-bound processing need not observe the fetch signal, and
1323
+ // can finish before an expired timer gets a turn. Guard every exit, with
1324
+ // caller cancellation taking precedence over the internal deadline.
1325
+ if (signal?.aborted)
1326
+ return abortedResult(url);
1327
+ if (controller.signal.aborted || Date.now() - startedAt >= timeoutMs) {
1328
+ return { url, title: "", content: "", error: "The operation was aborted." };
1329
+ }
1283
1330
  }
1284
1331
  }
1285
1332
  export function extractHeadingTitle(text) {