vibeman 0.0.0 → 0.0.1
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 +12 -0
- package/dist/index.js +116 -0
- package/dist/runtime/api/.tsbuildinfo +1 -0
- package/dist/runtime/api/agent/agent-service.d.ts +226 -0
- package/dist/runtime/api/agent/agent-service.js +901 -0
- package/dist/runtime/api/agent/ai-providers/claude-code-adapter.d.ts +61 -0
- package/dist/runtime/api/agent/ai-providers/claude-code-adapter.js +373 -0
- package/dist/runtime/api/agent/ai-providers/codex-cli-provider.d.ts +34 -0
- package/dist/runtime/api/agent/ai-providers/codex-cli-provider.js +281 -0
- package/dist/runtime/api/agent/ai-providers/index.d.ts +9 -0
- package/dist/runtime/api/agent/ai-providers/index.js +7 -0
- package/dist/runtime/api/agent/ai-providers/types.d.ts +180 -0
- package/dist/runtime/api/agent/ai-providers/types.js +5 -0
- package/dist/runtime/api/agent/codex-cli-provider.test.d.ts +1 -0
- package/dist/runtime/api/agent/codex-cli-provider.test.js +88 -0
- package/dist/runtime/api/agent/core-agent-service.d.ts +119 -0
- package/dist/runtime/api/agent/core-agent-service.js +267 -0
- package/dist/runtime/api/agent/parsers.d.ts +15 -0
- package/dist/runtime/api/agent/parsers.js +241 -0
- package/dist/runtime/api/agent/prompt-service.d.ts +17 -0
- package/dist/runtime/api/agent/prompt-service.js +340 -0
- package/dist/runtime/api/agent/routing-policy.d.ts +188 -0
- package/dist/runtime/api/agent/routing-policy.js +246 -0
- package/dist/runtime/api/api/router-helpers.d.ts +32 -0
- package/dist/runtime/api/api/router-helpers.js +31 -0
- package/dist/runtime/api/api/routers/ai.d.ts +188 -0
- package/dist/runtime/api/api/routers/ai.js +410 -0
- package/dist/runtime/api/api/routers/executions.d.ts +98 -0
- package/dist/runtime/api/api/routers/executions.js +103 -0
- package/dist/runtime/api/api/routers/git.d.ts +45 -0
- package/dist/runtime/api/api/routers/git.js +35 -0
- package/dist/runtime/api/api/routers/settings.d.ts +139 -0
- package/dist/runtime/api/api/routers/settings.js +113 -0
- package/dist/runtime/api/api/routers/tasks.d.ts +141 -0
- package/dist/runtime/api/api/routers/tasks.js +238 -0
- package/dist/runtime/api/api/routers/workflows.d.ts +268 -0
- package/dist/runtime/api/api/routers/workflows.js +308 -0
- package/dist/runtime/api/api/routers/worktrees.d.ts +102 -0
- package/dist/runtime/api/api/routers/worktrees.js +80 -0
- package/dist/runtime/api/api/trpc.d.ts +118 -0
- package/dist/runtime/api/api/trpc.js +34 -0
- package/dist/runtime/api/index.d.ts +9 -0
- package/dist/runtime/api/index.js +125 -0
- package/dist/runtime/api/lib/id-generator.d.ts +70 -0
- package/dist/runtime/api/lib/id-generator.js +123 -0
- package/dist/runtime/api/lib/image-paste-drop-extension.d.ts +26 -0
- package/dist/runtime/api/lib/image-paste-drop-extension.js +125 -0
- package/dist/runtime/api/lib/logger.d.ts +11 -0
- package/dist/runtime/api/lib/logger.js +188 -0
- package/dist/runtime/api/lib/markdown-utils.d.ts +8 -0
- package/dist/runtime/api/lib/markdown-utils.js +282 -0
- package/dist/runtime/api/lib/markdown-utils.test.d.ts +1 -0
- package/dist/runtime/api/lib/markdown-utils.test.js +348 -0
- package/dist/runtime/api/lib/server/agent-service-singleton.d.ts +6 -0
- package/dist/runtime/api/lib/server/agent-service-singleton.js +27 -0
- package/dist/runtime/api/lib/server/git-service-singleton.d.ts +6 -0
- package/dist/runtime/api/lib/server/git-service-singleton.js +47 -0
- package/dist/runtime/api/lib/server/project-root.d.ts +2 -0
- package/dist/runtime/api/lib/server/project-root.js +38 -0
- package/dist/runtime/api/lib/server/task-service-singleton.d.ts +7 -0
- package/dist/runtime/api/lib/server/task-service-singleton.js +58 -0
- package/dist/runtime/api/lib/server/vibing-orchestrator-singleton.d.ts +7 -0
- package/dist/runtime/api/lib/server/vibing-orchestrator-singleton.js +57 -0
- package/dist/runtime/api/lib/tiptap-utils.clamp-selection.test.d.ts +1 -0
- package/dist/runtime/api/lib/tiptap-utils.clamp-selection.test.js +27 -0
- package/dist/runtime/api/lib/tiptap-utils.d.ts +130 -0
- package/dist/runtime/api/lib/tiptap-utils.js +327 -0
- package/dist/runtime/api/lib/trpc/client.d.ts +1 -0
- package/dist/runtime/api/lib/trpc/client.js +5 -0
- package/dist/runtime/api/lib/trpc/server.d.ts +822 -0
- package/dist/runtime/api/lib/trpc/server.js +11 -0
- package/dist/runtime/api/lib/trpc/ws-server.d.ts +8 -0
- package/dist/runtime/api/lib/trpc/ws-server.js +33 -0
- package/dist/runtime/api/persistence/database-service.d.ts +14 -0
- package/dist/runtime/api/persistence/database-service.js +74 -0
- package/dist/runtime/api/persistence/execution-log-persistence.d.ts +90 -0
- package/dist/runtime/api/persistence/execution-log-persistence.js +410 -0
- package/dist/runtime/api/persistence/execution-log-persistence.test.d.ts +1 -0
- package/dist/runtime/api/persistence/execution-log-persistence.test.js +170 -0
- package/dist/runtime/api/router.d.ts +825 -0
- package/dist/runtime/api/router.js +56 -0
- package/dist/runtime/api/settings-service.d.ts +110 -0
- package/dist/runtime/api/settings-service.js +611 -0
- package/dist/runtime/api/tasks/file-watcher.d.ts +23 -0
- package/dist/runtime/api/tasks/file-watcher.js +88 -0
- package/dist/runtime/api/tasks/task-file-parser.d.ts +13 -0
- package/dist/runtime/api/tasks/task-file-parser.js +161 -0
- package/dist/runtime/api/tasks/task-service.d.ts +36 -0
- package/dist/runtime/api/tasks/task-service.js +173 -0
- package/dist/runtime/api/types/index.d.ts +179 -0
- package/dist/runtime/api/types/index.js +1 -0
- package/dist/runtime/api/types/settings.d.ts +81 -0
- package/dist/runtime/api/types/settings.js +2 -0
- package/dist/runtime/api/types.d.ts +2 -0
- package/dist/runtime/api/types.js +1 -0
- package/dist/runtime/api/utils/env.d.ts +6 -0
- package/dist/runtime/api/utils/env.js +12 -0
- package/dist/runtime/api/utils/stripNextEnv.d.ts +7 -0
- package/dist/runtime/api/utils/stripNextEnv.js +22 -0
- package/dist/runtime/api/utils/title-slug.d.ts +6 -0
- package/dist/runtime/api/utils/title-slug.js +77 -0
- package/dist/runtime/api/utils/url.d.ts +2 -0
- package/dist/runtime/api/utils/url.js +19 -0
- package/dist/runtime/api/vcs/git-history-service.d.ts +57 -0
- package/dist/runtime/api/vcs/git-history-service.js +228 -0
- package/dist/runtime/api/vcs/git-service.d.ts +127 -0
- package/dist/runtime/api/vcs/git-service.js +284 -0
- package/dist/runtime/api/vcs/worktree-service.d.ts +93 -0
- package/dist/runtime/api/vcs/worktree-service.js +506 -0
- package/dist/runtime/api/vcs/worktree-service.test.d.ts +1 -0
- package/dist/runtime/api/vcs/worktree-service.test.js +20 -0
- package/dist/runtime/api/workflows/quality-pipeline.d.ts +58 -0
- package/dist/runtime/api/workflows/quality-pipeline.js +400 -0
- package/dist/runtime/api/workflows/vibing-orchestrator.d.ts +313 -0
- package/dist/runtime/api/workflows/vibing-orchestrator.js +1861 -0
- package/dist/runtime/web/.next/BUILD_ID +1 -0
- package/dist/runtime/web/.next/app-build-manifest.json +59 -0
- package/dist/runtime/web/.next/app-path-routes-manifest.json +7 -0
- package/dist/runtime/web/.next/build-manifest.json +33 -0
- package/dist/runtime/web/.next/package.json +1 -0
- package/dist/runtime/web/.next/prerender-manifest.json +61 -0
- package/dist/runtime/web/.next/react-loadable-manifest.json +39 -0
- package/dist/runtime/web/.next/required-server-files.json +334 -0
- package/dist/runtime/web/.next/routes-manifest.json +62 -0
- package/dist/runtime/web/.next/server/app/_not-found/page.js +2 -0
- package/dist/runtime/web/.next/server/app/_not-found/page.js.nft.json +1 -0
- package/dist/runtime/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -0
- package/dist/runtime/web/.next/server/app/_not-found.html +7 -0
- package/dist/runtime/web/.next/server/app/_not-found.meta +8 -0
- package/dist/runtime/web/.next/server/app/_not-found.rsc +22 -0
- package/dist/runtime/web/.next/server/app/api/health/route.js +1 -0
- package/dist/runtime/web/.next/server/app/api/health/route.js.nft.json +1 -0
- package/dist/runtime/web/.next/server/app/api/health/route_client-reference-manifest.js +1 -0
- package/dist/runtime/web/.next/server/app/api/images/[...path]/route.js +1 -0
- package/dist/runtime/web/.next/server/app/api/images/[...path]/route.js.nft.json +1 -0
- package/dist/runtime/web/.next/server/app/api/images/[...path]/route_client-reference-manifest.js +1 -0
- package/dist/runtime/web/.next/server/app/api/upload/route.js +1 -0
- package/dist/runtime/web/.next/server/app/api/upload/route.js.nft.json +1 -0
- package/dist/runtime/web/.next/server/app/api/upload/route_client-reference-manifest.js +1 -0
- package/dist/runtime/web/.next/server/app/index.html +7 -0
- package/dist/runtime/web/.next/server/app/index.meta +7 -0
- package/dist/runtime/web/.next/server/app/index.rsc +27 -0
- package/dist/runtime/web/.next/server/app/page.js +147 -0
- package/dist/runtime/web/.next/server/app/page.js.nft.json +1 -0
- package/dist/runtime/web/.next/server/app/page_client-reference-manifest.js +1 -0
- package/dist/runtime/web/.next/server/app-paths-manifest.json +7 -0
- package/dist/runtime/web/.next/server/chunks/217.js +1 -0
- package/dist/runtime/web/.next/server/chunks/383.js +6 -0
- package/dist/runtime/web/.next/server/chunks/458.js +1 -0
- package/dist/runtime/web/.next/server/chunks/576.js +18 -0
- package/dist/runtime/web/.next/server/chunks/635.js +22 -0
- package/dist/runtime/web/.next/server/chunks/761.js +1 -0
- package/dist/runtime/web/.next/server/chunks/777.js +3 -0
- package/dist/runtime/web/.next/server/chunks/825.js +1 -0
- package/dist/runtime/web/.next/server/chunks/838.js +1 -0
- package/dist/runtime/web/.next/server/chunks/973.js +15 -0
- package/dist/runtime/web/.next/server/functions-config-manifest.json +4 -0
- package/dist/runtime/web/.next/server/middleware-build-manifest.js +1 -0
- package/dist/runtime/web/.next/server/middleware-manifest.json +6 -0
- package/dist/runtime/web/.next/server/middleware-react-loadable-manifest.js +1 -0
- package/dist/runtime/web/.next/server/next-font-manifest.js +1 -0
- package/dist/runtime/web/.next/server/next-font-manifest.json +1 -0
- package/dist/runtime/web/.next/server/pages/404.html +7 -0
- package/dist/runtime/web/.next/server/pages/500.html +1 -0
- package/dist/runtime/web/.next/server/pages/_app.js +1 -0
- package/dist/runtime/web/.next/server/pages/_app.js.nft.json +1 -0
- package/dist/runtime/web/.next/server/pages/_document.js +1 -0
- package/dist/runtime/web/.next/server/pages/_document.js.nft.json +1 -0
- package/dist/runtime/web/.next/server/pages/_error.js +19 -0
- package/dist/runtime/web/.next/server/pages/_error.js.nft.json +1 -0
- package/dist/runtime/web/.next/server/pages-manifest.json +6 -0
- package/dist/runtime/web/.next/server/server-reference-manifest.js +1 -0
- package/dist/runtime/web/.next/server/server-reference-manifest.json +1 -0
- package/dist/runtime/web/.next/server/webpack-runtime.js +1 -0
- package/dist/runtime/web/.next/static/1HR8N0rJkCvFRtbTPJMyH/_buildManifest.js +1 -0
- package/dist/runtime/web/.next/static/1HR8N0rJkCvFRtbTPJMyH/_ssgManifest.js +1 -0
- package/dist/runtime/web/.next/static/chunks/18-15c10d3288afef2e.js +1 -0
- package/dist/runtime/web/.next/static/chunks/1c0ca389.537bbe362e3ffbd9.js +3 -0
- package/dist/runtime/web/.next/static/chunks/22747d63-ad5da0c19f4cfe41.js +71 -0
- package/dist/runtime/web/.next/static/chunks/277-0142a939f08738c3.js +63 -0
- package/dist/runtime/web/.next/static/chunks/355.056c2645878a799a.js +1 -0
- package/dist/runtime/web/.next/static/chunks/420.a5ccf151c9e2b2f1.js +1 -0
- package/dist/runtime/web/.next/static/chunks/439.1be0c6242fd248d5.js +15 -0
- package/dist/runtime/web/.next/static/chunks/440.c52e7c0f797e22b2.js +1 -0
- package/dist/runtime/web/.next/static/chunks/575-e2478287c27da87b.js +1 -0
- package/dist/runtime/web/.next/static/chunks/691.920d88c115087314.js +1 -0
- package/dist/runtime/web/.next/static/chunks/765-e838910065b50c3d.js +1 -0
- package/dist/runtime/web/.next/static/chunks/87c73c54-09e1ba5c70e60a51.js +1 -0
- package/dist/runtime/web/.next/static/chunks/891cff7f.0f71fc028f87e683.js +1 -0
- package/dist/runtime/web/.next/static/chunks/8bb4d8db-3e2aa02b0a2384b9.js +1 -0
- package/dist/runtime/web/.next/static/chunks/9af238c7-271a911d4e99ab18.js +1 -0
- package/dist/runtime/web/.next/static/chunks/app/_not-found/page-1cb74d1cba27d0ab.js +1 -0
- package/dist/runtime/web/.next/static/chunks/app/api/health/route-105a61ae865ba536.js +1 -0
- package/dist/runtime/web/.next/static/chunks/app/api/images/[...path]/route-105a61ae865ba536.js +1 -0
- package/dist/runtime/web/.next/static/chunks/app/api/upload/route-105a61ae865ba536.js +1 -0
- package/dist/runtime/web/.next/static/chunks/app/layout-dc0cfd29075b2160.js +1 -0
- package/dist/runtime/web/.next/static/chunks/app/page-f34a8b196b18850b.js +1 -0
- package/dist/runtime/web/.next/static/chunks/cac567b0-5b77dd12911823cd.js +1 -0
- package/dist/runtime/web/.next/static/chunks/framework-2518f1345b5b2806.js +1 -0
- package/dist/runtime/web/.next/static/chunks/main-17665e5e39de9a8a.js +1 -0
- package/dist/runtime/web/.next/static/chunks/main-app-c0b0f5ba4f7f9d75.js +1 -0
- package/dist/runtime/web/.next/static/chunks/pages/_app-d6f6b3bbc3d81ee1.js +1 -0
- package/dist/runtime/web/.next/static/chunks/pages/_error-75a96cf1997cc3b9.js +1 -0
- package/dist/runtime/web/.next/static/chunks/polyfills-42372ed130431b0a.js +1 -0
- package/dist/runtime/web/.next/static/chunks/webpack-c8de37305b4635cf.js +1 -0
- package/dist/runtime/web/.next/static/css/08c950681f1a9a92.css +1 -0
- package/dist/runtime/web/.next/static/css/2728291c68f99cb1.css +3 -0
- package/dist/runtime/web/.next/static/css/521bd69cc298cd1a.css +1 -0
- package/dist/runtime/web/.next/static/css/537e22821e101b87.css +1 -0
- 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 +65 -0
- package/dist/runtime/web/server.js +44 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/package.json +80 -7
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
export interface VibemanSettings {
|
|
2
|
+
agents: {
|
|
3
|
+
defaultProvider: 'claude-code' | 'codex';
|
|
4
|
+
codingAgent: {
|
|
5
|
+
provider: 'claude-code' | 'codex';
|
|
6
|
+
model: 'claude-sonnet-4-20250514' | 'claude-opus-4-1-20250805' | 'claude-3-5-haiku-20241022' | 'gpt-5';
|
|
7
|
+
maxTokens?: number;
|
|
8
|
+
};
|
|
9
|
+
judgeAgent: {
|
|
10
|
+
provider: 'claude-code' | 'codex';
|
|
11
|
+
model: 'claude-sonnet-4-20250514' | 'claude-opus-4-1-20250805' | 'claude-3-5-haiku-20241022' | 'gpt-5';
|
|
12
|
+
maxTokens?: number;
|
|
13
|
+
reviewThresholdScore: number;
|
|
14
|
+
};
|
|
15
|
+
defaultPrompts: {
|
|
16
|
+
systemPrompt: string;
|
|
17
|
+
taskPrompt: string;
|
|
18
|
+
};
|
|
19
|
+
providers?: {
|
|
20
|
+
claudeCode?: {
|
|
21
|
+
binPath?: string;
|
|
22
|
+
};
|
|
23
|
+
codex?: {
|
|
24
|
+
binPath?: string;
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
defaultWorkflow: {
|
|
29
|
+
autoQualityChecks: boolean;
|
|
30
|
+
requireHumanApproval: boolean;
|
|
31
|
+
aiCodeReview: boolean;
|
|
32
|
+
maxImplementationAttempts: number;
|
|
33
|
+
autoCommit: boolean;
|
|
34
|
+
};
|
|
35
|
+
quality?: {
|
|
36
|
+
checks: Array<{
|
|
37
|
+
name: string;
|
|
38
|
+
command: string;
|
|
39
|
+
args?: string[];
|
|
40
|
+
timeout?: number;
|
|
41
|
+
enabled?: boolean;
|
|
42
|
+
}>;
|
|
43
|
+
};
|
|
44
|
+
development: {
|
|
45
|
+
vibeDir?: string;
|
|
46
|
+
git: {
|
|
47
|
+
defaultBranch: string;
|
|
48
|
+
worktreePath?: string;
|
|
49
|
+
};
|
|
50
|
+
editor?: {
|
|
51
|
+
type?: 'vscode' | 'cursor' | 'vim' | 'custom';
|
|
52
|
+
command?: string;
|
|
53
|
+
args?: string[];
|
|
54
|
+
name?: string;
|
|
55
|
+
openFileCommand?: string[];
|
|
56
|
+
openFolderCommand?: string[];
|
|
57
|
+
};
|
|
58
|
+
terminal?: {
|
|
59
|
+
type?: 'system' | 'iterm2' | 'warp' | 'custom';
|
|
60
|
+
command?: string;
|
|
61
|
+
args?: string[];
|
|
62
|
+
name?: string;
|
|
63
|
+
openCommand?: string[];
|
|
64
|
+
};
|
|
65
|
+
};
|
|
66
|
+
server: {
|
|
67
|
+
port: number;
|
|
68
|
+
host: string;
|
|
69
|
+
autoOpenBrowser: boolean;
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
export interface SettingsUpdateRequest {
|
|
73
|
+
path: string[];
|
|
74
|
+
value: unknown;
|
|
75
|
+
}
|
|
76
|
+
export interface SettingsValidationError {
|
|
77
|
+
path: string[];
|
|
78
|
+
message: string;
|
|
79
|
+
expected?: string;
|
|
80
|
+
received?: string;
|
|
81
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Environment utility functions
|
|
3
|
+
*/
|
|
4
|
+
export function isTestEnv() {
|
|
5
|
+
return process.env.NODE_ENV === 'test';
|
|
6
|
+
}
|
|
7
|
+
export function isDevelopment() {
|
|
8
|
+
return process.env.NODE_ENV === 'development';
|
|
9
|
+
}
|
|
10
|
+
export function isProduction() {
|
|
11
|
+
return process.env.NODE_ENV === 'production';
|
|
12
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Returns a shallow copy of `env` with all variables that Next.js
|
|
3
|
+
* adds or forces removed.
|
|
4
|
+
*/
|
|
5
|
+
export function stripNextInjectedEnv(env = process.env) {
|
|
6
|
+
const nextExact = new Set([
|
|
7
|
+
'__NEXT_PRIVATE_ORIGIN',
|
|
8
|
+
'__NEXT_PROCESSED_ENV',
|
|
9
|
+
'NEXT_PRIVATE_TRACE_ID',
|
|
10
|
+
'NEXT_PRIVATE_WORKER',
|
|
11
|
+
'NEXT_RUNTIME',
|
|
12
|
+
'TURBOPACK',
|
|
13
|
+
'PORT',
|
|
14
|
+
'NODE_ENV',
|
|
15
|
+
]);
|
|
16
|
+
const nextPrefixes = ['__NEXT_', 'NEXT_PRIVATE_']; // convenience
|
|
17
|
+
return Object.fromEntries(Object.entries(env).filter(([key]) => {
|
|
18
|
+
if (nextExact.has(key))
|
|
19
|
+
return false;
|
|
20
|
+
return !nextPrefixes.some((p) => key.startsWith(p));
|
|
21
|
+
}));
|
|
22
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export declare function slugFromTitle(title: string, options?: {
|
|
2
|
+
maxWords?: number;
|
|
3
|
+
maxLen?: number;
|
|
4
|
+
}): string;
|
|
5
|
+
export declare function generateHumanTaskId(type: string, title: string, existingIds?: string[]): string;
|
|
6
|
+
export declare function isValidTaskIdFormat(id: string): boolean;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import slugifyModule from 'slugify';
|
|
2
|
+
// Normalize slugify's mixed ESM/CJS export so it stays callable for NodeNext builds
|
|
3
|
+
const slugifyImpl = typeof slugifyModule === 'function'
|
|
4
|
+
? slugifyModule
|
|
5
|
+
: slugifyModule.default;
|
|
6
|
+
// Configure slugify for broad transliteration coverage
|
|
7
|
+
const slugify = (input) => slugifyImpl(input, {
|
|
8
|
+
lower: true,
|
|
9
|
+
strict: true, // remove anything except letters, numbers and replace spaces with -
|
|
10
|
+
trim: true,
|
|
11
|
+
});
|
|
12
|
+
const ALPHABET = '23456789ABCDEFGHJKLMNPQRSTUVWXYZ';
|
|
13
|
+
function randomSuffix(len = 3) {
|
|
14
|
+
let out = '';
|
|
15
|
+
for (let i = 0; i < len; i++) {
|
|
16
|
+
out += ALPHABET[Math.floor(Math.random() * ALPHABET.length)];
|
|
17
|
+
}
|
|
18
|
+
return out;
|
|
19
|
+
}
|
|
20
|
+
export function slugFromTitle(title, options) {
|
|
21
|
+
const { maxWords = 4, maxLen = 24 } = options || {};
|
|
22
|
+
const base = slugify(title || '');
|
|
23
|
+
if (!base)
|
|
24
|
+
return '';
|
|
25
|
+
// limit to N words
|
|
26
|
+
const parts = base.split('-').filter(Boolean);
|
|
27
|
+
const limited = parts.slice(0, maxWords);
|
|
28
|
+
// enforce max length by dropping trailing words or trimming the last
|
|
29
|
+
let slug = limited.join('-');
|
|
30
|
+
if (slug.length > maxLen) {
|
|
31
|
+
while (slug.length > maxLen && limited.length > 1) {
|
|
32
|
+
limited.pop();
|
|
33
|
+
slug = limited.join('-');
|
|
34
|
+
}
|
|
35
|
+
if (slug.length > maxLen) {
|
|
36
|
+
slug = slug.slice(0, maxLen).replace(/-+$/, '');
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return slug.toUpperCase();
|
|
40
|
+
}
|
|
41
|
+
export function generateHumanTaskId(type, title, existingIds = []) {
|
|
42
|
+
const typeMap = {
|
|
43
|
+
feature: 'FEAT',
|
|
44
|
+
bug: 'BUG',
|
|
45
|
+
chore: 'CHORE',
|
|
46
|
+
refactor: 'REF',
|
|
47
|
+
test: 'TEST',
|
|
48
|
+
doc: 'DOC',
|
|
49
|
+
};
|
|
50
|
+
const prefix = typeMap[(type || '').toLowerCase()] || 'TASK';
|
|
51
|
+
const slug = slugFromTitle(title);
|
|
52
|
+
// Fallback when transliteration is empty
|
|
53
|
+
const base = slug ? `${prefix}-${slug}` : `${prefix}`;
|
|
54
|
+
// ensure uniqueness with a short suffix; cap total length to 40
|
|
55
|
+
let attempt = 0;
|
|
56
|
+
while (attempt < 128) {
|
|
57
|
+
const suffix = randomSuffix(slug ? 3 : 4);
|
|
58
|
+
let candidate = slug ? `${base}-${suffix}` : `${base}-${suffix}`;
|
|
59
|
+
if (candidate.length > 40) {
|
|
60
|
+
// trim slug segment if too long
|
|
61
|
+
const over = candidate.length - 40;
|
|
62
|
+
const trimmedSlug = slug.slice(0, Math.max(0, slug.length - over)).replace(/-+$/, '');
|
|
63
|
+
candidate = trimmedSlug ? `${prefix}-${trimmedSlug}-${suffix}` : `${prefix}-${suffix}`;
|
|
64
|
+
}
|
|
65
|
+
if (!existingIds.includes(candidate))
|
|
66
|
+
return candidate;
|
|
67
|
+
attempt++;
|
|
68
|
+
}
|
|
69
|
+
// last resort
|
|
70
|
+
return `${prefix}-${randomSuffix(4)}`;
|
|
71
|
+
}
|
|
72
|
+
export function isValidTaskIdFormat(id) {
|
|
73
|
+
if (!id || id.length > 40)
|
|
74
|
+
return false;
|
|
75
|
+
// At least TYPE-SOMETHING (two segments), uppercase letters/digits separated by hyphens
|
|
76
|
+
return /^[A-Z0-9]+(?:-[A-Z0-9]+)+$/.test(id);
|
|
77
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export function buildUrlWithParam(pathname, searchParams, key, value) {
|
|
2
|
+
const sp = new URLSearchParams(searchParams);
|
|
3
|
+
if (value && value.length > 0) {
|
|
4
|
+
sp.set(key, value);
|
|
5
|
+
}
|
|
6
|
+
else {
|
|
7
|
+
sp.delete(key);
|
|
8
|
+
}
|
|
9
|
+
const qs = sp.toString();
|
|
10
|
+
return qs ? `${pathname}?${qs}` : pathname;
|
|
11
|
+
}
|
|
12
|
+
export function isValidTaskId(id) {
|
|
13
|
+
if (!id)
|
|
14
|
+
return false;
|
|
15
|
+
const up = String(id).toUpperCase();
|
|
16
|
+
if (up.length > 40)
|
|
17
|
+
return false;
|
|
18
|
+
return /^[A-Z0-9]+(?:-[A-Z0-9]+)+$/.test(up);
|
|
19
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
export interface TaskHistoryEntry {
|
|
2
|
+
commitHash: string;
|
|
3
|
+
shortHash: string;
|
|
4
|
+
author: string;
|
|
5
|
+
date: Date;
|
|
6
|
+
message: string;
|
|
7
|
+
changes: {
|
|
8
|
+
additions: number;
|
|
9
|
+
deletions: number;
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
export interface TaskFileContent {
|
|
13
|
+
commitHash: string;
|
|
14
|
+
content: string;
|
|
15
|
+
date: Date;
|
|
16
|
+
author: string;
|
|
17
|
+
}
|
|
18
|
+
export interface TaskDiffEntry {
|
|
19
|
+
fromHash: string;
|
|
20
|
+
toHash: string;
|
|
21
|
+
diff: string;
|
|
22
|
+
additions: number;
|
|
23
|
+
deletions: number;
|
|
24
|
+
}
|
|
25
|
+
export declare class GitHistoryService {
|
|
26
|
+
private git;
|
|
27
|
+
private projectRoot;
|
|
28
|
+
constructor(projectRoot?: string);
|
|
29
|
+
/**
|
|
30
|
+
* Get the history of changes for a specific task file
|
|
31
|
+
*/
|
|
32
|
+
getTaskHistory(taskId: string, limit?: number): Promise<TaskHistoryEntry[]>;
|
|
33
|
+
/**
|
|
34
|
+
* Get the content of a task file at a specific commit
|
|
35
|
+
*/
|
|
36
|
+
getTaskVersionContent(taskId: string, commitHash: string): Promise<TaskFileContent>;
|
|
37
|
+
/**
|
|
38
|
+
* Get the diff between two versions of a task file
|
|
39
|
+
*/
|
|
40
|
+
getTaskDiff(taskId: string, fromHash: string, toHash: string): Promise<TaskDiffEntry>;
|
|
41
|
+
/**
|
|
42
|
+
* Check if Git repository exists and is properly configured
|
|
43
|
+
*/
|
|
44
|
+
isGitRepositoryAvailable(): Promise<boolean>;
|
|
45
|
+
/**
|
|
46
|
+
* Get commit statistics for a specific file in a commit
|
|
47
|
+
*/
|
|
48
|
+
private getCommitStats;
|
|
49
|
+
/**
|
|
50
|
+
* Check if a task file has been renamed or moved by tracking it through Git history
|
|
51
|
+
*/
|
|
52
|
+
getTaskFileRenames(taskId: string): Promise<Array<{
|
|
53
|
+
oldPath: string;
|
|
54
|
+
newPath: string;
|
|
55
|
+
commitHash: string;
|
|
56
|
+
}>>;
|
|
57
|
+
}
|
|
@@ -0,0 +1,228 @@
|
|
|
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
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
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
|
+
/**
|
|
29
|
+
* Validate Git repository exists and is properly configured
|
|
30
|
+
*/
|
|
31
|
+
initializeRepository(): Promise<void>;
|
|
32
|
+
/**
|
|
33
|
+
* Get current Git status
|
|
34
|
+
*/
|
|
35
|
+
getStatus(): Promise<{
|
|
36
|
+
current: string;
|
|
37
|
+
staged: string[];
|
|
38
|
+
modified: string[];
|
|
39
|
+
untracked: string[];
|
|
40
|
+
ahead: number;
|
|
41
|
+
behind: number;
|
|
42
|
+
}>;
|
|
43
|
+
/**
|
|
44
|
+
* Generate branch name from task
|
|
45
|
+
*/
|
|
46
|
+
generateBranchName(task: Task): string;
|
|
47
|
+
/**
|
|
48
|
+
* Create a new branch for a task
|
|
49
|
+
*/
|
|
50
|
+
createBranch(task: Task, baseBranch?: string): Promise<BranchInfo>;
|
|
51
|
+
/**
|
|
52
|
+
* Stage and commit changes
|
|
53
|
+
*/
|
|
54
|
+
commitChanges(task: Task, message?: string, files?: string[]): Promise<CommitInfo>;
|
|
55
|
+
/**
|
|
56
|
+
* Generate standardized commit message
|
|
57
|
+
*/
|
|
58
|
+
generateCommitMessage(task: Task): string;
|
|
59
|
+
/**
|
|
60
|
+
* Get commit history for current branch
|
|
61
|
+
*/
|
|
62
|
+
getCommitHistory(maxCount?: number): Promise<CommitInfo[]>;
|
|
63
|
+
/**
|
|
64
|
+
* Get Git version information
|
|
65
|
+
*/
|
|
66
|
+
getGitVersion(): Promise<VersionResult>;
|
|
67
|
+
/**
|
|
68
|
+
* List all worktrees in the repository
|
|
69
|
+
*/
|
|
70
|
+
listWorktrees(): Promise<{
|
|
71
|
+
path: string;
|
|
72
|
+
branch: string;
|
|
73
|
+
prunable?: boolean;
|
|
74
|
+
}[]>;
|
|
75
|
+
/**
|
|
76
|
+
* Parse git worktree list output
|
|
77
|
+
*/
|
|
78
|
+
private parseWorktreeList;
|
|
79
|
+
/**
|
|
80
|
+
* Create a new worktree
|
|
81
|
+
*/
|
|
82
|
+
createWorktree(worktreePath: string, branchName: string, branchExists?: boolean): Promise<void>;
|
|
83
|
+
/**
|
|
84
|
+
* Remove a worktree
|
|
85
|
+
*/
|
|
86
|
+
removeWorktree(worktreePath: string, force?: boolean): Promise<void>;
|
|
87
|
+
/**
|
|
88
|
+
* Prune stale worktrees
|
|
89
|
+
*/
|
|
90
|
+
pruneWorktrees(): Promise<void>;
|
|
91
|
+
/**
|
|
92
|
+
* Delete a local branch
|
|
93
|
+
*/
|
|
94
|
+
deleteLocalBranch(branchName: string, force?: boolean): Promise<void>;
|
|
95
|
+
/**
|
|
96
|
+
* Check if branch exists locally
|
|
97
|
+
*/
|
|
98
|
+
branchExists(branchName: string): Promise<boolean>;
|
|
99
|
+
/**
|
|
100
|
+
* Sync with remote repository
|
|
101
|
+
*/
|
|
102
|
+
syncWithRemote(branchName?: string): Promise<void>;
|
|
103
|
+
/**
|
|
104
|
+
* Get Git instance for a specific directory
|
|
105
|
+
*/
|
|
106
|
+
getGitInstance(directory: string): SimpleGit;
|
|
107
|
+
/**
|
|
108
|
+
* Check Git status for a specific directory
|
|
109
|
+
*/
|
|
110
|
+
getGitStatus(directory: string): Promise<{
|
|
111
|
+
modified: string[];
|
|
112
|
+
staged: string[];
|
|
113
|
+
not_added: string[];
|
|
114
|
+
}>;
|
|
115
|
+
/**
|
|
116
|
+
* Check if directory has uncommitted changes
|
|
117
|
+
*/
|
|
118
|
+
hasUncommittedChanges(directory?: string): Promise<boolean>;
|
|
119
|
+
/**
|
|
120
|
+
* Get log for a specific directory/worktree
|
|
121
|
+
*/
|
|
122
|
+
getLog(directory: string, options: string[]): Promise<any>;
|
|
123
|
+
/**
|
|
124
|
+
* Push branch from specific directory
|
|
125
|
+
*/
|
|
126
|
+
pushFromDirectory(directory: string, remote: string, branchName: string, options?: string[]): Promise<void>;
|
|
127
|
+
}
|