openfox 1.6.79 → 1.6.80

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.
@@ -2,7 +2,7 @@ import {
2
2
  createVerifierNudgeConfig,
3
3
  runBuilderTurn,
4
4
  runChatTurn
5
- } from "./chunk-BG7QCFGG.js";
5
+ } from "./chunk-HPTMW2FT.js";
6
6
  import {
7
7
  TurnMetrics,
8
8
  agentExists,
@@ -37,7 +37,7 @@ import {
37
37
  setSkillEnabled,
38
38
  skillExists,
39
39
  spawnShellProcess
40
- } from "./chunk-UCZSBKG7.js";
40
+ } from "./chunk-7DOKXSMI.js";
41
41
  import {
42
42
  getProject
43
43
  } from "./chunk-CMQCO27Y.js";
@@ -87,7 +87,7 @@ import {
87
87
  updateSessionProvider,
88
88
  updateSessionRunning,
89
89
  updateSessionSummary
90
- } from "./chunk-RJRG2VER.js";
90
+ } from "./chunk-LHKXWUEK.js";
91
91
  import {
92
92
  initDatabase
93
93
  } from "./chunk-KIOUKC3Z.js";
@@ -108,7 +108,7 @@ import {
108
108
  parseClientMessage,
109
109
  serializeServerMessage,
110
110
  storedEventToServerMessage
111
- } from "./chunk-STYHKCG7.js";
111
+ } from "./chunk-UF6D2IPO.js";
112
112
  import {
113
113
  EventEmitter,
114
114
  provideAnswer
@@ -2287,17 +2287,6 @@ function resolveStatsIdentity(llmClient, getActiveProvider) {
2287
2287
  model
2288
2288
  };
2289
2289
  }
