@build-astron-co/nimbus 0.2.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 +628 -0
- package/bin/nimbus +38 -0
- package/package.json +80 -0
- package/src/__tests__/app.test.ts +76 -0
- package/src/__tests__/audit.test.ts +877 -0
- package/src/__tests__/circuit-breaker.test.ts +116 -0
- package/src/__tests__/cli-run.test.ts +115 -0
- package/src/__tests__/context-manager.test.ts +502 -0
- package/src/__tests__/context.test.ts +242 -0
- package/src/__tests__/enterprise.test.ts +401 -0
- package/src/__tests__/generator.test.ts +433 -0
- package/src/__tests__/hooks.test.ts +582 -0
- package/src/__tests__/init.test.ts +436 -0
- package/src/__tests__/intent-parser.test.ts +229 -0
- package/src/__tests__/llm-router.test.ts +209 -0
- package/src/__tests__/lsp.test.ts +293 -0
- package/src/__tests__/modes.test.ts +336 -0
- package/src/__tests__/permissions.test.ts +338 -0
- package/src/__tests__/serve.test.ts +275 -0
- package/src/__tests__/sessions.test.ts +227 -0
- package/src/__tests__/sharing.test.ts +288 -0
- package/src/__tests__/snapshots.test.ts +581 -0
- package/src/__tests__/state-db.test.ts +334 -0
- package/src/__tests__/stream-with-tools.test.ts +732 -0
- package/src/__tests__/subagents.test.ts +176 -0
- package/src/__tests__/system-prompt.test.ts +169 -0
- package/src/__tests__/tool-converter.test.ts +256 -0
- package/src/__tests__/tool-schemas.test.ts +397 -0
- package/src/__tests__/tools.test.ts +143 -0
- package/src/__tests__/version.test.ts +49 -0
- package/src/agent/compaction-agent.ts +227 -0
- package/src/agent/context-manager.ts +435 -0
- package/src/agent/context.ts +427 -0
- package/src/agent/deploy-preview.ts +426 -0
- package/src/agent/index.ts +68 -0
- package/src/agent/loop.ts +717 -0
- package/src/agent/modes.ts +429 -0
- package/src/agent/permissions.ts +466 -0
- package/src/agent/subagents/base.ts +116 -0
- package/src/agent/subagents/cost.ts +51 -0
- package/src/agent/subagents/explore.ts +42 -0
- package/src/agent/subagents/general.ts +54 -0
- package/src/agent/subagents/index.ts +102 -0
- package/src/agent/subagents/infra.ts +59 -0
- package/src/agent/subagents/security.ts +69 -0
- package/src/agent/system-prompt.ts +436 -0
- package/src/app.ts +122 -0
- package/src/audit/activity-log.ts +290 -0
- package/src/audit/compliance-checker.ts +540 -0
- package/src/audit/cost-tracker.ts +318 -0
- package/src/audit/index.ts +23 -0
- package/src/audit/security-scanner.ts +596 -0
- package/src/auth/guard.ts +75 -0
- package/src/auth/index.ts +56 -0
- package/src/auth/oauth.ts +455 -0
- package/src/auth/providers.ts +470 -0
- package/src/auth/sso.ts +113 -0
- package/src/auth/store.ts +505 -0
- package/src/auth/types.ts +187 -0
- package/src/build.ts +141 -0
- package/src/cli/index.ts +16 -0
- package/src/cli/init.ts +854 -0
- package/src/cli/openapi-spec.ts +356 -0
- package/src/cli/run.ts +237 -0
- package/src/cli/serve-auth.ts +80 -0
- package/src/cli/serve.ts +462 -0
- package/src/cli/web.ts +67 -0
- package/src/cli.ts +1417 -0
- package/src/clients/core-engine-client.ts +227 -0
- package/src/clients/enterprise-client.ts +334 -0
- package/src/clients/generator-client.ts +351 -0
- package/src/clients/git-client.ts +627 -0
- package/src/clients/github-client.ts +410 -0
- package/src/clients/helm-client.ts +504 -0
- package/src/clients/index.ts +80 -0
- package/src/clients/k8s-client.ts +497 -0
- package/src/clients/llm-client.ts +161 -0
- package/src/clients/rest-client.ts +130 -0
- package/src/clients/service-discovery.ts +33 -0
- package/src/clients/terraform-client.ts +482 -0
- package/src/clients/tools-client.ts +1843 -0
- package/src/clients/ws-client.ts +115 -0
- package/src/commands/analyze/index.ts +352 -0
- package/src/commands/apply/helm.ts +473 -0
- package/src/commands/apply/index.ts +213 -0
- package/src/commands/apply/k8s.ts +454 -0
- package/src/commands/apply/terraform.ts +582 -0
- package/src/commands/ask.ts +167 -0
- package/src/commands/audit/index.ts +238 -0
- package/src/commands/auth-cloud.ts +294 -0
- package/src/commands/auth-list.ts +134 -0
- package/src/commands/auth-profile.ts +121 -0
- package/src/commands/auth-status.ts +141 -0
- package/src/commands/aws/ec2.ts +501 -0
- package/src/commands/aws/iam.ts +397 -0
- package/src/commands/aws/index.ts +133 -0
- package/src/commands/aws/lambda.ts +396 -0
- package/src/commands/aws/rds.ts +439 -0
- package/src/commands/aws/s3.ts +439 -0
- package/src/commands/aws/vpc.ts +393 -0
- package/src/commands/aws-discover.ts +649 -0
- package/src/commands/aws-terraform.ts +805 -0
- package/src/commands/azure/aks.ts +376 -0
- package/src/commands/azure/functions.ts +253 -0
- package/src/commands/azure/index.ts +116 -0
- package/src/commands/azure/storage.ts +478 -0
- package/src/commands/azure/vm.ts +355 -0
- package/src/commands/billing/index.ts +256 -0
- package/src/commands/chat.ts +314 -0
- package/src/commands/config.ts +346 -0
- package/src/commands/cost/cloud-cost-estimator.ts +266 -0
- package/src/commands/cost/estimator.ts +79 -0
- package/src/commands/cost/index.ts +594 -0
- package/src/commands/cost/parsers/terraform.ts +273 -0
- package/src/commands/cost/parsers/types.ts +25 -0
- package/src/commands/cost/pricing/aws.ts +544 -0
- package/src/commands/cost/pricing/azure.ts +499 -0
- package/src/commands/cost/pricing/gcp.ts +396 -0
- package/src/commands/cost/pricing/index.ts +40 -0
- package/src/commands/demo.ts +250 -0
- package/src/commands/doctor.ts +794 -0
- package/src/commands/drift/index.ts +439 -0
- package/src/commands/explain.ts +277 -0
- package/src/commands/feedback.ts +389 -0
- package/src/commands/fix.ts +324 -0
- package/src/commands/fs/index.ts +402 -0
- package/src/commands/gcp/compute.ts +325 -0
- package/src/commands/gcp/functions.ts +271 -0
- package/src/commands/gcp/gke.ts +438 -0
- package/src/commands/gcp/iam.ts +344 -0
- package/src/commands/gcp/index.ts +129 -0
- package/src/commands/gcp/storage.ts +284 -0
- package/src/commands/generate-helm.ts +1249 -0
- package/src/commands/generate-k8s.ts +1560 -0
- package/src/commands/generate-terraform.ts +1460 -0
- package/src/commands/gh/index.ts +863 -0
- package/src/commands/git/index.ts +1343 -0
- package/src/commands/helm/index.ts +1126 -0
- package/src/commands/help.ts +539 -0
- package/src/commands/history.ts +142 -0
- package/src/commands/import.ts +868 -0
- package/src/commands/index.ts +367 -0
- package/src/commands/init.ts +1046 -0
- package/src/commands/k8s/index.ts +1137 -0
- package/src/commands/login.ts +631 -0
- package/src/commands/logout.ts +83 -0
- package/src/commands/onboarding.ts +228 -0
- package/src/commands/plan/display.ts +279 -0
- package/src/commands/plan/index.ts +599 -0
- package/src/commands/preview.ts +452 -0
- package/src/commands/questionnaire.ts +1270 -0
- package/src/commands/resume.ts +55 -0
- package/src/commands/team/index.ts +346 -0
- package/src/commands/template.ts +232 -0
- package/src/commands/tf/index.ts +1034 -0
- package/src/commands/upgrade.ts +550 -0
- package/src/commands/usage/index.ts +134 -0
- package/src/commands/version.ts +170 -0
- package/src/compat/index.ts +2 -0
- package/src/compat/runtime.ts +12 -0
- package/src/compat/sqlite.ts +107 -0
- package/src/config/index.ts +17 -0
- package/src/config/manager.ts +530 -0
- package/src/config/safety-policy.ts +358 -0
- package/src/config/schema.ts +125 -0
- package/src/config/types.ts +527 -0
- package/src/context/context-db.ts +199 -0
- package/src/demo/index.ts +349 -0
- package/src/demo/scenarios/full-journey.ts +229 -0
- package/src/demo/scenarios/getting-started.ts +127 -0
- package/src/demo/scenarios/helm-release.ts +341 -0
- package/src/demo/scenarios/k8s-deployment.ts +194 -0
- package/src/demo/scenarios/terraform-vpc.ts +170 -0
- package/src/demo/types.ts +92 -0
- package/src/engine/cost-estimator.ts +438 -0
- package/src/engine/diagram-generator.ts +256 -0
- package/src/engine/drift-detector.ts +902 -0
- package/src/engine/executor.ts +1035 -0
- package/src/engine/index.ts +76 -0
- package/src/engine/orchestrator.ts +636 -0
- package/src/engine/planner.ts +720 -0
- package/src/engine/safety.ts +743 -0
- package/src/engine/verifier.ts +770 -0
- package/src/enterprise/audit.ts +348 -0
- package/src/enterprise/auth.ts +270 -0
- package/src/enterprise/billing.ts +822 -0
- package/src/enterprise/index.ts +17 -0
- package/src/enterprise/teams.ts +443 -0
- package/src/generator/best-practices.ts +1608 -0
- package/src/generator/helm.ts +630 -0
- package/src/generator/index.ts +37 -0
- package/src/generator/intent-parser.ts +514 -0
- package/src/generator/kubernetes.ts +976 -0
- package/src/generator/terraform.ts +1867 -0
- package/src/history/index.ts +8 -0
- package/src/history/manager.ts +322 -0
- package/src/history/types.ts +34 -0
- package/src/hooks/config.ts +432 -0
- package/src/hooks/engine.ts +391 -0
- package/src/hooks/index.ts +4 -0
- package/src/llm/auth-bridge.ts +198 -0
- package/src/llm/circuit-breaker.ts +140 -0
- package/src/llm/config-loader.ts +201 -0
- package/src/llm/cost-calculator.ts +171 -0
- package/src/llm/index.ts +8 -0
- package/src/llm/model-aliases.ts +115 -0
- package/src/llm/provider-registry.ts +63 -0
- package/src/llm/providers/anthropic.ts +433 -0
- package/src/llm/providers/bedrock.ts +477 -0
- package/src/llm/providers/google.ts +405 -0
- package/src/llm/providers/ollama.ts +767 -0
- package/src/llm/providers/openai-compatible.ts +340 -0
- package/src/llm/providers/openai.ts +328 -0
- package/src/llm/providers/openrouter.ts +338 -0
- package/src/llm/router.ts +1035 -0
- package/src/llm/types.ts +232 -0
- package/src/lsp/client.ts +298 -0
- package/src/lsp/languages.ts +116 -0
- package/src/lsp/manager.ts +278 -0
- package/src/mcp/client.ts +402 -0
- package/src/mcp/index.ts +5 -0
- package/src/mcp/manager.ts +133 -0
- package/src/nimbus.ts +214 -0
- package/src/plugins/index.ts +27 -0
- package/src/plugins/loader.ts +334 -0
- package/src/plugins/manager.ts +376 -0
- package/src/plugins/types.ts +284 -0
- package/src/scanners/cicd-scanner.ts +258 -0
- package/src/scanners/cloud-scanner.ts +466 -0
- package/src/scanners/framework-scanner.ts +469 -0
- package/src/scanners/iac-scanner.ts +388 -0
- package/src/scanners/index.ts +539 -0
- package/src/scanners/language-scanner.ts +276 -0
- package/src/scanners/package-manager-scanner.ts +277 -0
- package/src/scanners/types.ts +172 -0
- package/src/sessions/manager.ts +365 -0
- package/src/sessions/types.ts +44 -0
- package/src/sharing/sync.ts +296 -0
- package/src/sharing/viewer.ts +97 -0
- package/src/snapshots/index.ts +2 -0
- package/src/snapshots/manager.ts +530 -0
- package/src/state/artifacts.ts +147 -0
- package/src/state/audit.ts +137 -0
- package/src/state/billing.ts +240 -0
- package/src/state/checkpoints.ts +117 -0
- package/src/state/config.ts +67 -0
- package/src/state/conversations.ts +14 -0
- package/src/state/credentials.ts +154 -0
- package/src/state/db.ts +58 -0
- package/src/state/index.ts +26 -0
- package/src/state/messages.ts +115 -0
- package/src/state/projects.ts +123 -0
- package/src/state/schema.ts +236 -0
- package/src/state/sessions.ts +147 -0
- package/src/state/teams.ts +200 -0
- package/src/telemetry.ts +108 -0
- package/src/tools/aws-ops.ts +952 -0
- package/src/tools/azure-ops.ts +579 -0
- package/src/tools/file-ops.ts +593 -0
- package/src/tools/gcp-ops.ts +625 -0
- package/src/tools/git-ops.ts +773 -0
- package/src/tools/github-ops.ts +799 -0
- package/src/tools/helm-ops.ts +943 -0
- package/src/tools/index.ts +17 -0
- package/src/tools/k8s-ops.ts +819 -0
- package/src/tools/schemas/converter.ts +184 -0
- package/src/tools/schemas/devops.ts +612 -0
- package/src/tools/schemas/index.ts +73 -0
- package/src/tools/schemas/standard.ts +1144 -0
- package/src/tools/schemas/types.ts +705 -0
- package/src/tools/terraform-ops.ts +862 -0
- package/src/types/ambient.d.ts +193 -0
- package/src/types/config.ts +83 -0
- package/src/types/drift.ts +116 -0
- package/src/types/enterprise.ts +335 -0
- package/src/types/index.ts +20 -0
- package/src/types/plan.ts +44 -0
- package/src/types/request.ts +65 -0
- package/src/types/response.ts +54 -0
- package/src/types/service.ts +51 -0
- package/src/ui/App.tsx +997 -0
- package/src/ui/DeployPreview.tsx +169 -0
- package/src/ui/Header.tsx +68 -0
- package/src/ui/InputBox.tsx +350 -0
- package/src/ui/MessageList.tsx +585 -0
- package/src/ui/PermissionPrompt.tsx +151 -0
- package/src/ui/StatusBar.tsx +158 -0
- package/src/ui/ToolCallDisplay.tsx +409 -0
- package/src/ui/chat-ui.ts +853 -0
- package/src/ui/index.ts +33 -0
- package/src/ui/ink/index.ts +711 -0
- package/src/ui/streaming.ts +176 -0
- package/src/ui/types.ts +57 -0
- package/src/utils/analytics.ts +72 -0
- package/src/utils/cost-warning.ts +27 -0
- package/src/utils/env.ts +46 -0
- package/src/utils/errors.ts +69 -0
- package/src/utils/event-bus.ts +38 -0
- package/src/utils/index.ts +24 -0
- package/src/utils/logger.ts +171 -0
- package/src/utils/rate-limiter.ts +121 -0
- package/src/utils/service-auth.ts +49 -0
- package/src/utils/validation.ts +53 -0
- package/src/version.ts +4 -0
- package/src/watcher/index.ts +163 -0
- package/src/wizard/approval.ts +383 -0
- package/src/wizard/index.ts +25 -0
- package/src/wizard/prompts.ts +338 -0
- package/src/wizard/types.ts +171 -0
- package/src/wizard/ui.ts +556 -0
- package/src/wizard/wizard.ts +304 -0
- package/tsconfig.json +24 -0
|
@@ -0,0 +1,773 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Git Operations — Embedded tool (stripped HTTP wrappers)
|
|
3
|
+
*
|
|
4
|
+
* Copied from services/git-tools-service/src/git/operations.ts
|
|
5
|
+
* Provides direct git operations for the embedded CLI binary.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import simpleGit, {
|
|
9
|
+
type SimpleGit,
|
|
10
|
+
type SimpleGitOptions,
|
|
11
|
+
type StatusResult,
|
|
12
|
+
type LogResult,
|
|
13
|
+
} from 'simple-git';
|
|
14
|
+
import { logger } from '../utils';
|
|
15
|
+
|
|
16
|
+
export interface GitCloneOptions {
|
|
17
|
+
url: string;
|
|
18
|
+
path: string;
|
|
19
|
+
branch?: string;
|
|
20
|
+
depth?: number;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface GitCommitOptions {
|
|
24
|
+
message: string;
|
|
25
|
+
amend?: boolean;
|
|
26
|
+
allowEmpty?: boolean;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface GitPushOptions {
|
|
30
|
+
remote?: string;
|
|
31
|
+
branch?: string;
|
|
32
|
+
force?: boolean;
|
|
33
|
+
setUpstream?: boolean;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface GitPullOptions {
|
|
37
|
+
remote?: string;
|
|
38
|
+
branch?: string;
|
|
39
|
+
rebase?: boolean;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export interface GitBranchOptions {
|
|
43
|
+
name: string;
|
|
44
|
+
checkout?: boolean;
|
|
45
|
+
startPoint?: string;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export interface GitMergeOptions {
|
|
49
|
+
branch: string;
|
|
50
|
+
noFf?: boolean;
|
|
51
|
+
squash?: boolean;
|
|
52
|
+
message?: string;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export interface GitLogOptions {
|
|
56
|
+
maxCount?: number;
|
|
57
|
+
from?: string;
|
|
58
|
+
to?: string;
|
|
59
|
+
file?: string;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export interface GitDiffOptions {
|
|
63
|
+
cached?: boolean;
|
|
64
|
+
nameOnly?: boolean;
|
|
65
|
+
from?: string;
|
|
66
|
+
to?: string;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export interface GitStashOptions {
|
|
70
|
+
command: 'push' | 'pop' | 'list' | 'drop' | 'apply' | 'clear';
|
|
71
|
+
message?: string;
|
|
72
|
+
index?: number;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export interface CherryPickOptions {
|
|
76
|
+
noCommit?: boolean;
|
|
77
|
+
edit?: boolean;
|
|
78
|
+
signoff?: boolean;
|
|
79
|
+
strategy?: string;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export interface RebaseOptions {
|
|
83
|
+
interactive?: boolean;
|
|
84
|
+
onto?: string;
|
|
85
|
+
preserveMerges?: boolean;
|
|
86
|
+
strategy?: string;
|
|
87
|
+
strategyOption?: string;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export interface TagOptions {
|
|
91
|
+
message?: string;
|
|
92
|
+
annotated?: boolean;
|
|
93
|
+
force?: boolean;
|
|
94
|
+
commit?: string;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export class GitOperations {
|
|
98
|
+
private git: SimpleGit;
|
|
99
|
+
private repoPath: string;
|
|
100
|
+
|
|
101
|
+
constructor(repoPath: string = process.cwd()) {
|
|
102
|
+
this.repoPath = repoPath;
|
|
103
|
+
const options: Partial<SimpleGitOptions> = {
|
|
104
|
+
baseDir: repoPath,
|
|
105
|
+
binary: 'git',
|
|
106
|
+
maxConcurrentProcesses: 6,
|
|
107
|
+
trimmed: true,
|
|
108
|
+
};
|
|
109
|
+
this.git = simpleGit(options);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Clone a repository
|
|
114
|
+
*/
|
|
115
|
+
async clone(options: GitCloneOptions): Promise<{ success: boolean; path: string }> {
|
|
116
|
+
logger.info(`Cloning repository from ${options.url} to ${options.path}`);
|
|
117
|
+
|
|
118
|
+
const cloneOptions: string[] = [];
|
|
119
|
+
if (options.branch) {
|
|
120
|
+
cloneOptions.push('--branch', options.branch);
|
|
121
|
+
}
|
|
122
|
+
if (options.depth) {
|
|
123
|
+
cloneOptions.push('--depth', options.depth.toString());
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
await simpleGit().clone(options.url, options.path, cloneOptions);
|
|
127
|
+
|
|
128
|
+
return { success: true, path: options.path };
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Get repository status
|
|
133
|
+
*/
|
|
134
|
+
async status(): Promise<StatusResult> {
|
|
135
|
+
logger.info(`Getting git status for ${this.repoPath}`);
|
|
136
|
+
return await this.git.status();
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Add files to staging
|
|
141
|
+
*/
|
|
142
|
+
async add(files: string | string[] = '.'): Promise<{ success: boolean; files: string[] }> {
|
|
143
|
+
const fileList = Array.isArray(files) ? files : [files];
|
|
144
|
+
logger.info(`Staging files: ${fileList.join(', ')}`);
|
|
145
|
+
|
|
146
|
+
await this.git.add(fileList);
|
|
147
|
+
|
|
148
|
+
return { success: true, files: fileList };
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Commit staged changes
|
|
153
|
+
*/
|
|
154
|
+
async commit(
|
|
155
|
+
options: GitCommitOptions
|
|
156
|
+
): Promise<{ success: boolean; hash: string; summary: string }> {
|
|
157
|
+
logger.info(`Committing with message: ${options.message}`);
|
|
158
|
+
|
|
159
|
+
const commitOptions: string[] = [];
|
|
160
|
+
if (options.amend) {
|
|
161
|
+
commitOptions.push('--amend');
|
|
162
|
+
}
|
|
163
|
+
if (options.allowEmpty) {
|
|
164
|
+
commitOptions.push('--allow-empty');
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const result = await this.git.commit(options.message, undefined, { '--': commitOptions });
|
|
168
|
+
|
|
169
|
+
return {
|
|
170
|
+
success: true,
|
|
171
|
+
hash: result.commit,
|
|
172
|
+
summary: result.summary
|
|
173
|
+
? `${result.summary.changes} changes, ${result.summary.insertions} insertions, ${result.summary.deletions} deletions`
|
|
174
|
+
: 'Committed',
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Push to remote
|
|
180
|
+
*/
|
|
181
|
+
async push(
|
|
182
|
+
options: GitPushOptions = {}
|
|
183
|
+
): Promise<{ success: boolean; remote: string; branch: string }> {
|
|
184
|
+
const remote = options.remote || 'origin';
|
|
185
|
+
logger.info(`Pushing to ${remote}${options.branch ? `/${options.branch}` : ''}`);
|
|
186
|
+
|
|
187
|
+
const pushOptions: string[] = [];
|
|
188
|
+
if (options.force) {
|
|
189
|
+
pushOptions.push('--force');
|
|
190
|
+
}
|
|
191
|
+
if (options.setUpstream) {
|
|
192
|
+
pushOptions.push('--set-upstream');
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
await this.git.push(remote, options.branch, pushOptions);
|
|
196
|
+
|
|
197
|
+
return { success: true, remote, branch: options.branch || 'current' };
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Pull from remote
|
|
202
|
+
*/
|
|
203
|
+
async pull(options: GitPullOptions = {}): Promise<{ success: boolean; summary: string }> {
|
|
204
|
+
const remote = options.remote || 'origin';
|
|
205
|
+
logger.info(`Pulling from ${remote}${options.branch ? `/${options.branch}` : ''}`);
|
|
206
|
+
|
|
207
|
+
const pullOptions: Record<string, string | null> = {};
|
|
208
|
+
if (options.rebase) {
|
|
209
|
+
pullOptions['--rebase'] = null;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const result = await this.git.pull(remote, options.branch, pullOptions);
|
|
213
|
+
|
|
214
|
+
return {
|
|
215
|
+
success: true,
|
|
216
|
+
summary: result.summary
|
|
217
|
+
? `${result.summary.changes} changes, ${result.summary.insertions} insertions, ${result.summary.deletions} deletions`
|
|
218
|
+
: 'Already up to date',
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Create a new branch
|
|
224
|
+
*/
|
|
225
|
+
async createBranch(options: GitBranchOptions): Promise<{ success: boolean; branch: string }> {
|
|
226
|
+
logger.info(`Creating branch: ${options.name}`);
|
|
227
|
+
|
|
228
|
+
if (options.checkout) {
|
|
229
|
+
if (options.startPoint) {
|
|
230
|
+
await this.git.checkoutBranch(options.name, options.startPoint);
|
|
231
|
+
} else {
|
|
232
|
+
await this.git.checkoutLocalBranch(options.name);
|
|
233
|
+
}
|
|
234
|
+
} else {
|
|
235
|
+
await this.git.branch([options.name, options.startPoint || 'HEAD']);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
return { success: true, branch: options.name };
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* List branches
|
|
243
|
+
*/
|
|
244
|
+
async listBranches(
|
|
245
|
+
showRemote: boolean = false
|
|
246
|
+
): Promise<{ current: string; branches: string[] }> {
|
|
247
|
+
logger.info('Listing branches');
|
|
248
|
+
|
|
249
|
+
const result = await this.git.branch(showRemote ? ['-a'] : []);
|
|
250
|
+
|
|
251
|
+
return {
|
|
252
|
+
current: result.current,
|
|
253
|
+
branches: result.all,
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Checkout a branch or commit
|
|
259
|
+
*/
|
|
260
|
+
async checkout(
|
|
261
|
+
target: string,
|
|
262
|
+
create: boolean = false
|
|
263
|
+
): Promise<{ success: boolean; target: string }> {
|
|
264
|
+
logger.info(`Checking out: ${target}`);
|
|
265
|
+
|
|
266
|
+
if (create) {
|
|
267
|
+
await this.git.checkoutLocalBranch(target);
|
|
268
|
+
} else {
|
|
269
|
+
await this.git.checkout(target);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
return { success: true, target };
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* Get diff
|
|
277
|
+
*/
|
|
278
|
+
async diff(options: GitDiffOptions = {}): Promise<{ diff: string; files: string[] }> {
|
|
279
|
+
logger.info('Getting diff');
|
|
280
|
+
|
|
281
|
+
const diffArgs: string[] = [];
|
|
282
|
+
if (options.cached) {
|
|
283
|
+
diffArgs.push('--cached');
|
|
284
|
+
}
|
|
285
|
+
if (options.nameOnly) {
|
|
286
|
+
diffArgs.push('--name-only');
|
|
287
|
+
}
|
|
288
|
+
if (options.from) {
|
|
289
|
+
diffArgs.push(options.from);
|
|
290
|
+
}
|
|
291
|
+
if (options.to) {
|
|
292
|
+
diffArgs.push(options.to);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
const diff = await this.git.diff(diffArgs);
|
|
296
|
+
const files = options.nameOnly ? diff.split('\n').filter(f => f) : [];
|
|
297
|
+
|
|
298
|
+
return { diff, files };
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* Get commit log
|
|
303
|
+
*/
|
|
304
|
+
async log(options: GitLogOptions = {}): Promise<LogResult> {
|
|
305
|
+
logger.info('Getting commit log');
|
|
306
|
+
|
|
307
|
+
const logOptions: any = {};
|
|
308
|
+
if (options.maxCount) {
|
|
309
|
+
logOptions.maxCount = options.maxCount;
|
|
310
|
+
}
|
|
311
|
+
if (options.from) {
|
|
312
|
+
logOptions.from = options.from;
|
|
313
|
+
}
|
|
314
|
+
if (options.to) {
|
|
315
|
+
logOptions.to = options.to;
|
|
316
|
+
}
|
|
317
|
+
if (options.file) {
|
|
318
|
+
logOptions.file = options.file;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
return await this.git.log(logOptions);
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
/**
|
|
325
|
+
* Merge a branch
|
|
326
|
+
*/
|
|
327
|
+
async merge(options: GitMergeOptions): Promise<{ success: boolean; result: string }> {
|
|
328
|
+
logger.info(`Merging branch: ${options.branch}`);
|
|
329
|
+
|
|
330
|
+
const mergeArgs: string[] = [options.branch];
|
|
331
|
+
if (options.noFf) {
|
|
332
|
+
mergeArgs.unshift('--no-ff');
|
|
333
|
+
}
|
|
334
|
+
if (options.squash) {
|
|
335
|
+
mergeArgs.unshift('--squash');
|
|
336
|
+
}
|
|
337
|
+
if (options.message) {
|
|
338
|
+
mergeArgs.unshift('-m', options.message);
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
const result = await this.git.merge(mergeArgs);
|
|
342
|
+
|
|
343
|
+
return {
|
|
344
|
+
success: true,
|
|
345
|
+
result: result.result || 'Merged successfully',
|
|
346
|
+
};
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
/**
|
|
350
|
+
* Stash operations
|
|
351
|
+
*/
|
|
352
|
+
async stash(options: GitStashOptions): Promise<{ success: boolean; result: string }> {
|
|
353
|
+
logger.info(`Stash operation: ${options.command}`);
|
|
354
|
+
|
|
355
|
+
let result: string;
|
|
356
|
+
|
|
357
|
+
switch (options.command) {
|
|
358
|
+
case 'push': {
|
|
359
|
+
const pushArgs = options.message ? ['-m', options.message] : [];
|
|
360
|
+
result = await this.git.stash(['push', ...pushArgs]);
|
|
361
|
+
break;
|
|
362
|
+
}
|
|
363
|
+
case 'pop':
|
|
364
|
+
result = await this.git.stash([
|
|
365
|
+
'pop',
|
|
366
|
+
...(options.index !== undefined ? [options.index.toString()] : []),
|
|
367
|
+
]);
|
|
368
|
+
break;
|
|
369
|
+
case 'apply':
|
|
370
|
+
result = await this.git.stash([
|
|
371
|
+
'apply',
|
|
372
|
+
...(options.index !== undefined ? [options.index.toString()] : []),
|
|
373
|
+
]);
|
|
374
|
+
break;
|
|
375
|
+
case 'drop':
|
|
376
|
+
result = await this.git.stash([
|
|
377
|
+
'drop',
|
|
378
|
+
...(options.index !== undefined ? [options.index.toString()] : []),
|
|
379
|
+
]);
|
|
380
|
+
break;
|
|
381
|
+
case 'list':
|
|
382
|
+
result = await this.git.stash(['list']);
|
|
383
|
+
break;
|
|
384
|
+
case 'clear':
|
|
385
|
+
result = await this.git.stash(['clear']);
|
|
386
|
+
break;
|
|
387
|
+
default:
|
|
388
|
+
throw new Error(`Unknown stash command: ${options.command}`);
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
return { success: true, result: result || 'Stash operation completed' };
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
/**
|
|
395
|
+
* Get current branch name
|
|
396
|
+
*/
|
|
397
|
+
async currentBranch(): Promise<string> {
|
|
398
|
+
const result = await this.git.revparse(['--abbrev-ref', 'HEAD']);
|
|
399
|
+
return result.trim();
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
/**
|
|
403
|
+
* Check if repository is clean
|
|
404
|
+
*/
|
|
405
|
+
async isClean(): Promise<boolean> {
|
|
406
|
+
const status = await this.status();
|
|
407
|
+
return status.isClean();
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
/**
|
|
411
|
+
* Reset to a commit
|
|
412
|
+
*/
|
|
413
|
+
async reset(
|
|
414
|
+
target: string,
|
|
415
|
+
mode: 'soft' | 'mixed' | 'hard' = 'mixed'
|
|
416
|
+
): Promise<{ success: boolean }> {
|
|
417
|
+
logger.info(`Resetting to ${target} with mode ${mode}`);
|
|
418
|
+
await this.git.reset([`--${mode}`, target]);
|
|
419
|
+
return { success: true };
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
/**
|
|
423
|
+
* Fetch from remote
|
|
424
|
+
*/
|
|
425
|
+
async fetch(remote: string = 'origin', prune: boolean = false): Promise<{ success: boolean }> {
|
|
426
|
+
logger.info(`Fetching from ${remote}`);
|
|
427
|
+
if (prune) {
|
|
428
|
+
await this.git.fetch(remote, ['--prune']);
|
|
429
|
+
} else {
|
|
430
|
+
await this.git.fetch(remote);
|
|
431
|
+
}
|
|
432
|
+
return { success: true };
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
/**
|
|
436
|
+
* Get remote URL
|
|
437
|
+
*/
|
|
438
|
+
async getRemoteUrl(remote: string = 'origin'): Promise<string | null> {
|
|
439
|
+
try {
|
|
440
|
+
const remotes = await this.git.getRemotes(true);
|
|
441
|
+
const targetRemote = remotes.find(r => r.name === remote);
|
|
442
|
+
return targetRemote?.refs?.fetch || null;
|
|
443
|
+
} catch {
|
|
444
|
+
return null;
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
/**
|
|
449
|
+
* Check if path is a git repository
|
|
450
|
+
*/
|
|
451
|
+
async isRepo(): Promise<boolean> {
|
|
452
|
+
return await this.git.checkIsRepo();
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
/**
|
|
456
|
+
* Initialize a new repository
|
|
457
|
+
*/
|
|
458
|
+
async init(bare: boolean = false): Promise<{ success: boolean }> {
|
|
459
|
+
logger.info(`Initializing git repository in ${this.repoPath}`);
|
|
460
|
+
await this.git.init(bare);
|
|
461
|
+
return { success: true };
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
/**
|
|
465
|
+
* Cherry-pick a commit
|
|
466
|
+
*/
|
|
467
|
+
async cherryPick(
|
|
468
|
+
commit: string,
|
|
469
|
+
options: CherryPickOptions = {}
|
|
470
|
+
): Promise<{ success: boolean; result: string }> {
|
|
471
|
+
logger.info(`Cherry-picking commit: ${commit}`);
|
|
472
|
+
|
|
473
|
+
const cherryPickArgs: string[] = [commit];
|
|
474
|
+
|
|
475
|
+
if (options.noCommit) {
|
|
476
|
+
cherryPickArgs.unshift('--no-commit');
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
if (options.edit) {
|
|
480
|
+
cherryPickArgs.unshift('-e');
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
if (options.signoff) {
|
|
484
|
+
cherryPickArgs.unshift('-s');
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
if (options.strategy) {
|
|
488
|
+
cherryPickArgs.unshift('-X', options.strategy);
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
// Use raw to execute cherry-pick
|
|
492
|
+
const result = await this.git.raw(['cherry-pick', ...cherryPickArgs]);
|
|
493
|
+
|
|
494
|
+
return {
|
|
495
|
+
success: true,
|
|
496
|
+
result: result || 'Cherry-pick completed successfully',
|
|
497
|
+
};
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
/**
|
|
501
|
+
* Rebase onto a target branch
|
|
502
|
+
*/
|
|
503
|
+
async rebase(
|
|
504
|
+
target: string,
|
|
505
|
+
options: RebaseOptions = {}
|
|
506
|
+
): Promise<{ success: boolean; result: string }> {
|
|
507
|
+
logger.info(`Rebasing onto: ${target}`);
|
|
508
|
+
|
|
509
|
+
const rebaseArgs: string[] = [];
|
|
510
|
+
|
|
511
|
+
if (options.interactive) {
|
|
512
|
+
// Note: Interactive rebase requires a terminal, so we skip it in automation
|
|
513
|
+
logger.warn('Interactive rebase not supported in automation mode');
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
if (options.onto) {
|
|
517
|
+
rebaseArgs.push('--onto', options.onto);
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
if (options.preserveMerges) {
|
|
521
|
+
rebaseArgs.push('--preserve-merges');
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
if (options.strategy) {
|
|
525
|
+
rebaseArgs.push('-s', options.strategy);
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
if (options.strategyOption) {
|
|
529
|
+
rebaseArgs.push('-X', options.strategyOption);
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
rebaseArgs.push(target);
|
|
533
|
+
|
|
534
|
+
const result = await this.git.rebase(rebaseArgs);
|
|
535
|
+
|
|
536
|
+
return {
|
|
537
|
+
success: true,
|
|
538
|
+
result: result || 'Rebase completed successfully',
|
|
539
|
+
};
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
/**
|
|
543
|
+
* Continue a rebase after resolving conflicts
|
|
544
|
+
*/
|
|
545
|
+
async rebaseContinue(): Promise<{ success: boolean; result: string }> {
|
|
546
|
+
logger.info('Continuing rebase');
|
|
547
|
+
const result = await this.git.rebase(['--continue']);
|
|
548
|
+
return {
|
|
549
|
+
success: true,
|
|
550
|
+
result: result || 'Rebase continued successfully',
|
|
551
|
+
};
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
/**
|
|
555
|
+
* Abort a rebase in progress
|
|
556
|
+
*/
|
|
557
|
+
async rebaseAbort(): Promise<{ success: boolean }> {
|
|
558
|
+
logger.info('Aborting rebase');
|
|
559
|
+
await this.git.rebase(['--abort']);
|
|
560
|
+
return { success: true };
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
/**
|
|
564
|
+
* Skip a commit during rebase
|
|
565
|
+
*/
|
|
566
|
+
async rebaseSkip(): Promise<{ success: boolean; result: string }> {
|
|
567
|
+
logger.info('Skipping commit during rebase');
|
|
568
|
+
const result = await this.git.rebase(['--skip']);
|
|
569
|
+
return {
|
|
570
|
+
success: true,
|
|
571
|
+
result: result || 'Commit skipped',
|
|
572
|
+
};
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
/**
|
|
576
|
+
* Create a tag
|
|
577
|
+
*/
|
|
578
|
+
async tag(name: string, options: TagOptions = {}): Promise<{ success: boolean; tag: string }> {
|
|
579
|
+
logger.info(`Creating tag: ${name}`);
|
|
580
|
+
|
|
581
|
+
const tagArgs: string[] = [];
|
|
582
|
+
|
|
583
|
+
if (options.annotated || options.message) {
|
|
584
|
+
tagArgs.push('-a');
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
if (options.message) {
|
|
588
|
+
tagArgs.push('-m', options.message);
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
if (options.force) {
|
|
592
|
+
tagArgs.push('-f');
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
tagArgs.push(name);
|
|
596
|
+
|
|
597
|
+
if (options.commit) {
|
|
598
|
+
tagArgs.push(options.commit);
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
await this.git.tag(tagArgs);
|
|
602
|
+
|
|
603
|
+
return { success: true, tag: name };
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
/**
|
|
607
|
+
* Delete a tag
|
|
608
|
+
*/
|
|
609
|
+
async deleteTag(name: string, remote?: string): Promise<{ success: boolean }> {
|
|
610
|
+
logger.info(`Deleting tag: ${name}`);
|
|
611
|
+
|
|
612
|
+
// Delete locally
|
|
613
|
+
await this.git.tag(['-d', name]);
|
|
614
|
+
|
|
615
|
+
// Delete from remote if specified
|
|
616
|
+
if (remote) {
|
|
617
|
+
await this.git.push(remote, `:refs/tags/${name}`);
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
return { success: true };
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
/**
|
|
624
|
+
* List tags
|
|
625
|
+
*/
|
|
626
|
+
async listTags(pattern?: string): Promise<string[]> {
|
|
627
|
+
logger.info('Listing tags');
|
|
628
|
+
|
|
629
|
+
const args = pattern ? ['-l', pattern] : [];
|
|
630
|
+
const result = await this.git.tags(args);
|
|
631
|
+
|
|
632
|
+
return result.all;
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
/**
|
|
636
|
+
* Push tags to remote
|
|
637
|
+
*/
|
|
638
|
+
async pushTags(remote: string = 'origin', tagName?: string): Promise<{ success: boolean }> {
|
|
639
|
+
logger.info(`Pushing tags to ${remote}`);
|
|
640
|
+
|
|
641
|
+
if (tagName) {
|
|
642
|
+
await this.git.push(remote, `refs/tags/${tagName}`);
|
|
643
|
+
} else {
|
|
644
|
+
await this.git.pushTags(remote);
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
return { success: true };
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
/**
|
|
651
|
+
* Show information about a tag
|
|
652
|
+
*/
|
|
653
|
+
async showTag(name: string): Promise<{ success: boolean; info: string }> {
|
|
654
|
+
logger.info(`Showing tag: ${name}`);
|
|
655
|
+
|
|
656
|
+
const result = await this.git.show(['--no-patch', name]);
|
|
657
|
+
|
|
658
|
+
return { success: true, info: result };
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
/**
|
|
662
|
+
* Check if there are conflicts
|
|
663
|
+
*/
|
|
664
|
+
async hasConflicts(): Promise<boolean> {
|
|
665
|
+
const status = await this.status();
|
|
666
|
+
return status.conflicted.length > 0;
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
/**
|
|
670
|
+
* Get list of conflicted files
|
|
671
|
+
*/
|
|
672
|
+
async getConflicts(): Promise<string[]> {
|
|
673
|
+
const status = await this.status();
|
|
674
|
+
return status.conflicted;
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
/**
|
|
678
|
+
* Abort cherry-pick in progress
|
|
679
|
+
*/
|
|
680
|
+
async cherryPickAbort(): Promise<{ success: boolean }> {
|
|
681
|
+
logger.info('Aborting cherry-pick');
|
|
682
|
+
await this.git.raw(['cherry-pick', '--abort']);
|
|
683
|
+
return { success: true };
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
/**
|
|
687
|
+
* Continue cherry-pick after resolving conflicts
|
|
688
|
+
*/
|
|
689
|
+
async cherryPickContinue(): Promise<{ success: boolean; result: string }> {
|
|
690
|
+
logger.info('Continuing cherry-pick');
|
|
691
|
+
const result = await this.git.raw(['cherry-pick', '--continue']);
|
|
692
|
+
return {
|
|
693
|
+
success: true,
|
|
694
|
+
result: result || 'Cherry-pick continued',
|
|
695
|
+
};
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
/**
|
|
699
|
+
* Show a specific commit
|
|
700
|
+
*/
|
|
701
|
+
async showCommit(commit: string): Promise<string> {
|
|
702
|
+
logger.info(`Showing commit: ${commit}`);
|
|
703
|
+
return await this.git.show([commit]);
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
/**
|
|
707
|
+
* Get the short hash for a ref
|
|
708
|
+
*/
|
|
709
|
+
async getShortHash(ref: string = 'HEAD'): Promise<string> {
|
|
710
|
+
const result = await this.git.revparse(['--short', ref]);
|
|
711
|
+
return result.trim();
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
/**
|
|
715
|
+
* Get the full hash for a ref
|
|
716
|
+
*/
|
|
717
|
+
async getFullHash(ref: string = 'HEAD'): Promise<string> {
|
|
718
|
+
const result = await this.git.revparse([ref]);
|
|
719
|
+
return result.trim();
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
/**
|
|
723
|
+
* Get the commit count between two refs
|
|
724
|
+
*/
|
|
725
|
+
async getCommitCount(from: string, to: string = 'HEAD'): Promise<number> {
|
|
726
|
+
const result = await this.git.raw(['rev-list', '--count', `${from}..${to}`]);
|
|
727
|
+
return parseInt(result.trim(), 10);
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
/**
|
|
731
|
+
* Revert a commit
|
|
732
|
+
*/
|
|
733
|
+
async revert(
|
|
734
|
+
commit: string,
|
|
735
|
+
options: { noCommit?: boolean; noEdit?: boolean } = {}
|
|
736
|
+
): Promise<{ success: boolean; result: string }> {
|
|
737
|
+
logger.info(`Reverting commit: ${commit}`);
|
|
738
|
+
|
|
739
|
+
const revertArgs: string[] = [];
|
|
740
|
+
|
|
741
|
+
if (options.noCommit) {
|
|
742
|
+
revertArgs.push('--no-commit');
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
if (options.noEdit) {
|
|
746
|
+
revertArgs.push('--no-edit');
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
revertArgs.push(commit);
|
|
750
|
+
|
|
751
|
+
const result = await this.git.raw(['revert', ...revertArgs]);
|
|
752
|
+
|
|
753
|
+
return {
|
|
754
|
+
success: true,
|
|
755
|
+
result: result || 'Revert completed successfully',
|
|
756
|
+
};
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
/**
|
|
760
|
+
* Blame a file
|
|
761
|
+
*/
|
|
762
|
+
async blame(file: string, options?: { startLine?: number; endLine?: number }): Promise<string> {
|
|
763
|
+
logger.info(`Getting blame for: ${file}`);
|
|
764
|
+
|
|
765
|
+
const args = [];
|
|
766
|
+
if (options?.startLine && options?.endLine) {
|
|
767
|
+
args.push(`-L${options.startLine},${options.endLine}`);
|
|
768
|
+
}
|
|
769
|
+
args.push(file);
|
|
770
|
+
|
|
771
|
+
return await this.git.raw(['blame', ...args]);
|
|
772
|
+
}
|
|
773
|
+
}
|