@cueloop/client 0.1.0-alpha.11 → 0.1.0-alpha.110

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 (360) hide show
  1. package/native/build-pty.sh +51 -0
  2. package/native/build.sh +82 -0
  3. package/native/darwin-arm64/libcuelooppty.dylib +0 -0
  4. package/native/darwin-arm64/libcueloopvt.dylib +0 -0
  5. package/native/src/pty.zig +193 -0
  6. package/native/src/shim.zig +114 -0
  7. package/package.json +42 -34
  8. package/src/annotations/annotation-palette.ts +63 -0
  9. package/src/annotations/components/AnnotationCards.stories.tsx +86 -0
  10. package/src/annotations/components/AnnotationCards.test.tsx +42 -0
  11. package/src/annotations/components/AnnotationCards.tsx +383 -0
  12. package/src/annotations/components/DiscussionMarkerRail.stories.tsx +54 -0
  13. package/src/annotations/components/DiscussionMarkerRail.tsx +189 -0
  14. package/src/annotations/discussions.ts +78 -0
  15. package/src/annotations/thread-selection.test.ts +210 -0
  16. package/src/annotations/thread-selection.ts +248 -0
  17. package/src/annotations/use-annotation-surface.tsx +1378 -0
  18. package/src/app/App.appearance.test.tsx +53 -0
  19. package/src/{App.autoclose.test.tsx → app/App.autoclose.test.tsx} +77 -51
  20. package/src/app/App.deleted-scroll.test.tsx +190 -0
  21. package/src/app/App.diff.test.tsx +313 -0
  22. package/src/app/App.export.test.tsx +105 -0
  23. package/src/app/App.focus.test.ts +89 -0
  24. package/src/app/App.harness-settings.test.tsx +77 -0
  25. package/src/app/App.identity.test.tsx +84 -0
  26. package/src/app/App.plan-render.test.tsx +211 -0
  27. package/src/app/App.plan-review.test.tsx +429 -0
  28. package/src/app/App.prototype-markdown.test.tsx +129 -0
  29. package/src/app/App.prototype.test.tsx +176 -0
  30. package/src/app/App.readonly.test.tsx +274 -0
  31. package/src/app/App.regression.test.tsx +99 -0
  32. package/src/app/App.rendering.test.tsx +134 -0
  33. package/src/app/App.share-dialog.test.tsx +177 -0
  34. package/src/app/App.submit-confirm.test.tsx +267 -0
  35. package/src/app/App.test.tsx +497 -0
  36. package/src/app/App.thread-agent.test.ts +20 -0
  37. package/src/app/App.toast.test.tsx +124 -0
  38. package/src/app/App.tsx +1758 -0
  39. package/src/app/App.visual.test.tsx +60 -0
  40. package/src/app/App.walk.test.tsx +300 -0
  41. package/src/app/App.workbench.test.tsx +1152 -0
  42. package/src/app/app-key-state.ts +61 -0
  43. package/src/app/app-screens.tsx +607 -0
  44. package/src/app/app-view-model.ts +178 -0
  45. package/src/app/components/AppHeader.stories.tsx +50 -0
  46. package/src/app/components/AppHeader.tsx +81 -0
  47. package/src/app/components/AppShell.brand.test.tsx +58 -0
  48. package/src/app/components/AppShell.extensions.test.tsx +191 -0
  49. package/src/app/components/AppShell.stories.tsx +89 -0
  50. package/src/app/components/AppShell.tsx +358 -0
  51. package/src/app/components/AppShell.zoom.test.tsx +149 -0
  52. package/src/app/components/Breadcrumb.stories.tsx +19 -0
  53. package/src/app/components/Breadcrumb.tsx +45 -0
  54. package/src/app/components/MenuBar.stories.tsx +28 -0
  55. package/src/app/components/MenuBar.tsx +44 -0
  56. package/src/app/components/PaneGrid.stories.tsx +84 -0
  57. package/src/app/components/PaneGrid.tsx +128 -0
  58. package/src/app/components/PanelColumn.stories.tsx +25 -0
  59. package/src/app/components/PanelColumn.tsx +93 -0
  60. package/src/app/components/ShellHeader.stories.tsx +50 -0
  61. package/src/app/components/ShellHeader.tsx +137 -0
  62. package/src/app/components/WorkspacePanels.stories.tsx +36 -0
  63. package/src/app/components/WorkspacePanels.tsx +121 -0
  64. package/src/app/components/pages/Workspace.stories.tsx +181 -0
  65. package/src/app/intent-dispatch.test.ts +729 -0
  66. package/src/app/intent-dispatch.ts +713 -0
  67. package/src/app/launch-layout.test.ts +78 -0
  68. package/src/app/launch-layout.ts +57 -0
  69. package/src/app/ready-signal.test.ts +85 -0
  70. package/src/app/ready-signal.ts +54 -0
  71. package/src/app/run.ts +111 -0
  72. package/src/{serve.test.ts → app/serve.test.ts} +28 -12
  73. package/src/app/serve.ts +111 -0
  74. package/src/app/version.ts +5 -0
  75. package/src/appearance/components/theme-context.stories.tsx +46 -0
  76. package/src/appearance/components/theme-context.tsx +37 -0
  77. package/src/appearance/theme-presets.test.ts +51 -0
  78. package/src/appearance/theme-presets.ts +219 -0
  79. package/src/appearance/theme.ts +112 -0
  80. package/src/appearance/visual/contrast.test.ts +35 -0
  81. package/src/appearance/visual/contrast.ts +33 -0
  82. package/src/diff/components/AnnotatableFileView.stories.tsx +42 -0
  83. package/src/diff/components/AnnotatableFileView.test.tsx +160 -0
  84. package/src/diff/components/AnnotatableFileView.tsx +142 -0
  85. package/src/diff/components/BareWorkbenchFileView.stories.tsx +27 -0
  86. package/src/diff/components/BareWorkbenchFileView.tsx +63 -0
  87. package/src/diff/components/DiffContentView.scroll.test.tsx +443 -0
  88. package/src/diff/components/DiffContentView.split.test.tsx +140 -0
  89. package/src/diff/components/DiffContentView.stories.tsx +80 -0
  90. package/src/diff/components/DiffContentView.syntax.test.tsx +85 -0
  91. package/src/diff/components/DiffContentView.tsx +1080 -0
  92. package/src/diff/components/WalkWizard.stories.tsx +100 -0
  93. package/src/diff/components/WalkWizard.tsx +146 -0
  94. package/src/diff/components/diff-content-view-layout.test.ts +198 -0
  95. package/src/diff/components/diff-content-view-layout.ts +87 -0
  96. package/src/diff/diff-fold.test.ts +78 -0
  97. package/src/diff/diff-fold.ts +130 -0
  98. package/src/diff/diff-hunk-curate.test.ts +315 -0
  99. package/src/diff/diff-hunk-curate.ts +155 -0
  100. package/src/diff/diff-intraline.test.ts +239 -0
  101. package/src/diff/diff-intraline.ts +244 -0
  102. package/src/diff/diff-syntax.test.ts +125 -0
  103. package/src/diff/diff-syntax.ts +194 -0
  104. package/src/diff/split-diff.test.ts +110 -0
  105. package/src/diff/split-diff.ts +150 -0
  106. package/src/diff/view-diff.test.ts +325 -0
  107. package/src/diff/view-diff.ts +540 -0
  108. package/src/diff/walk.test.ts +121 -0
  109. package/src/diff/walk.ts +76 -0
  110. package/src/index.ts +32 -2
  111. package/src/integrations/attribution.test.ts +31 -0
  112. package/src/integrations/attribution.ts +44 -0
  113. package/src/integrations/client-extension-registry.test.tsx +61 -0
  114. package/src/integrations/client-extension-registry.ts +163 -0
  115. package/src/integrations/clipboard.test.ts +23 -0
  116. package/src/integrations/clipboard.ts +34 -0
  117. package/src/integrations/components/ExtensionZone.stories.tsx +28 -0
  118. package/src/integrations/components/ExtensionZone.tsx +145 -0
  119. package/src/integrations/components/ShareDialog.agent.test.tsx +52 -0
  120. package/src/integrations/components/ShareDialog.stories.tsx +121 -0
  121. package/src/integrations/components/ShareDialog.tsx +602 -0
  122. package/src/integrations/components/share-dialog-store.ts +59 -0
  123. package/src/integrations/editor.test.ts +149 -0
  124. package/src/integrations/editor.ts +163 -0
  125. package/src/integrations/github-identity.test.ts +59 -0
  126. package/src/integrations/github-identity.ts +42 -0
  127. package/src/integrations/herdr.test.ts +43 -0
  128. package/src/integrations/herdr.ts +40 -0
  129. package/src/integrations/integrations.test.ts +41 -0
  130. package/src/integrations/integrations.ts +32 -0
  131. package/src/integrations/pasted-image.test.ts +67 -0
  132. package/src/integrations/pasted-image.ts +62 -0
  133. package/src/integrations/share.ts +283 -0
  134. package/src/keyboard/components/CompletionOverlay.stories.tsx +37 -0
  135. package/src/keyboard/components/CompletionOverlay.tsx +75 -0
  136. package/src/keyboard/components/HandleChipsInput.stories.tsx +24 -0
  137. package/src/keyboard/components/HandleChipsInput.test.tsx +35 -0
  138. package/src/keyboard/components/HandleChipsInput.tsx +147 -0
  139. package/src/keyboard/components/KeybindsDialog.stories.tsx +31 -0
  140. package/src/keyboard/components/KeybindsDialog.tsx +103 -0
  141. package/src/keyboard/components/NavModeHint.stories.tsx +40 -0
  142. package/src/keyboard/components/NavModeHint.tsx +31 -0
  143. package/src/keyboard/components/SlashComposer.stories.tsx +37 -0
  144. package/src/keyboard/components/SlashComposer.tsx +90 -0
  145. package/src/keyboard/key-bindings.test.ts +156 -0
  146. package/src/keyboard/key-bindings.ts +462 -0
  147. package/src/keyboard/keymap.test.ts +611 -0
  148. package/src/keyboard/keymap.ts +446 -0
  149. package/src/keyboard/skills.test.ts +74 -0
  150. package/src/keyboard/skills.ts +77 -0
  151. package/src/keyboard/slash-palette.test.ts +103 -0
  152. package/src/keyboard/slash-palette.ts +137 -0
  153. package/src/keyboard/thread-chords.test.ts +79 -0
  154. package/src/keyboard/thread-chords.ts +168 -0
  155. package/src/keyboard/use-shared-keyboard.ts +56 -0
  156. package/src/markdown/__snapshots__/view-plan.regression.test.ts.snap +100 -0
  157. package/src/markdown/components/MarkdownGridBlock.stories.tsx +33 -0
  158. package/src/markdown/components/MarkdownGridBlock.tsx +72 -0
  159. package/src/markdown/components/MarkdownThreadEditor.stories.tsx +15 -0
  160. package/src/markdown/components/MarkdownThreadEditor.test.tsx +98 -0
  161. package/src/markdown/components/MarkdownThreadEditor.tsx +165 -0
  162. package/src/markdown/components/ThreadView.selection.test.tsx +954 -0
  163. package/src/markdown/components/ThreadView.slash.test.tsx +146 -0
  164. package/src/markdown/components/ThreadView.stories.tsx +26 -0
  165. package/src/markdown/components/ThreadView.tsx +577 -0
  166. package/src/markdown/mark-runs.ts +125 -0
  167. package/src/markdown/markdown-editor-syntax-style.ts +66 -0
  168. package/src/markdown/markdown-grid.test.ts +101 -0
  169. package/src/markdown/markdown-grid.ts +209 -0
  170. package/src/markdown/markdown-highlight.test.ts +61 -0
  171. package/src/markdown/markdown-highlight.ts +125 -0
  172. package/src/markdown/thread-code-syntax.ts +48 -0
  173. package/src/markdown/use-thread-body-editing.tsx +54 -0
  174. package/src/markdown/view-plan.regression.test.ts +60 -0
  175. package/src/markdown/view-plan.test.ts +545 -0
  176. package/src/markdown/view-plan.ts +1061 -0
  177. package/src/performance/otlp-trace.test.ts +119 -0
  178. package/src/performance/otlp-trace.ts +134 -0
  179. package/src/performance/perf-report.ts +19 -0
  180. package/src/performance/perf-timings.test.ts +18 -0
  181. package/src/performance/perf-timings.ts +40 -0
  182. package/src/prototype/components/PrototypeContentView.stories.tsx +19 -0
  183. package/src/prototype/components/PrototypeContentView.tsx +459 -0
  184. package/src/prototype/prototype-browser.test.ts +81 -0
  185. package/src/prototype/prototype-browser.ts +332 -0
  186. package/src/prototype/prototype-pixels.tsx +35 -0
  187. package/src/settings/components/SettingsDialog.stories.tsx +117 -0
  188. package/src/settings/components/SettingsDialog.tsx +186 -0
  189. package/src/settings/components/SettingsRows.stories.tsx +18 -0
  190. package/src/settings/components/SettingsRows.tsx +112 -0
  191. package/src/settings/components/quick-actions-editor.stories.tsx +58 -0
  192. package/src/settings/components/quick-actions-editor.test.tsx +120 -0
  193. package/src/settings/components/quick-actions-editor.tsx +222 -0
  194. package/src/settings/config-identity.test.ts +78 -0
  195. package/src/settings/config.test.ts +754 -0
  196. package/src/settings/config.ts +718 -0
  197. package/src/settings/use-settings-dialog.test.tsx +172 -0
  198. package/src/settings/use-settings-dialog.tsx +465 -0
  199. package/src/settings/use-thread-harness-setting.test.tsx +87 -0
  200. package/src/settings/use-thread-harness-setting.ts +86 -0
  201. package/src/stories/__snapshots__/stories.test.tsx.snap +2358 -0
  202. package/src/stories/stories-app.tsx +196 -0
  203. package/src/stories/stories.test.tsx +78 -0
  204. package/src/stories/story-fixtures.ts +102 -0
  205. package/src/stories/story-tree.test.ts +108 -0
  206. package/src/stories/story.ts +160 -0
  207. package/src/terminal/ansi-screen.test.ts +28 -0
  208. package/src/terminal/ansi-screen.ts +77 -0
  209. package/src/terminal/components/AnsiScreen.stories.tsx +12 -0
  210. package/src/terminal/components/AnsiScreen.tsx +28 -0
  211. package/src/terminal/components/terminal-pane.test.tsx +40 -0
  212. package/src/terminal/components/terminal-pane.ts +208 -0
  213. package/src/terminal/ghostty-terminal.test.ts +85 -0
  214. package/src/terminal/ghostty-terminal.ts +207 -0
  215. package/src/terminal/kitty-image.test.ts +66 -0
  216. package/src/terminal/kitty-image.ts +140 -0
  217. package/src/terminal/pty.test.ts +81 -0
  218. package/src/terminal/pty.ts +255 -0
  219. package/src/testing/test-support.test.ts +266 -0
  220. package/src/testing/test-support.ts +424 -0
  221. package/src/thread/agent-continuation.test.ts +34 -0
  222. package/src/thread/agent-continuation.ts +13 -0
  223. package/src/thread/agent-transcript.test.ts +161 -0
  224. package/src/thread/agent-transcript.ts +344 -0
  225. package/src/thread/components/AgentConfigControls.stories.tsx +39 -0
  226. package/src/thread/components/AgentConfigControls.test.tsx +153 -0
  227. package/src/thread/components/AgentConfigControls.tsx +121 -0
  228. package/src/thread/components/AgentThreadPane.stories.tsx +105 -0
  229. package/src/thread/components/AgentThreadPane.test.tsx +1248 -0
  230. package/src/thread/components/AgentThreadPane.tsx +458 -0
  231. package/src/thread/components/ThreadFooter.stories.tsx +30 -0
  232. package/src/thread/components/ThreadFooter.test.tsx +49 -0
  233. package/src/thread/components/ThreadFooter.tsx +77 -0
  234. package/src/thread/components/ThreadTree.stories.tsx +46 -0
  235. package/src/thread/components/ThreadTree.test.tsx +41 -0
  236. package/src/thread/components/ThreadTree.tsx +268 -0
  237. package/src/thread/components/thread-tree.test.ts +138 -0
  238. package/src/thread/components/thread-tree.ts +112 -0
  239. package/src/thread/thread-controller.curate.test.ts +504 -0
  240. package/src/thread/thread-controller.derivation.test.ts +62 -0
  241. package/src/thread/thread-controller.live-diff.test.ts +357 -0
  242. package/src/thread/thread-controller.optimistic.test.ts +69 -0
  243. package/src/thread/thread-controller.share.test.ts +618 -0
  244. package/src/thread/thread-controller.switch-cache.test.ts +174 -0
  245. package/src/thread/thread-controller.tree.test.ts +263 -0
  246. package/src/thread/thread-controller.ts +2151 -0
  247. package/src/thread/tree-view.test.ts +128 -0
  248. package/src/thread/tree-view.ts +150 -0
  249. package/src/thread/use-thread-agent.test.tsx +209 -0
  250. package/src/thread/use-thread-agent.ts +122 -0
  251. package/src/ui/components/CodeBlock.stories.tsx +42 -0
  252. package/src/ui/components/CodeBlock.tsx +82 -0
  253. package/src/ui/components/ConfirmCard.stories.tsx +37 -0
  254. package/src/ui/components/ConfirmCard.tsx +151 -0
  255. package/src/ui/components/ConfirmDialog.stories.tsx +21 -0
  256. package/src/ui/components/ConfirmDialog.tsx +72 -0
  257. package/src/ui/components/OverlayScrollbar.stories.tsx +33 -0
  258. package/src/ui/components/OverlayScrollbar.test.tsx +142 -0
  259. package/src/ui/components/OverlayScrollbar.tsx +134 -0
  260. package/src/ui/components/PromptDialog.stories.tsx +36 -0
  261. package/src/ui/components/PromptDialog.test.tsx +65 -0
  262. package/src/ui/components/PromptDialog.tsx +101 -0
  263. package/src/ui/components/RootOverlay.stories.tsx +45 -0
  264. package/src/ui/components/RootOverlay.tsx +50 -0
  265. package/src/ui/components/ScrollArea.stories.tsx +20 -0
  266. package/src/ui/components/ScrollArea.tsx +63 -0
  267. package/src/ui/components/Toast.stories.tsx +19 -0
  268. package/src/ui/components/Toast.tsx +54 -0
  269. package/src/ui/components/Tooltip.stories.tsx +26 -0
  270. package/src/ui/components/Tooltip.tsx +93 -0
  271. package/src/ui/components/menu-control.stories.tsx +35 -0
  272. package/src/ui/components/menu-control.tsx +43 -0
  273. package/src/ui/components/primitives/Button.stories.tsx +32 -0
  274. package/src/ui/components/primitives/Button.tsx +58 -0
  275. package/src/ui/components/primitives/Card.stories.tsx +25 -0
  276. package/src/ui/components/primitives/Card.tsx +62 -0
  277. package/src/ui/components/primitives/Dialog.stories.tsx +24 -0
  278. package/src/ui/components/primitives/Dialog.test.tsx +38 -0
  279. package/src/ui/components/primitives/Dialog.tsx +69 -0
  280. package/src/ui/components/primitives/DialogActions.stories.tsx +20 -0
  281. package/src/ui/components/primitives/DialogActions.tsx +39 -0
  282. package/src/ui/components/primitives/IconButton.stories.tsx +36 -0
  283. package/src/ui/components/primitives/IconButton.tsx +58 -0
  284. package/src/ui/components/primitives/StatusBar.stories.tsx +11 -0
  285. package/src/ui/components/primitives/StatusBar.tsx +23 -0
  286. package/src/ui/components/primitives/Switch.stories.tsx +17 -0
  287. package/src/ui/components/primitives/Switch.tsx +32 -0
  288. package/src/ui/components/primitives/Tabs.stories.tsx +29 -0
  289. package/src/ui/components/primitives/Tabs.tsx +102 -0
  290. package/src/ui/components/primitives/Toolbar.stories.tsx +17 -0
  291. package/src/ui/components/primitives/Toolbar.tsx +14 -0
  292. package/src/ui/components/primitives/Tree.stories.tsx +124 -0
  293. package/src/ui/components/primitives/Tree.tsx +137 -0
  294. package/src/ui/components/primitives/frame.test.ts +12 -0
  295. package/src/ui/components/primitives/frame.ts +17 -0
  296. package/src/ui/components/primitives/icons.ts +61 -0
  297. package/src/ui/components/primitives/tree-model.test.ts +99 -0
  298. package/src/ui/components/primitives/tree-model.ts +144 -0
  299. package/src/ui/components/syntax-highlight.ts +154 -0
  300. package/src/ui/components/truncate-text.ts +7 -0
  301. package/src/ui/components/truncate-title.test.ts +31 -0
  302. package/src/ui/components/truncate-title.ts +16 -0
  303. package/src/ui/use-frame-measure.ts +88 -0
  304. package/src/ui/use-terminal-virtualizer.ts +286 -0
  305. package/src/workbench/components/ChangesColumn.stories.tsx +44 -0
  306. package/src/workbench/components/ChangesColumn.tsx +210 -0
  307. package/src/workbench/components/ChangesFileTree.test.tsx +184 -0
  308. package/src/workbench/components/EditorGrid.split.test.tsx +119 -0
  309. package/src/workbench/components/EditorGrid.stories.tsx +86 -0
  310. package/src/workbench/components/EditorGrid.tabs.test.tsx +118 -0
  311. package/src/workbench/components/EditorGrid.tsx +552 -0
  312. package/src/workbench/components/EditorGrid.zoom.test.tsx +132 -0
  313. package/src/workbench/components/FileContentsView.stories.tsx +16 -0
  314. package/src/workbench/components/FileContentsView.test.tsx +29 -0
  315. package/src/workbench/components/FileContentsView.tsx +104 -0
  316. package/src/workbench/components/GridTabContent.actions.test.tsx +151 -0
  317. package/src/workbench/components/GridTabContent.stories.tsx +59 -0
  318. package/src/workbench/components/GridTabContent.tsx +195 -0
  319. package/src/workbench/components/ProjectTreeView.stories.tsx +25 -0
  320. package/src/workbench/components/ProjectTreeView.test.tsx +239 -0
  321. package/src/workbench/components/ProjectTreeView.tsx +159 -0
  322. package/src/workbench/components/TreePane.stories.tsx +106 -0
  323. package/src/workbench/components/TreePane.tsx +157 -0
  324. package/src/workbench/components/WelcomePlayground.stories.tsx +12 -0
  325. package/src/workbench/components/WelcomePlayground.test.tsx +83 -0
  326. package/src/workbench/components/WelcomePlayground.tsx +138 -0
  327. package/src/workbench/components/editor-grid.test.ts +184 -0
  328. package/src/workbench/components/editor-grid.ts +284 -0
  329. package/src/workbench/components/file-tree.test.ts +60 -0
  330. package/src/workbench/components/file-tree.ts +114 -0
  331. package/src/workbench/use-changes-workbench.ts +210 -0
  332. package/src/workbench/use-remember-layout.ts +33 -0
  333. package/src/workbench/use-repo-changes.ts +93 -0
  334. package/src/workbench/workbench-snapshot.test.ts +99 -0
  335. package/src/workbench/workbench-snapshot.ts +59 -0
  336. package/src/App.diff.test.tsx +0 -99
  337. package/src/App.export.test.tsx +0 -88
  338. package/src/App.plan-review.test.tsx +0 -259
  339. package/src/App.readonly.test.tsx +0 -148
  340. package/src/App.rendering.test.tsx +0 -108
  341. package/src/App.submit-confirm.test.tsx +0 -183
  342. package/src/App.test.tsx +0 -218
  343. package/src/App.tsx +0 -1249
  344. package/src/config.test.ts +0 -116
  345. package/src/config.ts +0 -150
  346. package/src/editor.ts +0 -34
  347. package/src/herdr.test.ts +0 -68
  348. package/src/herdr.ts +0 -34
  349. package/src/keymap.test.ts +0 -270
  350. package/src/keymap.ts +0 -173
  351. package/src/run.ts +0 -30
  352. package/src/serve.ts +0 -75
  353. package/src/session-controller.ts +0 -398
  354. package/src/syntax.test.ts +0 -41
  355. package/src/syntax.ts +0 -88
  356. package/src/theme.ts +0 -46
  357. package/src/view-diff.test.ts +0 -55
  358. package/src/view-diff.ts +0 -86
  359. package/src/view.test.ts +0 -157
  360. package/src/view.ts +0 -364
