@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.
- package/README.md +6 -0
- package/dist/errors/agent-errors.d.ts +43 -0
- package/dist/errors/agent-errors.d.ts.map +1 -0
- package/dist/errors/agent-errors.js +69 -0
- package/dist/errors/agent-errors.js.map +1 -0
- package/dist/execution/adapters/claude-adapter.d.ts +63 -0
- package/dist/execution/adapters/claude-adapter.d.ts.map +1 -0
- package/dist/execution/adapters/claude-adapter.js +82 -0
- package/dist/execution/adapters/claude-adapter.js.map +1 -0
- package/dist/execution/adapters/codex-adapter.d.ts +67 -0
- package/dist/execution/adapters/codex-adapter.d.ts.map +1 -0
- package/dist/execution/adapters/codex-adapter.js +183 -0
- package/dist/execution/adapters/codex-adapter.js.map +1 -0
- package/dist/execution/adapters/codex-config-builder.d.ts +30 -0
- package/dist/execution/adapters/codex-config-builder.d.ts.map +1 -0
- package/dist/execution/adapters/codex-config-builder.js +110 -0
- package/dist/execution/adapters/codex-config-builder.js.map +1 -0
- package/dist/execution/adapters/copilot-adapter.d.ts +94 -0
- package/dist/execution/adapters/copilot-adapter.d.ts.map +1 -0
- package/dist/execution/adapters/copilot-adapter.js +163 -0
- package/dist/execution/adapters/copilot-adapter.js.map +1 -0
- package/dist/execution/adapters/copilot-config-builder.d.ts +48 -0
- package/dist/execution/adapters/copilot-config-builder.d.ts.map +1 -0
- package/dist/execution/adapters/copilot-config-builder.js +125 -0
- package/dist/execution/adapters/copilot-config-builder.js.map +1 -0
- package/dist/execution/adapters/cursor-adapter.d.ts +66 -0
- package/dist/execution/adapters/cursor-adapter.d.ts.map +1 -0
- package/dist/execution/adapters/cursor-adapter.js +121 -0
- package/dist/execution/adapters/cursor-adapter.js.map +1 -0
- package/dist/execution/adapters/cursor-config-builder.d.ts +29 -0
- package/dist/execution/adapters/cursor-config-builder.d.ts.map +1 -0
- package/dist/execution/adapters/cursor-config-builder.js +49 -0
- package/dist/execution/adapters/cursor-config-builder.js.map +1 -0
- package/dist/execution/adapters/shared/config-presets.d.ts +102 -0
- package/dist/execution/adapters/shared/config-presets.d.ts.map +1 -0
- package/dist/execution/adapters/shared/config-presets.js +205 -0
- package/dist/execution/adapters/shared/config-presets.js.map +1 -0
- package/dist/execution/adapters/shared/config-utils.d.ts +95 -0
- package/dist/execution/adapters/shared/config-utils.d.ts.map +1 -0
- package/dist/execution/adapters/shared/config-utils.js +163 -0
- package/dist/execution/adapters/shared/config-utils.js.map +1 -0
- package/dist/execution/adapters/shared/index.d.ts +8 -0
- package/dist/execution/adapters/shared/index.d.ts.map +1 -0
- package/dist/execution/adapters/shared/index.js +8 -0
- package/dist/execution/adapters/shared/index.js.map +1 -0
- package/dist/execution/executors/agent-executor-wrapper.d.ts +153 -0
- package/dist/execution/executors/agent-executor-wrapper.d.ts.map +1 -0
- package/dist/execution/executors/agent-executor-wrapper.js +652 -0
- package/dist/execution/executors/agent-executor-wrapper.js.map +1 -0
- package/dist/execution/executors/executor-factory.d.ts +95 -0
- package/dist/execution/executors/executor-factory.d.ts.map +1 -0
- package/dist/execution/executors/executor-factory.js +120 -0
- package/dist/execution/executors/executor-factory.js.map +1 -0
- package/dist/execution/output/ag-ui-adapter.d.ts +0 -2
- package/dist/execution/output/ag-ui-adapter.d.ts.map +1 -1
- package/dist/execution/output/ag-ui-adapter.js +0 -2
- package/dist/execution/output/ag-ui-adapter.js.map +1 -1
- package/dist/execution/output/index.d.ts +0 -3
- package/dist/execution/output/index.d.ts.map +1 -1
- package/dist/execution/output/index.js +0 -2
- package/dist/execution/output/index.js.map +1 -1
- package/dist/execution/output/normalized-to-ag-ui-adapter.d.ts +108 -0
- package/dist/execution/output/normalized-to-ag-ui-adapter.d.ts.map +1 -0
- package/dist/execution/output/normalized-to-ag-ui-adapter.js +321 -0
- package/dist/execution/output/normalized-to-ag-ui-adapter.js.map +1 -0
- package/dist/execution/process/builders/claude.d.ts +24 -57
- package/dist/execution/process/builders/claude.d.ts.map +1 -1
- package/dist/execution/process/builders/claude.js +153 -19
- package/dist/execution/process/builders/claude.js.map +1 -1
- package/dist/execution/transport/ipc-transport-manager.d.ts +74 -0
- package/dist/execution/transport/ipc-transport-manager.d.ts.map +1 -0
- package/dist/execution/transport/ipc-transport-manager.js +104 -0
- package/dist/execution/transport/ipc-transport-manager.js.map +1 -0
- package/dist/execution/transport/transport-manager.d.ts.map +1 -1
- package/dist/execution/transport/transport-manager.js +3 -0
- package/dist/execution/transport/transport-manager.js.map +1 -1
- package/dist/execution/worktree/conflict-detector.d.ts +85 -0
- package/dist/execution/worktree/conflict-detector.d.ts.map +1 -0
- package/dist/execution/worktree/conflict-detector.js +129 -0
- package/dist/execution/worktree/conflict-detector.js.map +1 -0
- package/dist/execution/worktree/git-cli.d.ts +9 -0
- package/dist/execution/worktree/git-cli.d.ts.map +1 -1
- package/dist/execution/worktree/git-cli.js +10 -0
- package/dist/execution/worktree/git-cli.js.map +1 -1
- package/dist/execution/worktree/git-sync-cli.d.ts +187 -0
- package/dist/execution/worktree/git-sync-cli.d.ts.map +1 -0
- package/dist/execution/worktree/git-sync-cli.js +350 -0
- package/dist/execution/worktree/git-sync-cli.js.map +1 -0
- package/dist/execution/worktree/manager.d.ts +18 -0
- package/dist/execution/worktree/manager.d.ts.map +1 -1
- package/dist/execution/worktree/manager.js +9 -3
- package/dist/execution/worktree/manager.js.map +1 -1
- package/dist/index.d.ts +1 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +132 -211
- package/dist/index.js.map +1 -1
- package/dist/middleware/project-context.d.ts +37 -0
- package/dist/middleware/project-context.d.ts.map +1 -0
- package/dist/middleware/project-context.js +91 -0
- package/dist/middleware/project-context.js.map +1 -0
- package/dist/public/assets/index-Bb_W5bUr.css +1 -0
- package/dist/public/assets/index-CFKL113G.js +710 -0
- package/dist/public/assets/index-CFKL113G.js.map +1 -0
- package/dist/public/assets/{react-vendor-ByUx1V_q.js → react-vendor-DiL5hC7l.js} +2 -2
- package/dist/public/assets/{react-vendor-ByUx1V_q.js.map → react-vendor-DiL5hC7l.js.map} +1 -1
- package/dist/public/assets/ui-vendor-B4WMPEfa.js +54 -0
- package/dist/public/assets/ui-vendor-B4WMPEfa.js.map +1 -0
- package/dist/public/index.html +4 -4
- package/dist/routes/agents.d.ts +3 -0
- package/dist/routes/agents.d.ts.map +1 -0
- package/dist/routes/agents.js +62 -0
- package/dist/routes/agents.js.map +1 -0
- package/dist/routes/config.d.ts +3 -0
- package/dist/routes/config.d.ts.map +1 -0
- package/dist/routes/config.js +25 -0
- package/dist/routes/config.js.map +1 -0
- package/dist/routes/editors.d.ts +15 -0
- package/dist/routes/editors.d.ts.map +1 -0
- package/dist/routes/editors.js +98 -0
- package/dist/routes/editors.js.map +1 -0
- package/dist/routes/executions-stream.d.ts +8 -5
- package/dist/routes/executions-stream.d.ts.map +1 -1
- package/dist/routes/executions-stream.js +10 -6
- package/dist/routes/executions-stream.js.map +1 -1
- package/dist/routes/executions.d.ts +6 -10
- package/dist/routes/executions.d.ts.map +1 -1
- package/dist/routes/executions.js +506 -54
- package/dist/routes/executions.js.map +1 -1
- package/dist/routes/feedback.d.ts +3 -2
- package/dist/routes/feedback.d.ts.map +1 -1
- package/dist/routes/feedback.js +12 -10
- package/dist/routes/feedback.js.map +1 -1
- package/dist/routes/files.d.ts +18 -0
- package/dist/routes/files.d.ts.map +1 -0
- package/dist/routes/files.js +89 -0
- package/dist/routes/files.js.map +1 -0
- package/dist/routes/issues.d.ts +3 -2
- package/dist/routes/issues.d.ts.map +1 -1
- package/dist/routes/issues.js +19 -18
- package/dist/routes/issues.js.map +1 -1
- package/dist/routes/projects.d.ts +11 -0
- package/dist/routes/projects.d.ts.map +1 -0
- package/dist/routes/projects.js +447 -0
- package/dist/routes/projects.js.map +1 -0
- package/dist/routes/relationships.d.ts +3 -2
- package/dist/routes/relationships.d.ts.map +1 -1
- package/dist/routes/relationships.js +12 -10
- package/dist/routes/relationships.js.map +1 -1
- package/dist/routes/repo-info.d.ts +3 -0
- package/dist/routes/repo-info.d.ts.map +1 -0
- package/dist/routes/repo-info.js +126 -0
- package/dist/routes/repo-info.js.map +1 -0
- package/dist/routes/specs.d.ts +3 -2
- package/dist/routes/specs.d.ts.map +1 -1
- package/dist/routes/specs.js +19 -18
- package/dist/routes/specs.js.map +1 -1
- package/dist/services/agent-registry.d.ts +140 -0
- package/dist/services/agent-registry.d.ts.map +1 -0
- package/dist/services/agent-registry.js +272 -0
- package/dist/services/agent-registry.js.map +1 -0
- package/dist/services/editor-service.d.ts +57 -0
- package/dist/services/editor-service.d.ts.map +1 -0
- package/dist/services/editor-service.js +204 -0
- package/dist/services/editor-service.js.map +1 -0
- package/dist/services/execution-changes-service.d.ts +92 -0
- package/dist/services/execution-changes-service.d.ts.map +1 -0
- package/dist/services/execution-changes-service.js +546 -0
- package/dist/services/execution-changes-service.js.map +1 -0
- package/dist/services/execution-lifecycle.d.ts +1 -0
- package/dist/services/execution-lifecycle.d.ts.map +1 -1
- package/dist/services/execution-lifecycle.js +37 -7
- package/dist/services/execution-lifecycle.js.map +1 -1
- package/dist/services/execution-logs-store.d.ts +75 -0
- package/dist/services/execution-logs-store.d.ts.map +1 -1
- package/dist/services/execution-logs-store.js +142 -2
- package/dist/services/execution-logs-store.js.map +1 -1
- package/dist/services/execution-service.d.ts +50 -58
- package/dist/services/execution-service.d.ts.map +1 -1
- package/dist/services/execution-service.js +433 -469
- package/dist/services/execution-service.js.map +1 -1
- package/dist/services/execution-worker-pool.d.ts +116 -0
- package/dist/services/execution-worker-pool.d.ts.map +1 -0
- package/dist/services/execution-worker-pool.js +326 -0
- package/dist/services/execution-worker-pool.js.map +1 -0
- package/dist/services/executions.d.ts +3 -0
- package/dist/services/executions.d.ts.map +1 -1
- package/dist/services/executions.js +11 -17
- package/dist/services/executions.js.map +1 -1
- package/dist/services/export.d.ts +8 -2
- package/dist/services/export.d.ts.map +1 -1
- package/dist/services/export.js +29 -23
- package/dist/services/export.js.map +1 -1
- package/dist/services/file-search/git-ls-files-strategy.d.ts +72 -0
- package/dist/services/file-search/git-ls-files-strategy.d.ts.map +1 -0
- package/dist/services/file-search/git-ls-files-strategy.js +176 -0
- package/dist/services/file-search/git-ls-files-strategy.js.map +1 -0
- package/dist/services/file-search/index.d.ts +9 -0
- package/dist/services/file-search/index.d.ts.map +1 -0
- package/dist/services/file-search/index.js +10 -0
- package/dist/services/file-search/index.js.map +1 -0
- package/dist/services/file-search/registry.d.ts +97 -0
- package/dist/services/file-search/registry.d.ts.map +1 -0
- package/dist/services/file-search/registry.js +140 -0
- package/dist/services/file-search/registry.js.map +1 -0
- package/dist/services/file-search/strategy.d.ts +58 -0
- package/dist/services/file-search/strategy.d.ts.map +1 -0
- package/dist/services/file-search/strategy.js +8 -0
- package/dist/services/file-search/strategy.js.map +1 -0
- package/dist/services/project-context.d.ts +69 -0
- package/dist/services/project-context.d.ts.map +1 -0
- package/dist/services/project-context.js +113 -0
- package/dist/services/project-context.js.map +1 -0
- package/dist/services/project-manager.d.ts +95 -0
- package/dist/services/project-manager.d.ts.map +1 -0
- package/dist/services/project-manager.js +388 -0
- package/dist/services/project-manager.js.map +1 -0
- package/dist/services/project-registry.d.ts +98 -0
- package/dist/services/project-registry.d.ts.map +1 -0
- package/dist/services/project-registry.js +289 -0
- package/dist/services/project-registry.js.map +1 -0
- package/dist/services/prompt-resolver.d.ts +97 -0
- package/dist/services/prompt-resolver.d.ts.map +1 -0
- package/dist/services/prompt-resolver.js +377 -0
- package/dist/services/prompt-resolver.js.map +1 -0
- package/dist/services/repo-info.d.ts +12 -0
- package/dist/services/repo-info.d.ts.map +1 -1
- package/dist/services/repo-info.js +46 -0
- package/dist/services/repo-info.js.map +1 -1
- package/dist/services/watcher.d.ts +3 -4
- package/dist/services/watcher.d.ts.map +1 -1
- package/dist/services/watcher.js +18 -35
- package/dist/services/watcher.js.map +1 -1
- package/dist/services/websocket.d.ts +30 -16
- package/dist/services/websocket.d.ts.map +1 -1
- package/dist/services/websocket.js +102 -37
- package/dist/services/websocket.js.map +1 -1
- package/dist/services/worktree-sync-service.d.ts +228 -0
- package/dist/services/worktree-sync-service.d.ts.map +1 -0
- package/dist/services/worktree-sync-service.js +563 -0
- package/dist/services/worktree-sync-service.js.map +1 -0
- package/dist/types/editor.d.ts +49 -0
- package/dist/types/editor.d.ts.map +1 -0
- package/dist/types/editor.js +50 -0
- package/dist/types/editor.js.map +1 -0
- package/dist/types/project.d.ts +58 -0
- package/dist/types/project.d.ts.map +1 -0
- package/dist/types/project.js +10 -0
- package/dist/types/project.js.map +1 -0
- package/dist/utils/executable-check.d.ts +36 -0
- package/dist/utils/executable-check.d.ts.map +1 -0
- package/dist/utils/executable-check.js +79 -0
- package/dist/utils/executable-check.js.map +1 -0
- package/dist/workers/execution-worker.d.ts +18 -0
- package/dist/workers/execution-worker.d.ts.map +1 -0
- package/dist/workers/execution-worker.js +340 -0
- package/dist/workers/execution-worker.js.map +1 -0
- package/dist/workers/worker-ipc.d.ts +84 -0
- package/dist/workers/worker-ipc.d.ts.map +1 -0
- package/dist/workers/worker-ipc.js +29 -0
- package/dist/workers/worker-ipc.js.map +1 -0
- package/package.json +6 -5
- package/dist/execution/output/ag-ui-integration.d.ts +0 -96
- package/dist/execution/output/ag-ui-integration.d.ts.map +0 -1
- package/dist/execution/output/ag-ui-integration.js +0 -96
- package/dist/execution/output/ag-ui-integration.js.map +0 -1
- package/dist/execution/output/claude-code-output-processor.d.ts +0 -321
- package/dist/execution/output/claude-code-output-processor.d.ts.map +0 -1
- package/dist/execution/output/claude-code-output-processor.js +0 -769
- package/dist/execution/output/claude-code-output-processor.js.map +0 -1
- package/dist/public/assets/index-B3SEMufD.js +0 -580
- package/dist/public/assets/index-B3SEMufD.js.map +0 -1
- package/dist/public/assets/index-D2YGL3gX.css +0 -1
- package/dist/public/assets/ui-vendor-CotR6bx9.js +0 -54
- package/dist/public/assets/ui-vendor-CotR6bx9.js.map +0 -1
|
@@ -2,50 +2,64 @@
|
|
|
2
2
|
* Executions API routes (mapped to /api)
|
|
3
3
|
*
|
|
4
4
|
* Provides REST API for managing issue executions.
|
|
5
|
+
*
|
|
6
|
+
* Note: All routes require X-Project-ID header via requireProject() middleware
|
|
5
7
|
*/
|
|
6
8
|
import { Router } from "express";
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
+
import { execSync } from "child_process";
|
|
10
|
+
import { NormalizedEntryToAgUiAdapter } from "../execution/output/normalized-to-ag-ui-adapter.js";
|
|
11
|
+
import { AgUiEventAdapter } from "../execution/output/ag-ui-adapter.js";
|
|
12
|
+
import { agentRegistryService } from "../services/agent-registry.js";
|
|
13
|
+
import { AgentNotFoundError, AgentNotImplementedError, AgentError, } from "../errors/agent-errors.js";
|
|
14
|
+
import { WorktreeSyncService, WorktreeSyncError, WorktreeSyncErrorCode, } from "../services/worktree-sync-service.js";
|
|
15
|
+
import { ExecutionChangesService } from "../services/execution-changes-service.js";
|
|
16
|
+
/**
|
|
17
|
+
* Get WorktreeSyncService instance for a request
|
|
18
|
+
*
|
|
19
|
+
* @param req - Express request with project context
|
|
20
|
+
* @returns WorktreeSyncService instance
|
|
21
|
+
*/
|
|
22
|
+
function getWorktreeSyncService(req) {
|
|
23
|
+
const db = req.project.db;
|
|
24
|
+
const repoPath = req.project.path;
|
|
25
|
+
return new WorktreeSyncService(db, repoPath);
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Get HTTP status code for WorktreeSyncError
|
|
29
|
+
*
|
|
30
|
+
* @param error - WorktreeSyncError instance
|
|
31
|
+
* @returns HTTP status code
|
|
32
|
+
*/
|
|
33
|
+
function getStatusCodeForSyncError(error) {
|
|
34
|
+
switch (error.code) {
|
|
35
|
+
case WorktreeSyncErrorCode.NO_WORKTREE:
|
|
36
|
+
case WorktreeSyncErrorCode.WORKTREE_MISSING:
|
|
37
|
+
case WorktreeSyncErrorCode.BRANCH_MISSING:
|
|
38
|
+
case WorktreeSyncErrorCode.TARGET_BRANCH_MISSING:
|
|
39
|
+
case WorktreeSyncErrorCode.EXECUTION_NOT_FOUND:
|
|
40
|
+
return 404; // Not found
|
|
41
|
+
case WorktreeSyncErrorCode.DIRTY_WORKING_TREE:
|
|
42
|
+
case WorktreeSyncErrorCode.CODE_CONFLICTS:
|
|
43
|
+
case WorktreeSyncErrorCode.NO_COMMON_BASE:
|
|
44
|
+
return 400; // Bad request (user must fix)
|
|
45
|
+
case WorktreeSyncErrorCode.MERGE_FAILED:
|
|
46
|
+
case WorktreeSyncErrorCode.JSONL_RESOLUTION_FAILED:
|
|
47
|
+
case WorktreeSyncErrorCode.DATABASE_SYNC_FAILED:
|
|
48
|
+
return 500; // Internal error
|
|
49
|
+
default:
|
|
50
|
+
return 500;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
9
53
|
/**
|
|
10
54
|
* Create executions router
|
|
11
55
|
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* @param executionService - Optional execution service instance
|
|
16
|
-
* @param logsStore - Optional execution logs store instance
|
|
56
|
+
* Note: ExecutionService and ExecutionLogsStore are accessed via req.project
|
|
57
|
+
* which is injected by the requireProject() middleware
|
|
58
|
+
*
|
|
17
59
|
* @returns Express router with execution endpoints
|
|
18
60
|
*/
|
|
19
|
-
export function createExecutionsRouter(
|
|
61
|
+
export function createExecutionsRouter() {
|
|
20
62
|
const router = Router();
|
|
21
|
-
const service = executionService ||
|
|
22
|
-
new ExecutionService(db, repoPath, undefined, transportManager);
|
|
23
|
-
const store = logsStore || new ExecutionLogsStore(db);
|
|
24
|
-
/**
|
|
25
|
-
* POST /api/issues/:issueId/executions/prepare
|
|
26
|
-
*
|
|
27
|
-
* Prepare an execution - render template and show preview
|
|
28
|
-
*/
|
|
29
|
-
router.post("/issues/:issueId/executions/prepare", async (req, res) => {
|
|
30
|
-
try {
|
|
31
|
-
const { issueId } = req.params;
|
|
32
|
-
const options = req.body || {};
|
|
33
|
-
const result = await service.prepareExecution(issueId, options);
|
|
34
|
-
res.json({
|
|
35
|
-
success: true,
|
|
36
|
-
data: result,
|
|
37
|
-
});
|
|
38
|
-
}
|
|
39
|
-
catch (error) {
|
|
40
|
-
console.error("[API Route] ERROR: Failed to prepare execution:", error);
|
|
41
|
-
res.status(500).json({
|
|
42
|
-
success: false,
|
|
43
|
-
data: null,
|
|
44
|
-
error_data: error instanceof Error ? error.message : String(error),
|
|
45
|
-
message: "Failed to prepare execution",
|
|
46
|
-
});
|
|
47
|
-
}
|
|
48
|
-
});
|
|
49
63
|
/**
|
|
50
64
|
* POST /api/issues/:issueId/executions
|
|
51
65
|
*
|
|
@@ -54,7 +68,7 @@ export function createExecutionsRouter(db, repoPath, transportManager, execution
|
|
|
54
68
|
router.post("/issues/:issueId/executions", async (req, res) => {
|
|
55
69
|
try {
|
|
56
70
|
const { issueId } = req.params;
|
|
57
|
-
const { config, prompt } = req.body;
|
|
71
|
+
const { config, prompt, agentType } = req.body;
|
|
58
72
|
// Validate required fields
|
|
59
73
|
if (!prompt) {
|
|
60
74
|
res.status(400).json({
|
|
@@ -64,7 +78,22 @@ export function createExecutionsRouter(db, repoPath, transportManager, execution
|
|
|
64
78
|
});
|
|
65
79
|
return;
|
|
66
80
|
}
|
|
67
|
-
|
|
81
|
+
// Validate agentType if provided
|
|
82
|
+
if (agentType) {
|
|
83
|
+
// Check if agent exists in registry
|
|
84
|
+
if (!agentRegistryService.hasAgent(agentType)) {
|
|
85
|
+
const availableAgents = agentRegistryService
|
|
86
|
+
.getAvailableAgents()
|
|
87
|
+
.map((a) => a.name);
|
|
88
|
+
throw new AgentNotFoundError(agentType, availableAgents);
|
|
89
|
+
}
|
|
90
|
+
// Check if agent is implemented
|
|
91
|
+
if (!agentRegistryService.isAgentImplemented(agentType)) {
|
|
92
|
+
throw new AgentNotImplementedError(agentType);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
const execution = await req.project.executionService.createExecution(issueId, config || {}, prompt, agentType // Optional, defaults to 'claude-code' in service
|
|
96
|
+
);
|
|
68
97
|
res.status(201).json({
|
|
69
98
|
success: true,
|
|
70
99
|
data: execution,
|
|
@@ -72,7 +101,39 @@ export function createExecutionsRouter(db, repoPath, transportManager, execution
|
|
|
72
101
|
}
|
|
73
102
|
catch (error) {
|
|
74
103
|
console.error("[API Route] ERROR: Failed to create execution:", error);
|
|
75
|
-
// Handle specific error
|
|
104
|
+
// Handle agent-specific errors with enhanced error responses
|
|
105
|
+
if (error instanceof AgentNotFoundError) {
|
|
106
|
+
res.status(400).json({
|
|
107
|
+
success: false,
|
|
108
|
+
data: null,
|
|
109
|
+
error: error.message,
|
|
110
|
+
code: error.code,
|
|
111
|
+
details: error.details,
|
|
112
|
+
});
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
if (error instanceof AgentNotImplementedError) {
|
|
116
|
+
res.status(501).json({
|
|
117
|
+
success: false,
|
|
118
|
+
data: null,
|
|
119
|
+
error: error.message,
|
|
120
|
+
code: error.code,
|
|
121
|
+
details: error.details,
|
|
122
|
+
});
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
if (error instanceof AgentError) {
|
|
126
|
+
// Generic agent error (400 by default)
|
|
127
|
+
res.status(400).json({
|
|
128
|
+
success: false,
|
|
129
|
+
data: null,
|
|
130
|
+
error: error.message,
|
|
131
|
+
code: error.code,
|
|
132
|
+
details: error.details,
|
|
133
|
+
});
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
// Handle other errors (backwards compatibility)
|
|
76
137
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
77
138
|
const statusCode = errorMessage.includes("not found") ? 404 : 500;
|
|
78
139
|
res.status(statusCode).json({
|
|
@@ -91,7 +152,7 @@ export function createExecutionsRouter(db, repoPath, transportManager, execution
|
|
|
91
152
|
router.get("/executions/:executionId", (req, res) => {
|
|
92
153
|
try {
|
|
93
154
|
const { executionId } = req.params;
|
|
94
|
-
const execution =
|
|
155
|
+
const execution = req.project.executionService.getExecution(executionId);
|
|
95
156
|
if (!execution) {
|
|
96
157
|
res.status(404).json({
|
|
97
158
|
success: false,
|
|
@@ -115,16 +176,86 @@ export function createExecutionsRouter(db, repoPath, transportManager, execution
|
|
|
115
176
|
});
|
|
116
177
|
}
|
|
117
178
|
});
|
|
179
|
+
/**
|
|
180
|
+
* GET /api/executions/:executionId/chain
|
|
181
|
+
*
|
|
182
|
+
* Get execution chain (root execution + all follow-ups)
|
|
183
|
+
*
|
|
184
|
+
* Returns the full chain of executions starting from the root.
|
|
185
|
+
* If the requested execution is a follow-up, finds the root and returns the full chain.
|
|
186
|
+
* Executions are ordered chronologically (oldest first).
|
|
187
|
+
*/
|
|
188
|
+
router.get("/executions/:executionId/chain", (req, res) => {
|
|
189
|
+
try {
|
|
190
|
+
const { executionId } = req.params;
|
|
191
|
+
const db = req.project.db;
|
|
192
|
+
// Get the requested execution
|
|
193
|
+
const execution = req.project.executionService.getExecution(executionId);
|
|
194
|
+
if (!execution) {
|
|
195
|
+
res.status(404).json({
|
|
196
|
+
success: false,
|
|
197
|
+
data: null,
|
|
198
|
+
message: `Execution not found: ${executionId}`,
|
|
199
|
+
});
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
// Find the root execution by traversing up parent_execution_id
|
|
203
|
+
let rootId = executionId;
|
|
204
|
+
let current = execution;
|
|
205
|
+
while (current.parent_execution_id) {
|
|
206
|
+
rootId = current.parent_execution_id;
|
|
207
|
+
const parent = req.project.executionService.getExecution(rootId);
|
|
208
|
+
if (!parent)
|
|
209
|
+
break;
|
|
210
|
+
current = parent;
|
|
211
|
+
}
|
|
212
|
+
// Get all executions in the chain (root + all descendants)
|
|
213
|
+
// Using recursive CTE to get all descendants
|
|
214
|
+
const chain = db
|
|
215
|
+
.prepare(`
|
|
216
|
+
WITH RECURSIVE execution_chain AS (
|
|
217
|
+
-- Base case: the root execution
|
|
218
|
+
SELECT * FROM executions WHERE id = ?
|
|
219
|
+
UNION ALL
|
|
220
|
+
-- Recursive case: children of executions in the chain
|
|
221
|
+
SELECT e.* FROM executions e
|
|
222
|
+
INNER JOIN execution_chain ec ON e.parent_execution_id = ec.id
|
|
223
|
+
)
|
|
224
|
+
SELECT * FROM execution_chain
|
|
225
|
+
ORDER BY created_at ASC
|
|
226
|
+
`)
|
|
227
|
+
.all(rootId);
|
|
228
|
+
res.json({
|
|
229
|
+
success: true,
|
|
230
|
+
data: {
|
|
231
|
+
rootId,
|
|
232
|
+
executions: chain,
|
|
233
|
+
},
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
catch (error) {
|
|
237
|
+
console.error("Error getting execution chain:", error);
|
|
238
|
+
res.status(500).json({
|
|
239
|
+
success: false,
|
|
240
|
+
data: null,
|
|
241
|
+
error_data: error instanceof Error ? error.message : String(error),
|
|
242
|
+
message: "Failed to get execution chain",
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
});
|
|
118
246
|
/**
|
|
119
247
|
* GET /api/executions/:executionId/logs
|
|
120
248
|
*
|
|
121
|
-
* Get
|
|
249
|
+
* Get AG-UI events for historical replay
|
|
250
|
+
*
|
|
251
|
+
* Fetches NormalizedEntry logs from storage and converts them to AG-UI events on-demand.
|
|
252
|
+
* This preserves full structured data in storage while serving UI-ready events to frontend.
|
|
122
253
|
*/
|
|
123
|
-
router.get("/executions/:executionId/logs", (req, res) => {
|
|
254
|
+
router.get("/executions/:executionId/logs", async (req, res) => {
|
|
124
255
|
try {
|
|
125
256
|
const { executionId } = req.params;
|
|
126
257
|
// Verify execution exists
|
|
127
|
-
const execution =
|
|
258
|
+
const execution = req.project.executionService.getExecution(executionId);
|
|
128
259
|
if (!execution) {
|
|
129
260
|
res.status(404).json({
|
|
130
261
|
success: false,
|
|
@@ -133,14 +264,27 @@ export function createExecutionsRouter(db, repoPath, transportManager, execution
|
|
|
133
264
|
});
|
|
134
265
|
return;
|
|
135
266
|
}
|
|
136
|
-
// Fetch
|
|
137
|
-
const
|
|
138
|
-
const metadata =
|
|
267
|
+
// Fetch normalized entries from storage
|
|
268
|
+
const normalizedEntries = req.project.logsStore.getNormalizedEntries(executionId);
|
|
269
|
+
const metadata = req.project.logsStore.getLogMetadata(executionId);
|
|
270
|
+
// Convert NormalizedEntry to AG-UI events on-demand
|
|
271
|
+
const events = [];
|
|
272
|
+
// Create a temporary AG-UI adapter to collect events
|
|
273
|
+
const agUiAdapter = new AgUiEventAdapter(executionId);
|
|
274
|
+
agUiAdapter.onEvent((event) => {
|
|
275
|
+
events.push(event);
|
|
276
|
+
});
|
|
277
|
+
// Create normalized adapter to transform entries
|
|
278
|
+
const normalizedAdapter = new NormalizedEntryToAgUiAdapter(agUiAdapter);
|
|
279
|
+
// Process all normalized entries through the adapter
|
|
280
|
+
for (const entry of normalizedEntries) {
|
|
281
|
+
await normalizedAdapter.processEntry(entry);
|
|
282
|
+
}
|
|
139
283
|
res.json({
|
|
140
284
|
success: true,
|
|
141
285
|
data: {
|
|
142
286
|
executionId,
|
|
143
|
-
|
|
287
|
+
events,
|
|
144
288
|
metadata: metadata
|
|
145
289
|
? {
|
|
146
290
|
lineCount: metadata.line_count,
|
|
@@ -167,6 +311,40 @@ export function createExecutionsRouter(db, repoPath, transportManager, execution
|
|
|
167
311
|
});
|
|
168
312
|
}
|
|
169
313
|
});
|
|
314
|
+
/**
|
|
315
|
+
* GET /api/executions/:executionId/changes
|
|
316
|
+
*
|
|
317
|
+
* Get code changes (file list + diff statistics) for an execution
|
|
318
|
+
*
|
|
319
|
+
* Calculates changes on-demand from commit SHAs. Supports:
|
|
320
|
+
* - Committed changes (commit-to-commit diff)
|
|
321
|
+
* - Uncommitted changes (working tree diff)
|
|
322
|
+
* - Unavailable states with clear error reasons
|
|
323
|
+
*/
|
|
324
|
+
router.get("/executions/:executionId/changes", async (req, res) => {
|
|
325
|
+
try {
|
|
326
|
+
const { executionId } = req.params;
|
|
327
|
+
const db = req.project.db;
|
|
328
|
+
const repoPath = req.project.path;
|
|
329
|
+
// Create changes service
|
|
330
|
+
const changesService = new ExecutionChangesService(db, repoPath);
|
|
331
|
+
// Get changes
|
|
332
|
+
const result = await changesService.getChanges(executionId);
|
|
333
|
+
res.json({
|
|
334
|
+
success: true,
|
|
335
|
+
data: result,
|
|
336
|
+
});
|
|
337
|
+
}
|
|
338
|
+
catch (error) {
|
|
339
|
+
console.error("[GET /executions/:id/changes] Error:", error);
|
|
340
|
+
res.status(500).json({
|
|
341
|
+
success: false,
|
|
342
|
+
data: null,
|
|
343
|
+
error_data: error instanceof Error ? error.message : String(error),
|
|
344
|
+
message: "Failed to calculate changes",
|
|
345
|
+
});
|
|
346
|
+
}
|
|
347
|
+
});
|
|
170
348
|
/**
|
|
171
349
|
* GET /api/issues/:issueId/executions
|
|
172
350
|
*
|
|
@@ -175,7 +353,7 @@ export function createExecutionsRouter(db, repoPath, transportManager, execution
|
|
|
175
353
|
router.get("/issues/:issueId/executions", (req, res) => {
|
|
176
354
|
try {
|
|
177
355
|
const { issueId } = req.params;
|
|
178
|
-
const executions =
|
|
356
|
+
const executions = req.project.executionService.listExecutions(issueId);
|
|
179
357
|
res.json({
|
|
180
358
|
success: true,
|
|
181
359
|
data: executions,
|
|
@@ -209,7 +387,7 @@ export function createExecutionsRouter(db, repoPath, transportManager, execution
|
|
|
209
387
|
});
|
|
210
388
|
return;
|
|
211
389
|
}
|
|
212
|
-
const followUpExecution = await
|
|
390
|
+
const followUpExecution = await req.project.executionService.createFollowUp(executionId, feedback);
|
|
213
391
|
res.status(201).json({
|
|
214
392
|
success: true,
|
|
215
393
|
data: followUpExecution,
|
|
@@ -232,14 +410,14 @@ export function createExecutionsRouter(db, repoPath, transportManager, execution
|
|
|
232
410
|
}
|
|
233
411
|
});
|
|
234
412
|
/**
|
|
235
|
-
*
|
|
413
|
+
* POST /api/executions/:executionId/cancel
|
|
236
414
|
*
|
|
237
415
|
* Cancel a running execution
|
|
238
416
|
*/
|
|
239
|
-
router.
|
|
417
|
+
router.post("/executions/:executionId/cancel", async (req, res) => {
|
|
240
418
|
try {
|
|
241
419
|
const { executionId } = req.params;
|
|
242
|
-
await
|
|
420
|
+
await req.project.executionService.cancelExecution(executionId);
|
|
243
421
|
res.json({
|
|
244
422
|
success: true,
|
|
245
423
|
data: { executionId },
|
|
@@ -259,6 +437,51 @@ export function createExecutionsRouter(db, repoPath, transportManager, execution
|
|
|
259
437
|
});
|
|
260
438
|
}
|
|
261
439
|
});
|
|
440
|
+
/**
|
|
441
|
+
* DELETE /api/executions/:executionId
|
|
442
|
+
*
|
|
443
|
+
* Delete an execution and its entire chain (or cancel if ?cancel=true)
|
|
444
|
+
*
|
|
445
|
+
* Query parameters:
|
|
446
|
+
* - cancel: if "true", cancel the execution instead of deleting it
|
|
447
|
+
* - deleteBranch: if "true", also delete the execution's branch
|
|
448
|
+
* - deleteWorktree: if "true", also delete the execution's worktree
|
|
449
|
+
*/
|
|
450
|
+
router.delete("/executions/:executionId", async (req, res) => {
|
|
451
|
+
try {
|
|
452
|
+
const { executionId } = req.params;
|
|
453
|
+
const { cancel, deleteBranch, deleteWorktree } = req.query;
|
|
454
|
+
// If cancel query param is true, cancel the execution
|
|
455
|
+
if (cancel === "true") {
|
|
456
|
+
await req.project.executionService.cancelExecution(executionId);
|
|
457
|
+
res.json({
|
|
458
|
+
success: true,
|
|
459
|
+
data: { executionId },
|
|
460
|
+
message: "Execution cancelled successfully",
|
|
461
|
+
});
|
|
462
|
+
return;
|
|
463
|
+
}
|
|
464
|
+
// Otherwise, delete the execution and its chain
|
|
465
|
+
await req.project.executionService.deleteExecution(executionId, deleteBranch === "true", deleteWorktree === "true");
|
|
466
|
+
res.json({
|
|
467
|
+
success: true,
|
|
468
|
+
data: { executionId },
|
|
469
|
+
message: "Execution deleted successfully",
|
|
470
|
+
});
|
|
471
|
+
}
|
|
472
|
+
catch (error) {
|
|
473
|
+
console.error("Error deleting/cancelling execution:", error);
|
|
474
|
+
// Handle specific error cases
|
|
475
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
476
|
+
const statusCode = errorMessage.includes("not found") ? 404 : 500;
|
|
477
|
+
res.status(statusCode).json({
|
|
478
|
+
success: false,
|
|
479
|
+
data: null,
|
|
480
|
+
error_data: errorMessage,
|
|
481
|
+
message: "Failed to delete/cancel execution",
|
|
482
|
+
});
|
|
483
|
+
}
|
|
484
|
+
});
|
|
262
485
|
/**
|
|
263
486
|
* GET /api/executions/:executionId/worktree
|
|
264
487
|
*
|
|
@@ -267,7 +490,7 @@ export function createExecutionsRouter(db, repoPath, transportManager, execution
|
|
|
267
490
|
router.get("/executions/:executionId/worktree", async (req, res) => {
|
|
268
491
|
try {
|
|
269
492
|
const { executionId } = req.params;
|
|
270
|
-
const exists = await
|
|
493
|
+
const exists = await req.project.executionService.worktreeExists(executionId);
|
|
271
494
|
res.json({
|
|
272
495
|
success: true,
|
|
273
496
|
data: { exists },
|
|
@@ -287,11 +510,15 @@ export function createExecutionsRouter(db, repoPath, transportManager, execution
|
|
|
287
510
|
* DELETE /api/executions/:executionId/worktree
|
|
288
511
|
*
|
|
289
512
|
* Delete the worktree for an execution
|
|
513
|
+
*
|
|
514
|
+
* Query parameters:
|
|
515
|
+
* - deleteBranch: if "true", also delete the execution's branch
|
|
290
516
|
*/
|
|
291
517
|
router.delete("/executions/:executionId/worktree", async (req, res) => {
|
|
292
518
|
try {
|
|
293
519
|
const { executionId } = req.params;
|
|
294
|
-
|
|
520
|
+
const { deleteBranch } = req.query;
|
|
521
|
+
await req.project.executionService.deleteWorktree(executionId, deleteBranch === "true");
|
|
295
522
|
res.json({
|
|
296
523
|
success: true,
|
|
297
524
|
data: { executionId },
|
|
@@ -318,6 +545,231 @@ export function createExecutionsRouter(db, repoPath, transportManager, execution
|
|
|
318
545
|
});
|
|
319
546
|
}
|
|
320
547
|
});
|
|
548
|
+
/**
|
|
549
|
+
* GET /api/executions/:executionId/sync/preview
|
|
550
|
+
*
|
|
551
|
+
* Preview sync changes and detect conflicts
|
|
552
|
+
*
|
|
553
|
+
* Returns preview of what would happen if sync is performed,
|
|
554
|
+
* including conflicts, diff, commits, and warnings.
|
|
555
|
+
*/
|
|
556
|
+
router.get("/executions/:executionId/sync/preview", async (req, res) => {
|
|
557
|
+
try {
|
|
558
|
+
const { executionId } = req.params;
|
|
559
|
+
// Get worktree sync service
|
|
560
|
+
const syncService = getWorktreeSyncService(req);
|
|
561
|
+
// Preview sync
|
|
562
|
+
const preview = await syncService.previewSync(executionId);
|
|
563
|
+
res.json({
|
|
564
|
+
success: true,
|
|
565
|
+
data: preview,
|
|
566
|
+
});
|
|
567
|
+
}
|
|
568
|
+
catch (error) {
|
|
569
|
+
console.error(`Failed to preview sync for execution ${req.params.executionId}:`, error);
|
|
570
|
+
if (error instanceof WorktreeSyncError) {
|
|
571
|
+
const statusCode = getStatusCodeForSyncError(error);
|
|
572
|
+
res.status(statusCode).json({
|
|
573
|
+
success: false,
|
|
574
|
+
data: null,
|
|
575
|
+
error: error.message,
|
|
576
|
+
code: error.code,
|
|
577
|
+
});
|
|
578
|
+
}
|
|
579
|
+
else {
|
|
580
|
+
res.status(500).json({
|
|
581
|
+
success: false,
|
|
582
|
+
data: null,
|
|
583
|
+
error: "Internal server error",
|
|
584
|
+
message: error instanceof Error ? error.message : String(error),
|
|
585
|
+
});
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
});
|
|
589
|
+
/**
|
|
590
|
+
* POST /api/executions/:executionId/sync/squash
|
|
591
|
+
*
|
|
592
|
+
* Perform squash sync operation
|
|
593
|
+
*
|
|
594
|
+
* Combines all worktree changes into a single commit on the target branch.
|
|
595
|
+
* Automatically resolves JSONL conflicts using merge-resolver.
|
|
596
|
+
*
|
|
597
|
+
* Request body:
|
|
598
|
+
* - commitMessage?: string - Optional custom commit message
|
|
599
|
+
*/
|
|
600
|
+
router.post("/executions/:executionId/sync/squash", async (req, res) => {
|
|
601
|
+
try {
|
|
602
|
+
const { executionId } = req.params;
|
|
603
|
+
const { commitMessage } = req.body || {};
|
|
604
|
+
// Get worktree sync service
|
|
605
|
+
const syncService = getWorktreeSyncService(req);
|
|
606
|
+
// Check if squashSync method exists
|
|
607
|
+
if (typeof syncService.squashSync !== "function") {
|
|
608
|
+
res.status(501).json({
|
|
609
|
+
success: false,
|
|
610
|
+
data: null,
|
|
611
|
+
error: "Squash sync not yet implemented",
|
|
612
|
+
message: "The squashSync operation is not available yet",
|
|
613
|
+
});
|
|
614
|
+
return;
|
|
615
|
+
}
|
|
616
|
+
// Perform squash sync
|
|
617
|
+
const result = await syncService.squashSync(executionId, commitMessage);
|
|
618
|
+
res.json({
|
|
619
|
+
success: true,
|
|
620
|
+
data: result,
|
|
621
|
+
});
|
|
622
|
+
}
|
|
623
|
+
catch (error) {
|
|
624
|
+
console.error(`Failed to squash sync execution ${req.params.executionId}:`, error);
|
|
625
|
+
if (error instanceof WorktreeSyncError) {
|
|
626
|
+
const statusCode = getStatusCodeForSyncError(error);
|
|
627
|
+
res.status(statusCode).json({
|
|
628
|
+
success: false,
|
|
629
|
+
data: null,
|
|
630
|
+
error: error.message,
|
|
631
|
+
code: error.code,
|
|
632
|
+
});
|
|
633
|
+
}
|
|
634
|
+
else {
|
|
635
|
+
res.status(500).json({
|
|
636
|
+
success: false,
|
|
637
|
+
data: null,
|
|
638
|
+
error: "Internal server error",
|
|
639
|
+
message: error instanceof Error ? error.message : String(error),
|
|
640
|
+
});
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
});
|
|
644
|
+
/**
|
|
645
|
+
* POST /api/executions/:executionId/commit
|
|
646
|
+
*
|
|
647
|
+
* Commit uncommitted changes for an execution
|
|
648
|
+
*
|
|
649
|
+
* Commits changes to the appropriate branch based on execution mode:
|
|
650
|
+
* - Local mode: Commits to target_branch (current branch)
|
|
651
|
+
* - Worktree mode: Commits to branch_name (temp branch) in worktree
|
|
652
|
+
*
|
|
653
|
+
* Request body:
|
|
654
|
+
* - message: string (required) - Commit message
|
|
655
|
+
*/
|
|
656
|
+
router.post("/executions/:executionId/commit", async (req, res) => {
|
|
657
|
+
try {
|
|
658
|
+
const { executionId } = req.params;
|
|
659
|
+
const { message } = req.body;
|
|
660
|
+
// Validate commit message
|
|
661
|
+
if (!message || typeof message !== "string" || !message.trim()) {
|
|
662
|
+
res.status(400).json({
|
|
663
|
+
success: false,
|
|
664
|
+
data: null,
|
|
665
|
+
message: "Commit message is required and must be non-empty",
|
|
666
|
+
});
|
|
667
|
+
return;
|
|
668
|
+
}
|
|
669
|
+
const db = req.project.db;
|
|
670
|
+
const repoPath = req.project.path;
|
|
671
|
+
// Load execution from database
|
|
672
|
+
const execution = db
|
|
673
|
+
.prepare("SELECT * FROM executions WHERE id = ?")
|
|
674
|
+
.get(executionId);
|
|
675
|
+
if (!execution) {
|
|
676
|
+
res.status(404).json({
|
|
677
|
+
success: false,
|
|
678
|
+
data: null,
|
|
679
|
+
message: "Execution not found",
|
|
680
|
+
});
|
|
681
|
+
return;
|
|
682
|
+
}
|
|
683
|
+
// Parse files_changed
|
|
684
|
+
let filesChanged = [];
|
|
685
|
+
try {
|
|
686
|
+
if (execution.files_changed) {
|
|
687
|
+
const parsed = typeof execution.files_changed === "string"
|
|
688
|
+
? JSON.parse(execution.files_changed)
|
|
689
|
+
: execution.files_changed;
|
|
690
|
+
filesChanged = Array.isArray(parsed) ? parsed : [parsed];
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
catch (error) {
|
|
694
|
+
console.error("Failed to parse files_changed:", error);
|
|
695
|
+
}
|
|
696
|
+
// Validate has uncommitted changes
|
|
697
|
+
if (filesChanged.length === 0) {
|
|
698
|
+
res.status(400).json({
|
|
699
|
+
success: false,
|
|
700
|
+
data: null,
|
|
701
|
+
message: "No files to commit",
|
|
702
|
+
});
|
|
703
|
+
return;
|
|
704
|
+
}
|
|
705
|
+
// Determine working directory and target branch based on mode
|
|
706
|
+
const mode = execution.mode || "local";
|
|
707
|
+
const workingDir = mode === "worktree" && execution.worktree_path
|
|
708
|
+
? execution.worktree_path
|
|
709
|
+
: repoPath;
|
|
710
|
+
const targetBranch = mode === "worktree"
|
|
711
|
+
? execution.branch_name
|
|
712
|
+
: execution.target_branch || "main";
|
|
713
|
+
console.log(`[Commit] Execution ${executionId}: mode=${mode}, workingDir=${workingDir}, targetBranch=${targetBranch}`);
|
|
714
|
+
// Escape commit message for shell
|
|
715
|
+
const escapedMessage = message.replace(/"/g, '\\"');
|
|
716
|
+
// Execute git operations
|
|
717
|
+
try {
|
|
718
|
+
// Add files
|
|
719
|
+
const addCommand = `git add ${filesChanged.map((f) => `"${f}"`).join(" ")}`;
|
|
720
|
+
execSync(addCommand, {
|
|
721
|
+
cwd: workingDir,
|
|
722
|
+
encoding: "utf-8",
|
|
723
|
+
stdio: "pipe",
|
|
724
|
+
});
|
|
725
|
+
// Commit with message
|
|
726
|
+
const commitCommand = `git commit -m "${escapedMessage}"`;
|
|
727
|
+
execSync(commitCommand, {
|
|
728
|
+
cwd: workingDir,
|
|
729
|
+
encoding: "utf-8",
|
|
730
|
+
stdio: "pipe",
|
|
731
|
+
});
|
|
732
|
+
// Get commit SHA
|
|
733
|
+
const commitSha = execSync("git rev-parse HEAD", {
|
|
734
|
+
cwd: workingDir,
|
|
735
|
+
encoding: "utf-8",
|
|
736
|
+
stdio: "pipe",
|
|
737
|
+
}).trim();
|
|
738
|
+
console.log(`[Commit] Successfully committed ${filesChanged.length} files: ${commitSha}`);
|
|
739
|
+
// Note: We do NOT update execution.after_commit here
|
|
740
|
+
// That field represents the state at execution completion time
|
|
741
|
+
// Manual commits after execution are tracked separately
|
|
742
|
+
res.json({
|
|
743
|
+
success: true,
|
|
744
|
+
data: {
|
|
745
|
+
commitSha,
|
|
746
|
+
filesCommitted: filesChanged.length,
|
|
747
|
+
branch: targetBranch,
|
|
748
|
+
},
|
|
749
|
+
message: `Successfully committed ${filesChanged.length} file${filesChanged.length !== 1 ? "s" : ""}`,
|
|
750
|
+
});
|
|
751
|
+
}
|
|
752
|
+
catch (gitError) {
|
|
753
|
+
console.error("Git operation failed:", gitError);
|
|
754
|
+
const errorMessage = gitError instanceof Error ? gitError.message : String(gitError);
|
|
755
|
+
res.status(500).json({
|
|
756
|
+
success: false,
|
|
757
|
+
data: null,
|
|
758
|
+
message: "Git commit failed",
|
|
759
|
+
error: errorMessage,
|
|
760
|
+
});
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
catch (error) {
|
|
764
|
+
console.error(`Failed to commit for execution ${req.params.executionId}:`, error);
|
|
765
|
+
res.status(500).json({
|
|
766
|
+
success: false,
|
|
767
|
+
data: null,
|
|
768
|
+
error: "Internal server error",
|
|
769
|
+
message: error instanceof Error ? error.message : String(error),
|
|
770
|
+
});
|
|
771
|
+
}
|
|
772
|
+
});
|
|
321
773
|
return router;
|
|
322
774
|
}
|
|
323
775
|
//# sourceMappingURL=executions.js.map
|