vibeman 0.0.5 → 0.0.7

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.
Files changed (239) hide show
  1. package/dist/api.js +43 -0
  2. package/dist/index.js +227 -104
  3. package/dist/ui/assets/index-C_kQPI1m.js +9 -0
  4. package/dist/ui/index.html +12 -0
  5. package/package.json +13 -46
  6. package/README.md +0 -12
  7. package/dist/runtime/api/.tsbuildinfo +0 -1
  8. package/dist/runtime/api/agent/agent-service.d.ts +0 -229
  9. package/dist/runtime/api/agent/agent-service.js +0 -963
  10. package/dist/runtime/api/agent/ai-providers/amp-cli-provider.d.ts +0 -38
  11. package/dist/runtime/api/agent/ai-providers/amp-cli-provider.js +0 -268
  12. package/dist/runtime/api/agent/ai-providers/claude-code-adapter.d.ts +0 -61
  13. package/dist/runtime/api/agent/ai-providers/claude-code-adapter.js +0 -362
  14. package/dist/runtime/api/agent/ai-providers/codex-cli-provider.d.ts +0 -36
  15. package/dist/runtime/api/agent/ai-providers/codex-cli-provider.js +0 -375
  16. package/dist/runtime/api/agent/ai-providers/gemini-cli-provider.d.ts +0 -24
  17. package/dist/runtime/api/agent/ai-providers/gemini-cli-provider.js +0 -291
  18. package/dist/runtime/api/agent/ai-providers/index.d.ts +0 -9
  19. package/dist/runtime/api/agent/ai-providers/index.js +0 -9
  20. package/dist/runtime/api/agent/ai-providers/types.d.ts +0 -185
  21. package/dist/runtime/api/agent/ai-providers/types.js +0 -5
  22. package/dist/runtime/api/agent/amp-cli-provider.test.d.ts +0 -1
  23. package/dist/runtime/api/agent/amp-cli-provider.test.js +0 -99
  24. package/dist/runtime/api/agent/codex-cli-provider.test.d.ts +0 -1
  25. package/dist/runtime/api/agent/codex-cli-provider.test.js +0 -172
  26. package/dist/runtime/api/agent/core-agent-service.d.ts +0 -119
  27. package/dist/runtime/api/agent/core-agent-service.js +0 -267
  28. package/dist/runtime/api/agent/parsers.d.ts +0 -16
  29. package/dist/runtime/api/agent/parsers.js +0 -308
  30. package/dist/runtime/api/agent/prompt-service.d.ts +0 -30
  31. package/dist/runtime/api/agent/prompt-service.js +0 -452
  32. package/dist/runtime/api/agent/prompt-service.test.d.ts +0 -1
  33. package/dist/runtime/api/agent/prompt-service.test.js +0 -265
  34. package/dist/runtime/api/agent/routing-policy.d.ts +0 -171
  35. package/dist/runtime/api/agent/routing-policy.js +0 -196
  36. package/dist/runtime/api/agent/routing-policy.test.d.ts +0 -1
  37. package/dist/runtime/api/agent/routing-policy.test.js +0 -63
  38. package/dist/runtime/api/api/router-helpers.d.ts +0 -32
  39. package/dist/runtime/api/api/router-helpers.js +0 -31
  40. package/dist/runtime/api/api/routers/ai.d.ts +0 -200
  41. package/dist/runtime/api/api/routers/ai.js +0 -396
  42. package/dist/runtime/api/api/routers/executions.d.ts +0 -93
  43. package/dist/runtime/api/api/routers/executions.js +0 -94
  44. package/dist/runtime/api/api/routers/git.d.ts +0 -45
  45. package/dist/runtime/api/api/routers/git.js +0 -35
  46. package/dist/runtime/api/api/routers/provider-config.d.ts +0 -199
  47. package/dist/runtime/api/api/routers/provider-config.js +0 -252
  48. package/dist/runtime/api/api/routers/settings.d.ts +0 -158
  49. package/dist/runtime/api/api/routers/settings.js +0 -129
  50. package/dist/runtime/api/api/routers/tasks.d.ts +0 -141
  51. package/dist/runtime/api/api/routers/tasks.js +0 -238
  52. package/dist/runtime/api/api/routers/workflows.d.ts +0 -275
  53. package/dist/runtime/api/api/routers/workflows.js +0 -311
  54. package/dist/runtime/api/api/routers/worktrees.d.ts +0 -101
  55. package/dist/runtime/api/api/routers/worktrees.js +0 -80
  56. package/dist/runtime/api/api/trpc.d.ts +0 -118
  57. package/dist/runtime/api/api/trpc.js +0 -34
  58. package/dist/runtime/api/index.d.ts +0 -9
  59. package/dist/runtime/api/index.js +0 -117
  60. package/dist/runtime/api/lib/id-generator.d.ts +0 -70
  61. package/dist/runtime/api/lib/id-generator.js +0 -123
  62. package/dist/runtime/api/lib/local-config.d.ts +0 -335
  63. package/dist/runtime/api/lib/local-config.js +0 -304
  64. package/dist/runtime/api/lib/logger.d.ts +0 -11
  65. package/dist/runtime/api/lib/logger.js +0 -188
  66. package/dist/runtime/api/lib/provider-detection.d.ts +0 -61
  67. package/dist/runtime/api/lib/provider-detection.js +0 -326
  68. package/dist/runtime/api/lib/server/agent-service-singleton.d.ts +0 -6
  69. package/dist/runtime/api/lib/server/agent-service-singleton.js +0 -27
  70. package/dist/runtime/api/lib/server/bootstrap.d.ts +0 -38
  71. package/dist/runtime/api/lib/server/bootstrap.js +0 -197
  72. package/dist/runtime/api/lib/server/git-service-singleton.d.ts +0 -6
  73. package/dist/runtime/api/lib/server/git-service-singleton.js +0 -47
  74. package/dist/runtime/api/lib/server/project-root.d.ts +0 -2
  75. package/dist/runtime/api/lib/server/project-root.js +0 -61
  76. package/dist/runtime/api/lib/server/task-service-singleton.d.ts +0 -7
  77. package/dist/runtime/api/lib/server/task-service-singleton.js +0 -58
  78. package/dist/runtime/api/lib/server/vibeman-info.d.ts +0 -5
  79. package/dist/runtime/api/lib/server/vibeman-info.js +0 -85
  80. package/dist/runtime/api/lib/server/vibing-orchestrator-singleton.d.ts +0 -7
  81. package/dist/runtime/api/lib/server/vibing-orchestrator-singleton.js +0 -57
  82. package/dist/runtime/api/lib/trpc/server.d.ts +0 -965
  83. package/dist/runtime/api/lib/trpc/server.js +0 -11
  84. package/dist/runtime/api/lib/trpc/ws-server.d.ts +0 -8
  85. package/dist/runtime/api/lib/trpc/ws-server.js +0 -33
  86. package/dist/runtime/api/persistence/database-service.d.ts +0 -14
  87. package/dist/runtime/api/persistence/database-service.js +0 -74
  88. package/dist/runtime/api/persistence/execution-log-persistence.d.ts +0 -90
  89. package/dist/runtime/api/persistence/execution-log-persistence.js +0 -426
  90. package/dist/runtime/api/persistence/execution-log-persistence.test.d.ts +0 -1
  91. package/dist/runtime/api/persistence/execution-log-persistence.test.js +0 -170
  92. package/dist/runtime/api/router.d.ts +0 -968
  93. package/dist/runtime/api/router.js +0 -34
  94. package/dist/runtime/api/settings-service.d.ts +0 -110
  95. package/dist/runtime/api/settings-service.js +0 -678
  96. package/dist/runtime/api/tasks/file-watcher.d.ts +0 -23
  97. package/dist/runtime/api/tasks/file-watcher.js +0 -88
  98. package/dist/runtime/api/tasks/task-file-parser.d.ts +0 -14
  99. package/dist/runtime/api/tasks/task-file-parser.js +0 -180
  100. package/dist/runtime/api/tasks/task-service.d.ts +0 -36
  101. package/dist/runtime/api/tasks/task-service.js +0 -173
  102. package/dist/runtime/api/tasks/task-updater.d.ts +0 -62
  103. package/dist/runtime/api/tasks/task-updater.js +0 -260
  104. package/dist/runtime/api/tasks/task-updater.test.d.ts +0 -1
  105. package/dist/runtime/api/tasks/task-updater.test.js +0 -303
  106. package/dist/runtime/api/types/index.d.ts +0 -186
  107. package/dist/runtime/api/types/index.js +0 -1
  108. package/dist/runtime/api/types/settings.d.ts +0 -105
  109. package/dist/runtime/api/types/settings.js +0 -2
  110. package/dist/runtime/api/types.d.ts +0 -2
  111. package/dist/runtime/api/types.js +0 -1
  112. package/dist/runtime/api/utils/env.d.ts +0 -6
  113. package/dist/runtime/api/utils/env.js +0 -12
  114. package/dist/runtime/api/utils/stripNextEnv.d.ts +0 -7
  115. package/dist/runtime/api/utils/stripNextEnv.js +0 -22
  116. package/dist/runtime/api/utils/title-slug.d.ts +0 -6
  117. package/dist/runtime/api/utils/title-slug.js +0 -77
  118. package/dist/runtime/api/utils/url.d.ts +0 -2
  119. package/dist/runtime/api/utils/url.js +0 -19
  120. package/dist/runtime/api/vcs/git-history-service.d.ts +0 -57
  121. package/dist/runtime/api/vcs/git-history-service.js +0 -228
  122. package/dist/runtime/api/vcs/git-service.d.ts +0 -136
  123. package/dist/runtime/api/vcs/git-service.js +0 -307
  124. package/dist/runtime/api/vcs/worktree-service.d.ts +0 -93
  125. package/dist/runtime/api/vcs/worktree-service.js +0 -518
  126. package/dist/runtime/api/vcs/worktree-service.test.d.ts +0 -1
  127. package/dist/runtime/api/vcs/worktree-service.test.js +0 -20
  128. package/dist/runtime/api/workflows/quality-pipeline.d.ts +0 -58
  129. package/dist/runtime/api/workflows/quality-pipeline.js +0 -401
  130. package/dist/runtime/api/workflows/vibing-orchestrator.d.ts +0 -406
  131. package/dist/runtime/api/workflows/vibing-orchestrator.js +0 -2462
  132. package/dist/runtime/api/workflows/workflow-effects.d.ts +0 -45
  133. package/dist/runtime/api/workflows/workflow-effects.js +0 -49
  134. package/dist/runtime/api/workflows/workflow-reconciler.d.ts +0 -65
  135. package/dist/runtime/api/workflows/workflow-reconciler.js +0 -226
  136. package/dist/runtime/api/workflows/workflow-reducer.d.ts +0 -26
  137. package/dist/runtime/api/workflows/workflow-reducer.js +0 -288
  138. package/dist/runtime/api/workflows/workflow-reducer.test.d.ts +0 -1
  139. package/dist/runtime/api/workflows/workflow-reducer.test.js +0 -247
  140. package/dist/runtime/api/workflows/workflow-schema.d.ts +0 -546
  141. package/dist/runtime/api/workflows/workflow-schema.js +0 -256
  142. package/dist/runtime/web/.next/BUILD_ID +0 -1
  143. package/dist/runtime/web/.next/app-build-manifest.json +0 -66
  144. package/dist/runtime/web/.next/app-path-routes-manifest.json +0 -8
  145. package/dist/runtime/web/.next/build-manifest.json +0 -33
  146. package/dist/runtime/web/.next/package.json +0 -1
  147. package/dist/runtime/web/.next/prerender-manifest.json +0 -61
  148. package/dist/runtime/web/.next/react-loadable-manifest.json +0 -8
  149. package/dist/runtime/web/.next/required-server-files.json +0 -334
  150. package/dist/runtime/web/.next/routes-manifest.json +0 -70
  151. package/dist/runtime/web/.next/server/app/.vibeman/assets/images/[...path]/route.js +0 -1
  152. package/dist/runtime/web/.next/server/app/.vibeman/assets/images/[...path]/route.js.nft.json +0 -1
  153. package/dist/runtime/web/.next/server/app/.vibeman/assets/images/[...path]/route_client-reference-manifest.js +0 -1
  154. package/dist/runtime/web/.next/server/app/_not-found/page.js +0 -2
  155. package/dist/runtime/web/.next/server/app/_not-found/page.js.nft.json +0 -1
  156. package/dist/runtime/web/.next/server/app/_not-found/page_client-reference-manifest.js +0 -1
  157. package/dist/runtime/web/.next/server/app/_not-found.html +0 -7
  158. package/dist/runtime/web/.next/server/app/_not-found.meta +0 -8
  159. package/dist/runtime/web/.next/server/app/_not-found.rsc +0 -22
  160. package/dist/runtime/web/.next/server/app/api/health/route.js +0 -1
  161. package/dist/runtime/web/.next/server/app/api/health/route.js.nft.json +0 -1
  162. package/dist/runtime/web/.next/server/app/api/health/route_client-reference-manifest.js +0 -1
  163. package/dist/runtime/web/.next/server/app/api/images/[...path]/route.js +0 -1
  164. package/dist/runtime/web/.next/server/app/api/images/[...path]/route.js.nft.json +0 -1
  165. package/dist/runtime/web/.next/server/app/api/images/[...path]/route_client-reference-manifest.js +0 -1
  166. package/dist/runtime/web/.next/server/app/api/upload/route.js +0 -1
  167. package/dist/runtime/web/.next/server/app/api/upload/route.js.nft.json +0 -1
  168. package/dist/runtime/web/.next/server/app/api/upload/route_client-reference-manifest.js +0 -1
  169. package/dist/runtime/web/.next/server/app/index.html +0 -7
  170. package/dist/runtime/web/.next/server/app/index.meta +0 -7
  171. package/dist/runtime/web/.next/server/app/index.rsc +0 -27
  172. package/dist/runtime/web/.next/server/app/page.js +0 -112
  173. package/dist/runtime/web/.next/server/app/page.js.nft.json +0 -1
  174. package/dist/runtime/web/.next/server/app/page_client-reference-manifest.js +0 -1
  175. package/dist/runtime/web/.next/server/app-paths-manifest.json +0 -8
  176. package/dist/runtime/web/.next/server/chunks/210.js +0 -1
  177. package/dist/runtime/web/.next/server/chunks/291.js +0 -18
  178. package/dist/runtime/web/.next/server/chunks/552.js +0 -22
  179. package/dist/runtime/web/.next/server/chunks/780.js +0 -1
  180. package/dist/runtime/web/.next/server/chunks/905.js +0 -6
  181. package/dist/runtime/web/.next/server/chunks/98.js +0 -1
  182. package/dist/runtime/web/.next/server/functions-config-manifest.json +0 -4
  183. package/dist/runtime/web/.next/server/middleware-build-manifest.js +0 -1
  184. package/dist/runtime/web/.next/server/middleware-manifest.json +0 -6
  185. package/dist/runtime/web/.next/server/middleware-react-loadable-manifest.js +0 -1
  186. package/dist/runtime/web/.next/server/next-font-manifest.js +0 -1
  187. package/dist/runtime/web/.next/server/next-font-manifest.json +0 -1
  188. package/dist/runtime/web/.next/server/pages/404.html +0 -7
  189. package/dist/runtime/web/.next/server/pages/500.html +0 -1
  190. package/dist/runtime/web/.next/server/pages/_app.js +0 -1
  191. package/dist/runtime/web/.next/server/pages/_app.js.nft.json +0 -1
  192. package/dist/runtime/web/.next/server/pages/_document.js +0 -1
  193. package/dist/runtime/web/.next/server/pages/_document.js.nft.json +0 -1
  194. package/dist/runtime/web/.next/server/pages/_error.js +0 -19
  195. package/dist/runtime/web/.next/server/pages/_error.js.nft.json +0 -1
  196. package/dist/runtime/web/.next/server/pages-manifest.json +0 -6
  197. package/dist/runtime/web/.next/server/server-reference-manifest.js +0 -1
  198. package/dist/runtime/web/.next/server/server-reference-manifest.json +0 -1
  199. package/dist/runtime/web/.next/server/webpack-runtime.js +0 -1
  200. package/dist/runtime/web/.next/static/LJFZk_8tvKFN_Ee4HqUuM/_buildManifest.js +0 -1
  201. package/dist/runtime/web/.next/static/LJFZk_8tvKFN_Ee4HqUuM/_ssgManifest.js +0 -1
  202. package/dist/runtime/web/.next/static/chunks/05c91ade-7d09b2b280adffd1.js +0 -1
  203. package/dist/runtime/web/.next/static/chunks/201-51bef3fa8c832e2e.js +0 -1
  204. package/dist/runtime/web/.next/static/chunks/524-89747ed9b0294f8a.js +0 -1
  205. package/dist/runtime/web/.next/static/chunks/554-8bec6e9cca6acc67.js +0 -1
  206. package/dist/runtime/web/.next/static/chunks/764.86e9503a69d45a85.js +0 -1
  207. package/dist/runtime/web/.next/static/chunks/7ab4dc20-239138e0ae7af24a.js +0 -1
  208. package/dist/runtime/web/.next/static/chunks/905-342391e3d3a3678f.js +0 -20
  209. package/dist/runtime/web/.next/static/chunks/a8a5ce16-4edea7df2d9b544a.js +0 -79
  210. package/dist/runtime/web/.next/static/chunks/ad74d572-4c1b162e2c15acaa.js +0 -1
  211. package/dist/runtime/web/.next/static/chunks/app/.vibeman/assets/images/[...path]/route-7b752a8641f96c1f.js +0 -1
  212. package/dist/runtime/web/.next/static/chunks/app/_not-found/page-34e66b251c2b5044.js +0 -1
  213. package/dist/runtime/web/.next/static/chunks/app/api/health/route-7b752a8641f96c1f.js +0 -1
  214. package/dist/runtime/web/.next/static/chunks/app/api/images/[...path]/route-7b752a8641f96c1f.js +0 -1
  215. package/dist/runtime/web/.next/static/chunks/app/api/upload/route-7b752a8641f96c1f.js +0 -1
  216. package/dist/runtime/web/.next/static/chunks/app/layout-df9ac93cb02b2385.js +0 -1
  217. package/dist/runtime/web/.next/static/chunks/app/page-6610743f7de5f92a.js +0 -1
  218. package/dist/runtime/web/.next/static/chunks/c25e0690-e9b798b8de667da1.js +0 -1
  219. package/dist/runtime/web/.next/static/chunks/framework-57157ec4d37f64aa.js +0 -1
  220. package/dist/runtime/web/.next/static/chunks/main-app-156cc0c60371bd78.js +0 -1
  221. package/dist/runtime/web/.next/static/chunks/main-df25d367c47b1fec.js +0 -1
  222. package/dist/runtime/web/.next/static/chunks/pages/_app-9f629a5e1131d19f.js +0 -1
  223. package/dist/runtime/web/.next/static/chunks/pages/_error-9238238274c7efcd.js +0 -1
  224. package/dist/runtime/web/.next/static/chunks/polyfills-42372ed130431b0a.js +0 -1
  225. package/dist/runtime/web/.next/static/chunks/webpack-cd50e39b423d1808.js +0 -1
  226. package/dist/runtime/web/.next/static/css/2728291c68f99cb1.css +0 -3
  227. package/dist/runtime/web/.next/static/css/4fbf378a264bd4ea.css +0 -1
  228. package/dist/runtime/web/.next/static/css/521bd69cc298cd1a.css +0 -1
  229. package/dist/runtime/web/.next/static/css/537e22821e101b87.css +0 -1
  230. package/dist/runtime/web/.next/static/media/19cfc7226ec3afaa-s.woff2 +0 -0
  231. package/dist/runtime/web/.next/static/media/21350d82a1f187e9-s.woff2 +0 -0
  232. package/dist/runtime/web/.next/static/media/8e9860b6e62d6359-s.woff2 +0 -0
  233. package/dist/runtime/web/.next/static/media/ba9851c3c22cd980-s.woff2 +0 -0
  234. package/dist/runtime/web/.next/static/media/c5fe6dc8356a8c31-s.woff2 +0 -0
  235. package/dist/runtime/web/.next/static/media/df0a9ae256c0569c-s.woff2 +0 -0
  236. package/dist/runtime/web/.next/static/media/e4af272ccee01ff0-s.p.woff2 +0 -0
  237. package/dist/runtime/web/package.json +0 -65
  238. package/dist/runtime/web/server.js +0 -44
  239. package/dist/tsconfig.tsbuildinfo +0 -1
