@rallycry/conveyor-agent 5.12.0 → 6.0.1
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-SQJJL2PU.js → chunk-HYWZJYPW.js} +144 -1335
- package/dist/chunk-HYWZJYPW.js.map +1 -0
- package/dist/cli.js +7 -6
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +2 -101
- package/dist/index.js +1 -1
- package/package.json +2 -2
- package/dist/chunk-SQJJL2PU.js.map +0 -1
|
@@ -427,23 +427,6 @@ 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
|
-
}
|
|
447
430
|
emitModeTransition(payload) {
|
|
448
431
|
if (!this.socket) return;
|
|
449
432
|
this.socket.emit("agentRunner:modeTransition", payload);
|
|
@@ -471,16 +454,9 @@ var ProjectConnection = class {
|
|
|
471
454
|
shutdownCallback = null;
|
|
472
455
|
chatMessageCallback = null;
|
|
473
456
|
earlyChatMessages = [];
|
|
474
|
-
auditRequestCallback = null;
|
|
475
|
-
// Branch switching callbacks
|
|
476
|
-
onSwitchBranch = null;
|
|
477
|
-
onSyncEnvironment = null;
|
|
478
|
-
onGetEnvStatus = null;
|
|
479
|
-
onRestartStartCommand = null;
|
|
480
457
|
constructor(config) {
|
|
481
458
|
this.config = config;
|
|
482
459
|
}
|
|
483
|
-
// oxlint-disable-next-line max-lines-per-function -- socket event registration requires co-located handlers
|
|
484
460
|
connect() {
|
|
485
461
|
return new Promise((resolve2, reject) => {
|
|
486
462
|
let settled = false;
|
|
@@ -520,37 +496,6 @@ var ProjectConnection = class {
|
|
|
520
496
|
this.earlyChatMessages.push(msg);
|
|
521
497
|
}
|
|
522
498
|
});
|
|
523
|
-
this.socket.on("projectRunner:auditTags", (data) => {
|
|
524
|
-
if (this.auditRequestCallback) {
|
|
525
|
-
this.auditRequestCallback(data);
|
|
526
|
-
}
|
|
527
|
-
});
|
|
528
|
-
this.socket.on(
|
|
529
|
-
"projectRunner:switchBranch",
|
|
530
|
-
(data, cb) => {
|
|
531
|
-
if (this.onSwitchBranch) this.onSwitchBranch(data, cb);
|
|
532
|
-
else cb({ ok: false, error: "switchBranch handler not registered" });
|
|
533
|
-
}
|
|
534
|
-
);
|
|
535
|
-
this.socket.on("projectRunner:syncEnvironment", (cb) => {
|
|
536
|
-
if (this.onSyncEnvironment) this.onSyncEnvironment(cb);
|
|
537
|
-
else cb({ ok: false, error: "syncEnvironment handler not registered" });
|
|
538
|
-
});
|
|
539
|
-
this.socket.on("projectRunner:getEnvStatus", (cb) => {
|
|
540
|
-
if (this.onGetEnvStatus) this.onGetEnvStatus(cb);
|
|
541
|
-
else cb({ ok: false, data: void 0 });
|
|
542
|
-
});
|
|
543
|
-
this.socket.on(
|
|
544
|
-
"projectRunner:restartStartCommand",
|
|
545
|
-
(_data, cb) => {
|
|
546
|
-
if (this.onRestartStartCommand) this.onRestartStartCommand(cb);
|
|
547
|
-
else cb({ ok: false, error: "restartStartCommand handler not registered" });
|
|
548
|
-
}
|
|
549
|
-
);
|
|
550
|
-
this.socket.on(
|
|
551
|
-
"projectRunner:runAuthTokenCommand",
|
|
552
|
-
(data, cb) => this.handleRunAuthTokenCommand(data.userEmail, cb)
|
|
553
|
-
);
|
|
554
499
|
this.socket.on("connect", () => {
|
|
555
500
|
if (!settled) {
|
|
556
501
|
settled = true;
|
|
@@ -582,17 +527,6 @@ var ProjectConnection = class {
|
|
|
582
527
|
}
|
|
583
528
|
this.earlyChatMessages = [];
|
|
584
529
|
}
|
|
585
|
-
onAuditRequest(callback) {
|
|
586
|
-
this.auditRequestCallback = callback;
|
|
587
|
-
}
|
|
588
|
-
emitAuditResult(data) {
|
|
589
|
-
if (!this.socket) return;
|
|
590
|
-
this.socket.emit("conveyor:tagAuditResult", data);
|
|
591
|
-
}
|
|
592
|
-
emitAuditProgress(data) {
|
|
593
|
-
if (!this.socket) return;
|
|
594
|
-
this.socket.emit("conveyor:tagAuditProgress", data);
|
|
595
|
-
}
|
|
596
530
|
sendHeartbeat() {
|
|
597
531
|
if (!this.socket) return;
|
|
598
532
|
this.socket.emit("projectRunner:heartbeat", {});
|
|
@@ -640,13 +574,13 @@ var ProjectConnection = class {
|
|
|
640
574
|
);
|
|
641
575
|
});
|
|
642
576
|
}
|
|
643
|
-
fetchChatHistory(limit
|
|
577
|
+
fetchChatHistory(limit) {
|
|
644
578
|
const socket = this.socket;
|
|
645
579
|
if (!socket) return Promise.reject(new Error("Not connected"));
|
|
646
580
|
return new Promise((resolve2, reject) => {
|
|
647
581
|
socket.emit(
|
|
648
582
|
"projectRunner:getChatHistory",
|
|
649
|
-
{ limit
|
|
583
|
+
{ limit },
|
|
650
584
|
(response) => {
|
|
651
585
|
if (response.success && response.data) resolve2(response.data);
|
|
652
586
|
else reject(new Error(response.error ?? "Failed to fetch chat history"));
|
|
@@ -654,84 +588,39 @@ var ProjectConnection = class {
|
|
|
654
588
|
);
|
|
655
589
|
});
|
|
656
590
|
}
|
|
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
|
-
}
|
|
689
|
-
emitNewCommitsDetected(data) {
|
|
690
|
-
if (!this.socket) return;
|
|
691
|
-
this.socket.emit("projectRunner:newCommitsDetected", data);
|
|
692
|
-
}
|
|
693
|
-
emitEnvironmentReady(data) {
|
|
694
|
-
if (!this.socket) return;
|
|
695
|
-
this.socket.emit("projectRunner:environmentReady", data);
|
|
696
|
-
}
|
|
697
|
-
emitEnvSwitchProgress(data) {
|
|
698
|
-
if (!this.socket) return;
|
|
699
|
-
this.socket.emit("projectRunner:envSwitchProgress", data);
|
|
700
|
-
}
|
|
701
|
-
handleRunAuthTokenCommand(userEmail, cb) {
|
|
702
|
-
try {
|
|
703
|
-
if (process.env.CODESPACES !== "true") {
|
|
704
|
-
cb({ ok: false, error: "Auth token command only available in codespace environments" });
|
|
705
|
-
return;
|
|
706
|
-
}
|
|
707
|
-
const authCmd = process.env.CONVEYOR_AUTH_TOKEN_COMMAND;
|
|
708
|
-
if (!authCmd) {
|
|
709
|
-
cb({ ok: false, error: "CONVEYOR_AUTH_TOKEN_COMMAND not configured" });
|
|
710
|
-
return;
|
|
711
|
-
}
|
|
712
|
-
const cwd = this.config.projectDir ?? process.cwd();
|
|
713
|
-
const token = runAuthTokenCommand(authCmd, userEmail, cwd);
|
|
714
|
-
if (!token) {
|
|
715
|
-
cb({
|
|
716
|
-
ok: false,
|
|
717
|
-
error: `Auth token command returned empty output. Command: ${authCmd}`
|
|
718
|
-
});
|
|
719
|
-
return;
|
|
720
|
-
}
|
|
721
|
-
cb({ ok: true, token });
|
|
722
|
-
} catch (error) {
|
|
723
|
-
cb({
|
|
724
|
-
ok: false,
|
|
725
|
-
error: error instanceof Error ? error.message : "Auth token command failed"
|
|
726
|
-
});
|
|
727
|
-
}
|
|
728
|
-
}
|
|
729
591
|
disconnect() {
|
|
730
592
|
this.socket?.disconnect();
|
|
731
593
|
this.socket = null;
|
|
732
594
|
}
|
|
733
595
|
};
|
|
734
596
|
|
|
597
|
+
// src/utils/logger.ts
|
|
598
|
+
import winston from "winston";
|
|
599
|
+
var { combine, timestamp, printf, colorize } = winston.format;
|
|
600
|
+
var customFormat = printf(({ level, message, timestamp: ts, service, ...meta }) => {
|
|
601
|
+
const svc = service ? `[${service}] ` : "";
|
|
602
|
+
const metaStr = Object.keys(meta).length ? ` ${JSON.stringify(meta)}` : "";
|
|
603
|
+
return `${ts} [${level}]: ${svc}${message}${metaStr}`;
|
|
604
|
+
});
|
|
605
|
+
var logger = winston.createLogger({
|
|
606
|
+
level: process.env.LOG_LEVEL ?? "info",
|
|
607
|
+
format: combine(timestamp({ format: "YYYY-MM-DD HH:mm:ss" }), combine(colorize(), customFormat)),
|
|
608
|
+
transports: [new winston.transports.Console()]
|
|
609
|
+
});
|
|
610
|
+
function createServiceLogger(serviceName) {
|
|
611
|
+
return logger.child({ service: serviceName });
|
|
612
|
+
}
|
|
613
|
+
function errorMeta(error) {
|
|
614
|
+
if (error instanceof Error) {
|
|
615
|
+
return {
|
|
616
|
+
message: error.message,
|
|
617
|
+
stack: error.stack,
|
|
618
|
+
..."code" in error && typeof error.code === "string" ? { code: error.code } : {}
|
|
619
|
+
};
|
|
620
|
+
}
|
|
621
|
+
return { message: String(error) };
|
|
622
|
+
}
|
|
623
|
+
|
|
735
624
|
// src/runner/worktree.ts
|
|
736
625
|
import { execSync as execSync2 } from "child_process";
|
|
737
626
|
import { existsSync } from "fs";
|
|
@@ -813,46 +702,11 @@ function unshallowRepo(workspaceDir) {
|
|
|
813
702
|
}
|
|
814
703
|
}
|
|
815
704
|
|
|
816
|
-
// src/utils/logger.ts
|
|
817
|
-
import winston from "winston";
|
|
818
|
-
var { combine, timestamp, printf, colorize } = winston.format;
|
|
819
|
-
var customFormat = printf(({ level, message, timestamp: ts, service, ...meta }) => {
|
|
820
|
-
const svc = service ? `[${service}] ` : "";
|
|
821
|
-
const metaStr = Object.keys(meta).length ? ` ${JSON.stringify(meta)}` : "";
|
|
822
|
-
return `${ts} [${level}]: ${svc}${message}${metaStr}`;
|
|
823
|
-
});
|
|
824
|
-
var logger = winston.createLogger({
|
|
825
|
-
level: process.env.LOG_LEVEL ?? "info",
|
|
826
|
-
format: combine(timestamp({ format: "YYYY-MM-DD HH:mm:ss" }), combine(colorize(), customFormat)),
|
|
827
|
-
transports: [new winston.transports.Console()]
|
|
828
|
-
});
|
|
829
|
-
function createServiceLogger(serviceName) {
|
|
830
|
-
return logger.child({ service: serviceName });
|
|
831
|
-
}
|
|
832
|
-
function errorMeta(error) {
|
|
833
|
-
if (error instanceof Error) {
|
|
834
|
-
return {
|
|
835
|
-
message: error.message,
|
|
836
|
-
stack: error.stack,
|
|
837
|
-
..."code" in error && typeof error.code === "string" ? { code: error.code } : {}
|
|
838
|
-
};
|
|
839
|
-
}
|
|
840
|
-
return { message: String(error) };
|
|
841
|
-
}
|
|
842
|
-
|
|
843
705
|
// src/runner/agent-runner.ts
|
|
844
706
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
845
707
|
import { execSync as execSync4 } from "child_process";
|
|
846
708
|
|
|
847
709
|
// src/execution/event-handlers.ts
|
|
848
|
-
function safeVoid(promise, context) {
|
|
849
|
-
if (promise && typeof promise.catch === "function") {
|
|
850
|
-
promise.catch((err) => {
|
|
851
|
-
process.stderr.write(`[safeVoid] ${context}: ${err}
|
|
852
|
-
`);
|
|
853
|
-
});
|
|
854
|
-
}
|
|
855
|
-
}
|
|
856
710
|
function epochSecondsToISO(value) {
|
|
857
711
|
if (typeof value === "string") return value;
|
|
858
712
|
if (typeof value !== "number" || value <= 0) return void 0;
|
|
@@ -891,10 +745,6 @@ async function processAssistantEvent(event, host, turnToolCalls) {
|
|
|
891
745
|
}
|
|
892
746
|
var API_ERROR_PATTERN = /API Error: [45]\d\d/;
|
|
893
747
|
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
|
-
}
|
|
898
748
|
function isRetriableMessage(msg) {
|
|
899
749
|
if (IMAGE_ERROR_PATTERN.test(msg)) return true;
|
|
900
750
|
if (API_ERROR_PATTERN.test(msg)) return true;
|
|
@@ -975,10 +825,6 @@ function handleErrorResult(event, host) {
|
|
|
975
825
|
if (isStaleSession) {
|
|
976
826
|
return { retriable: false, staleSession: true };
|
|
977
827
|
}
|
|
978
|
-
if (isAuthError(errorMsg)) {
|
|
979
|
-
host.connection.sendEvent({ type: "error", message: errorMsg });
|
|
980
|
-
return { retriable: false, authError: true };
|
|
981
|
-
}
|
|
982
828
|
const retriable = isRetriableMessage(errorMsg);
|
|
983
829
|
host.connection.sendEvent({ type: "error", message: errorMsg });
|
|
984
830
|
return { retriable };
|
|
@@ -1018,8 +864,7 @@ async function emitResultEvent(event, host, context, startTime, lastAssistantUsa
|
|
|
1018
864
|
return {
|
|
1019
865
|
retriable: result.retriable,
|
|
1020
866
|
resultSummary: result.resultSummary,
|
|
1021
|
-
staleSession: result.staleSession
|
|
1022
|
-
authError: result.authError
|
|
867
|
+
staleSession: result.staleSession
|
|
1023
868
|
};
|
|
1024
869
|
}
|
|
1025
870
|
function handleRateLimitEvent(event, host) {
|
|
@@ -1038,13 +883,13 @@ function handleRateLimitEvent(event, host) {
|
|
|
1038
883
|
const resetsAtDisplay = resetsAt ?? "unknown";
|
|
1039
884
|
const message = `Rate limit rejected (type: ${rate_limit_info.rateLimitType ?? "unknown"}, resets at: ${resetsAtDisplay})`;
|
|
1040
885
|
host.connection.sendEvent({ type: "error", message });
|
|
1041
|
-
|
|
886
|
+
void host.callbacks.onEvent({ type: "error", message });
|
|
1042
887
|
return resetsAt;
|
|
1043
888
|
} else if (status === "allowed_warning") {
|
|
1044
889
|
const utilization = rate_limit_info.utilization ? `${Math.round(rate_limit_info.utilization * 100)}%` : "high";
|
|
1045
890
|
const message = `Rate limit warning: ${utilization} utilization (type: ${rate_limit_info.rateLimitType ?? "unknown"})`;
|
|
1046
891
|
host.connection.sendEvent({ type: "thinking", message });
|
|
1047
|
-
|
|
892
|
+
void host.callbacks.onEvent({ type: "thinking", message });
|
|
1048
893
|
}
|
|
1049
894
|
return void 0;
|
|
1050
895
|
}
|
|
@@ -1062,46 +907,34 @@ async function handleSystemEvent(event, host, context, sessionIdStored) {
|
|
|
1062
907
|
}
|
|
1063
908
|
function handleSystemSubevents(systemEvent, host) {
|
|
1064
909
|
if (systemEvent.subtype === "compact_boundary") {
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
}),
|
|
1071
|
-
"compactBoundary"
|
|
1072
|
-
);
|
|
910
|
+
void host.callbacks.onEvent({
|
|
911
|
+
type: "context_compacted",
|
|
912
|
+
trigger: systemEvent.compact_metadata.trigger,
|
|
913
|
+
preTokens: systemEvent.compact_metadata.pre_tokens
|
|
914
|
+
});
|
|
1073
915
|
} else if (systemEvent.subtype === "task_started") {
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
}),
|
|
1080
|
-
"taskStarted"
|
|
1081
|
-
);
|
|
916
|
+
void host.callbacks.onEvent({
|
|
917
|
+
type: "subagent_started",
|
|
918
|
+
sdkTaskId: systemEvent.task_id,
|
|
919
|
+
description: systemEvent.description
|
|
920
|
+
});
|
|
1082
921
|
} else if (systemEvent.subtype === "task_progress") {
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
}),
|
|
1091
|
-
"taskProgress"
|
|
1092
|
-
);
|
|
922
|
+
void host.callbacks.onEvent({
|
|
923
|
+
type: "subagent_progress",
|
|
924
|
+
sdkTaskId: systemEvent.task_id,
|
|
925
|
+
description: systemEvent.description,
|
|
926
|
+
toolUses: systemEvent.usage?.tool_uses ?? 0,
|
|
927
|
+
durationMs: systemEvent.usage?.duration_ms ?? 0
|
|
928
|
+
});
|
|
1093
929
|
}
|
|
1094
930
|
}
|
|
1095
931
|
function handleToolProgressEvent(event, host) {
|
|
1096
932
|
const msg = event;
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
}),
|
|
1103
|
-
"toolProgress"
|
|
1104
|
-
);
|
|
933
|
+
void host.callbacks.onEvent({
|
|
934
|
+
type: "tool_progress",
|
|
935
|
+
toolName: msg.tool_name ?? "",
|
|
936
|
+
elapsedSeconds: msg.elapsed_time_seconds ?? 0
|
|
937
|
+
});
|
|
1105
938
|
}
|
|
1106
939
|
async function handleAssistantCase(event, host, turnToolCalls) {
|
|
1107
940
|
await processAssistantEvent(event, host, turnToolCalls);
|
|
@@ -1119,13 +952,11 @@ async function handleResultCase(event, host, context, startTime, isTyping, lastA
|
|
|
1119
952
|
retriable: resultInfo.retriable,
|
|
1120
953
|
resultSummary: resultInfo.resultSummary,
|
|
1121
954
|
staleSession: resultInfo.staleSession,
|
|
1122
|
-
authError: resultInfo.authError,
|
|
1123
955
|
stoppedTyping
|
|
1124
956
|
};
|
|
1125
957
|
}
|
|
1126
958
|
|
|
1127
959
|
// src/execution/event-processor.ts
|
|
1128
|
-
var API_ERROR_PATTERN2 = /API Error: [45]\d\d/;
|
|
1129
960
|
function stopTypingIfNeeded(host, isTyping) {
|
|
1130
961
|
if (isTyping) host.connection.sendTypingStop();
|
|
1131
962
|
}
|
|
@@ -1147,12 +978,6 @@ async function processAssistantCase(event, host, state) {
|
|
|
1147
978
|
}
|
|
1148
979
|
const usage = await handleAssistantCase(event, host, state.turnToolCalls);
|
|
1149
980
|
if (usage) state.lastAssistantUsage = usage;
|
|
1150
|
-
if (!state.sawApiError) {
|
|
1151
|
-
const fullText = event.message.content.filter((b) => b.type === "text").map((b) => b.text).join(" ");
|
|
1152
|
-
if (API_ERROR_PATTERN2.test(fullText)) {
|
|
1153
|
-
state.sawApiError = true;
|
|
1154
|
-
}
|
|
1155
|
-
}
|
|
1156
981
|
}
|
|
1157
982
|
async function processResultCase(event, host, context, startTime, state) {
|
|
1158
983
|
const info = await handleResultCase(
|
|
@@ -1167,7 +992,6 @@ async function processResultCase(event, host, context, startTime, state) {
|
|
|
1167
992
|
state.retriable = info.retriable;
|
|
1168
993
|
state.resultSummary = info.resultSummary;
|
|
1169
994
|
if (info.staleSession) state.staleSession = true;
|
|
1170
|
-
if (info.authError) state.authError = true;
|
|
1171
995
|
}
|
|
1172
996
|
async function processEvents(events, context, host) {
|
|
1173
997
|
const startTime = Date.now();
|
|
@@ -1177,11 +1001,9 @@ async function processEvents(events, context, host) {
|
|
|
1177
1001
|
sessionIdStored: false,
|
|
1178
1002
|
isTyping: false,
|
|
1179
1003
|
retriable: false,
|
|
1180
|
-
sawApiError: false,
|
|
1181
1004
|
resultSummary: void 0,
|
|
1182
1005
|
rateLimitResetsAt: void 0,
|
|
1183
1006
|
staleSession: void 0,
|
|
1184
|
-
authError: void 0,
|
|
1185
1007
|
lastAssistantUsage: void 0,
|
|
1186
1008
|
turnToolCalls: []
|
|
1187
1009
|
};
|
|
@@ -1218,11 +1040,10 @@ async function processEvents(events, context, host) {
|
|
|
1218
1040
|
}
|
|
1219
1041
|
stopTypingIfNeeded(host, state.isTyping);
|
|
1220
1042
|
return {
|
|
1221
|
-
retriable: state.retriable
|
|
1043
|
+
retriable: state.retriable,
|
|
1222
1044
|
resultSummary: state.resultSummary,
|
|
1223
1045
|
rateLimitResetsAt: state.rateLimitResetsAt,
|
|
1224
|
-
...state.staleSession && { staleSession: state.staleSession }
|
|
1225
|
-
...state.authError && { authError: state.authError }
|
|
1046
|
+
...state.staleSession && { staleSession: state.staleSession }
|
|
1226
1047
|
};
|
|
1227
1048
|
}
|
|
1228
1049
|
|
|
@@ -1580,8 +1401,6 @@ function buildDiscoveryPrompt(context) {
|
|
|
1580
1401
|
`You are in Discovery mode \u2014 helping plan and scope this task.`,
|
|
1581
1402
|
`- You have read-only codebase access (can read files, run git commands, search code)`,
|
|
1582
1403
|
`- You can write plan files in .claude/plans/ only \u2014 no other file writes`,
|
|
1583
|
-
`- Do NOT attempt to edit, write, or modify source code files \u2014 these operations will be denied`,
|
|
1584
|
-
`- If you identify code changes needed, describe them in the plan instead of implementing them`,
|
|
1585
1404
|
`- You can create and manage subtasks`,
|
|
1586
1405
|
`- Goal: collaborate with the user to create a clear plan`,
|
|
1587
1406
|
`- Proactively fill task properties (SP, tags, icon) as the plan takes shape`,
|
|
@@ -1716,14 +1535,6 @@ Project Agents:`);
|
|
|
1716
1535
|
parts.push(formatProjectAgentLine(pa));
|
|
1717
1536
|
}
|
|
1718
1537
|
}
|
|
1719
|
-
if (context.projectObjectives && context.projectObjectives.length > 0) {
|
|
1720
|
-
parts.push(`
|
|
1721
|
-
Project Objectives:`);
|
|
1722
|
-
for (const obj of context.projectObjectives) {
|
|
1723
|
-
const dates = `${obj.startDate.split("T")[0]} to ${obj.endDate.split("T")[0]}`;
|
|
1724
|
-
parts.push(`- **${obj.name}** (${dates})${obj.description ? ": " + obj.description : ""}`);
|
|
1725
|
-
}
|
|
1726
|
-
}
|
|
1727
1538
|
return parts;
|
|
1728
1539
|
}
|
|
1729
1540
|
function buildActivePreamble(context, workspaceDir) {
|
|
@@ -1846,7 +1657,7 @@ function detectRelaunchScenario(context, trustChatHistory = false) {
|
|
|
1846
1657
|
const hasNewUserMessages = messagesAfterAgent.some((m) => m.role === "user");
|
|
1847
1658
|
return hasNewUserMessages ? "feedback_relaunch" : "idle_relaunch";
|
|
1848
1659
|
}
|
|
1849
|
-
function buildRelaunchWithSession(mode, context, agentMode
|
|
1660
|
+
function buildRelaunchWithSession(mode, context, agentMode) {
|
|
1850
1661
|
const scenario = detectRelaunchScenario(context);
|
|
1851
1662
|
if (!context.claudeSessionId || scenario === "fresh") return null;
|
|
1852
1663
|
const parts = [];
|
|
@@ -1894,7 +1705,7 @@ Address the requested changes. Do NOT re-investigate the codebase from scratch o
|
|
|
1894
1705
|
`Run \`git log --oneline -10\` to review what you already committed.`,
|
|
1895
1706
|
`Review the current state of the codebase and verify everything is working correctly.`
|
|
1896
1707
|
);
|
|
1897
|
-
if (agentMode === "auto" || agentMode === "building"
|
|
1708
|
+
if (agentMode === "auto" || agentMode === "building") {
|
|
1898
1709
|
parts.push(
|
|
1899
1710
|
`If work is incomplete, continue implementing the plan. When finished, commit, push, and use mcp__conveyor__create_pull_request to open a PR.`,
|
|
1900
1711
|
`Do NOT go idle or wait for instructions \u2014 you are in auto mode.`
|
|
@@ -2100,7 +1911,7 @@ Address the requested changes directly. Do NOT re-investigate the codebase from
|
|
|
2100
1911
|
}
|
|
2101
1912
|
return parts;
|
|
2102
1913
|
}
|
|
2103
|
-
function buildInstructions(mode, context, scenario, agentMode
|
|
1914
|
+
function buildInstructions(mode, context, scenario, agentMode) {
|
|
2104
1915
|
const parts = [`
|
|
2105
1916
|
## Instructions`];
|
|
2106
1917
|
const isPm = mode === "pm";
|
|
@@ -2132,7 +1943,7 @@ function buildInstructions(mode, context, scenario, agentMode, isAuto) {
|
|
|
2132
1943
|
`Work on the git branch "${context.githubBranch}". Stay on this branch \u2014 do not checkout or create other branches.`,
|
|
2133
1944
|
`Run \`git log --oneline -10\` to review what you already committed, then verify the current state is correct.`
|
|
2134
1945
|
);
|
|
2135
|
-
if (agentMode === "auto" || agentMode === "building"
|
|
1946
|
+
if (agentMode === "auto" || agentMode === "building") {
|
|
2136
1947
|
parts.push(
|
|
2137
1948
|
`If work is incomplete, continue implementing the plan. When finished, commit, push, and use mcp__conveyor__create_pull_request to open a PR.`,
|
|
2138
1949
|
`Do NOT go idle or wait for instructions \u2014 you are in auto mode.`
|
|
@@ -2155,13 +1966,13 @@ function buildInstructions(mode, context, scenario, agentMode, isAuto) {
|
|
|
2155
1966
|
async function buildInitialPrompt(mode, context, isAuto, agentMode) {
|
|
2156
1967
|
const isPackRunner = mode === "pm" && !!isAuto && !!context.isParentTask;
|
|
2157
1968
|
if (!isPackRunner) {
|
|
2158
|
-
const sessionRelaunch = buildRelaunchWithSession(mode, context, agentMode
|
|
1969
|
+
const sessionRelaunch = buildRelaunchWithSession(mode, context, agentMode);
|
|
2159
1970
|
if (sessionRelaunch) return sessionRelaunch;
|
|
2160
1971
|
}
|
|
2161
1972
|
const isPm = mode === "pm";
|
|
2162
1973
|
const scenario = detectRelaunchScenario(context, isPm);
|
|
2163
1974
|
const body = await buildTaskBody(context);
|
|
2164
|
-
const instructions = isPackRunner ? buildPackRunnerInstructions(context, scenario) : buildInstructions(mode, context, scenario, agentMode
|
|
1975
|
+
const instructions = isPackRunner ? buildPackRunnerInstructions(context, scenario) : buildInstructions(mode, context, scenario, agentMode);
|
|
2165
1976
|
return [...body, ...instructions].join("\n");
|
|
2166
1977
|
}
|
|
2167
1978
|
|
|
@@ -2423,14 +2234,11 @@ function buildCreatePullRequestTool(connection) {
|
|
|
2423
2234
|
"Create a GitHub pull request for this task. Use this instead of gh CLI or git commands to create PRs.",
|
|
2424
2235
|
{
|
|
2425
2236
|
title: z.string().describe("The PR title"),
|
|
2426
|
-
body: z.string().describe("The PR description/body in markdown")
|
|
2427
|
-
branch: z.string().optional().describe(
|
|
2428
|
-
"The head branch name for the PR. If the task doesn't have a branch set, this will be used. Defaults to the task's existing branch."
|
|
2429
|
-
)
|
|
2237
|
+
body: z.string().describe("The PR description/body in markdown")
|
|
2430
2238
|
},
|
|
2431
|
-
async ({ title, body
|
|
2239
|
+
async ({ title, body }) => {
|
|
2432
2240
|
try {
|
|
2433
|
-
const result = await connection.createPR({ title, body
|
|
2241
|
+
const result = await connection.createPR({ title, body });
|
|
2434
2242
|
connection.sendEvent({
|
|
2435
2243
|
type: "pr_created",
|
|
2436
2244
|
url: result.url,
|
|
@@ -2918,9 +2726,7 @@ async function handleAskUserQuestion(host, input) {
|
|
|
2918
2726
|
}
|
|
2919
2727
|
return { behavior: "allow", updatedInput: { questions: input.questions, answers } };
|
|
2920
2728
|
}
|
|
2921
|
-
var DENIAL_WARNING_THRESHOLD = 3;
|
|
2922
2729
|
function buildCanUseTool(host) {
|
|
2923
|
-
let consecutiveDenials = 0;
|
|
2924
2730
|
return async (toolName, input) => {
|
|
2925
2731
|
if (toolName === "ExitPlanMode" && (host.agentMode === "auto" || host.agentMode === "discovery") && !host.hasExitedPlanMode) {
|
|
2926
2732
|
return await handleExitPlanMode(host, input);
|
|
@@ -2928,39 +2734,24 @@ function buildCanUseTool(host) {
|
|
|
2928
2734
|
if (toolName === "AskUserQuestion") {
|
|
2929
2735
|
return await handleAskUserQuestion(host, input);
|
|
2930
2736
|
}
|
|
2931
|
-
let result;
|
|
2932
2737
|
switch (host.agentMode) {
|
|
2933
2738
|
case "discovery":
|
|
2934
|
-
|
|
2935
|
-
break;
|
|
2739
|
+
return handleDiscoveryToolAccess(toolName, input);
|
|
2936
2740
|
case "building":
|
|
2937
|
-
|
|
2938
|
-
break;
|
|
2741
|
+
return handleBuildingToolAccess(toolName, input);
|
|
2939
2742
|
case "review":
|
|
2940
|
-
|
|
2941
|
-
break;
|
|
2743
|
+
return handleReviewToolAccess(toolName, input, host.isParentTask);
|
|
2942
2744
|
case "auto":
|
|
2943
|
-
|
|
2944
|
-
break;
|
|
2745
|
+
return handleAutoToolAccess(toolName, input, host.hasExitedPlanMode, host.isParentTask);
|
|
2945
2746
|
default:
|
|
2946
|
-
|
|
2747
|
+
return { behavior: "allow", updatedInput: input };
|
|
2947
2748
|
}
|
|
2948
|
-
if (result.behavior === "deny") {
|
|
2949
|
-
consecutiveDenials++;
|
|
2950
|
-
if (consecutiveDenials === DENIAL_WARNING_THRESHOLD) {
|
|
2951
|
-
host.connection.postChatMessage(
|
|
2952
|
-
`\u26A0\uFE0F Multiple tool denials detected. You are in ${host.agentMode} mode \u2014 file writes outside .claude/plans/ are not permitted. Focus on creating a plan instead of implementing code changes.`
|
|
2953
|
-
);
|
|
2954
|
-
}
|
|
2955
|
-
} else {
|
|
2956
|
-
consecutiveDenials = 0;
|
|
2957
|
-
}
|
|
2958
|
-
return result;
|
|
2959
2749
|
};
|
|
2960
2750
|
}
|
|
2961
2751
|
|
|
2962
2752
|
// src/execution/query-executor.ts
|
|
2963
|
-
var
|
|
2753
|
+
var logger2 = createServiceLogger("QueryExecutor");
|
|
2754
|
+
var API_ERROR_PATTERN2 = /API Error: [45]\d\d/;
|
|
2964
2755
|
var IMAGE_ERROR_PATTERN2 = /Could not process image/i;
|
|
2965
2756
|
var RETRY_DELAYS_MS = [6e4, 12e4, 18e4, 3e5];
|
|
2966
2757
|
function buildHooks(host) {
|
|
@@ -3048,7 +2839,10 @@ function buildQueryOptions(host, context) {
|
|
|
3048
2839
|
betas: settings.betas,
|
|
3049
2840
|
maxBudgetUsd: settings.maxBudgetUsd ?? 50,
|
|
3050
2841
|
disallowedTools: buildDisallowedTools(settings, mode, host.hasExitedPlanMode),
|
|
3051
|
-
enableFileCheckpointing: settings.enableFileCheckpointing
|
|
2842
|
+
enableFileCheckpointing: settings.enableFileCheckpointing,
|
|
2843
|
+
stderr: (data) => {
|
|
2844
|
+
logger2.warn("Claude Code stderr", { data: data.trimEnd() });
|
|
2845
|
+
}
|
|
3052
2846
|
};
|
|
3053
2847
|
if (isCloud && isReadOnly) {
|
|
3054
2848
|
baseOptions.sandbox = buildSandboxConfig(host);
|
|
@@ -3177,29 +2971,6 @@ async function buildRetryQuery(host, context, options, lastErrorWasImage) {
|
|
|
3177
2971
|
options: { ...options, resume: void 0 }
|
|
3178
2972
|
});
|
|
3179
2973
|
}
|
|
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
|
-
}
|
|
3203
2974
|
async function handleStaleSession(context, host, options) {
|
|
3204
2975
|
context.claudeSessionId = null;
|
|
3205
2976
|
host.connection.storeSessionId("");
|
|
@@ -3231,17 +3002,12 @@ function isStaleOrExitedSession(error, context) {
|
|
|
3231
3002
|
if (error.message.includes("No conversation found with session ID")) return true;
|
|
3232
3003
|
return !!context.claudeSessionId && error.message.includes("process exited");
|
|
3233
3004
|
}
|
|
3234
|
-
function getErrorMessage(error) {
|
|
3235
|
-
if (error instanceof Error) return error.message;
|
|
3236
|
-
if (typeof error === "string") return error;
|
|
3237
|
-
return String(error);
|
|
3238
|
-
}
|
|
3239
3005
|
function isRetriableError(error) {
|
|
3240
|
-
|
|
3241
|
-
return
|
|
3006
|
+
if (!(error instanceof Error)) return false;
|
|
3007
|
+
return API_ERROR_PATTERN2.test(error.message) || IMAGE_ERROR_PATTERN2.test(error.message);
|
|
3242
3008
|
}
|
|
3243
3009
|
function classifyImageError(error) {
|
|
3244
|
-
return IMAGE_ERROR_PATTERN2.test(
|
|
3010
|
+
return error instanceof Error && IMAGE_ERROR_PATTERN2.test(error.message);
|
|
3245
3011
|
}
|
|
3246
3012
|
async function emitRetryStatus(host, attempt, delayMs) {
|
|
3247
3013
|
const delayMin = Math.round(delayMs / 6e4);
|
|
@@ -3268,41 +3034,26 @@ function handleRetryError(error, context, host, options, prevImageError) {
|
|
|
3268
3034
|
if (isStaleOrExitedSession(error, context) && context.claudeSessionId) {
|
|
3269
3035
|
return handleStaleSession(context, host, options);
|
|
3270
3036
|
}
|
|
3271
|
-
if (isAuthError(getErrorMessage(error))) {
|
|
3272
|
-
return handleAuthError(context, host, options);
|
|
3273
|
-
}
|
|
3274
3037
|
if (!isRetriableError(error)) throw error;
|
|
3275
3038
|
return { action: "continue", lastErrorWasImage: classifyImageError(error) || prevImageError };
|
|
3276
3039
|
}
|
|
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
|
-
}
|
|
3295
3040
|
async function runWithRetry(initialQuery, context, host, options) {
|
|
3296
3041
|
let lastErrorWasImage = false;
|
|
3297
3042
|
for (let attempt = 0; attempt <= RETRY_DELAYS_MS.length; attempt++) {
|
|
3298
3043
|
if (host.isStopped()) return;
|
|
3299
3044
|
const agentQuery = attempt === 0 ? initialQuery : await buildRetryQuery(host, context, options, lastErrorWasImage);
|
|
3300
3045
|
try {
|
|
3301
|
-
const
|
|
3302
|
-
|
|
3303
|
-
if (
|
|
3304
|
-
|
|
3305
|
-
|
|
3046
|
+
const { retriable, resultSummary, modeRestart, rateLimitResetsAt, staleSession } = await processEvents(agentQuery, context, host);
|
|
3047
|
+
if (modeRestart || host.isStopped()) return;
|
|
3048
|
+
if (rateLimitResetsAt) {
|
|
3049
|
+
handleRateLimitPause(host, rateLimitResetsAt);
|
|
3050
|
+
return;
|
|
3051
|
+
}
|
|
3052
|
+
if (staleSession && context.claudeSessionId) {
|
|
3053
|
+
return handleStaleSession(context, host, options);
|
|
3054
|
+
}
|
|
3055
|
+
if (!retriable) return;
|
|
3056
|
+
lastErrorWasImage = IMAGE_ERROR_PATTERN2.test(resultSummary ?? "");
|
|
3306
3057
|
} catch (error) {
|
|
3307
3058
|
const outcome = handleRetryError(error, context, host, options, lastErrorWasImage);
|
|
3308
3059
|
if (outcome instanceof Promise) return outcome;
|
|
@@ -3682,7 +3433,7 @@ function buildQueryHost(deps) {
|
|
|
3682
3433
|
}
|
|
3683
3434
|
|
|
3684
3435
|
// src/runner/agent-runner.ts
|
|
3685
|
-
var
|
|
3436
|
+
var logger3 = createServiceLogger("AgentRunner");
|
|
3686
3437
|
var HEARTBEAT_INTERVAL_MS = 3e4;
|
|
3687
3438
|
var IDLE_TIMEOUT_MS = 30 * 60 * 1e3;
|
|
3688
3439
|
var AgentRunner = class {
|
|
@@ -3971,7 +3722,7 @@ var AgentRunner = class {
|
|
|
3971
3722
|
const s = this.taskContext.agentSettings ?? this.config.agentSettings ?? {};
|
|
3972
3723
|
const model = this.taskContext.model || this.config.model;
|
|
3973
3724
|
const thinking = formatThinkingSetting(s.thinking);
|
|
3974
|
-
|
|
3725
|
+
logger3.info("Effective agent settings", {
|
|
3975
3726
|
model,
|
|
3976
3727
|
mode: this.config.mode ?? "task",
|
|
3977
3728
|
effort: s.effort ?? "default",
|
|
@@ -4015,7 +3766,7 @@ var AgentRunner = class {
|
|
|
4015
3766
|
this.idleTimer = setTimeout(() => {
|
|
4016
3767
|
this.clearIdleTimers();
|
|
4017
3768
|
this.inputResolver = null;
|
|
4018
|
-
|
|
3769
|
+
logger3.info("Idle timeout reached, shutting down", {
|
|
4019
3770
|
idleMinutes: IDLE_TIMEOUT_MS / 6e4
|
|
4020
3771
|
});
|
|
4021
3772
|
this.connection.postChatMessage(
|
|
@@ -4132,269 +3883,12 @@ var AgentRunner = class {
|
|
|
4132
3883
|
|
|
4133
3884
|
// src/runner/project-runner.ts
|
|
4134
3885
|
import { fork } from "child_process";
|
|
4135
|
-
import { execSync as
|
|
3886
|
+
import { execSync as execSync5 } from "child_process";
|
|
4136
3887
|
import * as path from "path";
|
|
4137
3888
|
import { fileURLToPath } from "url";
|
|
4138
3889
|
|
|
4139
|
-
// src/runner/commit-watcher.ts
|
|
4140
|
-
import { execSync as execSync5 } from "child_process";
|
|
4141
|
-
var logger3 = createServiceLogger("CommitWatcher");
|
|
4142
|
-
var CommitWatcher = class {
|
|
4143
|
-
constructor(config, callbacks) {
|
|
4144
|
-
this.config = config;
|
|
4145
|
-
this.callbacks = callbacks;
|
|
4146
|
-
}
|
|
4147
|
-
interval = null;
|
|
4148
|
-
lastKnownRemoteSha = null;
|
|
4149
|
-
branch = null;
|
|
4150
|
-
debounceTimer = null;
|
|
4151
|
-
isSyncing = false;
|
|
4152
|
-
start(branch) {
|
|
4153
|
-
this.stop();
|
|
4154
|
-
this.branch = branch;
|
|
4155
|
-
this.lastKnownRemoteSha = this.getLocalHeadSha();
|
|
4156
|
-
this.interval = setInterval(() => void this.poll(), this.config.pollIntervalMs);
|
|
4157
|
-
logger3.info("Commit watcher started", {
|
|
4158
|
-
branch,
|
|
4159
|
-
baseSha: this.lastKnownRemoteSha?.slice(0, 8)
|
|
4160
|
-
});
|
|
4161
|
-
}
|
|
4162
|
-
stop() {
|
|
4163
|
-
if (this.interval) clearInterval(this.interval);
|
|
4164
|
-
if (this.debounceTimer) clearTimeout(this.debounceTimer);
|
|
4165
|
-
this.interval = null;
|
|
4166
|
-
this.debounceTimer = null;
|
|
4167
|
-
this.branch = null;
|
|
4168
|
-
this.lastKnownRemoteSha = null;
|
|
4169
|
-
this.isSyncing = false;
|
|
4170
|
-
}
|
|
4171
|
-
getLocalHeadSha() {
|
|
4172
|
-
return execSync5("git rev-parse HEAD", {
|
|
4173
|
-
cwd: this.config.projectDir,
|
|
4174
|
-
stdio: ["ignore", "pipe", "ignore"]
|
|
4175
|
-
}).toString().trim();
|
|
4176
|
-
}
|
|
4177
|
-
poll() {
|
|
4178
|
-
if (!this.branch || this.isSyncing) return;
|
|
4179
|
-
try {
|
|
4180
|
-
execSync5(`git fetch origin ${this.branch} --quiet`, {
|
|
4181
|
-
cwd: this.config.projectDir,
|
|
4182
|
-
stdio: "ignore",
|
|
4183
|
-
timeout: 3e4
|
|
4184
|
-
});
|
|
4185
|
-
const remoteSha = execSync5(`git rev-parse origin/${this.branch}`, {
|
|
4186
|
-
cwd: this.config.projectDir,
|
|
4187
|
-
stdio: ["ignore", "pipe", "ignore"]
|
|
4188
|
-
}).toString().trim();
|
|
4189
|
-
if (remoteSha !== this.lastKnownRemoteSha) {
|
|
4190
|
-
if (this.debounceTimer) clearTimeout(this.debounceTimer);
|
|
4191
|
-
this.debounceTimer = setTimeout(
|
|
4192
|
-
() => void this.handleNewCommits(remoteSha),
|
|
4193
|
-
this.config.debounceMs
|
|
4194
|
-
);
|
|
4195
|
-
}
|
|
4196
|
-
} catch {
|
|
4197
|
-
}
|
|
4198
|
-
}
|
|
4199
|
-
async handleNewCommits(remoteSha) {
|
|
4200
|
-
if (!this.branch) return;
|
|
4201
|
-
const previousSha = this.lastKnownRemoteSha ?? "HEAD";
|
|
4202
|
-
let commitCount = 1;
|
|
4203
|
-
let latestMessage = "";
|
|
4204
|
-
let latestAuthor = "";
|
|
4205
|
-
try {
|
|
4206
|
-
const countOutput = execSync5(`git rev-list --count ${previousSha}..origin/${this.branch}`, {
|
|
4207
|
-
cwd: this.config.projectDir,
|
|
4208
|
-
stdio: ["ignore", "pipe", "ignore"]
|
|
4209
|
-
}).toString().trim();
|
|
4210
|
-
commitCount = parseInt(countOutput, 10) || 1;
|
|
4211
|
-
const logOutput = execSync5(`git log -1 --format="%s|||%an" origin/${this.branch}`, {
|
|
4212
|
-
cwd: this.config.projectDir,
|
|
4213
|
-
stdio: ["ignore", "pipe", "ignore"]
|
|
4214
|
-
}).toString().trim();
|
|
4215
|
-
const parts = logOutput.split("|||");
|
|
4216
|
-
latestMessage = parts[0] ?? "";
|
|
4217
|
-
latestAuthor = parts[1] ?? "";
|
|
4218
|
-
} catch {
|
|
4219
|
-
}
|
|
4220
|
-
this.lastKnownRemoteSha = remoteSha;
|
|
4221
|
-
this.isSyncing = true;
|
|
4222
|
-
logger3.info("New commits detected", {
|
|
4223
|
-
branch: this.branch,
|
|
4224
|
-
commitCount,
|
|
4225
|
-
sha: remoteSha.slice(0, 8)
|
|
4226
|
-
});
|
|
4227
|
-
try {
|
|
4228
|
-
await this.callbacks.onNewCommits({
|
|
4229
|
-
branch: this.branch,
|
|
4230
|
-
previousSha,
|
|
4231
|
-
newCommitSha: remoteSha,
|
|
4232
|
-
commitCount,
|
|
4233
|
-
latestMessage,
|
|
4234
|
-
latestAuthor
|
|
4235
|
-
});
|
|
4236
|
-
} catch (err) {
|
|
4237
|
-
logger3.error("Error handling new commits", errorMeta(err));
|
|
4238
|
-
} finally {
|
|
4239
|
-
this.isSyncing = false;
|
|
4240
|
-
}
|
|
4241
|
-
}
|
|
4242
|
-
};
|
|
4243
|
-
|
|
4244
|
-
// src/runner/project-chat-handler.ts
|
|
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
3890
|
// src/runner/project-chat-handler.ts
|
|
3891
|
+
import { query as query2 } from "@anthropic-ai/claude-agent-sdk";
|
|
4398
3892
|
var logger4 = createServiceLogger("ProjectChat");
|
|
4399
3893
|
var FALLBACK_MODEL = "claude-sonnet-4-20250514";
|
|
4400
3894
|
function buildSystemPrompt2(projectDir, agentCtx) {
|
|
@@ -4451,7 +3945,7 @@ function processContentBlock(block, responseParts, turnToolCalls) {
|
|
|
4451
3945
|
logger4.debug("Tool use", { tool: block.name });
|
|
4452
3946
|
}
|
|
4453
3947
|
}
|
|
4454
|
-
async function fetchContext(connection
|
|
3948
|
+
async function fetchContext(connection) {
|
|
4455
3949
|
let agentCtx = null;
|
|
4456
3950
|
try {
|
|
4457
3951
|
agentCtx = await connection.fetchAgentContext();
|
|
@@ -4460,19 +3954,15 @@ async function fetchContext(connection, chatId) {
|
|
|
4460
3954
|
}
|
|
4461
3955
|
let chatHistory = [];
|
|
4462
3956
|
try {
|
|
4463
|
-
chatHistory = await connection.fetchChatHistory(30
|
|
3957
|
+
chatHistory = await connection.fetchChatHistory(30);
|
|
4464
3958
|
} catch {
|
|
4465
3959
|
logger4.warn("Could not fetch chat history, proceeding without it");
|
|
4466
3960
|
}
|
|
4467
3961
|
return { agentCtx, chatHistory };
|
|
4468
3962
|
}
|
|
4469
|
-
function buildChatQueryOptions(agentCtx, projectDir
|
|
3963
|
+
function buildChatQueryOptions(agentCtx, projectDir) {
|
|
4470
3964
|
const model = agentCtx?.model || FALLBACK_MODEL;
|
|
4471
3965
|
const settings = agentCtx?.agentSettings ?? {};
|
|
4472
|
-
const mcpServer = createSdkMcpServer2({
|
|
4473
|
-
name: "conveyor",
|
|
4474
|
-
tools: buildProjectTools(connection)
|
|
4475
|
-
});
|
|
4476
3966
|
return {
|
|
4477
3967
|
model,
|
|
4478
3968
|
systemPrompt: {
|
|
@@ -4484,48 +3974,12 @@ function buildChatQueryOptions(agentCtx, projectDir, connection) {
|
|
|
4484
3974
|
permissionMode: "bypassPermissions",
|
|
4485
3975
|
allowDangerouslySkipPermissions: true,
|
|
4486
3976
|
tools: { type: "preset", preset: "claude_code" },
|
|
4487
|
-
|
|
4488
|
-
|
|
4489
|
-
maxBudgetUsd: settings.maxBudgetUsd ?? 50,
|
|
3977
|
+
maxTurns: settings.maxTurns ?? 15,
|
|
3978
|
+
maxBudgetUsd: settings.maxBudgetUsd ?? 5,
|
|
4490
3979
|
effort: settings.effort,
|
|
4491
3980
|
thinking: settings.thinking
|
|
4492
3981
|
};
|
|
4493
3982
|
}
|
|
4494
|
-
function emitResultCostAndContext(event, connection) {
|
|
4495
|
-
const resultEvent = event;
|
|
4496
|
-
if (resultEvent.total_cost_usd !== void 0 && resultEvent.total_cost_usd > 0) {
|
|
4497
|
-
connection.emitEvent({
|
|
4498
|
-
type: "cost_update",
|
|
4499
|
-
costUsd: resultEvent.total_cost_usd
|
|
4500
|
-
});
|
|
4501
|
-
}
|
|
4502
|
-
if (resultEvent.modelUsage && typeof resultEvent.modelUsage === "object") {
|
|
4503
|
-
const modelUsage = resultEvent.modelUsage;
|
|
4504
|
-
let contextWindow = 0;
|
|
4505
|
-
let totalInputTokens = 0;
|
|
4506
|
-
let totalCacheRead = 0;
|
|
4507
|
-
let totalCacheCreation = 0;
|
|
4508
|
-
for (const data of Object.values(modelUsage)) {
|
|
4509
|
-
const d = data;
|
|
4510
|
-
totalInputTokens += d.inputTokens ?? 0;
|
|
4511
|
-
totalCacheRead += d.cacheReadInputTokens ?? 0;
|
|
4512
|
-
totalCacheCreation += d.cacheCreationInputTokens ?? 0;
|
|
4513
|
-
const cw = d.contextWindow ?? 0;
|
|
4514
|
-
if (cw > contextWindow) contextWindow = cw;
|
|
4515
|
-
}
|
|
4516
|
-
if (contextWindow > 0) {
|
|
4517
|
-
const queryInputTokens = totalInputTokens + totalCacheRead + totalCacheCreation;
|
|
4518
|
-
connection.emitEvent({
|
|
4519
|
-
type: "context_update",
|
|
4520
|
-
contextTokens: queryInputTokens,
|
|
4521
|
-
contextWindow,
|
|
4522
|
-
inputTokens: totalInputTokens,
|
|
4523
|
-
cacheReadInputTokens: totalCacheRead,
|
|
4524
|
-
cacheCreationInputTokens: totalCacheCreation
|
|
4525
|
-
});
|
|
4526
|
-
}
|
|
4527
|
-
}
|
|
4528
|
-
}
|
|
4529
3983
|
function processEventStream(event, connection, responseParts, turnToolCalls, isTyping) {
|
|
4530
3984
|
if (event.type === "assistant") {
|
|
4531
3985
|
if (!isTyping.value) {
|
|
@@ -4547,30 +4001,19 @@ function processEventStream(event, connection, responseParts, turnToolCalls, isT
|
|
|
4547
4001
|
connection.emitEvent({ type: "agent_typing_stop" });
|
|
4548
4002
|
isTyping.value = false;
|
|
4549
4003
|
}
|
|
4550
|
-
emitResultCostAndContext(event, connection);
|
|
4551
4004
|
return true;
|
|
4552
4005
|
}
|
|
4553
4006
|
return false;
|
|
4554
4007
|
}
|
|
4555
|
-
async function runChatQuery(message, connection, projectDir
|
|
4556
|
-
const { agentCtx, chatHistory } = await fetchContext(connection
|
|
4557
|
-
const options = buildChatQueryOptions(agentCtx, projectDir
|
|
4008
|
+
async function runChatQuery(message, connection, projectDir) {
|
|
4009
|
+
const { agentCtx, chatHistory } = await fetchContext(connection);
|
|
4010
|
+
const options = buildChatQueryOptions(agentCtx, projectDir);
|
|
4558
4011
|
const prompt = buildPrompt(message, chatHistory);
|
|
4559
|
-
|
|
4560
|
-
const events = query2({
|
|
4561
|
-
prompt,
|
|
4562
|
-
options,
|
|
4563
|
-
...sessionId ? { resume: sessionId } : {}
|
|
4564
|
-
});
|
|
4012
|
+
const events = query2({ prompt, options });
|
|
4565
4013
|
const responseParts = [];
|
|
4566
4014
|
const turnToolCalls = [];
|
|
4567
4015
|
const isTyping = { value: false };
|
|
4568
|
-
let resultSessionId;
|
|
4569
4016
|
for await (const event of events) {
|
|
4570
|
-
if (event.type === "result") {
|
|
4571
|
-
const resultEvent = event;
|
|
4572
|
-
resultSessionId = resultEvent.sessionId;
|
|
4573
|
-
}
|
|
4574
4017
|
const done = processEventStream(event, connection, responseParts, turnToolCalls, isTyping);
|
|
4575
4018
|
if (done) break;
|
|
4576
4019
|
}
|
|
@@ -4581,416 +4024,26 @@ async function runChatQuery(message, connection, projectDir, sessionId) {
|
|
|
4581
4024
|
if (responseText) {
|
|
4582
4025
|
await connection.emitChatMessage(responseText);
|
|
4583
4026
|
}
|
|
4584
|
-
return resultSessionId;
|
|
4585
4027
|
}
|
|
4586
|
-
async function handleProjectChatMessage(message, connection, projectDir
|
|
4587
|
-
connection.emitAgentStatus("
|
|
4028
|
+
async function handleProjectChatMessage(message, connection, projectDir) {
|
|
4029
|
+
connection.emitAgentStatus("busy");
|
|
4588
4030
|
try {
|
|
4589
|
-
|
|
4031
|
+
await runChatQuery(message, connection, projectDir);
|
|
4590
4032
|
} catch (error) {
|
|
4591
4033
|
logger4.error("Failed to handle message", errorMeta(error));
|
|
4592
|
-
connection.emitAgentStatus("error");
|
|
4593
4034
|
try {
|
|
4594
4035
|
await connection.emitChatMessage(
|
|
4595
4036
|
"I encountered an error processing your message. Please try again."
|
|
4596
4037
|
);
|
|
4597
4038
|
} catch {
|
|
4598
4039
|
}
|
|
4599
|
-
return void 0;
|
|
4600
|
-
} finally {
|
|
4601
|
-
connection.emitAgentStatus("idle");
|
|
4602
|
-
}
|
|
4603
|
-
}
|
|
4604
|
-
|
|
4605
|
-
// src/runner/project-audit-handler.ts
|
|
4606
|
-
import { query as query3 } from "@anthropic-ai/claude-agent-sdk";
|
|
4607
|
-
|
|
4608
|
-
// src/tools/audit-tools.ts
|
|
4609
|
-
import { randomUUID as randomUUID3 } from "crypto";
|
|
4610
|
-
import { tool as tool5, createSdkMcpServer as createSdkMcpServer3 } from "@anthropic-ai/claude-agent-sdk";
|
|
4611
|
-
import { z as z5 } from "zod";
|
|
4612
|
-
function mapCreateTag(input) {
|
|
4613
|
-
return {
|
|
4614
|
-
type: "create_tag",
|
|
4615
|
-
tagName: input.name,
|
|
4616
|
-
suggestion: `Create new tag "${input.name}"${input.description ? `: ${input.description}` : ""}`,
|
|
4617
|
-
reasoning: input.reasoning,
|
|
4618
|
-
payload: { name: input.name, color: input.color ?? "#6B7280", description: input.description }
|
|
4619
|
-
};
|
|
4620
|
-
}
|
|
4621
|
-
function mapUpdateDescription(input) {
|
|
4622
|
-
return {
|
|
4623
|
-
type: "update_description",
|
|
4624
|
-
tagId: input.tagId,
|
|
4625
|
-
tagName: input.tagName,
|
|
4626
|
-
suggestion: `Update description for "${input.tagName}"`,
|
|
4627
|
-
reasoning: input.reasoning,
|
|
4628
|
-
payload: { description: input.description }
|
|
4629
|
-
};
|
|
4630
|
-
}
|
|
4631
|
-
function mapContextLink(input) {
|
|
4632
|
-
return {
|
|
4633
|
-
type: "add_context_link",
|
|
4634
|
-
tagId: input.tagId,
|
|
4635
|
-
tagName: input.tagName,
|
|
4636
|
-
suggestion: `Link ${input.linkType}:${input.path} to "${input.tagName}"`,
|
|
4637
|
-
reasoning: input.reasoning,
|
|
4638
|
-
payload: { contextLink: { type: input.linkType, path: input.path, label: input.label } }
|
|
4639
|
-
};
|
|
4640
|
-
}
|
|
4641
|
-
function mapDocGap(input) {
|
|
4642
|
-
return {
|
|
4643
|
-
type: "documentation_gap",
|
|
4644
|
-
tagId: input.tagId,
|
|
4645
|
-
tagName: input.tagName,
|
|
4646
|
-
suggestion: `Documentation gap: ${input.filePath} (${input.readCount} reads)`,
|
|
4647
|
-
reasoning: input.reasoning,
|
|
4648
|
-
payload: {
|
|
4649
|
-
filePath: input.filePath,
|
|
4650
|
-
readCount: input.readCount,
|
|
4651
|
-
suggestedAction: input.suggestedAction
|
|
4652
|
-
}
|
|
4653
|
-
};
|
|
4654
|
-
}
|
|
4655
|
-
function mapMergeTags(input) {
|
|
4656
|
-
return {
|
|
4657
|
-
type: "merge_tags",
|
|
4658
|
-
tagId: input.tagId,
|
|
4659
|
-
tagName: input.tagName,
|
|
4660
|
-
suggestion: `Merge "${input.tagName}" into "${input.mergeIntoTagName}"`,
|
|
4661
|
-
reasoning: input.reasoning,
|
|
4662
|
-
payload: { mergeIntoTagId: input.mergeIntoTagId }
|
|
4663
|
-
};
|
|
4664
|
-
}
|
|
4665
|
-
function mapRenameTag(input) {
|
|
4666
|
-
return {
|
|
4667
|
-
type: "rename_tag",
|
|
4668
|
-
tagId: input.tagId,
|
|
4669
|
-
tagName: input.tagName,
|
|
4670
|
-
suggestion: `Rename "${input.tagName}" to "${input.newName}"`,
|
|
4671
|
-
reasoning: input.reasoning,
|
|
4672
|
-
payload: { newName: input.newName }
|
|
4673
|
-
};
|
|
4674
|
-
}
|
|
4675
|
-
var TOOL_MAPPERS = {
|
|
4676
|
-
recommend_create_tag: mapCreateTag,
|
|
4677
|
-
recommend_update_description: mapUpdateDescription,
|
|
4678
|
-
recommend_context_link: mapContextLink,
|
|
4679
|
-
flag_documentation_gap: mapDocGap,
|
|
4680
|
-
recommend_merge_tags: mapMergeTags,
|
|
4681
|
-
recommend_rename_tag: mapRenameTag
|
|
4682
|
-
};
|
|
4683
|
-
function collectRecommendation(toolName, input, collector, onRecommendation) {
|
|
4684
|
-
const mapper = TOOL_MAPPERS[toolName];
|
|
4685
|
-
if (!mapper) return JSON.stringify({ error: `Unknown tool: ${toolName}` });
|
|
4686
|
-
const rec = { id: randomUUID3(), ...mapper(input) };
|
|
4687
|
-
collector.recommendations.push(rec);
|
|
4688
|
-
onRecommendation?.({ tagName: rec.tagName ?? rec.type, type: rec.type });
|
|
4689
|
-
return JSON.stringify({ success: true, recommendationId: rec.id });
|
|
4690
|
-
}
|
|
4691
|
-
function createAuditMcpServer(collector, onRecommendation) {
|
|
4692
|
-
const auditTools = [
|
|
4693
|
-
tool5(
|
|
4694
|
-
"recommend_create_tag",
|
|
4695
|
-
"Recommend creating a new tag for an uncovered subsystem or area",
|
|
4696
|
-
{
|
|
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")
|
|
4701
|
-
},
|
|
4702
|
-
async (args) => {
|
|
4703
|
-
const result = collectRecommendation(
|
|
4704
|
-
"recommend_create_tag",
|
|
4705
|
-
args,
|
|
4706
|
-
collector,
|
|
4707
|
-
onRecommendation
|
|
4708
|
-
);
|
|
4709
|
-
return { content: [{ type: "text", text: result }] };
|
|
4710
|
-
}
|
|
4711
|
-
),
|
|
4712
|
-
tool5(
|
|
4713
|
-
"recommend_update_description",
|
|
4714
|
-
"Recommend updating a tag's description to better reflect its scope",
|
|
4715
|
-
{
|
|
4716
|
-
tagId: z5.string(),
|
|
4717
|
-
tagName: z5.string(),
|
|
4718
|
-
description: z5.string().describe("Proposed new description"),
|
|
4719
|
-
reasoning: z5.string()
|
|
4720
|
-
},
|
|
4721
|
-
async (args) => {
|
|
4722
|
-
const result = collectRecommendation(
|
|
4723
|
-
"recommend_update_description",
|
|
4724
|
-
args,
|
|
4725
|
-
collector,
|
|
4726
|
-
onRecommendation
|
|
4727
|
-
);
|
|
4728
|
-
return { content: [{ type: "text", text: result }] };
|
|
4729
|
-
}
|
|
4730
|
-
),
|
|
4731
|
-
tool5(
|
|
4732
|
-
"recommend_context_link",
|
|
4733
|
-
"Recommend linking a doc, rule, file, or folder to a tag's contextPaths",
|
|
4734
|
-
{
|
|
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()
|
|
4741
|
-
},
|
|
4742
|
-
async (args) => {
|
|
4743
|
-
const result = collectRecommendation(
|
|
4744
|
-
"recommend_context_link",
|
|
4745
|
-
args,
|
|
4746
|
-
collector,
|
|
4747
|
-
onRecommendation
|
|
4748
|
-
);
|
|
4749
|
-
return { content: [{ type: "text", text: result }] };
|
|
4750
|
-
}
|
|
4751
|
-
),
|
|
4752
|
-
tool5(
|
|
4753
|
-
"flag_documentation_gap",
|
|
4754
|
-
"Flag a file that agents read heavily but has no tag documentation linked",
|
|
4755
|
-
{
|
|
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()
|
|
4762
|
-
},
|
|
4763
|
-
async (args) => {
|
|
4764
|
-
const result = collectRecommendation(
|
|
4765
|
-
"flag_documentation_gap",
|
|
4766
|
-
args,
|
|
4767
|
-
collector,
|
|
4768
|
-
onRecommendation
|
|
4769
|
-
);
|
|
4770
|
-
return { content: [{ type: "text", text: result }] };
|
|
4771
|
-
}
|
|
4772
|
-
),
|
|
4773
|
-
tool5(
|
|
4774
|
-
"recommend_merge_tags",
|
|
4775
|
-
"Recommend merging one tag into another",
|
|
4776
|
-
{
|
|
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()
|
|
4782
|
-
},
|
|
4783
|
-
async (args) => {
|
|
4784
|
-
const result = collectRecommendation(
|
|
4785
|
-
"recommend_merge_tags",
|
|
4786
|
-
args,
|
|
4787
|
-
collector,
|
|
4788
|
-
onRecommendation
|
|
4789
|
-
);
|
|
4790
|
-
return { content: [{ type: "text", text: result }] };
|
|
4791
|
-
}
|
|
4792
|
-
),
|
|
4793
|
-
tool5(
|
|
4794
|
-
"recommend_rename_tag",
|
|
4795
|
-
"Recommend renaming a tag",
|
|
4796
|
-
{
|
|
4797
|
-
tagId: z5.string(),
|
|
4798
|
-
tagName: z5.string().describe("Current tag name"),
|
|
4799
|
-
newName: z5.string().describe("Proposed new name"),
|
|
4800
|
-
reasoning: z5.string()
|
|
4801
|
-
},
|
|
4802
|
-
async (args) => {
|
|
4803
|
-
const result = collectRecommendation(
|
|
4804
|
-
"recommend_rename_tag",
|
|
4805
|
-
args,
|
|
4806
|
-
collector,
|
|
4807
|
-
onRecommendation
|
|
4808
|
-
);
|
|
4809
|
-
return { content: [{ type: "text", text: result }] };
|
|
4810
|
-
}
|
|
4811
|
-
),
|
|
4812
|
-
tool5(
|
|
4813
|
-
"complete_audit",
|
|
4814
|
-
"Signal that the audit is complete with a summary of all findings",
|
|
4815
|
-
{ summary: z5.string().describe("Brief overview of all findings") },
|
|
4816
|
-
async (args) => {
|
|
4817
|
-
collector.complete = true;
|
|
4818
|
-
collector.summary = args.summary ?? "Audit completed.";
|
|
4819
|
-
return { content: [{ type: "text", text: JSON.stringify({ success: true }) }] };
|
|
4820
|
-
}
|
|
4821
|
-
)
|
|
4822
|
-
];
|
|
4823
|
-
return createSdkMcpServer3({
|
|
4824
|
-
name: "tag-audit",
|
|
4825
|
-
tools: auditTools
|
|
4826
|
-
});
|
|
4827
|
-
}
|
|
4828
|
-
|
|
4829
|
-
// src/runner/project-audit-handler.ts
|
|
4830
|
-
var logger5 = createServiceLogger("ProjectAudit");
|
|
4831
|
-
var FALLBACK_MODEL2 = "claude-sonnet-4-20250514";
|
|
4832
|
-
function buildTagSection(tags) {
|
|
4833
|
-
if (tags.length === 0) return "No tags configured yet.";
|
|
4834
|
-
return tags.map((t) => {
|
|
4835
|
-
const paths = t.contextPaths ?? [];
|
|
4836
|
-
const pathStr = paths.length > 0 ? `
|
|
4837
|
-
Context links: ${paths.map((p) => `${p.type}:${p.path}`).join(", ")}` : "";
|
|
4838
|
-
return ` - ${t.name} (id: ${t.id})${t.description ? `: ${t.description}` : " [no description]"}${pathStr}
|
|
4839
|
-
Active tasks: ${t.activeTaskCount}`;
|
|
4840
|
-
}).join("\n");
|
|
4841
|
-
}
|
|
4842
|
-
function buildHeatmapSection(entries) {
|
|
4843
|
-
if (entries.length === 0) return "No file read analytics data available.";
|
|
4844
|
-
return entries.slice(0, 50).map((e) => {
|
|
4845
|
-
const tagBreakdown = Object.entries(e.byTag).sort(([, a], [, b]) => b - a).map(([tag, count]) => `${tag}:${count}`).join(", ");
|
|
4846
|
-
return ` ${e.filePath} \u2014 ${e.totalReads} reads${tagBreakdown ? ` (${tagBreakdown})` : ""}`;
|
|
4847
|
-
}).join("\n");
|
|
4848
|
-
}
|
|
4849
|
-
function buildAuditSystemPrompt(projectName, tags, heatmapData, projectDir) {
|
|
4850
|
-
return [
|
|
4851
|
-
"You are a project organization expert analyzing tag taxonomy for a software project.",
|
|
4852
|
-
"Tags are used to categorize tasks and link relevant documentation/rules/files to subsystems.",
|
|
4853
|
-
"",
|
|
4854
|
-
`PROJECT: ${projectName}`,
|
|
4855
|
-
"",
|
|
4856
|
-
`EXISTING TAGS (${tags.length}):`,
|
|
4857
|
-
buildTagSection(tags),
|
|
4858
|
-
"",
|
|
4859
|
-
"FILE READ ANALYTICS (what agents actually read, by tag):",
|
|
4860
|
-
buildHeatmapSection(heatmapData),
|
|
4861
|
-
"",
|
|
4862
|
-
`You have full access to the codebase at: ${projectDir}`,
|
|
4863
|
-
"Use your file reading and searching tools to understand the codebase structure,",
|
|
4864
|
-
"module boundaries, and architectural patterns before making recommendations.",
|
|
4865
|
-
"",
|
|
4866
|
-
"ANALYSIS TASKS:",
|
|
4867
|
-
"1. Read actual source files to understand code areas and module boundaries",
|
|
4868
|
-
"2. Search for imports, class definitions, and architectural patterns",
|
|
4869
|
-
"3. Coverage: Are all major subsystems/services represented by tags?",
|
|
4870
|
-
"4. Descriptions: Do all tags have clear, useful descriptions?",
|
|
4871
|
-
"5. Context Links: Are relevant rules/docs/folders linked to tags via contextPaths?",
|
|
4872
|
-
"6. Documentation Gaps: Which high-read files lack linked documentation?",
|
|
4873
|
-
"7. Cleanup: Any tags that should be merged, renamed, or removed?",
|
|
4874
|
-
"",
|
|
4875
|
-
"Use the tag-audit MCP tools to submit each recommendation.",
|
|
4876
|
-
"Call complete_audit when you are done with a thorough summary.",
|
|
4877
|
-
"Be comprehensive \u2014 recommend all improvements your analysis supports.",
|
|
4878
|
-
"Analyze actual file contents, not just file names."
|
|
4879
|
-
].join("\n");
|
|
4880
|
-
}
|
|
4881
|
-
function emitToolCallProgress(event, request, connection) {
|
|
4882
|
-
if (event.type !== "assistant") return;
|
|
4883
|
-
const assistantEvent = event;
|
|
4884
|
-
for (const block of assistantEvent.message.content) {
|
|
4885
|
-
if (block.type === "tool_use" && block.name) {
|
|
4886
|
-
const inputStr = typeof block.input === "string" ? block.input : JSON.stringify(block.input);
|
|
4887
|
-
connection.emitAuditProgress({
|
|
4888
|
-
requestId: request.requestId,
|
|
4889
|
-
activity: {
|
|
4890
|
-
tool: block.name,
|
|
4891
|
-
input: inputStr.slice(0, 500),
|
|
4892
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
4893
|
-
}
|
|
4894
|
-
});
|
|
4895
|
-
}
|
|
4896
|
-
}
|
|
4897
|
-
}
|
|
4898
|
-
async function runAuditQuery(request, connection, projectDir) {
|
|
4899
|
-
connection.emitAgentStatus("fetching_context");
|
|
4900
|
-
let agentCtx = null;
|
|
4901
|
-
try {
|
|
4902
|
-
agentCtx = await connection.fetchAgentContext();
|
|
4903
|
-
} catch {
|
|
4904
|
-
logger5.warn("Could not fetch agent context for audit, using defaults");
|
|
4905
|
-
}
|
|
4906
|
-
connection.emitAgentStatus("running");
|
|
4907
|
-
const model = agentCtx?.model || FALLBACK_MODEL2;
|
|
4908
|
-
const settings = agentCtx?.agentSettings ?? {};
|
|
4909
|
-
const collector = {
|
|
4910
|
-
recommendations: [],
|
|
4911
|
-
summary: "Audit completed.",
|
|
4912
|
-
complete: false
|
|
4913
|
-
};
|
|
4914
|
-
const onRecommendation = (rec) => {
|
|
4915
|
-
connection.emitEvent({
|
|
4916
|
-
type: "audit_recommendation",
|
|
4917
|
-
tagName: rec.tagName,
|
|
4918
|
-
recommendationType: rec.type
|
|
4919
|
-
});
|
|
4920
|
-
};
|
|
4921
|
-
const systemPrompt = buildAuditSystemPrompt(
|
|
4922
|
-
request.projectName,
|
|
4923
|
-
request.tags,
|
|
4924
|
-
request.fileHeatmap,
|
|
4925
|
-
projectDir
|
|
4926
|
-
);
|
|
4927
|
-
const userPrompt = [
|
|
4928
|
-
"Analyze the project's tag taxonomy and submit recommendations using the tag-audit MCP tools.",
|
|
4929
|
-
`There are currently ${request.tags.length} tags configured.`,
|
|
4930
|
-
request.fileHeatmap.length > 0 ? `File analytics show ${request.fileHeatmap.length} files with read activity.` : "No file read analytics available.",
|
|
4931
|
-
"",
|
|
4932
|
-
"Start by exploring the codebase structure, then analyze each tag for accuracy and completeness.",
|
|
4933
|
-
"Call complete_audit when done."
|
|
4934
|
-
].join("\n");
|
|
4935
|
-
const events = query3({
|
|
4936
|
-
prompt: userPrompt,
|
|
4937
|
-
options: {
|
|
4938
|
-
model,
|
|
4939
|
-
systemPrompt: { type: "preset", preset: "claude_code", append: systemPrompt },
|
|
4940
|
-
cwd: projectDir,
|
|
4941
|
-
permissionMode: "bypassPermissions",
|
|
4942
|
-
allowDangerouslySkipPermissions: true,
|
|
4943
|
-
tools: { type: "preset", preset: "claude_code" },
|
|
4944
|
-
mcpServers: { "tag-audit": createAuditMcpServer(collector, onRecommendation) },
|
|
4945
|
-
maxTurns: settings.maxTurns ?? 75,
|
|
4946
|
-
maxBudgetUsd: settings.maxBudgetUsd ?? 5,
|
|
4947
|
-
effort: settings.effort,
|
|
4948
|
-
thinking: settings.thinking
|
|
4949
|
-
}
|
|
4950
|
-
});
|
|
4951
|
-
const responseParts = [];
|
|
4952
|
-
const turnToolCalls = [];
|
|
4953
|
-
const isTyping = { value: false };
|
|
4954
|
-
for await (const event of events) {
|
|
4955
|
-
emitToolCallProgress(event, request, connection);
|
|
4956
|
-
const done = processEventStream(event, connection, responseParts, turnToolCalls, isTyping);
|
|
4957
|
-
if (done) break;
|
|
4958
|
-
}
|
|
4959
|
-
if (isTyping.value) {
|
|
4960
|
-
connection.emitEvent({ type: "agent_typing_stop" });
|
|
4961
|
-
}
|
|
4962
|
-
return collector;
|
|
4963
|
-
}
|
|
4964
|
-
async function handleProjectAuditRequest(request, connection, projectDir) {
|
|
4965
|
-
connection.emitAgentStatus("running");
|
|
4966
|
-
try {
|
|
4967
|
-
const collector = await runAuditQuery(request, connection, projectDir);
|
|
4968
|
-
const result = {
|
|
4969
|
-
recommendations: collector.recommendations,
|
|
4970
|
-
summary: collector.summary,
|
|
4971
|
-
analyzedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
4972
|
-
};
|
|
4973
|
-
logger5.info("Tag audit completed", {
|
|
4974
|
-
requestId: request.requestId,
|
|
4975
|
-
recommendationCount: result.recommendations.length
|
|
4976
|
-
});
|
|
4977
|
-
connection.emitAuditResult({ requestId: request.requestId, result });
|
|
4978
|
-
} catch (error) {
|
|
4979
|
-
logger5.error("Tag audit failed", {
|
|
4980
|
-
requestId: request.requestId,
|
|
4981
|
-
...errorMeta(error)
|
|
4982
|
-
});
|
|
4983
|
-
connection.emitAuditResult({
|
|
4984
|
-
requestId: request.requestId,
|
|
4985
|
-
error: error instanceof Error ? error.message : "Tag audit failed"
|
|
4986
|
-
});
|
|
4987
4040
|
} finally {
|
|
4988
4041
|
connection.emitAgentStatus("idle");
|
|
4989
4042
|
}
|
|
4990
4043
|
}
|
|
4991
4044
|
|
|
4992
4045
|
// src/runner/project-runner.ts
|
|
4993
|
-
var
|
|
4046
|
+
var logger5 = createServiceLogger("ProjectRunner");
|
|
4994
4047
|
var __filename = fileURLToPath(import.meta.url);
|
|
4995
4048
|
var __dirname = path.dirname(__filename);
|
|
4996
4049
|
var HEARTBEAT_INTERVAL_MS2 = 3e4;
|
|
@@ -5009,12 +4062,12 @@ function setupWorkDir(projectDir, assignment) {
|
|
|
5009
4062
|
}
|
|
5010
4063
|
if (branch && branch !== devBranch) {
|
|
5011
4064
|
try {
|
|
5012
|
-
|
|
4065
|
+
execSync5(`git checkout ${branch}`, { cwd: workDir, stdio: "ignore" });
|
|
5013
4066
|
} catch {
|
|
5014
4067
|
try {
|
|
5015
|
-
|
|
4068
|
+
execSync5(`git checkout -b ${branch}`, { cwd: workDir, stdio: "ignore" });
|
|
5016
4069
|
} catch {
|
|
5017
|
-
|
|
4070
|
+
logger5.warn("Could not checkout branch", { taskId: shortId, branch });
|
|
5018
4071
|
}
|
|
5019
4072
|
}
|
|
5020
4073
|
}
|
|
@@ -5053,13 +4106,13 @@ function spawnChildAgent(assignment, workDir) {
|
|
|
5053
4106
|
child.stdout?.on("data", (data) => {
|
|
5054
4107
|
const lines = data.toString().trimEnd().split("\n");
|
|
5055
4108
|
for (const line of lines) {
|
|
5056
|
-
|
|
4109
|
+
logger5.info(line, { taskId: shortId });
|
|
5057
4110
|
}
|
|
5058
4111
|
});
|
|
5059
4112
|
child.stderr?.on("data", (data) => {
|
|
5060
4113
|
const lines = data.toString().trimEnd().split("\n");
|
|
5061
4114
|
for (const line of lines) {
|
|
5062
|
-
|
|
4115
|
+
logger5.error(line, { taskId: shortId });
|
|
5063
4116
|
}
|
|
5064
4117
|
});
|
|
5065
4118
|
return child;
|
|
@@ -5071,60 +4124,27 @@ var ProjectRunner = class {
|
|
|
5071
4124
|
heartbeatTimer = null;
|
|
5072
4125
|
stopping = false;
|
|
5073
4126
|
resolveLifecycle = null;
|
|
5074
|
-
chatSessionIds = /* @__PURE__ */ new Map();
|
|
5075
4127
|
// Start command process management
|
|
5076
4128
|
startCommandChild = null;
|
|
5077
4129
|
startCommandRunning = false;
|
|
5078
4130
|
setupComplete = false;
|
|
5079
|
-
branchSwitchCommand;
|
|
5080
|
-
commitWatcher;
|
|
5081
4131
|
constructor(config) {
|
|
5082
4132
|
this.projectDir = config.projectDir;
|
|
5083
4133
|
this.connection = new ProjectConnection({
|
|
5084
4134
|
apiUrl: config.conveyorApiUrl,
|
|
5085
4135
|
projectToken: config.projectToken,
|
|
5086
|
-
projectId: config.projectId
|
|
5087
|
-
projectDir: config.projectDir
|
|
4136
|
+
projectId: config.projectId
|
|
5088
4137
|
});
|
|
5089
|
-
this.commitWatcher = new CommitWatcher(
|
|
5090
|
-
{
|
|
5091
|
-
projectDir: this.projectDir,
|
|
5092
|
-
pollIntervalMs: Number(process.env.CONVEYOR_COMMIT_POLL_INTERVAL) || 1e4,
|
|
5093
|
-
debounceMs: 3e3
|
|
5094
|
-
},
|
|
5095
|
-
{
|
|
5096
|
-
onNewCommits: async (data) => {
|
|
5097
|
-
this.connection.emitNewCommitsDetected({
|
|
5098
|
-
branch: data.branch,
|
|
5099
|
-
commitCount: data.commitCount,
|
|
5100
|
-
latestCommit: {
|
|
5101
|
-
sha: data.newCommitSha,
|
|
5102
|
-
message: data.latestMessage,
|
|
5103
|
-
author: data.latestAuthor
|
|
5104
|
-
},
|
|
5105
|
-
autoSyncing: true
|
|
5106
|
-
});
|
|
5107
|
-
const startTime = Date.now();
|
|
5108
|
-
const stepsRun = await this.smartSync(data.previousSha, data.newCommitSha, data.branch);
|
|
5109
|
-
this.connection.emitEnvironmentReady({
|
|
5110
|
-
branch: data.branch,
|
|
5111
|
-
commitsSynced: data.commitCount,
|
|
5112
|
-
syncDurationMs: Date.now() - startTime,
|
|
5113
|
-
stepsRun
|
|
5114
|
-
});
|
|
5115
|
-
}
|
|
5116
|
-
}
|
|
5117
|
-
);
|
|
5118
4138
|
}
|
|
5119
4139
|
checkoutWorkspaceBranch() {
|
|
5120
4140
|
const workspaceBranch = process.env.CONVEYOR_WORKSPACE_BRANCH;
|
|
5121
4141
|
if (!workspaceBranch) return;
|
|
5122
4142
|
try {
|
|
5123
|
-
|
|
5124
|
-
|
|
5125
|
-
|
|
4143
|
+
execSync5(`git fetch origin ${workspaceBranch}`, { cwd: this.projectDir, stdio: "pipe" });
|
|
4144
|
+
execSync5(`git checkout ${workspaceBranch}`, { cwd: this.projectDir, stdio: "pipe" });
|
|
4145
|
+
logger5.info("Checked out workspace branch", { workspaceBranch });
|
|
5126
4146
|
} catch (err) {
|
|
5127
|
-
|
|
4147
|
+
logger5.warn("Failed to checkout workspace branch, continuing on current branch", {
|
|
5128
4148
|
workspaceBranch,
|
|
5129
4149
|
...errorMeta(err)
|
|
5130
4150
|
});
|
|
@@ -5133,15 +4153,15 @@ var ProjectRunner = class {
|
|
|
5133
4153
|
async executeSetupCommand() {
|
|
5134
4154
|
const cmd = process.env.CONVEYOR_SETUP_COMMAND;
|
|
5135
4155
|
if (!cmd) return;
|
|
5136
|
-
|
|
4156
|
+
logger5.info("Running setup command", { command: cmd });
|
|
5137
4157
|
try {
|
|
5138
4158
|
await runSetupCommand(cmd, this.projectDir, (stream, data) => {
|
|
5139
4159
|
this.connection.emitEvent({ type: "setup_output", stream, data });
|
|
5140
4160
|
(stream === "stderr" ? process.stderr : process.stdout).write(data);
|
|
5141
4161
|
});
|
|
5142
|
-
|
|
4162
|
+
logger5.info("Setup command completed");
|
|
5143
4163
|
} catch (error) {
|
|
5144
|
-
|
|
4164
|
+
logger5.error("Setup command failed", errorMeta(error));
|
|
5145
4165
|
this.connection.emitEvent({
|
|
5146
4166
|
type: "setup_error",
|
|
5147
4167
|
message: error instanceof Error ? error.message : "Setup command failed"
|
|
@@ -5152,7 +4172,7 @@ var ProjectRunner = class {
|
|
|
5152
4172
|
executeStartCommand() {
|
|
5153
4173
|
const cmd = process.env.CONVEYOR_START_COMMAND;
|
|
5154
4174
|
if (!cmd) return;
|
|
5155
|
-
|
|
4175
|
+
logger5.info("Running start command", { command: cmd });
|
|
5156
4176
|
const child = runStartCommand(cmd, this.projectDir, (stream, data) => {
|
|
5157
4177
|
this.connection.emitEvent({ type: "start_command_output", stream, data });
|
|
5158
4178
|
(stream === "stderr" ? process.stderr : process.stdout).write(data);
|
|
@@ -5162,7 +4182,7 @@ var ProjectRunner = class {
|
|
|
5162
4182
|
child.on("exit", (code, signal) => {
|
|
5163
4183
|
this.startCommandRunning = false;
|
|
5164
4184
|
this.startCommandChild = null;
|
|
5165
|
-
|
|
4185
|
+
logger5.info("Start command exited", { code, signal });
|
|
5166
4186
|
this.connection.emitEvent({
|
|
5167
4187
|
type: "start_command_exited",
|
|
5168
4188
|
code,
|
|
@@ -5173,13 +4193,13 @@ var ProjectRunner = class {
|
|
|
5173
4193
|
child.on("error", (err) => {
|
|
5174
4194
|
this.startCommandRunning = false;
|
|
5175
4195
|
this.startCommandChild = null;
|
|
5176
|
-
|
|
4196
|
+
logger5.error("Start command error", errorMeta(err));
|
|
5177
4197
|
});
|
|
5178
4198
|
}
|
|
5179
4199
|
async killStartCommand() {
|
|
5180
4200
|
const child = this.startCommandChild;
|
|
5181
4201
|
if (!child || !this.startCommandRunning) return;
|
|
5182
|
-
|
|
4202
|
+
logger5.info("Killing start command");
|
|
5183
4203
|
try {
|
|
5184
4204
|
if (child.pid) process.kill(-child.pid, "SIGTERM");
|
|
5185
4205
|
} catch {
|
|
@@ -5211,7 +4231,7 @@ var ProjectRunner = class {
|
|
|
5211
4231
|
getEnvironmentStatus() {
|
|
5212
4232
|
let currentBranch = "unknown";
|
|
5213
4233
|
try {
|
|
5214
|
-
currentBranch =
|
|
4234
|
+
currentBranch = execSync5("git branch --show-current", {
|
|
5215
4235
|
cwd: this.projectDir,
|
|
5216
4236
|
stdio: ["ignore", "pipe", "ignore"]
|
|
5217
4237
|
}).toString().trim();
|
|
@@ -5224,180 +4244,6 @@ var ProjectRunner = class {
|
|
|
5224
4244
|
previewPort: Number(process.env.CONVEYOR_PREVIEW_PORT) || null
|
|
5225
4245
|
};
|
|
5226
4246
|
}
|
|
5227
|
-
getCurrentBranch() {
|
|
5228
|
-
try {
|
|
5229
|
-
return execSync6("git branch --show-current", {
|
|
5230
|
-
cwd: this.projectDir,
|
|
5231
|
-
stdio: ["ignore", "pipe", "ignore"]
|
|
5232
|
-
}).toString().trim() || null;
|
|
5233
|
-
} catch {
|
|
5234
|
-
return null;
|
|
5235
|
-
}
|
|
5236
|
-
}
|
|
5237
|
-
// oxlint-disable-next-line max-lines-per-function, complexity -- sequential sync steps with per-step error handling
|
|
5238
|
-
async smartSync(previousSha, newSha, branch) {
|
|
5239
|
-
const stepsRun = [];
|
|
5240
|
-
const status = execSync6("git status --porcelain", {
|
|
5241
|
-
cwd: this.projectDir,
|
|
5242
|
-
stdio: ["ignore", "pipe", "ignore"]
|
|
5243
|
-
}).toString().trim();
|
|
5244
|
-
if (status) {
|
|
5245
|
-
this.connection.emitEvent({
|
|
5246
|
-
type: "commit_watch_warning",
|
|
5247
|
-
message: "Working tree has uncommitted changes. Auto-pull skipped."
|
|
5248
|
-
});
|
|
5249
|
-
return ["skipped:dirty_tree"];
|
|
5250
|
-
}
|
|
5251
|
-
await this.killStartCommand();
|
|
5252
|
-
this.connection.emitEnvSwitchProgress({ step: "pull", status: "running" });
|
|
5253
|
-
try {
|
|
5254
|
-
execSync6(`git pull origin ${branch}`, {
|
|
5255
|
-
cwd: this.projectDir,
|
|
5256
|
-
stdio: "pipe",
|
|
5257
|
-
timeout: 6e4
|
|
5258
|
-
});
|
|
5259
|
-
stepsRun.push("pull");
|
|
5260
|
-
this.connection.emitEnvSwitchProgress({ step: "pull", status: "success" });
|
|
5261
|
-
} catch (err) {
|
|
5262
|
-
const message = err instanceof Error ? err.message : "Pull failed";
|
|
5263
|
-
this.connection.emitEnvSwitchProgress({ step: "pull", status: "error", message });
|
|
5264
|
-
logger6.error("Git pull failed during commit sync", errorMeta(err));
|
|
5265
|
-
this.executeStartCommand();
|
|
5266
|
-
return ["error:pull"];
|
|
5267
|
-
}
|
|
5268
|
-
let changedFiles = [];
|
|
5269
|
-
try {
|
|
5270
|
-
changedFiles = execSync6(`git diff --name-only ${previousSha}..${newSha}`, {
|
|
5271
|
-
cwd: this.projectDir,
|
|
5272
|
-
stdio: ["ignore", "pipe", "ignore"]
|
|
5273
|
-
}).toString().trim().split("\n").filter(Boolean);
|
|
5274
|
-
} catch {
|
|
5275
|
-
}
|
|
5276
|
-
const needsInstall = changedFiles.some(
|
|
5277
|
-
(f) => f === "package.json" || f === "bun.lockb" || f === "bunfig.toml" || f.endsWith("/package.json") || f.endsWith("/bun.lockb")
|
|
5278
|
-
);
|
|
5279
|
-
const needsPrisma = changedFiles.some(
|
|
5280
|
-
(f) => f.includes("prisma/schema.prisma") || f.includes("prisma/migrations/")
|
|
5281
|
-
);
|
|
5282
|
-
const cmd = this.branchSwitchCommand ?? process.env.CONVEYOR_BRANCH_SWITCH_COMMAND;
|
|
5283
|
-
if (cmd && (needsInstall || needsPrisma)) {
|
|
5284
|
-
this.connection.emitEnvSwitchProgress({ step: "sync", status: "running" });
|
|
5285
|
-
try {
|
|
5286
|
-
await runSetupCommand(cmd, this.projectDir, (stream, data) => {
|
|
5287
|
-
this.connection.emitEvent({ type: "sync_output", stream, data });
|
|
5288
|
-
});
|
|
5289
|
-
stepsRun.push("branchSwitchCommand");
|
|
5290
|
-
this.connection.emitEnvSwitchProgress({ step: "sync", status: "success" });
|
|
5291
|
-
} catch (err) {
|
|
5292
|
-
const message = err instanceof Error ? err.message : "Sync command failed";
|
|
5293
|
-
this.connection.emitEnvSwitchProgress({ step: "sync", status: "error", message });
|
|
5294
|
-
logger6.error("Branch switch command failed during commit sync", errorMeta(err));
|
|
5295
|
-
}
|
|
5296
|
-
} else if (!cmd) {
|
|
5297
|
-
if (needsInstall) {
|
|
5298
|
-
this.connection.emitEnvSwitchProgress({ step: "install", status: "running" });
|
|
5299
|
-
try {
|
|
5300
|
-
execSync6("bun install", { cwd: this.projectDir, timeout: 12e4, stdio: "pipe" });
|
|
5301
|
-
stepsRun.push("install");
|
|
5302
|
-
this.connection.emitEnvSwitchProgress({ step: "install", status: "success" });
|
|
5303
|
-
} catch (err) {
|
|
5304
|
-
const message = err instanceof Error ? err.message : "Install failed";
|
|
5305
|
-
this.connection.emitEnvSwitchProgress({ step: "install", status: "error", message });
|
|
5306
|
-
logger6.error("bun install failed during commit sync", errorMeta(err));
|
|
5307
|
-
}
|
|
5308
|
-
}
|
|
5309
|
-
if (needsPrisma) {
|
|
5310
|
-
this.connection.emitEnvSwitchProgress({ step: "prisma", status: "running" });
|
|
5311
|
-
try {
|
|
5312
|
-
execSync6("bunx prisma generate", {
|
|
5313
|
-
cwd: this.projectDir,
|
|
5314
|
-
timeout: 6e4,
|
|
5315
|
-
stdio: "pipe"
|
|
5316
|
-
});
|
|
5317
|
-
execSync6("bunx prisma db push --accept-data-loss", {
|
|
5318
|
-
cwd: this.projectDir,
|
|
5319
|
-
timeout: 6e4,
|
|
5320
|
-
stdio: "pipe"
|
|
5321
|
-
});
|
|
5322
|
-
stepsRun.push("prisma");
|
|
5323
|
-
this.connection.emitEnvSwitchProgress({ step: "prisma", status: "success" });
|
|
5324
|
-
} catch (err) {
|
|
5325
|
-
const message = err instanceof Error ? err.message : "Prisma sync failed";
|
|
5326
|
-
this.connection.emitEnvSwitchProgress({ step: "prisma", status: "error", message });
|
|
5327
|
-
logger6.error("Prisma sync failed during commit sync", errorMeta(err));
|
|
5328
|
-
}
|
|
5329
|
-
}
|
|
5330
|
-
}
|
|
5331
|
-
this.executeStartCommand();
|
|
5332
|
-
stepsRun.push("startCommand");
|
|
5333
|
-
return stepsRun;
|
|
5334
|
-
}
|
|
5335
|
-
async handleSwitchBranch(data, callback) {
|
|
5336
|
-
const { branch, syncAfter } = data;
|
|
5337
|
-
try {
|
|
5338
|
-
this.connection.emitEnvSwitchProgress({ step: "fetch", status: "running" });
|
|
5339
|
-
try {
|
|
5340
|
-
execSync6("git fetch origin", { cwd: this.projectDir, stdio: "pipe" });
|
|
5341
|
-
} catch {
|
|
5342
|
-
logger6.warn("Git fetch failed during branch switch");
|
|
5343
|
-
}
|
|
5344
|
-
this.connection.emitEnvSwitchProgress({ step: "fetch", status: "success" });
|
|
5345
|
-
this.connection.emitEnvSwitchProgress({ step: "checkout", status: "running" });
|
|
5346
|
-
try {
|
|
5347
|
-
execSync6(`git checkout ${branch}`, { cwd: this.projectDir, stdio: "pipe" });
|
|
5348
|
-
} catch (err) {
|
|
5349
|
-
const message = err instanceof Error ? err.message : "Checkout failed";
|
|
5350
|
-
this.connection.emitEnvSwitchProgress({ step: "checkout", status: "error", message });
|
|
5351
|
-
callback({ ok: false, error: `Failed to checkout branch: ${message}` });
|
|
5352
|
-
return;
|
|
5353
|
-
}
|
|
5354
|
-
try {
|
|
5355
|
-
execSync6(`git pull origin ${branch}`, { cwd: this.projectDir, stdio: "pipe" });
|
|
5356
|
-
} catch {
|
|
5357
|
-
logger6.warn("Git pull failed during branch switch", { branch });
|
|
5358
|
-
}
|
|
5359
|
-
this.connection.emitEnvSwitchProgress({ step: "checkout", status: "success" });
|
|
5360
|
-
if (syncAfter !== false) {
|
|
5361
|
-
await this.handleSyncEnvironment();
|
|
5362
|
-
}
|
|
5363
|
-
this.commitWatcher.start(branch);
|
|
5364
|
-
callback({ ok: true, data: this.getEnvironmentStatus() });
|
|
5365
|
-
} catch (err) {
|
|
5366
|
-
const message = err instanceof Error ? err.message : "Branch switch failed";
|
|
5367
|
-
logger6.error("Branch switch failed", errorMeta(err));
|
|
5368
|
-
callback({ ok: false, error: message });
|
|
5369
|
-
}
|
|
5370
|
-
}
|
|
5371
|
-
async handleSyncEnvironment(callback) {
|
|
5372
|
-
try {
|
|
5373
|
-
await this.killStartCommand();
|
|
5374
|
-
const cmd = this.branchSwitchCommand ?? process.env.CONVEYOR_BRANCH_SWITCH_COMMAND;
|
|
5375
|
-
if (cmd) {
|
|
5376
|
-
this.connection.emitEnvSwitchProgress({ step: "sync", status: "running" });
|
|
5377
|
-
try {
|
|
5378
|
-
await runSetupCommand(cmd, this.projectDir, (stream, data) => {
|
|
5379
|
-
this.connection.emitEvent({ type: "sync_output", stream, data });
|
|
5380
|
-
(stream === "stderr" ? process.stderr : process.stdout).write(data);
|
|
5381
|
-
});
|
|
5382
|
-
this.connection.emitEnvSwitchProgress({ step: "sync", status: "success" });
|
|
5383
|
-
} catch (err) {
|
|
5384
|
-
const message = err instanceof Error ? err.message : "Sync command failed";
|
|
5385
|
-
this.connection.emitEnvSwitchProgress({ step: "sync", status: "error", message });
|
|
5386
|
-
logger6.error("Branch switch sync command failed", errorMeta(err));
|
|
5387
|
-
}
|
|
5388
|
-
}
|
|
5389
|
-
this.executeStartCommand();
|
|
5390
|
-
this.connection.emitEnvSwitchProgress({ step: "startCommand", status: "success" });
|
|
5391
|
-
callback?.({ ok: true, data: this.getEnvironmentStatus() });
|
|
5392
|
-
} catch (err) {
|
|
5393
|
-
const message = err instanceof Error ? err.message : "Sync failed";
|
|
5394
|
-
logger6.error("Environment sync failed", errorMeta(err));
|
|
5395
|
-
callback?.({ ok: false, error: message });
|
|
5396
|
-
}
|
|
5397
|
-
}
|
|
5398
|
-
handleGetEnvStatus(callback) {
|
|
5399
|
-
callback({ ok: true, data: this.getEnvironmentStatus() });
|
|
5400
|
-
}
|
|
5401
4247
|
async start() {
|
|
5402
4248
|
this.checkoutWorkspaceBranch();
|
|
5403
4249
|
await this.connection.connect();
|
|
@@ -5411,7 +4257,7 @@ var ProjectRunner = class {
|
|
|
5411
4257
|
startCommandRunning: this.startCommandRunning
|
|
5412
4258
|
});
|
|
5413
4259
|
} catch (error) {
|
|
5414
|
-
|
|
4260
|
+
logger5.error("Environment setup failed", errorMeta(error));
|
|
5415
4261
|
this.setupComplete = false;
|
|
5416
4262
|
}
|
|
5417
4263
|
this.connection.onTaskAssignment((assignment) => {
|
|
@@ -5421,53 +4267,17 @@ var ProjectRunner = class {
|
|
|
5421
4267
|
this.handleStopTask(data.taskId);
|
|
5422
4268
|
});
|
|
5423
4269
|
this.connection.onShutdown(() => {
|
|
5424
|
-
|
|
4270
|
+
logger5.info("Received shutdown signal from server");
|
|
5425
4271
|
void this.stop();
|
|
5426
4272
|
});
|
|
5427
4273
|
this.connection.onChatMessage((msg) => {
|
|
5428
|
-
|
|
5429
|
-
|
|
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
|
-
);
|
|
5438
|
-
});
|
|
5439
|
-
this.connection.onAuditRequest((request) => {
|
|
5440
|
-
logger6.debug("Received tag audit request", { requestId: request.requestId });
|
|
5441
|
-
void handleProjectAuditRequest(request, this.connection, this.projectDir);
|
|
4274
|
+
logger5.debug("Received project chat message");
|
|
4275
|
+
void handleProjectChatMessage(msg, this.connection, this.projectDir);
|
|
5442
4276
|
});
|
|
5443
|
-
this.connection.onSwitchBranch = (data, cb) => {
|
|
5444
|
-
void this.handleSwitchBranch(data, cb);
|
|
5445
|
-
};
|
|
5446
|
-
this.connection.onSyncEnvironment = (cb) => {
|
|
5447
|
-
void this.handleSyncEnvironment(cb);
|
|
5448
|
-
};
|
|
5449
|
-
this.connection.onGetEnvStatus = (cb) => {
|
|
5450
|
-
this.handleGetEnvStatus(cb);
|
|
5451
|
-
};
|
|
5452
|
-
this.connection.onRestartStartCommand = (cb) => {
|
|
5453
|
-
void this.restartStartCommand().then(() => cb({ ok: true })).catch(
|
|
5454
|
-
(err) => cb({ ok: false, error: err instanceof Error ? err.message : "Restart failed" })
|
|
5455
|
-
);
|
|
5456
|
-
};
|
|
5457
|
-
try {
|
|
5458
|
-
const context = await this.connection.fetchAgentContext();
|
|
5459
|
-
this.branchSwitchCommand = context?.branchSwitchCommand ?? process.env.CONVEYOR_BRANCH_SWITCH_COMMAND;
|
|
5460
|
-
} catch {
|
|
5461
|
-
this.branchSwitchCommand = process.env.CONVEYOR_BRANCH_SWITCH_COMMAND;
|
|
5462
|
-
}
|
|
5463
4277
|
this.heartbeatTimer = setInterval(() => {
|
|
5464
4278
|
this.connection.sendHeartbeat();
|
|
5465
4279
|
}, HEARTBEAT_INTERVAL_MS2);
|
|
5466
|
-
|
|
5467
|
-
if (currentBranch) {
|
|
5468
|
-
this.commitWatcher.start(currentBranch);
|
|
5469
|
-
}
|
|
5470
|
-
logger6.info("Connected, waiting for task assignments");
|
|
4280
|
+
logger5.info("Connected, waiting for task assignments");
|
|
5471
4281
|
await new Promise((resolve2) => {
|
|
5472
4282
|
this.resolveLifecycle = resolve2;
|
|
5473
4283
|
process.on("SIGTERM", () => void this.stop());
|
|
@@ -5478,11 +4288,11 @@ var ProjectRunner = class {
|
|
|
5478
4288
|
const { taskId, mode } = assignment;
|
|
5479
4289
|
const shortId = taskId.slice(0, 8);
|
|
5480
4290
|
if (this.activeAgents.has(taskId)) {
|
|
5481
|
-
|
|
4291
|
+
logger5.info("Task already running, skipping", { taskId: shortId });
|
|
5482
4292
|
return;
|
|
5483
4293
|
}
|
|
5484
4294
|
if (this.activeAgents.size >= MAX_CONCURRENT) {
|
|
5485
|
-
|
|
4295
|
+
logger5.warn("Max concurrent agents reached, rejecting task", {
|
|
5486
4296
|
maxConcurrent: MAX_CONCURRENT,
|
|
5487
4297
|
taskId: shortId
|
|
5488
4298
|
});
|
|
@@ -5491,9 +4301,9 @@ var ProjectRunner = class {
|
|
|
5491
4301
|
}
|
|
5492
4302
|
try {
|
|
5493
4303
|
try {
|
|
5494
|
-
|
|
4304
|
+
execSync5("git fetch origin", { cwd: this.projectDir, stdio: "ignore" });
|
|
5495
4305
|
} catch {
|
|
5496
|
-
|
|
4306
|
+
logger5.warn("Git fetch failed", { taskId: shortId });
|
|
5497
4307
|
}
|
|
5498
4308
|
const { workDir, usesWorktree } = setupWorkDir(this.projectDir, assignment);
|
|
5499
4309
|
const child = spawnChildAgent(assignment, workDir);
|
|
@@ -5504,12 +4314,12 @@ var ProjectRunner = class {
|
|
|
5504
4314
|
usesWorktree
|
|
5505
4315
|
});
|
|
5506
4316
|
this.connection.emitTaskStarted(taskId);
|
|
5507
|
-
|
|
4317
|
+
logger5.info("Started task", { taskId: shortId, mode, workDir });
|
|
5508
4318
|
child.on("exit", (code) => {
|
|
5509
4319
|
this.activeAgents.delete(taskId);
|
|
5510
4320
|
const reason = code === 0 ? "completed" : `exited with code ${code}`;
|
|
5511
4321
|
this.connection.emitTaskStopped(taskId, reason);
|
|
5512
|
-
|
|
4322
|
+
logger5.info("Task exited", { taskId: shortId, reason });
|
|
5513
4323
|
if (code === 0 && usesWorktree) {
|
|
5514
4324
|
try {
|
|
5515
4325
|
removeWorktree(this.projectDir, taskId);
|
|
@@ -5518,7 +4328,7 @@ var ProjectRunner = class {
|
|
|
5518
4328
|
}
|
|
5519
4329
|
});
|
|
5520
4330
|
} catch (error) {
|
|
5521
|
-
|
|
4331
|
+
logger5.error("Failed to start task", {
|
|
5522
4332
|
taskId: shortId,
|
|
5523
4333
|
...errorMeta(error)
|
|
5524
4334
|
});
|
|
@@ -5532,7 +4342,7 @@ var ProjectRunner = class {
|
|
|
5532
4342
|
const agent = this.activeAgents.get(taskId);
|
|
5533
4343
|
if (!agent) return;
|
|
5534
4344
|
const shortId = taskId.slice(0, 8);
|
|
5535
|
-
|
|
4345
|
+
logger5.info("Stopping task", { taskId: shortId });
|
|
5536
4346
|
agent.process.kill("SIGTERM");
|
|
5537
4347
|
const timer = setTimeout(() => {
|
|
5538
4348
|
if (this.activeAgents.has(taskId)) {
|
|
@@ -5552,8 +4362,7 @@ var ProjectRunner = class {
|
|
|
5552
4362
|
async stop() {
|
|
5553
4363
|
if (this.stopping) return;
|
|
5554
4364
|
this.stopping = true;
|
|
5555
|
-
|
|
5556
|
-
this.commitWatcher.stop();
|
|
4365
|
+
logger5.info("Shutting down");
|
|
5557
4366
|
await this.killStartCommand();
|
|
5558
4367
|
if (this.heartbeatTimer) {
|
|
5559
4368
|
clearInterval(this.heartbeatTimer);
|
|
@@ -5579,7 +4388,7 @@ var ProjectRunner = class {
|
|
|
5579
4388
|
})
|
|
5580
4389
|
]);
|
|
5581
4390
|
this.connection.disconnect();
|
|
5582
|
-
|
|
4391
|
+
logger5.info("Shutdown complete");
|
|
5583
4392
|
if (this.resolveLifecycle) {
|
|
5584
4393
|
this.resolveLifecycle();
|
|
5585
4394
|
this.resolveLifecycle = null;
|
|
@@ -5656,13 +4465,13 @@ export {
|
|
|
5656
4465
|
runStartCommand,
|
|
5657
4466
|
ConveyorConnection,
|
|
5658
4467
|
ProjectConnection,
|
|
4468
|
+
createServiceLogger,
|
|
4469
|
+
errorMeta,
|
|
5659
4470
|
ensureWorktree,
|
|
5660
4471
|
removeWorktree,
|
|
5661
4472
|
loadConveyorConfig,
|
|
5662
|
-
createServiceLogger,
|
|
5663
|
-
errorMeta,
|
|
5664
4473
|
AgentRunner,
|
|
5665
4474
|
ProjectRunner,
|
|
5666
4475
|
FileCache
|
|
5667
4476
|
};
|
|
5668
|
-
//# sourceMappingURL=chunk-
|
|
4477
|
+
//# sourceMappingURL=chunk-HYWZJYPW.js.map
|