@vibedeckx/darwin-arm64 0.2.18 → 0.2.19

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.
Files changed (2) hide show
  1. package/dist/bin.js +242 -15
  2. package/package.json +1 -1
package/dist/bin.js CHANGED
@@ -186274,7 +186274,7 @@ var createSearchCacheRepos = (kdb, _h) => ({
186274
186274
  });
186275
186275
 
186276
186276
  // src/storage/repositories/workflow-runs.ts
186277
- var ACTIVE = ["waiting_reviewer", "waiting_feedback", "sending_feedback"];
186277
+ var ACTIVE = ["waiting_reviewer", "waiting_feedback", "discussing", "sending_feedback"];
186278
186278
  var asRun = (row) => row;
186279
186279
  var createWorkflowRunRepos = (kdb) => ({
186280
186280
  workflowRuns: {
@@ -202331,7 +202331,7 @@ import { existsSync as existsSync3 } from "fs";
202331
202331
  // src/notification-milestones.ts
202332
202332
  var sessionResultReadyId = (sessionId, turnEndEntryIndex) => `session:${sessionId}:turn:${turnEndEntryIndex}:result-ready`;
202333
202333
  var sessionFailedId = (sessionId, turnEndEntryIndex) => `session:${sessionId}:turn:${turnEndEntryIndex}:failed`;
202334
- var reviewReadyId = (workflowRunId) => `workflow:${workflowRunId}:review-ready`;
202334
+ var reviewReadyId = (workflowRunId, turnEndEntryIndex) => `workflow:${workflowRunId}:turn:${turnEndEntryIndex}:review-ready`;
202335
202335
  var workflowFailedId = (workflowRunId, stateVersion) => `workflow:${workflowRunId}:failed:${stateVersion}`;
202336
202336
  function findTurnOpeningUserEntry(entries, beforeIndex) {
202337
202337
  let opening;
@@ -225173,6 +225173,19 @@ var AgentSessionManager = class {
225173
225173
  console.error(`[AgentSession] Error in ${label} handler for ${session.id}:`, err);
225174
225174
  });
225175
225175
  }
225176
+ /**
225177
+ * Same serial chain as `enqueueSessionWork`, for a caller that needs the
225178
+ * result back. The chain itself absorbs the outcome (success or failure) so
225179
+ * one queued step can never break the next; the caller gets the real promise.
225180
+ */
225181
+ runSerialForResult(session, work) {
225182
+ const result = session.eventChain.then(work);
225183
+ session.eventChain = result.then(
225184
+ () => void 0,
225185
+ () => void 0
225186
+ );
225187
+ return result;
225188
+ }
225176
225189
  clearGraceTimer(session) {
225177
225190
  if (session.graceTimer) {
225178
225191
  clearTimeout(session.graceTimer);
@@ -226051,6 +226064,86 @@ var AgentSessionManager = class {
226051
226064
  }
226052
226065
  return "ok";
226053
226066
  }
226067
+ /**
226068
+ * Set (or clear, with null) a session's model. The model is a spawn
226069
+ * argument, so it takes effect on the next process the session spawns —
226070
+ * immediately for a dormant session (a branch, or one that was stopped),
226071
+ * and after retiring the idle process for a session that has one.
226072
+ *
226073
+ * Refused ("busy") under exactly the rule switchAgentType uses: a turn in
226074
+ * flight on a session that has history. Both are respawn-shaped changes, so
226075
+ * a divergent rule here would only mean the model chip and the agent chip
226076
+ * lock at different moments in the same header row.
226077
+ *
226078
+ * The name is never validated — an unknown one is passed to the CLI and
226079
+ * fails there, same as at creation.
226080
+ *
226081
+ * The whole transition runs on the session's serial event chain and writes
226082
+ * the row BEFORE touching memory, so the three places a model lives — the
226083
+ * row, `session.model`, and the process spawned from it — can never disagree:
226084
+ * a failed write ("error") leaves all three exactly as they were.
226085
+ */
226086
+ async setModel(sessionId, model) {
226087
+ const session = this.sessions.get(sessionId);
226088
+ if (!session) return "not_found";
226089
+ const normalized = model?.trim() ? model.trim() : null;
226090
+ return this.runSerialForResult(session, async () => {
226091
+ if (session.model === normalized) return "ok";
226092
+ if (this.isModelChangeTooLate(session)) return "busy";
226093
+ console.log(`[AgentSession] Setting session ${sessionId} model ${session.model ?? "default"} \u2192 ${normalized ?? "default"}`);
226094
+ const previous = session.model;
226095
+ if (!session.skipDb) {
226096
+ try {
226097
+ await this.storage.agentSessions.updateModel(sessionId, normalized);
226098
+ } catch (err) {
226099
+ console.error(`[AgentSession] Failed to persist model for ${sessionId}:`, err);
226100
+ return "error";
226101
+ }
226102
+ if (this.isModelChangeTooLate(session)) {
226103
+ try {
226104
+ await this.storage.agentSessions.updateModel(sessionId, previous);
226105
+ } catch (err) {
226106
+ console.error(`[AgentSession] Failed to roll back model for ${sessionId}:`, err);
226107
+ }
226108
+ return "busy";
226109
+ }
226110
+ }
226111
+ session.model = normalized;
226112
+ if (session.process) {
226113
+ const proc = session.process;
226114
+ session.process = null;
226115
+ this.killProcess(proc);
226116
+ this.emitProcessAlive(session, false);
226117
+ await this.finalizeStreamingEntry(session);
226118
+ session.store.currentAssistantIndex = null;
226119
+ session.buffer = "";
226120
+ this.resetCompletion(session);
226121
+ session.dormant = true;
226122
+ if (session.status !== "stopped") {
226123
+ session.status = "stopped";
226124
+ if (!session.skipDb) {
226125
+ try {
226126
+ await this.storage.agentSessions.updateStatus(sessionId, "stopped");
226127
+ } catch (err) {
226128
+ console.error(`[AgentSession] Failed to persist stopped status for ${sessionId}:`, err);
226129
+ }
226130
+ }
226131
+ this.broadcastPatch(sessionId, ConversationPatch.updateStatus("stopped"));
226132
+ this.eventBus?.emit({ type: "session:status", projectId: session.projectId, branch: session.branch, sessionId: session.id, status: "stopped" });
226133
+ }
226134
+ }
226135
+ return "ok";
226136
+ });
226137
+ }
226138
+ /**
226139
+ * True once the model can no longer reach the CLI: a turn is in flight on a
226140
+ * session that has history. Same rule switchAgentType refuses on — both are
226141
+ * respawn-shaped changes, and a divergent rule would only mean the model
226142
+ * chip and the agent chip lock at different moments in the same header row.
226143
+ */
226144
+ isModelChangeTooLate(session) {
226145
+ return session.status === "running" && session.store.entries.some(Boolean);
226146
+ }
226054
226147
  /**
226055
226148
  * Switch permission mode for a session (preserves conversation history)
226056
226149
  */
@@ -226811,6 +226904,9 @@ function runUpdatedEventFromRemoteFrame(parsed, sessionId, remoteInfo) {
226811
226904
  const run2 = mapRemoteRun(bare, remoteInfo.remoteServerId, projectId);
226812
226905
  return { type: "workflow:run-updated", projectId, branch: run2.branch, run: run2 };
226813
226906
  }
226907
+ function runUpdatedFrameForSubscribers(evt) {
226908
+ return JSON.stringify({ workflowRunUpdated: evt.run });
226909
+ }
226814
226910
 
226815
226911
  // src/routes/notification-outbox-routes.ts
226816
226912
  var import_fastify_plugin = __toESM(require_plugin2(), 1);
@@ -226871,7 +226967,8 @@ var routes = async (fastify2) => {
226871
226967
  events: [],
226872
226968
  headCursor,
226873
226969
  nextCursor: headCursor,
226874
- hasMore: false
226970
+ hasMore: false,
226971
+ sessionTitle: null
226875
226972
  });
226876
226973
  continue;
226877
226974
  }
@@ -226881,12 +226978,14 @@ var routes = async (fastify2) => {
226881
226978
  validated.limit
226882
226979
  );
226883
226980
  const nextCursor = events.length > 0 ? events[events.length - 1].seq : request.after;
226981
+ const session = events.length > 0 ? await fastify2.storage.agentSessions.getById(request.sessionId) : void 0;
226884
226982
  sessions.push({
226885
226983
  sessionId: request.sessionId,
226886
226984
  events,
226887
226985
  headCursor,
226888
226986
  nextCursor,
226889
- hasMore: nextCursor < headCursor
226987
+ hasMore: nextCursor < headCursor,
226988
+ sessionTitle: session?.title ?? null
226890
226989
  });
226891
226990
  }
