Skip to content

Commit d36a44e

Browse files
authored
Cline Task Server (RooCodeInc#2773)
* added cline task server * moving test server into separate file * removed redundant test server in extension
1 parent cbcf89d commit d36a44e

File tree

3 files changed

+133
-6
lines changed

3 files changed

+133
-6
lines changed

.changeset/green-moose-walk.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"claude-dev": minor
3+
---
4+
5+
added cline server to take requests to make new tasks

src/extension.ts

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { DIFF_VIEW_URI_SCHEME } from "./integrations/editor/DiffViewProvider"
99
import assert from "node:assert"
1010
import { telemetryService } from "./services/telemetry/TelemetryService"
1111
import { WebviewProvider } from "./core/webview"
12+
import { createTestServer, shutdownTestServer } from "./services/test/TestServer"
1213

1314
/*
1415
Built using https://github.com/microsoft/vscode-webview-ui-toolkit
@@ -397,12 +398,6 @@ export function activate(context: vscode.ExtensionContext) {
397398
return createClineAPI(outputChannel, sidebarWebview.controller)
398399
}
399400

400-
// This method is called when your extension is deactivated
401-
export function deactivate() {
402-
telemetryService.shutdown()
403-
Logger.log("Cline extension deactivated")
404-
}
405-
406401
// TODO: Find a solution for automatically removing DEV related content from production builds.
407402
// This type of code is fine in production to keep. We just will want to remove it from production builds
408403
// to bring down built asset sizes.
@@ -411,6 +406,16 @@ export function deactivate() {
411406
// since vscode doesn't support hot reload for extensions
412407
const { IS_DEV, DEV_WORKSPACE_FOLDER, IS_TEST } = process.env
413408

409+
// This method is called when your extension is deactivated
410+
export function deactivate() {
411+
// Shutdown the test server if it exists
412+
shutdownTestServer()
413+
414+
telemetryService.shutdown()
415+
Logger.log("Cline extension deactivated")
416+
}
417+
418+
// Set up development mode file watcher
414419
if (IS_DEV && IS_DEV !== "false") {
415420
assert(DEV_WORKSPACE_FOLDER, "DEV_WORKSPACE_FOLDER must be set in development")
416421
const watcher = vscode.workspace.createFileSystemWatcher(new vscode.RelativePattern(DEV_WORKSPACE_FOLDER, "src/**/*"))
@@ -421,3 +426,8 @@ if (IS_DEV && IS_DEV !== "false") {
421426
vscode.commands.executeCommand("workbench.action.reloadWindow")
422427
})
423428
}
429+
430+
// Set up test server if in test mode
431+
if (IS_TEST && IS_TEST === "true") {
432+
createTestServer()
433+
}

src/services/test/TestServer.ts

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
import * as http from "http"
2+
import { Logger } from "../../services/logging/Logger"
3+
import { WebviewProvider } from "../../core/webview"
4+
5+
let testServer: http.Server | undefined
6+
7+
/**
8+
* Creates and starts an HTTP server for test automation
9+
* @returns The created HTTP server instance
10+
*/
11+
export function createTestServer(): http.Server {
12+
const PORT = 9876
13+
14+
testServer = http.createServer((req, res) => {
15+
// Set CORS headers
16+
res.setHeader("Access-Control-Allow-Origin", "*")
17+
res.setHeader("Access-Control-Allow-Methods", "POST, OPTIONS")
18+
res.setHeader("Access-Control-Allow-Headers", "Content-Type")
19+
20+
// Handle preflight requests
21+
if (req.method === "OPTIONS") {
22+
res.writeHead(204)
23+
res.end()
24+
return
25+
}
26+
27+
// Only handle POST requests to /task
28+
if (req.method !== "POST" || req.url !== "/task") {
29+
res.writeHead(404)
30+
res.end(JSON.stringify({ error: "Not found" }))
31+
return
32+
}
33+
34+
// Parse the request body
35+
let body = ""
36+
req.on("data", (chunk) => {
37+
body += chunk.toString()
38+
})
39+
40+
req.on("end", async () => {
41+
try {
42+
// Parse the JSON body
43+
const { task } = JSON.parse(body)
44+
45+
if (!task) {
46+
res.writeHead(400)
47+
res.end(JSON.stringify({ error: "Missing task parameter" }))
48+
return
49+
}
50+
51+
// Get a visible webview instance
52+
const visibleWebview = WebviewProvider.getVisibleInstance()
53+
if (!visibleWebview || !visibleWebview.controller) {
54+
res.writeHead(500)
55+
res.end(JSON.stringify({ error: "No active Cline instance found" }))
56+
return
57+
}
58+
59+
// Initiate a new task
60+
Logger.log(`Test server initiating task: ${task}`)
61+
62+
try {
63+
// Clear any existing task
64+
await visibleWebview.controller.clearTask()
65+
66+
// Ensure we're in Act mode before initiating the task
67+
const { chatSettings } = await visibleWebview.controller.getStateToPostToWebview()
68+
if (chatSettings.mode === "plan") {
69+
// Switch to Act mode if currently in Plan mode
70+
await visibleWebview.controller.togglePlanActModeWithChatSettings({ mode: "act" })
71+
}
72+
73+
// Initiate the new task
74+
const taskId = await visibleWebview.controller.initClineWithTask(task)
75+
76+
// Return success response with the task ID
77+
res.writeHead(200, { "Content-Type": "application/json" })
78+
res.end(JSON.stringify({ success: true, taskId }))
79+
} catch (error) {
80+
Logger.log(`Error initiating task: ${error}`)
81+
res.writeHead(500)
82+
res.end(JSON.stringify({ error: `Failed to initiate task: ${error}` }))
83+
}
84+
} catch (error) {
85+
res.writeHead(400)
86+
res.end(JSON.stringify({ error: `Invalid JSON: ${error}` }))
87+
}
88+
})
89+
})
90+
91+
testServer.listen(PORT, () => {
92+
Logger.log(`Test server listening on port ${PORT}`)
93+
})
94+
95+
// Handle server errors
96+
testServer.on("error", (error) => {
97+
Logger.log(`Test server error: ${error}`)
98+
})
99+
100+
return testServer
101+
}
102+
103+
/**
104+
* Shuts down the test server if it exists
105+
*/
106+
export function shutdownTestServer() {
107+
if (testServer) {
108+
testServer.close()
109+
Logger.log("Test server shut down")
110+
testServer = undefined
111+
}
112+
}

0 commit comments

Comments
 (0)