@@ -1,93 +0,0 @@
1
- import { EventEmitter } from 'events';
2
- import { Task, WorktreeInfo as BaseWorktreeInfo, WorktreeConfig } from '../types/index.js';
3
- import { GitService } from './git-service.js';
4
- export interface WorktreeInfo extends BaseWorktreeInfo {
5
- git: GitService;
6
- }
7
- export declare class WorktreeService extends EventEmitter {
8
- private worktrees;
9
- private inFlightCreates;
10
- private gitService;
11
- private projectRoot;
12
- private config;
13
- private initialized;
14
- private initPromise;
15
- constructor(projectRoot?: string, gitService?: GitService);
16
- /**
17
- * Initialize the worktree service
18
- */
19
- initialize(): Promise<void>;
20
- /**
21
- * Recover existing worktrees after restart
22
- */
23
- private recoverExistingWorktrees;
24
- /**
25
- * Extract task ID from worktree path
26
- * TODO: need to improve this to be more robust
27
- */
28
- private extractTaskIdFromPath;
29
- /**
30
- * Create a new worktree for a task
31
- */
32
- createWorktree(task: Task): Promise<WorktreeInfo>;
33
- /**
34
- * Symlink essential files to worktree
35
- */
36
- private symlinkEssentialFiles;
37
- /**
38
- * Get worktree info for a task
39
- */
40
- getWorktree(taskId: string): WorktreeInfo | null;
41
- /**
42
- * List all Git worktrees with connection status to Vibeman tasks
43
- */
44
- listWorktrees(): Promise<Array<BaseWorktreeInfo & {
45
- isConnectedToTask: boolean;
46
- }>>;
47
- /**
48
- * Unified cleanup: remove worktree first, then branch
49
- * For connected worktrees, use taskId; for unconnected, use worktreePath and branchName
50
- */
51
- cleanupWorktree(params: {
52
- taskId?: string;
53
- worktreePath?: string;
54
- branchName?: string;
55
- isConnectedToTask: boolean;
56
- force?: boolean;
57
- }): Promise<void>;
58
- /**
59
- * Delete a worktree
60
- */
61
- deleteWorktree(taskId: string, force?: boolean): Promise<void>;
62
- /**
63
- * Create pull request from worktree branch
64
- */
65
- createPullRequest(taskId: string, _baseBranch?: string): Promise<{
66
- success: boolean;
67
- pullRequest?: any;
68
- error?: string;
69
- }>;
70
- /**
71
- * Sync worktree state with Git (public method for manual refresh)
72
- */
73
- syncWorktreeState(): Promise<void>;
74
- /**
75
- * Validate Git version compatibility for worktrees
76
- */
77
- private validateGitVersion;
78
- /**
79
- * Get worktree counts (synchronous, from memory)
80
- */
81
- getWorktreeCounts(): {
82
- active: number;
83
- total: number;
84
- };
85
- /**
86
- * Get current configuration
87
- */
88
- getConfig(): WorktreeConfig;
89
- /**
90
- * Get GitService instance for advanced operations
91
- */
92
- getGitService(): GitService;
93
- }
@@ -1,518 +0,0 @@
1
- import { EventEmitter } from 'events';
2
- import { GitService } from './git-service.js';
3
- import { log } from '../lib/logger.js';
4
- import { getSettingsService } from '../settings-service.js';
5
- import { getProjectRoot } from '../lib/server/project-root.js';
6
- import path from 'path';
7
- import fs from 'fs/promises';
8
- export class WorktreeService extends EventEmitter {
9
- constructor(projectRoot = getProjectRoot(), gitService) {
10
- super();
11
- this.worktrees = new Map();
12
- this.inFlightCreates = new Map();
13
- this.initialized = false;
14
- this.initPromise = null;
15
- this.projectRoot = projectRoot;
16
- this.gitService = gitService || new GitService(projectRoot);
17
- // Load configuration from settings, with fallback to environment then default
18
- const settingsWorktreePath = (() => {
19
- try {
20
- const svc = getSettingsService();
21
- const s = svc.getSettings();
22
- return s?.development?.git?.worktreePath;
23
- }
24
- catch {
25
- return undefined;
26
- }
27
- })();
28
- this.config = {
29
- // Default to parent directory of the repo
30
- worktreePath: settingsWorktreePath || '../',
31
- };
32
- }
33
- /**
34
- * Initialize the worktree service
35
- */
36
- async initialize() {
37
- if (this.initialized)
38
- return;
39
- if (this.initPromise)
40
- return this.initPromise;
41
- this.initPromise = (async () => {
42
- try {
43
- // Check if project root exists and is a Git repository
44
- await fs.access(this.projectRoot);
45
- // Ensure Git is available and version is compatible
46
- await this.validateGitVersion();
47
- // Ensure recovery of any existing worktrees
48
- await this.recoverExistingWorktrees();
49
- this.initialized = true;
50
- log.debug('WorktreeService initialized', undefined, 'worktree-service');
51
- }
52
- catch (error) {
53
- log.error('WorktreeService initialization failed, disabling worktrees', error, 'worktree-service');
54
- }
55
- })();
56
- try {
57
- await this.initPromise;
58
- }
59
- finally {
60
- this.initPromise = null;
61
- }
62
- }
63
- /**
64
- * Recover existing worktrees after restart
65
- */
66
- async recoverExistingWorktrees() {
67
- try {
68
- const gitWorktrees = await this.gitService.listWorktrees();
69
- const validTaskIds = new Set();
70
- let sawPrunable = false;
71
- // First, recover valid worktrees from Git
72
- const baseDir = path.resolve(this.projectRoot, this.config.worktreePath);
73
- for (const worktree of gitWorktrees) {
74
- if (worktree.prunable) {
75
- sawPrunable = true;
76
- continue;
77
- }
78
- // Only consider worktrees under the configured base directory
79
- const wtPath = path.resolve(worktree.path);
80
- if (wtPath.startsWith(baseDir + path.sep) || wtPath === baseDir) {
81
- const taskId = this.extractTaskIdFromPath(worktree.path);
82
- if (taskId) {
83
- try {
84
- // Ensure the path exists before creating a git instance
85
- await fs.stat(worktree.path);
86
- const worktreeInfo = {
87
- taskId,
88
- path: worktree.path,
89
- branchName: worktree.branch,
90
- git: new GitService(worktree.path),
91
- };
92
- this.worktrees.set(taskId, worktreeInfo);
93
- validTaskIds.add(taskId);
94
- log.debug('Recovered worktree for task', { taskId }, 'worktree-service');
95
- }
96
- catch {
97
- // Path no longer exists; mark for prune
98
- sawPrunable = true;
99
- }
100
- }
101
- }
102
- }
103
- if (sawPrunable) {
104
- try {
105
- await this.gitService.pruneWorktrees();
106
- log.info('Pruned stale worktree entries during recovery', undefined, 'worktree-service');
107
- }
108
- catch (e) {
109
- log.error('Failed to prune stale worktrees during recovery', e, 'worktree-service');
110
- }
111
- }
112
- // Remove any in-memory worktrees that no longer exist in Git
113
- const inMemoryTaskIds = Array.from(this.worktrees.keys());
114
- for (const taskId of inMemoryTaskIds) {
115
- if (!validTaskIds.has(taskId)) {
116
- this.worktrees.delete(taskId);
117
- log.info('Removed stale worktree reference', { taskId }, 'worktree-service');
118
- }
119
- }
120
- }
121
- catch (error) {
122
- log.error('Could not recover existing worktrees', error, 'worktree-service');
123
- }
124
- }
125
- /**
126
- * Extract task ID from worktree path
127
- * TODO: need to improve this to be more robust
128
- */
129
- extractTaskIdFromPath(worktreePath) {
130
- const basename = path.basename(worktreePath);
131
- // Worktree directory format: {taskId}
132
- // Accept IDs like FEATURE-001, FEAT-ABC12, BUG-4XYZ9, FEAT-EDITOR-EXP
133
- // Previously this only allowed a single hyphen; expand to multiple hyphen-separated segments.
134
- return /^[A-Z0-9]+(?:-[A-Z0-9]+)+$/i.test(basename) ? basename : null;
135
- }
136
- /**
137
- * Create a new worktree for a task
138
- */
139
- async createWorktree(task) {
140
- // Check if worktree already exists for this task
141
- if (this.worktrees.has(task.id)) {
142
- const existing = this.worktrees.get(task.id);
143
- log.info('Using existing worktree for task', { taskId: task.id }, 'worktree-service');
144
- return existing;
145
- }
146
- // Deduplicate concurrent create calls per task
147
- const existingPromise = this.inFlightCreates.get(task.id);
148
- if (existingPromise)
149
- return existingPromise;
150
- // Generate branch name and worktree path
151
- const branchName = this.gitService.generateBranchName(task);
152
- const baseDir = path.resolve(this.projectRoot, this.config.worktreePath);
153
- // Ensure base directory exists
154
- await fs.mkdir(baseDir, { recursive: true });
155
- const worktreePath = path.resolve(baseDir, task.id);
156
- const createPromise = (async () => {
157
- try {
158
- // Ensure we're in sync with remote
159
- await this.gitService.syncWithRemote();
160
- // Check existing worktrees and branches to allow reuse on reruns
161
- const gitWorktrees = await this.gitService.listWorktrees();
162
- // Try to find an existing worktree for this branch or path
163
- const existingByBranch = gitWorktrees.find((w) => w.branch === branchName);
164
- const existingByPath = gitWorktrees.find((w) => path.resolve(w.path) === path.resolve(worktreePath));
165
- if (existingByBranch && !existingByBranch.prunable) {
166
- // Reuse existing worktree by branch
167
- const resolvedPath = path.resolve(existingByBranch.path);
168
- await this.symlinkEssentialFiles(resolvedPath);
169
- const worktreeInfo = {
170
- taskId: task.id,
171
- path: resolvedPath,
172
- branchName,
173
- git: new GitService(resolvedPath),
174
- };
175
- this.worktrees.set(task.id, worktreeInfo);
176
- log.info('Reused existing worktree for branch', { taskId: task.id, path: resolvedPath, branchName }, 'worktree-service');
177
- this.emit('worktreeCreated', worktreeInfo);
178
- return worktreeInfo;
179
- }
180
- if (existingByPath && !existingByPath.prunable) {
181
- // Path already registered as a worktree; use it
182
- const resolvedPath = path.resolve(existingByPath.path);
183
- await this.symlinkEssentialFiles(resolvedPath);
184
- const worktreeInfo = {
185
- taskId: task.id,
186
- path: resolvedPath,
187
- branchName: existingByPath.branch || branchName,
188
- git: new GitService(resolvedPath),
189
- };
190
- this.worktrees.set(task.id, worktreeInfo);
191
- log.info('Reused existing worktree by path', { taskId: task.id, path: resolvedPath, branchName: worktreeInfo.branchName }, 'worktree-service');
192
- this.emit('worktreeCreated', worktreeInfo);
193
- return worktreeInfo;
194
- }
195
- // If we found prunable entries for this path or branch, prune before attempting to add
196
- if ((existingByBranch && existingByBranch.prunable) ||
197
- (existingByPath && existingByPath.prunable)) {
198
- try {
199
- await this.gitService.pruneWorktrees();
200
- log.info('Pruned stale worktree entries', { branchName, worktreePath }, 'worktree-service');
201
- }
202
- catch (e) {
203
- log.error('Failed to prune worktrees', e, 'worktree-service');
204
- }
205
- }
206
- // Determine if branch already exists locally
207
- const branchExists = await this.gitService.branchExists(branchName);
208
- // Create the worktree using git service
209
- await this.gitService.createWorktree(worktreePath, branchName, branchExists);
210
- // Copy essential files (like .env) to the worktree
211
- await this.symlinkEssentialFiles(worktreePath);
212
- const worktreeInfo = {
213
- taskId: task.id,
214
- path: worktreePath,
215
- branchName,
216
- git: new GitService(worktreePath),
217
- };
218
- this.worktrees.set(task.id, worktreeInfo);
219
- log.info('Created worktree', { taskId: task.id, path: worktreePath }, 'worktree-service');
220
- this.emit('worktreeCreated', worktreeInfo);
221
- return worktreeInfo;
222
- }
223
- catch (error) {
224
- log.error('Failed to create worktree', error, 'worktree-service');
225
- // Cleanup on failure
226
- try {
227
- await fs.rm(worktreePath, { recursive: true, force: true });
228
- }
229
- catch {
230
- // Ignore cleanup errors
231
- }
232
- throw new Error(`Failed to create worktree: ${error instanceof Error ? error.message : String(error)}`);
233
- }
234
- finally {
235
- // Clear in-flight marker
236
- this.inFlightCreates.delete(task.id);
237
- }
238
- })();
239
- this.inFlightCreates.set(task.id, createPromise);
240
- return createPromise;
241
- }
242
- /**
243
- * Symlink essential files to worktree
244
- */
245
- async symlinkEssentialFiles(worktreePath) {
246
- // Link only .env and .env* files in the project root.
247
- let entries = [];
248
- try {
249
- entries = (await fs.readdir(this.projectRoot)).filter((name) => name.startsWith('.env'));
250
- }
251
- catch {
252
- entries = [];
253
- }
254
- for (const name of entries) {
255
- const isIgnored = await this.gitService.isIgnored(name);
256
- if (!isIgnored) {
257
- log.debug('Skipped non-ignored env file', { name }, 'worktree-service');
258
- continue;
259
- }
260
- const sourcePath = path.join(this.projectRoot, name);
261
- const targetPath = path.join(worktreePath, name);
262
- try {
263
- await fs.stat(sourcePath);
264
- await fs.mkdir(path.dirname(targetPath), { recursive: true });
265
- // Ensure idempotency: if target exists and links to source, skip
266
- let shouldCreate = true;
267
- try {
268
- const lst = await fs.lstat(targetPath);
269
- if (lst.isSymbolicLink()) {
270
- const linkTarget = await fs.readlink(targetPath);
271
- const resolved = path.resolve(path.dirname(targetPath), linkTarget);
272
- if (resolved === sourcePath) {
273
- shouldCreate = false;
274
- }
275
- }
276
- }
277
- catch (error) {
278
- const err = error;
279
- if (err?.code !== 'ENOENT') {
280
- log.debug('Failed to inspect existing worktree env link', { name, error }, 'worktree-service');
281
- }
282
- }
283
- if (shouldCreate) {
284
- // Remove any existing file/dir and create a symlink
285
- await fs.rm(targetPath, { recursive: true, force: true });
286
- const relative = path.relative(path.dirname(targetPath), sourcePath);
287
- await fs.symlink(relative, targetPath);
288
- log.debug('Symlinked to worktree', { name }, 'worktree-service');
289
- }
290
- }
291
- catch (error) {
292
- log.debug('Failed to symlink env file', { name, error }, 'worktree-service');
293
- }
294
- }
295
- }
296
- /**
297
- * Get worktree info for a task
298
- */
299
- getWorktree(taskId) {
300
- return this.worktrees.get(taskId) || null;
301
- }
302
- /**
303
- * List all Git worktrees with connection status to Vibeman tasks
304
- */
305
- async listWorktrees() {
306
- try {
307
- const gitWorktrees = await this.gitService.listWorktrees();
308
- const result = [];
309
- for (const gitWorktree of gitWorktrees) {
310
- if (gitWorktree.prunable) {
311
- continue; // Skip prunable worktrees
312
- }
313
- // Skip main branch worktree
314
- if (gitWorktree.branch === 'main' || gitWorktree.branch === 'master') {
315
- continue;
316
- }
317
- const taskId = this.extractTaskIdFromPath(gitWorktree.path);
318
- const isConnectedToTask = taskId ? this.worktrees.has(taskId) : false;
319
- result.push({
320
- taskId: taskId || path.basename(gitWorktree.path),
321
- path: gitWorktree.path,
322
- branchName: gitWorktree.branch,
323
- isConnectedToTask,
324
- });
325
- }
326
- return result;
327
- }
328
- catch (error) {
329
- log.error('Failed to list all worktrees', error, 'worktree-service');
330
- throw new Error(`Failed to list all worktrees: ${error instanceof Error ? error.message : String(error)}`);
331
- }
332
- }
333
- /**
334
- * Unified cleanup: remove worktree first, then branch
335
- * For connected worktrees, use taskId; for unconnected, use worktreePath and branchName
336
- */
337
- async cleanupWorktree(params) {
338
- const { taskId, worktreePath, branchName, isConnectedToTask, force = false } = params;
339
- try {
340
- let actualWorktreePath;
341
- let actualBranchName;
342
- if (isConnectedToTask && taskId) {
343
- // For connected worktrees, get info from tracked worktrees
344
- const worktree = this.worktrees.get(taskId);
345
- if (!worktree) {
346
- throw new Error(`Worktree for task ${taskId} not found`);
347
- }
348
- actualWorktreePath = worktree.path;
349
- actualBranchName = worktree.branchName;
350
- // Check for uncommitted changes unless forced
351
- if (!force) {
352
- const hasChanges = await this.gitService.hasUncommittedChanges(actualWorktreePath);
353
- if (hasChanges) {
354
- throw new Error(`Worktree has uncommitted changes. Use force=true to delete anyway.`);
355
- }
356
- }
357
- }
358
- else {
359
- // For unconnected worktrees, use provided paths
360
- if (!worktreePath || !branchName) {
361
- throw new Error('worktreePath and branchName are required for unconnected worktrees');
362
- }
363
- actualWorktreePath = worktreePath;
364
- actualBranchName = branchName;
365
- }
366
- // Step 1: Remove the worktree
367
- await this.gitService.removeWorktree(actualWorktreePath, force);
368
- // Step 2: Prune worktrees to ensure git state is clean before branch deletion
369
- await this.gitService.pruneWorktrees();
370
- // Step 3: Try to remove the branch (if it's not main/master)
371
- if (actualBranchName !== 'main' && actualBranchName !== 'master') {
372
- try {
373
- await this.gitService.deleteLocalBranch(actualBranchName, true);
374
- log.info('Deleted branch', { branchName: actualBranchName }, 'worktree-service');
375
- }
376
- catch (error) {
377
- // Log but continue - branch might not exist or already deleted
378
- log.warn('Could not delete branch after worktree removal', {
379
- branchName: actualBranchName,
380
- error: error instanceof Error ? error.message : String(error),
381
- }, 'worktree-service');
382
- }
383
- }
384
- // Step 4: Clean up tracking if it was a connected worktree
385
- if (isConnectedToTask && taskId) {
386
- this.worktrees.delete(taskId);
387
- this.emit('worktreeDeleted', taskId);
388
- }
389
- log.info('Successfully cleaned up worktree', {
390
- taskId,
391
- worktreePath: actualWorktreePath,
392
- branchName: actualBranchName,
393
- isConnectedToTask,
394
- }, 'worktree-service');
395
- }
396
- catch (error) {
397
- log.error('Failed to cleanup worktree', error, 'worktree-service');
398
- throw new Error(`Failed to cleanup worktree: ${error instanceof Error ? error.message : String(error)}`);
399
- }
400
- }
401
- /**
402
- * Delete a worktree
403
- */
404
- async deleteWorktree(taskId, force = false) {
405
- const worktree = this.worktrees.get(taskId);
406
- if (!worktree) {
407
- throw new Error(`Worktree for task ${taskId} not found`);
408
- }
409
- try {
410
- // Check for uncommitted changes unless forced
411
- if (!force) {
412
- const hasChanges = await this.gitService.hasUncommittedChanges(worktree.path);
413
- if (hasChanges) {
414
- throw new Error(`Worktree has uncommitted changes. Use force=true to delete anyway.`);
415
- }
416
- }
417
- // Remove worktree using git service
418
- await this.gitService.removeWorktree(worktree.path, force);
419
- // Prune worktrees to ensure git state is clean before branch deletion
420
- await this.gitService.pruneWorktrees();
421
- // Delete local branch if it exists and is not merged
422
- try {
423
- await this.gitService.deleteLocalBranch(worktree.branchName, force);
424
- log.info('Deleted branch', { branchName: worktree.branchName }, 'worktree-service');
425
- }
426
- catch (error) {
427
- log.warn('Could not delete branch', error, 'worktree-service');
428
- }
429
- // Remove from tracking
430
- this.worktrees.delete(taskId);
431
- log.info('Deleted worktree', { taskId }, 'worktree-service');
432
- this.emit('worktreeDeleted', { taskId, worktree });
433
- }
434
- catch (error) {
435
- log.error('Failed to delete worktree', error, 'worktree-service');
436
- throw new Error(`Failed to delete worktree: ${error instanceof Error ? error.message : String(error)}`);
437
- }
438
- }
439
- /**
440
- * Create pull request from worktree branch
441
- */
442
- async createPullRequest(taskId, _baseBranch = 'main') {
443
- const worktree = this.worktrees.get(taskId);
444
- if (!worktree) {
445
- return {
446
- success: false,
447
- error: `Worktree for task ${taskId} not found`,
448
- };
449
- }
450
- try {
451
- // Check if there are any commits in the worktree branch
452
- const gitLog = await this.gitService.getLog(worktree.path, ['-n', '1']);
453
- if (!gitLog.latest) {
454
- return {
455
- success: false,
456
- error: 'No commits found in worktree branch',
457
- };
458
- }
459
- // Push the branch to remote
460
- await this.gitService.pushFromDirectory(worktree.path, 'origin', worktree.branchName);
461
- log.info('Pushed branch for task - manual PR creation required', { taskId, branchName: worktree.branchName }, 'worktree-service');
462
- return {
463
- success: true,
464
- error: 'Branch pushed successfully. GitHub integration removed - please create PR manually.',
465
- };
466
- }
467
- catch (error) {
468
- log.error('Failed to push branch', error, 'worktree-service');
469
- return {
470
- success: false,
471
- error: error instanceof Error ? error.message : String(error),
472
- };
473
- }
474
- }
475
- /**
476
- * Sync worktree state with Git (public method for manual refresh)
477
- */
478
- async syncWorktreeState() {
479
- await this.recoverExistingWorktrees();
480
- log.info('Worktree state synchronized', undefined, 'worktree-service');
481
- }
482
- /**
483
- * Validate Git version compatibility for worktrees
484
- */
485
- async validateGitVersion() {
486
- try {
487
- const version = await this.gitService.getGitVersion();
488
- const versionNumber = parseFloat(String(version.major) + '.' + String(version.minor));
489
- if (versionNumber < 2.15) {
490
- log.warn('Git version not optimal for worktrees', { version: version.installed, recommended: '2.15+' }, 'worktree-service');
491
- }
492
- }
493
- catch {
494
- throw new Error('Git is not available. Please install Git 2.15+ to use worktree functionality.');
495
- }
496
- }
497
- /**
498
- * Get worktree counts (synchronous, from memory)
499
- */
500
- getWorktreeCounts() {
501
- return {
502
- active: this.worktrees.size,
503
- total: this.worktrees.size,
504
- };
505
- }
506
- /**
507
- * Get current configuration
508
- */
509
- getConfig() {
510
- return { ...this.config };
511
- }
512
- /**
513
- * Get GitService instance for advanced operations
514
- */
515
- getGitService() {
516
- return this.gitService;
517
- }
518
- }
@@ -1 +0,0 @@
1
- export {};
@@ -1,20 +0,0 @@
1
- import { describe, it, expect } from 'vitest';
2
- import { WorktreeService } from './worktree-service.js';
3
- describe('WorktreeService.extractTaskIdFromPath', () => {
4
- it('accepts simple hyphenated IDs', () => {
5
- const svc = new WorktreeService(process.cwd());
6
- const fn = svc.extractTaskIdFromPath.bind(svc);
7
- expect(fn('/tmp/FEAT-DFMXM')).toBe('FEAT-DFMXM');
8
- });
9
- it('accepts multi-hyphen IDs like FEAT-EDITOR-EXP', () => {
10
- const svc = new WorktreeService(process.cwd());
11
- const fn = svc.extractTaskIdFromPath.bind(svc);
12
- expect(fn('/any/path/FEAT-EDITOR-EXP')).toBe('FEAT-EDITOR-EXP');
13
- });
14
- it('rejects clearly non-matching names', () => {
15
- const svc = new WorktreeService(process.cwd());
16
- const fn = svc.extractTaskIdFromPath.bind(svc);
17
- expect(fn('/tmp/feat_editor_exp')).toBeNull();
18
- expect(fn('/tmp/feat editor exp')).toBeNull();
19
- });
20
- });
@@ -1,58 +0,0 @@
1
- import { QualityResults } from '../types/index.js';
2
- interface QualityCheck {
3
- name: string;
4
- command: string;
5
- args: string[];
6
- timeout: number;
7
- }
8
- export declare class QualityPipeline {
9
- getChecksFor(): Promise<QualityCheck[]>;
10
- private getChecks;
11
- private detectQualityChecks;
12
- private aiDetectQualityChecks;
13
- private getDefaultProviderName;
14
- /**
15
- * Public: Detect quality checks (AI-only) and persist to settings if found.
16
- * Does not execute any checks.
17
- */
18
- detectAndPersistChecks(workingDirectory: string): Promise<Array<{
19
- name: string;
20
- command: string;
21
- args: string[];
22
- timeout: number;
23
- enabled: boolean;
24
- }>>;
25
- /**
26
- * Run all quality checks in the specified directory
27
- */
28
- runChecks(workingDirectory: string): Promise<QualityResults>;
29
- /**
30
- * Run checks with streaming logs via callback.
31
- */
32
- runChecksStreaming(workingDirectory: string, onLog?: (line: string) => void | Promise<void>): Promise<QualityResults>;
33
- /**
34
- * Run a single quality check
35
- */
36
- private runCheck;
37
- /**
38
- * Run a command and return its output
39
- */
40
- private runCommand;
41
- private runCommandStreaming;
42
- private isMissingCommandError;
43
- /**
44
- * Run individual quality check by name
45
- */
46
- runSingleCheck(checkName: string, workingDirectory: string): Promise<{
47
- passed: boolean;
48
- output: string;
49
- }>;
50
- /**
51
- * Get quality pipeline configuration
52
- */
53
- getConfig(): {
54
- checks: never[];
55
- parallel: boolean;
56
- };
57
- }
58
- export {};