@@ -0,0 +1,60 @@
1
+ /** Scene visual regression: clicking a sidebar thread paints its title in the theme's accent, in both
2
+ * themes. Colours come from captureSpans, so a theme or click-feedback regression fails here. */
3
+
4
+ import { afterEach, beforeEach, expect, test } from "bun:test";
5
+ import React from "react";
6
+ import { App } from "./App";
7
+ import { clickText, isolateUserConfig, renderReadyApp, waitForText } from "../testing/test-support";
8
+ import { themeForName } from "../appearance/theme-presets";
9
+ import { rgbColorFromHex } from "../appearance/visual/contrast";
10
+ import { createTestReviewHome, type TestReviewHome } from "../../../../test/helpers/review-home";
11
+
12
+ let reviewHome: TestReviewHome;
13
+ let restoreUserConfig: () => void;
14
+
15
+ beforeEach(() => {
16
+ reviewHome = createTestReviewHome();
17
+ restoreUserConfig = isolateUserConfig(reviewHome.home);
18
+ reviewHome.createPlanSession("# First review\n", "First review");
19
+ reviewHome.createPlanSession("# Second review\n", "Second review");
20
+ });
21
+ afterEach(() => {
22
+ restoreUserConfig();
23
+ reviewHome.cleanup();
24
+ });
25
+
26
+ /** Whether any span containing `needle` is painted in `color` (the thread header carries the title dimly). */
27
+ function hasSpanColor(
28
+ setup: Awaited<ReturnType<typeof renderReadyApp>>,
29
+ needle: string,
30
+ color: readonly [number, number, number],
31
+ ): boolean {
32
+ for (const line of setup.captureSpans().lines) {
33
+ for (const span of line.spans) {
34
+ if (!span.text.includes(needle) || !span.fg) continue;
35
+
36
+ const [red, green, blue] = span.fg.toInts();
37
+
38
+ if (red === color[0] && green === color[1] && blue === color[2]) return true;
39
+ }
40
+ }
41
+
42
+ return false;
43
+ }
44
+
45
+ for (const mode of ["dark", "light"] as const) {
46
+ test(`clicking a thread paints it in the ${mode} accent`, async () => {
47
+ const accent = rgbColorFromHex(themeForName("cueloop", mode).accent);
48
+ const setup = await renderReadyApp(<App home={reviewHome.home} appearance={mode} />, {
49
+ width: 120,
50
+ height: 32,
51
+ });
52
+
53
+ await waitForText(setup, "Second review");
54
+
55
+ await clickText(setup, "Second review");
56
+
57
+ expect(hasSpanColor(setup, "Second review", accent)).toBe(true);
58
+ setup.renderer.destroy();
59
+ });
60
+ }
@@ -0,0 +1,300 @@
1
+ /** The guided walk in the virtual terminal: the wizard steps every changed file with a plain progress title, ] marks viewed and persists with the session, esc keeps progress, w resumes at the first unviewed file (across App instances via the daemon round-trip), the agent-note block renders only for files carrying a note, and the end card hands over to the submit confirm with the honest viewed count. */
2
+
3
+ import { afterEach, beforeEach, describe, expect, test } from "bun:test";
4
+ import { mkdtempSync, rmSync } from "node:fs";
5
+ import { tmpdir } from "node:os";
6
+ import { join } from "node:path";
7
+ import React from "react";
8
+ import { DaemonServer } from "@cueloop/daemon";
9
+ import type { Thread } from "@cueloop/schema";
10
+ import { App } from "./App";
11
+ import { DARK } from "../appearance/theme";
12
+ import {
13
+ isolateUserConfig,
14
+ press,
15
+ navCommand,
16
+ pressKey,
17
+ renderReadyApp,
18
+ waitForState,
19
+ waitForText,
20
+ waitForTextGone,
21
+ } from "../testing/test-support";
22
+
23
+ const PATCH = `diff --git a/src/a.ts b/src/a.ts
24
+ index 111..222 100644
25
+ --- a/src/a.ts
26
+ +++ b/src/a.ts
27
+ @@ -1,2 +1,2 @@
28
+ export const a = 1;
29
+ -export const b = 2;
30
+ +export const b = 3;
31
+ diff --git a/src/b.ts b/src/b.ts
32
+ index 333..444 100644
33
+ --- a/src/b.ts
34
+ +++ b/src/b.ts
35
+ @@ -1,2 +1,2 @@
36
+ // header
37
+ -old line
38
+ +new line
39
+ diff --git a/src/c.ts b/src/c.ts
40
+ index 555..666 100644
41
+ --- a/src/c.ts
42
+ +++ b/src/c.ts
43
+ @@ -1,1 +1,2 @@
44
+ keep
45
+ +added tail
46
+ `;
47
+
48
+ let home: string;
49
+ let restoreUserConfig: () => void;
50
+ let server: DaemonServer;
51
+ let session: Thread;
52
+
53
+ beforeEach(() => {
54
+ home = mkdtempSync(join(tmpdir(), "cueloop-walk-"));
55
+ restoreUserConfig = isolateUserConfig(home);
56
+ server = new DaemonServer({ home, idleExitMs: 0 });
57
+ server.start();
58
+ session = server.core.sessionCreate({
59
+ workspace: { repoRoot: "/repo", branch: "main" },
60
+ artifact: { type: "diff", content: PATCH, meta: { title: "working tree" } },
61
+ });
62
+ });
63
+ afterEach(() => {
64
+ restoreUserConfig();
65
+ server.stop();
66
+ rmSync(home, { recursive: true, force: true });
67
+ });
68
+
69
+ async function renderApp() {
70
+ const setup = await renderReadyApp(<App home={home} sessionId={session.id} />, {
71
+ width: 120,
72
+ height: 34,
73
+ });
74
+
75
+ // Wait for session content, not just the chrome: pressing w before the diff
76
+ // loads drops the walk intent (no session, no diff view) and hangs the test.
77
+ await waitForText(setup, "src/a.ts");
78
+
79
+ return setup;
80
+ }
81
+
82
+ type Setup = Awaited<ReturnType<typeof renderApp>>;
83
+
84
+ /** Foreground colors (hex) of every styled span containing the needle. */
85
+ function foregroundsOf(setup: Setup, needle: string): string[] {
86
+ const foregrounds: string[] = [];
87
+
88
+ for (const line of setup.captureSpans().lines) {
89
+ for (const span of line.spans) {
90
+ if (!span.text.includes(needle)) continue;
91
+
92
+ const [red, green, blue] = span.fg.toInts();
93
+
94
+ foregrounds.push(
95
+ "#" + [red, green, blue].map((part) => part.toString(16).padStart(2, "0")).join(""),
96
+ );
97
+ }
98
+ }
99
+
100
+ return foregrounds;
101
+ }
102
+
103
+ describe("the guided walk", () => {
104
+ test("w walks all three files: progress title, persisted marks, end card, submit hand-over", async () => {
105
+ // Arrange
106
+ const setup = await renderApp();
107
+
108
+ // Act
109
+ await navCommand(setup, "k");
110
+
111
+ // Assert
112
+ await waitForText(setup, "file 1 of 3 · 0 viewed");
113
+ expect(setup.captureCharFrame()).toContain("src/a.ts");
114
+ expect(setup.captureCharFrame()).toContain("+1 -1");
115
+
116
+ // Act
117
+ await press(setup, "]");
118
+
119
+ // Assert
120
+ await waitForText(setup, "file 2 of 3 · 1 viewed");
121
+ // the viewed mark rides the session record, not the client
122
+ await waitForState(setup, () =>
123
+ (server.core.sessionGet(session.id).viewedPaths ?? []).includes("src/a.ts"),
124
+ );
125
+
126
+ // Act
127
+ // [ steps back; the revisited card shows its viewed marker
128
+ await press(setup, "[");
129
+
130
+ // Assert
131
+ await waitForText(setup, "file 1 of 3 · 1 viewed");
132
+ expect(setup.captureCharFrame()).toContain("· viewed");
133
+
134
+ // Act
135
+ await press(setup, "]");
136
+
137
+ // Assert
138
+ await waitForText(setup, "file 2 of 3 · 1 viewed");
139
+
140
+ // Act
141
+ await press(setup, "]");
142
+
143
+ // Assert
144
+ await waitForText(setup, "file 3 of 3 · 2 viewed");
145
+
146
+ // Act
147
+ await press(setup, "]");
148
+
149
+ // Assert
150
+ await waitForText(setup, "walk complete");
151
+ expect(setup.captureCharFrame()).toContain("every file viewed (3/3)");
152
+ expect(server.core.sessionGet(session.id).viewedPaths).toEqual([
153
+ "src/a.ts",
154
+ "src/b.ts",
155
+ "src/c.ts",
156
+ ]);
157
+
158
+ // Act
159
+ // the end card's return leaves the walk and opens the rail confirm
160
+ await press(setup, "enter");
161
+
162
+ // Assert
163
+ await waitForText(setup, "Send message (");
164
+ expect(setup.captureCharFrame()).toContain("3/3 files viewed");
165
+
166
+ // Act
167
+ await pressKey(setup, "RETURN", { meta: true });
168
+
169
+ // Assert
170
+ await waitForState(setup, () => server.core.sessionGet(session.id).status === "resolved");
171
+ });
172
+
173
+ test("esc keeps progress and w resumes at the first unviewed file", async () => {
174
+ // Arrange
175
+ const setup = await renderApp();
176
+
177
+ await navCommand(setup, "k");
178
+ await waitForText(setup, "file 1 of 3 · 0 viewed");
179
+ await press(setup, "]");
180
+ await waitForText(setup, "file 2 of 3 · 1 viewed");
181
+
182
+ // Act
183
+ await press(setup, "escape");
184
+
185
+ // Assert
186
+ await waitForTextGone(setup, "file 2 of 3");
187
+ // the sheet is back at full strength: no wizard card on screen
188
+ expect(setup.captureCharFrame()).not.toContain("· 1 viewed");
189
+
190
+ // Act
191
+ await navCommand(setup, "k");
192
+
193
+ // Assert
194
+ await waitForText(setup, "file 2 of 3 · 1 viewed");
195
+ });
196
+
197
+ test("a half-walked review resumes across App instances via the daemon", async () => {
198
+ // Arrange
199
+ const first = await renderApp();
200
+
201
+ await navCommand(first, "k");
202
+ await waitForText(first, "file 1 of 3 · 0 viewed");
203
+ await press(first, "]");
204
+ await press(first, "]");
205
+ await waitForText(first, "file 3 of 3 · 2 viewed");
206
+ await waitForState(
207
+ first,
208
+ () => (server.core.sessionGet(session.id).viewedPaths ?? []).length === 2,
209
+ );
210
+ first.renderer.destroy();
211
+
212
+ // Act
213
+ // a fresh client reads the viewed set back from the session record
214
+ const second = await renderApp();
215
+
216
+ await navCommand(second, "k");
217
+
218
+ // Assert
219
+ await waitForText(second, "file 3 of 3 · 2 viewed");
220
+ expect(second.captureCharFrame()).toContain("src/c.ts");
221
+ // two full App boots with daemon round-trips need more than the default
222
+ // budget, and the whole-suite publish lane has timed even 15s out; give the
223
+ // double-boot chain generous headroom so runner load cannot flake it.
224
+ }, 60_000);
225
+
226
+ test("the agent-note block renders only for files carrying a note", async () => {
227
+ // Arrange
228
+ server.core.sessionAnnotate(session.id, {
229
+ id: "note-b",
230
+ kind: "note",
231
+ anchor: { quote: "src/b.ts", prefix: "", suffix: "" },
232
+ body: "Swaps the stale line for the new constant.",
233
+ });
234
+ const setup = await renderApp();
235
+
236
+ // Act
237
+ await navCommand(setup, "k");
238
+
239
+ // Assert
240
+ await waitForText(setup, "file 1 of 3");
241
+ expect(setup.captureCharFrame()).not.toContain("agent note");
242
+
243
+ // Act
244
+ await press(setup, "]");
245
+
246
+ // Assert
247
+ await waitForText(setup, "agent note");
248
+ expect(setup.captureCharFrame()).toContain("Swaps the stale line for the new constant.");
249
+
250
+ // Act
251
+ // a note is agent context, not reviewer feedback: it neither counts nor
252
+ // flips the default message, and never comes back in the feedback doc
253
+ await press(setup, "escape");
254
+ await waitForTextGone(setup, "agent note");
255
+ await pressKey(setup, "RETURN", { meta: true });
256
+ // nothing pending despite the note, so the confirm card defaults to approve
257
+ await waitForText(setup, "[approve]");
258
+ await pressKey(setup, "RETURN", { meta: true });
259
+
260
+ // Assert
261
+ await waitForState(setup, () => server.core.sessionGet(session.id).status === "resolved");
262
+ const resolved = server.core.sessionGet(session.id);
263
+
264
+ expect(resolved.message!.outcome).toBe("approved");
265
+ expect(resolved.message!.body).not.toContain("Swaps the stale line");
266
+ });
267
+
268
+ test("the sheet dims behind the wizard; the preview keeps the diff colors", async () => {
269
+ // Arrange
270
+ const setup = await renderApp();
271
+
272
+ // Assert
273
+ // before the walk the changed word on the added line wears the insertion color
274
+ await waitForText(setup, "+ new line");
275
+ expect(foregroundsOf(setup, "new")).toContain(DARK.insertedForeground);
276
+
277
+ // Act
278
+ await navCommand(setup, "k");
279
+
280
+ // Assert
281
+ await waitForText(setup, "file 1 of 3 · 0 viewed");
282
+ // dimmed: an added line the wizard preview does not show drops to the dim token...
283
+ expect(foregroundsOf(setup, "added tail")).toEqual([DARK.textDim]);
284
+ // ...while the wizard preview keeps the insertion color
285
+ expect(foregroundsOf(setup, "+export const b = 3;")).toContain(DARK.insertedForeground);
286
+ });
287
+
288
+ test("walking a resolved review answers read-only", async () => {
289
+ // Arrange
290
+ server.core.sessionSendMessage(session.id, "approved", "");
291
+ const setup = await renderApp();
292
+
293
+ // Act - renderApp already waited for the diff to load; the session is resolved
294
+ await navCommand(setup, "k");
295
+
296
+ // Assert
297
+ await waitForText(setup, "review submitted - read-only");
298
+ expect(setup.captureCharFrame()).not.toContain("file 1 of 3");
299
+ });
300
+ });