@achasoft/dsh-advanced-sidebar 0.1.0
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/LICENSE +21 -0
- package/README.md +205 -0
- package/cordis.patch.yml +158 -0
- package/lib/client.js +24890 -0
- package/lib/client.js.map +1 -0
- package/lib/host.js +3156 -0
- package/lib/index.js +20 -0
- package/lib/remote.js +1994 -0
- package/lib/typert.host.js +2000 -0
- package/package.json +136 -0
- package/types/client/ActionMenu.d.ts +36 -0
- package/types/client/Glyphs.d.ts +49 -0
- package/types/client/PanelHost.d.ts +24 -0
- package/types/client/Seats.d.ts +16 -0
- package/types/client/SettingsCard.d.ts +22 -0
- package/types/client/contract.d.ts +358 -0
- package/types/client/controller.d.ts +224 -0
- package/types/client/cx.d.ts +16 -0
- package/types/client/index.d.ts +39 -0
- package/types/client/locales.d.ts +474 -0
- package/types/client/panels/ChangesPanel.d.ts +22 -0
- package/types/client/panels/FilesPanel.d.ts +16 -0
- package/types/client/panels/PreviewPanel.d.ts +27 -0
- package/types/client/panels/TasksPanel.d.ts +28 -0
- package/types/client/panels/TerminalPanel.d.ts +40 -0
- package/types/client/panels/shared.d.ts +65 -0
- package/types/client/target.d.ts +23 -0
- package/types/client/terminal-screen.d.ts +95 -0
- package/types/client/ui/Alert.d.ts +30 -0
- package/types/client/ui/Badge.d.ts +24 -0
- package/types/client/ui/Button.d.ts +28 -0
- package/types/client/ui/Calendar.d.ts +65 -0
- package/types/client/ui/DatePicker.d.ts +41 -0
- package/types/client/ui/Dialog.d.ts +61 -0
- package/types/client/ui/DropdownMenu.d.ts +98 -0
- package/types/client/ui/Input.d.ts +25 -0
- package/types/client/ui/Layer.d.ts +56 -0
- package/types/client/ui/Select.d.ts +49 -0
- package/types/client/ui/Separator.d.ts +15 -0
- package/types/client/ui/Tabs.d.ts +49 -0
- package/types/client/ui/Toggle.d.ts +57 -0
- package/types/client/ui/Tooltip.d.ts +22 -0
- package/types/client/ui/anchor.d.ts +92 -0
- package/types/client/ui/index.d.ts +42 -0
- package/types/client/use-capability.d.ts +27 -0
- package/types/host/deletion.d.ts +57 -0
- package/types/host/files.d.ts +43 -0
- package/types/host/git.d.ts +198 -0
- package/types/host/index.d.ts +210 -0
- package/types/host/open-in.d.ts +93 -0
- package/types/host/paths.d.ts +55 -0
- package/types/host/porcelain.d.ts +51 -0
- package/types/host/preview.d.ts +185 -0
- package/types/host/run.d.ts +72 -0
- package/types/host/tasks.d.ts +80 -0
- package/types/host/terminals.d.ts +86 -0
- package/types/host/types.d.ts +877 -0
- package/types/index.d.ts +17 -0
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The kit's two binary controls: a switch for a setting, a checkbox for a row selection.
|
|
3
|
+
*
|
|
4
|
+
* Both are `<button role="switch">` / `<button role="checkbox">` rather than a styled
|
|
5
|
+
* `<input type="checkbox">`. A native checkbox cannot carry the thumb transition without pseudo
|
|
6
|
+
* elements that no longer expose their state to assistive technology once the input is hidden.
|
|
7
|
+
* @module @achasoft/dsh-advanced-sidebar/client/ui/Toggle
|
|
8
|
+
*/
|
|
9
|
+
import type { ReactNode } from 'react';
|
|
10
|
+
/** What both binary controls take. */
|
|
11
|
+
export interface ToggleProps {
|
|
12
|
+
/** Current state. */
|
|
13
|
+
checked: boolean;
|
|
14
|
+
/**
|
|
15
|
+
* The state changed.
|
|
16
|
+
* @param next - the state after the press.
|
|
17
|
+
*/
|
|
18
|
+
onCheckedChange: (next: boolean) => void;
|
|
19
|
+
/** Refuses the press and dims the control. */
|
|
20
|
+
disabled?: boolean | undefined;
|
|
21
|
+
/** Accessible name, when no visible label is associated. */
|
|
22
|
+
'aria-label'?: string | undefined;
|
|
23
|
+
/** The visible label's element id. */
|
|
24
|
+
'aria-labelledby'?: string | undefined;
|
|
25
|
+
/** The control's own id, for a `<label for>`. */
|
|
26
|
+
id?: string | undefined;
|
|
27
|
+
/** Additional classes. */
|
|
28
|
+
className?: string | undefined;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* A switch.
|
|
32
|
+
* @param props - the state, the change callback, and the accessibility attributes.
|
|
33
|
+
* @returns the switch element.
|
|
34
|
+
* @see {@link ToggleProps}
|
|
35
|
+
*/
|
|
36
|
+
export declare function Switch(props: ToggleProps): import("react").JSX.Element;
|
|
37
|
+
/**
|
|
38
|
+
* A checkbox.
|
|
39
|
+
* @param props - the state, the change callback, and the accessibility attributes.
|
|
40
|
+
* @returns the checkbox element.
|
|
41
|
+
* @see {@link ToggleProps}
|
|
42
|
+
*/
|
|
43
|
+
export declare function Checkbox(props: ToggleProps): import("react").JSX.Element;
|
|
44
|
+
/**
|
|
45
|
+
* A checkbox with its label, as one click target.
|
|
46
|
+
* @param props.checked - current state.
|
|
47
|
+
* @param props.onCheckedChange - the state changed.
|
|
48
|
+
* @param props.disabled - refuses the press.
|
|
49
|
+
* @param props.children - the label.
|
|
50
|
+
* @returns the labelled checkbox.
|
|
51
|
+
*/
|
|
52
|
+
export declare function CheckboxRow(props: {
|
|
53
|
+
checked: boolean;
|
|
54
|
+
onCheckedChange: (next: boolean) => void;
|
|
55
|
+
disabled?: boolean | undefined;
|
|
56
|
+
children: ReactNode;
|
|
57
|
+
}): import("react").JSX.Element;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The kit's tooltip: a hover/focus label placed with the same collision handling as every other
|
|
3
|
+
* layer, so a control at the dock's right edge does not describe itself off screen.
|
|
4
|
+
* @module @achasoft/dsh-advanced-sidebar/client/ui/Tooltip
|
|
5
|
+
*/
|
|
6
|
+
import type { ReactElement, ReactNode } from 'react';
|
|
7
|
+
import type { Side } from './anchor.ts';
|
|
8
|
+
/**
|
|
9
|
+
* A tooltip around one child.
|
|
10
|
+
*
|
|
11
|
+
* The child is wrapped rather than cloned: cloning would need to merge a ref and four handlers into
|
|
12
|
+
* whatever the caller passed, and a wrapper that lays out as its child costs nothing.
|
|
13
|
+
* @param props.label - the text; an empty label renders the child alone.
|
|
14
|
+
* @param props.side - preferred edge, flipped when the window cannot hold it there.
|
|
15
|
+
* @param props.children - the element being described.
|
|
16
|
+
* @returns the wrapped child, and the label while it is showing.
|
|
17
|
+
*/
|
|
18
|
+
export declare function Tooltip({ label, side, children }: {
|
|
19
|
+
label: string;
|
|
20
|
+
side?: Side | undefined;
|
|
21
|
+
children: ReactElement | ReactNode;
|
|
22
|
+
}): import("react").JSX.Element;
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Collision-aware placement for every layer this package floats above the page: the action menu,
|
|
3
|
+
* its submenus, the select lists, the date picker, and the tooltips.
|
|
4
|
+
*
|
|
5
|
+
* The harness's own `Menu` primitive clamps a root list into the viewport but pins a submenu at
|
|
6
|
+
* `left: calc(100% + 10px)` with no flip, so a menu opened near the right edge pushes its submenu
|
|
7
|
+
* off screen. Placement here is a pure function of four rectangles, which is what makes the flip
|
|
8
|
+
* decision testable and identical for every layer that uses it.
|
|
9
|
+
* @module @achasoft/dsh-advanced-sidebar/client/ui/anchor
|
|
10
|
+
*/
|
|
11
|
+
import type { CSSProperties, MutableRefObject } from 'react';
|
|
12
|
+
/** Which edge of the anchor the layer prefers to sit against. */
|
|
13
|
+
export type Side = 'top' | 'right' | 'bottom' | 'left';
|
|
14
|
+
/** Where the layer lines up along that edge. */
|
|
15
|
+
export type Align = 'start' | 'center' | 'end';
|
|
16
|
+
/** A rectangle in viewport coordinates; the browser's `DOMRect` satisfies it. */
|
|
17
|
+
export interface Box {
|
|
18
|
+
readonly left: number;
|
|
19
|
+
readonly top: number;
|
|
20
|
+
readonly right: number;
|
|
21
|
+
readonly bottom: number;
|
|
22
|
+
readonly width: number;
|
|
23
|
+
readonly height: number;
|
|
24
|
+
}
|
|
25
|
+
/** How one layer wants to sit against its anchor. */
|
|
26
|
+
export interface PlacementRequest {
|
|
27
|
+
/** Preferred edge; flipped to its opposite when the layer does not fit there. */
|
|
28
|
+
readonly side: Side;
|
|
29
|
+
/** Preferred alignment along that edge. */
|
|
30
|
+
readonly align: Align;
|
|
31
|
+
/** Gap between the anchor edge and the layer, in pixels. */
|
|
32
|
+
readonly sideOffset: number;
|
|
33
|
+
/** Shift along the alignment axis before collision handling, in pixels. */
|
|
34
|
+
readonly alignOffset: number;
|
|
35
|
+
/** Clearance kept from every viewport edge, in pixels. */
|
|
36
|
+
readonly padding: number;
|
|
37
|
+
}
|
|
38
|
+
/** Where a layer ended up, and how much room it was given. */
|
|
39
|
+
export interface Placement {
|
|
40
|
+
/** Viewport x of the layer's left edge. */
|
|
41
|
+
readonly left: number;
|
|
42
|
+
/** Viewport y of the layer's top edge. */
|
|
43
|
+
readonly top: number;
|
|
44
|
+
/** The edge actually used, after any flip. */
|
|
45
|
+
readonly side: Side;
|
|
46
|
+
/** The alignment actually used, after any flip. */
|
|
47
|
+
readonly align: Align;
|
|
48
|
+
/** Largest height the layer may occupy at this position; it scrolls internally past it. */
|
|
49
|
+
readonly maxHeight: number;
|
|
50
|
+
}
|
|
51
|
+
/** The default request; every layer overrides only what differs. */
|
|
52
|
+
export declare const DEFAULT_PLACEMENT: PlacementRequest;
|
|
53
|
+
/**
|
|
54
|
+
* Place one layer against its anchor, flipping to the opposite side when it does not fit and
|
|
55
|
+
* shifting along the other axis to stay inside the viewport.
|
|
56
|
+
*
|
|
57
|
+
* The flip is taken only when the opposite side has strictly more room: a layer that fits nowhere
|
|
58
|
+
* keeps the side it asked for and is capped by {@link Placement.maxHeight} instead of jumping to a
|
|
59
|
+
* side that is just as short.
|
|
60
|
+
* @param anchor - the trigger's rectangle, in viewport coordinates.
|
|
61
|
+
* @param layer - the layer's measured size.
|
|
62
|
+
* @param viewport - the viewport rectangle.
|
|
63
|
+
* @param request - the preferred side, alignment, gaps, and clearance.
|
|
64
|
+
* @returns where to position the layer and how tall it may be.
|
|
65
|
+
*/
|
|
66
|
+
export declare function placeLayer(anchor: Box, layer: {
|
|
67
|
+
readonly width: number;
|
|
68
|
+
readonly height: number;
|
|
69
|
+
}, viewport: Box, request: PlacementRequest): Placement;
|
|
70
|
+
/** A measured, positioned layer plus the trigger to re-measure it. */
|
|
71
|
+
export interface AnchoredLayer {
|
|
72
|
+
/** Attach to the floating element; its box is what placement measures. */
|
|
73
|
+
readonly ref: MutableRefObject<HTMLDivElement | null>;
|
|
74
|
+
/** Fixed-position style for the floating element, including its height cap. */
|
|
75
|
+
readonly style: CSSProperties;
|
|
76
|
+
/** The edge the layer ended up on, for a directional entry animation. */
|
|
77
|
+
readonly side: Side;
|
|
78
|
+
/** Re-measure and reposition now; safe to call from a layout effect. */
|
|
79
|
+
readonly place: () => void;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Position one floating element against a caller-owned anchor rectangle.
|
|
83
|
+
*
|
|
84
|
+
* The first placement runs in a layout effect against the hidden pre-render, so the first painted
|
|
85
|
+
* frame is already final — a layer that measured zero and corrected itself afterwards visibly
|
|
86
|
+
* jumps. While open, scroll (captured, so a scrolling pane counts) and resize re-place it.
|
|
87
|
+
* @param open - whether the layer is rendered; closed suspends every listener.
|
|
88
|
+
* @param getAnchorRect - the anchor's current rectangle; null skips placement for that frame.
|
|
89
|
+
* @param request - overrides of {@link DEFAULT_PLACEMENT}.
|
|
90
|
+
* @returns the ref, the style, the resolved side, and a manual re-place.
|
|
91
|
+
*/
|
|
92
|
+
export declare function useAnchoredLayer(open: boolean, getAnchorRect: () => DOMRect | null, request?: Partial<PlacementRequest>): AnchoredLayer;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The shadcn-vocabulary component kit this plugin's surfaces are built from.
|
|
3
|
+
*
|
|
4
|
+
* shadcn/ui cannot be installed into an out-of-tree browser half: it is Tailwind utilities over
|
|
5
|
+
* Radix primitives, and this package ships as one bundled CSS-Modules file with no Tailwind
|
|
6
|
+
* pipeline and no second React runtime to give Radix. What is reproduced is the vocabulary — the
|
|
7
|
+
* variant and size axes, the geometry scale, the flat bordered surfaces, and the focus ring — over
|
|
8
|
+
* the harness's own design tokens, so the components sit in the app's themes unmodified.
|
|
9
|
+
*
|
|
10
|
+
* They are also what fixes the menu: every floating surface is placed through the collision
|
|
11
|
+
* handling in {@link module:@achasoft/dsh-advanced-sidebar/client/ui/anchor}, which the harness's
|
|
12
|
+
* `Menu` primitive applies to a root list but not to a submenu.
|
|
13
|
+
* @module @achasoft/dsh-advanced-sidebar/client/ui
|
|
14
|
+
*/
|
|
15
|
+
export { Alert } from './Alert.tsx';
|
|
16
|
+
export type { AlertProps, AlertTone } from './Alert.tsx';
|
|
17
|
+
export { Badge } from './Badge.tsx';
|
|
18
|
+
export type { BadgeProps, BadgeVariant } from './Badge.tsx';
|
|
19
|
+
export { Button } from './Button.tsx';
|
|
20
|
+
export type { ButtonProps, ButtonSize, ButtonVariant } from './Button.tsx';
|
|
21
|
+
export { Calendar, dayKey, monthGrid, startOfDay } from './Calendar.tsx';
|
|
22
|
+
export type { CalendarProps } from './Calendar.tsx';
|
|
23
|
+
export { DatePicker } from './DatePicker.tsx';
|
|
24
|
+
export type { DatePickerProps } from './DatePicker.tsx';
|
|
25
|
+
export { AlertDialog, Dialog } from './Dialog.tsx';
|
|
26
|
+
export type { DialogProps } from './Dialog.tsx';
|
|
27
|
+
export { DropdownMenu } from './DropdownMenu.tsx';
|
|
28
|
+
export type { DropdownMenuProps, MenuItemNode, MenuLabelNode, MenuNode, MenuSeparatorNode, MenuSubNode, } from './DropdownMenu.tsx';
|
|
29
|
+
export { Input, Textarea } from './Input.tsx';
|
|
30
|
+
export type { InputProps } from './Input.tsx';
|
|
31
|
+
export { Layer, insideLayerTree } from './Layer.tsx';
|
|
32
|
+
export type { LayerProps } from './Layer.tsx';
|
|
33
|
+
export { Select } from './Select.tsx';
|
|
34
|
+
export type { SelectOption, SelectProps } from './Select.tsx';
|
|
35
|
+
export { Separator } from './Separator.tsx';
|
|
36
|
+
export { Tabs } from './Tabs.tsx';
|
|
37
|
+
export type { TabDescriptor, TabsProps } from './Tabs.tsx';
|
|
38
|
+
export { Checkbox, CheckboxRow, Switch } from './Toggle.tsx';
|
|
39
|
+
export type { ToggleProps } from './Toggle.tsx';
|
|
40
|
+
export { Tooltip } from './Tooltip.tsx';
|
|
41
|
+
export { DEFAULT_PLACEMENT, placeLayer, useAnchoredLayer } from './anchor.ts';
|
|
42
|
+
export type { Align, AnchoredLayer, Box, Placement, PlacementRequest, Side } from './anchor.ts';
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The capability-view hook shared by the two menu seats and the settings card.
|
|
3
|
+
*
|
|
4
|
+
* There is no host-to-client push channel available to an out-of-tree plugin, so the view is
|
|
5
|
+
* fetched rather than subscribed. It is fetched on demand — when a menu opens, when a card is
|
|
6
|
+
* expanded — rather than on a timer: the facts it carries (is git installed, does `code` resolve)
|
|
7
|
+
* change on the scale of an operator installing something, and a poll would spend a PATH scan per
|
|
8
|
+
* interval to notice.
|
|
9
|
+
* @module @achasoft/dsh-advanced-sidebar/client/use-capability
|
|
10
|
+
*/
|
|
11
|
+
import type { AdvancedSidebarView } from '../host/types.ts';
|
|
12
|
+
/** The view plus the trigger that re-reads it. */
|
|
13
|
+
export interface CapabilityHandle {
|
|
14
|
+
/** The last successful reading; undefined until one arrives. */
|
|
15
|
+
view: AdvancedSidebarView | undefined;
|
|
16
|
+
/** The transport failure of the last attempt, when it failed. */
|
|
17
|
+
error: string | undefined;
|
|
18
|
+
/** Ask for a fresh reading. Stable across renders, so it is safe in an effect's dependency list. */
|
|
19
|
+
refresh: () => void;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Read the Host capability view on demand.
|
|
23
|
+
* @param describe - the endpoint call.
|
|
24
|
+
* @param enabled - false suspends fetching entirely (a collapsed card, a seat switched off).
|
|
25
|
+
* @returns the view, the last error, and a stable refresh.
|
|
26
|
+
*/
|
|
27
|
+
export declare function useCapabilityView(describe: (signal?: AbortSignal) => Promise<AdvancedSidebarView>, enabled?: boolean): CapabilityHandle;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session deletion.
|
|
3
|
+
*
|
|
4
|
+
* No harness capability deletes a session: session persistence is append-only and exposes no delete
|
|
5
|
+
* verb, and the workspace registry can only ARCHIVE — hide a session while keeping its log and its
|
|
6
|
+
* accounting slot. Delete is therefore assembled here from the two things that do exist, and it is
|
|
7
|
+
* honest about which one it managed:
|
|
8
|
+
*
|
|
9
|
+
* - `archive` hides the session. Reversible in principle (the durable slot is preserved), and the
|
|
10
|
+
* only mode that can act on a session that is currently live.
|
|
11
|
+
* - `purge` additionally removes the persistence backend's own per-session artifact. Nothing undoes
|
|
12
|
+
* that, and a backend that keeps no per-session artifact (SQLite) reports the archive alone.
|
|
13
|
+
*
|
|
14
|
+
* A live session is never purged. Its writer holds the artifact open and a running turn would keep
|
|
15
|
+
* appending to a file that no longer exists, so the archive commits and the reason is returned.
|
|
16
|
+
* @module @achasoft/dsh-advanced-sidebar/host/deletion
|
|
17
|
+
*/
|
|
18
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
19
|
+
import type { AdvancedSidebarSettings, DeleteSessionRequest, DeleteSessionResult } from './types.ts';
|
|
20
|
+
/** What Delete can do on this Host right now. */
|
|
21
|
+
export interface DeletionCapability {
|
|
22
|
+
/** Whether the persistence backend exposes a per-session artifact that could be removed. */
|
|
23
|
+
readonly canPurge: boolean;
|
|
24
|
+
/** Why purging is unavailable, when it is. */
|
|
25
|
+
readonly reason?: string;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Commits Delete for the sidebar menu. Stateless apart from the context and settings it reads.
|
|
29
|
+
*/
|
|
30
|
+
export declare class SessionDeleter {
|
|
31
|
+
private readonly ctx;
|
|
32
|
+
private readonly source;
|
|
33
|
+
/**
|
|
34
|
+
* @param ctx - Host context carrying the workspace registry and session persistence.
|
|
35
|
+
* @param source - reads the current settings section; called per request.
|
|
36
|
+
*/
|
|
37
|
+
constructor(ctx: Context, source: () => AdvancedSidebarSettings);
|
|
38
|
+
/**
|
|
39
|
+
* Report whether the durable log can be removed at all.
|
|
40
|
+
* @returns the capability, with a reason when purging is impossible.
|
|
41
|
+
*/
|
|
42
|
+
describe(): DeletionCapability;
|
|
43
|
+
/**
|
|
44
|
+
* Hide one session, and remove its durable artifact when the mode and the Host allow it.
|
|
45
|
+
* @param request - the session to delete.
|
|
46
|
+
* @param signal - cancellation for the persistence listing.
|
|
47
|
+
* @returns what was actually done, or a classified failure.
|
|
48
|
+
*/
|
|
49
|
+
delete(request: DeleteSessionRequest, signal?: AbortSignal): Promise<DeleteSessionResult>;
|
|
50
|
+
/**
|
|
51
|
+
* Find the backend artifact for one session, or say why it will not be removed.
|
|
52
|
+
* @param sessionId - the session to look up.
|
|
53
|
+
* @param signal - cancellation for the persistence listing.
|
|
54
|
+
* @returns the artifact path, or the reason purging is skipped.
|
|
55
|
+
*/
|
|
56
|
+
private locateArtifact;
|
|
57
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File previews for the Files panel.
|
|
3
|
+
*
|
|
4
|
+
* Directory listing is not here: the Web Client already reaches the Host's own `browse` capability
|
|
5
|
+
* through `ctx.workspaces.listDirectory`, so the panel walks the tree with the same capability the
|
|
6
|
+
* workspace picker uses and this module owns only the read that surface has no verb for.
|
|
7
|
+
* @module @achasoft/dsh-advanced-sidebar/host/files
|
|
8
|
+
*/
|
|
9
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
10
|
+
import type { AdvancedSidebarSettings, CapabilityState, ListEntriesRequest, ListEntriesResult, ReadFileRequest, ReadFileResult } from './types.ts';
|
|
11
|
+
/** Reads file previews for the Files panel. */
|
|
12
|
+
export declare class FileReader {
|
|
13
|
+
private readonly ctx;
|
|
14
|
+
private readonly source;
|
|
15
|
+
/**
|
|
16
|
+
* @param ctx - Host context carrying the optional filesystem capability.
|
|
17
|
+
* @param source - reads the current settings section; called per request.
|
|
18
|
+
*/
|
|
19
|
+
constructor(ctx: Context, source: () => AdvancedSidebarSettings);
|
|
20
|
+
/**
|
|
21
|
+
* Report whether a preview can be read on this Host.
|
|
22
|
+
* @returns availability, with the reason when there is no filesystem.
|
|
23
|
+
*/
|
|
24
|
+
describe(): CapabilityState;
|
|
25
|
+
/**
|
|
26
|
+
* List one directory level inside a workspace.
|
|
27
|
+
*
|
|
28
|
+
* The Web Client's own `listDirectory` cannot serve this panel: the Host's browse capability
|
|
29
|
+
* returns directories only, because its one caller is a workspace picker. A file browser needs
|
|
30
|
+
* the files.
|
|
31
|
+
* @param request - the directory and the workspace it must stay inside.
|
|
32
|
+
* @param signal - cancellation for the listing.
|
|
33
|
+
* @returns the level, or a classified failure.
|
|
34
|
+
*/
|
|
35
|
+
list(request: ListEntriesRequest, signal?: AbortSignal): Promise<ListEntriesResult>;
|
|
36
|
+
/**
|
|
37
|
+
* Read one file, bounded by `filesMaxPreviewBytes`.
|
|
38
|
+
* @param request - the file and the workspace it must stay inside.
|
|
39
|
+
* @param signal - cancellation for the read.
|
|
40
|
+
* @returns the preview, or a classified failure.
|
|
41
|
+
*/
|
|
42
|
+
read(request: ReadFileRequest, signal?: AbortSignal): Promise<ReadFileResult>;
|
|
43
|
+
}
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Git readings for the Changes panel.
|
|
3
|
+
*
|
|
4
|
+
* The harness has no git capability, so this reads a repository the only way available to a plugin:
|
|
5
|
+
* by running `git` through `ctx.subprocess` and parsing its machine formats. Nothing here writes to
|
|
6
|
+
* a repository — the panel shows what changed and what one path's patch looks like, and every
|
|
7
|
+
* argument list is fixed here rather than assembled from browser text.
|
|
8
|
+
* @module @achasoft/dsh-advanced-sidebar/host/git
|
|
9
|
+
*/
|
|
10
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
11
|
+
import type { AdvancedSidebarSettings, CapabilityState, GitCommitMessageRequest, GitCommitMessageResult, GitCommitRequest, GitCommitResult, GitDiffRequest, GitDiffResult, GitPushRequest, GitPushResult, GitStageRequest, GitStageResult, GitStatusRequest, GitStatusResult } from './types.ts';
|
|
12
|
+
/**
|
|
13
|
+
* Take a model's answer down to the message itself.
|
|
14
|
+
*
|
|
15
|
+
* A model asked for plain text still fences it often enough that the panel would otherwise put
|
|
16
|
+
* ```` ``` ```` into a commit; the wrapper is removed only when it wraps the WHOLE answer, so a
|
|
17
|
+
* message that legitimately quotes a fenced block keeps it.
|
|
18
|
+
* @param text - what the model streamed.
|
|
19
|
+
* @returns the message, trimmed.
|
|
20
|
+
*/
|
|
21
|
+
export declare function stripFence(text: string): string;
|
|
22
|
+
/**
|
|
23
|
+
* Reads one workspace's git state. One instance serves every request; the resolved `git` path is
|
|
24
|
+
* cached across calls and dropped whenever a lookup fails, so installing git later needs no restart.
|
|
25
|
+
*/
|
|
26
|
+
export declare class GitReader {
|
|
27
|
+
private readonly ctx;
|
|
28
|
+
private readonly source;
|
|
29
|
+
private executable;
|
|
30
|
+
private version;
|
|
31
|
+
/**
|
|
32
|
+
* @param ctx - Host context carrying the subprocess and filesystem capabilities.
|
|
33
|
+
* @param source - reads the current settings section; called per request so a committed change
|
|
34
|
+
* reaches the next reading with no registration to rebuild.
|
|
35
|
+
*/
|
|
36
|
+
constructor(ctx: Context, source: () => AdvancedSidebarSettings);
|
|
37
|
+
/**
|
|
38
|
+
* Report whether git can answer on this Host.
|
|
39
|
+
* @param signal - cancellation for the lookup.
|
|
40
|
+
* @returns availability plus the version string when one was read.
|
|
41
|
+
*/
|
|
42
|
+
describe(signal?: AbortSignal): Promise<CapabilityState>;
|
|
43
|
+
/**
|
|
44
|
+
* Read one workspace's changed paths.
|
|
45
|
+
* @param request - the workspace directory to read.
|
|
46
|
+
* @param signal - cancellation for the reading.
|
|
47
|
+
* @returns the reading, or a classified failure.
|
|
48
|
+
*/
|
|
49
|
+
status(request: GitStatusRequest, signal?: AbortSignal): Promise<GitStatusResult>;
|
|
50
|
+
/**
|
|
51
|
+
* Read one path's patch.
|
|
52
|
+
* @param request - which path, and which of the two indexes to compare.
|
|
53
|
+
* @param signal - cancellation for the reading.
|
|
54
|
+
* @returns the patch, or a classified failure.
|
|
55
|
+
*/
|
|
56
|
+
diff(request: GitDiffRequest, signal?: AbortSignal): Promise<GitDiffResult>;
|
|
57
|
+
/**
|
|
58
|
+
* Stage paths.
|
|
59
|
+
* @param request - the workspace and the repository-relative paths to add.
|
|
60
|
+
* @param signal - cancellation for the write and the reading that follows it.
|
|
61
|
+
* @returns the reading after the write, or a classified failure.
|
|
62
|
+
*/
|
|
63
|
+
stage(request: GitStageRequest, signal?: AbortSignal): Promise<GitStageResult>;
|
|
64
|
+
/**
|
|
65
|
+
* Unstage paths, leaving the working tree untouched.
|
|
66
|
+
* @param request - the workspace and the repository-relative paths to restore.
|
|
67
|
+
* @param signal - cancellation for the write and the reading that follows it.
|
|
68
|
+
* @returns the reading after the write, or a classified failure.
|
|
69
|
+
*/
|
|
70
|
+
unstage(request: GitStageRequest, signal?: AbortSignal): Promise<GitStageResult>;
|
|
71
|
+
/**
|
|
72
|
+
* Record the staged changes.
|
|
73
|
+
*
|
|
74
|
+
* The message crosses as one argv element, so no shell ever sees it and nothing in it can become
|
|
75
|
+
* an option. Hooks run: a `pre-commit` that refuses is a real answer, and its stderr is returned
|
|
76
|
+
* verbatim rather than summarized.
|
|
77
|
+
* @param request - the workspace, the message, and whether to replace the previous commit.
|
|
78
|
+
* @param signal - cancellation for the commit and the reading that follows it.
|
|
79
|
+
* @returns the new commit and the reading after it, or a classified failure.
|
|
80
|
+
*/
|
|
81
|
+
commit(request: GitCommitRequest, signal?: AbortSignal): Promise<GitCommitResult>;
|
|
82
|
+
/**
|
|
83
|
+
* Send the current branch's commits to its remote.
|
|
84
|
+
*
|
|
85
|
+
* Only the current branch, and only to its own upstream: a refspec assembled from browser text
|
|
86
|
+
* would let one button push anything anywhere, and `git push` with no arguments already means
|
|
87
|
+
* exactly what the panel offers. A branch with no upstream is published only when the caller asks
|
|
88
|
+
* for it, because choosing a remote is a decision rather than a default.
|
|
89
|
+
* @param request - the workspace, and whether an unpublished branch may be published.
|
|
90
|
+
* @param signal - cancellation; the network wait runs under `gitPushTimeoutMs`.
|
|
91
|
+
* @returns the push, the reading after it, or a classified failure.
|
|
92
|
+
*/
|
|
93
|
+
push(request: GitPushRequest, signal?: AbortSignal): Promise<GitPushResult>;
|
|
94
|
+
/**
|
|
95
|
+
* Ask the deployment's own model to write a commit message for what is staged.
|
|
96
|
+
*
|
|
97
|
+
* The model sees the staged patch and nothing else — not the working tree, not the repository's
|
|
98
|
+
* history, not the session. It is the same model the composer is set to, so this needs no second
|
|
99
|
+
* credential and no second provider; a Host with no model reports the verb unavailable instead.
|
|
100
|
+
* @param request - the workspace, and whether the message is for an amend.
|
|
101
|
+
* @param signal - cancellation for the readings and the model call.
|
|
102
|
+
* @returns the drafted message, or a classified failure.
|
|
103
|
+
*/
|
|
104
|
+
draftCommitMessage(request: GitCommitMessageRequest, signal?: AbortSignal): Promise<GitCommitMessageResult>;
|
|
105
|
+
/**
|
|
106
|
+
* The patch a drafted message describes, bounded so a large change cannot become a large request.
|
|
107
|
+
* @param root - absolute repository root.
|
|
108
|
+
* @param amend - describe the previous commit's content as well as the index.
|
|
109
|
+
* @param signal - cancellation for the invocations.
|
|
110
|
+
* @returns the patch and whether it was cut, or the failure to return.
|
|
111
|
+
*/
|
|
112
|
+
private stagedPatch;
|
|
113
|
+
/**
|
|
114
|
+
* Whether HEAD has a parent commit.
|
|
115
|
+
* @param cwd - absolute repository root.
|
|
116
|
+
* @param signal - cancellation for the invocation.
|
|
117
|
+
* @returns true when `HEAD~1` resolves.
|
|
118
|
+
*/
|
|
119
|
+
private hasParent;
|
|
120
|
+
/**
|
|
121
|
+
* The remote an unpublished branch would be published to.
|
|
122
|
+
* @param cwd - absolute repository root.
|
|
123
|
+
* @param signal - cancellation for the invocation.
|
|
124
|
+
* @returns `origin` when it exists, else the first remote, else undefined.
|
|
125
|
+
*/
|
|
126
|
+
private defaultRemote;
|
|
127
|
+
/**
|
|
128
|
+
* Run one index write over contained paths, then re-read the repository.
|
|
129
|
+
* @param request - the workspace and the paths.
|
|
130
|
+
* @param signal - cancellation for both invocations.
|
|
131
|
+
* @param argv - builds the git arguments from the accepted paths.
|
|
132
|
+
* @returns the reading after the write, or a classified failure.
|
|
133
|
+
*/
|
|
134
|
+
private write;
|
|
135
|
+
/**
|
|
136
|
+
* Prove every path sits inside the repository before git is handed any of them.
|
|
137
|
+
*
|
|
138
|
+
* A path from the browser is untrusted input at a process boundary. `git add` and
|
|
139
|
+
* `git restore` both accept absolute paths and `..`, and `git diff --no-index` will read any file
|
|
140
|
+
* at all — so an unchecked path is a write outside the repository in one direction and an
|
|
141
|
+
* exfiltration route in the other.
|
|
142
|
+
* @param root - absolute repository root.
|
|
143
|
+
* @param paths - repository-relative paths, as the browser sent them.
|
|
144
|
+
* @param signal - cancellation for the resolutions.
|
|
145
|
+
* @returns the failure to return, or undefined when every path is inside.
|
|
146
|
+
*/
|
|
147
|
+
private contain;
|
|
148
|
+
/**
|
|
149
|
+
* The author `git commit` would record.
|
|
150
|
+
* @param cwd - the repository root.
|
|
151
|
+
* @param signal - cancellation for the invocation.
|
|
152
|
+
* @returns `Name <email>`, or undefined when git has no identity configured.
|
|
153
|
+
*/
|
|
154
|
+
private author;
|
|
155
|
+
/**
|
|
156
|
+
* Whether the index differs from HEAD.
|
|
157
|
+
* @param cwd - the repository root.
|
|
158
|
+
* @param signal - cancellation for the invocation.
|
|
159
|
+
* @returns true when a commit would record something.
|
|
160
|
+
*/
|
|
161
|
+
private hasStaged;
|
|
162
|
+
/**
|
|
163
|
+
* Report what the panel may do to this repository.
|
|
164
|
+
* @param cwd - the repository root.
|
|
165
|
+
* @param signal - cancellation for the identity lookup.
|
|
166
|
+
* @returns the write capability.
|
|
167
|
+
*/
|
|
168
|
+
private writeCapability;
|
|
169
|
+
/**
|
|
170
|
+
* Resolve the workspace and its repository once for both endpoints.
|
|
171
|
+
* @param workspacePath - the browser-supplied directory.
|
|
172
|
+
* @param signal - cancellation for the resolution and the `rev-parse`.
|
|
173
|
+
* @returns the repository and the resolved workspace, or the failure to return.
|
|
174
|
+
*/
|
|
175
|
+
private prepare;
|
|
176
|
+
/**
|
|
177
|
+
* Ask git where the repository containing a directory begins.
|
|
178
|
+
* @param cwd - the canonical workspace directory.
|
|
179
|
+
* @param signal - cancellation for the invocation.
|
|
180
|
+
* @returns the repository, or the failure to return.
|
|
181
|
+
*/
|
|
182
|
+
private locateRepository;
|
|
183
|
+
/**
|
|
184
|
+
* Run one git invocation with this plugin's own bounds.
|
|
185
|
+
* @param cwd - directory to run in.
|
|
186
|
+
* @param args - arguments after the executable.
|
|
187
|
+
* @param signal - the caller's cancellation.
|
|
188
|
+
* @returns the finished command.
|
|
189
|
+
*/
|
|
190
|
+
private git;
|
|
191
|
+
/**
|
|
192
|
+
* Resolve `git` once and remember it.
|
|
193
|
+
* @param signal - cancellation for the lookup.
|
|
194
|
+
* @returns the executable path, or undefined when git is absent.
|
|
195
|
+
* @throws {CommandUnavailableError} when no subprocess capability is mounted.
|
|
196
|
+
*/
|
|
197
|
+
private locate;
|
|
198
|
+
}
|