openfox 2.0.65 → 2.0.66

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 (59) hide show
  1. package/README.md +1 -0
  2. package/dist/agent-defaults/builder.agent.md +1 -1
  3. package/dist/agent-defaults/code-reviewer.agent.md +0 -1
  4. package/dist/agent-defaults/explorer.agent.md +0 -1
  5. package/dist/agent-defaults/planner.agent.md +1 -1
  6. package/dist/{branch.api-LAN42BA5.js → branch.api-3YJSWOZG.js} +5 -1
  7. package/dist/{chat-handler-MC3XZ3OV.js → chat-handler-ZRDNSLOG.js} +14 -12
  8. package/dist/{chunk-UEIQKG5P.js → chunk-3ACDQKK6.js} +290 -326
  9. package/dist/{chunk-RYIREJAW.js → chunk-5EO6SEGV.js} +2 -2
  10. package/dist/{chunk-OESYKZCM.js → chunk-5V5DM5E4.js} +3 -3
  11. package/dist/{chunk-QBYQ7KDX.js → chunk-B7WGOK7G.js} +16 -15
  12. package/dist/{chunk-Z6W4YHJB.js → chunk-BL5LOLVA.js} +17 -1
  13. package/dist/{chunk-TMUBLQFC.js → chunk-C3VLGVSQ.js} +3 -3
  14. package/dist/{chunk-ZPIZLTWU.js → chunk-GMXKJGJ2.js} +5 -1
  15. package/dist/{chunk-YQ3SOPBI.js → chunk-KXVFHMSM.js} +2 -2
  16. package/dist/chunk-OBK3I4KD.js +137 -0
  17. package/dist/{chunk-Z6H7SFQR.js → chunk-OE5B44P6.js} +258 -65
  18. package/dist/{chunk-PXJ4NOP4.js → chunk-PVRSNXD4.js} +2 -2
  19. package/dist/{chunk-X5YCWKNS.js → chunk-R4UTFE63.js} +53 -83
  20. package/dist/{chunk-4UYKN6JU.js → chunk-R7EED6ZU.js} +3 -3
  21. package/dist/{chunk-AIJE3RYH.js → chunk-TFDK6VSG.js} +33 -7
  22. package/dist/{chunk-QJ5FH5DP.js → chunk-TMHWQYWE.js} +4 -4
  23. package/dist/{chunk-VWPY2KWH.js → chunk-UBIHP5Z7.js} +8 -8
  24. package/dist/chunk-WGMJCFCE.js +14 -0
  25. package/dist/{chunk-LBGHZLLH.js → chunk-WNA5VPZG.js} +2 -2
  26. package/dist/{chunk-N4K3PNOS.js → chunk-ZUM2ZJOX.js} +46 -18
  27. package/dist/cli/dev.js +1 -1
  28. package/dist/cli/index.js +1 -1
  29. package/dist/{client-LAKW7TA5.js → client-BUX62J2K.js} +3 -3
  30. package/dist/{client-pure-DO3S675T.js → client-pure-U6ZYUPJQ.js} +6 -4
  31. package/dist/{compactor-I3N56PSJ.js → compactor-V43WJ3WX.js} +7 -7
  32. package/dist/{events-52XADT6Y.js → events-CDQ4HASP.js} +4 -4
  33. package/dist/{folding-2BGFLV5J.js → folding-V2K34EGN.js} +2 -2
  34. package/dist/{inspect-proxy-BV25JERQ.js → inspect-proxy-PKMDR47R.js} +4 -4
  35. package/dist/{orchestrator-IYJRQQKB.js → orchestrator-LZQTDOWM.js} +13 -11
  36. package/dist/package.json +1 -1
  37. package/dist/{processor-LUXKVIED.js → processor-7KAXESY5.js} +14 -12
  38. package/dist/{project-creator-IDW7RACH.js → project-creator-EMGRSPYS.js} +18 -5
  39. package/dist/{projects-BY227WT2.js → projects-7HSBZY2D.js} +3 -3
  40. package/dist/{protocol-Cq66hdDX.d.ts → protocol-42f_Png6.d.ts} +1 -1
  41. package/dist/provider/index.d.ts +4 -4
  42. package/dist/{provider-GYOW4OWQ.js → provider-BDH6JGZB.js} +4 -4
  43. package/dist/{provider-manager-HRHNF73A.js → provider-manager-D3KIOD5E.js} +4 -4
  44. package/dist/{serve-ZRTWVOL2.js → serve-HGHFN3D2.js} +18 -16
  45. package/dist/server/index.d.ts +26 -8
  46. package/dist/server/index.js +17 -15
  47. package/dist/{server-PXXGMFBT.js → server-W42ENYFX.js} +15 -13
  48. package/dist/{settings-JA4XUR3W.js → settings-ZZ6AKFPD.js} +3 -3
  49. package/dist/shared/index.d.ts +3 -3
  50. package/dist/{tools-ZZM36DAZ.js → tools-2EB7C6H2.js} +12 -10
  51. package/dist/{types-CDZakn7f.d.ts → types-apiMd7Df.d.ts} +1 -1
  52. package/dist/{types-akHmgvBk.d.ts → types-vezAEt_y.d.ts} +3 -1
  53. package/dist/web/assets/{index-Dc05znz4.css → index-B0Q5uK2h.css} +1 -1
  54. package/dist/web/assets/index-BhQN93bI.js +303 -0
  55. package/dist/web/index.html +2 -2
  56. package/dist/web/sw.js +1 -1
  57. package/dist/worktree-EIF75WGF.js +26 -0
  58. package/package.json +1 -1
  59. package/dist/web/assets/index-Bsi_le80.js +0 -303
