@sudocode-ai/local-server 0.1.7 → 0.1.9

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 (282) hide show
  1. package/README.md +6 -0
  2. package/dist/errors/agent-errors.d.ts +43 -0
  3. package/dist/errors/agent-errors.d.ts.map +1 -0
  4. package/dist/errors/agent-errors.js +69 -0
  5. package/dist/errors/agent-errors.js.map +1 -0
  6. package/dist/execution/adapters/claude-adapter.d.ts +63 -0
  7. package/dist/execution/adapters/claude-adapter.d.ts.map +1 -0
  8. package/dist/execution/adapters/claude-adapter.js +82 -0
  9. package/dist/execution/adapters/claude-adapter.js.map +1 -0
  10. package/dist/execution/adapters/codex-adapter.d.ts +67 -0
  11. package/dist/execution/adapters/codex-adapter.d.ts.map +1 -0
  12. package/dist/execution/adapters/codex-adapter.js +183 -0
  13. package/dist/execution/adapters/codex-adapter.js.map +1 -0
  14. package/dist/execution/adapters/codex-config-builder.d.ts +30 -0
  15. package/dist/execution/adapters/codex-config-builder.d.ts.map +1 -0
  16. package/dist/execution/adapters/codex-config-builder.js +110 -0
  17. package/dist/execution/adapters/codex-config-builder.js.map +1 -0
  18. package/dist/execution/adapters/copilot-adapter.d.ts +94 -0
  19. package/dist/execution/adapters/copilot-adapter.d.ts.map +1 -0
  20. package/dist/execution/adapters/copilot-adapter.js +163 -0
  21. package/dist/execution/adapters/copilot-adapter.js.map +1 -0
  22. package/dist/execution/adapters/copilot-config-builder.d.ts +48 -0
  23. package/dist/execution/adapters/copilot-config-builder.d.ts.map +1 -0
  24. package/dist/execution/adapters/copilot-config-builder.js +125 -0
  25. package/dist/execution/adapters/copilot-config-builder.js.map +1 -0
  26. package/dist/execution/adapters/cursor-adapter.d.ts +66 -0
  27. package/dist/execution/adapters/cursor-adapter.d.ts.map +1 -0
  28. package/dist/execution/adapters/cursor-adapter.js +121 -0
  29. package/dist/execution/adapters/cursor-adapter.js.map +1 -0
  30. package/dist/execution/adapters/cursor-config-builder.d.ts +29 -0
  31. package/dist/execution/adapters/cursor-config-builder.d.ts.map +1 -0
  32. package/dist/execution/adapters/cursor-config-builder.js +49 -0
  33. package/dist/execution/adapters/cursor-config-builder.js.map +1 -0
  34. package/dist/execution/adapters/shared/config-presets.d.ts +102 -0
  35. package/dist/execution/adapters/shared/config-presets.d.ts.map +1 -0
  36. package/dist/execution/adapters/shared/config-presets.js +205 -0
  37. package/dist/execution/adapters/shared/config-presets.js.map +1 -0
  38. package/dist/execution/adapters/shared/config-utils.d.ts +95 -0
  39. package/dist/execution/adapters/shared/config-utils.d.ts.map +1 -0
  40. package/dist/execution/adapters/shared/config-utils.js +163 -0
  41. package/dist/execution/adapters/shared/config-utils.js.map +1 -0
  42. package/dist/execution/adapters/shared/index.d.ts +8 -0
  43. package/dist/execution/adapters/shared/index.d.ts.map +1 -0
  44. package/dist/execution/adapters/shared/index.js +8 -0
  45. package/dist/execution/adapters/shared/index.js.map +1 -0
  46. package/dist/execution/executors/agent-executor-wrapper.d.ts +153 -0
  47. package/dist/execution/executors/agent-executor-wrapper.d.ts.map +1 -0
  48. package/dist/execution/executors/agent-executor-wrapper.js +652 -0
  49. package/dist/execution/executors/agent-executor-wrapper.js.map +1 -0
  50. package/dist/execution/executors/executor-factory.d.ts +95 -0
  51. package/dist/execution/executors/executor-factory.d.ts.map +1 -0
  52. package/dist/execution/executors/executor-factory.js +120 -0
  53. package/dist/execution/executors/executor-factory.js.map +1 -0
  54. package/dist/execution/output/ag-ui-adapter.d.ts +0 -2
  55. package/dist/execution/output/ag-ui-adapter.d.ts.map +1 -1
  56. package/dist/execution/output/ag-ui-adapter.js +0 -2
  57. package/dist/execution/output/ag-ui-adapter.js.map +1 -1
  58. package/dist/execution/output/index.d.ts +0 -3
  59. package/dist/execution/output/index.d.ts.map +1 -1
  60. package/dist/execution/output/index.js +0 -2
  61. package/dist/execution/output/index.js.map +1 -1
  62. package/dist/execution/output/normalized-to-ag-ui-adapter.d.ts +108 -0
  63. package/dist/execution/output/normalized-to-ag-ui-adapter.d.ts.map +1 -0
  64. package/dist/execution/output/normalized-to-ag-ui-adapter.js +321 -0
  65. package/dist/execution/output/normalized-to-ag-ui-adapter.js.map +1 -0
  66. package/dist/execution/process/builders/claude.d.ts +24 -57
  67. package/dist/execution/process/builders/claude.d.ts.map +1 -1
  68. package/dist/execution/process/builders/claude.js +153 -19
  69. package/dist/execution/process/builders/claude.js.map +1 -1
  70. package/dist/execution/transport/ipc-transport-manager.d.ts +74 -0
  71. package/dist/execution/transport/ipc-transport-manager.d.ts.map +1 -0
  72. package/dist/execution/transport/ipc-transport-manager.js +104 -0
  73. package/dist/execution/transport/ipc-transport-manager.js.map +1 -0
  74. package/dist/execution/transport/transport-manager.d.ts.map +1 -1
  75. package/dist/execution/transport/transport-manager.js +3 -0
  76. package/dist/execution/transport/transport-manager.js.map +1 -1
  77. package/dist/execution/worktree/conflict-detector.d.ts +85 -0
  78. package/dist/execution/worktree/conflict-detector.d.ts.map +1 -0
  79. package/dist/execution/worktree/conflict-detector.js +129 -0
  80. package/dist/execution/worktree/conflict-detector.js.map +1 -0
  81. package/dist/execution/worktree/git-cli.d.ts +9 -0
  82. package/dist/execution/worktree/git-cli.d.ts.map +1 -1
  83. package/dist/execution/worktree/git-cli.js +10 -0
  84. package/dist/execution/worktree/git-cli.js.map +1 -1
  85. package/dist/execution/worktree/git-sync-cli.d.ts +198 -0
  86. package/dist/execution/worktree/git-sync-cli.d.ts.map +1 -0
  87. package/dist/execution/worktree/git-sync-cli.js +401 -0
  88. package/dist/execution/worktree/git-sync-cli.js.map +1 -0
  89. package/dist/execution/worktree/manager.d.ts +18 -0
  90. package/dist/execution/worktree/manager.d.ts.map +1 -1
  91. package/dist/execution/worktree/manager.js +9 -3
  92. package/dist/execution/worktree/manager.js.map +1 -1
  93. package/dist/index.d.ts +1 -3
  94. package/dist/index.d.ts.map +1 -1
  95. package/dist/index.js +124 -229
  96. package/dist/index.js.map +1 -1
  97. package/dist/middleware/project-context.d.ts +37 -0
  98. package/dist/middleware/project-context.d.ts.map +1 -0
  99. package/dist/middleware/project-context.js +91 -0
  100. package/dist/middleware/project-context.js.map +1 -0
  101. package/dist/public/assets/index-DV9Tbujb.css +1 -0
  102. package/dist/public/assets/index-DcDX9-Ad.js +740 -0
  103. package/dist/public/assets/index-DcDX9-Ad.js.map +1 -0
  104. package/dist/public/assets/{react-vendor-ByUx1V_q.js → react-vendor-DiL5hC7l.js} +2 -2
  105. package/dist/public/assets/{react-vendor-ByUx1V_q.js.map → react-vendor-DiL5hC7l.js.map} +1 -1
  106. package/dist/public/assets/ui-vendor-B4WMPEfa.js +54 -0
  107. package/dist/public/assets/ui-vendor-B4WMPEfa.js.map +1 -0
  108. package/dist/public/index.html +4 -4
  109. package/dist/routes/agents.d.ts +3 -0
  110. package/dist/routes/agents.d.ts.map +1 -0
  111. package/dist/routes/agents.js +62 -0
  112. package/dist/routes/agents.js.map +1 -0
  113. package/dist/routes/config.d.ts +3 -0
  114. package/dist/routes/config.d.ts.map +1 -0
  115. package/dist/routes/config.js +25 -0
  116. package/dist/routes/config.js.map +1 -0
  117. package/dist/routes/editors.d.ts +15 -0
  118. package/dist/routes/editors.d.ts.map +1 -0
  119. package/dist/routes/editors.js +98 -0
  120. package/dist/routes/editors.js.map +1 -0
  121. package/dist/routes/executions-stream.d.ts +8 -5
  122. package/dist/routes/executions-stream.d.ts.map +1 -1
  123. package/dist/routes/executions-stream.js +10 -6
  124. package/dist/routes/executions-stream.js.map +1 -1
  125. package/dist/routes/executions.d.ts +6 -10
  126. package/dist/routes/executions.d.ts.map +1 -1
  127. package/dist/routes/executions.js +792 -37
  128. package/dist/routes/executions.js.map +1 -1
  129. package/dist/routes/feedback.d.ts +3 -2
  130. package/dist/routes/feedback.d.ts.map +1 -1
  131. package/dist/routes/feedback.js +12 -10
  132. package/dist/routes/feedback.js.map +1 -1
  133. package/dist/routes/files.d.ts +18 -0
  134. package/dist/routes/files.d.ts.map +1 -0
  135. package/dist/routes/files.js +89 -0
  136. package/dist/routes/files.js.map +1 -0
  137. package/dist/routes/issues.d.ts +3 -2
  138. package/dist/routes/issues.d.ts.map +1 -1
  139. package/dist/routes/issues.js +19 -18
  140. package/dist/routes/issues.js.map +1 -1
  141. package/dist/routes/projects.d.ts +11 -0
  142. package/dist/routes/projects.d.ts.map +1 -0
  143. package/dist/routes/projects.js +447 -0
  144. package/dist/routes/projects.js.map +1 -0
  145. package/dist/routes/relationships.d.ts +3 -2
  146. package/dist/routes/relationships.d.ts.map +1 -1
  147. package/dist/routes/relationships.js +12 -10
  148. package/dist/routes/relationships.js.map +1 -1
  149. package/dist/routes/repo-info.d.ts +3 -0
  150. package/dist/routes/repo-info.d.ts.map +1 -0
  151. package/dist/routes/repo-info.js +203 -0
  152. package/dist/routes/repo-info.js.map +1 -0
  153. package/dist/routes/specs.d.ts +3 -2
  154. package/dist/routes/specs.d.ts.map +1 -1
  155. package/dist/routes/specs.js +19 -18
  156. package/dist/routes/specs.js.map +1 -1
  157. package/dist/routes/version.d.ts +3 -0
  158. package/dist/routes/version.d.ts.map +1 -0
  159. package/dist/routes/version.js +25 -0
  160. package/dist/routes/version.js.map +1 -0
  161. package/dist/services/agent-registry.d.ts +140 -0
  162. package/dist/services/agent-registry.d.ts.map +1 -0
  163. package/dist/services/agent-registry.js +272 -0
  164. package/dist/services/agent-registry.js.map +1 -0
  165. package/dist/services/editor-service.d.ts +57 -0
  166. package/dist/services/editor-service.d.ts.map +1 -0
  167. package/dist/services/editor-service.js +204 -0
  168. package/dist/services/editor-service.js.map +1 -0
  169. package/dist/services/execution-changes-service.d.ts +110 -0
  170. package/dist/services/execution-changes-service.d.ts.map +1 -0
  171. package/dist/services/execution-changes-service.js +700 -0
  172. package/dist/services/execution-changes-service.js.map +1 -0
  173. package/dist/services/execution-lifecycle.d.ts +1 -0
  174. package/dist/services/execution-lifecycle.d.ts.map +1 -1
  175. package/dist/services/execution-lifecycle.js +37 -7
  176. package/dist/services/execution-lifecycle.js.map +1 -1
  177. package/dist/services/execution-logs-store.d.ts +75 -0
  178. package/dist/services/execution-logs-store.d.ts.map +1 -1
  179. package/dist/services/execution-logs-store.js +142 -2
  180. package/dist/services/execution-logs-store.js.map +1 -1
  181. package/dist/services/execution-service.d.ts +82 -59
  182. package/dist/services/execution-service.d.ts.map +1 -1
  183. package/dist/services/execution-service.js +514 -469
  184. package/dist/services/execution-service.js.map +1 -1
  185. package/dist/services/execution-worker-pool.d.ts +116 -0
  186. package/dist/services/execution-worker-pool.d.ts.map +1 -0
  187. package/dist/services/execution-worker-pool.js +326 -0
  188. package/dist/services/execution-worker-pool.js.map +1 -0
  189. package/dist/services/executions.d.ts +3 -0
  190. package/dist/services/executions.d.ts.map +1 -1
  191. package/dist/services/executions.js +11 -17
  192. package/dist/services/executions.js.map +1 -1
  193. package/dist/services/export.d.ts +8 -2
  194. package/dist/services/export.d.ts.map +1 -1
  195. package/dist/services/export.js +29 -23
  196. package/dist/services/export.js.map +1 -1
  197. package/dist/services/file-search/git-ls-files-strategy.d.ts +72 -0
  198. package/dist/services/file-search/git-ls-files-strategy.d.ts.map +1 -0
  199. package/dist/services/file-search/git-ls-files-strategy.js +176 -0
  200. package/dist/services/file-search/git-ls-files-strategy.js.map +1 -0
  201. package/dist/services/file-search/index.d.ts +9 -0
  202. package/dist/services/file-search/index.d.ts.map +1 -0
  203. package/dist/services/file-search/index.js +10 -0
  204. package/dist/services/file-search/index.js.map +1 -0
  205. package/dist/services/file-search/registry.d.ts +97 -0
  206. package/dist/services/file-search/registry.d.ts.map +1 -0
  207. package/dist/services/file-search/registry.js +140 -0
  208. package/dist/services/file-search/registry.js.map +1 -0
  209. package/dist/services/file-search/strategy.d.ts +58 -0
  210. package/dist/services/file-search/strategy.d.ts.map +1 -0
  211. package/dist/services/file-search/strategy.js +8 -0
  212. package/dist/services/file-search/strategy.js.map +1 -0
  213. package/dist/services/project-context.d.ts +69 -0
  214. package/dist/services/project-context.d.ts.map +1 -0
  215. package/dist/services/project-context.js +113 -0
  216. package/dist/services/project-context.js.map +1 -0
  217. package/dist/services/project-manager.d.ts +95 -0
  218. package/dist/services/project-manager.d.ts.map +1 -0
  219. package/dist/services/project-manager.js +388 -0
  220. package/dist/services/project-manager.js.map +1 -0
  221. package/dist/services/project-registry.d.ts +98 -0
  222. package/dist/services/project-registry.d.ts.map +1 -0
  223. package/dist/services/project-registry.js +289 -0
  224. package/dist/services/project-registry.js.map +1 -0
  225. package/dist/services/prompt-resolver.d.ts +97 -0
  226. package/dist/services/prompt-resolver.d.ts.map +1 -0
  227. package/dist/services/prompt-resolver.js +377 -0
  228. package/dist/services/prompt-resolver.js.map +1 -0
  229. package/dist/services/repo-info.d.ts +12 -0
  230. package/dist/services/repo-info.d.ts.map +1 -1
  231. package/dist/services/repo-info.js +46 -0
  232. package/dist/services/repo-info.js.map +1 -1
  233. package/dist/services/version-service.d.ts +14 -0
  234. package/dist/services/version-service.d.ts.map +1 -0
  235. package/dist/services/version-service.js +57 -0
  236. package/dist/services/version-service.js.map +1 -0
  237. package/dist/services/watcher.d.ts +3 -4
  238. package/dist/services/watcher.d.ts.map +1 -1
  239. package/dist/services/watcher.js +18 -35
  240. package/dist/services/watcher.js.map +1 -1
  241. package/dist/services/websocket.d.ts +30 -16
  242. package/dist/services/websocket.d.ts.map +1 -1
  243. package/dist/services/websocket.js +102 -37
  244. package/dist/services/websocket.js.map +1 -1
  245. package/dist/services/worktree-sync-service.d.ts +326 -0
  246. package/dist/services/worktree-sync-service.d.ts.map +1 -0
  247. package/dist/services/worktree-sync-service.js +1091 -0
  248. package/dist/services/worktree-sync-service.js.map +1 -0
  249. package/dist/types/editor.d.ts +49 -0
  250. package/dist/types/editor.d.ts.map +1 -0
  251. package/dist/types/editor.js +50 -0
  252. package/dist/types/editor.js.map +1 -0
  253. package/dist/types/project.d.ts +58 -0
  254. package/dist/types/project.d.ts.map +1 -0
  255. package/dist/types/project.js +10 -0
  256. package/dist/types/project.js.map +1 -0
  257. package/dist/utils/executable-check.d.ts +36 -0
  258. package/dist/utils/executable-check.d.ts.map +1 -0
  259. package/dist/utils/executable-check.js +79 -0
  260. package/dist/utils/executable-check.js.map +1 -0
  261. package/dist/workers/execution-worker.d.ts +18 -0
  262. package/dist/workers/execution-worker.d.ts.map +1 -0
  263. package/dist/workers/execution-worker.js +340 -0
  264. package/dist/workers/execution-worker.js.map +1 -0
  265. package/dist/workers/worker-ipc.d.ts +84 -0
  266. package/dist/workers/worker-ipc.d.ts.map +1 -0
  267. package/dist/workers/worker-ipc.js +29 -0
  268. package/dist/workers/worker-ipc.js.map +1 -0
  269. package/package.json +6 -5
  270. package/dist/execution/output/ag-ui-integration.d.ts +0 -96
  271. package/dist/execution/output/ag-ui-integration.d.ts.map +0 -1
  272. package/dist/execution/output/ag-ui-integration.js +0 -96
  273. package/dist/execution/output/ag-ui-integration.js.map +0 -1
  274. package/dist/execution/output/claude-code-output-processor.d.ts +0 -321
  275. package/dist/execution/output/claude-code-output-processor.d.ts.map +0 -1
  276. package/dist/execution/output/claude-code-output-processor.js +0 -769
  277. package/dist/execution/output/claude-code-output-processor.js.map +0 -1
  278. package/dist/public/assets/index-B3SEMufD.js +0 -580
  279. package/dist/public/assets/index-B3SEMufD.js.map +0 -1
  280. package/dist/public/assets/index-D2YGL3gX.css +0 -1
  281. package/dist/public/assets/ui-vendor-CotR6bx9.js +0 -54
  282. package/dist/public/assets/ui-vendor-CotR6bx9.js.map +0 -1
