@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,210 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The advanced-sidebar plugin's node half: one Remote namespace serving every operation the browser
|
|
3
|
+
* structurally cannot perform, plus the `advanced-sidebar` settings section both halves address.
|
|
4
|
+
*
|
|
5
|
+
* What is here and what is not follows one rule — the Host owns only what a browser cannot do. The
|
|
6
|
+
* session list, the workspace list, the background-task list, archiving, and directory listing all
|
|
7
|
+
* already reach the Web Client through capabilities it holds, so this endpoint adds no second copy
|
|
8
|
+
* of any of them. It answers for git (a subprocess), panel terminals (a pseudo-terminal), file
|
|
9
|
+
* previews (a filesystem read), external applications (a launch), stopping a background task
|
|
10
|
+
* (an owner-fenced registry), and deletion (a durable artifact).
|
|
11
|
+
*
|
|
12
|
+
* Nothing here is model-facing: no tool, no prompt section, no session event. Every result is a
|
|
13
|
+
* discriminated value rather than a throw, because the RPC gateway erases a business exception's
|
|
14
|
+
* classification and each panel's next move depends on which class it was.
|
|
15
|
+
* @module @achasoft/dsh-advanced-sidebar/host
|
|
16
|
+
*/
|
|
17
|
+
import { Context } from '@deepseek-ai/cordis';
|
|
18
|
+
import z from '@deepseek-ai/schemastery';
|
|
19
|
+
import { TypertRemoteService } from '@deepseek-ai/dsh-typert-protocol';
|
|
20
|
+
import type { AdvancedSidebarSettings, AdvancedSidebarView, DeleteSessionRequest, DeleteSessionResult, GitCommitMessageRequest, GitCommitMessageResult, GitCommitRequest, GitCommitResult, GitDiffRequest, GitDiffResult, GitPushRequest, GitPushResult, GitStageRequest, GitStageResult, GitStatusRequest, GitStatusResult, ListEntriesRequest, ListEntriesResult, OpenInRequest, OpenInResult, PreviewListRequest, PreviewListResult, PreviewLogsRequest, PreviewLogsResult, PreviewStartRequest, PreviewStartResult, PreviewStopRequest, PreviewStopResult, ReadFileRequest, ReadFileResult, TaskKillRequest, TaskKillResult, TaskOutputRequest, TaskOutputResult, TerminalAckResult, TerminalCloseRequest, TerminalOpenRequest, TerminalOpenResult, TerminalReadRequest, TerminalReadResult, TerminalSignalRequest, TerminalWriteRequest } from './types.ts';
|
|
21
|
+
export type * from './types.ts';
|
|
22
|
+
export { REVEAL_TARGET_ID } from './open-in.ts';
|
|
23
|
+
/**
|
|
24
|
+
* The settings namespace both halves address; the browser card joins the plugin tab on it.
|
|
25
|
+
*
|
|
26
|
+
* Kebab-case, unlike the Remote namespace below: a settings namespace is a kebab-case grammar the
|
|
27
|
+
* Host validates, while a Remote namespace is read as `ctx.remote.advancedSidebar.…` and so must be
|
|
28
|
+
* an identifier.
|
|
29
|
+
*/
|
|
30
|
+
export declare const ADVANCED_SIDEBAR_SETTINGS_NAMESPACE: import("@deepseek-ai/dsh-settings").SettingsNamespace;
|
|
31
|
+
/** Deployment configuration for the advanced sidebar; the `advanced-sidebar` section's own shape. */
|
|
32
|
+
export type Config = AdvancedSidebarSettings;
|
|
33
|
+
declare module '@deepseek-ai/cordis' {
|
|
34
|
+
interface Context {
|
|
35
|
+
advancedSidebar: AdvancedSidebarService;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
/** Host endpoint for the sidebar's advanced operations, and owner of the settings section. */
|
|
39
|
+
export declare class AdvancedSidebarService extends TypertRemoteService {
|
|
40
|
+
/** Loader validation for every deployment-varying choice this plugin makes. */
|
|
41
|
+
static Config: z<Config>;
|
|
42
|
+
private source;
|
|
43
|
+
private readonly git;
|
|
44
|
+
private readonly terminals;
|
|
45
|
+
private readonly launcher;
|
|
46
|
+
private readonly files;
|
|
47
|
+
private readonly tasks;
|
|
48
|
+
private readonly deleter;
|
|
49
|
+
private readonly preview;
|
|
50
|
+
/**
|
|
51
|
+
* @param ctx - Host context; every capability this service uses is resolved optionally, so a
|
|
52
|
+
* deployment missing one still serves a view that explains which panel is dark and why.
|
|
53
|
+
* @param config - the composition-layer preferences, used as the section's base layer.
|
|
54
|
+
*/
|
|
55
|
+
constructor(ctx: Context, config: Config);
|
|
56
|
+
/**
|
|
57
|
+
* Describe which operations this Host can serve, so the menu can disable an entry with a reason
|
|
58
|
+
* instead of offering one that fails when it is pressed.
|
|
59
|
+
* @param signal - gateway-supplied cancellation for the executable probes.
|
|
60
|
+
* @returns the capability view.
|
|
61
|
+
*/
|
|
62
|
+
describe(signal: AbortSignal): Promise<AdvancedSidebarView>;
|
|
63
|
+
/**
|
|
64
|
+
* Read one workspace's git status.
|
|
65
|
+
* @param request - the workspace directory.
|
|
66
|
+
* @param signal - gateway-supplied cancellation for the caller's abandoned request.
|
|
67
|
+
* @returns the reading, or a classified failure.
|
|
68
|
+
*/
|
|
69
|
+
gitStatus(request: GitStatusRequest, signal: AbortSignal): Promise<GitStatusResult>;
|
|
70
|
+
/**
|
|
71
|
+
* Read one path's patch.
|
|
72
|
+
* @param request - the path and which index to compare.
|
|
73
|
+
* @param signal - gateway-supplied cancellation for the caller's abandoned request.
|
|
74
|
+
* @returns the patch, or a classified failure.
|
|
75
|
+
*/
|
|
76
|
+
gitDiff(request: GitDiffRequest, signal: AbortSignal): Promise<GitDiffResult>;
|
|
77
|
+
/**
|
|
78
|
+
* Stage paths into the index.
|
|
79
|
+
* @param request - the workspace and the repository-relative paths.
|
|
80
|
+
* @param signal - gateway-supplied cancellation for the caller's abandoned request.
|
|
81
|
+
* @returns the reading after the write, or a classified failure.
|
|
82
|
+
*/
|
|
83
|
+
gitStage(request: GitStageRequest, signal: AbortSignal): Promise<GitStageResult>;
|
|
84
|
+
/**
|
|
85
|
+
* Take paths back out of the index, leaving the working tree alone.
|
|
86
|
+
* @param request - the workspace and the repository-relative paths.
|
|
87
|
+
* @param signal - gateway-supplied cancellation for the caller's abandoned request.
|
|
88
|
+
* @returns the reading after the write, or a classified failure.
|
|
89
|
+
*/
|
|
90
|
+
gitUnstage(request: GitStageRequest, signal: AbortSignal): Promise<GitStageResult>;
|
|
91
|
+
/**
|
|
92
|
+
* Record the staged changes.
|
|
93
|
+
* @param request - the workspace, the message, and whether to amend.
|
|
94
|
+
* @param signal - gateway-supplied cancellation; hooks run under `gitCommitTimeoutMs`.
|
|
95
|
+
* @returns the new commit and the reading after it, or a classified failure.
|
|
96
|
+
*/
|
|
97
|
+
gitCommit(request: GitCommitRequest, signal: AbortSignal): Promise<GitCommitResult>;
|
|
98
|
+
/**
|
|
99
|
+
* Send the current branch's commits to its remote.
|
|
100
|
+
* @param request - the workspace, and whether an unpublished branch may be published.
|
|
101
|
+
* @param signal - gateway-supplied cancellation; the network wait runs under `gitPushTimeoutMs`.
|
|
102
|
+
* @returns the push and the reading after it, or a classified failure.
|
|
103
|
+
*/
|
|
104
|
+
gitPush(request: GitPushRequest, signal: AbortSignal): Promise<GitPushResult>;
|
|
105
|
+
/**
|
|
106
|
+
* Ask the deployment's own model to write a commit message for what is staged.
|
|
107
|
+
* @param request - the workspace, and whether the message is for an amend.
|
|
108
|
+
* @param signal - gateway-supplied cancellation for the readings and the model call.
|
|
109
|
+
* @returns the drafted message, or a classified failure.
|
|
110
|
+
*/
|
|
111
|
+
gitCommitMessage(request: GitCommitMessageRequest, signal: AbortSignal): Promise<GitCommitMessageResult>;
|
|
112
|
+
/**
|
|
113
|
+
* Allocate a panel terminal.
|
|
114
|
+
* @param request - the workspace directory and the panel's measured geometry.
|
|
115
|
+
* @param signal - gateway-supplied cancellation of the allocation.
|
|
116
|
+
* @returns the handle, or a classified failure.
|
|
117
|
+
*/
|
|
118
|
+
terminalOpen(request: TerminalOpenRequest, signal: AbortSignal): Promise<TerminalOpenResult>;
|
|
119
|
+
/**
|
|
120
|
+
* Read a panel terminal's output from a caller-owned offset.
|
|
121
|
+
* @param request - the handle and the offset already rendered.
|
|
122
|
+
* @returns the delta and the process state, or a classified failure.
|
|
123
|
+
*/
|
|
124
|
+
terminalRead(request: TerminalReadRequest): Promise<TerminalReadResult>;
|
|
125
|
+
/**
|
|
126
|
+
* Send keystrokes to a panel terminal.
|
|
127
|
+
* @param request - the handle and the text to deliver verbatim.
|
|
128
|
+
* @returns settlement, or a classified failure.
|
|
129
|
+
*/
|
|
130
|
+
terminalWrite(request: TerminalWriteRequest): Promise<TerminalAckResult>;
|
|
131
|
+
/**
|
|
132
|
+
* Deliver a signal to a panel terminal's foreground process group.
|
|
133
|
+
* @param request - the handle and the signal.
|
|
134
|
+
* @returns settlement, or a classified failure.
|
|
135
|
+
*/
|
|
136
|
+
terminalSignal(request: TerminalSignalRequest): Promise<TerminalAckResult>;
|
|
137
|
+
/**
|
|
138
|
+
* Close a panel terminal.
|
|
139
|
+
* @param request - the handle.
|
|
140
|
+
* @returns settlement, or a classified failure.
|
|
141
|
+
*/
|
|
142
|
+
terminalClose(request: TerminalCloseRequest): Promise<TerminalAckResult>;
|
|
143
|
+
/**
|
|
144
|
+
* List one directory level for the Files panel.
|
|
145
|
+
* @param request - the directory and the workspace it must stay inside.
|
|
146
|
+
* @param signal - gateway-supplied cancellation for the caller's abandoned request.
|
|
147
|
+
* @returns the level, or a classified failure.
|
|
148
|
+
*/
|
|
149
|
+
listEntries(request: ListEntriesRequest, signal: AbortSignal): Promise<ListEntriesResult>;
|
|
150
|
+
/**
|
|
151
|
+
* List one workspace's preview launch configurations, each with its current state.
|
|
152
|
+
* @param request - the workspace to read.
|
|
153
|
+
* @param signal - gateway-supplied cancellation for the caller's abandoned request.
|
|
154
|
+
* @returns the list, or a classified failure.
|
|
155
|
+
*/
|
|
156
|
+
previewList(request: PreviewListRequest, signal: AbortSignal): Promise<PreviewListResult>;
|
|
157
|
+
/**
|
|
158
|
+
* Start one preview configuration.
|
|
159
|
+
* @param request - the workspace and the configuration name.
|
|
160
|
+
* @param signal - gateway-supplied cancellation of the start.
|
|
161
|
+
* @returns the started row, or a classified failure.
|
|
162
|
+
*/
|
|
163
|
+
previewStart(request: PreviewStartRequest, signal: AbortSignal): Promise<PreviewStartResult>;
|
|
164
|
+
/**
|
|
165
|
+
* Stop one running preview server.
|
|
166
|
+
* @param request - the handle.
|
|
167
|
+
* @returns settlement, or a classified failure.
|
|
168
|
+
*/
|
|
169
|
+
previewStop(request: PreviewStopRequest): Promise<PreviewStopResult>;
|
|
170
|
+
/**
|
|
171
|
+
* Read one preview server's output from a caller-owned offset, with its state at read time.
|
|
172
|
+
* @param request - the handle and the offset already rendered.
|
|
173
|
+
* @returns the delta and the state, or a classified failure.
|
|
174
|
+
*/
|
|
175
|
+
previewLogs(request: PreviewLogsRequest): Promise<PreviewLogsResult>;
|
|
176
|
+
/**
|
|
177
|
+
* Read one file for the Files panel preview.
|
|
178
|
+
* @param request - the file and the workspace it must stay inside.
|
|
179
|
+
* @param signal - gateway-supplied cancellation for the caller's abandoned request.
|
|
180
|
+
* @returns the preview, or a classified failure.
|
|
181
|
+
*/
|
|
182
|
+
readFile(request: ReadFileRequest, signal: AbortSignal): Promise<ReadFileResult>;
|
|
183
|
+
/**
|
|
184
|
+
* Hand one path to an external application or to the operating system's file manager.
|
|
185
|
+
* @param request - the target and the path.
|
|
186
|
+
* @param signal - gateway-supplied cancellation for the launch.
|
|
187
|
+
* @returns settlement, or a classified failure.
|
|
188
|
+
*/
|
|
189
|
+
openIn(request: OpenInRequest, signal: AbortSignal): Promise<OpenInResult>;
|
|
190
|
+
/**
|
|
191
|
+
* Stop one live background task.
|
|
192
|
+
* @param request - the owning session and the task id.
|
|
193
|
+
* @returns what the registry did, or a classified failure.
|
|
194
|
+
*/
|
|
195
|
+
taskKill(request: TaskKillRequest): Promise<TaskKillResult>;
|
|
196
|
+
/**
|
|
197
|
+
* Read one settled background task's output.
|
|
198
|
+
* @param request - the owning session and the task id.
|
|
199
|
+
* @returns the accumulated output, or a classified failure.
|
|
200
|
+
*/
|
|
201
|
+
taskOutput(request: TaskOutputRequest): Promise<TaskOutputResult>;
|
|
202
|
+
/**
|
|
203
|
+
* Delete one session: archive it, and remove its durable artifact when the mode and Host allow.
|
|
204
|
+
* @param request - the session to delete.
|
|
205
|
+
* @param signal - gateway-supplied cancellation for the persistence listing.
|
|
206
|
+
* @returns what was actually done, or a classified failure.
|
|
207
|
+
*/
|
|
208
|
+
deleteSession(request: DeleteSessionRequest, signal: AbortSignal): Promise<DeleteSessionResult>;
|
|
209
|
+
}
|
|
210
|
+
export default AdvancedSidebarService;
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Open in submenu's Host half: reveal a path in the operating system's file manager, and launch
|
|
3
|
+
* a configured external application on it.
|
|
4
|
+
*
|
|
5
|
+
* The harness's own `host.openPath` hands a path to its default application, which is the right
|
|
6
|
+
* verb for a directory and the wrong one for a file — a person asking to see a file in Finder does
|
|
7
|
+
* not want it opened in whatever edits `.ts`. This module keeps that distinction: a directory is
|
|
8
|
+
* opened, a file is selected in its folder.
|
|
9
|
+
* @module @achasoft/dsh-advanced-sidebar/host/open-in
|
|
10
|
+
*/
|
|
11
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
12
|
+
import type { AdvancedSidebarSettings, OpenInRequest, OpenInResult, OpenInTargetView } from './types.ts';
|
|
13
|
+
/** Id of the built-in file-manager target; no configured editor may claim it. */
|
|
14
|
+
export declare const REVEAL_TARGET_ID = "reveal";
|
|
15
|
+
/**
|
|
16
|
+
* Launches external applications for the Open in submenu. One instance serves every request and
|
|
17
|
+
* caches each target's resolved executable.
|
|
18
|
+
*/
|
|
19
|
+
export declare class OpenInLauncher {
|
|
20
|
+
private readonly ctx;
|
|
21
|
+
private readonly source;
|
|
22
|
+
private readonly resolved;
|
|
23
|
+
/**
|
|
24
|
+
* @param ctx - Host context carrying the subprocess and filesystem capabilities.
|
|
25
|
+
* @param source - reads the current settings section; called per request so an edited target list
|
|
26
|
+
* reaches the next menu with no registration to rebuild.
|
|
27
|
+
*/
|
|
28
|
+
constructor(ctx: Context, source: () => AdvancedSidebarSettings);
|
|
29
|
+
/**
|
|
30
|
+
* List every target in menu order with its availability.
|
|
31
|
+
*
|
|
32
|
+
* Unavailable targets are listed rather than hidden: a person who configured an editor and does
|
|
33
|
+
* not see it cannot tell a typo in `command` from a menu that simply has no such feature.
|
|
34
|
+
* @param signal - cancellation for the executable lookups.
|
|
35
|
+
* @returns the targets, file manager first.
|
|
36
|
+
*/
|
|
37
|
+
describe(signal?: AbortSignal): Promise<readonly OpenInTargetView[]>;
|
|
38
|
+
/**
|
|
39
|
+
* Hand one path to a target.
|
|
40
|
+
* @param request - which target, and which absolute path.
|
|
41
|
+
* @param signal - cancellation for the launch.
|
|
42
|
+
* @returns settlement, or a classified failure.
|
|
43
|
+
*/
|
|
44
|
+
open(request: OpenInRequest, signal?: AbortSignal): Promise<OpenInResult>;
|
|
45
|
+
/**
|
|
46
|
+
* Show a path in the operating system's file manager.
|
|
47
|
+
* @param target - the canonical path.
|
|
48
|
+
* @param directory - whether the path is a directory (opened) or a file (selected).
|
|
49
|
+
* @param signal - cancellation for the launch.
|
|
50
|
+
* @returns settlement, or a classified failure.
|
|
51
|
+
*/
|
|
52
|
+
private reveal;
|
|
53
|
+
/**
|
|
54
|
+
* The platform's file-manager invocation.
|
|
55
|
+
* @param platform - the Host platform.
|
|
56
|
+
* @param target - the canonical path; omitted while only the executable name is needed.
|
|
57
|
+
* @param directory - whether the path is a directory.
|
|
58
|
+
* @returns the argv and whether a non-zero exit is normal for it.
|
|
59
|
+
*/
|
|
60
|
+
private revealCommand;
|
|
61
|
+
/**
|
|
62
|
+
* Run one launcher and classify its outcome.
|
|
63
|
+
* @param argv - resolved executable and arguments.
|
|
64
|
+
* @param signal - cancellation for the launch.
|
|
65
|
+
* @param tolerateExit - accept a non-zero exit as success (Windows Explorer).
|
|
66
|
+
* @returns settlement, or a classified failure.
|
|
67
|
+
*/
|
|
68
|
+
private launch;
|
|
69
|
+
/**
|
|
70
|
+
* Resolve a file path that is not a directory.
|
|
71
|
+
* @param path - the browser-supplied path.
|
|
72
|
+
* @param signal - cancellation for the resolution.
|
|
73
|
+
* @returns the canonical path, or undefined when nothing is there.
|
|
74
|
+
*/
|
|
75
|
+
private resolveFile;
|
|
76
|
+
/**
|
|
77
|
+
* Whether one command resolves, without reporting why it does not.
|
|
78
|
+
* @param command - executable name or path.
|
|
79
|
+
* @param signal - cancellation for the lookup.
|
|
80
|
+
* @returns true when the command resolves.
|
|
81
|
+
*/
|
|
82
|
+
private available;
|
|
83
|
+
/**
|
|
84
|
+
* Resolve one command once and remember the answer, negative answers included.
|
|
85
|
+
* @param command - executable name or path.
|
|
86
|
+
* @param signal - cancellation for the lookup.
|
|
87
|
+
* @returns the executable path, or undefined when the command is absent.
|
|
88
|
+
* @throws {CommandUnavailableError} when no subprocess capability is mounted.
|
|
89
|
+
*/
|
|
90
|
+
private locate;
|
|
91
|
+
/** Drop every cached lookup, so an edited target list or a newly installed editor is re-probed. */
|
|
92
|
+
forget(): void;
|
|
93
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Path resolution and containment for every endpoint that takes a path from the browser.
|
|
3
|
+
*
|
|
4
|
+
* A browser-supplied path is untrusted input at a process boundary, so each one is resolved through
|
|
5
|
+
* `ctx.fs` and proved to sit inside the workspace it claims to belong to before any command, read,
|
|
6
|
+
* or launch sees it. `..` and symlinks are handled by the filesystem's own canonicalization rather
|
|
7
|
+
* than by string arithmetic here.
|
|
8
|
+
* @module @achasoft/dsh-advanced-sidebar/host/paths
|
|
9
|
+
*/
|
|
10
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
11
|
+
import type { FsTarget } from '@deepseek-ai/dsh-fs';
|
|
12
|
+
/** A resolved, contained path plus the canonical spelling a subprocess can open. */
|
|
13
|
+
export interface ResolvedPath {
|
|
14
|
+
/** The canonical target. */
|
|
15
|
+
readonly target: FsTarget;
|
|
16
|
+
/** Absolute path in the filesystem backend's execution world. */
|
|
17
|
+
readonly processPath: string;
|
|
18
|
+
}
|
|
19
|
+
/** Why a path could not be accepted. */
|
|
20
|
+
export type PathRejection =
|
|
21
|
+
/** No filesystem capability is mounted. */
|
|
22
|
+
{
|
|
23
|
+
readonly code: 'no-filesystem';
|
|
24
|
+
readonly message: string;
|
|
25
|
+
}
|
|
26
|
+
/** The path does not exist, or escaped the workspace it was asked about. */
|
|
27
|
+
| {
|
|
28
|
+
readonly code: 'path-denied';
|
|
29
|
+
readonly message: string;
|
|
30
|
+
};
|
|
31
|
+
/** Either a usable path or the reason it was refused. */
|
|
32
|
+
export type PathOutcome = {
|
|
33
|
+
readonly ok: true;
|
|
34
|
+
readonly value: ResolvedPath;
|
|
35
|
+
} | {
|
|
36
|
+
readonly ok: false;
|
|
37
|
+
readonly rejection: PathRejection;
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* Resolve one absolute directory as a workspace root.
|
|
41
|
+
* @param ctx - Host context carrying the optional filesystem capability.
|
|
42
|
+
* @param path - absolute directory path supplied by the browser.
|
|
43
|
+
* @param signal - cancellation for the backend round-trip.
|
|
44
|
+
* @returns the canonical directory, or the reason it was refused.
|
|
45
|
+
*/
|
|
46
|
+
export declare function resolveWorkspace(ctx: Context, path: string, signal?: AbortSignal): Promise<PathOutcome>;
|
|
47
|
+
/**
|
|
48
|
+
* Resolve one path and prove it sits inside an already-resolved workspace.
|
|
49
|
+
* @param ctx - Host context carrying the optional filesystem capability.
|
|
50
|
+
* @param workspace - the canonical workspace directory the path must stay within.
|
|
51
|
+
* @param path - absolute path supplied by the browser.
|
|
52
|
+
* @param signal - cancellation for the backend round-trip.
|
|
53
|
+
* @returns the canonical path, or the reason it was refused.
|
|
54
|
+
*/
|
|
55
|
+
export declare function resolveInside(ctx: Context, workspace: ResolvedPath, path: string, signal?: AbortSignal): Promise<PathOutcome>;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure parser for `git status --porcelain=v2 --branch -z`.
|
|
3
|
+
*
|
|
4
|
+
* Kept apart from the command runner so the format — which is the only part of the git integration
|
|
5
|
+
* with edge cases worth testing (renames carry two paths, `-z` terminates every line including the
|
|
6
|
+
* headers, and a path may contain any byte but NUL) — is exercised without a subprocess.
|
|
7
|
+
* @module @achasoft/dsh-advanced-sidebar/host/porcelain
|
|
8
|
+
*/
|
|
9
|
+
import type { GitFileChange } from './types.ts';
|
|
10
|
+
/** Branch facts from the `# branch.*` headers, all optional because an unborn branch has none. */
|
|
11
|
+
export interface PorcelainBranch {
|
|
12
|
+
/** Value of `# branch.head`, unless it is the literal `(detached)`. */
|
|
13
|
+
branch?: string;
|
|
14
|
+
/** Value of `# branch.upstream`. */
|
|
15
|
+
upstream?: string;
|
|
16
|
+
/** First figure of `# branch.ab`. */
|
|
17
|
+
ahead: number;
|
|
18
|
+
/** Second figure of `# branch.ab`, as a positive count. */
|
|
19
|
+
behind: number;
|
|
20
|
+
/** True when `# branch.head` is `(detached)`. */
|
|
21
|
+
detached: boolean;
|
|
22
|
+
}
|
|
23
|
+
/** Everything one status reading yields, before the caller groups or truncates it. */
|
|
24
|
+
export interface PorcelainStatus {
|
|
25
|
+
/** Branch position. */
|
|
26
|
+
branch: PorcelainBranch;
|
|
27
|
+
/** Every changed path in git's own order. */
|
|
28
|
+
changes: GitFileChange[];
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Parse one complete `--porcelain=v2 --branch -z` payload.
|
|
32
|
+
*
|
|
33
|
+
* Unknown record types are skipped rather than rejected: git adds record kinds over time, and a
|
|
34
|
+
* reading that lists every change it understood is more useful than one that refuses the whole
|
|
35
|
+
* repository because a future git emitted a line this parser has not met.
|
|
36
|
+
* @param payload - git's stdout, verbatim.
|
|
37
|
+
* @returns the branch facts and every parsed change.
|
|
38
|
+
*/
|
|
39
|
+
export declare function parsePorcelainV2(payload: string): PorcelainStatus;
|
|
40
|
+
/**
|
|
41
|
+
* Whether a change belongs in the staged group — its index state differs from HEAD.
|
|
42
|
+
* @param change - one parsed change.
|
|
43
|
+
* @returns true when a commit right now would record something for this path.
|
|
44
|
+
*/
|
|
45
|
+
export declare function isStaged(change: GitFileChange): boolean;
|
|
46
|
+
/**
|
|
47
|
+
* Whether a change belongs in the unstaged group — its working tree differs from the index.
|
|
48
|
+
* @param change - one parsed change.
|
|
49
|
+
* @returns true when the path has edits no commit would record yet.
|
|
50
|
+
*/
|
|
51
|
+
export declare function isUnstaged(change: GitFileChange): boolean;
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Preview servers: the Host half of the Preview panel.
|
|
3
|
+
*
|
|
4
|
+
* A person looking at a running application needs three things the browser cannot do for itself —
|
|
5
|
+
* start the process, know when its port is actually accepting, and read what it printed. This
|
|
6
|
+
* module owns all three, plus the merge of where configurations come from.
|
|
7
|
+
*
|
|
8
|
+
* Configurations are read from the workspace's own `.claude/launch.json` first and from the
|
|
9
|
+
* `previews` settings rows second, and a name declared in both is taken from the file. That order
|
|
10
|
+
* is the point: a repository already carrying that file gets a working panel with nothing else to
|
|
11
|
+
* write, and it stays the authority on how to run itself when a deployment also configures a row.
|
|
12
|
+
*
|
|
13
|
+
* Readiness is a TCP connect to the configured port, retried until it accepts or the deadline
|
|
14
|
+
* passes. An HTTP probe would need a path, a method, and an opinion about which status codes count;
|
|
15
|
+
* a listening socket is the one fact every dev server agrees on.
|
|
16
|
+
* @module @achasoft/dsh-advanced-sidebar/host/preview
|
|
17
|
+
*/
|
|
18
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
19
|
+
import type { AdvancedSidebarSettings, CapabilityState, PreviewLaunch, PreviewListRequest, PreviewListResult, PreviewLogsRequest, PreviewLogsResult, PreviewOrigin, PreviewStartRequest, PreviewStartResult, PreviewStopRequest, PreviewStopResult } from './types.ts';
|
|
20
|
+
/** One configuration plus where it was read from. */
|
|
21
|
+
interface Resolved {
|
|
22
|
+
/** The configuration. */
|
|
23
|
+
readonly launch: PreviewLaunch;
|
|
24
|
+
/** Which file it came from. */
|
|
25
|
+
readonly origin: PreviewOrigin;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Read one launch file's configurations.
|
|
29
|
+
*
|
|
30
|
+
* A malformed file is reported rather than thrown: the panel still lists the settings rows and says
|
|
31
|
+
* why the file was ignored, which is more useful than a Preview entry that refuses to open.
|
|
32
|
+
* @param text - the file's contents.
|
|
33
|
+
* @returns the configurations, or the reason the file was ignored.
|
|
34
|
+
*/
|
|
35
|
+
export declare function parseLaunchFile(text: string): {
|
|
36
|
+
launches: PreviewLaunch[];
|
|
37
|
+
} | {
|
|
38
|
+
error: string;
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* Merge a workspace's launch file with the settings rows.
|
|
42
|
+
*
|
|
43
|
+
* The file wins a name collision: a repository stating how to run itself outranks a deployment-wide
|
|
44
|
+
* default that happens to use the same name.
|
|
45
|
+
* @param fromFile - configurations read from `.claude/launch.json`.
|
|
46
|
+
* @param fromSettings - configurations from the `previews` settings rows.
|
|
47
|
+
* @returns the merged list, file rows first.
|
|
48
|
+
*/
|
|
49
|
+
export declare function mergeLaunches(fromFile: readonly PreviewLaunch[], fromSettings: readonly PreviewLaunch[]): Resolved[];
|
|
50
|
+
/**
|
|
51
|
+
* Owns every preview server in the process. One instance is created by the service and disposed
|
|
52
|
+
* with it, which is what guarantees no dev server outlives the plugin.
|
|
53
|
+
*/
|
|
54
|
+
export declare class PreviewServers {
|
|
55
|
+
private readonly ctx;
|
|
56
|
+
private readonly source;
|
|
57
|
+
private readonly records;
|
|
58
|
+
/**
|
|
59
|
+
* Configurations with a start already in flight, keyed `<workspace>\u0000<name>`.
|
|
60
|
+
*
|
|
61
|
+
* `start()` awaits a file read, a path resolution, and an executable lookup before it registers
|
|
62
|
+
* anything, so two starts of one row would both find no predecessor and both spawn — leaving a
|
|
63
|
+
* dev server on the port that no `serverId` any panel holds can ever stop.
|
|
64
|
+
*/
|
|
65
|
+
private readonly starting;
|
|
66
|
+
private closing;
|
|
67
|
+
/**
|
|
68
|
+
* @param ctx - Host context carrying the subprocess and filesystem capabilities.
|
|
69
|
+
* @param source - reads the current settings section; called per request.
|
|
70
|
+
*/
|
|
71
|
+
constructor(ctx: Context, source: () => AdvancedSidebarSettings);
|
|
72
|
+
/**
|
|
73
|
+
* Report whether a preview server can be started on this Host.
|
|
74
|
+
* @returns availability plus how many servers are already running.
|
|
75
|
+
*/
|
|
76
|
+
describe(): CapabilityState & {
|
|
77
|
+
running: number;
|
|
78
|
+
};
|
|
79
|
+
/**
|
|
80
|
+
* List one workspace's configurations, each with its current state.
|
|
81
|
+
* @param request - the workspace to read.
|
|
82
|
+
* @param signal - cancellation for the file read.
|
|
83
|
+
* @returns the list, or a classified failure.
|
|
84
|
+
*/
|
|
85
|
+
list(request: PreviewListRequest, signal?: AbortSignal): Promise<PreviewListResult>;
|
|
86
|
+
/**
|
|
87
|
+
* Start one configuration.
|
|
88
|
+
* @param request - the workspace and the configuration name.
|
|
89
|
+
* @param signal - cancellation of the start itself; a started server owns its later lifetime.
|
|
90
|
+
* @returns the started row, or a classified failure.
|
|
91
|
+
*/
|
|
92
|
+
start(request: PreviewStartRequest, signal?: AbortSignal): Promise<PreviewStartResult>;
|
|
93
|
+
/**
|
|
94
|
+
* Start one validated configuration, holding its in-flight claim.
|
|
95
|
+
* @param workspace - the resolved workspace.
|
|
96
|
+
* @param launch - the configuration, already known to name a command.
|
|
97
|
+
* @param origin - which file it came from.
|
|
98
|
+
* @param signal - cancellation of the start.
|
|
99
|
+
* @returns the started row, or a classified failure.
|
|
100
|
+
*/
|
|
101
|
+
private spawn;
|
|
102
|
+
/**
|
|
103
|
+
* Stop one server and forget it.
|
|
104
|
+
* @param request - the handle.
|
|
105
|
+
* @returns settlement, or a classified failure.
|
|
106
|
+
*/
|
|
107
|
+
stop(request: PreviewStopRequest): Promise<PreviewStopResult>;
|
|
108
|
+
/**
|
|
109
|
+
* Read one server's output from a caller-owned offset, with its state at read time.
|
|
110
|
+
* @param request - the handle and the offset already rendered.
|
|
111
|
+
* @returns the delta and the state, or a classified failure.
|
|
112
|
+
*/
|
|
113
|
+
logs(request: PreviewLogsRequest): PreviewLogsResult;
|
|
114
|
+
/**
|
|
115
|
+
* Terminate every server and refuse new ones. Called from the service's teardown effect.
|
|
116
|
+
* @returns after every process tree has exited.
|
|
117
|
+
*/
|
|
118
|
+
disposeAll(): Promise<void>;
|
|
119
|
+
/**
|
|
120
|
+
* The `previews` settings rows, normalized into the shape the merge reads.
|
|
121
|
+
* @returns the configured launches.
|
|
122
|
+
*/
|
|
123
|
+
private settingsLaunches;
|
|
124
|
+
/**
|
|
125
|
+
* Read and parse the workspace's launch file.
|
|
126
|
+
* @param workspace - the resolved workspace.
|
|
127
|
+
* @param signal - cancellation for the read.
|
|
128
|
+
* @returns the configurations, the file's path when it existed, and why it was ignored when it was.
|
|
129
|
+
*/
|
|
130
|
+
private readLaunchFile;
|
|
131
|
+
/**
|
|
132
|
+
* Resolve the directory one configuration runs in, proving it stays inside the workspace.
|
|
133
|
+
* @param workspace - the resolved workspace.
|
|
134
|
+
* @param launch - the configuration.
|
|
135
|
+
* @param signal - cancellation for the resolution.
|
|
136
|
+
* @returns the directory, or the failure to return.
|
|
137
|
+
*/
|
|
138
|
+
private launchDirectory;
|
|
139
|
+
/**
|
|
140
|
+
* Watch one process for its exit.
|
|
141
|
+
* @param record - the started server.
|
|
142
|
+
*/
|
|
143
|
+
private watch;
|
|
144
|
+
/**
|
|
145
|
+
* Probe one server's port until it accepts or the deadline passes.
|
|
146
|
+
* @param record - the started server.
|
|
147
|
+
*/
|
|
148
|
+
private awaitReady;
|
|
149
|
+
/**
|
|
150
|
+
* Move whatever the collected streams hold into the retained buffer.
|
|
151
|
+
*
|
|
152
|
+
* Both streams share one buffer and one offset, because the panel shows one log: a dev server
|
|
153
|
+
* prints its banner on one and its errors on the other, and two independently scrolling views of
|
|
154
|
+
* the same startup would be harder to read, not easier.
|
|
155
|
+
* @param record - the server to drain.
|
|
156
|
+
*/
|
|
157
|
+
private drain;
|
|
158
|
+
/**
|
|
159
|
+
* Find a live record for one workspace and configuration name.
|
|
160
|
+
* @param workspace - canonical workspace path.
|
|
161
|
+
* @param name - configuration name.
|
|
162
|
+
* @returns the record, when one exists.
|
|
163
|
+
*/
|
|
164
|
+
private find;
|
|
165
|
+
/**
|
|
166
|
+
* Stop one process tree without letting a cleanup fault escape.
|
|
167
|
+
* @param record - the server to stop.
|
|
168
|
+
* @returns after the tree has exited.
|
|
169
|
+
*/
|
|
170
|
+
private terminate;
|
|
171
|
+
/**
|
|
172
|
+
* Project one configuration into its view, attaching a live record when one exists.
|
|
173
|
+
* @param resolved - the configuration and its origin.
|
|
174
|
+
* @param workspace - canonical workspace path.
|
|
175
|
+
* @returns the view.
|
|
176
|
+
*/
|
|
177
|
+
private view;
|
|
178
|
+
/**
|
|
179
|
+
* Project one live record into its view.
|
|
180
|
+
* @param record - the server.
|
|
181
|
+
* @returns the view.
|
|
182
|
+
*/
|
|
183
|
+
private viewOf;
|
|
184
|
+
}
|
|
185
|
+
export {};
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One-shot command execution over `ctx.subprocess`, shared by the git reader and the Open in
|
|
3
|
+
* launcher.
|
|
4
|
+
*
|
|
5
|
+
* The subprocess seam applies no defaults, so every disposition, bound, and grace period is stated
|
|
6
|
+
* here from this plugin's own settings — which is also what keeps the two callers' behavior
|
|
7
|
+
* configurable from cordis.yml rather than from constants buried in a runner.
|
|
8
|
+
* @module @achasoft/dsh-advanced-sidebar/host/run
|
|
9
|
+
*/
|
|
10
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
11
|
+
/** Everything one invocation needs; nothing is defaulted. */
|
|
12
|
+
export interface CommandSpec {
|
|
13
|
+
/** Executable and arguments; `argv[0]` is a resolved executable path. */
|
|
14
|
+
readonly argv: readonly string[];
|
|
15
|
+
/** Working directory. */
|
|
16
|
+
readonly cwd: string;
|
|
17
|
+
/** Wall-clock bound; exceeding it terminates the process tree. */
|
|
18
|
+
readonly timeoutMs: number;
|
|
19
|
+
/** In-memory cap per stream, in bytes; overflow keeps the tail. */
|
|
20
|
+
readonly maxBytes: number;
|
|
21
|
+
/** TERM-to-KILL grace for the termination escalation. */
|
|
22
|
+
readonly graceMs: number;
|
|
23
|
+
/** Explicit environment entries layered over the provider's scrubbed base. */
|
|
24
|
+
readonly env?: Record<string, string>;
|
|
25
|
+
}
|
|
26
|
+
/** Exit facts and collected output of one finished command. */
|
|
27
|
+
export interface CommandOutcome {
|
|
28
|
+
/** Exit code; null when the process died from a signal. */
|
|
29
|
+
readonly exitCode: number | null;
|
|
30
|
+
/** Terminating signal; null on a normal exit. */
|
|
31
|
+
readonly signal: string | null;
|
|
32
|
+
/** Collected stdout. */
|
|
33
|
+
readonly stdout: string;
|
|
34
|
+
/** Collected stderr. */
|
|
35
|
+
readonly stderr: string;
|
|
36
|
+
/** True when the command was stopped by {@link CommandSpec.timeoutMs}. */
|
|
37
|
+
readonly timedOut: boolean;
|
|
38
|
+
/** True when the caller's own signal aborted the command. */
|
|
39
|
+
readonly aborted: boolean;
|
|
40
|
+
/**
|
|
41
|
+
* True when stdout exceeded {@link CommandSpec.maxBytes} and only its TAIL was retained.
|
|
42
|
+
*
|
|
43
|
+
* Reported rather than swallowed because it changes what the text means: a caller that then takes
|
|
44
|
+
* the head of this string is showing the middle of the real output, and would label it complete.
|
|
45
|
+
*/
|
|
46
|
+
readonly stdoutLossy: boolean;
|
|
47
|
+
}
|
|
48
|
+
/** No filesystem/subprocess capability, or a spawn that never produced a process. */
|
|
49
|
+
export declare class CommandUnavailableError extends Error {
|
|
50
|
+
/**
|
|
51
|
+
* @param message - operator diagnostic naming what was missing.
|
|
52
|
+
*/
|
|
53
|
+
constructor(message: string);
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Resolve one executable, returning undefined rather than throwing when it is absent.
|
|
57
|
+
* @param ctx - Host context carrying the optional subprocess capability.
|
|
58
|
+
* @param command - executable name or absolute path.
|
|
59
|
+
* @param signal - cancellation for the lookup.
|
|
60
|
+
* @returns the canonical executable path, or undefined when it does not resolve.
|
|
61
|
+
* @throws {CommandUnavailableError} when no subprocess capability is mounted.
|
|
62
|
+
*/
|
|
63
|
+
export declare function resolveCommand(ctx: Context, command: string, signal?: AbortSignal): Promise<string | undefined>;
|
|
64
|
+
/**
|
|
65
|
+
* Run one command to completion under a timeout.
|
|
66
|
+
* @param ctx - Host context carrying the optional subprocess capability.
|
|
67
|
+
* @param spec - the fully specified invocation.
|
|
68
|
+
* @param signal - the caller's cancellation, distinguished from the timeout in the outcome.
|
|
69
|
+
* @returns exit facts and collected output.
|
|
70
|
+
* @throws {CommandUnavailableError} when no subprocess capability is mounted.
|
|
71
|
+
*/
|
|
72
|
+
export declare function runCommand(ctx: Context, spec: CommandSpec, signal?: AbortSignal): Promise<CommandOutcome>;
|