@@ -21,7 +21,7 @@ import {
21
21
  tokenFromPassword,
22
22
  verifyPassword,
23
23
  workflowExists
24
- } from "./chunk-N4K3PNOS.js";
24
+ } from "./chunk-ZUM2ZJOX.js";
25
25
  import {
26
26
  agentExists,
27
27
  createToolRegistry,
@@ -66,12 +66,12 @@ import {
66
66
  setSkillEnabled,
67
67
  skillExists,
68
68
  updateOwnedSkill
69
- } from "./chunk-UEIQKG5P.js";
69
+ } from "./chunk-3ACDQKK6.js";
70
70
  import {
71
71
  ALWAYS_ALLOWED,
72
72
  ALWAYS_ALLOWED_FOR_SUBAGENTS,
73
73
  TOP_LEVEL_ONLY_TOOLS
74
- } from "./chunk-X5YCWKNS.js";
74
+ } from "./chunk-R4UTFE63.js";
75
75
  import {
76
76
  getPathSeparator,
77
77
  isAbsolutePath
@@ -79,6 +79,9 @@ import {
79
79
  import {
80
80
  createMcpTools
81
81
  } from "./chunk-NWO6GRYE.js";
82
+ import {
83
+ ensureWorktree
84
+ } from "./chunk-OBK3I4KD.js";
82
85
  import {
83
86
  createSession,
84
87
  deleteSession,
@@ -104,8 +107,9 @@ import {
104
107
  updateSessionDangerLevel,
105
108
  updateSessionMetadata,
106
109
  updateSessionProvider,
107
- updateSessionRunning
108
- } from "./chunk-AIJE3RYH.js";
110
+ updateSessionRunning,
111
+ updateSessionWorkdir
112
+ } from "./chunk-TFDK6VSG.js";
109
113
  import {
110
114
  createContextStateMessage
111
115
  } from "./chunk-F4PMNP7S.js";
@@ -113,22 +117,22 @@ import {
113
117
  deleteSetting,
114
118
  getSetting,
115
119
  setSetting
116
- } from "./chunk-PXJ4NOP4.js";
120
+ } from "./chunk-PVRSNXD4.js";
117
121
  import {
118
122
  EventEmitter
119
123
  } from "./chunk-EU3WWTFH.js";
120
124
  import {
121
125
  getProject
122
- } from "./chunk-YQ3SOPBI.js";
126
+ } from "./chunk-KXVFHMSM.js";
123
127
  import {
124
128
  initDatabase
125
- } from "./chunk-ZPIZLTWU.js";
129
+ } from "./chunk-GMXKJGJ2.js";
126
130
  import {
127
131
  createProviderManager,
128
132
  detectModel,
129
133
  getLlmStatus,
130
134
  parseDefaultModelSelection
131
- } from "./chunk-RYIREJAW.js";
135
+ } from "./chunk-5EO6SEGV.js";
132
136
  import {
133
137
  getModelProfile
134
138
  } from "./chunk-V4IE7HJY.js";
