@rallycry/conveyor-agent 5.11.1 → 5.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-U3YWTVH3.js → chunk-4RFYCO2T.js} +458 -113
- package/dist/chunk-4RFYCO2T.js.map +1 -0
- package/dist/cli.js +1 -1
- package/dist/index.d.ts +40 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-U3YWTVH3.js.map +0 -1
|
@@ -230,6 +230,18 @@ var ConveyorConnection = class _ConveyorConnection {
|
|
|
230
230
|
resolve2();
|
|
231
231
|
}
|
|
232
232
|
});
|
|
233
|
+
this.socket.on("disconnect", (reason) => {
|
|
234
|
+
process.stderr.write(`[conveyor] Socket disconnected: ${reason}
|
|
235
|
+
`);
|
|
236
|
+
});
|
|
237
|
+
this.socket.io.on("reconnect", (attempt) => {
|
|
238
|
+
process.stderr.write(`[conveyor] Reconnected after ${attempt} attempt(s)
|
|
239
|
+
`);
|
|
240
|
+
});
|
|
241
|
+
this.socket.io.on("reconnect_error", (err) => {
|
|
242
|
+
process.stderr.write(`[conveyor] Reconnection error: ${err.message}
|
|
243
|
+
`);
|
|
244
|
+
});
|
|
233
245
|
this.socket.io.on("reconnect_attempt", () => {
|
|
234
246
|
attempts++;
|
|
235
247
|
if (!settled && attempts >= maxInitialAttempts) {
|
|
@@ -557,6 +569,18 @@ var ProjectConnection = class {
|
|
|
557
569
|
resolve2();
|
|
558
570
|
}
|
|
559
571
|
});
|
|
572
|
+
this.socket.on("disconnect", (reason) => {
|
|
573
|
+
process.stderr.write(`[conveyor] Project socket disconnected: ${reason}
|
|
574
|
+
`);
|
|
575
|
+
});
|
|
576
|
+
this.socket.io.on("reconnect", (attempt) => {
|
|
577
|
+
process.stderr.write(`[conveyor] Project socket reconnected after ${attempt} attempt(s)
|
|
578
|
+
`);
|
|
579
|
+
});
|
|
580
|
+
this.socket.io.on("reconnect_error", (err) => {
|
|
581
|
+
process.stderr.write(`[conveyor] Project socket reconnection error: ${err.message}
|
|
582
|
+
`);
|
|
583
|
+
});
|
|
560
584
|
this.socket.io.on("reconnect_attempt", () => {
|
|
561
585
|
attempts++;
|
|
562
586
|
if (!settled && attempts >= maxInitialAttempts) {
|
|
@@ -640,13 +664,13 @@ var ProjectConnection = class {
|
|
|
640
664
|
);
|
|
641
665
|
});
|
|
642
666
|
}
|
|
643
|
-
fetchChatHistory(limit) {
|
|
667
|
+
fetchChatHistory(limit, chatId) {
|
|
644
668
|
const socket = this.socket;
|
|
645
669
|
if (!socket) return Promise.reject(new Error("Not connected"));
|
|
646
670
|
return new Promise((resolve2, reject) => {
|
|
647
671
|
socket.emit(
|
|
648
672
|
"projectRunner:getChatHistory",
|
|
649
|
-
{ limit },
|
|
673
|
+
{ limit, chatId },
|
|
650
674
|
(response) => {
|
|
651
675
|
if (response.success && response.data) resolve2(response.data);
|
|
652
676
|
else reject(new Error(response.error ?? "Failed to fetch chat history"));
|
|
@@ -654,6 +678,38 @@ var ProjectConnection = class {
|
|
|
654
678
|
);
|
|
655
679
|
});
|
|
656
680
|
}
|
|
681
|
+
// ── Project MCP tool request methods ──
|
|
682
|
+
requestListTasks(params) {
|
|
683
|
+
return this.requestWithCallback("projectRunner:listTasks", params);
|
|
684
|
+
}
|
|
685
|
+
requestGetTask(taskId) {
|
|
686
|
+
return this.requestWithCallback("projectRunner:getTask", { taskId });
|
|
687
|
+
}
|
|
688
|
+
requestCreateTask(params) {
|
|
689
|
+
return this.requestWithCallback("projectRunner:createTask", params);
|
|
690
|
+
}
|
|
691
|
+
requestUpdateTask(params) {
|
|
692
|
+
return this.requestWithCallback("projectRunner:updateTask", params);
|
|
693
|
+
}
|
|
694
|
+
requestSearchTasks(params) {
|
|
695
|
+
return this.requestWithCallback("projectRunner:searchTasks", params);
|
|
696
|
+
}
|
|
697
|
+
requestListTags() {
|
|
698
|
+
return this.requestWithCallback("projectRunner:listTags", {});
|
|
699
|
+
}
|
|
700
|
+
requestGetProjectSummary() {
|
|
701
|
+
return this.requestWithCallback("projectRunner:getProjectSummary", {});
|
|
702
|
+
}
|
|
703
|
+
requestWithCallback(event, data) {
|
|
704
|
+
const socket = this.socket;
|
|
705
|
+
if (!socket) return Promise.reject(new Error("Not connected"));
|
|
706
|
+
return new Promise((resolve2, reject) => {
|
|
707
|
+
socket.emit(event, data, (response) => {
|
|
708
|
+
if (response.success) resolve2(response.data);
|
|
709
|
+
else reject(new Error(response.error ?? `${event} failed`));
|
|
710
|
+
});
|
|
711
|
+
});
|
|
712
|
+
}
|
|
657
713
|
emitNewCommitsDetected(data) {
|
|
658
714
|
if (!this.socket) return;
|
|
659
715
|
this.socket.emit("projectRunner:newCommitsDetected", data);
|
|
@@ -701,9 +757,32 @@ var ProjectConnection = class {
|
|
|
701
757
|
};
|
|
702
758
|
|
|
703
759
|
// src/runner/worktree.ts
|
|
704
|
-
import { execSync as
|
|
760
|
+
import { execSync as execSync3 } from "child_process";
|
|
705
761
|
import { existsSync } from "fs";
|
|
706
762
|
import { join } from "path";
|
|
763
|
+
|
|
764
|
+
// src/runner/git-utils.ts
|
|
765
|
+
import { execSync as execSync2 } from "child_process";
|
|
766
|
+
function hasUncommittedChanges(cwd) {
|
|
767
|
+
const status = execSync2("git status --porcelain", {
|
|
768
|
+
cwd,
|
|
769
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
770
|
+
}).toString().trim();
|
|
771
|
+
return status.length > 0;
|
|
772
|
+
}
|
|
773
|
+
function getCurrentBranch(cwd) {
|
|
774
|
+
try {
|
|
775
|
+
const branch = execSync2("git branch --show-current", {
|
|
776
|
+
cwd,
|
|
777
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
778
|
+
}).toString().trim();
|
|
779
|
+
return branch || null;
|
|
780
|
+
} catch {
|
|
781
|
+
return null;
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
// src/runner/worktree.ts
|
|
707
786
|
var WORKTREE_DIR = ".worktrees";
|
|
708
787
|
function ensureWorktree(projectDir, taskId, branch) {
|
|
709
788
|
if (projectDir.includes(`/${WORKTREE_DIR}/`)) {
|
|
@@ -712,8 +791,11 @@ function ensureWorktree(projectDir, taskId, branch) {
|
|
|
712
791
|
const worktreePath = join(projectDir, WORKTREE_DIR, taskId);
|
|
713
792
|
if (existsSync(worktreePath)) {
|
|
714
793
|
if (branch) {
|
|
794
|
+
if (hasUncommittedChanges(worktreePath)) {
|
|
795
|
+
return worktreePath;
|
|
796
|
+
}
|
|
715
797
|
try {
|
|
716
|
-
|
|
798
|
+
execSync3(`git checkout --detach origin/${branch}`, {
|
|
717
799
|
cwd: worktreePath,
|
|
718
800
|
stdio: "ignore"
|
|
719
801
|
});
|
|
@@ -723,17 +805,39 @@ function ensureWorktree(projectDir, taskId, branch) {
|
|
|
723
805
|
return worktreePath;
|
|
724
806
|
}
|
|
725
807
|
const ref = branch ? `origin/${branch}` : "HEAD";
|
|
726
|
-
|
|
808
|
+
execSync3(`git worktree add --detach "${worktreePath}" ${ref}`, {
|
|
727
809
|
cwd: projectDir,
|
|
728
810
|
stdio: "ignore"
|
|
729
811
|
});
|
|
730
812
|
return worktreePath;
|
|
731
813
|
}
|
|
814
|
+
function detachWorktreeBranch(projectDir, branch) {
|
|
815
|
+
try {
|
|
816
|
+
const output = execSync3("git worktree list --porcelain", {
|
|
817
|
+
cwd: projectDir,
|
|
818
|
+
encoding: "utf-8"
|
|
819
|
+
});
|
|
820
|
+
const entries = output.split("\n\n");
|
|
821
|
+
for (const entry of entries) {
|
|
822
|
+
const lines = entry.trim().split("\n");
|
|
823
|
+
const worktreeLine = lines.find((l) => l.startsWith("worktree "));
|
|
824
|
+
const branchLine = lines.find((l) => l.startsWith("branch "));
|
|
825
|
+
if (!worktreeLine || branchLine !== `branch refs/heads/${branch}`) continue;
|
|
826
|
+
const worktreePath = worktreeLine.replace("worktree ", "");
|
|
827
|
+
if (!worktreePath.includes(`/${WORKTREE_DIR}/`)) continue;
|
|
828
|
+
try {
|
|
829
|
+
execSync3("git checkout --detach", { cwd: worktreePath, stdio: "ignore" });
|
|
830
|
+
} catch {
|
|
831
|
+
}
|
|
832
|
+
}
|
|
833
|
+
} catch {
|
|
834
|
+
}
|
|
835
|
+
}
|
|
732
836
|
function removeWorktree(projectDir, taskId) {
|
|
733
837
|
const worktreePath = join(projectDir, WORKTREE_DIR, taskId);
|
|
734
838
|
if (!existsSync(worktreePath)) return;
|
|
735
839
|
try {
|
|
736
|
-
|
|
840
|
+
execSync3(`git worktree remove "${worktreePath}" --force`, {
|
|
737
841
|
cwd: projectDir,
|
|
738
842
|
stdio: "ignore"
|
|
739
843
|
});
|
|
@@ -769,10 +873,10 @@ function loadConveyorConfig(_workspaceDir) {
|
|
|
769
873
|
}
|
|
770
874
|
|
|
771
875
|
// src/setup/codespace.ts
|
|
772
|
-
import { execSync as
|
|
876
|
+
import { execSync as execSync4 } from "child_process";
|
|
773
877
|
function unshallowRepo(workspaceDir) {
|
|
774
878
|
try {
|
|
775
|
-
|
|
879
|
+
execSync4("git fetch --unshallow", {
|
|
776
880
|
cwd: workspaceDir,
|
|
777
881
|
stdio: "ignore",
|
|
778
882
|
timeout: 6e4
|
|
@@ -810,7 +914,7 @@ function errorMeta(error) {
|
|
|
810
914
|
|
|
811
915
|
// src/runner/agent-runner.ts
|
|
812
916
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
813
|
-
import { execSync as
|
|
917
|
+
import { execSync as execSync5 } from "child_process";
|
|
814
918
|
|
|
815
919
|
// src/execution/event-handlers.ts
|
|
816
920
|
function safeVoid(promise, context) {
|
|
@@ -3444,6 +3548,47 @@ async function executeSetupConfig(config, runnerConfig, connection, setupLog) {
|
|
|
3444
3548
|
async function checkoutTaskBranch(runnerConfig, connection, callbacks, setupLog) {
|
|
3445
3549
|
const taskBranch = process.env.CONVEYOR_TASK_BRANCH;
|
|
3446
3550
|
if (!taskBranch) return true;
|
|
3551
|
+
const currentBranch = getCurrentBranch(runnerConfig.workspaceDir);
|
|
3552
|
+
if (currentBranch === taskBranch) {
|
|
3553
|
+
pushSetupLog(setupLog, `[conveyor] Already on ${taskBranch}, skipping checkout`);
|
|
3554
|
+
connection.sendEvent({
|
|
3555
|
+
type: "setup_output",
|
|
3556
|
+
stream: "stdout",
|
|
3557
|
+
data: `Already on branch ${taskBranch}, skipping checkout
|
|
3558
|
+
`
|
|
3559
|
+
});
|
|
3560
|
+
try {
|
|
3561
|
+
await runSetupCommand(
|
|
3562
|
+
`git fetch origin ${taskBranch}`,
|
|
3563
|
+
runnerConfig.workspaceDir,
|
|
3564
|
+
(stream, data) => {
|
|
3565
|
+
connection.sendEvent({ type: "setup_output", stream, data });
|
|
3566
|
+
}
|
|
3567
|
+
);
|
|
3568
|
+
} catch {
|
|
3569
|
+
}
|
|
3570
|
+
return true;
|
|
3571
|
+
}
|
|
3572
|
+
let didStash = false;
|
|
3573
|
+
if (hasUncommittedChanges(runnerConfig.workspaceDir)) {
|
|
3574
|
+
pushSetupLog(setupLog, `[conveyor] Uncommitted changes detected, stashing before checkout`);
|
|
3575
|
+
connection.sendEvent({
|
|
3576
|
+
type: "setup_output",
|
|
3577
|
+
stream: "stdout",
|
|
3578
|
+
data: "Uncommitted changes detected \u2014 stashing before branch switch\n"
|
|
3579
|
+
});
|
|
3580
|
+
try {
|
|
3581
|
+
await runSetupCommand(
|
|
3582
|
+
`git stash push -m "conveyor-auto-stash"`,
|
|
3583
|
+
runnerConfig.workspaceDir,
|
|
3584
|
+
(stream, data) => {
|
|
3585
|
+
connection.sendEvent({ type: "setup_output", stream, data });
|
|
3586
|
+
}
|
|
3587
|
+
);
|
|
3588
|
+
didStash = true;
|
|
3589
|
+
} catch {
|
|
3590
|
+
}
|
|
3591
|
+
}
|
|
3447
3592
|
pushSetupLog(setupLog, `[conveyor] Switching to task branch ${taskBranch}...`);
|
|
3448
3593
|
connection.sendEvent({
|
|
3449
3594
|
type: "setup_output",
|
|
@@ -3463,6 +3608,19 @@ async function checkoutTaskBranch(runnerConfig, connection, callbacks, setupLog)
|
|
|
3463
3608
|
}
|
|
3464
3609
|
);
|
|
3465
3610
|
pushSetupLog(setupLog, `[conveyor] Switched to ${taskBranch}`);
|
|
3611
|
+
if (didStash) {
|
|
3612
|
+
try {
|
|
3613
|
+
await runSetupCommand("git stash pop", runnerConfig.workspaceDir, (stream, data) => {
|
|
3614
|
+
connection.sendEvent({ type: "setup_output", stream, data });
|
|
3615
|
+
});
|
|
3616
|
+
pushSetupLog(setupLog, `[conveyor] Restored stashed changes`);
|
|
3617
|
+
} catch {
|
|
3618
|
+
pushSetupLog(
|
|
3619
|
+
setupLog,
|
|
3620
|
+
`[conveyor] Warning: stash pop had conflicts \u2014 agent may need to resolve`
|
|
3621
|
+
);
|
|
3622
|
+
}
|
|
3623
|
+
}
|
|
3466
3624
|
return true;
|
|
3467
3625
|
} catch (error) {
|
|
3468
3626
|
const message = `Failed to checkout ${taskBranch}: ${error instanceof Error ? error.message : "unknown error"}`;
|
|
@@ -3807,12 +3965,22 @@ var AgentRunner = class {
|
|
|
3807
3965
|
}
|
|
3808
3966
|
checkoutWorktreeBranch() {
|
|
3809
3967
|
if (!this.worktreeActive || !this.taskContext?.githubBranch) return;
|
|
3968
|
+
const branch = this.taskContext.githubBranch;
|
|
3969
|
+
const cwd = this.config.workspaceDir;
|
|
3970
|
+
if (getCurrentBranch(cwd) === branch) return;
|
|
3810
3971
|
try {
|
|
3811
|
-
|
|
3812
|
-
|
|
3813
|
-
cwd:
|
|
3814
|
-
|
|
3815
|
-
}
|
|
3972
|
+
let didStash = false;
|
|
3973
|
+
if (hasUncommittedChanges(cwd)) {
|
|
3974
|
+
execSync5(`git stash push -m "conveyor-auto-stash"`, { cwd, stdio: "ignore" });
|
|
3975
|
+
didStash = true;
|
|
3976
|
+
}
|
|
3977
|
+
execSync5(`git fetch origin ${branch} && git checkout ${branch}`, { cwd, stdio: "ignore" });
|
|
3978
|
+
if (didStash) {
|
|
3979
|
+
try {
|
|
3980
|
+
execSync5("git stash pop", { cwd, stdio: "ignore" });
|
|
3981
|
+
} catch {
|
|
3982
|
+
}
|
|
3983
|
+
}
|
|
3816
3984
|
} catch {
|
|
3817
3985
|
}
|
|
3818
3986
|
}
|
|
@@ -4100,12 +4268,12 @@ var AgentRunner = class {
|
|
|
4100
4268
|
|
|
4101
4269
|
// src/runner/project-runner.ts
|
|
4102
4270
|
import { fork } from "child_process";
|
|
4103
|
-
import { execSync as
|
|
4271
|
+
import { execSync as execSync7 } from "child_process";
|
|
4104
4272
|
import * as path from "path";
|
|
4105
4273
|
import { fileURLToPath } from "url";
|
|
4106
4274
|
|
|
4107
4275
|
// src/runner/commit-watcher.ts
|
|
4108
|
-
import { execSync as
|
|
4276
|
+
import { execSync as execSync6 } from "child_process";
|
|
4109
4277
|
var logger3 = createServiceLogger("CommitWatcher");
|
|
4110
4278
|
var CommitWatcher = class {
|
|
4111
4279
|
constructor(config, callbacks) {
|
|
@@ -4137,7 +4305,7 @@ var CommitWatcher = class {
|
|
|
4137
4305
|
this.isSyncing = false;
|
|
4138
4306
|
}
|
|
4139
4307
|
getLocalHeadSha() {
|
|
4140
|
-
return
|
|
4308
|
+
return execSync6("git rev-parse HEAD", {
|
|
4141
4309
|
cwd: this.config.projectDir,
|
|
4142
4310
|
stdio: ["ignore", "pipe", "ignore"]
|
|
4143
4311
|
}).toString().trim();
|
|
@@ -4145,12 +4313,12 @@ var CommitWatcher = class {
|
|
|
4145
4313
|
poll() {
|
|
4146
4314
|
if (!this.branch || this.isSyncing) return;
|
|
4147
4315
|
try {
|
|
4148
|
-
|
|
4316
|
+
execSync6(`git fetch origin ${this.branch} --quiet`, {
|
|
4149
4317
|
cwd: this.config.projectDir,
|
|
4150
4318
|
stdio: "ignore",
|
|
4151
4319
|
timeout: 3e4
|
|
4152
4320
|
});
|
|
4153
|
-
const remoteSha =
|
|
4321
|
+
const remoteSha = execSync6(`git rev-parse origin/${this.branch}`, {
|
|
4154
4322
|
cwd: this.config.projectDir,
|
|
4155
4323
|
stdio: ["ignore", "pipe", "ignore"]
|
|
4156
4324
|
}).toString().trim();
|
|
@@ -4171,12 +4339,12 @@ var CommitWatcher = class {
|
|
|
4171
4339
|
let latestMessage = "";
|
|
4172
4340
|
let latestAuthor = "";
|
|
4173
4341
|
try {
|
|
4174
|
-
const countOutput =
|
|
4342
|
+
const countOutput = execSync6(`git rev-list --count ${previousSha}..origin/${this.branch}`, {
|
|
4175
4343
|
cwd: this.config.projectDir,
|
|
4176
4344
|
stdio: ["ignore", "pipe", "ignore"]
|
|
4177
4345
|
}).toString().trim();
|
|
4178
4346
|
commitCount = parseInt(countOutput, 10) || 1;
|
|
4179
|
-
const logOutput =
|
|
4347
|
+
const logOutput = execSync6(`git log -1 --format="%s|||%an" origin/${this.branch}`, {
|
|
4180
4348
|
cwd: this.config.projectDir,
|
|
4181
4349
|
stdio: ["ignore", "pipe", "ignore"]
|
|
4182
4350
|
}).toString().trim();
|
|
@@ -4210,7 +4378,159 @@ var CommitWatcher = class {
|
|
|
4210
4378
|
};
|
|
4211
4379
|
|
|
4212
4380
|
// src/runner/project-chat-handler.ts
|
|
4213
|
-
import {
|
|
4381
|
+
import {
|
|
4382
|
+
query as query2,
|
|
4383
|
+
createSdkMcpServer as createSdkMcpServer2
|
|
4384
|
+
} from "@anthropic-ai/claude-agent-sdk";
|
|
4385
|
+
|
|
4386
|
+
// src/tools/project-tools.ts
|
|
4387
|
+
import { tool as tool4 } from "@anthropic-ai/claude-agent-sdk";
|
|
4388
|
+
import { z as z4 } from "zod";
|
|
4389
|
+
function buildReadTools(connection) {
|
|
4390
|
+
return [
|
|
4391
|
+
tool4(
|
|
4392
|
+
"list_tasks",
|
|
4393
|
+
"List tasks in the project. Optionally filter by status or assignee.",
|
|
4394
|
+
{
|
|
4395
|
+
status: z4.string().optional().describe("Filter by task status (e.g. Planning, Open, InProgress, ReviewPR, Complete)"),
|
|
4396
|
+
assigneeId: z4.string().optional().describe("Filter by assigned user ID"),
|
|
4397
|
+
limit: z4.number().optional().describe("Max number of tasks to return (default 50)")
|
|
4398
|
+
},
|
|
4399
|
+
async (params) => {
|
|
4400
|
+
try {
|
|
4401
|
+
const tasks = await connection.requestListTasks(params);
|
|
4402
|
+
return textResult(JSON.stringify(tasks, null, 2));
|
|
4403
|
+
} catch (error) {
|
|
4404
|
+
return textResult(
|
|
4405
|
+
`Failed to list tasks: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
4406
|
+
);
|
|
4407
|
+
}
|
|
4408
|
+
},
|
|
4409
|
+
{ annotations: { readOnlyHint: true } }
|
|
4410
|
+
),
|
|
4411
|
+
tool4(
|
|
4412
|
+
"get_task",
|
|
4413
|
+
"Get detailed information about a task including its chat messages, child tasks, and codespace status.",
|
|
4414
|
+
{ task_id: z4.string().describe("The task ID to look up") },
|
|
4415
|
+
async ({ task_id }) => {
|
|
4416
|
+
try {
|
|
4417
|
+
const task = await connection.requestGetTask(task_id);
|
|
4418
|
+
return textResult(JSON.stringify(task, null, 2));
|
|
4419
|
+
} catch (error) {
|
|
4420
|
+
return textResult(
|
|
4421
|
+
`Failed to get task: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
4422
|
+
);
|
|
4423
|
+
}
|
|
4424
|
+
},
|
|
4425
|
+
{ annotations: { readOnlyHint: true } }
|
|
4426
|
+
),
|
|
4427
|
+
tool4(
|
|
4428
|
+
"search_tasks",
|
|
4429
|
+
"Search tasks by tags, text query, or status filters.",
|
|
4430
|
+
{
|
|
4431
|
+
tagNames: z4.array(z4.string()).optional().describe("Filter by tag names"),
|
|
4432
|
+
searchQuery: z4.string().optional().describe("Text search in title/description"),
|
|
4433
|
+
statusFilters: z4.array(z4.string()).optional().describe("Filter by statuses"),
|
|
4434
|
+
limit: z4.number().optional().describe("Max results (default 20)")
|
|
4435
|
+
},
|
|
4436
|
+
async (params) => {
|
|
4437
|
+
try {
|
|
4438
|
+
const tasks = await connection.requestSearchTasks(params);
|
|
4439
|
+
return textResult(JSON.stringify(tasks, null, 2));
|
|
4440
|
+
} catch (error) {
|
|
4441
|
+
return textResult(
|
|
4442
|
+
`Failed to search tasks: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
4443
|
+
);
|
|
4444
|
+
}
|
|
4445
|
+
},
|
|
4446
|
+
{ annotations: { readOnlyHint: true } }
|
|
4447
|
+
),
|
|
4448
|
+
tool4(
|
|
4449
|
+
"list_tags",
|
|
4450
|
+
"List all tags available in the project.",
|
|
4451
|
+
{},
|
|
4452
|
+
async () => {
|
|
4453
|
+
try {
|
|
4454
|
+
const tags = await connection.requestListTags();
|
|
4455
|
+
return textResult(JSON.stringify(tags, null, 2));
|
|
4456
|
+
} catch (error) {
|
|
4457
|
+
return textResult(
|
|
4458
|
+
`Failed to list tags: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
4459
|
+
);
|
|
4460
|
+
}
|
|
4461
|
+
},
|
|
4462
|
+
{ annotations: { readOnlyHint: true } }
|
|
4463
|
+
),
|
|
4464
|
+
tool4(
|
|
4465
|
+
"get_project_summary",
|
|
4466
|
+
"Get a summary of the project including task counts by status and active builds.",
|
|
4467
|
+
{},
|
|
4468
|
+
async () => {
|
|
4469
|
+
try {
|
|
4470
|
+
const summary = await connection.requestGetProjectSummary();
|
|
4471
|
+
return textResult(JSON.stringify(summary, null, 2));
|
|
4472
|
+
} catch (error) {
|
|
4473
|
+
return textResult(
|
|
4474
|
+
`Failed to get project summary: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
4475
|
+
);
|
|
4476
|
+
}
|
|
4477
|
+
},
|
|
4478
|
+
{ annotations: { readOnlyHint: true } }
|
|
4479
|
+
)
|
|
4480
|
+
];
|
|
4481
|
+
}
|
|
4482
|
+
function buildMutationTools(connection) {
|
|
4483
|
+
return [
|
|
4484
|
+
tool4(
|
|
4485
|
+
"create_task",
|
|
4486
|
+
"Create a new task in the project.",
|
|
4487
|
+
{
|
|
4488
|
+
title: z4.string().describe("Task title"),
|
|
4489
|
+
description: z4.string().optional().describe("Task description"),
|
|
4490
|
+
plan: z4.string().optional().describe("Implementation plan in markdown"),
|
|
4491
|
+
status: z4.string().optional().describe("Initial status (default: Planning)"),
|
|
4492
|
+
isBug: z4.boolean().optional().describe("Whether this is a bug report")
|
|
4493
|
+
},
|
|
4494
|
+
async (params) => {
|
|
4495
|
+
try {
|
|
4496
|
+
const result = await connection.requestCreateTask(params);
|
|
4497
|
+
return textResult(`Task created: ${result.slug} (ID: ${result.id})`);
|
|
4498
|
+
} catch (error) {
|
|
4499
|
+
return textResult(
|
|
4500
|
+
`Failed to create task: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
4501
|
+
);
|
|
4502
|
+
}
|
|
4503
|
+
}
|
|
4504
|
+
),
|
|
4505
|
+
tool4(
|
|
4506
|
+
"update_task",
|
|
4507
|
+
"Update an existing task's title, description, plan, status, or assignee.",
|
|
4508
|
+
{
|
|
4509
|
+
task_id: z4.string().describe("The task ID to update"),
|
|
4510
|
+
title: z4.string().optional().describe("New title"),
|
|
4511
|
+
description: z4.string().optional().describe("New description"),
|
|
4512
|
+
plan: z4.string().optional().describe("New plan in markdown"),
|
|
4513
|
+
status: z4.string().optional().describe("New status"),
|
|
4514
|
+
assignedUserId: z4.string().nullable().optional().describe("Assign to user ID, or null to unassign")
|
|
4515
|
+
},
|
|
4516
|
+
async ({ task_id, ...fields }) => {
|
|
4517
|
+
try {
|
|
4518
|
+
await connection.requestUpdateTask({ taskId: task_id, ...fields });
|
|
4519
|
+
return textResult("Task updated successfully.");
|
|
4520
|
+
} catch (error) {
|
|
4521
|
+
return textResult(
|
|
4522
|
+
`Failed to update task: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
4523
|
+
);
|
|
4524
|
+
}
|
|
4525
|
+
}
|
|
4526
|
+
)
|
|
4527
|
+
];
|
|
4528
|
+
}
|
|
4529
|
+
function buildProjectTools(connection) {
|
|
4530
|
+
return [...buildReadTools(connection), ...buildMutationTools(connection)];
|
|
4531
|
+
}
|
|
4532
|
+
|
|
4533
|
+
// src/runner/project-chat-handler.ts
|
|
4214
4534
|
var logger4 = createServiceLogger("ProjectChat");
|
|
4215
4535
|
var FALLBACK_MODEL = "claude-sonnet-4-20250514";
|
|
4216
4536
|
function buildSystemPrompt2(projectDir, agentCtx) {
|
|
@@ -4267,7 +4587,7 @@ function processContentBlock(block, responseParts, turnToolCalls) {
|
|
|
4267
4587
|
logger4.debug("Tool use", { tool: block.name });
|
|
4268
4588
|
}
|
|
4269
4589
|
}
|
|
4270
|
-
async function fetchContext(connection) {
|
|
4590
|
+
async function fetchContext(connection, chatId) {
|
|
4271
4591
|
let agentCtx = null;
|
|
4272
4592
|
try {
|
|
4273
4593
|
agentCtx = await connection.fetchAgentContext();
|
|
@@ -4276,15 +4596,19 @@ async function fetchContext(connection) {
|
|
|
4276
4596
|
}
|
|
4277
4597
|
let chatHistory = [];
|
|
4278
4598
|
try {
|
|
4279
|
-
chatHistory = await connection.fetchChatHistory(30);
|
|
4599
|
+
chatHistory = await connection.fetchChatHistory(30, chatId);
|
|
4280
4600
|
} catch {
|
|
4281
4601
|
logger4.warn("Could not fetch chat history, proceeding without it");
|
|
4282
4602
|
}
|
|
4283
4603
|
return { agentCtx, chatHistory };
|
|
4284
4604
|
}
|
|
4285
|
-
function buildChatQueryOptions(agentCtx, projectDir) {
|
|
4605
|
+
function buildChatQueryOptions(agentCtx, projectDir, connection) {
|
|
4286
4606
|
const model = agentCtx?.model || FALLBACK_MODEL;
|
|
4287
4607
|
const settings = agentCtx?.agentSettings ?? {};
|
|
4608
|
+
const mcpServer = createSdkMcpServer2({
|
|
4609
|
+
name: "conveyor",
|
|
4610
|
+
tools: buildProjectTools(connection)
|
|
4611
|
+
});
|
|
4288
4612
|
return {
|
|
4289
4613
|
model,
|
|
4290
4614
|
systemPrompt: {
|
|
@@ -4296,8 +4620,9 @@ function buildChatQueryOptions(agentCtx, projectDir) {
|
|
|
4296
4620
|
permissionMode: "bypassPermissions",
|
|
4297
4621
|
allowDangerouslySkipPermissions: true,
|
|
4298
4622
|
tools: { type: "preset", preset: "claude_code" },
|
|
4299
|
-
|
|
4300
|
-
|
|
4623
|
+
mcpServers: { conveyor: mcpServer },
|
|
4624
|
+
maxTurns: settings.maxTurns ?? 30,
|
|
4625
|
+
maxBudgetUsd: settings.maxBudgetUsd ?? 50,
|
|
4301
4626
|
effort: settings.effort,
|
|
4302
4627
|
thinking: settings.thinking
|
|
4303
4628
|
};
|
|
@@ -4363,16 +4688,25 @@ function processEventStream(event, connection, responseParts, turnToolCalls, isT
|
|
|
4363
4688
|
}
|
|
4364
4689
|
return false;
|
|
4365
4690
|
}
|
|
4366
|
-
async function runChatQuery(message, connection, projectDir) {
|
|
4367
|
-
const { agentCtx, chatHistory } = await fetchContext(connection);
|
|
4368
|
-
const options = buildChatQueryOptions(agentCtx, projectDir);
|
|
4691
|
+
async function runChatQuery(message, connection, projectDir, sessionId) {
|
|
4692
|
+
const { agentCtx, chatHistory } = await fetchContext(connection, message.chatId);
|
|
4693
|
+
const options = buildChatQueryOptions(agentCtx, projectDir, connection);
|
|
4369
4694
|
const prompt = buildPrompt(message, chatHistory);
|
|
4370
4695
|
connection.emitAgentStatus("running");
|
|
4371
|
-
const events = query2({
|
|
4696
|
+
const events = query2({
|
|
4697
|
+
prompt,
|
|
4698
|
+
options,
|
|
4699
|
+
...sessionId ? { resume: sessionId } : {}
|
|
4700
|
+
});
|
|
4372
4701
|
const responseParts = [];
|
|
4373
4702
|
const turnToolCalls = [];
|
|
4374
4703
|
const isTyping = { value: false };
|
|
4704
|
+
let resultSessionId;
|
|
4375
4705
|
for await (const event of events) {
|
|
4706
|
+
if (event.type === "result") {
|
|
4707
|
+
const resultEvent = event;
|
|
4708
|
+
resultSessionId = resultEvent.sessionId;
|
|
4709
|
+
}
|
|
4376
4710
|
const done = processEventStream(event, connection, responseParts, turnToolCalls, isTyping);
|
|
4377
4711
|
if (done) break;
|
|
4378
4712
|
}
|
|
@@ -4383,11 +4717,12 @@ async function runChatQuery(message, connection, projectDir) {
|
|
|
4383
4717
|
if (responseText) {
|
|
4384
4718
|
await connection.emitChatMessage(responseText);
|
|
4385
4719
|
}
|
|
4720
|
+
return resultSessionId;
|
|
4386
4721
|
}
|
|
4387
|
-
async function handleProjectChatMessage(message, connection, projectDir) {
|
|
4722
|
+
async function handleProjectChatMessage(message, connection, projectDir, sessionId) {
|
|
4388
4723
|
connection.emitAgentStatus("fetching_context");
|
|
4389
4724
|
try {
|
|
4390
|
-
await runChatQuery(message, connection, projectDir);
|
|
4725
|
+
return await runChatQuery(message, connection, projectDir, sessionId);
|
|
4391
4726
|
} catch (error) {
|
|
4392
4727
|
logger4.error("Failed to handle message", errorMeta(error));
|
|
4393
4728
|
connection.emitAgentStatus("error");
|
|
@@ -4397,6 +4732,7 @@ async function handleProjectChatMessage(message, connection, projectDir) {
|
|
|
4397
4732
|
);
|
|
4398
4733
|
} catch {
|
|
4399
4734
|
}
|
|
4735
|
+
return void 0;
|
|
4400
4736
|
} finally {
|
|
4401
4737
|
connection.emitAgentStatus("idle");
|
|
4402
4738
|
}
|
|
@@ -4407,8 +4743,8 @@ import { query as query3 } from "@anthropic-ai/claude-agent-sdk";
|
|
|
4407
4743
|
|
|
4408
4744
|
// src/tools/audit-tools.ts
|
|
4409
4745
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
4410
|
-
import { tool as
|
|
4411
|
-
import { z as
|
|
4746
|
+
import { tool as tool5, createSdkMcpServer as createSdkMcpServer3 } from "@anthropic-ai/claude-agent-sdk";
|
|
4747
|
+
import { z as z5 } from "zod";
|
|
4412
4748
|
function mapCreateTag(input) {
|
|
4413
4749
|
return {
|
|
4414
4750
|
type: "create_tag",
|
|
@@ -4490,14 +4826,14 @@ function collectRecommendation(toolName, input, collector, onRecommendation) {
|
|
|
4490
4826
|
}
|
|
4491
4827
|
function createAuditMcpServer(collector, onRecommendation) {
|
|
4492
4828
|
const auditTools = [
|
|
4493
|
-
|
|
4829
|
+
tool5(
|
|
4494
4830
|
"recommend_create_tag",
|
|
4495
4831
|
"Recommend creating a new tag for an uncovered subsystem or area",
|
|
4496
4832
|
{
|
|
4497
|
-
name:
|
|
4498
|
-
color:
|
|
4499
|
-
description:
|
|
4500
|
-
reasoning:
|
|
4833
|
+
name: z5.string().describe("Proposed tag name (lowercase, hyphenated)"),
|
|
4834
|
+
color: z5.string().optional().describe("Hex color code"),
|
|
4835
|
+
description: z5.string().describe("What this tag covers"),
|
|
4836
|
+
reasoning: z5.string().describe("Why this tag should be created")
|
|
4501
4837
|
},
|
|
4502
4838
|
async (args) => {
|
|
4503
4839
|
const result = collectRecommendation(
|
|
@@ -4509,14 +4845,14 @@ function createAuditMcpServer(collector, onRecommendation) {
|
|
|
4509
4845
|
return { content: [{ type: "text", text: result }] };
|
|
4510
4846
|
}
|
|
4511
4847
|
),
|
|
4512
|
-
|
|
4848
|
+
tool5(
|
|
4513
4849
|
"recommend_update_description",
|
|
4514
4850
|
"Recommend updating a tag's description to better reflect its scope",
|
|
4515
4851
|
{
|
|
4516
|
-
tagId:
|
|
4517
|
-
tagName:
|
|
4518
|
-
description:
|
|
4519
|
-
reasoning:
|
|
4852
|
+
tagId: z5.string(),
|
|
4853
|
+
tagName: z5.string(),
|
|
4854
|
+
description: z5.string().describe("Proposed new description"),
|
|
4855
|
+
reasoning: z5.string()
|
|
4520
4856
|
},
|
|
4521
4857
|
async (args) => {
|
|
4522
4858
|
const result = collectRecommendation(
|
|
@@ -4528,16 +4864,16 @@ function createAuditMcpServer(collector, onRecommendation) {
|
|
|
4528
4864
|
return { content: [{ type: "text", text: result }] };
|
|
4529
4865
|
}
|
|
4530
4866
|
),
|
|
4531
|
-
|
|
4867
|
+
tool5(
|
|
4532
4868
|
"recommend_context_link",
|
|
4533
4869
|
"Recommend linking a doc, rule, file, or folder to a tag's contextPaths",
|
|
4534
4870
|
{
|
|
4535
|
-
tagId:
|
|
4536
|
-
tagName:
|
|
4537
|
-
linkType:
|
|
4538
|
-
path:
|
|
4539
|
-
label:
|
|
4540
|
-
reasoning:
|
|
4871
|
+
tagId: z5.string(),
|
|
4872
|
+
tagName: z5.string(),
|
|
4873
|
+
linkType: z5.enum(["rule", "doc", "file", "folder"]),
|
|
4874
|
+
path: z5.string(),
|
|
4875
|
+
label: z5.string().optional(),
|
|
4876
|
+
reasoning: z5.string()
|
|
4541
4877
|
},
|
|
4542
4878
|
async (args) => {
|
|
4543
4879
|
const result = collectRecommendation(
|
|
@@ -4549,16 +4885,16 @@ function createAuditMcpServer(collector, onRecommendation) {
|
|
|
4549
4885
|
return { content: [{ type: "text", text: result }] };
|
|
4550
4886
|
}
|
|
4551
4887
|
),
|
|
4552
|
-
|
|
4888
|
+
tool5(
|
|
4553
4889
|
"flag_documentation_gap",
|
|
4554
4890
|
"Flag a file that agents read heavily but has no tag documentation linked",
|
|
4555
4891
|
{
|
|
4556
|
-
tagName:
|
|
4557
|
-
tagId:
|
|
4558
|
-
filePath:
|
|
4559
|
-
readCount:
|
|
4560
|
-
suggestedAction:
|
|
4561
|
-
reasoning:
|
|
4892
|
+
tagName: z5.string().describe("Tag whose agents read this file"),
|
|
4893
|
+
tagId: z5.string().optional(),
|
|
4894
|
+
filePath: z5.string(),
|
|
4895
|
+
readCount: z5.number(),
|
|
4896
|
+
suggestedAction: z5.string().describe("What doc or rule should be created"),
|
|
4897
|
+
reasoning: z5.string()
|
|
4562
4898
|
},
|
|
4563
4899
|
async (args) => {
|
|
4564
4900
|
const result = collectRecommendation(
|
|
@@ -4570,15 +4906,15 @@ function createAuditMcpServer(collector, onRecommendation) {
|
|
|
4570
4906
|
return { content: [{ type: "text", text: result }] };
|
|
4571
4907
|
}
|
|
4572
4908
|
),
|
|
4573
|
-
|
|
4909
|
+
tool5(
|
|
4574
4910
|
"recommend_merge_tags",
|
|
4575
4911
|
"Recommend merging one tag into another",
|
|
4576
4912
|
{
|
|
4577
|
-
tagId:
|
|
4578
|
-
tagName:
|
|
4579
|
-
mergeIntoTagId:
|
|
4580
|
-
mergeIntoTagName:
|
|
4581
|
-
reasoning:
|
|
4913
|
+
tagId: z5.string().describe("Tag ID to be merged (removed after merge)"),
|
|
4914
|
+
tagName: z5.string().describe("Name of the tag to be merged"),
|
|
4915
|
+
mergeIntoTagId: z5.string().describe("Tag ID to merge into (kept)"),
|
|
4916
|
+
mergeIntoTagName: z5.string(),
|
|
4917
|
+
reasoning: z5.string()
|
|
4582
4918
|
},
|
|
4583
4919
|
async (args) => {
|
|
4584
4920
|
const result = collectRecommendation(
|
|
@@ -4590,14 +4926,14 @@ function createAuditMcpServer(collector, onRecommendation) {
|
|
|
4590
4926
|
return { content: [{ type: "text", text: result }] };
|
|
4591
4927
|
}
|
|
4592
4928
|
),
|
|
4593
|
-
|
|
4929
|
+
tool5(
|
|
4594
4930
|
"recommend_rename_tag",
|
|
4595
4931
|
"Recommend renaming a tag",
|
|
4596
4932
|
{
|
|
4597
|
-
tagId:
|
|
4598
|
-
tagName:
|
|
4599
|
-
newName:
|
|
4600
|
-
reasoning:
|
|
4933
|
+
tagId: z5.string(),
|
|
4934
|
+
tagName: z5.string().describe("Current tag name"),
|
|
4935
|
+
newName: z5.string().describe("Proposed new name"),
|
|
4936
|
+
reasoning: z5.string()
|
|
4601
4937
|
},
|
|
4602
4938
|
async (args) => {
|
|
4603
4939
|
const result = collectRecommendation(
|
|
@@ -4609,10 +4945,10 @@ function createAuditMcpServer(collector, onRecommendation) {
|
|
|
4609
4945
|
return { content: [{ type: "text", text: result }] };
|
|
4610
4946
|
}
|
|
4611
4947
|
),
|
|
4612
|
-
|
|
4948
|
+
tool5(
|
|
4613
4949
|
"complete_audit",
|
|
4614
4950
|
"Signal that the audit is complete with a summary of all findings",
|
|
4615
|
-
{ summary:
|
|
4951
|
+
{ summary: z5.string().describe("Brief overview of all findings") },
|
|
4616
4952
|
async (args) => {
|
|
4617
4953
|
collector.complete = true;
|
|
4618
4954
|
collector.summary = args.summary ?? "Audit completed.";
|
|
@@ -4620,7 +4956,7 @@ function createAuditMcpServer(collector, onRecommendation) {
|
|
|
4620
4956
|
}
|
|
4621
4957
|
)
|
|
4622
4958
|
];
|
|
4623
|
-
return
|
|
4959
|
+
return createSdkMcpServer3({
|
|
4624
4960
|
name: "tag-audit",
|
|
4625
4961
|
tools: auditTools
|
|
4626
4962
|
});
|
|
@@ -4808,13 +5144,20 @@ function setupWorkDir(projectDir, assignment) {
|
|
|
4808
5144
|
workDir = projectDir;
|
|
4809
5145
|
}
|
|
4810
5146
|
if (branch && branch !== devBranch) {
|
|
4811
|
-
|
|
4812
|
-
|
|
4813
|
-
|
|
5147
|
+
if (hasUncommittedChanges(workDir)) {
|
|
5148
|
+
logger6.warn("Uncommitted changes in work dir, skipping checkout", {
|
|
5149
|
+
taskId: shortId,
|
|
5150
|
+
branch
|
|
5151
|
+
});
|
|
5152
|
+
} else {
|
|
4814
5153
|
try {
|
|
4815
|
-
|
|
5154
|
+
execSync7(`git checkout ${branch}`, { cwd: workDir, stdio: "ignore" });
|
|
4816
5155
|
} catch {
|
|
4817
|
-
|
|
5156
|
+
try {
|
|
5157
|
+
execSync7(`git checkout -b ${branch}`, { cwd: workDir, stdio: "ignore" });
|
|
5158
|
+
} catch {
|
|
5159
|
+
logger6.warn("Could not checkout branch", { taskId: shortId, branch });
|
|
5160
|
+
}
|
|
4818
5161
|
}
|
|
4819
5162
|
}
|
|
4820
5163
|
}
|
|
@@ -4871,6 +5214,7 @@ var ProjectRunner = class {
|
|
|
4871
5214
|
heartbeatTimer = null;
|
|
4872
5215
|
stopping = false;
|
|
4873
5216
|
resolveLifecycle = null;
|
|
5217
|
+
chatSessionIds = /* @__PURE__ */ new Map();
|
|
4874
5218
|
// Start command process management
|
|
4875
5219
|
startCommandChild = null;
|
|
4876
5220
|
startCommandRunning = false;
|
|
@@ -4918,9 +5262,20 @@ var ProjectRunner = class {
|
|
|
4918
5262
|
checkoutWorkspaceBranch() {
|
|
4919
5263
|
const workspaceBranch = process.env.CONVEYOR_WORKSPACE_BRANCH;
|
|
4920
5264
|
if (!workspaceBranch) return;
|
|
5265
|
+
const currentBranch = this.getCurrentBranch();
|
|
5266
|
+
if (currentBranch === workspaceBranch) {
|
|
5267
|
+
logger6.info("Already on workspace branch", { workspaceBranch });
|
|
5268
|
+
return;
|
|
5269
|
+
}
|
|
5270
|
+
if (hasUncommittedChanges(this.projectDir)) {
|
|
5271
|
+
logger6.warn("Uncommitted changes detected, skipping workspace branch checkout", {
|
|
5272
|
+
workspaceBranch
|
|
5273
|
+
});
|
|
5274
|
+
return;
|
|
5275
|
+
}
|
|
4921
5276
|
try {
|
|
4922
|
-
|
|
4923
|
-
|
|
5277
|
+
execSync7(`git fetch origin ${workspaceBranch}`, { cwd: this.projectDir, stdio: "pipe" });
|
|
5278
|
+
execSync7(`git checkout ${workspaceBranch}`, { cwd: this.projectDir, stdio: "pipe" });
|
|
4924
5279
|
logger6.info("Checked out workspace branch", { workspaceBranch });
|
|
4925
5280
|
} catch (err) {
|
|
4926
5281
|
logger6.warn("Failed to checkout workspace branch, continuing on current branch", {
|
|
@@ -5008,39 +5363,20 @@ var ProjectRunner = class {
|
|
|
5008
5363
|
this.executeStartCommand();
|
|
5009
5364
|
}
|
|
5010
5365
|
getEnvironmentStatus() {
|
|
5011
|
-
let currentBranch = "unknown";
|
|
5012
|
-
try {
|
|
5013
|
-
currentBranch = execSync6("git branch --show-current", {
|
|
5014
|
-
cwd: this.projectDir,
|
|
5015
|
-
stdio: ["ignore", "pipe", "ignore"]
|
|
5016
|
-
}).toString().trim();
|
|
5017
|
-
} catch {
|
|
5018
|
-
}
|
|
5019
5366
|
return {
|
|
5020
5367
|
setupComplete: this.setupComplete,
|
|
5021
5368
|
startCommandRunning: this.startCommandRunning,
|
|
5022
|
-
currentBranch,
|
|
5369
|
+
currentBranch: this.getCurrentBranch() ?? "unknown",
|
|
5023
5370
|
previewPort: Number(process.env.CONVEYOR_PREVIEW_PORT) || null
|
|
5024
5371
|
};
|
|
5025
5372
|
}
|
|
5026
5373
|
getCurrentBranch() {
|
|
5027
|
-
|
|
5028
|
-
return execSync6("git branch --show-current", {
|
|
5029
|
-
cwd: this.projectDir,
|
|
5030
|
-
stdio: ["ignore", "pipe", "ignore"]
|
|
5031
|
-
}).toString().trim() || null;
|
|
5032
|
-
} catch {
|
|
5033
|
-
return null;
|
|
5034
|
-
}
|
|
5374
|
+
return getCurrentBranch(this.projectDir);
|
|
5035
5375
|
}
|
|
5036
5376
|
// oxlint-disable-next-line max-lines-per-function, complexity -- sequential sync steps with per-step error handling
|
|
5037
5377
|
async smartSync(previousSha, newSha, branch) {
|
|
5038
5378
|
const stepsRun = [];
|
|
5039
|
-
|
|
5040
|
-
cwd: this.projectDir,
|
|
5041
|
-
stdio: ["ignore", "pipe", "ignore"]
|
|
5042
|
-
}).toString().trim();
|
|
5043
|
-
if (status) {
|
|
5379
|
+
if (hasUncommittedChanges(this.projectDir)) {
|
|
5044
5380
|
this.connection.emitEvent({
|
|
5045
5381
|
type: "commit_watch_warning",
|
|
5046
5382
|
message: "Working tree has uncommitted changes. Auto-pull skipped."
|
|
@@ -5050,7 +5386,7 @@ var ProjectRunner = class {
|
|
|
5050
5386
|
await this.killStartCommand();
|
|
5051
5387
|
this.connection.emitEnvSwitchProgress({ step: "pull", status: "running" });
|
|
5052
5388
|
try {
|
|
5053
|
-
|
|
5389
|
+
execSync7(`git pull origin ${branch}`, {
|
|
5054
5390
|
cwd: this.projectDir,
|
|
5055
5391
|
stdio: "pipe",
|
|
5056
5392
|
timeout: 6e4
|
|
@@ -5066,7 +5402,7 @@ var ProjectRunner = class {
|
|
|
5066
5402
|
}
|
|
5067
5403
|
let changedFiles = [];
|
|
5068
5404
|
try {
|
|
5069
|
-
changedFiles =
|
|
5405
|
+
changedFiles = execSync7(`git diff --name-only ${previousSha}..${newSha}`, {
|
|
5070
5406
|
cwd: this.projectDir,
|
|
5071
5407
|
stdio: ["ignore", "pipe", "ignore"]
|
|
5072
5408
|
}).toString().trim().split("\n").filter(Boolean);
|
|
@@ -5096,7 +5432,7 @@ var ProjectRunner = class {
|
|
|
5096
5432
|
if (needsInstall) {
|
|
5097
5433
|
this.connection.emitEnvSwitchProgress({ step: "install", status: "running" });
|
|
5098
5434
|
try {
|
|
5099
|
-
|
|
5435
|
+
execSync7("bun install", { cwd: this.projectDir, timeout: 12e4, stdio: "pipe" });
|
|
5100
5436
|
stepsRun.push("install");
|
|
5101
5437
|
this.connection.emitEnvSwitchProgress({ step: "install", status: "success" });
|
|
5102
5438
|
} catch (err) {
|
|
@@ -5108,12 +5444,12 @@ var ProjectRunner = class {
|
|
|
5108
5444
|
if (needsPrisma) {
|
|
5109
5445
|
this.connection.emitEnvSwitchProgress({ step: "prisma", status: "running" });
|
|
5110
5446
|
try {
|
|
5111
|
-
|
|
5447
|
+
execSync7("bunx prisma generate", {
|
|
5112
5448
|
cwd: this.projectDir,
|
|
5113
5449
|
timeout: 6e4,
|
|
5114
5450
|
stdio: "pipe"
|
|
5115
5451
|
});
|
|
5116
|
-
|
|
5452
|
+
execSync7("bunx prisma db push --accept-data-loss", {
|
|
5117
5453
|
cwd: this.projectDir,
|
|
5118
5454
|
timeout: 6e4,
|
|
5119
5455
|
stdio: "pipe"
|
|
@@ -5136,14 +5472,15 @@ var ProjectRunner = class {
|
|
|
5136
5472
|
try {
|
|
5137
5473
|
this.connection.emitEnvSwitchProgress({ step: "fetch", status: "running" });
|
|
5138
5474
|
try {
|
|
5139
|
-
|
|
5475
|
+
execSync7("git fetch origin", { cwd: this.projectDir, stdio: "pipe" });
|
|
5140
5476
|
} catch {
|
|
5141
5477
|
logger6.warn("Git fetch failed during branch switch");
|
|
5142
5478
|
}
|
|
5143
5479
|
this.connection.emitEnvSwitchProgress({ step: "fetch", status: "success" });
|
|
5480
|
+
detachWorktreeBranch(this.projectDir, branch);
|
|
5144
5481
|
this.connection.emitEnvSwitchProgress({ step: "checkout", status: "running" });
|
|
5145
5482
|
try {
|
|
5146
|
-
|
|
5483
|
+
execSync7(`git checkout ${branch}`, { cwd: this.projectDir, stdio: "pipe" });
|
|
5147
5484
|
} catch (err) {
|
|
5148
5485
|
const message = err instanceof Error ? err.message : "Checkout failed";
|
|
5149
5486
|
this.connection.emitEnvSwitchProgress({ step: "checkout", status: "error", message });
|
|
@@ -5151,7 +5488,7 @@ var ProjectRunner = class {
|
|
|
5151
5488
|
return;
|
|
5152
5489
|
}
|
|
5153
5490
|
try {
|
|
5154
|
-
|
|
5491
|
+
execSync7(`git pull origin ${branch}`, { cwd: this.projectDir, stdio: "pipe" });
|
|
5155
5492
|
} catch {
|
|
5156
5493
|
logger6.warn("Git pull failed during branch switch", { branch });
|
|
5157
5494
|
}
|
|
@@ -5225,7 +5562,15 @@ var ProjectRunner = class {
|
|
|
5225
5562
|
});
|
|
5226
5563
|
this.connection.onChatMessage((msg) => {
|
|
5227
5564
|
logger6.debug("Received project chat message");
|
|
5228
|
-
|
|
5565
|
+
const chatId = msg.chatId ?? "default";
|
|
5566
|
+
const existingSessionId = this.chatSessionIds.get(chatId);
|
|
5567
|
+
void handleProjectChatMessage(msg, this.connection, this.projectDir, existingSessionId).then(
|
|
5568
|
+
(newSessionId) => {
|
|
5569
|
+
if (newSessionId) {
|
|
5570
|
+
this.chatSessionIds.set(chatId, newSessionId);
|
|
5571
|
+
}
|
|
5572
|
+
}
|
|
5573
|
+
);
|
|
5229
5574
|
});
|
|
5230
5575
|
this.connection.onAuditRequest((request) => {
|
|
5231
5576
|
logger6.debug("Received tag audit request", { requestId: request.requestId });
|
|
@@ -5282,7 +5627,7 @@ var ProjectRunner = class {
|
|
|
5282
5627
|
}
|
|
5283
5628
|
try {
|
|
5284
5629
|
try {
|
|
5285
|
-
|
|
5630
|
+
execSync7("git fetch origin", { cwd: this.projectDir, stdio: "ignore" });
|
|
5286
5631
|
} catch {
|
|
5287
5632
|
logger6.warn("Git fetch failed", { taskId: shortId });
|
|
5288
5633
|
}
|
|
@@ -5456,4 +5801,4 @@ export {
|
|
|
5456
5801
|
ProjectRunner,
|
|
5457
5802
|
FileCache
|
|
5458
5803
|
};
|
|
5459
|
-
//# sourceMappingURL=chunk-
|
|
5804
|
+
//# sourceMappingURL=chunk-4RFYCO2T.js.map
|