@rallycry/conveyor-agent 5.11.0 → 5.12.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.
- package/dist/{chunk-LBEAK2VJ.js → chunk-SQJJL2PU.js} +347 -70
- package/dist/chunk-SQJJL2PU.js.map +1 -0
- package/dist/cli.js +1 -1
- package/dist/index.d.ts +37 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-LBEAK2VJ.js.map +0 -1
|
@@ -427,6 +427,23 @@ var ConveyorConnection = class _ConveyorConnection {
|
|
|
427
427
|
triggerIdentification() {
|
|
428
428
|
return triggerIdentification(this.socket);
|
|
429
429
|
}
|
|
430
|
+
async refreshAuthToken() {
|
|
431
|
+
const codespaceName = process.env.CODESPACE_NAME;
|
|
432
|
+
const apiUrl = process.env.CONVEYOR_API_URL ?? this.config.conveyorApiUrl;
|
|
433
|
+
if (!codespaceName || !apiUrl) return false;
|
|
434
|
+
try {
|
|
435
|
+
const response = await fetch(`${apiUrl}/api/codespace/bootstrap/${codespaceName}`);
|
|
436
|
+
if (!response.ok) return false;
|
|
437
|
+
const config = await response.json();
|
|
438
|
+
if (config.envVars?.CLAUDE_CODE_OAUTH_TOKEN) {
|
|
439
|
+
process.env.CLAUDE_CODE_OAUTH_TOKEN = config.envVars.CLAUDE_CODE_OAUTH_TOKEN;
|
|
440
|
+
return true;
|
|
441
|
+
}
|
|
442
|
+
return false;
|
|
443
|
+
} catch {
|
|
444
|
+
return false;
|
|
445
|
+
}
|
|
446
|
+
}
|
|
430
447
|
emitModeTransition(payload) {
|
|
431
448
|
if (!this.socket) return;
|
|
432
449
|
this.socket.emit("agentRunner:modeTransition", payload);
|
|
@@ -623,13 +640,13 @@ var ProjectConnection = class {
|
|
|
623
640
|
);
|
|
624
641
|
});
|
|
625
642
|
}
|
|
626
|
-
fetchChatHistory(limit) {
|
|
643
|
+
fetchChatHistory(limit, chatId) {
|
|
627
644
|
const socket = this.socket;
|
|
628
645
|
if (!socket) return Promise.reject(new Error("Not connected"));
|
|
629
646
|
return new Promise((resolve2, reject) => {
|
|
630
647
|
socket.emit(
|
|
631
648
|
"projectRunner:getChatHistory",
|
|
632
|
-
{ limit },
|
|
649
|
+
{ limit, chatId },
|
|
633
650
|
(response) => {
|
|
634
651
|
if (response.success && response.data) resolve2(response.data);
|
|
635
652
|
else reject(new Error(response.error ?? "Failed to fetch chat history"));
|
|
@@ -637,6 +654,38 @@ var ProjectConnection = class {
|
|
|
637
654
|
);
|
|
638
655
|
});
|
|
639
656
|
}
|
|
657
|
+
// ── Project MCP tool request methods ──
|
|
658
|
+
requestListTasks(params) {
|
|
659
|
+
return this.requestWithCallback("projectRunner:listTasks", params);
|
|
660
|
+
}
|
|
661
|
+
requestGetTask(taskId) {
|
|
662
|
+
return this.requestWithCallback("projectRunner:getTask", { taskId });
|
|
663
|
+
}
|
|
664
|
+
requestCreateTask(params) {
|
|
665
|
+
return this.requestWithCallback("projectRunner:createTask", params);
|
|
666
|
+
}
|
|
667
|
+
requestUpdateTask(params) {
|
|
668
|
+
return this.requestWithCallback("projectRunner:updateTask", params);
|
|
669
|
+
}
|
|
670
|
+
requestSearchTasks(params) {
|
|
671
|
+
return this.requestWithCallback("projectRunner:searchTasks", params);
|
|
672
|
+
}
|
|
673
|
+
requestListTags() {
|
|
674
|
+
return this.requestWithCallback("projectRunner:listTags", {});
|
|
675
|
+
}
|
|
676
|
+
requestGetProjectSummary() {
|
|
677
|
+
return this.requestWithCallback("projectRunner:getProjectSummary", {});
|
|
678
|
+
}
|
|
679
|
+
requestWithCallback(event, data) {
|
|
680
|
+
const socket = this.socket;
|
|
681
|
+
if (!socket) return Promise.reject(new Error("Not connected"));
|
|
682
|
+
return new Promise((resolve2, reject) => {
|
|
683
|
+
socket.emit(event, data, (response) => {
|
|
684
|
+
if (response.success) resolve2(response.data);
|
|
685
|
+
else reject(new Error(response.error ?? `${event} failed`));
|
|
686
|
+
});
|
|
687
|
+
});
|
|
688
|
+
}
|
|
640
689
|
emitNewCommitsDetected(data) {
|
|
641
690
|
if (!this.socket) return;
|
|
642
691
|
this.socket.emit("projectRunner:newCommitsDetected", data);
|
|
@@ -842,6 +891,10 @@ async function processAssistantEvent(event, host, turnToolCalls) {
|
|
|
842
891
|
}
|
|
843
892
|
var API_ERROR_PATTERN = /API Error: [45]\d\d/;
|
|
844
893
|
var IMAGE_ERROR_PATTERN = /Could not process image/i;
|
|
894
|
+
var AUTH_ERROR_PATTERN = /Not logged in|Please run \/login|authentication failed|invalid.*token|unauthorized/i;
|
|
895
|
+
function isAuthError(msg) {
|
|
896
|
+
return AUTH_ERROR_PATTERN.test(msg);
|
|
897
|
+
}
|
|
845
898
|
function isRetriableMessage(msg) {
|
|
846
899
|
if (IMAGE_ERROR_PATTERN.test(msg)) return true;
|
|
847
900
|
if (API_ERROR_PATTERN.test(msg)) return true;
|
|
@@ -922,6 +975,10 @@ function handleErrorResult(event, host) {
|
|
|
922
975
|
if (isStaleSession) {
|
|
923
976
|
return { retriable: false, staleSession: true };
|
|
924
977
|
}
|
|
978
|
+
if (isAuthError(errorMsg)) {
|
|
979
|
+
host.connection.sendEvent({ type: "error", message: errorMsg });
|
|
980
|
+
return { retriable: false, authError: true };
|
|
981
|
+
}
|
|
925
982
|
const retriable = isRetriableMessage(errorMsg);
|
|
926
983
|
host.connection.sendEvent({ type: "error", message: errorMsg });
|
|
927
984
|
return { retriable };
|
|
@@ -961,7 +1018,8 @@ async function emitResultEvent(event, host, context, startTime, lastAssistantUsa
|
|
|
961
1018
|
return {
|
|
962
1019
|
retriable: result.retriable,
|
|
963
1020
|
resultSummary: result.resultSummary,
|
|
964
|
-
staleSession: result.staleSession
|
|
1021
|
+
staleSession: result.staleSession,
|
|
1022
|
+
authError: result.authError
|
|
965
1023
|
};
|
|
966
1024
|
}
|
|
967
1025
|
function handleRateLimitEvent(event, host) {
|
|
@@ -1061,6 +1119,7 @@ async function handleResultCase(event, host, context, startTime, isTyping, lastA
|
|
|
1061
1119
|
retriable: resultInfo.retriable,
|
|
1062
1120
|
resultSummary: resultInfo.resultSummary,
|
|
1063
1121
|
staleSession: resultInfo.staleSession,
|
|
1122
|
+
authError: resultInfo.authError,
|
|
1064
1123
|
stoppedTyping
|
|
1065
1124
|
};
|
|
1066
1125
|
}
|
|
@@ -1108,6 +1167,7 @@ async function processResultCase(event, host, context, startTime, state) {
|
|
|
1108
1167
|
state.retriable = info.retriable;
|
|
1109
1168
|
state.resultSummary = info.resultSummary;
|
|
1110
1169
|
if (info.staleSession) state.staleSession = true;
|
|
1170
|
+
if (info.authError) state.authError = true;
|
|
1111
1171
|
}
|
|
1112
1172
|
async function processEvents(events, context, host) {
|
|
1113
1173
|
const startTime = Date.now();
|
|
@@ -1121,6 +1181,7 @@ async function processEvents(events, context, host) {
|
|
|
1121
1181
|
resultSummary: void 0,
|
|
1122
1182
|
rateLimitResetsAt: void 0,
|
|
1123
1183
|
staleSession: void 0,
|
|
1184
|
+
authError: void 0,
|
|
1124
1185
|
lastAssistantUsage: void 0,
|
|
1125
1186
|
turnToolCalls: []
|
|
1126
1187
|
};
|
|
@@ -1160,7 +1221,8 @@ async function processEvents(events, context, host) {
|
|
|
1160
1221
|
retriable: state.retriable || state.sawApiError,
|
|
1161
1222
|
resultSummary: state.resultSummary,
|
|
1162
1223
|
rateLimitResetsAt: state.rateLimitResetsAt,
|
|
1163
|
-
...state.staleSession && { staleSession: state.staleSession }
|
|
1224
|
+
...state.staleSession && { staleSession: state.staleSession },
|
|
1225
|
+
...state.authError && { authError: state.authError }
|
|
1164
1226
|
};
|
|
1165
1227
|
}
|
|
1166
1228
|
|
|
@@ -3115,6 +3177,29 @@ async function buildRetryQuery(host, context, options, lastErrorWasImage) {
|
|
|
3115
3177
|
options: { ...options, resume: void 0 }
|
|
3116
3178
|
});
|
|
3117
3179
|
}
|
|
3180
|
+
async function handleAuthError(context, host, options) {
|
|
3181
|
+
host.connection.postChatMessage("Authentication expired. Re-bootstrapping credentials...");
|
|
3182
|
+
const refreshed = await host.connection.refreshAuthToken();
|
|
3183
|
+
if (!refreshed) {
|
|
3184
|
+
host.connection.postChatMessage("Failed to refresh authentication. Agent will restart.");
|
|
3185
|
+
host.connection.sendEvent({
|
|
3186
|
+
type: "error",
|
|
3187
|
+
message: "Auth re-bootstrap failed, exiting for restart"
|
|
3188
|
+
});
|
|
3189
|
+
process.exit(1);
|
|
3190
|
+
}
|
|
3191
|
+
context.claudeSessionId = null;
|
|
3192
|
+
host.connection.storeSessionId("");
|
|
3193
|
+
const freshPrompt = buildMultimodalPrompt(
|
|
3194
|
+
await buildInitialPrompt(host.config.mode, context, host.config.isAuto, host.agentMode),
|
|
3195
|
+
context
|
|
3196
|
+
);
|
|
3197
|
+
const freshQuery = query({
|
|
3198
|
+
prompt: host.createInputStream(freshPrompt),
|
|
3199
|
+
options: { ...options, resume: void 0 }
|
|
3200
|
+
});
|
|
3201
|
+
return runWithRetry(freshQuery, context, host, options);
|
|
3202
|
+
}
|
|
3118
3203
|
async function handleStaleSession(context, host, options) {
|
|
3119
3204
|
context.claudeSessionId = null;
|
|
3120
3205
|
host.connection.storeSessionId("");
|
|
@@ -3183,26 +3268,41 @@ function handleRetryError(error, context, host, options, prevImageError) {
|
|
|
3183
3268
|
if (isStaleOrExitedSession(error, context) && context.claudeSessionId) {
|
|
3184
3269
|
return handleStaleSession(context, host, options);
|
|
3185
3270
|
}
|
|
3271
|
+
if (isAuthError(getErrorMessage(error))) {
|
|
3272
|
+
return handleAuthError(context, host, options);
|
|
3273
|
+
}
|
|
3186
3274
|
if (!isRetriableError(error)) throw error;
|
|
3187
3275
|
return { action: "continue", lastErrorWasImage: classifyImageError(error) || prevImageError };
|
|
3188
3276
|
}
|
|
3277
|
+
function handleProcessResult(result, context, host, options) {
|
|
3278
|
+
if (result.modeRestart || host.isStopped()) return { action: "return" };
|
|
3279
|
+
if (result.rateLimitResetsAt) {
|
|
3280
|
+
handleRateLimitPause(host, result.rateLimitResetsAt);
|
|
3281
|
+
return { action: "return" };
|
|
3282
|
+
}
|
|
3283
|
+
if (result.staleSession && context.claudeSessionId) {
|
|
3284
|
+
return { action: "return_promise", promise: handleStaleSession(context, host, options) };
|
|
3285
|
+
}
|
|
3286
|
+
if (result.authError) {
|
|
3287
|
+
return { action: "return_promise", promise: handleAuthError(context, host, options) };
|
|
3288
|
+
}
|
|
3289
|
+
if (!result.retriable) return { action: "return" };
|
|
3290
|
+
return {
|
|
3291
|
+
action: "continue",
|
|
3292
|
+
lastErrorWasImage: IMAGE_ERROR_PATTERN2.test(result.resultSummary ?? "")
|
|
3293
|
+
};
|
|
3294
|
+
}
|
|
3189
3295
|
async function runWithRetry(initialQuery, context, host, options) {
|
|
3190
3296
|
let lastErrorWasImage = false;
|
|
3191
3297
|
for (let attempt = 0; attempt <= RETRY_DELAYS_MS.length; attempt++) {
|
|
3192
3298
|
if (host.isStopped()) return;
|
|
3193
3299
|
const agentQuery = attempt === 0 ? initialQuery : await buildRetryQuery(host, context, options, lastErrorWasImage);
|
|
3194
3300
|
try {
|
|
3195
|
-
const
|
|
3196
|
-
|
|
3197
|
-
if (
|
|
3198
|
-
|
|
3199
|
-
|
|
3200
|
-
}
|
|
3201
|
-
if (staleSession && context.claudeSessionId) {
|
|
3202
|
-
return handleStaleSession(context, host, options);
|
|
3203
|
-
}
|
|
3204
|
-
if (!retriable) return;
|
|
3205
|
-
lastErrorWasImage = IMAGE_ERROR_PATTERN2.test(resultSummary ?? "");
|
|
3301
|
+
const result = await processEvents(agentQuery, context, host);
|
|
3302
|
+
const outcome = handleProcessResult(result, context, host, options);
|
|
3303
|
+
if (outcome.action === "return") return;
|
|
3304
|
+
if (outcome.action === "return_promise") return outcome.promise;
|
|
3305
|
+
lastErrorWasImage = outcome.lastErrorWasImage;
|
|
3206
3306
|
} catch (error) {
|
|
3207
3307
|
const outcome = handleRetryError(error, context, host, options, lastErrorWasImage);
|
|
3208
3308
|
if (outcome instanceof Promise) return outcome;
|
|
@@ -4142,7 +4242,159 @@ var CommitWatcher = class {
|
|
|
4142
4242
|
};
|
|
4143
4243
|
|
|
4144
4244
|
// src/runner/project-chat-handler.ts
|
|
4145
|
-
import {
|
|
4245
|
+
import {
|
|
4246
|
+
query as query2,
|
|
4247
|
+
createSdkMcpServer as createSdkMcpServer2
|
|
4248
|
+
} from "@anthropic-ai/claude-agent-sdk";
|
|
4249
|
+
|
|
4250
|
+
// src/tools/project-tools.ts
|
|
4251
|
+
import { tool as tool4 } from "@anthropic-ai/claude-agent-sdk";
|
|
4252
|
+
import { z as z4 } from "zod";
|
|
4253
|
+
function buildReadTools(connection) {
|
|
4254
|
+
return [
|
|
4255
|
+
tool4(
|
|
4256
|
+
"list_tasks",
|
|
4257
|
+
"List tasks in the project. Optionally filter by status or assignee.",
|
|
4258
|
+
{
|
|
4259
|
+
status: z4.string().optional().describe("Filter by task status (e.g. Planning, Open, InProgress, ReviewPR, Complete)"),
|
|
4260
|
+
assigneeId: z4.string().optional().describe("Filter by assigned user ID"),
|
|
4261
|
+
limit: z4.number().optional().describe("Max number of tasks to return (default 50)")
|
|
4262
|
+
},
|
|
4263
|
+
async (params) => {
|
|
4264
|
+
try {
|
|
4265
|
+
const tasks = await connection.requestListTasks(params);
|
|
4266
|
+
return textResult(JSON.stringify(tasks, null, 2));
|
|
4267
|
+
} catch (error) {
|
|
4268
|
+
return textResult(
|
|
4269
|
+
`Failed to list tasks: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
4270
|
+
);
|
|
4271
|
+
}
|
|
4272
|
+
},
|
|
4273
|
+
{ annotations: { readOnlyHint: true } }
|
|
4274
|
+
),
|
|
4275
|
+
tool4(
|
|
4276
|
+
"get_task",
|
|
4277
|
+
"Get detailed information about a task including its chat messages, child tasks, and codespace status.",
|
|
4278
|
+
{ task_id: z4.string().describe("The task ID to look up") },
|
|
4279
|
+
async ({ task_id }) => {
|
|
4280
|
+
try {
|
|
4281
|
+
const task = await connection.requestGetTask(task_id);
|
|
4282
|
+
return textResult(JSON.stringify(task, null, 2));
|
|
4283
|
+
} catch (error) {
|
|
4284
|
+
return textResult(
|
|
4285
|
+
`Failed to get task: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
4286
|
+
);
|
|
4287
|
+
}
|
|
4288
|
+
},
|
|
4289
|
+
{ annotations: { readOnlyHint: true } }
|
|
4290
|
+
),
|
|
4291
|
+
tool4(
|
|
4292
|
+
"search_tasks",
|
|
4293
|
+
"Search tasks by tags, text query, or status filters.",
|
|
4294
|
+
{
|
|
4295
|
+
tagNames: z4.array(z4.string()).optional().describe("Filter by tag names"),
|
|
4296
|
+
searchQuery: z4.string().optional().describe("Text search in title/description"),
|
|
4297
|
+
statusFilters: z4.array(z4.string()).optional().describe("Filter by statuses"),
|
|
4298
|
+
limit: z4.number().optional().describe("Max results (default 20)")
|
|
4299
|
+
},
|
|
4300
|
+
async (params) => {
|
|
4301
|
+
try {
|
|
4302
|
+
const tasks = await connection.requestSearchTasks(params);
|
|
4303
|
+
return textResult(JSON.stringify(tasks, null, 2));
|
|
4304
|
+
} catch (error) {
|
|
4305
|
+
return textResult(
|
|
4306
|
+
`Failed to search tasks: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
4307
|
+
);
|
|
4308
|
+
}
|
|
4309
|
+
},
|
|
4310
|
+
{ annotations: { readOnlyHint: true } }
|
|
4311
|
+
),
|
|
4312
|
+
tool4(
|
|
4313
|
+
"list_tags",
|
|
4314
|
+
"List all tags available in the project.",
|
|
4315
|
+
{},
|
|
4316
|
+
async () => {
|
|
4317
|
+
try {
|
|
4318
|
+
const tags = await connection.requestListTags();
|
|
4319
|
+
return textResult(JSON.stringify(tags, null, 2));
|
|
4320
|
+
} catch (error) {
|
|
4321
|
+
return textResult(
|
|
4322
|
+
`Failed to list tags: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
4323
|
+
);
|
|
4324
|
+
}
|
|
4325
|
+
},
|
|
4326
|
+
{ annotations: { readOnlyHint: true } }
|
|
4327
|
+
),
|
|
4328
|
+
tool4(
|
|
4329
|
+
"get_project_summary",
|
|
4330
|
+
"Get a summary of the project including task counts by status and active builds.",
|
|
4331
|
+
{},
|
|
4332
|
+
async () => {
|
|
4333
|
+
try {
|
|
4334
|
+
const summary = await connection.requestGetProjectSummary();
|
|
4335
|
+
return textResult(JSON.stringify(summary, null, 2));
|
|
4336
|
+
} catch (error) {
|
|
4337
|
+
return textResult(
|
|
4338
|
+
`Failed to get project summary: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
4339
|
+
);
|
|
4340
|
+
}
|
|
4341
|
+
},
|
|
4342
|
+
{ annotations: { readOnlyHint: true } }
|
|
4343
|
+
)
|
|
4344
|
+
];
|
|
4345
|
+
}
|
|
4346
|
+
function buildMutationTools(connection) {
|
|
4347
|
+
return [
|
|
4348
|
+
tool4(
|
|
4349
|
+
"create_task",
|
|
4350
|
+
"Create a new task in the project.",
|
|
4351
|
+
{
|
|
4352
|
+
title: z4.string().describe("Task title"),
|
|
4353
|
+
description: z4.string().optional().describe("Task description"),
|
|
4354
|
+
plan: z4.string().optional().describe("Implementation plan in markdown"),
|
|
4355
|
+
status: z4.string().optional().describe("Initial status (default: Planning)"),
|
|
4356
|
+
isBug: z4.boolean().optional().describe("Whether this is a bug report")
|
|
4357
|
+
},
|
|
4358
|
+
async (params) => {
|
|
4359
|
+
try {
|
|
4360
|
+
const result = await connection.requestCreateTask(params);
|
|
4361
|
+
return textResult(`Task created: ${result.slug} (ID: ${result.id})`);
|
|
4362
|
+
} catch (error) {
|
|
4363
|
+
return textResult(
|
|
4364
|
+
`Failed to create task: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
4365
|
+
);
|
|
4366
|
+
}
|
|
4367
|
+
}
|
|
4368
|
+
),
|
|
4369
|
+
tool4(
|
|
4370
|
+
"update_task",
|
|
4371
|
+
"Update an existing task's title, description, plan, status, or assignee.",
|
|
4372
|
+
{
|
|
4373
|
+
task_id: z4.string().describe("The task ID to update"),
|
|
4374
|
+
title: z4.string().optional().describe("New title"),
|
|
4375
|
+
description: z4.string().optional().describe("New description"),
|
|
4376
|
+
plan: z4.string().optional().describe("New plan in markdown"),
|
|
4377
|
+
status: z4.string().optional().describe("New status"),
|
|
4378
|
+
assignedUserId: z4.string().nullable().optional().describe("Assign to user ID, or null to unassign")
|
|
4379
|
+
},
|
|
4380
|
+
async ({ task_id, ...fields }) => {
|
|
4381
|
+
try {
|
|
4382
|
+
await connection.requestUpdateTask({ taskId: task_id, ...fields });
|
|
4383
|
+
return textResult("Task updated successfully.");
|
|
4384
|
+
} catch (error) {
|
|
4385
|
+
return textResult(
|
|
4386
|
+
`Failed to update task: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
4387
|
+
);
|
|
4388
|
+
}
|
|
4389
|
+
}
|
|
4390
|
+
)
|
|
4391
|
+
];
|
|
4392
|
+
}
|
|
4393
|
+
function buildProjectTools(connection) {
|
|
4394
|
+
return [...buildReadTools(connection), ...buildMutationTools(connection)];
|
|
4395
|
+
}
|
|
4396
|
+
|
|
4397
|
+
// src/runner/project-chat-handler.ts
|
|
4146
4398
|
var logger4 = createServiceLogger("ProjectChat");
|
|
4147
4399
|
var FALLBACK_MODEL = "claude-sonnet-4-20250514";
|
|
4148
4400
|
function buildSystemPrompt2(projectDir, agentCtx) {
|
|
@@ -4199,7 +4451,7 @@ function processContentBlock(block, responseParts, turnToolCalls) {
|
|
|
4199
4451
|
logger4.debug("Tool use", { tool: block.name });
|
|
4200
4452
|
}
|
|
4201
4453
|
}
|
|
4202
|
-
async function fetchContext(connection) {
|
|
4454
|
+
async function fetchContext(connection, chatId) {
|
|
4203
4455
|
let agentCtx = null;
|
|
4204
4456
|
try {
|
|
4205
4457
|
agentCtx = await connection.fetchAgentContext();
|
|
@@ -4208,15 +4460,19 @@ async function fetchContext(connection) {
|
|
|
4208
4460
|
}
|
|
4209
4461
|
let chatHistory = [];
|
|
4210
4462
|
try {
|
|
4211
|
-
chatHistory = await connection.fetchChatHistory(30);
|
|
4463
|
+
chatHistory = await connection.fetchChatHistory(30, chatId);
|
|
4212
4464
|
} catch {
|
|
4213
4465
|
logger4.warn("Could not fetch chat history, proceeding without it");
|
|
4214
4466
|
}
|
|
4215
4467
|
return { agentCtx, chatHistory };
|
|
4216
4468
|
}
|
|
4217
|
-
function buildChatQueryOptions(agentCtx, projectDir) {
|
|
4469
|
+
function buildChatQueryOptions(agentCtx, projectDir, connection) {
|
|
4218
4470
|
const model = agentCtx?.model || FALLBACK_MODEL;
|
|
4219
4471
|
const settings = agentCtx?.agentSettings ?? {};
|
|
4472
|
+
const mcpServer = createSdkMcpServer2({
|
|
4473
|
+
name: "conveyor",
|
|
4474
|
+
tools: buildProjectTools(connection)
|
|
4475
|
+
});
|
|
4220
4476
|
return {
|
|
4221
4477
|
model,
|
|
4222
4478
|
systemPrompt: {
|
|
@@ -4228,8 +4484,9 @@ function buildChatQueryOptions(agentCtx, projectDir) {
|
|
|
4228
4484
|
permissionMode: "bypassPermissions",
|
|
4229
4485
|
allowDangerouslySkipPermissions: true,
|
|
4230
4486
|
tools: { type: "preset", preset: "claude_code" },
|
|
4231
|
-
|
|
4232
|
-
|
|
4487
|
+
mcpServers: { conveyor: mcpServer },
|
|
4488
|
+
maxTurns: settings.maxTurns ?? 30,
|
|
4489
|
+
maxBudgetUsd: settings.maxBudgetUsd ?? 50,
|
|
4233
4490
|
effort: settings.effort,
|
|
4234
4491
|
thinking: settings.thinking
|
|
4235
4492
|
};
|
|
@@ -4295,16 +4552,25 @@ function processEventStream(event, connection, responseParts, turnToolCalls, isT
|
|
|
4295
4552
|
}
|
|
4296
4553
|
return false;
|
|
4297
4554
|
}
|
|
4298
|
-
async function runChatQuery(message, connection, projectDir) {
|
|
4299
|
-
const { agentCtx, chatHistory } = await fetchContext(connection);
|
|
4300
|
-
const options = buildChatQueryOptions(agentCtx, projectDir);
|
|
4555
|
+
async function runChatQuery(message, connection, projectDir, sessionId) {
|
|
4556
|
+
const { agentCtx, chatHistory } = await fetchContext(connection, message.chatId);
|
|
4557
|
+
const options = buildChatQueryOptions(agentCtx, projectDir, connection);
|
|
4301
4558
|
const prompt = buildPrompt(message, chatHistory);
|
|
4302
4559
|
connection.emitAgentStatus("running");
|
|
4303
|
-
const events = query2({
|
|
4560
|
+
const events = query2({
|
|
4561
|
+
prompt,
|
|
4562
|
+
options,
|
|
4563
|
+
...sessionId ? { resume: sessionId } : {}
|
|
4564
|
+
});
|
|
4304
4565
|
const responseParts = [];
|
|
4305
4566
|
const turnToolCalls = [];
|
|
4306
4567
|
const isTyping = { value: false };
|
|
4568
|
+
let resultSessionId;
|
|
4307
4569
|
for await (const event of events) {
|
|
4570
|
+
if (event.type === "result") {
|
|
4571
|
+
const resultEvent = event;
|
|
4572
|
+
resultSessionId = resultEvent.sessionId;
|
|
4573
|
+
}
|
|
4308
4574
|
const done = processEventStream(event, connection, responseParts, turnToolCalls, isTyping);
|
|
4309
4575
|
if (done) break;
|
|
4310
4576
|
}
|
|
@@ -4315,11 +4581,12 @@ async function runChatQuery(message, connection, projectDir) {
|
|
|
4315
4581
|
if (responseText) {
|
|
4316
4582
|
await connection.emitChatMessage(responseText);
|
|
4317
4583
|
}
|
|
4584
|
+
return resultSessionId;
|
|
4318
4585
|
}
|
|
4319
|
-
async function handleProjectChatMessage(message, connection, projectDir) {
|
|
4586
|
+
async function handleProjectChatMessage(message, connection, projectDir, sessionId) {
|
|
4320
4587
|
connection.emitAgentStatus("fetching_context");
|
|
4321
4588
|
try {
|
|
4322
|
-
await runChatQuery(message, connection, projectDir);
|
|
4589
|
+
return await runChatQuery(message, connection, projectDir, sessionId);
|
|
4323
4590
|
} catch (error) {
|
|
4324
4591
|
logger4.error("Failed to handle message", errorMeta(error));
|
|
4325
4592
|
connection.emitAgentStatus("error");
|
|
@@ -4329,6 +4596,7 @@ async function handleProjectChatMessage(message, connection, projectDir) {
|
|
|
4329
4596
|
);
|
|
4330
4597
|
} catch {
|
|
4331
4598
|
}
|
|
4599
|
+
return void 0;
|
|
4332
4600
|
} finally {
|
|
4333
4601
|
connection.emitAgentStatus("idle");
|
|
4334
4602
|
}
|
|
@@ -4339,8 +4607,8 @@ import { query as query3 } from "@anthropic-ai/claude-agent-sdk";
|
|
|
4339
4607
|
|
|
4340
4608
|
// src/tools/audit-tools.ts
|
|
4341
4609
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
4342
|
-
import { tool as
|
|
4343
|
-
import { z as
|
|
4610
|
+
import { tool as tool5, createSdkMcpServer as createSdkMcpServer3 } from "@anthropic-ai/claude-agent-sdk";
|
|
4611
|
+
import { z as z5 } from "zod";
|
|
4344
4612
|
function mapCreateTag(input) {
|
|
4345
4613
|
return {
|
|
4346
4614
|
type: "create_tag",
|
|
@@ -4422,14 +4690,14 @@ function collectRecommendation(toolName, input, collector, onRecommendation) {
|
|
|
4422
4690
|
}
|
|
4423
4691
|
function createAuditMcpServer(collector, onRecommendation) {
|
|
4424
4692
|
const auditTools = [
|
|
4425
|
-
|
|
4693
|
+
tool5(
|
|
4426
4694
|
"recommend_create_tag",
|
|
4427
4695
|
"Recommend creating a new tag for an uncovered subsystem or area",
|
|
4428
4696
|
{
|
|
4429
|
-
name:
|
|
4430
|
-
color:
|
|
4431
|
-
description:
|
|
4432
|
-
reasoning:
|
|
4697
|
+
name: z5.string().describe("Proposed tag name (lowercase, hyphenated)"),
|
|
4698
|
+
color: z5.string().optional().describe("Hex color code"),
|
|
4699
|
+
description: z5.string().describe("What this tag covers"),
|
|
4700
|
+
reasoning: z5.string().describe("Why this tag should be created")
|
|
4433
4701
|
},
|
|
4434
4702
|
async (args) => {
|
|
4435
4703
|
const result = collectRecommendation(
|
|
@@ -4441,14 +4709,14 @@ function createAuditMcpServer(collector, onRecommendation) {
|
|
|
4441
4709
|
return { content: [{ type: "text", text: result }] };
|
|
4442
4710
|
}
|
|
4443
4711
|
),
|
|
4444
|
-
|
|
4712
|
+
tool5(
|
|
4445
4713
|
"recommend_update_description",
|
|
4446
4714
|
"Recommend updating a tag's description to better reflect its scope",
|
|
4447
4715
|
{
|
|
4448
|
-
tagId:
|
|
4449
|
-
tagName:
|
|
4450
|
-
description:
|
|
4451
|
-
reasoning:
|
|
4716
|
+
tagId: z5.string(),
|
|
4717
|
+
tagName: z5.string(),
|
|
4718
|
+
description: z5.string().describe("Proposed new description"),
|
|
4719
|
+
reasoning: z5.string()
|
|
4452
4720
|
},
|
|
4453
4721
|
async (args) => {
|
|
4454
4722
|
const result = collectRecommendation(
|
|
@@ -4460,16 +4728,16 @@ function createAuditMcpServer(collector, onRecommendation) {
|
|
|
4460
4728
|
return { content: [{ type: "text", text: result }] };
|
|
4461
4729
|
}
|
|
4462
4730
|
),
|
|
4463
|
-
|
|
4731
|
+
tool5(
|
|
4464
4732
|
"recommend_context_link",
|
|
4465
4733
|
"Recommend linking a doc, rule, file, or folder to a tag's contextPaths",
|
|
4466
4734
|
{
|
|
4467
|
-
tagId:
|
|
4468
|
-
tagName:
|
|
4469
|
-
linkType:
|
|
4470
|
-
path:
|
|
4471
|
-
label:
|
|
4472
|
-
reasoning:
|
|
4735
|
+
tagId: z5.string(),
|
|
4736
|
+
tagName: z5.string(),
|
|
4737
|
+
linkType: z5.enum(["rule", "doc", "file", "folder"]),
|
|
4738
|
+
path: z5.string(),
|
|
4739
|
+
label: z5.string().optional(),
|
|
4740
|
+
reasoning: z5.string()
|
|
4473
4741
|
},
|
|
4474
4742
|
async (args) => {
|
|
4475
4743
|
const result = collectRecommendation(
|
|
@@ -4481,16 +4749,16 @@ function createAuditMcpServer(collector, onRecommendation) {
|
|
|
4481
4749
|
return { content: [{ type: "text", text: result }] };
|
|
4482
4750
|
}
|
|
4483
4751
|
),
|
|
4484
|
-
|
|
4752
|
+
tool5(
|
|
4485
4753
|
"flag_documentation_gap",
|
|
4486
4754
|
"Flag a file that agents read heavily but has no tag documentation linked",
|
|
4487
4755
|
{
|
|
4488
|
-
tagName:
|
|
4489
|
-
tagId:
|
|
4490
|
-
filePath:
|
|
4491
|
-
readCount:
|
|
4492
|
-
suggestedAction:
|
|
4493
|
-
reasoning:
|
|
4756
|
+
tagName: z5.string().describe("Tag whose agents read this file"),
|
|
4757
|
+
tagId: z5.string().optional(),
|
|
4758
|
+
filePath: z5.string(),
|
|
4759
|
+
readCount: z5.number(),
|
|
4760
|
+
suggestedAction: z5.string().describe("What doc or rule should be created"),
|
|
4761
|
+
reasoning: z5.string()
|
|
4494
4762
|
},
|
|
4495
4763
|
async (args) => {
|
|
4496
4764
|
const result = collectRecommendation(
|
|
@@ -4502,15 +4770,15 @@ function createAuditMcpServer(collector, onRecommendation) {
|
|
|
4502
4770
|
return { content: [{ type: "text", text: result }] };
|
|
4503
4771
|
}
|
|
4504
4772
|
),
|
|
4505
|
-
|
|
4773
|
+
tool5(
|
|
4506
4774
|
"recommend_merge_tags",
|
|
4507
4775
|
"Recommend merging one tag into another",
|
|
4508
4776
|
{
|
|
4509
|
-
tagId:
|
|
4510
|
-
tagName:
|
|
4511
|
-
mergeIntoTagId:
|
|
4512
|
-
mergeIntoTagName:
|
|
4513
|
-
reasoning:
|
|
4777
|
+
tagId: z5.string().describe("Tag ID to be merged (removed after merge)"),
|
|
4778
|
+
tagName: z5.string().describe("Name of the tag to be merged"),
|
|
4779
|
+
mergeIntoTagId: z5.string().describe("Tag ID to merge into (kept)"),
|
|
4780
|
+
mergeIntoTagName: z5.string(),
|
|
4781
|
+
reasoning: z5.string()
|
|
4514
4782
|
},
|
|
4515
4783
|
async (args) => {
|
|
4516
4784
|
const result = collectRecommendation(
|
|
@@ -4522,14 +4790,14 @@ function createAuditMcpServer(collector, onRecommendation) {
|
|
|
4522
4790
|
return { content: [{ type: "text", text: result }] };
|
|
4523
4791
|
}
|
|
4524
4792
|
),
|
|
4525
|
-
|
|
4793
|
+
tool5(
|
|
4526
4794
|
"recommend_rename_tag",
|
|
4527
4795
|
"Recommend renaming a tag",
|
|
4528
4796
|
{
|
|
4529
|
-
tagId:
|
|
4530
|
-
tagName:
|
|
4531
|
-
newName:
|
|
4532
|
-
reasoning:
|
|
4797
|
+
tagId: z5.string(),
|
|
4798
|
+
tagName: z5.string().describe("Current tag name"),
|
|
4799
|
+
newName: z5.string().describe("Proposed new name"),
|
|
4800
|
+
reasoning: z5.string()
|
|
4533
4801
|
},
|
|
4534
4802
|
async (args) => {
|
|
4535
4803
|
const result = collectRecommendation(
|
|
@@ -4541,10 +4809,10 @@ function createAuditMcpServer(collector, onRecommendation) {
|
|
|
4541
4809
|
return { content: [{ type: "text", text: result }] };
|
|
4542
4810
|
}
|
|
4543
4811
|
),
|
|
4544
|
-
|
|
4812
|
+
tool5(
|
|
4545
4813
|
"complete_audit",
|
|
4546
4814
|
"Signal that the audit is complete with a summary of all findings",
|
|
4547
|
-
{ summary:
|
|
4815
|
+
{ summary: z5.string().describe("Brief overview of all findings") },
|
|
4548
4816
|
async (args) => {
|
|
4549
4817
|
collector.complete = true;
|
|
4550
4818
|
collector.summary = args.summary ?? "Audit completed.";
|
|
@@ -4552,7 +4820,7 @@ function createAuditMcpServer(collector, onRecommendation) {
|
|
|
4552
4820
|
}
|
|
4553
4821
|
)
|
|
4554
4822
|
];
|
|
4555
|
-
return
|
|
4823
|
+
return createSdkMcpServer3({
|
|
4556
4824
|
name: "tag-audit",
|
|
4557
4825
|
tools: auditTools
|
|
4558
4826
|
});
|
|
@@ -4674,7 +4942,7 @@ async function runAuditQuery(request, connection, projectDir) {
|
|
|
4674
4942
|
allowDangerouslySkipPermissions: true,
|
|
4675
4943
|
tools: { type: "preset", preset: "claude_code" },
|
|
4676
4944
|
mcpServers: { "tag-audit": createAuditMcpServer(collector, onRecommendation) },
|
|
4677
|
-
maxTurns: settings.maxTurns ??
|
|
4945
|
+
maxTurns: settings.maxTurns ?? 75,
|
|
4678
4946
|
maxBudgetUsd: settings.maxBudgetUsd ?? 5,
|
|
4679
4947
|
effort: settings.effort,
|
|
4680
4948
|
thinking: settings.thinking
|
|
@@ -4803,6 +5071,7 @@ var ProjectRunner = class {
|
|
|
4803
5071
|
heartbeatTimer = null;
|
|
4804
5072
|
stopping = false;
|
|
4805
5073
|
resolveLifecycle = null;
|
|
5074
|
+
chatSessionIds = /* @__PURE__ */ new Map();
|
|
4806
5075
|
// Start command process management
|
|
4807
5076
|
startCommandChild = null;
|
|
4808
5077
|
startCommandRunning = false;
|
|
@@ -5157,7 +5426,15 @@ var ProjectRunner = class {
|
|
|
5157
5426
|
});
|
|
5158
5427
|
this.connection.onChatMessage((msg) => {
|
|
5159
5428
|
logger6.debug("Received project chat message");
|
|
5160
|
-
|
|
5429
|
+
const chatId = msg.chatId ?? "default";
|
|
5430
|
+
const existingSessionId = this.chatSessionIds.get(chatId);
|
|
5431
|
+
void handleProjectChatMessage(msg, this.connection, this.projectDir, existingSessionId).then(
|
|
5432
|
+
(newSessionId) => {
|
|
5433
|
+
if (newSessionId) {
|
|
5434
|
+
this.chatSessionIds.set(chatId, newSessionId);
|
|
5435
|
+
}
|
|
5436
|
+
}
|
|
5437
|
+
);
|
|
5161
5438
|
});
|
|
5162
5439
|
this.connection.onAuditRequest((request) => {
|
|
5163
5440
|
logger6.debug("Received tag audit request", { requestId: request.requestId });
|
|
@@ -5388,4 +5665,4 @@ export {
|
|
|
5388
5665
|
ProjectRunner,
|
|
5389
5666
|
FileCache
|
|
5390
5667
|
};
|
|
5391
|
-
//# sourceMappingURL=chunk-
|
|
5668
|
+
//# sourceMappingURL=chunk-SQJJL2PU.js.map
|