openfox 2.0.66 → 2.0.67

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 (33) hide show
  1. package/dist/{chat-handler-ZRDNSLOG.js → chat-handler-72DFHK5K.js} +11 -10
  2. package/dist/{chunk-OE5B44P6.js → chunk-2GRUQN2B.js} +209 -137
  3. package/dist/{chunk-WNA5VPZG.js → chunk-4QBDV6LX.js} +16 -13
  4. package/dist/{chunk-ZUM2ZJOX.js → chunk-B6JUWVTK.js} +54 -16
  5. package/dist/{chunk-R7EED6ZU.js → chunk-MQHMT5WF.js} +2 -2
  6. package/dist/{chunk-UBIHP5Z7.js → chunk-PYRH4G2J.js} +7 -33
  7. package/dist/{chunk-BGTEIA2S.js → chunk-TFCHWMOJ.js} +23 -30
  8. package/dist/{chunk-R4UTFE63.js → chunk-TJO4QFDQ.js} +7 -4
  9. package/dist/{chunk-OBK3I4KD.js → chunk-VLV3XWZS.js} +57 -3
  10. package/dist/chunk-X5DOUA3Z.js +66 -0
  11. package/dist/{chunk-PVRSNXD4.js → chunk-XUPKS5FL.js} +5 -3
  12. package/dist/{chunk-3ACDQKK6.js → chunk-YU6DZAVA.js} +27 -48
  13. package/dist/{chunk-5V5DM5E4.js → chunk-ZLON3JTI.js} +2 -2
  14. package/dist/cli/dev.js +1 -1
  15. package/dist/cli/index.js +1 -1
  16. package/dist/{compactor-V43WJ3WX.js → compactor-74CZVUWI.js} +5 -3
  17. package/dist/{inspect-proxy-PKMDR47R.js → inspect-proxy-OVEFBJ26.js} +2 -2
  18. package/dist/{manager-344C5JLZ.js → manager-JXYRGR6B.js} +6 -2
  19. package/dist/{orchestrator-LZQTDOWM.js → orchestrator-FEMPJOZD.js} +11 -12
  20. package/dist/package.json +2 -1
  21. package/dist/platform-AB3GIEGO.js +21 -0
  22. package/dist/{processor-7KAXESY5.js → processor-QB3NMRMO.js} +11 -10
  23. package/dist/{serve-HGHFN3D2.js → serve-32FAA4FX.js} +14 -13
  24. package/dist/server/index.js +13 -12
  25. package/dist/{server-W42ENYFX.js → server-OYE7GERR.js} +13 -12
  26. package/dist/{settings-ZZ6AKFPD.js → settings-6ZPWOBWL.js} +2 -2
  27. package/dist/{tools-2EB7C6H2.js → tools-INWP6FGV.js} +10 -9
  28. package/dist/web/assets/{index-B0Q5uK2h.css → index-BELeAs12.css} +1 -1
  29. package/dist/web/assets/{index-BhQN93bI.js → index-C3n65CNu.js} +76 -76
  30. package/dist/web/index.html +2 -2
  31. package/dist/web/sw.js +1 -1
  32. package/dist/{worktree-EIF75WGF.js → worktree-6U45P63P.js} +6 -2
  33. package/package.json +2 -1
@@ -22,17 +22,20 @@ function buildHttpHeaders(resHeaders, status, contentLengthOverride, contentType
22
22
  }
23
23
  var proxyPool = /* @__PURE__ */ new Map();
24
24
  var nextOffset = 0;
