dsh-diff-approval 0.21.0 → 0.22.1

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.
@@ -0,0 +1,38 @@
1
+ /**
2
+ * A crash inside the panel must not take the review away for the rest of the page.
3
+ *
4
+ * The slot renderer wraps every seat in its own boundary, but a crash there
5
+ * *abdicates* the entry: the footer row, the header button and the docked tab
6
+ * disappear for the life of the page, with nothing on screen to say why and no way
7
+ * back but a reload. This boundary keeps a failure inside our own tree instead —
8
+ * the entry stays registered, it says what happened, and one press retries the
9
+ * render — so a broken panel can never present as "the panel is gone" or as a
10
+ * blank surface with no explanation.
11
+ *
12
+ * @module dsh-diff-approval/client/boundary
13
+ */
14
+ import { Component } from 'react';
15
+ import type { ErrorInfo, ReactNode } from 'react';
16
+ import type { Translator } from './locales.ts';
17
+ /** Props of the boundary and of the face it shows in place of its children. */
18
+ export interface PanelBoundaryProps {
19
+ /** The panel mount to keep contained. */
20
+ children?: ReactNode;
21
+ /** The panel's translator, for the failure note's copy. */
22
+ t: Translator;
23
+ }
24
+ /** State: whether a child has thrown since the last retry. */
25
+ interface PanelBoundaryState {
26
+ failed: boolean;
27
+ }
28
+ /**
29
+ * Keep one panel mount's crash inside its own slot entry, with a visible note and
30
+ * a retry that re-renders it.
31
+ */
32
+ export declare class PanelBoundary extends Component<PanelBoundaryProps, PanelBoundaryState> {
33
+ state: PanelBoundaryState;
34
+ static getDerivedStateFromError(): PanelBoundaryState;
35
+ componentDidCatch(error: unknown, info: ErrorInfo): void;
36
+ render(): ReactNode;
37
+ }
38
+ export {};
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Pasting a copied reference into the composer, and where the caret goes.
3
+ *
4
+ * The reference lands in the draft whatever the panel is doing. The caret is a
5
+ * different question: the review panel can be over the composer, and moving the
6
+ * focus into a field the reader cannot see would take their next keystrokes with it.
7
+ * So the focus is asked for only when the composer is really visible.
8
+ *
9
+ * @module dsh-diff-approval/client/composer-cover
10
+ */
11
+ /**
12
+ * Whether the review panel is covering the chat composer as it stands right now.
13
+ *
14
+ * Measured, not inferred from the presentation, because the cases do not line up one
15
+ * per mode:
16
+ * - floating with the composer edge left uncovered, the panel stops above the
17
+ * composer — except when the window is too short for the panel's own minimum
18
+ * height, and then it covers every edge, the composer's included (the phone case);
19
+ * - floating over an undocked ("hero") composer, the panel spans the conversation
20
+ * and the composer sits inside it;
21
+ * - docked in the right sidebar, the composer is normally in the conversation column
22
+ * beside the pane and stays visible — but a fullscreen sidebar spans the window,
23
+ * and the panel inside it spans the window too.
24
+ * Whatever a layout does next, an overlap is an overlap, so this measures the two
25
+ * boxes and the fraction of the composer they share.
26
+ * @returns whether the panel covers more than {@link COMPOSER_COVERED_RATIO} of the
27
+ * composer.
28
+ */
29
+ export declare function composerCoveredByPanel(): boolean;
30
+ /**
31
+ * Take the caret out of the composer when it is holding it.
32
+ *
33
+ * Declining to *move* the caret there is not enough on its own: the chord works with
34
+ * the caret wherever it is, and the caret is usually in the composer — someone who
35
+ * was typing, then selected a few lines in the diff with the mouse (a selection does
36
+ * not move the focus), would have the reference pasted into a composer they cannot
37
+ * see and their next keystrokes land in it. So a hidden composer loses the caret.
38
+ */
39
+ export declare function leaveComposerCaret(): void;
40
+ /**
41
+ * Append a copied reference to the composer's draft, and leave the caret there only
42
+ * when the composer is not behind the panel.
43
+ * @param appendDraft - writes the reference into the addressed session's draft.
44
+ * @param reference - the copied `(file:line)` reference.
45
+ */
46
+ export declare function pasteReferenceIntoComposer(appendDraft: (reference: string) => void, reference: string): void;
@@ -32,6 +32,17 @@ export declare const TOGGLE_PANEL_EVENT = "diff-approval:toggle-panel";
32
32
  /** The floating panel's own visibility, published on every change so a second
33
33
  * entry can light up while the panel is open (`detail.open`). */
34
34
  export declare const PANEL_STATE_EVENT = "diff-approval:panel-state";