226892
226991
  return reply.code(200).send({ sessions });
@@ -226904,6 +227003,7 @@ var SYNC_INTERVAL_MS = 6e4;
226904
227003
  var COMPLETION_NUDGE_DEBOUNCE_MS = 250;
226905
227004
  var MAX_CONCURRENT_SERVERS = 4;
226906
227005
  var MAX_PAGES_PER_SYNC = 50;
227006
+ var MAX_SESSION_TITLE_LENGTH = 200;
226907
227007
  function localWorkflowRunId(remoteServerId, projectId, remoteRunId) {
226908
227008
  return `remote-${remoteServerId}-${projectId}-${remoteRunId}`;
226909
227009
  }
@@ -227225,6 +227325,7 @@ var RemoteNotificationSync = class {
227225
227325
  console.warn(`[RemoteNotifications] project ${mapping.project_id} not found; skipping ${mapping.local_session_id}`);
227226
227326
  return false;
227227
227327
  }
227328
+ const sessionTitle = typeof session.sessionTitle === "string" ? session.sessionTitle.slice(0, MAX_SESSION_TITLE_LENGTH) : null;
227228
227329
  for (const event of session.events) {
227229
227330
  const notification = await this.notificationService.buildNotification(event, {
227230
227331
  id: localNotificationId(remoteServerId, event.id),
@@ -227232,7 +227333,7 @@ var RemoteNotificationSync = class {
227232
227333
  projectId: mapping.project_id,
227233
227334
  sessionId: mapping.local_session_id,
227234
227335
  workflowRunId: event.workflow_run_id ? localWorkflowRunId(remoteServerId, mapping.project_id, event.workflow_run_id) : null
227235
- });
227336
+ }, { sessionTitle });
227236
227337
  const { inserted } = await this.storage.notifications.importRemote({
227237
227338
  notification,
227238
227339
  remoteServerId,
@@ -227450,9 +227551,10 @@ function connectPersistentRemoteWs(sessionId, remoteInfo, cache2, wsOptions, rev
227450
227551
  }
227451
227552
  }
227452
227553
  } else if ("workflowRunUpdated" in parsed) {
227453
- if (eventBus) {
227454
- const evt = runUpdatedEventFromRemoteFrame(parsed, sessionId, remoteInfo);
227455
- if (evt) eventBus.emit(evt);
227554
+ const evt = runUpdatedEventFromRemoteFrame(parsed, sessionId, remoteInfo);
227555
+ if (evt) {
227556
+ eventBus?.emit(evt);
227557
+ cache2.broadcast(sessionId, runUpdatedFrameForSubscribers(evt));
227456
227558
  }
227457
227559
  } else if ("processAlive" in parsed) {
227458
227560
  cache2.broadcast(sessionId, raw);
@@ -230126,11 +230228,24 @@ ${opts.reviewFocus}` : null,
230126
230228
  function buildFeedbackMessage(feedback) {
230127
230229
  return [
230128
230230
  "[Review Feedback]",
230129
- "A reviewer agent examined your last completed work. Please address the following feedback:",
230231
+ "A reviewer agent examined your last completed work. It was in read-only mode and saw only this turn's diff plus a distilled brief of the conversation, so it may be working from wrong premises. Treat its findings as input to verify, not as conclusions.",
230232
+ "",
230233
+ "- Verify each item against the code before changing anything.",
230234
+ "- Push back when you have grounds: say what the item gets wrong and leave the code as it is. Do not change code to be agreeable.",
230235
+ "- Address blocking findings first; non-blocking notes need not be done this turn.",
230236
+ "- Do not widen the scope: no fixes the reviewer did not raise, no abstractions for hypothetical cases.",
230237
+ "- Close with a per-item account: fixed, or not fixed and why.",
230130
230238
  "",
230131
230239
  feedback
230132
230240
  ].join("\n");
230133
230241
  }
230242
+ var FINAL_VERDICT_PROMPT = [
230243
+ "[Final verdict request]",
230244
+ "\u8BF7\u628A\u8BA8\u8BBA\u540E\u7684\u6700\u7EC8 review \u610F\u89C1\u5B8C\u6574\u8F93\u51FA\u4E3A\u9762\u5411\u4F5C\u8005\u7684\u5B9A\u7A3F\u3002\u8FD9\u6BB5\u8F93\u51FA\u5C06\u539F\u6837\u53D1\u9001\u7ED9\u4F5C\u8005\u2014\u2014\u4E0D\u8981\u5305\u542B\u5BF9\u8BDD\u6027\u5185\u5BB9\uFF1A\u4E0D\u8981\u5F15\u7528\u8BA8\u8BBA\u8FC7\u7A0B\u672C\u8EAB\uFF0C\u4E0D\u8981\u5411\u6211\u63D0\u95EE\u3002",
230245
+ "- \u5438\u6536\u8BA8\u8BBA\u4E2D\u8FBE\u6210\u4E00\u81F4\u7684\u4FEE\u6B63\uFF1A\u64A4\u56DE\u7684\u6761\u76EE\u4E0D\u518D\u51FA\u73B0\uFF0C\u4FEE\u8BA2\u8FC7\u7684\u6761\u76EE\u4EE5\u4FEE\u8BA2\u540E\u7684\u5F62\u5F0F\u7ED9\u51FA\u3002",
230246
+ "- \u4FDD\u6301\u5177\u4F53\uFF1A\u6BCF\u6761\u6307\u660E\u6587\u4EF6/\u4F4D\u7F6E\u4E0E\u95EE\u9898\uFF0C\u4EE5\u53CA\u671F\u671B\u7684\u4FEE\u590D\u65B9\u5411\u3002",
230247
+ ...VERDICT_INSTRUCTIONS
230248
+ ].join("\n");
230134
230249
  var REVIEWER_AGENT_TYPES = /* @__PURE__ */ new Set(["claude-code", "codex"]);
230135
230250
  var WorkflowEngine = class {
230136
230251
  constructor(storage, agentOps) {
@@ -230452,7 +230567,7 @@ var WorkflowEngine = class {
230452
230567
  ...driftNote ? { error: driftNote } : {}
230453
230568
  },
230454
230569
  {
230455
- id: reviewReadyId(run2.id),
230570
+ id: reviewReadyId(run2.id, boundary),
230456
230571
  kind: "review_ready",
230457
230572
  project_id: run2.project_id,
230458
230573
  branch: run2.branch,
@@ -230499,12 +230614,49 @@ var WorkflowEngine = class {
230499
230614
  this.emitRunUpdated(done);
230500
230615
  return done;
230501
230616
  }
230617
+ /**
230618
+ * Discussion → verdict: CAS the run back onto the reviewer track and inject
230619
+ * the final-verdict prompt. From waiting_reviewer the existing
230620
+ * handleTaskCompleted path reopens the gate with the new turn's output.
230621
+ * Send failure rolls the claim back so the finalize button stays actionable —
230622
+ * mirror of approveFeedback's no-auto-retry contract.
230623
+ */
230624
+ async requestFinalVerdict(runId) {
230625
+ const run2 = await this.storage.workflowRuns.getById(runId);
230626
+ if (!run2 || run2.status !== "discussing" || !run2.reviewer_session_id) {
230627
+ throw new WorkflowError("bad-state", "run \u4E0D\u5728\u8BA8\u8BBA\u72B6\u6001");
230628
+ }
230629
+ const reviewerSession = await this.storage.agentSessions.getById(run2.reviewer_session_id);
230630
+ if (reviewerSession && reviewerSession.status === "running") {
230631
+ throw new WorkflowError("session-busy", "reviewer \u6B63\u5728\u56DE\u590D\u4E2D\uFF0C\u8BF7\u7B49\u5F85\u5176\u5B8C\u6210\u540E\u518D\u751F\u6210\u7EC8\u7A3F");
230632
+ }
230633
+ const claimed = await this.storage.workflowRuns.transition(runId, "discussing", "waiting_reviewer", { error: null });
230634
+ if (!claimed) throw new WorkflowError("bad-state", "run \u72B6\u6001\u5DF2\u53D8\u5316\uFF08\u53EF\u80FD\u5DF2\u88AB\u5904\u7406\uFF09");
230635
+ const project = await this.storage.projects.getById(run2.project_id);
230636
+ const sent = await this.agentOps.sendUserMessage(run2.reviewer_session_id, FINAL_VERDICT_PROMPT, project?.path ?? void 0, void 0, REVIEWER_TURN).catch(() => false);
230637
+ if (!sent) {
230638
+ const rolledBack = await this.storage.workflowRuns.transition(runId, "waiting_reviewer", "discussing", {
230639
+ error: "\u53D1\u9001\u5931\u8D25\uFF1Areviewer session \u53EF\u80FD\u672A\u8FD0\u884C\u3002\u8BF7\u5728\u5176\u7A97\u53E3\u4E2D\u5524\u9192\u540E\u91CD\u8BD5\uFF0C\u6216\u7ED3\u675F\u672C\u6B21 review\u3002"
230640
+ });
230641
+ if (!rolledBack) {
230642
+ console.warn(
230643
+ `requestFinalVerdict: rollback CAS lost for run ${runId} \u2014 run moved concurrently (e.g. cancelled) while the send was in flight; rollback skipped`
230644
+ );
230645
+ }
230646
+ const rolled = await this.storage.workflowRuns.getById(runId);
230647
+ if (rolled) this.emitRunUpdated(rolled);
230648
+ throw new WorkflowError("send-failed", "\u5411 reviewer \u53D1\u9001\u7EC8\u7A3F\u8BF7\u6C42\u5931\u8D25");
230649
+ }
230650
+ const updated = await this.storage.workflowRuns.getById(runId);
230651
+ this.emitRunUpdated(updated);
230652
+ return updated;
230653
+ }
230502
230654
  async cancelRun(runId, reason) {
230503
230655
  const run2 = await this.storage.workflowRuns.getById(runId);
230504
230656
  if (!run2) return void 0;
230505
230657
  if (TERMINAL_STATUSES.has(run2.status)) return run2;
230506
230658
  const patch = reason ? { error: reason } : void 0;
230507
- const cancelled = await this.storage.workflowRuns.transition(runId, "waiting_reviewer", "cancelled", patch) || await this.storage.workflowRuns.transition(runId, "waiting_feedback", "cancelled", patch);
230659
+ const cancelled = await this.storage.workflowRuns.transition(runId, "waiting_reviewer", "cancelled", patch) || await this.storage.workflowRuns.transition(runId, "waiting_feedback", "cancelled", patch) || await this.storage.workflowRuns.transition(runId, "discussing", "cancelled", patch);
230508
230660
  if (!cancelled) {
230509
230661
  const current = await this.storage.workflowRuns.getById(runId);
230510
230662
  if (current?.status === "sending_feedback") {
@@ -230522,6 +230674,10 @@ var WorkflowEngine = class {
230522
230674
  /**
230523
230675
  * Human takeover (spec §3.4): user sent a message directly to a run session.
230524
230676
  *
230677
+ * Reviewer 分流:向 reviewer 发消息不再是接管——它开启一轮讨论,把 run
230678
+ * 移入 `discussing`(gate 收起),等待显式的 requestFinalVerdict 重新出稿。
230679
+ * 只有向 source session 发消息才算接管,结束 run。
230680
+ *
230525
230681
  * Never-throws contract: this is called inline from the agent-session
230526
230682
  * `/message` route BEFORE the user's message is delivered
230527
230683
  * (agentOps.sendUserMessage). A throw here would abort delivery of that
@@ -230536,8 +230692,23 @@ var WorkflowEngine = class {
230536
230692
  async handleExternalUserMessage(sessionId) {
230537
230693
  const p2 = this.participants.get(sessionId);
230538
230694
  if (!p2) return;
230695
+ if (p2.role === "reviewer") {
230696
+ try {
230697
+ const moved = await this.storage.workflowRuns.transition(p2.runId, "waiting_feedback", "discussing", { error: null }) || await this.storage.workflowRuns.transition(p2.runId, "waiting_reviewer", "discussing", { error: null });
230698
+ if (moved) {
230699
+ const updated = await this.storage.workflowRuns.getById(p2.runId);
230700
+ if (updated) this.emitRunUpdated(updated);
230701
+ }
230702
+ } catch (err) {
230703
+ console.error(
230704
+ `[WorkflowEngine] handleExternalUserMessage: failed moving run ${p2.runId} to discussing; swallowed to honor never-throws contract`,
230705
+ err
230706
+ );
230707
+ }
230708
+ return;
230709
+ }
230539
230710
  try {
230540
- await this.cancelRun(p2.runId, "\u7528\u6237\u63A5\u7BA1\uFF1A\u76F4\u63A5\u5411 run \u5185\u7684 session \u53D1\u9001\u4E86\u6D88\u606F\uFF0Creview \u5DF2\u7ED3\u675F\u3002");
230711
+ await this.cancelRun(p2.runId, "\u7528\u6237\u63A5\u7BA1\uFF1A\u76F4\u63A5\u5411 source session \u53D1\u9001\u4E86\u6D88\u606F\uFF0Creview \u5DF2\u7ED3\u675F\u3002");
230541
230712
  } catch (err) {
230542
230713
  if (err instanceof WorkflowError && err.code === "bad-state") {
230543
230714
  console.warn(
@@ -232422,8 +232593,12 @@ var NotificationService = class {
232422
232593
  * Assemble the persisted row. `ids` is separate from the event because remote
232423
232594
  * imports substitute front-local identities (see RemoteNotificationSync) while
232424
232595
  * reusing this exact copy generation.
232596
+ *
232597
+ * `opts.sessionTitle` covers the remote-import case: the front has a mapping
232598
+ * but no local session row, so the worker's query-time title is the only way
232599
+ * to label the notification with the session's name.
232425
232600
  */
232426
- async buildNotification(event, ids) {
232601
+ async buildNotification(event, ids, opts) {
232427
232602
  const session = ids.sessionId ? await this.storage.agentSessions.getById(ids.sessionId) : void 0;
232428
232603
  const project = await this.storage.projects.getById(ids.projectId);
232429
232604
  return {
@@ -232436,7 +232611,7 @@ var NotificationService = class {
232436
232611
  workflow_run_id: ids.workflowRunId,
232437
232612
  title: notificationTitle(event.kind),
232438
232613
  body: notificationBody({
232439
- sessionTitle: session?.title,
232614
+ sessionTitle: session?.title ?? opts?.sessionTitle,
232440
232615
  branch: event.branch,
232441
232616
  projectName: project?.name
232442
232617
  }),
@@ -236551,6 +236726,54 @@ var routes12 = async (fastify2) => {
236551
236726
  return reply.code(200).send({ success: true, agentType });
236552
236727
  }
236553
236728
  );
236729
+ fastify2.post(
236730
+ "/api/agent-sessions/:sessionId/model",
236731
+ async (req, reply) => {
236732
+ const body = req.body || {};
236733
+ if (body.model === void 0) {
236734
+ return reply.code(400).send({ error: "model is required (null for the CLI default)" });
236735
+ }
236736
+ const { model } = body;
236737
+ if (model !== null && typeof model !== "string") {
236738
+ return reply.code(400).send({ error: "model must be a string or null" });
236739
+ }
236740
+ const userId = requireAuth(req, reply);
236741
+ if (userId === null) return;
236742
+ if (req.params.sessionId.startsWith("remote-")) {
236743
+ const remoteInfo = await getAuthorizedRemoteSessionInfo(req.params.sessionId, userId);
236744
+ if (!remoteInfo) {
236745
+ return reply.code(404).send({ error: "Remote session not found" });
236746
+ }
236747
+ const result = await proxyAuto(
236748
+ remoteInfo.remoteServerId,
236749
+ remoteInfo.remoteUrl,
236750
+ remoteInfo.remoteApiKey,
236751
+ "POST",
236752
+ `/api/agent-sessions/${remoteInfo.remoteSessionId}/model`,
236753
+ { model }
236754
+ );
236755
+ return reply.code(proxyStatus(result)).send(result.data);
236756
+ }
236757
+ const row = await fastify2.storage.agentSessions.getById(req.params.sessionId);
236758
+ if (!row || !await fastify2.storage.projects.getById(row.project_id, userId)) {
236759
+ return reply.code(404).send({ error: "Session not found" });
236760
+ }
236761
+ const outcome = await fastify2.agentSessionManager.setModel(req.params.sessionId, model);
236762
+ if (outcome === "not_found") {
236763
+ return reply.code(404).send({ error: "Session not found" });
236764
+ }
236765
+ if (outcome === "busy") {
236766
+ return reply.code(409).send({ error: "Agent is currently running \u2014 stop it before changing the model" });
236767
+ }
236768
+ if (outcome === "error") {
236769
+ return reply.code(500).send({ error: "Couldn't save the model \u2014 the session kept its current one" });
236770
+ }
236771
+ return reply.code(200).send({
236772
+ success: true,
236773
+ model: fastify2.agentSessionManager.getSession(req.params.sessionId)?.model ?? null
236774
+ });
236775
+ }
236776
+ );
236554
236777
  fastify2.post(
236555
236778
  "/api/agent-sessions/:sessionId/branch",
236556
236779
  async (req, reply) => {
@@ -238358,7 +238581,11 @@ async function routes19(fastify2) {
238358
238581
  const run2 = await fastify2.workflowEngine.cancelRun(req.params.id);
238359
238582
  return reply.send({ run: run2 });
238360
238583
  }
238361
- return reply.code(400).send({ error: "action must be approve or cancel" });
238584
+ if (action === "finalize") {
238585
+ const run2 = await fastify2.workflowEngine.requestFinalVerdict(req.params.id);
238586
+ return reply.send({ run: run2 });
238587
+ }
238588
+ return reply.code(400).send({ error: "action must be approve, cancel or finalize" });
238362
238589
  } catch (err) {
238363
238590
  const status = errStatus(err);
238364
238591
  if (status) return reply.code(status).send({ error: err.message });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vibedeckx/darwin-arm64",
3
- "version": "0.2.18",
3
+ "version": "0.2.19",
4
4
  "description": "Vibedeckx platform binaries for macOS ARM64",
5
5
  "os": [
6
6
  "darwin"