@gajae-code/coding-agent 0.11.6 → 0.11.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.
Files changed (259) hide show
  1. package/CHANGELOG.md +92 -0
  2. package/dist/types/capability/index.d.ts +10 -20
  3. package/dist/types/capability/types.d.ts +3 -0
  4. package/dist/types/cli/args.d.ts +0 -2
  5. package/dist/types/commands/daemon.d.ts +2 -2
  6. package/dist/types/commands/sdk.d.ts +20 -2
  7. package/dist/types/config/keybindings.d.ts +34 -4
  8. package/dist/types/config/model-profile-activation.d.ts +4 -3
  9. package/dist/types/config/model-profile-contract.d.ts +38 -0
  10. package/dist/types/config/settings-schema.d.ts +70 -7
  11. package/dist/types/edit/modes/patch.d.ts +13 -0
  12. package/dist/types/edit/path-mutation-lock.d.ts +15 -0
  13. package/dist/types/eval/py/executor.d.ts +1 -1
  14. package/dist/types/eval/py/runner-artifact.d.ts +8 -0
  15. package/dist/types/eval/py/tool-bridge.d.ts +1 -2
  16. package/dist/types/gjc-runtime/repository-binding.d.ts +63 -0
  17. package/dist/types/gjc-runtime/ultragoal-guard.d.ts +6 -5
  18. package/dist/types/gjc-runtime/ultragoal-receipt-freshness.d.ts +20 -0
  19. package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +43 -5
  20. package/dist/types/main.d.ts +32 -1
  21. package/dist/types/modes/components/btw-panel.d.ts +1 -0
  22. package/dist/types/modes/components/model-selector.d.ts +2 -0
  23. package/dist/types/modes/components/runtime-mcp-add-wizard.d.ts +2 -1
  24. package/dist/types/modes/components/tool-status-header.d.ts +4 -2
  25. package/dist/types/modes/components/welcome.d.ts +2 -0
  26. package/dist/types/modes/controllers/btw-controller.d.ts +5 -0
  27. package/dist/types/modes/controllers/command-controller.d.ts +2 -0
  28. package/dist/types/modes/controllers/selector-controller.d.ts +2 -1
  29. package/dist/types/modes/interactive-mode.d.ts +7 -2
  30. package/dist/types/modes/prompt-action-autocomplete.d.ts +6 -1
  31. package/dist/types/modes/prompt-suggestion-controller.d.ts +35 -0
  32. package/dist/types/modes/shared/agent-wire/workflow-gate-broker.d.ts +2 -2
  33. package/dist/types/modes/types.d.ts +4 -0
  34. package/dist/types/modes/utils/hotkeys-markdown.d.ts +2 -1
  35. package/dist/types/runtime-mcp/content-limits.d.ts +7 -0
  36. package/dist/types/runtime-mcp/manager.d.ts +1 -1
  37. package/dist/types/runtime-mcp/oauth-flow.d.ts +0 -5
  38. package/dist/types/runtime-mcp/plugin-network-boundary.d.ts +14 -0
  39. package/dist/types/sdk/broker/broker.d.ts +2 -0
  40. package/dist/types/sdk/broker/lifecycle.d.ts +6 -0
  41. package/dist/types/sdk/bus/chat-daemon-control.d.ts +6 -1
  42. package/dist/types/sdk/bus/config-commands.d.ts +2 -2
  43. package/dist/types/sdk/bus/config.d.ts +2 -0
  44. package/dist/types/sdk/bus/conversation-store.d.ts +1 -0
  45. package/dist/types/sdk/bus/index.d.ts +26 -1
  46. package/dist/types/sdk/bus/lifecycle-commands.d.ts +5 -4
  47. package/dist/types/sdk/bus/notification-orchestration.d.ts +1 -0
  48. package/dist/types/sdk/bus/notification-service.d.ts +34 -0
  49. package/dist/types/sdk/bus/prompt-reconciliation.d.ts +105 -0
  50. package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +18 -3
  51. package/dist/types/sdk/bus/telegram-daemon-control.d.ts +5 -1
  52. package/dist/types/sdk/bus/telegram-daemon.d.ts +189 -4
  53. package/dist/types/sdk/bus/telegram-reference.d.ts +2 -0
  54. package/dist/types/sdk/bus/topic-registry.d.ts +88 -2
  55. package/dist/types/sdk/client/discovery.d.ts +2 -0
  56. package/dist/types/sdk/client/liveness.d.ts +7 -0
  57. package/dist/types/sdk/host/control/operations.d.ts +1 -1
  58. package/dist/types/sdk/host/host.d.ts +1 -1
  59. package/dist/types/sdk/host/query/handlers.d.ts +9 -0
  60. package/dist/types/sdk/index.d.ts +2 -0
  61. package/dist/types/sdk/prompt-status.d.ts +88 -0
  62. package/dist/types/sdk/session-directory.d.ts +1 -1
  63. package/dist/types/sdk/startup-capability.d.ts +3 -0
  64. package/dist/types/sdk/transport/auth-preface.d.ts +9 -0
  65. package/dist/types/sdk/transport/index.d.ts +12 -0
  66. package/dist/types/sdk/transport/relay.d.ts +43 -0
  67. package/dist/types/sdk/transport/serve-cli.d.ts +4 -0
  68. package/dist/types/sdk/transport/socket.d.ts +7 -0
  69. package/dist/types/sdk/transport/stdio.d.ts +3 -0
  70. package/dist/types/session/agent-session.d.ts +30 -5
  71. package/dist/types/session/btw-contract.d.ts +16 -0
  72. package/dist/types/session/internal/managed-session-scope.d.ts +32 -9
  73. package/dist/types/session/internal/managed-session-storage.d.ts +27 -10
  74. package/dist/types/session/internal/native-publish-outcome.d.ts +48 -0
  75. package/dist/types/session/session-manager.d.ts +25 -4
  76. package/dist/types/session/session-storage.d.ts +18 -0
  77. package/dist/types/setup/credential-import.d.ts +5 -1
  78. package/dist/types/setup/provider-onboarding.d.ts +2 -0
  79. package/dist/types/ssh/utils.d.ts +1 -0
  80. package/dist/types/task/discovery.d.ts +3 -1
  81. package/dist/types/task/index.d.ts +3 -1
  82. package/dist/types/task/receipt.d.ts +2 -0
  83. package/dist/types/task/types.d.ts +94 -0
  84. package/dist/types/tools/ask.d.ts +454 -174
  85. package/dist/types/tools/fetch.d.ts +5 -8
  86. package/dist/types/tools/image-gen.d.ts +63 -1
  87. package/dist/types/tools/index.d.ts +4 -0
  88. package/dist/types/tools/skill-discovery.d.ts +7 -0
  89. package/dist/types/tools/sqlite-reader.d.ts +7 -0
  90. package/dist/types/utils/prompt-suggestion.d.ts +33 -0
  91. package/dist/types/utils/shell-snapshot.d.ts +12 -0
  92. package/dist/types/web/insane/bridge.d.ts +1 -0
  93. package/dist/types/web/insane/url-guard.d.ts +17 -0
  94. package/package.json +8 -8
  95. package/scripts/capture-platform-shortcut-labels-showcase.ts +342 -0
  96. package/scripts/dogfood-repository-binding.ts +209 -0
  97. package/scripts/generate-sdk-operation-inventory.ts +4 -0
  98. package/scripts/run-test-manifest.ts +4 -4
  99. package/src/capability/index.ts +50 -42
  100. package/src/capability/types.ts +3 -0
  101. package/src/cli/args.ts +2 -92
  102. package/src/cli/notify-cli.ts +5 -38
  103. package/src/cli/setup-cli.ts +10 -4
  104. package/src/cli.ts +52 -9
  105. package/src/commands/daemon.ts +22 -5
  106. package/src/commands/sdk.ts +44 -11
  107. package/src/config/keybindings.ts +158 -25
  108. package/src/config/model-profile-activation.ts +7 -18
  109. package/src/config/model-profile-contract.ts +161 -0
  110. package/src/config/model-profiles.ts +18 -0
  111. package/src/config/model-registry.ts +11 -1
  112. package/src/config/settings-schema.ts +73 -7
  113. package/src/coordinator-mcp/model-preset.ts +21 -74
  114. package/src/defaults/gjc/skills/deep-interview/SKILL.md +2 -2
  115. package/src/defaults/gjc/skills/ralplan/SKILL.md +3 -1
  116. package/src/defaults/gjc/skills/ultragoal/SKILL.md +42 -1
  117. package/src/discovery/ssh.ts +12 -1
  118. package/src/edit/index.ts +3 -6
  119. package/src/edit/modes/patch.ts +38 -1
  120. package/src/edit/modes/replace.ts +42 -0
  121. package/src/edit/path-mutation-lock.ts +112 -0
  122. package/src/eval/py/executor.ts +30 -11
  123. package/src/eval/py/kernel.ts +1 -21
  124. package/src/eval/py/prelude.py +2 -2
  125. package/src/eval/py/runner-artifact.ts +84 -0
  126. package/src/eval/py/tool-bridge.ts +34 -18
  127. package/src/extensibility/gjc-plugins/runtime-adapters.ts +2 -1
  128. package/src/extensibility/plugins/marketplace/fetcher.ts +191 -7
  129. package/src/gjc-runtime/launch-tmux.ts +1 -1
  130. package/src/gjc-runtime/managed-owner-supervisor.ts +83 -4
  131. package/src/gjc-runtime/ralplan-runtime.ts +75 -3
  132. package/src/gjc-runtime/repository-binding.ts +267 -0
  133. package/src/gjc-runtime/session-state-sidecar.ts +25 -9
  134. package/src/gjc-runtime/tmux-owner-isolation.ts +2 -1
  135. package/src/gjc-runtime/tmux-sessions.ts +45 -6
  136. package/src/gjc-runtime/ultragoal-guard.ts +93 -15
  137. package/src/gjc-runtime/ultragoal-receipt-freshness.ts +103 -0
  138. package/src/gjc-runtime/ultragoal-runtime.ts +456 -31
  139. package/src/gjc-runtime/workflow-manifest.generated.json +58 -0
  140. package/src/gjc-runtime/workflow-manifest.ts +23 -0
  141. package/src/internal-urls/docs-index.generated.ts +12 -10
  142. package/src/internal-urls/local-protocol.ts +64 -21
  143. package/src/internal-urls/mcp-protocol.ts +73 -11
  144. package/src/main.ts +111 -37
  145. package/src/modes/DESIGN.md +5 -0
  146. package/src/modes/acp/acp-agent.ts +50 -16
  147. package/src/modes/action-registry.ts +1 -1
  148. package/src/modes/components/btw-panel.ts +82 -16
  149. package/src/modes/components/model-selector.ts +73 -11
  150. package/src/modes/components/plan-preview-overlay.ts +1 -1
  151. package/src/modes/components/runtime-mcp-add-wizard.ts +5 -0
  152. package/src/modes/components/tool-status-header.ts +25 -4
  153. package/src/modes/components/welcome.ts +22 -18
  154. package/src/modes/controllers/btw-controller.ts +119 -36
  155. package/src/modes/controllers/command-controller.ts +97 -54
  156. package/src/modes/controllers/event-controller.ts +10 -0
  157. package/src/modes/controllers/input-controller.ts +38 -2
  158. package/src/modes/controllers/runtime-mcp-command-controller.ts +29 -6
  159. package/src/modes/controllers/selector-controller.ts +149 -63
  160. package/src/modes/interactive-mode.ts +57 -34
  161. package/src/modes/prompt-action-autocomplete.ts +32 -13
  162. package/src/modes/prompt-suggestion-controller.ts +96 -0
  163. package/src/modes/shared/agent-wire/workflow-gate-broker.ts +2 -2
  164. package/src/modes/types.ts +4 -0
  165. package/src/modes/utils/hotkeys-markdown.ts +64 -36
  166. package/src/modes/utils/ui-helpers.ts +5 -3
  167. package/src/prompts/agents/architect.md +0 -1
  168. package/src/prompts/agents/critic.md +0 -1
  169. package/src/prompts/system/btw-user.md +3 -8
  170. package/src/prompts/system/prompt-suggestion-system.md +32 -0
  171. package/src/prompts/system/system-prompt.md +6 -4
  172. package/src/prompts/tools/cron.md +3 -1
  173. package/src/prompts/tools/skill-discovery.md +1 -0
  174. package/src/runtime-mcp/client.ts +41 -55
  175. package/src/runtime-mcp/content-limits.ts +71 -0
  176. package/src/runtime-mcp/json-rpc.ts +23 -9
  177. package/src/runtime-mcp/manager.ts +51 -53
  178. package/src/runtime-mcp/oauth-flow.ts +0 -72
  179. package/src/runtime-mcp/plugin-network-boundary.ts +101 -0
  180. package/src/runtime-mcp/transports/http.ts +63 -22
  181. package/src/sdk/broker/broker.ts +34 -20
  182. package/src/sdk/broker/lifecycle.ts +185 -36
  183. package/src/sdk/bus/chat-daemon-control.ts +19 -5
  184. package/src/sdk/bus/config-commands.ts +2 -2
  185. package/src/sdk/bus/config.ts +9 -1
  186. package/src/sdk/bus/conversation-store.ts +40 -6
  187. package/src/sdk/bus/index.ts +244 -70
  188. package/src/sdk/bus/lifecycle-commands.ts +63 -10
  189. package/src/sdk/bus/lifecycle-control-runtime.ts +11 -2
  190. package/src/sdk/bus/lifecycle-orchestrator.ts +32 -1
  191. package/src/sdk/bus/notification-orchestration.ts +12 -0
  192. package/src/sdk/bus/notification-service.ts +68 -20
  193. package/src/sdk/bus/prompt-reconciliation.ts +239 -0
  194. package/src/sdk/bus/recent-activity.ts +90 -26
  195. package/src/sdk/bus/telegram-daemon-contract.ts +18 -3
  196. package/src/sdk/bus/telegram-daemon-control.ts +147 -35
  197. package/src/sdk/bus/telegram-daemon.ts +2463 -450
  198. package/src/sdk/bus/telegram-reference.ts +20 -2
  199. package/src/sdk/bus/topic-registry.ts +451 -12
  200. package/src/sdk/cli/session-cli.ts +15 -2
  201. package/src/sdk/client/discovery.ts +19 -3
  202. package/src/sdk/client/liveness.ts +49 -0
  203. package/src/sdk/host/control/dispatch.ts +1 -1
  204. package/src/sdk/host/control/operations.ts +1 -1
  205. package/src/sdk/host/host.ts +2 -6
  206. package/src/sdk/host/query/handlers.ts +70 -5
  207. package/src/sdk/index.ts +12 -0
  208. package/src/sdk/prompt-status.ts +97 -0
  209. package/src/sdk/protocol/operation-inventory.generated.json +58 -0
  210. package/src/sdk/protocol/operation-registry.ts +18 -4
  211. package/src/sdk/session-directory.ts +5 -1
  212. package/src/sdk/session.ts +31 -5
  213. package/src/sdk/startup-capability.ts +9 -1
  214. package/src/sdk/transport/auth-preface.ts +82 -0
  215. package/src/sdk/transport/index.ts +18 -0
  216. package/src/sdk/transport/relay.ts +252 -0
  217. package/src/sdk/transport/serve-cli.ts +105 -0
  218. package/src/sdk/transport/socket.ts +197 -0
  219. package/src/sdk/transport/stdio.ts +17 -0
  220. package/src/session/agent-session.ts +292 -154
  221. package/src/session/blob-store.ts +25 -7
  222. package/src/session/btw-contract.ts +59 -0
  223. package/src/session/internal/managed-session-scope.ts +1163 -137
  224. package/src/session/internal/managed-session-storage.ts +397 -234
  225. package/src/session/internal/native-publish-outcome.ts +266 -0
  226. package/src/session/session-manager.ts +620 -403
  227. package/src/session/session-storage.ts +128 -11
  228. package/src/setup/credential-import.ts +28 -3
  229. package/src/setup/provider-onboarding.ts +30 -1
  230. package/src/setup/provider-presets.json +2 -1
  231. package/src/slash-commands/builtin-registry.ts +1 -1
  232. package/src/ssh/utils.ts +14 -0
  233. package/src/task/discovery.ts +8 -2
  234. package/src/task/gjc-command.ts +2 -2
  235. package/src/task/index.ts +121 -15
  236. package/src/task/receipt.ts +3 -0
  237. package/src/task/types.ts +34 -3
  238. package/src/tools/ask.ts +199 -89
  239. package/src/tools/ast-edit.ts +2 -2
  240. package/src/tools/bash-pty-selection.ts +2 -2
  241. package/src/tools/browser/screenshot-format.ts +6 -1
  242. package/src/tools/cron.ts +1 -1
  243. package/src/tools/fetch.ts +13 -131
  244. package/src/tools/image-gen.ts +476 -23
  245. package/src/tools/index.ts +4 -0
  246. package/src/tools/read.ts +2 -0
  247. package/src/tools/render-utils.ts +7 -1
  248. package/src/tools/skill-discovery.ts +39 -3
  249. package/src/tools/sqlite-reader.ts +63 -5
  250. package/src/utils/edit-mode.ts +2 -2
  251. package/src/utils/pasted-image-path.ts +15 -6
  252. package/src/utils/prompt-suggestion.ts +265 -0
  253. package/src/utils/shell-snapshot.ts +173 -63
  254. package/src/utils/sixel.ts +3 -3
  255. package/src/web/insane/bridge.ts +5 -1
  256. package/src/web/insane/url-guard.ts +140 -27
  257. package/src/web/scrapers/docs-rs.ts +30 -5
  258. package/src/web/scrapers/types.ts +19 -49
  259. package/src/web/scrapers/utils.ts +12 -26
