vibeman 0.0.5 → 0.0.6
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/dist/api.js +49 -0
- package/dist/cli.js +135 -0
- package/dist/ui/index-gnk6rhxs.js +9 -0
- package/dist/ui/index.html +10 -0
- package/dist/ui/index.js +2 -0
- package/package.json +10 -46
- package/README.md +0 -12
- package/dist/index.js +0 -114
- package/dist/runtime/api/.tsbuildinfo +0 -1
- package/dist/runtime/api/agent/agent-service.d.ts +0 -229
- package/dist/runtime/api/agent/agent-service.js +0 -963
- package/dist/runtime/api/agent/ai-providers/amp-cli-provider.d.ts +0 -38
- package/dist/runtime/api/agent/ai-providers/amp-cli-provider.js +0 -268
- package/dist/runtime/api/agent/ai-providers/claude-code-adapter.d.ts +0 -61
- package/dist/runtime/api/agent/ai-providers/claude-code-adapter.js +0 -362
- package/dist/runtime/api/agent/ai-providers/codex-cli-provider.d.ts +0 -36
- package/dist/runtime/api/agent/ai-providers/codex-cli-provider.js +0 -375
- package/dist/runtime/api/agent/ai-providers/gemini-cli-provider.d.ts +0 -24
- package/dist/runtime/api/agent/ai-providers/gemini-cli-provider.js +0 -291
- package/dist/runtime/api/agent/ai-providers/index.d.ts +0 -9
- package/dist/runtime/api/agent/ai-providers/index.js +0 -9
- package/dist/runtime/api/agent/ai-providers/types.d.ts +0 -185
- package/dist/runtime/api/agent/ai-providers/types.js +0 -5
- package/dist/runtime/api/agent/amp-cli-provider.test.d.ts +0 -1
- package/dist/runtime/api/agent/amp-cli-provider.test.js +0 -99
- package/dist/runtime/api/agent/codex-cli-provider.test.d.ts +0 -1
- package/dist/runtime/api/agent/codex-cli-provider.test.js +0 -172
- package/dist/runtime/api/agent/core-agent-service.d.ts +0 -119
- package/dist/runtime/api/agent/core-agent-service.js +0 -267
- package/dist/runtime/api/agent/parsers.d.ts +0 -16
- package/dist/runtime/api/agent/parsers.js +0 -308
- package/dist/runtime/api/agent/prompt-service.d.ts +0 -30
- package/dist/runtime/api/agent/prompt-service.js +0 -452
- package/dist/runtime/api/agent/prompt-service.test.d.ts +0 -1
- package/dist/runtime/api/agent/prompt-service.test.js +0 -265
- package/dist/runtime/api/agent/routing-policy.d.ts +0 -171
- package/dist/runtime/api/agent/routing-policy.js +0 -196
- package/dist/runtime/api/agent/routing-policy.test.d.ts +0 -1
- package/dist/runtime/api/agent/routing-policy.test.js +0 -63
- package/dist/runtime/api/api/router-helpers.d.ts +0 -32
- package/dist/runtime/api/api/router-helpers.js +0 -31
- package/dist/runtime/api/api/routers/ai.d.ts +0 -200
- package/dist/runtime/api/api/routers/ai.js +0 -396
- package/dist/runtime/api/api/routers/executions.d.ts +0 -93
- package/dist/runtime/api/api/routers/executions.js +0 -94
- package/dist/runtime/api/api/routers/git.d.ts +0 -45
- package/dist/runtime/api/api/routers/git.js +0 -35
- package/dist/runtime/api/api/routers/provider-config.d.ts +0 -199
- package/dist/runtime/api/api/routers/provider-config.js +0 -252
- package/dist/runtime/api/api/routers/settings.d.ts +0 -158
- package/dist/runtime/api/api/routers/settings.js +0 -129
- package/dist/runtime/api/api/routers/tasks.d.ts +0 -141
- package/dist/runtime/api/api/routers/tasks.js +0 -238
- package/dist/runtime/api/api/routers/workflows.d.ts +0 -275
- package/dist/runtime/api/api/routers/workflows.js +0 -311
- package/dist/runtime/api/api/routers/worktrees.d.ts +0 -101
- package/dist/runtime/api/api/routers/worktrees.js +0 -80
- package/dist/runtime/api/api/trpc.d.ts +0 -118
- package/dist/runtime/api/api/trpc.js +0 -34
- package/dist/runtime/api/index.d.ts +0 -9
- package/dist/runtime/api/index.js +0 -117
- package/dist/runtime/api/lib/id-generator.d.ts +0 -70
- package/dist/runtime/api/lib/id-generator.js +0 -123
- package/dist/runtime/api/lib/local-config.d.ts +0 -335
- package/dist/runtime/api/lib/local-config.js +0 -304
- package/dist/runtime/api/lib/logger.d.ts +0 -11
- package/dist/runtime/api/lib/logger.js +0 -188
- package/dist/runtime/api/lib/provider-detection.d.ts +0 -61
- package/dist/runtime/api/lib/provider-detection.js +0 -326
- package/dist/runtime/api/lib/server/agent-service-singleton.d.ts +0 -6
- package/dist/runtime/api/lib/server/agent-service-singleton.js +0 -27
- package/dist/runtime/api/lib/server/bootstrap.d.ts +0 -38
- package/dist/runtime/api/lib/server/bootstrap.js +0 -197
- package/dist/runtime/api/lib/server/git-service-singleton.d.ts +0 -6
- package/dist/runtime/api/lib/server/git-service-singleton.js +0 -47
- package/dist/runtime/api/lib/server/project-root.d.ts +0 -2
- package/dist/runtime/api/lib/server/project-root.js +0 -61
- package/dist/runtime/api/lib/server/task-service-singleton.d.ts +0 -7
- package/dist/runtime/api/lib/server/task-service-singleton.js +0 -58
- package/dist/runtime/api/lib/server/vibeman-info.d.ts +0 -5
- package/dist/runtime/api/lib/server/vibeman-info.js +0 -85
- package/dist/runtime/api/lib/server/vibing-orchestrator-singleton.d.ts +0 -7
- package/dist/runtime/api/lib/server/vibing-orchestrator-singleton.js +0 -57
- package/dist/runtime/api/lib/trpc/server.d.ts +0 -965
- package/dist/runtime/api/lib/trpc/server.js +0 -11
- package/dist/runtime/api/lib/trpc/ws-server.d.ts +0 -8
- package/dist/runtime/api/lib/trpc/ws-server.js +0 -33
- package/dist/runtime/api/persistence/database-service.d.ts +0 -14
- package/dist/runtime/api/persistence/database-service.js +0 -74
- package/dist/runtime/api/persistence/execution-log-persistence.d.ts +0 -90
- package/dist/runtime/api/persistence/execution-log-persistence.js +0 -426
- package/dist/runtime/api/persistence/execution-log-persistence.test.d.ts +0 -1
- package/dist/runtime/api/persistence/execution-log-persistence.test.js +0 -170
- package/dist/runtime/api/router.d.ts +0 -968
- package/dist/runtime/api/router.js +0 -34
- package/dist/runtime/api/settings-service.d.ts +0 -110
- package/dist/runtime/api/settings-service.js +0 -678
- package/dist/runtime/api/tasks/file-watcher.d.ts +0 -23
- package/dist/runtime/api/tasks/file-watcher.js +0 -88
- package/dist/runtime/api/tasks/task-file-parser.d.ts +0 -14
- package/dist/runtime/api/tasks/task-file-parser.js +0 -180
- package/dist/runtime/api/tasks/task-service.d.ts +0 -36
- package/dist/runtime/api/tasks/task-service.js +0 -173
- package/dist/runtime/api/tasks/task-updater.d.ts +0 -62
- package/dist/runtime/api/tasks/task-updater.js +0 -260
- package/dist/runtime/api/tasks/task-updater.test.d.ts +0 -1
- package/dist/runtime/api/tasks/task-updater.test.js +0 -303
- package/dist/runtime/api/types/index.d.ts +0 -186
- package/dist/runtime/api/types/index.js +0 -1
- package/dist/runtime/api/types/settings.d.ts +0 -105
- package/dist/runtime/api/types/settings.js +0 -2
- package/dist/runtime/api/types.d.ts +0 -2
- package/dist/runtime/api/types.js +0 -1
- package/dist/runtime/api/utils/env.d.ts +0 -6
- package/dist/runtime/api/utils/env.js +0 -12
- package/dist/runtime/api/utils/stripNextEnv.d.ts +0 -7
- package/dist/runtime/api/utils/stripNextEnv.js +0 -22
- package/dist/runtime/api/utils/title-slug.d.ts +0 -6
- package/dist/runtime/api/utils/title-slug.js +0 -77
- package/dist/runtime/api/utils/url.d.ts +0 -2
- package/dist/runtime/api/utils/url.js +0 -19
- package/dist/runtime/api/vcs/git-history-service.d.ts +0 -57
- package/dist/runtime/api/vcs/git-history-service.js +0 -228
- package/dist/runtime/api/vcs/git-service.d.ts +0 -136
- package/dist/runtime/api/vcs/git-service.js +0 -307
- package/dist/runtime/api/vcs/worktree-service.d.ts +0 -93
- package/dist/runtime/api/vcs/worktree-service.js +0 -518
- package/dist/runtime/api/vcs/worktree-service.test.d.ts +0 -1
- package/dist/runtime/api/vcs/worktree-service.test.js +0 -20
- package/dist/runtime/api/workflows/quality-pipeline.d.ts +0 -58
- package/dist/runtime/api/workflows/quality-pipeline.js +0 -401
- package/dist/runtime/api/workflows/vibing-orchestrator.d.ts +0 -406
- package/dist/runtime/api/workflows/vibing-orchestrator.js +0 -2462
- package/dist/runtime/api/workflows/workflow-effects.d.ts +0 -45
- package/dist/runtime/api/workflows/workflow-effects.js +0 -49
- package/dist/runtime/api/workflows/workflow-reconciler.d.ts +0 -65
- package/dist/runtime/api/workflows/workflow-reconciler.js +0 -226
- package/dist/runtime/api/workflows/workflow-reducer.d.ts +0 -26
- package/dist/runtime/api/workflows/workflow-reducer.js +0 -288
- package/dist/runtime/api/workflows/workflow-reducer.test.d.ts +0 -1
- package/dist/runtime/api/workflows/workflow-reducer.test.js +0 -247
- package/dist/runtime/api/workflows/workflow-schema.d.ts +0 -546
- package/dist/runtime/api/workflows/workflow-schema.js +0 -256
- package/dist/runtime/web/.next/BUILD_ID +0 -1
- package/dist/runtime/web/.next/app-build-manifest.json +0 -66
- package/dist/runtime/web/.next/app-path-routes-manifest.json +0 -8
- package/dist/runtime/web/.next/build-manifest.json +0 -33
- package/dist/runtime/web/.next/package.json +0 -1
- package/dist/runtime/web/.next/prerender-manifest.json +0 -61
- package/dist/runtime/web/.next/react-loadable-manifest.json +0 -8
- package/dist/runtime/web/.next/required-server-files.json +0 -334
- package/dist/runtime/web/.next/routes-manifest.json +0 -70
- package/dist/runtime/web/.next/server/app/.vibeman/assets/images/[...path]/route.js +0 -1
- package/dist/runtime/web/.next/server/app/.vibeman/assets/images/[...path]/route.js.nft.json +0 -1
- package/dist/runtime/web/.next/server/app/.vibeman/assets/images/[...path]/route_client-reference-manifest.js +0 -1
- package/dist/runtime/web/.next/server/app/_not-found/page.js +0 -2
- package/dist/runtime/web/.next/server/app/_not-found/page.js.nft.json +0 -1
- package/dist/runtime/web/.next/server/app/_not-found/page_client-reference-manifest.js +0 -1
- package/dist/runtime/web/.next/server/app/_not-found.html +0 -7
- package/dist/runtime/web/.next/server/app/_not-found.meta +0 -8
- package/dist/runtime/web/.next/server/app/_not-found.rsc +0 -22
- package/dist/runtime/web/.next/server/app/api/health/route.js +0 -1
- package/dist/runtime/web/.next/server/app/api/health/route.js.nft.json +0 -1
- package/dist/runtime/web/.next/server/app/api/health/route_client-reference-manifest.js +0 -1
- package/dist/runtime/web/.next/server/app/api/images/[...path]/route.js +0 -1
- package/dist/runtime/web/.next/server/app/api/images/[...path]/route.js.nft.json +0 -1
- package/dist/runtime/web/.next/server/app/api/images/[...path]/route_client-reference-manifest.js +0 -1
- package/dist/runtime/web/.next/server/app/api/upload/route.js +0 -1
- package/dist/runtime/web/.next/server/app/api/upload/route.js.nft.json +0 -1
- package/dist/runtime/web/.next/server/app/api/upload/route_client-reference-manifest.js +0 -1
- package/dist/runtime/web/.next/server/app/index.html +0 -7
- package/dist/runtime/web/.next/server/app/index.meta +0 -7
- package/dist/runtime/web/.next/server/app/index.rsc +0 -27
- package/dist/runtime/web/.next/server/app/page.js +0 -112
- package/dist/runtime/web/.next/server/app/page.js.nft.json +0 -1
- package/dist/runtime/web/.next/server/app/page_client-reference-manifest.js +0 -1
- package/dist/runtime/web/.next/server/app-paths-manifest.json +0 -8
- package/dist/runtime/web/.next/server/chunks/210.js +0 -1
- package/dist/runtime/web/.next/server/chunks/291.js +0 -18
- package/dist/runtime/web/.next/server/chunks/552.js +0 -22
- package/dist/runtime/web/.next/server/chunks/780.js +0 -1
- package/dist/runtime/web/.next/server/chunks/905.js +0 -6
- package/dist/runtime/web/.next/server/chunks/98.js +0 -1
- package/dist/runtime/web/.next/server/functions-config-manifest.json +0 -4
- package/dist/runtime/web/.next/server/middleware-build-manifest.js +0 -1
- package/dist/runtime/web/.next/server/middleware-manifest.json +0 -6
- package/dist/runtime/web/.next/server/middleware-react-loadable-manifest.js +0 -1
- package/dist/runtime/web/.next/server/next-font-manifest.js +0 -1
- package/dist/runtime/web/.next/server/next-font-manifest.json +0 -1
- package/dist/runtime/web/.next/server/pages/404.html +0 -7
- package/dist/runtime/web/.next/server/pages/500.html +0 -1
- package/dist/runtime/web/.next/server/pages/_app.js +0 -1
- package/dist/runtime/web/.next/server/pages/_app.js.nft.json +0 -1
- package/dist/runtime/web/.next/server/pages/_document.js +0 -1
- package/dist/runtime/web/.next/server/pages/_document.js.nft.json +0 -1
- package/dist/runtime/web/.next/server/pages/_error.js +0 -19
- package/dist/runtime/web/.next/server/pages/_error.js.nft.json +0 -1
- package/dist/runtime/web/.next/server/pages-manifest.json +0 -6
- package/dist/runtime/web/.next/server/server-reference-manifest.js +0 -1
- package/dist/runtime/web/.next/server/server-reference-manifest.json +0 -1
- package/dist/runtime/web/.next/server/webpack-runtime.js +0 -1
- package/dist/runtime/web/.next/static/LJFZk_8tvKFN_Ee4HqUuM/_buildManifest.js +0 -1
- package/dist/runtime/web/.next/static/LJFZk_8tvKFN_Ee4HqUuM/_ssgManifest.js +0 -1
- package/dist/runtime/web/.next/static/chunks/05c91ade-7d09b2b280adffd1.js +0 -1
- package/dist/runtime/web/.next/static/chunks/201-51bef3fa8c832e2e.js +0 -1
- package/dist/runtime/web/.next/static/chunks/524-89747ed9b0294f8a.js +0 -1
- package/dist/runtime/web/.next/static/chunks/554-8bec6e9cca6acc67.js +0 -1
- package/dist/runtime/web/.next/static/chunks/764.86e9503a69d45a85.js +0 -1
- package/dist/runtime/web/.next/static/chunks/7ab4dc20-239138e0ae7af24a.js +0 -1
- package/dist/runtime/web/.next/static/chunks/905-342391e3d3a3678f.js +0 -20
- package/dist/runtime/web/.next/static/chunks/a8a5ce16-4edea7df2d9b544a.js +0 -79
- package/dist/runtime/web/.next/static/chunks/ad74d572-4c1b162e2c15acaa.js +0 -1
- package/dist/runtime/web/.next/static/chunks/app/.vibeman/assets/images/[...path]/route-7b752a8641f96c1f.js +0 -1
- package/dist/runtime/web/.next/static/chunks/app/_not-found/page-34e66b251c2b5044.js +0 -1
- package/dist/runtime/web/.next/static/chunks/app/api/health/route-7b752a8641f96c1f.js +0 -1
- package/dist/runtime/web/.next/static/chunks/app/api/images/[...path]/route-7b752a8641f96c1f.js +0 -1
- package/dist/runtime/web/.next/static/chunks/app/api/upload/route-7b752a8641f96c1f.js +0 -1
- package/dist/runtime/web/.next/static/chunks/app/layout-df9ac93cb02b2385.js +0 -1
- package/dist/runtime/web/.next/static/chunks/app/page-6610743f7de5f92a.js +0 -1
- package/dist/runtime/web/.next/static/chunks/c25e0690-e9b798b8de667da1.js +0 -1
- package/dist/runtime/web/.next/static/chunks/framework-57157ec4d37f64aa.js +0 -1
- package/dist/runtime/web/.next/static/chunks/main-app-156cc0c60371bd78.js +0 -1
- package/dist/runtime/web/.next/static/chunks/main-df25d367c47b1fec.js +0 -1
- package/dist/runtime/web/.next/static/chunks/pages/_app-9f629a5e1131d19f.js +0 -1
- package/dist/runtime/web/.next/static/chunks/pages/_error-9238238274c7efcd.js +0 -1
- package/dist/runtime/web/.next/static/chunks/polyfills-42372ed130431b0a.js +0 -1
- package/dist/runtime/web/.next/static/chunks/webpack-cd50e39b423d1808.js +0 -1
- package/dist/runtime/web/.next/static/css/2728291c68f99cb1.css +0 -3
- package/dist/runtime/web/.next/static/css/4fbf378a264bd4ea.css +0 -1
- package/dist/runtime/web/.next/static/css/521bd69cc298cd1a.css +0 -1
- package/dist/runtime/web/.next/static/css/537e22821e101b87.css +0 -1
- package/dist/runtime/web/.next/static/media/19cfc7226ec3afaa-s.woff2 +0 -0
- package/dist/runtime/web/.next/static/media/21350d82a1f187e9-s.woff2 +0 -0
- package/dist/runtime/web/.next/static/media/8e9860b6e62d6359-s.woff2 +0 -0
- package/dist/runtime/web/.next/static/media/ba9851c3c22cd980-s.woff2 +0 -0
- package/dist/runtime/web/.next/static/media/c5fe6dc8356a8c31-s.woff2 +0 -0
- package/dist/runtime/web/.next/static/media/df0a9ae256c0569c-s.woff2 +0 -0
- package/dist/runtime/web/.next/static/media/e4af272ccee01ff0-s.p.woff2 +0 -0
- package/dist/runtime/web/package.json +0 -65
- package/dist/runtime/web/server.js +0 -44
- package/dist/tsconfig.tsbuildinfo +0 -1
|
@@ -1,228 +0,0 @@
|
|
|
1
|
-
import { simpleGit } from 'simple-git';
|
|
2
|
-
import { getProjectRoot } from '../lib/server/project-root.js';
|
|
3
|
-
import { log } from '../lib/logger.js';
|
|
4
|
-
import path from 'path';
|
|
5
|
-
export class GitHistoryService {
|
|
6
|
-
constructor(projectRoot = getProjectRoot()) {
|
|
7
|
-
this.projectRoot = projectRoot;
|
|
8
|
-
this.git = simpleGit(projectRoot);
|
|
9
|
-
}
|
|
10
|
-
/**
|
|
11
|
-
* Get the history of changes for a specific task file
|
|
12
|
-
*/
|
|
13
|
-
async getTaskHistory(taskId, limit = 50) {
|
|
14
|
-
try {
|
|
15
|
-
const taskFilePath = path.join('.vibeman', 'tasks', `${taskId}.md`);
|
|
16
|
-
// Check if the task file exists in the current working directory
|
|
17
|
-
const taskExists = await this.git.raw(['ls-files', taskFilePath]).then((output) => output.trim().length > 0, () => false);
|
|
18
|
-
if (!taskExists) {
|
|
19
|
-
// File doesn't exist in Git, return empty history
|
|
20
|
-
return [];
|
|
21
|
-
}
|
|
22
|
-
// Use --follow to track file through renames and --no-merges to avoid merge commits
|
|
23
|
-
const logResult = await this.git.raw([
|
|
24
|
-
'log',
|
|
25
|
-
'--follow',
|
|
26
|
-
'--no-merges',
|
|
27
|
-
'--pretty=format:%H|%h|%an|%ad|%s',
|
|
28
|
-
'--date=iso',
|
|
29
|
-
`--max-count=${limit}`,
|
|
30
|
-
'--',
|
|
31
|
-
taskFilePath,
|
|
32
|
-
]);
|
|
33
|
-
if (!logResult.trim()) {
|
|
34
|
-
return [];
|
|
35
|
-
}
|
|
36
|
-
const commits = logResult.trim().split('\n');
|
|
37
|
-
const history = [];
|
|
38
|
-
for (const commitLine of commits) {
|
|
39
|
-
const [hash, shortHash, author, dateStr, ...messageParts] = commitLine.split('|');
|
|
40
|
-
const message = messageParts.join('|'); // Rejoin in case message contains |
|
|
41
|
-
if (!hash || !shortHash || !author || !dateStr) {
|
|
42
|
-
continue;
|
|
43
|
-
}
|
|
44
|
-
try {
|
|
45
|
-
// Get the diff stats for this specific file in this commit
|
|
46
|
-
const stats = await this.getCommitStats(hash, taskFilePath);
|
|
47
|
-
history.push({
|
|
48
|
-
commitHash: hash,
|
|
49
|
-
shortHash,
|
|
50
|
-
author,
|
|
51
|
-
date: new Date(dateStr),
|
|
52
|
-
message,
|
|
53
|
-
changes: stats,
|
|
54
|
-
});
|
|
55
|
-
}
|
|
56
|
-
catch (error) {
|
|
57
|
-
log.warn('Failed to get stats for commit', { hash, error }, 'git-history-service');
|
|
58
|
-
// Add entry without stats
|
|
59
|
-
history.push({
|
|
60
|
-
commitHash: hash,
|
|
61
|
-
shortHash,
|
|
62
|
-
author,
|
|
63
|
-
date: new Date(dateStr),
|
|
64
|
-
message,
|
|
65
|
-
changes: { additions: 0, deletions: 0 },
|
|
66
|
-
});
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
return history;
|
|
70
|
-
}
|
|
71
|
-
catch (error) {
|
|
72
|
-
log.error('Failed to get task history', { taskId, error }, 'git-history-service');
|
|
73
|
-
throw new Error(`Failed to retrieve history for task ${taskId}: ${String(error)}`);
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
/**
|
|
77
|
-
* Get the content of a task file at a specific commit
|
|
78
|
-
*/
|
|
79
|
-
async getTaskVersionContent(taskId, commitHash) {
|
|
80
|
-
try {
|
|
81
|
-
const taskFilePath = path.join('.vibeman', 'tasks', `${taskId}.md`);
|
|
82
|
-
// Get the file content at the specific commit
|
|
83
|
-
const content = await this.git.show([`${commitHash}:${taskFilePath}`]);
|
|
84
|
-
// Get commit information
|
|
85
|
-
const commitInfo = await this.git.raw([
|
|
86
|
-
'show',
|
|
87
|
-
'--pretty=format:%an|%ad',
|
|
88
|
-
'--date=iso',
|
|
89
|
-
'--no-patch',
|
|
90
|
-
commitHash,
|
|
91
|
-
]);
|
|
92
|
-
const [author, dateStr] = commitInfo.trim().split('|');
|
|
93
|
-
return {
|
|
94
|
-
commitHash,
|
|
95
|
-
content,
|
|
96
|
-
date: new Date(dateStr),
|
|
97
|
-
author: author || 'Unknown',
|
|
98
|
-
};
|
|
99
|
-
}
|
|
100
|
-
catch (error) {
|
|
101
|
-
log.error('Failed to get task version content', { taskId, commitHash, error }, 'git-history-service');
|
|
102
|
-
throw new Error(`Failed to retrieve content for task ${taskId} at commit ${commitHash}: ${String(error)}`);
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
/**
|
|
106
|
-
* Get the diff between two versions of a task file
|
|
107
|
-
*/
|
|
108
|
-
async getTaskDiff(taskId, fromHash, toHash) {
|
|
109
|
-
try {
|
|
110
|
-
const taskFilePath = path.join('.vibeman', 'tasks', `${taskId}.md`);
|
|
111
|
-
// Get the diff between two commits for the specific file
|
|
112
|
-
const diff = await this.git.raw(['diff', `${fromHash}..${toHash}`, '--', taskFilePath]);
|
|
113
|
-
// Get diff stats
|
|
114
|
-
const stats = await this.git.raw([
|
|
115
|
-
'diff',
|
|
116
|
-
'--numstat',
|
|
117
|
-
`${fromHash}..${toHash}`,
|
|
118
|
-
'--',
|
|
119
|
-
taskFilePath,
|
|
120
|
-
]);
|
|
121
|
-
let additions = 0;
|
|
122
|
-
let deletions = 0;
|
|
123
|
-
if (stats.trim()) {
|
|
124
|
-
const [addStr, delStr] = stats.trim().split('\t');
|
|
125
|
-
additions = parseInt(addStr, 10) || 0;
|
|
126
|
-
deletions = parseInt(delStr, 10) || 0;
|
|
127
|
-
}
|
|
128
|
-
return {
|
|
129
|
-
fromHash,
|
|
130
|
-
toHash,
|
|
131
|
-
diff,
|
|
132
|
-
additions,
|
|
133
|
-
deletions,
|
|
134
|
-
};
|
|
135
|
-
}
|
|
136
|
-
catch (error) {
|
|
137
|
-
log.error('Failed to get task diff', { taskId, fromHash, toHash, error }, 'git-history-service');
|
|
138
|
-
throw new Error(`Failed to get diff for task ${taskId} between ${fromHash} and ${toHash}: ${String(error)}`);
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
/**
|
|
142
|
-
* Check if Git repository exists and is properly configured
|
|
143
|
-
*/
|
|
144
|
-
async isGitRepositoryAvailable() {
|
|
145
|
-
try {
|
|
146
|
-
const isRepo = await this.git.checkIsRepo();
|
|
147
|
-
return isRepo;
|
|
148
|
-
}
|
|
149
|
-
catch {
|
|
150
|
-
return false;
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
/**
|
|
154
|
-
* Get commit statistics for a specific file in a commit
|
|
155
|
-
*/
|
|
156
|
-
async getCommitStats(commitHash, filePath) {
|
|
157
|
-
try {
|
|
158
|
-
// Get the parent commit hash
|
|
159
|
-
const parentHash = await this.git.raw(['rev-parse', `${commitHash}^`]).catch(() => {
|
|
160
|
-
// This is likely the initial commit, compare against empty tree
|
|
161
|
-
return '4b825dc642cb6eb9a060e54bf8d69288fbee4904'; // Git's empty tree hash
|
|
162
|
-
});
|
|
163
|
-
const stats = await this.git.raw([
|
|
164
|
-
'diff',
|
|
165
|
-
'--numstat',
|
|
166
|
-
parentHash.trim(),
|
|
167
|
-
commitHash,
|
|
168
|
-
'--',
|
|
169
|
-
filePath,
|
|
170
|
-
]);
|
|
171
|
-
if (!stats.trim()) {
|
|
172
|
-
return { additions: 0, deletions: 0 };
|
|
173
|
-
}
|
|
174
|
-
const [addStr, delStr] = stats.trim().split('\t');
|
|
175
|
-
return {
|
|
176
|
-
additions: parseInt(addStr, 10) || 0,
|
|
177
|
-
deletions: parseInt(delStr, 10) || 0,
|
|
178
|
-
};
|
|
179
|
-
}
|
|
180
|
-
catch {
|
|
181
|
-
return { additions: 0, deletions: 0 };
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
/**
|
|
185
|
-
* Check if a task file has been renamed or moved by tracking it through Git history
|
|
186
|
-
*/
|
|
187
|
-
async getTaskFileRenames(taskId) {
|
|
188
|
-
try {
|
|
189
|
-
const taskFilePath = path.join('.vibeman', 'tasks', `${taskId}.md`);
|
|
190
|
-
// Use git log --follow --name-status to track renames
|
|
191
|
-
const logResult = await this.git.raw([
|
|
192
|
-
'log',
|
|
193
|
-
'--follow',
|
|
194
|
-
'--name-status',
|
|
195
|
-
'--pretty=format:%H',
|
|
196
|
-
'--',
|
|
197
|
-
taskFilePath,
|
|
198
|
-
]);
|
|
199
|
-
const renames = [];
|
|
200
|
-
const lines = logResult.trim().split('\n');
|
|
201
|
-
let currentCommit = '';
|
|
202
|
-
for (const line of lines) {
|
|
203
|
-
if (line.match(/^[a-f0-9]{40}$/)) {
|
|
204
|
-
// This is a commit hash
|
|
205
|
-
currentCommit = line;
|
|
206
|
-
}
|
|
207
|
-
else if (line.startsWith('R') && currentCommit) {
|
|
208
|
-
// This is a rename operation (R100, R090, etc.)
|
|
209
|
-
const parts = line.split('\t');
|
|
210
|
-
if (parts.length >= 3) {
|
|
211
|
-
const oldPath = parts[1];
|
|
212
|
-
const newPath = parts[2];
|
|
213
|
-
renames.push({
|
|
214
|
-
oldPath,
|
|
215
|
-
newPath,
|
|
216
|
-
commitHash: currentCommit,
|
|
217
|
-
});
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
return renames;
|
|
222
|
-
}
|
|
223
|
-
catch (error) {
|
|
224
|
-
log.warn('Failed to get task file renames', { taskId, error }, 'git-history-service');
|
|
225
|
-
return [];
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
}
|
|
@@ -1,136 +0,0 @@
|
|
|
1
|
-
import { SimpleGit, VersionResult } from 'simple-git';
|
|
2
|
-
import { Task } from '../types/index.js';
|
|
3
|
-
export interface GitConfig {
|
|
4
|
-
remoteUrl?: string;
|
|
5
|
-
defaultBranch?: string;
|
|
6
|
-
}
|
|
7
|
-
export interface BranchInfo {
|
|
8
|
-
name: string;
|
|
9
|
-
exists: boolean;
|
|
10
|
-
isCurrentBranch: boolean;
|
|
11
|
-
}
|
|
12
|
-
export interface CommitInfo {
|
|
13
|
-
hash: string;
|
|
14
|
-
message: string;
|
|
15
|
-
author: string;
|
|
16
|
-
date: Date;
|
|
17
|
-
}
|
|
18
|
-
export interface WorktreeCreationResult {
|
|
19
|
-
path: string;
|
|
20
|
-
branchName: string;
|
|
21
|
-
existed: boolean;
|
|
22
|
-
}
|
|
23
|
-
export declare class GitService {
|
|
24
|
-
private git;
|
|
25
|
-
private config;
|
|
26
|
-
private projectRoot;
|
|
27
|
-
constructor(projectRoot?: string, config?: GitConfig);
|
|
28
|
-
getProjectRoot(): string;
|
|
29
|
-
/**
|
|
30
|
-
* Validate Git repository exists and is properly configured
|
|
31
|
-
*/
|
|
32
|
-
initializeRepository(): Promise<void>;
|
|
33
|
-
/**
|
|
34
|
-
* Get current Git status
|
|
35
|
-
*/
|
|
36
|
-
getStatus(): Promise<{
|
|
37
|
-
current: string;
|
|
38
|
-
staged: string[];
|
|
39
|
-
modified: string[];
|
|
40
|
-
untracked: string[];
|
|
41
|
-
ahead: number;
|
|
42
|
-
behind: number;
|
|
43
|
-
}>;
|
|
44
|
-
/**
|
|
45
|
-
* Generate branch name from task
|
|
46
|
-
*/
|
|
47
|
-
generateBranchName(task: Task): string;
|
|
48
|
-
/**
|
|
49
|
-
* Create a new branch for a task
|
|
50
|
-
*/
|
|
51
|
-
createBranch(task: Task, baseBranch?: string): Promise<BranchInfo>;
|
|
52
|
-
/**
|
|
53
|
-
* Stage and commit changes
|
|
54
|
-
*/
|
|
55
|
-
commitChanges(task: Task, message?: string, files?: string[]): Promise<CommitInfo>;
|
|
56
|
-
/**
|
|
57
|
-
* Generate standardized commit message
|
|
58
|
-
*/
|
|
59
|
-
generateCommitMessage(task: Task): string;
|
|
60
|
-
/**
|
|
61
|
-
* Get commit history for current branch
|
|
62
|
-
*/
|
|
63
|
-
getCommitHistory(maxCount?: number): Promise<CommitInfo[]>;
|
|
64
|
-
/**
|
|
65
|
-
* Get Git version information
|
|
66
|
-
*/
|
|
67
|
-
getGitVersion(): Promise<VersionResult>;
|
|
68
|
-
/**
|
|
69
|
-
* Check whether a path is ignored by git.
|
|
70
|
-
*/
|
|
71
|
-
isIgnored(relativePath: string): Promise<boolean>;
|
|
72
|
-
/**
|
|
73
|
-
* Get the current HEAD commit hash
|
|
74
|
-
*/
|
|
75
|
-
getHeadCommitHash(short?: boolean): Promise<string>;
|
|
76
|
-
/**
|
|
77
|
-
* List all worktrees in the repository
|
|
78
|
-
*/
|
|
79
|
-
listWorktrees(): Promise<{
|
|
80
|
-
path: string;
|
|
81
|
-
branch: string;
|
|
82
|
-
prunable?: boolean;
|
|
83
|
-
}[]>;
|
|
84
|
-
/**
|
|
85
|
-
* Parse git worktree list output
|
|
86
|
-
*/
|
|
87
|
-
private parseWorktreeList;
|
|
88
|
-
/**
|
|
89
|
-
* Create a new worktree
|
|
90
|
-
*/
|
|
91
|
-
createWorktree(worktreePath: string, branchName: string, branchExists?: boolean): Promise<void>;
|
|
92
|
-
/**
|
|
93
|
-
* Remove a worktree
|
|
94
|
-
*/
|
|
95
|
-
removeWorktree(worktreePath: string, force?: boolean): Promise<void>;
|
|
96
|
-
/**
|
|
97
|
-
* Prune stale worktrees
|
|
98
|
-
*/
|
|
99
|
-
pruneWorktrees(): Promise<void>;
|
|
100
|
-
/**
|
|
101
|
-
* Delete a local branch
|
|
102
|
-
*/
|
|
103
|
-
deleteLocalBranch(branchName: string, force?: boolean): Promise<void>;
|
|
104
|
-
/**
|
|
105
|
-
* Check if branch exists locally
|
|
106
|
-
*/
|
|
107
|
-
branchExists(branchName: string): Promise<boolean>;
|
|
108
|
-
/**
|
|
109
|
-
* Sync with remote repository
|
|
110
|
-
*/
|
|
111
|
-
syncWithRemote(branchName?: string): Promise<void>;
|
|
112
|
-
/**
|
|
113
|
-
* Get Git instance for a specific directory
|
|
114
|
-
*/
|
|
115
|
-
getGitInstance(directory: string): SimpleGit;
|
|
116
|
-
/**
|
|
117
|
-
* Check Git status for a specific directory
|
|
118
|
-
*/
|
|
119
|
-
getGitStatus(directory: string): Promise<{
|
|
120
|
-
modified: string[];
|
|
121
|
-
staged: string[];
|
|
122
|
-
not_added: string[];
|
|
123
|
-
}>;
|
|
124
|
-
/**
|
|
125
|
-
* Check if directory has uncommitted changes
|
|
126
|
-
*/
|
|
127
|
-
hasUncommittedChanges(directory?: string): Promise<boolean>;
|
|
128
|
-
/**
|
|
129
|
-
* Get log for a specific directory/worktree
|
|
130
|
-
*/
|
|
131
|
-
getLog(directory: string, options: string[]): Promise<any>;
|
|
132
|
-
/**
|
|
133
|
-
* Push branch from specific directory
|
|
134
|
-
*/
|
|
135
|
-
pushFromDirectory(directory: string, remote: string, branchName: string, options?: string[]): Promise<void>;
|
|
136
|
-
}
|
|
@@ -1,307 +0,0 @@
|
|
|
1
|
-
import { simpleGit } from 'simple-git';
|
|
2
|
-
import { log } from '../lib/logger.js';
|
|
3
|
-
import { getProjectRoot } from '../lib/server/project-root.js';
|
|
4
|
-
export class GitService {
|
|
5
|
-
constructor(projectRoot = getProjectRoot(), config = {}) {
|
|
6
|
-
this.projectRoot = projectRoot;
|
|
7
|
-
this.config = config;
|
|
8
|
-
this.git = simpleGit(projectRoot);
|
|
9
|
-
}
|
|
10
|
-
getProjectRoot() {
|
|
11
|
-
return this.projectRoot;
|
|
12
|
-
}
|
|
13
|
-
/**
|
|
14
|
-
* Validate Git repository exists and is properly configured
|
|
15
|
-
*/
|
|
16
|
-
async initializeRepository() {
|
|
17
|
-
const isRepo = await this.git.checkIsRepo();
|
|
18
|
-
if (!isRepo) {
|
|
19
|
-
const error = new Error(`Directory ${this.projectRoot} is not a Git repository. Please run 'git init' first.`);
|
|
20
|
-
log.error('Git repository not found', error, 'git-service');
|
|
21
|
-
throw error;
|
|
22
|
-
}
|
|
23
|
-
// Set up basic Git configuration if not present
|
|
24
|
-
try {
|
|
25
|
-
await this.git.raw(['config', 'user.name']);
|
|
26
|
-
}
|
|
27
|
-
catch {
|
|
28
|
-
await this.git.addConfig('user.name', 'Vibeman');
|
|
29
|
-
await this.git.addConfig('user.email', 'vibeman@localhost');
|
|
30
|
-
log.info('Set default Git user configuration', undefined, 'git-service');
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
/**
|
|
34
|
-
* Get current Git status
|
|
35
|
-
*/
|
|
36
|
-
async getStatus() {
|
|
37
|
-
const status = await this.git.status();
|
|
38
|
-
return {
|
|
39
|
-
current: status.current || 'main',
|
|
40
|
-
staged: status.staged,
|
|
41
|
-
modified: status.modified,
|
|
42
|
-
untracked: status.not_added,
|
|
43
|
-
ahead: status.ahead,
|
|
44
|
-
behind: status.behind,
|
|
45
|
-
};
|
|
46
|
-
}
|
|
47
|
-
/**
|
|
48
|
-
* Generate branch name from task
|
|
49
|
-
*/
|
|
50
|
-
generateBranchName(task) {
|
|
51
|
-
const typePrefix = {
|
|
52
|
-
feature: 'feat',
|
|
53
|
-
bug: 'fix',
|
|
54
|
-
chore: 'chore',
|
|
55
|
-
refactor: 'refactor',
|
|
56
|
-
test: 'test',
|
|
57
|
-
doc: 'docs',
|
|
58
|
-
}[task.type];
|
|
59
|
-
// Keep branch concise and deterministic, use only the task id
|
|
60
|
-
return `${typePrefix}/${task.id.toLowerCase()}`;
|
|
61
|
-
}
|
|
62
|
-
/**
|
|
63
|
-
* Create a new branch for a task
|
|
64
|
-
*/
|
|
65
|
-
async createBranch(task, baseBranch) {
|
|
66
|
-
const branchName = this.generateBranchName(task);
|
|
67
|
-
const base = baseBranch || this.config.defaultBranch || 'main';
|
|
68
|
-
// Check if branch already exists
|
|
69
|
-
const branches = await this.git.branchLocal();
|
|
70
|
-
const exists = branches.all.includes(branchName);
|
|
71
|
-
if (exists) {
|
|
72
|
-
log.info('Branch already exists', { branchName }, 'git-service');
|
|
73
|
-
await this.git.checkout(branchName);
|
|
74
|
-
return {
|
|
75
|
-
name: branchName,
|
|
76
|
-
exists: true,
|
|
77
|
-
isCurrentBranch: true,
|
|
78
|
-
};
|
|
79
|
-
}
|
|
80
|
-
// Ensure we're on the base branch and it's up to date
|
|
81
|
-
try {
|
|
82
|
-
await this.git.checkout(base);
|
|
83
|
-
await this.git.pull('origin', base);
|
|
84
|
-
}
|
|
85
|
-
catch (error) {
|
|
86
|
-
log.warn('Could not update base branch', error, 'git-service');
|
|
87
|
-
}
|
|
88
|
-
// Create and checkout new branch
|
|
89
|
-
await this.git.checkoutLocalBranch(branchName);
|
|
90
|
-
log.info('Created and checked out branch', { branchName }, 'git-service');
|
|
91
|
-
return {
|
|
92
|
-
name: branchName,
|
|
93
|
-
exists: false,
|
|
94
|
-
isCurrentBranch: true,
|
|
95
|
-
};
|
|
96
|
-
}
|
|
97
|
-
/**
|
|
98
|
-
* Stage and commit changes
|
|
99
|
-
*/
|
|
100
|
-
async commitChanges(task, message, files = ['.']) {
|
|
101
|
-
// Stage only the specified files
|
|
102
|
-
for (const file of files) {
|
|
103
|
-
await this.git.add(file);
|
|
104
|
-
}
|
|
105
|
-
// Generate commit message if not provided
|
|
106
|
-
const commitMessage = message || this.generateCommitMessage(task);
|
|
107
|
-
// Commit only the specified files (avoid committing other pre-staged changes)
|
|
108
|
-
const result = await this.git.commit(commitMessage, files);
|
|
109
|
-
log.info('Committed changes', { commit: result.commit }, 'git-service');
|
|
110
|
-
return {
|
|
111
|
-
hash: result.commit,
|
|
112
|
-
message: commitMessage,
|
|
113
|
-
author: 'Vibeman',
|
|
114
|
-
date: new Date(),
|
|
115
|
-
};
|
|
116
|
-
}
|
|
117
|
-
/**
|
|
118
|
-
* Generate standardized commit message
|
|
119
|
-
*/
|
|
120
|
-
generateCommitMessage(task) {
|
|
121
|
-
const typeMap = {
|
|
122
|
-
feature: 'feat',
|
|
123
|
-
bug: 'fix',
|
|
124
|
-
chore: 'chore',
|
|
125
|
-
refactor: 'refactor',
|
|
126
|
-
test: 'test',
|
|
127
|
-
doc: 'docs',
|
|
128
|
-
};
|
|
129
|
-
const type = typeMap[task.type];
|
|
130
|
-
const scope = task.tags.length > 0 ? `(${task.tags[0]})` : '';
|
|
131
|
-
return `${type}${scope}: ${task.title}\n\n${task.id}: ${task.title}\n\nImplemented via Vibeman`;
|
|
132
|
-
}
|
|
133
|
-
/**
|
|
134
|
-
* Get commit history for current branch
|
|
135
|
-
*/
|
|
136
|
-
async getCommitHistory(maxCount = 10) {
|
|
137
|
-
const log = await this.git.log({ maxCount });
|
|
138
|
-
return log.all.map((commit) => ({
|
|
139
|
-
hash: commit.hash,
|
|
140
|
-
message: commit.message,
|
|
141
|
-
author: commit.author_name,
|
|
142
|
-
date: new Date(commit.date),
|
|
143
|
-
}));
|
|
144
|
-
}
|
|
145
|
-
/**
|
|
146
|
-
* Get Git version information
|
|
147
|
-
*/
|
|
148
|
-
async getGitVersion() {
|
|
149
|
-
return await this.git.version();
|
|
150
|
-
}
|
|
151
|
-
/**
|
|
152
|
-
* Check whether a path is ignored by git.
|
|
153
|
-
*/
|
|
154
|
-
async isIgnored(relativePath) {
|
|
155
|
-
try {
|
|
156
|
-
await this.git.raw(['check-ignore', '-q', relativePath]);
|
|
157
|
-
return true;
|
|
158
|
-
}
|
|
159
|
-
catch (error) {
|
|
160
|
-
return false;
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
/**
|
|
164
|
-
* Get the current HEAD commit hash
|
|
165
|
-
*/
|
|
166
|
-
async getHeadCommitHash(short = true) {
|
|
167
|
-
const args = short ? ['--short', 'HEAD'] : ['HEAD'];
|
|
168
|
-
const hash = await this.git.revparse(args);
|
|
169
|
-
return hash.trim();
|
|
170
|
-
}
|
|
171
|
-
/**
|
|
172
|
-
* List all worktrees in the repository
|
|
173
|
-
*/
|
|
174
|
-
async listWorktrees() {
|
|
175
|
-
const worktreeList = await this.git.raw(['worktree', 'list', '--porcelain']);
|
|
176
|
-
return this.parseWorktreeList(worktreeList);
|
|
177
|
-
}
|
|
178
|
-
/**
|
|
179
|
-
* Parse git worktree list output
|
|
180
|
-
*/
|
|
181
|
-
parseWorktreeList(output) {
|
|
182
|
-
const lines = output.trim().split('\n');
|
|
183
|
-
const worktrees = [];
|
|
184
|
-
let currentWorktree = {};
|
|
185
|
-
for (const line of lines) {
|
|
186
|
-
if (line.startsWith('worktree ')) {
|
|
187
|
-
if (currentWorktree.path) {
|
|
188
|
-
worktrees.push(currentWorktree);
|
|
189
|
-
}
|
|
190
|
-
currentWorktree = { path: line.substring(9) };
|
|
191
|
-
}
|
|
192
|
-
else if (line.startsWith('branch ')) {
|
|
193
|
-
const ref = line.substring(7);
|
|
194
|
-
// Strip refs/heads/ prefix if present for readability
|
|
195
|
-
currentWorktree.branch = ref.startsWith('refs/heads/') ? ref.substring(11) : ref;
|
|
196
|
-
}
|
|
197
|
-
else if (line.startsWith('prunable')) {
|
|
198
|
-
currentWorktree.prunable = true;
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
if (currentWorktree.path) {
|
|
202
|
-
worktrees.push(currentWorktree);
|
|
203
|
-
}
|
|
204
|
-
return worktrees;
|
|
205
|
-
}
|
|
206
|
-
/**
|
|
207
|
-
* Create a new worktree
|
|
208
|
-
*/
|
|
209
|
-
async createWorktree(worktreePath, branchName, branchExists) {
|
|
210
|
-
if (branchExists) {
|
|
211
|
-
// Create worktree attached to existing branch (no -b)
|
|
212
|
-
await this.git.raw(['worktree', 'add', worktreePath, branchName]);
|
|
213
|
-
}
|
|
214
|
-
else {
|
|
215
|
-
// Create worktree and new branch
|
|
216
|
-
await this.git.raw(['worktree', 'add', worktreePath, '-b', branchName]);
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
/**
|
|
220
|
-
* Remove a worktree
|
|
221
|
-
*/
|
|
222
|
-
async removeWorktree(worktreePath, force = false) {
|
|
223
|
-
const args = ['worktree', 'remove', worktreePath];
|
|
224
|
-
if (force)
|
|
225
|
-
args.push('--force');
|
|
226
|
-
await this.git.raw(args);
|
|
227
|
-
}
|
|
228
|
-
/**
|
|
229
|
-
* Prune stale worktrees
|
|
230
|
-
*/
|
|
231
|
-
async pruneWorktrees() {
|
|
232
|
-
await this.git.raw(['worktree', 'prune']);
|
|
233
|
-
}
|
|
234
|
-
/**
|
|
235
|
-
* Delete a local branch
|
|
236
|
-
*/
|
|
237
|
-
async deleteLocalBranch(branchName, force = false) {
|
|
238
|
-
await this.git.deleteLocalBranch(branchName, force);
|
|
239
|
-
}
|
|
240
|
-
/**
|
|
241
|
-
* Check if branch exists locally
|
|
242
|
-
*/
|
|
243
|
-
async branchExists(branchName) {
|
|
244
|
-
const localBranches = await this.git.branchLocal();
|
|
245
|
-
return !!localBranches.all.find((b) => b === branchName);
|
|
246
|
-
}
|
|
247
|
-
/**
|
|
248
|
-
* Sync with remote repository
|
|
249
|
-
*/
|
|
250
|
-
async syncWithRemote(branchName) {
|
|
251
|
-
try {
|
|
252
|
-
const status = await this.git.status();
|
|
253
|
-
const currentBranch = branchName || status.current;
|
|
254
|
-
if (currentBranch && currentBranch !== 'HEAD') {
|
|
255
|
-
await this.git.fetch();
|
|
256
|
-
log.info('Synced with remote repository', undefined, 'git-service');
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
catch (error) {
|
|
260
|
-
log.warn('Could not sync with remote', error, 'git-service');
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
/**
|
|
264
|
-
* Get Git instance for a specific directory
|
|
265
|
-
*/
|
|
266
|
-
getGitInstance(directory) {
|
|
267
|
-
return simpleGit(directory);
|
|
268
|
-
}
|
|
269
|
-
/**
|
|
270
|
-
* Check Git status for a specific directory
|
|
271
|
-
*/
|
|
272
|
-
async getGitStatus(directory) {
|
|
273
|
-
const git = this.getGitInstance(directory);
|
|
274
|
-
const status = await git.status();
|
|
275
|
-
return {
|
|
276
|
-
modified: status.modified,
|
|
277
|
-
staged: status.staged,
|
|
278
|
-
not_added: status.not_added,
|
|
279
|
-
};
|
|
280
|
-
}
|
|
281
|
-
/**
|
|
282
|
-
* Check if directory has uncommitted changes
|
|
283
|
-
*/
|
|
284
|
-
async hasUncommittedChanges(directory = this.projectRoot) {
|
|
285
|
-
try {
|
|
286
|
-
const status = await this.getGitStatus(directory);
|
|
287
|
-
return status.modified.length > 0 || status.staged.length > 0 || status.not_added.length > 0;
|
|
288
|
-
}
|
|
289
|
-
catch {
|
|
290
|
-
return false;
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
/**
|
|
294
|
-
* Get log for a specific directory/worktree
|
|
295
|
-
*/
|
|
296
|
-
async getLog(directory, options) {
|
|
297
|
-
const git = this.getGitInstance(directory);
|
|
298
|
-
return await git.log(options);
|
|
299
|
-
}
|
|
300
|
-
/**
|
|
301
|
-
* Push branch from specific directory
|
|
302
|
-
*/
|
|
303
|
-
async pushFromDirectory(directory, remote, branchName, options = []) {
|
|
304
|
-
const git = this.getGitInstance(directory);
|
|
305
|
-
await git.push(remote, branchName, options);
|
|
306
|
-
}
|
|
307
|
-
}
|