@cueloop/client 0.1.0-alpha.33 → 0.1.0-alpha.35
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 +130 -4
- package/src/App.export.test.tsx +22 -4
- package/src/App.plan-review.test.tsx +127 -27
- package/src/App.readonly.test.tsx +31 -8
- package/src/App.rendering.test.tsx +12 -3
- package/src/App.review-panel.test.tsx +11 -3
- package/src/App.submit-confirm.test.tsx +12 -7
- package/src/App.test.tsx +46 -9
- package/src/App.toast.test.tsx +10 -3
- package/src/App.tsx +400 -100
- package/src/App.walk.test.tsx +30 -10
- package/src/attribution.ts +8 -2
- package/src/clipboard.ts +5 -1
- package/src/components/AnnotationCard.stories.tsx +28 -9
- package/src/components/AnnotationCard.tsx +53 -38
- 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 +22 -5
- package/src/components/ConfirmDialog.tsx +9 -1
- package/src/components/DiffSheet.scroll.test.tsx +123 -0
- package/src/components/DiffSheet.stories.tsx +18 -2
- package/src/components/DiffSheet.syntax.test.tsx +62 -0
- package/src/components/DiffSheet.tsx +184 -98
- package/src/components/InboxList.stories.tsx +16 -3
- package/src/components/InboxList.tsx +17 -10
- package/src/components/KeybindsDialog.tsx +19 -3
- package/src/components/MarkerPopover.stories.tsx +58 -0
- package/src/components/MarkerPopover.tsx +102 -0
- package/src/components/MenuBar.stories.tsx +5 -1
- package/src/components/MenuBar.tsx +18 -2
- package/src/components/PlanSheet.stories.tsx +34 -2
- package/src/components/PlanSheet.tsx +141 -32
- package/src/components/PromptDialog.tsx +18 -2
- package/src/components/ReviewPanel.stories.tsx +13 -3
- package/src/components/ReviewPanel.tsx +8 -4
- package/src/components/ReviewRail.stories.tsx +145 -72
- package/src/components/ReviewRail.tsx +177 -38
- package/src/components/SettingsDialog.stories.tsx +51 -3
- package/src/components/SettingsDialog.tsx +8 -3
- package/src/components/SettingsRows.tsx +19 -3
- package/src/components/Toast.tsx +17 -2
- package/src/components/WalkWizard.stories.tsx +13 -2
- package/src/components/WalkWizard.tsx +9 -3
- package/src/components/__snapshots__/stories.test.tsx.snap +281 -83
- package/src/components/diff-sheet-layout.test.ts +127 -0
- package/src/components/diff-sheet-layout.ts +167 -0
- package/src/components/primitives/Button.tsx +5 -1
- package/src/components/primitives/Dialog.tsx +9 -1
- package/src/components/primitives/Tabs.tsx +24 -4
- 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 +36 -14
- 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 +11 -3
- package/src/session-controller.curate.test.ts +253 -0
- package/src/session-controller.share.test.ts +65 -17
- package/src/session-controller.ts +301 -26
- package/src/share.ts +41 -8
- package/src/test-support.ts +16 -6
- package/src/theme-presets.ts +168 -0
- package/src/theme.ts +1 -3
- 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
|
@@ -51,7 +51,10 @@ afterEach(() => {
|
|
|
51
51
|
});
|
|
52
52
|
|
|
53
53
|
async function frame(): Promise<string> {
|
|
54
|
-
const setup = await testRender(<App home={home} sessionId={session.id} />, {
|
|
54
|
+
const setup = await testRender(<App home={home} sessionId={session.id} />, {
|
|
55
|
+
width: 120,
|
|
56
|
+
height: 36,
|
|
57
|
+
});
|
|
55
58
|
await waitForText(setup, "Render Plan");
|
|
56
59
|
// async highlights settle within the visual-idle wait
|
|
57
60
|
await setup.waitForVisualIdle();
|
|
@@ -112,11 +115,17 @@ describe("block spacing", () => {
|
|
|
112
115
|
workspace: { repoRoot: "/repo", branch: "main" },
|
|
113
116
|
artifact: { type: "plan", content: listPlan, meta: {} },
|
|
114
117
|
});
|
|
115
|
-
const setup = await testRender(<App home={home} sessionId={s2.id} />, {
|
|
118
|
+
const setup = await testRender(<App home={home} sessionId={s2.id} />, {
|
|
119
|
+
width: 120,
|
|
120
|
+
height: 30,
|
|
121
|
+
});
|
|
116
122
|
await waitForText(setup, "one");
|
|
117
123
|
|
|
118
124
|
// Assert
|
|
119
|
-
const lines = setup
|
|
125
|
+
const lines = setup
|
|
126
|
+
.captureCharFrame()
|
|
127
|
+
.split("\n")
|
|
128
|
+
.map((line) => line.trimEnd());
|
|
120
129
|
const one = lines.findIndex((line) => line.includes("- one"));
|
|
121
130
|
expect(lines[one + 1]).toContain("- two");
|
|
122
131
|
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/** The review panel end to end: the b key cycles expanded -> compact -> hidden -> expanded on the live App, and the collapse mode persists to the user config so it survives a restart. Rendering details are locked by the ReviewPanel stories; this suite proves the App wiring and the persistence. */
|
|
2
2
|
|
|
3
3
|
import { afterEach, beforeEach, describe, expect, test } from "bun:test";
|
|
4
|
-
import { mkdtempSync,
|
|
4
|
+
import { mkdtempSync, rmSync } from "node:fs";
|
|
5
5
|
import { tmpdir } from "node:os";
|
|
6
6
|
import { join } from "node:path";
|
|
7
7
|
import React from "react";
|
|
@@ -38,7 +38,10 @@ afterEach(() => {
|
|
|
38
38
|
});
|
|
39
39
|
|
|
40
40
|
async function renderApp() {
|
|
41
|
-
const setup = await testRender(<App home={home} sessionId={session.id} />, {
|
|
41
|
+
const setup = await testRender(<App home={home} sessionId={session.id} />, {
|
|
42
|
+
width: 120,
|
|
43
|
+
height: 30,
|
|
44
|
+
});
|
|
42
45
|
await waitForText(setup, "Review");
|
|
43
46
|
return setup;
|
|
44
47
|
}
|
|
@@ -49,7 +52,12 @@ describe("review panel", () => {
|
|
|
49
52
|
const setup = await renderApp();
|
|
50
53
|
// the plan frame widens as the rail shrinks: expanded < compact < hidden.
|
|
51
54
|
// its width is the column of its top-right corner (the first ╮ on the row).
|
|
52
|
-
const planWidth = () =>
|
|
55
|
+
const planWidth = () =>
|
|
56
|
+
setup
|
|
57
|
+
.captureCharFrame()
|
|
58
|
+
.split("\n")
|
|
59
|
+
.find((line) => line.includes("╮"))
|
|
60
|
+
?.indexOf("╮") ?? 0;
|
|
53
61
|
|
|
54
62
|
// Assert: expanded shows the submit button and leaves room for the rail
|
|
55
63
|
expect(setup.captureCharFrame()).toContain("Submit review");
|
|
@@ -35,7 +35,11 @@ beforeEach(() => {
|
|
|
35
35
|
server.start();
|
|
36
36
|
session = server.core.sessionCreate({
|
|
37
37
|
workspace: { repoRoot: "/repo", branch: "main" },
|
|
38
|
-
artifact: {
|
|
38
|
+
artifact: {
|
|
39
|
+
type: "plan",
|
|
40
|
+
content: PLAN,
|
|
41
|
+
meta: { title: "Migration Plan", planPath: "plan.md" },
|
|
42
|
+
},
|
|
39
43
|
});
|
|
40
44
|
});
|
|
41
45
|
afterEach(() => {
|
|
@@ -45,16 +49,17 @@ afterEach(() => {
|
|
|
45
49
|
});
|
|
46
50
|
|
|
47
51
|
async function renderApp(options: { readOnly?: boolean } = {}) {
|
|
48
|
-
const setup = await testRender(
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
+
const setup = await testRender(
|
|
53
|
+
<App home={home} sessionId={session.id} readOnly={options.readOnly ?? false} />,
|
|
54
|
+
{
|
|
55
|
+
width: 120,
|
|
56
|
+
height: 32,
|
|
57
|
+
},
|
|
58
|
+
);
|
|
52
59
|
await waitForText(setup, "cueloop");
|
|
53
60
|
return setup;
|
|
54
61
|
}
|
|
55
62
|
|
|
56
|
-
type Setup = Awaited<ReturnType<typeof renderApp>>;
|
|
57
|
-
|
|
58
63
|
/** Seed annotations directly through the daemon core (all on one block). */
|
|
59
64
|
function seedAnnotations(count: number): void {
|
|
60
65
|
const blocks = parseBlocks(PLAN);
|
package/src/App.test.tsx
CHANGED
|
@@ -9,7 +9,13 @@ import { testRender } from "@opentui/react/test-utils";
|
|
|
9
9
|
import { DaemonServer } from "@cueloop/daemon";
|
|
10
10
|
import type { ReviewSession } from "@cueloop/schema";
|
|
11
11
|
import { App } from "./App";
|
|
12
|
-
import {
|
|
12
|
+
import {
|
|
13
|
+
isolateUserConfig,
|
|
14
|
+
press,
|
|
15
|
+
typeText as type,
|
|
16
|
+
waitForState,
|
|
17
|
+
waitForText,
|
|
18
|
+
} from "./test-support";
|
|
13
19
|
|
|
14
20
|
const PLAN = `# Migration Plan
|
|
15
21
|
|
|
@@ -35,7 +41,11 @@ beforeEach(() => {
|
|
|
35
41
|
server.start();
|
|
36
42
|
session = server.core.sessionCreate({
|
|
37
43
|
workspace: { repoRoot: "/repo", branch: "main" },
|
|
38
|
-
artifact: {
|
|
44
|
+
artifact: {
|
|
45
|
+
type: "plan",
|
|
46
|
+
content: PLAN,
|
|
47
|
+
meta: { title: "Migration Plan", planPath: "plan.md" },
|
|
48
|
+
},
|
|
39
49
|
});
|
|
40
50
|
});
|
|
41
51
|
afterEach(() => {
|
|
@@ -138,8 +148,8 @@ describe("keyboard grammar", () => {
|
|
|
138
148
|
// Act
|
|
139
149
|
await press(setup, "x");
|
|
140
150
|
|
|
141
|
-
// Assert
|
|
142
|
-
await waitForText(setup, "
|
|
151
|
+
// Assert - the rail shows the cut as a removal card titled CUT · me
|
|
152
|
+
await waitForText(setup, "CUT · me");
|
|
143
153
|
expect(server.core.sessionGet(session.id).workingCopy).not.toContain("move the store");
|
|
144
154
|
|
|
145
155
|
// Act
|
|
@@ -221,14 +231,17 @@ describe("submit", () => {
|
|
|
221
231
|
});
|
|
222
232
|
|
|
223
233
|
describe("inbox", () => {
|
|
224
|
-
test("inbox mode
|
|
234
|
+
test("inbox mode wears the review chrome (header + menu bar) and opens a session", async () => {
|
|
225
235
|
// Arrange
|
|
226
236
|
const setup = await testRender(<App home={home} />, { width: 120, height: 32 });
|
|
227
|
-
await waitForText(setup, "
|
|
237
|
+
await waitForText(setup, "cueloop");
|
|
228
238
|
|
|
229
|
-
// Assert
|
|
230
|
-
|
|
231
|
-
expect(
|
|
239
|
+
// Assert - the same header/menu chrome as review, plus the session row
|
|
240
|
+
const frame = setup.captureCharFrame();
|
|
241
|
+
expect(frame).toContain("cueloop · resume");
|
|
242
|
+
expect(frame).toContain("Migration Plan");
|
|
243
|
+
expect(frame).toContain("menu"); // the shared MenuBar sits at the bottom
|
|
244
|
+
expect(frame).not.toContain("inbox ("); // the old inline header is gone
|
|
232
245
|
|
|
233
246
|
// Act
|
|
234
247
|
await press(setup, "enter");
|
|
@@ -236,4 +249,28 @@ describe("inbox", () => {
|
|
|
236
249
|
// Assert
|
|
237
250
|
await waitForText(setup, "Submit review");
|
|
238
251
|
});
|
|
252
|
+
|
|
253
|
+
test("the menu opens from the inbox and escape is not a trap", async () => {
|
|
254
|
+
// Arrange
|
|
255
|
+
const setup = await testRender(<App home={home} />, { width: 120, height: 32 });
|
|
256
|
+
await waitForText(setup, "cueloop · resume");
|
|
257
|
+
const lines = setup.captureCharFrame().split("\n");
|
|
258
|
+
const menuRow = lines.findIndex((line) => line.includes("menu"));
|
|
259
|
+
const menuColumn = lines[menuRow]!.indexOf("menu");
|
|
260
|
+
|
|
261
|
+
// Act - open the drop-up from the shared menu bar
|
|
262
|
+
await setup.mockMouse.click(menuColumn + 1, menuRow);
|
|
263
|
+
|
|
264
|
+
// Assert - the drop-up options appear
|
|
265
|
+
await waitForText(setup, "Keybinds");
|
|
266
|
+
expect(setup.captureCharFrame()).toContain("Settings");
|
|
267
|
+
|
|
268
|
+
// Act - escape closes the menu (not a trap), and the inbox nav still works
|
|
269
|
+
await press(setup, "escape");
|
|
270
|
+
await waitForState(setup, () => !setup.captureCharFrame().includes("Keybinds"));
|
|
271
|
+
await press(setup, "enter");
|
|
272
|
+
|
|
273
|
+
// Assert
|
|
274
|
+
await waitForText(setup, "Submit review");
|
|
275
|
+
});
|
|
239
276
|
});
|
package/src/App.toast.test.tsx
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/** The share toast is non-modal: while it is up, escape still cancels an open overlay. */
|
|
2
2
|
|
|
3
|
-
import { afterEach, beforeEach, describe,
|
|
3
|
+
import { afterEach, beforeEach, describe, mock, test } from "bun:test";
|
|
4
4
|
import { mkdtempSync, rmSync } from "node:fs";
|
|
5
5
|
import { tmpdir } from "node:os";
|
|
6
6
|
import { join } from "node:path";
|
|
@@ -36,7 +36,11 @@ beforeEach(() => {
|
|
|
36
36
|
server.start();
|
|
37
37
|
session = server.core.sessionCreate({
|
|
38
38
|
workspace: { repoRoot: "/repo", branch: "main" },
|
|
39
|
-
artifact: {
|
|
39
|
+
artifact: {
|
|
40
|
+
type: "plan",
|
|
41
|
+
content: PLAN,
|
|
42
|
+
meta: { title: "Migration Plan", planPath: "plan.md" },
|
|
43
|
+
},
|
|
40
44
|
});
|
|
41
45
|
});
|
|
42
46
|
afterEach(() => {
|
|
@@ -48,7 +52,10 @@ afterEach(() => {
|
|
|
48
52
|
describe("share toast", () => {
|
|
49
53
|
test("escape cancels an open composer even while the toast is up", async () => {
|
|
50
54
|
// Arrange
|
|
51
|
-
const setup = await testRender(<App home={home} sessionId={session.id} />, {
|
|
55
|
+
const setup = await testRender(<App home={home} sessionId={session.id} />, {
|
|
56
|
+
width: 120,
|
|
57
|
+
height: 32,
|
|
58
|
+
});
|
|
52
59
|
await waitForText(setup, "cueloop");
|
|
53
60
|
|
|
54
61
|
// Act: share raises the toast, then open a composer under it
|