@cueloop/client 0.1.0-alpha.32 → 0.1.0-alpha.34
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.
- package/package.json +27 -26
- package/src/App.autoclose.test.tsx +7 -4
- package/src/App.diff.test.tsx +131 -5
- package/src/App.export.test.tsx +23 -5
- package/src/App.plan-review.test.tsx +133 -32
- package/src/App.readonly.test.tsx +35 -13
- package/src/App.rendering.test.tsx +14 -4
- package/src/App.review-panel.test.tsx +27 -15
- package/src/App.submit-confirm.test.tsx +14 -13
- package/src/App.test.tsx +50 -13
- package/src/App.toast.test.tsx +75 -0
- package/src/App.tsx +505 -101
- package/src/App.walk.test.tsx +31 -11
- package/src/attribution.ts +8 -2
- package/src/clipboard.ts +5 -1
- package/src/components/AnnotationCard.stories.tsx +29 -10
- package/src/components/AnnotationCard.tsx +57 -37
- package/src/components/Breadcrumb.tsx +7 -1
- package/src/components/CodeBlock.stories.tsx +19 -2
- package/src/components/CodeBlock.tsx +24 -9
- package/src/components/CompletionOverlay.tsx +13 -3
- package/src/components/ConfirmCard.stories.tsx +22 -3
- package/src/components/ConfirmCard.tsx +23 -5
- package/src/components/ConfirmDialog.tsx +10 -2
- package/src/components/DiffSheet.scroll.test.tsx +123 -0
- package/src/components/DiffSheet.stories.tsx +35 -1
- package/src/components/DiffSheet.syntax.test.tsx +62 -0
- package/src/components/DiffSheet.tsx +213 -101
- package/src/components/InboxList.stories.tsx +16 -3
- package/src/components/InboxList.tsx +17 -10
- package/src/components/KeybindsDialog.stories.tsx +31 -0
- package/src/components/KeybindsDialog.tsx +58 -0
- package/src/components/MarkerPopover.stories.tsx +58 -0
- package/src/components/MarkerPopover.tsx +102 -0
- package/src/components/MenuBar.stories.tsx +37 -0
- package/src/components/MenuBar.tsx +74 -0
- package/src/components/PlanSheet.stories.tsx +35 -3
- package/src/components/PlanSheet.tsx +160 -100
- package/src/components/PromptDialog.tsx +19 -3
- package/src/components/ReviewPanel.stories.tsx +17 -19
- package/src/components/ReviewPanel.tsx +17 -32
- package/src/components/ReviewRail.stories.tsx +159 -47
- package/src/components/ReviewRail.tsx +206 -62
- package/src/components/SettingsDialog.stories.tsx +51 -3
- package/src/components/SettingsDialog.tsx +11 -5
- package/src/components/SettingsRows.stories.tsx +1 -1
- package/src/components/SettingsRows.tsx +19 -3
- package/src/components/Toast.stories.tsx +12 -0
- package/src/components/Toast.tsx +44 -0
- package/src/components/WalkWizard.stories.tsx +13 -2
- package/src/components/WalkWizard.tsx +9 -3
- package/src/components/__snapshots__/stories.test.tsx.snap +853 -623
- package/src/components/diff-sheet-layout.test.ts +127 -0
- package/src/components/diff-sheet-layout.ts +167 -0
- package/src/components/primitives/Button.stories.tsx +2 -2
- package/src/components/primitives/Button.tsx +5 -1
- package/src/components/primitives/Dialog.tsx +12 -1
- package/src/components/primitives/Tabs.tsx +40 -39
- package/src/components/stories-app.tsx +34 -6
- package/src/components/story-fixtures.ts +11 -3
- package/src/components/story.ts +3 -1
- package/src/components/syntax-highlight.ts +47 -12
- package/src/components/theme-context.stories.tsx +6 -1
- package/src/components/theme-context.tsx +7 -1
- package/src/config.test.ts +178 -2
- package/src/config.ts +121 -23
- package/src/diff-hunk-curate.test.ts +315 -0
- package/src/diff-hunk-curate.ts +233 -0
- package/src/diff-intraline.test.ts +164 -0
- package/src/diff-intraline.ts +132 -0
- package/src/diff-syntax.test.ts +96 -0
- package/src/diff-syntax.ts +154 -0
- package/src/editor.test.ts +13 -4
- package/src/editor.ts +31 -5
- package/src/herdr.ts +8 -2
- package/src/index.ts +9 -1
- package/src/integrations.ts +3 -1
- package/src/intent-dispatch.test.ts +193 -9
- package/src/intent-dispatch.ts +151 -18
- package/src/key-bindings.test.ts +19 -9
- package/src/key-bindings.ts +77 -16
- package/src/keymap.test.ts +171 -26
- package/src/keymap.ts +83 -16
- package/src/review-panel.test.ts +3 -1
- package/src/review-panel.ts +9 -2
- package/src/serve.test.ts +13 -5
- package/src/session-controller.curate.test.ts +253 -0
- package/src/session-controller.share.test.ts +77 -16
- package/src/session-controller.ts +319 -26
- package/src/share.ts +41 -8
- package/src/test-support.ts +97 -23
- package/src/theme-presets.ts +168 -0
- package/src/theme.ts +1 -3
- package/src/version.ts +5 -0
- package/src/view-diff.ts +15 -4
- package/src/view-plan.test.ts +40 -6
- package/src/view-plan.ts +71 -28
- package/src/walk.test.ts +7 -2
- package/src/walk.ts +7 -2
- package/src/components/ComposeBar.stories.tsx +0 -18
- package/src/components/ComposeBar.tsx +0 -54
|
@@ -8,13 +8,16 @@ import type { SessionClient } from "@cueloop/daemon/client";
|
|
|
8
8
|
const publishShare = mock(async () => ({ line: "ssh p_abc123xy@cueloop.dev", copied: true }));
|
|
9
9
|
let remote: ReviewSession;
|
|
10
10
|
const pullShare = mock(async () => remote);
|
|
11
|
-
const pushShare = mock(
|
|
11
|
+
const pushShare = mock(
|
|
12
|
+
async (_shareId: string, _annotations: Array<Omit<Annotation, "createdAt">>) => {},
|
|
13
|
+
);
|
|
12
14
|
mock.module("./share", () => ({
|
|
13
15
|
publishShare,
|
|
14
16
|
pullShare,
|
|
15
17
|
pushShare,
|
|
16
18
|
shareIdFromLine: (line: string) => line.match(/^ssh (\S+)@/)?.[1],
|
|
17
|
-
collaboratorAnnotations: (session: ReviewSession) =>
|
|
19
|
+
collaboratorAnnotations: (session: ReviewSession) =>
|
|
20
|
+
session.annotations.filter((annotation) => annotation.author),
|
|
18
21
|
}));
|
|
19
22
|
|
|
20
23
|
const { createReviewController, SHARE_POLL_MS } = await import("./session-controller");
|
|
@@ -35,7 +38,14 @@ function sessionFixture(overrides: Partial<ReviewSession> = {}): ReviewSession {
|
|
|
35
38
|
}
|
|
36
39
|
|
|
37
40
|
function annotation(id: string, author: string): Annotation {
|
|
38
|
-
return {
|
|
41
|
+
return {
|
|
42
|
+
id,
|
|
43
|
+
kind: "comment",
|
|
44
|
+
anchor: { quote: "Plan", prefix: "", suffix: "" },
|
|
45
|
+
body: "note",
|
|
46
|
+
author,
|
|
47
|
+
createdAt: "2026-01-01T00:00:00.000Z",
|
|
48
|
+
};
|
|
39
49
|
}
|
|
40
50
|
|
|
41
51
|
function fakeClient(session: ReviewSession): SessionClient {
|
|
@@ -45,10 +55,13 @@ function fakeClient(session: ReviewSession): SessionClient {
|
|
|
45
55
|
sessionGet: async () => session,
|
|
46
56
|
sessionList: async () => [session],
|
|
47
57
|
sessionAnnotate: mock(async () => session),
|
|
48
|
-
sessionSetShareId: mock(
|
|
58
|
+
sessionSetShareId: mock(
|
|
59
|
+
async (_id: string, shareId: string) => ((session.shareId = shareId), session),
|
|
60
|
+
),
|
|
49
61
|
sessionMergeShared: mock(async (_id: string, incoming: { annotations: Annotation[] }) => {
|
|
50
62
|
const known = new Set(session.annotations.map((existing) => existing.id));
|
|
51
|
-
for (const note of incoming.annotations)
|
|
63
|
+
for (const note of incoming.annotations)
|
|
64
|
+
if (!known.has(note.id)) session.annotations.push(note);
|
|
52
65
|
return session;
|
|
53
66
|
}),
|
|
54
67
|
close: () => {},
|
|
@@ -62,7 +75,11 @@ async function connectedController(
|
|
|
62
75
|
clock?: ManualClock,
|
|
63
76
|
): Promise<{ controller: ReturnType<typeof createReviewController>; client: SessionClient }> {
|
|
64
77
|
const client = fakeClient(session);
|
|
65
|
-
const controller = createReviewController({
|
|
78
|
+
const controller = createReviewController({
|
|
79
|
+
sessionId: session.id,
|
|
80
|
+
openClient: async () => client,
|
|
81
|
+
clock,
|
|
82
|
+
});
|
|
66
83
|
controller.connect();
|
|
67
84
|
await tick();
|
|
68
85
|
return { controller, client };
|
|
@@ -80,6 +97,22 @@ describe("share", () => {
|
|
|
80
97
|
// Assert
|
|
81
98
|
expect(client.sessionSetShareId).toHaveBeenCalledWith("ses_1", "p_abc123xy");
|
|
82
99
|
});
|
|
100
|
+
|
|
101
|
+
test("surfaces the ssh line as a toast, not an inline status", async () => {
|
|
102
|
+
// Arrange
|
|
103
|
+
const { controller } = await connectedController(sessionFixture());
|
|
104
|
+
|
|
105
|
+
// Act
|
|
106
|
+
controller.share();
|
|
107
|
+
await tick();
|
|
108
|
+
|
|
109
|
+
// Assert
|
|
110
|
+
expect(controller.getSnapshot().toast).toEqual({
|
|
111
|
+
body: "ssh p_abc123xy@cueloop.dev",
|
|
112
|
+
title: "share link copied",
|
|
113
|
+
});
|
|
114
|
+
expect(controller.getSnapshot().status).not.toContain("ssh p_abc123xy@cueloop.dev");
|
|
115
|
+
});
|
|
83
116
|
});
|
|
84
117
|
|
|
85
118
|
describe("pullShared", () => {
|
|
@@ -89,7 +122,9 @@ describe("pullShared", () => {
|
|
|
89
122
|
annotations: [annotation("a1", "SHA256:mate")],
|
|
90
123
|
participants: [{ id: "SHA256:mate", provider: "ssh", name: "Sam" }],
|
|
91
124
|
});
|
|
92
|
-
const { controller, client } = await connectedController(
|
|
125
|
+
const { controller, client } = await connectedController(
|
|
126
|
+
sessionFixture({ shareId: "p_abc123xy" }),
|
|
127
|
+
);
|
|
93
128
|
|
|
94
129
|
// Act
|
|
95
130
|
controller.pullShared();
|
|
@@ -122,7 +157,9 @@ describe("mirror on annotate", () => {
|
|
|
122
157
|
test("pushes an edited note up when the plan is shared", async () => {
|
|
123
158
|
// Arrange
|
|
124
159
|
pushShare.mockClear();
|
|
125
|
-
const { controller } = await connectedController(
|
|
160
|
+
const { controller } = await connectedController(
|
|
161
|
+
sessionFixture({ shareId: "p_abc123xy", annotations: [annotation("a1", "SHA256:me")] }),
|
|
162
|
+
);
|
|
126
163
|
|
|
127
164
|
// Act
|
|
128
165
|
controller.updateAnnotation("a1", "revised body");
|
|
@@ -131,13 +168,22 @@ describe("mirror on annotate", () => {
|
|
|
131
168
|
// Assert
|
|
132
169
|
expect(pushShare).toHaveBeenCalledTimes(1);
|
|
133
170
|
expect(pushShare.mock.calls[0]?.[0]).toBe("p_abc123xy");
|
|
134
|
-
expect(pushShare.mock.calls[0]?.[1]).toEqual([
|
|
171
|
+
expect(pushShare.mock.calls[0]?.[1]).toEqual([
|
|
172
|
+
{
|
|
173
|
+
id: "a1",
|
|
174
|
+
kind: "comment",
|
|
175
|
+
anchor: { quote: "Plan", prefix: "", suffix: "" },
|
|
176
|
+
body: "revised body",
|
|
177
|
+
},
|
|
178
|
+
]);
|
|
135
179
|
});
|
|
136
180
|
|
|
137
181
|
test("does not push when the plan was never shared", async () => {
|
|
138
182
|
// Arrange
|
|
139
183
|
pushShare.mockClear();
|
|
140
|
-
const { controller } = await connectedController(
|
|
184
|
+
const { controller } = await connectedController(
|
|
185
|
+
sessionFixture({ annotations: [annotation("a1", "SHA256:me")] }),
|
|
186
|
+
);
|
|
141
187
|
|
|
142
188
|
// Act
|
|
143
189
|
controller.updateAnnotation("a1", "revised body");
|
|
@@ -150,7 +196,9 @@ describe("mirror on annotate", () => {
|
|
|
150
196
|
test("does not push when the local write is rejected", async () => {
|
|
151
197
|
// Arrange - the daemon write fails (e.g. a resolved session)
|
|
152
198
|
pushShare.mockClear();
|
|
153
|
-
const { controller, client } = await connectedController(
|
|
199
|
+
const { controller, client } = await connectedController(
|
|
200
|
+
sessionFixture({ shareId: "p_abc123xy", annotations: [annotation("a1", "SHA256:me")] }),
|
|
201
|
+
);
|
|
154
202
|
(client.sessionAnnotate as ReturnType<typeof mock>).mockImplementationOnce(async () => {
|
|
155
203
|
throw new Error("session is resolved");
|
|
156
204
|
});
|
|
@@ -170,7 +218,10 @@ describe("startSharePoll", () => {
|
|
|
170
218
|
pullShare.mockClear();
|
|
171
219
|
remote = sessionFixture({ annotations: [] });
|
|
172
220
|
const clock = new ManualClock();
|
|
173
|
-
const { controller } = await connectedController(
|
|
221
|
+
const { controller } = await connectedController(
|
|
222
|
+
sessionFixture({ shareId: "p_abc123xy" }),
|
|
223
|
+
clock,
|
|
224
|
+
);
|
|
174
225
|
|
|
175
226
|
// Act - immediate pull
|
|
176
227
|
const stop = controller.startSharePoll();
|
|
@@ -200,9 +251,14 @@ describe("startSharePoll", () => {
|
|
|
200
251
|
pullShare.mockClear();
|
|
201
252
|
remote = sessionFixture({ annotations: [] });
|
|
202
253
|
let release: () => void = () => {};
|
|
203
|
-
pullShare.mockImplementationOnce(
|
|
254
|
+
pullShare.mockImplementationOnce(
|
|
255
|
+
() => new Promise<ReviewSession>((resolve) => (release = () => resolve(remote))),
|
|
256
|
+
);
|
|
204
257
|
const clock = new ManualClock();
|
|
205
|
-
const { controller } = await connectedController(
|
|
258
|
+
const { controller } = await connectedController(
|
|
259
|
+
sessionFixture({ shareId: "p_abc123xy" }),
|
|
260
|
+
clock,
|
|
261
|
+
);
|
|
206
262
|
|
|
207
263
|
// Act - start (pull is in flight), leave, then let the pull settle
|
|
208
264
|
const stop = controller.startSharePoll();
|
|
@@ -223,9 +279,14 @@ describe("startSharePoll", () => {
|
|
|
223
279
|
pullShare.mockClear();
|
|
224
280
|
remote = sessionFixture({ annotations: [] });
|
|
225
281
|
let release: () => void = () => {};
|
|
226
|
-
pullShare.mockImplementationOnce(
|
|
282
|
+
pullShare.mockImplementationOnce(
|
|
283
|
+
() => new Promise<ReviewSession>((resolve) => (release = () => resolve(remote))),
|
|
284
|
+
);
|
|
227
285
|
const clock = new ManualClock();
|
|
228
|
-
const { controller } = await connectedController(
|
|
286
|
+
const { controller } = await connectedController(
|
|
287
|
+
sessionFixture({ shareId: "p_abc123xy" }),
|
|
288
|
+
clock,
|
|
289
|
+
);
|
|
229
290
|
|
|
230
291
|
// Act - run A starts (pull hangs), then run B restarts while A is in flight
|
|
231
292
|
controller.startSharePoll();
|