@@ -2542,7 +2546,7 @@ var SessionManager = class {
2542
2546
  * Create a new session. Emits session.initialized event.
2543
2547
  * Note: maxTokens is no longer stored in the session - it comes from the current model config
2544
2548
  */
2545
- createSession(projectId, title, providerId, providerModel) {
2549
+ createSession(projectId, title, providerId, providerModel, worktree) {
2546
2550
  const project = getProject(projectId);
2547
2551
  if (!project) {
2548
2552
  throw new Error(`Project not found: ${projectId}`);
@@ -2552,10 +2556,11 @@ var SessionManager = class {
2552
2556
  const existingSessions = listSessionsByProject(projectId, 1e3, 0);
2553
2557
  sessionTitle = `Session ${existingSessions.sessions.length + 1}`;
2554
2558
  }
2555
- logger.debug("Creating session", { projectId, workdir: project.workdir, title: sessionTitle });
2556
- const dbSession = createSession(projectId, project.workdir, sessionTitle, providerId, providerModel);
2559
+ const effectiveWorkdir = worktree ?? project.workdir;
2560
+ logger.debug("Creating session", { projectId, workdir: effectiveWorkdir, title: sessionTitle });
2561
+ const dbSession = createSession(projectId, effectiveWorkdir, sessionTitle, providerId, providerModel, worktree);
2557
2562
  const contextWindowId = crypto.randomUUID();
2558
- emitSessionInitialized(dbSession.id, projectId, project.workdir, contextWindowId, sessionTitle);
2563
+ emitSessionInitialized(dbSession.id, projectId, effectiveWorkdir, contextWindowId, sessionTitle);
2559
2564
  const session = this.buildSessionFromDb(dbSession);
2560
2565
  this.emit({ type: "session_created", session });
2561
2566
  return session;
@@ -2750,6 +2755,7 @@ var SessionManager = class {
2750
2755
  if (message.attachments !== void 0) options.attachments = message.attachments;
2751
2756
  if (message.subAgentId !== void 0) options.subAgentId = message.subAgentId;
2752
2757
  if (message.subAgentType !== void 0) options.subAgentType = message.subAgentType;
2758
+ if (message.metadata !== void 0) options.metadata = message.metadata;
2753
2759
  const messageId = emitUserMessage(sessionId, message.content, options);
2754
2760
  const result = {
2755
2761
  id: messageId,
@@ -2763,6 +2769,7 @@ var SessionManager = class {
2763
2769
  if (message.attachments !== void 0) result.attachments = message.attachments;
2764
2770
  if (message.subAgentId !== void 0) result.subAgentId = message.subAgentId;
2765
2771
  if (message.subAgentType !== void 0) result.subAgentType = message.subAgentType;
2772
+ if (message.metadata !== void 0) result.metadata = message.metadata;
2766
2773
  this.emit({ type: "message_added", sessionId, message: result });
2767
2774
  return result;
2768
2775
  }
@@ -2902,12 +2909,6 @@ var SessionManager = class {
2902
2909
  // ============================================================================
2903
2910
  // Execution State (runtime tracking, not persisted to events)
2904
2911
  // ============================================================================
2905
- /**
2906
- * Record that a file was modified.
2907
- */
2908
- addModifiedFile(sessionId, filePath) {
2909
- logger.debug("addModifiedFile called", { sessionId, filePath });
2910
- }
2911
2912
  /**
2912
2913
  * Add a criterion. Returns the updated criteria list.
2913
2914
  */
@@ -3157,10 +3158,113 @@ var SessionManager = class {
3157
3158
  // ============================================================================
3158
3159
  /**
3159
3160
  * Get the LSP manager for a session.
3161
+ * Uses worktree path when active, otherwise the project workdir.
3160
3162
  */
3161
3163
  getLspManager(sessionId) {
3162
3164
  const session = this.requireSession(sessionId);
3163
- return getLspManager(sessionId, session.workdir);
3165
+ const effectiveWorkdir = session.worktree ?? session.workdir;
3166
+ return getLspManager(sessionId, effectiveWorkdir);
3167
+ }
3168
+ // ============================================================================
3169
+ // Worktree Lifecycle
3170
+ // ============================================================================
3171
+ /**
3172
+ * Create a git worktree for an existing session and move the session into it.
3173
+ * Keeps session.workdir as the project root (stable system prompt).
3174
+ * Sets session.worktree to the worktree path for tool execution.
3175
+ * Restarts LSP to pick up the new workdir.
3176
+ * Injects a system reminder to inform the agent about the worktree.
3177
+ */
3178
+ async createSessionWorktree(sessionId, name) {
3179
+ const session = this.requireSession(sessionId);
3180
+ const project = getProject(session.projectId);
3181
+ if (!project) throw new Error(`Project not found: ${session.projectId}`);
3182
+ if (session.worktree) throw new Error("Session already has a worktree");
3183
+ const result = await ensureWorktree(project.workdir, name);
3184
+ updateSessionWorkdir(sessionId, project.workdir, result.path);
3185
+ try {
3186
+ await shutdownLspManager(sessionId);
3187
+ } catch (err) {
3188
+ logger.error("Error shutting down LSP for worktree switch", { sessionId, error: err });
3189
+ }
3190
+ const reminderContent = `<system-reminder>
3191
+ This session is now operating in a git worktree at ${result.path}.
3192
+ All file and git operations should use this directory.
3193
+ </system-reminder>`;
3194
+ this.addMessage(sessionId, {
3195
+ role: "user",
3196
+ content: reminderContent,
3197
+ isSystemGenerated: true,
3198
+ messageKind: "auto-prompt",
3199
+ metadata: { type: "worktree", name: "Worktree", color: "#22c55e", kind: "definition", branchName: name }
3200
+ });
3201
+ const updated = this.requireSession(sessionId);
3202
+ this.emit({ type: "session_updated", session: updated });
3203
+ return updated;
3204
+ }
3205
+ /**
3206
+ * Attach session to an existing worktree by path.
3207
+ * Sets session.worktree to the given path without creating a new worktree.
3208
+ * Restarts LSP to pick up the new workdir.
3209
+ */
3210
+ async attachSessionWorktree(sessionId, wtPath) {
3211
+ const session = this.requireSession(sessionId);
3212
+ if (session.worktree) throw new Error("Session already has a worktree");
3213
+ updateSessionWorkdir(sessionId, session.workdir, wtPath);
3214
+ try {
3215
+ await shutdownLspManager(sessionId);
3216
+ } catch (err) {
3217
+ logger.error("Error shutting down LSP for worktree attach", { sessionId, error: err });
3218
+ }
3219
+ const branchName = wtPath.includes("/worktrees/") ? wtPath.split("/worktrees/")[1] ?? wtPath : wtPath;
3220
+ const reminderContent = `<system-reminder>
3221
+ This session is now operating in a git worktree at ${wtPath}.
3222
+ All file and git operations should use this directory.
3223
+ </system-reminder>`;
3224
+ this.addMessage(sessionId, {
3225
+ role: "user",
3226
+ content: reminderContent,
3227
+ isSystemGenerated: true,
3228
+ messageKind: "auto-prompt",
3229
+ metadata: { type: "worktree", name: "Worktree", color: "#22c55e", kind: "definition", branchName }
3230
+ });
3231
+ const updated = this.requireSession(sessionId);
3232
+ this.emit({ type: "session_updated", session: updated });
3233
+ return updated;
3234
+ }
3235
+ /**
3236
+ * Close the worktree for a session and move it back to the project root.
3237
+ * Clears session.worktree — session.workdir stays as project root.
3238
+ * Restarts LSP to pick up the original workdir.
3239
+ * Injects a system reminder to inform the agent the worktree is closed.
3240
+ */
3241
+ async closeSessionWorktree(sessionId) {
3242
+ const session = this.requireSession(sessionId);
3243
+ if (!session.worktree) throw new Error("Session does not have a worktree");
3244
+ const project = getProject(session.projectId);
3245
+ if (!project) throw new Error(`Project not found: ${session.projectId}`);
3246
+ const closedPath = session.worktree;
3247
+ const branchName = closedPath.includes("/worktrees/") ? closedPath.split("/worktrees/")[1] ?? closedPath : closedPath;
3248
+ updateSessionWorkdir(sessionId, project.workdir, null);
3249
+ try {
3250
+ await shutdownLspManager(sessionId);
3251
+ } catch (err) {
3252
+ logger.error("Error shutting down LSP for worktree close", { sessionId, error: err });
3253
+ }
3254
+ const reminderContent = `<system-reminder>
3255
+ The worktree at ${closedPath} has been closed.
3256
+ Operating in the original project directory at ${project.workdir}.
3257
+ </system-reminder>`;
3258
+ this.addMessage(sessionId, {
3259
+ role: "user",
3260
+ content: reminderContent,
3261
+ isSystemGenerated: true,
3262
+ messageKind: "auto-prompt",
3263
+ metadata: { type: "worktree", name: "Worktree", color: "#ef4444", kind: "reminder", branchName }
3264
+ });
3265
+ const updated = this.requireSession(sessionId);
3266
+ this.emit({ type: "session_updated", session: updated });
3267
+ return updated;
3164
3268
  }
3165
3269
  // ============================================================================
3166
3270
  // Active Session
@@ -3243,8 +3347,18 @@ var SessionManager = class {
3243
3347
  contextWindows: [],
3244
3348
  // Derived from events, not stored separately
3245
3349
  executionState: eventState.cachedSystemPrompt || cachedPrompt ? {
3246
- cachedSystemPrompt: cachedPrompt?.systemPrompt ?? eventState.cachedSystemPrompt,
3247
- dynamicContextHash: cachedPrompt?.hash ?? eventState.dynamicContextHash
3350
+ iteration: 0,
3351
+ readFiles: {},
3352
+ consecutiveFailures: 0,
3353
+ currentTokenCount: 0,
3354
+ messageCountAtLastUpdate: messages.length,
3355
+ compactionCount: 0,
3356
+ startedAt: (/* @__PURE__ */ new Date()).toISOString(),
3357
+ lastActivityAt: (/* @__PURE__ */ new Date()).toISOString(),
3358
+ ...cachedPrompt?.systemPrompt ? { cachedSystemPrompt: cachedPrompt.systemPrompt } : {},
3359
+ ...eventState.cachedSystemPrompt && !cachedPrompt?.systemPrompt ? { cachedSystemPrompt: eventState.cachedSystemPrompt } : {},
3360
+ ...cachedPrompt?.hash ? { dynamicContextHash: cachedPrompt.hash } : {},
3361
+ ...eventState.dynamicContextHash && !cachedPrompt?.hash ? { dynamicContextHash: eventState.dynamicContextHash } : {}
3248
3362
  } : null
3249
3363
  };
3250
3364
  }
@@ -4076,7 +4190,7 @@ import { Router as Router8 } from "express";
4076
4190
  import { spawn as spawn2 } from "child_process";
4077
4191
 
4078
4192
  // src/constants.ts
4079
- var VERSION = "2.0.65";
4193
+ var VERSION = "2.0.66";
4080
4194
 
4081
4195
  // src/server/routes/auto-update.ts
4082
4196
  var updateInProgress = false;
@@ -4516,7 +4630,7 @@ async function createServerHandle(config3) {
4516
4630
  setMcpTools(mcpTools);
4517
4631
  logger.info("MCP tools registered", { count: mcpTools.length });
4518
4632
  }
4519
- const { signalMcpReady } = await import("./server-PXXGMFBT.js");
4633
+ const { signalMcpReady } = await import("./server-W42ENYFX.js");
4520
4634
  signalMcpReady();
4521
4635
  });
4522
4636
  const app = express();
@@ -4578,7 +4692,7 @@ async function createServerHandle(config3) {
4578
4692
  res.json({ tools });
4579
4693
  });
4580
4694
  app.get("/api/projects", async (_req, res) => {
4581
- const { listProjects } = await import("./projects-BY227WT2.js");
4695
+ const { listProjects } = await import("./projects-7HSBZY2D.js");
4582
4696
  const projects = listProjects();
4583
4697
  res.json({ projects });
4584
4698
  });
@@ -4587,7 +4701,7 @@ async function createServerHandle(config3) {
4587
4701
  if (!name || !workdir) {
4588
4702
  return res.status(400).json({ error: "name and workdir are required" });
4589
4703
  }
4590
- const { createDirectoryWithGit } = await import("./project-creator-IDW7RACH.js");
4704
+ const { createDirectoryWithGit } = await import("./project-creator-EMGRSPYS.js");
4591
4705
  try {
4592
4706
  const project = await createDirectoryWithGit(name, workdir);
4593
4707
  res.status(201).json({ project });
@@ -4632,7 +4746,7 @@ async function createServerHandle(config3) {
4632
4746
  }
4633
4747
  });
4634
4748
  app.get("/api/projects/:id", async (req, res) => {
4635
- const { getProject: getProject2 } = await import("./projects-BY227WT2.js");
4749
+ const { getProject: getProject2 } = await import("./projects-7HSBZY2D.js");
4636
4750
  const project = getProject2(req.params.id);
4637
4751
  if (!project) {
4638
4752
  return res.status(404).json({ error: "Project not found" });
@@ -4640,7 +4754,7 @@ async function createServerHandle(config3) {
4640
4754
  res.json({ project });
4641
4755
  });
4642
4756
  app.put("/api/projects/:id", async (req, res) => {
4643
- const { updateProject } = await import("./projects-BY227WT2.js");
4757
+ const { updateProject } = await import("./projects-7HSBZY2D.js");
4644
4758
  const { name, customInstructions, dangerLevel } = req.body;
4645
4759
  const updates = {};
4646
4760
  if (name !== void 0) updates.name = name;
@@ -4653,7 +4767,7 @@ async function createServerHandle(config3) {
4653
4767
  res.json({ project: updated });
4654
4768
  });
4655
4769
  app.delete("/api/projects/:id", async (req, res) => {
4656
- const { getProject: getProject2, deleteProject } = await import("./projects-BY227WT2.js");
4770
+ const { getProject: getProject2, deleteProject } = await import("./projects-7HSBZY2D.js");
4657
4771
  const project = getProject2(req.params.id);
4658
4772
  if (!project) {
4659
4773
  return res.status(404).json({ error: "Project not found" });
@@ -4662,7 +4776,7 @@ async function createServerHandle(config3) {
4662
4776
  res.json({ success: true });
4663
4777
  });
4664
4778
  app.put("/api/projects/:id/star", async (req, res) => {
4665
- const { toggleStar } = await import("./projects-BY227WT2.js");
4779
+ const { toggleStar } = await import("./projects-7HSBZY2D.js");
4666
4780
  const { isStarred } = req.body;
4667
4781
  if (typeof isStarred !== "boolean") {
4668
4782
  return res.status(400).json({ error: "isStarred is required and must be a boolean" });
@@ -4673,8 +4787,53 @@ async function createServerHandle(config3) {
4673
4787
  }
4674
4788
  res.json({ project });
4675
4789
  });
4790
+ app.get("/api/projects/:id/branches", async (req, res) => {
4791
+ const { getProject: getProject2 } = await import("./projects-7HSBZY2D.js");
4792
+ const project = getProject2(req.params.id);
4793
+ if (!project) return res.status(404).json({ error: "Project not found" });
4794
+ const { listBranches } = await import("./worktree-EIF75WGF.js");
4795
+ const branches = await listBranches(project.workdir);
4796
+ res.json({ branches });
4797
+ });
4798
+ app.post("/api/projects/:id/checkout", async (req, res) => {
4799
+ const { getProject: getProject2 } = await import("./projects-7HSBZY2D.js");
4800
+ const project = getProject2(req.params.id);
4801
+ if (!project) return res.status(404).json({ error: "Project not found" });
4802
+ const { branch } = req.body;
4803
+ if (!branch || typeof branch !== "string") return res.status(400).json({ error: "branch is required" });
4804
+ const { checkoutBranch } = await import("./worktree-EIF75WGF.js");
4805
+ try {
4806
+ await checkoutBranch(project.workdir, branch);
4807
+ res.json({ branch });
4808
+ } catch (err) {
4809
+ res.status(400).json({ error: err instanceof Error ? err.message : "Failed to checkout branch" });
4810
+ }
4811
+ });
4812
+ app.post("/api/projects/:id/checkout-new", async (req, res) => {
4813
+ const { getProject: getProject2 } = await import("./projects-7HSBZY2D.js");
4814
+ const project = getProject2(req.params.id);
4815
+ if (!project) return res.status(404).json({ error: "Project not found" });
4816
+ const { name } = req.body;
4817
+ if (!name || typeof name !== "string") return res.status(400).json({ error: "name is required" });
4818
+ const { createBranch } = await import("./worktree-EIF75WGF.js");
4819
+ try {
4820
+ await createBranch(project.workdir, name);
4821
+ res.json({ branch: name });
4822
+ } catch (err) {
4823
+ res.status(400).json({ error: err instanceof Error ? err.message : "Failed to create branch" });
4824
+ }
4825
+ });
4826
+ app.get("/api/projects/:id/worktrees", async (req, res) => {
4827
+ const { getProject: getProject2 } = await import("./projects-7HSBZY2D.js");
4828
+ const project = getProject2(req.params.id);
4829
+ if (!project) return res.status(404).json({ error: "Project not found" });
4830
+ const { listWorktrees } = await import("./worktree-EIF75WGF.js");
4831
+ const all = await listWorktrees(project.workdir);
4832
+ const worktrees = all.filter((wt) => wt.path !== project.workdir);
4833
+ res.json({ worktrees });
4834
+ });
4676
4835
  app.get("/api/sessions", async (req, res) => {
4677
- const { getRecentUserPromptsForSession } = await import("./events-52XADT6Y.js");
4836
+ const { getRecentUserPromptsForSession } = await import("./events-CDQ4HASP.js");
4678
4837
  const projectId = req.query["projectId"];
4679
4838
  const limit = Math.min(parseInt(req.query["limit"]) || 20, 100);
4680
4839
  const offset = parseInt(req.query["offset"]) || 0;
@@ -4706,10 +4865,44 @@ async function createServerHandle(config3) {
4706
4865
  const session = sessionManager.createSession(projectId, title, providerId ?? null, model ?? null);
4707
4866
  res.status(201).json({ session });
4708
4867
  });
4868
+ app.post("/api/sessions/:id/worktree", async (req, res) => {
4869
+ const session = sessionManager.getSession(req.params.id);
4870
+ if (!session) return res.status(404).json({ error: "Session not found" });
4871
+ const { name } = req.body;
4872
+ if (!name || typeof name !== "string") return res.status(400).json({ error: "name is required" });
4873
+ try {
4874
+ const updated = await sessionManager.createSessionWorktree(req.params.id, name);
4875
+ res.json({ session: updated });
4876
+ } catch (err) {
4877
+ res.status(400).json({ error: err instanceof Error ? err.message : "Failed to create worktree" });
4878
+ }
4879
+ });
4880
+ app.post("/api/sessions/:id/close-worktree", async (req, res) => {
4881
+ const session = sessionManager.getSession(req.params.id);
4882
+ if (!session) return res.status(404).json({ error: "Session not found" });
4883
+ try {
4884
+ const updated = await sessionManager.closeSessionWorktree(req.params.id);
4885
+ res.json({ session: updated });
4886
+ } catch (err) {
4887
+ res.status(400).json({ error: err instanceof Error ? err.message : "Failed to close worktree" });
4888
+ }
4889
+ });
4890
+ app.post("/api/sessions/:id/attach-worktree", async (req, res) => {
4891
+ const session = sessionManager.getSession(req.params.id);
4892
+ if (!session) return res.status(404).json({ error: "Session not found" });
4893
+ const { path } = req.body;
4894
+ if (!path || typeof path !== "string") return res.status(400).json({ error: "path is required" });
4895
+ try {
4896
+ const updated = await sessionManager.attachSessionWorktree(req.params.id, path);
4897
+ res.json({ session: updated });
4898
+ } catch (err) {
4899
+ res.status(400).json({ error: err instanceof Error ? err.message : "Failed to attach worktree" });
4900
+ }
4901
+ });
4709
4902
  app.get("/api/sessions/:id", async (req, res) => {
4710
- const { getEventStore: getEventStore2 } = await import("./events-52XADT6Y.js");
4711
- const { buildMessagesFromStoredEvents } = await import("./folding-2BGFLV5J.js");
4712
- const { getPendingQuestionsForSession } = await import("./tools-ZZM36DAZ.js");
4903
+ const { getEventStore: getEventStore2 } = await import("./events-CDQ4HASP.js");
4904
+ const { buildMessagesFromStoredEvents } = await import("./folding-V2K34EGN.js");
4905
+ const { getPendingQuestionsForSession } = await import("./tools-2EB7C6H2.js");
4713
4906
  const session = sessionManager.getSession(req.params.id);
4714
4907
  if (!session) {
4715
4908
  return res.status(404).json({ error: "Session not found" });
@@ -4728,8 +4921,8 @@ async function createServerHandle(config3) {
4728
4921
  if (!session) {
4729
4922
  return res.status(404).json({ error: "Session not found" });
4730
4923
  }
4731
- const { stopSessionExecution } = await import("./chat-handler-MC3XZ3OV.js");
4732
- const { cancelQuestionsForSession, cancelPathConfirmationsForSession } = await import("./tools-ZZM36DAZ.js");
4924
+ const { stopSessionExecution } = await import("./chat-handler-ZRDNSLOG.js");
4925
+ const { cancelQuestionsForSession, cancelPathConfirmationsForSession } = await import("./tools-2EB7C6H2.js");
4733
4926
  sessionManager.clearMessageQueue(sessionId);
4734
4927
  stopSessionExecution(sessionId, sessionManager);
4735
4928
  abortSession(sessionId);
@@ -4748,8 +4941,8 @@ async function createServerHandle(config3) {
4748
4941
  res.json({ success: true });
4749
4942
  });
4750
4943
  app.post("/api/sessions/:id/provider", async (req, res) => {
4751
- const { getEventStore: getEventStore2 } = await import("./events-52XADT6Y.js");
4752
- const { buildMessagesFromStoredEvents } = await import("./folding-2BGFLV5J.js");
4944
+ const { getEventStore: getEventStore2 } = await import("./events-CDQ4HASP.js");
4945
+ const { buildMessagesFromStoredEvents } = await import("./folding-V2K34EGN.js");
4753
4946
  const sessionId = req.params.id;
4754
4947
  const session = sessionManager.getSession(sessionId);
4755
4948
  if (!session) {
@@ -4826,8 +5019,8 @@ async function createServerHandle(config3) {
4826
5019
  res.json({ success: true });
4827
5020
  });
4828
5021
  app.put("/api/sessions/:id/mode", async (req, res) => {
4829
- const { getEventStore: getEventStore2 } = await import("./events-52XADT6Y.js");
4830
- const { buildMessagesFromStoredEvents } = await import("./folding-2BGFLV5J.js");
5022
+ const { getEventStore: getEventStore2 } = await import("./events-CDQ4HASP.js");
5023
+ const { buildMessagesFromStoredEvents } = await import("./folding-V2K34EGN.js");
4831
5024
  const sessionId = req.params.id;
4832
5025
  const session = sessionManager.getSession(sessionId);
4833
5026
  if (!session) {
@@ -4883,15 +5076,15 @@ async function createServerHandle(config3) {
4883
5076
  if (!callId || approved === void 0) {
4884
5077
  return res.status(400).json({ error: "callId and approved are required" });
4885
5078
  }
4886
- const { providePathConfirmation } = await import("./tools-ZZM36DAZ.js");
5079
+ const { providePathConfirmation } = await import("./tools-2EB7C6H2.js");
4887
5080
  const result = providePathConfirmation(callId, approved, alwaysAllow);
4888
5081
  if (!result.found) {
4889
5082
  return res.status(404).json({ error: "No pending path confirmation with that ID" });
4890
5083
  }
4891
- const { getEventStore: getEventStore2 } = await import("./events-52XADT6Y.js");
4892
- const { buildMessagesFromStoredEvents, foldPendingConfirmations } = await import("./folding-2BGFLV5J.js");
5084
+ const { getEventStore: getEventStore2 } = await import("./events-CDQ4HASP.js");
5085
+ const { buildMessagesFromStoredEvents, foldPendingConfirmations } = await import("./folding-V2K34EGN.js");
4893
5086
  const { createSessionStateMessage } = await import("./protocol-CTNE3ANP.js");
4894
- const { getPendingQuestionsForSession } = await import("./tools-ZZM36DAZ.js");
5087
+ const { getPendingQuestionsForSession } = await import("./tools-2EB7C6H2.js");
4895
5088
  const eventStore = getEventStore2();
4896
5089
  const events = eventStore.getEvents(sessionId);
4897
5090
  const messages = buildMessagesFromStoredEvents(events);
@@ -4912,7 +5105,7 @@ async function createServerHandle(config3) {
4912
5105
  if (!skip && typeof answer !== "string") {
4913
5106
  return res.status(400).json({ error: "answer is required when not skipping" });
4914
5107
  }
4915
- const { provideAnswer } = await import("./tools-ZZM36DAZ.js");
5108
+ const { provideAnswer } = await import("./tools-2EB7C6H2.js");
4916
5109
  const found = provideAnswer(callId, answer ?? "", skip ?? false);
4917
5110
  if (!found) {
4918
5111
  return res.status(404).json({ error: "No pending question with that ID" });
@@ -4940,7 +5133,7 @@ async function createServerHandle(config3) {
4940
5133
  if (!session) {
4941
5134
  return res.status(404).json({ error: "Session not found" });
4942
5135
  }
4943
- const { getSetting: getSetting2, SETTINGS_KEYS } = await import("./settings-JA4XUR3W.js");
5136
+ const { getSetting: getSetting2, SETTINGS_KEYS } = await import("./settings-ZZ6AKFPD.js");
4944
5137
  if (getSetting2(SETTINGS_KEYS.CACHE_WARMING) !== "true") {
4945
5138
  return res.json({ success: false, reason: "disabled" });
4946
5139
  }
@@ -4972,7 +5165,7 @@ async function createServerHandle(config3) {
4972
5165
  backend: activeProvider?.backend ?? llmClient.getBackend(),
4973
5166
  model: llmClient.getModel()
4974
5167
  };
4975
- const { runAgentTurn, TurnMetrics } = await import("./orchestrator-IYJRQQKB.js");
5168
+ const { runAgentTurn, TurnMetrics } = await import("./orchestrator-LZQTDOWM.js");
4976
5169
  runAgentTurn(
4977
5170
  {
4978
5171
  sessionManager,
@@ -5010,15 +5203,15 @@ async function createServerHandle(config3) {
5010
5203
  if (!session) {
5011
5204
  return res.status(404).json({ error: "Session not found" });
5012
5205
  }
5013
- const { stopSessionExecution } = await import("./chat-handler-MC3XZ3OV.js");
5014
- const { cancelQuestionsForSession, cancelPathConfirmationsForSession } = await import("./tools-ZZM36DAZ.js");
5206
+ const { stopSessionExecution } = await import("./chat-handler-ZRDNSLOG.js");
5207
+ const { cancelQuestionsForSession, cancelPathConfirmationsForSession } = await import("./tools-2EB7C6H2.js");
5015
5208
  const queuedMessages = sessionManager.getQueueState(sessionId);
5016
5209
  sessionManager.clearMessageQueue(sessionId);
5017
5210
  stopSessionExecution(sessionId, sessionManager);
5018
5211
  abortSession(sessionId);
5019
5212
  cancelQuestionsForSession(sessionId, "Session stopped by user");
5020
5213
  cancelPathConfirmationsForSession(sessionId, "Session stopped by user");
5021
- const eventStore = (await import("./events-52XADT6Y.js")).getEventStore();
5214
+ const eventStore = (await import("./events-CDQ4HASP.js")).getEventStore();
5022
5215
  eventStore.append(sessionId, { type: "running.changed", data: { isRunning: false } });
5023
5216
  res.json({ success: true, queuedMessages });
5024
5217
  });
@@ -5032,7 +5225,7 @@ async function createServerHandle(config3) {
5032
5225
  if (typeof messageIndex !== "number" || messageIndex < 0) {
5033
5226
  return res.status(400).json({ error: "messageIndex must be a non-negative number" });
5034
5227
  }
5035
- const { truncateSessionMessages } = await import("./events-52XADT6Y.js");
5228
+ const { truncateSessionMessages } = await import("./events-CDQ4HASP.js");
5036
5229
  truncateSessionMessages(sessionId, messageIndex);
5037
5230
  res.json({ success: true });
5038
5231
  });
@@ -5046,8 +5239,8 @@ async function createServerHandle(config3) {
5046
5239
  if (typeof messageId !== "string" || !messageId) {
5047
5240
  return res.status(400).json({ error: "messageId is required" });
5048
5241
  }
5049
- const { getEventStore: getEventStore2 } = await import("./events-52XADT6Y.js");
5050
- const { buildMessagesFromStoredEvents } = await import("./folding-2BGFLV5J.js");
5242
+ const { getEventStore: getEventStore2 } = await import("./events-CDQ4HASP.js");
5243
+ const { buildMessagesFromStoredEvents } = await import("./folding-V2K34EGN.js");
5051
5244
  const eventStore = getEventStore2();
5052
5245
  const events = eventStore.getEvents(sessionId);
5053
5246
  const messages = buildMessagesFromStoredEvents(events);
@@ -5059,7 +5252,7 @@ async function createServerHandle(config3) {
5059
5252
  if (msg.role !== "user" || msg.isSystemGenerated) {
5060
5253
  return res.status(400).json({ error: "Can only replay user messages" });
5061
5254
  }
5062
- const { truncateSessionMessages } = await import("./events-52XADT6Y.js");
5255
+ const { truncateSessionMessages } = await import("./events-CDQ4HASP.js");
5063
5256
  truncateSessionMessages(sessionId, msgIndex - 1);
5064
5257
  sessionManager.queueMessage(sessionId, "asap", msg.content, msg.attachments, msg.messageKind);
5065
5258
  res.json({ success: true });
@@ -5091,7 +5284,7 @@ async function createServerHandle(config3) {
5091
5284
  res.json({ accepted: true });
5092
5285
  });
5093
5286
  app.get("/api/settings", async (req, res) => {
5094
- const { getSetting: getSetting2, SETTINGS_DEFAULTS } = await import("./settings-JA4XUR3W.js");
5287
+ const { getSetting: getSetting2, SETTINGS_DEFAULTS } = await import("./settings-ZZ6AKFPD.js");
5095
5288
  const keysParam = req.query["keys"];
5096
5289
  if (!keysParam) {
5097
5290
  return res.status(400).json({ error: "keys query parameter is required" });
@@ -5104,19 +5297,19 @@ async function createServerHandle(config3) {
5104
5297
  res.json(result);
5105
5298
  });
5106
5299
  app.get("/api/settings/:key", async (req, res) => {
5107
- const { getSetting: getSetting2, SETTINGS_DEFAULTS } = await import("./settings-JA4XUR3W.js");
5300
+ const { getSetting: getSetting2, SETTINGS_DEFAULTS } = await import("./settings-ZZ6AKFPD.js");
5108
5301
  const key = req.params.key;
5109
5302
  const value = getSetting2(key) ?? SETTINGS_DEFAULTS[key] ?? null;
5110
5303
  res.json({ key, value });
5111
5304
  });
5112
5305
  app.get("/api/settings/:key", async (req, res) => {
5113
- const { getSetting: getSetting2, SETTINGS_DEFAULTS } = await import("./settings-JA4XUR3W.js");
5306
+ const { getSetting: getSetting2, SETTINGS_DEFAULTS } = await import("./settings-ZZ6AKFPD.js");
5114
5307
  const key = req.params.key;
5115
5308
  const value = getSetting2(key) ?? SETTINGS_DEFAULTS[key] ?? null;
5116
5309
  res.json({ key, value });
5117
5310
  });
5118
5311
  app.put("/api/settings/:key", async (req, res) => {
5119
- const { setSetting: setSetting2 } = await import("./settings-JA4XUR3W.js");
5312
+ const { setSetting: setSetting2 } = await import("./settings-ZZ6AKFPD.js");
5120
5313
  const key = req.params.key;
5121
5314
  const { value } = req.body;
5122
5315
  if (value === void 0) {
@@ -5301,7 +5494,7 @@ async function createServerHandle(config3) {
5301
5494
  const backend = req.query["backend"];
5302
5495
  if (!url) return res.status(400).json({ error: "url is required" });
5303
5496
  try {
5304
- const { fetchModelsWithContext } = await import("./provider-manager-HRHNF73A.js");
5497
+ const { fetchModelsWithContext } = await import("./provider-manager-D3KIOD5E.js");
5305
5498
  const { getModelProfile: getModelProfile2 } = await import("./profiles-5J7F4BML.js");
5306
5499
  const models = await fetchModelsWithContext(
5307
5500
  url,
@@ -5371,7 +5564,7 @@ async function createServerHandle(config3) {
5371
5564
  }
5372
5565
  const { getModelProfile: getModelProfile2 } = await import("./profiles-5J7F4BML.js");
5373
5566
  const { getBackendCapabilities } = await import("./backend-P3GHHLHJ.js");
5374
- const { buildNonStreamingCreateParams } = await import("./client-pure-DO3S675T.js");
5567
+ const { buildNonStreamingCreateParams } = await import("./client-pure-U6ZYUPJQ.js");
5375
5568
  const { OpenAIHttpClient } = await import("./http-client-PIWB7BXK.js");
5376
5569
  const { ensureVersionPrefix } = await import("./url-utils-SAJP7AEX.js");
5377
5570
  const profile = getModelProfile2(model);
@@ -5629,7 +5822,7 @@ async function createServerHandle(config3) {
5629
5822
  });
5630
5823
  async function rebuildMcpTools() {
5631
5824
  const { createMcpTools: createMcpTools2 } = await import("./tool-adapter-MOGEI6TP.js");
5632
- const { setMcpTools: setMcpTools2 } = await import("./tools-ZZM36DAZ.js");
5825
+ const { setMcpTools: setMcpTools2 } = await import("./tools-2EB7C6H2.js");
5633
5826
  const mcpTools = createMcpTools2(mcpManager);
5634
5827
  setMcpTools2(mcpTools);
5635
5828
  }
@@ -5820,7 +6013,7 @@ async function createServerHandle(config3) {
5820
6013
  res.status(500).json({ error: err instanceof Error ? err.message : "Failed to stop process" });
5821
6014
  }
5822
6015
  });
5823
- const { getCurrentBranch } = await import("./branch.api-LAN42BA5.js");
6016
+ const { getCurrentBranch } = await import("./branch.api-3YJSWOZG.js");
5824
6017
  app.get("/api/branch", async (req, res) => {
5825
6018
  await getCurrentBranch(req, res);
5826
6019
  });
@@ -5949,7 +6142,7 @@ async function createServerHandle(config3) {
5949
6142
  const state = sessionManager.getContextState(sessionId);
5950
6143
  wssExports.broadcastForSession(sessionId, createContextStateMessage(state));
5951
6144
  });
5952
- const { QueueProcessor } = await import("./processor-LUXKVIED.js");
6145
+ const { QueueProcessor } = await import("./processor-7KAXESY5.js");
5953
6146
  const queueProcessor = new QueueProcessor({
5954
6147
  sessionManager,
5955
6148
  providerManager,
@@ -5991,7 +6184,7 @@ async function createServerHandle(config3) {
5991
6184
  void (async () => {
5992
6185
  await devServerManager.stopAll();
5993
6186
  await mcpManager.disconnectAll();
5994
- const { stopAllInspectProxies } = await import("./inspect-proxy-BV25JERQ.js");
6187
+ const { stopAllInspectProxies } = await import("./inspect-proxy-PKMDR47R.js");
5995
6188
  stopAllInspectProxies();
5996
6189
  const { cleanupAllProcesses } = await import("./store-FXTCHBI4.js");
5997
6190
  cleanupAllProcesses();
@@ -6030,4 +6223,4 @@ export {
6030
6223
  createServerHandle,
6031
6224
  createServer
6032
6225
  };
6033
- //# sourceMappingURL=chunk-Z6H7SFQR.js.map
6226
+ //# sourceMappingURL=chunk-OE5B44P6.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  getDatabase
3
- } from "./chunk-ZPIZLTWU.js";
3
+ } from "./chunk-GMXKJGJ2.js";
4
4
 
5
5
  // src/server/db/settings.ts
6
6
  var SETTINGS_KEYS = {
@@ -99,4 +99,4 @@ export {
99
99
  deleteSetting,
100
100
  getAllSettings
101
101
  };
102
- //# sourceMappingURL=chunk-PXJ4NOP4.js.map
102
+ //# sourceMappingURL=chunk-PVRSNXD4.js.map