2290
- function buildSessionState(sessionManager, sessionId) {
2291
- const session = sessionManager.getSession(sessionId);
2292
- if (!session) {
2293
- return { session: null, messages: [], pendingConfirmations: [] };
2294
- }
2295
- const eventStore = getEventStore();
2296
- const events = eventStore.getEvents(sessionId);
2297
- const messages = events.length > 0 ? buildMessagesFromStoredEvents(events) : [];
2298
- const pendingConfirmations = foldPendingConfirmations(events);
2299
- return { session, messages, pendingConfirmations };
2300
- }
2301
2290
  function addUserMessageAndBroadcast(sessionManager, sessionId, message, broadcastFn) {
2302
2291
  const userMessage = sessionManager.addMessage(sessionId, {
2303
2292
  role: "user",
@@ -2342,6 +2331,7 @@ function processQueueAndRestartTurn(sessionManager, sessionId, drainFn, queueMod
2342
2331
  return true;
2343
2332
  }
2344
2333
  var activeAgents = /* @__PURE__ */ new Map();
2334
+ var MAX_SEND_QUEUE_SIZE = 1e3;
2345
2335
  function createWebSocketServer(httpServer, config, getLLMClient, getActiveProvider, sessionManager, providerManager) {
2346
2336
  const wss = new WebSocketServer({ server: httpServer });
2347
2337
  const clients = /* @__PURE__ */ new Map();
@@ -2408,6 +2398,37 @@ function createWebSocketServer(httpServer, config, getLLMClient, getActiveProvid
2408
2398
  }
2409
2399
  }
2410
2400
  };
2401
+ function enqueueSend(client, data, seq) {
2402
+ if (client.sendQueue.length >= MAX_SEND_QUEUE_SIZE) {
2403
+ logger.warn("WebSocket send queue full, dropping message", {
2404
+ queueSize: client.sendQueue.length,
2405
+ sessionId: client.activeSessionId
2406
+ });
2407
+ return;
2408
+ }
2409
+ client.sendQueue.push({ data, seq });
2410
+ processSendQueue(client);
2411
+ }
2412
+ function processSendQueue(client) {
2413
+ if (client.isSending || client.sendQueue.length === 0) {
2414
+ return;
2415
+ }
2416
+ client.isSending = true;
2417
+ const item = client.sendQueue.shift();
2418
+ if (client.ws.readyState === WebSocket2.OPEN) {
2419
+ client.ws.send(item.data, (err) => {
2420
+ if (err) {
2421
+ logger.debug("WebSocket send error", { error: err });
2422
+ }
2423
+ client.isSending = false;
2424
+ client.lastSentSeq = item.seq;
2425
+ processSendQueue(client);
2426
+ });
2427
+ } else {
2428
+ client.isSending = false;
2429
+ processSendQueue(client);
2430
+ }
2431
+ }
2411
2432
  const llmForSession = (sessionId) => getSessionLLMClient?.(sessionId) ?? getLLMClient();
2412
2433
  const statsForSession = (sessionId) => getSessionStatsIdentity?.(sessionId) ?? resolveStatsIdentity(getLLMClient(), getActiveProvider);
2413
2434
  function cleanupAfterTurn(sessionId, controller, sendFn, setRunningOnEarlyReturn) {
@@ -2464,47 +2485,12 @@ function createWebSocketServer(httpServer, config, getLLMClient, getActiveProvid
2464
2485
  cleanupAfterTurn(sessionId, controller, broadcastForSession, false);
2465
2486
  });
2466
2487
  }
2467
- sessionManager.subscribe((event) => {
2468
- const sessionId = "sessionId" in event ? event.sessionId : "session" in event ? event.session.id : null;
2469
- if (!sessionId) return;
2470
- for (const [ws, client] of clients) {
2471
- if (ws.readyState !== WebSocket2.OPEN) continue;
2472
- if (event.type === "session_created") {
2473
- const session = sessionManager.getSession(sessionId);
2474
- if (session) {
2475
- const { messages, pendingConfirmations } = buildSessionState(sessionManager, sessionId);
2476
- ws.send(
2477
- serializeServerMessage({
2478
- ...createSessionStateMessage(session, messages, pendingConfirmations),
2479
- sessionId
2480
- })
2481
- );
2482
- }
2483
- continue;
2484
- }
2485
- if (isSubscribedToSession(client, sessionId)) {
2486
- if (event.type === "session_updated") {
2487
- const { session, messages, pendingConfirmations } = buildSessionState(sessionManager, sessionId);
2488
- if (session) {
2489
- ws.send(
2490
- serializeServerMessage({
2491
- ...createSessionStateMessage(session, messages, pendingConfirmations),
2492
- sessionId
2493
- })
2494
- );
2495
- }
2496
- }
2497
- if (event.type === "running_changed") {
2498
- ws.send(serializeServerMessage({ ...createSessionRunningMessage(event.isRunning), sessionId }));
2499
- }
2500
- }
2501
- }
2502
- });
2503
2488
  const broadcastAll = (msg) => {
2504
2489
  const serialized = serializeServerMessage(msg);
2505
- for (const [clientWs] of clients) {
2490
+ for (const [clientWs, client] of clients) {
2506
2491
  if (clientWs.readyState === WebSocket2.OPEN) {
2507
- clientWs.send(serialized);
2492
+ const seq = client.lastSentSeq + 1;
2493
+ enqueueSend(client, serialized, seq);
2508
2494
  }
2509
2495
  }
2510
2496
  };
@@ -2532,7 +2518,8 @@ function createWebSocketServer(httpServer, config, getLLMClient, getActiveProvid
2532
2518
  for (const [clientWs, client] of clients) {
2533
2519
  if (client.activeSessionId === sessionId) {
2534
2520
  if (clientWs.readyState === WebSocket2.OPEN) {
2535
- clientWs.send(serializeServerMessage(msg));
2521
+ const seq = client.lastSentSeq + 1;
2522
+ enqueueSend(client, serializeServerMessage(msg), seq);
2536
2523
  }
2537
2524
  }
2538
2525
  }
@@ -2550,7 +2537,14 @@ function createWebSocketServer(httpServer, config, getLLMClient, getActiveProvid
2550
2537
  }
2551
2538
  }
2552
2539
  logger.debug("WebSocket client connected");
2553
- clients.set(ws, { ws, activeSessionId: null, globalSubscription: null });
2540
+ clients.set(ws, {
2541
+ ws,
2542
+ activeSessionId: null,
2543
+ globalSubscription: null,
2544
+ sendQueue: [],
2545
+ isSending: false,
2546
+ lastSentSeq: 0
2547
+ });
2554
2548
  const eventStore = getEventStore();
2555
2549
  const { iterator: globalIterator, unsubscribe: globalUnsubscribe } = eventStore.subscribeAll();
2556
2550
  clients.get(ws).globalSubscription = globalUnsubscribe;
@@ -2560,7 +2554,12 @@ function createWebSocketServer(httpServer, config, getLLMClient, getActiveProvid
2560
2554
  if (ws.readyState !== WebSocket2.OPEN) break;
2561
2555
  const serverMsg = storedEventToServerMessage(storedEvent);
2562
2556
  if (serverMsg) {
2563
- ws.send(serializeServerMessage({ ...serverMsg, seq: storedEvent.seq, sessionId: storedEvent.sessionId }));
2557
+ const client = clients.get(ws);
2558
+ enqueueSend(
2559
+ client,
2560
+ serializeServerMessage({ ...serverMsg, seq: storedEvent.seq, sessionId: storedEvent.sessionId }),
2561
+ storedEvent.seq
2562
+ );
2564
2563
  }
2565
2564
  }
2566
2565
  } catch (error) {
@@ -2570,7 +2569,13 @@ function createWebSocketServer(httpServer, config, getLLMClient, getActiveProvid
2570
2569
  ws.on("message", async (data) => {
2571
2570
  const message = parseClientMessage(data.toString());
2572
2571
  if (!message) {
2573
- ws.send(serializeServerMessage(createErrorMessage("INVALID_MESSAGE", "Invalid message format")));
2572
+ const client2 = clients.get(ws);
2573
+ const seq = client2.lastSentSeq + 1;
2574
+ enqueueSend(
2575
+ client2,
2576
+ serializeServerMessage(createErrorMessage("INVALID_MESSAGE", "Invalid message format")),
2577
+ seq
2578
+ );
2574
2579
  return;
2575
2580
  }
2576
2581
  if (message.type.startsWith("terminal.")) {
@@ -2593,14 +2598,19 @@ function createWebSocketServer(httpServer, config, getLLMClient, getActiveProvid
2593
2598
  llmForSession,
2594
2599
  statsForSession,
2595
2600
  startTurnWithCompletionChain,
2596
- cleanupAfterTurn
2601
+ cleanupAfterTurn,
2602
+ enqueueSend
2597
2603
  );
2598
2604
  } catch (error) {
2599
2605
  logger.error("Error handling client message", { error, type: message.type });
2600
- ws.send(
2606
+ const client2 = clients.get(ws);
2607
+ const seq = client2.lastSentSeq + 1;
2608
+ enqueueSend(
2609
+ client2,
2601
2610
  serializeServerMessage(
2602
2611
  createErrorMessage("INTERNAL_ERROR", error instanceof Error ? error.message : "Unknown error", message.id)
2603
- )
2612
+ ),
2613
+ seq
2604
2614
  );
2605
2615
  }
2606
2616
  });
@@ -2611,6 +2621,10 @@ function createWebSocketServer(httpServer, config, getLLMClient, getActiveProvid
2611
2621
  client.globalSubscription();
2612
2622
  }
2613
2623
  unsubscribeAllFromTerminal(ws);
2624
+ if (client) {
2625
+ client.sendQueue = [];
2626
+ client.isSending = false;
2627
+ }
2614
2628
  clients.delete(ws);
2615
2629
  });
2616
2630
  ws.on("error", (error) => {
@@ -2632,10 +2646,11 @@ function createWebSocketServer(httpServer, config, getLLMClient, getActiveProvid
2632
2646
  broadcastForSession
2633
2647
  };
2634
2648
  }
2635
- async function handleClientMessage(ws, client, message, _getLLMClient, _getActiveProvider, sessionManager, _broadcastForSession, _providerManager, _getSessionLLMClient, _getSessionStatsIdentity, llmForSession, statsForSession, _startTurnWithCompletionChain, cleanupAfterTurn) {
2649
+ async function handleClientMessage(ws, client, message, _getLLMClient, _getActiveProvider, sessionManager, _broadcastForSession, _providerManager, _getSessionLLMClient, _getSessionStatsIdentity, llmForSession, statsForSession, _startTurnWithCompletionChain, cleanupAfterTurn, enqueueSendFn) {
2636
2650
  const send = (msg) => {
2637
2651
  if (ws.readyState === WebSocket2.OPEN) {
2638
- ws.send(serializeServerMessage(msg));
2652
+ const seq = client.lastSentSeq + 1;
2653
+ enqueueSendFn(client, serializeServerMessage(msg), seq);
2639
2654
  }
2640
2655
  };
2641
2656
  const sendForSession = (sessionId, msg) => {
@@ -5242,7 +5257,7 @@ function createTerminalRoutes() {
5242
5257
  }
5243
5258
 
5244
5259
  // src/constants.ts
5245
- var VERSION = "1.6.79";
5260
+ var VERSION = "1.6.80";
5246
5261
 
5247
5262
  // src/server/index.ts
5248
5263
  var __dirname2 = dirname5(fileURLToPath4(import.meta.url));
@@ -5370,9 +5385,49 @@ async function createServerHandle(config) {
5370
5385
  if (!name || !workdir) {
5371
5386
  return res.status(400).json({ error: "name and workdir are required" });
5372
5387
  }
5373
- const { createDirectoryWithGit } = await import("./project-creator-VD7MLOWE.js");
5374
- const project = await createDirectoryWithGit(name, workdir);
5375
- res.status(201).json({ project });
5388
+ const { createDirectoryWithGit } = await import("./project-creator-GPOIXKX4.js");
5389
+ try {
5390
+ const project = await createDirectoryWithGit(name, workdir);
5391
+ res.status(201).json({ project });
5392
+ } catch (err) {
5393
+ const eaccError = err;
5394
+ return res.status(403).json({
5395
+ error: eaccError.message || "Unknown error",
5396
+ code: eaccError.code || "UNKNOWN",
5397
+ path: workdir
5398
+ });
5399
+ }
5400
+ });
5401
+ app.post("/api/projects/check-permissions", async (req, res) => {
5402
+ const { path: targetPath } = req.body;
5403
+ if (!targetPath) {
5404
+ return res.status(400).json({ error: "path is required" });
5405
+ }
5406
+ const { checkPermissions } = await import("./permissions-Z2IIV2V7.js");
5407
+ const result = await checkPermissions(targetPath);
5408
+ if (result.success) {
5409
+ res.json(result);
5410
+ } else {
5411
+ const status = result.status ?? 500;
5412
+ res.status(status).json({ error: result.error });
5413
+ }
5414
+ });
5415
+ app.post("/api/projects/fix-permissions", async (req, res) => {
5416
+ const { path: targetPath, action } = req.body;
5417
+ if (!targetPath) {
5418
+ return res.status(400).json({ error: "path is required" });
5419
+ }
5420
+ if (!["group", "ownership", "join_group", "join_group_and_group"].includes(action)) {
5421
+ return res.status(400).json({ error: 'action must be "group", "ownership", "join_group", or "join_group_and_group"' });
5422
+ }
5423
+ const { fixPermissions } = await import("./permissions-Z2IIV2V7.js");
5424
+ const result = await fixPermissions(targetPath, action);
5425
+ if (result.success) {
5426
+ res.json(result);
5427
+ } else {
5428
+ const status = result.status ?? 500;
5429
+ res.status(status).json(result);
5430
+ }
5376
5431
  });
5377
5432
  app.get("/api/projects/:id", async (req, res) => {
5378
5433
  const { getProject: getProject2 } = await import("./projects-XLMSDFTQ.js");
@@ -5404,7 +5459,7 @@ async function createServerHandle(config) {
5404
5459
  res.json({ success: true });
5405
5460
  });
5406
5461
  app.get("/api/sessions", async (req, res) => {
5407
- const { getRecentUserPromptsForSession } = await import("./events-ND5GZBT2.js");
5462
+ const { getRecentUserPromptsForSession } = await import("./events-QDUOJQML.js");
5408
5463
  const projectId = req.query["projectId"];
5409
5464
  const limit = Math.min(parseInt(req.query["limit"]) || 20, 100);
5410
5465
  const offset = parseInt(req.query["offset"]) || 0;
@@ -5437,7 +5492,7 @@ async function createServerHandle(config) {
5437
5492
  res.status(201).json({ session });
5438
5493
  });
5439
5494
  app.get("/api/sessions/:id", async (req, res) => {
5440
- const { getEventStore: getEventStore2 } = await import("./events-ND5GZBT2.js");
5495
+ const { getEventStore: getEventStore2 } = await import("./events-QDUOJQML.js");
5441
5496
  const { buildMessagesFromStoredEvents: buildMessagesFromStoredEvents2 } = await import("./folding-XIKR6AFM.js");
5442
5497
  const session = sessionManager.getSession(req.params.id);
5443
5498
  if (!session) {
@@ -5468,7 +5523,7 @@ async function createServerHandle(config) {
5468
5523
  res.json({ success: true });
5469
5524
  });
5470
5525
  app.post("/api/sessions/:id/provider", async (req, res) => {
5471
- const { getEventStore: getEventStore2 } = await import("./events-ND5GZBT2.js");
5526
+ const { getEventStore: getEventStore2 } = await import("./events-QDUOJQML.js");
5472
5527
  const { buildMessagesFromStoredEvents: buildMessagesFromStoredEvents2 } = await import("./folding-XIKR6AFM.js");
5473
5528
  const sessionId = req.params.id;
5474
5529
  const session = sessionManager.getSession(sessionId);
@@ -5506,7 +5561,7 @@ async function createServerHandle(config) {
5506
5561
  res.json({ success: true });
5507
5562
  });
5508
5563
  app.put("/api/sessions/:id/mode", async (req, res) => {
5509
- const { getEventStore: getEventStore2 } = await import("./events-ND5GZBT2.js");
5564
+ const { getEventStore: getEventStore2 } = await import("./events-QDUOJQML.js");
5510
5565
  const { buildMessagesFromStoredEvents: buildMessagesFromStoredEvents2 } = await import("./folding-XIKR6AFM.js");
5511
5566
  const sessionId = req.params.id;
5512
5567
  const session = sessionManager.getSession(sessionId);
@@ -5559,14 +5614,14 @@ async function createServerHandle(config) {
5559
5614
  if (!callId || approved === void 0) {
5560
5615
  return res.status(400).json({ error: "callId and approved are required" });
5561
5616
  }
5562
- const { providePathConfirmation } = await import("./tools-W6OPDFQV.js");
5617
+ const { providePathConfirmation } = await import("./tools-B4KSCOWC.js");
5563
5618
  const result = providePathConfirmation(callId, approved, alwaysAllow);
5564
5619
  if (!result.found) {
5565
5620
  return res.status(404).json({ error: "No pending path confirmation with that ID" });
5566
5621
  }
5567
- const { getEventStore: getEventStore2 } = await import("./events-ND5GZBT2.js");
5622
+ const { getEventStore: getEventStore2 } = await import("./events-QDUOJQML.js");
5568
5623
  const { buildMessagesFromStoredEvents: buildMessagesFromStoredEvents2, foldPendingConfirmations: foldPendingConfirmations2 } = await import("./folding-XIKR6AFM.js");
5569
- const { createSessionStateMessage: createSessionStateMessage2 } = await import("./protocol-4CTV7OZC.js");
5624
+ const { createSessionStateMessage: createSessionStateMessage2 } = await import("./protocol-IXFNYZEX.js");
5570
5625
  const eventStore = getEventStore2();
5571
5626
  const events = eventStore.getEvents(sessionId);
5572
5627
  const messages = buildMessagesFromStoredEvents2(events);
@@ -5583,7 +5638,7 @@ async function createServerHandle(config) {
5583
5638
  if (!callId || !answer) {
5584
5639
  return res.status(400).json({ error: "callId and answer are required" });
5585
5640
  }
5586
- const { provideAnswer: provideAnswer2 } = await import("./tools-W6OPDFQV.js");
5641
+ const { provideAnswer: provideAnswer2 } = await import("./tools-B4KSCOWC.js");
5587
5642
  const found = provideAnswer2(callId, answer);
5588
5643
  if (!found) {
5589
5644
  return res.status(404).json({ error: "No pending question with that ID" });
@@ -5619,14 +5674,14 @@ async function createServerHandle(config) {
5619
5674
  if (!session) {
5620
5675
  return res.status(404).json({ error: "Session not found" });
5621
5676
  }
5622
- const { stopSessionExecution } = await import("./chat-handler-EKAO6CIB.js");
5623
- const { cancelQuestionsForSession, cancelPathConfirmationsForSession } = await import("./tools-W6OPDFQV.js");
5677
+ const { stopSessionExecution } = await import("./chat-handler-PO5OBBJE.js");
5678
+ const { cancelQuestionsForSession, cancelPathConfirmationsForSession } = await import("./tools-B4KSCOWC.js");
5624
5679
  stopSessionExecution(sessionId, sessionManager);
5625
5680
  abortSession(sessionId);
5626
5681
  cancelQuestionsForSession(sessionId, "Session stopped by user");
5627
5682
  cancelPathConfirmationsForSession(sessionId, "Session stopped by user");
5628
5683
  sessionManager.clearMessageQueue(sessionId);
5629
- const eventStore = (await import("./events-ND5GZBT2.js")).getEventStore();
5684
+ const eventStore = (await import("./events-QDUOJQML.js")).getEventStore();
5630
5685
  eventStore.append(sessionId, { type: "running.changed", data: { isRunning: false } });
5631
5686
  res.json({ success: true });
5632
5687
  });
@@ -5640,7 +5695,7 @@ async function createServerHandle(config) {
5640
5695
  if (typeof messageIndex !== "number" || messageIndex < 0) {
5641
5696
  return res.status(400).json({ error: "messageIndex must be a non-negative number" });
5642
5697
  }
5643
- const { truncateSessionMessages } = await import("./events-ND5GZBT2.js");
5698
+ const { truncateSessionMessages } = await import("./events-QDUOJQML.js");
5644
5699
  truncateSessionMessages(sessionId, messageIndex);
5645
5700
  res.json({ success: true });
5646
5701
  });
@@ -6108,7 +6163,7 @@ async function createServerHandle(config) {
6108
6163
  providerManager
6109
6164
  );
6110
6165
  const wss = wssExports.wss;
6111
- const { QueueProcessor } = await import("./processor-O35Q3EZT.js");
6166
+ const { QueueProcessor } = await import("./processor-SAS6Z2XZ.js");
6112
6167
  const queueProcessor = new QueueProcessor({
6113
6168
  sessionManager,
6114
6169
  providerManager,
@@ -6183,4 +6238,4 @@ export {
6183
6238
  createServerHandle,
6184
6239
  createServer
6185
6240
  };
6186
- //# sourceMappingURL=chunk-3JU4NOQD.js.map
6241
+ //# sourceMappingURL=chunk-YLLWWYDA.js.map
package/dist/cli/dev.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  runCli
4
- } from "../chunk-HOD7GVQ5.js";
4
+ } from "../chunk-GFLXCEZA.js";
5
5
  import {
6
6
  logger
7
7
  } from "../chunk-K44MW7JJ.js";
package/dist/cli/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  runCli
4
- } from "../chunk-HOD7GVQ5.js";
4
+ } from "../chunk-GFLXCEZA.js";
5
5
  import {
6
6
  logger
7
7
  } from "../chunk-K44MW7JJ.js";
@@ -37,7 +37,7 @@ import {
37
37
  isStoredEvent,
38
38
  isTurnEvent,
39
39
  truncateSessionMessages
40
- } from "./chunk-RJRG2VER.js";
40
+ } from "./chunk-LHKXWUEK.js";
41
41
  import "./chunk-KIOUKC3Z.js";
42
42
  import {
43
43
  buildContextMessagesFromEventHistory,
@@ -113,4 +113,4 @@ export {
113
113
  isTurnEvent,
114
114
  truncateSessionMessages
115
115
  };
116
- //# sourceMappingURL=events-ND5GZBT2.js.map
116
+ //# sourceMappingURL=events-QDUOJQML.js.map
@@ -3,7 +3,7 @@ import {
3
3
  runBuilderTurn,
4
4
  runChatTurn,
5
5
  runVerifierTurn
6
- } from "./chunk-BG7QCFGG.js";
6
+ } from "./chunk-HPTMW2FT.js";
7
7
  import {
8
8
  TurnMetrics,
9
9
  createChatDoneEvent,
@@ -11,17 +11,17 @@ import {
11
11
  createMessageStartEvent,
12
12
  createToolCallEvent,
13
13
  createToolResultEvent
14
- } from "./chunk-UCZSBKG7.js";
14
+ } from "./chunk-7DOKXSMI.js";
15
15
  import "./chunk-OXI26S7U.js";
16
16
  import "./chunk-CMQCO27Y.js";
17
17
  import "./chunk-DL6ZILAF.js";
18
18
  import "./chunk-PBGOZMVY.js";
19
19
  import "./chunk-VRGRAQDG.js";
20
20
  import "./chunk-CUDAT6SS.js";
21
- import "./chunk-RJRG2VER.js";
21
+ import "./chunk-LHKXWUEK.js";
22
22
  import "./chunk-KIOUKC3Z.js";
23
23
  import "./chunk-TS5XFQ2D.js";
24
- import "./chunk-STYHKCG7.js";
24
+ import "./chunk-UF6D2IPO.js";
25
25
  import "./chunk-BJYPTN5S.js";
26
26
  import "./chunk-NDJ6FKSP.js";
27
27
  import "./chunk-CQGTEGKL.js";
@@ -40,4 +40,4 @@ export {
40
40
  runChatTurn,
41
41
  runVerifierTurn
42
42
  };
43
- //# sourceMappingURL=orchestrator-5U4O4K7V.js.map
43
+ //# sourceMappingURL=orchestrator-LVD4YU54.js.map
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openfox",
3
- "version": "1.6.79",
3
+ "version": "1.6.80",
4
4
  "description": "Local-LLM-first agentic coding assistant",
5
5
  "type": "module",
6
6
  "bin": {
@@ -0,0 +1,109 @@
1
+ // src/server/utils/permissions.ts
2
+ import { execSync } from "child_process";
3
+ import { resolve } from "path";
4
+ import { access, stat } from "fs/promises";
5
+ import { constants } from "fs";
6
+ function sanitizeShellArg(arg) {
7
+ if (!/^[a-zA-Z0-9._-]+$/.test(arg)) {
8
+ throw new Error(`Invalid argument: ${arg}`);
9
+ }
10
+ return arg;
11
+ }
12
+ async function getDirInfo(targetPath) {
13
+ const resolvedPath = resolve(targetPath);
14
+ try {
15
+ await access(resolvedPath, constants.F_OK);
16
+ } catch {
17
+ throw new Error("Path not found");
18
+ }
19
+ let sudoAvailable;
20
+ try {
21
+ execSync("sudo -n true", { stdio: "pipe" });
22
+ sudoAvailable = true;
23
+ } catch {
24
+ sudoAvailable = false;
25
+ }
26
+ const dirStat = await stat(resolvedPath);
27
+ const groupGid = dirStat.gid;
28
+ const currentUser = sanitizeShellArg(execSync("id -un", { encoding: "utf-8" }).trim());
29
+ const groupsOutput = execSync(`id -Gn ${currentUser}`, { encoding: "utf-8" }).trim();
30
+ const userGroups = groupsOutput.split(/\s+/);
31
+ let groupName = null;
32
+ try {
33
+ const rawGroupName = execSync(`getent group ${groupGid}`, { encoding: "utf-8" }).split(":")[0]?.trim();
34
+ groupName = rawGroupName ? sanitizeShellArg(rawGroupName) : null;
35
+ } catch {
36
+ }
37
+ const userInGroup = groupName ? userGroups.includes(groupName) : false;
38
+ const groupHasWrite = (dirStat.mode & 16) !== 0;
39
+ return { resolvedPath, groupGid, groupName, userGroups, userInGroup, groupHasWrite, sudoAvailable };
40
+ }
41
+ async function checkPermissions(targetPath) {
42
+ try {
43
+ const info = await getDirInfo(targetPath);
44
+ return {
45
+ success: true,
46
+ sudoAvailable: info.sudoAvailable,
47
+ userInGroup: info.userInGroup,
48
+ groupHasWrite: info.groupHasWrite,
49
+ groupName: info.groupName
50
+ };
51
+ } catch (err) {
52
+ const message = err instanceof Error ? err.message : "Unknown error";
53
+ if (message === "Path not found") {
54
+ return { success: false, error: message, status: 404 };
55
+ }
56
+ return { success: false, error: err instanceof Error ? err.message : "Unknown error", status: 500 };
57
+ }
58
+ }
59
+ async function fixPermissions(targetPath, action) {
60
+ try {
61
+ const info = await getDirInfo(targetPath);
62
+ if (action === "group") {
63
+ if (!info.userInGroup) {
64
+ return {
65
+ success: false,
66
+ sudoAvailable: info.sudoAvailable,
67
+ error: 'You are not in the group that owns this directory. Use "Join group & extend group permissions" instead.'
68
+ };
69
+ }
70
+ execSync(`sudo chmod g+w "${info.resolvedPath}"`, { stdio: "pipe" });
71
+ return { success: true, sudoAvailable: info.sudoAvailable, method: "group" };
72
+ }
73
+ if (action === "join_group") {
74
+ if (!info.groupName) {
75
+ return { success: false, sudoAvailable: info.sudoAvailable, error: "Could not determine group name" };
76
+ }
77
+ const currentUser = execSync("id -un", { encoding: "utf-8" }).trim();
78
+ execSync(`sudo usermod -aG ${sanitizeShellArg(info.groupName)} ${sanitizeShellArg(currentUser)}`, {
79
+ stdio: "pipe"
80
+ });
81
+ return { success: true, sudoAvailable: info.sudoAvailable, method: "join_group" };
82
+ }
83
+ if (action === "join_group_and_group") {
84
+ if (!info.groupName) {
85
+ return { success: false, sudoAvailable: info.sudoAvailable, error: "Could not determine group name" };
86
+ }
87
+ execSync(`sudo chmod g+w "${info.resolvedPath}"`, { stdio: "pipe" });
88
+ const currentUser = execSync("id -un", { encoding: "utf-8" }).trim();
89
+ execSync(`sudo usermod -aG ${sanitizeShellArg(info.groupName)} ${sanitizeShellArg(currentUser)}`, {
90
+ stdio: "pipe"
91
+ });
92
+ return { success: true, sudoAvailable: info.sudoAvailable, method: "join_group_and_group" };
93
+ }
94
+ const ownerUser = execSync("id -un", { encoding: "utf-8" }).trim();
95
+ execSync(`sudo chown -R ${sanitizeShellArg(ownerUser)} "${info.resolvedPath}"`, { stdio: "pipe" });
96
+ return { success: true, sudoAvailable: info.sudoAvailable, method: "ownership" };
97
+ } catch (err) {
98
+ const message = err instanceof Error ? err.message : "Unknown error";
99
+ if (message === "Path not found") {
100
+ return { success: false, sudoAvailable: true, error: message, status: 404 };
101
+ }
102
+ return { success: false, sudoAvailable: true, error: message };
103
+ }
104
+ }
105
+ export {
106
+ checkPermissions,
107
+ fixPermissions
108
+ };
109
+ //# sourceMappingURL=permissions-Z2IIV2V7.js.map
@@ -5,16 +5,16 @@ import {
5
5
  generateSessionName,
6
6
  getSessionMessageCount,
7
7
  needsNameGenerationCheck
8
- } from "./chunk-2IZMUXMP.js";
8
+ } from "./chunk-A5W6JUYZ.js";
9
9
  import {
10
10
  getEventStore
11
- } from "./chunk-RJRG2VER.js";
11
+ } from "./chunk-LHKXWUEK.js";
12
12
  import "./chunk-KIOUKC3Z.js";
13
13
  import "./chunk-TS5XFQ2D.js";
14
14
  import {
15
15
  createChatMessageMessage,
16
16
  createSessionRunningMessage
17
- } from "./chunk-STYHKCG7.js";
17
+ } from "./chunk-UF6D2IPO.js";
18
18
  import "./chunk-NDJ6FKSP.js";
19
19
  import "./chunk-B5AP3RSV.js";
20
20
  import {
@@ -177,7 +177,7 @@ var QueueProcessor = class {
177
177
  backend: provider?.backend ?? llmClient.getBackend(),
178
178
  model: llmClient.getModel()
179
179
  };
180
- const { runChatTurn } = await import("./orchestrator-5U4O4K7V.js");
180
+ const { runChatTurn } = await import("./orchestrator-LVD4YU54.js");
181
181
  const runChatTurnParams = buildRunChatTurnParams({
182
182
  sessionManager,
183
183
  sessionId,
@@ -193,18 +193,25 @@ var QueueProcessor = class {
193
193
  logger.error("QueueProcessor turn error", { sessionId, error });
194
194
  }).finally(() => {
195
195
  this.activeAgents.delete(sessionId);
196
- const session2 = this.deps.sessionManager.getSession(sessionId);
197
- if (!session2) {
198
- this.deps.sessionManager.setRunning(sessionId, false);
199
- this.deps.broadcastForSession(sessionId, createSessionRunningMessage(false));
200
- return;
201
- }
202
- const hasMore = sessionManager.hasQueuedMessages(sessionId);
203
- if (!hasMore) {
204
- finalizeTurnCompletion(sessionId, sessionManager, broadcastForSession);
205
- return;
196
+ try {
197
+ const session2 = sessionManager.getSession(sessionId);
198
+ if (!session2) {
199
+ sessionManager.setRunning(sessionId, false);
200
+ broadcastForSession(sessionId, createSessionRunningMessage(false));
201
+ return;
202
+ }
203
+ const hasMore = sessionManager.hasQueuedMessages(sessionId);
204
+ if (!hasMore) {
205
+ finalizeTurnCompletion(sessionId, sessionManager, broadcastForSession);
206
+ return;
207
+ }
208
+ this.startTurn(sessionId);
209
+ } catch (error) {
210
+ logger.error("Error in turn completion cleanup", {
211
+ sessionId,
212
+ error: error instanceof Error ? error.message : String(error)
213
+ });
206
214
  }
207
- this.startTurn(sessionId);
208
215
  });
209
216
  }
210
217
  getSessionMessageCount(sessionId) {
@@ -214,4 +221,4 @@ var QueueProcessor = class {
214
221
  export {
215
222
  QueueProcessor
216
223
  };
217
- //# sourceMappingURL=processor-O35Q3EZT.js.map
224
+ //# sourceMappingURL=processor-SAS6Z2XZ.js.map