@cueloop/client 0.1.0-alpha.102 → 0.1.0-alpha.103

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 (122) hide show
  1. package/package.json +5 -5
  2. package/src/annotations/annotation-palette.ts +1 -0
  3. package/src/annotations/components/AnnotationCards.tsx +4 -0
  4. package/src/annotations/components/DiscussionMarkerRail.tsx +3 -0
  5. package/src/annotations/discussions.ts +1 -0
  6. package/src/annotations/thread-selection.ts +6 -0
  7. package/src/annotations/use-annotation-surface.tsx +97 -0
  8. package/src/app/App.deleted-scroll.test.tsx +3 -0
  9. package/src/app/App.harness-settings.test.tsx +77 -0
  10. package/src/app/App.plan-render.test.tsx +2 -0
  11. package/src/app/App.plan-review.test.tsx +1 -0
  12. package/src/app/App.test.tsx +1 -0
  13. package/src/app/App.tsx +67 -1
  14. package/src/app/App.visual.test.tsx +1 -0
  15. package/src/app/App.walk.test.tsx +1 -0
  16. package/src/app/App.workbench.test.tsx +1 -0
  17. package/src/app/app-screens.tsx +1 -0
  18. package/src/app/app-view-model.ts +7 -0
  19. package/src/app/components/WorkspacePanels.tsx +1 -0
  20. package/src/app/intent-dispatch.test.ts +1 -0
  21. package/src/app/intent-dispatch.ts +26 -0
  22. package/src/app/ready-signal.ts +2 -0
  23. package/src/app/run.ts +2 -0
  24. package/src/app/serve.test.ts +4 -0
  25. package/src/diff/components/AnnotatableFileView.tsx +1 -0
  26. package/src/diff/components/DiffContentView.scroll.test.tsx +9 -0
  27. package/src/diff/components/DiffContentView.syntax.test.tsx +1 -0
  28. package/src/diff/components/DiffContentView.tsx +25 -0
  29. package/src/diff/components/diff-content-view-layout.ts +3 -0
  30. package/src/diff/diff-fold.ts +4 -0
  31. package/src/diff/diff-hunk-curate.ts +3 -0
  32. package/src/diff/diff-intraline.ts +6 -0
  33. package/src/diff/diff-syntax.ts +8 -0
  34. package/src/diff/split-diff.ts +6 -0
  35. package/src/diff/view-diff.ts +18 -0
  36. package/src/diff/walk.ts +3 -0
  37. package/src/integrations/attribution.ts +2 -0
  38. package/src/integrations/client-extension-registry.ts +4 -0
  39. package/src/integrations/clipboard.ts +1 -0
  40. package/src/integrations/components/ShareDialog.agent.test.tsx +2 -0
  41. package/src/integrations/components/ShareDialog.tsx +28 -0
  42. package/src/integrations/editor.ts +3 -0
  43. package/src/integrations/github-identity.test.ts +1 -0
  44. package/src/integrations/github-identity.ts +1 -0
  45. package/src/integrations/herdr.ts +2 -0
  46. package/src/integrations/pasted-image.ts +2 -0
  47. package/src/integrations/share.ts +4 -0
  48. package/src/keyboard/components/HandleChipsInput.tsx +4 -0
  49. package/src/keyboard/components/SlashComposer.tsx +3 -0
  50. package/src/keyboard/key-bindings.ts +3 -0
  51. package/src/keyboard/keymap.ts +51 -0
  52. package/src/keyboard/skills.ts +2 -0
  53. package/src/keyboard/slash-palette.ts +8 -0
  54. package/src/keyboard/thread-chords.ts +5 -0
  55. package/src/keyboard/use-shared-keyboard.ts +1 -0
  56. package/src/markdown/components/MarkdownThreadEditor.tsx +3 -0
  57. package/src/markdown/components/ThreadView.selection.test.tsx +3 -0
  58. package/src/markdown/components/ThreadView.tsx +13 -0
  59. package/src/markdown/mark-runs.ts +4 -0
  60. package/src/markdown/markdown-editor-syntax-style.ts +1 -0
  61. package/src/markdown/markdown-grid.ts +6 -0
  62. package/src/markdown/markdown-highlight.ts +1 -0
  63. package/src/markdown/thread-code-syntax.ts +3 -0
  64. package/src/markdown/view-plan.ts +52 -0
  65. package/src/performance/perf-report.ts +1 -0
  66. package/src/performance/perf-timings.ts +1 -0
  67. package/src/prototype/components/PrototypeContentView.tsx +17 -0
  68. package/src/prototype/prototype-browser.ts +11 -0
  69. package/src/settings/components/SettingsDialog.tsx +3 -0
  70. package/src/settings/config.test.ts +41 -0
  71. package/src/settings/config.ts +44 -0
  72. package/src/settings/use-settings-dialog.test.tsx +98 -0
  73. package/src/settings/use-settings-dialog.tsx +38 -1
  74. package/src/settings/use-thread-harness-setting.test.tsx +87 -0
  75. package/src/settings/use-thread-harness-setting.ts +86 -0
  76. package/src/stories/stories.test.tsx +4 -0
  77. package/src/stories/story.ts +6 -0
  78. package/src/terminal/ansi-screen.ts +5 -0
  79. package/src/terminal/components/terminal-pane.ts +12 -0
  80. package/src/terminal/ghostty-terminal.ts +10 -0
  81. package/src/terminal/kitty-image.ts +3 -0
  82. package/src/terminal/pty.ts +9 -0
  83. package/src/testing/test-support.test.ts +2 -0
  84. package/src/testing/test-support.ts +16 -0
  85. package/src/thread/agent-continuation.test.ts +2 -0
  86. package/src/thread/agent-transcript.ts +7 -0
  87. package/src/thread/components/AgentConfigControls.tsx +1 -0
  88. package/src/thread/components/AgentThreadPane.test.tsx +31 -0
  89. package/src/thread/components/AgentThreadPane.tsx +12 -0
  90. package/src/thread/components/ThreadTree.tsx +1 -0
  91. package/src/thread/components/thread-tree.test.ts +1 -0
  92. package/src/thread/thread-controller.curate.test.ts +2 -0
  93. package/src/thread/thread-controller.ts +123 -0
  94. package/src/thread/tree-view.ts +4 -0
  95. package/src/thread/use-thread-agent.test.tsx +1 -0
  96. package/src/thread/use-thread-agent.ts +5 -0
  97. package/src/ui/components/OverlayScrollbar.test.tsx +3 -0
  98. package/src/ui/components/OverlayScrollbar.tsx +5 -0
  99. package/src/ui/components/PromptDialog.tsx +2 -0
  100. package/src/ui/components/RootOverlay.tsx +1 -0
  101. package/src/ui/components/ScrollArea.tsx +2 -0
  102. package/src/ui/components/primitives/Button.tsx +1 -0
  103. package/src/ui/components/primitives/Tabs.tsx +1 -0
  104. package/src/ui/components/primitives/Tree.tsx +4 -0
  105. package/src/ui/components/primitives/tree-model.ts +7 -0
  106. package/src/ui/components/syntax-highlight.ts +5 -0
  107. package/src/ui/components/truncate-title.ts +1 -0
  108. package/src/ui/use-frame-measure.ts +3 -0
  109. package/src/ui/use-terminal-virtualizer.ts +6 -0
  110. package/src/workbench/components/ChangesColumn.tsx +7 -0
  111. package/src/workbench/components/ChangesFileTree.test.tsx +3 -0
  112. package/src/workbench/components/EditorGrid.tsx +8 -0
  113. package/src/workbench/components/FileContentsView.tsx +2 -0
  114. package/src/workbench/components/GridTabContent.tsx +2 -0
  115. package/src/workbench/components/ProjectTreeView.test.tsx +3 -0
  116. package/src/workbench/components/ProjectTreeView.tsx +8 -0
  117. package/src/workbench/components/TreePane.tsx +2 -0
  118. package/src/workbench/components/editor-grid.ts +3 -0
  119. package/src/workbench/components/file-tree.ts +2 -0
  120. package/src/workbench/use-changes-workbench.ts +5 -0
  121. package/src/workbench/use-remember-layout.ts +2 -0
  122. package/src/workbench/use-repo-changes.ts +2 -0