@@ -0,0 +1,388 @@
1
+ import * as fs from "fs";
2
+ import * as path from "path";
3
+ import { ProjectContext } from "./project-context.js";
4
+ import { initDatabase } from "./db.js";
5
+ import { TransportManager } from "../execution/transport/transport-manager.js";
6
+ import { ExecutionService } from "./execution-service.js";
7
+ import { ExecutionLogsStore } from "./execution-logs-store.js";
8
+ import { WorktreeManager } from "../execution/worktree/manager.js";
9
+ import { getWorktreeConfig } from "../execution/worktree/config.js";
10
+ import { ExecutionLifecycleService } from "./execution-lifecycle.js";
11
+ import { startServerWatcher } from "./watcher.js";
12
+ import { Ok, Err } from "../types/project.js";
13
+ import { broadcastIssueUpdate, broadcastSpecUpdate } from "./websocket.js";
14
+ import { getIssueById } from "./issues.js";
15
+ import { getSpecById } from "./specs.js";
16
+ import { performInitialization, isInitialized, } from "@sudocode-ai/cli/dist/cli/init-commands.js";
17
+ /**
18
+ * ProjectManager manages the lifecycle of multiple open projects.
19
+ *
20
+ * Responsibilities:
21
+ * - Open and close projects
22
+ * - Validate project directories
23
+ * - Cache database connections with TTL eviction
24
+ * - Track all open projects
25
+ * - Coordinate with ProjectRegistry for persistence
26
+ *
27
+ * Architecture:
28
+ * - Each open project gets a ProjectContext with isolated services
29
+ * - Database connections are cached for 30 minutes after project close
30
+ * - All services (file watcher, executions, etc.) are per-project
31
+ */
32
+ export class ProjectManager {
33
+ registry;
34
+ openProjects = new Map();
35
+ dbCache = new Map();
36
+ /** Database connection TTL: 30 minutes */
37
+ DB_CACHE_TTL = 30 * 60 * 1000;
38
+ /** Whether file watching is enabled */
39
+ watchEnabled;
40
+ constructor(registry, options) {
41
+ this.registry = registry;
42
+ this.watchEnabled = options?.watchEnabled ?? true;
43
+ }
44
+ /**
45
+ * Open a project and initialize all its services
46
+ * @param projectPath - Absolute path to project root directory
47
+ * @returns ProjectContext for the opened project
48
+ */
49
+ async openProject(projectPath) {
50
+ try {
51
+ // 1. Validate project structure
52
+ const validation = this.validateProject(projectPath);
53
+ if (!validation.ok) {
54
+ return validation;
55
+ }
56
+ // 2. Generate or lookup project ID
57
+ const projectId = this.registry.generateProjectId(projectPath);
58
+ // 3. Check if already open
59
+ const existing = this.openProjects.get(projectId);
60
+ if (existing) {
61
+ console.log(`Project already open: ${projectId}`);
62
+ this.registry.updateLastOpened(projectId);
63
+ await this.registry.save();
64
+ return Ok(existing);
65
+ }
66
+ // 4. Initialize database (check cache first)
67
+ const db = await this.getOrCreateDatabase(projectId, projectPath);
68
+ // 5. Initialize all services for this project
69
+ const sudocodeDir = path.join(projectPath, ".sudocode");
70
+ const transportManager = new TransportManager();
71
+ const logsStore = new ExecutionLogsStore(db);
72
+ const worktreeConfig = getWorktreeConfig(projectPath);
73
+ const worktreeManager = new WorktreeManager(worktreeConfig);
74
+ // NOTE: Worker pool execution is disabled - using in-process execution
75
+ // Worker pool can be re-enabled by uncommenting the ExecutionWorkerPool creation
76
+ // and passing it to ExecutionService and ProjectContext
77
+ // Create execution service without worker pool (will use in-process execution)
78
+ const executionService = new ExecutionService(db, projectId, projectPath, undefined, transportManager, logsStore, undefined // No worker pool - use in-process execution
79
+ );
80
+ // 6. Create project context
81
+ const context = new ProjectContext(projectId, projectPath, sudocodeDir, db, transportManager, executionService, logsStore, worktreeManager, undefined // No worker pool
82
+ );
83
+ await context.initialize();
84
+ // 7. Start file watcher if enabled
85
+ if (this.watchEnabled) {
86
+ context.watcher = startServerWatcher({
87
+ db,
88
+ baseDir: sudocodeDir,
89
+ onFileChange: (info) => {
90
+ console.log(`[project-manager] File change in ${projectId}`);
91
+ // Broadcast WebSocket updates based on entity type
92
+ if (info.entityType && info.entityId) {
93
+ if (info.entityType === "issue") {
94
+ // Use entity from event if available (optimization)
95
+ if (info.entity) {
96
+ broadcastIssueUpdate(projectId, info.entityId, "updated", info.entity);
97
+ }
98
+ else {
99
+ // Fallback to DB query (for backward compatibility)
100
+ const issue = getIssueById(db, info.entityId);
101
+ if (issue) {
102
+ broadcastIssueUpdate(projectId, info.entityId, "updated", issue);
103
+ }
104
+ }
105
+ }
106
+ else if (info.entityType === "spec") {
107
+ // Use entity from event if available (optimization)
108
+ if (info.entity) {
109
+ broadcastSpecUpdate(projectId, info.entityId, "updated", info.entity);
110
+ }
111
+ else {
112
+ // Fallback to DB query (for backward compatibility)
113
+ const spec = getSpecById(db, info.entityId);
114
+ if (spec) {
115
+ broadcastSpecUpdate(projectId, info.entityId, "updated", spec);
116
+ }
117
+ }
118
+ }
119
+ }
120
+ },
121
+ });
122
+ }
123
+ // 8. Cleanup orphaned worktrees on first open
124
+ if (worktreeConfig.cleanupOrphanedWorktreesOnStartup) {
125
+ try {
126
+ const lifecycleService = new ExecutionLifecycleService(db, projectPath, worktreeManager);
127
+ await lifecycleService.cleanupOrphanedWorktrees();
128
+ console.log(`Cleaned up orphaned worktrees for ${projectId}`);
129
+ }
130
+ catch (error) {
131
+ console.warn(`Failed to cleanup orphaned worktrees for ${projectId}:`, error);
132
+ // Don't fail the open operation
133
+ }
134
+ }
135
+ // 9. Register and track
136
+ this.registry.registerProject(projectPath);
137
+ this.registry.updateLastOpened(projectId);
138
+ await this.registry.save();
139
+ this.openProjects.set(projectId, context);
140
+ console.log(`Project opened successfully: ${projectId} at ${projectPath}`);
141
+ return Ok(context);
142
+ }
143
+ catch (error) {
144
+ console.error(`Failed to open project at ${projectPath}:`, error);
145
+ return Err({
146
+ type: "UNKNOWN",
147
+ message: error.message || String(error),
148
+ });
149
+ }
150
+ }
151
+ /**
152
+ * Initialize a new sudocode project in an existing directory
153
+ * @param projectPath - Absolute path to project root directory
154
+ * @param name - Optional custom project name
155
+ * @returns ProjectContext for the initialized and opened project
156
+ */
157
+ async initializeProject(projectPath, name) {
158
+ try {
159
+ // 1. Check that path exists
160
+ if (!fs.existsSync(projectPath)) {
161
+ return Err({
162
+ type: "PATH_NOT_FOUND",
163
+ path: projectPath,
164
+ });
165
+ }
166
+ // 2. Check that it's a directory
167
+ const stats = fs.statSync(projectPath);
168
+ if (!stats.isDirectory()) {
169
+ return Err({
170
+ type: "INVALID_PROJECT",
171
+ message: `Path is not a directory: ${projectPath}`,
172
+ });
173
+ }
174
+ // 3. Check if already initialized
175
+ const sudocodeDir = path.join(projectPath, ".sudocode");
176
+ if (isInitialized(sudocodeDir)) {
177
+ // Already initialized, just open it
178
+ console.log(`Project already initialized at ${projectPath}, opening...`);
179
+ return this.openProject(projectPath);
180
+ }
181
+ // 4. Perform initialization using CLI's performInitialization
182
+ console.log(`Initializing new project at ${projectPath}`);
183
+ await performInitialization({
184
+ dir: sudocodeDir,
185
+ jsonOutput: true, // Suppress CLI console output
186
+ });
187
+ // 5. Update project name in registry if provided
188
+ const projectId = this.registry.generateProjectId(projectPath);
189
+ if (name) {
190
+ this.registry.registerProject(projectPath);
191
+ this.registry.updateProject(projectId, { name });
192
+ await this.registry.save();
193
+ }
194
+ // 6. Open the newly initialized project
195
+ return this.openProject(projectPath);
196
+ }
197
+ catch (error) {
198
+ console.error(`Failed to initialize project at ${projectPath}:`, error);
199
+ return Err({
200
+ type: "UNKNOWN",
201
+ message: error.message || String(error),
202
+ });
203
+ }
204
+ }
205
+ /**
206
+ * Close a project and cleanup its resources
207
+ * @param projectId - Project ID to close
208
+ * @param keepDbInCache - Whether to keep database in cache (default: true)
209
+ */
210
+ async closeProject(projectId, keepDbInCache = true) {
211
+ const context = this.openProjects.get(projectId);
212
+ if (!context) {
213
+ console.warn(`Cannot close project ${projectId}: not open`);
214
+ return;
215
+ }
216
+ console.log(`Closing project: ${projectId}`);
217
+ try {
218
+ // Shutdown project context (stops watcher, cancels executions, etc.)
219
+ await context.shutdown();
220
+ // Keep DB in cache for fast reopening (unless explicitly disabled)
221
+ if (keepDbInCache) {
222
+ this.addToDbCache(projectId, context.db);
223
+ }
224
+ else {
225
+ context.db.close();
226
+ }
227
+ // Remove from active projects
228
+ this.openProjects.delete(projectId);
229
+ // TODO: Broadcast project_closed WebSocket message
230
+ console.log(`Project closed: ${projectId}`);
231
+ }
232
+ catch (error) {
233
+ console.error(`Error closing project ${projectId}:`, error);
234
+ throw error;
235
+ }
236
+ }
237
+ /**
238
+ * Get an open project by ID
239
+ */
240
+ getProject(projectId) {
241
+ return this.openProjects.get(projectId) || null;
242
+ }
243
+ /**
244
+ * Get all currently open projects
245
+ */
246
+ getAllOpenProjects() {
247
+ return Array.from(this.openProjects.values());
248
+ }
249
+ /**
250
+ * Check if a project is currently open
251
+ */
252
+ isProjectOpen(projectId) {
253
+ return this.openProjects.has(projectId);
254
+ }
255
+ /**
256
+ * Validate that a project directory is valid for opening
257
+ */
258
+ validateProject(projectPath) {
259
+ // Check that path exists
260
+ if (!fs.existsSync(projectPath)) {
261
+ return Err({
262
+ type: "PATH_NOT_FOUND",
263
+ path: projectPath,
264
+ });
265
+ }
266
+ // Check that it's a directory
267
+ const stats = fs.statSync(projectPath);
268
+ if (!stats.isDirectory()) {
269
+ return Err({
270
+ type: "INVALID_PROJECT",
271
+ message: `Path is not a directory: ${projectPath}`,
272
+ });
273
+ }
274
+ // Check that .sudocode directory exists
275
+ const sudocodeDir = path.join(projectPath, ".sudocode");
276
+ if (!fs.existsSync(sudocodeDir)) {
277
+ return Err({
278
+ type: "INVALID_PROJECT",
279
+ message: `Missing .sudocode directory: ${sudocodeDir}`,
280
+ });
281
+ }
282
+ // Check that cache.db exists
283
+ const dbPath = path.join(sudocodeDir, "cache.db");
284
+ if (!fs.existsSync(dbPath)) {
285
+ return Err({
286
+ type: "INVALID_PROJECT",
287
+ message: `Missing cache.db file: ${dbPath}`,
288
+ });
289
+ }
290
+ return Ok(undefined);
291
+ }
292
+ /**
293
+ * Get or create a database connection for a project
294
+ * Checks cache first, then initializes new connection
295
+ */
296
+ async getOrCreateDatabase(projectId, projectPath) {
297
+ // Check cache
298
+ const cached = this.dbCache.get(projectId);
299
+ if (cached) {
300
+ console.log(`Using cached database for ${projectId}`);
301
+ cached.lastAccessed = new Date();
302
+ // Clear eviction timer since we're using it again
303
+ if (cached.evictionTimer) {
304
+ clearTimeout(cached.evictionTimer);
305
+ cached.evictionTimer = undefined;
306
+ }
307
+ // Remove from cache (will be managed by project context)
308
+ this.dbCache.delete(projectId);
309
+ return cached.db;
310
+ }
311
+ // Initialize new database
312
+ const dbPath = path.join(projectPath, ".sudocode", "cache.db");
313
+ console.log(`Initializing new database for ${projectId} at ${dbPath}`);
314
+ const db = initDatabase({ path: dbPath });
315
+ return db;
316
+ }
317
+ /**
318
+ * Add a database to the cache with TTL eviction
319
+ */
320
+ addToDbCache(projectId, db) {
321
+ // Clear any existing cache entry
322
+ const existing = this.dbCache.get(projectId);
323
+ if (existing?.evictionTimer) {
324
+ clearTimeout(existing.evictionTimer);
325
+ }
326
+ // Add to cache
327
+ const cached = {
328
+ db,
329
+ lastAccessed: new Date(),
330
+ };
331
+ // Schedule eviction
332
+ cached.evictionTimer = setTimeout(() => {
333
+ const entry = this.dbCache.get(projectId);
334
+ if (entry) {
335
+ const age = Date.now() - entry.lastAccessed.getTime();
336
+ if (age >= this.DB_CACHE_TTL) {
337
+ console.log(`Evicting cached database for ${projectId} (age: ${age}ms)`);
338
+ try {
339
+ entry.db.close();
340
+ }
341
+ catch (error) {
342
+ console.error(`Error closing cached database for ${projectId}:`, error);
343
+ }
344
+ this.dbCache.delete(projectId);
345
+ }
346
+ }
347
+ }, this.DB_CACHE_TTL);
348
+ this.dbCache.set(projectId, cached);
349
+ console.log(`Database cached for ${projectId} (TTL: ${this.DB_CACHE_TTL}ms)`);
350
+ }
351
+ /**
352
+ * Get summary of all projects (open and cached)
353
+ */
354
+ getSummary() {
355
+ return {
356
+ openProjects: this.getAllOpenProjects().map((p) => p.getSummary()),
357
+ cachedDatabases: Array.from(this.dbCache.keys()),
358
+ totalOpen: this.openProjects.size,
359
+ totalCached: this.dbCache.size,
360
+ };
361
+ }
362
+ /**
363
+ * Shutdown the project manager and cleanup all resources
364
+ */
365
+ async shutdown() {
366
+ console.log("Shutting down ProjectManager...");
367
+ // Close all open projects
368
+ const projectIds = Array.from(this.openProjects.keys());
369
+ for (const projectId of projectIds) {
370
+ await this.closeProject(projectId, false); // Don't cache on shutdown
371
+ }
372
+ // Close all cached databases
373
+ for (const [projectId, cached] of this.dbCache.entries()) {
374
+ if (cached.evictionTimer) {
375
+ clearTimeout(cached.evictionTimer);
376
+ }
377
+ try {
378
+ cached.db.close();
379
+ }
380
+ catch (error) {
381
+ console.error(`Error closing cached database for ${projectId}:`, error);
382
+ }
383
+ }
384
+ this.dbCache.clear();
385
+ console.log("ProjectManager shutdown complete");
386
+ }
387
+ }
388
+ //# sourceMappingURL=project-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"project-manager.js","sourceRoot":"","sources":["../../src/services/project-manager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,98 @@
1
+ import type { ProjectInfo, ProjectsConfig, ProjectError, Result } from '../types/project.js';
2
+ /**
3
+ * ProjectRegistry manages the persistent storage of registered projects.
4
+ *
5
+ * Configuration is stored at ~/.config/sudocode/projects.json and includes:
6
+ * - Registered projects with metadata
7
+ * - Recent projects list
8
+ * - User settings
9
+ */
10
+ export declare class ProjectRegistry {
11
+ private configPath;
12
+ private config;
13
+ /**
14
+ * Create a new ProjectRegistry instance
15
+ * @param configPath - Optional custom config file path (defaults to ~/.config/sudocode/projects.json)
16
+ */
17
+ constructor(configPath?: string);
18
+ /**
19
+ * Get the default config file path following XDG Base Directory specification
20
+ */
21
+ private getDefaultConfigPath;
22
+ /**
23
+ * Load configuration from disk. Creates default config if file doesn't exist.
24
+ * @throws {Error} If config file is corrupted or unreadable
25
+ */
26
+ load(): Promise<Result<void, ProjectError>>;
27
+ /**
28
+ * Save configuration to disk atomically (write to temp file, then rename)
29
+ */
30
+ save(): Promise<Result<void, ProjectError>>;
31
+ /**
32
+ * Generate a deterministic, human-readable project ID from path
33
+ * Format: <repo-name>-<8-char-hash>
34
+ * Example: sudocode-a1b2c3d4
35
+ */
36
+ generateProjectId(projectPath: string): string;
37
+ /**
38
+ * Register a new project or update existing one
39
+ * @param projectPath - Absolute path to project root directory
40
+ * @returns ProjectInfo for the registered project
41
+ */
42
+ registerProject(projectPath: string): ProjectInfo;
43
+ /**
44
+ * Unregister a project (remove from registry)
45
+ * @param projectId - Project ID to remove
46
+ * @returns true if project was removed, false if not found
47
+ */
48
+ unregisterProject(projectId: string): boolean;
49
+ /**
50
+ * Get project info by ID
51
+ */
52
+ getProject(projectId: string): ProjectInfo | null;
53
+ /**
54
+ * Get all registered projects
55
+ */
56
+ getAllProjects(): ProjectInfo[];
57
+ /**
58
+ * Update the lastOpenedAt timestamp for a project
59
+ */
60
+ updateLastOpened(projectId: string): void;
61
+ /**
62
+ * Add a project to the recent projects list
63
+ * Maintains the list at maxRecentProjects size with most recent first
64
+ */
65
+ addToRecent(projectId: string): void;
66
+ /**
67
+ * Get recent projects (ordered by most recent first)
68
+ */
69
+ getRecentProjects(): ProjectInfo[];
70
+ /**
71
+ * Update project metadata
72
+ * @param projectId - Project ID to update
73
+ * @param updates - Partial project info to update
74
+ * @returns true if project was updated, false if not found
75
+ */
76
+ updateProject(projectId: string, updates: Partial<Pick<ProjectInfo, 'name' | 'favorite'>>): boolean;
77
+ /**
78
+ * Toggle favorite status for a project
79
+ */
80
+ toggleFavorite(projectId: string): boolean;
81
+ /**
82
+ * Get all favorite projects
83
+ */
84
+ getFavoriteProjects(): ProjectInfo[];
85
+ /**
86
+ * Update user settings
87
+ */
88
+ updateSettings(settings: Partial<ProjectsConfig['settings']>): void;
89
+ /**
90
+ * Get current settings
91
+ */
92
+ getSettings(): ProjectsConfig['settings'];
93
+ /**
94
+ * Get the config file path
95
+ */
96
+ getConfigPath(): string;
97
+ }
98
+ //# sourceMappingURL=project-registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"project-registry.d.ts","sourceRoot":"","sources":["../../src/services/project-registry.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAA;AAe5F;;;;;;;GAOG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,UAAU,CAAQ;IAC1B,OAAO,CAAC,MAAM,CAAgB;IAE9B;;;OAGG;gBACS,UAAU,CAAC,EAAE,MAAM;IAK/B;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAM5B;;;OAGG;IACG,IAAI,IAAI,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;IA+CjD;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;IA0BjD;;;;OAIG;IACH,iBAAiB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM;IAsB9C;;;;OAIG;IACH,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,WAAW;IA+BjD;;;;OAIG;IACH,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO;IAe7C;;OAEG;IACH,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI;IAIjD;;OAEG;IACH,cAAc,IAAI,WAAW,EAAE;IAI/B;;OAEG;IACH,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAOzC;;;OAGG;IACH,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAgBpC;;OAEG;IACH,iBAAiB,IAAI,WAAW,EAAE;IAMlC;;;;;OAKG;IACH,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,MAAM,GAAG,UAAU,CAAC,CAAC,GAAG,OAAO;IAiBnG;;OAEG;IACH,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO;IAU1C;;OAEG;IACH,mBAAmB,IAAI,WAAW,EAAE;IAIpC;;OAEG;IACH,cAAc,CAAC,QAAQ,EAAE,OAAO,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC,GAAG,IAAI;IAOnE;;OAEG;IACH,WAAW,IAAI,cAAc,CAAC,UAAU,CAAC;IAIzC;;OAEG;IACH,aAAa,IAAI,MAAM;CAGxB"}