35
+ /** Name a file for the panel to show, from a mount that is not the panel itself
36
+ * (the produced-file chip): every mounted panel instance switches to it and lands
37
+ * on its first change — the ask is "show me this diff", not "put me back where I
38
+ * was". The file is also recorded as the last one, so an instance that only
39
+ * appears afterwards (the docked tab) opens the same file the same way. */
40
+ export declare const OPEN_PANEL_FILE_EVENT = "diff-approval:panel-file";
41
+ /** Payload of {@link OPEN_PANEL_FILE_EVENT}. */
42
+ export interface PanelFileDetail {
43
+ /** The pending entry to show. */
44
+ fileId: string;
45
+ }
35
46
  /** Payload of {@link PANEL_STATE_EVENT}. */
36
47
  export interface PanelStateDetail {
37
48
  /** Whether the floating panel is showing right now. */
@@ -136,6 +147,16 @@ export interface DockHostContext {
136
147
  * @returns the state; `attach` reports availability and the tab's own visibility.
137
148
  */
138
149
  export declare function createDockState(): DockState;
150
+ /**
151
+ * The tab body: the review panel, docked. The panel's content is one portaled
152
+ * block, so instead of restructuring it this hands it a host element of the
153
+ * sidebar's own making to portal into — the tab body owns the element it fills.
154
+ * @param props - the seat's runtime props, this plugin's face, and `useTabInfo`.
155
+ * @returns the host element and, once it exists, the docked panel inside it.
156
+ */
157
+ /** Keeps a failure inside the tab from taking the app's tree down with it, and
158
+ * from leaving the pane blank: {@link PanelBoundary} says what happened and can
159
+ * re-render the panel without a reload. */
139
160
  export declare function DiffDockBody(props: DiffDockBodyProps): ReactNode;
140
161
  /**
141
162
  * The tab chip: the mode switch, then the panel's title with the pending count —
@@ -144,6 +144,8 @@ export declare const zh: {
144
144
  'action.closeHint': string;
145
145
  'action.closeHintEsc': string;
146
146
  'action.summonHint': string;
147
+ 'action.retry': string;
148
+ 'panel.crashed': string;
147
149
  'status.kept': string;
148
150
  'status.reverted': string;
149
151
  'status.missing': string;
@@ -337,6 +339,8 @@ export declare const en: {
337
339
  'action.closeHint': string;
338
340
  'action.closeHintEsc': string;
339
341
  'action.summonHint': string;
342
+ 'action.retry': string;
343
+ 'panel.crashed': string;
340
344
  'status.kept': string;
341
345
  'status.reverted': string;
342
346
  'status.missing': string;
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Where the review panel was left, for this page's lifetime.
3
+ *
4
+ * Closing the panel is not "done reviewing": reopening it should put the reader
5
+ * back on the file they were in, at the offset they were at. That is a fact about
6
+ * this visit rather than a stored preference, so it lives in module state — which
7
+ * also gives the two mounts that show the panel (the floating overlay and the
8
+ * docked tab) one shared memory, so switching presentation does not lose the
9
+ * place, and a reload starts clean.
10
+ *
11
+ * Keyed by session: two sessions have their own pending lists, and one session's
12
+ * panel must not resume another's file.
13
+ *
14
+ * @module dsh-diff-approval/client/panel-memory
15
+ */
16
+ /**
17
+ * Remember that a session's panel was left showing one file, and where in it.
18
+ * @param sessionId - the session the panel was reviewing; nothing is recorded
19
+ * without one.
20
+ * @param view - the pending entry that was open, and the code view's scrollTop.
21
+ * An absent offset *forgets* any remembered place for that file, which is what
22
+ * a caller that is about to open it at its first change wants: a mount that only
23
+ * appears afterwards then lands there too, instead of on a stale offset.
24
+ */
25
+ export declare function rememberPanelView(sessionId: string | undefined, view: {
26
+ fileId: string;
27
+ scrollTop?: number | undefined;
28
+ }): void;
29
+ /**
30
+ * The file a session's panel was last showing.
31
+ * @param sessionId - the session, if any.
32
+ * @returns the pending entry id, or undefined when that session's panel has never
33
+ * closed on a file.
34
+ */
35
+ export declare function lastPanelFile(sessionId: string | undefined): string | undefined;
36
+ /**
37
+ * How far down one file was left, when it has been left before.
38
+ * @param sessionId - the session, if any.
39
+ * @param fileId - the pending entry id.
40
+ * @returns the remembered scrollTop, or undefined when there is none.
41
+ */
42
+ export declare function panelFileOffset(sessionId: string | undefined, fileId: string): number | undefined;
43
+ /**
44
+ * Forget every session's record. A page reload does this by itself; a test calls
45
+ * it to start from a clean page rather than inheriting the previous case's place.
46
+ */
47
+ export declare function resetPanelMemory(): void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-diff-approval",
3
- "version": "0.21.0",
3
+ "version": "0.22.1",
4
4
  "description": "DeepSeek Harness plugin: pending-edit review with whole-file diff and Keep/Revert",
5
5
  "packageManager": "pnpm@11.21.0",
6
6
  "author": "Wu Zhiwei",