@kenkaiiii/ggcoder 4.3.230 → 4.3.232

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 (255) hide show
  1. package/dist/cli.d.ts.map +1 -1
  2. package/dist/cli.js +3 -0
  3. package/dist/cli.js.map +1 -1
  4. package/dist/config.d.ts +1 -0
  5. package/dist/config.d.ts.map +1 -1
  6. package/dist/config.js +7 -1
  7. package/dist/config.js.map +1 -1
  8. package/dist/config.test.d.ts +2 -0
  9. package/dist/config.test.d.ts.map +1 -0
  10. package/dist/config.test.js +29 -0
  11. package/dist/config.test.js.map +1 -0
  12. package/dist/core/goal-controller.d.ts +27 -6
  13. package/dist/core/goal-controller.d.ts.map +1 -1
  14. package/dist/core/goal-controller.js +246 -141
  15. package/dist/core/goal-controller.js.map +1 -1
  16. package/dist/core/goal-controller.test.js +210 -79
  17. package/dist/core/goal-controller.test.js.map +1 -1
  18. package/dist/core/goal-engine.d.ts +61 -0
  19. package/dist/core/goal-engine.d.ts.map +1 -0
  20. package/dist/core/goal-engine.js +123 -0
  21. package/dist/core/goal-engine.js.map +1 -0
  22. package/dist/core/goal-engine.test.d.ts +2 -0
  23. package/dist/core/goal-engine.test.d.ts.map +1 -0
  24. package/dist/core/goal-engine.test.js +295 -0
  25. package/dist/core/goal-engine.test.js.map +1 -0
  26. package/dist/core/goal-integration.d.ts +80 -0
  27. package/dist/core/goal-integration.d.ts.map +1 -0
  28. package/dist/core/goal-integration.js +296 -0
  29. package/dist/core/goal-integration.js.map +1 -0
  30. package/dist/core/goal-integration.test.d.ts +2 -0
  31. package/dist/core/goal-integration.test.d.ts.map +1 -0
  32. package/dist/core/goal-integration.test.js +369 -0
  33. package/dist/core/goal-integration.test.js.map +1 -0
  34. package/dist/core/goal-prerequisites.test.js +37 -1
  35. package/dist/core/goal-prerequisites.test.js.map +1 -1
  36. package/dist/core/goal-store.d.ts +80 -1
  37. package/dist/core/goal-store.d.ts.map +1 -1
  38. package/dist/core/goal-store.js +232 -65
  39. package/dist/core/goal-store.js.map +1 -1
  40. package/dist/core/goal-store.test.js +111 -2
  41. package/dist/core/goal-store.test.js.map +1 -1
  42. package/dist/core/goal-worker.d.ts.map +1 -1
  43. package/dist/core/goal-worker.js +55 -4
  44. package/dist/core/goal-worker.js.map +1 -1
  45. package/dist/core/goal-worker.test.js +75 -6
  46. package/dist/core/goal-worker.test.js.map +1 -1
  47. package/dist/core/goal-worktree.d.ts +55 -1
  48. package/dist/core/goal-worktree.d.ts.map +1 -1
  49. package/dist/core/goal-worktree.js +164 -1
  50. package/dist/core/goal-worktree.js.map +1 -1
  51. package/dist/core/goal-worktree.test.js +226 -4
  52. package/dist/core/goal-worktree.test.js.map +1 -1
  53. package/dist/core/ideal-review.d.ts +20 -0
  54. package/dist/core/ideal-review.d.ts.map +1 -0
  55. package/dist/core/ideal-review.js +55 -0
  56. package/dist/core/ideal-review.js.map +1 -0
  57. package/dist/core/ideal-review.test.d.ts +2 -0
  58. package/dist/core/ideal-review.test.d.ts.map +1 -0
  59. package/dist/core/ideal-review.test.js +59 -0
  60. package/dist/core/ideal-review.test.js.map +1 -0
  61. package/dist/core/settings-manager.d.ts +1 -0
  62. package/dist/core/settings-manager.d.ts.map +1 -1
  63. package/dist/core/settings-manager.js +2 -0
  64. package/dist/core/settings-manager.js.map +1 -1
  65. package/dist/system-prompt.d.ts.map +1 -1
  66. package/dist/system-prompt.js +9 -6
  67. package/dist/system-prompt.js.map +1 -1
  68. package/dist/system-prompt.test.js +1 -1
  69. package/dist/system-prompt.test.js.map +1 -1
  70. package/dist/tools/edit-diff.d.ts +17 -4
  71. package/dist/tools/edit-diff.d.ts.map +1 -1
  72. package/dist/tools/edit-diff.js +78 -16
  73. package/dist/tools/edit-diff.js.map +1 -1
  74. package/dist/tools/edit-diff.test.js +31 -1
  75. package/dist/tools/edit-diff.test.js.map +1 -1
  76. package/dist/tools/edit-robustness.test.d.ts +2 -0
  77. package/dist/tools/edit-robustness.test.d.ts.map +1 -0
  78. package/dist/tools/edit-robustness.test.js +415 -0
  79. package/dist/tools/edit-robustness.test.js.map +1 -0
  80. package/dist/tools/edit.d.ts.map +1 -1
  81. package/dist/tools/edit.js +15 -16
  82. package/dist/tools/edit.js.map +1 -1
  83. package/dist/tools/edit.test.js +23 -12
  84. package/dist/tools/edit.test.js.map +1 -1
  85. package/dist/tools/goals.d.ts +9 -1
  86. package/dist/tools/goals.d.ts.map +1 -1
  87. package/dist/tools/goals.js +78 -25
  88. package/dist/tools/goals.js.map +1 -1
  89. package/dist/tools/goals.test.js +142 -11
  90. package/dist/tools/goals.test.js.map +1 -1
  91. package/dist/tools/html-extract.d.ts +58 -0
  92. package/dist/tools/html-extract.d.ts.map +1 -0
  93. package/dist/tools/html-extract.js +130 -0
  94. package/dist/tools/html-extract.js.map +1 -0
  95. package/dist/tools/html-extract.test.d.ts +2 -0
  96. package/dist/tools/html-extract.test.d.ts.map +1 -0
  97. package/dist/tools/html-extract.test.js +60 -0
  98. package/dist/tools/html-extract.test.js.map +1 -0
  99. package/dist/tools/pdf-extract.d.ts +18 -0
  100. package/dist/tools/pdf-extract.d.ts.map +1 -0
  101. package/dist/tools/pdf-extract.js +43 -0
  102. package/dist/tools/pdf-extract.js.map +1 -0
  103. package/dist/tools/pdf-extract.test.d.ts +2 -0
  104. package/dist/tools/pdf-extract.test.d.ts.map +1 -0
  105. package/dist/tools/pdf-extract.test.js +15 -0
  106. package/dist/tools/pdf-extract.test.js.map +1 -0
  107. package/dist/tools/prompt-hints.d.ts.map +1 -1
  108. package/dist/tools/prompt-hints.js +2 -1
  109. package/dist/tools/prompt-hints.js.map +1 -1
  110. package/dist/tools/web-fetch.d.ts +16 -1
  111. package/dist/tools/web-fetch.d.ts.map +1 -1
  112. package/dist/tools/web-fetch.js +357 -45
  113. package/dist/tools/web-fetch.js.map +1 -1
  114. package/dist/tools/web-fetch.test.js +263 -2
  115. package/dist/tools/web-fetch.test.js.map +1 -1
  116. package/dist/tools/web-search.d.ts +14 -0
  117. package/dist/tools/web-search.d.ts.map +1 -1
  118. package/dist/tools/web-search.js +321 -35
  119. package/dist/tools/web-search.js.map +1 -1
  120. package/dist/tools/web-search.test.js +144 -1
  121. package/dist/tools/web-search.test.js.map +1 -1
  122. package/dist/ui/App.d.ts +11 -1
  123. package/dist/ui/App.d.ts.map +1 -1
  124. package/dist/ui/App.js +132 -17
  125. package/dist/ui/App.js.map +1 -1
  126. package/dist/ui/app-items.d.ts +14 -1
  127. package/dist/ui/app-items.d.ts.map +1 -1
  128. package/dist/ui/app-items.js +2 -0
  129. package/dist/ui/app-items.js.map +1 -1
  130. package/dist/ui/components/ChatLayout.d.ts +8 -1
  131. package/dist/ui/components/ChatLayout.d.ts.map +1 -1
  132. package/dist/ui/components/ChatLayout.js +4 -1
  133. package/dist/ui/components/ChatLayout.js.map +1 -1
  134. package/dist/ui/components/ChatScreen.d.ts +14 -1
  135. package/dist/ui/components/ChatScreen.d.ts.map +1 -1
  136. package/dist/ui/components/ChatScreen.js +3 -2
  137. package/dist/ui/components/ChatScreen.js.map +1 -1
  138. package/dist/ui/components/IdealHookMessage.d.ts +12 -0
  139. package/dist/ui/components/IdealHookMessage.d.ts.map +1 -0
  140. package/dist/ui/components/IdealHookMessage.js +24 -0
  141. package/dist/ui/components/IdealHookMessage.js.map +1 -0
  142. package/dist/ui/components/InputArea.d.ts +13 -1
  143. package/dist/ui/components/InputArea.d.ts.map +1 -1
  144. package/dist/ui/components/InputArea.js +96 -12
  145. package/dist/ui/components/InputArea.js.map +1 -1
  146. package/dist/ui/components/TranscriptViewport.d.ts +34 -0
  147. package/dist/ui/components/TranscriptViewport.d.ts.map +1 -0
  148. package/dist/ui/components/TranscriptViewport.js +45 -0
  149. package/dist/ui/components/TranscriptViewport.js.map +1 -0
  150. package/dist/ui/footer-jump-regression.test.d.ts +2 -0
  151. package/dist/ui/footer-jump-regression.test.d.ts.map +1 -0
  152. package/dist/ui/footer-jump-regression.test.js +167 -0
  153. package/dist/ui/footer-jump-regression.test.js.map +1 -0
  154. package/dist/ui/goal-events.d.ts +1 -1
  155. package/dist/ui/goal-events.d.ts.map +1 -1
  156. package/dist/ui/goal-events.js +2 -2
  157. package/dist/ui/goal-events.js.map +1 -1
  158. package/dist/ui/goal-events.test.js +2 -2
  159. package/dist/ui/goal-events.test.js.map +1 -1
  160. package/dist/ui/goal-lifecycle-orchestration.test.js +13 -97
  161. package/dist/ui/goal-lifecycle-orchestration.test.js.map +1 -1
  162. package/dist/ui/goal-progress.d.ts.map +1 -1
  163. package/dist/ui/goal-progress.js +0 -1
  164. package/dist/ui/goal-progress.js.map +1 -1
  165. package/dist/ui/goal-run-helpers.d.ts +0 -4
  166. package/dist/ui/goal-run-helpers.d.ts.map +1 -1
  167. package/dist/ui/goal-run-helpers.js +2 -21
  168. package/dist/ui/goal-run-helpers.js.map +1 -1
  169. package/dist/ui/hooks/useAgentLoop.d.ts +2 -0
  170. package/dist/ui/hooks/useAgentLoop.d.ts.map +1 -1
  171. package/dist/ui/hooks/useAgentLoop.js +45 -1
  172. package/dist/ui/hooks/useAgentLoop.js.map +1 -1
  173. package/dist/ui/hooks/useChatLayoutMeasurements.d.ts +8 -0
  174. package/dist/ui/hooks/useChatLayoutMeasurements.d.ts.map +1 -1
  175. package/dist/ui/hooks/useChatLayoutMeasurements.js +2 -0
  176. package/dist/ui/hooks/useChatLayoutMeasurements.js.map +1 -1
  177. package/dist/ui/hooks/useGoalOrchestration.d.ts +2 -1
  178. package/dist/ui/hooks/useGoalOrchestration.d.ts.map +1 -1
  179. package/dist/ui/hooks/useGoalOrchestration.js +198 -80
  180. package/dist/ui/hooks/useGoalOrchestration.js.map +1 -1
  181. package/dist/ui/hooks/useTerminalSize.d.ts +8 -1
  182. package/dist/ui/hooks/useTerminalSize.d.ts.map +1 -1
  183. package/dist/ui/hooks/useTerminalSize.js +12 -2
  184. package/dist/ui/hooks/useTerminalSize.js.map +1 -1
  185. package/dist/ui/hooks/useTranscriptHistory.d.ts +1 -1
  186. package/dist/ui/hooks/useTranscriptHistory.d.ts.map +1 -1
  187. package/dist/ui/hooks/useTranscriptHistory.js +23 -9
  188. package/dist/ui/hooks/useTranscriptHistory.js.map +1 -1
  189. package/dist/ui/hooks/useTranscriptHistory.test.d.ts +2 -0
  190. package/dist/ui/hooks/useTranscriptHistory.test.d.ts.map +1 -0
  191. package/dist/ui/hooks/useTranscriptHistory.test.js +61 -0
  192. package/dist/ui/hooks/useTranscriptHistory.test.js.map +1 -0
  193. package/dist/ui/hooks/useTranscriptScroll.d.ts +30 -0
  194. package/dist/ui/hooks/useTranscriptScroll.d.ts.map +1 -0
  195. package/dist/ui/hooks/useTranscriptScroll.js +44 -0
  196. package/dist/ui/hooks/useTranscriptScroll.js.map +1 -0
  197. package/dist/ui/hooks/useTranscriptScroll.test.d.ts +2 -0
  198. package/dist/ui/hooks/useTranscriptScroll.test.d.ts.map +1 -0
  199. package/dist/ui/hooks/useTranscriptScroll.test.js +119 -0
  200. package/dist/ui/hooks/useTranscriptScroll.test.js.map +1 -0
  201. package/dist/ui/live-area-clamp.test.js +11 -2
  202. package/dist/ui/live-area-clamp.test.js.map +1 -1
  203. package/dist/ui/render.d.ts +11 -0
  204. package/dist/ui/render.d.ts.map +1 -1
  205. package/dist/ui/render.js +71 -7
  206. package/dist/ui/render.js.map +1 -1
  207. package/dist/ui/stores/transcript-scroll-store.d.ts +27 -0
  208. package/dist/ui/stores/transcript-scroll-store.d.ts.map +1 -0
  209. package/dist/ui/stores/transcript-scroll-store.js +73 -0
  210. package/dist/ui/stores/transcript-scroll-store.js.map +1 -0
  211. package/dist/ui/stores/transcript-scroll-store.test.d.ts +2 -0
  212. package/dist/ui/stores/transcript-scroll-store.test.d.ts.map +1 -0
  213. package/dist/ui/stores/transcript-scroll-store.test.js +73 -0
  214. package/dist/ui/stores/transcript-scroll-store.test.js.map +1 -0
  215. package/dist/ui/terminal-history.d.ts.map +1 -1
  216. package/dist/ui/terminal-history.js +8 -0
  217. package/dist/ui/terminal-history.js.map +1 -1
  218. package/dist/ui/testing/screen-recorder.d.ts +29 -0
  219. package/dist/ui/testing/screen-recorder.d.ts.map +1 -0
  220. package/dist/ui/testing/screen-recorder.js +179 -0
  221. package/dist/ui/testing/screen-recorder.js.map +1 -0
  222. package/dist/ui/transcript/TranscriptRenderer.d.ts.map +1 -1
  223. package/dist/ui/transcript/TranscriptRenderer.js +4 -1
  224. package/dist/ui/transcript/TranscriptRenderer.js.map +1 -1
  225. package/dist/ui/transcript/spacing.d.ts +3 -2
  226. package/dist/ui/transcript/spacing.d.ts.map +1 -1
  227. package/dist/ui/transcript/spacing.js +8 -0
  228. package/dist/ui/transcript/spacing.js.map +1 -1
  229. package/dist/ui/transcript/spacing.test.js +31 -0
  230. package/dist/ui/transcript/spacing.test.js.map +1 -1
  231. package/dist/ui/transcript/transcript-lines.d.ts +32 -0
  232. package/dist/ui/transcript/transcript-lines.d.ts.map +1 -0
  233. package/dist/ui/transcript/transcript-lines.js +82 -0
  234. package/dist/ui/transcript/transcript-lines.js.map +1 -0
  235. package/dist/ui/transcript/transcript-lines.test.d.ts +2 -0
  236. package/dist/ui/transcript/transcript-lines.test.d.ts.map +1 -0
  237. package/dist/ui/transcript/transcript-lines.test.js +76 -0
  238. package/dist/ui/transcript/transcript-lines.test.js.map +1 -0
  239. package/dist/ui/transcript-viewport-pinning.test.d.ts +2 -0
  240. package/dist/ui/transcript-viewport-pinning.test.d.ts.map +1 -0
  241. package/dist/ui/transcript-viewport-pinning.test.js +148 -0
  242. package/dist/ui/transcript-viewport-pinning.test.js.map +1 -0
  243. package/dist/ui/tui-history-parity.test.js +8 -0
  244. package/dist/ui/tui-history-parity.test.js.map +1 -1
  245. package/dist/ui/tui-simulation.test.d.ts +2 -0
  246. package/dist/ui/tui-simulation.test.d.ts.map +1 -0
  247. package/dist/ui/tui-simulation.test.js +138 -0
  248. package/dist/ui/tui-simulation.test.js.map +1 -0
  249. package/dist/ui/tui-terminal-recorder.test.d.ts +2 -0
  250. package/dist/ui/tui-terminal-recorder.test.d.ts.map +1 -0
  251. package/dist/ui/tui-terminal-recorder.test.js +134 -0
  252. package/dist/ui/tui-terminal-recorder.test.js.map +1 -0
  253. package/dist/utils/format.js +7 -0
  254. package/dist/utils/format.js.map +1 -1
  255. package/package.json +12 -6