@@ -4,7 +4,7 @@ import type { AgentToolResult } from "@gajae-code/agent-core";
4
4
  import type { ImageContent, TextContent } from "@gajae-code/ai";
5
5
  import { htmlToMarkdown } from "@gajae-code/natives";
6
6
  import { type Component, Text } from "@gajae-code/tui";
7
- import { $which, ptree, truncate } from "@gajae-code/utils";
7
+ import { ptree, truncate } from "@gajae-code/utils";
8
8
  import type { Settings } from "../config/settings";
9
9
  import type { RenderResultOptions } from "../extensibility/custom-tools/types";
10
10
  import { type Theme, theme } from "../modes/theme/theme";
@@ -15,10 +15,8 @@ import { renderStatusLine } from "../tui";
15
15
  import { CachedOutputBlock } from "../tui/output-block";
16
16
  import { formatDimensionNote, resizeImage } from "../utils/image-resize";
17
17
  import { parseHtmlLazy } from "../utils/linkedom";
18
- import { ensureTool } from "../utils/tools-manager";
19
- import { INSANE_NOTES, tryInsaneFetch } from "../web/insane/bridge";
20
- import { validatePublicHttpUrl, validatePublicHttpUrlForInsane } from "../web/insane/url-guard";
21
- import { extractWithParallel, findParallelApiKey, getParallelExtractContent } from "../web/parallel";
18
+ import { INSANE_NOTES } from "../web/insane/bridge";
19
+ import { validatePublicHttpUrl } from "../web/insane/url-guard";
22
20
  import { specialHandlers } from "../web/scrapers";
