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.
Files changed (241) hide show
  1. package/dist/api.js +49 -0
  2. package/dist/cli.js +135 -0
  3. package/dist/ui/index-gnk6rhxs.js +9 -0
  4. package/dist/ui/index.html +10 -0
  5. package/dist/ui/index.js +2 -0
  6. package/package.json +10 -46
  7. package/README.md +0 -12
  8. package/dist/index.js +0 -114
  9. package/dist/runtime/api/.tsbuildinfo +0 -1
  10. package/dist/runtime/api/agent/agent-service.d.ts +0 -229
  11. package/dist/runtime/api/agent/agent-service.js +0 -963
  12. package/dist/runtime/api/agent/ai-providers/amp-cli-provider.d.ts +0 -38
  13. package/dist/runtime/api/agent/ai-providers/amp-cli-provider.js +0 -268
  14. package/dist/runtime/api/agent/ai-providers/claude-code-adapter.d.ts +0 -61
  15. package/dist/runtime/api/agent/ai-providers/claude-code-adapter.js +0 -362
  16. package/dist/runtime/api/agent/ai-providers/codex-cli-provider.d.ts +0 -36
  17. package/dist/runtime/api/agent/ai-providers/codex-cli-provider.js +0 -375
  18. package/dist/runtime/api/agent/ai-providers/gemini-cli-provider.d.ts +0 -24
  19. package/dist/runtime/api/agent/ai-providers/gemini-cli-provider.js +0 -291
  20. package/dist/runtime/api/agent/ai-providers/index.d.ts +0 -9
  21. package/dist/runtime/api/agent/ai-providers/index.js +0 -9
  22. package/dist/runtime/api/agent/ai-providers/types.d.ts +0 -185
  23. package/dist/runtime/api/agent/ai-providers/types.js +0 -5
  24. package/dist/runtime/api/agent/amp-cli-provider.test.d.ts +0 -1
  25. package/dist/runtime/api/agent/amp-cli-provider.test.js +0 -99
  26. package/dist/runtime/api/agent/codex-cli-provider.test.d.ts +0 -1
  27. package/dist/runtime/api/agent/codex-cli-provider.test.js +0 -172
  28. package/dist/runtime/api/agent/core-agent-service.d.ts +0 -119
  29. package/dist/runtime/api/agent/core-agent-service.js +0 -267
  30. package/dist/runtime/api/agent/parsers.d.ts +0 -16
  31. package/dist/runtime/api/agent/parsers.js +0 -308
  32. package/dist/runtime/api/agent/prompt-service.d.ts +0 -30
  33. package/dist/runtime/api/agent/prompt-service.js +0 -452
  34. package/dist/runtime/api/agent/prompt-service.test.d.ts +0 -1
  35. package/dist/runtime/api/agent/prompt-service.test.js +0 -265
  36. package/dist/runtime/api/agent/routing-policy.d.ts +0 -171
  37. package/dist/runtime/api/agent/routing-policy.js +0 -196
  38. package/dist/runtime/api/agent/routing-policy.test.d.ts +0 -1
  39. package/dist/runtime/api/agent/routing-policy.test.js +0 -63
  40. package/dist/runtime/api/api/router-helpers.d.ts +0 -32
  41. package/dist/runtime/api/api/router-helpers.js +0 -31
  42. package/dist/runtime/api/api/routers/ai.d.ts +0 -200
  43. package/dist/runtime/api/api/routers/ai.js +0 -396
  44. package/dist/runtime/api/api/routers/executions.d.ts +0 -93
  45. package/dist/runtime/api/api/routers/executions.js +0 -94
  46. package/dist/runtime/api/api/routers/git.d.ts +0 -45
  47. package/dist/runtime/api/api/routers/git.js +0 -35
  48. package/dist/runtime/api/api/routers/provider-config.d.ts +0 -199
  49. package/dist/runtime/api/api/routers/provider-config.js +0 -252
  50. package/dist/runtime/api/api/routers/settings.d.ts +0 -158
  51. package/dist/runtime/api/api/routers/settings.js +0 -129
  52. package/dist/runtime/api/api/routers/tasks.d.ts +0 -141
  53. package/dist/runtime/api/api/routers/tasks.js +0 -238
  54. package/dist/runtime/api/api/routers/workflows.d.ts +0 -275
  55. package/dist/runtime/api/api/routers/workflows.js +0 -311
  56. package/dist/runtime/api/api/routers/worktrees.d.ts +0 -101
  57. package/dist/runtime/api/api/routers/worktrees.js +0 -80
  58. package/dist/runtime/api/api/trpc.d.ts +0 -118
  59. package/dist/runtime/api/api/trpc.js +0 -34
  60. package/dist/runtime/api/index.d.ts +0 -9
  61. package/dist/runtime/api/index.js +0 -117
  62. package/dist/runtime/api/lib/id-generator.d.ts +0 -70
  63. package/dist/runtime/api/lib/id-generator.js +0 -123
  64. package/dist/runtime/api/lib/local-config.d.ts +0 -335
  65. package/dist/runtime/api/lib/local-config.js +0 -304
  66. package/dist/runtime/api/lib/logger.d.ts +0 -11
  67. package/dist/runtime/api/lib/logger.js +0 -188
  68. package/dist/runtime/api/lib/provider-detection.d.ts +0 -61
  69. package/dist/runtime/api/lib/provider-detection.js +0 -326
  70. package/dist/runtime/api/lib/server/agent-service-singleton.d.ts +0 -6
  71. package/dist/runtime/api/lib/server/agent-service-singleton.js +0 -27
  72. package/dist/runtime/api/lib/server/bootstrap.d.ts +0 -38
  73. package/dist/runtime/api/lib/server/bootstrap.js +0 -197
  74. package/dist/runtime/api/lib/server/git-service-singleton.d.ts +0 -6
  75. package/dist/runtime/api/lib/server/git-service-singleton.js +0 -47
  76. package/dist/runtime/api/lib/server/project-root.d.ts +0 -2
  77. package/dist/runtime/api/lib/server/project-root.js +0 -61
  78. package/dist/runtime/api/lib/server/task-service-singleton.d.ts +0 -7
  79. package/dist/runtime/api/lib/server/task-service-singleton.js +0 -58
  80. package/dist/runtime/api/lib/server/vibeman-info.d.ts +0 -5
  81. package/dist/runtime/api/lib/server/vibeman-info.js +0 -85
  82. package/dist/runtime/api/lib/server/vibing-orchestrator-singleton.d.ts +0 -7
  83. package/dist/runtime/api/lib/server/vibing-orchestrator-singleton.js +0 -57
  84. package/dist/runtime/api/lib/trpc/server.d.ts +0 -965
  85. package/dist/runtime/api/lib/trpc/server.js +0 -11
  86. package/dist/runtime/api/lib/trpc/ws-server.d.ts +0 -8
  87. package/dist/runtime/api/lib/trpc/ws-server.js +0 -33
  88. package/dist/runtime/api/persistence/database-service.d.ts +0 -14
  89. package/dist/runtime/api/persistence/database-service.js +0 -74
  90. package/dist/runtime/api/persistence/execution-log-persistence.d.ts +0 -90
  91. package/dist/runtime/api/persistence/execution-log-persistence.js +0 -426
  92. package/dist/runtime/api/persistence/execution-log-persistence.test.d.ts +0 -1
  93. package/dist/runtime/api/persistence/execution-log-persistence.test.js +0 -170
  94. package/dist/runtime/api/router.d.ts +0 -968
  95. package/dist/runtime/api/router.js +0 -34
  96. package/dist/runtime/api/settings-service.d.ts +0 -110
  97. package/dist/runtime/api/settings-service.js +0 -678
  98. package/dist/runtime/api/tasks/file-watcher.d.ts +0 -23
  99. package/dist/runtime/api/tasks/file-watcher.js +0 -88
  100. package/dist/runtime/api/tasks/task-file-parser.d.ts +0 -14
  101. package/dist/runtime/api/tasks/task-file-parser.js +0 -180
  102. package/dist/runtime/api/tasks/task-service.d.ts +0 -36
  103. package/dist/runtime/api/tasks/task-service.js +0 -173
  104. package/dist/runtime/api/tasks/task-updater.d.ts +0 -62
  105. package/dist/runtime/api/tasks/task-updater.js +0 -260
  106. package/dist/runtime/api/tasks/task-updater.test.d.ts +0 -1
  107. package/dist/runtime/api/tasks/task-updater.test.js +0 -303
  108. package/dist/runtime/api/types/index.d.ts +0 -186
  109. package/dist/runtime/api/types/index.js +0 -1
  110. package/dist/runtime/api/types/settings.d.ts +0 -105
  111. package/dist/runtime/api/types/settings.js +0 -2
  112. package/dist/runtime/api/types.d.ts +0 -2
  113. package/dist/runtime/api/types.js +0 -1
  114. package/dist/runtime/api/utils/env.d.ts +0 -6
  115. package/dist/runtime/api/utils/env.js +0 -12
  116. package/dist/runtime/api/utils/stripNextEnv.d.ts +0 -7
  117. package/dist/runtime/api/utils/stripNextEnv.js +0 -22
  118. package/dist/runtime/api/utils/title-slug.d.ts +0 -6
  119. package/dist/runtime/api/utils/title-slug.js +0 -77
  120. package/dist/runtime/api/utils/url.d.ts +0 -2
  121. package/dist/runtime/api/utils/url.js +0 -19
  122. package/dist/runtime/api/vcs/git-history-service.d.ts +0 -57
  123. package/dist/runtime/api/vcs/git-history-service.js +0 -228
  124. package/dist/runtime/api/vcs/git-service.d.ts +0 -136
  125. package/dist/runtime/api/vcs/git-service.js +0 -307
  126. package/dist/runtime/api/vcs/worktree-service.d.ts +0 -93
  127. package/dist/runtime/api/vcs/worktree-service.js +0 -518
  128. package/dist/runtime/api/vcs/worktree-service.test.d.ts +0 -1
  129. package/dist/runtime/api/vcs/worktree-service.test.js +0 -20
  130. package/dist/runtime/api/workflows/quality-pipeline.d.ts +0 -58
  131. package/dist/runtime/api/workflows/quality-pipeline.js +0 -401
  132. package/dist/runtime/api/workflows/vibing-orchestrator.d.ts +0 -406
  133. package/dist/runtime/api/workflows/vibing-orchestrator.js +0 -2462
  134. package/dist/runtime/api/workflows/workflow-effects.d.ts +0 -45
  135. package/dist/runtime/api/workflows/workflow-effects.js +0 -49
  136. package/dist/runtime/api/workflows/workflow-reconciler.d.ts +0 -65
  137. package/dist/runtime/api/workflows/workflow-reconciler.js +0 -226
  138. package/dist/runtime/api/workflows/workflow-reducer.d.ts +0 -26
  139. package/dist/runtime/api/workflows/workflow-reducer.js +0 -288
  140. package/dist/runtime/api/workflows/workflow-reducer.test.d.ts +0 -1
  141. package/dist/runtime/api/workflows/workflow-reducer.test.js +0 -247
  142. package/dist/runtime/api/workflows/workflow-schema.d.ts +0 -546
  143. package/dist/runtime/api/workflows/workflow-schema.js +0 -256
  144. package/dist/runtime/web/.next/BUILD_ID +0 -1
  145. package/dist/runtime/web/.next/app-build-manifest.json +0 -66
  146. package/dist/runtime/web/.next/app-path-routes-manifest.json +0 -8
  147. package/dist/runtime/web/.next/build-manifest.json +0 -33
  148. package/dist/runtime/web/.next/package.json +0 -1
  149. package/dist/runtime/web/.next/prerender-manifest.json +0 -61
  150. package/dist/runtime/web/.next/react-loadable-manifest.json +0 -8
  151. package/dist/runtime/web/.next/required-server-files.json +0 -334
  152. package/dist/runtime/web/.next/routes-manifest.json +0 -70
  153. package/dist/runtime/web/.next/server/app/.vibeman/assets/images/[...path]/route.js +0 -1
  154. package/dist/runtime/web/.next/server/app/.vibeman/assets/images/[...path]/route.js.nft.json +0 -1
  155. package/dist/runtime/web/.next/server/app/.vibeman/assets/images/[...path]/route_client-reference-manifest.js +0 -1
  156. package/dist/runtime/web/.next/server/app/_not-found/page.js +0 -2
  157. package/dist/runtime/web/.next/server/app/_not-found/page.js.nft.json +0 -1
  158. package/dist/runtime/web/.next/server/app/_not-found/page_client-reference-manifest.js +0 -1
  159. package/dist/runtime/web/.next/server/app/_not-found.html +0 -7
  160. package/dist/runtime/web/.next/server/app/_not-found.meta +0 -8
  161. package/dist/runtime/web/.next/server/app/_not-found.rsc +0 -22
  162. package/dist/runtime/web/.next/server/app/api/health/route.js +0 -1
  163. package/dist/runtime/web/.next/server/app/api/health/route.js.nft.json +0 -1
  164. package/dist/runtime/web/.next/server/app/api/health/route_client-reference-manifest.js +0 -1
  165. package/dist/runtime/web/.next/server/app/api/images/[...path]/route.js +0 -1
  166. package/dist/runtime/web/.next/server/app/api/images/[...path]/route.js.nft.json +0 -1
  167. package/dist/runtime/web/.next/server/app/api/images/[...path]/route_client-reference-manifest.js +0 -1
  168. package/dist/runtime/web/.next/server/app/api/upload/route.js +0 -1
  169. package/dist/runtime/web/.next/server/app/api/upload/route.js.nft.json +0 -1
  170. package/dist/runtime/web/.next/server/app/api/upload/route_client-reference-manifest.js +0 -1
  171. package/dist/runtime/web/.next/server/app/index.html +0 -7
  172. package/dist/runtime/web/.next/server/app/index.meta +0 -7
  173. package/dist/runtime/web/.next/server/app/index.rsc +0 -27
  174. package/dist/runtime/web/.next/server/app/page.js +0 -112
  175. package/dist/runtime/web/.next/server/app/page.js.nft.json +0 -1
  176. package/dist/runtime/web/.next/server/app/page_client-reference-manifest.js +0 -1
  177. package/dist/runtime/web/.next/server/app-paths-manifest.json +0 -8
  178. package/dist/runtime/web/.next/server/chunks/210.js +0 -1
  179. package/dist/runtime/web/.next/server/chunks/291.js +0 -18
  180. package/dist/runtime/web/.next/server/chunks/552.js +0 -22
  181. package/dist/runtime/web/.next/server/chunks/780.js +0 -1
  182. package/dist/runtime/web/.next/server/chunks/905.js +0 -6
  183. package/dist/runtime/web/.next/server/chunks/98.js +0 -1
  184. package/dist/runtime/web/.next/server/functions-config-manifest.json +0 -4
  185. package/dist/runtime/web/.next/server/middleware-build-manifest.js +0 -1
  186. package/dist/runtime/web/.next/server/middleware-manifest.json +0 -6
  187. package/dist/runtime/web/.next/server/middleware-react-loadable-manifest.js +0 -1
  188. package/dist/runtime/web/.next/server/next-font-manifest.js +0 -1
  189. package/dist/runtime/web/.next/server/next-font-manifest.json +0 -1
  190. package/dist/runtime/web/.next/server/pages/404.html +0 -7
  191. package/dist/runtime/web/.next/server/pages/500.html +0 -1
  192. package/dist/runtime/web/.next/server/pages/_app.js +0 -1
  193. package/dist/runtime/web/.next/server/pages/_app.js.nft.json +0 -1
  194. package/dist/runtime/web/.next/server/pages/_document.js +0 -1
  195. package/dist/runtime/web/.next/server/pages/_document.js.nft.json +0 -1
  196. package/dist/runtime/web/.next/server/pages/_error.js +0 -19
  197. package/dist/runtime/web/.next/server/pages/_error.js.nft.json +0 -1
  198. package/dist/runtime/web/.next/server/pages-manifest.json +0 -6
  199. package/dist/runtime/web/.next/server/server-reference-manifest.js +0 -1
  200. package/dist/runtime/web/.next/server/server-reference-manifest.json +0 -1
  201. package/dist/runtime/web/.next/server/webpack-runtime.js +0 -1
  202. package/dist/runtime/web/.next/static/LJFZk_8tvKFN_Ee4HqUuM/_buildManifest.js +0 -1
  203. package/dist/runtime/web/.next/static/LJFZk_8tvKFN_Ee4HqUuM/_ssgManifest.js +0 -1
  204. package/dist/runtime/web/.next/static/chunks/05c91ade-7d09b2b280adffd1.js +0 -1
  205. package/dist/runtime/web/.next/static/chunks/201-51bef3fa8c832e2e.js +0 -1
  206. package/dist/runtime/web/.next/static/chunks/524-89747ed9b0294f8a.js +0 -1
  207. package/dist/runtime/web/.next/static/chunks/554-8bec6e9cca6acc67.js +0 -1
  208. package/dist/runtime/web/.next/static/chunks/764.86e9503a69d45a85.js +0 -1
  209. package/dist/runtime/web/.next/static/chunks/7ab4dc20-239138e0ae7af24a.js +0 -1
  210. package/dist/runtime/web/.next/static/chunks/905-342391e3d3a3678f.js +0 -20
  211. package/dist/runtime/web/.next/static/chunks/a8a5ce16-4edea7df2d9b544a.js +0 -79
  212. package/dist/runtime/web/.next/static/chunks/ad74d572-4c1b162e2c15acaa.js +0 -1
  213. package/dist/runtime/web/.next/static/chunks/app/.vibeman/assets/images/[...path]/route-7b752a8641f96c1f.js +0 -1
  214. package/dist/runtime/web/.next/static/chunks/app/_not-found/page-34e66b251c2b5044.js +0 -1
  215. package/dist/runtime/web/.next/static/chunks/app/api/health/route-7b752a8641f96c1f.js +0 -1
  216. package/dist/runtime/web/.next/static/chunks/app/api/images/[...path]/route-7b752a8641f96c1f.js +0 -1
  217. package/dist/runtime/web/.next/static/chunks/app/api/upload/route-7b752a8641f96c1f.js +0 -1
  218. package/dist/runtime/web/.next/static/chunks/app/layout-df9ac93cb02b2385.js +0 -1
  219. package/dist/runtime/web/.next/static/chunks/app/page-6610743f7de5f92a.js +0 -1
  220. package/dist/runtime/web/.next/static/chunks/c25e0690-e9b798b8de667da1.js +0 -1
  221. package/dist/runtime/web/.next/static/chunks/framework-57157ec4d37f64aa.js +0 -1
  222. package/dist/runtime/web/.next/static/chunks/main-app-156cc0c60371bd78.js +0 -1
  223. package/dist/runtime/web/.next/static/chunks/main-df25d367c47b1fec.js +0 -1
  224. package/dist/runtime/web/.next/static/chunks/pages/_app-9f629a5e1131d19f.js +0 -1
  225. package/dist/runtime/web/.next/static/chunks/pages/_error-9238238274c7efcd.js +0 -1
  226. package/dist/runtime/web/.next/static/chunks/polyfills-42372ed130431b0a.js +0 -1
  227. package/dist/runtime/web/.next/static/chunks/webpack-cd50e39b423d1808.js +0 -1
  228. package/dist/runtime/web/.next/static/css/2728291c68f99cb1.css +0 -3
  229. package/dist/runtime/web/.next/static/css/4fbf378a264bd4ea.css +0 -1
  230. package/dist/runtime/web/.next/static/css/521bd69cc298cd1a.css +0 -1
  231. package/dist/runtime/web/.next/static/css/537e22821e101b87.css +0 -1
  232. package/dist/runtime/web/.next/static/media/19cfc7226ec3afaa-s.woff2 +0 -0
  233. package/dist/runtime/web/.next/static/media/21350d82a1f187e9-s.woff2 +0 -0
  234. package/dist/runtime/web/.next/static/media/8e9860b6e62d6359-s.woff2 +0 -0
  235. package/dist/runtime/web/.next/static/media/ba9851c3c22cd980-s.woff2 +0 -0
  236. package/dist/runtime/web/.next/static/media/c5fe6dc8356a8c31-s.woff2 +0 -0
  237. package/dist/runtime/web/.next/static/media/df0a9ae256c0569c-s.woff2 +0 -0
  238. package/dist/runtime/web/.next/static/media/e4af272ccee01ff0-s.p.woff2 +0 -0
  239. package/dist/runtime/web/package.json +0 -65
  240. package/dist/runtime/web/server.js +0 -44
  241. 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 {};