@sudocode-ai/local-server 0.1.7 → 0.1.8

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 (274) 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 +187 -0
  86. package/dist/execution/worktree/git-sync-cli.d.ts.map +1 -0
  87. package/dist/execution/worktree/git-sync-cli.js +350 -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 +132 -211
  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-Bb_W5bUr.css +1 -0
  102. package/dist/public/assets/index-CFKL113G.js +710 -0
  103. package/dist/public/assets/index-CFKL113G.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 +506 -54
  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 +126 -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/services/agent-registry.d.ts +140 -0
  158. package/dist/services/agent-registry.d.ts.map +1 -0
  159. package/dist/services/agent-registry.js +272 -0
  160. package/dist/services/agent-registry.js.map +1 -0
  161. package/dist/services/editor-service.d.ts +57 -0
  162. package/dist/services/editor-service.d.ts.map +1 -0
  163. package/dist/services/editor-service.js +204 -0
  164. package/dist/services/editor-service.js.map +1 -0
  165. package/dist/services/execution-changes-service.d.ts +92 -0
  166. package/dist/services/execution-changes-service.d.ts.map +1 -0
  167. package/dist/services/execution-changes-service.js +546 -0
  168. package/dist/services/execution-changes-service.js.map +1 -0
  169. package/dist/services/execution-lifecycle.d.ts +1 -0
  170. package/dist/services/execution-lifecycle.d.ts.map +1 -1
  171. package/dist/services/execution-lifecycle.js +37 -7
  172. package/dist/services/execution-lifecycle.js.map +1 -1
  173. package/dist/services/execution-logs-store.d.ts +75 -0
  174. package/dist/services/execution-logs-store.d.ts.map +1 -1
  175. package/dist/services/execution-logs-store.js +142 -2
  176. package/dist/services/execution-logs-store.js.map +1 -1
  177. package/dist/services/execution-service.d.ts +50 -58
  178. package/dist/services/execution-service.d.ts.map +1 -1
  179. package/dist/services/execution-service.js +433 -469
  180. package/dist/services/execution-service.js.map +1 -1
  181. package/dist/services/execution-worker-pool.d.ts +116 -0
  182. package/dist/services/execution-worker-pool.d.ts.map +1 -0
  183. package/dist/services/execution-worker-pool.js +326 -0
  184. package/dist/services/execution-worker-pool.js.map +1 -0
  185. package/dist/services/executions.d.ts +3 -0
  186. package/dist/services/executions.d.ts.map +1 -1
  187. package/dist/services/executions.js +11 -17
  188. package/dist/services/executions.js.map +1 -1
  189. package/dist/services/export.d.ts +8 -2
  190. package/dist/services/export.d.ts.map +1 -1
  191. package/dist/services/export.js +29 -23
  192. package/dist/services/export.js.map +1 -1
  193. package/dist/services/file-search/git-ls-files-strategy.d.ts +72 -0
  194. package/dist/services/file-search/git-ls-files-strategy.d.ts.map +1 -0
  195. package/dist/services/file-search/git-ls-files-strategy.js +176 -0
  196. package/dist/services/file-search/git-ls-files-strategy.js.map +1 -0
  197. package/dist/services/file-search/index.d.ts +9 -0
  198. package/dist/services/file-search/index.d.ts.map +1 -0
  199. package/dist/services/file-search/index.js +10 -0
  200. package/dist/services/file-search/index.js.map +1 -0
  201. package/dist/services/file-search/registry.d.ts +97 -0
  202. package/dist/services/file-search/registry.d.ts.map +1 -0
  203. package/dist/services/file-search/registry.js +140 -0
  204. package/dist/services/file-search/registry.js.map +1 -0
  205. package/dist/services/file-search/strategy.d.ts +58 -0
  206. package/dist/services/file-search/strategy.d.ts.map +1 -0
  207. package/dist/services/file-search/strategy.js +8 -0
  208. package/dist/services/file-search/strategy.js.map +1 -0
  209. package/dist/services/project-context.d.ts +69 -0
  210. package/dist/services/project-context.d.ts.map +1 -0
  211. package/dist/services/project-context.js +113 -0
  212. package/dist/services/project-context.js.map +1 -0
  213. package/dist/services/project-manager.d.ts +95 -0
  214. package/dist/services/project-manager.d.ts.map +1 -0
  215. package/dist/services/project-manager.js +388 -0
  216. package/dist/services/project-manager.js.map +1 -0
  217. package/dist/services/project-registry.d.ts +98 -0
  218. package/dist/services/project-registry.d.ts.map +1 -0
  219. package/dist/services/project-registry.js +289 -0
  220. package/dist/services/project-registry.js.map +1 -0
  221. package/dist/services/prompt-resolver.d.ts +97 -0
  222. package/dist/services/prompt-resolver.d.ts.map +1 -0
  223. package/dist/services/prompt-resolver.js +377 -0
  224. package/dist/services/prompt-resolver.js.map +1 -0
  225. package/dist/services/repo-info.d.ts +12 -0
  226. package/dist/services/repo-info.d.ts.map +1 -1
  227. package/dist/services/repo-info.js +46 -0
  228. package/dist/services/repo-info.js.map +1 -1
  229. package/dist/services/watcher.d.ts +3 -4
  230. package/dist/services/watcher.d.ts.map +1 -1
  231. package/dist/services/watcher.js +18 -35
  232. package/dist/services/watcher.js.map +1 -1
  233. package/dist/services/websocket.d.ts +30 -16
  234. package/dist/services/websocket.d.ts.map +1 -1
  235. package/dist/services/websocket.js +102 -37
  236. package/dist/services/websocket.js.map +1 -1
  237. package/dist/services/worktree-sync-service.d.ts +228 -0
  238. package/dist/services/worktree-sync-service.d.ts.map +1 -0
  239. package/dist/services/worktree-sync-service.js +563 -0
  240. package/dist/services/worktree-sync-service.js.map +1 -0
  241. package/dist/types/editor.d.ts +49 -0
  242. package/dist/types/editor.d.ts.map +1 -0
  243. package/dist/types/editor.js +50 -0
  244. package/dist/types/editor.js.map +1 -0
  245. package/dist/types/project.d.ts +58 -0
  246. package/dist/types/project.d.ts.map +1 -0
  247. package/dist/types/project.js +10 -0
  248. package/dist/types/project.js.map +1 -0
  249. package/dist/utils/executable-check.d.ts +36 -0
  250. package/dist/utils/executable-check.d.ts.map +1 -0
  251. package/dist/utils/executable-check.js +79 -0
  252. package/dist/utils/executable-check.js.map +1 -0
  253. package/dist/workers/execution-worker.d.ts +18 -0
  254. package/dist/workers/execution-worker.d.ts.map +1 -0
  255. package/dist/workers/execution-worker.js +340 -0
  256. package/dist/workers/execution-worker.js.map +1 -0
  257. package/dist/workers/worker-ipc.d.ts +84 -0
  258. package/dist/workers/worker-ipc.d.ts.map +1 -0
  259. package/dist/workers/worker-ipc.js +29 -0
  260. package/dist/workers/worker-ipc.js.map +1 -0
  261. package/package.json +6 -5
  262. package/dist/execution/output/ag-ui-integration.d.ts +0 -96
  263. package/dist/execution/output/ag-ui-integration.d.ts.map +0 -1
  264. package/dist/execution/output/ag-ui-integration.js +0 -96
  265. package/dist/execution/output/ag-ui-integration.js.map +0 -1
  266. package/dist/execution/output/claude-code-output-processor.d.ts +0 -321
  267. package/dist/execution/output/claude-code-output-processor.d.ts.map +0 -1
  268. package/dist/execution/output/claude-code-output-processor.js +0 -769
  269. package/dist/execution/output/claude-code-output-processor.js.map +0 -1
  270. package/dist/public/assets/index-B3SEMufD.js +0 -580
  271. package/dist/public/assets/index-B3SEMufD.js.map +0 -1
  272. package/dist/public/assets/index-D2YGL3gX.css +0 -1
  273. package/dist/public/assets/ui-vendor-CotR6bx9.js +0 -54
  274. package/dist/public/assets/ui-vendor-CotR6bx9.js.map +0 -1