23
21
  import type { RenderResult } from "../web/scrapers/types";
24
22
  import { finalizeOutput, loadPage, looksLikeHtml, MAX_OUTPUT_CHARS } from "../web/scrapers/types";
@@ -93,13 +91,6 @@ const MAX_INLINE_IMAGE_OUTPUT_BYTES = 300 * 1024;
93
91
  // Utilities
94
92
  // =============================================================================
95
93
 
96
- /**
97
- * Check if a command exists (cross-platform)
98
- */
99
- function hasCommand(cmd: string): boolean {
100
- return Boolean($which(cmd));
101
- }
102
-
103
94
  /**
104
95
  * Build llms.txt candidates scoped to the requested URL
105
96
  */
@@ -537,96 +528,18 @@ async function parseFeedToMarkdown(content: string, maxItems = 10): Promise<stri
537
528
  return content; // Fall back to raw content
538
529
  }
539
530
 
540
- /**
541
- * Render HTML to markdown using Parallel, jina, trafilatura, lynx (in order of preference)
542
- */
543
- async function renderHtmlToText(
544
- url: string,
531
+ export async function renderHtmlToText(
545
532
  html: string,
546
- timeout: number,
547
- settings: Settings,
548
- userSignal: AbortSignal | undefined,
549
- storage: AgentStorage | null,
533
+ signal?: AbortSignal,
550
534
  ): Promise<{ content: string; ok: boolean; method: string }> {
551
- const signal = ptree.combineSignals(userSignal, timeout * 1000);
552
- const execOptions = {
553
- mode: "group" as const,
554
- allowNonZero: true,
555
- allowAbort: true,
556
- stderr: "full" as const,
557
- signal,
558
- };
559
-
560
- // Try Parallel extract first when credentials are configured
561
- if (settings.get("providers.parallelFetch") && findParallelApiKey(storage)) {
562
- try {
563
- const parallelResult = await extractWithParallel(
564
- [url],
565
- {
566
- objective: "Extract the main content",
567
- excerpts: true,
568
- fullContent: false,
569
- signal,
570
- },
571
- storage,
572
- );
573
- const firstDocument = parallelResult.results[0];
574
- if (firstDocument) {
575
- const content = getParallelExtractContent(firstDocument);
576
- if (content.trim().length > 100 && !isLowQualityOutput(content)) {
577
- return { content, ok: true, method: "parallel" };
578
- }
579
- }
580
- } catch {
581
- // Parallel extract failed, continue to next method
582
- signal?.throwIfAborted();
583
- }
584
- }
585
-
586
- // Try jina first (reader API)
587
535
  try {
588
- const jinaUrl = `https://r.jina.ai/${url}`;
589
- const response = await fetch(jinaUrl, {
590
- headers: { Accept: "text/markdown" },
591
- signal,
592
- });
593
- if (response.ok) {
594
- const content = await response.text();
595
- if (content.trim().length > 100 && !isLowQualityOutput(content)) {
596
- return { content, ok: true, method: "jina" };
597
- }
598
- }
599
- } catch {
600
- // Jina failed, continue to next method
601
536
  signal?.throwIfAborted();
602
- }
603
-
604
- // Try trafilatura (auto-install via uv/pip)
605
- const trafilatura = await ensureTool("trafilatura", { signal, silent: true });
606
- if (trafilatura) {
607
- const result = await ptree.exec([trafilatura, "-u", url, "--output-format", "markdown"], execOptions);
608
- if (result.ok && result.stdout.trim().length > 100) {
609
- return { content: result.stdout, ok: true, method: "trafilatura" };
610
- }
611
- }
612
-
613
- // Try lynx (can't auto-install, system package)
614
- const lynx = hasCommand("lynx");
615
- if (lynx) {
616
- const result = await ptree.exec(["lynx", "-dump", "-nolist", "-width", "250", url], execOptions);
617
- if (result.ok) {
618
- return { content: result.stdout, ok: true, method: "lynx" };
619
- }
620
- }
621
-
622
- // Fall back to native converter (fastest, no network/subprocess)
623
- try {
624
537
  const content = await htmlToMarkdown(html, { cleanContent: true });
625
538
  if (content.trim().length > 100 && !isLowQualityOutput(content)) {
626
539
  return { content, ok: true, method: "native" };
627
540
  }
628
541
  } catch {
629
- // Native converter failed, continue to next method
542
+ // Native conversion failed; the caller returns its bounded raw HTML.
630
543
  signal?.throwIfAborted();
631
544
  }
632
545
  return { content: "", ok: false, method: "none" };
@@ -707,14 +620,6 @@ async function handleSpecialUrls(
707
620
  // Main Render Function
708
621
  // =============================================================================
709
622
 
710
- /**
711
- * Opt-in insane-search fallback for blocked / degraded public URL reads.
712
- *
713
- * Returns a finalized `method: "insane"` result on success, or null (so the
714
- * caller continues with its normal degraded behavior). Fail-closed: no note,
715
- * guard DNS, dependency probe, or subprocess when raw mode or the opt-in
716
- * setting is off. The public-URL guard runs BEFORE any probe/spawn.
717
- */
718
623
  export async function tryInsaneFallback(args: {
719
624
  url: string;
720
625
  finalUrl: string;
@@ -727,32 +632,7 @@ export async function tryInsaneFallback(args: {
727
632
  }): Promise<FetchRenderResult | null> {
728
633
  if (args.raw) return null;
729
634
  if (args.settings.get("web.insaneFallback") !== true) return null;
730
-
731
- const target = args.finalUrl || args.url;
732
- const guard = await validatePublicHttpUrlForInsane(target);
733
- if (!guard.ok) {
734
- args.notes.push(INSANE_NOTES.guardBlocked(guard.reason));
735
- return null;
736
- }
737
-
738
- const result = await tryInsaneFetch(guard.url.toString(), {
739
- timeoutMs: args.timeout * 1000,
740
- signal: args.signal,
741
- });
742
- if (result.ok) {
743
- const output = finalizeOutput(result.content);
744
- return {
745
- url: args.url,
746
- finalUrl: target,
747
- contentType: "text/markdown",
748
- method: "insane",
749
- content: output.content,
750
- fetchedAt: args.fetchedAt,
751
- truncated: output.truncated,
752
- notes: [...args.notes, ...result.notes],
753
- };
754
- }
755
- for (const note of result.notes) args.notes.push(note);
635
+ args.notes.push(INSANE_NOTES.securityDisabled);
756
636
  return null;
757
637
  }
758
638
 
@@ -772,6 +652,7 @@ async function renderUrl(
772
652
  if (signal?.aborted) {
773
653
  throw new ToolAbortError();
774
654
  }
655
+ const preflightSignal = ptree.combineSignals(signal, timeout * 1000);
775
656
 
776
657
  // Handle internal protocol URLs (e.g., pi-internal://) - return empty
777
658
  if (url.startsWith("pi-internal://")) {
@@ -789,7 +670,8 @@ async function renderUrl(
789
670
 
790
671
  // Step 0: Normalize URL (ensure scheme for special handlers)
791
672
  url = normalizeUrl(url);
792
- const publicUrl = await validatePublicHttpUrl(url);
673
+ const publicUrl = await validatePublicHttpUrl(url, { signal: preflightSignal });
674
+ if (signal?.aborted) throw new ToolAbortError();
793
675
  if (!publicUrl.ok) {
794
676
  notes.push(`Blocked URL fetch: target URL is not public HTTP(S): ${publicUrl.reason}`);
795
677
  return {
@@ -1138,10 +1020,10 @@ async function renderUrl(
1138
1020
  throw new ToolAbortError();
1139
1021
  }
1140
1022
 
1141
- // 5E: Render HTML with lynx or html2text
1142
- const htmlResult = await renderHtmlToText(finalUrl, rawContent, timeout, settings, signal, storage);
1023
+ // 5E: Render only the bytes already fetched above.
1024
+ const htmlResult = await renderHtmlToText(rawContent, signal);
1143
1025
  if (!htmlResult.ok) {
1144
- notes.push("html rendering failed (lynx/html2text unavailable)");
1026
+ notes.push("native HTML rendering failed");
1145
1027
  const insane = await tryInsaneFallback({ url, finalUrl, timeout, raw, settings, signal, fetchedAt, notes });
1146
1028
  if (insane) return insane;
1147
1029
  const output = finalizeOutput(rawContent);