@@ -1,5 +1,5 @@
1
1
  import { afterEach, describe, expect, it, vi } from "vitest";
2
- import { createWebSearchTool, isAdSearchResultUrl } from "./web-search.js";
2
+ import { canonicalSearchResultUrl, createWebSearchTool, isAdSearchResultUrl, normalizeDomain, } from "./web-search.js";
3
3
  const originalFetch = globalThis.fetch;
4
4
  function context() {
5
5
  return { signal: new AbortController().signal, toolCallId: "test" };
@@ -8,6 +8,16 @@ afterEach(() => {
8
8
  globalThis.fetch = originalFetch;
9
9
  vi.restoreAllMocks();
10
10
  });
11
+ describe("canonicalSearchResultUrl", () => {
12
+ it("strips tracking params and fragments while sorting remaining params", () => {
13
+ expect(canonicalSearchResultUrl("https://example.com/docs?utm_source=x&b=2&a=1&fbclid=abc#section")).toBe("https://example.com/docs?a=1&b=2");
14
+ });
15
+ it("unwraps nested redirect params safely", () => {
16
+ expect(canonicalSearchResultUrl("/l/?url=https%3A%2F%2Fexample.com%2Fguide%3Futm_medium%3Dcpc%26x%3D1")).toBe("https://example.com/guide?x=1");
17
+ expect(canonicalSearchResultUrl("https://duckduckgo.com/y.js?u3=https%3A%2F%2Fwww.bing.com%2Faclick%3Fld%3Dabc")).toBeNull();
18
+ expect(canonicalSearchResultUrl("javascript:alert(1)")).toBeNull();
19
+ });
20
+ });
11
21
  describe("isAdSearchResultUrl", () => {
12
22
  it("blocks DuckDuckGo ad redirects", () => {
13
23
  const url = "https://duckduckgo.com/y.js?ad_domain=nordvpn.com&ad_provider=bingv7aa&ad_type=txad&u3=https%3A%2F%2Fwww.bing.com%2Faclick%3Fld%3Dabc";
@@ -17,11 +27,32 @@ describe("isAdSearchResultUrl", () => {
17
27
  expect(isAdSearchResultUrl("https://www.bing.com/aclick?ld=abc&msclkid=123")).toBe(true);
18
28
  expect(isAdSearchResultUrl("https://www.google.com/aclk?sa=l&adurl=https%3A%2F%2Fexample.com")).toBe(true);
19
29
  });
30
+ it("blocks affiliate and ad network hosts", () => {
31
+ expect(isAdSearchResultUrl("https://awin1.com/cread.php?awinmid=1")).toBe(true);
32
+ expect(isAdSearchResultUrl("https://ads.linkedin.com/click?id=1")).toBe(true);
33
+ });
20
34
  it("allows ordinary organic result URLs", () => {
21
35
  expect(isAdSearchResultUrl("https://developer.mozilla.org/en-US/docs/Web/API/fetch")).toBe(false);
22
36
  expect(isAdSearchResultUrl("/l/?uddg=https%3A%2F%2Fwww.typescriptlang.org%2Fdocs%2F")).toBe(false);
23
37
  });
24
38
  });
39
+ describe("normalizeDomain", () => {
40
+ it("lowercases and strips scheme and wildcard prefixes", () => {
41
+ expect(normalizeDomain("https://Docs.Python.ORG")).toBe("docs.python.org");
42
+ expect(normalizeDomain("*.example.com")).toBe("example.com");
43
+ expect(normalizeDomain(" github.com ")).toBe("github.com");
44
+ });
45
+ it("converts Unicode homographs to punycode", () => {
46
+ // "аррӏе" uses Cyrillic look-alikes; hostname normalizes to xn-- punycode.
47
+ const result = normalizeDomain("аррӏе.com");
48
+ expect(result).toMatch(/^xn--/);
49
+ expect(result).not.toBe("apple.com");
50
+ });
51
+ it("returns null for un-parseable input", () => {
52
+ expect(normalizeDomain("")).toBeNull();
53
+ expect(normalizeDomain(" ")).toBeNull();
54
+ });
55
+ });
25
56
  describe("createWebSearchTool", () => {
26
57
  it("filters ad results from live parser output before returning organic results", async () => {
27
58
  const html = `
@@ -95,6 +126,118 @@ describe("createWebSearchTool", () => {
95
126
  expect(result).toContain("from Brave");
96
127
  expect(result).not.toContain("Cheap laptops for sale");
97
128
  });
129
+ it("applies time_range and include_domains to the request", async () => {
130
+ let capturedUrl = "";
131
+ globalThis.fetch = vi.fn(async (input) => {
132
+ capturedUrl = String(input);
133
+ // Return organic result only on the Google branch.
134
+ if (capturedUrl.includes("google.com")) {
135
+ return new Response(`<div class="g"><a href="https://docs.python.org/3/"><h3>Python Docs</h3></a><div class="VwiC3b">Official Python documentation.</div></div>`, { status: 200 });
136
+ }
137
+ return new Response("<html></html>", { status: 200 });
138
+ });
139
+ const result = await createWebSearchTool().execute({
140
+ query: "asyncio",
141
+ include_domains: ["docs.python.org"],
142
+ time_range: "week",
143
+ max_results: 5,
144
+ }, context());
145
+ // Last captured URL is the Google branch with recency + site scoping.
146
+ expect(capturedUrl).toContain("tbs=qdr:w");
147
+ expect(decodeURIComponent(capturedUrl)).toContain("site:docs.python.org");
148
+ expect(result).toContain("Python Docs");
149
+ expect(result).toContain("past week");
150
+ });
151
+ it("drops results from excluded domains client-side", async () => {
152
+ const html = `
153
+ <a class="result__a" href="/l/?uddg=https%3A%2F%2Fw3schools.com%2Ffetch">W3Schools Fetch</a>
154
+ <a class="result__snippet">Tutorial content.</a>
155
+ <a class="result__a" href="/l/?uddg=https%3A%2F%2Fdeveloper.mozilla.org%2Fen-US%2Fdocs%2FWeb%2FAPI%2FFetch_API">Fetch API - MDN</a>
156
+ <a class="result__snippet">MDN reference.</a>
157
+ `;
158
+ globalThis.fetch = vi.fn(async () => new Response(html, { status: 200 }));
159
+ const result = await createWebSearchTool().execute({ query: "fetch api", exclude_domains: ["w3schools.com"], max_results: 5 }, context());
160
+ expect(result).toContain("Fetch API - MDN");
161
+ expect(result).not.toContain("W3Schools");
162
+ expect(result).toContain("-site:w3schools.com");
163
+ });
164
+ it("filters coupon spam for non-commerce queries but keeps it for commerce queries", async () => {
165
+ const html = `
166
+ <a class="result__a" href="https://coupon.example.com/typescript">TypeScript coupon code</a>
167
+ <a class="result__snippet">Exclusive deal and discount code for docs.</a>
168
+ <a class="result__a" href="https://www.typescriptlang.org/docs/">TypeScript Documentation</a>
169
+ <a class="result__snippet">Official TypeScript docs.</a>
170
+ `;
171
+ globalThis.fetch = vi.fn(async () => new Response(html, { status: 200 }));
172
+ const docsResult = await createWebSearchTool().execute({ query: "typescript docs", max_results: 5 }, context());
173
+ expect(docsResult).toContain("TypeScript Documentation");
174
+ expect(docsResult).not.toContain("TypeScript coupon code");
175
+ expect(docsResult).toContain("filtered 1 spam result");
176
+ globalThis.fetch = vi.fn(async () => new Response(html, { status: 200 }));
177
+ const commerceResult = await createWebSearchTool().execute({ query: "best typescript coupon", max_results: 5 }, context());
178
+ expect(commerceResult).toContain("TypeScript coupon code");
179
+ });
180
+ it("collapses duplicate canonical URLs and reports duplicate count", async () => {
181
+ const html = `
182
+ <a class="result__a" href="https://example.com/docs?utm_source=a&b=2&a=1#top">Docs first</a>
183
+ <a class="result__snippet">First snippet.</a>
184
+ <a class="result__a" href="https://example.com/docs?a=1&b=2">Docs duplicate</a>
185
+ <a class="result__snippet">Duplicate snippet.</a>
186
+ `;
187
+ globalThis.fetch = vi.fn(async () => new Response(html, { status: 200 }));
188
+ const result = await createWebSearchTool().execute({ query: "example docs", max_results: 5 }, context());
189
+ expect(result).toContain("Docs first");
190
+ expect(result).not.toContain("Docs duplicate");
191
+ expect(result).toContain("1 duplicate");
192
+ });
193
+ it("skips sponsored parser blocks and returns organic results", async () => {
194
+ const html = `
195
+ <li class="b_algo b_ad">
196
+ <h2><a href="https://example-ad.com/offer">Sponsored offer</a></h2>
197
+ <div class="b_adlabel">Ad</div><p>Buy now.</p>
198
+ </li>
199
+ <li class="b_algo">
200
+ <h2><a href="https://developer.mozilla.org/docs/Web/API/Fetch_API">Fetch API - MDN</a></h2>
201
+ <div class="b_caption"><p>Useful organic snippet.</p></div>
202
+ </li>
203
+ `;
204
+ globalThis.fetch = vi
205
+ .fn()
206
+ .mockResolvedValueOnce(new Response("<html></html>", { status: 200 }))
207
+ .mockResolvedValueOnce(new Response("<html></html>", { status: 200 }))
208
+ .mockResolvedValueOnce(new Response("<html></html>", { status: 200 }))
209
+ .mockResolvedValueOnce(new Response(html, { status: 200 }));
210
+ const result = await createWebSearchTool().execute({ query: "fetch api mdn", max_results: 5 }, context());
211
+ expect(result).toContain("Fetch API - MDN");
212
+ expect(result).not.toContain("Sponsored offer");
213
+ expect(result).toContain("from Bing");
214
+ });
215
+ it("reports filtered ad counts only when non-zero", async () => {
216
+ const html = `
217
+ <a class="result__a" href="https://googleadservices.com/pagead/aclk">Cloud hosting</a>
218
+ <a class="result__snippet">Fast platform overview.</a>
219
+ <a class="result__a" href="https://example.com/docs">Docs</a>
220
+ <a class="result__snippet">Organic docs.</a>
221
+ `;
222
+ globalThis.fetch = vi.fn(async () => new Response(html, { status: 200 }));
223
+ const filtered = await createWebSearchTool().execute({ query: "example docs", max_results: 5 }, context());
224
+ expect(filtered).toContain("filtered 1 ad");
225
+ globalThis.fetch = vi.fn(async () => new Response(`<a class="result__a" href="https://example.com/docs">Docs</a><a class="result__snippet">Organic docs.</a>`, { status: 200 }));
226
+ const clean = await createWebSearchTool().execute({ query: "example docs", max_results: 5 }, context());
227
+ expect(clean).not.toContain("filtered");
228
+ });
229
+ it("rejects setting both include_domains and exclude_domains via the schema", () => {
230
+ const tool = createWebSearchTool();
231
+ const parsed = tool.parameters.safeParse({
232
+ query: "x",
233
+ include_domains: ["a.com"],
234
+ exclude_domains: ["b.com"],
235
+ });
236
+ expect(parsed.success).toBe(false);
237
+ if (!parsed.success) {
238
+ expect(parsed.error.issues.some((i) => /mutually exclusive/i.test(i.message))).toBe(true);
239
+ }
240
+ });
98
241
  it("uses Bing as a fallback and unwraps Bing redirect URLs", async () => {
99
242
  const blockedHtml = "<html>captcha blocked challenge-form</html>";
100
243
  const bingURL = `https://www.bing.com/ck/a?u=a1${Buffer.from("https://www.typescriptlang.org/docs/", "utf8").toString("base64url")}`;
@@ -1 +1 @@
1
- {"version":3,"file":"web-search.test.js","sourceRoot":"","sources":["../../src/tools/web-search.test.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"web-search.test.js","sourceRoot":"","sources":["../../src/tools/web-search.test.ts"],"names":[],"mappings":"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"}
package/dist/ui/App.d.ts CHANGED
@@ -20,7 +20,7 @@ export { getNextThinkingLevel } from "./thinking-level.js";
20
20
  export { appendGoalProgressDraft, completedItemsWithDurableGoalTerminalProgress, formatGoalTerminalProgress, getGoalContinuationChoiceKey, routeGoalSyntheticEvent, truncateGoalProgressText, } from "./goal-progress.js";
21
21
  export { getChatControlsLayoutDecision, getDoneFlushDecision, getGoalActivationPaneTransition, getGoalSetupFinishedPaneTransition, getGoalSetupPaneTransitionAfterRun, getScrollStabilizationDecision, getStaticHistoryKey, hasParagraphBreakLiveUserMessage, isTallLiveUserMessage, nextGoalModeAfterAgentDone, shouldHideHistoryForOverlayView, shouldHideStaticItemsForOverlayView, shouldResetUIForGoalSetupPaneTransition, shouldStabilizeOverlayPaneRerender, shouldTopSpaceAfterPrintedAgentBoundary, shouldTopSpaceAssistantAfterToolBoundary, shouldTopSpaceStreamingAssistant, } from "./layout-decisions.js";
22
22
  export { getNextGeneratedItemId, isActiveItem, partitionCompleted, pinStreamingTextBeforeToolBoundary, } from "./item-helpers.js";
23
- export { buildGoalDirtyWorktreePauseRun, buildGoalDirtyWorktreeUserPrompt, buildGoalUserPauseRun, goalDirtyWorktreeInfoText, goalRunNeedsExplicitContinuationAfterWorker, shouldKeepGoalRunTrackedAfterDecision, shouldRunGoalTaskInMainCheckout, } from "./goal-run-helpers.js";
23
+ export { buildGoalUserPauseRun, goalRunNeedsExplicitContinuationAfterWorker, shouldKeepGoalRunTrackedAfterDecision, shouldRunGoalTaskInMainCheckout, } from "./goal-run-helpers.js";
24
24
  export interface AppProps {
25
25
  provider: Provider;
26
26
  model: string;
@@ -36,6 +36,7 @@ export interface AppProps {
36
36
  cwd: string;
37
37
  version: string;
38
38
  showTokenUsage?: boolean;
39
+ idealReviewEnabled?: boolean;
39
40
  onSlashCommand?: (input: string) => Promise<string | null>;
40
41
  loggedInProviders?: Provider[];
41
42
  credentialsByProvider?: Record<string, {
@@ -72,6 +73,14 @@ export interface AppProps {
72
73
  onExitPlan?: (planPath: string) => Promise<string>;
73
74
  };
74
75
  terminalHistoryPrinter?: TerminalHistoryPrinter;
76
+ /**
77
+ * When true, the UI runs in the alternate-screen fullscreen viewport: the
78
+ * transcript is rendered inside Ink as a bounded, app-scrolled region above a
79
+ * pinned controls region, and nothing is written to native scrollback. This
80
+ * is what keeps the footer a truly fixed bottom region. Defaults off (legacy
81
+ * scrollback path) for non-TTY / CI / print modes.
82
+ */
83
+ fullscreen?: boolean;
75
84
  /**
76
85
  * Wired by `renderApp`. Tears down the current Ink instance and renders
77
86
  * a fresh one. Patching Ink's internal frame tracking in place is
@@ -148,6 +157,7 @@ export interface AppProps {
148
157
  goalMode?: GoalMode;
149
158
  planMode?: boolean;
150
159
  sessionStats?: SessionStats;
160
+ idealReviewEnabled?: boolean;
151
161
  };
152
162
  }
153
163
  export declare function App(props: AppProps): import("react/jsx-runtime").JSX.Element;
@@ -1 +1 @@
1
- {"version":3,"file":"App.d.ts","sourceRoot":"","sources":["../../src/ui/App.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"App.d.ts","sourceRoot":"","sources":["../../src/ui/App.tsx"],"names":[],"mappings":"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"}
package/dist/ui/App.js CHANGED
@@ -48,22 +48,27 @@ import { isGoalSyntheticEvent, parseGoalSyntheticEvent } from "./goal-events.js"
48
48
  import { buildUserContentWithAttachments } from "./prompt-routing.js";
49
49
  import { submitPromptCommand } from "./submit-prompt-command.js";
50
50
  import { handleUiSlashCommand } from "./submit-slash-commands.js";
51
+ import { buildIdealReviewMessage, evaluateIdealReview } from "../core/ideal-review.js";
51
52
  import { getNextThinkingLevel, isThinkingLevelSupported } from "./thinking-level.js";
52
53
  import { appendGoalProgressDraft, completedItemsWithDurableGoalTerminalProgress, } from "./goal-progress.js";
53
54
  import { getDoneFlushDecision, nextGoalModeAfterAgentDone, shouldTopSpaceAfterPrintedAgentBoundary, shouldTopSpaceStreamingAssistant, } from "./layout-decisions.js";
54
55
  import { isTranscriptSpacingItem } from "./transcript/spacing.js";
56
+ import { buildTranscriptLines } from "./transcript/transcript-lines.js";
57
+ import { useTranscriptScroll } from "./hooks/useTranscriptScroll.js";
58
+ import { scrollTranscriptByLines } from "./stores/transcript-scroll-store.js";
55
59
  import { renderTranscriptItem } from "./transcript/TranscriptRenderer.js";
56
60
  import { formatDuration } from "./duration-format.js";
57
61
  import { pickDurationVerb } from "./duration-summary.js";
58
62
  import { toErrorItem } from "./error-item.js";
59
63
  import { addLinesChanged, buildSessionSummary, createSessionStats, recordServerToolCall, recordToolEnd, recordTurnEnd, } from "./session-summary.js";
60
64
  import { compactHistory, getNextGeneratedItemId, isActiveItem, isSameAssistantText, normalizeAssistantText, partitionCompleted, pinStreamingTextBeforeToolBoundary, removeItemsWithIds, uniqueItemsById, } from "./item-helpers.js";
65
+ import { IDEAL_HOOK_NOTICE_TEXT } from "./app-items.js";
61
66
  export { buildGoalSetupPromptFromPlanner, buildUserContentWithAttachments, collectAssistantTextSince, isGoalPromptCommandName, routePromptCommandInput, runGoalPromptSetupSequence, } from "./prompt-routing.js";
62
67
  export { getNextThinkingLevel } from "./thinking-level.js";
63
68
  export { appendGoalProgressDraft, completedItemsWithDurableGoalTerminalProgress, formatGoalTerminalProgress, getGoalContinuationChoiceKey, routeGoalSyntheticEvent, truncateGoalProgressText, } from "./goal-progress.js";
64
69
  export { getChatControlsLayoutDecision, getDoneFlushDecision, getGoalActivationPaneTransition, getGoalSetupFinishedPaneTransition, getGoalSetupPaneTransitionAfterRun, getScrollStabilizationDecision, getStaticHistoryKey, hasParagraphBreakLiveUserMessage, isTallLiveUserMessage, nextGoalModeAfterAgentDone, shouldHideHistoryForOverlayView, shouldHideStaticItemsForOverlayView, shouldResetUIForGoalSetupPaneTransition, shouldStabilizeOverlayPaneRerender, shouldTopSpaceAfterPrintedAgentBoundary, shouldTopSpaceAssistantAfterToolBoundary, shouldTopSpaceStreamingAssistant, } from "./layout-decisions.js";
65
70
  export { getNextGeneratedItemId, isActiveItem, partitionCompleted, pinStreamingTextBeforeToolBoundary, } from "./item-helpers.js";
66
- export { buildGoalDirtyWorktreePauseRun, buildGoalDirtyWorktreeUserPrompt, buildGoalUserPauseRun, goalDirtyWorktreeInfoText, goalRunNeedsExplicitContinuationAfterWorker, shouldKeepGoalRunTrackedAfterDecision, shouldRunGoalTaskInMainCheckout, } from "./goal-run-helpers.js";
71
+ export { buildGoalUserPauseRun, goalRunNeedsExplicitContinuationAfterWorker, shouldKeepGoalRunTrackedAfterDecision, shouldRunGoalTaskInMainCheckout, } from "./goal-run-helpers.js";
67
72
  /** Tools that get aggregated into a single compact group when possible. */
68
73
  const AGGREGATABLE_TOOLS = new Set([
69
74
  "read",
@@ -100,6 +105,9 @@ export function App(props) {
100
105
  const { columns, rows } = useTerminalSize();
101
106
  // Hoisted before terminal title hook so it can reference them
102
107
  const [lastUserMessage, setLastUserMessage] = useState("");
108
+ // Bumped on every prompt submit; the fullscreen transcript scroll controller
109
+ // watches this to snap back to the bottom so the newest output is visible.
110
+ const [scrollResetToken, setScrollResetToken] = useState(0);
103
111
  const [exitPending, setExitPending] = useState(false);
104
112
  const [quittingSummary, setQuittingSummary] = useState(null);
105
113
  // Terminal title — updated later after agentLoop is created
@@ -204,6 +212,8 @@ export function App(props) {
204
212
  const persistedIndexRef = useRef(messagesRef.current.length);
205
213
  const sessionStatsRef = useRef(props.sessionStore?.sessionStats ??
206
214
  createSessionStats({ sessionId: props.sessionStore?.sessionId ?? props.sessionId }));
215
+ const [idealReviewEnabled, setIdealReviewEnabled] = useState(props.sessionStore?.idealReviewEnabled ?? props.idealReviewEnabled ?? true);
216
+ const idealReviewEnabledRef = useRef(idealReviewEnabled);
207
217
  /** Last actual API-reported input token count (from turn_end). */
208
218
  const lastActualTokensRef = useRef(0);
209
219
  /** Timestamp (ms) when lastActualTokensRef was last updated by turn_end. */
@@ -235,6 +245,11 @@ export function App(props) {
235
245
  const appendGoalProgress = useCallback((item) => {
236
246
  setLiveItems((prev) => appendGoalProgressDraft(prev, item, getId));
237
247
  }, []);
248
+ useEffect(() => {
249
+ idealReviewEnabledRef.current = idealReviewEnabled;
250
+ if (props.sessionStore)
251
+ props.sessionStore.idealReviewEnabled = idealReviewEnabled;
252
+ }, [idealReviewEnabled, props.sessionStore]);
238
253
  const goalNumberForRun = useCallback((runId) => Math.max(1, goalStatusEntries.findIndex((entry) => entry.runId === runId) + 1), [goalStatusEntries]);
239
254
  const clearGoalStatusEntry = useCallback((runId) => {
240
255
  setGoalStatusEntries((prev) => {
@@ -271,7 +286,12 @@ export function App(props) {
271
286
  queuedGoalSyntheticEventsRef,
272
287
  });
273
288
  const { pendingHistoryFlushRef, streamedAssistantFlushRef, queueFlush, finalizeSubmittedUserItem, clearPendingHistory, } = useTranscriptHistory({
274
- terminalHistoryPrinter: props.terminalHistoryPrinter,
289
+ // In fullscreen alt-screen mode the transcript renders inside Ink (the
290
+ // viewport), so we must NOT write completed rows to native scrollback —
291
+ // doing so would scroll the live frame. Dropping the printer keeps history
292
+ // accumulating in React state (still flushed + persisted) without any
293
+ // stdout writes. The legacy scrollback path keeps the printer.
294
+ terminalHistoryPrinter: props.fullscreen ? undefined : props.terminalHistoryPrinter,
275
295
  terminalHistoryContext: {
276
296
  theme,
277
297
  columns,
@@ -636,6 +656,22 @@ export function App(props) {
636
656
  projectId: activeProjectId,
637
657
  resolveCredentials,
638
658
  transformContext,
659
+ getIdealReviewMessage: (stats) => {
660
+ if (!idealReviewEnabledRef.current)
661
+ return null;
662
+ const decision = evaluateIdealReview(stats);
663
+ if (!decision.shouldReview)
664
+ return null;
665
+ log("INFO", "ideal", "Injecting ideal review before final response", {
666
+ score: String(decision.score),
667
+ reasons: decision.reasons.join(", "),
668
+ });
669
+ setLiveItems((prev) => [
670
+ ...prev,
671
+ { kind: "ideal_hook", text: IDEAL_HOOK_NOTICE_TEXT, id: getId() },
672
+ ]);
673
+ return buildIdealReviewMessage(decision.reasons);
674
+ },
639
675
  }, {
640
676
  onComplete: useCallback(() => {
641
677
  persistNewMessages();
@@ -1155,15 +1191,14 @@ export function App(props) {
1155
1191
  setDoneStatus({ durationMs, toolsUsed, verb: pickDurationVerb(toolsUsed) });
1156
1192
  playNotificationSound();
1157
1193
  }
1158
- // Finalize rows. Do NOT clear the live area here — keep the items
1159
- // mounted and let the flush drain effect write them to scrollback
1160
- // FIRST and only then remove them from the live area. Clearing live
1161
- // up front (return []) erases the rows a frame before the sink writes
1162
- // them back into scrollback, which makes each finalized item blink
1163
- // out and the TUI jump as the agent finishes. Write-then-clear keeps
1164
- // every row continuously on screen (live → scrollback), matching how
1165
- // Ink's <Static> moves a finalized item in a single atomic frame.
1166
- if (doneDecision.flushLiveItems) {
1194
+ // Keep the final assistant response mounted in the live frame after a
1195
+ // normal chat turn finishes. Moving a large final response to terminal
1196
+ // history at this moment writes many scrollback rows while the footer is
1197
+ // still mounted, which visibly pushes the input/footer upward. The final
1198
+ // response is flushed on the next submit before the new prompt is shown.
1199
+ // Non-chat overlay transitions still flush so setup/plan/goal output
1200
+ // does not vanish during remounts.
1201
+ if (doneDecision.flushLiveItems && !doneDecision.showDoneStatus) {
1167
1202
  setLiveItems((prev) => {
1168
1203
  if (prev.length > 0)
1169
1204
  queueFlush(prev);
@@ -1506,6 +1541,26 @@ export function App(props) {
1506
1541
  // has not grown.
1507
1542
  await applyLanguageDetectionRef.current("input");
1508
1543
  }
1544
+ if (trimmed === "/ideal-on" || trimmed === "/ideal-off") {
1545
+ const next = trimmed === "/ideal-on";
1546
+ setIdealReviewEnabled(next);
1547
+ if (props.settingsFile) {
1548
+ const sm = new SettingsManager(props.settingsFile);
1549
+ await sm.load();
1550
+ await sm.set("idealReviewEnabled", next);
1551
+ }
1552
+ setLiveItems((prev) => [
1553
+ ...prev,
1554
+ {
1555
+ kind: "info",
1556
+ text: next
1557
+ ? "Ideal review enabled. Use /ideal-off to disable it."
1558
+ : "Ideal review disabled. Use /ideal-on to enable it.",
1559
+ id: getId(),
1560
+ },
1561
+ ]);
1562
+ return;
1563
+ }
1509
1564
  // /rewind — open the checkpoint picker (needs React state + the store).
1510
1565
  if (trimmed === "/rewind") {
1511
1566
  const store = props.checkpointStore;
@@ -1684,6 +1739,7 @@ export function App(props) {
1684
1739
  id: getId(),
1685
1740
  };
1686
1741
  setLastUserMessage(input);
1742
+ setScrollResetToken((token) => token + 1);
1687
1743
  setDoneStatus(null);
1688
1744
  // Clear stale plan progress if there's no active approved plan
1689
1745
  // (avoids lingering progress from a completed or abandoned plan run)
@@ -1691,7 +1747,7 @@ export function App(props) {
1691
1747
  planStepsRef.current = [];
1692
1748
  setPlanSteps([]);
1693
1749
  }
1694
- finalizeSubmittedUserItem(userItem);
1750
+ finalizeSubmittedUserItem(userItem, liveItems);
1695
1751
  // Open a per-turn checkpoint capturing the conversation position right
1696
1752
  // before this exchange, so /rewind can restore pre-turn code/chat state.
1697
1753
  if (props.checkpointStore) {
@@ -1724,6 +1780,7 @@ export function App(props) {
1724
1780
  compactConversation,
1725
1781
  currentModel,
1726
1782
  finalizeSubmittedUserItem,
1783
+ liveItems,
1727
1784
  props.cwd,
1728
1785
  props.onSlashCommand,
1729
1786
  props.resetUI,
@@ -1915,6 +1972,14 @@ export function App(props) {
1915
1972
  { name: "compact", aliases: ["c"], description: "Compact context", sectionTitle: "built-in" },
1916
1973
  { name: "clear", aliases: [], description: "Clear session", sectionTitle: "built-in" },
1917
1974
  { name: "theme", aliases: ["t"], description: "Switch theme", sectionTitle: "built-in" },
1975
+ {
1976
+ name: idealReviewEnabled ? "ideal-off" : "ideal-on",
1977
+ aliases: [],
1978
+ description: idealReviewEnabled
1979
+ ? "Disable pre-final ideal review"
1980
+ : "Enable pre-final ideal review",
1981
+ sectionTitle: "built-in",
1982
+ },
1918
1983
  {
1919
1984
  name: "rewind",
1920
1985
  aliases: [],
@@ -1936,13 +2001,13 @@ export function App(props) {
1936
2001
  sectionTitle: "built-in",
1937
2002
  },
1938
2003
  ];
1939
- }, [customCommands]);
2004
+ }, [customCommands, idealReviewEnabled]);
1940
2005
  const renderItem = (item, index, items) => renderTranscriptItem({
1941
2006
  item,
1942
2007
  index,
1943
2008
  items,
1944
- pendingHistoryFlushLastItem: pendingHistoryFlushRef.current.at(-1),
1945
- historyLastItem: history.at(-1),
2009
+ pendingHistoryFlushLastItem: index === 0 ? pendingHistoryFlushRef.current.at(-1) : undefined,
2010
+ historyLastItem: index === 0 ? history.at(-1) : undefined,
1946
2011
  version: props.version,
1947
2012
  currentModel,
1948
2013
  currentProvider,
@@ -2052,7 +2117,7 @@ export function App(props) {
2052
2117
  });
2053
2118
  const isSkillsView = overlay === "skills";
2054
2119
  const isPlanView = overlay === "plan";
2055
- const { footerStatusLayout, activityVisible, stallStatusVisible, statusSlotVisible, mainControlsRef, measuredLiveAreaRows, } = useChatLayoutMeasurements({
2120
+ const { footerStatusLayout, activityVisible, stallStatusVisible, statusSlotVisible, mainControlsRef, measuredLiveAreaRows, viewportRows, } = useChatLayoutMeasurements({
2056
2121
  rows,
2057
2122
  columns,
2058
2123
  backgroundTaskCount: bgTasks.length,
@@ -2129,6 +2194,54 @@ export function App(props) {
2129
2194
  // mid-stream, the live remainder is the next paragraph — re-insert the blank
2130
2195
  // line that separated them so the live tail lines up with the flushed history.
2131
2196
  const streamingContinuesFlushed = streamedAssistantFlushRef.current.flushedChars > 0;
2197
+ // ── Fullscreen alt-screen transcript ───────────────────
2198
+ // Flatten history + live items + in-flight streaming into the flat ANSI line
2199
+ // buffer the viewport renders. Reuses the same serializer the legacy
2200
+ // scrollback printer used, so the transcript looks identical. Only computed
2201
+ // when fullscreen is active (the legacy path renders items through Ink).
2202
+ const transcriptContext = useMemo(() => ({
2203
+ theme,
2204
+ columns,
2205
+ version: props.version,
2206
+ model: currentModel,
2207
+ provider: currentProvider,
2208
+ cwd: displayedCwd,
2209
+ }), [theme, columns, props.version, currentModel, currentProvider, displayedCwd]);
2210
+ const transcriptLines = useMemo(() => {
2211
+ if (!props.fullscreen)
2212
+ return [];
2213
+ const items = [...history, ...uniqueItemsById(liveItems)];
2214
+ const hasStreaming = visibleStreamingText.length > 0 || agentLoop.streamingThinking.length > 0;
2215
+ if (hasStreaming) {
2216
+ items.push({
2217
+ kind: "assistant",
2218
+ text: visibleStreamingText,
2219
+ thinking: agentLoop.streamingThinking,
2220
+ thinkingMs: agentLoop.thinkingMs,
2221
+ continuation: streamingContinuesFlushed,
2222
+ id: "__streaming__",
2223
+ });
2224
+ }
2225
+ return buildTranscriptLines(items, transcriptContext);
2226
+ }, [
2227
+ props.fullscreen,
2228
+ history,
2229
+ liveItems,
2230
+ visibleStreamingText,
2231
+ agentLoop.streamingThinking,
2232
+ agentLoop.thinkingMs,
2233
+ streamingContinuesFlushed,
2234
+ transcriptContext,
2235
+ ]);
2236
+ // Keyboard + bounds controller. The offset itself lives in the external
2237
+ // transcript-scroll store; the viewport subscribes to it directly so scroll
2238
+ // re-renders only the viewport, not this whole component.
2239
+ useTranscriptScroll({
2240
+ totalLines: transcriptLines.length,
2241
+ viewportRows,
2242
+ active: !!props.fullscreen && !overlay && !taskBarFocused,
2243
+ resetToken: scrollResetToken,
2244
+ });
2132
2245
  const visibleQueuedCount = liveItems.filter((item) => item.kind === "queued").length;
2133
2246
  const hiddenQueuedCount = Math.max(0, agentLoop.queuedCount - visibleQueuedCount);
2134
2247
  const shouldTopSpaceQueueIndicator = hiddenQueuedCount > 0 &&
@@ -2427,7 +2540,7 @@ export function App(props) {
2427
2540
  if (quittingSummary) {
2428
2541
  return (_jsx(Box, { flexDirection: "column", width: columns, flexShrink: 0, flexGrow: 0, children: _jsx(SessionSummaryDisplay, { summary: quittingSummary }) }));
2429
2542
  }
2430
- return (_jsx(Box, { flexDirection: "column", width: columns, flexShrink: 0, flexGrow: 0, children: rewindCheckpoints ? (_jsx(RewindOverlay, { checkpoints: rewindCheckpoints, onRestore: handleRewindRestore, onCancel: handleRewindCancel })) : fullScreenOverlay ? (_jsx(FullScreenOverlayRouter, { overlay: fullScreenOverlay, version: props.version, cwd: props.cwd, agentRunning: agentLoop.isRunning, planAutoExpand: planAutoExpand, onClosePixel: handleCloseRemountableOverlay, onPixelFixOne: handlePixelFixOne, onPixelFixAll: handlePixelFixAll, onCloseSkills: handleCloseRemountableOverlay, onClosePlan: handleClosePlanOverlay, onApprovePlan: handleApprovePlan, onRejectPlan: handleRejectPlan })) : (_jsx(ChatScreen, { columns: columns, liveItems: uniqueItemsById(liveItems), renderItem: renderItem, isRunning: agentLoop.isRunning, visibleStreamingText: visibleStreamingText, streamingThinking: agentLoop.streamingThinking, thinkingMs: agentLoop.thinkingMs, reserveStreamingSpacing: shouldReserveStreamingSpacing, renderMarkdown: renderMarkdown, measuredLiveAreaRows: measuredLiveAreaRows, assistantMarginTop: shouldTopSpaceStreamingText || streamingContinuesFlushed ? 1 : 0, streamingContinuation: streamingContinuesFlushed, controlsRef: mainControlsRef, hiddenQueuedCount: hiddenQueuedCount, queueIndicatorMarginTop: shouldTopSpaceQueueIndicator ? 2 : 1, theme: theme, statusSlotVisible: statusSlotVisible, activityVisible: activityVisible, stallStatusVisible: stallStatusVisible, doneStatus: doneStatus, activityPhase: agentLoop.activityPhase, elapsedMs: agentLoop.elapsedMs, runStartRef: agentLoop.runStartRef, isThinking: agentLoop.isThinking, thinkingLevel: thinkingLevel, tokenEstimate: agentLoop.streamedTokenEstimate, charCountRef: agentLoop.charCountRef, realTokensAccumRef: agentLoop.realTokensAccumRef, lastUserMessage: lastUserMessage, activeToolNames: agentLoop.activeToolCalls.map((tc) => tc.name), retryInfo: agentLoop.retryInfo, planDone: planSteps.filter((s) => s.completed).length, planTotal: planSteps.length, formatDuration: formatDuration, inputControls: {
2543
+ return (_jsx(Box, { flexDirection: "column", width: columns, flexShrink: 0, flexGrow: 0, children: rewindCheckpoints ? (_jsx(RewindOverlay, { checkpoints: rewindCheckpoints, onRestore: handleRewindRestore, onCancel: handleRewindCancel })) : fullScreenOverlay ? (_jsx(FullScreenOverlayRouter, { overlay: fullScreenOverlay, version: props.version, cwd: props.cwd, agentRunning: agentLoop.isRunning, planAutoExpand: planAutoExpand, onClosePixel: handleCloseRemountableOverlay, onPixelFixOne: handlePixelFixOne, onPixelFixAll: handlePixelFixAll, onCloseSkills: handleCloseRemountableOverlay, onClosePlan: handleClosePlanOverlay, onApprovePlan: handleApprovePlan, onRejectPlan: handleRejectPlan })) : (_jsx(ChatScreen, { columns: columns, liveItems: uniqueItemsById(liveItems), renderItem: renderItem, isRunning: agentLoop.isRunning, visibleStreamingText: visibleStreamingText, streamingThinking: agentLoop.streamingThinking, thinkingMs: agentLoop.thinkingMs, reserveStreamingSpacing: shouldReserveStreamingSpacing, renderMarkdown: renderMarkdown, measuredLiveAreaRows: measuredLiveAreaRows, fullscreen: props.fullscreen, rows: rows, transcriptLines: transcriptLines, viewportRows: viewportRows, assistantMarginTop: shouldTopSpaceStreamingText || streamingContinuesFlushed ? 1 : 0, streamingContinuation: streamingContinuesFlushed, controlsRef: mainControlsRef, hiddenQueuedCount: hiddenQueuedCount, queueIndicatorMarginTop: shouldTopSpaceQueueIndicator ? 2 : 1, theme: theme, statusSlotVisible: statusSlotVisible, activityVisible: activityVisible, stallStatusVisible: stallStatusVisible, doneStatus: doneStatus, activityPhase: agentLoop.activityPhase, elapsedMs: agentLoop.elapsedMs, runStartRef: agentLoop.runStartRef, isThinking: agentLoop.isThinking, thinkingLevel: thinkingLevel, tokenEstimate: agentLoop.streamedTokenEstimate, charCountRef: agentLoop.charCountRef, realTokensAccumRef: agentLoop.realTokensAccumRef, lastUserMessage: lastUserMessage, activeToolNames: agentLoop.activeToolCalls.map((tc) => tc.name), retryInfo: agentLoop.retryInfo, planDone: planSteps.filter((s) => s.completed).length, planTotal: planSteps.length, formatDuration: formatDuration, inputControls: {
2431
2544
  onSubmit: handleSubmit,
2432
2545
  onAbort: handleAbort,
2433
2546
  injectText: composerInject,
@@ -2441,6 +2554,8 @@ export function App(props) {
2441
2554
  onToggleMarkdown: () => setRenderMarkdown((prev) => !prev),
2442
2555
  cwd: props.cwd,
2443
2556
  commands: allCommands,
2557
+ mouseScroll: props.fullscreen,
2558
+ onScroll: scrollTranscriptByLines,
2444
2559
  }, taskPicker: {
2445
2560
  open: taskPicker.open,
2446
2561
  tasks: taskPicker.tasks,