@@ -43,6 +43,33 @@ const empty: ThreadAgentState = {
43
43
  comments: [],
44
44
  };
45
45
 
46
+ test("a failed harness turn displays its error below the conversation", async () => {
47
+ const failure = "OAuth auth derivation failed: missing provider module";
48
+ const { client } = createTestAgentClient({ ...empty, phase: { kind: "failed", error: failure } });
49
+ const setup = await testRender(
50
+ <AgentThreadPane
51
+ thread={thread}
52
+ client={client}
53
+ focused
54
+ theme={DARK}
55
+ onActiveChange={noop}
56
+ onOpenFile={noop}
57
+ >
58
+ {artifactView(thread)}
59
+ </AgentThreadPane>,
60
+ { width: 100, height: 24 },
61
+ );
62
+
63
+ try {
64
+ await waitForText(setup, "Original artifact");
65
+ await settle(setup);
66
+ expect(setup.captureCharFrame()).toContain(failure);
67
+ expect(setup.captureCharFrame()).not.toContain("Thinking");
68
+ } finally {
69
+ setup.renderer.destroy();
70
+ }
71
+ });
72
+
46
73
  function createTestAgentClient(initial: ThreadAgentState) {
47
74
  let state = initial;
48
75
  const prompts: AgentPromptRequest[] = [];
@@ -56,6 +83,7 @@ function createTestAgentClient(initial: ThreadAgentState) {
56
83
  agentGet: async () => state,
57
84
  agentPrompt: async (params) => {
58
85
  prompts.push(params);
86
+
59
87
  if (params.text)
60
88
  state = {
61
89
  ...state,
@@ -287,6 +315,7 @@ test("three bottom prompts survive delayed acceptance and remain separate submis
287
315
 
288
316
  client.agentPrompt = async (params) => {
289
317
  prompts.push(params.text);
318
+
290
319
  if (prompts.length === 1)
291
320
  return new Promise((resolve) => {
292
321
  release = resolve;
@@ -868,6 +897,7 @@ test("an arriving reply preserves a bottom draft and submits it as the next prom
868
897
 
869
898
  client.agentPrompt = async (params) => {
870
899
  prompts.push(params);
900
+
871
901
  if (prompts.length === 1)
872
902
  return new Promise<ThreadAgentState>((resolve) => {
873
903
  finish = resolve;
@@ -1038,6 +1068,7 @@ test("a failed mutation flush restores the prompt alongside a newer visible draf
1038
1068
  onOpenFile={noop}
1039
1069
  flushMutations={() => {
1040
1070
  if (flushStarted) return Promise.resolve();
1071
+
1041
1072
  flushStarted = true;
1042
1073
 
1043
1074
  return failedFlush;
@@ -80,6 +80,7 @@ export function AgentThreadPane(props: AgentThreadPaneProps): React.ReactNode {
80
80
 
81
81
  useEffect(() => {
82
82
  if (!busy) return;
83
+
83
84
  const timer = setInterval(() => setPulse((value) => !value), 600);
84
85
 
85
86
  return () => clearInterval(timer);
@@ -119,7 +120,9 @@ export function AgentThreadPane(props: AgentThreadPaneProps): React.ReactNode {
119
120
 
120
121
  const invoke = async (commentId?: string): Promise<void> => {
121
122
  if (thread.status !== "pending") return;
123
+
122
124
  if (!commentId && !draft.current.trim()) return;
125
+
123
126
  invocations.current.push({
124
127
  text: draft.current,
125
128
  commentId: commentId
@@ -128,7 +131,9 @@ export function AgentThreadPane(props: AgentThreadPaneProps): React.ReactNode {
128
131
  writes: pendingWrites.current.splice(0),
129
132
  });
130
133
  draft.current = "";
134
+
131
135
  if (invoking.current) return;
136
+
132
137
  invoking.current = true;
133
138
 
134
139
  const rejected: string[] = [];
@@ -144,6 +149,7 @@ export function AgentThreadPane(props: AgentThreadPaneProps): React.ReactNode {
144
149
  rejected.push(input.text);
145
150
  continue;
146
151
  }
152
+
147
153
  await props.flushMutations?.();
148
154
  const accepted = await agent.act((client) =>
149
155
  client.agentPrompt({
@@ -219,6 +225,7 @@ export function AgentThreadPane(props: AgentThreadPaneProps): React.ReactNode {
219
225
  );
220
226
 
221
227
  if (!submission) return undefined;
228
+
222
229
  if (submission.status === "failed" && props.client?.canControlAgent !== false)
223
230
  return {
224
231
  label: "Retry",
@@ -293,6 +300,7 @@ export function AgentThreadPane(props: AgentThreadPaneProps): React.ReactNode {
293
300
 
294
301
  return;
295
302
  }
303
+
296
304
  if (source?.kind === "mirror") {
297
305
  const mirrorId = projection.marks.get(span.start.blockIndex)?.[0]?.annotationId;
298
306
 
@@ -300,15 +308,18 @@ export function AgentThreadPane(props: AgentThreadPaneProps): React.ReactNode {
300
308
 
301
309
  return;
302
310
  }
311
+
303
312
  if (source?.kind === "artifact" && end?.kind === "artifact") {
304
313
  return child?.onAnnotate(span, body);
305
314
  }
315
+
306
316
  if (
307
317
  source?.kind !== "message" ||
308
318
  end?.kind !== "message" ||
309
319
  source.messageId !== end.messageId
310
320
  )
311
321
  return;
322
+
312
323
  const message = state.messages.find((entry) => entry.id === source.messageId)!;
313
324
  const localState = { ...state, messages: [message] };
314
325
  const comment = commentOnAgentSpan(
@@ -347,6 +358,7 @@ export function AgentThreadPane(props: AgentThreadPaneProps): React.ReactNode {
347
358
  {state.phase.kind === "offline" ? (
348
359
  <text fg={theme.textMuted}>Owner offline</text>
349
360
  ) : null}
361
+ {state.phase.kind === "failed" ? <text fg={theme.red}>{state.phase.error}</text> : null}
350
362
  {busy ? <text fg={pulse ? theme.textDim : theme.textMuted}>Thinking…</text> : null}
351
363
  {state.phase.kind === "permission" && props.client?.canControlAgent !== false ? (
352
364
  <>
@@ -116,6 +116,7 @@ function ThreadRow(props: ThreadRowProps): React.ReactNode {
116
116
 
117
117
  useEffect(() => {
118
118
  if (!menuOpen) return;
119
+
119
120
  // the full-screen box closes the menu on an outside click; the menu drops from under the kebab
120
121
  setOverlay(
121
122
  "thread-menu",
@@ -6,6 +6,7 @@ function session(id: string, title: string, rootCommit?: string, remote?: string
6
6
  const workspace: WorkspaceKey = { repoRoot: `/home/dev/${id}-checkout`, branch: "main" };
7
7
 
8
8
  if (rootCommit !== undefined) workspace.rootCommit = rootCommit;
9
+
9
10
  if (remote !== undefined) workspace.remote = remote;
10
11
 
11
12
  return {
@@ -99,6 +99,7 @@ function fakeClient(initial: Thread, sink: WorkingCopySink): ThreadClient {
99
99
 
100
100
  sink.workingCopy = content;
101
101
  session = { ...session, workingCopy: content };
102
+
102
103
  if (content === undefined) delete session.workingCopy;
103
104
 
104
105
  return session;
@@ -111,6 +112,7 @@ function fakeClient(initial: Thread, sink: WorkingCopySink): ThreadClient {
111
112
 
112
113
  sink.workingCopy = content;
113
114
  session = { ...session, workingCopy: content };
115
+
114
116
  if (rejections.length) session.curation = rejections;
115
117
  else delete session.curation;
116
118