25
- function getAvailablePort() {
26
- const base = Number(process.env["OPENFOX_PORT"] ?? 10369);
27
- const used = /* @__PURE__ */ new Set();
28
- for (const instance of proxyPool.values()) {
29
- const addr = instance.server.address();
30
- if (addr && typeof addr === "object") used.add(addr.port);
31
- }
32
- for (let port = base + 1; port < base + 200; port++) {
33
- if (!used.has(port)) return port;
25
+ async function getAvailablePort(proxyBase) {
26
+ for (let port = proxyBase; port < proxyBase + 200; port++) {
27
+ if (await tryBind(port)) return port;
34
28
  }
35
- return base + (nextOffset++ % 200 + 1);
29
+ return proxyBase + nextOffset++ % 200;
30
+ }
31
+ function tryBind(port) {
32
+ return new Promise((resolve) => {
33
+ const server = net.createServer();
34
+ server.on("error", () => resolve(false));
35
+ server.listen(port, "127.0.0.1", () => {
36
+ server.close(() => resolve(true));
37
+ });
38
+ });
36
39
  }
37
40
  function parseReqHeaders(str) {
38
41
  const lines = str.split("\r\n");
@@ -85,8 +88,8 @@ function dechunk(buf) {
85
88
  }
86
89
  return Buffer.concat(parts);
87
90
  }
88
- function startInspectProxy(target, sessionManager, workdir) {
89
- const port = getAvailablePort();
91
+ async function startInspectProxy(target, sessionManager, devServerPort, workdir) {
92
+ const port = await getAvailablePort(devServerPort + 1e3);
90
93
  const server = net.createServer((client) => {
91
94
  let clientHead = "";
92
95
  let clientParsed = false;
@@ -340,4 +343,4 @@ export {
340
343
  startInspectProxy,
341
344
  stopAllInspectProxies
342
345
  };
343
- //# sourceMappingURL=chunk-WNA5VPZG.js.map
346
+ //# sourceMappingURL=chunk-4QBDV6LX.js.map
@@ -1,15 +1,13 @@
1
- import {
2
- appendCompactionPrompt
3
- } from "./chunk-5V5DM5E4.js";
4
1
  import {
5
2
  applyDynamicContext,
6
3
  computeSessionHash,
7
- injectWorkflowKickoffIfNeeded,
8
4
  runAgentTurn,
9
5
  runChatTurn
10
- } from "./chunk-UBIHP5Z7.js";
6
+ } from "./chunk-PYRH4G2J.js";
7
+ import {
8
+ appendCompactionPrompt
9
+ } from "./chunk-ZLON3JTI.js";
11
10
  import {
12
- checkAborted,
13
11
  deleteItemFromDir,
14
12
  devServerManager,
15
13
  executeSubAgent,
@@ -17,17 +15,17 @@ import {
17
15
  getToolRegistryForAgent,
18
16
  jsonSerializer,
19
17
  loadAllAgentsDefault,
20
- saveItemToDir,
21
- spawnShellProcess
22
- } from "./chunk-3ACDQKK6.js";
18
+ saveItemToDir
19
+ } from "./chunk-YU6DZAVA.js";
23
20
  import {
24
21
  TurnMetrics,
25
22
  createMessageStartEvent
26
- } from "./chunk-R4UTFE63.js";
23
+ } from "./chunk-TJO4QFDQ.js";
27
24
  import {
28
- getPlatformShell,
29
- onProcessEvent
30
- } from "./chunk-BGTEIA2S.js";
25
+ checkAborted,
26
+ onProcessEvent,
27
+ spawnShellProcess
28
+ } from "./chunk-TFCHWMOJ.js";
31
29
  import {
32
30
  gitSpawnEnv
33
31
  } from "./chunk-WGMJCFCE.js";
@@ -55,6 +53,9 @@ import {
55
53
  serializeServerMessage,
56
54
  storedEventToServerMessage
57
55
  } from "./chunk-F4PMNP7S.js";
56
+ import {
57
+ getPlatformShell
58
+ } from "./chunk-X5DOUA3Z.js";
58
59
  import {
59
60
  getPendingQuestionsForSession,
60
61
  provideAnswer
@@ -91,6 +92,9 @@ var TerminalManager = class {
91
92
  generateId() {
92
93
  return `term_${Date.now()}_${Math.random().toString(36).slice(2, 11)}`;
93
94
  }
95
+ // Uses getPlatformShell() directly instead of spawnShell() because
96
+ // node-pty.spawn() has a different API than child_process.spawn().
97
+ // PTY requires the command and argv separately, not a shell -c invocation.
94
98
  getShell() {
95
99
  return getPlatformShell().command;
96
100
  }
@@ -678,6 +682,21 @@ function emitWorkflowMessage(eventStore, sessionId, content, windowOptions, onMe
678
682
  }
679
683
  return msgId;
680
684
  }
685
+ function injectGenericKickoff(sessionId) {
686
+ const eventStore = getEventStore();
687
+ const windowOpts = getCurrentWindowMessageOptions(sessionId);
688
+ const msgId = crypto.randomUUID();
689
+ eventStore.append(
690
+ sessionId,
691
+ createMessageStartEvent(msgId, "user", "Proceed with the current step.", {
692
+ ...windowOpts ?? {},
693
+ isSystemGenerated: true,
694
+ messageKind: "auto-prompt",
695
+ metadata: { type: "workflow", name: "Workflow", color: "#f59e0b" }
696
+ })
697
+ );
698
+ eventStore.append(sessionId, { type: "message.done", data: { messageId: msgId } });
699
+ }
681
700
  function getCurrentWindowMessageOptions(sessionId) {
682
701
  const contextWindowId = getCurrentContextWindowId(sessionId);
683
702
  return contextWindowId ? { contextWindowId } : void 0;
@@ -848,7 +867,7 @@ async function executeWorkflow(workflow, options, subGroup) {
848
867
  agentStep.agentId ?? "planner",
849
868
  append,
850
869
  {
851
- ...!firstEntryForStep.has(step.id) && !agentStep.prompt && options.injectWorkflowKickoff === true ? { injectKickoff: () => injectWorkflowKickoffIfNeeded(sessionManager, sessionId, es) } : {},
870
+ ...!firstEntryForStep.has(step.id) && !agentStep.prompt ? { injectKickoff: () => injectGenericKickoff(sessionId) } : {},
852
871
  onToolExecuted: (toolCall, toolResult) => {
853
872
  if (toolCall.name === "step_done" && toolResult.success) {
854
873
  stepDoneCalled = true;
@@ -1591,10 +1610,30 @@ function createWebSocketServer(httpServer, _config, getLLMClient, getActiveProvi
1591
1610
  const messages = buildMessagesFromStoredEvents(events);
1592
1611
  const pendingConfirmations = foldPendingConfirmations(events);
1593
1612
  const pendingQuestions = getPendingQuestionsForSession(updatedSession.id);
1613
+ const effectiveWorkdir = updatedSession.worktree ?? updatedSession.workdir;
1614
+ let worktreeChanged = false;
1615
+ for (const [, client] of clients) {
1616
+ if (client.activeSessionId === updatedSession.id && client.activeWorkdir !== effectiveWorkdir) {
1617
+ worktreeChanged = true;
1618
+ const prevWorkdir = client.activeWorkdir;
1619
+ client.activeWorkdir = effectiveWorkdir;
1620
+ if (prevWorkdir) moduleStopGitPolling(prevWorkdir);
1621
+ }
1622
+ }
1623
+ if (effectiveWorkdir) moduleStartGitPolling(effectiveWorkdir);
1594
1624
  broadcastForSession(
1595
1625
  updatedSession.id,
1596
1626
  createSessionStateMessage(updatedSession, messages, pendingConfirmations, pendingQuestions)
1597
1627
  );
1628
+ if (worktreeChanged && effectiveWorkdir) {
1629
+ ;
1630
+ (async () => {
1631
+ const branch = await moduleGitBranch(effectiveWorkdir);
1632
+ if (!branch) return;
1633
+ const { files } = await moduleGitDiff(effectiveWorkdir);
1634
+ broadcastForSession(updatedSession.id, createGitStatusMessage(branch, files));
1635
+ })();
1636
+ }
1598
1637
  }
1599
1638
  });
1600
1639
  onProcessEvent((_processId, msg) => {
@@ -2023,7 +2062,6 @@ ${content}` : workflowInfo;
2023
2062
  sessionId,
2024
2063
  llmClient: llmForSession(sessionId),
2025
2064
  statsIdentity: statsForSession(sessionId),
2026
- injectWorkflowKickoff: !hasUserMessage,
2027
2065
  ...launchPayload?.workflowId ? { workflowId: launchPayload.workflowId } : {},
2028
2066
  ...launchPayload?.subGroup ? { subGroup: launchPayload.subGroup } : {},
2029
2067
  ...hasUserMessage ? {
@@ -2120,4 +2158,4 @@ export {
2120
2158
  signalMcpReady,
2121
2159
  createWebSocketServer
2122
2160
  };
2123
- //# sourceMappingURL=chunk-ZUM2ZJOX.js.map
2161
+ //# sourceMappingURL=chunk-B6JUWVTK.js.map
@@ -208,7 +208,7 @@ async function runCli(options) {
208
208
  if (!configExists) {
209
209
  await runNetworkSetup(mode);
210
210
  }
211
- const { runServe } = await import("./serve-HGHFN3D2.js");
211
+ const { runServe } = await import("./serve-32FAA4FX.js");
212
212
  const serveOptions = { mode };
213
213
  if (values.port) serveOptions.port = parseInt(values.port);
214
214
  if (values["no-browser"] === true) serveOptions.openBrowser = false;
@@ -220,4 +220,4 @@ async function runCli(options) {
220
220
  export {
221
221
  runCli
222
222
  };
223
- //# sourceMappingURL=chunk-R7EED6ZU.js.map
223
+ //# sourceMappingURL=chunk-MQHMT5WF.js.map
@@ -10,16 +10,15 @@ import {
10
10
  loadAllAgentsDefault,
11
11
  processEventsForConversation,
12
12
  runTopLevelAgentLoop
13
- } from "./chunk-3ACDQKK6.js";
13
+ } from "./chunk-YU6DZAVA.js";
14
14
  import {
15
15
  TurnMetrics,
16
- WORKFLOW_KICKOFF_PROMPT,
17
16
  buildAgentReminder,
18
17
  buildAgentSmallReminder,
19
18
  buildTopLevelSystemPrompt,
20
19
  createChatDoneEvent,
21
20
  createMessageStartEvent
22
- } from "./chunk-R4UTFE63.js";
21
+ } from "./chunk-TJO4QFDQ.js";
23
22
  import {
24
23
  getCurrentContextWindowId,
25
24
  getCurrentWindowMessageOptions,
@@ -65,7 +64,7 @@ function resolveAgentDef(sessionManager, sessionId) {
65
64
  }
66
65
  async function buildCachedPrompt(sessionManager, sessionId, agentDef) {
67
66
  const { instructionContent, skills } = await loadSessionContext(sessionManager, sessionId);
68
- const { getToolRegistryForAgent: getToolRegistryForAgent2 } = await import("./tools-2EB7C6H2.js");
67
+ const { getToolRegistryForAgent: getToolRegistryForAgent2 } = await import("./tools-INWP6FGV.js");
69
68
  const tools = getToolRegistryForAgent2(agentDef).definitions;
70
69
  const toolFingerprint = getToolFingerprint(tools);
71
70
  const allAgents = await loadAllAgentsDefault();
@@ -78,7 +77,7 @@ async function buildCachedPrompt(sessionManager, sessionId, agentDef) {
78
77
  async function computeSessionHash(sessionManager, sessionId) {
79
78
  const { instructionContent, skills } = await loadSessionContext(sessionManager, sessionId);
80
79
  const agentDef = await resolveAgentDef(sessionManager, sessionId);
81
- const { getToolRegistryForAgent: getToolRegistryForAgent2 } = await import("./tools-2EB7C6H2.js");
80
+ const { getToolRegistryForAgent: getToolRegistryForAgent2 } = await import("./tools-INWP6FGV.js");
82
81
  const tools = getToolRegistryForAgent2(agentDef).definitions;
83
82
  const toolFingerprint = getToolFingerprint(tools);
84
83
  return computeDynamicContextHash(instructionContent, skills, toolFingerprint);
@@ -96,7 +95,7 @@ async function applyDynamicContext(sessionManager, sessionId) {
96
95
 
97
96
  // src/server/chat/orchestrator.ts
98
97
  async function buildRetryPatterns() {
99
- const { getSetting, SETTINGS_KEYS } = await import("./settings-ZZ6AKFPD.js");
98
+ const { getSetting, SETTINGS_KEYS } = await import("./settings-6ZPWOBWL.js");
100
99
  const raw = getSetting(SETTINGS_KEYS.RETRY_PATTERNS);
101
100
  if (!raw) {
102
101
  const oldXmlProtection = getSetting("llm.disableXmlProtection");
@@ -338,30 +337,6 @@ async function runAgentTurn(options, turnMetrics, agentId, append, callbacks) {
338
337
  turnMetrics
339
338
  );
340
339
  }
341
- function injectWorkflowKickoffIfNeeded(sessionManager, sessionId, eventStore) {
342
- const session = sessionManager.requireSession(sessionId);
343
- const currentWindowMessageOptions = getCurrentContextWindowId(sessionId) ? { contextWindowId: getCurrentContextWindowId(sessionId) } : void 0;
344
- const events = eventStore.getEvents(sessionId);
345
- const hasKickoff = events.some((e) => {
346
- if (e.type !== "message.start") return false;
347
- const data = e.data;
348
- return data.messageKind === "auto-prompt" && data.content?.includes("fulfil the");
349
- });
350
- if (!hasKickoff) {
351
- const kickoffMsgId = crypto.randomUUID();
352
- const kickoffContent = WORKFLOW_KICKOFF_PROMPT(session.criteria.length);
353
- eventStore.append(
354
- sessionId,
355
- createMessageStartEvent(kickoffMsgId, "user", kickoffContent, {
356
- ...currentWindowMessageOptions ?? {},
357
- isSystemGenerated: true,
358
- messageKind: "auto-prompt",
359
- metadata: { type: "workflow", name: "Workflow", color: "#f59e0b" }
360
- })
361
- );
362
- eventStore.append(sessionId, { type: "message.done", data: { messageId: kickoffMsgId } });
363
- }
364
- }
365
340
  function buildSnapshot(sessionManager, sessionId, _lastStats) {
366
341
  const eventStore = getEventStore();
367
342
  const session = sessionManager.requireSession(sessionId);
@@ -380,7 +355,6 @@ export {
380
355
  computeSessionHash,
381
356
  applyDynamicContext,
382
357
  runChatTurn,
383
- runAgentTurn,
384
- injectWorkflowKickoffIfNeeded
358
+ runAgentTurn
385
359
  };
386
- //# sourceMappingURL=chunk-UBIHP5Z7.js.map
360
+ //# sourceMappingURL=chunk-PYRH4G2J.js.map
@@ -9,30 +9,27 @@ import {
9
9
  startProcess,
10
10
  updateStatus
11
11
  } from "./chunk-PK2RMVMB.js";
12
+ import {
13
+ getPlatformShell
14
+ } from "./chunk-X5DOUA3Z.js";
12
15
 
13
- // src/server/tools/background-process/manager.ts
16
+ // src/server/utils/shell.ts
14
17
  import { spawn } from "child_process";
15
-
16
- // src/server/utils/platform.ts
17
- import os from "os";
18
- function getPlatformShell() {
19
- if (process.platform === "win32") {
20
- return { command: "cmd.exe", args: ["/c"] };
21
- }
22
- const userShell = os.userInfo().shell;
23
- if (userShell) {
24
- return { command: userShell, args: ["-c"] };
25
- }
26
- return { command: "sh", args: ["-c"] };
18
+ function checkAborted(signal) {
19
+ return !!signal?.aborted;
27
20
  }
28
- function getPathSeparator() {
29
- return process.platform === "win32" ? ";" : ":";
30
- }
31
- function isWindowsPath(path) {
32
- return /^[A-Za-z]:[/\\]/.test(path);
21
+ function spawnShell(command, options) {
22
+ const shell = getPlatformShell();
23
+ return spawn(shell.command, [...shell.args, command], {
24
+ cwd: options.cwd,
25
+ env: { ...process.env },
26
+ stdio: options.stdio ?? ["ignore", "pipe", "pipe"],
27
+ windowsHide: true,
28
+ ...options.detached ? { detached: true } : {}
29
+ });
33
30
  }
34
- function isAbsolutePath(path) {
35
- return path.startsWith("/") || isWindowsPath(path);
31
+ function spawnShellProcess(command, cwd, _signal, detached = false) {
32
+ return spawnShell(command, { cwd, detached });
36
33
  }
37
34
 
38
35
  // src/server/tools/background-process/manager.ts
@@ -64,13 +61,9 @@ function createProcess2(sessionId, name, command, cwd, timeout) {
64
61
  function startProcessCommand(processId, sessionId, command, cwd) {
65
62
  const proc = startProcess(processId, sessionId, 0);
66
63
  if (!proc) return null;
67
- const shell = getPlatformShell();
68
- const child = spawn(shell.command, [...shell.args, command], {
64
+ const child = spawnShell(command, {
69
65
  cwd,
70
- env: { ...process.env, FORCE_COLOR: "1" },
71
- stdio: ["ignore", "pipe", "pipe"],
72
- detached: true,
73
- windowsHide: true
66
+ detached: true
74
67
  });
75
68
  proc.pid = child.pid ?? null;
76
69
  updateStatus(processId, sessionId, "running");
@@ -143,9 +136,9 @@ function getProcessLogs(processId, since = 0, maxLines) {
143
136
  }
144
137
 
145
138
  export {
146
- getPlatformShell,
147
- getPathSeparator,
148
- isAbsolutePath,
139
+ checkAborted,
140
+ spawnShell,
141
+ spawnShellProcess,
149
142
  onProcessEvent,
150
143
  createProcess2 as createProcess,
151
144
  startProcessCommand,
@@ -154,4 +147,4 @@ export {
154
147
  getSessionProcesses2 as getSessionProcesses,
155
148
  getProcessLogs
156
149
  };
157
- //# sourceMappingURL=chunk-BGTEIA2S.js.map
150
+ //# sourceMappingURL=chunk-TFCHWMOJ.js.map
@@ -1,3 +1,6 @@
1
+ import {
2
+ getPlatformShell
3
+ } from "./chunk-X5DOUA3Z.js";
1
4
  import {
2
5
  streamWithSegments
3
6
  } from "./chunk-J2GP3J3X.js";
@@ -33,6 +36,7 @@ function computeEffectiveTools(allowedTools, type) {
33
36
  }
34
37
 
35
38
  // src/server/chat/prompts.ts
39
+ import { basename } from "path";
36
40
  function buildBasePrompt(workdir, customInstructions, skills, modelName) {
37
41
  const instructionsSection = customInstructions ? `
38
42
 
@@ -47,7 +51,8 @@ Today's date is ${(/* @__PURE__ */ new Date()).toISOString().split("T")[0].repla
47
51
 
48
52
  ## ENVIRONMENT
49
53
  Working directory: ${workdir}
50
- Platform: ${process.platform} (${process.arch})${modelLine}
54
+ Platform: ${process.platform} (${process.arch})
55
+ Shell (run_command): ${basename(getPlatformShell().command)}${modelLine}
51
56
 
52
57
  ## CORE BEHAVIOR
53
58
  Help user complete tasks safely and efficiently.
@@ -226,7 +231,6 @@ function buildAgentSmallReminder(name) {
226
231
  Reminder: you are in '${name}' mode.
227
232
  </system-reminder>`;
228
233
  }
229
- var WORKFLOW_KICKOFF_PROMPT = (criteriaCount) => `Implement the task and make sure you fulfil the ${criteriaCount} criteria.`;
230
234
  var COMPACTION_PROMPT = `You are a helpful AI assistant tasked with summarizing conversations for continuation.
231
235
 
232
236
  Summarize the conversation history concisely, preserving:
@@ -664,7 +668,6 @@ export {
664
668
  buildTopLevelSystemPrompt,
665
669
  buildAgentReminder,
666
670
  buildAgentSmallReminder,
667
- WORKFLOW_KICKOFF_PROMPT,
668
671
  COMPACTION_PROMPT,
669
672
  streamLLMPure,
670
673
  TurnMetrics,
@@ -675,4 +678,4 @@ export {
675
678
  createChatDoneEvent,
676
679
  consumeStreamGenerator
677
680
  };
678
- //# sourceMappingURL=chunk-R4UTFE63.js.map
681
+ //# sourceMappingURL=chunk-TJO4QFDQ.js.map
@@ -7,8 +7,9 @@ import {
7
7
 
8
8
  // src/server/git/worktree.ts
9
9
  import { spawn } from "child_process";
10
- import { mkdir, readFile, appendFile, stat } from "fs/promises";
10
+ import { mkdir, readFile, appendFile, stat, symlink } from "fs/promises";
11
11
  import { resolve } from "path";
12
+ import copy from "@danieldietrich/copy";
12
13
  function captureStdout(cwd, args) {
13
14
  return new Promise((resolvePromise) => {
14
15
  const proc = spawn("git", args, { cwd, env: gitSpawnEnv(), stdio: ["ignore", "pipe", "ignore"] });
@@ -122,6 +123,57 @@ async function ensureWorktree(projectDir, name, startBranch) {
122
123
  }
123
124
  return { path: wtPath, name };
124
125
  }
126
+ async function getIgnoredDirectories(projectDir) {
127
+ const out = await captureStdout(projectDir, [
128
+ "ls-files",
129
+ "--others",
130
+ "--ignored",
131
+ "--exclude-standard",
132
+ "--directory"
133
+ ]);
134
+ if (!out) return [];
135
+ return out.trim().split("\n").filter(Boolean);
136
+ }
137
+ function resolveStrategy(relPath, config) {
138
+ const normalized = relPath.replace(/\/$/, "");
139
+ const basename = normalized.split("/").pop() ?? normalized;
140
+ return config.overrides?.[normalized] ?? config.overrides?.[basename] ?? config.ignoredAssets;
141
+ }
142
+ async function syncIgnoredAssets(projectDir, worktreePath, config) {
143
+ const ignoredPaths = await getIgnoredDirectories(projectDir);
144
+ if (ignoredPaths.length === 0) return;
145
+ const results = [];
146
+ for (const relPath of ignoredPaths) {
147
+ const sourcePath = resolve(projectDir, relPath);
148
+ const targetPath = resolve(worktreePath, relPath);
149
+ try {
150
+ await stat(sourcePath);
151
+ } catch {
152
+ continue;
153
+ }
154
+ const strategy = resolveStrategy(relPath, config);
155
+ if (strategy === "skip") continue;
156
+ try {
157
+ if (strategy === "symlink") {
158
+ try {
159
+ await stat(targetPath);
160
+ continue;
161
+ } catch {
162
+ }
163
+ await symlink(sourcePath, targetPath);
164
+ results.push(`symlink ${relPath}`);
165
+ } else if (strategy === "copy") {
166
+ await copy(sourcePath, targetPath);
167
+ results.push(`copy ${relPath}`);
168
+ }
169
+ } catch (err) {
170
+ logger.warn("Failed to sync ignored asset to worktree", { relPath, strategy, error: String(err) });
171
+ }
172
+ }
173
+ if (results.length > 0) {
174
+ logger.info("Synced ignored assets to worktree", { count: results.length, actions: results });
175
+ }
176
+ }
125
177
 
126
178
  export {
127
179
  getGitBranch,
@@ -132,6 +184,8 @@ export {
132
184
  listBranches,
133
185
  checkoutBranch,
134
186
  createBranch,
135
- ensureWorktree
187
+ ensureWorktree,
188
+ getIgnoredDirectories,
189
+ syncIgnoredAssets
136
190
  };
137
- //# sourceMappingURL=chunk-OBK3I4KD.js.map
191
+ //# sourceMappingURL=chunk-VLV3XWZS.js.map
@@ -0,0 +1,66 @@
1
+ import {
2
+ SETTINGS_KEYS,
3
+ getSetting
4
+ } from "./chunk-XUPKS5FL.js";
5
+
6
+ // src/server/utils/platform.ts
7
+ import os from "os";
8
+ import { existsSync } from "fs";
9
+ import { join } from "path";
10
+ function findGitBash() {
11
+ const candidates = [
12
+ process.env["ProgramFiles"] && join(process.env["ProgramFiles"], "Git", "bin", "bash.exe"),
13
+ process.env["ProgramFiles(x86)"] && join(process.env["ProgramFiles(x86)"], "Git", "bin", "bash.exe"),
14
+ process.env["LocalAppData"] && join(process.env["LocalAppData"], "Programs", "Git", "bin", "bash.exe")
15
+ ].filter((p) => !!p);
16
+ return candidates.find((p) => existsSync(p)) ?? null;
17
+ }
18
+ var CMD_SHELL = { command: "cmd.exe", args: ["/c"] };
19
+ var WINDOWS_SHELLS = {
20
+ cmd: () => CMD_SHELL,
21
+ powershell: () => ({ command: "powershell.exe", args: ["-NoProfile", "-Command"] }),
22
+ gitbash: () => {
23
+ const bash = findGitBash();
24
+ return bash ? { command: bash, args: ["-c"] } : null;
25
+ }
26
+ };
27
+ function listAvailableShells() {
28
+ if (process.platform !== "win32") {
29
+ return [];
30
+ }
31
+ return [
32
+ { id: "cmd", label: "cmd.exe", available: true },
33
+ { id: "powershell", label: "PowerShell", available: true },
34
+ { id: "gitbash", label: "Git Bash", available: findGitBash() !== null }
35
+ ];
36
+ }
37
+ function getPlatformShell() {
38
+ if (process.platform === "win32") {
39
+ const choice = getSetting(SETTINGS_KEYS.TOOLS_SHELL) ?? "cmd";
40
+ return WINDOWS_SHELLS[choice]?.() ?? CMD_SHELL;
41
+ }
42
+ const userShell = os.userInfo().shell;
43
+ if (userShell) {
44
+ return { command: userShell, args: ["-c"] };
45
+ }
46
+ return { command: "sh", args: ["-c"] };
47
+ }
48
+ function getPathSeparator() {
49
+ return process.platform === "win32" ? ";" : ":";
50
+ }
51
+ function isWindowsPath(path) {
52
+ return /^[A-Za-z]:[/\\]/.test(path);
53
+ }
54
+ function isAbsolutePath(path) {
55
+ return path.startsWith("/") || isWindowsPath(path);
56
+ }
57
+
58
+ export {
59
+ findGitBash,
60
+ listAvailableShells,
61
+ getPlatformShell,
62
+ getPathSeparator,
63
+ isWindowsPath,
64
+ isAbsolutePath
65
+ };
66
+ //# sourceMappingURL=chunk-X5DOUA3Z.js.map
@@ -25,7 +25,8 @@ var SETTINGS_KEYS = {
25
25
  SEARCH_TAVILY_API_KEY: "search.tavilyApiKey",
26
26
  SEARCH_SEARXNG_URL: "search.searxngUrl",
27
27
  SEARCH_SEARXNG_API_KEY: "search.searxngApiKey",
28
- TOOLS_USE_RTK: "tools.useRtk"
28
+ TOOLS_USE_RTK: "tools.useRtk",
29
+ TOOLS_SHELL: "tools.shell"
29
30
  };
30
31
  var SETTINGS_DEFAULTS = {
31
32
  [SETTINGS_KEYS.DISPLAY_SHOW_THINKING]: "true",
@@ -51,7 +52,8 @@ var SETTINGS_DEFAULTS = {
51
52
  { type: "chord", key: "4", modifiers: ["ctrl"] }
52
53
  ]
53
54
  }),
54
- [SETTINGS_KEYS.TOOLS_USE_RTK]: "false"
55
+ [SETTINGS_KEYS.TOOLS_USE_RTK]: "false",
56
+ [SETTINGS_KEYS.TOOLS_SHELL]: "cmd"
55
57
  };
56
58
  function getSetting(key) {
57
59
  try {
@@ -99,4 +101,4 @@ export {
99
101
  deleteSetting,
100
102
  getAllSettings
101
103
  };
102
- //# sourceMappingURL=chunk-PVRSNXD4.js.map
104
+ //# sourceMappingURL=chunk-XUPKS5FL.js.map