@vibedeckx/linux-x64 0.2.5 → 0.2.7
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/bin.js +299 -20
- package/package.json +1 -1
package/dist/bin.js
CHANGED
|
@@ -186146,7 +186146,11 @@ var asRun = (row) => row;
|
|
|
186146
186146
|
var createWorkflowRunRepos = (kdb) => ({
|
|
186147
186147
|
workflowRuns: {
|
|
186148
186148
|
create: async (opts) => {
|
|
186149
|
-
await kdb.insertInto("workflow_runs").values({
|
|
186149
|
+
await kdb.insertInto("workflow_runs").values({
|
|
186150
|
+
...opts,
|
|
186151
|
+
reviewer_session_id: opts.reviewer_session_id ?? null,
|
|
186152
|
+
status: "waiting_reviewer"
|
|
186153
|
+
}).execute();
|
|
186150
186154
|
const row = await kdb.selectFrom("workflow_runs").selectAll().where("id", "=", opts.id).executeTakeFirstOrThrow();
|
|
186151
186155
|
return asRun(row);
|
|
186152
186156
|
},
|
|
@@ -186169,6 +186173,10 @@ var createWorkflowRunRepos = (kdb) => ({
|
|
|
186169
186173
|
])).executeTakeFirst();
|
|
186170
186174
|
return row ? asRun(row) : void 0;
|
|
186171
186175
|
},
|
|
186176
|
+
getLatestCompletedBySource: async (sourceSessionId) => {
|
|
186177
|
+
const row = await kdb.selectFrom("workflow_runs").selectAll().where("source_session_id", "=", sourceSessionId).where("status", "=", "completed").where("reviewer_session_id", "is not", null).orderBy("created_at", "desc").orderBy(sql`rowid`, "desc").executeTakeFirst();
|
|
186178
|
+
return row ? asRun(row) : void 0;
|
|
186179
|
+
},
|
|
186172
186180
|
update: async (id, patch) => {
|
|
186173
186181
|
if (Object.keys(patch).length > 0) {
|
|
186174
186182
|
await kdb.updateTable("workflow_runs").set({ ...patch, updated_at: sql`datetime('now')` }).where("id", "=", id).execute();
|
|
@@ -224161,6 +224169,20 @@ var AgentSessionManager = class {
|
|
|
224161
224169
|
this.titleResolved.add(sessionId);
|
|
224162
224170
|
return true;
|
|
224163
224171
|
}
|
|
224172
|
+
/**
|
|
224173
|
+
* Write a caller-determined final title and claim the one-shot slot so the
|
|
224174
|
+
* AI title generator never fires for this session — same pattern as the
|
|
224175
|
+
* Branch path's "Branch - <source title>". The slot is claimed before the
|
|
224176
|
+
* DB write: even if the write fails, a degraded placeholder title beats an
|
|
224177
|
+
* AI title racing in over the caller's intent.
|
|
224178
|
+
*/
|
|
224179
|
+
async setFinalSessionTitle(sessionId, title) {
|
|
224180
|
+
this.markTitleResolved(sessionId);
|
|
224181
|
+
await this.storage.agentSessions.updateTitle(sessionId, title);
|
|
224182
|
+
this.broadcastRaw(sessionId, { titleUpdated: { title } });
|
|
224183
|
+
const session = this.sessions.get(sessionId);
|
|
224184
|
+
if (session) this.emitSessionTitle(session.projectId, session.branch, sessionId, title);
|
|
224185
|
+
}
|
|
224164
224186
|
isProcessAlive(session) {
|
|
224165
224187
|
return !!session.process && session.process.exitCode === null && !session.dormant;
|
|
224166
224188
|
}
|
|
@@ -226013,6 +226035,13 @@ function mapRemoteRun(run2, remoteServerId, projectId) {
|
|
|
226013
226035
|
reviewer_session_id: run2.reviewer_session_id ? `${prefix}${run2.reviewer_session_id}` : null
|
|
226014
226036
|
};
|
|
226015
226037
|
}
|
|
226038
|
+
function mapRemoteReviewerCandidate(candidate, remoteServerId, projectId) {
|
|
226039
|
+
if (!candidate?.sessionId) return candidate;
|
|
226040
|
+
return {
|
|
226041
|
+
...candidate,
|
|
226042
|
+
sessionId: `remote-${remoteServerId}-${projectId}-${candidate.sessionId}`
|
|
226043
|
+
};
|
|
226044
|
+
}
|
|
226016
226045
|
function runUpdatedEventFromRemoteFrame(parsed, sessionId, remoteInfo) {
|
|
226017
226046
|
if (!("workflowRunUpdated" in parsed)) return null;
|
|
226018
226047
|
const bare = parsed.workflowRunUpdated;
|
|
@@ -228699,9 +228728,10 @@ function extractLatestTurnEndIndex(entries) {
|
|
|
228699
228728
|
}
|
|
228700
228729
|
return null;
|
|
228701
228730
|
}
|
|
228702
|
-
function
|
|
228731
|
+
function extractLastAssistantInTurn(entries, beforeIndex) {
|
|
228703
228732
|
for (let i = beforeIndex - 1; i >= 0; i--) {
|
|
228704
228733
|
const e = entries[i];
|
|
228734
|
+
if (e?.type === "user") return null;
|
|
228705
228735
|
if (e?.type === "assistant" && typeof e.content === "string" && e.content.trim()) return e.content;
|
|
228706
228736
|
}
|
|
228707
228737
|
return null;
|
|
@@ -228732,6 +228762,27 @@ ${opts.reviewFocus}` : null,
|
|
|
228732
228762
|
"\nEnd your final message with a clear, actionable list of feedback items \u2014 or state explicitly that the work looks good."
|
|
228733
228763
|
].filter((l) => l !== null).join("\n");
|
|
228734
228764
|
}
|
|
228765
|
+
function reviewTargetPromptLine(target) {
|
|
228766
|
+
return target.baseHead ? `- The work was captured at commit ${target.baseHead}${target.diffStat ? ` with uncommitted changes (${target.diffStat})` : " with no uncommitted changes"}.` : null;
|
|
228767
|
+
}
|
|
228768
|
+
function buildRereviewerPrompt(opts) {
|
|
228769
|
+
return [
|
|
228770
|
+
"The source agent has addressed feedback from your previous review.",
|
|
228771
|
+
"Review the latest workspace state again.",
|
|
228772
|
+
opts.taskContext ? `
|
|
228773
|
+
## Latest source turn
|
|
228774
|
+
${opts.taskContext}` : null,
|
|
228775
|
+
opts.reviewFocus ? `
|
|
228776
|
+
## Review focus
|
|
228777
|
+
${opts.reviewFocus}` : null,
|
|
228778
|
+
"\n## How to review",
|
|
228779
|
+
"- Verify whether your previous feedback was addressed correctly.",
|
|
228780
|
+
"- Check for regressions and remaining correctness or test gaps.",
|
|
228781
|
+
"- Do NOT modify files \u2014 remain in read-only review mode.",
|
|
228782
|
+
reviewTargetPromptLine(opts.target),
|
|
228783
|
+
"- End with actionable feedback, or explicitly state that it looks good."
|
|
228784
|
+
].filter((line) => line !== null).join("\n");
|
|
228785
|
+
}
|
|
228735
228786
|
function buildFeedbackMessage(feedback) {
|
|
228736
228787
|
return [
|
|
228737
228788
|
"[Review Feedback]",
|
|
@@ -228740,6 +228791,7 @@ function buildFeedbackMessage(feedback) {
|
|
|
228740
228791
|
feedback
|
|
228741
228792
|
].join("\n");
|
|
228742
228793
|
}
|
|
228794
|
+
var REVIEWER_AGENT_TYPES = /* @__PURE__ */ new Set(["claude-code", "codex"]);
|
|
228743
228795
|
var WorkflowEngine = class {
|
|
228744
228796
|
constructor(storage, agentOps) {
|
|
228745
228797
|
this.storage = storage;
|
|
@@ -228789,6 +228841,15 @@ var WorkflowEngine = class {
|
|
|
228789
228841
|
if (p2.runId === run2.id) this.participants.delete(sid);
|
|
228790
228842
|
}
|
|
228791
228843
|
}
|
|
228844
|
+
releaseReservations(runId) {
|
|
228845
|
+
for (const [sid, participant] of this.participants) {
|
|
228846
|
+
if (participant.runId === runId) this.participants.delete(sid);
|
|
228847
|
+
}
|
|
228848
|
+
}
|
|
228849
|
+
async failRun(run2, error48) {
|
|
228850
|
+
const failed = await this.storage.workflowRuns.update(run2.id, { status: "failed", error: error48 });
|
|
228851
|
+
if (failed) this.untrackRun(failed);
|
|
228852
|
+
}
|
|
228792
228853
|
/** Sync check used by ChatSessionManager before waking the commander model. */
|
|
228793
228854
|
shouldSuppressAgentEvent(sessionId) {
|
|
228794
228855
|
return this.participants.get(sessionId)?.role === "reviewer";
|
|
@@ -228796,14 +228857,62 @@ var WorkflowEngine = class {
|
|
|
228796
228857
|
isSessionInActiveRun(sessionId) {
|
|
228797
228858
|
return this.participants.has(sessionId);
|
|
228798
228859
|
}
|
|
228860
|
+
async getReviewerCandidate(sourceSessionId) {
|
|
228861
|
+
const previous = await this.storage.workflowRuns.getLatestCompletedBySource(sourceSessionId);
|
|
228862
|
+
if (!previous?.reviewer_session_id) return null;
|
|
228863
|
+
const unavailable = (reason) => ({
|
|
228864
|
+
available: false,
|
|
228865
|
+
sessionId: null,
|
|
228866
|
+
title: null,
|
|
228867
|
+
agentType: null,
|
|
228868
|
+
reason
|
|
228869
|
+
});
|
|
228870
|
+
const source = await this.storage.agentSessions.getById(sourceSessionId);
|
|
228871
|
+
const reviewer = await this.storage.agentSessions.getById(previous.reviewer_session_id);
|
|
228872
|
+
if (!reviewer) return unavailable("deleted");
|
|
228873
|
+
if (!source || reviewer.project_id !== source.project_id || reviewer.project_id !== previous.project_id) {
|
|
228874
|
+
return unavailable("project-mismatch");
|
|
228875
|
+
}
|
|
228876
|
+
if ((reviewer.branch || null) !== (source.branch || null) || (reviewer.branch || null) !== previous.branch) {
|
|
228877
|
+
return unavailable("branch-mismatch");
|
|
228878
|
+
}
|
|
228879
|
+
if (!REVIEWER_AGENT_TYPES.has(reviewer.agent_type)) {
|
|
228880
|
+
return unavailable("unsupported-agent");
|
|
228881
|
+
}
|
|
228882
|
+
if (reviewer.status === "running") return unavailable("running");
|
|
228883
|
+
if (reviewer.status !== "stopped") return unavailable("unavailable");
|
|
228884
|
+
if (this.participants.has(reviewer.id) || await this.storage.workflowRuns.getActiveBySession(reviewer.id)) {
|
|
228885
|
+
return unavailable("busy");
|
|
228886
|
+
}
|
|
228887
|
+
return {
|
|
228888
|
+
available: true,
|
|
228889
|
+
sessionId: reviewer.id,
|
|
228890
|
+
title: reviewer.title ?? null,
|
|
228891
|
+
agentType: reviewer.agent_type,
|
|
228892
|
+
reason: null
|
|
228893
|
+
};
|
|
228894
|
+
}
|
|
228799
228895
|
async startAdhocReview(opts) {
|
|
228800
|
-
if (
|
|
228801
|
-
throw new WorkflowError("
|
|
228896
|
+
if (opts.reviewerSessionId === opts.sourceSessionId) {
|
|
228897
|
+
throw new WorkflowError("reviewer-unavailable", "reviewer session \u4E0D\u80FD\u4E0E source session \u76F8\u540C");
|
|
228898
|
+
}
|
|
228899
|
+
const runId = randomUUID5();
|
|
228900
|
+
const participantIds = [opts.sourceSessionId, opts.reviewerSessionId].filter((id) => Boolean(id));
|
|
228901
|
+
for (const sessionId of participantIds) {
|
|
228902
|
+
if (this.participants.has(sessionId)) {
|
|
228903
|
+
throw new WorkflowError("session-busy", "\u8BE5 session \u5DF2\u5728\u4E00\u4E2A\u8FDB\u884C\u4E2D\u7684 review \u91CC");
|
|
228904
|
+
}
|
|
228905
|
+
}
|
|
228906
|
+
this.participants.set(opts.sourceSessionId, { runId, role: "source" });
|
|
228907
|
+
if (opts.reviewerSessionId) {
|
|
228908
|
+
this.participants.set(opts.reviewerSessionId, { runId, role: "reviewer" });
|
|
228802
228909
|
}
|
|
228803
|
-
this.participants.set(opts.sourceSessionId, { runId: "pending", role: "source" });
|
|
228804
228910
|
try {
|
|
228805
|
-
const
|
|
228806
|
-
|
|
228911
|
+
for (const sessionId of participantIds) {
|
|
228912
|
+
if (await this.storage.workflowRuns.getActiveBySession(sessionId)) {
|
|
228913
|
+
throw new WorkflowError("session-busy", "\u8BE5 session \u5DF2\u5728\u4E00\u4E2A\u8FDB\u884C\u4E2D\u7684 review \u91CC");
|
|
228914
|
+
}
|
|
228915
|
+
}
|
|
228807
228916
|
const sourceSession = await this.storage.agentSessions.getById(opts.sourceSessionId);
|
|
228808
228917
|
if (sourceSession?.status === "running") {
|
|
228809
228918
|
throw new WorkflowError("source-running", "source session \u6B63\u5728\u8FD0\u884C\uFF0C\u8BF7\u7B49\u5F85\u5F53\u524D turn \u5B8C\u6210\u540E\u518D\u53D1\u8D77 review");
|
|
@@ -228815,16 +228924,61 @@ var WorkflowEngine = class {
|
|
|
228815
228924
|
}
|
|
228816
228925
|
const worktreePath = resolveWorktreePath(opts.project.path, opts.branch);
|
|
228817
228926
|
const target = captureReviewTarget(worktreePath);
|
|
228927
|
+
let reviewerSession = null;
|
|
228928
|
+
if (opts.reviewerSessionId) {
|
|
228929
|
+
reviewerSession = await this.storage.agentSessions.getById(opts.reviewerSessionId);
|
|
228930
|
+
if (!reviewerSession) {
|
|
228931
|
+
throw new WorkflowError("reviewer-unavailable", "\u4E0A\u6B21 reviewer session \u5DF2\u4E0D\u5B58\u5728");
|
|
228932
|
+
}
|
|
228933
|
+
if (reviewerSession.project_id !== opts.project.id) {
|
|
228934
|
+
throw new WorkflowError("reviewer-unavailable", "reviewer session \u4E0D\u5C5E\u4E8E\u5F53\u524D\u9879\u76EE");
|
|
228935
|
+
}
|
|
228936
|
+
if ((reviewerSession.branch || null) !== opts.branch) {
|
|
228937
|
+
throw new WorkflowError("reviewer-unavailable", "reviewer session \u4E0D\u5C5E\u4E8E\u5F53\u524D branch");
|
|
228938
|
+
}
|
|
228939
|
+
if (!REVIEWER_AGENT_TYPES.has(reviewerSession.agent_type)) {
|
|
228940
|
+
throw new WorkflowError("reviewer-unavailable", "reviewer agent \u7C7B\u578B\u4E0D\u53EF\u7528");
|
|
228941
|
+
}
|
|
228942
|
+
if (reviewerSession.status !== "stopped") {
|
|
228943
|
+
throw new WorkflowError("reviewer-unavailable", "reviewer session \u6B63\u5728\u8FD0\u884C\u6216\u4E0D\u53EF\u7528");
|
|
228944
|
+
}
|
|
228945
|
+
}
|
|
228818
228946
|
const run2 = await this.storage.workflowRuns.create({
|
|
228819
|
-
id:
|
|
228947
|
+
id: runId,
|
|
228820
228948
|
project_id: opts.project.id,
|
|
228821
228949
|
branch: opts.branch,
|
|
228822
228950
|
source_session_id: opts.sourceSessionId,
|
|
228823
228951
|
source_turn_end_index: turnEndIndex,
|
|
228824
228952
|
review_focus: opts.reviewFocus ?? null,
|
|
228825
|
-
review_target: JSON.stringify(target)
|
|
228953
|
+
review_target: JSON.stringify(target),
|
|
228954
|
+
reviewer_session_id: opts.reviewerSessionId ?? null
|
|
228826
228955
|
});
|
|
228827
228956
|
this.trackParticipants(run2);
|
|
228957
|
+
if (opts.reviewerSessionId && reviewerSession) {
|
|
228958
|
+
if (reviewerSession.permission_mode !== "plan") {
|
|
228959
|
+
let switched = false;
|
|
228960
|
+
try {
|
|
228961
|
+
switched = await this.agentOps.switchMode(opts.reviewerSessionId, opts.project.path, "plan");
|
|
228962
|
+
} catch {
|
|
228963
|
+
}
|
|
228964
|
+
if (!switched) {
|
|
228965
|
+
await this.failRun(run2, "\u65E0\u6CD5\u5C06 reviewer \u6062\u590D\u4E3A\u53EA\u8BFB plan \u6A21\u5F0F");
|
|
228966
|
+
throw new WorkflowError("reviewer-unavailable", "\u65E0\u6CD5\u5C06 reviewer \u6062\u590D\u4E3A\u53EA\u8BFB plan \u6A21\u5F0F");
|
|
228967
|
+
}
|
|
228968
|
+
}
|
|
228969
|
+
const prompt = buildRereviewerPrompt({
|
|
228970
|
+
taskContext: extractTaskContextBefore(entries, turnEndIndex),
|
|
228971
|
+
reviewFocus: opts.reviewFocus ?? null,
|
|
228972
|
+
target
|
|
228973
|
+
});
|
|
228974
|
+
const sent = await this.agentOps.sendUserMessage(opts.reviewerSessionId, prompt, opts.project.path).catch(() => false);
|
|
228975
|
+
if (!sent) {
|
|
228976
|
+
await this.failRun(run2, "\u5411\u4E0A\u6B21 reviewer \u6295\u9012\u590D\u5BA1\u4EFB\u52A1\u5931\u8D25");
|
|
228977
|
+
throw new WorkflowError("send-failed", "\u5411\u4E0A\u6B21 reviewer \u6295\u9012\u590D\u5BA1\u4EFB\u52A1\u5931\u8D25");
|
|
228978
|
+
}
|
|
228979
|
+
this.emitRunUpdated(run2);
|
|
228980
|
+
return run2;
|
|
228981
|
+
}
|
|
228828
228982
|
try {
|
|
228829
228983
|
const reviewerId = await this.agentOps.createNewSession(
|
|
228830
228984
|
opts.project.id,
|
|
@@ -228832,11 +228986,16 @@ var WorkflowEngine = class {
|
|
|
228832
228986
|
opts.project.path,
|
|
228833
228987
|
false,
|
|
228834
228988
|
"plan",
|
|
228835
|
-
"claude-code",
|
|
228989
|
+
opts.reviewerAgentType ?? "claude-code",
|
|
228836
228990
|
true
|
|
228837
228991
|
);
|
|
228992
|
+
const taskContext = extractTaskContextBefore(entries, turnEndIndex);
|
|
228993
|
+
await this.agentOps.setFinalSessionTitle(
|
|
228994
|
+
reviewerId,
|
|
228995
|
+
`Review - ${sourceSession?.title || (taskContext ? snippetTitle(taskContext) : null) || "Conversation"}`
|
|
228996
|
+
).catch((err) => console.warn(`[WorkflowEngine] failed to set reviewer title for ${reviewerId}:`, err));
|
|
228838
228997
|
const prompt = buildReviewerPrompt({
|
|
228839
|
-
taskContext
|
|
228998
|
+
taskContext,
|
|
228840
228999
|
reviewFocus: opts.reviewFocus ?? null,
|
|
228841
229000
|
target
|
|
228842
229001
|
});
|
|
@@ -228863,9 +229022,7 @@ var WorkflowEngine = class {
|
|
|
228863
229022
|
throw new WorkflowError("spawn-failed", "\u521B\u5EFA reviewer session \u5931\u8D25");
|
|
228864
229023
|
}
|
|
228865
229024
|
} catch (err) {
|
|
228866
|
-
|
|
228867
|
-
this.participants.delete(opts.sourceSessionId);
|
|
228868
|
-
}
|
|
229025
|
+
this.releaseReservations(runId);
|
|
228869
229026
|
throw err;
|
|
228870
229027
|
}
|
|
228871
229028
|
}
|
|
@@ -228876,7 +229033,7 @@ var WorkflowEngine = class {
|
|
|
228876
229033
|
if (!run2 || run2.status !== "waiting_reviewer") return;
|
|
228877
229034
|
const entries = this.agentOps.getRawMessages(event.sessionId);
|
|
228878
229035
|
const boundary = event.turnEndEntryIndex ?? extractLatestTurnEndIndex(entries) ?? entries.length;
|
|
228879
|
-
const feedback =
|
|
229036
|
+
const feedback = extractLastAssistantInTurn(entries, boundary) ?? "(reviewer \u6CA1\u6709\u8F93\u51FA\u53EF\u7528\u7684\u53CD\u9988\u6587\u672C)";
|
|
228880
229037
|
let driftNote = null;
|
|
228881
229038
|
try {
|
|
228882
229039
|
const target = run2.review_target ? JSON.parse(run2.review_target) : null;
|
|
@@ -234913,6 +235070,9 @@ var routes11 = async (fastify2) => {
|
|
|
234913
235070
|
);
|
|
234914
235071
|
return reply.code(proxyStatus(result)).send(result.data);
|
|
234915
235072
|
}
|
|
235073
|
+
if (fastify2.workflowEngine.isSessionInActiveRun(req.params.sessionId)) {
|
|
235074
|
+
return reply.code(409).send({ error: "Session is participating in an active review" });
|
|
235075
|
+
}
|
|
234916
235076
|
const session = fastify2.agentSessionManager.getSession(req.params.sessionId);
|
|
234917
235077
|
if (!session) {
|
|
234918
235078
|
return reply.code(404).send({ error: "Session not found" });
|
|
@@ -234952,6 +235112,9 @@ var routes11 = async (fastify2) => {
|
|
|
234952
235112
|
);
|
|
234953
235113
|
return reply.code(proxyStatus(result)).send(result.data);
|
|
234954
235114
|
}
|
|
235115
|
+
if (fastify2.workflowEngine.isSessionInActiveRun(req.params.sessionId)) {
|
|
235116
|
+
return reply.code(409).send({ error: "Session is participating in an active review" });
|
|
235117
|
+
}
|
|
234955
235118
|
const session = fastify2.agentSessionManager.getSession(req.params.sessionId);
|
|
234956
235119
|
if (!session) {
|
|
234957
235120
|
return reply.code(404).send({ error: "Session not found" });
|
|
@@ -235890,6 +236053,10 @@ var command_routes_default = (0, import_fastify_plugin18.default)(routes17, { na
|
|
|
235890
236053
|
|
|
235891
236054
|
// src/routes/workflow-run-routes.ts
|
|
235892
236055
|
var import_fastify_plugin19 = __toESM(require_plugin2(), 1);
|
|
236056
|
+
function parseReviewerAgentType(raw) {
|
|
236057
|
+
if (raw === void 0) return void 0;
|
|
236058
|
+
return typeof raw === "string" && REVIEWER_AGENT_TYPES.has(raw) ? raw : null;
|
|
236059
|
+
}
|
|
235893
236060
|
function errStatus(err) {
|
|
235894
236061
|
if (!(err instanceof WorkflowError)) return null;
|
|
235895
236062
|
switch (err.code) {
|
|
@@ -235897,6 +236064,8 @@ function errStatus(err) {
|
|
|
235897
236064
|
return 409;
|
|
235898
236065
|
case "source-running":
|
|
235899
236066
|
return 409;
|
|
236067
|
+
case "reviewer-unavailable":
|
|
236068
|
+
return 409;
|
|
235900
236069
|
case "bad-state":
|
|
235901
236070
|
return 409;
|
|
235902
236071
|
case "no-completed-turn":
|
|
@@ -235934,6 +236103,16 @@ async function routes18(fastify2) {
|
|
|
235934
236103
|
if (userId === null) return;
|
|
235935
236104
|
const { projectId, branch, sourceSessionId, reviewFocus, sourceTurnEndIndex } = req.body ?? {};
|
|
235936
236105
|
if (!projectId || !sourceSessionId) return reply.code(400).send({ error: "projectId and sourceSessionId are required" });
|
|
236106
|
+
const reviewerAgentType = parseReviewerAgentType(req.body?.reviewerAgentType);
|
|
236107
|
+
if (reviewerAgentType === null) return reply.code(400).send({ error: "reviewerAgentType must be one of: claude-code, codex" });
|
|
236108
|
+
const reviewerSessionIdRaw = req.body?.reviewerSessionId;
|
|
236109
|
+
if (reviewerSessionIdRaw !== void 0 && (typeof reviewerSessionIdRaw !== "string" || reviewerSessionIdRaw.trim() === "")) {
|
|
236110
|
+
return reply.code(400).send({ error: "reviewerSessionId must be a non-empty string" });
|
|
236111
|
+
}
|
|
236112
|
+
if (reviewerSessionIdRaw !== void 0 && reviewerAgentType !== void 0) {
|
|
236113
|
+
return reply.code(400).send({ error: "reviewerSessionId and reviewerAgentType are mutually exclusive" });
|
|
236114
|
+
}
|
|
236115
|
+
const reviewerSessionId = reviewerSessionIdRaw?.trim();
|
|
235937
236116
|
if (sourceSessionId.startsWith("remote-")) {
|
|
235938
236117
|
const remoteInfo = fastify2.remoteSessionMap.get(sourceSessionId);
|
|
235939
236118
|
if (!remoteInfo) return reply.code(404).send({ error: "Session not found" });
|
|
@@ -235941,10 +236120,20 @@ async function routes18(fastify2) {
|
|
|
235941
236120
|
if (derivedProjectId !== projectId) return reply.code(404).send({ error: "Session not found" });
|
|
235942
236121
|
const remoteProject = await fastify2.storage.projects.getById(projectId, userId);
|
|
235943
236122
|
if (!remoteProject) return reply.code(404).send({ error: "Project not found" });
|
|
236123
|
+
let bareReviewerSessionId;
|
|
236124
|
+
if (reviewerSessionId) {
|
|
236125
|
+
const reviewerInfo = fastify2.remoteSessionMap.get(reviewerSessionId);
|
|
236126
|
+
if (!reviewerInfo || reviewerInfo.remoteServerId !== remoteInfo.remoteServerId || projectIdFromRemoteSessionId(reviewerSessionId, reviewerInfo) !== projectId) {
|
|
236127
|
+
return reply.code(404).send({ error: "Reviewer session not found" });
|
|
236128
|
+
}
|
|
236129
|
+
bareReviewerSessionId = reviewerInfo.remoteSessionId;
|
|
236130
|
+
}
|
|
235944
236131
|
const result = await proxyAuto(remoteInfo, "POST", "/api/path/workflow-runs", {
|
|
235945
236132
|
sourceSessionId: remoteInfo.remoteSessionId,
|
|
235946
236133
|
reviewFocus,
|
|
235947
|
-
sourceTurnEndIndex
|
|
236134
|
+
sourceTurnEndIndex,
|
|
236135
|
+
reviewerAgentType,
|
|
236136
|
+
reviewerSessionId: bareReviewerSessionId
|
|
235948
236137
|
});
|
|
235949
236138
|
if (!result.ok) return sendProxyFailure(reply, result);
|
|
235950
236139
|
const bareRun = result.data.run;
|
|
@@ -235957,13 +236146,14 @@ async function routes18(fastify2) {
|
|
|
235957
236146
|
projectId
|
|
235958
236147
|
});
|
|
235959
236148
|
if (bareRun.reviewer_session_id && localRun.reviewer_session_id) {
|
|
235960
|
-
|
|
236149
|
+
const reviewerInfo = {
|
|
235961
236150
|
remoteServerId: remoteInfo.remoteServerId,
|
|
235962
236151
|
remoteUrl: remoteInfo.remoteUrl,
|
|
235963
236152
|
remoteApiKey: remoteInfo.remoteApiKey,
|
|
235964
236153
|
remoteSessionId: bareRun.reviewer_session_id,
|
|
235965
236154
|
branch: bareRun.branch
|
|
235966
|
-
}
|
|
236155
|
+
};
|
|
236156
|
+
fastify2.remoteSessionMap.set(localRun.reviewer_session_id, reviewerInfo);
|
|
235967
236157
|
await fastify2.storage.remoteSessionMappings.upsert(
|
|
235968
236158
|
localRun.reviewer_session_id,
|
|
235969
236159
|
projectId,
|
|
@@ -235978,6 +236168,22 @@ async function routes18(fastify2) {
|
|
|
235978
236168
|
eventBus: fastify2.eventBus,
|
|
235979
236169
|
agentSessionManager: fastify2.agentSessionManager
|
|
235980
236170
|
});
|
|
236171
|
+
fastify2.eventBus.emit({
|
|
236172
|
+
type: "session:process",
|
|
236173
|
+
projectId,
|
|
236174
|
+
branch: bareRun.branch,
|
|
236175
|
+
sessionId: localRun.reviewer_session_id,
|
|
236176
|
+
alive: true
|
|
236177
|
+
});
|
|
236178
|
+
fastify2.eventBus.emit({
|
|
236179
|
+
type: "session:status",
|
|
236180
|
+
projectId,
|
|
236181
|
+
branch: bareRun.branch,
|
|
236182
|
+
sessionId: localRun.reviewer_session_id,
|
|
236183
|
+
status: "running"
|
|
236184
|
+
});
|
|
236185
|
+
fastify2.agentSessionManager.markTitleResolved(localRun.reviewer_session_id);
|
|
236186
|
+
await fastify2.storage.remoteSessionMappings.markTitleResolved(localRun.reviewer_session_id);
|
|
235981
236187
|
}
|
|
235982
236188
|
fastify2.eventBus.emit({ type: "workflow:run-updated", projectId, branch: bareRun.branch, run: localRun });
|
|
235983
236189
|
return reply.code(201).send({ run: localRun });
|
|
@@ -235999,7 +236205,9 @@ async function routes18(fastify2) {
|
|
|
235999
236205
|
branch: runBranch,
|
|
236000
236206
|
sourceSessionId,
|
|
236001
236207
|
reviewFocus,
|
|
236002
|
-
sourceTurnEndIndex
|
|
236208
|
+
sourceTurnEndIndex,
|
|
236209
|
+
reviewerAgentType,
|
|
236210
|
+
reviewerSessionId
|
|
236003
236211
|
});
|
|
236004
236212
|
return reply.code(201).send({ run: run2 });
|
|
236005
236213
|
} catch (err) {
|
|
@@ -236008,6 +236216,55 @@ async function routes18(fastify2) {
|
|
|
236008
236216
|
throw err;
|
|
236009
236217
|
}
|
|
236010
236218
|
});
|
|
236219
|
+
fastify2.get("/api/workflow-runs/reviewer-candidate", async (req, reply) => {
|
|
236220
|
+
const userId = requireAuth(req, reply);
|
|
236221
|
+
if (userId === null) return;
|
|
236222
|
+
const { projectId, sourceSessionId } = req.query;
|
|
236223
|
+
if (!projectId || !sourceSessionId) {
|
|
236224
|
+
return reply.code(400).send({ error: "projectId and sourceSessionId are required" });
|
|
236225
|
+
}
|
|
236226
|
+
const project = await fastify2.storage.projects.getById(projectId, userId);
|
|
236227
|
+
if (!project) return reply.code(404).send({ error: "Project not found" });
|
|
236228
|
+
if (sourceSessionId.startsWith("remote-")) {
|
|
236229
|
+
const remoteInfo = fastify2.remoteSessionMap.get(sourceSessionId);
|
|
236230
|
+
if (!remoteInfo || projectIdFromRemoteSessionId(sourceSessionId, remoteInfo) !== projectId) {
|
|
236231
|
+
return reply.code(404).send({ error: "Session not found" });
|
|
236232
|
+
}
|
|
236233
|
+
const params = new URLSearchParams({ sourceSessionId: remoteInfo.remoteSessionId });
|
|
236234
|
+
const result = await proxyAuto(
|
|
236235
|
+
remoteInfo,
|
|
236236
|
+
"GET",
|
|
236237
|
+
`/api/path/workflow-runs/reviewer-candidate?${params}`
|
|
236238
|
+
);
|
|
236239
|
+
if (!result.ok) return sendProxyFailure(reply, result);
|
|
236240
|
+
const bareCandidate = result.data.candidate;
|
|
236241
|
+
const candidate2 = mapRemoteReviewerCandidate(bareCandidate, remoteInfo.remoteServerId, projectId);
|
|
236242
|
+
if (bareCandidate?.sessionId && candidate2?.sessionId) {
|
|
236243
|
+
const reviewerInfo = {
|
|
236244
|
+
remoteServerId: remoteInfo.remoteServerId,
|
|
236245
|
+
remoteUrl: remoteInfo.remoteUrl,
|
|
236246
|
+
remoteApiKey: remoteInfo.remoteApiKey,
|
|
236247
|
+
remoteSessionId: bareCandidate.sessionId,
|
|
236248
|
+
branch: remoteInfo.branch
|
|
236249
|
+
};
|
|
236250
|
+
fastify2.remoteSessionMap.set(candidate2.sessionId, reviewerInfo);
|
|
236251
|
+
await fastify2.storage.remoteSessionMappings.upsert(
|
|
236252
|
+
candidate2.sessionId,
|
|
236253
|
+
projectId,
|
|
236254
|
+
remoteInfo.remoteServerId,
|
|
236255
|
+
bareCandidate.sessionId,
|
|
236256
|
+
remoteInfo.branch
|
|
236257
|
+
);
|
|
236258
|
+
}
|
|
236259
|
+
return reply.send({ candidate: candidate2 });
|
|
236260
|
+
}
|
|
236261
|
+
const sourceSession = await fastify2.storage.agentSessions.getById(sourceSessionId);
|
|
236262
|
+
if (!sourceSession || sourceSession.project_id !== projectId) {
|
|
236263
|
+
return reply.code(404).send({ error: "Session not found" });
|
|
236264
|
+
}
|
|
236265
|
+
const candidate = await fastify2.workflowEngine.getReviewerCandidate(sourceSessionId);
|
|
236266
|
+
return reply.send({ candidate });
|
|
236267
|
+
});
|
|
236011
236268
|
fastify2.get(
|
|
236012
236269
|
"/api/workflow-runs",
|
|
236013
236270
|
async (req, reply) => {
|
|
@@ -236128,6 +236385,16 @@ async function routes18(fastify2) {
|
|
|
236128
236385
|
if (userId === null) return;
|
|
236129
236386
|
const { sourceSessionId, reviewFocus, sourceTurnEndIndex } = req.body ?? {};
|
|
236130
236387
|
if (!sourceSessionId) return reply.code(400).send({ error: "sourceSessionId is required" });
|
|
236388
|
+
const reviewerAgentType = parseReviewerAgentType(req.body?.reviewerAgentType);
|
|
236389
|
+
if (reviewerAgentType === null) return reply.code(400).send({ error: "reviewerAgentType must be one of: claude-code, codex" });
|
|
236390
|
+
const reviewerSessionIdRaw = req.body?.reviewerSessionId;
|
|
236391
|
+
if (reviewerSessionIdRaw !== void 0 && (typeof reviewerSessionIdRaw !== "string" || reviewerSessionIdRaw.trim() === "")) {
|
|
236392
|
+
return reply.code(400).send({ error: "reviewerSessionId must be a non-empty string" });
|
|
236393
|
+
}
|
|
236394
|
+
if (reviewerSessionIdRaw !== void 0 && reviewerAgentType !== void 0) {
|
|
236395
|
+
return reply.code(400).send({ error: "reviewerSessionId and reviewerAgentType are mutually exclusive" });
|
|
236396
|
+
}
|
|
236397
|
+
const reviewerSessionId = reviewerSessionIdRaw?.trim();
|
|
236131
236398
|
const sourceSession = await fastify2.storage.agentSessions.getById(sourceSessionId);
|
|
236132
236399
|
if (!sourceSession) return reply.code(404).send({ error: "Session not found" });
|
|
236133
236400
|
const project = await fastify2.storage.projects.getById(sourceSession.project_id);
|
|
@@ -236139,7 +236406,9 @@ async function routes18(fastify2) {
|
|
|
236139
236406
|
branch: sourceSession.branch || null,
|
|
236140
236407
|
sourceSessionId,
|
|
236141
236408
|
reviewFocus,
|
|
236142
|
-
sourceTurnEndIndex
|
|
236409
|
+
sourceTurnEndIndex,
|
|
236410
|
+
reviewerAgentType,
|
|
236411
|
+
reviewerSessionId
|
|
236143
236412
|
});
|
|
236144
236413
|
return reply.code(201).send({ run: run2 });
|
|
236145
236414
|
} catch (err) {
|
|
@@ -236148,6 +236417,16 @@ async function routes18(fastify2) {
|
|
|
236148
236417
|
throw err;
|
|
236149
236418
|
}
|
|
236150
236419
|
});
|
|
236420
|
+
fastify2.get("/api/path/workflow-runs/reviewer-candidate", async (req, reply) => {
|
|
236421
|
+
const userId = requireAuth(req, reply);
|
|
236422
|
+
if (userId === null) return;
|
|
236423
|
+
const { sourceSessionId } = req.query;
|
|
236424
|
+
if (!sourceSessionId) return reply.code(400).send({ error: "sourceSessionId is required" });
|
|
236425
|
+
const sourceSession = await fastify2.storage.agentSessions.getById(sourceSessionId);
|
|
236426
|
+
if (!sourceSession) return reply.code(404).send({ error: "Session not found" });
|
|
236427
|
+
const candidate = await fastify2.workflowEngine.getReviewerCandidate(sourceSessionId);
|
|
236428
|
+
return reply.send({ candidate });
|
|
236429
|
+
});
|
|
236151
236430
|
fastify2.get("/api/path/workflow-runs", async (req, reply) => {
|
|
236152
236431
|
const userId = requireAuth(req, reply);
|
|
236153
236432
|
if (userId === null) return;
|