@@ -0,0 +1,652 @@
1
+ /**
2
+ * AgentExecutorWrapper - Generic wrapper for any agent adapter
3
+ *
4
+ * Provides a unified execution interface that works with any IAgentAdapter.
5
+ * Supports Claude Code, Codex, Cursor, Copilot, and any future agents.
6
+ *
7
+ * @module execution/executors/agent-executor-wrapper
8
+ */
9
+ import { ClaudeCodeExecutor, CodexExecutor, CursorExecutor, CopilotExecutor, } from "agent-execution-engine/agents";
10
+ import { NormalizedEntryToAgUiAdapter } from "../output/normalized-to-ag-ui-adapter.js";
11
+ import { AgUiEventAdapter } from "../output/ag-ui-adapter.js";
12
+ import { updateExecution, getExecution } from "../../services/executions.js";
13
+ import { broadcastExecutionUpdate } from "../../services/websocket.js";
14
+ import { execSync } from "child_process";
15
+ import { ExecutionChangesService } from "../../services/execution-changes-service.js";
16
+ /**
17
+ * Generic wrapper for any agent adapter
18
+ *
19
+ * Provides basic execution lifecycle management for any agent that implements
20
+ * IAgentAdapter. This is a simplified version compared to ClaudeExecutorWrapper,
21
+ * which has specialized logic for Claude Code's protocol peer.
22
+ *
23
+ * @example
24
+ * ```typescript
25
+ * const wrapper = new AgentExecutorWrapper({
26
+ * adapter: codexAdapter,
27
+ * agentConfig: {
28
+ * workDir: '/path/to/repo',
29
+ * apiKey: 'sk-...',
30
+ * model: 'code-davinci-002',
31
+ * },
32
+ * lifecycleService,
33
+ * logsStore,
34
+ * projectId: 'my-project',
35
+ * db,
36
+ * transportManager,
37
+ * });
38
+ *
39
+ * await wrapper.executeWithLifecycle(executionId, task, workDir);
40
+ * ```
41
+ */
42
+ export class AgentExecutorWrapper {
43
+ adapter;
44
+ executor;
45
+ /** Agent type used for executor selection and logging */
46
+ agentType;
47
+ _agentConfig;
48
+ logsStore;
49
+ transportManager;
50
+ projectId;
51
+ db;
52
+ processConfig;
53
+ activeExecutions;
54
+ /** Track completion state for Claude Code executions (from protocol peer) */
55
+ completionState;
56
+ constructor(config) {
57
+ this.adapter = config.adapter;
58
+ this.agentType = config.agentType;
59
+ this._agentConfig = config.agentConfig;
60
+ this.logsStore = config.logsStore;
61
+ this.transportManager = config.transportManager;
62
+ this.projectId = config.projectId;
63
+ this.db = config.db;
64
+ this.activeExecutions = new Map();
65
+ this.completionState = new Map();
66
+ // Build process configuration from agent-specific config
67
+ this.processConfig = this.adapter.buildProcessConfig(this._agentConfig);
68
+ // Create executor instance based on agent type
69
+ this.executor = this.createExecutor(config.agentType, this._agentConfig);
70
+ console.log("[AgentExecutorWrapper] Initialized", {
71
+ agentType: this.agentType,
72
+ adapterName: this.adapter.metadata.name,
73
+ projectId: this.projectId,
74
+ workDir: this.processConfig.workDir,
75
+ hasTransport: !!this.transportManager,
76
+ hasLogsStore: !!this.logsStore,
77
+ });
78
+ }
79
+ /**
80
+ * Create the appropriate executor for the given agent type
81
+ *
82
+ * @param agentType - Type of agent
83
+ * @param agentConfig - Agent configuration
84
+ * @returns Executor instance
85
+ */
86
+ createExecutor(agentType, agentConfig) {
87
+ switch (agentType) {
88
+ case "claude-code":
89
+ return new ClaudeCodeExecutor({
90
+ workDir: agentConfig.workDir,
91
+ executablePath: agentConfig.claudePath,
92
+ print: agentConfig.print ?? true,
93
+ outputFormat: agentConfig.outputFormat ?? "stream-json",
94
+ verbose: agentConfig.verbose ?? true,
95
+ dangerouslySkipPermissions: agentConfig.dangerouslySkipPermissions ?? true,
96
+ });
97
+ case "codex":
98
+ return new CodexExecutor(agentConfig);
99
+ case "cursor":
100
+ return new CursorExecutor(agentConfig);
101
+ case "copilot":
102
+ return new CopilotExecutor(agentConfig);
103
+ default:
104
+ throw new Error(`Unknown agent type: ${agentType}`);
105
+ }
106
+ }
107
+ /**
108
+ * Execute a task with full lifecycle management
109
+ *
110
+ * @param executionId - Unique execution identifier
111
+ * @param task - Task to execute
112
+ * @param workDir - Working directory for execution
113
+ */
114
+ async executeWithLifecycle(executionId, task, workDir) {
115
+ console.log(`[AgentExecutorWrapper] Starting execution ${executionId}`, {
116
+ agentType: this.adapter.metadata.name,
117
+ taskId: task.id,
118
+ workDir,
119
+ });
120
+ // 1. Setup AG-UI system
121
+ const { agUiAdapter, normalizedAdapter } = this.setupAgUiSystem(executionId);
122
+ // 2. Connect to transport
123
+ if (this.transportManager) {
124
+ this.transportManager.connectAdapter(agUiAdapter, executionId);
125
+ console.log(`[AgentExecutorWrapper] Connected AG-UI adapter to transport for ${executionId}`);
126
+ }
127
+ try {
128
+ // 3. Emit run started event
129
+ agUiAdapter.emitRunStarted({
130
+ model: task.config?.model || this.adapter.metadata.name,
131
+ timestamp: new Date().toISOString(),
132
+ });
133
+ // 4. Update execution status to running
134
+ updateExecution(this.db, executionId, { status: "running" });
135
+ const execution = getExecution(this.db, executionId);
136
+ if (execution) {
137
+ broadcastExecutionUpdate(this.projectId, executionId, "status_changed", execution, execution.issue_id || undefined);
138
+ }
139
+ // 5. Execute task with agent executor
140
+ console.log(`[AgentExecutorWrapper] Spawning ${this.adapter.metadata.name} process for ${executionId}`, {
141
+ taskId: task.id,
142
+ workDir,
143
+ promptLength: task.prompt.length,
144
+ });
145
+ const spawned = await this.executor.executeTask(task);
146
+ console.log(`[AgentExecutorWrapper] ${this.adapter.metadata.name} process spawned for ${executionId}`, {
147
+ pid: spawned.process.process?.pid,
148
+ spawnfile: spawned.process.process?.spawnfile,
149
+ });
150
+ // 6. Store cancellation handle
151
+ this.activeExecutions.set(executionId, {
152
+ cancel: () => {
153
+ if (spawned.process.process) {
154
+ spawned.process.process.kill("SIGTERM");
155
+ }
156
+ },
157
+ });
158
+ // 7. Initialize completion state for Claude Code
159
+ if (this.agentType === "claude-code") {
160
+ this.completionState.set(executionId, {
161
+ completed: false,
162
+ exitCode: 0,
163
+ });
164
+ }
165
+ // 8. Create output stream from process stdout/stderr
166
+ const outputStream = this.createOutputChunks(spawned.process, executionId);
167
+ const normalized = this.executor.normalizeOutput(outputStream, workDir);
168
+ // 9. Process normalized output (runs concurrently with process)
169
+ const processOutputPromise = this.processNormalizedOutput(executionId, normalized, normalizedAdapter);
170
+ // 10. Capture stderr for debugging
171
+ const childProcess = spawned.process.process;
172
+ if (childProcess && childProcess.stderr) {
173
+ let stderrOutput = "";
174
+ childProcess.stderr.on("data", (data) => {
175
+ const chunk = data.toString();
176
+ stderrOutput += chunk;
177
+ console.error(`[AgentExecutorWrapper] ${this.adapter.metadata.name} stderr for ${executionId}:`, chunk);
178
+ });
179
+ }
180
+ // 11. Wait for output processing to complete
181
+ await processOutputPromise;
182
+ console.log(`[AgentExecutorWrapper] Output processing completed for ${executionId}`);
183
+ // 12. Close stdin to signal the process to exit (for Claude Code with peer)
184
+ if (this.agentType === "claude-code" &&
185
+ childProcess &&
186
+ childProcess.stdin) {
187
+ try {
188
+ childProcess.stdin.end();
189
+ console.log(`[AgentExecutorWrapper] Closed stdin for Claude Code process ${executionId}`);
190
+ }
191
+ catch (error) {
192
+ console.error(`[AgentExecutorWrapper] Error closing stdin for ${executionId}:`, error);
193
+ }
194
+ }
195
+ // 13. Wait for process to exit (with timeout for Claude Code)
196
+ const exitCode = await Promise.race([
197
+ new Promise((resolve) => {
198
+ if (!childProcess) {
199
+ // Use completion state for Claude Code if available
200
+ if (this.agentType === "claude-code") {
201
+ const state = this.completionState.get(executionId);
202
+ resolve(state?.exitCode ?? 0);
203
+ }
204
+ else {
205
+ resolve(0);
206
+ }
207
+ return;
208
+ }
209
+ childProcess.on("exit", (code) => {
210
+ console.log(`[AgentExecutorWrapper] Process exited with code ${code} for ${executionId}`);
211
+ // For Claude Code, use completion state exit code if available (more reliable)
212
+ if (this.agentType === "claude-code") {
213
+ const state = this.completionState.get(executionId);
214
+ if (state?.completed) {
215
+ console.log(`[AgentExecutorWrapper] Using completion state exit code ${state.exitCode} for ${executionId}`);
216
+ resolve(state.exitCode);
217
+ return;
218
+ }
219
+ }
220
+ resolve(code ?? 0);
221
+ });
222
+ childProcess.on("error", (error) => {
223
+ console.error(`[AgentExecutorWrapper] Process error for ${executionId}:`, error);
224
+ resolve(1);
225
+ });
226
+ }),
227
+ // Timeout for Claude Code processes that may not exit cleanly
228
+ this.agentType === "claude-code"
229
+ ? new Promise((resolve) => {
230
+ setTimeout(() => {
231
+ console.log(`[AgentExecutorWrapper] Process exit timeout for ${executionId}, using completion state`);
232
+ if (childProcess && !childProcess.killed) {
233
+ childProcess.kill("SIGTERM");
234
+ }
235
+ // Use completion state exit code
236
+ const state = this.completionState.get(executionId);
237
+ resolve(state?.exitCode ?? 0);
238
+ }, 5000);
239
+ })
240
+ : new Promise(() => { }), // Never resolves for non-Claude agents
241
+ ]);
242
+ // 14. Handle completion
243
+ if (exitCode === 0) {
244
+ await this.handleSuccess(executionId);
245
+ agUiAdapter.emitRunFinished({ exitCode });
246
+ }
247
+ else {
248
+ throw new Error(`Process exited with code ${exitCode}`);
249
+ }
250
+ }
251
+ catch (error) {
252
+ console.error(`[AgentExecutorWrapper] Execution failed for ${executionId}:`, error);
253
+ await this.handleError(executionId, error);
254
+ agUiAdapter.emitRunError(error instanceof Error ? error.message : String(error));
255
+ throw error;
256
+ }
257
+ finally {
258
+ // Cleanup
259
+ this.activeExecutions.delete(executionId);
260
+ this.completionState.delete(executionId);
261
+ if (this.transportManager) {
262
+ this.transportManager.disconnectAdapter(agUiAdapter);
263
+ console.log(`[AgentExecutorWrapper] Disconnected AG-UI adapter for ${executionId}`);
264
+ }
265
+ }
266
+ }
267
+ /**
268
+ * Resume a task from a previous session
269
+ *
270
+ * @param executionId - Unique execution identifier
271
+ * @param sessionId - Session ID to resume from
272
+ * @param task - Task to resume
273
+ * @param workDir - Working directory for execution
274
+ */
275
+ async resumeWithLifecycle(executionId, sessionId, task, workDir) {
276
+ // Check if executor supports resume
277
+ const capabilities = this.executor.getCapabilities?.();
278
+ if (!capabilities?.supportsSessionResume || !this.executor.resumeTask) {
279
+ console.log(`[AgentExecutorWrapper] Resume not supported for agent '${this.adapter.metadata.name}'`);
280
+ throw new Error(`Resume functionality not supported for agent '${this.adapter.metadata.name}'`);
281
+ }
282
+ console.log(`[AgentExecutorWrapper] Resuming session ${sessionId} for ${executionId}`);
283
+ // Setup AG-UI system
284
+ const { agUiAdapter, normalizedAdapter } = this.setupAgUiSystem(executionId);
285
+ if (this.transportManager) {
286
+ this.transportManager.connectAdapter(agUiAdapter, executionId);
287
+ }
288
+ try {
289
+ agUiAdapter.emitRunStarted({
290
+ model: task.config?.model || this.adapter.metadata.name,
291
+ sessionId,
292
+ resumed: true,
293
+ });
294
+ // Update status and session_id (sessionId is the path used for resumption)
295
+ updateExecution(this.db, executionId, {
296
+ status: "running",
297
+ session_id: sessionId,
298
+ });
299
+ const execution = getExecution(this.db, executionId);
300
+ if (execution) {
301
+ broadcastExecutionUpdate(this.projectId, executionId, "status_changed", execution, execution.issue_id || undefined);
302
+ }
303
+ // Use resumeTask instead of executeTask
304
+ const spawned = await this.executor.resumeTask(task, sessionId);
305
+ this.activeExecutions.set(executionId, {
306
+ cancel: () => {
307
+ if (spawned.process.process) {
308
+ spawned.process.process.kill("SIGTERM");
309
+ }
310
+ },
311
+ });
312
+ // Initialize completion state for Claude Code
313
+ if (this.agentType === "claude-code") {
314
+ this.completionState.set(executionId, {
315
+ completed: false,
316
+ exitCode: 0,
317
+ });
318
+ }
319
+ // Create output streams
320
+ const outputChunks = this.createOutputChunks(spawned.process, executionId);
321
+ const normalized = this.executor.normalizeOutput(outputChunks, workDir);
322
+ const processOutputPromise = this.processNormalizedOutput(executionId, normalized, normalizedAdapter);
323
+ await processOutputPromise;
324
+ // For Claude Code, use completion state; for others, wait for process exit
325
+ let exitCode = 0;
326
+ if (this.agentType === "claude-code") {
327
+ const state = this.completionState.get(executionId);
328
+ exitCode = state?.exitCode ?? 0;
329
+ console.log(`[AgentExecutorWrapper] Using completion state exit code ${exitCode} for resumed ${executionId}`);
330
+ }
331
+ else {
332
+ exitCode = await new Promise((resolve, reject) => {
333
+ const childProcess = spawned.process.process;
334
+ if (!childProcess) {
335
+ reject(new Error("No child process available"));
336
+ return;
337
+ }
338
+ childProcess.on("exit", (code) => resolve(code || 0));
339
+ childProcess.on("error", (error) => reject(error));
340
+ });
341
+ }
342
+ if (exitCode === 0) {
343
+ await this.handleSuccess(executionId);
344
+ agUiAdapter.emitRunFinished({ exitCode });
345
+ }
346
+ else {
347
+ throw new Error(`Process exited with code ${exitCode}`);
348
+ }
349
+ }
350
+ catch (error) {
351
+ await this.handleError(executionId, error);
352
+ agUiAdapter.emitRunError(error instanceof Error ? error.message : String(error));
353
+ throw error;
354
+ }
355
+ finally {
356
+ this.activeExecutions.delete(executionId);
357
+ this.completionState.delete(executionId);
358
+ if (this.transportManager) {
359
+ this.transportManager.disconnectAdapter(agUiAdapter);
360
+ }
361
+ }
362
+ }
363
+ /**
364
+ * Cancel a running execution
365
+ *
366
+ * @param executionId - Execution ID to cancel
367
+ */
368
+ async cancel(executionId) {
369
+ console.log(`[AgentExecutorWrapper] Cancel execution ${executionId}`);
370
+ // Kill the process if active
371
+ const execution = this.activeExecutions.get(executionId);
372
+ if (execution) {
373
+ execution.cancel();
374
+ this.activeExecutions.delete(executionId);
375
+ }
376
+ else {
377
+ console.warn(`[AgentExecutorWrapper] No active execution found for ${executionId}`);
378
+ }
379
+ // Capture final commit before marking stopped
380
+ const dbExecution = getExecution(this.db, executionId);
381
+ const repoPath = dbExecution?.worktree_path || this.processConfig.workDir;
382
+ let afterCommit;
383
+ try {
384
+ afterCommit = execSync("git rev-parse HEAD", {
385
+ cwd: repoPath,
386
+ encoding: "utf-8",
387
+ }).trim();
388
+ }
389
+ catch (error) {
390
+ console.warn(`[AgentExecutorWrapper] Failed to capture after_commit for cancelled execution ${executionId}:`, error instanceof Error ? error.message : String(error));
391
+ // Continue - this is supplementary data
392
+ }
393
+ // Update database status
394
+ updateExecution(this.db, executionId, {
395
+ after_commit: afterCommit,
396
+ status: "stopped",
397
+ completed_at: new Date().toISOString(),
398
+ });
399
+ const updatedExecution = getExecution(this.db, executionId);
400
+ if (updatedExecution) {
401
+ broadcastExecutionUpdate(this.projectId, executionId, "status_changed", updatedExecution, updatedExecution.issue_id || undefined);
402
+ }
403
+ }
404
+ /**
405
+ * Setup AG-UI system for execution
406
+ *
407
+ * @private
408
+ */
409
+ setupAgUiSystem(executionId) {
410
+ const agUiAdapter = new AgUiEventAdapter(executionId);
411
+ const normalizedAdapter = new NormalizedEntryToAgUiAdapter(agUiAdapter);
412
+ console.log(`[AgentExecutorWrapper] Setup AG-UI system for ${executionId}`);
413
+ return { agUiAdapter, normalizedAdapter };
414
+ }
415
+ /**
416
+ * Process normalized output from agent
417
+ *
418
+ * For Claude Code: Also captures session ID from metadata for session resumption
419
+ *
420
+ * @private
421
+ */
422
+ async processNormalizedOutput(executionId, normalized, normalizedAdapter) {
423
+ console.log(`[AgentExecutorWrapper] Processing normalized output for ${executionId}`);
424
+ let entryCount = 0;
425
+ let sessionIdCaptured = false;
426
+ for await (const entry of normalized) {
427
+ entryCount++;
428
+ // Log first 10 entries and every 100th entry for debugging
429
+ if (entryCount <= 10 || entryCount % 100 === 0) {
430
+ console.log(`[AgentExecutorWrapper] Entry ${entryCount} for ${executionId}:`, {
431
+ index: entry.index,
432
+ kind: entry.type.kind,
433
+ timestamp: entry.timestamp,
434
+ hasMetadata: !!entry.metadata,
435
+ sessionId: entry.metadata?.sessionId,
436
+ });
437
+ }
438
+ try {
439
+ // Capture session ID from metadata for Claude Code (populated by normalizer from SystemMessage)
440
+ if (this.agentType === "claude-code" &&
441
+ !sessionIdCaptured &&
442
+ entry.metadata?.sessionId) {
443
+ const sessionId = entry.metadata.sessionId;
444
+ updateExecution(this.db, executionId, { session_id: sessionId });
445
+ console.log(`[AgentExecutorWrapper] Captured session ID from metadata: ${sessionId} for ${executionId}`);
446
+ sessionIdCaptured = true;
447
+ }
448
+ // 1. Store normalized entry for historical replay
449
+ this.logsStore.appendNormalizedEntry(executionId, entry);
450
+ // 2. Convert to AG-UI and broadcast for real-time streaming
451
+ await normalizedAdapter.processEntry(entry);
452
+ }
453
+ catch (error) {
454
+ console.error(`[AgentExecutorWrapper] Error processing entry for ${executionId}:`, {
455
+ entryIndex: entry.index,
456
+ entryType: entry.type.kind,
457
+ error: error instanceof Error ? error.message : String(error),
458
+ });
459
+ // Continue processing (don't fail entire execution for one entry)
460
+ }
461
+ }
462
+ console.log(`[AgentExecutorWrapper] Finished processing ${entryCount} entries for ${executionId}`);
463
+ }
464
+ /**
465
+ * Handle successful execution
466
+ *
467
+ * @private
468
+ */
469
+ async handleSuccess(executionId) {
470
+ console.log(`[AgentExecutorWrapper] Execution ${executionId} completed successfully`);
471
+ // Capture final commit before marking complete
472
+ const execution = getExecution(this.db, executionId);
473
+ const repoPath = execution?.worktree_path || this.processConfig.workDir;
474
+ let afterCommit;
475
+ try {
476
+ afterCommit = execSync("git rev-parse HEAD", {
477
+ cwd: repoPath,
478
+ encoding: "utf-8",
479
+ }).trim();
480
+ }
481
+ catch (error) {
482
+ console.warn(`[AgentExecutorWrapper] Failed to capture after_commit for execution ${executionId}:`, error instanceof Error ? error.message : String(error));
483
+ // Continue - this is supplementary data
484
+ }
485
+ // Calculate file changes using ExecutionChangesService
486
+ let filesChangedJson = null;
487
+ try {
488
+ // Import and instantiate ExecutionChangesService
489
+ const changesService = new ExecutionChangesService(this.db, this.processConfig.workDir);
490
+ // Get changes for this execution
491
+ const changesResult = await changesService.getChanges(executionId);
492
+ if (changesResult.available && changesResult.captured) {
493
+ // Extract just the file paths from the changes
494
+ const filePaths = changesResult.captured.files.map((f) => f.path);
495
+ filesChangedJson = JSON.stringify(filePaths);
496
+ console.log(`[AgentExecutorWrapper] Captured ${filePaths.length} file changes for execution ${executionId}`);
497
+ }
498
+ else {
499
+ console.log(`[AgentExecutorWrapper] No file changes detected for execution ${executionId}:`, changesResult.reason);
500
+ }
501
+ }
502
+ catch (error) {
503
+ console.warn(`[AgentExecutorWrapper] Failed to calculate files_changed for execution ${executionId}:`, error instanceof Error ? error.message : String(error));
504
+ // Continue - this is supplementary data
505
+ }
506
+ updateExecution(this.db, executionId, {
507
+ after_commit: afterCommit,
508
+ files_changed: filesChangedJson,
509
+ status: "completed",
510
+ completed_at: new Date().toISOString(),
511
+ exit_code: 0,
512
+ });
513
+ const updatedExecution = getExecution(this.db, executionId);
514
+ if (updatedExecution) {
515
+ broadcastExecutionUpdate(this.projectId, executionId, "status_changed", updatedExecution, updatedExecution.issue_id || undefined);
516
+ }
517
+ }
518
+ /**
519
+ * Handle execution error
520
+ *
521
+ * @private
522
+ */
523
+ async handleError(executionId, error) {
524
+ console.error(`[AgentExecutorWrapper] Execution ${executionId} failed:`, error);
525
+ // Calculate file changes even for failed executions
526
+ // (user may want to commit partial work)
527
+ let filesChangedJson = null;
528
+ try {
529
+ const changesService = new ExecutionChangesService(this.db, this.processConfig.workDir);
530
+ const changesResult = await changesService.getChanges(executionId);
531
+ if (changesResult.available && changesResult.captured) {
532
+ const filePaths = changesResult.captured.files.map((f) => f.path);
533
+ filesChangedJson = JSON.stringify(filePaths);
534
+ console.log(`[AgentExecutorWrapper] Captured ${filePaths.length} file changes for failed execution ${executionId}`);
535
+ }
536
+ }
537
+ catch (calcError) {
538
+ console.warn(`[AgentExecutorWrapper] Failed to calculate files_changed for failed execution ${executionId}:`, calcError instanceof Error ? calcError.message : String(calcError));
539
+ }
540
+ updateExecution(this.db, executionId, {
541
+ status: "failed",
542
+ completed_at: new Date().toISOString(),
543
+ error_message: error.message,
544
+ files_changed: filesChangedJson,
545
+ });
546
+ const execution = getExecution(this.db, executionId);
547
+ if (execution) {
548
+ broadcastExecutionUpdate(this.projectId, executionId, "status_changed", execution, execution.issue_id || undefined);
549
+ }
550
+ }
551
+ /**
552
+ * Create output chunk stream from ManagedProcess
553
+ *
554
+ * For Claude Code: Uses protocol peer to receive messages
555
+ * For other agents: Reads directly from stdout/stderr streams
556
+ *
557
+ * @private
558
+ */
559
+ async *createOutputChunks(process, executionId) {
560
+ // Check if this is a Claude Code process with a protocol peer
561
+ const peer = process.peer;
562
+ if (this.agentType === "claude-code") {
563
+ // Claude Code REQUIRES a protocol peer
564
+ if (!peer) {
565
+ throw new Error("No peer attached to Claude Code process - cannot read output");
566
+ }
567
+ // Claude Code: Use protocol peer messages
568
+ console.log("[AgentExecutorWrapper] Using protocol peer for Claude Code output");
569
+ yield* this.peerMessagesToOutputChunks(peer, executionId);
570
+ return;
571
+ }
572
+ // Other agents: Use stdout/stderr streams
573
+ if (!process.streams) {
574
+ throw new Error("Process does not have streams available");
575
+ }
576
+ const { stdout, stderr } = process.streams;
577
+ // Merge stdout and stderr
578
+ const streams = [];
579
+ if (stdout) {
580
+ streams.push(this.streamToChunks(stdout, "stdout"));
581
+ }
582
+ if (stderr) {
583
+ streams.push(this.streamToChunks(stderr, "stderr"));
584
+ }
585
+ // Yield chunks from all streams
586
+ for (const stream of streams) {
587
+ for await (const chunk of stream) {
588
+ yield chunk;
589
+ }
590
+ }
591
+ }
592
+ /**
593
+ * Convert protocol peer messages to output chunks
594
+ *
595
+ * Used for Claude Code which uses a protocol peer that consumes stdout
596
+ * Updates completion state when result message is received
597
+ *
598
+ * @private
599
+ */
600
+ async *peerMessagesToOutputChunks(peer, executionId) {
601
+ const messageQueue = [];
602
+ let streamEnded = false;
603
+ let exitDetected = false;
604
+ // Register message handler
605
+ peer.onMessage((message) => {
606
+ messageQueue.push(message);
607
+ // Detect completion and update completion state
608
+ if (message.type === "result" &&
609
+ (message.subtype === "success" || message.subtype === "failure")) {
610
+ exitDetected = true;
611
+ const exitCode = message.subtype === "success" ? 0 : 1;
612
+ this.completionState.set(executionId, { completed: true, exitCode });
613
+ console.log(`[AgentExecutorWrapper] Detected completion from peer for ${executionId}:`, { subtype: message.subtype, exitCode });
614
+ }
615
+ });
616
+ // Process messages until completion
617
+ while (!streamEnded || messageQueue.length > 0) {
618
+ if (messageQueue.length === 0) {
619
+ if (exitDetected) {
620
+ streamEnded = true;
621
+ break;
622
+ }
623
+ // Wait for more messages
624
+ await new Promise((resolve) => setTimeout(resolve, 10));
625
+ continue;
626
+ }
627
+ // Convert message to stream-json line format
628
+ const message = messageQueue.shift();
629
+ const line = JSON.stringify(message) + "\n";
630
+ yield {
631
+ type: "stdout",
632
+ data: Buffer.from(line, "utf-8"),
633
+ timestamp: new Date(),
634
+ };
635
+ }
636
+ }
637
+ /**
638
+ * Convert a readable stream to output chunks
639
+ *
640
+ * @private
641
+ */
642
+ async *streamToChunks(stream, type) {
643
+ for await (const chunk of stream) {
644
+ yield {
645
+ type,
646
+ data: Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk),
647
+ timestamp: new Date(),
648
+ };
649
+ }
650
+ }
651
+ }
652
+ //# sourceMappingURL=agent-executor-wrapper.js.map