@rallycry/conveyor-agent 0.1.0

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.
@@ -0,0 +1,402 @@
1
+ // src/connection.ts
2
+ import { io } from "socket.io-client";
3
+ var ConveyorConnection = class {
4
+ socket = null;
5
+ config;
6
+ constructor(config) {
7
+ this.config = config;
8
+ }
9
+ async connect() {
10
+ return new Promise((resolve, reject) => {
11
+ this.socket = io(this.config.conveyorApiUrl, {
12
+ auth: { taskToken: this.config.taskToken },
13
+ transports: ["websocket"],
14
+ reconnection: true,
15
+ reconnectionAttempts: 10,
16
+ reconnectionDelay: 1e3
17
+ });
18
+ this.socket.on("connect", () => {
19
+ resolve();
20
+ });
21
+ this.socket.on("connect_error", (err) => {
22
+ reject(err);
23
+ });
24
+ });
25
+ }
26
+ async fetchTaskContext() {
27
+ const socket = this.socket;
28
+ if (!socket) throw new Error("Not connected");
29
+ return new Promise((resolve, reject) => {
30
+ socket.emit(
31
+ "agentRunner:getTaskContext",
32
+ { taskId: this.config.taskId },
33
+ (response) => {
34
+ if (response.success && response.data) {
35
+ resolve(response.data);
36
+ } else {
37
+ reject(new Error(response.error ?? "Failed to fetch task context"));
38
+ }
39
+ }
40
+ );
41
+ });
42
+ }
43
+ sendEvent(event) {
44
+ if (!this.socket) throw new Error("Not connected");
45
+ this.socket.emit("agentRunner:event", {
46
+ taskId: this.config.taskId,
47
+ event
48
+ });
49
+ }
50
+ updateStatus(status) {
51
+ if (!this.socket) throw new Error("Not connected");
52
+ this.socket.emit("agentRunner:statusUpdate", {
53
+ taskId: this.config.taskId,
54
+ status
55
+ });
56
+ }
57
+ postChatMessage(content) {
58
+ if (!this.socket) throw new Error("Not connected");
59
+ this.socket.emit("agentRunner:chatMessage", {
60
+ taskId: this.config.taskId,
61
+ content
62
+ });
63
+ }
64
+ onChatMessage(callback) {
65
+ this.socket?.on("agentRunner:incomingMessage", callback);
66
+ }
67
+ onStopRequested(callback) {
68
+ this.socket?.on("agentRunner:stop", callback);
69
+ }
70
+ disconnect() {
71
+ this.socket?.disconnect();
72
+ this.socket = null;
73
+ }
74
+ };
75
+
76
+ // src/runner.ts
77
+ import { query, tool, createSdkMcpServer } from "@anthropic-ai/claude-agent-sdk";
78
+ import { z } from "zod";
79
+ var AgentRunner = class {
80
+ config;
81
+ connection;
82
+ callbacks;
83
+ stopped = false;
84
+ inputResolver = null;
85
+ pendingMessages = [];
86
+ currentTurnToolCalls = [];
87
+ constructor(config, callbacks) {
88
+ this.config = config;
89
+ this.connection = new ConveyorConnection(config);
90
+ this.callbacks = callbacks;
91
+ }
92
+ async start() {
93
+ await this.callbacks.onStatusChange("connecting");
94
+ await this.connection.connect();
95
+ await this.callbacks.onStatusChange("fetching_context");
96
+ const context = await this.connection.fetchTaskContext();
97
+ this.connection.onStopRequested(() => {
98
+ this.stopped = true;
99
+ });
100
+ this.connection.onChatMessage((message) => {
101
+ this.injectHumanMessage(message.content);
102
+ });
103
+ await this.callbacks.onStatusChange("running");
104
+ this.connection.sendEvent({
105
+ type: "connected",
106
+ taskId: this.config.taskId
107
+ });
108
+ try {
109
+ await this.executeTask(context);
110
+ } catch (error) {
111
+ const message = error instanceof Error ? error.message : "Unknown error";
112
+ this.connection.sendEvent({ type: "error", message });
113
+ await this.callbacks.onEvent({ type: "error", message });
114
+ throw error;
115
+ } finally {
116
+ await this.callbacks.onStatusChange("finished");
117
+ this.connection.disconnect();
118
+ }
119
+ }
120
+ injectHumanMessage(content) {
121
+ const msg = {
122
+ type: "user",
123
+ session_id: "",
124
+ message: { role: "user", content },
125
+ parent_tool_use_id: null
126
+ };
127
+ if (this.inputResolver) {
128
+ const resolve = this.inputResolver;
129
+ this.inputResolver = null;
130
+ resolve(msg);
131
+ } else {
132
+ this.pendingMessages.push(msg);
133
+ }
134
+ }
135
+ async *createInputStream(initialPrompt) {
136
+ yield {
137
+ type: "user",
138
+ session_id: "",
139
+ message: { role: "user", content: initialPrompt },
140
+ parent_tool_use_id: null
141
+ };
142
+ while (!this.stopped) {
143
+ if (this.pendingMessages.length > 0) {
144
+ const next = this.pendingMessages.shift();
145
+ if (next) {
146
+ yield next;
147
+ }
148
+ continue;
149
+ }
150
+ await this.callbacks.onStatusChange("waiting_for_input");
151
+ const msg = await new Promise((resolve) => {
152
+ this.inputResolver = resolve;
153
+ const checkStopped = setInterval(() => {
154
+ if (this.stopped) {
155
+ clearInterval(checkStopped);
156
+ this.inputResolver = null;
157
+ resolve(null);
158
+ }
159
+ }, 1e3);
160
+ });
161
+ if (!msg) break;
162
+ await this.callbacks.onStatusChange("running");
163
+ yield msg;
164
+ }
165
+ }
166
+ buildInitialPrompt(context) {
167
+ const parts = [];
168
+ parts.push(`# Task: ${context.title}`);
169
+ if (context.description) {
170
+ parts.push(`
171
+ ## Description
172
+ ${context.description}`);
173
+ }
174
+ if (context.plan) {
175
+ parts.push(`
176
+ ## Plan
177
+ ${context.plan}`);
178
+ }
179
+ if (context.chatHistory.length > 0) {
180
+ const relevant = context.chatHistory.slice(-20);
181
+ parts.push(`
182
+ ## Recent Chat Context`);
183
+ for (const msg of relevant) {
184
+ const sender = msg.userName ?? msg.role;
185
+ parts.push(`[${sender}]: ${msg.content}`);
186
+ }
187
+ }
188
+ parts.push(
189
+ `
190
+ ## Instructions`,
191
+ `Execute the task plan above. Work on the git branch "${context.githubBranch}".`,
192
+ `When finished, commit your changes, push the branch, and create a pull request.`
193
+ );
194
+ return parts.join("\n");
195
+ }
196
+ buildSystemPrompt(context) {
197
+ const parts = [
198
+ `You are an AI agent working on a task for the "${context.title}" project.`,
199
+ `You are running inside a GitHub Codespace with full access to the repository.`
200
+ ];
201
+ if (this.config.instructions) {
202
+ parts.push(`
203
+ Agent Instructions:
204
+ ${this.config.instructions}`);
205
+ }
206
+ parts.push(
207
+ `
208
+ You have access to Conveyor MCP tools to interact with the task management system.`,
209
+ `Use the post_to_chat tool to communicate progress or ask questions.`,
210
+ `Use the read_task_chat tool to check for new messages from the team.`
211
+ );
212
+ return parts.join("\n");
213
+ }
214
+ // eslint-disable-next-line @typescript-eslint/explicit-function-return-type
215
+ createConveyorMcpServer() {
216
+ const connection = this.connection;
217
+ const config = this.config;
218
+ const textResult = (text) => ({
219
+ content: [{ type: "text", text }]
220
+ });
221
+ return createSdkMcpServer({
222
+ name: "conveyor",
223
+ tools: [
224
+ tool(
225
+ "read_task_chat",
226
+ "Read recent messages from the task chat to see team feedback or instructions",
227
+ { limit: z.number().optional().describe("Number of recent messages to fetch (default 20)") },
228
+ (_args) => {
229
+ return Promise.resolve(textResult(
230
+ JSON.stringify({ note: "Chat history was provided in the initial context. Use post_to_chat to ask the team questions." })
231
+ ));
232
+ },
233
+ { annotations: { readOnly: true } }
234
+ ),
235
+ tool(
236
+ "post_to_chat",
237
+ "Post a message to the task chat visible to all team members",
238
+ { message: z.string().describe("The message to post to the team") },
239
+ ({ message }) => {
240
+ connection.postChatMessage(message);
241
+ return Promise.resolve(textResult("Message posted to task chat."));
242
+ }
243
+ ),
244
+ tool(
245
+ "update_task_status",
246
+ "Update the task status on the Kanban board",
247
+ {
248
+ status: z.enum(["InProgress", "ReviewPR", "Complete"]).describe("The new status for the task")
249
+ },
250
+ ({ status }) => {
251
+ connection.updateStatus(status);
252
+ return Promise.resolve(textResult(`Task status updated to ${status}.`));
253
+ }
254
+ ),
255
+ tool(
256
+ "report_pr_created",
257
+ "Report that a pull request has been created for this task",
258
+ {
259
+ url: z.string().describe("The URL of the pull request"),
260
+ number: z.number().describe("The PR number")
261
+ },
262
+ ({ url, number }) => {
263
+ connection.sendEvent({ type: "pr_created", url, number });
264
+ return Promise.resolve(textResult(`PR #${number} reported to Conveyor.`));
265
+ }
266
+ ),
267
+ tool(
268
+ "get_task_plan",
269
+ "Re-read the latest task plan in case it was updated",
270
+ {},
271
+ async () => {
272
+ try {
273
+ const context = await connection.fetchTaskContext();
274
+ return textResult(context.plan ?? "No plan available.");
275
+ } catch {
276
+ return textResult(`Task ID: ${config.taskId} - could not fetch updated plan.`);
277
+ }
278
+ },
279
+ { annotations: { readOnly: true } }
280
+ )
281
+ ]
282
+ });
283
+ }
284
+ async processEvents(events) {
285
+ const startTime = Date.now();
286
+ let totalCostUsd = 0;
287
+ for await (const event of events) {
288
+ if (this.stopped) break;
289
+ switch (event.type) {
290
+ case "assistant": {
291
+ const msg = event.message;
292
+ const content = msg.content;
293
+ for (const block of content) {
294
+ const blockType = block.type;
295
+ if (blockType === "text") {
296
+ const text = block.text;
297
+ this.connection.sendEvent({ type: "message", content: text });
298
+ this.connection.postChatMessage(text);
299
+ await this.callbacks.onEvent({ type: "message", content: text });
300
+ } else if (blockType === "tool_use") {
301
+ const name = block.name;
302
+ const inputStr = typeof block.input === "string" ? block.input : JSON.stringify(block.input);
303
+ const summary = {
304
+ tool: name,
305
+ input: inputStr.slice(0, 500),
306
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
307
+ };
308
+ this.currentTurnToolCalls.push(summary);
309
+ this.connection.sendEvent({
310
+ type: "tool_use",
311
+ tool: name,
312
+ input: inputStr
313
+ });
314
+ await this.callbacks.onEvent({
315
+ type: "tool_use",
316
+ tool: name,
317
+ input: inputStr
318
+ });
319
+ }
320
+ }
321
+ if (this.currentTurnToolCalls.length > 0) {
322
+ this.connection.sendEvent({
323
+ type: "turn_end",
324
+ toolCalls: [...this.currentTurnToolCalls]
325
+ });
326
+ this.currentTurnToolCalls = [];
327
+ }
328
+ break;
329
+ }
330
+ case "result": {
331
+ const resultEvent = event;
332
+ if (resultEvent.subtype === "success") {
333
+ totalCostUsd = "total_cost_usd" in resultEvent ? resultEvent.total_cost_usd : 0;
334
+ const durationMs = Date.now() - startTime;
335
+ const summary = "result" in resultEvent ? String(resultEvent.result) : "Task completed.";
336
+ this.connection.sendEvent({
337
+ type: "completed",
338
+ summary,
339
+ costUsd: totalCostUsd,
340
+ durationMs
341
+ });
342
+ await this.callbacks.onEvent({
343
+ type: "completed",
344
+ summary,
345
+ costUsd: totalCostUsd,
346
+ durationMs
347
+ });
348
+ } else {
349
+ const errors = "errors" in resultEvent ? resultEvent.errors : [];
350
+ const errorMsg = errors.length > 0 ? errors.join(", ") : `Agent stopped: ${resultEvent.subtype}`;
351
+ this.connection.sendEvent({ type: "error", message: errorMsg });
352
+ await this.callbacks.onEvent({ type: "error", message: errorMsg });
353
+ }
354
+ break;
355
+ }
356
+ case "system": {
357
+ if (event.subtype === "init") {
358
+ await this.callbacks.onEvent({
359
+ type: "thinking",
360
+ message: `Agent initialized (model: ${event.model})`
361
+ });
362
+ }
363
+ break;
364
+ }
365
+ }
366
+ }
367
+ }
368
+ async executeTask(context) {
369
+ if (this.stopped) return;
370
+ const initialPrompt = this.buildInitialPrompt(context);
371
+ const systemPrompt = this.buildSystemPrompt(context);
372
+ const conveyorMcp = this.createConveyorMcpServer();
373
+ const inputStream = this.createInputStream(initialPrompt);
374
+ const agentQuery = query({
375
+ prompt: inputStream,
376
+ options: {
377
+ model: this.config.model,
378
+ systemPrompt,
379
+ cwd: this.config.workspaceDir,
380
+ permissionMode: "bypassPermissions",
381
+ allowDangerouslySkipPermissions: true,
382
+ tools: { type: "preset", preset: "claude_code" },
383
+ mcpServers: { conveyor: conveyorMcp },
384
+ maxTurns: 100
385
+ }
386
+ });
387
+ await this.processEvents(agentQuery);
388
+ }
389
+ stop() {
390
+ this.stopped = true;
391
+ if (this.inputResolver) {
392
+ this.inputResolver(null);
393
+ this.inputResolver = null;
394
+ }
395
+ }
396
+ };
397
+
398
+ export {
399
+ ConveyorConnection,
400
+ AgentRunner
401
+ };
402
+ //# sourceMappingURL=chunk-LTQXNGLW.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/connection.ts","../src/runner.ts"],"sourcesContent":["import { io, type Socket } from \"socket.io-client\";\nimport type { AgentRunnerConfig, TaskContext, AgentEvent } from \"./types.js\";\n\nexport class ConveyorConnection {\n private socket: Socket | null = null;\n private config: AgentRunnerConfig;\n\n constructor(config: AgentRunnerConfig) {\n this.config = config;\n }\n\n async connect(): Promise<void> {\n return new Promise((resolve, reject) => {\n this.socket = io(this.config.conveyorApiUrl, {\n auth: { taskToken: this.config.taskToken },\n transports: [\"websocket\"],\n reconnection: true,\n reconnectionAttempts: 10,\n reconnectionDelay: 1000,\n });\n\n this.socket.on(\"connect\", () => {\n resolve();\n });\n this.socket.on(\"connect_error\", (err: Error) => {\n reject(err);\n });\n });\n }\n\n async fetchTaskContext(): Promise<TaskContext> {\n const socket = this.socket;\n if (!socket) throw new Error(\"Not connected\");\n\n return new Promise((resolve, reject) => {\n socket.emit(\n \"agentRunner:getTaskContext\",\n { taskId: this.config.taskId },\n (response: { success: boolean; data?: TaskContext; error?: string }): void => {\n if (response.success && response.data) {\n resolve(response.data);\n } else {\n reject(new Error(response.error ?? \"Failed to fetch task context\"));\n }\n }\n );\n });\n }\n\n sendEvent(event: AgentEvent): void {\n if (!this.socket) throw new Error(\"Not connected\");\n\n this.socket.emit(\"agentRunner:event\", {\n taskId: this.config.taskId,\n event,\n });\n }\n\n updateStatus(status: string): void {\n if (!this.socket) throw new Error(\"Not connected\");\n\n this.socket.emit(\"agentRunner:statusUpdate\", {\n taskId: this.config.taskId,\n status,\n });\n }\n\n postChatMessage(content: string): void {\n if (!this.socket) throw new Error(\"Not connected\");\n\n this.socket.emit(\"agentRunner:chatMessage\", {\n taskId: this.config.taskId,\n content,\n });\n }\n\n onChatMessage(callback: (message: { content: string; userId: string }) => void): void {\n this.socket?.on(\"agentRunner:incomingMessage\", callback);\n }\n\n onStopRequested(callback: () => void): void {\n this.socket?.on(\"agentRunner:stop\", callback);\n }\n\n disconnect(): void {\n this.socket?.disconnect();\n this.socket = null;\n }\n}\n","import { query, tool, createSdkMcpServer, type SDKMessage, type SDKUserMessage } from \"@anthropic-ai/claude-agent-sdk\";\nimport { z } from \"zod\";\nimport type {\n AgentRunnerConfig,\n AgentRunnerCallbacks,\n TaskContext,\n ActivityEventSummary,\n} from \"./types.js\";\nimport { ConveyorConnection } from \"./connection.js\";\n\nexport class AgentRunner {\n private config: AgentRunnerConfig;\n private connection: ConveyorConnection;\n private callbacks: AgentRunnerCallbacks;\n private stopped = false;\n private inputResolver: ((msg: SDKUserMessage) => void) | null = null;\n private pendingMessages: SDKUserMessage[] = [];\n private currentTurnToolCalls: ActivityEventSummary[] = [];\n\n constructor(config: AgentRunnerConfig, callbacks: AgentRunnerCallbacks) {\n this.config = config;\n this.connection = new ConveyorConnection(config);\n this.callbacks = callbacks;\n }\n\n async start(): Promise<void> {\n await this.callbacks.onStatusChange(\"connecting\");\n await this.connection.connect();\n\n await this.callbacks.onStatusChange(\"fetching_context\");\n const context = await this.connection.fetchTaskContext();\n\n this.connection.onStopRequested(() => {\n this.stopped = true;\n });\n\n this.connection.onChatMessage((message) => {\n this.injectHumanMessage(message.content);\n });\n\n await this.callbacks.onStatusChange(\"running\");\n this.connection.sendEvent({\n type: \"connected\",\n taskId: this.config.taskId,\n });\n\n try {\n await this.executeTask(context);\n } catch (error) {\n const message = error instanceof Error ? error.message : \"Unknown error\";\n this.connection.sendEvent({ type: \"error\", message });\n await this.callbacks.onEvent({ type: \"error\", message });\n throw error;\n } finally {\n await this.callbacks.onStatusChange(\"finished\");\n this.connection.disconnect();\n }\n }\n\n private injectHumanMessage(content: string): void {\n const msg: SDKUserMessage = {\n type: \"user\" as const,\n session_id: \"\",\n message: { role: \"user\" as const, content },\n parent_tool_use_id: null,\n };\n\n if (this.inputResolver) {\n const resolve = this.inputResolver;\n this.inputResolver = null;\n resolve(msg);\n } else {\n this.pendingMessages.push(msg);\n }\n }\n\n private async *createInputStream(\n initialPrompt: string\n ): AsyncGenerator<SDKUserMessage, void, unknown> {\n yield {\n type: \"user\" as const,\n session_id: \"\",\n message: { role: \"user\" as const, content: initialPrompt },\n parent_tool_use_id: null,\n };\n\n while (!this.stopped) {\n if (this.pendingMessages.length > 0) {\n const next = this.pendingMessages.shift();\n if (next) { yield next; }\n continue;\n }\n\n await this.callbacks.onStatusChange(\"waiting_for_input\");\n const msg = await new Promise<SDKUserMessage | null>((resolve) => {\n this.inputResolver = resolve as (msg: SDKUserMessage) => void;\n\n const checkStopped = setInterval(() => {\n if (this.stopped) {\n clearInterval(checkStopped);\n this.inputResolver = null;\n resolve(null);\n }\n }, 1000);\n });\n\n if (!msg) break;\n await this.callbacks.onStatusChange(\"running\");\n yield msg;\n }\n }\n\n private buildInitialPrompt(context: TaskContext): string {\n const parts: string[] = [];\n\n parts.push(`# Task: ${context.title}`);\n if (context.description) {\n parts.push(`\\n## Description\\n${context.description}`);\n }\n if (context.plan) {\n parts.push(`\\n## Plan\\n${context.plan}`);\n }\n if (context.chatHistory.length > 0) {\n const relevant = context.chatHistory.slice(-20);\n parts.push(`\\n## Recent Chat Context`);\n for (const msg of relevant) {\n const sender = msg.userName ?? msg.role;\n parts.push(`[${sender}]: ${msg.content}`);\n }\n }\n parts.push(\n `\\n## Instructions`,\n `Execute the task plan above. Work on the git branch \"${context.githubBranch}\".`,\n `When finished, commit your changes, push the branch, and create a pull request.`\n );\n\n return parts.join(\"\\n\");\n }\n\n private buildSystemPrompt(context: TaskContext): string {\n const parts = [\n `You are an AI agent working on a task for the \"${context.title}\" project.`,\n `You are running inside a GitHub Codespace with full access to the repository.`,\n ];\n if (this.config.instructions) {\n parts.push(`\\nAgent Instructions:\\n${this.config.instructions}`);\n }\n parts.push(\n `\\nYou have access to Conveyor MCP tools to interact with the task management system.`,\n `Use the post_to_chat tool to communicate progress or ask questions.`,\n `Use the read_task_chat tool to check for new messages from the team.`\n );\n return parts.join(\"\\n\");\n }\n\n // eslint-disable-next-line @typescript-eslint/explicit-function-return-type\n private createConveyorMcpServer() {\n const connection = this.connection;\n const config = this.config;\n\n const textResult = (text: string): { content: { type: \"text\"; text: string }[] } => ({\n content: [{ type: \"text\" as const, text }],\n });\n\n return createSdkMcpServer({\n name: \"conveyor\",\n tools: [\n tool(\n \"read_task_chat\",\n \"Read recent messages from the task chat to see team feedback or instructions\",\n { limit: z.number().optional().describe(\"Number of recent messages to fetch (default 20)\") },\n (_args) => {\n return Promise.resolve(textResult(\n JSON.stringify({ note: \"Chat history was provided in the initial context. Use post_to_chat to ask the team questions.\" })\n ));\n },\n { annotations: { readOnly: true } }\n ),\n tool(\n \"post_to_chat\",\n \"Post a message to the task chat visible to all team members\",\n { message: z.string().describe(\"The message to post to the team\") },\n ({ message }) => {\n connection.postChatMessage(message);\n return Promise.resolve(textResult(\"Message posted to task chat.\"));\n }\n ),\n tool(\n \"update_task_status\",\n \"Update the task status on the Kanban board\",\n {\n status: z\n .enum([\"InProgress\", \"ReviewPR\", \"Complete\"])\n .describe(\"The new status for the task\"),\n },\n ({ status }) => {\n connection.updateStatus(status);\n return Promise.resolve(textResult(`Task status updated to ${status}.`));\n }\n ),\n tool(\n \"report_pr_created\",\n \"Report that a pull request has been created for this task\",\n {\n url: z.string().describe(\"The URL of the pull request\"),\n number: z.number().describe(\"The PR number\"),\n },\n ({ url, number }) => {\n connection.sendEvent({ type: \"pr_created\", url, number });\n return Promise.resolve(textResult(`PR #${number} reported to Conveyor.`));\n }\n ),\n tool(\n \"get_task_plan\",\n \"Re-read the latest task plan in case it was updated\",\n {},\n async () => {\n try {\n const context = await connection.fetchTaskContext();\n return textResult(context.plan ?? \"No plan available.\");\n } catch {\n return textResult(`Task ID: ${config.taskId} - could not fetch updated plan.`);\n }\n },\n { annotations: { readOnly: true } }\n ),\n ],\n });\n }\n\n private async processEvents(events: AsyncGenerator<SDKMessage, void>): Promise<void> {\n const startTime = Date.now();\n let totalCostUsd = 0;\n\n for await (const event of events) {\n if (this.stopped) break;\n\n switch (event.type) {\n case \"assistant\": {\n const msg = event.message as unknown as Record<string, unknown>;\n const content = msg.content as Record<string, unknown>[];\n for (const block of content) {\n const blockType = block.type as string;\n if (blockType === \"text\") {\n const text = block.text as string;\n this.connection.sendEvent({ type: \"message\", content: text });\n this.connection.postChatMessage(text);\n await this.callbacks.onEvent({ type: \"message\", content: text });\n } else if (blockType === \"tool_use\") {\n const name = block.name as string;\n const inputStr =\n typeof block.input === \"string\"\n ? block.input\n : JSON.stringify(block.input);\n const summary: ActivityEventSummary = {\n tool: name,\n input: inputStr.slice(0, 500),\n timestamp: new Date().toISOString(),\n };\n this.currentTurnToolCalls.push(summary);\n this.connection.sendEvent({\n type: \"tool_use\",\n tool: name,\n input: inputStr,\n });\n await this.callbacks.onEvent({\n type: \"tool_use\",\n tool: name,\n input: inputStr,\n });\n }\n }\n\n if (this.currentTurnToolCalls.length > 0) {\n this.connection.sendEvent({\n type: \"turn_end\",\n toolCalls: [...this.currentTurnToolCalls],\n });\n this.currentTurnToolCalls = [];\n }\n break;\n }\n\n case \"result\": {\n const resultEvent = event as SDKMessage & { type: \"result\"; subtype: string };\n if (resultEvent.subtype === \"success\") {\n totalCostUsd = \"total_cost_usd\" in resultEvent ? (resultEvent as Record<string, unknown>).total_cost_usd as number : 0;\n const durationMs = Date.now() - startTime;\n const summary = \"result\" in resultEvent ? String((resultEvent as Record<string, unknown>).result) : \"Task completed.\";\n\n this.connection.sendEvent({\n type: \"completed\",\n summary,\n costUsd: totalCostUsd,\n durationMs,\n });\n\n await this.callbacks.onEvent({\n type: \"completed\",\n summary,\n costUsd: totalCostUsd,\n durationMs,\n });\n } else {\n const errors = \"errors\" in resultEvent ? (resultEvent as Record<string, unknown>).errors as string[] : [];\n const errorMsg = errors.length > 0 ? errors.join(\", \") : `Agent stopped: ${resultEvent.subtype}`;\n this.connection.sendEvent({ type: \"error\", message: errorMsg });\n await this.callbacks.onEvent({ type: \"error\", message: errorMsg });\n }\n break;\n }\n\n case \"system\": {\n if (event.subtype === \"init\") {\n await this.callbacks.onEvent({\n type: \"thinking\",\n message: `Agent initialized (model: ${event.model})`,\n });\n }\n break;\n }\n }\n }\n }\n\n private async executeTask(context: TaskContext): Promise<void> {\n if (this.stopped) return;\n\n const initialPrompt = this.buildInitialPrompt(context);\n const systemPrompt = this.buildSystemPrompt(context);\n const conveyorMcp = this.createConveyorMcpServer();\n const inputStream = this.createInputStream(initialPrompt);\n\n const agentQuery = query({\n prompt: inputStream,\n options: {\n model: this.config.model,\n systemPrompt,\n cwd: this.config.workspaceDir,\n permissionMode: \"bypassPermissions\",\n allowDangerouslySkipPermissions: true,\n tools: { type: \"preset\", preset: \"claude_code\" },\n mcpServers: { conveyor: conveyorMcp },\n maxTurns: 100,\n },\n });\n\n await this.processEvents(agentQuery);\n }\n\n stop(): void {\n this.stopped = true;\n if (this.inputResolver) {\n this.inputResolver(null as unknown as SDKUserMessage);\n this.inputResolver = null;\n }\n }\n}\n"],"mappings":"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","names":[]}
package/dist/cli.d.ts ADDED
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node
package/dist/cli.js ADDED
@@ -0,0 +1,51 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ AgentRunner
4
+ } from "./chunk-LTQXNGLW.js";
5
+
6
+ // src/cli.ts
7
+ var CONVEYOR_API_URL = process.env.CONVEYOR_API_URL;
8
+ var CONVEYOR_TASK_TOKEN = process.env.CONVEYOR_TASK_TOKEN;
9
+ var CONVEYOR_TASK_ID = process.env.CONVEYOR_TASK_ID;
10
+ var CONVEYOR_MODEL = process.env.CONVEYOR_MODEL ?? "claude-sonnet-4-20250514";
11
+ var CONVEYOR_INSTRUCTIONS = process.env.CONVEYOR_INSTRUCTIONS ?? "";
12
+ var CONVEYOR_WORKSPACE = process.env.CONVEYOR_WORKSPACE ?? process.cwd();
13
+ if (!CONVEYOR_API_URL || !CONVEYOR_TASK_TOKEN || !CONVEYOR_TASK_ID) {
14
+ console.error("Missing required environment variables:");
15
+ console.error(" CONVEYOR_API_URL - URL of the Conveyor API server");
16
+ console.error(" CONVEYOR_TASK_TOKEN - JWT token for task authentication");
17
+ console.error(" CONVEYOR_TASK_ID - ID of the task to execute");
18
+ process.exit(1);
19
+ }
20
+ var runner = new AgentRunner(
21
+ {
22
+ conveyorApiUrl: CONVEYOR_API_URL,
23
+ taskToken: CONVEYOR_TASK_TOKEN,
24
+ taskId: CONVEYOR_TASK_ID,
25
+ model: CONVEYOR_MODEL,
26
+ instructions: CONVEYOR_INSTRUCTIONS,
27
+ workspaceDir: CONVEYOR_WORKSPACE
28
+ },
29
+ {
30
+ onEvent: (event) => {
31
+ const detail = "message" in event ? event.message : "content" in event ? event.content : "summary" in event ? event.summary : "";
32
+ console.log(`[${event.type}] ${detail}`);
33
+ },
34
+ onStatusChange: (status) => {
35
+ console.log(`[status] ${status}`);
36
+ }
37
+ }
38
+ );
39
+ process.on("SIGTERM", () => {
40
+ console.log("Received SIGTERM, stopping agent...");
41
+ runner.stop();
42
+ });
43
+ process.on("SIGINT", () => {
44
+ console.log("Received SIGINT, stopping agent...");
45
+ runner.stop();
46
+ });
47
+ runner.start().catch((error) => {
48
+ console.error("Agent runner failed:", error);
49
+ process.exit(1);
50
+ });
51
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\n/* eslint-disable no-console */\n\nimport { AgentRunner } from \"./runner.js\";\nimport type { AgentEvent, AgentRunnerStatus } from \"./types.js\";\n\nconst CONVEYOR_API_URL = process.env.CONVEYOR_API_URL;\nconst CONVEYOR_TASK_TOKEN = process.env.CONVEYOR_TASK_TOKEN;\nconst CONVEYOR_TASK_ID = process.env.CONVEYOR_TASK_ID;\nconst CONVEYOR_MODEL = process.env.CONVEYOR_MODEL ?? \"claude-sonnet-4-20250514\";\nconst CONVEYOR_INSTRUCTIONS = process.env.CONVEYOR_INSTRUCTIONS ?? \"\";\nconst CONVEYOR_WORKSPACE = process.env.CONVEYOR_WORKSPACE ?? process.cwd();\n\nif (!CONVEYOR_API_URL || !CONVEYOR_TASK_TOKEN || !CONVEYOR_TASK_ID) {\n console.error(\"Missing required environment variables:\");\n console.error(\" CONVEYOR_API_URL - URL of the Conveyor API server\");\n console.error(\" CONVEYOR_TASK_TOKEN - JWT token for task authentication\");\n console.error(\" CONVEYOR_TASK_ID - ID of the task to execute\");\n process.exit(1);\n}\n\nconst runner = new AgentRunner(\n {\n conveyorApiUrl: CONVEYOR_API_URL,\n taskToken: CONVEYOR_TASK_TOKEN,\n taskId: CONVEYOR_TASK_ID,\n model: CONVEYOR_MODEL,\n instructions: CONVEYOR_INSTRUCTIONS,\n workspaceDir: CONVEYOR_WORKSPACE,\n },\n {\n onEvent: (event: AgentEvent) => {\n const detail =\n \"message\" in event\n ? event.message\n : \"content\" in event\n ? event.content\n : \"summary\" in event\n ? event.summary\n : \"\";\n console.log(`[${event.type}] ${detail}`);\n },\n onStatusChange: (status: AgentRunnerStatus) => {\n console.log(`[status] ${status}`);\n },\n }\n);\n\nprocess.on(\"SIGTERM\", () => {\n console.log(\"Received SIGTERM, stopping agent...\");\n runner.stop();\n});\n\nprocess.on(\"SIGINT\", () => {\n console.log(\"Received SIGINT, stopping agent...\");\n runner.stop();\n});\n\nrunner.start().catch((error: unknown) => {\n console.error(\"Agent runner failed:\", error);\n process.exit(1);\n});\n"],"mappings":";;;;;;AAMA,IAAM,mBAAmB,QAAQ,IAAI;AACrC,IAAM,sBAAsB,QAAQ,IAAI;AACxC,IAAM,mBAAmB,QAAQ,IAAI;AACrC,IAAM,iBAAiB,QAAQ,IAAI,kBAAkB;AACrD,IAAM,wBAAwB,QAAQ,IAAI,yBAAyB;AACnE,IAAM,qBAAqB,QAAQ,IAAI,sBAAsB,QAAQ,IAAI;AAEzE,IAAI,CAAC,oBAAoB,CAAC,uBAAuB,CAAC,kBAAkB;AAClE,UAAQ,MAAM,yCAAyC;AACvD,UAAQ,MAAM,qDAAqD;AACnE,UAAQ,MAAM,2DAA2D;AACzE,UAAQ,MAAM,gDAAgD;AAC9D,UAAQ,KAAK,CAAC;AAChB;AAEA,IAAM,SAAS,IAAI;AAAA,EACjB;AAAA,IACE,gBAAgB;AAAA,IAChB,WAAW;AAAA,IACX,QAAQ;AAAA,IACR,OAAO;AAAA,IACP,cAAc;AAAA,IACd,cAAc;AAAA,EAChB;AAAA,EACA;AAAA,IACE,SAAS,CAAC,UAAsB;AAC9B,YAAM,SACJ,aAAa,QACT,MAAM,UACN,aAAa,QACX,MAAM,UACN,aAAa,QACX,MAAM,UACN;AACV,cAAQ,IAAI,IAAI,MAAM,IAAI,KAAK,MAAM,EAAE;AAAA,IACzC;AAAA,IACA,gBAAgB,CAAC,WAA8B;AAC7C,cAAQ,IAAI,YAAY,MAAM,EAAE;AAAA,IAClC;AAAA,EACF;AACF;AAEA,QAAQ,GAAG,WAAW,MAAM;AAC1B,UAAQ,IAAI,qCAAqC;AACjD,SAAO,KAAK;AACd,CAAC;AAED,QAAQ,GAAG,UAAU,MAAM;AACzB,UAAQ,IAAI,oCAAoC;AAChD,SAAO,KAAK;AACd,CAAC;AAED,OAAO,MAAM,EAAE,MAAM,CAAC,UAAmB;AACvC,UAAQ,MAAM,wBAAwB,KAAK;AAC3C,UAAQ,KAAK,CAAC;AAChB,CAAC;","names":[]}
@@ -0,0 +1,112 @@
1
+ interface AgentRunnerConfig {
2
+ conveyorApiUrl: string;
3
+ taskToken: string;
4
+ taskId: string;
5
+ model: string;
6
+ instructions: string;
7
+ workspaceDir: string;
8
+ }
9
+ interface TaskContext {
10
+ taskId: string;
11
+ projectId: string;
12
+ title: string;
13
+ description: string | null;
14
+ plan: string | null;
15
+ chatHistory: ChatMessage[];
16
+ agentInstructions: string;
17
+ model: string;
18
+ githubBranch: string;
19
+ }
20
+ interface ChatMessage {
21
+ role: "user" | "assistant" | "system";
22
+ content: string;
23
+ userId?: string;
24
+ userName?: string;
25
+ createdAt: string;
26
+ }
27
+ type AgentEvent = {
28
+ type: "connected";
29
+ taskId: string;
30
+ } | {
31
+ type: "thinking";
32
+ message: string;
33
+ } | {
34
+ type: "tool_use";
35
+ tool: string;
36
+ input: string;
37
+ } | {
38
+ type: "tool_result";
39
+ tool: string;
40
+ output: string;
41
+ isError?: boolean;
42
+ } | {
43
+ type: "message";
44
+ content: string;
45
+ } | {
46
+ type: "error";
47
+ message: string;
48
+ } | {
49
+ type: "completed";
50
+ summary: string;
51
+ costUsd?: number;
52
+ durationMs?: number;
53
+ } | {
54
+ type: "pr_created";
55
+ url: string;
56
+ number: number;
57
+ } | {
58
+ type: "turn_start";
59
+ } | {
60
+ type: "turn_end";
61
+ toolCalls: ActivityEventSummary[];
62
+ };
63
+ interface ActivityEventSummary {
64
+ tool: string;
65
+ input?: string;
66
+ output?: string;
67
+ timestamp: string;
68
+ }
69
+ type AgentRunnerStatus = "connecting" | "fetching_context" | "running" | "waiting_for_input" | "stopping" | "finished" | "error";
70
+ interface AgentRunnerCallbacks {
71
+ onEvent: (event: AgentEvent) => void | Promise<void>;
72
+ onStatusChange: (status: AgentRunnerStatus) => void | Promise<void>;
73
+ }
74
+
75
+ declare class AgentRunner {
76
+ private config;
77
+ private connection;
78
+ private callbacks;
79
+ private stopped;
80
+ private inputResolver;
81
+ private pendingMessages;
82
+ private currentTurnToolCalls;
83
+ constructor(config: AgentRunnerConfig, callbacks: AgentRunnerCallbacks);
84
+ start(): Promise<void>;
85
+ private injectHumanMessage;
86
+ private createInputStream;
87
+ private buildInitialPrompt;
88
+ private buildSystemPrompt;
89
+ private createConveyorMcpServer;
90
+ private processEvents;
91
+ private executeTask;
92
+ stop(): void;
93
+ }
94
+
95
+ declare class ConveyorConnection {
96
+ private socket;
97
+ private config;
98
+ constructor(config: AgentRunnerConfig);
99
+ connect(): Promise<void>;
100
+ fetchTaskContext(): Promise<TaskContext>;
101
+ sendEvent(event: AgentEvent): void;
102
+ updateStatus(status: string): void;
103
+ postChatMessage(content: string): void;
104
+ onChatMessage(callback: (message: {
105
+ content: string;
106
+ userId: string;
107
+ }) => void): void;
108
+ onStopRequested(callback: () => void): void;
109
+ disconnect(): void;
110
+ }
111
+
112
+ export { type AgentEvent, AgentRunner, type AgentRunnerCallbacks, type AgentRunnerConfig, type ChatMessage, ConveyorConnection, type TaskContext };
package/dist/index.js ADDED
@@ -0,0 +1,9 @@
1
+ import {
2
+ AgentRunner,
3
+ ConveyorConnection
4
+ } from "./chunk-LTQXNGLW.js";
5
+ export {
6
+ AgentRunner,
7
+ ConveyorConnection
8
+ };
9
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
package/package.json ADDED
@@ -0,0 +1,39 @@
1
+ {
2
+ "name": "@rallycry/conveyor-agent",
3
+ "version": "0.1.0",
4
+ "description": "Conveyor cloud build agent runner - executes task plans inside GitHub Codespaces",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "bin": {
9
+ "conveyor-agent": "./dist/cli.js"
10
+ },
11
+ "files": [
12
+ "dist"
13
+ ],
14
+ "publishConfig": {
15
+ "access": "public"
16
+ },
17
+ "scripts": {
18
+ "build": "tsup",
19
+ "dev": "tsup --watch",
20
+ "lint": "eslint src",
21
+ "lint:fix": "eslint src --fix",
22
+ "typecheck": "tsc --noEmit",
23
+ "prepublishOnly": "pnpm build"
24
+ },
25
+ "keywords": ["conveyor", "agent", "codespace", "claude"],
26
+ "license": "MIT",
27
+ "dependencies": {
28
+ "@anthropic-ai/claude-agent-sdk": "^0.2.71",
29
+ "socket.io-client": "^4.7.4",
30
+ "winston": "^3.11.0",
31
+ "zod": "^3.25.76"
32
+ },
33
+ "devDependencies": {
34
+ "@project/eslint-config": "workspace:*",
35
+ "eslint": "^9.0.0",
36
+ "tsup": "^8.0.0",
37
+ "typescript": "^5.3.0"
38
+ }
39
+ }