dsh-easygit-plugin 0.2.1 → 0.2.2
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/README.md +13 -6
- package/README.zh-CN.md +13 -6
- package/lib/client.js +531 -21
- package/lib/index.js +355 -23
- package/lib/types/client/index.d.ts +9 -1
- package/lib/types/client/view-model.d.ts +12 -1
- package/lib/types/host/actions.d.ts +6 -4
- package/lib/types/host/git-repository-service.d.ts +11 -2
- package/lib/types/host/plugin.d.ts +22 -2
- package/lib/types/host/proposal-service.d.ts +2 -1
- package/lib/types/shared/contracts.d.ts +93 -6
- package/package.json +2 -1
|
@@ -18,14 +18,15 @@ interface ProposalVerification {
|
|
|
18
18
|
message: string;
|
|
19
19
|
changedState: string;
|
|
20
20
|
}
|
|
21
|
+
interface RepositoryContext {
|
|
22
|
+
workdir: string;
|
|
23
|
+
policy: unknown;
|
|
24
|
+
}
|
|
21
25
|
interface EasyGitActionDependencies {
|
|
22
26
|
repository: GitRepositoryService;
|
|
23
27
|
proposalStorageReady: Promise<void>;
|
|
24
28
|
shell: ShellService | null;
|
|
25
|
-
repositoryContext(sessionId: string):
|
|
26
|
-
workdir: string;
|
|
27
|
-
policy: unknown;
|
|
28
|
-
} | null;
|
|
29
|
+
repositoryContext(sessionId: string): RepositoryContext | null;
|
|
29
30
|
latestPending(sessionId: string): StoredProposal | null;
|
|
30
31
|
findProposal(sessionId: string, proposalId: unknown): StoredProposal | undefined;
|
|
31
32
|
proposalView(proposal: StoredProposal): ProposalView;
|
|
@@ -34,6 +35,7 @@ interface EasyGitActionDependencies {
|
|
|
34
35
|
runChecks(shell: ShellService | null, workdir: string, checks: ReturnType<typeof deriveChecks>): Promise<string[]>;
|
|
35
36
|
verifyProposal(shell: ShellService | null, proposal: StoredProposal): Promise<ProposalVerification>;
|
|
36
37
|
executeProposal(shell: ShellService | null, proposal: StoredProposal, policy: unknown, persist: () => Promise<void>): Promise<UnknownRecord>;
|
|
38
|
+
recoverFailedCommand(sessionId: string, workdir: string, operationId: string, action: string, command: string, message: string, errorOutput: string, errorCode: string, reason: string): Promise<UnknownRecord | null>;
|
|
37
39
|
resolveExecutionPolicy(sessionId: string): unknown;
|
|
38
40
|
}
|
|
39
41
|
/** Register the Client-to-Host POST dispatcher with a 1 MiB body limit. */
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { ActionResult, CommitDetail, CommitDiffResult, CommitSummary, DiffResult, RepositoryReferences, RepositorySummary, StashSummary } from '../shared/contracts';
|
|
2
|
-
export type { BranchSummary, CommitDetail, CommitDiffResult, CommitFileChange, CommitRefSummary, CommitSummary, DiffResult, ReferenceSummary, RepositoryFile, RepositoryReferences, RepositorySummary, StashSummary, } from '../shared/contracts';
|
|
1
|
+
import type { ActionResult, CommitDetail, CommitDiffResult, CommitSummary, DiffResult, RepositoryReferences, RepositorySummary, StashSummary, SyncState } from '../shared/contracts';
|
|
2
|
+
export type { BranchSummary, CommitDetail, CommitDiffResult, CommitFileChange, CommitRefSummary, CommitSummary, DiffResult, ReferenceSummary, RepositoryFile, RepositoryReferences, RepositorySummary, StashSummary, SyncState, } from '../shared/contracts';
|
|
3
3
|
export interface GitRunResult {
|
|
4
4
|
exitCode: number | null;
|
|
5
5
|
signal?: string | null;
|
|
@@ -39,6 +39,13 @@ export declare class GitRepositoryService {
|
|
|
39
39
|
getCommitDetail(workdir: string, hash: unknown, signal?: AbortSignal, sandboxPolicy?: unknown): Promise<ActionResult<CommitDetail>>;
|
|
40
40
|
getCommitDiff(workdir: string, hash: unknown, signal?: AbortSignal, sandboxPolicy?: unknown): Promise<ActionResult<CommitDiffResult>>;
|
|
41
41
|
getStashes(workdir: string, signal?: AbortSignal, sandboxPolicy?: unknown): Promise<ActionResult<StashSummary[]>>;
|
|
42
|
+
getSyncState(workdir: string, signal?: AbortSignal, sandboxPolicy?: unknown): Promise<ActionResult<SyncState>>;
|
|
43
|
+
fetchRemote(request: MutationRequest, remote: unknown): Promise<ActionResult<SyncState>>;
|
|
44
|
+
pullFfOnly(request: MutationRequest): Promise<ActionResult<SyncState>>;
|
|
45
|
+
pushCurrent(request: MutationRequest, remote: unknown, branch: unknown, setUpstream: boolean): Promise<ActionResult<SyncState>>;
|
|
46
|
+
rebaseOnto(request: MutationRequest, target: unknown, confirmRisk: boolean): Promise<ActionResult<SyncState>>;
|
|
47
|
+
continueRebase(request: MutationRequest, confirmRisk: boolean): Promise<ActionResult<SyncState>>;
|
|
48
|
+
abortRebase(request: MutationRequest, confirmRisk: boolean): Promise<ActionResult<SyncState>>;
|
|
42
49
|
stagePaths(request: MutationRequest, paths: unknown): Promise<ActionResult<RepositorySummary>>;
|
|
43
50
|
unstagePaths(request: MutationRequest, paths: unknown): Promise<ActionResult<RepositorySummary>>;
|
|
44
51
|
stageAll(request: MutationRequest): Promise<ActionResult<RepositorySummary>>;
|
|
@@ -49,5 +56,7 @@ export declare class GitRepositoryService {
|
|
|
49
56
|
deleteBranch(request: MutationRequest, name: unknown, force: boolean, confirmRisk: boolean): Promise<ActionResult<RepositorySummary>>;
|
|
50
57
|
private validatePaths;
|
|
51
58
|
private mutate;
|
|
59
|
+
private mutateSync;
|
|
60
|
+
private mutateAndRead;
|
|
52
61
|
private pruneOperations;
|
|
53
62
|
}
|
|
@@ -8,8 +8,9 @@
|
|
|
8
8
|
* The exposed model tools are git_propose and git_repo_state. Repository changes
|
|
9
9
|
* are only available through the Client action route.
|
|
10
10
|
*/
|
|
11
|
+
import type { GitFailureContext } from '../shared/contracts';
|
|
11
12
|
import { ProposalService, type ProposalView, type StoredProposal } from './proposal-service';
|
|
12
|
-
import { type ShellService } from './git-repository-service';
|
|
13
|
+
import { GitRepositoryService, type ShellService } from './git-repository-service';
|
|
13
14
|
import { addPathsOf, classifyRisk, classifyStepsRisk, deriveChecks, modernizeCommand, parseCommand, quoteShellArg, redactAndLimit, redactSecrets, validateCommand, type ExpectedCheck } from './command-policy';
|
|
14
15
|
type UnknownRecord = Record<string, unknown>;
|
|
15
16
|
interface HostContext {
|
|
@@ -32,11 +33,15 @@ interface ProposalExecutionResult extends UnknownRecord {
|
|
|
32
33
|
stdout: string;
|
|
33
34
|
stderr: string;
|
|
34
35
|
diagnostics: string;
|
|
36
|
+
failure?: GitFailureContext;
|
|
35
37
|
recovery?: {
|
|
36
38
|
suggestion: string;
|
|
37
39
|
command: string;
|
|
38
40
|
proposalId: string | null;
|
|
39
41
|
} | null;
|
|
42
|
+
analysis?: {
|
|
43
|
+
proposalId: string;
|
|
44
|
+
};
|
|
40
45
|
error: string;
|
|
41
46
|
}
|
|
42
47
|
interface ProposalVerification {
|
|
@@ -69,8 +74,20 @@ declare function executeRegisteredProposal(shell: ShellService | null | undefine
|
|
|
69
74
|
* A null command means the condition requires manual remediation.
|
|
70
75
|
*/
|
|
71
76
|
declare function buildRecovery(_proposal: StoredProposal, failedStep: StoredProposal['steps'][number] | undefined, diagnostics: string): RecoverySuggestion | null;
|
|
77
|
+
declare function buildRecoveryForCommand(cmd: string, text: string, reason?: string): RecoverySuggestion | null;
|
|
78
|
+
declare function recoverFailedCommand(activeShell: ShellService | null | undefined, sessionId: string, workdir: string, operationId: string, action: string, command: string, message: string, errorOutput: string, errorCode: string, reason: string): Promise<{
|
|
79
|
+
failure: GitFailureContext;
|
|
80
|
+
recovery?: {
|
|
81
|
+
suggestion: string;
|
|
82
|
+
command: string;
|
|
83
|
+
proposalId: string | null;
|
|
84
|
+
};
|
|
85
|
+
analysis?: {
|
|
86
|
+
proposalId: string;
|
|
87
|
+
};
|
|
88
|
+
} | null>;
|
|
72
89
|
/** Register a recovery command as a pending proposal in the same session. */
|
|
73
|
-
declare function registerRecoveryProposal(failedProposal: Pick<StoredProposal, 'sessionId' | 'workdir'>, recovery: RecoverySuggestion): StoredProposal | null;
|
|
90
|
+
declare function registerRecoveryProposal(failedProposal: Pick<StoredProposal, 'sessionId' | 'workdir'>, recovery: RecoverySuggestion, failure?: GitFailureContext): StoredProposal | null;
|
|
74
91
|
declare function storeProposal(sessionId: string, proposal: StoredProposal): StoredProposal;
|
|
75
92
|
declare function findProposal(sessionId: string, proposalId: unknown): StoredProposal | undefined;
|
|
76
93
|
declare function proposalView(proposal: StoredProposal): ProposalView;
|
|
@@ -98,12 +115,15 @@ declare const _default: {
|
|
|
98
115
|
executeProposalSteps: typeof executeProposalSteps;
|
|
99
116
|
executeRegisteredProposal: typeof executeRegisteredProposal;
|
|
100
117
|
buildRecovery: typeof buildRecovery;
|
|
118
|
+
buildRecoveryForCommand: typeof buildRecoveryForCommand;
|
|
119
|
+
recoverFailedCommand: typeof recoverFailedCommand;
|
|
101
120
|
registerRecoveryProposal: typeof registerRecoveryProposal;
|
|
102
121
|
storeProposal: typeof storeProposal;
|
|
103
122
|
findProposal: typeof findProposal;
|
|
104
123
|
proposalView: typeof proposalView;
|
|
105
124
|
latestPending: typeof latestPending;
|
|
106
125
|
ProposalService: typeof ProposalService;
|
|
126
|
+
GitRepositoryService: typeof GitRepositoryService;
|
|
107
127
|
};
|
|
108
128
|
};
|
|
109
129
|
export = _default;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ProposalStatus, ProposalView } from '../shared/contracts';
|
|
1
|
+
import type { GitFailureContext, ProposalStatus, ProposalView } from '../shared/contracts';
|
|
2
2
|
export type { ProposalView } from '../shared/contracts';
|
|
3
3
|
import type { RiskLevel } from './command-policy';
|
|
4
4
|
export interface ProposalStep {
|
|
@@ -23,6 +23,7 @@ export interface StoredProposal {
|
|
|
23
23
|
fingerprint: string | null;
|
|
24
24
|
verified: boolean;
|
|
25
25
|
result: Record<string, unknown> | null;
|
|
26
|
+
failure?: GitFailureContext;
|
|
26
27
|
[key: string]: unknown;
|
|
27
28
|
}
|
|
28
29
|
export interface ProposalStorageUnit {
|
|
@@ -1,7 +1,29 @@
|
|
|
1
1
|
/** Shared Client-to-Host contracts. */
|
|
2
2
|
export type ProposalStatus = 'pending' | 'running' | 'succeeded' | 'failed' | 'verified' | 'dismissed';
|
|
3
3
|
export type ActionErrorCode = 'NOT_GIT_REPOSITORY' | 'SESSION_NOT_FOUND' | 'INVALID_ARGUMENT' | 'STATE_CONFLICT' | 'OPERATION_DUPLICATE' | 'GIT_FAILED' | 'TIMEOUT' | 'PERMISSION_DENIED' | 'INTERNAL_ERROR';
|
|
4
|
-
export type ActionFailureReason = 'CURRENT_BRANCH' | 'BRANCH_NOT_FOUND' | 'UNMERGED_BRANCH';
|
|
4
|
+
export type ActionFailureReason = 'CURRENT_BRANCH' | 'BRANCH_NOT_FOUND' | 'BRANCH_EXISTS' | 'UNMERGED_BRANCH' | 'NO_REMOTE' | 'NO_UPSTREAM' | 'DETACHED_HEAD' | 'DIRTY_WORKTREE' | 'CONFLICTS_PRESENT' | 'REBASE_IN_PROGRESS' | 'NO_REBASE_IN_PROGRESS' | 'REF_NOT_FOUND';
|
|
5
|
+
export interface GitFailureContext {
|
|
6
|
+
source: 'workbench' | 'proposal';
|
|
7
|
+
code: string;
|
|
8
|
+
action: string;
|
|
9
|
+
command: string;
|
|
10
|
+
message: string;
|
|
11
|
+
stdout: string;
|
|
12
|
+
stderr: string;
|
|
13
|
+
diagnostics: string;
|
|
14
|
+
exitCode: number | null;
|
|
15
|
+
timedOut: boolean;
|
|
16
|
+
mayHavePartialChanges: boolean;
|
|
17
|
+
occurredAt: number;
|
|
18
|
+
}
|
|
19
|
+
export interface RecoveryProposal {
|
|
20
|
+
suggestion: string;
|
|
21
|
+
command: string;
|
|
22
|
+
proposalId: string | null;
|
|
23
|
+
}
|
|
24
|
+
export interface AgentAnalysisRequest {
|
|
25
|
+
proposalId: string;
|
|
26
|
+
}
|
|
5
27
|
export type ActionResult<T> = {
|
|
6
28
|
ok: true;
|
|
7
29
|
data: T;
|
|
@@ -12,6 +34,9 @@ export type ActionResult<T> = {
|
|
|
12
34
|
message: string;
|
|
13
35
|
diagnostics?: string;
|
|
14
36
|
reason?: ActionFailureReason;
|
|
37
|
+
failure?: GitFailureContext;
|
|
38
|
+
recovery?: RecoveryProposal;
|
|
39
|
+
analysis?: AgentAnalysisRequest;
|
|
15
40
|
};
|
|
16
41
|
export interface RepositoryFile {
|
|
17
42
|
indexStatus: string;
|
|
@@ -27,6 +52,19 @@ export interface RepositorySummary {
|
|
|
27
52
|
files: RepositoryFile[];
|
|
28
53
|
stagedCount: number;
|
|
29
54
|
}
|
|
55
|
+
export interface SyncState {
|
|
56
|
+
topLevel: string;
|
|
57
|
+
branch: string;
|
|
58
|
+
head: string;
|
|
59
|
+
upstream: string;
|
|
60
|
+
remotes: string[];
|
|
61
|
+
ahead: number;
|
|
62
|
+
behind: number;
|
|
63
|
+
dirty: boolean;
|
|
64
|
+
conflictCount: number;
|
|
65
|
+
rebaseInProgress: boolean;
|
|
66
|
+
files: RepositoryFile[];
|
|
67
|
+
}
|
|
30
68
|
export interface BranchSummary {
|
|
31
69
|
name: string;
|
|
32
70
|
current: boolean;
|
|
@@ -120,6 +158,10 @@ export interface ProposalView {
|
|
|
120
158
|
result: Record<string, unknown> | null;
|
|
121
159
|
closed: boolean;
|
|
122
160
|
copied: boolean;
|
|
161
|
+
failure?: GitFailureContext;
|
|
162
|
+
recoverySuggestion?: string;
|
|
163
|
+
needsAgentAnalysis?: boolean;
|
|
164
|
+
analysisRequestedAt?: number;
|
|
123
165
|
}
|
|
124
166
|
export type ProposalStateResponse = {
|
|
125
167
|
ok: true;
|
|
@@ -156,11 +198,9 @@ export interface ProposalExecutionResponse extends ProposalCommandResponse {
|
|
|
156
198
|
stdout?: string;
|
|
157
199
|
stderr?: string;
|
|
158
200
|
diagnostics?: string;
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
proposalId: string | null;
|
|
163
|
-
} | null;
|
|
201
|
+
failure?: GitFailureContext;
|
|
202
|
+
recovery?: RecoveryProposal | null;
|
|
203
|
+
analysis?: AgentAnalysisRequest;
|
|
164
204
|
}
|
|
165
205
|
export interface EasyGitRequestMap {
|
|
166
206
|
'get-summary': {
|
|
@@ -189,6 +229,9 @@ export interface EasyGitRequestMap {
|
|
|
189
229
|
'get-stashes': {
|
|
190
230
|
sessionId: string;
|
|
191
231
|
};
|
|
232
|
+
'get-sync-state': {
|
|
233
|
+
sessionId: string;
|
|
234
|
+
};
|
|
192
235
|
'stage-paths': {
|
|
193
236
|
sessionId: string;
|
|
194
237
|
operationId: string;
|
|
@@ -230,6 +273,42 @@ export interface EasyGitRequestMap {
|
|
|
230
273
|
force?: boolean;
|
|
231
274
|
confirmRisk?: boolean;
|
|
232
275
|
};
|
|
276
|
+
fetch: {
|
|
277
|
+
sessionId: string;
|
|
278
|
+
operationId: string;
|
|
279
|
+
remote: string;
|
|
280
|
+
};
|
|
281
|
+
pull: {
|
|
282
|
+
sessionId: string;
|
|
283
|
+
operationId: string;
|
|
284
|
+
};
|
|
285
|
+
push: {
|
|
286
|
+
sessionId: string;
|
|
287
|
+
operationId: string;
|
|
288
|
+
remote?: string;
|
|
289
|
+
branch?: string;
|
|
290
|
+
setUpstream?: boolean;
|
|
291
|
+
};
|
|
292
|
+
rebase: {
|
|
293
|
+
sessionId: string;
|
|
294
|
+
operationId: string;
|
|
295
|
+
target: string;
|
|
296
|
+
confirmRisk?: boolean;
|
|
297
|
+
};
|
|
298
|
+
'rebase-continue': {
|
|
299
|
+
sessionId: string;
|
|
300
|
+
operationId: string;
|
|
301
|
+
confirmRisk?: boolean;
|
|
302
|
+
};
|
|
303
|
+
'rebase-abort': {
|
|
304
|
+
sessionId: string;
|
|
305
|
+
operationId: string;
|
|
306
|
+
confirmRisk?: boolean;
|
|
307
|
+
};
|
|
308
|
+
'request-analysis': {
|
|
309
|
+
sessionId: string;
|
|
310
|
+
proposalId: string;
|
|
311
|
+
};
|
|
233
312
|
state: {
|
|
234
313
|
sessionId: string;
|
|
235
314
|
};
|
|
@@ -261,6 +340,7 @@ export interface EasyGitResponseMap {
|
|
|
261
340
|
'get-commit-detail': ActionResult<CommitDetail>;
|
|
262
341
|
'get-commit-diff': ActionResult<CommitDiffResult>;
|
|
263
342
|
'get-stashes': ActionResult<StashSummary[]>;
|
|
343
|
+
'get-sync-state': ActionResult<SyncState>;
|
|
264
344
|
'stage-paths': ActionResult<RepositorySummary>;
|
|
265
345
|
'unstage-paths': ActionResult<RepositorySummary>;
|
|
266
346
|
'stage-all': ActionResult<RepositorySummary>;
|
|
@@ -269,6 +349,13 @@ export interface EasyGitResponseMap {
|
|
|
269
349
|
'create-branch': ActionResult<RepositorySummary>;
|
|
270
350
|
'switch-branch': ActionResult<RepositorySummary>;
|
|
271
351
|
'delete-branch': ActionResult<RepositorySummary>;
|
|
352
|
+
fetch: ActionResult<SyncState>;
|
|
353
|
+
pull: ActionResult<SyncState>;
|
|
354
|
+
push: ActionResult<SyncState>;
|
|
355
|
+
rebase: ActionResult<SyncState>;
|
|
356
|
+
'rebase-continue': ActionResult<SyncState>;
|
|
357
|
+
'rebase-abort': ActionResult<SyncState>;
|
|
358
|
+
'request-analysis': ProposalCommandResponse;
|
|
272
359
|
state: ProposalStateResponse;
|
|
273
360
|
dismiss: ProposalCommandResponse;
|
|
274
361
|
'mark-copied': ProposalCommandResponse;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-easygit-plugin",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"description": "面向 DeepSeek Harness Web 的可视化 Git 工作台,支持查看仓库状态与提交记录、快捷执行常用 Git 操作,以及安全运行自然语言生成的分步骤命令提议。",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "lib/index.js",
|
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
"platform": "web",
|
|
25
25
|
"inject": [
|
|
26
26
|
"@deepseek-ai/dsh-client-runtime",
|
|
27
|
+
"@deepseek-ai/dsh-client-connection",
|
|
27
28
|
"@deepseek-ai/dsh-client-ui-conversation",
|
|
28
29
|
"@deepseek-ai/dsh-client-ui-layout"
|
|
29
30
|
]
|